Xastir-Release-2.2.4/0000775000175000017500000000000015151324131013321 5ustar hibbyhibbyXastir-Release-2.2.4/.dir-locals.el0000664000175000017500000000014315151324131015750 0ustar hibbyhibby((nil . ((indent-tabs-mode . nil) (c-basic-offset . 2) (tab-width . 2)) )) Xastir-Release-2.2.4/.github/0000775000175000017500000000000015151324131014661 5ustar hibbyhibbyXastir-Release-2.2.4/.github/workflows/0000775000175000017500000000000015151324131016716 5ustar hibbyhibbyXastir-Release-2.2.4/.github/workflows/test-build.yml0000664000175000017500000000743615151324131021527 0ustar hibbyhibbyname: Test Builds on: push: branches: [ "master" ] pull_request: branches: [ "master" ] workflow_dispatch: jobs: basic-ubuntu-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Update Packages run: sudo apt-get update - name: Install Packages run: sudo apt-get install -y build-essential xorg-dev graphicsmagick libgraphicsmagick1-dev libmotif-dev libcurl4-openssl-dev libpcre2-dev libdb-dev shapelib libshp-dev libxpm-dev - name: Bootstrap run: ./bootstrap.sh - name: configure run: ./configure CPPFLAGS="-I/usr/include/geotiff" - name: make run: make - name: make install run: sudo make install full-ubuntu-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Update Packages run: sudo apt-get update - name: Install Packages run: sudo apt-get install -y build-essential xorg-dev graphicsmagick libgraphicsmagick1-dev libmotif-dev libcurl4-openssl-dev libpcre2-dev libdb-dev shapelib libshp-dev libxpm-dev libproj-dev festival festival-dev libgeotiff-dev gpsman gpsmanshp libcjson1 libcjson-dev wget - name: Bootstrap (with autoreconf) run: autoreconf -i - name: configure run: ./configure CPPFLAGS="-I/usr/include/geotiff" - name: make run: make - name: make check run: make check - name: make install run: sudo make install - name: get NWS data run: sudo /usr/local/share/xastir/scripts/get-NWSdata macos-build: runs-on: macos-latest steps: - uses: actions/checkout@v4 - name: Install XQuartz run: brew install xquartz --cask - name: Install Packages run: brew install autoconf automake libtool berkeley-db graphicsmagick libgeotiff openmotif pcre proj shapelib cjson - name: Bootstrap run: ./bootstrap.sh - name: configure run: ./configure CPPFLAGS="-I/usr/include/geotiff -I/opt/homebrew/include -I/opt/homebrew/opt/berkeley-db/include" "LDFLAGS=-L/opt/homebrew/lib -L/opt/homebrew/opt/berkeley-db/lib" - name: make run: make - name: make check run: make check - name: make install run: sudo make install freebsd-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set-up VM uses: vmactions/freebsd-vm@v1 with: sync: nfs usesh: true prepare: | pkg install -y devel/autoconf devel/automake devel/shapelib devel/pcre2 graphics/GraphicsMagick graphics/libgeotiff ftp/curl databases/db18 lang/gcc13 x11-toolkits/open-motif audio/festival devel/libcjson lang/gcc14 - name: Bootstrap shell: freebsd {0} run: | cd $GITHUB_WORKSPACE autoreconf -i - name: configure out-of-source gcc13 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE cd .. mkdir build cd build ../Xastir/configure --with-bdb-incdir=/usr/local/include/db18 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++13 - name: configure out-of-source gcc14 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE cd .. mkdir build-gcc14 cd build-gcc14 ../Xastir/configure --with-bdb-incdir=/usr/local/include/db18 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++14 - name: make gcc13 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE/../build make - name: make gcc14 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE/../build-gcc14 make - name: make check gcc13 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE/../build make check - name: make check gcc14 shell: freebsd {0} run: | cd $GITHUB_WORKSPACE/../build-gcc14 make check Xastir-Release-2.2.4/.vimrc0000664000175000017500000000143315151324131014443 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/AUTHORS0000664000175000017500000000372615151324131014401 0ustar hibbyhibby Developers and Contributors _________________________________________________________________ Here we attempt to list most of the Xastir developers and contributors who have devoted large amounts of time to making Xastir one of the best APRS(tm) clients ever. Unfortunately we can't devote much time to keeping this list current or adding new contributors. Xastir was originally written by Frank Giannandrea, KC2GJS (was KC0DGE). APRS(tm) is a Trademark of Bob Bruninga Developers and Contributors (in alphabetical order): DK7IN Rolf Bleher HI8GN Jose R Marte A IK0YUP Alessandro Frigeri K2DLS Dan Srebnick KA6HLD Jerry Dunmire KA9KIM Mike Sims KB3EGH Derrick Brashear KB3EHW Reuven Gevaryahu (our resident docs guy!) KC2ELS Jack Twilley KD5AMB Mark Grennan KD6VPE Jim Sevilla KD6ZWR Chris Bell KE4NFJ Gerald Stueve (K4INT) KG4IJB Charles Byam KM5VY Tom Russo N0RPM Jason Godfrey N0VH Jim Chandler N2YGK Alan Crosswell N3NYN Michael G Petry N7IPB Ken Koster N7TAP Olivier Calle N8YSZ Dan Brown PE1DNN Henk de Groot VE3UNW Richard Hagemyer VE6LFM Lloyd Miller WE7U Curt Mills SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used to describe it. So be it. Thanks Tony and Steve! Thanks go to all the people who have made individual contributions to the Xastir project by sending bug-reports, patches, or who have otherwise supported the project. There are too many to list. If you think that you are missing from this list contact the Xastir Development Team at . _________________________________________________________________ Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/CC_OpenStreetMap_logo.png0000664000175000017500000001226315151324131020146 0ustar hibbyhibbyPNG  IHDR'sRGBbKGD pHYs  tIME) dPtEXtCommentCreated with GIMPWIDATxyxTsf$IH JX $A.(^K}JU(zzmz}JXܠ Q [p!{&3G2 /Yss|n߇ JU? pqv1e&%zмhL7ͷ aaa#Aи\VUt:?z=Q?mintob"˲YRu/RϞ7jױvPlk9{\o]Bѐ0vaqцˮ\ĤmK1RSSU&ZJv0<  jAZkA@T*T*U,H$-(%Q$QidI9_ wA~>*^s{K_U$ iƬ97CSo5G˸1n6Obn-ݍWrᖯrvz}*2c2?8Y]x EZݷSju_CJ%2ߡ0H}b-C$P8K`.GVhDmyO%ix$@tL$>oө]RRe? FA-j l%{~ ,>>ZIz@bI[6l fù3jtԯ@|o+N@WkTqѩn*[s^{x| f_Y͸IvNv!no!6.VR'O}lwaÆcG 8/ډF9FV!oSm.RNX,XVIOO`׮]PTTnWεfYytc4 ?@`; B1p8}x9===XVINN555X"f3Ϯ{;R)3'j ^{wݡmǗP˕O$)y,HIˉ#>\N71#D9qGyҥr~~sMMM.O>mF;bUQaa!+VPHIMᵍ`4Ul6mҫΰ(䐒3?}^/>z^B  D~vyt*с)2CV3u NdZ*eS _6/hl,TiG{K'.;V125j5@ ơC;'TWW+淪׽4 6LFuj wjRUY}+8]oIƬܽd)w/YJƬܱ%9nd||^?vd(0j( }?Hd :V_3u&1mtNvL&#:X fKЀb B0Ue+Dqq&\bX(..V(\Į]%՚).(K3:q鵕AמKN_VZSH5L-^ ~Ưׯ`P=@h#Ǣ7@7A t; $)R 不˃"VM">ތ Jwu8zhw\\ |hZ{~ҹ6mVp.0׮u~ T5AA)0]Cee%gXmdddA &{zz< wZF^xxbuG.ܸ"19aMwQg7 (B-P jzz5M m@$#ccT΢O%U$A"EY۶ee,_\/F,e544mvGPaalz/} {uo ֯@OptvҫW3 MMaH`6D׫HIIAj4cьAK:#iʹ aЄyM9j@Gpsm-X|s.c2eJT{{{-..V:477WildeeIff&k֬9k~SAkQIq86TRf3+x/J0 $˫h<.L& 2vsV^z nEAjXc'tq0EDQ_ʄdzk>|_l7qDv{b A/Zδldff8fa%++댶Ç+ѼjJh p &b*** (";;9hX裘FXYitbaʕv\HbF3"AO' Wd-\}\1^HV^0^lSWN8 U7a?:;1 Dw,o6c2;w c<6Vvzꥭ0s8- :b*?oOS[mmm.9O19* DQQ))5N1'V7ɓ}cĉJ:|==]]1}/w1!/#p|l}FRR2 pY•KtwrQ*NzDðwܣbbT{Oc<4AQXXnqƱf͚Swh[I?U_Pc?Vb6),,$++KZ!++c6y8~O1EhbR'NTesqvu!h4 ƥ7{f!n# a,\tM7,`ߞշ̤8ZQH|*ٌ[;_eG0GÇ<3ڂa@CJ9;lX ϭ"HKKb`/fR'Q&.X|Ca6f3:k4w0jezgIlp;W];/ʏau3:~?cGslF_1u7jet:֬^C", ]]]2eL###죽txkdtV'],ܺhQ8y<ȽTF-MlR,0a$fIp4T(JEYg>t/_>$A$ϭ[o A1Ƞ?$Mp(-?.7F&LmS:\~a[߆qxW}x8*T})ݰT{DQBL'>>֬Yd#v]ar ?ĢF*wzA'I0y) t6ӝK}[^hLaMHosX&J(ͫ|٧N0GBT]I5bt=I'@WnMSMZ}7P"{@ 4ie\if#Dٓ1}\}u Ӂd$*.F H?a][g_;'dۙ:m*?ɏyͷ 33M6w?+5,+s|V?&Q}}ᜈg@?v:KV<,Їhg1&.z:ۍǃ/Q%@)]%t$f͙EsS3UUU477zIKK`0: (nj3/x`KV֬^?`dit 42Hy4 eHP{D0)Π;G]}_tׁ$[9{>gƦQeTUN@eJr. xt`0IENDB`Xastir-Release-2.2.4/CC_OpenStreetMap_txt.png0000664000175000017500000000363615151324131020031 0ustar hibbyhibbyPNG  IHDR@UsRGBbKGD pHYs  tIMElޫtEXtCommentCreated with GIMPWIDAThZ_Ho~涖d5M)DtPhlnv";PP wAي(`H! Vʈ9&|?}yk{ de( # 2_($Mٓ!K"NG&''I}}=4_NRb~Jrss֭[Imm-q8)~N''D.v XBrssI^^r QD"ZMFFFڦ%3d`` eիW6lBD<EgggHE$ݻwq[SS?tX,bp)y ߿1::EA?Ǐg4 ~?~?4 X?|B˅X,˅={`||||1lS|BJD2Ld]g{x<DBz5t1X,F4ӧqm̙3"!P91ArQc˅#GѣGĉ4^ܹ]va۶mB,쫫|2󑝝 ٌjm?!QYY"Ю>B f QsgϞh4B*B" `0-- X7%h4 N±cbhݍF{,\.\.OyP. ՞yj!XwIm:i AAz\t߸q|XXX@gg'Ν;G5͘_bf\9ϟPH$j|RrFݍ8cP(Ly-lWR)>Lp58uJ%v؁V?}ԸϞ=K+ ۷߿g5^[[P(G+++D4^?PXXH7b߿0ɱbqۏd2hjjm"U8G* S^B0177/BRszO;QKKK)f? "b1%H&D1l6J%>}{&NFXmQPP@݋M \9'j=mlH$G.xT*+m;_}=oJn˘իWj#eɓ'j_|IkCjSVyʱ~r;( !FPPn݂^ &''a6 _ h[LlgaxxX 33304Asq(hAEElقS >;[ "PUURp8pQH$䠹^pAqݨH_I$L&L&b ^| JX JݞC{GGi}zoo/uVa4_pMHҔSʁ˖n|&ۋ/~B4Asq9;$C,# 2 3/_jE]IENDB`Xastir-Release-2.2.4/CONTRIBUTING.md0000664000175000017500000005416215151324131015562 0ustar hibbyhibby# Contributing to the Xastir project Hello possible new developer, and welcome to the Xastir project! ## Ways to contribute There are many ways to contribute to a project, and not all mean that you have to write code. * You can ask and answer questions on the Xastir mailing list * You can report bugs * You can fix bugs * You can add or modify features in Xastir ### Asking and answering questions Please subscribe to our mailing list as listed on the official Xastir web site, http://xastir.org/. You may also want to keep an eye on Github Discussions at https://github.com/Xastir/Xastir/discussions . ### Please don't open a Github Issue for questions about the code Github's "Issue" tracker is for reporting bugs. We would prefer it if you would not use Xastir's git hub issue tracker just to ask questions, as this is not the ideal forum and doesn't reach the full Xastir user community. Your best bet is to get your question in front of as many users' eyes as possible, and the mailing list is the way to do that. ### Github Discussions is fair game However, you may also use "GitHub Discussions" to ask questions, especially if the mailing list seems not to be getting you any response. ### Side benefits of subscribing to the mailing list and watching Discussions on github Once you're confident enough with Xastir to be answering users' questions, your presence on the mailing list will naturally allow you to see and answer those questions, too. ### Reporting bugs If you believe you might have found a bug, your first step might be to ask about it on the mailing list to see if it's really a bug, if you're making a mistake, or if it's just a difference between what you expect and what the code actually does. If you are reasonably sure that you have found a real bug and wish to report it, open an issue on the Xastir Github repository at https://github.com/Xastir/Xastir. Realize that Xastir is entirely a volunteer effort largely moved forward by very busy people, and your bug might not get fixed in short order, and it might not even get fixed unless you fix it yourself. ### Fixing bugs Another way you can contribute is to fix bugs yourself and submit pull requests to the group for your changes to be added to the main code base. You could fix bugs that you find yourself, or could look through the existing list of issues on Github and pick one to fix. If you do this, you will want to follow the procedure below that describes how to submit code changes for review and acceptance. ### Adding or modifying features in Xastir Maybe Xastir is lacking some feature you really want, or you really would like to make some other feature of Xastir work differently. The first step here might be to start a discussion on the mailing list to see if other users like your addition or modification before pressing ahead with it, but you could always just go ahead with the development and offer it as a suggested change through the pull request mechanism. Asking on the mailing list first is more likely to get a faster response when your pull request shows up.. ## General guidelines for contributing code In order to get contributed patches accepted more easily by the Xastir developers: * Read [Coding Standard](https://github.com/Xastir/Xastir/wiki/Coding-Standard). Make sure to follow the formatting and indentation rules, and in particular the tab format (spaces, not tabs). If you don't like some of the formatting rules, abide by them anyway for consistency. Some of the developers don't like some of the formatting rules either, but consistency is more important than ideas we might have of coding style! * Check the Xastir issue tracker: http://github.com/Xastir/Xastir/issues You need a GitHub account to create new issues, but this is free. This is one of the best places to see what needs to be worked on, and to see if anyone else has had a similar idea. * Check with the Xastir-Dev list first to see if anyone else is working on that particular idea or section of code. * Verify on the Xastir-Dev list that your idea has some merit and chance of being accepted before you put your valuable time into the change. * Make sure you're willing to abide by the GPL license with respect to your changes. * Use as generic C as possible, and comment what you've done, in English please! * Keep in mind that Xastir runs on multiple operating systems, so code for that. Some #ifdef's may be required in order to make it work for the various operating systems. * Xastir can be run in multiple languages, so code for that. If any user text is added, make sure to add language strings for them to the language files. If you don't know a particular language, add it to all of the language files in English. It will be translated by others later. ## Contributing code changes to the project While it is always possible to create a patch set and email the result to Xastir developers, this is no longer a desirable way to proceed. The preferred method of contributing source changes is through GitHub "pull requests." (See https://help.github.com/articles/about-pull-requests/) In a (rather large) nutshell this process goes like this: * Log in to Xastir's github repo at https://github.com/Xastir/Xastir.git and click the "Fork" button. This will create a copy of the repo that you have full control of. Once you have created a fork, here's a general approach you can use: * Clone your repo: cd git clone https://github.com/youruserid/Xastir.git cd Xastir The result of this step is that you will have a primary remote named "origin" that points at your forked repository. It will also have checked out the default branch, which in the case of the Xastir repo is just the "master" branch. * Add the official repo as a second remote called "upstream": git remote add upstream https://github.com/Xastir/Xastir.git Now your local repo knows about two remote repos -- yours, and the official project repo. Now make git sync to this remote, too: git fetch upstream * Create a topic branch to work on: git checkout -b * Do all your work while checked out in this branch. As you work, use git add/git commit commands to save your changes in logical chunks. Staging your changes in multiple commits this way helps keep the project history readable. See the notes below regarding formatting of commit messages, please. * When you have finished your work (or when you think you have) and are ready to ask for it to be reviewed and accepted, you will need to publish your changes to GitHub and initiate a pull request. * First, make sure your repo has an up-to-date master branch: ``` git fetch upstream # This fetches changes in the official rep git checkout master # go back to the master branch git merge upstream/master # brings your local master up to date git push origin : # this brings your GitHub fork up to date # by pushing all branches that exist # locally and upstream to origin git checkout # get your branch back ``` * Always rebase your feature branch so that it branches off of the current head of the master branch: ``` git rebase master # makes sure that your branch is based # on the most recent version of master ``` * Now publish your branch in your GitHub fork (your "origin" remote). git push -u origin Now your changes exist on the named branch in your GitHub repo, and may be shared with others. NOTE: If you have correctly refrained from touching the code on the master branch, the merge of upstream master will always be as simple as shown here, with no conflicts possible --- all you're doing is grabbing what others have done while you were working. In times of great activity on master (there are seldom such times) it is possible, though, that the rebase operation can show conflicts between upstream changes and your changes that you will have to fix yourself. Resolving these conflicts requires editing your code, fixing the conflict markers, then doing additional git add/git commit operations and a third command to tell git rebase to continue after the conflict resolution. Please see the Pro Git book at https://git-scm.com/book/en/v2 for guidance should this happen to you. * A good practice at this point, before you've asked the Xastir developers to merge your work, to create a "draft" pull request. They can easily check out your fork and make sure there are no hidden issues you hadn't detected. See below for a suggestion of the easiest way to check out other people's topic branches. Most importantly, when you create your pull request it will also run all of Xastir's Github Actions, checking that your new code compiles on several different operating systems. This addresses the concern that you've created non-portable changes and gives you the opportunity to fix them if you have. * Now you are ready to ask for your code to be reviewed and accepted. * Open your web browser to your GitHub repo for your fork at https://github.com/youruserid/Xastir.git. * Using the pull-down menu, select your feature branch name. * To the right, you'll see a button marked "Pull request." Click it to begin the process of creating an automated request to pull your code into the main repo. Fill out all of the form and create a pull request. If your pull request is still a work in progress, add the text "WIP:" in the title, and after you create the pull request click the "Convert to draft" link. This tells the development team that the work isn't done and is not ready to merge, but they can still review what's done already and make suggestions or demands for further changes. * A member of the Xastir project will review your changes and comment on the pull request. If the changes are straightforward, your request may be accepted directly, or you may be requested to make further changes. * If you need to add more commits to address concerns brought up in the review of your pull request, just make them on your topic branch and push them again: ``` git checkout git add git commit git push ``` Since you have already associated your topic branch with your forked remote in a previous step, it is no longer necessary to say "-u origin branchname" here. * If this goes on for very long, it could come to pass that master has changed again. If so, you may need to rebase and force-push your topic branch. Ideally, you should endeavor to make your pull requests as easy to test and review as possible, so that it doesn't take forever for developers to get around to testing them and merging them. * If you created a Work In Progress/draft pull request, when all of your work is done return to your pull request page and click "Ready for review" button and remove the "WIP:" from the pull request's name. This tells the development team that you think it's safe to merge your changes. There are lots of guidelines out there about how to make good pull requests. Please read https://github.com/blog/1943-how-to-write-the-perfect-pull-request for one such article. ## Git Commit Message Format Git commit messages need to be in a certain format to make the best use of the "git log" commands. In particular the first line needs to be 50 chars or less, then a BLANK LINE, then a detailed commit message. See this link for more info: http://chris.beams.io/posts/git-commit/ ## Checking out other people's work It was mentioned above that sometimes it is a good practice to ask other people to check out your code changes before a pull request is opened. This section contains some simple ways for Xastir users and developers to check out code in other people's repos with a minimum of fuss. Say user "sumgai" has a topic branch named "sumnufeetyur" in a fork of Xastir at "https://github.com/sumgai/Xastir.git". You want to pull those changes and test them out. This can always be done just by cloning the entire fork, but that is not necessary, since most of the fork is a straight copy of the official repo. You can instead just grab sumgai's changes: * I'm assuming you're already checked out from the master branch, but let's make sure: git checkout master * In your regular Xastir clone directory, create a new branch to hold sumgai's work, and switch to it: git checkout -b sumgai-sumnufeetyur When you do this, all you've done so far is to create a new name for a copy of master. * Now pull sumgai's branch into yours: git pull https://github.com/sumgai/Xastir.git sumnufeetuyr Your sumgai-sumnufeetyur branch will now match sumgai's sumnufeetur branch exactly. This does generally work best if sumgai has kept his branch rebased off of master, which is why we recommend that approach. * You can now build the code and test it as usual. * When you're done testing sumgai's code, you can go back to the unmodified Xastir just by doing "git checkout master," and rebuilding the code. If you no longer want to keep a copy of sumgai's work around, you can delete the branch with git branch -D sumgai-sumnufeetyur **Note to developers**: The process of doing this checkout of others' branches is exactly what GitHub recommends as the first steps to resolving pull requests manually through the CLI instead of through github's web interface. ## Debugging hints Xastir is a multi-threaded and multi-process application. It uses both threads and forks to do it's work. You must have a debugger that is capable of following these kinds of twists and turns in a program. Many older versions cannot. ### Old notes on using GDB with Xastir *The notes in this section were taken from an old email thread and were written by Tom Russo* According to everything I can find about GDB, debugging of multithreaded apps has been supported in gdb for some time, and are certainly supported in gdb 6.x. For the last couple days I've been running xastir inside gdb instead of at the command prompt --- perhaps I won't keep forgetting to start it with -t now, and when it crashes I'll be where I need to be. This is possibly an option for you, too, if you're seeing segfaults frequently enough and can't solve the core file question. Try this: gdb /usr/local/bin/xastir > run -t *The ">" above is a gdb prompt --- don't type it!* When it crashes, it'll pop you right out into the debugger, whether a core file was created or not. You could then view the active threads: info threads and get a stack trace of where the crash happened: where You could also probably list the code near where the crash happened: list If you send the output of those three commands to the xastir-dev list then it might help us narrow down the causes. ### Other old debugging notes *This section was also taken from an old email chain, and was written by Curt Mills* Note that the meaning of the "-t" command-line flag has been reversed *[Ed. Note: from what it was in earlier days of Xastir]*. "xastir -?" should show the change once you compile it. This means that we'll do core dumps by default upon segfault instead of using the internal Xastir segfault handler. We've also re-enabled the "-g" compile option for GCC so that debugging information will remain embedded in the executable (unless you strip it). This should aid the development team to debug problems. > Also, I cannot find anything in man bash that talks about core > dumps nor segmentation faults. Seems like some stuff we're just supposed to know. _How_ we're supposed to know I don't know either... ;-) Perhaps that last bit about SUID/SGID might be a clue: There are often exceptions to the rules for SUID/SGID programs. Try _not_ setting Xastir SUID (if you're not using AX.25 kernel networking ports that is) to see if you get a core file. Can you send a SIGSEGV to the running process and make it dump? I just tried this and I'm not getting a core file either. Ah, I see in the "man bash" page: ulimit -a All current limits are reported This gives me: core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited max locked memory (kbytes, -l) 32 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) unlimited cpu time (seconds, -t) unlimited max user processes (-u) 6139 virtual memory (kbytes, -v) unlimited So... Looks like I need to set "ulimit -c" and try again: ulimit -c unlimited Now when I do "kill -11 " I get this: [1]+ Segmentation fault (core dumped) xastir and this: -rw------- 1 archer users 12320768 2006-02-02 09:31 core.7586 I just added "ulimit -c unlimited" to my .profile. For what it's worth, if Xastir has SUID permission bit set (4755) I don't get a core dump, but if it is reset I do (0755). I can invoke ddd like this (it uses gdb under the hood): ddd /usr/local/bin/xastir core.7586 & or gdb like this: gdb -c core.7586 /usr/local/bin/xastir Once you have the program and core file loaded into the debugger you can display a backtrace to see where the program died. In the case of ddd, it's Status->Backtrace, then you click on one of the entries to make the source code window display the exact location. Another good debugger to try is "UPS". Another note about core files: Sometimes they get written where you don't expect. I just had one appear in ~/.xastir/tmp, so if you think you should have a core file and can't find it, try: find . -type f | grep core The core file may be written to a directory that Xastir is currently in, instead of where you started Xastir from. ### Customized debugging builds Sometimes it is helpful to build xastir with specialized compiler options to aid in debugging. For example, if you're trying to hunt down elusive segfaults, and you're using GCC, it might be wise to build with "-O -g -fno-inline" to prevent the compiler from optimizing quite so vigorously; aggressive optimization can sometimes lead to the debugger saying the code died on one line when in fact it's happening somewhere else. To build with custom CFLAGS like this, just tell configure what you want CFLAGS to be: mkdir -p build cd build ../configure CFLAGS="-O -g -fno-inline" Naturally, unless you're using build directories separate from the source directory (see below under "Segregating specialized builds"), you need to build every file after changing configure like this, so do a make clean before building: make clean make make install Remember not to "make install-strip" when trying to do debugging builds, or your core files will not have debugging symbols in them and it will be harder to get useful information out of the debugger. ### Segregating specialized builds The automake/autoconf setup of xastir makes it easy to maintain several different builds of the code without having to clean out the directory and rebuild every time. One does this with "build directories" and executable suffixes. To use this capability, make sure you're starting with a completely clean source directory. In the directory where you normally do your "git pull", do a make distclean. This will remove anything that configure created as well as anything that make created. From this point forward, you don't build xastir in the source code directory anymore. Make an empty directory somewhere --- this will be your build directory. I put my build directories in parallel with the source code directory. So my tree looks like this: XASTIR-DEV | +----/Xastir (source directory) | +---/build-normal | +---/build-debug and so on. Some developers put their build directories inside the Xastir tree instead. It doesn't matter, but does change how you invoke configure (you have to use the correct relative path to configure below). So I would do: cd XASTIR-DEV mkdir -p build-normal In the build directory, you run configure using the path to the configure script: cd build-normal ../Xastir/configure make make install The configure script uses the path that you gave when you ran it to figure out where to find the source code. The beauty of this is you can make a second build without doing a make clean: cd XASTIR-DEV mkdir -p build-debug cd build-debug ../Xastir/configure --program-suffix="-debug" CFLAGS="-O -g -fno-inline" make && sudo make install This will build a second binary called "xastir-debug" and install it, but because you've done the build in a separate directory, your normal compile is untouched. cd ~/XASTIR-DEV/xastir git pull cd ../build-normal make && sudo make install cd ../build-debug make && sudo make install will update both of your builds. I also use this technique to share a single xastir source tree over NFS, building the code for multiple operating systems in separate build directories. (log in to CYGWIN machine, mount NFS directory) cd /mounted/directory/XASTIR-DEV mkdir -p build-cygnus ../Xastir/configure make && make install It can also be used to maintain specialized configurations, for example a build with "rtree" disabled, a build with map caching disabled, etc. This is a good development trick to keep yourself honest --- make sure you can still build all your custom builds when you've done a large hacking run, and want to check if you have broken things inside ifdefs. Doing that without build directories requires a huge number of configure/make/make distclean cycles. ## More? Anything else? Let's hear about what's still confusing or needs to be expanded in this document. Thanks! APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/COPYING0000664000175000017500000004312715151324131014363 0ustar hibbyhibby GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 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. Xastir-Release-2.2.4/COPYING.LIB.LESSTIF0000664000175000017500000006126115151324131016077 0ustar hibbyhibby GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 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. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, 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 library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, 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 companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU 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. Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! Xastir-Release-2.2.4/ChangeLog0000664000175000017500000345630215151324131015110 0ustar hibbyhibby2012-11-02 * ChangeLog Xastir project stopped updating the ChangeLogs in 2012, and until then the changelog was generated manually from CVS history. The project no longer uses CVS, and now relies on git history to show the history of the project. Please see the output of "git log" if you want to know what has happened to the code and why, and add the "--name-status" option if you want to know what files were changed. 2012-11-01 11:57 we7u * .cvsignore, AUTHORS, ChangeLog, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.CYGWIN, README.Contributing, README.OSM_maps, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, callpass.1, changes.txt, configure.ac, install-xastir, testdbfawk.1, update-xastir, xastir.1, xastir_udp_client.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/OSM_Cloudmade_administrative.dbfawk, config/OSM_Cloudmade_highway.dbfawk, config/OSM_Cloudmade_natural.dbfawk, config/OSM_Cloudmade_poi.dbfawk, config/OSM_Cloudmade_water_and_coastline.dbfawk, config/arealm.dbfawk, config/areawater.dbfawk, config/cousub.dbfawk, config/cousub00.dbfawk, config/edge.dbfawk, config/featnames.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsc_ddmmyy_09.dbfawk, config/nwsc_ddmmyy_09b.dbfawk, config/nwsc_ddmmyy_10.dbfawk, config/nwsc_ddmmyy_10a.dbfawk, config/nwshzddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzddmmyy_09.dbfawk, config/nwsmzddmmyy_11.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddap12.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsozddmmyy_09.dbfawk, config/nwsw_ddjn12.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsw_ddmmyy_09.dbfawk, config/nwsw_ddmmyy_10.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwsz_ddmmyy_09.dbfawk, config/nwsz_ddmmyy_10.dbfawk, config/nwsz_ddmmyy_10b.dbfawk, config/nwsz_ddmmyy_10c.dbfawk, config/nwszoddmmyy.dbfawk, config/pointlm.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/stored_track.dbfawk, config/tabblock.dbfawk, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tl_2009_nn_county.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.d72_d710, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.d72_d710, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/BUILDRPMS, scripts/Coordinate.pm, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/UIView2XastirLog.pl, scripts/Xastir_tigerpoly.py, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable, scripts/example_objects.log, scripts/geopdf2gtiff.pl, scripts/get-fcc-rac.pl, scripts/get-gnis, scripts/get-maptools.sh, scripts/get-pop, scripts/get_shapelib.sh, scripts/kiss-off.pl, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl, scripts/object2shp.pl, scripts/pos2shp.pl, scripts/slideshow.pl, scripts/test_coord.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/track-get.pl, scripts/waypoint-get.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.h, src/awk.h, src/bulletin_gui.h, src/color.h, src/database.h, src/datum.h, src/db_gis.h, src/dbfawk.h, src/draw_symbols.h, src/fcc_data.h, src/festival.h, src/fetch_remote.h, src/geo.h, src/gps.h, src/hashtable.h, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.h, src/igate.h, src/interface.h, src/io.h, src/lang.h, src/leak_detection.h, src/list_gui.h, src/macspeech.c, src/main.h, src/map_OSM.c, src/map_OSM.h, src/map_cache.h, src/maps.h, src/messages.h, src/objects.h, src/popup.h, src/rac_data.h, src/rotated.h, src/rpl_malloc.h, src/shp_hash.h, src/snprintf.h, src/symbols.h, src/tile_mgmnt.h, src/track_gui.h, src/util.h, src/wx.h, src/x_spider.h, src/xa_config.h, src/xastir.h, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating the Copyright notices. Bumping revision to 2.0.2 in preparation for stable release. 2012-10-22 17:37 tvrusso * src/interface.c: Tidy up a comment and remove some now-commented-out code. At this point, everything that I had hoped to be in the next stable release is in place. 2012-10-22 16:59 we7u * src/: interface.c, interface_gui.c, xa_config.c: The rest of the code to implement "TNC Delay" for the serial tnc types of interfaces. This is most useful with a KAM TNC. Note that one can hand edit the value up to 9,999,999 us in the Xastir config file, but pressing the togglebutton will enter 1,000,000 us by default. Thanks for that idea Tom! 2012-10-22 16:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.h, src/interface_gui.c, src/xa_config.c: Implementing the GUI and save/restore portions of the "Add Delay" togglebutton for the three types of Serial TNC interfaces. The back-end code which actually uses the button value hasn't been coded yet. 2012-10-11 11:25 we7u * scripts/get-fcc-rac.pl: Fixing the RAC database fetch/install. 2012-10-11 11:09 we7u * scripts/get-NWSdata: Updating for the current set of NWS filenames. 2012-10-11 10:58 tvrusso * symbols/: Makefile.am, icon.png: Add a PNG icon for Xastir, converted from the icon.xbm file in the src directory. I did this because I generally create a desktop shortcut to Xastir on my laptop, and as of the most recent version of Gnome I am unable to use an xbm to do so, but a PNG works. This new icon is installed into ${prefix}/share/xastir/symbols and may be used by the user to define a custom icon for a desktop shortcut. Remember, the Xastir project does not directly support distro-specific (or desktop-specific) packages, but we do want to make sure that those who generate such packages have the tools and files they need to do so. 2012-10-10 15:18 tvrusso * help/: help-Dutch.dat, help-Portuguese.dat: The Dutch and Portuguese help files were actually not in Dutch or Portuguese, but English, and were woefully outdated. Copied the current English helpfile into those two, so at least the only thing that's wrong with them would be that they're not in the language they're supposed to be. 2012-10-10 15:16 tvrusso * ChangeLog, help/help-English.dat: Regenerate ChangeLog from CVS logs. Add a "what's new in Xastir 2.0.1" section to the on-line help. Looking over our non-English helpfiles, it is clear that it has been a very long time since anyone has translated the help into other languages. The German help file hasn't been updated since Xastir 1.2, Spanish hasn't been updated since 1.1, and several languages have help files, but they're still in English. 2012-10-10 14:46 tvrusso * scripts/cvs2cl.pl: Add cvs2cl script (from http://www.red-bean.com/cvs2cl/cvs2cl.pl) to our tools. This generates a ChangeLog from cvs commit logs. 2012-10-07 10:41 tvrusso * configure.ac: Move probe for proj to before probe for shapelib. When using internal shapelib, the probe checks whether "use_proj" is "yes", but until this commit, use_proj was unset until *AFTER* the shapelib probe. This led to warnings from the shell about unary "=" in a test (if test $use_proj = "yes") 2012-10-05 13:19 we7u * scripts/get-NWSdata: Updating a file or two, and changing the order of FILE1 and FILE2 in the definitions to match the order they are on the NWS web pages. We will need to check this file again on/after Oct 11 as several of the filenames change then. 2012-10-05 12:56 we7u * scripts/get-fcc-rac.pl: Changing the RAC address to one that currently works. The old site looks to have a brand spanking new version of Drupal on it, so they may have messed up the rest of the machine temporarily (or permanently). 2012-09-26 21:15 tvrusso * acinclude.m4, configure.ac: Remove some unnecessary macros from the probes for Berkeley DB. The code in acinclude.m4 to probe for Berkeley DB was copied from another project, and included a macro that tried to guess how to add a "runpath" to the build. On most systems this is either -Rlibrarydirectory or -Wl,rpath,librarydirectory, but the macro in our acinclude.m4 was in fact correctly identifying the way to do it ONLY on Linux, and then discarding the information anyway. Thus, this was a no-op on Linux, and was wrong elsewhere (but also a no-op). The technique used to do the probe also broke when the compiler was clang, but again, to no effect because the result was discarded anyway. SO since the result wasn't used, why probe it? I have removed the macros and replaced the use of "XASTIR_ADD_LIBRARY_TO" with a simple shell variable assignment. While I was at it, I removed the deprecated two-argument call to AM_INIT_AUTOMAKE. It has started causing newer versions of automake to complain, and has been deprecated for some time. 2012-09-23 09:19 tvrusso * src/: db.c, fcc_data.c, igate.c, interface.c, location_gui.c, main.c, map_OSM.c, map_WMS.c, map_cache.c, map_geo.c, map_shp.c, map_tiger.c, maps.c, messages.c, messages_gui.c, objects.c, rac_data.c, track_gui.c, util.c, xa_config.c, xa_config.h: Big commit for a little, insidious threading problem. xa_config.c provides a function called get_user_base_dir(char*) that returns a pointer to a string that is the concatenation of the base configuration directory for Xastir (usually ~/.xastir, but selectable by the user with a command line option or environment variable) and the argument. This function was highly thread-unsafe --- it kept a local static char array that it used to build the concatenated string, then returned a pointer to the local array. This function was used in multiple threads, meaning that one thread could start scribbling into the static array while another was writing into it. I first tried to fix this by adding a mutex that locked the writes for all but one thread at a time, but that wasn't even good enough, because after unlocking the write mutex another thread could write into the buffer while the first thread was reading the results just produced. The result of this mess was a highly unpredictable tendency for Xastir to start producing corrupted paths from this function. This would show up most often on multi-core machines with threading libraries that let threads run simultaneously on different cores, but it could show up on single-core machines with just the right scheduler. It is revealed most easily by enabling multiple logging options (e.g. TNC logging, NET logging, WX logging) and PNG snapshots all at once. In testing, I found this sufficient to produce corrupted file paths in an hour or so. I'm somewhat surprised that nobody has ever reported this issue, because I've been seeing it for ages. This commit replaces the original get_user_base_dir implementation with one that requires the caller to provide its own buffer, and completely removes the use of the static buffer. More than 200 calls to get_user_base_dir had to be modified, but some simplifcation was also possible --- I was able to replace a few usages like this: xastir_snprintf(dest_string, sizeof(dest_string), "%s", get_user_base_dir("tmp")); with: get_user_base_dir("tmp", dest_string, sizeof(dest_string)); get_user_base_dir still returns the pointer to the destination string, so it can still be used as an argument to log_data or xastir_snprintf where necessary. I also replaced several wasteful uses of the function. There were places where get_user_base_dir was being called repeatedly with the same argument many times in a single function. I replaced this usage in many cases with a single call to store the answer in a local buffer, and use that repeatedly. Since implementing this change I have seen Xastir run without producing a single corrupted path, even with TNC, NET, and WX logging and PNG snapshots turned on. 2012-09-21 18:32 tvrusso * configure.ac, src/main.c: Ifdef out the hack added to main.c to deal with the broken Xorg-server 1.7.5. This server version had a bug that interfered with all motif programs, causing them to grab the cursor and never release it when a context (pop-up) menu was created. The bug was promptly fixed, but not before several distros locked in version 1.7.5 as their supported version. The workaround ungrabs the cursor, but has the annoying side-effect of making the user hold down the button that brings up the menu, rather than allowing a quick click to access it. This commit puts the hack into an ifdef, and enables the user to select the workaround by adding "--with-xorg_175_workaround" to the configure line. The default behavior is now to NOT use the workaround. The workaround and configure.ac code to enable it should be removed completely in one release cycle. Xorg-server 1.7.5 is long gone, and keeping this code around is a nod to the fact that some people do not upgrade for years. One more release cycle should be enough to forget this mistake ever happened. 2012-09-20 22:11 tvrusso * src/map_OSM.c: Patch from Tom Hayward (KD7LXL): This patch fixes an issue in the OSM tile download loop. If a tile is 404, 403, or any other error that doesn't return a valid image, imagemagick (or gm) puts the error info in &exception. Subsequent iterations read &exception, note the error, and fail to composite any further tiles. This patch adds GetExceptionInfo() to the end of the loop, so subsequent iterations do not start off with error info in the exception struct. 2012-09-19 07:56 tvrusso * Davis/src/db2APRS.c, LaCrosse/src/open2300db2APRS.c: Make sure to include before using umask(), to avoid compiler warning about implicit declaration. 2012-09-14 13:57 tvrusso * config/tnc-startup.kam, src/interface.c: Definitive fix for KAM TNCs. The KAM apparently does not go into converse mode if one sends "K\r" and immediately sends the stuff you want to go into the converse. It requires a tiny delay between the command to go into converse mode and the data. I have inserted a 50ms delay after sending the converse command, which should be insignificant enough that nobody will need it to be a configurable option. This fix has been confirmed to end the problems with KAM TNCs, and the 50ms delay was the smallest delay tested. Also commented out two commands in tnc-startup.kam that do not apparently exist in the KAM. 2012-09-08 15:07 tvrusso * Davis/src/db2APRS.c: Reverting my last change to the Davis Meteo->APRS glue program. This is in response to testing by Dean Groe, who is so far the only person on the xastir mailing list who has fed back any information about the behavior of the code after my last commit. Turns out that Meteo does not appear to put "Total Rain" (rain since station reset) into the database in the "raintotal" field, it appears to put "rain since midnight" there, i.e. "total rain for today." This is not what Xastir means, since it has a separate spot for "today's rain." Thus, it is pointless to be sending the extra data to Xastir, because it is a duplicate of something else we already have. I am changing only the Davis database glue program, and leaving in place the LaCrosse changes --- LaCrosse stations *do* maintain their own record of "total rain" and open2300 does put that data into the database. It's just Meteo that doesn't. 2012-08-31 16:39 tvrusso * Davis/configure.ac, Davis/src/db2APRS.c, LaCrosse/src/open2300db2APRS.c, src/wx.c: Fix for Davis and LaCrosse weather stations. Neither of the two "db2APRS" programs for these stations provided "total rain" (rain since wx station reset), and thus Xastir would show a blank in the Own Weather Data dialog box for this. Further, LaCrosse weather stations don't report rain-since-midnight, and by not having total rain available, Xastir isn't able to compute the missing datum. This commit does three things: adds total rain to the string that db2APRS and open2300db2APRS send adds code to Xastir to parse the new bit of data adds code to Xastir to compute rain-since-midnight if total rain is available AND rain-since-midnight is not sent from the wx station. WARNING: THE CODE FOR db2APRS has NOT been tested except to assure that it compiles cleanly. I have no Davis weather station to test it on. The LaCrosse code runs correctly. 2012-08-26 11:34 tvrusso * INSTALL, README.Getting-Started: Update documentation to reflect some changes in GPSMan and GPSManShp. 2012-08-26 11:28 tvrusso * src/main.c: Current versions of gpsman and gpsmanshp now require "Shapefile" and "dim=2" instead of "Shapefile_2D" For quite a long time the gpsman maintainer kept backward compatibility, but it's gone now. This commit resolves issue http://sourceforge.net/tracker/?func=detail&aid=1820056&group_id=45562&atid=443271 in the sourceforge bug tracker. 2012-08-26 11:11 tvrusso * acinclude.m4: Remove bashism from configure process, per sourceforge bug https://sourceforge.net/tracker/?func=detail&aid=3422711&group_id=45562&atid=443271 2012-08-25 09:38 tvrusso * src/: awk.c, bulletin_gui.c, color.c, datum.c, db_gis.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, fetch_remote.c, geo-client.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, main.c, map_OSM.c, map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_pop.c, map_shp.c, map_tif.c, map_tiger.c, messages.c, messages_gui.c, objects.c, popup_gui.c, rac_data.c, rotated.c, rpl_malloc.c, shp_hash.c, snprintf.c, sound.c, testdbfawk.c, tile_mgmnt.c, track_gui.c, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, xa_config.c, xastir_udp_client.c: update neglected copyright dates. Notably, update the one that shows up in the Help->About dialog. 2012-08-22 18:05 tvrusso * help/help-English.dat: Update help file to reflect recent change to "Serial TNC with GPS on AUX port" interface type, documenting the 'Send Control-E to get GPS data?' checkbox. I can only update this in English. Translations requested for our other supported languages. 2012-08-22 17:41 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface_gui.c, src/main.c: Remove a horrid work-around of some bad behavior of Xastir with Kenwood D7* radios with attached GPS. Back in 2006, several Xastir users noticed that when Xastir was attached to a Kenwood D700 (and other Kenwood APRS radios) using the "TNC with GPS on AUX port" interface type, every time Xastir tried to transmit the TNC would reply with an "Eh?" error when sent the MYCALL line that precedes a posit. We realized that there must be some kind of junk in the TNC buffer that was causing the MYCALL line to not be recognized. In some cases, this had bad consequences, especially if no previous MYCALL had succeeded --- the result would be that the TNC would transmit using the default MYCALL, "NOCALL". Since we couldn't for the life of us figure out what the junk in the buffer was, we kludged: Before sending MYCALL, Xastir would send a carriage return, letting the "eh?" error happen where it had no consequence. This was a horrid kludge, as it just swept the real problem under the rug. The real issue is that "Serial TNC with GPS on AUX port" was written to support devices like the Kantronics KPC-3+, which requires that Xastir send a Control-E to the TNC in order to poll it for GPS data. This is how the KPC-3+ multiplexes the output serial port --- normally it sends packet data to the serial port, but immediately after receiving a Control-E from the connected computer, it sends one NMEA string from the GPS instead. The Kenwwood radios stream the GPS data and packet data together all the time, and not only do not require a Control-E to switch between them, they don't even read the Control-Es. The "Eh?" errors from the Kenwood TNCs were it complaining that MYCALL was preceded by all those Control-E characters that Xastir had been sending since the last transmit. This commit adds a configuration option to the Serial TNC with GPS on AUX port set-up dialog so that one can turn this control-E feature on and off as appropriate. THIS HAS USER-VISIBLE IMPACT FOR ALL KENWOOD USERS: If you are currently using Xastir with a Kenwood radio, after doing this update you MUST open your interface property dialog and de-select the 'Send Control-E to get GPS data?" check box. If you do NOT take this step, you will begin seeing the old "Eh?" problem on your TNC, and may well transmit your posit as NOCALL. This may seem an annoyance, but really, this is the fix that we should have put in place six years ago. 2012-08-14 15:14 tvrusso * src/db.c: Fix two instances of a logical AND being used where a bit-wise AND was intended. In this case, the test was supposed to be checking that a station posit was not a third-party packet, but was improperly doing flag && ST_3RD_PT instead of flag & ST_3RD_PT. This impacts ONLY speech-enabled band opening alerts. It is unlikely that anyone was even using these. I found this error only because clang spits out warnings about it. The specific warning is that one is attempting to do a logical AND with a constant value (which is more likely an error than intentional). 2012-08-13 10:22 tvrusso * src/: database.h, wx.c: EXPERIMENTAL COMMIT FOR TESTING PURPOSES. This commit modifies the weather station code so taht stations which provide 1-hour, 24-hour, and since-midnight rain rates (e.g. Davis through Meteo and db2APRS, LaCrosse, and Davis APRS Data Logger) do not have those station- provided data overwritten by Xastir when it tries to recalculate these quantities from "total rain" (i.e. total rainfall since the weather station was reset). The Davis Meteo/LaCrosse code does not even provide "total rainfall" information (though the database they access does in fact have this information), and the APRS Data Logger does not provide total rainfall. All three provide per-hour and 24-hour rain data, and the Data Logger provides rain-since -midnight. What this code does is add a flag to the WeatherRow structure that is set to 1 by stations that provide total rain, and to zero by stations that provide the rate data instead. In "cycle_weather", the three rate strings are only overwritten if the flag is 1, and are left as the station set them if the flag is 0. This should address issues of transmitted rain rates being completely incorrect for Davis and LaCrosse stations. Needs a lot more testing to assure that there is no impact on other stations. This code should result in no change in Xastir's behavior for any station other than Davis or LaCrosse. 2012-08-08 19:19 tvrusso * src/: main.c, xa_config.c: Patch by Tom Hayward. This commit allows the "posit interval" slider to go all the way to zero. If zero, Xastir will not emit timed beacons. It also adds a SIGUSR2 signal handler. If Xastir receives a SIGUSR2, it will beacon immediately. This commit provides all the functionality requested by David Ranch on the Xastir mailing list in this post: http://lists.xastir.org/pipermail/xastir/2012-August/020936.html 2012-07-27 12:58 tvrusso * src/: interface.c, interface.h: Remove commented-out, hard-coded choices of 'conv' and 'k' to put a TNC into "converse" mode. The Interface Properties dialog now allows a user to specify this at run time, and the presence of this commented-out code was confusing some users into thinking they still might need to edit source code to change it. 2012-07-24 17:17 tvrusso * LaCrosse/weatherdump.sql: Modify mysql database for LaCrosse to support more digits of precision for wind direction and other data that can exceed 99.9. "decimal(3,1)" means 3 digits with one past the decimal, i.e. +/-99.9. It was being used for fields that could take values well outside this range. I know that in at least one prior incarnation, this usage accepted 3 digits to the left of the decimal, but now it doesn't. My weather station has been misreporting wind direction ever since I did a major overhaul that required re-loading the mysql data from a dump. 2012-07-10 14:02 we7u * Makefile.am: Tweaking the URL for the cycle map for OSM (shows contours). 2012-07-05 11:53 tvrusso * src/: igate.c, messages.c: Silence some warnings that showed up when building with CLang instead of GCC. One (in igate.c) is just a misuse of "debug_level && 1024" instead of "debug_level & 1024), and the changes in messages.c are all about use of things like: found =- 1; which it warns as a potential mistake, since it is common to intend this to be: found -= 1; Making it found = -1; clarifies the intent for the compiler and stops it from warning. 2012-05-31 11:49 tvrusso * src/wx.c: Fix incorrect test of sscanf return value. When I changed the scanf to ignore the PXXX field, I forgot to decrease the value. 2012-05-31 11:41 tvrusso * src/wx.c: Add a string to the APRS DataLogger debug output. 2012-05-26 19:57 tvrusso * src/wx.c: Fix what seems to be a serious error in the Davis APRS DataLogger code. When I first wrote this section I decoded pXXX into "wx_prec_24" and PXXX into "wx_prec_00" since pXXX means "rain in last 24 hours" and PXXX means "rain since midnight." But Xastir actually computes those things itself, and the DAVISMETEO code puts pXXX into "wx_rain_total" instead. AA9VI has been having Issues with his DataLogger, in that Xastir is zeroing out the rainfall improperly. Turns out that's because I'm never setting wx_rain_total, and Xastir needs that. So I'm removing "rp-" and "rP-" from the debug output, no longer saving PXXX into wx_prec_00 (it's discarded now), and am now saving pXXX into wx_rain_total so that Xastir can handle it properly. This should fix Mike's problem. 2012-05-15 08:29 tvrusso * src/map_tif.c: Replace include of "projects.h" with "proj_api.h" and remove use of what is now considered an internal structure (struct PJ). Replace that usage with a pointer to such a structure (projPJ, which is a typedef to a pointer to a PJ). Proj.4 has removed "projects.h" from the installation of that library, because much that's in it is considered private implementation details that should not have been exposed. That many packages use those internals directly is considered a problem in those other packages, and a bug request in proj.4's bug tracker to reinstate projects.h as an installed file was closed with the status "wontfix". Codes that use the public API of proj.4 are supposed to include "proj_api.h" and use the API calls, not direct access to internal data structures or functions that are not intended for use outside the library. 2012-05-14 13:38 tvrusso * config/Makefile.am, config/nwsozddap12.dbfawk, config/nwsw_ddjn12.dbfawk, scripts/get-NWSdata, src/testdbfawk.c: Update get-NWSdata to fetch the very latest NWS data. Some of the files it was trying to get are non longer available. Before committing, I assured that *ALL* files that get-NWSdata downloads have corresponding matching dbfawk files. Two of the files (oz and w) have had their dbf signatures change, so needed new dbfawk files. Updated Makefiles to install these new files (which I've named according to a new convention, instead of _ddmmyy_year, I'm using mmyy that matches the dbf file to which it corresponds). Fix a spelling error in testdbfawk ("mathing" instead of "matching"). 2012-05-10 18:55 tvrusso * src/: db.c, maps.c: Comment out fprintfs to stderr that were introduced by last commit. They are spewing info to stderr of an exact sort that other types of weather alerts have commented out. 2012-05-08 11:04 tvrusso * src/wx.c: Fix debug output for Davis APRS DataLogger so that it actually prints the decoded values for 24-hour and since-midnight precipitation. 2012-05-06 09:09 tvrusso * configure.ac: make a single change of if [ "$var" = "yes" ] to if test "$var" = "yes" because I found that a Fedora 15 install was complaining about the former. 2012-03-05 10:49 we7u * symbols/: tornado.xbm, winter_wx.xbm, wntr_strm.xbm: Removing no longer used weather alert files. We renamed them slightly to match the alert_tag text in the NWS weather alerts. 2012-03-05 10:47 we7u * symbols/Makefile.am, symbols/torndo.xbm, symbols/winter_storm.xbm, symbols/winter_weather.xbm, src/map_shp.c, src/util.c, src/util.h: A rewrite of a patch supplied by Arnaud, F4EIR, which simplifies how we do alert->tag processing. We now grab the alert tag, change it to lower-case, then find a matching file on the filesystem. If not found, we grab one called "alert.xbm" as a default. This change will allow adding more files over time for more types (or Country's) alerts. Arnaud has plans to add support for France's weather alerts. 2012-03-02 12:28 we7u * README.Getting-Started, README.MAPS: Updating the copyright year for these two files. 2012-03-02 12:26 we7u * config/Makefile.am, config/gfe_coastal_waters.dbfawk, config/gfe_coastal_waters_warnings.dbfawk, config/gfe_fire_weather.dbfawk, config/gfe_metro_areas.dbfawk, config/gfe_public_weather.dbfawk, scripts/Makefile.am, scripts/get-BOMdata, src/alert.c, src/db.c, src/maps.c, src/util.c: Tweaks to allow using Australian Bureau of Metrology weather alerts in Xastir. This allows lighting up zones in a similar manner to the NWS weather alerts. Thanks to Geoff Gatward, VK2XJG/VK8GG, for this work! 2012-03-02 12:10 we7u * config/nwsmzddmmyy_11.dbfawk, config/nwsz_ddmmyy_11.dbfawk, scripts/get-NWSdata: Updates to the NWS fetch script and dbfawk files by Geoff Gatward, VK2XJG/VK8GG. Thanks! 2012-03-01 10:11 we7u * FAQ: Adding 4.34 question/answer from the web-based FAQ, and 4.35 from a question answered by Tom Russo on the mailing list (added with permission). 2012-02-04 16:10 tvrusso * README.Getting-Started, README.MAPS, scripts/Makefile.am: Change scripts Makefile.am to remove misuse of "pkglib_SCRIPTS" as this usage was one that was not intended to be correct, but was silently accepted by older versions of automake. Now automake enforces certain rules about what directory prefixes may be used with what "primaries" (such as _SCRIPTS and _DATA), and "pkglib" is forbidden as a prefix to "_SCRIPTS." This change also changes where scripts are installed. They used to get installed to /usr/local/lib/xastir, now they go to /usr/local/share/xastir/scripts. Documentation has been updated to fix references to the old directory. 2011-10-20 19:08 tvrusso * README.MAPS: Testing CVSROOT/loginfo change. 2011-10-20 18:45 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added a new box in the TNC properties dialog for setting the CONVERSE mode command. If blank it will get set to "k" which most TNC's accept. Can be set to "conv" for TNC's like the KPC-2 on an individual port basis. 2011-09-08 12:47 tvrusso * config/: Makefile.am, nwsz_ddmmyy_11.dbfawk: Add a new dbfawk file for the newest NWS Zone file, which once again has different dbf signature than all previous versions. 2011-09-05 13:24 tvrusso * scripts/geopdf2gtiff.pl: Remove creation options for PACKBITS compression, until I figure out why that's creating tiffs Xastir can't read. 2011-09-05 12:58 tvrusso * scripts/geopdf2gtiff.pl: Add a "fix neatline" option for GeoPDFs with bad neatlines, such as the most recent US Topo editions, which have neatlines that include all the collar. This hack works when the user specifies --fixneatline or -f, and rounds the left, right, top, and bottom of the image down to the nearest 7.5' quad boundary, and uses those values to construct its own neatline prior to calling gdalwarp with the -cutline -crop_to_cutline options. 2011-09-05 10:54 tvrusso * scripts/geopdf2gtiff.pl: Add compress=packbits to geotiff creation options for minor disk space savings. 2011-09-05 10:29 tvrusso * scripts/: Makefile.am, geopdf2gtiff.pl: Added script to convert GeoPDF files to usable GeoTIFF files. This involves extracting the neatline from the GeoPDF, then doing a gdalwarp to strip the collar and warp to EPSG:4326 coordinate system (WGS84 equidistant cylindrical projection), and finally to dither to 8 bit if there is more than one band present. I have found that some GeoPDF files lie about their neatlines, saying the neatline encloses the whole raster including the collar. There is nothing to be done about this except to hand-craft an FGD file for such GeoPDFs. With an FGD file, Xastir will collar-strip itself. This seems only to be a problem with some of the fancier new-style GeoPDF files, the "Digital Maps, Beta." 2011-07-06 00:45 we7u * config/: Makefile.am, tnc-startup.d72_d710, tnc-stop.d72_d710: New start/stop files for Kenwood D72 and D710, contributed by Kai Günter, LA3QMA. Thanks! 2011-05-31 08:37 gstueve * config/Makefile.am, config/nwsc_ddmmyy_10a.dbfawk, config/nwsmzddmmyy_11.dbfawk, config/nwsw_ddmmyy_10.dbfawk, config/nwsz_ddmmyy_10c.dbfawk, scripts/get-NWSdata: Make sure we have good mapping files for current NWS data files. Also get current set of files from NWS. 2011-03-26 20:07 jedunmire * src/map_OSM.c: - fix for downloading tile '5 of 4' bug - the bug and the fix are cosmetic and should not impact any other operations. 2011-02-25 22:06 we7u * config/: Makefile.am, nwsc_ddmmyy_10.dbfawk, nwshzddmmyy.dbfawk, nwsz_ddmmyy_10b.dbfawk: Updating dbfawk files to match current set of NWS Shapefiles. 2011-02-25 15:06 we7u * scripts/get-NWSdata: Updating to the most recent valid NWS files for alerts. We'll need to update our dbfawk files to match these. 2011-01-23 17:29 we7u * scripts/get-NWSdata: Updating to latest NWS Shapefiles. 2011-01-03 17:30 we7u * README: Added the OpenSuSE-11.3 repository to the notes plus a command-line option to configure which picks up another needed library location. 2010-12-31 04:58 we7u * help/help-English.dat: Revising the tactical callsign text a bit. 2010-12-31 04:41 we7u * FAQ: Changed the "Can I run multiple Xastir's at once" answer to incorporate use of the new(er) "-c" command-line flag. 2010-12-31 04:17 we7u * help/help-English.dat: Added info about publishing tactical callsigns across the air and later revoking those assignments via APRS messaging. 2010-12-20 15:43 jedunmire * src/map_OSM.c: - Re-organized a few lines in map_OSM.c so that it not produce an error message when *Magick libraries are not used. 2010-12-04 17:37 tvrusso * configure.ac, src/shapelib/contrib/Makefile.am: Fix configure/make so that it works properly when internal shapelib is being built on a system without libproj. 2010-11-08 17:48 tvrusso * Makefile.am: Fix for bug reported by Jeremy Utley, in which using DESTDIR at install time was depositing some CC_*.png files in a directory that ignored DESTDIR. 2010-10-25 20:25 we7u * configure.ac: Bumping CVS up to v2.0.1 for further development. 2010-10-25 20:02 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Setting up for the v2.0.0 stable release. 2010-10-24 10:01 we7u * config/language-French.sys: Updates by Arnaud, F4EIR. Thanks! 2010-10-24 09:59 we7u * config/language-German.sys: Updates by Rolf, DK7IN. Thanks! 2010-10-05 07:14 chicoreus * scripts/db_gis_mysql.sql: Fixing script to generate database and tables for MySQL based persistence. Previous versions include invalid syntax. Changes herein largely follow patch by Dan Zubey N7NMD. This script has now been tested both with grant statments commented out and with grants included. 2010-09-30 08:35 gstueve * scripts/get-NWSdata: Update files for current boundaries. 2010-09-28 20:55 jedunmire * src/map_geo.c: - eliminate the warning about a missing prototype for DistroyImagePixels() but enabling prototypes for 'private' functions in GraphicsMagick. 2010-09-23 19:24 jedunmire * src/map_OSM.c: - changes to transparency code for OSM tiled maps. This fixes the problem with 16-bit *Magick quantums. 2010-09-21 07:46 we7u * src/list_gui.c: A patch by Jason Godfrey, N0RPM, which fixes the segfault on list close problem. We were calling XtDestroyWidget() on child widgets, but calling it on the parent is sufficient. We just have to make sure there aren't any references to those child widgets first. 2010-09-08 11:13 jedunmire * Makefile.am, src/Makefile.am, src/tile_mgmnt.c, src/tile_test.c: - Removed obsolete tile experiment application (tile_test) - Stopped using http 'newer than' requests for OSM tiles. The 'newer than' test was ignored by all observed OSM servers and caused corrupted downloads and long delays for the topOSM tiles. - Changed the names of the TopOSM files so that they layer automatically. 2010-08-17 10:26 gstueve * src/main.c: Add setlocale() back in place to calm Warnings about charset mismatch. 2010-08-14 16:21 we7u * src/wx.c: Fixes for One-Wire-Daemon ARNE protocol mode to allow the use of the current string output: 12 parameters instead of 19. We allow use of either format now. 2010-08-14 14:32 jedunmire * Makefile.am, OSM_template, README.OSM_maps, src/map_OSM.c, src/map_OSM.h, src/map_geo.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c: - fix for '1 of 0' tile download message - fixed a memory leak in map_OSM.c - fixed installation of OSM CC icons - added support for .jpg tiles - implemented transparency for tiles. No more red blocks for missing tiles, tiles can be stacked, and lower levels show through for missing tiles. - zoom level limits for OSM maps - New map definitions for topOSM 2010-08-13 14:53 we7u * src/map_shp.c: A fix for segfaults caused by some Shapefile maps. Kyle and Nathan Mills were my consultants for fixing this bug, though the final bug-fix was mine. 2010-08-10 02:11 we7u * src/xa_config.c: Faster processing of the config file. We now call fseek to reset to the beginning of the file only if we don't find a particular option the first time through. We were calling it before every search, plus were reading in another line in the loop before we checked whether we had found the current option (making us go one too far each time). 2010-08-10 01:39 we7u * .cvsignore, src/.cvsignore: Adding a few files to .cvsignore to keep the cvs status clean. 2010-08-10 01:22 we7u * src/: alert.c, db.c, interface.c, interface.h, util.c, util.h, x_spider.c, xa_config.c: More work to help assure that config file reading/writing is consistent no matter the locale. Replacing more dangerous string functions with safer functions. Combined split_string_char and split_string into one function. Added get_float() and store_float() function to simplify code. 2010-08-10 01:07 we7u * src/main.c: Adding more setlocale() calls before we read in the config data. 2010-08-04 04:12 we7u * config/: OSM_Cloudmade_administrative.dbfawk, Makefile.am, OSM_Cloudmade_highway.dbfawk, OSM_Cloudmade_natural.dbfawk, OSM_Cloudmade_poi.dbfawk, OSM_Cloudmade_water_and_coastline.dbfawk: Adding dbfawk files for the Open Street Maps "Cloudmade" Shapefile extracts. 2010-08-01 22:12 we7u * configure.ac: Mark GeoTiff support as a "no" if we can't find the geotiff include files. 2010-08-01 21:06 we7u * configure.ac: Removing the extra -I for finding libgeotiff. It appears to be distribution-specific, depending on where they decide to stuff the include files. libgeotiff itself when installed from sources goes into /usr/include and Xastir finds it readily. 2010-08-01 15:25 we7u * configure.ac: Updating path to libgeotiff include files. 2010-07-30 20:12 jedunmire * README.OSM_maps, src/fetch_remote.c, src/fetch_remote.h, src/map_OSM.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c: - cached OSM tiles are not checked for updates after 7 days - tile downloads will use http pipelining if supported by the server - new debug level, 8192 for verbose curl output 2010-07-30 11:18 we7u * Makefile.am: Fixing a minor hitch the install-exec-hook. 2010-07-29 14:57 jedunmire * src/map_OSM.c: - fixed compile error when map-cache is disabled 2010-07-27 09:48 we7u * src/fetch_remote.c: Adding a prototype needed on some systems. 2010-07-27 01:40 we7u * CC_OpenStreetMap_logo.png, CC_OpenStreetMap_txt.png, ChangeLog, Makefile.am, OSM_template, README.OSM_maps, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/Makefile.am, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_WMS.c, src/fetch_remote.c, src/fetch_remote.h, src/map_geo.c, src/map_tiger.c, src/maps.c, src/tile_mgmnt.c, src/tile_mgmnt.h, src/tile_test.c, src/track_gui.c, src/util.c, src/util.h: Open Street Maps tiling patches by Jerry Dunmire, KA6HLD. Way to go Jerry! 2010-07-21 04:52 we7u * .cvsignore, src/shapelib/contrib/.cvsignore: Updating .cvsignore files to current build configuration. 2010-07-12 23:12 we7u * src/shapelib/contrib/: my_nan.h, shpgeo.c: Attempting to fix the "endian-ness" tests. 2010-07-12 11:22 we7u * src/shapelib/contrib/my_nan.h: Fixing up BYTE_ORDER so that internal Shapelib compiles on more machines. 2010-07-11 16:39 we7u * src/: main.c, objects.h: Getting rid of the final two compiler warnings, again by switch to the use of intptr_t instead of int. Other systems may have more warnings, but this OpenSuSE-11.2 64-bit system compiles Xastir cleanly now. 2010-07-11 16:31 we7u * src/: draw_symbols.c, interface.c, map_shp.c, messages_gui.c, objects.c, shp_hash.c, testdbfawk.c: Getting rid of more compiler warnings, mostly by casting to/from intptr_t. 2010-07-11 14:41 we7u * src/rtree/: index.c, index.h, rect.c: Fixed some long-standing compiler warnings in the rtree code. Seems to still work properly. 2010-07-11 13:30 we7u * src/shapelib/: dbfdump.c, shputils.c, contrib/dbfcat.c, contrib/shpdxf.c, contrib/shpgeo.c, contrib/shpproj.c: More minor tweaks to get rid of compiler warnings. Of particular note are some TODO entries added to a couple of files for two enumerated values that weren't being handled in "switch" statements. There still isn't any code for those case statements, but the compiler warnings are gone. 2010-07-11 01:01 we7u * src/shapelib/shputils.c: Adding some braces for some "if" statements so that the enclosed else clause won't be ambiguous. 2010-07-11 00:57 we7u * src/shapelib/: shpdump.c, shptreedump.c, contrib/shpdxf.c: Fixing a few more compiler warnings. 2010-07-11 00:51 we7u * src/shapelib/: shptreedump.c, shputils.c, contrib/shpcentrd.c, contrib/shpdata.c, contrib/shpdxf.c, contrib/shpfix.c, contrib/shpinfo.c, contrib/shpproj.c, contrib/shpwkb.c: Fixing more compiler warnings. There are a few left yet. 2010-07-11 00:24 we7u * src/shapelib/: dbfdump.c, shprewind.c, shputils.c, contrib/dbfcat.c, contrib/dbfinfo.c, contrib/shpcentrd.c, contrib/shpdata.c, contrib/shpdxf.c, contrib/shpgeo.c, contrib/shpinfo.c, contrib/shpproj.c, contrib/shpwkb.c: Fixing multiple minor warnings with Shapelib. Still plenty left. 2010-07-10 23:31 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Changing the shapelib and shapelib/contrib Makefile.am files so that the binaries don't get installed during "make install" 2010-07-10 23:22 we7u * src/shapelib/: Makefile.am, shputils.c, contrib/Makefile.am: Setting up the rest of shapelib and shapelib/contrib so that everything compiles. Had to add an include to shputils.c and add a "1" parameter to exit() in one spot. 2010-07-10 22:52 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Now building libshape.a in both the shapelib and the shapelib/contrib directories so that we can build executables in both places successfully. 2010-07-10 22:39 we7u * src/shapelib/: Makefile.am, contrib/Makefile.am: Adding more binaries into the build. The ones in "contrib" still depend on "libshape.a" in the "shapelib" dir and we still need to figure out how to build that library first. 2010-07-10 13:53 tvrusso * src/shapelib/: Makefile.am, contrib/Makefile.am: Modifications to internal shapelib support so that dbfinfo (from the contrib directory) builds when internal shapelib builds. Until now, none of the "contrib" programs were built. 2010-07-06 23:16 we7u * src/main.c: Patch by Jerry Dunmire to prevent use of F4 key (Open Street Map optimum zoom) when Disable Fast Zoom is activated on the Map menu. 2010-07-03 15:09 we7u * scripts/: coord-convert.pl, inf2geo.pl, mapfgd.pl, overlay.pl, ozi2geo.pl, permutations.pl, ridge_radar.pl: Removing the Copyright noticed from scripts that were released to the public domain. They are mutually exclusive. 2010-07-02 00:17 we7u * config/tl_2009_aiannh.dbfawk: I screwed up the credit on that last commit. Those dbfawk files come to us courtesy of Peter Gamache, KC0TFB. Sorry about that! 2010-07-02 00:12 we7u * config/: Makefile.am, tl_2009_aiannh.dbfawk, tl_2009_aits.dbfawk, tl_2009_arealm.dbfawk, tl_2009_areawater.dbfawk, tl_2009_county.dbfawk, tl_2009_cousub.dbfawk, tl_2009_edges.dbfawk, tl_2009_mil.dbfawk, tl_2009_nn_county.dbfawk, tl_2009_pointlm.dbfawk, tl_2009_zcta5.dbfawk: Contributions by Kevin Paetzold, K1KWP. Thanks! 2010-07-02 00:08 we7u * scripts/: Makefile.am, ridge_radar.pl: Adding ridge_radar.pl, which computes a .geo file for a particular NWS abbreviation. Contribution by Jeremy McDermond (NH6Z). Thanks! 2010-06-30 16:31 we7u * src/map_OSM.c: Adding the ImageMagick ifdef's back in. Patch by Jerry Dunmire. 2010-06-29 23:41 we7u * src/: main.c, map_geo.c: F4 key multiple maps fix by Jerry Dunmire. 2010-06-29 23:25 we7u * src/: interface.c, main.c, wx.c, wx.h: A fix for Radio Shack/Huger/Oregon Scientific weather stations connected via the WX200d daemon. This fix may also help direct-connected weather stations of the above type, but since I don't have any to test with, it's unknown until someone tries. 2010-06-29 10:01 we7u * Makefile.am, tigermap.geo: First step at removing tigermap.geo: Making it invisible to the user. 2010-06-28 14:25 we7u * OSM_cloudmade_1.geo, OSM_cloudmade_2.geo, OSM_cloudmade_5.geo, OSM_cloudmade_998.geo, OSM_cloudmade_999.geo, OSM_cycle.geo, OSM_mapnik.geo, OSM_osmarender.geo, OSM_skiing.geo: Removing .geo files that are now created from a template. 2010-06-28 13:49 we7u * OSM_template: Need to commit a new file after Jerry's latest patch for things to work for everyone else! 2010-06-28 12:17 we7u * OSM_cloudmade_1.osm, OSM_cloudmade_2.osm, OSM_cloudmade_5.osm, OSM_cloudmade_998.osm, OSM_cloudmade_999.osm, OSM_cycle.osm, OSM_mapnik.osm, OSM_osmarender.osm, OSM_skiing.osm: A bit of cleanup: Getting rid of the no-longer-used *.osm files. 2010-06-28 12:14 we7u * Makefile.am, OSM_cloudmade_1.geo, OSM_cloudmade_2.geo, OSM_cloudmade_5.geo, OSM_cloudmade_998.geo, OSM_cloudmade_999.geo, OSM_cycle.geo, OSM_mapnik.geo, OSM_osmarender.geo, OSM_skiing.geo, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_geo.c, src/maps.c: Mods by Jerry Dunmmire WRT OSM. His notes: Summary of changes: - scaling corrected - requested OSM map size limited to 2000x2000 and +/-89 deg latitude - no 'binned' zoom levels - new function key (F4) to 'optimize' zoom level for OSM - .osm maps eliminated - OSM map files (.geo) built from a single template Details: scaling corrected: This required a major rewrite of the map_OSM.c code since the map_tiger.c code that it was based on did not support Mercator projection. Note that due to size limitations from the server and the use of Mercator scaling when the OSM bitmap images are rendered, some OSM maps will not fill the display window. This is particularly common when using a large display window. Selecting an optimized OSM zoom level (F4) will generally, but not always, result in bit map image that fills the window. map size limitations: The OSM map server that is used by this code limits the returned bitmap image to 2000 pixels in either direction. Also, as a side effect of the Mercator projection, latitude values must be limited to -90 < lat < 90. no binned zoom levels: Attempts to constrain the linear Xastir scaling to the binned OSM levels has been unsuccessful. The final straw was a problem with float to integer transitions that would result in looping and oscillation between levels. new function key to optimize OSM zoom levels: Since bitmap images do not scale well, they will always look best when the Xastir scale is closest to the OSM scale. A function key (F4) has been defined that will adjust the Xastir scale to the nearest OSM level and redraw the screen. Note that even if the scale is not changed, the F4 key will redraw the screen- this is intentional on my part. The F4 key works only if an OSM map is selected. If the F4 key is already defined for some other use on your system you can specify an alternative key by modifying the map files (OSM*.geo). The specified value must be an X11 KeySym value. Setting the value to 0 will disable the key. .osm maps eliminated Since binned scale levels are no longer supported, the .osm extension is no longer needed. .osm file will not be installed. If your maps directory (typically /usr/local/share/xastir/maps/Online/) contains .osm file from an previous install you will have to remove them by hand. You should also re-index your files (Map->Configure->Index:Reindex ALL maps) to remove them from the Map Chooser. OSM map files (.geo) built from a single template: This is primarily of interest to developers and results in a cleaner source tree. 2010-06-28 12:01 we7u * configure.ac: Commenting out the tests for libgps, which we're currently not using. 2010-06-18 22:35 we7u * src/interface.c: Skipping the hostname lookup if we pass an IP address instead of a hostname. 2010-06-18 22:11 we7u * src/interface_gui.c: Changing default GPSD port to 2947. 2010-06-18 21:57 we7u * configure.ac, src/interface.c: Changes to support pre-2.90 and post-2.90 versions of GPSD network connections. We now send the "R\r\n" command across (old method), then then send: ?WATCH={"enable":true,"nmea":true}\r\n (new method). Between the two strings either version of GPSD daemon gets kick-started into sending us NMEA strings. 2010-06-17 20:41 we7u * configure.ac: Changing one summary line (text only). 2010-06-17 20:07 we7u * configure.ac, src/interface.c: Added the configure test for libgps and the gps.h header file, necessary to continue with adding gpsd support into Xastir. More to do yet. 2010-06-17 16:24 we7u * src/util.c: Added a debugging statement, but it's commented out. Useful at times. 2010-06-15 07:29 we7u * OpenStreetMaps.osm: Part of the OSM linear patch by Jerry Dunmire. 2010-06-15 07:28 we7u * Makefile.am, OSM_cloudmade_1.geo, OSM_cloudmade_1.osm, OSM_cloudmade_2.geo, OSM_cloudmade_2.osm, OSM_cloudmade_5.geo, OSM_cloudmade_5.osm, OSM_cloudmade_998.geo, OSM_cloudmade_998.osm, OSM_cloudmade_999.geo, OSM_cloudmade_999.osm, OSM_cycle.geo, OSM_cycle.osm, OSM_mapnik.geo, OSM_mapnik.osm, OSM_osmarender.geo, OSM_osmarender.osm, OSM_skiing.geo, OSM_skiing.osm, src/map_OSM.c, src/map_OSM.h, src/map_geo.c: OpenStreetMaps linear scaling patches by Jerry Dunmire. Thanks! 2010-06-10 19:04 we7u * OpenStreetMaps.geo: Another patch by Jerry Dunmire, KA6HLD. 2010-06-10 19:02 we7u * Makefile.am, OpenStreetMaps.osm, src/main.c, src/map_geo.c, src/maps.c: Another OSM patch by Jerry Dunmire, KA6HLD. 2010-06-09 16:28 we7u * src/: db.c, igate.c, interface.c, interface_gui.c, main.c, map_OSM.c, map_WMS.c, map_shp.c, map_tiger.c, maps.c, messages_gui.c, objects.c, view_message_gui.c, wx_gui.c: More tweaks by Jerry Dunmire, KA6HLD. These get rid of some compiler warnings with newer GCC compilers. 2010-06-09 11:51 we7u * AUTHORS, Makefile.am, OpenStreetMaps.geo, src/Makefile.am, src/main.c, src/map_OSM.c, src/map_OSM.h, src/map_geo.c: Initial patches to use Open Street Maps with Xastir. This appears to be a good replacement for the now-defunct Tigermap server. Patches contributed by Jerry Dunmire, KA6HLD. Thanks Jerry! 2010-05-27 07:01 gstueve * scripts/: get-fcc-rac.pl, get-gnis: Uodate copyright info in a couple of scripts. 2010-05-07 09:23 tvrusso * src/main.c: Add a very simple hack cribbed from the "Grace" project http://patch-tracker.debian.org/patch/series/view/grace/1:5.1.22-5/motiflockup.diff to work around some extreme breakage introduced by Xorg server around version 1.7.5. This breakage changed the way the server handles "passive grabs" and has broken *all* motif programs that use XmCreatePopupMenu (among other things); such programs will grab the mouse cursor upon creating the pop-up and restrict cursor motion to within the parent widget of the intended popup, rendering the desktop completely unusable until the X server is killed. The correct fix is to update Xorg server (the fix is apparently in the yet-to-be-released 1.7.6), but that is not an option for some users of systems that only use stable releases of Xorg, and sometimes not even then (think Ubuntu, where they tend to stick only to bug-fix updates in a given LTS tree, and don't go to the next release number). Thus, it is necessary either to patch motif libraries or work-around the issue in applications. Since patching motif libraries is not a reasonable thing to require of our users, it's worthwhile to hack Xastir. The work-around ungrabs the mouse cursor immediately after the call to XmCreatePopupMenu. It's an almost trivial modification of the code. Tested on Xorg-server 1.6.5 and Xorg-server 1.7.5. Looks good, so committing it. The fix does have one unfortunate side effect on the newer server , as it is somewhat more difficult to tap the right mouse button and get the right-click menu to stay up, but it is possible. On the older server it appears to have no effect at all, which is good. 2010-04-23 07:00 gstueve * src/bulletin_gui.c: Remove annoying blank line from end of bulletin list. 2010-04-21 12:36 gstueve * config/Makefile.am: Fix source identification to work for BSD make. Should now work for new and old make utilities. I like these derived language files to test for added labels as I admit to a language deficiency. 2010-04-19 10:48 gstueve * config/Makefile.am: Permit derived language files to be generated from source file w/o requiring configure elements to be rerun. 2010-04-19 10:45 gstueve * config/Makefile.am, config/nwsz_ddmmyy_10.dbfawk, scripts/get-NWSdata: Add matching dbfawk file for new zone description file from NWS. 2010-03-10 22:24 we7u * src/db.c: Initializing a temp area object's color to a value to get rid of a compiler warning. 2010-03-10 20:03 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c: Mike, W2SWR, attempted to deploy Xastir over a MySQL database, and in the process helped to find multiple issues, including both an inability to compile xastir with just --with-mysql, and multiple causes for segfaults starting and stopping database interfaces and saving data. This commit addresses these issues. Xastir now compiles and runs with either or both --with-mysql and --with-postgis, as reqired definitions for each have now been appropriately included with preprocessor directives. The key fix for stability is in db_gis.h, the connection array has been redefined from an array pointer to an array, and the MYSQL object in the Connection struct has been changed from a MYSQL pointer to a MYSQL. Calls to methods that pass database connections have been rewritten to pass the address of the connection (&aDbConnection), rather than the connection. Multiple other fixes, mostly involving correcting the use of pointers, have been made to the db_gis.c code, and these have been tested and found to work with storage and retrieval of large quantities of internet feed data (on the order of 800,000 records) to both MySQL and Postgis databases, with xastir compiled with --with-mysql, --with-postgis separately, and with --with-mysql --with-postgis together. Also fixed a user interface bug that prevented retention of a selection of mysql(spatial) as a database type. 2010-03-05 21:52 we7u * FAQ: Adding more info to the Fedora 12 right-click bug problem/solution. 2010-02-28 07:47 we7u * scripts/inf2geo.pl: Added some comments about GM/IM prerequisites. Made it clear what the script does for the user. 2010-02-27 17:33 we7u * src/x_spider.c: Client connections to Xastir's server port had this problem: The last connected client, if it disconnected, would lock up the server. The pointer code taking care of removing objects in the linked list has been reworked. It no longer matters which order of client connects/disconnects are applied to the server. Thanks to Nathan Mills for helping me figure this out and test this. 2010-02-19 17:33 gstueve * src/interface.c: Fix spelling in error message that lintian found. 2010-02-16 20:13 chicoreus * src/db_gis.c: The node_path stored to a mysql database is not being truncated correctly with xastir_snprintf(), as the current length of the station->node_path_ptr that is providing the character array is used as the limit, rather than the maximum length allocated for the node_path into which it is being placed, thus causing a crash on trying to store a MySQL record for a position when the path exceeds 56 characters in length. 2010-02-16 17:47 we7u * FAQ: Tweaked the Fedora 12 right-click answer to point to "yum update". 2010-02-11 21:13 we7u * src/util.c: Taking an initial WIDE2-1 out of the equation which looks for WIDEn-N following WIDEn-N. 2010-02-06 19:48 we7u * Makefile.am: Setting up README.CYGWIN so that it gets copied to the docs directory with the rest of the docs during the install step. 2010-02-03 09:37 we7u * FAQ: Added Kevin K1KWP's note about getting right-click menus working in Fedora 12. 2010-02-01 10:37 gstueve * testdbfawk.1, xastir_udp_client.1: Quiet some warnings from manpages about hyphens and minus signs. 2010-01-31 12:10 we7u * configure.ac: Bumping the revision number for new development. 2010-01-31 12:09 we7u * README.Contributing: Updating text to call out the new place for the developers instructions (Xastir.org Wiki). 2010-01-31 00:45 we7u * ChangeLog: Committing latest ChangeLog (derived from cvs log) before release. 2010-01-31 00:44 we7u * symbols/symbols.dat: Updated wheelchair symbol plus new power plant symbol by Kyle Mills. Thanks! 2010-01-31 00:24 we7u * README.CYGWIN: A re-written Cygwin install by David Flood, KD7MYC. Thanks! 2010-01-31 00:19 we7u * README.MAPS: Tweaks by David Aitcheson, kb3efs. Thanks! A few minor tweaks by we7u. 2010-01-30 23:42 we7u * ChangeLog: Committing latest changelog before release. 2010-01-30 23:41 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.8 stable release. Changing revision numbers. 2010-01-30 18:12 we7u * AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, callpass.1, changes.txt, configure.ac, install-xastir, testdbfawk.1, update-xastir, xastir.1, xastir_udp_client.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/AUTHORS, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/Makefile.am, config/arealm.dbfawk, config/areawater.dbfawk, config/cousub.dbfawk, config/cousub00.dbfawk, config/edge.dbfawk, config/featnames.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsc_ddmmyy_09.dbfawk, config/nwsc_ddmmyy_09b.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzddmmyy_09.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsozddmmyy_09.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsw_ddmmyy_09.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwsz_ddmmyy_09.dbfawk, config/nwszoddmmyy.dbfawk, config/pointlm.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/stored_track.dbfawk, config/tabblock.dbfawk, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Coordinate.pm, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/UIView2XastirLog.pl, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/get-NWSdata, scripts/get-fcc-rac.pl, scripts/get-gnis, scripts/get-maptools.sh, scripts/get-pop, scripts/get_shapelib.sh, scripts/inf2geo.pl, scripts/kiss-off.pl, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl, scripts/object2shp.pl, scripts/overlay.pl, scripts/ozi2geo.pl, scripts/permutations.pl, scripts/pos2shp.pl, scripts/slideshow.pl, scripts/test_coord.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/track-get.pl, scripts/waypoint-get.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_pop.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testdbfawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating Copyright notice for 2010. 2010-01-25 20:09 chicoreus * src/db_gis.c: Make fails with errors when configured with just --with-mysql. Fixing nesting of HAVE_POSTGIS and HAVE_MYSQL directives so that xastir will build with just --with-mysql. Both compiler warnings and runtime errors remain when built --with-mysql --without-postgis. 2010-01-16 22:27 tvrusso * src/main.c: Fix three instances of a string compare being attempted by: char chararray[EXTENT] read chararray from some file if (chararray == "string literal") { } which is bad form in C and could lead to undefined behavior. The correct way to do this is with strcmp or strncmp. I replaced this with: if (strncmp(chararray,"string literal",strlen(chararray))==0) { } This is silently accepted by most older compilers, but is warned about by gcc 4.4 (the default compiler in Ubuntu 9.10). 2010-01-12 11:32 tvrusso * src/objects.c: Fix to my most recent fix; make sure that the code that doesn't get the compiler warning actually does the same thing that it did before the fix. 2010-01-12 09:47 tvrusso * src/objects.c: Minor tweak to silence a warning about "dereferencing type-punned pointer breaks strict-aliasing rules." 2010-01-11 19:30 tvrusso * src/: db.c, objects.c: Fix two bugs. 1) Bug 1698474 in the sourceforge tracker (Expire code messes up internal linked-list order) The title of the bug is erroneous. The expire code doesn't mess up any internal linked-list order. The expire code was being messed up by a broken linked-list order. What was breaking the list was the handling of our own objects. Code throughout objects.c was continually resetting the time stamp of station records to sec_now() withouth then moving the station record to the end of the time-sorted list. This led to the time-sorted list not being time-sorted anymore. The expire code explicitly depends on the list remaining sorted at all times. There was also a small block of code dating back to version 1.1 of db.c that also skipped moving a station record in the time-sorted list if it was our object or item. This very old code appears to do nothing at all. I have removed it. The time sorted list MUST be kept in time-sorted order. There was also a variable (object_is_mine_previous) that was set by this block of code but never accessed anywhere else. I've removed that variable, too. Additionally, the check_station_remove function erroneously checks "is_my_station" to determine if the station or object in question is owned by "me." It should be checking (is_my_station || is_my_object_item) to be consistent with the older conditional that is commented out just above it. 2) Creating an object that has the same name as a previously killed object would lead to an "immovable" object being created. This bug was never entered into the issue tracker. Prior to this commit, the following actions would create an object that could not be moved: create object a delete object a create object a Once the second create was done, the object a could not be moved by any means on the screen -- either by dragging with the Move button down or using the Modify Object dialog. The reason was that the code to handle resurrecting a killed object was improperly flagging the new object as being "my station" in addition to being flagged as "my object." The code that decodes position strings would see this flag and refuse to move the object "because I know my position better." Furthermore, the resurrection code would remove the old killed record from the name-sorted list, but not really delete the station record, leaving it in the time-sorted list. This also impacted expiration. This commit fixes the improper flagging as "my station" and completely deletes the station record for a killed object when we create a new object with the same name. 2010-01-01 15:04 we7u * src/main.c: Fixed some side-effects regarding zoom boxes when map lock is enabled. 2010-01-01 06:22 gstueve * src/db.c: Recall one of my tests from the wild. It escaped before its' time. 2009-12-31 03:10 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Finishing up the map lock code. 2009-12-29 13:56 we7u * src/main.c: Detaching the map lock from three areas where they are more complicated operations and therefore aren't easily done by mistake. Therefore no map lock required for those three. 2009-12-27 08:26 gstueve * callpass.1, testdbfawk.1, xastir.1, xastir_udp_client.1: Update APRS site reference to useful URL. 2009-12-27 07:29 gstueve * callpass.1: Add reference to xastir in NAME section to allow `apropos` to associate. 2009-12-25 07:20 we7u * README: Updating the SuSE 11.x ham repository info. 2009-12-22 13:37 gstueve * Makefile.am, src/db.c, src/lclint.script: Add additional man pages to list for publication. 2009-12-22 13:20 gstueve * callpass.1, testdbfawk.1, xastir.1, xastir_udp_client.1: Add simple documentation for all applications. Provide APRS reference in NAME section for 'apropos' & 'whatis' lookup. Make sure NAME section is parseable for scanning. 2009-12-22 02:56 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c, src/xastir.h: Adding map zoom/pan lock feature to the Map menu. 2009-12-17 09:44 gstueve * xastir.spec.in: Allow rpmbuild spec to work for 64bit environments also. 2009-12-08 11:34 we7u * README.MAPS: Updating the location of the RAC callsign manual download to match the URL in the get-fcc-rac.pl script. 2009-12-07 16:34 tvrusso * FAQ: Update FAQ to include updated answer to the "black images from imagemagick" question, and add a FAQ about compilation woes due to use of ImageMagick with HDRI support. 2009-12-04 10:54 tvrusso * src/: map_WMS.c, map_geo.c, map_tiger.c: Fix for the problem where Xastir will display black images when compiled against GraphicsMagick with its new default QuantumDepth of 8, or ImageMagick with its optional QuantumDepth of 8. The problem was that when the image was not a colormapped image (e.g. JPEG or other full color type), Xastir was assuming (incorrectly) that a Quantum was the same type as the red, green, and blue components of an XColor, and using the Quantums directly out of the pixel_pack in a call that required the latter. The result was that when pack_pixel_bits returned, the result was always that the packed pixel bits were always 0x000000, because it was taking the high-order 8 bits from the unsigned short to which the unsigned char was being cast. What was needed was a little block of code that massaged the pixel_pack values into unsigned shorts at that point if QuantumDepth is 8. This fix applies the same fix to map_tiger, map_geo and map_WMS, all of which had duplicated code (ugh) that made the same mistaken assumption of Quantum/unsigned short equivalence. This fix does NOT address the problem that exists on a few systems, where ImageMagick has been compiled with HDRI (High Dynamic Range Image) support. On those systems, a Quantum is not even an integer type, it's a float or double. Dealing with *that* mess will be harder. Ideally, the duplicated code between map_WMS, map_geo, and map_tiger should be consolidated according to good software engineering principles. 2009-11-26 08:52 tvrusso * LaCrosse/src/open2300db2APRS.c: Fix for an insidious bug in open2300db2APRS that relied on an unsafe internal behavior of the mysql API. The function Get_Latest_WX makes 2 SQL queries to the server, one to get the highest value of the "timestamp" field present in the DB, an another to get the row with that timestamp. Only after the first query was the function calling "row = mysql_fetch_row(&result)". That function returns a char ** that can be used to pick off the field values. Somehow, despite never being called after the second query, the row array still managed (on some systems) to have the right data in it --- presumably because the API call was returning a pointer to an internal block of memory that contained the field values, and on the systems where this worked that block wasn't moving. When I upgraded my BSD system and recompiled mysql, this started failing, and open2300db2APRS would segfault. Calling mysql_fetch_row after the second query fixes it. While I was at it, I fixed a mistake in some debug output that prints the number of fields retrieved by the query. 2009-11-09 12:46 we7u * scripts/UIView2XastirLog.pl: New script to convert UI-View log files to Xastir-format log files. Timestamp info is currently removed during the conversion. 2009-10-13 23:25 we7u * scripts/get-NWSdata: Updating the get-NWSdata script to snag the latest-latest NWS Shapefile maps used for weather alerts. 2009-10-13 23:24 we7u * config/: Makefile.am, nwsc_ddmmyy_09b.dbfawk, nwsmzddmmyy_09.dbfawk, nwsozddmmyy_09.dbfawk, nwsw_ddmmyy_09.dbfawk, nwsz_ddmmyy_09.dbfawk: Adding yet another round of dbfawk files to match new NWS Shapefile signatures. 2009-10-11 22:18 we7u * configure.ac: Bumping devel version up to 1.9.7 2009-10-10 11:28 we7u * scripts/: do_xastir_release_dev, do_xastir_release_stable: Updating to new SourceForge release process. 2009-10-10 10:41 we7u * ChangeLog, configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.6 stable release. 2009-08-12 11:59 we7u * src/main.c: Adding minWidth and minHeight to the fallback resources string in main() to attempt fixing the compiz/fusion bug with tiny unsizeable dialogs. 2009-08-12 11:14 we7u * FAQ: Adding a blurb regarding "compiz" and cigar-shaped windows in Xastir. Thanks to Tom R. for this text which I modified somewhat. 2009-07-31 21:19 tvrusso * config/nwsc_ddmmyy_09.dbfawk: Add a comment about the difference between this file and the nwsc_ddmmyy file. 2009-07-31 21:17 tvrusso * config/: Makefile.am, nwsc_ddmmyy_09.dbfawk: Add a new nwsc_ddmmyy file with different signature to match the very latest shapefiles. I am adding this as a new dbfawk instead of modifying the existing one so that those who don't wish to update their shapefiles will not have to, and those who have only the new ones will actually be able to use them. Xastir will pick the dbfawk file with the matching signature. 2009-07-31 15:38 we7u * src/wx_gui.c: Changing the weather alert FINGER server since WXSVR.net has been offline for a while. We're switching to Pete's new system (AE5PL) which is already online and functional. 2009-07-30 12:41 tvrusso * symbols/symbols.dat: Change color of ICP (Incident Command Post, /c) symbol to match the color specified in FEMA and NWCG ICS materials. (I'm working through lots of these courses while simultaneously trying to get Xastir integrated more into our local SAR system, and getting these discrepancies of terminology and symbology fixed is important). 2009-07-28 15:51 tvrusso * config/predefined_SAR.sys: Make predefined SAR objects conform with NIMS standard ICS terminology. There is no "Helipoint" in that terminology. The term "Helispot" is used for what we were previously calling a "Helipoint." 2009-07-28 15:49 tvrusso * src/objects.c: Fix predefined object name to conform with standard ICS terminology. A "Helispot" is a temporary landing place for helicopters. There is no "Helipoint" in standard ICS terminology. 2009-07-28 14:35 we7u * src/alert.c: Temporary change to allow viewing of compressed-zone format alerts sent by Pete Loveall, AE5PL's server. 2009-07-27 18:44 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Display of latest comment if H2O symbol plus object or item, and the comment time = the latest object/item update time. This is to support fast viewing of flood gauges during emergencies, using the data from the Firenet gage.pl script. 2009-06-29 00:14 we7u * src/db.c: Fixing Canadian callsign lookup to add VO and VY prefixes. 2009-06-19 23:01 tvrusso * src/shp_hash.c: Insert a conditional around code that uses a pointer returned by SHPReadObject. A user is finding that SHPReadObject is having an fread problem on one of his shapefiles, and returning NULL. This commit prevents Xastir from trying to dereference the null pointer. 2009-06-03 21:25 we7u * src/shapelib/: dbfadd.c, dbfcreate.c, shpadd.c, shpcreate.c, shpdump.c, shptest.c, shptreedump.c, shputils.c: Getting rid of compiler warnings due to unused variable. 2009-06-03 15:24 we7u * src/shapelib/: dbfadd.c, shpcreate.c: Adding includes for string.h to get rid of compiler warnings. 2009-06-03 14:57 tvrusso * src/shapelib/Makefile.am: Not really sure why this worked before but now doesn't work for Curt, but there was nothing in the src/shapelib/Makefile.am to make the {shp,dbf}{add,create} programs link with the shapelib we just built. Put that in. Rebootstrap before trying. 2009-05-22 16:23 we7u * scripts/pos2shp.pl: Changed some comments WRT the TODO for the comment field. 2009-05-22 14:41 we7u * README.MAPS: Adding bits about APRS Overlay files and the pos2shp.pl script. 2009-05-22 14:35 we7u * scripts/Makefile.am: Adding pos2shp.pl to list of scripts to install. 2009-05-22 14:23 we7u * scripts/pos2shp.pl: Better version. Limits $name to 9 chars and chops trailing spaces on same. 2009-05-22 14:14 we7u * scripts/pos2shp.pl: First working version. Needs more error checking, needs to assure the name field is properly formatted, and needs to do something with the comment field yet. 2009-05-22 13:16 we7u * scripts/pos2shp.pl: Updated comments, removed live_or_dead code. Has NOT been converted to parse POS format files yet (Overlay files). 2009-05-22 11:19 we7u * scripts/pos2shp.pl: Start of a pos2shp.pl script. No code changes yet from the original object2shp.pl script it started from. 2009-05-22 10:44 tvrusso * src/shapelib/Makefile.am: Change internal shapelib makefile so that it *does* install the create and add programs if we're building with internal shapelib. Note: This should not be tested by those who have shapelib tools installed from a package unless you know how to do it without clobbering them. Hint: configure --prefix=/some/other/base/than/usr/local will make sure that the new test install doesn't clober anything that the normal install created. 2009-05-22 10:30 tvrusso * src/shapelib/Makefile.am: Add "noinst_PROGRAMS" to the internal shapelib build so that shpcreate, shpadd, dbfcreate and dbfadd are built if the user is building the local shapelib. They are not installed, because I didn't want to test that feature. To make it so that they *are* installed when make install is called, one needs only change "noinst_PROGRAMS" in src/shapelib/Makefile.am to "bin_PROGRAMS" . 2009-05-19 13:47 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/wx.c: Add support for the Davis 6540 "Weatherlink for APRS" with "Streaming Data Logger". This attachment to the Davis Vantage Pro causes the device to stream APRS posits (sans fromcall, tocall, and path) to the serial port instead of requiring polling. With such a device, Meteo and the associated glue program (db2APRS or whatever it's called) are unnecessary, so long as this patch is in place. Also update language files as needed. 2009-05-09 07:15 tvrusso * src/db.c: Move "create_garmin_waypoint" call outside of "if (sound_play_prox_message)" conditional. A local user was completely confused why his garmin wasn't receiving waypoint data from Xastir, and when I hunted through the coude found that this feature only works if you have audio alerts for proximity warnings turned on. This seems wrong, so I moved the conditionals around so that waypoints are created if you're within proximity warning distance, whether or not you've actually got the old audio alarm turned on for proximity warnings. 2009-04-30 12:25 gstueve * src/: database.h, db.c: Fix band opening logic to ignore 3rd party traffic. Should make this really work for band opening and not messages from network. Fix Bug ID:2749796. 2009-04-30 11:52 gstueve * src/: main.c, shp_hash.c, shp_hash.h: We already know the current time, there is no need to ask again. 2009-04-29 20:08 gstueve * scripts/get-fcc-rac.pl: Minimize memory footprint for constrained systems. Do memory intense activity as late as possible. 2009-04-25 23:40 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c: Fix an annoyance related to DF bearing reports. Sometimes a bad parse of garbled Mic-E data causes Xastir to think that a D700 (or other mobile) is sending a DF report. Even if only a single such garbled transmission is received, the station is shown with DF bearing information for as long as it's in the database. Watching a mobile drive around with randomly moving DF beam lines is distracting. Not being able to make it go away without restarting Xastir has been annoying. Another way for this to happen is for some bonehead (such as KM5VY) to create a series of DF objects from an external program with his callsign as base name and sequential numbers to identify the reports (say "KM5VY-1", "KM5VY-2", etc.) until he happens to hit the SSID of the station that's sending the reports (say, KM5VY-8). What happens is the "object" data gets attached to the Xastir instance itself. This bogus beam heading shows up forever until shutting down Xastir. This happened today on a SAR ELT DF practice. The name of the bonehead has not been changed to protect the bonehead. This commit adds the ability to clear such bogosity. Now, the "Station Info" dialog for any station with DF bearing information has a "Clear DF Bearing" button that will zero out the bearing and NRQ strings for the station, removing the unwanted (and presumably incorrect) bearing lines until the station transmits them again (which probably means they're wanted and not incorrect). 2009-04-25 21:53 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Add a map-decluttering option. Prior to this commit, "Station->Filter Display->Display DF Attributes" would draw a pair of bearing lines for every DF object. The lines drawn represented the stated beamwidth of the report. Unfortunately, in a big DFing operation, this rapidly leads to a huge clutter on the map, making it very difficult, if not impossible, to read. I saw this during a big DF practice this morning, and just had to change it. I have added two new buttons under Display DF Attributes: "Display DF Beamwidth" and "Display DF Bearing." Selecting the first and not the second gives the current behavior. Selecting the second and not the first draws only the stated bearing, not the beamwidth. Selecting both draws all three lines for those who really, really like cluttered maps. The color of red used for the bearing line and the beamwidth lines is slightly different. I tried to set up xa_config so that when people first start up Xastir after updating, they'll recover the original behavior --- "Display DF Bearing" defaults to off if it's not found in the config file. Unless the new option is deliberately selected, users should not notice the change. Both Display DF Bearing and Display DF Beamwidth are greyed out if "Display DF Attributes" is deselected. Updated all the language files with the "update-language.pl" script to support the new menu items. A lot of other things got changed in the language files with this action, but those seemed mostly to be comments. 2009-04-24 13:10 gstueve * scripts/get-fcc-rac.pl: Move sort back to system package. PERL does parsing well, not sorting. 2009-04-17 16:10 we7u * config/: arealm.dbfawk, areawater.dbfawk, cousub.dbfawk, cousub00.dbfawk, edge.dbfawk, featnames.dbfawk, pointlm.dbfawk, tabblock.dbfawk: Updating the URL for the Shapefiles to point to the 2008 shapefiles instead of 2007! 2009-04-17 09:12 we7u * config/: Makefile.am, arealm.dbfawk, areawater.dbfawk, cousub.dbfawk, cousub00.dbfawk, edge.dbfawk, featnames.dbfawk, pointlm.dbfawk, tabblock.dbfawk: Adding the dbfawk files worked on by Richard Polivka, N6NKO, Craig Anderson, N6YXK, and Dale Seaburg, KG5LT, which help to nicely render 2008 Tiger Shapeline files. A note from Craig about layering: "...use "vi" on the map_index.sys file while xastir is not running. Once you are editing the file, use the following 3 commands in "vi" to change the layers. This assumes that, like with my xastir, new maps get added into the list at layer 1000. :g/tabblock/s/01000/00995/ :g/pointlm/s/01000/00996/ :g/arealm/s/01000/00997/ (translation: global search throughout the file for lines with "arealm" and substitute on that line for "01000", a "00997") This moves the tabblock (& tabblock00) files, pointlm files, and arealm files down underneath the roads maps. Otherwise the roads can get covered up by urban background coloring. Or you can do this through the GUI interface as well." 2009-04-16 19:55 we7u * src/wx.c: Fixing up the Peet Bros 2000 data logging and packet mode decoding for wind direction. These were really 4-character fields but the first two chars should be zeroed out. We were reading in only the 2nd two characters and then zeroing them out (the reading of interest). 2009-04-16 14:20 tvrusso * scripts/values.pl.in: Change values.pl.in so it references #!/usr/bin/perl instead of #!/bin/perl. Neither is strictly correct since perl could be installed just about anywhere on any system, but this brings it in line with all the rest of the scripts here. Ideally the location of the perl interpreter should be probed by configure and substituted in all the scripts, but that is probably more work than it's worth given that all of our scripts have had /usr/bin/perl hardcoded all this time. #!/usr/bin/env perl is sometimes suggested to make such scripts system-independent, but this is generally considered a security vulnerability because it uses the first "perl" that appears in the user's path, which might be a malicious bit of code. 2009-04-16 12:34 tvrusso * configure.ac, scripts/Makefile.am, scripts/values.in, scripts/values.pl.in: Remove inappropriate use of GNU Make extensions in scripts/Makefile.am. These were introduced to generate scripts/values and scripts/values.pl from scripts/values.in and scripts/values.pl.in, but this is the wrong approach. Generating these files from the .in's should be done by adding them to the configure.ac AC_CONFIG_FILES list and by using standard substitution strings in the .in files. Non-standard substitution strings can also be used if one also adds AC_SUBST calls to the configure.ac file. The standard substitution string for prefix is @prefix@ not @PREFIX@. 2009-04-16 12:26 gstueve * scripts/Makefile.am: Makefile should actually work properly for split source/build configuration. 2009-04-16 11:56 gstueve * scripts/Makefile.am: Make sure proper Makefile is updated when Makefile.am is updated. 2009-04-16 11:39 we7u * src/: main.c, messages.h, view_message_gui.c, xa_config.c: Saving/restoring the status of the CAD Objects buttons and the View Messages TNC/NET/MINE selection buttons. 2009-04-16 11:28 gstueve * scripts/: get-NWSdata, get-gnis, get-pop: Remove another possible bashism reported by checkbashisms script. 2009-04-16 09:25 we7u * scripts/: Makefile.am, slideshow.pl: Adding slideshow.pl, a script which snags the snapshot.png files into a separate directory and renames them for possible later use as a slideshow or animated movie. 2009-04-13 13:18 gstueve * scripts/get-pop: Position files are only ASCII, don't push AK or HI through recoding. 2009-04-13 13:10 gstueve * scripts/get-pop: Adjust download site to complete list. Retain tamu site for reference. 2009-04-13 11:34 gstueve * src/: locate_gui.c, maps.h: Add ability to locate map features from population format files. 2009-04-13 11:13 gstueve * src/map_pop.c: Missed these. Had compiled on other system. Mistyped entry. 2009-04-13 10:32 gstueve * src/: map_gnis.c, map_pop.c: Found a couple of locations that could get unhappy about trying to read bad data. 2009-04-13 10:16 gstueve * scripts/Makefile.am, scripts/get-pop, src/Makefile.am, src/map_pop.c, src/maps.c: Reintroduce previous population geolocator processing into new file type. The .pop file extension will reflect the old information. GNIS does not have authorative population data, we should use census info. The script will look to aprs.tamu.edu but I was not able to locate all of the states data files. 2009-04-08 09:24 gstueve * scripts/get-gnis: Get rid of bashism that escaped my first tests. 2009-04-08 09:17 gstueve * scripts/get-gnis: Add recode to convert AK & HI UTF-16 files to UTF-8 to give us a fighting chance to actually locate anything in those states. 2009-04-07 14:17 gstueve * scripts/get-gnis: USGS has made geocodes a moving target. Current file is 20090401. 2009-04-07 02:23 gstueve * src/main.c: Repair damage to map properties dialog inflicted by last check-in. 2009-04-06 09:07 gstueve * src/interface_gui.c: Move Path entries around to reduce vertical challenge. 2009-04-05 17:28 gstueve * src/map_gnis.c: Update field sequence to match current GNIS file layout. 2009-04-04 23:10 gstueve * src/list_gui.c: Update max display list to symbolic count. 2009-04-04 21:14 gstueve * src/list_gui.c: Clean up station list to actually line up with icon and line height. 2009-04-04 19:21 gstueve * src/objects.c: Maintain pointer to cursor to keep memory usage clean. 2009-04-04 11:37 gstueve * scripts/: .cvsignore, Makefile.am, coord-convert.pl, get-NWSdata, get-fcc-rac.pl, get-gnis, icontable.pl, values.in, values.pl.in, xastir-fixcfg.sh, xastir-migrate.sh: Fix the scripts to match the structure for placement of files by using -prefix from configure process to allow matchup to FHS placement. 2009-04-04 11:28 gstueve * m4/xmhtml.m4: Wrap macro name to keep everyone happy. Remove autoreconf complaint. 2009-04-03 07:08 gstueve * src/: main.c, main.h: Upgrade to session aware application space. Permit GNOME window manager to clean up without warning message about unsaved data. Permit restart to keep proper character translations for display. Clean up some free memory leaks and update for Motif 2.0 XmString functions. 2009-04-02 18:22 gstueve * src/interface.c: Remove extraneous include entry. 2009-04-02 15:09 gstueve * src/xastir.h: Remove external reference to internal application close out function. 2009-03-31 20:06 tvrusso * scripts/object2shp.pl: Fix a minor, but completely inconsequential error in this script. It would produce shapefiles with every shape having the same ID attribute. Doesn't matter at all since ID is not used for anything, but this is the right fix. 2009-03-31 12:56 we7u * src/rac_data.c: Fixing a 64-bit mode bug in the RAC callsign lookup code. 2009-02-06 09:22 gstueve * README.MAPS: Add hint for Australian rules Weather Alerts & update address for FCC data. 2009-02-06 08:51 gstueve * scripts/get-NWSdata: Update to latest from US NWS. 2009-01-08 17:53 we7u * README.win32: Adding notes WRT a Cygwin xorg-x11-devel 7.x compile error and how to fix it, courtesy of David Flood, KD7MYC. 2009-01-02 00:15 we7u * src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testdbfawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, m4/Makefile.am: Updating copyright notices for 2009. 2009-01-01 23:58 we7u * src/: rtree/Makefile.am, rtree/card.c, rtree/card.h, rtree/gammavol.c, rtree/index.c, rtree/index.h, rtree/node.c, rtree/rect.c, rtree/sphvol.c, rtree/split_l.c, rtree/split_l.h, rtree/split_q.c, rtree/split_q.h, shapelib/Makefile.am, shapelib/contrib/Makefile.am: Updating the copyright notices for 2009. 2009-01-01 23:56 we7u * scripts/: LSB-BUILD, LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB, Makefile.am, Xastir_tigerpoly.py, example_objects.log, get-NWSdata, get-fcc-rac.pl, get-gnis, get-maptools.sh, get_shapelib.sh, langElmerFudd.pl, langMuppetsChef.pl, langOldeEnglish.pl, langPigLatin.pl, langPirateEnglish.pl, toporama250k.pl, toporama50k.pl, xastir-fixcfg.sh, xastir-migrate.sh: Updating copyright notices for 2009. 2009-01-01 23:54 we7u * callpass/: Makefile.am, callpass.c: Updating the copyright notices for 2009. 2009-01-01 23:51 we7u * symbols/Makefile.am, symbols/symbols.dat, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui: Updating the copyright notices for 2009. 2008-12-31 20:37 we7u * src/xa_config.c: Changing xastir.cnf -> xastir.cnf.1 to a copy_file() call instead of a move(). This assures that we'll always have a config file in place even if we error-out before we can complete the next block which renames xastir.cnf.tmp -> xastir.cnf. 2008-12-31 20:18 we7u * src/xa_config.c: A better ordering for writing the config file. We now write a temporary file. If successful, we rename all the backups and then rename the temporary file as the current config file. This should help to minimize the instances of config file corruption. 2008-12-09 08:10 we7u * FAQ, README, README.Contributing, README.Getting-Started, README.win32: Adding notes about having to subscribe to the mailing lists before posting. 2008-11-26 09:39 we7u * src/draw_symbols.c: Correcting a comment. 2008-11-24 12:27 we7u * scripts/example_objects.log: Adding a link to the Xastir Wiki where images of these objects can be seen. 2008-11-12 15:26 tvrusso * src/map_geo.c: Comment out the use of GetOnePixel and the variable it assigns to. This is for two reasons: 1) F*!#*ng ImageMagick has broken its API yet again with version 6.4.5, making GetOnePixel no longer compatible with usage prior to 6.4.4 2) map_geo.c does this: PixelPacket target; target=GetOnePixel(image,0,0) after which it does NOTHING with the pixel so retrieved. So commenting out this useless line is less work than what I had started doing, which was hacking the configure detection of ImageMagick to distinguish between pre-6.4.5 and post-6.4.5, and coding around this garbage. I Hate ImageMagick. 2008-10-17 00:18 we7u * config/tnc-startup.aea: Turning on the HID function which is required on AEA TNC's for proper identification if they're digipeating. Since we have digipeating turned on in this file... 2008-10-16 09:20 we7u * ChangeLog: Updating for devel release. 2008-10-08 21:57 we7u * src/map_shp.c: Getting rid of a 64-bit compiler warning by changing an "(int)NULL" to a "0". 2008-10-08 21:56 we7u * src/db.c: Changing a debug format so that it doesn't cause a warning on 64-bit machines. 2008-10-08 08:11 we7u * src/maps.c: Getting rid of two compiler warnings: One by forcing a terminator into the first char of a string buffer instead of doing an empty xastir_snprintf(), another by casting a strlen() result to an int for an fprintf. 2008-10-07 23:10 we7u * src/shp_hash.c: Reverting back to the original code for strncpy() in this module: The previous change caused a panic. 2008-10-07 22:59 we7u * src/shp_hash.c: Getting rid of another strncpy() call. 2008-10-07 22:43 we7u * src/util.c: Forcibly terminating a string as an added precaution. 2008-10-07 22:42 we7u * src/shp_hash.c: Adding some blank lines to delimit an strcpy() call. 2008-10-07 22:41 we7u * src/objects.c: Getting rid of an strcat() call. 2008-10-07 22:41 we7u * src/db.c: Getting rid of some strncpy() calls. 2008-10-07 22:40 we7u * src/awk.c: Updating a comment. 2008-10-07 22:14 we7u * src/: db.c, fcc_data.c, hostname.c, igate.c, interface.c, interface_gui.c, locate_gui.c, map_WMS.c, map_geo.c, map_shp.c, map_tiger.c, maps.c, messages.c, objects.c, util.c, wx.c, x_spider.c, xa_config.c: Fixing some off-by-one errors in string handling. 2008-10-07 21:42 we7u * src/: alert.c, main.c: Fixing some off-by-one errors in string handling. 2008-10-06 22:04 we7u * src/main.c: Fixing the my_text string buffer in TrackMouse() so that it won't get overrun. The worst conditions are English Units, Dist/Bearing Status enabled, Degrees/Minutes/Seconds, zoomed out to world view and putting the mouse in the "corner" of the world (10,000+ miles). This results in about 54 characters being used whereas the original string buffer was only capable of holding 49. 2008-09-26 07:30 gstueve * src/x_spider.c: Make sure both sides of the pipe are satisfied before releasing the memory. The system is not happy about trying to read data from free space. 2008-09-24 12:44 we7u * .cvsignore: Ignore the derived file "xastir-lsb.spec" as well. 2008-09-24 12:18 we7u * src/.cvsignore: Ignoring testdbfawk now instead of testawk file. 2008-09-24 11:03 gstueve * src/map_tiger.c: Found one more place that needed to release ExceptionInfo when interrupted. 2008-09-24 09:16 tvrusso * README.MAPS, scripts/LSB-BUILD, src/Makefile.am, src/testawk.c, src/testdbfawk.c: Rename "testawk" to "testdbfawk" and add it to the list of programs that "make install" will install. This addresses a couple of issues: 0) Testawk is a *terrible* name for this program, because in fact it does not test "awk", the system program, but rather "dbfawk," the Xastir feature inspired by awk but completely unrelated to awk in any other sense. 1) testawk was never installed by Xastir's build process, meaning that packagers of Xastir binaries for various systems did not bundle this little program with their binary packages. There is even a bug in debian's bug tracker from an Xastir user asking that the xastir package have testawk installed (in a non-standard place because of its "generic, even misleading name") by the .deb package. I've updated README.MAPS and the LSB-BUILD script to make them refer to testdbfawk instead of testawk. I'll still have to change various web resources so they point at the new program, too. 2008-09-22 13:19 we7u * src/x_spider.c: Removing an earlier change 'cuz it makes the server ports die when a client disconnects. Without this line they appear to be solid again. 2008-09-11 06:07 we7u * src/main.c: Grey'ing out the xfontsel buttons when that app's not available. 2008-09-09 22:38 we7u * src/xa_config.c: Saving/restoring the tracking station callsign to/from the config file, but not saving the state of the tracking toggle. This means that the last tracked callsign will be remembered but tracking will not be on when Xastir starts up. 2008-09-09 22:17 we7u * src/db.c: A proper label for the new "Track Station" button on the Station Info dialog. 2008-09-09 22:11 we7u * src/db.c: Initial working version of "Track Station" from the Station Info dialog. Still needs additions to the language files for the button label. 2008-09-09 20:10 we7u * src/interface.c: Adding some comments near four areas that cause compiler warnings which we can currently do nothing about. 2008-09-09 20:09 we7u * src/testawk.c: Changing an int* to an int to get rid of a compiler warning about a mismatch. 2008-09-09 20:07 we7u * acinclude.m4: Adding /opt/local/ directory to the test for binaries (MacPorts). Changing the order of some compiler flags to help find GM before IM on FreeBSD systems. 2008-09-09 08:47 we7u * src/util.c: Changing the return type for a curl function to get rid of a warning caused by newer versions of libcurl. 2008-09-09 08:37 we7u * src/: main.c, track_gui.c: Adding #ifdef's around SED and MV calls. 2008-09-09 08:20 we7u * src/main.c: Added #ifdef around XFONTSEL call so that absence of the binary won't cause compile problems. 2008-09-08 09:13 we7u * ChangeLog, scripts/Makefile.am: Adding lang* scripts to package build. Updating ChangeLog to latest. 2008-09-03 08:46 gstueve * config/.cvsignore: Get CVS to forget about the generated language files. 2008-09-03 08:43 gstueve * src/main.c: Get valgrind to stop complaining about the lost blocks in the app_context. 2008-09-03 06:06 we7u * scripts/langPirateEnglish.pl: Translating "Maps" as well as "Map". 2008-08-31 16:45 we7u * scripts/langMuppetsChef.pl: Enabling more of the regex. Much better "translation". 2008-08-31 16:27 we7u * scripts/: langElmerFudd.pl, langMuppetsChef.pl, langPigLatin.pl, langPirateEnglish.pl: More updates to the derived language scripts. 2008-08-31 15:31 we7u * scripts/langOldeEnglish.pl: Rewriting the script so that anchoring & substitutions work in the regex. 2008-08-31 13:52 we7u * bootstrap.sh, scripts/langElmerFudd.pl, scripts/langMuppetsChef.pl, scripts/langOldeEnglish.pl, scripts/langPigLatin.pl, scripts/langPirateEnglish.pl: Updates to derived languages scripts, preparing for possible future uses. 2008-08-31 09:26 we7u * scripts/langPirateEnglish.pl: More for TLAPD. 2008-08-30 18:56 we7u * scripts/langPirateEnglish.pl: More Pirate updates. 2008-08-30 18:14 we7u * scripts/langPirateEnglish.pl: Latest Pirate updates. 2008-08-30 17:31 we7u * scripts/langPirateEnglish.pl: Added a few more Xastir-specific translations. 2008-08-30 16:30 we7u * INSTALL, README.Getting-Started, README.win32, bootstrap.sh, config/Makefile.am, help/help-English.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, src/main.c: Adding five new official languages to the "-l" flag in Xastir. 2008-08-30 16:28 we7u * scripts/: langElmerFudd.pl, langMuppetsChef.pl, langOldeEnglish.pl, langPirateEnglish.pl: Adding more official languages. 2008-08-29 22:21 we7u * scripts/langPigLatin.pl: Changing a comment to avoid the RCS tag substitution as well. 2008-08-29 22:19 we7u * scripts/langPigLatin.pl: Changed the match string so that RCS/CVS won't substitute a new Id: string in our REGEX expression. 2008-08-29 22:12 we7u * scripts/langPigLatin.pl: Renamed from PigLatin.pl 2008-08-29 22:11 we7u * scripts/PigLatin.pl: Moving this file to langPigLatin.pl 2008-08-28 08:14 gstueve * scripts/: get-maptools.sh, get_shapelib.sh: Use available resources to make use of temporary file as safe as possible. 2008-08-28 07:24 gstueve * scripts/get_shapelib.sh: Use same library logic as get-maptools.sh and clear temporary file for our use. 2008-08-28 07:22 gstueve * scripts/get-maptools.sh: Make sure to get temporary file out of way so we don't copy into something outside our expectation. 2008-08-27 06:25 tvrusso * acinclude.m4: Introduce proper quoting of AC_CACHE_CHECK arguments in XASTIR_GUESS_RUNPATH_SWITCH macro. 2008-08-27 06:23 tvrusso * acinclude.m4: Fix the XASTIR_GUESS_RUNPATH_SWITCH macro so that it uses AC_CACHE_CHECK with a CACHE-ID that conforms to the naming conventions expected. In versions of autoconf 2.62 and later, using a CACHE-ID without the "_cv_" string included in its name produces an annoying and possibly confusing warning message: configure.ac:572: warning: AC_CACHE_VAL(xastir_runpath_switch, ...): suspicious cache-id, must contain _cv_ to be cached ../../lib/autoconf/general.m4:1973: AC_CACHE_VAL is expanded from... ../../lib/autoconf/general.m4:1993: AC_CACHE_CHECK is expanded from... acinclude.m4:1131: XASTIR_GUESS_RUNPATH_SWITCH is expanded from... acinclude.m4:1120: XASTIR_ADD_LIBPATH_TO is expanded from... acinclude.m4:964: XASTIR_BERKELEY_DB_CHK_LIB is expanded from... ../../lib/m4sugar/m4sh.m4:508: AS_IF is expanded from... ../../lib/autoconf/general.m4:2461: AC_COMPILE_IFELSE is expanded from... ../../lib/autoconf/general.m4:2469: AC_TRY_COMPILE is expanded from... acinclude.m4:1059: XASTIR_BERKELEY_DB_CHK is expanded from... configure.ac:572: the top level several times during bootstrap. By renaming "xastir_runpath_switch" to "xastir_cv_runpath_switch" throughout acinclude.m4, this warning is silenced and the variable is cached as intended. According to the autoconf documentation, cache variables *MUST* have the "_cv_" string in their names. It is only in recent versions of autoconf that violating this requirement is actually flagged as a warning. 2008-08-25 08:19 gstueve * src/testawk.c: Add prefix to indicate that we are printing hexadecimal value. 2008-08-21 09:50 gstueve * src/bulletin_gui.c: Make sure everything is allocated for bulletins before use. 2008-08-21 09:48 gstueve * src/dbfawk.c: Release memory & directory after we finish with them. 2008-08-18 19:02 gstueve * scripts/get-fcc-rac.pl: No need to extract unsorted file to disk. Process directly into script. 2008-08-15 13:24 we7u * configure.ac, scripts/BUILDRPMS: Setting up for 1.9.5 development versions. 2008-08-15 12:51 we7u * ChangeLog: Updating ChangeLog to match latest changes (for upcoming stable release). 2008-08-15 12:50 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Updating version numbers for upcoming stable release. 2008-08-15 12:41 we7u * configure.ac: Checking for curl/curl.h include file in the libcurl test to make sure we can actually compile with it. Also only check for wget if the libcurl tests fail. 2008-08-14 21:39 we7u * configure.ac: Adding a "--without-libcurl" option to configure. 2008-08-14 21:36 we7u * acinclude.m4: Slight reformatting of help text (added spaces). 2008-08-12 12:16 we7u * src/db.c: Changing a tab to a newline at the end of Tactical Call in Station Info box. This prepares us for longer tactical calls. 2008-08-05 20:03 gstueve * src/map_geo.c: Found one more place to release ExceptionInfo for ImageMagick, hopefully last needed to minimize unbalanced memory usage in maps. 2008-08-04 07:27 we7u * xastir-min.spec.in, xastir.spec.in, scripts/BUILDRPMS: Getting rid of include/Xm/Xm.h requirement in RPM build spec files. Uncommenting a few print statements in the BUILDRPMS script that were commented out by mistake. 2008-08-03 10:26 we7u * xastir-min.spec.in, xastir.spec.in: Updating to new path for Motif include files. 2008-08-03 09:18 we7u * scripts/BUILDRPMS: Preparing for creation of SuSE-11.0 RPM's. 2008-08-01 19:14 we7u * src/db.c: Adding debug_level filtering to the TACTICAL code. 2008-08-01 07:55 we7u * ChangeLog: Updating ChangeLog before doing -dev release. 2008-08-01 05:42 gstueve * src/: map_geo.c, map_WMS.c, map_tiger.c: Make sure that error returns are covered by ImageMagick release code. 2008-07-31 23:21 gstueve * src/map_gdal.c: Give GDAL a chance to release data from GDALAllRegister at end of run. 2008-07-31 20:24 gstueve * src/map_WMS.c: Make sure to deal with cleaning up ExceptionInfo when finished with map. 2008-07-31 20:20 gstueve * src/map_tiger.c: Make sure to cleanup allocated space before returning to caller. ImageMagick exceptionInfo needed to be destroyed when finished. 2008-07-31 17:09 we7u * src/: main.c, xa_config.c: Reverting to "fixed" font as the default for the SYSTEM and STATION fonts. 2008-07-30 08:24 we7u * src/: database.h, db.c, util.c: More Tactical Call changes: Assignments before a station shows up work. Clearing an assignment causes the string to be freed and the pointer nulled. Max tactical call length is now 57. 2008-07-28 02:10 we7u * src/db.c: Cleaning up the input parameters for one of the new tactical call helper routines. Leading/trailing spaces on callsign or tac-callsign affect the results little now. Lower-case callsigns are converted to upper case now. One minor annoyance: Blanking out callsigns using messages to TACTICAL results in this being displayed in the station chooser when there are more than one station under the mouse: "()". The proper display should be the callsign in that case, so perhaps spaces are still getting saved in the tactical callsign slot -or- the tactical callsign string isn't getting free'd and the pointer NULLed out (the latter is most likely). 2008-07-28 01:37 we7u * src/: db.c, util.c, util.h: The beginnings of being able to share Tactical Call data with others over the air. This code works, decoding messages sent to "TACTICAL" which are in one of these four formats: My Home WE7U-3=My Home WE7U-3=My Home;WE7U-12=Curt's Jeep;WE7U-15=I Don't Know WE7U-3=;WE7U-12=;WE7U-15= In the first case it'll assign "My Home" as the tactical callsign for the station that sent the message. In the last case it'll remove tactical callsigns for the listed stations. For testing remember that you can't send a new message to TACTICAL until the previous message has either timed-out or been cancelled. 2008-07-18 08:26 gstueve * scripts/get-NWSdata: Update to current Marine Zone. There are changes due in September for a few of the zone files. Need to watch for implementation date. 2008-07-11 15:03 tvrusso * acinclude.m4: Fix spelling error in AC_SEARCH_LIBS line for Magick/MagickCore. This is mostly irrelevant, because LIBS already has the right stuff in it if Magick-config --libs isn't lying, and for most users this test will be a no-op. 2008-07-10 08:46 chicoreus * src/db_gis.c: Issue: 2015173 Missing #ifdef for MySQL causes xastir to segfault when built with only --with-postgis. Found by Jeffrey Johnson. 2008-07-07 15:26 tvrusso * src/maps.c: Fix map metadata for upper left corner. Previously, the code was using the same coordinate pair to compute the upper left and lower right corner strings. For some reason, this ultimately made somewhat correct labels for UTM, but completely wrong labels for Lat/Lon. Since this simple change makes the code produce correct labels for all coordinate systems, and the other shouldn't have worked for any, I feel safe committing it. But I would have liked to understand why it worked at all for UTM. 2008-07-07 09:53 we7u * ChangeLog: [no log message] 2008-07-03 07:55 gstueve * src/alert.c: Increase size of titles for alerts to allow for large area alerts to be processed w/o loss of compressed info. 2008-07-03 06:12 we7u * src/db.c: If text on black background style selected, draw a black rectangle in that corner of the map first so that the scale lines show up well. 2008-07-02 17:12 gstueve * AUTHORS, src/main.h: Update current callsign for K4INT. 2008-07-02 12:06 gstueve * src/map_WMS.c: Remove extra fclose(f) of already closed file. Keep everyone happy. 2008-07-02 11:03 we7u * src/db.c: Decode DAO patch by Tapio Sokura, OH2KKU. This doesn't do anything with any datum transmitted, but does give us the extra precision sent via the DAO extension. We still need to change the white precision rectangle for the station on our map to make it smaller (not included in this change). 2008-07-02 06:54 we7u * src/db.c: Feature request 756236: Have Range Scale and Ruler text at bottom of map screen follow the same text style selection as the station text, to make them easier to read. 2008-07-01 20:04 we7u * src/: bulletin_gui.c, db.c, draw_symbols.c, geocoder_gui.c, interface_gui.c, list_gui.c, locate_gui.c, location_gui.c, main.c, map_geo.c, maps.c, messages_gui.c, objects.c, popup_gui.c, track_gui.c, view_message_gui.c, wx_gui.c, xastir.h: The remaining major updates to allow changing the "system" or "menu" font throughout the applicaton. 2008-06-30 18:47 gstueve * scripts/get-gnis: Remove extra path separator. 2008-06-30 16:40 we7u * src/: draw_symbols.c, main.c, maps.c, popup_gui.c, xa_config.c, xastir.h: Patches to implement a GUI interface for changing fonts, plus added error-checking to some of the font code. 2008-06-30 16:39 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: The first of two commits adding a GUI interface for changing system/ station/atv_id fonts. 2008-06-30 07:02 gstueve * scripts/get-gnis: Update path for file from USGS and adjust suffix for current file layout. 2008-06-27 13:10 we7u * src/main.c: More menus converted to allow using user-specified fonts. 2008-06-27 12:48 we7u * src/: main.c, popup_gui.c, xa_config.c, xastir.h: Adding the capability for users to specify the fonts used for the system fonts, station fonts (on map screen), and the ATV_ID font. Currently the users will have to edit the fonts in xastir.cnf, but later a GUI access method for editing can be added. 2008-06-27 12:45 we7u * src/maps.c: Fixing the initialization of arrays for map labels. 2008-06-27 06:41 we7u * configure.ac, src/main.c, src/track_gui.c: Adding path tests for "mv", "sed", and "xfontsel", plus the correct bits of code in the .c files to use those paths. 2008-06-26 12:10 we7u * src/main.c: Specifying more of the font characteristics for the font used when USE_LARGE_STATION_FONT is defined. 2008-06-26 07:41 we7u * src/db.c: A fix for the Citizen's Weather filter to get rid of the new "DW" prefixed stations, plus more strict filtering so that we don't also get rid of Uruguay and Phillipines weather stations with this same filter. 2008-06-25 16:30 we7u * src/main.c: Fixing the system fonts so that they work on more systems. 2008-06-25 06:41 we7u * scripts/toporama250k.pl: Updated the instructions for running the script plus got rid of DOS line-end characters that had somehow crept in. Those line-end characters prevented the Perl interpreter from running on Linux. 2008-06-25 06:39 we7u * scripts/toporama50k.pl: Updated the instructions for running the script. 2008-06-25 06:38 we7u * help/help-English.dat: Changed the name of the fcc-get script to get-fcc-rac.pl 2008-06-25 06:37 we7u * src/db.c: Station Info: Special-case check for objects sent by "WINLINK". We keep the object name as the "origin" in this case instead of "WINLINK". This solves the "FCC" instead of "RAC" button problem for objects with Canadian callsigns, allowing us to look of RAC licensing information. 2008-06-24 08:52 we7u * README.Getting-Started, README.MAPS: Updating the name of the get-fcc-rac.pl script in the docs. 2008-06-24 08:48 we7u * scripts/: Makefile.am, fcc-get, fcc-get.pl, get-fcc-rac.pl: Combined fcc-get and fcc-get.pl into one script called get-fcc-rac.pl 2008-06-23 15:42 we7u * README: Adding the SuSE-11.0 Ham Radio repository URL. 2008-06-13 06:43 gstueve * scripts/get-NWSdata: Remove the bashism to keep people happy. 2008-06-13 00:37 gstueve * config/nwsz_ddmmyy.dbfawk: Actually get the signature template right for Watches. 2008-06-13 00:25 gstueve * config/: nwsmzddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Actually get the template to match the available dataset. 2008-06-12 20:27 gstueve * scripts/get-NWSdata: Missed that one of the files was in a different directory. 2008-06-12 18:49 gstueve * scripts/get-NWSdata: Introduced bashism to reduce size & improve consistency for all files. 2008-06-12 12:30 gstueve * config/Makefile.am, config/nwsz1ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, scripts/get-NWSdata: Adjust script and dbfawk for current set of files from NWS. There are newer sets of files for upcoming dates. 2008-06-11 06:39 gstueve * src/x_spider.c: Reduce side effects of free memory by clearing pointer after deallocation. 2008-06-09 12:28 we7u * scripts/: LSB-BUILD, LSB-BUILD-ALL, LSB-BUILD-GRAPHICSMAGICK: Committing latest changes for LSB build. Am not done yet getting LSB to build properly on OpenSUSE-10.3, but this is a good start. 2008-06-09 12:25 we7u * ChangeLog: Keeping it up to date with CVS commits. 2008-06-09 12:23 we7u * scripts/do_xastir_release_stable: Changed SF upload process to match what they currently allow. 2008-06-09 12:23 we7u * scripts/do_xastir_release_dev: Change SF upload process to match what they currently allow. 2008-06-04 04:23 gstueve * src/db.c: Allow Objects that have space in name to work with Tactical Call Sign addition. 2008-05-30 08:32 gstueve * src/db.c: Add tactical call sign to station pick list when multiple stations under cursor. 2008-05-29 10:15 we7u * FAQ, README.Getting-Started: Updating some of the PATH wording. 2008-05-27 12:04 gstueve * src/messages.c: Start fixing elements to allow Group & Bulletin messages to go unacknowledged. 2008-05-21 09:08 tvrusso * src/util.c: Fix makeMultiline (an unused function) so that it produces offsets in the same sense that xastir decodes them --- i.e. that positive longitude offsets are west of the reference point. 2008-05-09 11:20 gstueve * src/interface.c: Make sure not to add break character if no altitude to be reported. 2008-05-09 11:18 gstueve * src/: util.c, util.h: Make sure course and speed are treated as non-negative numbers only. 2008-05-06 04:05 gstueve * scripts/fcc-get.pl: Remove extra CR at end of each line and deal with full list only once. 2008-05-05 13:00 gstueve * scripts/: Makefile.am, fcc-get, fcc-get.pl: Adjust fcc file processing to deal with vanity call update. 2008-05-02 09:58 tvrusso * acinclude.m4: Change "AC_CHECK_LIB" to "AC_SEARCH_LIBS" for ImageMagick. A recent update to ImageMagick stuffs the "WriteImage" function into libMagickCore instead of libMagick, and the older probe was missing it. With this change, I see that WriteImage gets found without adding anything to LIBS, because "Magick-config" already stuffed the right thing into LIBS. 2008-04-13 22:31 we7u * src/util.c: Fixing a bug found with latest wget: --timestamping and -O options can't be used together. Getting rid of the timestamping option which we can live without. 2008-04-13 21:31 we7u * src/util.c: Updating wget and libcurl fetches to specify "Xastir" as the user-agent string in the request. This is to support the new restrictions that findu.com has implemented. 2008-03-20 21:11 chicoreus * src/: db.c, interface_gui.c, main.c: Minor cleanup of comments and un-needed code from testing problems with database connections. 2008-03-20 21:00 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c: Identified and fixed problem underlying stability of multiple database connections (space for connection structures was incorrectly allocated so that writing an error message into one connection overwrote memory used by another connection). Fixed additional problems related to connection failures and added more resilience to database connection problems. 2008-03-18 19:10 chicoreus * src/: db.c, db_gis.c, db_gis.h, interface.c, interface_gui.c, main.c, main.h: Overhaul of the way sql database connections are handled, reducing the complexity by eliminating the ConnectionList struct, and creating an array of Connections, one for each interface. More than one database connection can now be run at once, though there is still an issue with pointers or memory handling somewhere and instabilites can be produced by stopping and starting database connections. Moved all the db_gis related debug_level tests from 1 to 4096. 2008-03-11 20:27 tvrusso * acinclude.m4: Fix a fairly dumb thing in the probe for Berkeley DB --- it was always resetting the result (BDB_LIB_FOUND) to "-ldb" even if the actual library found was something else. This variable was used only to report to the user what library was found, never as the actual "-l" flag. This could have led to confusion, but not improper operation. 2008-03-06 12:47 we7u * scripts/BUILDRPMS: Updating to SuSE-10.3 for generation of RPM's. 2008-03-03 20:00 tvrusso * README.MAPS: Add link to FAA digital data products web site. You can purchase FAA sectionals in GeoTIFF format there. 2008-02-29 08:54 chicoreus * src/: database.h, db.c, db_gis.c, interface_gui.c: Added trails to db_gis code. Multiple points from one station retrieved from a database query are added as trailpoints. Existing stations heard from other sources and retrieved from a database query aren't duplicated as DataRows, but have appropriate trail points added (if the existing position is older than the database data, the existing position becomes as trailpoint; if the database data is older, it gets added as trailpoints). Added timeformat to add_simple_station, as Postgresql and MySQL timestamps don't both include the local timezone "%z" in the current simple station query formats. Added APRS_WXn character constants as a workaround, since AprsTypes and Record Type character constants are used inconsistently in DataRow.record_type, and AprsTypes without character constants don't write cleanly into MySQL or Postgresql database records. Added and commented out lines to start database connections from interfaces Left commented out as multiple open database connections are still unstable and segfault. 2008-02-27 20:02 gstueve * scripts/fcc-get: FCC moved the database again. Look for it in new place. 2008-02-21 20:57 chicoreus * src/: database.h, db.c, db_gis.c, interface.c: Improvements to the tollerance of the db_gis code to problems with connections to databases and improved reporting of problems in making connections. Added code to add tracks for stations retrieved from the database. Still needs work, as the existing db.c code for adding stations and points to the tracks of stations makes different assumptions about the order in which positions are recieved than the order of records queried in db_gis.c. 2008-02-21 20:51 chicoreus * scripts/: db_gis_mysql.sql, db_gis_postgis.sql: Adding some indexes to speed up retrieval of station records. Adding a view that could be used with mapserver to return icon files for each station. 2008-02-16 08:15 we7u * src/main.c: Switching the Garmin RINO processing to use uncompressed packets for now as there is a problem with either this section of code or the Compressed encoding code for particular positions. Change the ABOUT message to include additional copyright information. 2008-02-07 18:47 chicoreus * src/: main.c, main.h, maps.c, maps.h, xa_config.c: Adding two new KML export features: 1) KML Snapshots - on a regular basis (using the same timing as PNG snapshots), write all currently known stations to a kml file. 2) KML file to accompany PNG snapshots. After converting snapshot.png to snapshot.jpg, the accompanying snapshot.kml file can be used to layer the snapshot.jpg image on the landscape in a kml application. The KML produced is valid and appears to work, but hasn't been extensively tested. This (along with the allready committed export a single station track to kml feeature) should complete the feature request for KML export: http://sourceforge.net/tracker/index.php?func=detail&aid=1863377&group_id=45562&atid=443274 2008-02-07 18:35 chicoreus * help/help-English.dat: Added help text describing KML export and snapshot features. 2008-02-07 18:33 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding menu item for regular snapshots of all heard stations to a kml file, analogus to png snapshots. 2008-02-07 18:29 chicoreus * scripts/: kml_snapshot_feed.kml, kml_snapshot_to_web.sh: An example kml file and a shell script to allow png snapshots with their accompanying snapshot.kml file to be used as a regularly updated kml feed on a webserver (allowing the current snapshot from xastir to be draped over the landscape in a kml application remotely subscribing to the feed.) 2008-01-29 19:08 chicoreus * help/help-English.dat: Correcting a spelling error (found by Curt). Placing more references to button titles in quotes to make the description of the station info dialog more consistent. Clarifying (hopefully) some of the description of saving tracks from the station info dialog. 2008-01-25 21:45 chicoreus * src/: db.c, util.c, util.h: Added a utility function to return a date/time in w3c timestamp format, required for valid timestamps in kml files. Rearranged the log station to kml code, and added timestamped placemarks for each location of a station in a track. This produces kml output that validates, and should behave like the "Shroeder" whale shark example file (moving a station location along its track as a time slider control is moved in Google Earth). This has not yet been tested to see if the behavior is as desired. 2008-01-24 22:21 chicoreus * INSTALL, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat: Localization for Station->Export All->Export kml menu items. User documentation of KML export. User documentation for spatial database support. Added some fault recovery comments to spatial database configuration section of INSTALL. 2008-01-24 22:18 chicoreus * src/: database.h, db.c, main.c: Adding Station->Export all menu, with option to export all station records to a single kml file. 2008-01-24 14:36 chicoreus * src/: interface_gui.c, main.c, objects.c: Fix for bug 1863228. Lesstif doesn't yet fully support combo boxes, which are used in 4 places in Xastir (for user configurable predefined objects file in defaults dialog, cad object line type in the cad object details dialog, and twice in the interface properties dialog when defining a sql database interface. An alternate lesstif menu that mimics a combo box control (modified from xpdf's XPDFViewer.cc), is applied in three of these four cases (the fourth currently only has a single option, and might not be the best control for the situation, picking database schema type[s]). This has been tested on lesstif 0.94.4 and openmotif 2.3.0. 2008-01-23 00:23 we7u * src/interface.c: Added "volatile" keyword to a couple of variables to assure they don't get overwritten by longjmp. 2008-01-22 23:34 we7u * src/track_gui.c: Converting from mucking with pointers to pass to variables to a thread, to passing a pointer to a struct instead. This last method should avoid architecture-dependent problems in the download findu trail processing. 2008-01-22 23:08 we7u * src/track_gui.c: Added a comment regarding a section of code which does type-punning and may be architecture-dependent. 2008-01-22 23:07 we7u * src/messages.c: Commented out "altgroup" section of conditional which always equates to true ('cuz it's an address). 2008-01-22 23:05 we7u * src/interface.c: Added a couple of comments. 2008-01-22 22:00 we7u * src/map_cache.c: Reformatting debug statement so that it won't generate compiler warnings. 2008-01-22 20:49 we7u * src/wx.c: Fixing a buffer overrun. Found via a compiler warning on OpenSuSE-10.3 2008-01-22 20:48 we7u * src/map_geo.c: Reformatting a debug statement so it won't cause compiler warnings. 2008-01-22 20:47 we7u * src/map_gdal.c: Getting rid of a conditional that always evaluates as true: The address of "label". 2008-01-22 20:46 we7u * src/map_dos.c: Fixing an array overflow condition that has existed for a LONG time. Found via a compiler warning on OpenSuSE-10.3 2008-01-22 20:45 we7u * src/map_WMS.c: Changing debug statement format so it won't cause a compiler warning to be issued. 2008-01-22 20:43 we7u * INSTALL: Adding a note about RINO's: That Xastir cannot cause a poll of the remote RINO units over the air. 2008-01-18 18:49 chicoreus * src/db_gis.c: More cleanup of db_gis code. 2008-01-18 18:48 chicoreus * src/main.c: Adding test in UpdateTime to avoid opening the same database interface twice during startup if it is marked to both activate on startup and load stations on startup. 2008-01-17 19:21 chicoreus * src/: db.c, db_gis.c, main.c: Minor stability improvements to db_gis code. Adding some sanity checks for null database connections when running queries to reduce segfaults. Begining cleanup of the db_gis code. Removing some leftover unused variables and code. Explicit type casting of some pointers in function calls to suppress compiler warnings. 2008-01-16 20:33 chicoreus * src/: database.h, db.c, db_gis.c, main.c, objects.c: First pass at exporting station tracks as kml files. On clicking store track on the station information dialog, both an xastir format file and a kml file for the selected station will be written to ~/.xastir/tracklogs Added more comments on how database schema version and series compatability should work. Fixed (superficially) a bug where station data would be written to a non-open database connection causing a segfault. Connection handling in db_gis is fragile and needs review. 2008-01-16 11:38 we7u * scripts/: BUILDRPMS, LSB-BUILD: Updating to 1.9.3 release number. 2008-01-16 11:33 we7u * AUTHORS, ChangeLog, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgr2shppoly_2006.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/PigLatin.pl, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-NWSdata, scripts/get-gnis, scripts/get-maptools.sh, scripts/get_shapelib.sh, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/db_gis.c, src/db_gis.h, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, symbols/Makefile.am, symbols/symbols.dat: Updating the copyright notices for 2008. 2008-01-16 10:32 we7u * configure.ac: Preparing for devel release, bumping revision number. 2008-01-10 07:35 chicoreus * src/: interface.c, main.c, objects.c: Fixing bug where objects/items created by the user are not displayed until Xastir is restarted. Adding more debugging information when loading predefined objects from a file. 2008-01-09 21:06 chicoreus * src/: db.c, db_gis.c: Fix from Curt for some compile warnings in xastirWKTPointToLatitude(). Fix to incorrect data being written to MySQL table simpleStationSpatial in the origin and node_path fields. Note: When selecting data from MySQL simpleStationSpatial, use the AsText() function on position. For example, to retrieve the 10 most recently heard stations: select station, symbol, overlay, aprstype, AsText(position), transmit_time, origin, record_type, node_path from simpleStationSpatial order by transmit_time desc limit 10 ; 2008-01-08 17:22 chicoreus * src/interface.c: Possible bug fix for the can't have two sql database interfaces open at the same time issue. Pointers around Connections need review. 2008-01-08 07:00 chicoreus * src/: db_gis.c, db_gis.h, interface.c, main.c: db_gis.c closeConnection now linked to stop button on interfaces. SQL database state (open,closed,error[on connect only]) state shown on interface list. 2008-01-07 20:35 chicoreus * INSTALL, scripts/db_gis_mysql.sql, scripts/db_gis_postgis.sql, src/db_gis.c, src/interface_gui.c, src/objects.c: Added some installation instructions for spatial database support. Added a workaround for lesstif not having full implementation of combo boxes (borrowed from xpdf's XPDFViewer.cc) to the dbms selection control on the spatial database interface dialog. Fix needs to be propagated to several other places. Fixes to sql scripts to build mysql and postgis database tables. 2008-01-01 14:58 chicoreus * src/: database.h, db.c, db_gis.c, db_gis.h, interface.c, interface.h, interface_gui.c, main.c, main.h, xa_config.c: Significant updates to db_gis code, supporting storage of station data to both MySQL and postgis enabled Postgresql databases. Stations heard in Xastir can have the core station information logged to either a Postgres or MySQL database (Bug: currently both aren't working at the same time), and then retrieved in a subsequent Xastir session (or by a different Xastir instance, or by another GIS application (such as QGIS over a postgis database populated from Xastir)). Tested with MySQL 5.0.32, may not work with MySQL 4.1. Tested with Postgres 8.1.9 2008-01-01 14:50 chicoreus * scripts/: db_gis_mysql.sql, db_gis_postgis.sql: Adding sql scripts to create tables for persistent storage of basic station data. One script for mysql, another for postgis enabled postgresql. Currently only supports a single simple table with the minimun station information. 2007-12-18 12:56 tvrusso * configure.ac: Fix improper probing of curl library when LSB is not being used. AC_CHECK_LIB can have two or three arguments. With two arguments it tests for the presence of a function named in the second argument in the library named by the first argument, and if found defines HAVE_LIBxxxxx and adds -lxxxxx to LIBS. In the three-argument case, it does the probe the same way, but instead of the default "define HAVE_LIBxxxxx and add -lxxxxx to LIBS" it does what it's told in the third argument. That means if you want to rely on HAVE_LIBxxxxx and LIBS="${LIBS} -lxxxxx" then you have to do it yourself in the third argument. The AC_CHECK_LIB for curl was only doing the extra thing, which was to set "use_curl" to "yes". I recently discovered this by trying to build and use xastir on a freshly installed system that had libcurl but no wget (most of my other systems have both). The bug in the use of AC_CHECK_LIB meant that libcurl was found, but never linked in nor was HAVE_LIBCURL ever set in config.h. With this fix, curl is now both properly detected *and* the detection properly communicated to the code. 2007-12-13 22:23 tvrusso * config/tgr2shp.dbfawk: Add "P" feature class to handle "Provisional" road data in TIGER/Line shapefiles. According to the TIGER/Line Technical Documentation for feature class "P" The U.S. Census Bureau has created a new CFCC type that may appear on street features only. Some streets that normally would be classified as "A" class features may be coded with a "P" instead of the "A" to indicate that the feature is a a "provisional" feature. Provisional features are those streets that were added from reference sources or other programs in preparation for Census 2000, but were not field verified by census staff during field operations or through the use of aerial photography or imagery. As these featues are verified in futuer operations the provisional flag will be removed for subsequent TIGER/Line releases. The numeric portion of the CFCC still classifies the street as if an "A" were preceding it. So this just involves changing the matching pattern from CFCC=A... to CFCC=[AP]... in all the feature-class A rules. 2007-12-05 08:40 tvrusso * README.MAPS: Add more text to the section on Geocommuity's DRG Data Bundle deals. Turns out that some areas have DRGs produced by some agency other than the USGS, and those agencies don't necessarily produce GeoTiff files with proper metadata. The Tennesee Valley Authority is among those agencies that don't properly include GeoTiff tags for projection and datum. This renders DRG data bundles for states with portions of their area covered by the TVA partially defective --- special preprocessing is necessary to get the files into a state that can be used in Xastir. 2007-11-14 07:05 tvrusso * README.MAPS: Add a pointer to a vendor of inexpensive GeoTIFF format DRGs for the US. They're one of the USGS's data partners that is listed elsewhere in the document, but in a different context. Thanks to Eric, KZ5ED, for calling it to my attention. 2007-11-07 13:37 tvrusso * src/: main.c, map_WMS.c, map_geo.c, map_tiger.c, maps.c: Work around the fact that ImageMagick's api.h rudely includes their autoconf-generated config.h, which therefore defines the same PACKAGE and VERSION macros that we do. In most files, this produces an annoying but harmless warning message about a redefinition. For main.c, however, it cause Magick's PACKAGE name and VERSION to be used in place of our own. That is, our About window will announce that we're ImageMagick version 6.3.x. For the files in which it's a harmless warning, I've done an #undef of the two macros to shut up the compiler warnings. In main.c, I've created two new char* variables and initialized them to PACKAGE and VERSION before including magick's api.h, and then undef'd them. This preservs the contents of our macros by substituting them in C code right away, then gets rid of them so the warnings are shut up. Attempting to do: #define XASTIR_PACKAGE PACKAGE #undef PACKAGE #include #undef PACKAGE #define PACKAGE XASTIR_PACKAGE doesn't help. All that does is silence the warning. Magick's package name is still used when we try to use the PACKAGE macro later. Macro expansions aren't variable assignments, and the code above does nothing more than define PACKAGE to PACKAGE and thence to "ImageMagick", after briefly allowing api.h to change its meaning without warning. Adding an "#undef XASTIR_PACKAGE" after all that is even worse, and results in fatal compilation errors. There's probably some preprocessor game that can be played to kludge this, but saving the string we want to keep somewhere where it's safe from preprocessor meddling seems the better choice. 2007-11-06 09:10 we7u * configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.9.2 stable release. 2007-09-24 19:41 we7u * src/track_gui.c: Finished the regex code for converting HTML->Text for downloaded findu.com tracks. 2007-09-22 03:53 we7u * src/track_gui.c: Commenting out unused variable. 2007-09-22 03:25 we7u * configure.ac: Commenting out the html2text discovery code. 2007-09-22 03:25 we7u * configure.ac: Checking in the html2text discovery code in case we may want it in the future. 2007-09-22 03:24 we7u * src/track_gui.c: Doing the html2text via sed statements. 2007-09-22 01:29 we7u * src/track_gui.c: Converting the downloaded findu.com raw packets from HTML to text. Still need to look for "html2text" and find out it's path in the autoconf scripts in order to integrate this properly. 2007-09-16 18:31 tvrusso * src/interface_gui.c: Fix misplaced #endif /* HAVE_DB */ that was breaking the gui for networked AGWPE. 2007-09-04 13:09 we7u * src/db.c: Changing the new variable "i" to "ii" to make it easier to search for in the sources, plus getting rid of the declaration for the case where we're not using an SQL database (to get rid of a compiler warning). 2007-08-31 05:20 gstueve * src/map_geo.c: Add subroutine to release memory consistently for exit points. 2007-08-28 16:16 we7u * scripts/PigLatin.pl: Updated one comment. 2007-08-28 15:32 we7u * scripts/PigLatin.pl: Initial commit. 2007-08-24 06:44 gstueve * src/igate.c: Push active groups through the gateway between RF<->INet. 2007-08-24 06:42 gstueve * src/: messages.c, messages.h: Export group_active for use in igate of group transmission list. 2007-08-22 08:42 gstueve * src/alert.c: Make sure to test against initialized data. 2007-08-20 20:10 chicoreus * src/db.c, src/db_gis.c, src/db_gis.h, src/interface.c, src/interface_gui.c, src/main.c, symbols/symbols.dat: Cleaning up db_gis code. Some cleanup of error messages. Moved some debugging messages into debug_level & 1. Altered simpleStation table structure to add three more columns: alter table simpleStation add column origin varchar(9) not null default ''; alter table simpleStation add column record_type varchar(1); alter table simpleStation add column node_path varchar(56); These seem necessary for recreating DataRow records out of simpleStation database records. Added more testing and handling of data that is to be written to database records. Still needs better sanitizing. Tested saving DataRow records derived from internet feeds to MySQL (old), and Postgresql(8)/Postgis records. 2007-08-20 12:22 we7u * src/main.c: Adding two casts to (int *) back in. They are required to get rid of compiler warnings with some versions of GCC. 2007-08-17 15:08 gstueve * src/: map_WMS.c, map_cache.c, map_geo.c, map_tiger.c: Make sure to free allocated memory after we are done playing with it. 2007-08-16 12:28 gstueve * src/main.c: Make sure colors are identified as Pixel not int types. 2007-08-16 12:26 gstueve * src/list_gui.c: Make sure SL_scroll is initialized for full operation. 2007-08-16 10:36 gstueve * src/map_geo.c: Make sure we return the exception data to free space when done. Don't leave it as unclaimed uggage. 2007-08-16 10:01 gstueve * src/list_gui.c: Make sure the station_list displays give back the memory after they are done playing with it. They are not expected to lose it. 2007-08-15 10:57 gstueve * src/draw_symbols.c: Pixel values are 'unsigned long' not 'int' on 64 bit machines. 2007-08-15 10:41 gstueve * src/: main.c, main.h, xastir.h: Type of colors & trail_colors is Pixel, not int. Especially on 64 bit machines. 2007-08-15 08:44 we7u * src/map_cache.c: Backing out this change as it caused this error and Xastir to blow up when a new map image was cached to disk: "glibc detected *** double free or corruption" 2007-08-14 09:41 we7u * src/util.c: Adding a minor comment. Thanks to Gerald Stueve for re-examining all this code. He's doing a WONDERFUL job of finding/fixing bugs! 2007-08-14 09:28 we7u * src/: db_gis.c, db_gis.h: Adding the RCS ID tag and tweaking the copyright statements to show correct dates and attribution for these two files. 2007-08-13 13:23 gstueve * src/main.c: Clear entire block of appshell, not just first pointer space. 2007-08-13 13:22 gstueve * src/x_spider.c: No need to have extra layer of callback, go directly to exit. 2007-08-13 12:55 gstueve * src/x_spider.c: Allow the subprocesses to cleanup and exit on interrupt. 2007-08-13 12:54 gstueve * src/rac_data.c: Make sure we aren't checking against unitialized data. 2007-08-13 09:17 tvrusso * README.MAPS: Add the answer to a frequently asked question about TIGER/Line 2006 SE shapefile zip files ("what's the difference between the Polylines and Polygons directory?"). 2007-08-11 19:00 chicoreus * src/: db_gis.c, db_gis.h: Simple schema insert added for Postgresql/postgis. Tested with Postgresql 8.2 and postgis 1.2.1. Simple station records can now be written to MySQL and Postgresql/Postgis databases, but xastir can't yet extract any data back. 2007-08-10 16:15 gstueve * src/util.c: Make sure to initialize string before testing fixed offset values. Valgrind identified the dereferences with errors. 2007-08-10 16:11 gstueve * src/map_cache.c: Valgrind again. Make sure to release memory after using it. 2007-08-10 16:09 gstueve * src/db.c: More valgrind identified errors. Make sure to initialize tested variables. 2007-08-10 15:48 gstueve * src/x_spider.c: Add clear_proc_title to clean up environment pointers. 2007-08-10 07:06 gstueve * src/x_spider.c: valgrind is our friend. Make sure not to step back too far for line end. 2007-08-09 13:12 gstueve * src/map_shp.c: Make sure to Destroy a region before overwriting the value. Identified by valgrind. 2007-08-09 07:07 gstueve * src/wx_gui.c: change to newer function - item = XmStringCreateLtoR(temp, XmFONTLIST_DEFAULT_TAG); + item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); to replace deprecated function. 2007-08-08 08:29 we7u * src/interface.c: Moving one of the SQL debug printf's inside an #ifdef block so that we won't normally see it. 2007-08-07 18:55 chicoreus * src/: db_gis.c, db_gis.h: Change to error handling in the event of an xastir coordinate for a station that doesn't translate to a valid lat/long - returns error message indicating conversion problem rather than as database problem. 2007-08-07 13:33 gstueve * src/map_pdb.c: Allow more granularity for debugging actions. Remove unneeded global definitions. 2007-08-07 10:29 chicoreus * src/interface_gui.c: Removing some unecessary debugging messages. 2007-08-07 09:24 chicoreus * src/: interface.c, interface_gui.c: Bug fix - SQL database interface definitions were always being placed as interface 0 in the interface list. 2007-08-07 09:08 we7u * src/interface.c: Adding "#ifdef HAVE_DB" around the SQL database interface type so that it doesn't appear in the list unless configure finds that we have support for it. 2007-08-07 09:05 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding the SQL Database string to the other language files. 2007-08-07 08:31 we7u * src/messages_gui.c: Commenting out an unused variable which causes a compiler warning. 2007-08-07 08:31 we7u * src/interface_gui.c: Adding "#ifdef HAVE_DB" around a couple of fprintf's. 2007-08-06 18:06 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/db.c, src/db_gis.c, src/db_gis.h, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c, src/messages_gui.c, src/util.c, src/util.h, src/xa_config.c: Further work on sql server (MySQL/Postgis) support. Began integration of sql connection management with interface UI. Able to create a connection to a MySQL database, and on starting it, save list of all current stations to a simple single table db. Code still needs substantial work before it is usable. 2007-07-30 10:13 we7u * INSTALL: Updating libgeotiff instructions for latest released version (1.2.4). 2007-07-27 08:55 we7u * README.Getting-Started: Adding another note explaining that "internal" on the Shapelib summary line is ok. 2007-07-27 08:48 we7u * README.Getting-Started, configure.ac: Getting rid of the "Building with" text on the configure summary line. Fixing one of the README's to match. 2007-07-25 08:53 we7u * INSTALL: Revising the install instructions for the optional Shapefile utilities to correspond to the current sources. 2007-07-25 08:45 we7u * src/shapelib/contrib/: dbfcat.c, dbfinfo.c, shpcat.c, shpcentrd.c, shpdxf.c, shpfix.c, shpgeo.c, shpinfo.c, shpproj.c: Adding includes necessary for warning-free compiles. 2007-07-25 08:45 we7u * src/shapelib/contrib/.cvsignore: Adding shpproj executable to CVS ignore. 2007-07-25 08:37 we7u * src/shapelib/: Makefile_shapelib_orig, shpcreate.c, shpdump.c, shprewind.c: Added shprewind.c to the "clean" target of the original Makefile. Added stdlib.h includes to some of the utilities to get a clean compile. 2007-07-25 08:10 we7u * INSTALL: Adding instructions for compiling some of the optional Shapelib utilities and contributed Shapelib utilities. 2007-07-23 09:58 we7u * src/db_gis.c: Moving the strtof test below the config.h include. 2007-07-23 08:58 tvrusso * configure.ac, src/db_gis.c: Fix up usage of strtof for systems that are so old they don't have this function. 2007-07-18 09:20 we7u * src/db.c: Correcting a spelling error in a debug statement. 2007-07-16 07:38 chicoreus * INSTALL: Fixing typo in install documentation. Patch from Jim Tittsler - jtittsler Tracker: [ 1695864 ] INSTALL typo ImageMagick->GraphicsMagick 2007-07-14 20:39 chicoreus * src/main.c: [no log message] 2007-07-14 20:37 chicoreus * src/: Makefile.am, db_gis.c, db_gis.h, lclint.script: Framework for spatial database support. Should compile, but won't do anything yet. 2007-07-14 20:33 chicoreus * acinclude.m4, configure.ac: Adding tests for MySQL, Postgresql, and Postgis for spatial database support 2007-07-09 20:03 tvrusso * README.MAPS: Fix up mistaken information about TIGER/Line data. Update pointers to geocoding files (we were still pointing users to the 2003 data, which is a poor match to recent TIGER/Line shapefiles). 2007-07-06 15:43 we7u * configure.ac: For the summary, we now refuse to display the developer section unless one of those options has been enabled. This is so normal users don't have to worry about that section. 2007-07-06 15:06 we7u * configure.ac: More additions to the summary output. 2007-07-06 14:32 we7u * configure.ac: Changing some of the summary text. 2007-07-06 12:24 we7u * src/main.c: Bumping up the size of the Help->About "Libraries Used" string. 2007-07-06 12:17 we7u * configure.ac: A few more small tweaks to the configure summary output. 2007-07-06 12:04 we7u * configure.ac: Reformatting the configure summary output. Adding wget/libcurl to the summary as well. 2007-07-02 16:43 tvrusso * configure.ac: Remove hack to use external rtree library --- differences between GRASS's rtree library and ours make it so that we can't use them interchangably. The difference is in the size of floating point variables used in the Rect structure (we use floats as did the original author, GRASS uses it modified to have doubles, which vastly increases memory usage for no real gain). This should remedy all of the Fedora users problems. Unless it doesn't. 2007-07-02 16:37 tvrusso * src/: map_shp.c, shp_hash.c, rtree/card.c, rtree/card.h, rtree/index.c, rtree/index.h, rtree/node.c, rtree/rect.c, rtree/split_l.c, rtree/split_l.h: Turns out that putting a suffix on all symbols in the rtree library was very simple and fast, so I Just Did It. This should probably fix the problem for Fedora users with GDAL installed from repository, once I remove the "external rtree" bit from configure.ac. 2007-07-02 15:08 we7u * FAQ: Adding a section to the Map Problems/Solutions question about deleting the Xastir user directory and starting over when all else fails. 2007-07-02 14:34 we7u * FAQ: Added some debugging instructions for maps not working. 2007-07-02 14:19 we7u * FAQ: Updating the version number where "APX" is quoted. 2007-07-02 12:34 we7u * FAQ: Added a question/answer about how to solve the problem: station trail not displaying. 2007-07-02 12:12 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the ALTNET box so that it is smaller and has a label. 2007-07-02 05:55 tvrusso * src/rtree/: split_l.c, split_l.h: Undo the CoverSplit->l_CoverSplit change made last week. The real issue was that some repositories have a GDAL that includes GRASS libraries including a libgrass_rtree that duplicates the rtree functionality. Xastir's rtree library is precisely the one that GRASS uses (based on public domain (i.e. uncopyrighted) software from www.superliminal.com), and this leads to a link conflict that produces an obscure and cryptic error message at link time. Renaming the CoverSplit variable was just a band-aid that was suggested for a trial run while diagnosing the problem, not a recommended fix. 2007-07-01 21:20 tvrusso * configure.ac: Add a note at the end that tells whether we're using external rtree (e.g. from GDAL) or our own internal version. 2007-07-01 21:12 tvrusso * configure.ac: Fix configure so that it checks for the presence of RTreeSearch in other libraries before it builds our own rtree library. This is necessary because some repositories have a GDAL that was built with GRASS support (against current recommendations), and that brings in an rtree library unbidden. The result of trying to link our own in unconditionally is a cryptic message about CoverSplit not being relocatable. The only testing I've done is that this doesn't break builds with GDAL that has no GRASS support. I am unable to test it in the case for which it is intended. I'll have to ask that someone with an F7 system do that. 2007-06-29 13:22 we7u * src/rtree/: split_l.c, split_l.h: Trying a rename of CoverSplit to l_CoverSplit to see if this fixes the Fedora linking problem. 2007-06-21 12:10 we7u * src/interface.c: Removing stale lockfiles when it was our own process group which created them earlier. 2007-06-20 09:25 we7u * src/map_geo.c: Adding a few comments to the code for the new transparent color linked list functions. 2007-06-20 09:18 we7u * README.MAPS: Tweaking the TRANSPARENT note to state that multiple lines may be used. 2007-06-20 09:11 we7u * WMSRadar.geo, src/map_geo.c: Commenting out debug fprintf plus adding another black and a white color as transparent colors to WMSRadar.geo. 2007-06-20 08:42 we7u * src/: main.h, map_WMS.c, map_geo.c, maps.h: First attempt at multiple TRANSPARENT support for .geo files. Not fully tested yet, but doesn't appear to fall over either. 2007-06-15 11:44 we7u * scripts/LSB-BUILD: Updating to latest rev number for release. 2007-06-10 09:53 tvrusso * scripts/get-NWSdata: Update get-NWSdata to pull down the new files instead of trying to get some old and now non-existent files. 2007-05-28 16:59 chicoreus * src/: main.c, main.h, objects.c: Disabling close polygon item on CAD menu when not in draw mode. 2007-05-28 12:53 tvrusso * src/util.c: Fix a comment about multiline length. 2007-05-28 12:51 tvrusso * src/: db.c, util.c, util.h: Make the add_comment function stop stripping leading spaces. This is to allow multiline objects with no leading text, which otherwise get broken. Add a makeMultiline function to util.c. Given arrays of lat/lon pairs, will produce a multiline string representing that array and a centroid value that can be used for creating an object. Bunch of debugging output added to extract_multipoint that I needed to help me track down why my multilines were disappearing (it was because of the leading space stripping). Nobody is calling makeMultiline yet. It could be used for transmitting CAD objects if someone wanted to hack that in. I've tested makeMultiline in an external program to generate strings, then created objects by pasting the strings into the comment box of the create object dialog. 2007-05-21 07:51 tvrusso * README.MAPS: Update the TIGER/Line information. 2007-05-09 10:36 tvrusso * config/: Makefile.am, tgr2shppoly_2006.dbfawk: Add a new DBFAWK file for the 2006 TIGER/Line data. This data has "UACU" and "URCU" fields instead of the RS_A15 and RS_A16 fields that older TIGER/Line data had. 2007-05-04 13:18 we7u * help/help-English.dat: Added a note stating that all PHG values must be specified before Xastir will transmit the values. 2007-05-02 13:58 we7u * src/interface.c: Checking the result code, providing more info on why an "open" failed. 2007-05-02 12:54 we7u * configure.ac, scripts/BUILDRPMS: Setting up for the next devel release. 2007-05-02 12:14 we7u * ChangeLog, configure.ac, scripts/BUILDRPMS, scripts/LSB-BUILD, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for stable 1.9.0 release. 2007-04-27 09:55 tvrusso * src/db.c: Cast the time_t value to (long int) before passing to fprintf. On some systems (e.g. FreeBSD) time_t isn't a long, and using a %ld format for it generates a warning. On other systems, time_t *is* a long int and using a %d format generates a warning. So punt: cast to (long int) and use %ld. This should make all those systems shut up with their warnings. 2007-04-27 06:52 we7u * src/db.c: Changing some debug printf's from %d to %ld for printing some time variables. 2007-04-27 06:47 we7u * src/db.c: Changing some printf's to %ld instead of %d for some debug time printouts. 2007-04-27 06:45 we7u * src/db.c: Adding a missing "void" in a function header. 2007-04-27 06:44 we7u * src/database.h: Adding a missing "void" in a function declaration. 2007-04-20 10:03 we7u * FAQ: Added some debugging instructions for the missing "xastir.rgb" file and/or other files upon Xastir startup. 2007-04-16 11:17 tvrusso * src/: database.h, db.c: More debugging code to look into bug #1698474 Add a "dump_time_sorted_list" method and calls to it so we can actually view the entire time sorted list as soon as the sanity check fails. Also reduce the debugging expire time from 1 hour to 5 minutes. 2007-04-12 08:40 we7u * FAQ: Adding a link to the timing slider dialog screen capture. 2007-04-11 10:33 we7u * FAQ: Added section 4.28 describing the problem with missing labels on the Configure->Timing dialog. It also describes what the labels should be. 2007-04-09 08:20 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2007-03-31 12:49 tvrusso * src/: database.h, db.c: Add some sanity checking to the EXPIRE_DEBUG logic. I am still seeing that every few weeks my xastir run starts to have stations that should have expired 10 days ago, but still has 'em. This really screws up the ALOHA calculations. This sanity checking just goes through the entire time-sorted list and checks to see if any stations are older than the expire time, and does this immediately after the expiration is processed. The sanity checking only happens when EXPIRE_DEBUG is defined. The expire code assumes that the list is sorted by time, and stops when it finds a station newer than the expire time. If the list is somehow getting corrupted and no longer properly sorted, that would explain the behavior I'm seeing. I still haven't found the problem, but this should at least tell me if the list management has a bug or not. 2007-03-22 10:05 gstueve * scripts/fcc-get: Sort only on callsign. Don't use following fields. 2007-03-13 07:55 gstueve * scripts/fcc-get: Actually use web instead of older ftp server to get fcc data. 2007-03-13 07:32 gstueve * scripts/fcc-get: Make sure not to get rid of an old fcc data file if unable to get replacement file. 2007-03-07 21:17 tvrusso * src/: database.h, db.c: Change "check_station_remove" and "check_message_remove" to take a time_t for curr_time instead of an int. time_t's are what's passed in, so let's keep it consistent. I do not believe this has anything at all to do with the fact that my xastir instance isn't deleting stations on the 1-day cycle I ask it to --- on my system a time_t and an int are the same size, and time_t is defined as an int32, not an unsigned or anything. But it's still the right thing to do. 2007-03-06 13:58 we7u * src/map_geo.c: Getting rid of a compiler warning when we compile with ImageMagick. 2007-03-06 11:31 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c, maps.c: Changing the path to the GraphicsMagick api.h file to match what we're currently compiling against. 2007-03-06 11:30 we7u * scripts/LSB-BUILD: Forcing the use of GraphicsMagick instead of ImageMagick, per the newer command-line flags we use for Xastir's configure. 2007-02-27 15:19 gstueve * src/bulletin_gui.c: Move display update until after the new data is posted to list. 2007-02-27 13:33 gstueve * src/alert.c: Keep trying to clear out old data for new messages. 2007-02-24 14:08 gstueve * src/wx_gui.c: Make sure updating Wx Alert List doesn't crash because selected item was replaced by unselected item. 2007-02-22 08:29 we7u * INSTALL: Adding "ldconfig" invocations for GM/IM installs. 2007-02-22 08:14 we7u * INSTALL: Changing the command-line options for configuring GraphicsMagick to something a bit simpler. 2007-02-22 07:26 gstueve * src/alert.c: Compressed Wx alerts are precisely 3 elements long. 2007-02-22 07:20 gstueve * src/: alert.c, util.c: Really, really take care of NWS_ message from Thailand. Remove stale compressed weather alerts from consideration. 2007-02-21 08:47 gstueve * src/util.c: Fix error case from Thailand station sending message to NWS_ about 80th birthday anniversary of King. 2007-02-21 08:02 gstueve * src/db.c: Make conditional look like what it is (a for loop, not simple while). 2007-02-16 20:11 gstueve * src/db.c: Make sure debug_level is tested as BitWise value NOT logical value. 2007-02-16 13:01 we7u * INSTALL: Grammar error. Fixed. 2007-02-16 12:22 gstueve * src/main.c: Fixed [ 1553641 ] Zoom Error (Integer Math?). Increment by 1 for 10% zoom-out when less than zoom level 10. 2007-02-16 11:48 we7u * scripts/get-NWSdata: Updating the script to snag the latest-latest files. 2007-02-16 11:48 we7u * src/map_geo.c: Getting rid of a compiler warning having to do with the wrong size specified in an printf. 2007-02-16 11:48 we7u * INSTALL: Adding GraphicsMagick instructions. 2007-02-16 09:05 we7u * scripts/LSB-BUILD: Moving the defines for the REV and FILENAME near the top. Deleting old xastir-lsb-*.bz2 files before we start so that we don't upload old files each time. 2007-02-15 08:41 we7u * README.Getting-Started: Adding a comment about how to test audio file playing from the command-line. 2007-02-14 07:20 we7u * src/maps.c: Adding more comments. No code changes. 2007-02-13 12:22 gstueve * src/maps.c: Make sure all sides of the box are checked, not just three of them. Also make sure if an alert is not on screen clear it off. 2007-02-13 07:30 we7u * src/interface_gui.c: Changing the defaults for new internet connections to: rotate.aprs.net, port 14580, filter "m/500", reconnect enabled. 2007-02-13 05:21 gstueve * scripts/fcc-get: Update script to retrieve Canadian callsign data from new location. I had not gotten a new update from previous location since September, 2006. 2007-02-09 22:52 we7u * README.Getting-Started: Adding an entry for the new "Home" key function. 2007-02-09 22:49 we7u * src/main.c: The "Home" key now centers the map on your station's position. 2007-02-09 19:31 we7u * src/map_geo.c: Changing back to the original path for the Toposerver images. The problem was fixed on findu's end. 2007-02-09 19:04 we7u * src/map_cache.c: Commenting out one assignment (not used) which causes a compiler warning on some systems. 2007-02-09 18:24 we7u * Davis/README: Fixing an errant path in the instructions. 2007-02-08 13:02 we7u * src/map_geo.c: Hopefully a tweak that will help make online Toporama maps work again in the future. Have to wait for Gerry to look at the server configuration before we'll know for sure. 2007-02-06 12:30 we7u * src/maps.c: Casting some long int results to int's. 2007-02-06 08:24 we7u * src/maps.c: A fix for the UTM/MGRS major grid lines not appearing. 2007-02-06 06:55 we7u * scripts/inf2geo.pl: Updating the script to use GraphicsMagick's "gm" program. If not found, try ImageMagick's "identify" program. If that not found, output an error message suggesting that one or the other be installed. 2007-02-06 06:14 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing "MGRS" label to "MGRS2". When it was implemented they were calling the two available ones "MGRS-Old" and "MGRS-New". Now "MGRS-New" is called "MGRS2" and there's talk of an "MGRS3" soon... 2007-01-27 10:41 tvrusso * configure.ac: re-enable check for the X Printing Extension library. Apparently this is needed by libXm and some systems do not properly bring in the indirect dependence through the dynamic loader. It would probably be better to detect that condition than just blindly checking for Xp (which we don't use). Regardless, it should never be necessary to install development headers for libXp just to build xastir, which was what one user was confused about and which led me to remove the check in the first place. 2007-01-24 13:19 tvrusso * configure.ac: Remove probe for the X Printing Extension library. Xastir doesn't use it, and there's no point probing for it. Someone was confused into thinking they needed to install it on Ubuntu 6.10 because configure said it couldn't find the library. They don't, coz we don't use it. 2007-01-16 07:15 we7u * scripts/LSB-BUILD: We now remove /opt/Xastir/* during the build so that we get a clean tar file, plus dates have been added to the filename. 2007-01-13 19:57 we7u * src/messages_gui.c: We now check whether Lesstif is compiled in and skip doing the dynamic widget thing on the Send Message dialog if so. 2007-01-12 11:52 we7u * src/messages_gui.c: Another LSB/Lesstif tweak, plus making sure we fill in the history on Send Message dialogs brought up through the new "Show Pending Messages" menu entry. 2007-01-12 10:39 we7u * src/maps.c: Changing strcasestr to strstr for Cygwin compatibility. We don't really need case-insensitive matching there anyway. 2007-01-12 09:13 we7u * acinclude.m4: A fix for the GraphicsMagick/ImageMagick problem where GM is not on the system but Xastir tries to compile with it. 2007-01-12 08:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/messages.h, src/messages_gui.c: Adding a "Show Pending Messages" menu option to the Message menu. This one looks through the outgoing queue and brings up a Send Message dialog for each current QSO. 2007-01-09 09:33 we7u * src/messages_gui.c: Another couple of tweaks to keep Lesstif from segfaulting with the LSB compile. 2007-01-08 13:47 we7u * src/xa_config.c: Updated some comments. No code changes. 2007-01-08 13:21 we7u * src/messages_gui.c: Fixes to prevent segfaults with LSB-Xastir. It appears that Lesstif cannot currently handle removing/adding widgets to an already-realized dialog without segfaulting. Here we stick with the default one-long-input-field if we're compiling for LSB. 2007-01-05 12:20 we7u * src/db.c: Moved the code which _only_ depends on search_station_name() higher in the Station_data() function so that the dialog doesn't get drawn if not needed. 2007-01-05 12:00 we7u * scripts/LSB-BUILD-ALL: Switching back to Lesstif-0.95.0 as 0.94.4 didn't improve things. 2007-01-05 11:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/maps.c: Fixing the print properties dialog so that it only comes up if "gv" is detected. Getting rid of gv-specific options on the command-line when "gv" is not being used as a print-previewer. Adding a couple of strings to the language files. 2007-01-04 12:28 we7u * scripts/LSB-BUILD-ALL: Changing some comments. No code changes. 2007-01-04 10:12 we7u * scripts/LSB-BUILD-ALL: Switching from Lesstif-0.95.0 to 0.94.4 for a while to see if the resulting binary is more stable. 2007-01-03 11:38 we7u * symbols/Makefile.am, symbols/symbols.dat, src/rtree/Makefile.am, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h, src/Makefile.am, src/alert.c, src/alert.h, src/awk.c, src/awk.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/database.h, src/datum.c, src/datum.h, src/db.c, src/dbfawk.c, src/dbfawk.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/geo-client.c, src/geo-find.c, src/geo.h, src/geocoder_gui.c, src/gps.c, src/gps.h, src/hashtable.c, src/hashtable.h, src/hashtable_itr.c, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/io.h, src/lang.c, src/lang.h, src/leak_detection.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/main.h, src/map_WMS.c, src/map_cache.c, src/map_cache.h, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/objects.c, src/objects.h, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/rpl_malloc.c, src/rpl_malloc.h, src/shp_hash.c, src/shp_hash.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/testawk.c, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/x_spider.c, src/x_spider.h, src/xa_config.c, src/xa_config.h, src/xastir.h, src/xastir_udp_client.c, src/shapelib/Makefile.am, src/shapelib/contrib/Makefile.am, config/24kgrid.dbfawk, config/Makefile.am, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GDAL, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB, scripts/Makefile.am, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-NWSdata, scripts/get-gnis, scripts/get-maptools.sh, scripts/get_shapelib.sh, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, LaCrosse/Makefile.am, LaCrosse/README, LaCrosse/bootstrap.sh, LaCrosse/configure.ac, LaCrosse/src/Makefile.am, LaCrosse/src/defs.h, LaCrosse/src/open2300db2APRS.c, callpass/Makefile.am, callpass/callpass.c, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am: Updating Copyright info. 2006-12-29 18:35 we7u * src/maps.c: Moving a new variable declaration above statements in the function. 2006-12-29 10:57 we7u * src/maps.c: Moving many of the error messages to pop-up dialogs for the user-instigated print and print preview functions. We also now allow a previewer other than "gv" to be used, although we're still passing gv-specific parameters to it (something more to fix). 2006-12-29 10:10 we7u * src/: maps.c, xa_config.c: Added #ifdef's for GV_PATH and LPR_PATH so that we compile ok on systems which don't have these two utilities. 2006-12-28 23:27 we7u * src/maps.c: More changes to printing. Printing direct should be functional now. 2006-12-28 22:37 we7u * src/: maps.c, maps.h, xa_config.c: Revising the new printing code a bit more. Now saves/restores the printer and previewer paths from file plus allows the user to change them. More to do yet. 2006-12-28 16:14 we7u * src/: main.c, maps.c, maps.h: A start towards having a separate dialog for printing or print previewing/printing. Not complete yet, but shows the direction I'm heading. 2006-12-20 18:51 we7u * acinclude.m4: Removing the libdb-5.0 options. 2006-12-20 16:04 we7u * acinclude.m4: Fixing the variable save/restore code for the GraphicsMagick and ImageMagick tests. 2006-12-19 22:54 we7u * scripts/get-maptools.sh: Adding checks for "wget", "gtar", "bsdtar", "tar", and "gunzip". The script will attempt to configure to the set of utilities that are available. If the proper utilities cannot be found the script will exit before downloading any files. 2006-12-19 17:38 we7u * scripts/get-maptools.sh: Searching for GNU tar before continuing with the script. 2006-12-19 13:45 tvrusso * src/map_shp.c: Remove unused variable to silence warnings. 2006-12-19 13:39 tvrusso * src/: main.c, map_shp.c, util.c, util.h: A tiny addition: make sure we always write out a valid ".prj" file to go with any of the shapefiles we create (currently, that's GPS downloads and saved APRS tracks). Doing so makes sure that tools other than Xastir that use the .prj file to determine the coordinate system of a shapefile will know what's in there. This includes OGR's projection transformation tools, the QGIS GIS data viewer, and other GIS software such as GRASS or (ugh) ESRI products. It is a cardinal sin to create GIS data that doesn't tell you what coordinate system it's in. Strike one dark stain from our souls. 2006-12-18 23:31 tvrusso * configure.ac: Switch default for rtree from no to yes. It will now build as long as shapefile support is building, unless explicitly disabled. Disabling rtree now requires "--without-rtree". 2006-12-18 13:09 we7u * xastir.spec.in: Forcing ImageMagick over GraphicsMagick, as that is what is supplied with SuSE. Also enabling rtree. 2006-12-18 13:09 we7u * xastir-min.spec.in: Forcing ImageMagick over GraphicsMagick for this package, as that's what is supplied with SuSE. 2006-12-18 11:45 we7u * acinclude.m4: Removing "/opt/lib" and "/opt/bin" for OSX search paths as these are not used by DarwinPorts/MacPorts. 2006-12-18 11:35 we7u * acinclude.m4: Simplifying the ImageMagick and GraphicsMagick tests, but adding extra search paths when configuring on OSX. Adding more libdb paths to the search paths for that library. 2006-12-18 11:30 we7u * configure.ac: Commenting out some warnings regarding ImageMagick and GraphicsMagick: This info is self-evident in the configure output now. 2006-12-16 22:55 we7u * scripts/get-maptools.sh: Taking out the hard-coded path to "tar". 2006-12-15 12:56 we7u * acinclude.m4: Adding searches for ImageMagick and GraphicsMagick in "/opt/local/bin" (OSX DarwinPorts). 2006-12-15 12:53 we7u * configure.ac: Correcting the GM/IM logic, adding comments. 2006-12-15 10:32 tvrusso * config/Makefile.am, config/stored_track.dbfawk, src/map_shp.c: Add a Label field to the dbf file created by the "Store Track" feature when shapelib is available. Add a dbfawk file so that stored tracks can be rendered properly even if they aren't in the GPS directory. Users can customize presentation of the stored track by copying the global dbfawk file to the directory with the shapefile, giving it the same basename as the shapefile, and tweaking it as needed. This should allow more convenient use of the maps created by storing tracks than the method that based rendering on the file name and directory. 2006-12-15 09:43 we7u * src/main.c: Reversing the order of the HAVE_GRAPHICSMAGICK/HAVE_IMAGEMAGICK #ifdef's. 2006-12-15 08:06 we7u * acinclude.m4: Reformatting a couple of lines. No code changes. 2006-12-14 22:02 tvrusso * src/map_shp.c: Fix of my previous fix to the GPS vs. DBFAWK issue. Somehow I managed to get it to ignore the fact that the file was in the GPS directory even when there *WAS* no dbfawk file. The problem was that I tested for the non-nullness of "sig_info" after sig_info was filled in with a default signature's pointer. Needed to put the test before that default case. 2006-12-14 13:22 we7u * configure.ac: Giving up for now on skipping the wget tests if libcurl is found. Also moved "rtree" out of the experimental category, putting it up with the other regular options (above the dashed line in the summary). 2006-12-14 12:17 we7u * scripts/LSB-BUILD: Added a comment. 2006-12-14 12:17 we7u * acinclude.m4, configure.ac: Removing the tests for "cat" and "cp". Tweaking the "wget" code a bit more (but still not skipped if libcurl is found first). 2006-12-14 12:15 we7u * src/: main.c, objects.c: Using the new copy_file() function instead of /bin/cp. 2006-12-14 12:14 we7u * src/: util.c, util.h: Added copy_file() function written by Adam Hahn, AI4QB, and contributed to the public domain. We've modified it from his initial code so any bugs are our fault. 2006-12-14 09:06 we7u * acinclude.m4: Commenting out the code which checks for the "cat" command. We don't use it anywhere in our code. 2006-12-13 21:34 we7u * acinclude.m4: Fixing some errors I introduced with the last commit. 2006-12-13 21:02 we7u * acinclude.m4: Improvements in the ImageMagick and GraphicsMagick detection. 2006-12-12 22:50 tvrusso * src/: main.c, map_shp.c: Make DBFAWK trump the gps_flag. This means that if a file is in the GPS directory and there is a DBFAWK file to go with it, the DBFAWK file controls the rendering. It is still the case that if there is NO dbfawk file, or if DBFAWK is not enabled, the hard-coded GPS stuff (i.e. fixed width and line style, color taken from file name) is used. Also, change the dbfawk file created upon GPS download to match the style that the hard-coded GPS stuff would use. 2006-12-12 22:46 we7u * acinclude.m4, configure.ac: A few tweaks to the GraphicsMagick/ImageMagick tests. 2006-12-12 19:06 we7u * acinclude.m4, configure.ac, src/objects.c, src/xa_config.c, src/xastir.h, src/maps.h, src/maps.c, src/main.c, src/map_WMS.c, src/map_geo.c, src/map_tiger.c: Changes to allow using GraphicsMagick library and "gm convert" in place of the ImageMagick library and "convert". Xastir will now prefer GraphicsMagick over ImageMagick if both are present on the system. 2006-12-12 09:57 we7u * scripts/: LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Updating some comments. 2006-12-12 08:38 we7u * scripts/LSB-BUILD: Enabling the Festival client to be compiled into LSB. This has a couple of small downsides: 1) The user will get a "cannot connect to Festival" message on start up if they haven't installed/run the festival daemon, and 2) If anything else is running on localhost TCP port 1314 Xastir may try to talk to it. The upside is that installing/running a Festival daemon will work with the LSB binary to produce speech. 2006-12-12 08:36 we7u * acinclude.m4: Removing define for FESTIVAL_PATH. We don't use this in our code, plus if we chose to later it'd make another external dependency that'd need to be solved for the LSB distribution. I believe this was originally added in case we wished to call the festival binary directly instead of doing a TCP connection to the festival daemon on port 1314. 2006-12-12 07:49 we7u * README.win32, acinclude.m4, src/wx_gui.c: Getting rid of our dependence on the "/usr/bin/finger" external executable. It's been replaced by our own TCP/IP finger code. This is used for fetching the NOAA weather text from "wxsvr.net". 2006-12-12 06:35 we7u * src/db.c: Comment correction. 2006-12-11 12:39 we7u * scripts/LSB-BUILD: Cleaning up the lsbappchk calls. 2006-12-11 12:38 we7u * LICENSE: Minor changes to comments. 2006-12-11 09:22 we7u * scripts/LSB-BUILD: A minor change to the flags for lsbappchk. 2006-12-10 20:19 tvrusso * src/main.c: Change the "display_level" value in the stuff output as a dbfawk file for downloaded gps tracks. The value that was there was absurdly low. 2006-12-08 21:02 we7u * scripts/LSB-BUILD-XPM: We don't appear to need a separate libXpm so deleting the build script for it. 2006-12-08 21:00 we7u * scripts/LSB-BUILD-ALL: Removing the libXpm build as we're picking it up automatically from somewhere else now that we've enabled the header files for it. 2006-12-08 20:56 we7u * LICENSE: Removing libXpm license as we don't appear to need to include a separate libXpm anyway. We're already picking it up from LSB or from Motif or something. 2006-12-08 13:48 we7u * scripts/LSB-BUILD-ALL: Putting the XPM build one step later. 2006-12-08 13:16 we7u * scripts/LSB-BUILD-ALL: Adding a comment about libXpm. 2006-12-08 13:14 we7u * scripts/LSB-BUILD-ALL: Adding libXpm build to the script. 2006-12-08 13:12 we7u * scripts/LSB-BUILD-XPM: An LSB build script for libXpm. 2006-12-08 13:11 we7u * scripts/LSB-BUILD: Adding libXpm instructions for the LSB build. 2006-12-08 13:10 we7u * configure.ac: Adding libXpm to the LSB build. Needed for Snapshots and Printing. 2006-12-08 13:09 we7u * LICENSE: Adding the license for libXpm. 2006-12-08 12:16 we7u * scripts/LSB-BUILD: Copying "gm" from GraphicsMagick into our LSB build. 2006-12-08 12:15 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Installing "gm" utility as well (that's where we can get to "convert" in GraphicsMagick). 2006-12-08 12:14 we7u * src/main.c: Restarting the Xastir binary no matter where it was configured to be installed. 2006-12-08 12:13 we7u * configure.ac: Setting defines for Xastir paths. We can use them in the C-code to do things like restart ourselves. 2006-12-08 12:12 we7u * acinclude.m4: Setting up to be able to do Printing and Snapshots with the LSB version. 2006-12-08 12:12 we7u * INSTALL: Documenting the depending on Xpm for Printing and Snapshots. 2006-12-08 08:04 we7u * src/wx_gui.c: Fixing up the finger code for fetching NOAA weather alert text. We now pipe STDERR to STDOUT so that we can see any errors in the dialog. The syntax is shell-specific so we perhaps need a better way to do it. The syntax used should work for SH or BASH shells, and I think Korn shell, but not for CSH? We also now use HAVE_FINGER defines to enable/disable the actual finger call in the code. 2006-12-08 06:58 we7u * LICENSE: Changing some comments. 2006-12-08 06:45 we7u * src/wx_gui.c: Using the new FINGER_PATH that we now put into config.h via acinclude.m4. 2006-12-08 06:44 we7u * acinclude.m4: Adding a search for the "finger" binary. 2006-12-07 12:22 we7u * xastir-lsb.spec.in, scripts/LSB-BUILD: Changing install location for LSB-like (non-certified) version from /opt/lsb-xastir/ to /opt/Xastir/ 2006-12-07 12:09 we7u * xastir-lsb.spec.in: Changing the install location from /opt/lsb-xastir to /opt/xastir. We don't have (and probably will never request/pay for) LSB compliance. 2006-12-07 11:58 we7u * Makefile.am, xastir-lsb.spec.in: Adding more docs to the install locations. 2006-12-07 11:49 we7u * scripts/: LSB-BUILD-ALL, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Adding a comment which states we do NOT have LSB compliance. 2006-12-07 11:48 we7u * xastir-lsb.spec.in, scripts/LSB-BUILD: Adding a comment which states that we do NOT have LSB-compliance. 2006-12-07 11:47 we7u * LICENSE: Documenting the licenses for the optional libraries that we might distribute with an Xastir statically-linked binary. 2006-12-07 11:47 we7u * COPYING.LIB.LESSTIF: Adding the license file for Lesstif, for the case where we're distributing an Xastir statically-linked binary. 2006-12-07 09:33 we7u * configure.ac, scripts/LSB-BUILD, scripts/LSB-BUILD-ALL, scripts/LSB-BUILD-CURL, scripts/LSB-BUILD-DB, scripts/LSB-BUILD-GRAPHICSMAGICK, scripts/LSB-BUILD-JASPER, scripts/LSB-BUILD-JPEG, scripts/LSB-BUILD-LESSTIF, scripts/LSB-BUILD-PCRE, scripts/LSB-BUILD-PNG, scripts/LSB-BUILD-ZLIB: More changes to the LSB Xastir build and the LSB build for the optional libraries. We now install the libraries in /opt/lsb-tmp/ and then compile Xastir statically against the libraries there, via symlinks from the /opt/lsb/include/ and /opt/lsb/lib/ directories. 2006-12-06 11:46 we7u * scripts/: LSB-BUILD, LSB-BUILD-CURL, LSB-BUILD-DB, LSB-BUILD-GDAL, LSB-BUILD-GRAPHICSMAGICK, LSB-BUILD-JASPER, LSB-BUILD-JPEG, LSB-BUILD-LESSTIF, LSB-BUILD-PCRE, LSB-BUILD-PNG, LSB-BUILD-ZLIB: Minor tweaks for LSB compiling. 2006-12-06 11:45 we7u * scripts/LSB-BUILD-ALL: An one-stop-shopping script to build the optional libraries under LSB before we compile Xastir under LSB. 2006-12-05 12:45 we7u * src/main.c: Correcting one comment. 2006-12-05 06:43 we7u * scripts/LSB-BUILD: Removing the gdal symlinks from the comments as we've handled them in configure.ac/acinclude.m4 instead. Xastir will look for gdal in /opt/lsb-gdal/lib and /opt/lsb-gdal/include directories. 2006-12-05 06:42 we7u * configure.ac: Removing "(Experimental)" from the LSB summary line. Changing "lsb" to "LSB" which is more proper. 2006-12-04 11:52 we7u * scripts/LSB-BUILD-GDAL: Adding a commented-out option. No effect to the code. 2006-12-04 09:51 tvrusso * src/shapelib/contrib/: doc/shpproj.txt, tests/shpproj.sh: Just noticed that I never cvs added these two files from the shapelib distribution. Since we are currently distributing the whole shapelib distribution with unmodified license, it is necessary to include all of the whole shapelib distribution. 2006-12-04 09:30 we7u * scripts/LSB-BUILD-GDAL: Initial attempt to get GDAL compiled under LSB. Not functional yet. 2006-12-04 09:29 we7u * scripts/LSB-BUILD: Added a couple of steps to create the .tar.bz2 file and transfer it to the download site. 2006-12-04 08:27 we7u * src/util.c: Enabling CURLOPT_NOSIGNAL option to libcurl if the libcurl version supports it. This prevents segfaults for the case where we get a DNS timeout when initiating a libcurl transfer. 2006-12-03 14:01 we7u * scripts/LSB-BUILD: Changes in comments for GDAL compiling under LSB. GDAL is not working yet though for LSB. 2006-12-03 13:58 we7u * configure.ac: Enabling GDAL library for LSB compile. 2006-12-03 13:54 we7u * src/util.c: Enabling another curl option if compiling w/LSB. 2006-12-03 13:50 we7u * src/track_gui.c: Adding a comment. 2006-12-01 13:47 we7u * configure.ac: Changing some of the text to GraphicsMagick when doing LSB compiles. 2006-12-01 13:47 we7u * USRadar.geo: Changing the black value to match the LSB GraphicsMagick. 2006-12-01 13:38 we7u * src/: map_geo.c, maps.c: Updating some messages to include GraphicsMagick. 2006-12-01 13:27 we7u * scripts/: LSB-BUILD-DB, LSB-BUILD: Adding Berkeley DB to the LSB build to enable map caching. 2006-12-01 12:47 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Enabling PNG in the build. It works now. 2006-12-01 12:46 we7u * scripts/LSB-BUILD: Updating the build comments. 2006-12-01 12:21 we7u * scripts/LSB-BUILD-JASPER: An LSB build script for the Jasper library, to give us jpeg-2000 support in GraphicsMagick. 2006-12-01 12:20 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: Making jpeg images work for us. 2006-12-01 11:34 we7u * scripts/LSB-BUILD: Updating some comments. 2006-12-01 11:32 we7u * configure.ac: GrahicsMagick-LSB changes. 2006-12-01 09:49 we7u * scripts/LSB-BUILD-GRAPHICSMAGICK: A build script for GraphicsMagick under LSB. 2006-12-01 09:48 we7u * scripts/LSB-BUILD: Adding GrahicsMagick support. 2006-12-01 07:49 we7u * scripts/LSB-BUILD-PNG: Adding an LSB build script for the libpng library, needed for GraphicsMagick or ImageMagick. 2006-11-30 21:05 we7u * scripts/LSB-BUILD-CURL: Adding an LSB build script for libcurl. 2006-11-30 21:03 we7u * scripts/LSB-BUILD: Updating the notes. 2006-11-30 21:01 we7u * configure.ac: Enabling libcurl for LSB. 2006-11-30 13:20 we7u * scripts/LSB-BUILD: Updating the comments. 2006-11-30 13:15 we7u * scripts/LSB-BUILD: Adding pcre and dbfawk to the LSB build script. 2006-11-30 13:14 we7u * scripts/LSB-BUILD-PCRE: An LSB build script for the PCRE library. 2006-11-30 12:33 we7u * scripts/LSB-BUILD: Adding some comments. 2006-11-30 12:04 we7u * scripts/LSB-BUILD-LESSTIF: Adding a commented out command which is useful to see what will be installed without actually installing anything. 2006-11-30 12:04 we7u * scripts/LSB-BUILD: Modifying build to include geotiff and proj support. 2006-11-30 12:03 we7u * scripts/: LSB-BUILD-JPEG, LSB-BUILD-ZLIB: Adding scripts to build libjpeg and libz under LSB. Needed for geotiff support. 2006-11-30 12:02 we7u * configure.ac: LSB mods for geotiff. 2006-11-30 09:26 we7u * scripts/LSB-BUILD: Adding libproj to the mix. It is LSB-compliant. 2006-11-27 08:35 we7u * scripts/LSB-BUILD: Adding rtree to the LSB build. 2006-11-27 08:19 we7u * scripts/LSB-BUILD-LESSTIF: Changes to comments. 2006-11-27 08:18 we7u * scripts/LSB-BUILD: Updating to match my current working copy of the file. 2006-11-27 08:17 we7u * xastir-lsb.spec.in: Updating to match my current copy. 2006-11-27 08:06 we7u * src/map_geo.c: Adding an LF to one warning message. 2006-11-24 11:57 we7u * configure.ac: Adding the RPM spec file for LSB. 2006-11-24 11:51 we7u * xastir-lsb.spec.in: Inital attempt at an RPM spec file for LSB. Not complete yet. 2006-11-24 11:46 we7u * xastir-min.spec.in, xastir.spec.in: Correcting the "Source" line in the header so the version number comes out right. 2006-11-22 11:48 we7u * scripts/LSB-BUILD-LESSTIF: Updating comments. 2006-11-22 11:46 we7u * scripts/LSB-BUILD: Stripping the executables created, adding some more comments. 2006-11-22 11:30 we7u * scripts/LSB-BUILD-LESSTIF: Updating the notes at the top to show the SUCCESSFUL way of compiling Lesstif against LSB. 2006-11-22 11:27 we7u * scripts/LSB-BUILD: Updated to show latest LSB build method. 2006-11-21 07:52 we7u * scripts/LSB-BUILD: Updating the comments. 2006-11-21 07:35 we7u * scripts/LSB-BUILD-LESSTIF: Adding more comments at the top. 2006-11-20 15:37 we7u * scripts/LSB-BUILD-LESSTIF: Adding a comment, commenting out a currently-unused line, and enabling shared libs to be created. 2006-11-20 15:33 we7u * scripts/LSB-BUILD: Adding a comment plus commenting out a currently-unused line. 2006-11-20 15:17 we7u * configure.ac: Another LSB mod. 2006-11-20 14:52 we7u * scripts/: LSB-BUILD, LSB-BUILD-LESSTIF: Preliminary scripts for building LSB-compatible Lesstif and Xastir. They're not fully functional yet. 2006-11-20 14:50 we7u * scripts/fcc-get: Fixing the RCS tag. 2006-11-20 10:31 we7u * src/shapelib/Makefile.am: Updating the Copyright year. 2006-11-20 10:24 we7u * scripts/fcc-get: Changing the RAC portion of the script to match their current server configuration. 2006-11-19 14:05 tvrusso * README.win32: Another tiny update to README.win32 to bring it up-to-date with the reality of today's cygwin and sync with the Wiki HowTo:Windows page. 2006-11-19 14:00 tvrusso * README.win32: Fix up another little issue with this document. I'm doing this piecemeal, because I'm finding things as I'm editing the same information on the Wiki, and want this file to be consistent with that. 2006-11-19 13:56 tvrusso * README.win32: Fix up a little error in the "building shapelib from source" section. It referred to a "_reent" error when really it was about the error involving "__getreent". 2006-11-19 13:34 tvrusso * README.win32: Add note about preferring internal shapelib support unless the external is needed for something other than xastir. This should cut down on our "How do I get around this error message..." support questions from new Cygwin users. 2006-11-17 07:45 kg4ijb * ChangeLog: [no log message] 2006-11-17 00:53 tvrusso * scripts/get-maptools.sh: Found yet another annoying issue with libgeotiff build on ubuntu (and probably anywhere where gcc 4 is used). The problem is that the official tarball has the modification times of configure.in newer than configure, and a makefile that regenerates configure whenever it's older than configure.in --- and then runs it with no arguments. Since we need to run configure with some arguments, that completely messes everything up. Add a "touch configure" command to the commented-out part of the script that makes configure newer than configure.in and bypasses that part of the Makefile. A kludge upon a kludge upon a kludge. I missed this subtlety because when I finally tracked down the "ld -shared" issue, it was in a dirty directory -- one that had already had configure regenerated and which therefore no longer had the broken timestamps. 2006-11-16 21:31 tvrusso * scripts/get-maptools.sh: Add commented-out fix for GCC 4.x issues with libgeotiff. Not uncommenting them, because it might be wrong on some platforms that don't use GCC at all. 2006-11-16 20:13 tvrusso * scripts/get-maptools.sh: A number of small fixes to the get-maptools script: 1) Make sure $XASTIR_TMP exists before trying to download files into it 2) Fix a typo (LDCONf_FILE vs. LDCONF_FILE) 3) Update version of gdal to 1.3.2 (1.3.1 does not compile in recent GCC) 4) Build geotiff before gdal, since gdal will use the libgeotiff if it finds it. 2006-11-16 09:12 we7u * Makefile.am: Getting rid of the symlink I recently added which pointed from /usr/local/share/xastir/doc to /usr/local/doc/xastir. Near as I can tell we're fairly well FHS-compliant now with Xastir. 2006-11-15 12:11 we7u * Makefile.am: Forcing the removal of the old $prefix/share/xastir/doc directory and creating a symlink to the new location. 2006-11-15 11:49 we7u * Makefile.am, xastir-min.spec.in, xastir.spec.in: Moving the doc files to an FHS-compliant directory. For a user installing from sources they'll get installed in "/usr/local/share/doc/xastir/" instead of the old location of "/usr/local/share/xastir/doc". 2006-11-15 08:45 we7u * Makefile.am, xastir-min.spec.in, xastir.spec.in: Changing the man page directory from $prefix/man to $prefix/share/man, per FHS-2.3 and LSB-3.1 2006-11-15 07:50 we7u * xastir-min.spec.in: Changing "--without-shapelib" to "--with-internal-shapelib" to take adantage of the new shapelib library we include with Xastir. 2006-11-15 07:48 we7u * .cvsignore: Adding two derived files back in. 2006-11-15 07:47 we7u * xastir-min.spec, xastir.spec: Put these files into CVS by mistake. They are derived files. Silly me. 2006-11-15 07:08 we7u * scripts/BUILDRPMS: Changing the "minimum" description to include building with internal Shapelib. 2006-11-15 07:08 we7u * .cvsignore: Updating for current list of files. 2006-11-15 07:07 we7u * xastir-min.spec, xastir.spec: Adding the spec files that I've been using. I'm surprised that they weren't added before, but I had added them to my .cvsignore file and so didn't notice. 2006-11-14 13:30 we7u * src/shapelib/dbfopen.c: The last revision also commented out an unused variable that I forgot to mention in the cvs log. 2006-11-14 13:28 we7u * src/shapelib/: shpopen.c, shptree.c: Commenting out some variables that give off compiler warnings. 2006-11-14 13:28 we7u * src/shapelib/dbfopen.c: Casting a couple of variables to int's to get rid of compiler warnings. 2006-11-14 12:58 we7u * README.Getting-Started: Adding missing command-line options to the docs. 2006-11-14 12:42 we7u * src/xa_config.c: Changing some default settings, useful for first-time users of Xastir to see what more of the options might be plus give them a good operational starting point. 2006-11-14 12:09 kg4ijb * ChangeLog: [no log message] 2006-11-14 11:52 we7u * configure.ac: Fixing up the Shapelib config options. 2006-11-14 11:52 we7u * xastir.1: Updating the man page a bit. 2006-11-14 08:28 we7u * configure.ac: Changes to make it obvious in the configure output text and in Help->About that we're using the internal Shapelib. This change doesn't affect summary.log. 2006-11-14 07:41 we7u * src/main.c: Putting a newline in front of the Motif version string in Help->About. 2006-11-14 00:19 tvrusso * configure.ac: Fix the "-I" flag in CPPFLAGS when local shapelib is being built. As it was, the compiler would not find the local shapefil.h file unless you were building in the actual xastir source code directory, or if shapefil.h was already installed system-wide. Noticed this while attempting a fresh build on a brand new laptop, on which I'd decided to attempt the simplest possible build, with no shapelib installed. 2006-11-13 11:46 we7u * README.Getting-Started: Added notes about the private copy of Shapelib and when it might be used, the "wget" requirement for the get-NWSdata script, putting in a callsign when initially starting Xastir, and a list of various places to get Xastir help. 2006-11-13 11:43 we7u * README.win32: Mentioning the private Shapelib version and when it might be used. 2006-11-13 11:43 we7u * README.MAPS: Mentioning "wget" as a requirement for get-NWSdata. Mentioning the private install of Shapelib. 2006-11-13 11:41 we7u * INSTALL: Adding info about the alternate method of getting Shapefile support. 2006-11-13 07:10 tvrusso * README.Contributing: Fix up a mistake in the description of "build directories", and add a reference to that technique to an earlier section that advocates doing all the builds in the source directory. Build directories are such a powerful tool for developers, we should make sure we recommend it when talking about doing multiple builds. 2006-11-13 06:56 tvrusso * README.win32: Attach a date to qualify the meaning of "latest" in the ImageMagick section. 2006-11-13 06:48 tvrusso * src/Makefile.am: Add a testawk_LDADD line to src/Makefile.am so that this test program can link if shapelib is not installed. I have no idea why this didn't fail when I was testing the shapelib addition. 2006-11-13 06:25 we7u * README.win32: Updating the description for ImageMagick bug. 2006-11-13 06:24 we7u * src/: .cvsignore, shapelib/.cvsignore: Adding another couple of derived files to the .cvsignore file. 2006-11-12 17:36 we7u * src/main.c: Enabling default map on initial startup, plus if the callsign is "NOCALL", bring up the Configure->Station dialog. 2006-11-12 17:26 we7u * src/xa_config.c: Getting rid of many of the messages you get on startup when config file settings are missing. 2006-11-11 16:26 tvrusso * src/shapelib/contrib/Makefile.am: Add CVS revision information and copyright. 2006-11-11 16:11 we7u * README.MAPS: Adding attribution for the default map. 2006-11-11 15:46 tvrusso * configure.ac, src/shapelib/Makefile.am, src/shapelib/shprewind, src/shapelib/contrib/.cvsignore, src/shapelib/contrib/Makefile, src/shapelib/contrib/Makefile.am, src/shapelib/contrib/Makefile_orig: Add EXTRA_DIST and DIST_SUBDIRS lines so that the shapelib stuff is properly bundled when doing a "make dist" for release. The Makefile.am in the contrib directory does not actually build any of the contrib codes. That's another step for another moment. I just wanted to make sure that any make dist that is done is sure to bundle the entire shapelib directory in order to comply with the terms of the license. The "Makefile_orig" script in the shapelib/contrib directory could be used temporarily to build the shapelib tools. Ultimately, they could be built by the new makefile, but it's not really the goal of this exercise to do all that. In fact, at some point it might be reasonable for xastir's shapelib directory to contain only the files needed for building the library, but that will probably require modifying it to be under GPL instead of LGPL. That's just a matter of editing some license files, not any code. Also, removed the shprewind file from the shapelib directory. This is a linux binary that for some reason was in the shapelib source tarball I had. It should never have been added to xastir's CVS repository. 2006-11-11 15:01 we7u * Makefile.am: Adding a default map to the distribution. 2006-11-11 14:51 we7u * worldhi.map: Adding a default map. Map was created by Keith Sproul, WU2Z, and used with his permission. 2006-11-10 13:49 tvrusso * src/shapelib/.cvsignore: Add .cvsignore. 2006-11-10 13:49 tvrusso * src/shapelib/Makefile.in: CVS cleanup. 2006-11-10 13:48 tvrusso * configure.ac, src/Makefile.am, src/shapelib/ChangeLog, src/shapelib/LICENSE.LGPL, src/shapelib/Makefile.am, src/shapelib/Makefile.in, src/shapelib/Makefile_shapelib_orig, src/shapelib/README, src/shapelib/README.tree, src/shapelib/dbf_api.html, src/shapelib/dbfadd.c, src/shapelib/dbfcreate.c, src/shapelib/dbfdump.c, src/shapelib/dbfopen.c, src/shapelib/libtool, src/shapelib/makefile.vc, src/shapelib/makeshape.sh, src/shapelib/mkinstalldirs, src/shapelib/shapefil.h, src/shapelib/shapelib.def, src/shapelib/shapelib.html, src/shapelib/shp_api.html, src/shapelib/shpadd.c, src/shapelib/shpcreate.c, src/shapelib/shpdump.c, src/shapelib/shpopen.c, src/shapelib/shprewind, src/shapelib/shprewind.c, src/shapelib/shptest.c, src/shapelib/shptree.c, src/shapelib/shptreedump.c, src/shapelib/shputils.c, src/shapelib/stream1.out, src/shapelib/stream1.sh, src/shapelib/stream2.out, src/shapelib/stream2.sh, src/shapelib/stream3.out, src/shapelib/contrib/Makefile, src/shapelib/contrib/ShapeFileII.pas, src/shapelib/contrib/dbfcat.c, src/shapelib/contrib/dbfinfo.c, src/shapelib/contrib/makefile.vc, src/shapelib/contrib/my_nan.h, src/shapelib/contrib/shpcat.c, src/shapelib/contrib/shpcentrd.c, src/shapelib/contrib/shpdata.c, src/shapelib/contrib/shpdxf.c, src/shapelib/contrib/shpfix.c, src/shapelib/contrib/shpgeo.c, src/shapelib/contrib/shpgeo.h, src/shapelib/contrib/shpinfo.c, src/shapelib/contrib/shpproj.c, src/shapelib/contrib/shpwkb.c: Add shapelib as an internal library, and use it if we don't find an external one. Make a loud warning if we do so, because the result of this is that we'll have a bigger executable. This commit is bigger than it needs to be, because it includes all of shapelib, including the contrib directory. Added an automake-generated Makefile for this thing. Builds only a static library, and calls it "libshape.a" instead of "libshp.a" so that if we use ask to use the static one while there is also an external one installed, the linker doesn't pull in the shared library one unbidden. This stuff can be tested on a system with libshp installed by configuring with "--without-shapelib" I will be removing Makefile.in because it's not supposed to be in CVS. My mistake. 2006-11-09 14:34 kg4ijb * ChangeLog: [no log message] 2006-11-09 08:23 we7u * src/xa_config.c: Changing the default window size on initial startup. The minimum width/height are set up in main.c:create_appshell() anyway, so we can't reduce the window small enough to cause segfaults by doing this change. 2006-11-09 08:21 we7u * src/main.c: Changed one comment. No code changes. 2006-11-05 17:16 tvrusso * README.win32: Add information about problems with Cygwin ImageMagick. The notes in the README.win32 refer to "recent versions" of cygwin containing ImageMagick 5.5.7, which is very outdated. Current versions of Cygwin come with 6.0.4, and there are real problems due to that version being linked with Display Postscript support --- X.org stopped supporting that, and now ImageMagick doesn't work on Cygwin unless you find a few DLLs off the net. The paragraph I added here points the user at an article that explains the issue and shows two workarounds (installing the DLLs or building ImageMagick from source code instead). 2006-11-03 12:31 we7u * src/util.c: Adding a diff by Tapio Sokura, which a few comment changes by me. Thanks! This fixes the lower-case callsigns problem for internet paths. 2006-11-02 10:34 we7u * scripts/BUILDRPMS: Setting up for building RPM's for the current development version. 2006-11-02 08:03 we7u * configure.ac: Setting up for the next development source version number. 2006-11-02 06:43 we7u * configure.ac, scripts/BUILDRPMS, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Setting up to do the 1.8.4 release. 2006-11-01 06:57 we7u * config/language-German.sys: Updates by Rolf Bleher. Thanks! 2006-10-26 08:52 we7u * Davis/: configure.ac, src/db2APRS.c, src/defs.h: Tweaks by Bruce Bennett: "I fixed some issues brought out by the latest MySQL (5.0.x ver), added metric/english switch, rooted out some old bugs and made some improvement on debug messages." 2006-10-26 06:50 we7u * src/db.c: Fixing problems with Aloha circle units in multiple places. 2006-10-25 08:16 we7u * REGRESSION_TESTS: Lining up the line to match the rest. 2006-10-24 11:03 we7u * REGRESSION_TESTS: Adding another test which disables the /usr/include/magick/ directory before attempting a compile. This disables ImageMagick. 2006-10-24 11:02 we7u * src/map_geo.c: Adding another two ifdef's so that the code will compile in the case that we have XPM support but no ImageMagick support. 2006-10-11 14:39 we7u * src/db.c: Another patch by Jesse, KF4HZU. Thanks! 2006-10-05 09:11 we7u * src/db.c: Skipping any processing of lines from logfiles that begin with '#'. 2006-10-05 08:29 we7u * src/db.c: A fix for numeric overlays on base-91 packets by Jesse, KF4HZU. 2006-10-05 07:46 we7u * src/db.c: Some SKY bulletins came in that had "EMERGENCY" in the text. This caused Xastir to try to process the packets twice on order to get a position first and then pop up the emergency dialogs. Since there was no position in the packet this caused an infinite loop as Xastir passed the packet through the processing again and again. The fix is to NOT send a packet through the processing again, which will make it necessary for Xastir to receive two EMERGENCY packets if a position is not known yet for the station, but it will at least not cause Xastir to get in an infinite loop. We also skip storing any SKY packets now as they just take up memory and we never do anything further with the packets. 2006-09-27 12:23 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding US National Grid designator to the MGRS label. If in NAD83/WGS84 they are equivalent. 2006-09-25 06:24 we7u * src/main.c: A tweak by Dick Reichenbach, KC8OBZ, to split the status line into two lines when using a 640x480 display. Thanks! 2006-09-20 08:22 tvrusso * src/interface.c: Add comments to show where it is necessary to fix data_out_ax25 so that it isn't confused by leading white-space in commands. No code changes. The idea was to document what I know I need to do to fix the problem that Mike Fenske saw when the \r was added before MYCALL commands. The quick fix was not to add the \r if sending to an AX25 port, but the clean fix would be to make data_out_ax25 not care about leading white space. 2006-09-19 20:14 tvrusso * src/interface.c: What might be a less intrusive way of introducing that extra carriage return into the MYCALL line. The code for AX25 ports tries to decode the mycall line, and that decoding was getting confused by the leading \r. This quick "fix" simply checks to see if we're writing to an AX25 port, and if so, doesn't add the \r. A more correct way to fix this would be to fix the decoding of MYCALLs by data_out_ax25 so it doesn't get tripped up by the first \r. This is meant to be a quick hack to let both things work properly until I figure out how to desensitize data_out_ax25. 2006-09-19 19:55 tvrusso * src/interface.c: Removing carriage return I had put in before MYCALL sent to TNCs. The original intent was to do what was supposed to be an inconsequential extra carriage return when writing to the TNC to work around some garbled data issues that are happening on D700s. Unfortunately, some bit of code downstream of "output_my_aprs_data" is seeing the extra carriage return and screwing up. Bleah. Removing the "fix" until I figure out what is going on. 2006-09-19 09:12 chicoreus * src/list_gui.c: Removing double cast. 2006-09-19 08:58 chicoreus * src/: database.h, db.c, list_gui.c: Fixing bugs in previous commit. Added note about database.h being name used instead of db.h Previous commit email message bounced, changes were: 1) Converted hard coded MY_TRAIL_DIFF_COLOR to user configurable my_trail_diff_color and added to configuration ui and config file. 2) Linked station icon in station list to an onclick callback to center the map on the station. Included alternate callback to pop up station details window. Needs checking, as I think the callback needs to filter mouse events. 3) Added, but haven't yet internationalized display of area in acres when measuring distances/areas on the map. Needs to be generalised and linked to all the places display of an area might be desired. 2006-09-19 07:43 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/db.c, src/list_gui.c, src/main.c, src/main.h, src/xa_config.c: Three changes: 1) Converted hard coded MY_TRAIL_DIFF_COLOR to user configurable my_trail_diff_color and added to configuration ui and config file. 2) Linked station icon in station list to an onclick callback to center the map on the station. Included alternate callback to pop up station details window. Needs checking, as I think the callback needs to filter mouse events. 3) Added, but haven't yet internationalized display of area in acres when measuring distances/areas on the map. Needs to be generalised and linked to all the places display of an area might be desired. 2006-09-19 06:55 we7u * src/db.c: Removing the '*' after our callsign when injecting packets into the internet (our injection ID that we add). 2006-09-15 09:59 tvrusso * src/interface.c: Inexplicable fix for an equally inexplicable but very persistent problem. My Kenwood D700 complains loudly ("EH?") almost every time Xastir tries to set MYCALL before a posit. This commit adds a carriage return right before MYCALL is sent. For whatever reason, this eliminates the problem. Clearly, the d700 gets in some strange state where the first command sent after re-entering command mode is not recognized every time. Since a failure of MYCALL to be set before transmit can mean the wrong callsign (or NOCALL) being attached to a posit, this is potentially a significant fix. I will comment more on it in a follow-up email to the users mailing list. 2006-09-15 09:53 we7u * INSTALL: A tweak by Chip, N1MIE. 2006-09-10 18:03 we7u * src/db.c: Backing out the igate changes until they can be tested further. They appear to have broken most or all igating -> RF. 2006-09-08 17:35 we7u * src/: db.c, main.c, main.h, messages.c, messages_gui.c, popup_gui.c, track_gui.c: Implementing command-line flags for tracking a station and for disabling popups plus disabling Send Message dialogs on incoming messages. May need some more tweaking to get rid of all popups, but this should be a good start. 2006-09-08 11:10 we7u * src/db.c: Attempting to igate more types of packets to RF, for the cases where it is appropriate to do so. This should fix the directed query problem, at least when gating _to_ RF. Will look at the other case as well (gating->INET), which may not be broken. 2006-09-02 16:43 we7u * src/db.c: Adding parsing for RDF packets, with checking to make sure they really _are_ RDF packets this time. 2006-09-01 06:21 we7u * src/db.c: Added a date/timestamp to bearing/distance popup for emergency packets. 2006-09-01 06:05 we7u * src/db.c: Tweaking the processing of emergency packets (Mic_E packets and standard packets) so that the packet gets processed twice if the first time comes up with a 0.0 distance (which means an unknown distance). This often allows us to match our distance check ( < 280 miles ) the first time a packet is received, instead of having to wait for the 2nd occurrence of the packet. Also: We now bring up a popup with the bearing and distance to the emergency station if it passes our checks. 2006-09-01 04:46 we7u * src/db.c: Added another comment in the RDF section. 2006-09-01 04:45 we7u * src/messages_gui.c: Changing input focus to the first message box after sending each message. For D700 or D7 mode to make typing messages easier. 2006-08-31 14:36 we7u * src/: db.c, main.c, maps.c, maps.h, util.c, util.h: Writing wx alerts to file in the correct format now. Storing/restoring wx alerts from file. Fixed a bug in the weather alerts code where they wouldn't draw right away. 2006-08-31 14:27 we7u * src/wx_gui.c: Skipping NULL alert entries instead of returning when we hit the first one. This lets us see all of the active alerts. 2006-08-30 12:29 we7u * src/: db.c, main.c, main.h, messages_gui.c, xa_config.c: Logging for messages and weather alerts. Starting to add more buttons to the Send Message->Change Path dialog. 2006-08-30 12:21 we7u * src/Makefile.am: Putting the files in correct alphabetical order. 2006-08-30 04:38 we7u * src/db.c: This change implements the capability to receive messages that were sent to our other SSID's. We don't ack them. They cause a Send Message box to pop up like normal except there's a special note prepended to each message line stating which SSID the message was sent to. This allows us to catch messages sent to our other stations and respond to them if desired. We skip displaying these messages if the message originated from our station, as two message boxes for the same QSO is very confusing (and unnecessary). 2006-08-30 04:12 we7u * src/interface.c: Fixes for KISS mode when using "DIRECT PATH". 2006-08-29 15:34 we7u * src/: db.c, main.c: Adding context-sensitive Send Message To option to the mouse menu. 2006-08-29 15:26 we7u * src/messages_gui.c: Changing to APRHH and APHH as the TOCALLS which mean a HamHUD. 2006-08-29 15:24 we7u * src/view_message_gui.c: Making "Mine Only" take precedence over the range in the View->Messages dialog. 2006-08-29 07:31 we7u * src/messages_gui.c: Minor fixes to the Send Message changes. Tied the select_station_type capability into the New/Refresh Callsign button as well. 2006-08-29 05:15 we7u * src/xa_config.c: Checking for blank strings in config file, replacing with defaults where it makes sense. 2006-08-28 18:01 we7u * src/messages_gui.c: Fixing HamHUD-II detect and setting max size of messages to 20 for that device. 2006-08-28 16:23 we7u * src/messages_gui.c: Initial attempt to have the Send Message dialog automatically choose the HamHUD/D700/D7 settings based on the remote station. 2006-08-28 12:29 we7u * src/: messages.c, messages.h, messages_gui.c: Added Send Message formatting for HamHUD 20-character display. 2006-08-25 15:33 we7u * src/: db.c, messages.c, messages.h, messages_gui.c: Adding error messages to the Send Message dialog. Fixing directed queries. Adding D7A and D700 input modes to the Send Message dialog. Fixed a long message bug so 67-char messages can now be sent. 2006-08-25 15:24 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding some warning messages for the Send Message dialog. 2006-08-25 04:42 we7u * src/db.c: Changed the Capabilities display in View Incoming Data so that it shows my own outgoing ?IGATE? packets as well. 2006-08-25 04:25 we7u * src/messages_gui.c: Updated some comments. No code changes. 2006-08-24 16:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/messages_gui.c, src/view_message_gui.c: Implementing Station Capabilities and Mine Only options on Incoming Data dialog. Added Mine Only and interface selection options to View Messages dialog. 2006-08-24 16:29 we7u * src/popup_gui.c: Protecting popup functions from possible bad inputs. 2006-08-23 13:45 we7u * src/db.c: Implemented 120-second random delay before responding to an ?IGATE? query. Implemented the response for an ?APRS? query, including the 120-second random delay. 2006-08-23 08:53 we7u * src/main.c: Refuse to print out the measured angle for the case where we're doing on-screen measuring at zoom==1. Angles change at that zoom level. 2006-08-23 08:09 we7u * src/map_geo.c: Adding a comment about a future Terra/Toposerver enhancement: Crossing UTM zone boundaries, splitting the map fetch into two fetches. 2006-08-23 07:14 we7u * src/maps.c: Added more debug output from map_visible() 2006-08-23 07:14 we7u * src/map_geo.c: Separating "zstr" used in UTM->lat/long calls into zstr0 and ztr1. We were running into problems when we crossed UTM zones with a map. 2006-08-23 07:12 we7u * src/main.c: Added a method to have Xastir spit out coordinates in Xastir Coordinate System. Change a global variable at the top of main.c to a 1 to enable it. 2006-08-23 05:19 we7u * src/maps.c: Adding some debug statements. 2006-08-23 05:17 we7u * src/map_geo.c: Changing one comment. 2006-08-23 05:17 we7u * src/main.c: Moving reload_object_item() and Restore_CAD_Objects_from_file() from main() up into UpdateTime(). This is so that the image can be created and the global map corner variables updates first. Points were getting rejected on loading because these variables were not initialized yet. 2006-08-22 11:20 tvrusso * src/messages_gui.c: Fix the Send_message_change_path_destroy_shell function so it doesn't ever try to destroy a shell when the pointer is null. This was causing segfaults for me whenever a messaging dialog was closed, whether I'd accessed a change_path dialog or not. 2006-08-22 08:27 we7u * src/messages_gui.c: Closing the Change Path dialog if the Send Message dialog is closed. 2006-08-22 07:20 we7u * src/messages_gui.c: Setting the path and change path widgets so that they stretch properly with the dialog. 2006-08-22 07:12 we7u * src/messages_gui.c: Simplifying the Send Message dialog a bit more, taking the Reverse Path widgets out of that dialog. They still exist in the Change Path dialog. 2006-08-22 05:35 we7u * src/messages_gui.c: Minor adjustments to the widgets of the Send Message and Change Path dialogs. 2006-08-22 04:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages_gui.c: Swapping a couple of lines of widgets in the Send Message dialog. More tweaks to lang strings for Send Message and Change path dialogs. 2006-08-22 04:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages.h, src/messages_gui.c: Creating language file entries for new Send Message and Change Path widgets. Adding "Reverse Path:" labels to both dialogs. 2006-08-22 04:08 we7u * src/messages_gui.c: Changing reverse-path calculation to get rid of Q-construct and anything after it before reversing the path. 2006-08-21 19:35 we7u * src/messages_gui.c: A better Send Message dialog. More testing to be done yet, but so far it looks better than the old. 2006-08-21 18:01 we7u * src/: interface.c, messages.c, messages.h, messages_gui.c: The beginnings of a separate dialog for changing the path from the Send Message dialog. Mostly working as-is but not very pretty. 2006-08-21 09:18 we7u * src/messages_gui.c: Added some TODO comments to Send_Message(). 2006-08-21 06:58 we7u * src/popup.h: Cranking up max popups to 30. 2006-08-21 06:33 we7u * src/db.c: A fix for bug #1474401, where an auto-answer or some other message to us which doesn't have a message-ID ends up showing up in a Group Message dialog. This fix makes them appear in a Send Message dialog, plus we refuse to ack them which is correct behavior. 2006-08-21 04:44 we7u * src/main.c: Changing from a 1us delay to a 2ms delay inside UpdateTime(). Adding/ changing some comments. 2006-08-21 04:42 we7u * src/interface.c: Moving one debug line inside the data_lock block to make sure it doesn't get corrupted by another thread. 2006-08-19 15:19 we7u * src/interface.c: More correct fixes for truncation problem with new incoming data queue code. 2006-08-19 11:54 we7u * src/interface.c: A fix for the circular queue pointer problem. The read pointer was not getting advanced in the same manner around the queue as the write pointer, giving us an off-by-one error. 2006-08-19 10:42 we7u * src/interface.c: A temporary fix to the new queue code problem where it truncates the last character off the strings. 2006-08-18 14:52 tvrusso * src/map_shp.c: Remove commented-out ifndef of label-skipping code. It won't be needed. 2006-08-18 08:28 we7u * src/map_shp.c: Adding an #ifndef block for Tom Russo to play with. Currently commented out. If the block is enabled it will cause Xastir to draw every label for each polyline instead of skipping some based on zoom level. 2006-08-18 06:57 we7u * src/map_shp.c: Added some comments. 2006-08-18 04:07 we7u * src/: interface.c, interface.h, main.c: Shortening the delay at the end of UpdateTime() again to 10. Global variables for passing data from the read threads to main have been changed to a circular queue. This lets us queue up data from the read threads when we're busy drawing maps and such, then process it quickly when we're freed up. 2006-08-18 04:02 we7u * src/x_spider.c: Shortening delays so that we don't corrupt packets if we're fed them quickly by the pipe from Xastir. 2006-08-17 05:59 we7u * src/database.h: Renaming a function parameter so that it's not confused with a global variable name. 2006-08-17 05:47 we7u * src/db.c: Renaming a function parameter so that it won't be confused with a global variable name. 2006-08-15 03:38 we7u * src/map_shp.c: Patch for RTREE functionality with the new Shapefile speed mods. 2006-08-14 13:06 we7u * src/map_shp.c: Fixing an infinite loop condition that can happen if a Shapefile has points below -180.0 or above 180.0. 2006-08-14 12:38 we7u * src/track_gui.c: Changing from "sed --in-place" to "sed -i", perhaps more compatible across versions? 2006-08-14 12:34 we7u * src/track_gui.c: Fixing findu.com fetch trail function for base-91 packets w/no comment/course/speed/altitude. 2006-08-14 11:01 we7u * FAQ: Added another bit to the "remote restart" section. 2006-08-14 08:53 we7u * src/map_gnis.c: Reorganization to provide speedups. This one cuts about 50% of the time when zoomed in. 2006-08-14 08:52 we7u * src/map_gdal.c: Limiting to screen size instead of +/-32767. Added a comment about another possible optimization. 2006-08-14 05:24 we7u * INSTALL: Adding an invocation line for gprof that I use so I don't need to figure it out each time. 2006-08-14 05:12 we7u * src/: map_gdal.c, map_shp.c, maps.c, maps.h: Removing error-text parameter from map_visible_lat_lon() as we're not using it. Changed the order of checks in map_visible_lat_lon() to perhaps speed things up slightly based on which lines get his most often (gprof). Changed skip parameter for HandlePendingEvents in map_shp.c from 50 to 64, which is a power of 2 (perhaps faster?) and roughly the switchover point (via gprof) for lower CPU. 2006-08-11 16:58 we7u * src/: db.c, draw_symbols.c, map_gdal.c, map_shp.c, maps.c, maps.h, objects.c: Added dupe-checking for screen points to draw_vector and draw_point. Reduced the number of HandlePendingEvents calls we're doing inside the inner loop of map_shp.c. The end result is a speedup in Shapefile drawing. 2006-08-11 05:04 we7u * src/maps.h: Getting rid of stub for recompute_lat_lon() function which was deleted. 2006-08-11 05:03 we7u * src/: maps.c, util.c: Getting rid of duplicate code in the form of recompute_lat_long() and the global variables it populated. We have duplicate functionality in the f_NW_corner_longitude, f_SE_corner_longitude, f_SE_corner_latitude, and f_NW_corner_latitude global variables and the code that populates them. 2006-08-10 09:15 we7u * src/db.c: Took out a bit too much on one of the previous 2 or 3 revisions. Adding computation of screen coordinates back in for trail labels. 2006-08-10 09:09 we7u * src/: db.c, draw_symbols.c, map_gnis.c, map_shp.c, objects.c: Moving screen boundary checks into draw_nice_string() and removing them from lots of other places. 2006-08-10 09:08 we7u * src/maps.c: Adding a clip2d_screen() function for line-clipping to screen boundaries. Not used yet. 2006-08-10 06:01 we7u * src/maps.c: Added some sanity checking for dbfawk font_size variable. 2006-08-10 05:41 we7u * src/map_gdal.c: Added some comments. 2006-08-10 04:35 we7u * src/db.c: Changing to draw_point() instead of XDrawPoint for the vertice point drawing of tracklines. 2006-08-09 21:02 we7u * src/: db.c, draw_symbols.c, util.h, main.c, map_dos.c, map_gdal.c, map_gnis.c, map_shp.c, maps.c: Adding protection for the parameters of the XDraw* calls, making sure they don't go over 16 bits. 2006-08-09 07:56 we7u * src/draw_symbols.c: Changing the lu16 inline function to pass back the correct type and check against the correct max number. Added a bunch of comments elsewhere. 2006-08-09 07:03 we7u * src/draw_symbols.c: Limiting params to X11 drawing calls to 16-bit values. This should help prevent segfaults. We're actually limiting them more than we need to in most cases, but this should be ok. 2006-08-09 04:36 we7u * src/db.c: Added a debug line and comment. This one lets us play with/display aloha circles on startup if uncommented. 2006-08-09 04:35 we7u * src/draw_symbols.c: Fix for Aloha circle not getting drawn if it doesn't fit entirely on the screen. 2006-08-08 15:32 we7u * src/Makefile.am: A fix for a permissions problem that happens with compiledate.c every once in a while. This fix is by Dan Brown. 2006-08-08 15:30 we7u * src/draw_symbols.h: Checking in a header file that didn't get checked in with the other sources during the last commit. Dropped a couple of parameters from the draw_symbol() function. 2006-08-08 12:41 we7u * src/: db.c, draw_symbols.c: Fixed draw_pod_circle(), draw_bearing(), draw_phg_rng() and draw_DF_circle() so that they draw even when the symbol is off-screen. 2006-08-08 07:34 we7u * src/db.c: Fix for ambiguity box not getting disabled. 2006-08-08 06:05 we7u * src/maps.c: Added some comments about possible optimizations in the draw_point and draw_point_ll functions. Commented out the check against drawing long vectors to screen there as the clip2d* algorithms should take care of that for us. 2006-08-08 05:36 we7u * src/maps.c: Moving some of the functions to a different order that makes more sense. No real code changes. 2006-08-07 13:19 tvrusso * config/: 24kgrid.dbfawk, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsmzoddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, nwszoddmmyy.dbfawk, tgr2shp.dbfawk, tgr2shppoly.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: Fix broken dbffields variables in all dbfawk files. The dbfawk file is supposed to have semicolon-terminated statements. Unfortunately, the parser is busted and doesn't actually handle the case where the semicolons are omitted correctly. So, for example, BEGIN { dbfinfo="Blah:Diblah:Diblahdiblah"; dbffields="Blah:Diblah:Diblahdiblah" } winds up getting the newline-space at the end of the line added to dbffields, and thus in the list of names to be retrieved from the dbf file. This never matches the last field when applied to the dbf files, which have no such extra characters in the field names. This bug is masked by *how* the dbffields variables were actually set in the included dbfawk files: BEGIN { dbfinfo="Blah:Diblah:Diblahdiblah"; dbffields="Blah:Diblah:Diblahdiblah"} That is, since there was no newline between " and }, dbfawk didn't do the wrong thing. Unfortunately, many people have patterned their own dbfawk files after the ones in the config directory, and so this missing-semicolon deal got propagated (I am among those propagating it, as all my shape_web dbfawk files omitted the semicolon, but also put the brace right after the "). The problem only gets exposed when the user inserts a newline after the quote. This commit adds the semicolon (and a newline) after the dbffields closing quote. The real fix is to fix the dbfawk/awk parser so it doesn't let syntax errors like this slip through. 2006-08-07 12:56 we7u * src/maps.c: Renaming the window corner global variables. 2006-08-07 12:55 we7u * src/main.c: Renaming the window corner global variables. Updating some new global variables describing the SE corner in float and long format when necessary. 2006-08-07 12:53 we7u * src/: objects.c, xa_config.c, util.c: Renaming the window corner global variables. 2006-08-07 12:50 we7u * src/: location.c, location_gui.c, map_WMS.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c: Renaming the window corner global variables. 2006-08-07 12:49 we7u * src/: db.c, draw_symbols.c, xastir.h: Renaming the global variables describing the corners of the map window. Fixes for aloha circles and multipoing drawings so that they should appear if the symbol they're attached to is off-screen. 2006-08-07 06:49 we7u * src/draw_symbols.c: Getting rid of unused code. 2006-08-07 06:37 we7u * src/maps.c: Adding clipt(), clip2d(), clipt_long(), and clip2d_long() functions. These are implementations of the Liang/Barsky/Slater line-clipping algorithm. Modified draw_vector() and draw_vector_ll() to use them. Changing cutoff points for points/vectors to be consistent (+/-16000). 2006-08-07 06:33 we7u * src/db.c: Changing draw_trail() to use the draw_vector() function. 2006-08-07 06:27 we7u * src/: map_gdal.c, map_shp.c: Tweaking the pixel min/max cutoff numbers to make them consistent throughout the code. 2006-08-07 04:13 we7u * src/draw_symbols.c: Changed one comment. No code changes. 2006-08-04 07:35 we7u * src/maps.c: Changed draw_point() so that if it lies outside the screen we don't call the X11 draw routine. 2006-08-04 05:57 we7u * src/draw_symbols.c: A fix for dead-reckoning where the angle goes whacko at close-in zoom levels. 2006-08-04 04:42 we7u * src/db.c: Setting the precision rectangle sizes for our own station, whether transmit is enabled or not. 2006-08-04 04:17 we7u * src/track_gui.c: Using raw.cgi instead of rawposit.cgi to fetch packets from findu. This allows us to snag ALL packets from the station during the specified period instead of just posits. Weather, status, etc. 2006-08-04 03:55 we7u * src/db.c: Fixing the display of altnet's. Somewhere along the line we reversed it accidentally. 2006-08-03 16:32 we7u * src/db.c: Tweaking the NMEA decoding routines so that they pass back the number of digits after the decimal point. Changing the display for NMEA so that the number of digits changes the size of the "precision" rectangle. 2006-08-03 16:26 we7u * src/util.c: Fixing convert_lat_s2l() and convert_lon_s2l() so that they can handle from 0 to 6 characters after the decimal point for lat/long conversions. 2006-08-03 08:57 we7u * src/: db.c, objects.c: Fixing the problem where objects don't appear on the map after created. Also fixed transmission of objects so that if they have a course/speed the new position is sent out at the transmit interval. 2006-08-03 03:46 we7u * src/: database.h, db.c, draw_symbols.c, draw_symbols.h: The beginnings of the correct way of drawing the "precision" rectangles. Not all of the different types of packets are correctly sized yet, but many are. 2006-08-02 17:19 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Changing "precision" circles to rectangles, with the correct direction offset from the symbol for the different hemispheres. They are slightly too large at the moment, but at least of reasonable size. 2006-08-02 08:26 we7u * src/util.c: The chdir() call in log_data() appears to corrupt our "file" parameter. We don't appear to need the chdir() function call anyway, so have commented it out. We get passed the complete root-anchored path/filename as-is. 2006-08-02 05:30 we7u * src/db.c: Allowing the Station Chooser dialog to be closed without forcing the Station Info dialog to be closed. Commenting out the restore_position section in Station_data() as it isn't working correctly. 2006-08-02 04:58 we7u * src/objects.c: Changed/added some comments. No code changes. 2006-08-02 04:53 we7u * src/objects.c: Backing out the update of the Edit & Delete CAD Objects dialogs when allocating the first vertice of a new CAD Object. It's a bit confusing when the windows move on top of the drawing area when you do the first click, so I decided not to update then. 2006-08-02 04:47 we7u * src/objects.c: Updating the Edit and Delete CAD Objects dialogs at more places: *) When we create the first vertice on a new polygon *) When we hit either the Done or Cancel buttons on the Close Polygon dialog. 2006-08-01 07:49 we7u * src/: objects.c, util.c: Effectively removing the rounding code that was added on 6/21/2006. The rounding was not done properly to take into account overflow from seconds to minutes, or from minutes to degrees. 2006-08-01 05:49 we7u * src/popup_gui.c: Bumping up the min size for popup messages slightly. 2006-08-01 05:40 we7u * src/popup_gui.c: A start at fixing the problem where a popup message will come up too small on the screen and can't be resized. We now set a minimum size and don't fix the size, so it can be resized if necessary to read the message. 2006-07-31 06:42 we7u * src/objects.c: Fixed double-dash option for CAD objects. Update Edit/Erase CAD object dialogs if objects are changed. Use "" names if no actual label is selected. Commented out one message to STDERR during normal pre-defined objects processing, fixed up another message here to use get_user_base_dir() or get_data_base_dir() as appropriate. 2006-07-31 06:30 we7u * src/interface.c: Notifying the operator if emergency beacon mode is enabled but no transmits are actually occuring, for various reasons. 2006-07-31 06:28 we7u * src/messages.h: Cranking up max message windows from 10 to 25. 2006-07-31 06:27 we7u * src/main.c: Warning the user if ALTNET is enabled on startup (can be confusing when a new user sets this and then sees no stations). Setting a fixed beacon interval of 60 seconds if emergency beacon mode is enabled. 2006-07-31 06:25 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more strings for popup messages throughout the code, plus language strings for CAD Objects. 2006-07-25 07:53 we7u * src/util.c: A first attempt at snagging course/speed out of the previous posit if the last posit doesn't have it, for dead-reckoning purposes. It will only do this if the previous posit is still within the dead-reckoning timeout period. The goal here is to do dead-reckoning properly for stations which alternate GPGGA/GPRMC sentences (GPGGA don't have course/speed). 2006-07-24 12:04 we7u * src/draw_symbols.c: Removing dead or useless code. Reorganizing some of the tests where we determine whether to draw a particular symbol or attribute based on whether it is in the current view. 2006-07-24 12:01 we7u * src/db.c: Changing to setting flags in the station record when it's our station or object/item, then checking flags, instead of checking the "call_sign" or "origin" constantly throughout the code with string compares. Got rid of the second drawing iteration where we were drawing new stations to the screen _and_ to pixmap_final. We now draw to the screen and rely on the next full screen-update to do the rest. 2006-07-24 11:54 we7u * src/main.c: Fixing the -geometry flag so that it works for strings like: "-geometry -0-0" 2006-07-22 07:47 tvrusso * src/dbfawk.c: Possible fix for bug that prevents dbfawk files with a single field in the dbffields list from working unless a colon is added to the end of the list. This appears to be a very platform dependent bug, as I have never been able to reproduce the problem. But the fix is still valid --- the issue is that no null terminator is added to a field name unless a colon is found. This fix doesn't break anything, but I'm unable to verify that it actually fixes the problem reported, since I have never actually seen that problem in action. 2006-07-20 13:05 we7u * src/maps.c: Dump a couple of messages out from map_indexer() to STDERR. This makes it evident why Xastir is so busy when first started up in a fresh config directory, if there are a lot of maps present on the system. 2006-07-20 12:28 we7u * src/main.c: Nope, 50 was too slow, but 25 looks good so far. 2006-07-20 12:23 we7u * src/main.c: Slowing down the main UpdateTime() loop again. We seem to keep up with a 2.6 kernel with nexttime=50. Previously 10. 2006-07-19 07:40 we7u * src/: igate.c, interface.c, main.c, maps.c, messages.c, xa_config.c: Fixes to get rid of complete path in the config file for variables that need to change between different configs. If a user has specified a complete path (other than the default path), Xastir will honor it. If the default path is there, Xastir will shorten it so that multiple configs may use it. 2006-07-19 04:27 we7u * src/: database.h, db.c, list_gui.c, objects.c: Getting rid of many of the is_my_call() invocations, instead setting flag bits in the DataRow->flag variable to specify whether it's our callsign-SSID or whether it's an object/item owned by us. This gets rid of literally millions of string compares. 2006-07-17 17:41 we7u * src/db.c: Skip doing dead-reckoning if scale > 8000. Doing point-caching of last-point-drawn in draw_trail() to reduce the amount of drawing we do when it's the same screen pixel over and over (when zoomed out). 2006-07-17 17:38 we7u * src/database.h: Adding a new flag definition in preparation for a rewrite of the is_my_call() function. 2006-07-17 09:12 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c: Patch for bug 1522493 by Dan Brown, n8ysz: The caching "bad" files problem. It should whack things out of the cache if, for whatever reason, they're unusable. 2006-07-17 04:57 we7u * src/: main.c, xa_config.c, xa_config.h: More tweaks by Dan Brown, n8ysz: Cleaned up the get_user_base_dir() in xa_config.c to be more careful about returning complete paths. 2006-07-16 12:02 tvrusso * src/: color.c, map_geo.c: Clean up transparency code for .geo maps, removing debug output. This now works properly for 16 and 24 bit DirectColor/TrueColor displays. It is horribly broken for 8-bit displays, but as far as I can tell it was horribly broken *before* I started. On 8-bit displays the WMSRadar image doesn't even get displayed, transparent or not, before *and* after my changes. I was unable to figure out why. 2006-07-16 10:21 tvrusso * src/: color.c, map_geo.c: An interim commit of partial fixes to the transparency problem on .geo files. Mostly committing this to get it to a machine that has a display that isn't 24-bit for testing. Lots of cruft in here needs editing out after testing is complete. 2006-07-14 11:50 we7u * README.Getting-Started, xastir.1: Updates by Dan Brown, n8ysz. 2006-07-14 08:53 we7u * src/: main.c, xa_config.c: Additions/fixes to implement alternate Xastir config directories. Patch submitted by Dan Brown, n8ysz. 2006-07-13 05:10 we7u * scripts/get-NWSdata: Fixing up the domain names so that they all match (for consistency). 2006-07-12 10:47 we7u * scripts/get-NWSdata: Updating one NWS shapefile name to latest version. 2006-07-12 10:47 we7u * README.MAPS: Updating the text for NWS Shapefile names to match the NOAA website. 2006-07-12 07:24 we7u * src/draw_symbols.c: A fix for the bug where text-on-black obscure text above/below slightly due to the black background. We now separate the text by another pixel and the problem goes away. 2006-07-11 09:06 tvrusso * WMSRadar.geo: Tweak transparency value. For some time now, the actual "no reflection" value that's been coming in has been hex value 0x010101, not "0x000000". On 24-bit displays that means that the default file was displaying with an opaque nearly-black background instead of a transparent one. The actual no-reflection value returned by the WMS server has changed back and forth between 0x000000 and 0x010101 often in the history of the WMSRadar file and will probably need to be changed again some time in the future. It has been pretty consistently 0x010101 for several weeks now. 2006-07-11 07:38 we7u * src/db.c: Fixing incorrect timestamps for local station. This was causing track points to get expired immediately so that the station didn't show a track if being run with only a GPS interface. 2006-07-11 06:02 we7u * src/draw_symbols.c: Fixes for dead-reckoning 180 degree problem and for the DR arc being slightly off. 2006-07-11 05:18 we7u * src/draw_symbols.c: Removing dead code. 2006-07-11 05:06 we7u * src/draw_symbols.c: More efficient dead-reckoning code plus commenting out unused sections of code. 2006-07-11 04:41 we7u * src/draw_symbols.c: More tweaks to dead-reckoning. We now attempt to display the arc and the DR'ed trail if either the symbol or the DR'ed symbol are on-screen. Added an "if" clause to the DR'ed symbol drawing so it is only drawn when on-screen. Commented out old code that we're not using anymore. 2006-07-11 04:01 we7u * src/util.c: Another fix by Dan Brown, n8ysz. This one keeps the log files at or below the max logfile size. 2006-07-11 03:59 we7u * src/interface.c: Removing a duplicate include line. Thanks to Dan Brown for finding it. 2006-07-10 20:15 we7u * src/draw_symbols.c: Implenting DR arcs again. Problems near/at 180 degrees, but other than that it seems to work fine. 2006-07-10 10:24 we7u * src/db.c: Disabling the XtRemoveGrab() function call which causes warnings on some OS'es. I don't believe we actually need it. We'll find out for sure when more users try out this version. 2006-07-10 10:23 we7u * src/draw_symbols.c: Test code for re-enabling the dead-reckoning arc's. Not complete/correct yet, but it's a start. 2006-07-10 09:40 we7u * src/wx.c: Fixes by Mike Loebl, kb1mts, to add barometric pressure and humidity decoding to ARNE format. 2006-07-10 05:57 we7u * src/main.c: Fixing high CPU usage problems on FreeBSD, changing nexttime from 2ms to 10ms. Thanks to Carl Makin for this tweak. 2006-07-10 04:09 we7u * src/util.c: Fixes by Dan Brown, n8ysz, for Xastir bug 1518805: "Log files can fill up hard drive". We now limit a log file to about 2MB at which point we roll it over to a new filename and create a new empty file to write to. We keep up to 3 of these backup files plus the current log file at any given time, which makes for between 6MB and 8MB of data that we keep. 2006-07-07 09:10 we7u * README.Contributing: Added a section by Dan Brown. 2006-07-07 08:06 we7u * scripts/BUILDRPMS: Tweaking the rev number. 2006-07-06 09:23 we7u * src/main.c: Fixes by Dan Brown, n8ysz, for Xastir bugs 1515197 "segfault if XASTIR_USER_BASE no existing" and 1517761, "No error check on config dir mkdir". 2006-07-06 08:36 we7u * src/: main.c, track_gui.c: Fixes for the blank label problem on sliders with certain releases of OpenMotif. This relates to problems with using XtVaTypedArg within an XtVaCreateManagedWidget() function. Instead we now call XmStringCreateLocalized() before the call, and XmStringFree() afterwards. 2006-07-05 07:17 we7u * src/: Makefile.am, main.c: A patch to add compile time/date to the Help->About dialog, by Dan Brown, N8YSZ. 2006-06-29 10:04 we7u * src/xa_config.c: Making the igate -> RF path default be "WIDE2-1". 2006-06-27 07:25 we7u * src/igate.c: Reorganizing the logic slightly to make it easier to understand w.r.t. the gating of objects/items/stations to RF via the nws-stations.txt file. Added/updated several comments. 2006-06-23 09:03 we7u * src/db.c: Adding more comments. No code changes. 2006-06-23 08:31 we7u * src/igate.c: Changing igating->RF around so that if a station or object name is found in the nws-stations.txt file, it will get gated to RF whether or not "TCPXX" is found in the path. This allows more types of things to be gated to RF if manually specified in the nws-stations.txt file. 2006-06-22 05:42 we7u * src/db.c: Mostly changes to comments, but changed the error ellipses from black to white. Still need to draw truncation rectangles instead in some cases. 2006-06-21 07:49 we7u * src/objects.c: Tweaking the rounding in objects.c 2006-06-21 06:12 we7u * src/util.c: Changing some comments. 2006-06-21 05:41 we7u * src/: interface.c, util.c: Fixing up posits so that we round properly instead of truncating the higher resolution digits. For some-odd reason the fprintf doesn't round up properly at 0.5, so we add a 0.01 to the number so that it rounds up. 2006-06-21 04:51 we7u * src/db.c: Changing one comment. 2006-06-20 05:55 we7u * src/: database.h, db.c, draw_symbols.c: An attempt to do the error ellipses for position packets. This is most likely not the display we'll finalize on, but it's a start. We draw circles for the less-precise posits, but as Tom Russo pointed out they should probably be rectangles. Also, the GPGGA/GPRMC/GPGLL code needs some work w.r.t. these. 2006-06-19 14:47 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Making sure we don't try to do dead-reckoning on stations that have position ambiguity enabled. 2006-06-19 11:58 we7u * README: Adding notes for OpenSuSE 10.1 2006-06-16 13:29 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: More ambiguity fixes. 2006-06-16 12:58 we7u * src/: database.h, db.c: Correcting the spelling of "ellipse". 2006-06-16 12:08 we7u * src/draw_symbols.c: Changes to a few comments. 2006-06-16 12:06 we7u * src/: database.h, db.c, draw_symbols.c, draw_symbols.h: Adding a variable for doing error_ellipses around posits. Not in use yet. Changed the position ambiguity around so that it is correct and the symbol position inside the rectangle is correct. Still need to fix up the grid-square code in the draw_ambiguity function though. 2006-06-15 14:28 we7u * src/draw_symbols.c: Fixing up some of the ambiguity rectangle stuff. All but the grid squares look ok now, but the smallest rectangle ends up with the symbol placed off-center, which still needs to be fixed. 2006-06-15 12:46 we7u * src/draw_symbols.c: Changing from stippled ambiguity rectangles to solid lines. 2006-06-15 07:33 we7u * src/draw_symbols.c: Changing ambiguity rectangles from filled to unfilled, plus drawing lines from symbol to each corner of rectangle so we know which symbol is being drawn with the ambiguity. 2006-06-14 13:55 we7u * src/database.h: Doesn't make much sense to add the new parameter to the station database at this time when code doesn't use it. It would only take up memory. Commenting it out for now until we get to using it. 2006-06-14 13:50 we7u * src/database.h: Preliminary addition of an error_elipse storage area for the station record. Not actually used in the code yet as we're still discussing how it should best be used/displayed. 2006-06-14 07:17 gstueve * src/util.c: Only check VHF porion of path. Still need to process 2nd portion for proper behavior. 2006-06-14 07:13 gstueve * src/util.c: Only change lower case characters to uppper, don't bother to rewrite upper. 2006-06-14 07:10 gstueve * src/util.c: Fix spelling in comment. 2006-06-12 09:17 we7u * FAQ: Added "socat" to the FAQ. 2006-06-08 14:04 we7u * src/: db.c, objects.c: Changed some comments to show the last GPROF percentages for the heavy-hitters. No code changes here. 2006-06-07 07:18 we7u * config/tnc-startup.d700: Changed the comments at the top. Added note about Alinco's. 2006-06-07 07:03 tvrusso * FAQ: Update pointer to latest version of the FAQ. The URLs that were here were very outdated. 2006-06-06 12:22 we7u * src/db.c: Some packets with an extra digit in the latitude end up going through the compressed packet decode routine. This fix causes those packets to be rejected from that routine. 2006-06-05 15:01 we7u * Davis/src/db2APRS.c: Davis mods by Clay Jackson, n7qnm. Added some MySQL error checking, set it up so it would always get the 'latest' records, and generally improved the error handling (things like 0 or >100 pct humidity, pressure below 26 or above 31, and so on). 2006-06-05 12:20 we7u * scripts/get-NWSdata: Tweaking the script so that it only fetches files we don't already have. 2006-06-05 12:19 we7u * configure.ac: Bumping revision for devel to 1.8.3. 2006-06-05 11:50 we7u * configure.ac, scripts/BUILDRPMS, scripts/do_xastir_release_dev: Updating to 1.8.2 to get ready for stable release. 2006-06-05 11:43 we7u * scripts/do_xastir_release_stable: Updating default version number. 2006-06-05 10:14 we7u * README.MAPS: Added a section describing how to create your own Shapefile maps with Xastir. Added a section describing CAD Object polygons. 2006-06-05 09:46 we7u * scripts/fcc-get: Updating to match newer "sort" function's syntax. 2006-06-02 09:43 we7u * config/language-German.sys: Updates by DK7IN. Thanks! 2006-06-02 08:35 we7u * scripts/get-NWSdata: Updating to latest NOAA filenames. 2006-06-01 10:05 we7u * README.MAPS: Fixing the path for gpx2shape so that people look for it in the scripts directory. 2006-06-01 10:04 we7u * scripts/Makefile.am: Adding gpx2shape to the build. 2006-06-01 10:04 we7u * scripts/gpx2shape: A nice contribution by James Washer. Convert GPX files to Shapefiles. 2006-06-01 09:35 we7u * README.MAPS: Added a blurb about National Geographic's Topo, TPO/TPG files, mapXchange, gpsbabel, and gpx2shape.pl. 2006-06-01 07:17 we7u * README.MAPS: A bit added by Kyle Kienapfel regarding the Canada topo file. Thanks! 2006-05-31 13:39 we7u * src/igate.c: Disallowing igating of general queries in either direction. Directed queries still get gated as appropriate. 2006-05-31 13:36 we7u * src/db.c: Added some comments. 2006-05-31 12:57 we7u * src/: db.c, wx.c: Fixing the backwards conversions for wind speed for Peet Bros. Ultimeter-II weather stations. The correct units are km/h if the sentence begins with '#', and mph if the sentence begins with '*'. 2006-05-31 12:30 we7u * src/wx.c: Changes to comments/added some comments. 2006-05-31 11:39 we7u * src/wx.c: Zeroing the first two digits on wind speed for Peet Bros 2k as per the docs. 2006-05-31 11:25 we7u * src/wx.c: Changing a few variables to make the code more consistent. Instead of pointing back to the original data to check for ">7", we look at the first character of our substring temp_data1[0]. 2006-05-31 11:09 we7u * src/wx.c: Fixes for Peet weather stations, negative value decoding. 2006-05-30 13:06 we7u * src/map_gnis.c: Fixes to make Xastir handle the type of GNIS files found at: which have shorter lines than the ones at: 2006-05-30 11:50 we7u * src/interface.c: Really complicated fix for Xastir dropping the last character of a packet. A fix for the last fix I put in. 2006-05-30 09:07 we7u * src/db.c: Changed one comment. 2006-05-30 08:18 we7u * src/: database.h, db.c, interface.c, main.c: A bug fix for KISS or AGWPE ports. The AX.25 header increases in size when it gets converted to TAPR2-style headers. If there were enough digipeaters in the path then the complete packet can get truncated on the tail-end. This patch fixes it by allocating a separate buffer that is quite large for each packet before the header decoding function. 2006-05-17 12:28 we7u * src/db.c: Fixing the reply-ack problem during messaging. It was an off-by-one error. Our ack_string looked like "}5o" instead of "5o", which made the comparison fail. 2006-05-13 09:27 we7u * src/Makefile.am: Adding rpl_malloc.h to the build. 2006-05-12 13:32 tvrusso * FAQ: Add command for converting Root files to new scheme. Of course, if someone could check this file out to see the commands, they've already done the conversion... 2006-05-12 13:05 we7u * scripts/do_xastir_release_dev: Fixing a typo. 2006-05-12 13:03 we7u * install-xastir: Updating to the latest SourceForge CVS server names. 2006-05-12 13:00 we7u * scripts/: do_xastir_release_dev, do_xastir_release_stable: Updating to correspond to latest CVS server names. 2006-05-12 12:44 we7u * FAQ, README.CVS, README.win32: Updating the CVS instructions to correspond to the changes implemented today on SourceForge. 2006-05-12 12:44 we7u * config/tnc-startup.d700: Adding "HEADERLN off", which we appear to have missed at some point. 2006-05-04 08:01 we7u * README.win32: Added a note about what to call COM1/COM2 in Cygwin. 2006-04-29 10:19 tvrusso * symbols/symbols.dat: Change \V symbol (VORTAC) to something that looks like what the other APRS codes use, matching the VORTAC symbol on aviation charts. 2006-04-24 12:21 we7u * src/: alert.c, awk.c, bulletin_gui.c, color.c, datum.c, db.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, macspeech.c, main.c, map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, messages.c, messages_gui.c, objects.c, rotated.c, rpl_malloc.c, shp_hash.c, snprintf.c, sound.c, testawk.c, track_gui.c, util.c, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, xastir_udp_client.c: More fixes for rpl_malloc, plus made the callouts for config.h more consistent. 2006-04-24 10:20 we7u * src/: Makefile.am, festival.c, rotated.c, util.c, util.h: Separating out the rpl_malloc code so that it can be used in other programs like testawk. 2006-04-24 10:19 we7u * src/: rpl_malloc.c, rpl_malloc.h: Separating out the rpl_malloc stuff so that it can be used in other programs like testawk. 2006-04-21 14:01 we7u * src/db.c: Correcting spelling in one comment. 2006-04-21 13:51 we7u * src/db.c: This change clears the transmitted message so it won't get transmitted again after a REJ packet, and gets rid of a printf to STDERR for each REJ. 2006-04-21 12:58 we7u * src/db.c: Added support for REJ packets, including igating of same. Yet to be tested. 2006-04-21 12:57 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added a "*REJECT*" string for REJ packets. 2006-04-20 09:47 we7u * README.win32: A tweak by Wes Johnston for getting bootstrap.sh to run properly. 2006-04-20 08:05 we7u * src/wx.c: Reverting back to the code for version 1.54, as the rounding for negative numbers wasn't done correctly and caused more harm than good. 2006-04-20 07:22 we7u * symbols/: alert.xbm, flood.xbm, red_flag.xbm, snow.xbm, tornado.xbm, wind.xbm, winter_wx.xbm, wntr_strm.xbm: Thanks to Jason Winningham, kg4wsv, for these weather alert pics that stack up much more nicely than the originals, while leaving more of the map below visible. 2006-04-10 07:31 we7u * scripts/get-maptools.sh: Script to get/install several of the map libraries, written by Dan Brown, N8YSZ. 2006-04-05 09:13 we7u * scripts/Makefile.am: Adding two of the newer scripts into the Makefile. 2006-04-05 09:09 we7u * README.win32: A tweak by Joe Cotton to get the finger command working in Xastir/Cygwin. 2006-03-16 18:32 tvrusso * INSTALL: Put the word "shapelib" closer to the place where we explain how to install it, so it is more quickly found by a search with "less" or "grep". 2006-03-16 00:03 tvrusso * README.MAPS: Fixx mispleling. 2006-03-16 00:02 tvrusso * README.MAPS: Added a little commentary about the mrsiddecode program. 2006-03-13 17:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/objects.c: Shortening "Area" to "A" for CAD objects. Also shortening the unit descriptions. 2006-03-13 17:32 we7u * src/db.c: Refusing to do the emergency popups until/unless we have a position for a station. It's hard to help someone if we don't know where they are at. This keeps Xastir from annoying the crap out of people every 30 minutes if a posit for that station isn't coming in, but a packet with certain keywords _is_ coming in regularly. 2006-03-10 12:56 we7u * INSTALL: Added another note about libtiff-3.8.0 2006-03-10 12:45 we7u * INSTALL: Adding solution text regarding the libgdal/libgeotiff GTIFProj4ToLatLong problem. 2006-03-10 12:28 tvrusso * README.MAPS: Fix a handful of mispleellings and mistales. 2006-03-10 12:09 tvrusso * README.MAPS: Rearrange some of the discussion of how to manipulate randomly mutilated GeoTIFF files. 2006-03-10 08:16 we7u * README.MAPS: Adding a section about using gdal_translate to convert crappy geoTIFF's to usable ones. Thanks to Tom Russo for the info on how to do this. 2006-03-10 08:15 we7u * INSTALL: Slightly changing some wording in the gdal section. Nothing of importance. 2006-03-09 12:47 we7u * INSTALL: Updating various library revision numbers. Added a note about a possible geoTIFF conflict when installing GDAL. 2006-03-09 12:46 we7u * src/map_tif.c: Making sure that Proj.4 error messages appear only under the correct circumstances. 2006-03-08 18:43 we7u * src/db.c: Initial implementation of a distance check for warnings/alerts. Default is set to 280 miles or kilometers (whichever mode you are set in), and the check defaults to ON, meaning it will check each time whether the station is within that distance. This version has no user controls for the new functionality implemented yet. 2006-03-07 18:44 we7u * src/wx.c: Fixing the rounding for some of the values that can be negative, coming from weather stations. 2006-03-07 16:41 we7u * FAQ, README.Getting-Started, README.win32: Updating/Adding instructions for snagging NWS files via new script. 2006-03-07 09:56 we7u * README.MAPS: Adding filename patterns to the NWS file descriptions. 2006-03-07 09:56 we7u * scripts/get-NWSdata: Adding the fire weather zones to the mix. 2006-03-07 09:05 we7u * README.MAPS: Adding a bit about the get-NWSdata script. 2006-03-07 09:04 we7u * scripts/get-NWSdata: Modified the script to do one download/unzip/delete the .zip file, then start on the next. This will keep disk space requirements down plus not have the .zip files hanging around when we're all done. 2006-03-07 08:53 we7u * scripts/get-NWSdata: A new script to fetch NWS data files used for weather alerts. Curt, WE7U and Steven, WM5Z had a hand in writing it. 2006-03-03 12:31 we7u * src/db.c: Checking for 8-bit characters in Mic-E packets, except for the case of 8-bit telemetry extension fields where we skip the check. 2006-03-03 08:19 we7u * src/track_gui.c: Re-enabling the popup on findu track download failure, as it doesn't appear to be the source of James Ewen's segfaults when his DNS failure occurs. It appears to be a segfault from libcurl itself. 2006-03-02 14:53 we7u * README.win32: Added a note about compiling libproj into gdal statically in order to install on Cygwin. 2006-03-01 10:37 we7u * config/tnc-startup.thd7: Commenting out the hbaud line and adding a comment about it. 2006-03-01 08:30 we7u * README.Contributing: Added a note about core files appearing where you least expect them. 2006-03-01 08:02 we7u * src/track_gui.c: Adding comments near another popup message that could conceivably cause segfaults: The "Success" message from fetching a findu trail. This particular popup has worked properly for me with no segfaults so far. We may need to investigate whether multiple threads writing to X11 at the same time can cause segfaults. I believe I've seen this in other cases, but my memory may be faulty on this matter. 2006-02-28 11:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c, src/maps.h, src/xa_config.c: Checking in mods by Dalen Kruse, KC0OVU, which implement a timing slider for snapshots with a range from 1 to 30 minutes. 2006-02-28 00:01 we7u * src/track_gui.c: Getting rid of the GUI stuff in fetch findu trail: It happens in a separate thread now and we can't write to the GUI from two threads at once due to possible segfaults. 2006-02-27 13:02 we7u * src/wx.c: A fix for negative values being interpreted incorrectly due to varying sizes of INT on different systems. 2006-02-27 11:40 we7u * config/tnc-startup.thd7: Changing HBAUD to 9600 so that it matches the default serial port speed. 2006-02-24 19:01 tvrusso * src/db.c: Fix appallingly stupid mistake in passing arguments to XtVaSetValues. I coulda *sworn* I had just copied what was already there, but apparently not. This fixes the problem where the Incoming Data scrolled text widget was not scrolling to the bottom of the incoming data as new stuff was added. 2006-02-24 10:38 tvrusso * src/db.c: Complete refactor of how the "packet_data_string" stuff is updated and displayed. We no longer do "memmove" to cycle old data out of the array, but rather use a two-dimensional array of strings treated as a ring. Data is shifted out of the Display Incoming Data dialog box using XmReplaceText calls. I have tested this out in several ways and it appears to function precisely as the old one was intended to do. This *might* be the solution to the sporadic segfaults we've been seeing and the less harmful "line too long for array" warnings. 2006-02-23 16:38 we7u * src/db.c: Add a null pointer check to delete_station_memory(). Changed an "if" to an "else" clause in insert_new_station(), which just made the code slightly simpler but didn't change any operation. Multiple comment changes. 2006-02-23 16:01 we7u * src/xa_config.c: Increasing the default for Internet Map Timeout from 90 to 120 seconds. 2006-02-23 15:59 we7u * src/util.c: Adding messages something like "Possible timeout, try increasing Internet Map Timeout" to the libcurl and wget code. 2006-02-22 08:53 chicoreus * src/maps.c: Adding grid labels for UTM major grid. All grid types and resolutions now have some kind of labeling available. 2006-02-22 08:51 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added metadata text for UTM major zones. 2006-02-19 12:50 rzg * src/dbfawk.c: Small memory leak found by valgrind; I think this should fix it. 2006-02-19 12:02 tvrusso * scripts/object2shp.pl: Bug fix. Make sure to ignore comment lines in the object file, or any other lines that don't start with semicolon. 2006-02-19 11:56 tvrusso * README.MAPS: Add explanation of how to use object2shp.pl into README.MAPS under the "Rolling your own shapefile maps" section. 2006-02-19 11:48 tvrusso * scripts/: Makefile.am, object2shp.pl: Per discussion on xastir mailing list, a script to create shapefile maps from the object.log file. This will enable quick and dirty generation of special purpose map overlays by plunking down objects, creating shapefiles, then deleting the objects. 2006-02-16 21:50 we7u * src/: database.h, db.c, list_gui.c: Changing the names of pointers so that their function is more easily recognizable. 2006-02-16 12:45 we7u * src/x_spider.c: Added more output messages in case of error which suggest killing old Xastir processes in order to remove the error. 2006-02-16 12:44 we7u * src/: db.c, messages.c: Fixing up msg_data_add() so that we can tell when we've rejected a message. Tweaked the code which invokes it so that it knows the difference between new/old/rejected messages. 2006-02-15 08:46 chicoreus * src/: maps.c, maps.h: Refinements to the calculation of latitude and longitude grid spacing. Triming the latitude and longitude strings in the grid border when zoomed out. Reduced the number of variables being passed in the functions called by draw_grid() by moving them to function calls or constants. 2006-02-14 14:00 we7u * src/db.c: Initializing struct pointers to NULL right after malloc of the struct, before we try inserting it into any linked lists. 2006-02-14 13:11 we7u * src/: database.h, db.c, gps.c, igate.c, objects.c: Converting all MAX_TNC_LINE_SIZE (was 300) to MAX_LINE_SIZE (currently 512). Just simplifying things. 2006-02-14 12:07 we7u * src/db.c: Printing out ALL of the guard bands that get corrupted, not just the first one that's noticed. 2006-02-14 11:59 we7u * src/db.c: Adding a couple more guard bands, changing them to only 10 chars each, making the error text print out which guard band was corrupted. 2006-02-14 11:34 we7u * src/db.c: Making the Incoming Data display's char array manipulation code a bit less scary. It had the potential to overflow if conditions were just right, but the conditions were extremely unlikely to occur. 2006-02-14 11:33 we7u * src/interface.c: Bumping up the sizes of some char arrays. Just because. Probably don't help much, but don't hurt either. 2006-02-14 11:32 we7u * src/main.h: Removing some unused defines. 2006-02-13 12:30 we7u * src/: db.c, interface.c, interface.h, main.c: Adding guard bands around the main station pointer variables, plus code to check for intrusion into those guard bands. This may help us to find the current segfault problem. 2006-02-12 16:13 chicoreus * help/help-English.dat: Changing the grid border help to include latitude and longitude. 2006-02-12 16:10 chicoreus * src/maps.c: First cut at an algorithmic method for determining the spacing of latitude and longitude grid lines at a scale appropriate for the current window size and map zoom. 2006-02-12 10:03 we7u * src/db.c: Correcting some debug output message text. 2006-02-11 18:10 we7u * src/db.c: Doing some more error-checking in the station record pointers. We do an abort() if we end up with dangling pointers, which should give us a core dump immediately. 2006-02-10 12:27 we7u * REGRESSION_TESTS, configure.ac: Tweaks to add more regression tests and format the output so that it's easier to read. 2006-02-10 11:13 tvrusso * README.Contributing: Add a section on using separate "build directories" to maintain specialized builds rather than building in the source tree. 2006-02-09 17:08 we7u * src/maps.c: Fixes for the map grid segfault problem. 2006-02-09 15:14 tvrusso * README.Contributing: Change commentary on how to do debugging builds. 2006-02-09 14:32 we7u * README.Contributing: Adding a debugging note from Tom Russo. 2006-02-09 13:27 tvrusso * acinclude.m4: Change XASTIR_COMPILER_FLAGS so that it doesn't insert "-g -O2" unconditionally. That is unnecessary since we call AC_PROG_CC, which *conditionally* inserts "-g -O2" into CFLAGS if the user hasn't specified CFLAGS on the configure line. This should allow users to build specialized debugging versions such as ./configure CFLAGS="-O -g -fno-inline" and not have configure stick a "-O2" in unbidden. 2006-02-09 12:41 we7u * src/maps.c: A temporary fix to skip computing the UTM/MGRS grid if we run into a problem, before we segfault. 2006-02-09 12:14 we7u * src/maps.c: Adding some comments. 2006-02-09 12:12 we7u * src/maps.c: Again splitting the minor UTM grid stuff into separate functions. 2006-02-09 11:40 we7u * src/maps.c: Reorganizing the draw_grid() function. Breaking it up into smaller pieces. 2006-02-08 07:11 we7u * src/main.c: Checking for proper status of unlink in pid_file_check(). 2006-02-08 06:28 we7u * src/main.c: Removing some code that doesn't get used in the RINO download section of the switch. 2006-02-06 18:37 we7u * src/maps.c: Commenting out unnecessary code. 2006-02-06 18:33 we7u * INSTALL, README.Getting-Started, UPGRADE, update-xastir: Clarifying the use of SUID root a bit. Removing that command from update-xastir so that the default will be to create a core file. 2006-02-06 13:35 we7u * src/maps.c: Some fixes for segfaults and divide-by-zero faults in the draw_grid() function. At least one more segfault path remains in this body of code. 2006-02-06 09:03 we7u * README.Contributing: Adding more info to the debugger info. 2006-02-06 08:21 we7u * src/db.c: Tweaking Mic-E decoding logic to properly decode overlay characters. 2006-02-03 10:09 chicoreus * src/util.h: Missing an extern 2006-02-03 09:47 chicoreus * src/: maps.c, util.c, util.h: Adding MGRS to labeled grid border. 2006-02-03 09:46 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing grid metadata text to allow MGRS support. 2006-02-02 14:02 we7u * src/maps.c: Extending some char arrays so that they're long enough to hold the terminator. 2006-02-02 10:58 chicoreus * src/: main.c, maps.c, util.c, xastir.h: Added degree and minutes symbols to lat/long grid border labels by adding constants for convert_xastir_to_UTM() to produce strings containing these symbols. Truncation of trailing zeroes on UTM grid labels, with number of zeroes removed depending on utm_grid_spacing_m. Changed following feedback from use of printed maps during a GPSAR training. Added internationalization for lat/long and UTM grid border metadata. Added metadata on top border for labeled lat/long grids. Latitude drawn on both left and right borders. Put the xastir coordinate to MGRS conversion into a function that extracts the components of the MGRS string separately, then made convert_xastir_to_MGRS_str() a wrapper around this function in prepration for labeling the MGRS grid. 2006-02-02 09:57 we7u * README.Contributing: Adding info about core dumps and how to bring up a debugger. 2006-02-02 08:49 we7u * README.Getting-Started, src/main.c: Reversing the meaning of the "-t" command-line flag: The segfault handler is now turned off by default (meaning we'll dump core instead). The "-t" flag turns on the internal segfault handler now instead of disabling it. 2006-02-02 08:04 we7u * configure.ac: Commenting out the code that removed the "-g" GCC option. As Tom pointed out, it was a bad idea. 2006-02-02 07:29 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added internationalization strings for metadata line for top border of map when map grid border is displayed. 2006-02-02 07:10 we7u * src/util.c: A fix for the missing UTM grids with gcc-4.x problem. 2006-02-02 07:10 we7u * src/maps.c: Changing one debug output line. 2006-02-01 08:42 we7u * acinclude.m4: Patching the search list for Berkely DB library by adding 4.3 and 4.4 search paths. 2006-02-01 08:24 chicoreus * src/maps.c: Added border labels for latitude and longitude grid. 2006-01-31 10:32 chicoreus * src/maps.c: More tuning of labeled border for UTM grid. Added Zone number and letter in all four corners when two zones are shown. All text in border changed to black with border color outline. For two zones, northings for one zone appear on the left side of the screen northings for the other on the right. The left zone is labeled in black, the right zone labeled in blue. Minor fixes to turn off display of labels where they run off the screen. 2006-01-30 07:31 tvrusso * configure.ac, src/maps.c: "roundf", recently used in maps.c, is a newer extension that is not present in systems that still have old C compilers. Insert a check for roundf, and a workaround for systems that don't support it. 2006-01-28 11:21 we7u * bootstrap.sh: Fixing the file test syntax to use Bourne syntax instead of Bash. 2006-01-27 20:36 chicoreus * src/maps.c: Minor changes and bug fixes to the UTM grid border labeling code. Includes rounding of the grid labels to correctly label 10,000 m, 1,000m, and 100m grids, not just the 100m grid. 2006-01-27 15:40 chicoreus * src/: maps.c, rotated.c: Added code to RotatedTextItem in rotated.c library to handle special case of rotation of text 90 degrees counter clockwise. In this case, text is rotated by directly transposing x and y coordinates, rather than by applying a sine and cosine transformation to rotate the text, something that produces an italic appearance to the rotated text (making it harder to read, especially when printed). This change is to support more legible text on the labeled UTM grid on the border of the map, especially for producing maps to be printed. Also made minor changes to border label code in maps.c to make quick and dirty improvements to appearance. 2006-01-27 08:30 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Since the three bootstrap.sh scripts are the same anyway, run the one from one directory up instead so that we don't have to keep rev'ing all three of them when a change is needed. Like, duh! 2006-01-27 08:14 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Updating for Solaris. 2006-01-27 08:10 we7u * bootstrap.sh: Removing the comment marks that I shouldn't have committed to CVS. 2006-01-27 08:05 we7u * bootstrap.sh: Updating for automake system directories on Solaris. 2006-01-27 06:57 we7u * README: Updating the SuSE 10 notes to mention libcurl-dev as well. 2006-01-26 14:51 we7u * Davis/src/Makefile.am: Installing the compiled db2APRS into the bin directory. 2006-01-26 12:57 we7u * scripts/BUILDRPMS: Getting rid of some shell warnings. 2006-01-26 12:39 we7u * Makefile.am, scripts/BUILDRPMS: Adding LaCrosse directory into the build. 2006-01-26 11:06 we7u * Davis/.cvsignore, LaCrosse/.cvsignore: Updating the list of files that CVS should skip. 2006-01-26 08:59 we7u * Davis/bootstrap.sh, LaCrosse/bootstrap.sh: Updating bootstrap.sh for separate weather apps so they are the same as the main Xastir bootstrap.sh 2006-01-26 07:55 n0vh * LaCrosse/: weatherdump.sql, src/Makefile.am: SQL file of open2300 database 2006-01-26 07:44 we7u * Davis/: .cvsignore, src/.cvsignore: Adding .cvsignore files for the Davis directories to reduce the amount of "noise" that cvs status returns. 2006-01-26 07:42 we7u * LaCrosse/: .cvsignore, src/.cvsignore: Adding .cvsignore files for these two new directories so that cvs status doesn't return too many unneeded lines. 2006-01-26 07:38 n0vh * LaCrosse/src/open2300db2APRS.c: Fixed an issue with SIGPWR on non-Linux systems 2006-01-26 07:38 n0vh * LaCrosse/configure.ac: Minor updates to compile on non-linux systems 2006-01-25 15:11 n0vh * LaCrosse/README: Minor correction to directory in BUILD section 2006-01-25 14:46 n0vh * LaCrosse/README: Changed to make it more relavent to open2300db2APRS 2006-01-25 12:34 n0vh * LaCrosse/src/open2300db2APRS.c.bak: Not needed. 2006-01-25 12:26 we7u * LaCrosse/src/open2300db2APRS.c: Fixing a warning given by gcc-4. clen must be a socklen_t instead of an int. 2006-01-25 11:52 n0vh * LaCrosse/src/: Makefile, Makefile.in, open2300db2APRS, open2300db2APRS.o: Removed files that should be in CVS 2006-01-25 11:50 n0vh * LaCrosse/Makefile.am: Put back this needed file 2006-01-25 11:49 n0vh * LaCrosse/: Makefile, Makefile.am, Makefile.in, aclocal.m4, config.h, config.h.in, config.log, config.status, configure, stamp-h1: Removed files that should be there 2006-01-25 11:36 n0vh * LaCrosse/: AUTHORS, COPYING, ChangeLog, INSTALL, Makefile, Makefile.am, Makefile.in, NEWS, README, aclocal.m4, bootstrap.sh, config.h, config.h.in, config.log, config.status, configure, configure.ac, stamp-h1, src/Makefile, src/Makefile.am, src/Makefile.in, src/defs.h, src/open2300db2APRS, src/open2300db2APRS.c, src/open2300db2APRS.c.bak, src/open2300db2APRS.o: Support for LaCrosse WX-23xx weather station support 2006-01-25 11:33 n0vh * config/: language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Update for future LaCrosse 23xx weather station support. 2006-01-25 11:32 n0vh * config/language-Dutch.sys: Updated with future LaCrosse 23xx stuff. 2006-01-25 08:46 chicoreus * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added missing "MAPFONT008|Border Labels||" to support user selectable font for drawing labels on the UTM tickmarks on the labled border. 2006-01-23 21:46 we7u * src/: maps.c, maps.h: Fixing up some function prototypes to get rid of some compiler warnings. 2006-01-23 15:47 chicoreus * config/language-English.sys, src/db.c, src/main.c, src/maps.c, src/xa_config.c, src/xastir.h: Drawing fonts with an outline on the border results in text that is very difficult to read on a printout. Added a user selectable font for drawing labels on the UTM tickmarks on the labled border. 2006-01-23 12:41 we7u * src/map_tif.c: Getting rid of dependencies on cpl_csv.h, which contains a private (not public) interface. 2006-01-23 12:02 we7u * src/: main.c, main.h: Testing for old/new kernel based on number of signals available. We then use this to decide whether to set "OLD_PTHREADS", which enables or disables the SIGUSR1 handler in the code. Old kernels only has 32 signals, therefore Linux Pthreads used SIGUSR1 and SIGUSR2 in their implementation. We use SIGUSR1 for our Snapshot-on-demand function, therefore we must disable this code if we're running older Pthreads on Linux. 2006-01-23 12:00 we7u * configure.ac, src/util.c: Testing for deprecated/new pthread functions, modifying code to correspond based on what's found. 2006-01-20 13:15 we7u * src/x_spider.c: Another small tweak for Linux Standard Base 3.0 compliance. 2006-01-20 09:58 we7u * README: Tweaked the SuSE 10 notes regarding a bootstrap.sh warning. 2006-01-20 08:52 we7u * README, bootstrap.sh: Formatting changes to bootstrap.sh. Added a section to README which details getting rid of an SuSE-10 warning when running bootstrap.sh. 2006-01-19 12:43 we7u * README: Adding a note about SuSE 10.0 and problems with AX.25 kernel mode. 2006-01-19 12:24 we7u * bootstrap.sh: Fixing a problem in Automake 1.9 (on SuSE 10 at least) where the mkinstalldir script doesn't get copied over by Automake. We have to copy it over ourselves after we invoke Automake. 2006-01-19 09:20 we7u * REGRESSION_TESTS: Updated the format a bit. 2006-01-19 09:17 we7u * src/db.c: A fix for another killer packet. This one had to do with a while loop overrunning an ack_string variable. Changed to xastir_snprintf() functions there and it solved the immediate problem. 2006-01-18 14:40 we7u * src/map_tif.c: Commenting out an include because it causes an error on Cygwin. Of course it causes a warning under gcc-4.0 on Linux when it's commented out... 2006-01-18 12:13 we7u * REGRESSION_TESTS: Updating the tests for LSB and to make them more convenient to run. 2006-01-18 09:10 we7u * FAQ: Adding some VNC configuration info. 2006-01-18 08:50 we7u * INSTALL: Updating/re-ordering the list of configure options. 2006-01-18 08:49 we7u * src/map_tif.c: Getting rid of some gcc-4.0 compiler warnings. 2006-01-18 08:49 we7u * Davis/src/db2APRS.c: Getting rid of a gcc-4.0 compiler warning about signedness. 2006-01-18 08:48 we7u * Davis/bootstrap.sh: Making the script parallel the main Xastir bootstrap script. 2006-01-18 07:31 we7u * src/interface_gui.c: Mods to comply with maximum baud rates allowed under LSB. 2006-01-18 07:11 we7u * acinclude.m4, configure.ac, src/util.c: Initial tweaks to help get Xastir compiled under Linux Standard Base 3.0 (LSB 3.0). Have more work to do to get there, but this is a good start. 2006-01-18 07:00 we7u * src/: main.c, map_cache.c: A fix for the X11 fault caused when the DB Library header/library versions don't match. The code should now just disable map caching and keep right on going. 2006-01-18 06:48 we7u * src/x_spider.c: Changing one declaration to get rid of one gcc4.0 warning. 2006-01-17 13:06 we7u * src/alert.c, src/awk.c, src/bulletin_gui.c, src/color.c, src/datum.c, src/db.c, src/dbfawk.c, src/draw_symbols.c, src/fcc_data.c, src/festival.c, src/geo-client.c, src/geo-find.c, src/geocoder_gui.c, src/gps.c, src/hashtable.c, src/hashtable_itr.c, src/hostname.c, src/igate.c, src/interface.c, src/interface_gui.c, src/io-common.c, src/io-mmap.c, src/lang.c, src/list_gui.c, src/locate_gui.c, src/location.c, src/location_gui.c, src/macspeech.c, src/main.c, src/map_cache.c, src/Makefile.am, src/map_WMS.c, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/map_tiger.c, src/maps.c, src/messages.c, src/messages_gui.c, src/objects.c, src/popup_gui.c, src/rac_data.c, src/rotated.c, src/shp_hash.c, src/snprintf.c, src/sound.c, src/testawk.c, src/track_gui.c, src/util.c, src/view_message_gui.c, src/wx.c, src/wx_gui.c, src/x_spider.c, src/xa_config.c, src/xastir_udp_client.c, AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, LICENSE, Makefile.am, NEWS, README, README.CVS, README.Contributing, README.Getting-Started, README.MAPS, README.win32, REGRESSION_TESTS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, install-xastir, update-xastir, xastir.1, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Makefile.am, scripts/Xastir_tigerpoly.py, scripts/example_objects.log, scripts/fcc-get, scripts/get-gnis, scripts/get_shapelib.sh, scripts/inf2geo.pl, scripts/ozi2geo.pl, scripts/toporama250k.pl, scripts/toporama50k.pl, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh: Updating copyright info. 2006-01-17 13:03 we7u * symbols/Makefile.am, symbols/symbols.dat, config/24kgrid.dbfawk, config/gps_wpt.dbfawk, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/tnc-startup.aea, config/tnc-startup.d700, config/tnc-startup.kam, config/tnc-startup.kpc2, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-startup.tnc2, config/tnc-startup.tnc2-ui, config/tnc-stop.d700, config/tnc-stop.sys, config/tnc-stop.thd7, config/tnc-stop.tnc2-ui, config/Makefile.am, config/nwsmzddmmyy.dbfawk, config/nwsmzoddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/nwszoddmmyy.dbfawk, config/predefined_EVENT.sys, config/predefined_SAR.sys, config/tgr2shp.dbfawk, config/tgr2shppoly.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, callpass/Makefile.am, callpass/callpass.c, Davis/Makefile.am, Davis/README, Davis/bootstrap.sh, Davis/configure.ac, Davis/src/Makefile.am, Davis/src/db2APRS.c, Davis/src/defs.h, src/alert.h, src/awk.h, src/bulletin_gui.h, src/color.h, src/database.h, src/datum.h, src/dbfawk.h, src/draw_symbols.h, src/fcc_data.h, src/festival.h, src/geo.h, src/gps.h, src/hashtable.h, src/hashtable_itr.h, src/hashtable_private.h, src/hostname.h, src/igate.h, src/interface.h, src/io.h, src/lang.h, src/leak_detection.h, src/list_gui.h, src/main.h, src/map_cache.h, src/maps.h, src/messages.h, src/objects.h, src/popup.h, src/rac_data.h, src/rotated.h, src/shp_hash.h, src/snprintf.h, src/symbols.h, src/track_gui.h, src/util.h, src/wx.h, src/x_spider.h, src/xa_config.h, src/xastir.h: Updating copyright info. 2006-01-17 12:10 we7u * scripts/BUILDRPMS: Correcting bugs that crept in. 2006-01-17 11:58 we7u * scripts/BUILDRPMS: Updating script for latest SuSE RPM build. 2006-01-17 11:47 we7u * INSTALL, README: Updating notes to call out latest packages. Adding SuSE 10.0 instructions to README. 2006-01-16 10:21 we7u * scripts/BUILDRPMS: Updating script for latest release numbers. 2006-01-16 09:12 we7u * configure.ac: Bumping version to 1.8.1 for new mods. 2006-01-16 09:04 we7u * configure.ac, scripts/do_xastir_release_dev, scripts/do_xastir_release_stable: Preparing for 1.8.0 release. 2006-01-13 07:34 we7u * bootstrap.sh: Changing the prompts a bit. We now see a countdown to completion. 2006-01-12 16:06 tvrusso * README.MAPS: Fix error in command line for sorting the EN.dat file from FCC. 2006-01-12 08:58 we7u * config/language-German.sys: Another update from Rolf. 2006-01-12 07:25 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2006-01-11 12:28 we7u * src/db.c: Processing/decoding the altitude extension on more packet types. Altitude wasn't being decoded for some weather and grid packets. It is now. 2006-01-11 12:27 we7u * help/help-English.dat: Adding some notes about lack of altitude in compressed-mode posits. 2006-01-11 07:43 we7u * src/db.c: Fixing a decoding bug w.r.t. lower-case N/S/E/W in a couple of types of packets. 2006-01-10 09:03 francais1 * config/language-French.sys: More updates from Jacques Chion, with some tweaks and translation of GPSS* strings. 2006-01-09 14:10 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM. Thanks! 2006-01-06 18:45 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing a bug on the GPS Status dialog. It wasn't reporting the correct status for WAAS. Corrected that and added more possibilities for status. 2006-01-03 13:59 chicoreus * src/db.c: Minor bugfix: Range Scale and Scale bar were drawn displaced when border was on and grid was off (even though border is only shown when grid is on). 2006-01-02 13:34 we7u * src/db.c: Fixing segfault that occurs in extract_multipoints() when data == NULL. 2005-12-31 18:38 chicoreus * help/help-English.dat: Added Documentation of Map/Enable Map Border. 2005-12-31 07:13 chicoreus * src/maps.c: Bug fixes in the labeling of utm zones, northing lines, and easting lines when the grid is labeled. When grid is finely spaced on the screen, only alternate lines are labeled. Grid and zones are labeled correctly and reasonably most of the time when more than one lettered zone row appears on the screen. Still has some problems, but works for most places. 2005-12-29 13:11 we7u * INSTALL: Added instructions for updating /etc/ld.so.conf.d/ directory for those systems that use this alternate method. Courtesy of Dale, KB9JJA. Thanks! 2005-12-20 18:01 chicoreus * src/: main.c, objects.c: Performance tuning: Moved call to redraw_symbols out of CAD_vertice_allocate to prevent repeated redrawing on each vertex of each cad object loaded from a file at startup. 2005-12-20 10:24 chicoreus * src/maps.c: In trying to work out what draw_grid is doing, added some documentation to the utm_grid structures. Added a test inside draw_grid so that the utm grid labeling code is only running for utm_grid.zone elements that contain rows and columns. 2005-12-19 10:18 chicoreus * src/maps.c: Minor bugfix and additional comments on code for labeling UTM grid. Changed format to include leading zeroes for easting and northing. 2005-12-19 09:40 chicoreus * README.MAPS: Added brief discussion of gdalinfo and gdal_translate for handling geotiff files that aren't in byte form or contain multiple bands. 2005-12-16 14:13 chicoreus * src/maps.c: Added the ability to draw a 1 pixel outline in a different color to rotated text in draw_rotated_label_text_common() and some of its wrappers. 2005-12-16 14:09 chicoreus * src/xa_config.c: Making draw_labeled_grid_border persistent between restarts. 2005-12-15 14:10 chicoreus * src/: db.c, main.c, main.h, maps.c: First cut at adding a labeled border to the map shown on the screen for printing. This can be used, for example, to print maps with a labeled UTM grid for a SAR task team showing the area they are to search. Metadata about the map is displayed in the top border, coordinates of grid lines are displayed on the bottom and right borders (to make it easier for people to correctly read and report UTM coordinates in the form zone easting northing. The labeled border is displayed when both the grid and the border are enabled. There are still problems and missing features. The rotated font on the right border is not the pretty font used on the rest of the border. The border and grid labels are only drawn for a UTM grid, not for a Lat/Lon grid. Zone designators are not properly displayed when more than one zone is visible on the screen. When grid lines are closely spaced, the grid labels overlap on the screen. 2005-12-15 10:31 we7u * README.win32: Fixing a typo. 2005-12-15 10:24 chicoreus * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: First rough cut at adding a labeled border to a map to allow the printing of arbitrary maps with a labeled grid (that can, for example, be printed and given to SAR task teams). If the map grid is enabled, and the border is enabled, a white border is drawn as part of the grid and labels for each grid line are added in this border. Metadata describing the map are also added in the border. This is a first rough cut with several problems. It is only implemented for a UTM grid, not for a Lat/Long grid. The rotated numbers do not use the same clean font as the non-rotated numbers. The labels in the border are not clearly distinguishable when the grid is tightly spaced on the screen. The zone labels do not work properly when more than one zone is on the screen. The choice of labeling the bottom border and the right border with the UTM grid line easting and northings is deliberate to help people to correctly read the map and report UTM coordinates in the form: zone easting northing. 2005-12-13 14:11 we7u * config/Makefile.am: Correcting the name of the dbfawk file that we want automatically removed. I forgot the underline first time around. 2005-12-13 07:54 we7u * src/objects.c: Tweaking a debug statement so we don't get a segfault if we hit a null pointer. 2005-12-12 18:50 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added localization strings for map display of CAD object metadata. Added update of CAD objects on toggle of display of metadata. 2005-12-12 14:56 chicoreus * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/main.c, src/main.h, src/objects.c, src/objects.h: Adding more user interface elements to CAD Object display 1) Clarifying user side handling of raw_probability as a percent 2) Allow user to set CAD boundary line type 3) Allow user to toggle on and off display of CAD Polygons, Label, Area, and probability. 2005-12-11 10:20 we7u * src/main.c: Fixing the Station->Configure submenu. Wasn't working on Lesstif but was fine on OpenMotif. Should work on both now. 2005-12-07 18:55 chicoreus * help/help-English.dat: Edited CAD object text to reflect the movement of the CAD object functions from the mouse menu to the toolbar and the View and Map menus. Added some text for Probability Circle Objects. 2005-12-07 17:04 we7u * src/interface.c: Only twiddle DTR on HSP ports if global transmit is enabled. 2005-12-07 17:02 we7u * src/objects.c: Very minor formatting change. No code changes. 2005-12-07 12:40 we7u * config/Makefile.am: Automating the deletion of the nwsfzddmmyy.dbfawk file from the /usr/local/share/xastir/config directory during install. We don't use it anymore and it causes problems if present. 2005-12-07 10:38 we7u * src/interface.c: Patch by Paul Morris, modified slightly by me, to make objects work for the case when global transmits have been disabled. 2005-12-07 09:32 tvrusso * config/: Makefile.am, nwsfz_ddmmyy.dbfawk: Remove unnecessary (and problematic) nwsfz_ddmmyy.dbfawk file. 2005-12-07 08:09 we7u * src/map_gdal.c: Moving some struct typedef's and nested functions out of the main function so that it will compile with latest MacOSX GCC compiler. 2005-12-06 22:41 we7u * src/map_shp.c: Made code more correct by changing alert->title to modified_title in a couple of places. modified_title is a copy of alert->title so the real-world effects of this change are little to none. Tweaked some comments in the area as well. 2005-12-06 19:04 tvrusso * config/nwsmzddmmyy.dbfawk: Fix incorrect key generation for mzddmmyy.shp file. The key produced by the dbfawk rule must match the key that comes from the NWS alert. These will generally be "XX_Zyyy". The "ID" field of the mzddmmyy.dbf record is of form "XXZyyy", and prior to this commit it was used directly as the key, thereby never matching any alerts. This fix inserts the _ character after the first to characters of the ID field to produce a usable key. 2005-12-06 13:35 we7u * src/map_shp.c: Added more debugging text for dbfawk and wx alerts. 2005-12-06 12:53 we7u * src/maps.c: Correcting some comments. 2005-12-06 12:50 we7u * src/maps.c: Adding a bit more text to one wx alert debug message. 2005-12-06 12:26 we7u * src/interface.c: Moving a nested function so that it is no longer nested. This is necessary in order to compile on MacOSX with their latest GCC compiler. 2005-12-06 11:34 we7u * src/util.c: Changing a nested function to non-nested in order to enable compiling with the latest MacOSX compiler. 2005-12-04 19:05 we7u * src/: main.c, xastir.h, festival.c: Adding a "Test" button to the Configure->Speech dialog for testing the speech subsystem and for adjusting the audio levels (by an external program). 2005-12-01 11:32 we7u * update-xastir: Changing the "make" step so that it doesn't run as root. 2005-12-01 09:22 we7u * src/map_gdal.c: Commenting out and include that we're currently not using. 2005-11-29 22:36 we7u * src/map_pdb.c: Implementing the same sorts of map interruption capability for PocketAPRS maps that we just did for the other types of maps. 2005-11-28 19:16 we7u * src/: map_WMS.c, map_gdal.c, map_geo.c, map_shp.c, map_tif.c, map_tiger.c: Adding more map interrupt code, to make it easier/faster to interrupt map drawing by panning or zooming. 2005-11-28 12:51 we7u * src/map_shp.c: Adding capability to interrupt map drawing and start over in the inner loops of the GNIS and DOS map drawing functions. This makes panning or zooming cause an interrupt much quicker while drawing maps, allowing Xastir to restart the redraw process sooner. 2005-11-28 12:43 we7u * src/: map_dos.c, map_gnis.c: Adding capability to interrupt map drawing and start over in the inner loops of the GNIS and DOS map drawing functions. This makes panning or zooming cause an interrupt much quicker while drawing maps, allowing Xastir to restart the redraw process sooner. 2005-11-23 14:37 we7u * scripts/do_xastir_release_stable: Adding another admin script so that it won't get lost. 2005-11-23 14:32 we7u * scripts/do_xastir_release_dev: Adding another couple of admin scripts so they won't ever get lost. 2005-11-23 14:28 we7u * scripts/STABLE: Adding another admin script to the repository so that it won't get lost. 2005-11-23 14:27 we7u * scripts/BUILDRPMS: Adding the RPM Build script so that it will be available as an example to others. 2005-11-23 11:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/map_cache.c: Disabling map caching if dblib header/library mismatch, to help prevent segfaults. Also doing a popup now when this condition is found as Xastir starts up. 2005-11-23 11:33 we7u * NWS-TEST.log: Changed some comments. 2005-11-23 11:33 we7u * README.MAPS: Added a blurb about how to test weather alert functionality. 2005-11-22 14:31 we7u * NWS-TEST.log: Added some more notes. 2005-11-22 12:49 we7u * NWS-TEST.log: Moved one OR alert over to the coast and made it blue, to stand out more against the other alerts. 2005-11-22 12:35 we7u * NWS-TEST.log: Moving all of the tests to the Northwest region so we don't have to look all over the country for them. 2005-11-22 11:57 we7u * NWS-TEST.log: Changing the colors for adjacent alerts, making it easier to differentiate between them. 2005-11-22 10:41 we7u * NWS-TEST.log: Adding a file which can be used to test out the weather alert functionality. 2005-11-18 16:36 we7u * src/map_shp.c: Fix for RED_FLAG weather alerts. 2005-11-18 12:00 we7u * src/main.c: Making more menus detachable. Splitting the toolbar buttons vertically by a few more pixels to make it look better on Cygwin. 2005-11-18 11:59 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Getting rid of a couple of unused labels, reclaiming one for the new "Draw" toolbar togglebutton. 2005-11-18 07:48 we7u * src/wx_gui.c: Changed tab to spaces. 2005-11-17 09:04 we7u * src/main.c: Adding the cad polygons list to the map->CAD Objects submenu. It still has a link in the View menu as well. 2005-11-17 08:56 we7u * src/main.c: Moving the remaining CAD Object stuff to the Map menu (from the mouse menu) 2005-11-17 07:41 we7u * src/objects.c: Changing colors of CAD Polygon labels and probability. Extending string so that it display 0.00% through 100.00% and displays the '%' sign. 2005-11-17 06:57 we7u * .cvsignore: Added make.log and xastir-min.spec 2005-11-16 22:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/objects.c, src/objects.h: Moving Draw CAD functions to main menu and toolbar. 2005-11-16 18:43 we7u * src/objects.c: Adding a cancel button to the CAD Objects detailed info dialog. Fixing the area size as listed in the same dialog. 2005-11-16 13:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing from "Erase All" to "Erase" for menu entry. 2005-11-16 13:50 we7u * src/main.c: Changing one comment. 2005-11-16 13:00 we7u * src/objects.c: Changing "Cancel" to "Close" on CAD Object list dialog. 2005-11-16 12:52 we7u * src/objects.c: Fixing CAD area labels and comments so that they get retrieved properly from file. 2005-11-16 12:19 we7u * src/main.c: Moving some items from the Map and Station menu into Configure submenus. 2005-11-16 11:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/objects.c, src/objects.h: More from Paul Morris: Allows edits of the data associated with CAD objects and moving more of the Close CAD object code into functions. It also adds localization to the delete CAD object dialog. 2005-11-16 10:08 we7u * xastir-min.spec.in, Makefile.am, configure.ac: Adding a new spec.in file which skips all of the optional libraries except for ImageMagick. 2005-11-10 14:38 gstueve * src/map_shp.c: Add test for debugging alert match to reduce noise on display. 2005-11-10 08:57 we7u * scripts/fcc-get: Yet another try to fix the Id string. 2005-11-10 08:37 we7u * scripts/fcc-get: Trying to fix Id string again. 2005-11-10 08:36 we7u * scripts/fcc-get: Fixing the RCS Id: string so that it gets populated by CVS. 2005-11-10 07:51 gstueve * src/objects.c: Use the time that was already provided. Don't bother system for it again. 2005-11-10 07:28 gstueve * src/: alert.c, alert.h, bulletin_gui.c, bulletin_gui.h, database.h, db.c, main.c, messages.c, messages.h, popup.h, popup_gui.c: Use the time that we already have from UpdateTime and not keep asking the system for it over and over again. 2005-11-10 06:59 gstueve * scripts/fcc-get: Remove the extra CR where ever possible, real OS has no need for such. 2005-11-09 06:03 gstueve * src/interface.c: Adjust error messages to describe problem in current function. 2005-11-08 21:57 gstueve * config/Makefile.am: Add old zone file dbf into Makefile list. 2005-11-08 21:44 gstueve * config/: Makefile.am, nwsmzoddmmyy.dbfawk: Add back in the old mz dbf definition. 2005-11-08 17:40 gstueve * src/maps.c: Add cancelled Alerts to list of mapped but don't draw on display. 2005-11-08 16:07 gstueve * config/nwszoddmmyy.dbfawk: Add old Zone file match for older dbf structure. 2005-11-08 11:15 gstueve * src/main.c: We already have a good idea of what time it is inside UpdateTime. It is NOT necessary to always be asking the system what time it is within one function and its support routines. This is not a '25 or 6 to 4' need. 2005-11-08 06:52 gstueve * src/: database.h, db.c, main.c: Make packet display logic much more efficient. Do it all in fewest moves. 2005-11-08 06:35 gstueve * src/map_gnis.c: Visual optimization. Make things easier to read. 2005-11-07 14:33 we7u * src/db.c: Changing comments about KISS variants. 2005-11-07 12:33 we7u * src/db.c: Changed one comment. 2005-11-07 09:04 we7u * src/main.c: Adding a NULL parameter to close out the parameter list for two XtVaGetValues() calls. 2005-11-07 06:14 gstueve * src/fcc_data.c: Optimize the use of substr so the function is MUCH more efficient. 2005-11-07 06:12 gstueve * config/: nwsmzddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: The newer shapefiles no longer have the additional fields, so system was not matching file structure. Make it match better. 2005-11-06 16:14 we7u * src/util.c: Fixing the remove_trailing_dash_zero() routine. It was changing "-10" into "-1" which is quite wrong. 2005-11-03 12:15 we7u * src/: db.c, interface.c: Making sure we don't transmit if the global disable or the individual interface disables are activated. 2005-11-02 11:01 we7u * src/db.c: Adding some notes about KISS and CRC's. 2005-11-02 07:40 we7u * src/xastir_udp_client.c: Changed length from int to socklen_t to get rid of warning messages for some compilers. 2005-11-01 13:32 gstueve * src/util.c: Go back to whining about dual-band TNC separator. 2005-11-01 11:21 gstueve * src/alert.c: Add debugging detail for unparsed alerts. 2005-11-01 11:18 gstueve * src/util.c: First cut to stop whining on dual-band TNC with WIDEn-m paradigm. 2005-10-26 21:58 we7u * src/interface.c: Truncating transmitted posits at the spec-specified length. Long comments can't make us transmit out-of-spec packets anymore. 2005-10-26 21:52 we7u * src/sound.c: Added a missing include that causes a problem on Solaris if missing. 2005-10-26 12:16 we7u * src/main.c: Re-enabling the messages to STDERR when SIGHUP is sent to the main process and a restart is occurring. Add comment about disabling SIGHUP handler in child processes. 2005-10-26 12:14 we7u * src/interface.c: Tweaks to assure that the global disables on the Interface menu have the correct effect. 2005-10-26 12:11 we7u * src/: hostname.c, macspeech.c, sound.c, x_spider.c: Regressing to default SIGHUP handler in child processes instead of our special restart() signal handler. 2005-10-26 12:07 we7u * REGRESSION_TESTS: Added date stamps and more comments. 2005-10-26 08:46 we7u * src/main.c: Changing the messages that appear as Xastir shuts down, putting them back under debug_level control in restart(). restart() gets called multiple times due to sending SIGHUP to the TCP/UDP servers during shutdown, and the messages were appearing multiple times if those servers were running. 2005-10-25 18:01 we7u * src/util.c: Fixing the alert expiration problem. May need to be checked when we switch out of daylight savings time again. 2005-10-25 13:08 we7u * src/main.c: Adding an include so that we can use the ComboBox widget. 2005-10-25 13:04 we7u * src/main.c: Limiting the selection box for preconfigured object filenames on the Configure->Defaults dialog to three items. 2005-10-25 12:53 we7u * src/main.c: Minor cleanups of the predefined object code: Added a few free's for XmStrings, allocated memory before an XtGetValues call. 2005-10-25 12:25 we7u * src/: util.c, util.h: Making rpl_malloc() compile in all cases and put a prototype for it in util.h to get rid of more compiler warnings. rpl_malloc() only gets used if AC_FUNC_MALLOC detetcs a version of malloc that doesn't return a valid pointer if you try to malloc zero bytes. These changes make it compile ok on FC4. 2005-10-25 08:18 we7u * src/util.c: Added some comments. 2005-10-24 20:37 we7u * REGRESSION_TESTS: Added some notes about future directions we could go to make the tests a bit more complete. 2005-10-24 20:36 we7u * FAQ: Tweaked the "restart Xastir" paragraph to keep it up-to-date. 2005-10-24 12:29 we7u * src/: main.c, main.h: Patch to allow SIGHUP to cause Xastir to restart properly. This patch also appears to carry along the original command-line parameters and environment to the new task. The xastir.pid file is correct in all cases, and in fact the main process ID doesn't change between restarts. 2005-10-24 12:27 we7u * src/macspeech.c: Spawning a separate process for sending the text to the Mac OSX speech subsystem. We also incorporate a limit of 10 processes that can be waiting for the subsystem to be freed up. If 10 processes are waiting and another speech request is made, the latter is dropped. No provision is made for the ORDER that the (up to) ten processes get access to the speech subsystem either so the order will most likely get mixed up if you're trying to send speech strings out too fast. 2005-10-24 08:52 we7u * help/help-English.dat, src/main.c, src/objects.c, src/objects.h: Another SAR patch from Paul Morris. Here's what he says: This one implements a dialog for selecting CAD objects to delete from the Erase All CAD polygon menu item along with implementing delete by name in CAD_object_delete(). It also adds some help text on prepared objects and CAD objects and changes the XmStringCreateLocalized() calls to XmStringCreateLtoR(). 2005-10-21 21:46 we7u * src/main.c: Restarting on SIGHUP a bit better. It now sends argv[] at least the first time around. Need to figure out why the 2nd time doesn't work at all. Perhaps signal handlers are getting messed up on reboot? 2005-10-21 13:28 we7u * src/objects.c: Another tweak by Paul Morris for proper handling of CAD objects. 2005-10-21 12:33 we7u * FAQ: Reworded text for SIGHUP. 2005-10-21 12:27 we7u * FAQ: Adding the SIGHUP stuff to the FAQ. 2005-10-21 12:18 we7u * README.Getting-Started: Added some more signals to the External Stimuli section. 2005-10-21 12:11 we7u * src/main.c: Adding support for SIGHUP. Xastir will save/exit/restart if a SIGHUP is received. Also enabled a #define near the top of main.c that enables the xastir.pid processing. If someone attempts to start Xastir and there's a process running with that PID, Xastir will exit. The SIGHUP support works, but the command-line parameters aren't carried through as the normal processing for them devours them out of the argv[] array. We need to save that array away or use a non-destructive method of processing the parameters. 2005-10-21 11:02 we7u * src/objects.c: Small tweak so that the code looks in the /usr/local/share/xastir/config directory for the predefined objects for now. Later we'll add the capability of overriding the system files with local user files. 2005-10-21 10:41 we7u * src/interface_gui.c: Reordering the management & positioning statements so that it doesn't appear on the screen until it gets positioned. 2005-10-21 07:27 tvrusso * src/: main.c, objects.c: Move variable declarations to tops of blocks to satisfy old-fashioned compilers that hate the modern practice of declaring variables just before their use. 2005-10-20 15:47 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing pre-defined objects labels to more descriptive words. 2005-10-20 15:02 we7u * src/main.c: Getting rid of Button1 assignment for CAD objects. This prevents us from zooming/panning/measuring while creating a CAD object. 2005-10-20 14:52 we7u * config/Makefile.am: Adding predefined files to Makefile so they'll get installed. 2005-10-20 14:52 we7u * config/: predefined_EVENT.sys, predefined_SAR.sys: Example pre-defined SAR/Event object files by Paul Morris. 2005-10-20 14:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/database.h, src/main.c, src/main.h, src/objects.c, src/objects.h, src/xa_config.c: Patch by Paul Morris, AA3SD, to tweak CAD objects functionality a bit and add pre-defined SAR/Event objects from files. 2005-10-20 13:34 we7u * src/color.c: Reformatting. No real code changes. 2005-10-20 13:12 gstueve * src/: alert.c, alert.h, wx_gui.c: Reintroduce SKYWARN addendum to Wx Messages & sort Wx Alert list. Only sort list if window is activated. 2005-10-20 13:08 gstueve * src/: map_shp.c, maps.c: Move the on_screen decision to a position where it really works. 2005-10-20 10:58 we7u * README.MAPS: Changing one sentence to make things more clear. 2005-10-20 10:57 we7u * README.MAPS: Removing an unnecessary statement. 2005-10-20 10:53 we7u * README.MAPS: Was missing a pipe symbol in the new sort command. Also use the same command for all operating systems with this tweak. 2005-10-20 10:21 we7u * README.MAPS: Fix submitted by A. Carver for FCC database sorting for Cygwin. 2005-10-20 09:35 we7u * src/interface_gui.c: Changing default path to WIDE2-2 instead of WIDE for new interfaces. 2005-10-20 05:41 gstueve * src/maps.c: Activate debugging messages from commented fprintf messages. 2005-10-20 05:35 gstueve * src/util.c: Clamp limits of map to nearest edge. Not clipping/clamping & report error. 2005-10-19 18:29 we7u * src/: map_WMS.c, map_geo.c, map_tif.c, map_tiger.c: Commenting out the XFreeColors() calls for now. Cygwin seems to be much more sensitive to these calls than Linux. 2005-10-19 13:24 we7u * src/interface.c: Disabling sending of my own posits to x_spider if transmit_disable is non-zero. 2005-10-19 13:19 we7u * src/interface.c: Cease sending packets to x_spider if loopback_only is in effect. 2005-10-19 13:19 we7u * src/objects.c: Added some comments. 2005-10-19 12:54 we7u * src/objects.c: Getting rid of "Transmitting objects/items" statusline message if transmit of those types of packets is disabled globally. 2005-10-19 12:21 we7u * src/: map_WMS.c, map_geo.c, map_tif.c, map_tiger.c: Adding XFreeColors() calls just before each XAllocColor() call. This is to keep the counters in sync that count how many times each color is allocated, hopefully preventing the can't allocate color warning messages. 2005-10-19 12:20 we7u * src/color.c: Adding a comment. No code changes. 2005-10-17 14:35 we7u * configure.ac: Bumping version number to 1.7.1 for further development. 2005-10-17 14:12 we7u * configure.ac: Bumping the release number to 1.7.0. 2005-10-17 13:46 francais1 * config/language-French.sys: Merci a Jacques Chion, F6CWO 2005-10-17 13:41 we7u * config/: language-Dutch.sys, language-English.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Fixing some typos: Missing pipe symbols at the end of strings. French language file will be fixed shortly too, along with a few more translations. Thanks to Olivier for catching these. 2005-10-17 12:16 we7u * README, help/help-English.dat: Added notes about Bob Bruninga's list of generic callsigns that should be gated to RF. 2005-10-17 11:53 we7u * help/help-English.dat: Added a What's New section for up-and-coming 1.7.0 release. Added notes regarding gating specific stations to RF and which generic callsigns that Bob Bruninga recommends doing that with. 2005-10-17 11:51 we7u * README.win32: Reformatting the list of languages available. 2005-10-17 11:50 we7u * README.Getting-Started: Changing the revision number in an example. Updating the example Xastir help text. 2005-10-17 11:49 we7u * README.Contributing: Changing a revision number in an example. 2005-10-17 11:49 we7u * README: Adding a note about a few calls that Bob Bruninga recommends always gating to RF. 2005-10-17 11:47 we7u * INSTALL: Tweaking formatting of -l language notes. 2005-10-16 10:16 we7u * config/language-German.sys: An update to the German language file by Rolf Bleher, DK7IN. Thanks! 2005-10-15 18:51 we7u * config/language-Dutch.sys: Updates by Han Sytsma. Thanks! 2005-10-15 18:50 we7u * config/language-English.sys: Fixing a typo. 2005-10-15 10:30 we7u * src/map_tif.c: Making sure the projects.h include isn't needed unless libgdal is compiled in as well. Got rid of UV define and changed invocation to "projUV" instead. 2005-10-15 09:42 we7u * src/map_tif.c: Fixing a problem caused by the new code which fixes the gdal/geotiff bug. This fix cuases the original functions to be called if gdal isn't installed. 2005-10-14 11:06 we7u * src/map_tif.c: Received permission from Frank Warmerdam to use some of his code inside Xastir, relicensing it under GPL. We use this new right to include one function in map_tif.c which allows us to keep topo maps support even when libgdal is compiled in. 2005-10-14 08:11 we7u * README.win32: Added a note about running configure from an xterm so that "gv" support will be compiled in. If run from a non-X11 window, "gv" configure test fails. 2005-10-13 13:51 francais1 * config/language-French.sys: Some more strings translated, but not all... 2005-10-13 08:39 gstueve * src/main.c: Put the full title back on the window, so we can know what machine is running the app. 2005-10-12 17:09 we7u * src/messages.c: Added code that will switch back to RF if no TX-enabled INET interfaces are up. 2005-10-12 13:09 we7u * src/messages.c: New message routing which should take care of a bug-list item: Ceasing to transmit when messaging with internet station and internet interfaces go down. Problem remaining with this code: We transmit out RF interfaces even if QSO'ing with station over internet interface. 2005-10-12 11:33 we7u * src/: locate_gui.c, main.c, messages_gui.c, track_gui.c, util.c, util.h: Fixing all of the callsign entry fields so that "-0" is truncated from the end of the string when used. 2005-10-11 16:52 we7u * src/main.c: Tweaks to convert callsign-0 to callsign for configure station dialog. 2005-10-11 10:12 we7u * src/db.c: Added a bit of debugging. No effect for normal operation. 2005-10-11 08:16 we7u * src/db.c: Slightly better igating of messages. This versions saves the message+acks away and then uses that exact string again when igating it, instead of putting together the bits and pieces at that point like the previous code. 2005-10-10 22:07 we7u * src/db.c: Another tweak to get reply-ack's propagated through an Xastir igate to RF. This one is tested and works. 2005-10-10 18:29 we7u * src/db.c: Comment changes. Also changed the fprintf() for REJ packets to only dump text to STDERR if the REJ was sent to my_callsign. 2005-10-10 12:11 we7u * src/db.c: Changed one comment. 2005-10-10 11:52 we7u * src/db.c: Added comments. fprintf() to stderr when we receive a REJ packet. We can receive those when a Kenwood radio's message buffer is full. 2005-10-10 11:48 we7u * src/messages.c: Minor tweaks w.r.t. REPLY-ACK protocol. Making sure we strip off the unneeded portion before we check the ACK. 2005-10-10 09:31 we7u * src/db.c: Fixing igating of messages to RF for messages with REPLY-ACK protocol at the end. We were originally sending our processed ACK at the end which knocked off the free-ack portion. Now we send the full five-character unprocessed REPLY-ACK. 2005-10-10 09:29 we7u * src/igate.c: Adding some comments. 2005-10-10 08:23 we7u * src/main.c: Fixing a couple of compiler problems via casting. Problems were not seen with SuSE compiler but were seen on other systems. 2005-10-07 18:16 we7u * src/objects.c: Tweaks to avoid other object/item/station names when creating SAR objects. Xastir will now add a number to the end of the typical name (starting at "2") in order to create a unique name. This makes for extremely fast placement of important mission objects without worrying about old mission objects or conflicting with other people's current missions. 2005-10-07 18:13 we7u * src/main.c: Added some comments. 2005-10-07 18:10 we7u * src/db.c: Added some comments. 2005-10-07 18:07 we7u * src/track_gui.c: Added a comment. 2005-10-07 18:05 we7u * src/list_gui.c: Added some comments. 2005-10-07 13:16 we7u * src/objects.c: Added some comments. 2005-10-07 12:49 we7u * src/objects.c: Adding fprintf() statements to help work on the SAR objects code. 2005-10-07 12:26 we7u * src/: main.c, xa_config.c, xastir.h: Checking in some work having to do with saving/restoring X/Y offsets for the main window. The code doesn't work yet so it commented out. 2005-10-07 12:25 we7u * src/objects.c: Adding some comments about future coding that needs to be done w.r.t. SAR objects. 2005-10-07 11:16 we7u * src/Makefile.am: Another minor tweak for the icon. 2005-10-07 11:15 we7u * src/Makefile.am: Adding the icon.xbm file into the Makefiles. 2005-10-06 13:50 tvrusso * src/: main.c, objects.c: Move declarations of variables to before first executable lines of code, to satisfy old-fashioned compilers (gcc 2.95, etc.) 2005-10-06 13:45 we7u * src/icon.xbm: Someone pointed out that the RF radiation wasn't symmetrical. Now it is. 2005-10-06 12:46 we7u * src/objects.c: Commenting out a debug statement. 2005-10-06 12:39 we7u * src/: main.c, objects.c, objects.h: Commenting out the wm_hints code. Adding a "Create SAR Objects" entry to the mouse menu. That last was written and contributed by Paul J. Morris, aa3sd. Thanks! 2005-10-06 12:37 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding "Create SAR Objects" right-click mouse menu. 2005-10-06 12:19 we7u * src/icon.xbm: Added radio transmissions emanating from the antenna. 2005-10-05 23:47 we7u * src/: icon.xbm, main.c: Separating out the icon into its own file. 2005-10-05 22:49 we7u * src/main.c: Casting to type "Dimension" is not proper for parameters passed to XtSetArg(). Have changed to variables of that type for parameter passing. Also cleaned up the -geometry code a bit. The windows are now sized properly per the command-line parameters. 2005-10-05 17:25 we7u * src/main.c: A better version of the -geometry code that is starting to work on Cygwin. The size is larger than specified, perhaps because it is based on char sizes instead of pixels? Anyway, this part of the code is starting to work. 2005-10-05 11:37 we7u * src/main.c: Rearranging things. No code changes. 2005-10-05 08:34 we7u * src/main.c: Another attempt at the -geometry stuff. Here we only use size_hints in one case, plus we lock down the minWidth and minHeight of the main widget when we create it (to the size we want it to appear as), but change those parameters before we map the window to the screen. This method was borrowed from the Lincity project where they do similar things. As usual, this stuff works for me on Linux/FVWM2. 2005-10-04 12:12 we7u * src/: main.c, xa_config.c: Another shot at this -geometry stuff. Moved the size_hints stuff after the window is mapped. Added an icon. 2005-10-04 09:11 we7u * src/main.c: Reducing the number of size_hints variables I'm setting. Changing XtPopup() to XMapWindow() for appshell. 2005-10-03 13:13 we7u * src/xa_config.c: Tweaking SCREEN_ZOOM to match new highest-allowed value for zoom level. 2005-10-03 13:11 we7u * src/main.c: Allow a higher zoom level for entire world, for rather small map windows. 2005-10-03 13:05 we7u * src/main.c: Attempting to recenter view when zooming out all the way. Doesn't quite work yet. 2005-10-03 12:56 we7u * src/main.c: Getting rid of the X-dimension checks in check_range() in order to make it easier to play at the +/-180 boundaries. 2005-10-03 12:51 we7u * src/main.c: A slightly better system for controlling left/right edges of map when at left/right edge of world. check_range(). 2005-10-03 11:34 we7u * src/main.c: Fixes for -geometry support and main window save/restore support. 2005-10-03 11:33 we7u * src/xa_config.c: Changing the minimum size that can be restored to for Xastir's main window. 2005-10-02 12:27 we7u * src/main.c: Adding window manager hints back in. 2005-10-01 23:26 we7u * src/: db.c, draw_symbols.c, geocoder_gui.c, interface_gui.c, list_gui.c, locate_gui.c, maps.c, xastir.h, bulletin_gui.c, main.c, messages_gui.c, objects.c, popup_gui.c, track_gui.c, view_message_gui.c, wx_gui.c: Getting rid of the Global.top widget which was unmapped. Making appshell be the top level widget. Added parsing for the -geometry command-line variable via XParseGeometry() so that we can tell when either the height/width or the x/y offsets have been specified. We then set up appshell based on that info or using the config file data if it wasn't specified on the command-line. 2005-10-01 17:46 we7u * src/main.c: Commenting out the 100x100 minimum window size parameters. 2005-09-30 13:16 we7u * src/main.c: Commenting out the code which sets min_width/min_height in the XSizeHints struct. 2005-09-30 11:25 we7u * src/main.c: Commenting out base_width and base_height parameters as they override the min_width/min_height parameters if specified. We only need one set. 2005-09-30 11:02 we7u * src/main.c: Another shot at the XSizeHints stuff (-geometry). Learning a bit more with each iteration. 2005-09-30 08:58 we7u * src/main.c: Of course some of those I commented out previously appear to matter, so here they are, enabled in the code again. 2005-09-30 08:51 we7u * src/main.c: Getting rid of a few unused variables. Commenting out sections in the geometry setting portions that appear to have no effect. 2005-09-30 07:44 tvrusso * DEBUG_LEVELS: Change statement that the highest debug level is 2047 to 4095. There is now a debug level of 2048 (ALOHA calculation and multipoint object debugging). 2005-09-30 07:27 we7u * INSTALL, help/help-English.dat: Updating the docs regarding TCP and UDP server ports. 2005-09-30 07:01 we7u * src/main.c: Changed PSize flag to USSize to indicate that the user had specified the size of the window in that one case. This gives it a higher priority. 2005-09-30 06:46 we7u * help/help-English.dat: Updating the xastir_udp_client description. 2005-09-30 05:26 we7u * src/db.c: Telemetry fix which adds it as status to the station record, submitted by Andrew Rich, vk4tec. Thanks! 2005-09-30 02:50 we7u * src/main.c: Took another look at the XSizeHints struct. Might work better now to provide proper geometry hints to window managers. 2005-09-29 12:19 we7u * src/map_tif.c: Casting to the correct type for X11 calls. 2005-09-29 12:19 we7u * src/: db.c, location.c, main.c, map_WMS.c, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tiger.c, maps.c, objects.c, popup_gui.c: Casting to the correct type in X11 calls. Adding more debug output to create_appshell() for -geometry stuff. 2005-09-29 11:00 we7u * acinclude.m4: Fix by Thorsten Lockert. Fixes a problem on MacOSX where -lgdal can have revision numbers after it. Without this fix the test compile using gdal fails. 2005-09-29 08:42 we7u * src/main.c: Added more debugging output for -geometry. 2005-09-29 07:59 we7u * src/main.c: Moving some variable declarations to the correct spot. Ended up originally putting them after a bit of functional code, but they must be at the start of a block for many compilers. 2005-09-29 07:37 we7u * src/main.c: Changing to 3rd-party packets for packets sent from UDP to the RF ports. 2005-09-28 13:21 we7u * src/main.c: Commenting out some unused variables. 2005-09-28 13:02 we7u * src/main.c: More mods for UDP->RF. This version may be working but it needs testing on a system with real RF interfaces to see if it behaves properly. 2005-09-28 09:24 we7u * src/: main.c, x_spider.c, x_spider.h: Continuing work on support for UDP server port. We're getting closer now to supporting sending of packets to RF. 2005-09-28 09:22 we7u * src/xastir_udp_client.c: Changed the help text. 2005-09-28 09:03 we7u * symbols/symbols.dat: Adding the /F, Farm Equipment, symbol, as a green tractor. Also added hash mark delimiters between each symbol definition. 2005-09-28 07:50 we7u * config/language-German.sys: Updates by Andreas Bier, dl1hrc. Thanks! 2005-09-27 08:16 we7u * src/main.c: Simplifying startup of the application in main(). Changing to XtVaOpenApplication, which supersedes the function call we were using before, and removing some explicit function calls that are handled automatically by both the old and the new function call (unnecessary code). These changes are being made to implement proper support for the "-geometry" command-line flag. 2005-09-25 19:35 we7u * src/: alert.h, database.h, db.c, draw_symbols.c, geocoder_gui.c, interface.c, main.h, maps.h, track_gui.c, util.h, Makefile.am, main.c, maps.c, util.c: Moving the Object/Item/Cad_Object code into objects.h and objects.c. 2005-09-25 19:26 we7u * src/: objects.c, objects.h: Moving nearly all of the Object/Item/CAD Object code into one header and one source file. This makes main.c quite a bit smaller. 2005-09-24 11:21 we7u * src/main.c: Proper numeric checks for Global.top size/offsets, for deciding whether to make the 2nd Xastir window (the first visible window) copy either set of parameters. 2005-09-24 11:00 we7u * src/: list_gui.c, main.c: Changing variables used in XtVaGetValues() calls to "Dimension" or "Position". Adding an out-of-range check for dimension for the case where we're attempting to discover whether the first window has had -geometry specified. 2005-09-23 17:18 we7u * src/main.c: First working version of the "-geometry" command-line flag. Will hopefully know soon if it works on all platforms we support. Let the testing begin! 2005-09-23 12:01 we7u * src/main.c: "-geometry" switch now works for sizing the application (instead of "-g"), but the X/Y offsets still don't work. 2005-09-22 19:18 tvrusso * src/main.c: Give "appshell_width" and "appshell_height" initial values of 0. This allows the contents of the xastir.cnf file's SCREEN_WIDTH and SCREEN_HEIGHT to be used if no geometry is specified in -g. As it was, if one didn't give -g then these two settings in the config file were ignored and a 100x100 window appeared on every start-up. 2005-09-22 13:32 we7u * src/main.c: A fix for Xastir hanging if the -g flag is used but only offsets are specified. 2005-09-22 13:07 we7u * src/main.c: Initial implementation of the "-g" geometry command-line flag. It supports sizing the application, but doesn't support X/Y offsets yet. That's in the works though. 2005-09-21 22:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/track_gui.c: Added success/failure popups to findu trail download. Changed max_trail_colors to a define instead of an int. Added a Change Trail Color button to the Station Info dialog. 2005-09-21 11:51 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/track_gui.c: Popping up an error if the new backgrounded fetch findu trail fails. Changing variables that the thread depends on to "static" so they'll be around when the thread needs them. 2005-09-20 17:35 tvrusso * acinclude.m4: Restructure test for gv slightly, so that AC_PATH_PROG is called first, and version is tested if gv is found. The case where gv is found, but `gv -v | cut -d ' ' -f 1` not being "gv" is in fact a sign of error that needs to be reported in a meaningful way. Turns out that when I do my normal cygwin build (which is usually done in a non-X cygwin run to save memory), the old way of probing gv found the gv executable, but because "gv -v" tries to connect to the X server and reports failure if it can't, configure was telling me that gv was found, but the build would actually happen without gv. This was quite confusing. With the new test as committed here, I still can't build with gv outside of an xterm on cygwin, but the reason actually shows up in the configure output. 2005-09-17 11:33 we7u * src/lang.h: Bumping up the size of the language buffer as we're bumping up against the limits now for some languages. 2005-09-16 16:46 we7u * src/xastir_udp_client.c: Changing some comments and the usage text. 2005-09-16 16:45 we7u * src/track_gui.c: Trying to protect the track download so that only one can be done at once. Not perfect yet as sometimes the GUI locks up. More to do. 2005-09-16 16:34 we7u * config/language-English.sys: Changing "New Call" to "New Station" for the speech strings. I think it sounds better. 2005-09-16 14:09 we7u * config/language-English.sys: Adding an 's' to the end of "Enable Server Ports". 2005-09-16 14:09 we7u * config/language-German.sys: Updates courtesy of Andreas Bier, dl1hrc. Thanks! 2005-09-16 13:18 we7u * help/help-English.dat: Tweaking the text regarding the UDP server/client. Adding more about the -identify command-line flag. 2005-09-16 13:14 we7u * src/xastir_udp_client.c: Making the output from the -identify response go to STDOUT instead of STDERR. Only makes sense so it can be piped more easily into scripts and such. 2005-09-16 13:09 we7u * src/xastir_udp_client.c: Implemented the "-identify" command-line flag. The "message" portion must have at least a single char in order for the identify query to be sent to the server. 2005-09-16 12:37 we7u * help/help-English.dat, src/x_spider.c: Now we send UDP packets out the x_spider TCP ports as well, if the packet is authenticated properly. 2005-09-16 12:26 we7u * src/x_spider.c: Adding a "-identify" option to the UDP server. It returns a UDP packet containing the callsign. 2005-09-16 11:48 we7u * src/track_gui.c: Putting the fetch_findu_trail function into a separate background thread. 2005-09-16 11:48 we7u * help/help-English.dat: Adding text about the UDP server feature and the xastir_udp_client. 2005-09-16 07:38 we7u * src/: x_spider.h, xastir_udp_client.c: Moving the default port for UDP from 2024 to 2023, as TCP and UDP can co-exist on the same port number. 2005-09-15 16:59 we7u * src/xastir_udp_client.c: Fixed the hostname lookup. You can now specify any hostname and port. 2005-09-15 12:38 we7u * src/util.c: Adding the long integer time at the beginning of the timestamp line for the log files. Makes sorting easy. 2005-09-15 11:56 we7u * src/: util.c, wx.c: Changing timestamping to add a timestamp line per packet instead of once per 30 seconds. 2005-09-15 11:47 we7u * src/: x_spider.c, xastir_udp_client.c: Adding authentication to the UDP packets. 2005-09-15 11:45 we7u * src/db.c: Allowing user-defined and telemetry packets to be gated. 2005-09-15 07:54 we7u * src/.cvsignore: Adding xastir_udp_client to the ignore list. 2005-09-15 07:52 we7u * src/: Makefile.am, x_spider.c: Renaming the UDP client from udp_client to xastir_udp_client. 2005-09-15 07:51 we7u * src/xastir_udp_client.c: Renaming this file from udp_client.c to xastir_udp_client.c, to avoid similar names for UDP clients. 2005-09-15 07:50 we7u * src/udp_client.c: Renaming this file to xastir_udp_client.c 2005-09-14 21:53 we7u * src/: interface.c, main.c, x_spider.c, x_spider.h: Adding a UDP server at port 2024. 2005-09-14 21:45 we7u * src/Makefile.am: Adding the udp client. 2005-09-14 21:44 we7u * src/udp_client.c: Initial checkin of a UDP client. Currently this is hard-coded to talk to the localhost address, but that can be fixed later. It also hangs currently if the server isn't responding. 2005-09-09 13:08 we7u * src/db.c: Fixing a typo in one of the new langcode() string callouts. 2005-09-09 12:20 we7u * src/: db.c, main.c, util.c: Replacing a bunch of hard-coded strings with langcode() strings. 2005-09-09 12:19 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more language strings to replace hard-coded strings. 2005-09-08 21:46 we7u * src/: draw_symbols.c, fcc_data.c, geocoder_gui.c, map_cache.c, rac_data.c, view_message_gui.c, xa_config.c: Adding language strings for previously hard-coded values. Changed get_long and get_int functions in xa_config.c to give better output when variables are missing or out-of-range in the config file upon Xastir startup. 2005-09-08 21:40 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding more language strings for previously hard-coded English values. 2005-09-08 09:49 we7u * INSTALL: Adding a blurb about conflicts between GDAL internal libraries and external libraries that Xastir can use. 2005-09-08 09:39 tvrusso * acinclude.m4: Move -lgdal to end of LIBS line if it's found. It is possible for gdal to be using its own internal geotiff library, and this can interfere with use of an external one in xastir. Having it later in the line than geotiff can fix that. This could cause problems for systems with busted linkers that need gdal to be earlier than everything it depends on. If that happens, it might be necessary to add the contents of "gdal-config --dep-libs" to LIBS after -lgdal. 2005-09-08 08:58 we7u * src/map_tif.c: Commenting out some unnecessary includes. Adding some error messages when function calls fail. Minor reformatting w.r.t. braces to match the Xastir project standard. 2005-09-07 12:30 we7u * src/main.c: Assuring that the "System time jumped backwards 1 seconds!" message doesn't say "0 seconds!", as I've seen recently due to the way the code was originally written. 2005-09-02 18:42 we7u * acinclude.m4: More appropriate output for the case where gv is not found by configure. 2005-09-02 16:00 we7u * acinclude.m4: Adding a clause for the case where no usable "gv" is found. 2005-09-02 15:34 we7u * acinclude.m4: Another stab at trying to do the "gv" revision tests. 2005-09-02 15:34 we7u * src/maps.c: Pop up warning messages if we try to print but don't have the proper support compiled in. 2005-09-02 13:54 we7u * acinclude.m4, src/maps.c: Tweaks to hopefully determine automatically which version of "gv" is being used and change the code to correspond to the proper API. 2005-09-02 12:30 we7u * src/maps.c: Preparing for configure.ac tests that will determine the "gv" version, then we can change how we call up "gv" based on that. 2005-09-02 08:47 we7u * src/x_spider.c: Changing to a combination for the "Hello" server message, per the APRS INET conventions. 2005-09-01 10:00 we7u * README.Getting-Started: Modified the note regarding geocode files. 2005-09-01 08:08 we7u * configure.ac, src/main.c: Adding a test for sigignore() to configure.ac, and code to use it in main.c. We were getting a warning under Solaris by using signal() with SIG_IGN as the parameter. 2005-09-01 07:43 we7u * src/util.c: Adding strings.h include. Need for Solaris. 2005-08-31 21:16 we7u * config/tnc-startup.kpc3: Removing "exp on" from the file. I guess SOMEBODY doesn't think we need AEA commands in a KANTRONICS config file. The nerve! 2005-08-31 14:42 we7u * REGRESSION_TESTS: Blowing away the autom4te.cache directory at the start of each run, to make sure that we start out ultra-clean. 2005-08-31 09:59 we7u * configure.ac: Attempt to remove "-no-unused" from linking stage for Cygwin builds, as GCC links to complain about that flag during linking. 2005-08-30 14:19 we7u * acinclude.m4: Changing grep syntax so that it will work with non-GNU grep (Solaris). Getting rid of dash near the end. 2005-08-30 13:52 we7u * src/: awk.c, bulletin_gui.c, db.c, main.c, map_WMS.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c: Mucking about with the strings.h includes. 2005-08-30 13:28 kd6zwr * src/: awk.c, geo-find.c, io-common.c, map_gnis.c: protecting the strings.h with an ifdef, and casting isspace() family of macros to match man page (int). 2005-08-30 12:41 we7u * src/awk.c: Adding a strings.h include for Solaris support. 2005-08-30 11:33 we7u * src/db.c: Displaying the raw packet in a dialog for the case where we detect "EMERGENCY" in the comment field or one of the emergency-type destination callsigns in a packet. 2005-08-30 11:31 we7u * config/tnc-startup.paccomm: Commenting out a "WIDE" alias that remained. Changed it to "LOCAL" also. 2005-08-30 11:31 we7u * src/locate_gui.c: Skipping the dialog destroy call if you hit the FCC/RAC lookup or the Locate button. The dialog now has to be manually cleared by hitting the Cancel button. 2005-08-29 08:06 we7u * src/: db.c, interface.c, wx.c: Fixing warnings seen on OSX 10.4. Very minor "signedness" warnings in string functions. 2005-08-27 17:21 we7u * src/x_spider.c: Tweaking a patch provided by James Washer that will send a string out the server port on each connect. My chances were merely to the format of the string. Thanks go to James for the patch itself. 2005-08-26 14:12 tvrusso * configure.ac, src/hostname.c: Fix so that hostname.c can compile on systems that define neither sighandler_t nor sig_t. This is necessary because of the new cast to sighandler_t of the second argument of signal() that was put there to shut gcc warnings up. 2005-08-25 14:29 we7u * acinclude.m4: Getting rid of some extra restores of variables that I shouldn't have added last go-around. 2005-08-25 13:48 we7u * acinclude.m4: Summary text and summary.log were incorrect if gdal wasn't found. Fixed. 2005-08-25 08:11 we7u * src/db.c: Commenting out some debug code. 2005-08-24 21:27 we7u * src/xa_config.c: Simplifying the get_long() and get_int() code per discussions with Tom Russo. Also attempting to get rid of some compiler warnings that we see with FreeBSD. 2005-08-24 10:58 we7u * src/main.c: Switching the state of trap_segfault variable to make more sense. 2005-08-24 09:50 we7u * src/main.c: Change in text suggested by James Washer. Also added the -t option to the command-flag help text. 2005-08-24 09:07 we7u * src/xa_config.c: Removing some ill-advised casts to time_t's. Was trying to get rid of warnings that appear on FreeBSD, but this was the wrong approach and didn't fix the problem. 2005-08-23 21:08 tvrusso * configure.ac, src/hostname.c: Change logic for deciding when to use a sigjmp_buf vs. a jmp_buf. The code that was originally here would only work if sigjmp_buf was a #define, but on some systems it's a typedef. The new code works for both. 2005-08-23 19:53 we7u * src/: awk.c, bulletin_gui.c, map_gdal.c, maps.c: Fixing up function headers to be ANSI-C compliant. 2005-08-23 16:25 we7u * INSTALL: Tweaking the GDAL install instructions a bit more. 2005-08-23 16:04 we7u * INSTALL: Updating the GDAL install instructions. 2005-08-23 14:38 we7u * configure.ac: Changing the summary format slightly. No code changes. 2005-08-23 14:23 we7u * configure.ac: Drawing a line in the configure summary between the normal and the more unusual parameters. 2005-08-23 14:18 we7u * configure.ac: Changing some text on the summary output. No code changes. 2005-08-23 13:52 tvrusso * acinclude.m4: Add configure-time check for usability of -Wno-unused-parameter. Older compilers (not newer as was indicated in the comments) don't like that and need -Wno-unused instead. Return -W to the CFLAGS, and use whatever -Wno-unused* works. 2005-08-23 12:39 we7u * src/interface.c: Added a new time_t variable that we can use to call ctime() with, in order to avoid a compiler warning. 2005-08-23 12:38 we7u * src/xa_config.c: Changing a bunch of pointer casts from "long *" to "time_t *" to avoid compiler warnings. 2005-08-23 12:36 we7u * src/util.c: Casting some time_t's to long's to avoid compiler warnings. 2005-08-23 12:35 we7u * src/main.c: Casting a time_t to an unsigned long to remove a compiler warning. Fixing up a function header to make it ANSI-C compliant. 2005-08-23 12:32 we7u * src/db.c: Casting some time_t's to long's to get rid of warnings. 2005-08-23 12:32 we7u * src/alert.c: Casting some time_t's to unsigned long's to get rid of warnings. 2005-08-23 12:30 we7u * acinclude.m4: Taking some of the new compiler flags back out as one of them isn't recognized on some versions of GCC, and the other causes too many warnings without it. Hopefully we can add the "-W" back in at a later date once we figure out how to get rid of the "unused parameter" warnings on a case-by-case basis. 2005-08-22 16:02 we7u * src/io-mmap.c: Cleaning up compiler warnings. 2005-08-22 15:21 we7u * acinclude.m4: Adding "-W" and "-Wno-unused_parameter" compiler flags. Still a clean compile with SuSE Linux 9.0. No errors, no warnings. 2005-08-22 11:45 we7u * src/: db.c, interface.c, interface.h: Added is_local_interface() and is_network_interface() functions. Changed packet_data_add() to use them, and to changes it functionality so that packets transmitted to local interfaces would be visible in the incoming data dialog. 2005-08-22 11:37 we7u * src/: shp_hash.c, shp_hash.h: Fixing up prototypes and function headers so that they are ANSI-C compatible. 2005-08-22 11:36 we7u * src/rtree/: card.c, gammavol.c, index.c, index.h, node.c, rect.c: Fixing up prototypes and function headers so they are ANSI-C compatible. 2005-08-22 11:35 we7u * REGRESSION_TESTS: Tweaking to match new format for summary.log file (we only want to show the first line now). 2005-08-19 18:53 we7u * src/: database.h, db.c, map_cache.c, map_cache.h, map_shp.c, maps.c, testawk.c: Fixing up function and prototype definitions so they are ansi-C standard and will pass the new compiler tests that were just added. 2005-08-19 18:40 we7u * acinclude.m4: Adding more strict compiler checking. 2005-08-19 18:27 we7u * INSTALL: Adding notes about malloc debugging. 2005-08-19 14:31 we7u * src/draw_symbols.c: Adding/changing some comments. 2005-08-19 14:26 we7u * src/draw_symbols.c: Real fix for memory leak in the font metrics code. Don't know why we need a '1' parameter for this system call, but with a '0' we end up with a leak. 2005-08-19 13:32 we7u * src/draw_symbols.c: Fix for big memory leak. 2005-08-19 11:33 tvrusso * configure.ac, src/hostname.c: Add probe for sighandler_t definition, and code to work around it being missing. 2005-08-18 16:54 we7u * src/interface.c: Fooled myself. Last fixes weren't fixes but stopped the compile. Will rework that fix later. 2005-08-18 16:51 we7u * src/interface.c: Putting a few casts in to get rid of "-pedantic" warnings. 2005-08-18 16:21 we7u * src/map_cache.c: Getting rid of three more "-pedantic" warnings. 2005-08-18 16:09 we7u * src/interface.c: More tweaks so that the "-pedantic" compiler flag will show fewer warnings. 2005-08-18 15:56 we7u * src/: hostname.c, shp_hash.c: Fixing up minor warnings that the "-pedantic" compiler flag revealed. 2005-08-18 15:27 we7u * src/: alert.c, db.c: Getting rid of another couple of warnings that the "-pedantic" compiler flag revealed. Very minor stuff. 2005-08-18 15:11 we7u * src/hashtable_private.h: Removing the semicolon at the end of a function that "-pedantic" compiler flag caught. 2005-08-18 14:49 tvrusso * acinclude.m4, src/testawk.c: Make use of LIBS in the gdal probe without gdal-config match the usage with gdal-config fix bogon in awk_rule table in testawk.c 2005-08-18 14:43 we7u * src/messages_gui.c: Casting to an "int" in order to get around a compiler warning that we get if we turn on stricter checking. 2005-08-18 14:42 we7u * src/main.c: Adding a missing initializer. 2005-08-18 14:00 we7u * src/: leak_detection.h, util.h: Tweaks by Tom Russo to make the new include arrangement work on FreeBSD. Evidently I broke that platform with my most recent include file changes. 2005-08-18 08:28 we7u * src/view_message_gui.c: Moving the dmalloc code to a separate header file. 2005-08-18 08:27 we7u * src/util.c: Messing with the hash iterator free's again. Moving dmalloc code to a separate header file. 2005-08-18 08:26 we7u * src/: map_gdal.c, maps.c, wx_gui.c: Messing with the hash iterator free's again. 2005-08-18 08:26 we7u * src/leak_detection.h: Here's where the malloc and dmalloc code was moved to. The order in which this is done with respect to the libgc code is critical, therefore it has all been moved to this one header file so the order can be closely guarded. 2005-08-18 08:24 we7u * src/interface_gui.c: Removing the dmalloc code. 2005-08-18 08:23 we7u * src/: hashtable_private.h, hashtable_itr.c: Removing the xastir.h include. 2005-08-18 08:22 we7u * src/hashtable.c: Moving a comment. 2005-08-18 08:22 we7u * src/db.c: Removing dmalloc ifdef's. 2005-08-18 08:21 we7u * src/alert.c: Getting rid of dmalloc ifdef's. We use libgc to do similar things. Messing with the iterator ifdef's again. 2005-08-17 13:16 we7u * src/util.c: Skipping the free() of the hashtable iterator in all cases. 2005-08-17 13:13 we7u * src/maps.c: Moving alert-related code to debug level 2. Skipping hash iterator free() calls for now as they cause segfaults if libgc is compiled in. 2005-08-17 13:11 we7u * src/db.c: Changing debug_level to 2 for wx_alert-related code. 2005-08-17 13:10 we7u * src/alert.c: Added some debug statements. Skipping hash iterator free() as it causes segfaults. 2005-08-17 12:13 we7u * src/util.c: Adding leak_detector.h include. Simplifying add_tactical_to_hash() function. 2005-08-17 12:12 we7u * src/: map_WMS.c, map_cache.c, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, messages.c, messages_gui.c, popup_gui.c, rac_data.c, rotated.c, shp_hash.c, snprintf.c, sound.c, testawk.c, track_gui.c, util.h, view_message_gui.c, wx.c, wx_gui.c, x_spider.c, x_spider.h, xa_config.c, xastir.h: Adding leak_detector.h include. 2005-08-17 12:11 we7u * src/main.c: Adding leak_detector.h include. Changing memory leak check to every 60 seconds (from 5 minutes). 2005-08-17 12:08 we7u * src/: awk.c, bulletin_gui.c, color.c, datum.c, db.c, dbfawk.c, draw_symbols.c, fcc_data.c, festival.c, geo-find.c, geocoder_gui.c, gps.c, hashtable.c, hashtable_itr.c, hostname.c, igate.c, interface.c, interface.h, interface_gui.c, io-common.c, io-mmap.c, lang.c, list_gui.c, locate_gui.c, location.c, location_gui.c, macspeech.c: Adding leak_detector.h include. 2005-08-17 12:06 we7u * src/alert.c: Adding leak_detector.h include. Simplifying the add_wx_alert_to_hash function. 2005-08-17 12:04 we7u * src/Makefile.am: Adding the leak_detector.h file. 2005-08-17 12:02 we7u * src/leak_detection.h: Moving the LIBGC defines/includes into a new header file. The order in which these are used in a C module is important, as is the order that the thread includes are done. This will help assure that the order remains consistent so that the memory leak detection will work. 2005-08-17 11:59 we7u * INSTALL: Tweaking the libgc instructions. 2005-08-15 17:47 we7u * src/util.c: Separating out the pointers so we can better keep track of them, assuring that we're not overwriting anything we shouldn't. Freeing some malloc'ed space for the case where hash inserts fail. 2005-08-15 17:45 we7u * src/shp_hash.c: Freeing some malloc'ed space for the case where hash inserts fail. 2005-08-15 17:44 we7u * src/map_gdal.c: Freeing some malloc'ed space for the cases where hash inserts fail. 2005-08-15 17:44 we7u * src/alert.c: Changing a memcpy to an xastir_snprintf call in order to assure that the string is terminated. Added some debugging set_dangerous/clear_dangerous calls. 2005-08-15 17:42 we7u * src/main.c: Making the RINO download timeout slider always visible in the timing dialog, but insensitive if gpsman is not compiled in. 2005-08-15 13:01 we7u * configure.ac: Adding a very short summary of the configure tests and results to summary.log. This should aid in debugging as we can more quickly see what passed/failed on a particular user's machine. 2005-08-14 23:43 we7u * src/map_shp.c: Committing Tom Russo's fix to remove colon chars in track->shapefile save routine. Seems Cygwin doesn't like colons in filenames. 2005-08-13 09:43 we7u * README.win32: Fixing a couple of typos. 2005-08-12 22:21 we7u * src/main.c: Moving one define to the top of the file. This one contains some copyright dates and appears in the Help dialog, so must be updated periodically. This new location for it is much better than having it hidden in the middle of the file. 2005-08-12 22:07 we7u * src/util.c: Adding spaces around the "==" in the #if statement added today. 2005-08-12 20:17 we7u * acinclude.m4, configure.ac: Taking out the new MALLOC test added today as AC_FUNC_MALLOC already does what we need. 2005-08-12 14:37 we7u * acinclude.m4, configure.ac, src/util.c: Adding rpl_malloc() function in util.c, and the associated hooks into acinclude.m4 and configure.ac to get it called. This is to replace malloc() for those cases where malloc() doesn't behave properly. 2005-08-12 14:36 we7u * INSTALL: Adding a note about libgc's extra memory usage. 2005-08-12 13:41 we7u * config/language-Portuguese.sys: Shortening the Portuguese version of "Enable Weather Alerts" string. 2005-08-12 12:37 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added a Reset button to the Change Debug Level dialog. 2005-08-12 12:36 we7u * src/: alert.c, main.c, map_gdal.c, maps.c, util.c, wx_gui.c: Added a reset button to the Change Debug Level dialog. Made the Enable WX Alerts menu item be grey'ed out if Shapelib not installed. Added debug statements multiple places. Put #ifndef's around a bunch of free(iterator) statements for the case when libgc is configured into the compile (else segfaults occur). 2005-08-12 12:27 we7u * config/: language-Dutch.sys, language-English.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Removing "Counties" from the Enable Weather Alerts text. 2005-08-12 08:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Adding a custom zoom option to the right-click zoom levels menu. 2005-08-11 13:40 we7u * src/main.c: Moving the Center & Zoom dialog to the Maps menu. 2005-08-11 12:46 we7u * REGRESSION_TESTS: Added a default configure/compile at the end, both to test this case and to get the codebase back to normal for the system it's run on. 2005-08-11 12:20 we7u * REGRESSION_TESTS: Removed a couple of el-stupido test cases. Nice'ed everything. 2005-08-10 18:37 we7u * configure.ac: Adding warnings so that library dependencies are obvious. Adding code so that missing dependencies cause dependent libraries to be skipped. 2005-08-10 18:35 we7u * INSTALL: Added an ASCII-art drawing showing the library dependencies. 2005-08-10 14:06 we7u * configure.ac: Adding another configure warning for missing library. 2005-08-10 12:00 we7u * REGRESSION_TESTS: Adding tests for ALL libraries minus one, each in turn. 2005-08-10 11:58 we7u * configure.ac: Forcing use_rtree to OFF and issuing a warning if Shapelib is not being used. 2005-08-10 11:39 we7u * src/: main.c, shp_hash.c: Fixing the code for the case where rtree has been requested buy Shapelib is not compiled in. It makes no sense to do this, but at least it will compile for this case now. 2005-08-10 11:38 we7u * src/track_gui.c: Tweaking the Fetch Findu Trail function so that it matches what findu is capable of for the trail duration. Changed the start time and duration time max values to #defines at the top of the file so we can change it more easily next time around. 2005-08-09 08:57 tvrusso * acinclude.m4: Fix for broken fix of broken fix of probe for gdal. After I fixed the multiply-included -lgdal issue and made sure that I'd separated out -Ls from -ls, I never made sure that the -l got into LIBS. I was counting on AC_CHECK_LIB to do that, but it only does so if you don't provide an ACTION-IF-FOUND. 2005-08-08 20:53 tvrusso * acinclude.m4: Add ugly hack to work around gdal-config's idiosyncratic merging of LDFLAGS and LIBS data with the single "gdal-config --libs" command. Other programs with -config scripts have --ldflags and --libs to keep the stuff separate. 2005-08-08 20:18 tvrusso * acinclude.m4: Fix broken attempt to replace old flags into variables after failing test. 2005-08-08 14:12 francais1 * config/language-French.sys: Incorporated most changes from Jacques Chion 2005-08-08 12:27 we7u * src/track_gui.c: Adding a debug statement. 2005-08-06 11:11 tvrusso * acinclude.m4: Fix up AC_CHECK_GDAL so it uses LIBS instead of LDFLAGS. This makes it more consistent with other usages. gdal-config --libs actuall returns both LDFLAGS and LIBS type information, and using its output for LDFLAGS winds up putting the -lgdal flag very early in the link line. This could be a problem on some systems. 2005-08-06 11:05 tvrusso * acinclude.m4: Fix dumb mistake in the section that handles the "gdal-config not found" condition. 2005-08-06 11:01 tvrusso * acinclude.m4, configure.ac: Make probe for gdal use gdal-config if it can be found. If gdal-config is in the user's path, use it to get LDFLAGS and CPPFLAGS to help the probe for gdal.h and libgdal.a. Otherwise, use the current settings of LDFLAGS and CPPFLAGS and hope they're found. In doing this, I think I see that the probe XASTIR_CHECK_IMAGEMAGICK has a few bugs in it. 2005-08-06 00:14 tvrusso * src/db.c: Fix new emergency processing in decode_ax25_line so that it only attempts to work on valid packets. This was causing segfaults at strcmp(my_callsign,call_sign) when connecting to an internet server (upon receiving the # javAPRServ line), because call_sign was NULL. 2005-08-05 18:14 we7u * REGRESSION_TESTS: Making the output a bit easier to understand. 2005-08-04 20:13 we7u * src/draw_symbols.c: Using font metrics to determine size of font. We then use that to determine the size for the black rectangle underneath the font. 2005-08-04 12:34 we7u * src/: db.c, draw_symbols.h, draw_symbols.c: Drawing a line between the waypoint symbol and the station that originated it. Per the spec. 2005-08-03 18:52 we7u * symbols/symbols.dat: Updating a symbol or three. 2005-08-03 13:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h: Have implemented an EMERGENCY BEACON transmit capability. Look for it under the "Help" menu (appropriate, no?). 2005-08-03 12:15 we7u * REGRESSION_TESTS: More minor cleanups. No real changes. 2005-08-03 12:01 we7u * src/db.c: Added emergency beacon decode for the string "EMERGENCY" anywhere in the packet, plus the strings: ALARM ALERT WARNING WXALARM EM If seen in the TO: field of the packet. This matches the decoding provided by APRS+SA for this feature. 2005-08-02 13:22 we7u * REGRESSION_TESTS: Small tweaks to improve the output and give us info while it is running instead of all the output at the end. 2005-08-01 21:40 we7u * REGRESSION_TESTS: Changing the order of the individual flag tests to match the summary output order from "configure". 2005-08-01 21:18 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Taking "RELAY" out of the digipeat? label. 2005-08-01 21:16 we7u * REGRESSION_TESTS: Fiximg the grep at the end. 2005-08-01 19:33 we7u * REGRESSION_TESTS: Initial checkin. A "dumb" script the way it is currently written, but it could be made much more intelligent over time, and extended to perform more tests. 2005-08-01 19:29 we7u * symbols/symbols.dat: Changing the symbols to be more spec-compliant. The spec keeps changing on us. Added an SUV symbol. Moved the Shelter symbol to the secondary table. Changed the background on the Storm Watch symbol to orange instead of red. Still need to do the waypoint symbol so it is a red circle and have a line going between it and the mobile transmitting it, plus need to change "No Sym Yet" to a circle with a slash through it, per the latest spec addendum. It would be worth taking a look at all the symbols to verify compliance. 2005-08-01 19:26 we7u * src/map_geo.c: Getting rid of a compiler warning (unused variable) when ImageMagick isn't compiled in. 2005-08-01 15:08 tvrusso * src/map_shp.c: Move declaration of draw_filled out of WITH_DBFAWK ifdef. 2005-08-01 14:34 we7u * src/main.c: Updating the year on the Help->About copyright notice. 2005-08-01 12:43 we7u * configure.ac, help/help-English.dat: Bumping version to 1.6.1 for further development. 2005-08-01 11:11 we7u * help/help-English.dat: Updating the what's new section for 1.6.0. 2005-08-01 10:54 we7u * README.Contributing, README.Getting-Started, configure.ac, help/help-English.dat: Bumping the version to 1.6.0. 2005-07-30 23:19 we7u * src/: bulletin_gui.c, db.c, interface_gui.c, maps.h, locate_gui.c, location_gui.c, main.c, map_gnis.c, messages_gui.c, wx_gui.c: Adding new capability to the Map Feature Search function: Now returns a chooser dialog that allows seeing up to the first fifty matches for the search, then centering the map on any of them. Also tweaked array sizes throughout the code used for sending parameters to X11 calls. 2005-07-29 12:32 we7u * src/: locate_gui.c, map_gnis.c, maps.h: Changing locate_place() to gnis_locate_place() because it is too similar to the function Locate_place(). Added some comments w.r.t. putting in a chooser option for the Locate Map Feature function. 2005-07-29 12:31 we7u * src/db.c: Changing some comments. No code changes. 2005-07-29 12:29 we7u * src/xa_config.c: Calling the new remove_all_spaces() function on one variable read in from the config file. 2005-07-29 12:29 we7u * src/: util.c, util.h: Added a "remove_all_spaces" function. 2005-07-28 13:41 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tif.c, src/xa_config.c: Implementing the XOR function for combining USGS DRG colors with underlying map colors. Changed some labels with respect to this new function. 2005-07-26 12:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the DRG Color Filtering labels to the correct color names. 2005-07-26 12:39 tvrusso * src/map_gdal.c: Fix extern declaration of draw_shapefile_map 2005-07-26 12:32 tvrusso * src/main.c: Add a comment. 2005-07-26 12:16 tvrusso * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_dos.c, src/map_gdal.c, src/map_geo.c, src/map_gnis.c, src/map_pdb.c, src/map_shp.c, src/map_tif.c, src/maps.c, src/maps.h: Implement auto detection of USGS DRG topo maps (the ones actually from USGS, with proper GeoTIFF tags). Changed map driver interface to take a struct of map flags instead of a single "draw_filled" integer. Changed map properties to support setting of Yes/No/Auto for a given map's "USGS DRG" field. If Yes, the color map is assumed to be USGS's and the color settings in Map->Configure USGS DRG are used. If No, all colors in the colormap are displayed. If Auto, the tiff's Image Description tag is queried and if it begins with "USGS DRG GeoTIFF" then it's as if the setting was Yes, and if it doesn't (or the tag does not exist) then it is as if the setting was No. Added rowcol to map properties dialog to handle the extra buttons without widening the window. Cleaned up the code in main.c that locates the filename in a map properties line. It was being done by hardcoding the offset in 8 places to 31. Moved the magic number to a preprocessor symbol so it only needs to be changed once now. There has got to be a cleaner way still, but that's enough for now. Changed all map drivers to support the new map_data_flags struct instead of the int draw_filled. Changed language files. Not sure I got all of them right. 2005-07-25 10:00 tvrusso * src/xa_config.c: Change DRG_COLORS settings so that they default to ON if a config file is read in that doesn't contain the settings. This will make sure that users who upgrade don't get surprised by having all their topo maps disappear upon upgrading. 2005-07-23 19:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tif.c, src/xa_config.c, src/xastir.h: Added a Configure USGS DRG dialog. Allows turning on/off various drawing colors on geoTIFF images. 2005-07-22 18:27 we7u * src/map_tif.c: Added a couple of defines at the top that control whether we display an entire topo map or just the contours, and which color we display them in. 2005-07-22 12:42 we7u * src/util.c: Cleaning up the curl code a bit more: Removed unnecssary includes and moved the one remaining include up to the top of the file. 2005-07-21 23:17 we7u * config/language-Dutch.sys: Translating one label. 2005-07-21 23:08 we7u * src/: track_gui.c, map_WMS.c, map_geo.c, map_tiger.c, maps.c, util.c, util.h: Consolidating all of the libcurl and wget functionality into util.c:fetch_remote_file(). This should make the code much easier to maintain and extend. 2005-07-21 21:33 we7u * INSTALL: Adding some instructions provided by Tom Russo for specifying an unusual location of libdb to configure. 2005-07-21 13:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/geocoder_gui.c: Correcting the "Find Address" label in several spots. 2005-07-21 12:53 we7u * INSTALL: Adding a list of libraries for a full-up Xastir compile on SuSE 9.0 to aid people in deciding which libraries might be needed. 2005-07-20 19:19 we7u * src/: map_cache.c, map_cache.h, main.c: Added a run-time check for matching versions in db.h and libdb.so. 2005-07-20 19:12 we7u * src/track_gui.c: Fixing the duration hours slider so that it can't be any larger than the start hours slider. 2005-07-20 11:50 we7u * INSTALL: Adding some text having to do with using the optional Berkeley DB Library for map caching. 2005-07-20 11:49 we7u * acinclude.m4: Adding some comments to the XASTIR_BERKELEY_DB_CHK_LIB function. Things we need to add/figure out in order to assure that the Berkeley DB Library can be successfully used with Xastir. 2005-07-19 22:13 we7u * help/help-English.dat: Added an example of how to use the Fetch trail from Findu timing sliders. 2005-07-19 22:09 we7u * src/: main.h, db.c, xa_config.c: Implementing user-configurable digipeater callsigns. Users will now be able to edit the comma-delimited string in their xastir.cnf file. There are no GUI tie-ins for editing the string at this point. 2005-07-19 21:43 we7u * help/help-English.dat: Adding some more detail about the Map Chooser->Properties dialog. Adding some new text about the user-configurable relay digipeater callsigns which will be committed to CVS shortly. 2005-07-19 21:41 we7u * configure.ac: Reordering the summary.log and Help->About library strings plus adding the few that were missing. 2005-07-19 21:38 we7u * README.MAPS: Minor tweak to one comment. Nothing substantial. 2005-07-19 12:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing up the displayed string for Beam Heading objects, "Bearing:" string. 2005-07-18 11:12 tvrusso * src/draw_symbols.c: Fix for broken DF directional lines when zoomed in tight. Restricts range of lines to something close to the screen, rather than the full range allowed by the DF object's NRQ (or the default of 512 nautical miles. 2005-07-16 23:19 we7u * src/interface_gui.c: Allowing the passcode to be longer (up to 20 chars). Useful in a few instances, and similar to what's allowed currently in the AGWPE code. 2005-07-16 23:17 we7u * src/x_spider.c: Adding a #define and some #ifdef's that allow compiling the code in either standalone daemon mode or called-function mode. 2005-07-15 09:30 we7u * src/main.c: Adding spaces to the help text. 2005-07-15 09:18 we7u * xastir.spec.in: Re-ordering the docs alphabetically. No real change. 2005-07-13 12:37 we7u * src/util.c: Adding some comments. Preparatory to redoing some code. 2005-07-12 19:44 tvrusso * config/tgr2shppoly.dbfawk: Make polygon boundaries the same color as fill. Now that boundaries are no longer stippled the same way as the fill, the black boundaries are too glaring. 2005-07-12 16:06 tvrusso * src/map_shp.c: Reset stipple style to solid when drawing boundaries of polygons with dbfawk. They were getting drawin in the stipple pattern used for fill, which made for fuzzy boundaries. 2005-07-11 12:25 we7u * configure.ac: Fixing the Geotiff summary line so that it says "no" if libproj isn't found. It was blank until now in this case. 2005-07-11 12:24 we7u * src/map_geo.c: Moving one line so that this will compile ok without warnings if no ImageMagick. 2005-07-11 10:50 we7u * src/xastir.h: If ImageMagick is not found, util.c compile will fail without this change. 2005-07-11 07:55 tvrusso * src/main.c: Put use of map_cache_fetch_disable into the same ifdef as the definition of that variable, so that people who aren't using map caching can link. 2005-07-10 10:56 tvrusso * FAQ: Change question 5.4 to actually have "5.4" in its title. 2005-07-10 08:37 tvrusso * scripts/Xastir_tigerpoly.py: Add -d flag to the Usage error message. 2005-07-10 08:36 tvrusso * scripts/Xastir_tigerpoly.py: Add "-d" option to this script to allow dissolution of common boundaries between polygons with the same Landmark designation. This is done by scanning all PolyChainLink records, checking that both left and right polygon have associated AreaLandmark records, and that both AreaLandmark records point to the same Land record. If they do, then the two polygons are dissolved into one. The option is not the default. Using this option makes the output shapefile be topologically inequivalent to the original TIGER/Line data, and as such they are suitable only for display. Distributing data produced in this manner should be done with a prominient disclaimer pointing out that the shapefiles are for display purposes, not serious GIS use. Dissolving polygons in this way makes the TIGER data look much nicer (but still pretty ugly) in xastir -- large landmarks no longer have many copies of the labels, and no longer have ugly internal dashed boundaries that mean nothing. 2005-07-08 20:30 we7u * src/dbfawk.c: A fix for the emacs temp-file bug that is invoked by temp file symlinks of the form ".*.dbfawk" while editing dbfawk files. The code will now ignore anything but regular files, and ignores directories and files that have a leading period. 2005-07-08 20:27 we7u * src/: main.c, map_WMS.c, map_cache.c, map_cache.h, map_geo.c, map_tiger.c: Enabling the reload maps (without cache) option on the Map menu, with the back-end code in place to implement it. A few tweaks to the map_cache_del() function to return with error code under certain conditions. 2005-07-08 13:19 we7u * src/main.c: Comment changes only. 2005-07-08 12:24 we7u * src/main.c: Changed some comments. 2005-07-08 00:07 we7u * src/main.c: Implemented "Flush Entire Map Cache" function. 2005-07-07 19:22 we7u * src/xastir.h: Renaming tigermap_timeout to net_map_timeout. 2005-07-07 19:21 we7u * src/: map_geo.c, main.c, map_WMS.c, map_tiger.c, util.c, xa_config.c: Moving the tigermap slider to the file->configure->timing dialog. Changing it's label so that it is obvious it is for all internet map downloads, not just Tigermaps. Changing the tigermap_timeout global variable to net_map_timeout to more fully reflect its use. 2005-07-07 18:52 we7u * help/help-English.dat: Updating map caching lingo. Adding more special .GEO file keywords and updating some that were there to match the latest code. 2005-07-07 18:49 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding some strings for map caching controls. Tweaking another string having to do with the map download timeout slider. 2005-07-07 18:47 we7u * README.MAPS: Updating the lingo w.r.t. map caching. 2005-07-07 18:46 we7u * INSTALL: Minor comment change. 2005-07-06 22:38 we7u * src/: map_WMS.c, map_geo.c, map_tiger.c, util.c: Making the curl timeouts track with the tigermap_timeout global variable. Previously they were set to a fixed 30 second timeout. Not enough for slow links. 2005-07-06 20:38 tvrusso * config/tgr2shppoly.dbfawk: Make intermittent water polygons a pale stippled fill. 2005-07-06 18:25 we7u * src/map_geo.c: Added some comments. Made one fprintf only active in debug mode. 2005-07-06 13:35 tvrusso * scripts/Xastir_tigerpoly.py: While trying to understand why my TIGER polygon maps have so many identically-named small polygons, I discovered an error in the Xastir_tigerpoly.py script that was propagated from the original GDAL tigerpoly.py script. The TIGER/Line format has a "Type I" record that links complete chains (Type 1) to "GT-Polygons" through the "POLYIDL" and "POLYIDR" attributes. But according to the TIGER/Line documentation, a Type I record that contains identical POLYIDL and POLYIDR attributes is a line that is internal to a polygon, and should not be included in its boundary. The original tigerpoly.py script from which Xastir_tigerpoly.py was derived simply added all lines with either POLYIDL or POLYIDR to the boundary of polygon POLYID. That means that these internal points were not only incorrectly added to the boundary of POLYID, they were added twice. A simple test to throw away such "PolyChainLink" data (in the OGR parlance, "Type I record" in the TIGER parlance) removes this incorrect assembly of polygon boundaries. This does *not* fix the issue of there being lots of tiny, identically-named polygons in a given area (that's just how the data is), but it DOES correct the "Error in computing fill/hole ring" warnings I've been getting since forever, every time these TIGER/Line-converted polygon shapefiles are loaded. It also fixes the problem I had trying to import these polygon shapefiles into GRASS, which noticed and griped angrily about the topological incorrectness of the data. Unfortunately, taking advantage of this fix would require regenerating all the TIGER polygon shapefiles that are up on xastir.tamu.edu --- probably not worth the effort. But should there be a new round of corrected TIGER data that gets processed, the script is now producing (more) topologically correct shapefiles. It might be a good idea to feed this back to Frank Warmerdam, on whose tigerpoly.py script Xastir_tigerpoly.py was based. 2005-07-06 12:58 we7u * src/: main.h, map_geo.c, map_tiger.c: Adding a parameter to the draw_tiger_map() function, to be used for future implementation in the tiger code for a "refresh map w/o cache" option. 2005-07-06 12:28 we7u * src/: main.h, map_WMS.c, map_geo.c: Added caching for all types of internet maps, disabled by adding a "REFRESH" tag to the .geo file. 2005-07-06 12:27 we7u * src/map_cache.c: Added some bulletproofing and some more debug messages. 2005-07-06 12:26 we7u * src/map_tiger.c: Changed one debug message. 2005-07-06 08:27 we7u * src/map_tiger.c: Adding some comments. 2005-07-06 08:25 we7u * src/map_tif.c: Changing a printf into an fprintf. 2005-07-06 08:22 we7u * src/: hostname.c, main.c, messages.c, sound.c, x_spider.c: Changing some printf's to fprintf's, snprintf's to xastir_snprintf's. Adding timestamp to x_spider messages which are sent to the console. 2005-07-01 15:23 we7u * INSTALL, README.Getting-Started, configure.ac: Adding a "--without-map-cache" flag to configure. Updating docs to match. 2005-06-30 17:12 we7u * src/map_tiger.c: Fixing a compile problem that occurs if ImageMagick isn't installed. 2005-06-30 17:11 we7u * src/map_gdal.c: Removing "static" from the function returns of functions defined inside functions. Evidently the latest GCC enforces that restriction. 2005-06-30 17:09 we7u * README.MAPS, FAQ, README.win32, help/help-English.dat, help/help-German.dat, help/help-Portuguese.dat: Cleaning up some docs w.r.t. Terraserver info. Adding a few more FAQ entries that come up from time to time. 2005-06-30 13:29 we7u * FAQ: Adding a bit about the Terraserver zone-crossing problem. 2005-06-30 13:16 we7u * Makefile.am, terraserver-reflectivity.geo, terraserver-topo.geo, terraserver-urban.geo, terraserver.geo, toposerver.geo, src/map_geo.c: Changed the name of toposerver.geo to terraserver-topo.geo. Added more options for terraserver so that we can use all four options available currently. Put a bit more debugging code and parameter checking code into map_geo.c. 2005-06-29 09:29 we7u * src/map_gdal.c: Putting draw_shapefile_map() between ifdef's, as it isn't defined in some cases (if shapelib isn't available). 2005-06-25 17:46 tvrusso * FAQ: Just copy a FAQ heading into the TOC. 2005-06-25 17:30 tvrusso * src/maps.c: Undo bonehead commit by KM5VY (me). I had mistakenly thought that "draw_filled" was a new map index parameter, and tried to get the index_retrieve_from_file function to set defaults for shapefiles differently. This was an error, as draw_filled has always existed. There is no way to "fix up" the index when running with new code -- the user is simply going to have to go through the map properties and turn Auto on if he/she wants filled shapefiles to respect the dbfawk file's settings. The reason I thought the commit was right was that I was testing it on an index that had been passed through awk to remove the draw_filled variable. It then inserted reasonable defaults, but that's not the point. It's unfortunate that a user with an existing batch of filled shapefiles and dbfawk enabled will wind up surprised that they stopped being filled, but that's the way it is. 2005-06-25 09:02 we7u * src/util.c: A fix for digipeating: valid_path() was adding an asterisk on to the end of wideN-n/traceN-n digi's that had n!=N. This caused unused digi's that were earlier in the path to be skipped in the relay_digipeat() code. For instance a path of "wide1-1,wide2-2" was working, but a path of "wide1-1,wide2-1" was being changed into "wide1-1,wide2-1*", and the wide1-1 digi would be skipped. 2005-06-24 16:09 we7u * src/db.c: Length of temp variable was too short to handle max header length. 2005-06-23 22:55 we7u * src/map_cache.c: Adding a bunch of segfault debug code in order to find a problem that one user is having with map caching of tigermaps. 2005-06-23 13:26 we7u * AUTHORS: Adding Dan Brown to the list. 2005-06-23 13:14 we7u * AUTHORS: Adding Alan Crosswell to the list. 2005-06-23 13:10 we7u * AUTHORS: Adding Tom Russo to the list. 2005-06-23 12:27 we7u * AUTHORS: Adding Derrick to the list. 2005-06-23 09:07 tvrusso * src/maps.c: Fix migration of pre-"auto fill" map_index.sys to new format. 2005-06-22 22:47 tvrusso * src/map_shp.c: Fix broken handling of "auto" shapefile filling. There was a test of "draw_filled" to see if it was set to "auto", but if it was, then draw_filled was changed to whatever the dbfawk file "filled" value was. Since that was always 0 or 1, it meant that every shape after the first one would not have "draw_filled" set to auto anymore, and the entire shapefile would be filled with whatever that first shape's value was (on or off). 2005-06-22 12:47 we7u * src/map_shp.c: Fixing up the default polygon fill condition for when dbfawk file is not present (just a comment change) or for when dbfawk support is not compiled into Xastir, for the case where "Auto" fill is selected. 2005-06-22 12:30 we7u * README.MAPS, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_shp.c, src/maps.c, src/maps.h: Implementing an "Auto" function in the Map Properties dialog for polygon fills. "Auto" will cause a dbfawk file to be used, if it is present. The "Yes" (On) and "No" (Off) filled options that existed before will now override a dbfawk file, so you can use a Shapefile map in three different ways now from the Map Properties dialog. I use this "No" option for instance to make the NOAA Counties Shapefile into a vector map so I can overlay it on top of a raster map, use the "Yes" function to use it as a base map of the U.S., or use the "Auto" function to get all the advanced per-object coloring possible from the dbfawk file, including county names, border colors, etc. The default setting for new Shapefiles will be "Auto". Default for all other types of maps will be "No" or "Off". 2005-06-21 18:15 we7u * src/db.c: Updating some comments. 2005-06-21 18:12 we7u * src/map_tiger.c: Adding set/clear_dangerous() calls to aid in debugging segfaults. 2005-06-21 18:10 we7u * src/: util.c, util.h, map_gdal.c: Moving set_dangerous() and clear_dangerous to util.c/util.h and making them globally available. These routines set/clear a string which gets dumped out upon segfault. A debugging tool mostly. 2005-06-21 13:13 we7u * src/db.c: Moved check for zero unused digipeater fields in relay_digipeat() function down a few lines in the code, to AFTER where we reposition past the destination callsign. 2005-06-21 12:43 we7u * src/util.c: Adding checks for used-up WIDEn-N/TRACEn-N digipeater slots and for maximum total digipeats to the check_unproto_path() function. Max digipeats is only allowed to be as high as MAX_WIDES + 1, no more. For instance, if MAX_WIDES is 4, then "WIDE1-1,WIDE4-4" is legal, "WIDE1-1,WIDE,WIDE4-4", "WIDE5-5", or "WIDE,WIDE,WIDE,WIDE,WIDE,WIDE" are not. 2005-06-21 08:18 we7u * config/nwsc_ddmmyy.dbfawk: Changing back to filled and black border for the counties. It just makes too excellent of a base map at present as-is. Will tweak back to non-filled once the Xastir code is changed to allow overriding that parameter in Map Properties. 2005-06-21 08:09 we7u * config/nwsc_ddmmyy.dbfawk: Reducing the line width for the county borders. 2005-06-21 08:05 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Changing to non-filled. Will soon try to tweak Xastir code so that the filled option can be chosen in the map properties and override the dbfawk setting, so at least the counties file can be selectively chosen to be filled. It makes a good base map sometimes. 2005-06-20 13:34 we7u * src/map_cache.c: A tweak by Dan Brown to help eliminate segfaults in Tigermap caching. 2005-06-20 08:05 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Changing default fill color to dark grey instead of purple. 2005-06-17 07:35 we7u * WMSRadar.geo: Changing a comment. 2005-06-14 14:01 we7u * src/interface.c: Commenting out a debug fprintf statement. 2005-06-14 12:59 we7u * src/: interface.c, interface.h: Adding a #define in interface.h called CONVERSE_MODE. This can be set to "k" or "conv" via different defines to account for different TNC command sets. 2005-06-14 12:39 we7u * src/interface.c: Changed some comments. 2005-06-13 19:45 we7u * config/: Makefile.am, tnc-startup.tnc2: Adding a TAPR-2 style startup file. This one is mostly a copy of the tnc-startup.paccomm file for the moment, but will probably diverge from it over time. 2005-06-10 09:55 tvrusso * src/db.c: Add additional check on wx stations to aloha calculations. APRSDos only checks the symbol for "_", we were only checking if there's any WX data. I was finding that some stations with _ symbols were not being classed as wx stations, apparently because their last posit had no weather or something. Add "_" to the test. 2005-06-09 18:19 we7u * DEBUG_LEVELS: Adding Multipoint to the 2048 level description. Naming the function in main.c that must be changed if more levels are added. 2005-06-08 22:08 tvrusso * DEBUG_LEVELS, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/database.h, src/db.c, src/main.c: Several improvements of ALOHA reporting, as discussed on xastir-dev 1) Change #ifdef DEBUG_ALOHA to a debug level test (2048) 2) Add periodic display of ALOHA range in status line 3) Add a "View->ALOHA Statistics" menu option. Pops up a dialog with ALOHA range, number of stations in ALOHA circle, count of various types of stations, and age of ALOHA calculation. 2005-06-08 09:00 we7u * FAQ: Adding a bit about how to turn off the aloha circle display. 2005-06-08 08:45 we7u * src/main.c: Calculating the Aloha circle even if the feature is turned off. This means that if the feature is turned back on again the circle will be accurate. The processing occurs so seldom anyway that it's not much of a hit. 2005-06-07 22:33 tvrusso * src/map_tiger.c: Fix initialization of local_filename[0] so that gcc 2.95 can compile this file. 2005-06-07 22:16 tvrusso * src/db.c: Fix mistake in logic of aloha_distance() that was letting some oddly configured mobiles to slip through the cracks (those with trackpoints and no speed). 2005-06-07 13:04 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the aloha circle string to "Display" instead of "Disable". 2005-06-07 13:01 we7u * src/: db.c, main.c: Fixing some minor errors in the aloha toggle code. Changing the name of the toggle and callback to be more consistent with the rest of the code. 2005-06-07 12:54 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Adding an option to disable the Aloha Circle. This option is not saved to the config file, by choice. It's intended that the Aloha circle be on the map for the default case so that people might make use of it. The toggle has been added for those rare cases where the Aloha Circle needs to be removed from the screen. 2005-06-07 09:25 we7u * src/map_tiger.c: Reorganization by Dan Brown, n8ysz. This is in preparation for another way-cool feature that Dan is working on. Stay tuned! 2005-06-07 05:33 tvrusso * src/draw_symbols.h: Declare draw_aloha_circle to suppress compilation warnings. 2005-06-06 23:06 tvrusso * src/database.h: Put an ifdef around a struct element only used for debugging. This should cut down on memory use during ALOHA calculation when not debugging. 2005-06-06 22:54 tvrusso * FAQ, src/database.h, src/db.c, src/draw_symbols.c, src/main.c: Feature request 1043058 Add function to display ALOHA circles on the map. ALOHA radius calculated according to Bob Bruninga's alohacir.txt file, and private communications. 2005-06-02 08:27 we7u * README.win32: Adding a note about shutting down applications before updating files. 2005-06-01 13:11 we7u * scripts/Makefile.am: Adding get_shapelib.sh to list of scripts to install. 2005-06-01 13:06 we7u * INSTALL, README.win32: Adding notes about the xastir/scripts/get_shapelib.sh script. 2005-06-01 13:04 we7u * scripts/get_shapelib.sh: Script to get/install Shapelib by Dan Brown, n8ysz. Thanks! 2005-06-01 12:24 we7u * INSTALL, README.win32, src/db.c, src/gps.c: Adding some notes about building Shapelib that Dan Brown came up with. Tweaking the GPS GPGGA and GPRMC comments in the sources. 2005-05-31 19:48 tvrusso * README.MAPS: Remove statement that is no longer true. 2005-05-31 15:25 tvrusso * src/map_tif.c: Make lat/lon rasters subject to same kinds of scan-line-skipping optimizations as UTM rasters have always had. The trick was to realize that "scale_y" has units of "hundredths of seconds per pixel" and that PixelScale in lat/long rasters has the units of "degrees per pixel". 2005-05-31 12:32 we7u * WMSRadar.geo, src/main.h, src/map_WMS.c, src/map_geo.c, src/maps.h: Implementing TRANSPARENT keyword for WMS maps and changing WMSradar.geo to correspond. 2005-05-25 12:12 gstueve * src/alert.c: Fix spelling in comment. 2005-05-25 11:42 we7u * WMSRadar.geo, src/map_WMS.c: Moving the VERSION tag into the .geo file. Some servers are picky about this, so it can't be hard-coded. 2005-05-24 12:49 we7u * src/map_WMS.c: Adding/changing some comments. 2005-05-24 12:21 we7u * src/map_WMS.c: Moving more of the WMS parameters into the .geo file instead of hard-coding them. 2005-05-24 12:20 we7u * WMSRadar.geo: Moving more of the parameters into the .geo file instead of hard-coding them. 2005-05-24 07:23 we7u * WMSRadar.geo: Getting rid of the county outlines in the downloaded image. 2005-05-23 13:16 we7u * src/map_WMS.c: Corected some comments. Turned off debug output. 2005-05-23 12:59 we7u * WMSRadar.geo, src/map_WMS.c: Moving more of the parameters into the .geo file instead of hard-coded (allows more options to be specified via the .geo files). Tweaked the scaling so that the vertical scaling is correct now. 2005-05-23 12:30 we7u * src/util.c: Tweaking the lat/long string conversion routines so they'll handle more input formats. 2005-05-20 07:33 we7u * src/map_WMS.c: Small tweaks to the URL generation for WMS servers. Map registration is not correct yet. 2005-05-19 08:43 we7u * src/.cvsignore: Adding "xastir" as well so that we won't see that in the CVS status listings. It's obviously a derived file. 2005-05-19 08:26 we7u * .cvsignore, callpass/.cvsignore, config/.cvsignore, help/.cvsignore, m4/.cvsignore, scripts/.cvsignore, src/.cvsignore, src/rtree/.cvsignore, symbols/.cvsignore: Adding more lines to the .cvsignore files in order to clean up CVS status listings. 2005-05-19 08:01 we7u * Makefile.am, WMSRadar.geo, src/Makefile.am, src/main.h, src/map_WMS.c, src/map_geo.c: Adding initial support for WMS map formats. This is not complete yet, but the functionality is enough to give a taste for what is possible in the near future. Registration is still a bit off plus we need to add methods for the user to specify layers desired, specifying WMS servers from the GUI, etc. 2005-05-18 12:24 we7u * src/gps.c: Modified parsing of GPGGA and GPRMC NMEA sentences to handle more variations in the sentence structure. 2005-05-18 12:23 we7u * src/db.c: Changing some comments and debug statements having to do with GPGGA and GPRMC NMEA sentence parsing. 2005-05-18 09:41 we7u * src/gps.c: Tweak to the GPGGA parsing to allow a '3' for GPS fix quality. 2005-05-17 13:41 we7u * src/util.c: I've had this patch around for a couple of weeks. It should allow matching on non-numeric SSID's for messaging now, such as "WHO-IS" and "AE5PL-EM", which are the two test cases that broke messaging earlier. It has not been fully tested on RF yet, but appears to work when directly on the internet feeds. 2005-05-09 10:09 we7u * configure.ac, help/help-English.dat: Setting up for further CVS development of Xastir. Changing rev to 1.5.1 to differentiate it from the 1.5.0 stable release. Added a new "What's New in Xastir BETA" section to the help-English.dat file. 2005-05-09 09:34 we7u * README.Contributing, README.Getting-Started, configure.ac, help/help-English.dat: Updating for soon to be done 1.5.0 release. 2005-05-09 09:32 we7u * src/db.c: Spelling fix in comment. No code changes. 2005-05-06 13:59 we7u * src/awk.c: Another tweak by by John Laxson, KC0PZN. This one fixes something that I messed up when I incorporated his first patch. 2005-05-05 12:36 we7u * src/interface.c: Changed one comment. No code changes. 2005-05-05 12:23 we7u * src/awk.c: Tweak by John Laxson, KC0PZN, to speed up dbfawk on MacOSX. Thanks! 2005-05-05 12:19 we7u * README: Getting rid of version number where it's not needed. Will save us some work in the future. 2005-04-29 15:06 kd6zwr * src/interface.c: Fixes for segmentation faults on Solaris. Sending a NULL pointer to a %s argument to any of the *printf() functions (actually strlen() inside it) causes the fault. This patch intializes two vars to "" instead of NULL, {Which is OK!!} protects a function by whacking NULLs into ""s, and moves a debug printf below a NULL check. 2005-04-26 11:24 we7u * src/interface.c: If an interface goes down due to a connection being lost or inactivity, the 1st check_ports() call will bring it back up now. Previously it would wait for the 2nd check_ports() call before bringing it back up. 2005-04-25 12:44 we7u * README.MAPS: Added a paragraph about splitting large Shapefiles into tiles. 2005-04-25 12:44 we7u * README.Getting-Started: Minor changes to a couple of sentences. 2005-04-19 10:39 we7u * src/track_gui.c: Fix by David Flood, kd7myc. Turns of TrackMe button if you leave tracking on but change the call being tracked via the menus. Thanks! 2005-04-17 21:31 rzg * help/help-English.dat: Updated the "what's new", shamelessly ripping parts of curt's release notes because I'm behind in keeping up with CVS. :-P 2005-04-15 10:42 we7u * xastir.spec.in: Adding a few more docs to the doc list. 2005-04-15 10:02 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Changes by Andreas Bier, DL1HRC, to allow setting a tnc2multi into KISS mode via a togglebutton on the interface dialog. We can probably extend this later to put other types of TNC's into KISS mode and/or to take them out of KISS mode when shutting down the interface. I also changed the default for new interfaces to have RELAY/WIDE1-1 digipeat turned off. 2005-04-15 09:30 we7u * README.Contributing: More info about diff's and patching. 2005-04-15 09:01 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changes by Andreas Bier, DL1HRC. Thanks! 2005-04-14 12:38 we7u * README.Getting-Started: Adding more notes about the 2nd-tier servers. 2005-04-14 11:31 we7u * Makefile.am: Adding the new doc into the Makefile structure. 2005-04-14 10:35 we7u * README.Contributing: Adding a document to assist budding developers. 2005-04-13 08:50 we7u * src/util.c: Fixing a path check problem. It wasn't verifying that the char before the '-' was a digit before applying N-n checks to the callsign. 2005-04-12 21:12 we7u * README.Getting-Started: Pointing to a list of 2nd-tier servers instead of suggesting Firenet.us. 2005-04-12 08:50 we7u * help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, src/interface.c: Changing the default path. Changing the docs to match. 2005-04-11 13:07 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys, tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: Changing from RELAY to WIDE1-1 in prompts and TNC startup files. 2005-04-11 12:51 we7u * FAQ, README.Getting-Started: Updating the path discussions to cover the new scheme (WIDE1-1 instead of RELAY). 2005-04-06 12:26 we7u * src/: db.c, util.c: Making the "RELAY" digipeat work with either RELAY or WIDE1-1, per the latest APRSSIG recommendations on how to do paths and digipeating. 2005-04-06 10:03 we7u * src/util.c: Allowing WIDE1-1 as a RELAY type of callsign per the new paradism. 2005-03-31 12:43 we7u * src/: db.c, util.c: Fixes to make the new WHO-IS server work with Xastir. 2005-03-30 09:12 we7u * src/: map_geo.c, map_tiger.c, util.c: Changing text of one type of error message. 2005-03-25 22:33 we7u * README.MAPS: Added a note about a blemish in the Haversine formula we use for distance calculation. 2005-03-25 12:53 we7u * scripts/permutations.pl: Changes to the comments/description. 2005-03-25 12:26 we7u * src/datum.h: Changing some comments. 2005-03-25 09:06 we7u * README.MAPS: Added a summary regarding our distance/angle/area calculations. 2005-03-24 12:25 we7u * src/: datum.h, main.c, util.c: Switching to Gerry-recommended Earth radii plus putting them into central defines in datum.h. That makes them easier to update in the future. 2005-03-23 22:05 we7u * src/main.c: Converting the Measure function from calculating area via planar geometry to computing it using spherical calculations. It should be much closer to reality now, particularly as one zooms out. 2005-03-23 21:57 we7u * src/util.c: Changing some comments. 2005-03-23 21:51 we7u * src/util.h: Making a couple of routines available to other modules. 2005-03-23 12:36 we7u * src/util.c: Converting the distance calculations from using the Law of Cosines for Spherical Geometry to using the Haversine Formula. This should be more accurate for shorter distances, no real change for longer distances. 2005-03-23 09:33 we7u * src/main.c: Bumping the check interval for inactivity from 1 minute to 5 minutes. This means that if we lose an internet connection we might not get it back for between 10 to 15 minutes (instead of the current 2 to 3 minutes), but it also means that server connections won't bounce up and down as much if there are few packets coming down the pipe. One packet every 5 minutes is enough to keep the connection going. 2005-03-22 15:10 we7u * src/util.c: Changed some comments. 2005-03-22 13:11 we7u * src/draw_symbols.c: Added/changed some comments. 2005-03-22 12:38 we7u * README.Getting-Started: Added an enumeration of the various ways of controlling Xastir itself. 2005-03-21 20:57 we7u * src/: database.h, db.c, draw_symbols.c: Fixes for DF objects to make the beamwidths and angles correct. Also fixed the "Unusable" beamwidth so that it still appears as a DF object in the Object->Modify dialog. 2005-03-20 16:33 tvrusso * src/testawk.c: Add initializer for pattern, add variable for label_color, and add appropriate code so that dbfawk files that set label_color can be tested. 2005-03-18 13:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/util.c, src/db.c: Fixing decoding of compressed DF beam objects/items. Fixing the display in Station Info of DF stations. 2005-03-18 12:09 we7u * src/: db.c, main.c: Fixes for varying truncation on object/item comments. We were allowing comments that were longer than 43 chars, which were truncated during later transmits by check_and_transmit_objects_items(). We now no longer allow the extra length packets to be transmitted. The spaces that were added for Pmin/Pmax are now no longer added: that was another cause for the varying truncation of the comment. Fixed the object/item transmit routines so that we can now send compressed-mode for all types. The decode routines now have to catch up. 2005-03-17 13:16 we7u * src/db.c: Better implmentation of my debug tweak that will work with more compilers. 2005-03-17 13:07 we7u * src/db.c: Removing some comments. 2005-03-17 12:30 we7u * src/draw_symbols.c: More work on dead-reckoning to position the ghost symbols and the dashed lines correctly. Have disabled the arcs for now as the positioning is not correct for them with the current code. 2005-03-17 12:28 we7u * src/util.c: Added poor-man's rounding to the places we construct the transmitted lat/long's. This helps with dead-reckoning of symbols at close-in zoom levels. 2005-03-17 12:27 we7u * src/db.c: Added a define and some ifndef's to make some debug easier. 2005-03-17 07:34 we7u * src/map_cache.c: Tweaks by Dan Brown, N8YSZ. 2005-03-17 07:21 we7u * src/database.h: Changed one comment. 2005-03-16 13:36 we7u * src/: igate.c, interface.c, interface_gui.c, location_gui.c, main.c, map_geo.c, map_gnis.c, map_shp.c, map_tif.c, maps.c, util.c, wx.c, xa_config.c: Checking the return codes for scanf/sscanf/fscanf functions. 2005-03-16 12:15 we7u * src/: alert.c, db.c: Checking the return codes of scanf/sscanf/fscanf functions. 2005-03-16 11:34 we7u * src/util.c: A workaround for an sscanf() bug that shows up on Cygwin. It wasn't parsing the lat/long properly in compress_posit(). Re-coded the routine to do everything manually. The other 60 or so places that scanf() and it's variants are used should also be checked for correct operation on Cygwin. 2005-03-15 16:50 we7u * src/util.c: Fix for incorrect compressed packets on Cygwin. Evidently the 'N' in the latitude is getting passed to the routine as an 'n', which causes the problem. The root cause of the problem is probably that the latitude variable is getting messed up sometime earlier. 2005-03-15 11:25 we7u * src/wx.c: Tweaks for Davis WX station by Clay Jackson, n7qnm. 2005-03-14 17:58 we7u * src/: database.h, db.c: Decoding weather from "Position with Timestamp no APRS messaging" packets. 2005-03-14 13:15 we7u * src/: database.h, db.c, main.c: Fixing a bug that crept in while coding some object/item stuff. Moving some comments to a more appropriate place. Commenting out the last_modified_time variable for now, as it's not actually implemented in the dead-reckoning code yet. 2005-03-13 19:11 we7u * src/: database.h, db.c, main.c: Dead-reckoning of objects and items: Working a bit better with this version. We now use the latest DR'ed position when making a change to the object/item. Moving a DR'ed object/item works. One thing that doesn't work now is trying to update the position of a moving object/item using the Modify dialog: The lat/long boxes are ignored now in favor of the DR'ed position. Also note that the on-screen DR function is a bit off in speed and direction from the more accurate function that actually moves the object along. This is yet to be fixed. 2005-03-11 22:38 we7u * src/db.c: Dead-reckoning for compressed objects/items as well. 2005-03-11 22:10 we7u * src/db.c: Better accuracy for the angle calculations for object dead-reckoning. 2005-03-11 21:19 we7u * src/db.c: Transmitting dead-reckoned object/item positions is starting to work in this version. More to do yet, but it could be useful as-is. 2005-03-11 08:45 we7u * src/db.c: Commenting out the code that moves dead-reckoned objects. Not correct yet. 2005-03-11 07:52 we7u * src/db.c: Initial version of dead-reckoning for objects. Dead-reckoned positions are transmitted now at the decaying transmit interval. Still need to do more work on this, like computing the latest dead-reckoned position and transmitting that position at the point an object/item is changed, correcting the disparity between the on-screen DR and the transmitted DR (on-screen DR appears to compute angle based on screen pixels, while the transmitted DR computes angle based on lat/long). The log file is ignored in these changes also: If Xastir crashes or is shut down, time for the DR object will be lost and it will start DR'ing at the point it was last transmitted at before shutdown. 2005-03-10 13:02 we7u * src/: database.h, db.c, main.c: Preliminary work for fixing dead-reckoning of objects/items. More to do yet, but this last_modified_time variable is needed to get started on the problem. 2005-03-08 13:05 we7u * src/main.c: Mods by Dan Brown, N8YSZ. Prevent multiple Xastir's from getting run by a single user. The prevents config files from getting corrupted. 2005-03-08 10:31 we7u * FAQ: Updates by Dan Brown and myself. 2005-03-08 09:16 tvrusso * configure.ac: Fix dummm mistake in help text for --with-rtree 2005-03-03 11:41 we7u * README.MAPS: Added the temporary Wiki location. 2005-03-03 11:39 we7u * README.MAPS: Added a note about the populated places GNIS file. 2005-03-03 09:24 we7u * README: Adding a note about n1ofz's web page and binary Xastir installation. 2005-03-02 11:47 we7u * README: Added a note about gating stations, objects, and items to RF. 2005-03-02 11:41 we7u * src/igate.c: Removing a debug printf that is used for checking out gating to RF. 2005-03-02 09:39 we7u * src/interface_gui.c: Fix for an annoying warning that X11 puts out when you add an interface in Xastir. 2005-03-02 08:56 tvrusso * src/map_tif.c: Comment out warning when a geotiff file has no PCS. Geotiffs without PCS (Projected Coordinate System) tags are assumed to be lat/lon rasters. Now that this capability is being more widely used, especially by users outside the US, this warning is just an annoyance. It was only there because it was once cause to reject a raster if it had no PCS. 2005-03-01 12:55 we7u * src/igate.c: Allowing nws-stations.txt changes to take effect right away for stations being gated to RF. If the file has been changed, the in-memory database gets updated. 2005-03-01 12:32 we7u * src/main.c: Allow re-creating of an object or item that has been killed and is still in the database. Previous code wouldn't allow that and brought up a warning popup. Now the popup happens only if a "live" object/item is in the database with the same name. 2005-03-01 12:05 we7u * src/: igate.h, db.c, igate.c: Igating of specific objects/items to RF is now possible by listing the object or item name in data/nws-stations.txt. The listing is case-insensitive. Putting a wild-card source callsign in that file doesn't get objects/items from that station igated to RF, but other packets from that callsign do get gated. Objects/items have to be specifically listed by name, as the code stands now. 2005-03-01 11:36 we7u * src/db.c: Proper RF gating of objects/items when the originating callsign is specified in the data/nws-stations.txt file. The previous code was incorrect w.r.t. object/item gating. 2005-03-01 09:09 we7u * src/: db.c, igate.c: Initial attempt at gating individual stations through to RF, if those stations are spelled out in the data/nws-stations.txt file. Wildcarding is inherent, so "we7u" will match "we7u", "we7ua", and "we7uaa" through "we7uzz". This change also means that any packets (like posits perhaps) from an NWS station that are not weather alerts will now get gated to RF. Hopefully this won't be a problem. I've left an fprintf() in the code so you'll see which new packets are gated through to RF (prints to STDERR). We'll remove that fprintf() later once we're satisfied with the new operation. 2005-02-28 09:11 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Fixing the selected stations count (on status bar) for dead-reckoned stations. They were getting counted twice, once for the non-ghosted and once for the ghosted symbol. 2005-02-26 18:04 shadow * INSTALL: update imagemagick info 2005-02-24 16:01 we7u * FAQ: Adding instructions for running more than one Xastir at once on the same machine. 2005-02-20 10:07 tvrusso * README: Bring some of the FreeBSD notes up to date. It is no longer necessary to use "gmake" instead of "make" with xastir's build on FreeBSD, and the comments about autoconf versions were very old. Also, change reference to the "current" version 1.1.x of xastir. 2005-02-18 11:38 we7u * README: Changes suggested by Dan Brown, plus another one or two added by me. Fixing mailing list and Xastir link addresses. 2005-02-17 01:14 we7u * src/util.c: Better version of the function which checks the unproto paths as they are entered by the user. This one checks for all the proper relations between the n-N numbers, and limits them to MAX_WIDES (which is set in util.h). 2005-02-16 15:20 tvrusso * src/util.c: Repair check_unproto_path to fix mistakes I'd made in last commit (atoi() on a character rather than string), and rearrange things so that some odd usages in the original code still work. I have not cleaned it up properly. Instances of changing character pointers in a conditional remain as they were in original code, and flagging "bad" paths like "WIDE1-2" results in "Path too long" error message when it should say instead "very strange path". But it will NOT reject paths like WIDE2-1 anymore, and will accept paths like WIDE7-2 (even though the first digit is essentially meaningless when used this way). This time I actually tested these fixes and they work. 2005-02-16 13:38 tvrusso * src/util.c: Simple change to stop "WIDEN-n" where N!=n being flagged as a "Bad Path" Instead, it now checks that N>=n, and only reports "NMessage Traffic window to single-line format, unless the line is long in which case it wraps. 2004-12-22 19:09 tvrusso * src/map_shp.c: Fix for a logic mistake I introduced last night. This might be the source of the unpredictable segfaults I'm seeing at random times hours apart. If not, I'll get that one pinned down ASAP. This was still a mistake, even if it's not the source of those. 2004-12-22 14:56 we7u * src/: database.h, db.c, main.c, main.h: Fixing selected station count so that it updates immediately on the status line if the number changes. Change the "stations" variable to "station_count" to make it easier to grep for in the future. 2004-12-22 14:49 we7u * src/interface_gui.c: Fixing Interface Control dialog so that it looks the same after properties have been changed. It had been missing the up/down designation per port. 2004-12-22 10:07 we7u * src/: main.c, main.h, db.c: Making the selected stations count on the status line update quickly when it changes. 2004-12-22 08:44 we7u * src/main.c: Fixing the Select All button in Map Chooser->Properties so that it doesn't toggle the selections, but actually does what its label says it'll do. 2004-12-21 23:18 we7u * src/db.c: Changes to Group Messages/Queries so that multi-line messages will show in the dialog, and so that messages that don't require ack's don't show up as unacked (highlighted) in the dialog. 2004-12-21 22:48 tvrusso * src/rtree/node.c: Clean up debugging output mistakenly committed. 2004-12-21 22:22 tvrusso * src/: main.c, map_shp.c, maps.c, maps.h, shp_hash.c, shp_hash.h, rtree/node.c: Round of RTree usage optimizations. 1) If a shapefile's bounding box is entirely contained in the current viewport, don't bother doing an RTreeSearch for visible shapes --- just read the file sequentially. Don't even bother accessing the hash table for the file. 2) Store a time stamp every time a shapefiles hash table entry is accessed. 3) Every hour, walk through the hash table and purge records that have not been accessed in 1 hour. (this needs to become a configurable time) This should improve memory usage for a few special use cases, and free up RAM wasted on shapefiles that are not really going to benefit from having the RTree fast lookup. I've not run this for long times to see how the memory usage behaves --- once the RTree is allocated and freed, the processes resident size doesn't seem to drop down, but it does make the space that was freed available for indexing a different shapefile. There are probably many ways to make this even more flexible and automatically adaptive to the users' usage patterns. This should be a good start, though. 2004-12-21 21:08 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.h, src/main.c: The ST_DIRECT stuff appears to be fixed now. This tweak makes the APRS-Direct query work properly again plus adds a selected/total stations display to the status line where there was just total stations listed before. 2004-12-21 19:23 we7u * src/db.c: Another tweak to the ST_DIRECT stuff. This tweak causes us to overwrite the saved path only if 1) the current packet is direct, 2) the ST_DIRECT path is not set, or 3) ST_DIRECT is set but nothing has been heard direct for the last hour. The end result is that we should see the most recent directly-heard path in Station Info, unless the station has not been heard direct for the last hour, in which case we may see a digipeated path or an INET path there. 2004-12-21 17:35 we7u * src/db.c: More work on fixing up the ST_DIRECT flag. 2004-12-21 12:29 we7u * src/: database.h, db.c: Attempting a fix to the ST_DIRECT bit being set incorrectly at times, for stations that straddle both RF and INET feeds. Lots of things were inter-related here, so this may not be the final fix. It should be better than the old code though. 2004-12-20 17:58 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/main.c, src/messages.c: Combining the two Interface dialogs into one dialog. Fixing the Map Chooser->Properties dialog so that it keeps the selected list each time you change something. 2004-12-20 14:14 tvrusso * src/: map_shp.c, shp_hash.c, rtree/index.c, rtree/index.h, rtree/node.c, rtree/split_l.c: Give GCC fewer things to whine about. In each case here where gcc whined about possible use of variables before initialization, code was in place that would always set that variable first. But it was all in conditionals that gcc couldn't possibly know were always true before any use of the variables. Added initializers to shut it up. 2004-12-19 21:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages_gui.c: Fixing transmit of messags so that the three illegal chars (per the spec) cannot be transmitted. We now substitute '.' for any of those three, then alert the operator that we've done so via a popup message. 2004-12-19 18:56 we7u * src/db.c: Added code to check for incorrect case in queries and notify us. This may be used to send a message back to the originator asking them to please follow the APRS spec, or the messages may be ignored. They go to STDERR currently. The same code was added to the unimplemented query sections, but commented out. 2004-12-19 00:44 we7u * src/db.c: Fixing the Station Info dialog so that it will display stations in the Station Chooser dialog +/- 20 pixels in either direction from the mouse pointer. 2004-12-18 17:08 we7u * src/x_spider.c: Adding some returns in the case of a few socket & pipe errors, to get the process to close and not waste CPU on Cygwin. 2004-12-18 13:06 tvrusso * configure.ac, src/Makefile.am: Change configure and makefiles so that if the user does not ask for rtree, the library isn't even built and the -L/-l options aren't used. Not doing this before was just laziness on my part. 2004-12-18 12:43 tvrusso * src/rtree/Makefile.in: Removing something that should not have been committed --- Makefile.in is supposed to be created by bootstrap. 2004-12-18 12:29 tvrusso * src/rtree/sources.htm: Fix up pointers to original source code location and author's web site. 2004-12-17 23:51 we7u * src/shp_hash.c: Fixing up some #ifdef's for the shapefil.h include. 2004-12-17 17:58 we7u * src/x_spider.c: Changing some error messages. 2004-12-17 04:15 tvrusso * configure.ac, src/Makefile.am, src/map_shp.c, src/maps.c, src/maps.h, src/shp_hash.c, src/shp_hash.h, src/rtree/Makefile.am, src/rtree/Makefile.in, src/rtree/card.c, src/rtree/card.h, src/rtree/gammavol.c, src/rtree/index.c, src/rtree/index.h, src/rtree/node.c, src/rtree/rect.c, src/rtree/sources.htm, src/rtree/sphvol.c, src/rtree/split_l.c, src/rtree/split_l.h, src/rtree/split_q.c, src/rtree/split_q.h: Experimental "RTree" spatial indexing feature. To enable, use "--with-rtree" in configure. Current implementation is very memory intensive, but speeds up rendering of large shapefiles. Needs further work. without the "--with-rtree" option the code behaves as before, all changes are ifdef'd out. 2004-12-16 20:36 we7u * src/x_spider.c: Added a couple of test for a closed pipe or socket. Trying to solve an x_spider problem on Cygwin where we get error messages at the server's STDERR when a client disconnects. 2004-12-16 12:40 tvrusso * src/db.c: Exclude own station from "DIRECTS" reply to APRSD query. 2004-12-15 22:01 tvrusso * src/testawk.c: Minor tweaks to README.MAPS Change testawk.c to remove a feature that uses command line args as a dbfawk program literal --- this is why usages like testawk foo.dbfawk foo.bar (a likely guess at usage) lead to segfaults instead of helpful messages. Change usage string to reflect reality. I hope nobody really used that feature, but it doesn't seem likely, and it was definitely the case that the segfaults were confusing users. 2004-12-15 21:29 tvrusso * README.MAPS, src/db.c: README.MAPS: add a little explanation of how to use testawk (which has the habit of segfaulting on commandlines it doesn't understand) db.c: An attempt to make APRSD (Direct Station Query) responses not be limited to a single line when there are too many direct stations to fit on that line. I have not been able to test the db.c change yet, as I can't hear more than 5 stations directly, so I have to commit this and wait till my partner in crime in Albuquerque can get this update, rebuild xastir, and run long enough to hear a few dozen direct stations so I can query him. 2004-12-15 13:58 tvrusso * config/Makefile.am: Add 24kgrid.dbfawk to list of things to install. 2004-12-15 09:56 tvrusso * config/24kgrid.dbfawk: Adding dbfawk for the 24kgrid shapefile from geocomm.com. 2004-12-15 09:03 we7u * README.MAPS: Added a pointer to the Canadian shapefile street maps. 2004-12-14 20:30 we7u * src/map_tiger.c: Moving the "Loading..." message to below where the variable is initialized which it uses to print. 2004-12-14 13:26 we7u * README.MAPS: Making the IMAGESIZE line requirements more noticeable. 2004-12-14 12:17 we7u * src/: database.h, db.c, main.c: Adding interface numbers to the Incoming Data dialog. "sp" for packet received on the server port (port 2023), 1 or 2-digit numbers for anything else. 2004-12-14 11:39 we7u * src/interface.c: Fixing the double-header problem for packets heading out port 2023. Hopefully this is the last of it. 2004-12-14 08:01 we7u * src/interface_gui.c: Fix to prevent bringing up an interface upon changing its properties. Fix by Dan Brown, n8ysz. 2004-12-12 19:19 tvrusso * src/db.c: Change to look for message ID after *final* "{" in a message rather than first. This improves interoperability with UI-View, which will ack a malformed message like: KB7ZVA-1>APU25N,TCPIP*,qAC,KB7ZVA-1::KM5VY :{Duh{76 (the first { is technically illegal) by acking message 76, whereas prior to this commit xastir would see the message ID as "Duh{7" and do: KM5VY>APX142,TCPIP*::KB7ZVA-1 :ackDuh{7 causing UI-View to ack message 7, and assorted other nonsense. Tested only by having one instance of xastir send a malformed message to another and seeing the ack of the real message ID. 2004-12-12 14:21 tvrusso * config/tgr2shppoly.dbfawk, src/map_shp.c: Make polygon draws respect the "skip_it" step --- until now it was not possible to use the dbfawk variable "display_level" to shut off drawing specific polygons at large zooms. Don't know why I hadn't noticed that all that wasn't working. Now that they're being paid attention to, had to tweak all the display_levels in tgr2shppoly.dbfawk so things show up at reasonable levels. 2004-12-09 18:35 we7u * configure.ac: Fixing the comment so that it is accurate. 2004-12-09 18:32 we7u * configure.ac: Adding a case statement for Cygwin that will change "-O2" compiler flags to " ". This should speed up Cygwin compiling a great deal, at the expense of slightly larger, more inefficent executables. 2004-12-09 12:27 we7u * INSTALL, README.Getting-Started, configure.ac, update-xastir: Making --without-errorpopups be the default. Must add "--with-errorpopups" in order to get the previous operation now. Added some code to configure.ac to remove the "-g" compiler option, so we'll get stripped executables by default now. 2004-12-08 08:57 we7u * src/: gps.c, interface_gui.c: Disabling the time-set togglebutton when running Cygwin. 2004-12-08 06:58 we7u * src/main.c: Finally, a fix for the keyboard modifiers problem, where any modifiers enabled will mess up the mouse menus. The problem turned out to be a Motif 2.x function that doesn't work properly with modifiers. Switching to the Motif 1.x function that accomplishes the same thing fixed it. 2004-12-07 21:45 we7u * src/: map_geo.c, map_tiger.c, util.c: Conditionally compiling various libcurl calls into the code based on libcurl version. 2004-12-07 11:39 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding some currently unused options for libcurl. These are options that were added recently, so only some libcurl versions have them. They have to do with ftp and http proxying. 2004-12-07 10:48 we7u * FAQ: Changed the proxy note a bit. 2004-12-07 09:48 we7u * FAQ: Added instructions for getting through and http proxy server. 2004-12-07 09:32 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding another libcurl option so that it can read the ~/.netrc file. This is needed by those using http proxy servers so they can get through the firewall. 2004-12-07 00:05 we7u * src/: util.c, util.h: Added a new define to util.h so that the maximum WIDE/TRACE digi's can be specified. 2004-12-06 23:16 we7u * src/util.c: Fix to allow multiple specific callsigns in path without Xastir complaining about it. 2004-12-06 22:01 we7u * src/: interface.c, messages.c, view_message_gui.c: Some HP/UX fixes by Dan Brown. Another fix for transmit KISS packets, getting rid of 0x00 bytes between the KISS frames. 2004-12-05 13:46 we7u * scripts/Makefile.am: Added get-gnis to the list. 2004-12-05 13:41 we7u * scripts/get-gnis: Script to snag GNIS files from the download site. Written by Dan Brown, N8YSZ. 2004-12-05 13:20 we7u * src/: map_cache.c, map_cache.h: More good tweaks by Dan Brown, N8YSZ. 2004-12-04 10:05 we7u * README.MAPS: Added a writeup for map caching, courtesy of Dan Brown, n8ysz. 2004-12-04 08:56 we7u * FAQ: Added a bit about the MAGICK_HOME variable. 2004-12-04 08:49 we7u * FAQ: Added Festival debugging info. 2004-12-01 11:45 we7u * src/: messages.c, messages_gui.c: Added some comments. Fixed multi-line messages so that they appear correctly in the Send Message dialog. 2004-11-30 20:34 we7u * src/: database.h, db.c, messages.c: Adding the tries counter to the Send Message dialog. 2004-11-30 14:59 tvrusso * config/tgr2shppoly.dbfawk: Another really minor tweak to tiger polygon shapefile colorings. Looks like there are no easily selected (by CFCC) city boundaries in the files created by Xastir_tigerpoly.py, which makes it impossible to color them with the current dbfawk file. Gonna have to figure that out. 2004-11-30 13:23 we7u * src/db.c: Variable-length non-highlighting for the interval timer value. Lets us keep the line as short as possible yet still do the highlighting in the correct place (the message text). 2004-11-30 13:12 we7u * src/: database.h, db.c, messages.c: Displaying the message timer interval in the Send Message dialog for active messages. 2004-11-30 12:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/messages.c, src/messages.h, src/messages_gui.c: Updates to messenging. We can now see queued messages before they get to the transmit stage. New button added to kick the timer back to original values (to get a QSO going again). Timer value is currently sent to STDERR, but will eventually be placed into the Send Message GUI as well. 2004-11-30 10:43 tvrusso * config/tgr2shppoly.dbfawk, config/xastir.rgb, src/color.h, src/main.c: changes to coloration of shapefile tiger polygons. Matches online colors a little better now. 2004-11-29 22:56 we7u * src/: map_tiger.c, map_cache.c, map_cache.h: More map caching mods by Dan Brown, n8ysz. 2004-11-29 21:14 we7u * src/messages.c: Getting rid of extra message transmit before timeout. This causes us to transmit exactly MAX_TRIES times, instead of MAX_TRIES + 1. 2004-11-29 12:55 we7u * src/: database.h, db.c, messages.c: Adding a "CANCELLED" indicator to the Send Message box for those messages that made it to transmit from the queue but got manually cancelled by the user. 2004-11-29 11:58 we7u * src/: messages.h, messages.c: More RF-friendly decaying algorithm for messages. We start at 7 seconds and double the interval each time. Timeout occurs at about 2 hours if no ACK received. 2004-11-29 11:37 we7u * src/x_spider.c: Changing from LF to CRLF in lines sent to clients which have connected to the server port. 2004-11-28 10:03 tvrusso * acinclude.m4: Change probe for db.h to use AC_TRY_COMPILE instead of AC_CHECK_HEADER, so that we can apply the same usability test that is present in map_cache.c. 2004-11-27 18:56 we7u * src/x_spider.c: Making sure that lines sent out the server port have "\r\n" at the end. Before we just had '\r', which doesn't correspond to the way the internet servers did it. 2004-11-25 22:10 we7u * README.win32: Completing the GDAL/OGR library instructions for Cygwin. 2004-11-25 17:35 we7u * README.win32: Adding Dave Flood's comments about compiling GDAL/OGR under Cygwin. 2004-11-23 09:19 we7u * scripts/inf2geo.pl: Added usage messages if invoked without parameters. 2004-11-22 08:59 we7u * update-xastir: Adding timestamps and output to make.log for each step. 2004-11-20 22:26 we7u * acinclude.m4: A small change to hopefully make configure find the correct convert.exe on Cygwin/Windows installations. 2004-11-19 22:13 we7u * README.win32: Adding a note about documenting the system variables soas to guard against changes in the future. 2004-11-19 19:15 we7u * README.win32: Adding info at the top about CD installs that are available. 2004-11-19 18:49 we7u * src/: map_geo.c, map_tiger.c, util.c: Backing out a few libcurl options that aren't in earlier libcurl packages. 2004-11-19 11:01 we7u * README.win32: Getting the db libraries listed properly. 2004-11-19 08:26 we7u * update-xastir: Change in a comment. 2004-11-19 08:11 we7u * README.win32: Fixing the order of the Cygwin packages. 2004-11-19 07:20 we7u * update-xastir: Tweaks for Cygwin to eliminate the "sudo" keyword there. 2004-11-18 16:03 we7u * install-xastir: Changing the comments around at the end to simplify things. 2004-11-18 14:16 we7u * install-xastir: Adding more comments at the end. 2004-11-18 13:06 we7u * update-xastir: Adding a couple of command-line options to the cvs update command. 2004-11-18 12:51 we7u * install-xastir: A script to help in the initial install of Xastir via CVS. For those folks challenged by the Unix way of doing things. 2004-11-18 12:29 we7u * README.CVS, README.win32: Updating the instructions with respect to the "update-xastir" script. 2004-11-18 12:23 we7u * update-xastir: Added a comment. 2004-11-18 10:59 we7u * INSTALL, README.CVS, README.win32, UPGRADE, update-xastir: Adding an update-xastir script and tweaking updating instructions a bit. 2004-11-17 10:48 we7u * README: Added HP/UX instructions per Dan Brown, N8YSZ. Current state of HP/UX port is: Segfaults when connected to internet server, but appears to run otherwise. Not fully tested. 2004-11-17 10:28 we7u * src/main.c: Fixing up a return that shouldn't pass back a parameter. 2004-11-17 09:57 we7u * src/main.c: Checking for map interrupts and returning, just before each call to display_file(), which is the function which draws objects/tracks. 2004-11-17 09:46 we7u * src/: map_geo.c, map_tiger.c, util.c: Adding timeouts to libcurl calls. Wget calls already have them. 2004-11-17 09:00 we7u * src/map_geo.c: If ImageMagick is not found, we now refuse to load a .geo map unless "xpm" is found in the filename. 2004-11-17 08:11 we7u * src/: maps.c, maps.h, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, map_dos.c: Setting default map layers based on the type of file. Raster map = 0, vector maps = 1000, GNIS = 99,999. 2004-11-16 14:50 we7u * configure.ac: Reversing the order of the map caching/Imagemagick checks. Just in case. We've had trouble before where if ImageMagick checks fail, they corrupt some of the settings for the other checks, unless ImageMagick is the last of the bunch. 2004-11-16 12:09 we7u * FAQ: Getting rid of "localhost" on the netcat example line. Redundant. 2004-11-16 12:04 we7u * FAQ: Updating the netcat info in the FAQ. 2004-11-16 10:15 we7u * README.win32: Tweaking the library install instructions per David Flood. 2004-11-15 21:05 we7u * src/maps.c: Prevent a segfault when Xastir is having trouble writing the map objects to file. 2004-11-15 10:05 tvrusso * acinclude.m4: Fix of fix for fix of fix of probe for db library. Amounts to removing a comment character from a critical line that I'd accidentally commented out. Without this fix, building xastir on a machine without a db library installed will fail with an error message at link stage about a missing "-ldb". That's because the configure script never reset the LIBS variable after the probe. 2004-11-15 08:52 we7u * src/map_cache.c: Moving more of the includes inside the #ifdef. Including config.h so we get a direct answer as to whether USE_MAP_CACHE is defined before we include anything else. 2004-11-15 08:22 we7u * src/map_cache.c: Moving a couple of includes below the USE_MAP_CACHE #ifdef. Makes it compile on systems that don't have the map caching enabled. 2004-11-13 17:10 tvrusso * acinclude.m4: Handful of changes to improve probe of db for map caching. 1) remove attempts to probe db version 3 libraries, coz the code that uses db actually won't work unless the version is 4 or above. 2) make the probe stop probing when it finds a library that works. Otherwise the probe keeps overwriting the "dblib" variable with "no". 3) comment out the attempt to probe for db_open if db_create isn't found. That would only work if the code that uses db_create were inside appropriate ifdefs, which was probably the case in the package from which the autoconf macro was obtained. 4) Change the comment about "FreeBSD puts this in a weird place" enough to give a reader an idea of where to look. 2004-11-13 16:54 we7u * src/map_cache.c: Moving the #ifdef below the #includes, so that we have a chance of having the USE_MAP_CACHE variable be defined. 2004-11-13 16:12 tvrusso * acinclude.m4, configure.ac: A minor tweak to add "Building with map caching.....: " to the list of things that are printed out at the end of the configuration run. 2004-11-13 06:00 tvrusso * src/map_cache.c: Move the #endif for USE_MAP_CACHE to a place where it actually takes out code that can't compile if USE_MAP_CACHE isn't defined. 2004-11-12 16:40 shadow * acinclude.m4: link against the real libdb we found; use the header path for it we found 2004-11-12 16:17 we7u * README.win32: Adding libdb and libdb-devel as necessary libs. 2004-11-12 15:50 we7u * INSTALL: Adding a blurb about libdb. 2004-11-12 11:31 we7u * README.win32: Added info about NTFS "convert.exe" getting run instead of ImageMagick's "convert.exe". Added instructions written up by Randy, KK6RW, regarding auto-starting Xastir. William McKeehan, KI4HDU, contributed to those instructions and was the inspiration for them. 2004-11-12 10:52 we7u * src/: map_cache.c, map_cache.h: Moving variables to the top of the blocks (for the BSD guys), changing the expire time for maps to 6 months instead of one hour. 2004-11-12 10:47 we7u * src/map_tiger.c: Moving the variable declaration up to the top of the block before those FreeBSD guys get on my case! 2004-11-12 10:24 we7u * acinclude.m4, src/Makefile.am: The final two pieces to enable the new feature, if the Berkeley DB libraries are installed and usable. 2004-11-12 09:17 we7u * configure.ac: Added a comment. 2004-11-12 09:10 we7u * acinclude.m4: A tweak to add "-ldb" to the LIBS line if the DB library is found. 2004-11-12 09:09 we7u * src/: map_cache.c, map_cache.h, map_tiger.c: Adding code that performs caching of tigermaps, courtesy of Dan Brown, N8YSZ. 2004-11-12 09:03 we7u * src/main.c: Preliminary work to include a new map feature. 2004-11-12 08:37 we7u * INSTALL: Adding another link for a list of internet servers, plus a link to the filtering syntax web page. Links courtesy of Rick Green. Thanks! 2004-11-11 09:19 we7u * INSTALL: Updating the GDAL instructions somewhat. 2004-11-10 11:58 we7u * src/db.h: Removing db.h. It has been renamed as database.h. 2004-11-10 11:58 shadow * acinclude.m4, configure.ac: berkeley db configure test. may need slight tweaking for which function it tests for (db_open/db_create/solmething else) 2004-11-10 11:58 we7u * src/: Makefile.am, alert.h, db.c, draw_symbols.c, util.c, util.h, wx.h, xastir.h: Renaming db.h to database.h in order to avoid a conflict with Berkeley DB include file of the same name. 2004-11-10 11:56 we7u * src/database.h: Renaming db.h to database.h, in order to avoid a potential conflict with the berkeley DB include file of the same name. 2004-11-05 15:07 we7u * src/festival.c: Closing the file descriptor for the socket at the point where the Festival connect fails. 2004-11-05 08:57 we7u * configure.ac: Bumping the development sources up to 1.4.2. Just released 1.4.1 stable. 2004-11-05 08:37 we7u * src/: igate.c, util.c: Assuring that we don't igate packets while reading tactical calls in from file. 2004-11-04 12:27 we7u * src/: db.c, igate.c, main.c: Fixing the problem where reading in a log file causes the packets to be igated to the NET. 2004-11-04 10:53 we7u * src/map_gdal.c: Free'ing the hash iterators at the correct points. 2004-11-02 12:37 we7u * src/: hashtable.c, hashtable_itr.c, hashtable_private.h: Tweaks so that the GC_MALLOC/GC_FREE defines apply to the hashtable code as well. 2004-11-02 07:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c: Making the transmit and Interface->Properties long-path warning messages different. 2004-11-02 07:19 we7u * src/util.c: Changing one variable so that it local to where it is used instead of at the top of the routine. Changed flags to be counting flags instead of booleans, so we can later use them to count digipeater types. Added some comments. 2004-11-01 12:34 we7u * src/util.c: Tweaking the path-check code so that trace,wide2-2 and wide,wide2-2 paths and similar are allowed. 2004-11-01 09:11 tvrusso * configure.ac, src/util.c: Add probe for strndup to configure.ac. Ifdef use of strndup in src/util.c. strndup is a GNU extension and not portable to non-GNU systems. strdup is portable, so is used if strndup isn't available. 2004-10-30 14:13 we7u * src/: interface.c, interface_gui.c: Adding path checks to the igate path. 2004-10-30 14:01 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding another string for igate path checking. 2004-10-30 13:23 tvrusso * README.win32: Add note to section on installing libproj and libgeotiff. Both of these libraries are now available directly through cygwin setup, simplifying the installation. 2004-10-30 12:06 we7u * src/interface.c: Adding the path check code into each posit and object/item transmit, at the spot where the unproto path is selected. This probably needs to be added to the igate path code as well. 2004-10-29 13:15 we7u * src/interface_gui.c: Another tweak by Ryan Butler, KB0JQO, to check UNPROTO paths on more types of interfaces. 2004-10-29 13:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/util.c, src/util.h: Tweaks by Ryan Butler, KB0JQO, to check the unproto paths on interfaces for excessively long paths. Performs the path checks when you hit the OK button on the Interface->Properties dialog. 2004-10-29 08:53 we7u * src/map_gdal.c: Enabling tiger polygons for normal use. Tweaked the code so that the polygon reassembly only gets done if we have "filled" enabled for that map. 2004-10-29 07:53 we7u * src/map_gdal.c: Experimentally derived at better hash sizes (twice the max size needed for any county in the state of WA). Correct code now for free'ing the landmark hash. Sped up the TLID linked list code, but still testing that to make sure the polygons are made correctly (it reverses the order that the line segments are added to the geometryCollection). 2004-10-28 22:14 we7u * src/map_gdal.c: More tweaks to the tiger code. Still not enabled for general use. 2004-10-27 10:03 we7u * src/map_gdal.c: First working version of Tiger polygon code. #ifdef'ed out of the compile at present. 2004-10-27 10:02 we7u * src/Makefile.am: Adding the hashtable files. 2004-10-27 09:58 we7u * src/: hashtable.c, hashtable.h, hashtable_itr.c, hashtable_itr.h, hashtable_private.h: Adding generic hashtable functions. 2004-10-26 23:24 we7u * src/map_gdal.c: Starting to draw some filled polygons for Tiger maps. Still not ready for prime-time so the code is still disabled by an #ifdef. 2004-10-26 22:44 we7u * src/map_gdal.c: More Tiger polygon code changes. The code is generating polygon geometries from the tiger data now, so the next step is to start drawing them. 2004-10-26 19:55 we7u * src/map_gdal.c: Implementing hash functions for the Tiger polygon code. Still #ifdef'ed out, so it won't get compiled in currently. 2004-10-23 20:38 tvrusso * README.MAPS: Mention the Xastir_tigerpoly.py script in the place where this file previously said that shapefile conversion of TIGER/Line data didn't contain polygon features. 2004-10-23 15:24 we7u * src/main.c: Fixing the segfault caused by closing the Map labels font dialag before closing xfontsel. Had to put in a couple of "xfontsel_query = 0" statements in the callbacks for the Map labels font dialog. 2004-10-22 08:25 we7u * src/map_gdal.c: Added some debug code. It's not enabled currently. 2004-10-21 19:54 we7u * src/map_gdal.c: Added much of the code needed to reconstruct the Tiger polygons. The new code is commented out right now as it's not quite complete and it really slows things down as well. Optimization will happen AFTER the code is working. 2004-10-21 12:45 we7u * src/map_gdal.c: Changed some comments. 2004-10-21 12:28 we7u * src/map_gdal.c: Changed one variable name from i to ii (easier to grep for). Added some comments. 2004-10-21 01:55 tvrusso * config/tgr2shppoly.dbfawk: Don't display name of feature if it is "None" (what some fields output by Xastir_tigerpoly.py get, a feature inherited from tigerpoly.py -- haven't figured out why). 2004-10-21 01:51 tvrusso * config/Makefile.am, config/tgr2shppoly.dbfawk, scripts/Makefile.am, scripts/Xastir_tigerpoly.py: Add python/OGR script to generate polygon shapefiles from TIGER/Line data. Add dbfawk file to make them look less ugly than if there weren't one. Putting this in CVS merely to get it out there for community hackage. 2004-10-20 21:19 we7u * src/map_gdal.c: Added some comments. 2004-10-20 14:30 we7u * src/: geo-find.c, geocoder_gui.c: Find Address works again. 2004-10-20 12:37 tvrusso * src/map_gdal.c: Fix mid-function declarations to allow compilation by gcc 2.95. 2004-10-20 09:42 we7u * src/map_gdal.c: Changes to comments only. 2004-10-20 08:37 we7u * src/map_gdal.c: More messing with water layers. Nothing major. 2004-10-19 19:17 we7u * src/map_gdal.c: Commenting out the "Loading" message. 2004-10-19 18:13 we7u * src/map_gdal.c: Shapefiles are working again in GDAL. 2004-10-19 11:36 we7u * src/map_gdal.c: More color and line tweaks. This change probably disables Shapefiles, but SDTS and TIGER/Line files display properly now. 2004-10-19 09:02 we7u * src/map_gdal.c: Moving all of the color code into the guess_vector_attributes function. Later we'll be able to convert this function into our map preferences system once that is fully defined. Added color to the SDTS files. 2004-10-19 07:45 we7u * src/map_gdal.c: Faster determination of layer name. 2004-10-18 22:22 we7u * src/map_gdal.c: Starting to support proper color scheme for SDTS-format maps. At least have contours in yellow and other layers in black now. 2004-10-18 21:08 we7u * src/map_gdal.c: Fixing OGR indexing so that the transform is invoked every time. Required for UTM/State-plane maps. 2004-10-18 13:17 we7u * src/maps.c: Changing default Shapefile translator back to Shapelib. 2004-10-18 13:09 we7u * src/map_gdal.c: Truncating the points better. Was truncating at 0 for negative values, which doesn't work. We just need to keep away from the +16000/-16000 points and greater, which invoke X11 drawing bugs. Truncating at zero creates dummy lines along our top and left window borders. 2004-10-18 12:58 we7u * src/map_gdal.c: Very weak attempt at detecting hypsography and hydropraphy SDTS files to decide to color them yellow, keyed off "HY"or "HP" anywhere in the full filename (that's why it is weak). Other SDTS maps get colored black currently. 2004-10-18 11:57 we7u * src/: bulletin_gui.c, db.c, list_gui.c, main.c, main.h, map_gdal.c, maps.c, util.c, view_message_gui.c, wx_gui.c, xa_config.c: Changing the name of a global variable. Tweaking elevation for SDTS contours so that they are in the correct units. 2004-10-18 09:39 we7u * src/map_gdal.c: Outputting the correct label on elevations now from SDTS files. Later will try to switch it to match the setting of the Enable English Units togglebutton so that we can get a consistent display. 2004-10-18 07:55 we7u * src/map_gdal.c: Added some notes. No code changes. 2004-10-15 21:25 we7u * src/map_gdal.c: Changing text from "ft" to "m" for elevation. SDTS file appear to have elevation in meters. Also changing back to yellow for the contour lines as it is highly visible whereas the white/gray is not in many cases. 2004-10-15 12:24 we7u * src/map_gdal.c: Default coloring for raw Tiger/Line maps. 2004-10-15 09:27 we7u * src/map_gdal.c: Repositioning labels slightly. Fixing segfault caused by earlier "skip" option. 2004-10-15 08:36 we7u * src/map_gdal.c: Changing to lighter colors again for contours and their labels. They need to show up on top of terraserver images. Brown doesn't cut it. Changed the contours to gray80 and the labels to white. 2004-10-15 07:56 we7u * src/map_gdal.c: Changing to brown for the contours and corresponding labels. Closer to the USGS topo map colors. 2004-10-15 07:44 we7u * src/map_gdal.c: Drawing more labels along each object. Tied to zoom level so that we reduce the quantity of labels as we zoom out. 2004-10-15 07:22 we7u * src/map_gdal.c: Setting a few hard-coded default colors from some types of map objects. Later we'll redo this so that the preferences come from a file. Re-enabled code that dumps out the layer information. Added elevation display for SDTS-format DLG contours. 2004-10-14 21:12 we7u * src/map_gdal.c: Several fixes. Spatial filtering now works properly. 2004-10-14 12:52 we7u * src/map_gdal.c: Simplified some of the code. Have SDTS contours working again, but have a problem with those files and spatial filtering yet. This version works but puts out error messages to STDERR with SDTS files. 2004-10-13 23:05 we7u * src/map_gdal.c: Sped up GDAL maps: Implemented the spatial filtering mechanism inherent in the library. We now filter using our viewport as the bounding rectangle, which really speeds things up as you zoom in. 2004-10-13 22:57 we7u * src/maps.c: Fix for draw_vector function. It now rearranges the bottom/top/left/right if it's called with things out of order, before calling map_visible. This gets fewer vectors rejected due to being off-screen/more vectors actually get drawn. 2004-10-12 08:34 we7u * src/map_gdal.c: Fixing up debug messages. Sending weather alerts off to the draw_shapefile_map function for now. 2004-10-11 19:11 we7u * src/map_gdal.c: Nicer labels for OGR plus rotation. 2004-10-11 13:12 we7u * src/map_gdal.c: Slight reformatting. No code changes. 2004-10-11 13:06 we7u * src/map_gdal.c: Labels for OGR point files as well. Untested. 2004-10-11 12:56 we7u * src/map_gdal.c: Initial labels for OGR vector maps. Not colored yet, not rotated, but better than nothing, which is what we had before! 2004-10-11 12:15 tvrusso * src/map_tif.c: Add some error messages to the "geoTIFF file not in proper format" block, so the user can see what is actually wrong with the file. 2004-10-11 09:27 we7u * scripts/: toporama250k.pl, toporama50k.pl: Tweaking one comment that gets written out to the .geo files. 2004-10-10 12:16 tvrusso * src/testawk.c: Fix mistake in font_size output --- make sure appears on correct line. 2004-10-10 12:01 tvrusso * src/testawk.c: Add "font_size" variable to those that are read and output by testawk. testawk still lags significantly behind xastir in what it reads and outputs. 2004-10-08 11:33 we7u * scripts/: toporama250k.pl, toporama50k.pl: Oops. Changing copyright to correct one. 2004-10-08 11:31 we7u * scripts/: toporama250k.pl, toporama50k.pl: Adding copyright and licensing info. 2004-10-08 11:20 we7u * scripts/: Makefile.am, toporama250k.pl, toporama50k.pl: Scripts to snag Canadian toporama map files and create .geo files for them. Created mostly from code submitted by Adi Linden, VA3ADI. 2004-10-07 19:15 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Making a few more warnings go to popups instead of STDERR. Fixing object/item code so that you can't create a new object/item that has the same name as another station/object/item in the database. 2004-10-07 14:43 we7u * src/: db.c, geocoder_gui.c: Removing some white space. 2004-10-07 10:16 we7u * src/main.c: Fixing another Xt call that should have a NULL at the end. 2004-10-07 09:29 we7u * src/main.c: Slightly better check_range() function. This one snaps the left/right of the map to the left/right of the display in most cases. Still more work to do before I'll be satisfied with the operation though. 2004-10-07 08:44 we7u * src/main.c: Tweaking check_range() so that it doesn't allow us to zoom out beyond the N/S poles. It will resize the Y scale factor so that it fits the window perfectly N/S. More work will probably be done on this function later so that we fit E/W perfectly as we zoom out as well (depending on the window's aspect ratio). 2004-10-07 08:14 shadow * src/: db.c, main.c: update calls to XrtVaGetValues to terminate with NULL 2004-10-06 22:45 we7u * src/main.c: Minor tweak to how center/zoom is calculated. Check for edge of earth now. May be more tweaks to come for this part of the code. 2004-10-06 22:17 we7u * src/main.c: Tweaking a few more minor GUI things for Map View object creation. 2004-10-06 21:44 we7u * src/main.c: Computes proper range now when creating Map View objects. 2004-10-06 20:28 we7u * src/db.c: Fixing transmit of objects/items so that they send out PHG or RNG as the first parameter in the comment field. 2004-10-06 17:15 we7u * src/main.c: Fixing the language command-line switch. Initial implementation of the code for creating Map View objects (not complete yet). 2004-10-05 22:17 shadow * src/awk.c: awk_find_sym can return NULL; don't assume src->type is valid. 2004-10-05 17:20 shadow * config/tgr2shp.dbfawk: dd missing double-quote in FENAME default case handling 2004-10-05 10:11 we7u * src/: db.c, main.c: Fixing the Move Object function so that we can only move objects that we already own. Any SSID will work. If we don't own it, we have to adopt the object first before we can move it. This keeps us from accidentally moving objects if we accidentally leave the Move function on and then click/drag on the map display. 2004-10-05 08:54 we7u * Makefile.am: Adding a new Texas radar geo file. 2004-10-05 08:54 we7u * TXRadar.geo: Adding a new geo file for Texas radar, contributed by Gerry Creager. 2004-10-04 22:12 we7u * src/db.c: Fixing a typo in extract_powergain_range() which caused it to skip parsing PHG strings. 2004-10-04 13:20 we7u * FAQ: Adding another link for the remote serial port stuff. 2004-10-04 12:58 we7u * src/db.c: Reducing the number of positions displayed in Station Info from 100 to 50. This is in order to speed up the automatic updates version of the Station Info dialog. 2004-10-04 12:25 we7u * FAQ: Adding links to the serial port redirectory programs, courtesy of Mike Fenske. 2004-10-04 10:17 we7u * src/wx.c: Fixing the 000/360 wind course problem. We should now transmit "360" when the wind direction is 0, as the APRS spec requires. 2004-10-04 10:16 we7u * README.CVS: Adding a note about the "wheel" group and sudo. 2004-10-04 09:20 we7u * FAQ: Adding info regarding connecting to remote serial ports. 2004-10-04 09:17 we7u * README.MAPS: Adding a link to the national transportation atlas map files, link provided by Derrick J Brashear. 2004-10-04 08:32 we7u * src/xa_config.c: Changing default fonts to be non-italic. A bit more readable. 2004-10-03 12:46 we7u * configure.ac: Small tweak to avoid a conflict with a similarly-named define in the GDAL library. 2004-10-03 00:04 we7u * src/testawk.c: Giving up on this file for now in terms of compiling with strict error-checking. 2004-10-02 23:17 we7u * src/interface.c: Fixing a few more problems that were found by compiling with strict error-checking. 2004-10-02 22:43 we7u * src/: interface.c, testawk.c, x_spider.c: More tweaks from compiling with stronger error-checking. 2004-10-02 22:19 we7u * src/main.c: Fixing up a few things found by running with these compile flags: "-g -O2 -pipe -Wall -pthread -Wpointer-arith -W -pedantic" 2004-10-02 21:58 we7u * src/: db.c, draw_symbols.c, geo-find.c, hostname.c, map_shp.c, map_tif.c, maps.c, util.c, wx.c, x_spider.c: Fixing up a few things found by running with these compile flags: "-g -O2 -pipe -Wall -pthread -Wpointer-arith -W -pedantic" 2004-10-02 11:08 we7u * src/: draw_symbols.c, locate_gui.c, maps.c, messages_gui.c, testawk.c, xastir.h, main.c: Tweaks to get rid of compiler warnings on 64-bit CPU's. Fixing up mostly casts to/from pointers and int's using some macros from the FreeCIV project to help us. 2004-10-01 09:19 we7u * README.CVS: Adding "sudo" instructions. 2004-09-29 09:04 tvrusso * src/map_shp.c: Repair broken stippling of filled polygons under dbfawk. Before this commit, stippling was set too early in the code and not turned off before label drawing began, rendering map labels for stippled polygons unreadable. 2004-09-29 00:10 tvrusso * README.MAPS, src/map_shp.c: Add "fill_stipple" dbfawk variable, and support for it. Now, if a dbfawk file sets filled=1, fill_style=2, and fill_stipple={0,1,2}, the filled polygons will be stippled instead of solid. fill_stipple=0 gives 13% stipple fill_stipple=1 gives 25% stipple fill_stipple=2 gives 50% stipple. "fill_style=2" corresponds to FillStippled per XSetFillStyle. 2004-09-28 14:53 gstueve * src/messages.c: Add check for DOS EOL markup. 2004-09-28 11:01 we7u * FAQ: Added a bit about NumLock/ScrollLock/CapsLock messing up Motif programs, and one way to solve it. 2004-09-28 08:40 we7u * src/db.c: Fixing Station Chooser dialog so that it expands properly. It used to increase the size of the buttons instead of increasing the size of the station window. 2004-09-27 09:49 tvrusso * FAQ: Add FAQ entries for autoconf-related FAQs. 2004-09-27 08:04 tvrusso * Makefile.am: Return "dist-bzip2" to the AUTOMAKE_OPTIONS variable. it is true that --dist-bzip2 is not a valid automake option, but the AUTOMAKE_OPTIONS variable doesn't generate --options for automake, it has an effect on the generated makefile itself. In this case, dist-bzip2 adds a dist-bzip2 target to the makefile. As far as I can tell, the folks who are having trouble with this option are not in fact using automake 1.6.3 or later. In ha2vr's case it turned out he was actually using automake 1.4, even though automake 1.9 was supposedly installed on his system. 2004-09-26 17:29 tvrusso * Makefile.am, acinclude.m4, bootstrap.sh: Per discussions on xastir mailing list: - remove "dist-bzip2" from "AUTOMAKE_OPTIONS" in Makefile.am. - Fix underquoted AC_DEFUN of AC_CHECK_GMTOFF Also, add a print statement to end of "bootstrap.sh" so it's clear when it's finished successfully. 2004-09-24 14:16 we7u * src/wx.c: Fixing the offsets and data length for the Peet Complete-mode wind speed fields. 2004-09-24 12:42 we7u * src/main.c: Commenting out some debug code. 2004-09-24 12:42 we7u * src/util.c: Removing some dead code from the compressed posit routine. 2004-09-24 12:35 we7u * src/db.c: Fixing symbol drawing so that Map View objects "range" circles aren't drawn. Fixing compressed posits so that csT bytes are always removed when decoding. Adding "Current Range:" output to Station Info dialog. 2004-09-24 12:32 we7u * src/draw_symbols.c: Reducing the size of the wind barbs as we zoom out. 2004-09-24 12:30 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added range output to Station Info dialog. Added missing tactical call string to some language files. 2004-09-24 09:49 tvrusso * src/db.h: Remove DOS line terminators. Reformat long lines. 2004-09-23 20:29 we7u * src/: db.c, main.c, main.h: This change implements decoding for Map View "eyeball" objects. 2004-09-22 13:00 we7u * src/main.c: Adding a bit more output to the "time has reversed" fprintf's. We now dump out the number of seconds we went backwards and the date/time of the event. 2004-09-22 12:25 we7u * README.CVS: Added a note about autoconf and automake. 2004-09-20 12:15 we7u * src/x_spider.c: Another tweak to allow multiple spaces between "pass" and the passcode. 2004-09-20 12:10 we7u * src/x_spider.c: Fixing user/pass login in the Server code so that both of them are position-independent. 2004-09-19 19:29 tvrusso * src/main.c: Add the base file name to the dbfawk file for downloaded GPS tracks and routes. This allows the name of the track to be displayed along with the line data when these files are used outside of the GPS directory. I forgot to add this component of the data in in my first commit. 2004-09-19 16:52 tvrusso * README.MAPS: A little cleanup of the discussion involving "gdalwarp." 2004-09-19 16:39 tvrusso * README.MAPS, src/map_tif.c: This is a patch I've been using for several months now: it allows xastir to use geotiff files that are already unprojected lat/lon maps. It simply checks the "PCS" key in the geotif file, and if it's not there then the file is assumed to be in lat/lon and can be used as is without transformation. It has no effect on maps that are not already in lat/lon, and so will be invisible to anyone who hasn't needed the ability to read in unprojected geotiff files. README.MAPS updated to explain that gdalwarp can be used to convert maps into lat/lon unprojected maps. Also added a place to find useful geotiff maps that need such conversion (FAA sectionals from aviationtoolbox.org). Tweaked the stuff on shapefile reprojection. What was there were verbose snippets from an email exchange between Curt and me. Made them a bit shorter and more to-the-point. The importing of lat/lon geotiff files is significantly slower than the importing of USGS quads, because the optimized reads that skip over scanlines based on zoom level don't work. I intended to figure out how to make them work, but never did the work. If folks start using this a lot and get me to bump it up in priority I can revisit it. 2004-09-19 15:50 tvrusso * config/Makefile.am, config/gps_wpt.dbfawk, src/main.c: config: New DBFAWK file for waypoints files downloaded through GPSMan. Now, DBFAWK- enabled xastir will display names of waypoints next to the symbol, no matter what directory they're put in. Add gps_wpt.dbfawk file to makefile. src: make xastir write out a simple dbfawk file to go along with GPSMan track and route shapefiles. Prior to this, these files would only display in the selected color if they were copied into /usr/local/share/xastir/maps/GPS, and would display in all black if they were anywhere else. Unfortunately, because we have no control over the fields created by GPSMan for these shapefiles, it is not possible to stick the color itself into the dbf file, as Alan had suggested in various comments in the code. To use these new things: for waypoints, do nothing -- the dbfawk file is generic and applies to any GPSMan waypoint file. For tracks and routes: Make sure to copy the dbfawk file when you copy the shapefile and dbf file to a maps directory. Xastir will use it. For tracks and routes downloaded prior to this patch: the dbfawk file is simple, just copy one for a map of the same color. 2004-09-18 13:30 we7u * src/map_shp.c: Fixing the "Loading" and "Indexing" messages so that they don't overrun our limited real estate on the status line. 2004-09-18 13:25 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_tif.c, map_tiger.c: Fixing the "Loading" and "Indexing" messages during map activity so that they don't overrun our limited real estate on the status line. 2004-09-17 13:44 we7u * src/interface.c: Increasing the wait time in the loop where we're connecting up network interfaces. Was 20ms, now 250ms. 2004-09-17 12:56 we7u * src/: fcc_data.c, geocoder_gui.c, locate_gui.c, location_gui.c, map_gnis.c, rac_data.c, track_gui.c: Bypassing the new configure flag with a few more popups that are user-requested. 2004-09-17 12:46 we7u * src/: main.c, popup_gui.c, xastir.h: Tweaks so that a few of the popups will continue to display in that manner (instead of heading to STDERR). 2004-09-17 12:22 we7u * INSTALL, README.Getting-Started, acinclude.m4, configure.ac, src/popup_gui.c: Implementing the "--without-errorpopups" configure flag. If invoked, popup_messages() writes to STDERR instead of causing a popup dialog to appear. 2004-09-17 10:12 tvrusso * src/main.c: Put Cygwin-specific setting of nexttime into the UpdateTime function. Remove the two Cygwin-specific usleep(2) from the end of UpdateTime. With these changes, running xastir on Cygwin under Win2K on a 2GHz machine went from taking up 90+% of the CPU to taking around 20% --- most of that in system processes, and mostly that high when X events are being processed. 2004-09-16 12:31 we7u * configure.ac: Bumping the revision to 1.4.1, as we just did a stable release at 1.4.0. 2004-09-16 07:47 we7u * src/xa_config.c: Changing default sound command from "vplay" to "play" as it is much more common. 2004-09-16 07:00 tvrusso * src/map_gnis.c: Quick, trivial commit both to make sure I'm set up right and to remove a slightly annoying error message when I'm looking at New Mexico with GNIS: Add "ruin" as a recognized gnis entry type. Ideally, this mapping of gnis entries to zoom level limits should be in metadata rather than a large if/elseif/elseif... block, but that's another issue. 2004-09-15 13:19 we7u * src/db.c: Re-ordering "if" statements to speed things up slightly. 2004-09-15 12:59 we7u * src/db.c: Another speedup (lower CPU usage). 2004-09-15 12:44 we7u * src/alert.c: Reducing CPU usage of normal_title(). 2004-09-15 12:43 we7u * src/db.h: Slowing down minimum object timing by another five seconds. Reduces how often we look through our database, keeping CPU usage down. 2004-09-15 10:08 we7u * src/db.c: Swapping two "if" statements in a loop, as the is_my_call() function appears to be faster than the boolean operations to determine whether it's an object/item. 2004-09-14 12:32 we7u * src/db.c: Making is_my_call() and check_and_transmit_objects_items() more efficient. Found during profiling that these routines were eating up CPU. 2004-09-13 19:50 we7u * INSTALL, configure.ac: Adding the "--with-profiling" flag. Updating docs to reflect it. 2004-09-13 12:56 we7u * src/map_shp.c: Changing label storage to a hash table instead of an array, to speed things up. Using the first character of the string as the hash index. Tried using lower 7 bits of first two chars, and lower 6 bits of first two chars: Profiling showed that using the first character was faster. 2004-09-13 12:54 we7u * src/rotated.c: Moving math into appropriate parts of loop to speed it up. Anything that is static through all iterations of a loop is moved outside that loop for speed. 2004-09-10 16:09 we7u * src/draw_symbols.c: Implementing a cache for the most recent five symbols used. Speeds up drawing by quite a bit (found by profiling). 2004-09-10 12:26 we7u * src/main.c: More speedups found by profiling. Checking for new gps map only once per second now, updating the stations count on the status line once per second instead of continuously. 2004-09-10 09:19 we7u * src/main.c: Adding some Cygwin-specific usleep's in UpdateTime() in order to reduce CPU usage on those systems. 2004-09-10 08:49 we7u * src/awk.c: Sped up awk_find_sym() a bit. 2004-09-10 08:37 we7u * src/rotated.c: Sped up font rotation by moving some floating-point math outside the inner loop. 2004-09-10 08:27 we7u * src/alert.c: Fixing a minor compiler warning. 2004-09-09 20:37 we7u * src/maps.c: Fixing a bug I introduced earlier today while speeding up map indexing. 2004-09-09 12:59 we7u * src/maps.c: Speeding up the maps.c:index_retrieve() function. Making it more efficient. Perhaps the next step would be to turn it into a hash lookup, but that would require changing perhaps several other routines to match. 2004-09-09 09:11 we7u * README.Getting-Started: Adding another note about callpass. 2004-09-09 08:06 we7u * INSTALL: Adding another note to the profiling section. 2004-09-08 20:43 we7u * src/alert.c: Major speedup in weather alert code, found through profiling. 2004-09-08 12:22 we7u * INSTALL: Adding a section on checking for memory leaks. 2004-09-08 10:48 we7u * INSTALL: Adding profiling instructions. 2004-09-07 14:40 we7u * FAQ: Added a bit about MacOSX USB adapters, courtesy of Jeff Wigal, WY7Q. 2004-09-07 14:06 we7u * src/util.c: Changing format for time so that Cygwin can understand more of it. Tweak courtesy of Henk de Groot. 2004-09-07 10:15 we7u * README.Getting-Started, README.win32: Tweaking the notes about GPSMan/gpsmanshp. 2004-09-07 08:39 we7u * src/festival.c: Adding some usleep() function calls for the case where we can't open a socket to Festival, so that we don't spin our wheels too fast trying to open sockets. 2004-09-06 21:06 rzg * help/help-English.dat: Done the body, just "whats new" section left. 2004-09-06 18:44 we7u * src/main.c: Fixes for the Filled and Automaps columns in Map Chooser->Properties dialog. 2004-09-04 23:24 rzg * help/help-English.dat: Updating helpfile some more, still have last 1/3rd to go over and "whats new" section to write. FIXMEs up for grabs; and if anyone otherwise wants to help let me know. 2004-09-03 08:16 we7u * src/db.c: Drawing symbol after we draw circles and other items. Trying to keep the text on top so that it is more readable. 2004-09-02 22:37 we7u * src/db.c: Moving the weather info to the top of the Station Info dialog, for the cases where we have weather info stored. The weather info is the most important info for that station in that case, so it should be readable without scrolling. Stations without weather data are unaffected by this change. 2004-09-02 20:19 we7u * src/db.c: Fixed a small bug in positionless weather decoding where it wasn't decoding course/speed fields. We now take another look for course/speed if either of them are empty. Before both of them had to be empty before we tried another type of parsing for them. Did the and->or conversion in several places in extract_weather(), so the change affects more than just positionless weather packets. 2004-09-02 13:58 we7u * config/language-Dutch.sys: Another tweak from Henk & Han. 2004-09-02 11:36 we7u * config/language-Dutch.sys: More mods by Henk. 2004-09-02 10:51 we7u * FAQ: Updating the locale-specific answers. 2004-09-02 10:45 we7u * src/main.c: Fixing the locale for numbers to "C". We require this in order to be able to write and parse our config files and .geo files properly when the LC_NUMERIC or LANG environment variables are set to something else. This affects the printf and scanf sorts of functions. 2004-09-02 07:49 we7u * src/: main.c, xa_config.c: Bumping the max timeout for tigermaps from 120 to 180 seconds since so many people are getting timeouts with it. 2004-09-01 12:34 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM, and Henk de Groot, PE1DNN. Thanks! 2004-09-01 10:51 we7u * README.Getting-Started, configure.ac: Bumping to the next release number, 1.4. 2004-09-01 08:37 we7u * config/language-Spanish.sys: A few translations by Charles Twardy. Thanks! 2004-08-31 11:56 we7u * config/language-Dutch.sys: Updates by Henk de Groot, PE1DNN. Thanks! 2004-08-31 11:05 we7u * help/help-English.dat: Minor tweaks to descriptions about object timing. 2004-08-31 10:30 francais1 * config/language-French.sys: Updated 2004-08-31 09:52 we7u * config/language-Portuguese.sys: Updates by David Quental, CT1DRB. Thanks! 2004-08-31 09:46 we7u * src/db.c: Tweak which helps to prevent parsing of weather fields out of comment data. 2004-08-31 09:08 rzg * help/help-English.dat: Updating helpfile for release, about 1/3rd done. 2004-08-31 07:40 we7u * config/language-Italian.sys: Updates by Alessandro Frigeri, IK0YUP. Thanks! 2004-08-30 08:49 we7u * src/interface.c: Adding a terminating zero to the AGWPE packets in port_read() instead of in parse_agwpe_packet(). 2004-08-30 08:28 we7u * src/interface.c: Adding a string terminator to the end of the AGWPE raw packets before we start processing them. This keeps portions of previously received packets from getting appended to our current string during our processing. 2004-08-30 07:38 we7u * README.win32: Changing to Henk de Groot's optimized Festival install instructions. 2004-08-28 15:43 we7u * README.win32: Added Festival instructions for Win32 courtesy of Tom Russo. Thanks! 2004-08-27 13:09 we7u * src/main.c: Fix for high CPU-usage when time skips backwards. This fix causes Xastir to sleep a bit in the UpdateTime() loop until time catches up again, thereby avoiding the problem. It also dumps a message out to STDERR as it goes into/out of this mode. 2004-08-27 07:44 we7u * src/map_gdal.c: Changed the gdal output on startup to show only those map formats that have been enabled in Xastir AND are supported by the GDAL library that we're compiled against. 2004-08-27 07:16 we7u * config/language-German.sys: Tweaks by Rolf Bleher, DK7IN. Thanks! 2004-08-26 18:07 shadow * configure.ac: update libgeotiff/libtiff/libproj configure tests such that 1) libproj is checked for only once 2) libtiff is used if found when testing for libgeotiff revised test from Tom Russo KM5VY and tested on MacOS X and Linux. 2004-08-26 14:03 we7u * src/db.c: Fixing the code so that snow can be parsed out of a weather report only if course/speed has already been parsed/deleted from the string. 2004-08-26 11:09 we7u * src/alert.c: Fix for high-CPU bug when malformed NWS weather alert packet is received. 2004-08-25 12:45 we7u * src/db.c: Fix for truncated lines when using AGWPE or Serial KISS TNC interfaces. 2004-08-25 12:40 we7u * src/interface.c: Changed comments. No code changes. 2004-08-25 12:39 we7u * src/main.c: Changed a comment. No code changes. 2004-08-24 18:59 we7u * scripts/: Makefile.am, kiss-off.pl: Adding a kiss-off script to take a TNC out of KISS mode. 2004-08-24 18:53 we7u * src/: main.c, db.c: Fixing the object/item comment-field bug. 2004-08-23 21:47 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, help/help-English.dat, src/messages.c, src/messages.h, src/messages_gui.c: Changing the label on the Clear Messages button, adding a new button for deleting the outgoing messages to that station, relocating the buttons to the bottom row. 2004-08-23 12:48 we7u * README.Getting-Started: Added notes about where to look for instructions for other OS'es. 2004-08-22 11:39 we7u * src/main.c: Changed one comment. 2004-08-21 17:01 we7u * src/: db.c, util.c, util.h: More fixes for xastir_snprintf size parameter, including adding a size parameter to a few other functions that can be used to prevent overrunning strings. 2004-08-21 16:55 we7u * src/wx.c: Reformatting of code and rechecking the size parameter for xastir_snprintf function calls. 2004-08-20 23:48 we7u * src/wx_gui.c: Reformatting some code. 2004-08-20 23:35 we7u * src/: view_message_gui.c, x_spider.c: More cleanup of the size parameter for xastir_snprintf calls. 2004-08-20 23:13 we7u * src/: db.c, geocoder_gui.c, gps.c, hostname.c, igate.c, interface.c, maps.c: Cleaning up the size parameter for a bunch of xastir_snprintf calls. 2004-08-20 13:50 we7u * src/db.c: Fix for bad longitude for your own station. 2004-08-20 11:38 we7u * src/db.c: Fixing problem with truncated comment/status strings. Was setting the length in the xastir_snprintf() call to the length of the pointer instead of the length of the malloc'ed string buffer. 2004-08-20 10:27 we7u * src/maps.c: Added a comment. 2004-08-20 10:25 we7u * src/: awk.c, geo-find.c: Reformatting of geo-find.c. Added comment to both files. 2004-08-20 10:22 we7u * src/db.c: Moving ptr into the block where it is used. 2004-08-20 10:19 kd6zwr * src/db.c: Moving a declaration up to the top to allow it to be compiled. 2004-08-20 09:52 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Reducing the resolution on the snow reports, as they are only reported by inch, not by 100's of an inch. 2004-08-19 21:06 we7u * src/: alert.c, awk.c, db.c, geo-find.c, igate.c, interface.c, messages_gui.c, util.c, view_message_gui.c, wx.c, x_spider.c: More on the strcat/strcpy/strncpy reduction/elimination. I think this finishes off all the strcat/strcpy calls, and there are only 24 strncpy calls left in the code. 2004-08-19 13:10 we7u * README.Getting-Started: Attempting to answer the question: "Why must I compile from sources?" 2004-08-19 12:54 we7u * Makefile.am: Adding the new README.Getting-Started into the installation scripts. 2004-08-19 12:48 we7u * README.Getting-Started: Spellling fix. 2004-08-19 12:45 we7u * README.Getting-Started: First checkin. Fairly complete. 2004-08-19 12:38 we7u * src/: alert.c, bulletin_gui.c, db.c, dbfawk.c, gps.c, gps.h, hostname.c, hostname.h, igate.c, interface.c, interface_gui.c, location_gui.c, main.c, map_shp.c, map_tiger.c, messages_gui.c, rotated.c, view_message_gui.c, wx_gui.c: More work to eliminate strcat/strcpy/strncpy from the code. 2004-08-18 23:45 we7u * src/: map_tiger.c, maps.c, x_spider.c: More strcat/strcpy fixes. Changing to safer string-handling routines. 2004-08-18 23:38 we7u * src/: db.c, interface.c, main.c, map_dos.c, messages_gui.c, popup_gui.c, rac_data.c, sound.c, track_gui.c, xa_config.c, location_gui.c, alert.c, datum.c, draw_symbols.c, fcc_data.c, festival.c, geocoder_gui.c, gps.c, igate.c, list_gui.c, locate_gui.c, map_geo.c, map_gnis.c, messages.c, util.c, wx.c, map_shp.c: More strcat/strcpy fixes. Changing to much safer string-handling routines. 2004-08-18 23:31 we7u * src/: geo.h, gps.h, main.h, messages.h, wx.h, xastir.h: strcat/strcpy fixes. Changing to much safer string-handling routines. 2004-08-18 13:35 we7u * src/: alert.c, fcc_data.c, hostname.c, igate.c, interface_gui.c, locate_gui.c, map_geo.c, map_shp.c, maps.c, messages.c, messages_gui.c, util.c, x_spider.c: Converting more strcat() function calls to strncat(). Safer. 2004-08-17 21:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/list_gui.c, src/maps.c, src/wx.c: Changed wx_snow to be inches instead of 1/100 inch. We now ghost the weather info (mostly) separately from posit info. Got rid of "
" from track logs read in from findu.com. Fixed realloc's in maps.c so that they won't cause a memory leak if they fail. Fixed Peet Bros. complete mode decoding so that the proper wind speed is parsed. Fix by Matt Werner, kb0kqa, for the 3-hour barometric pressure reading for Peet Bros. complete mode parsing. 2004-08-17 17:17 we7u * src/main.c: Changed formatting, added comments. No code changes. 2004-08-17 09:41 we7u * src/wx.c: Fix for 3-hour barometer with Peet U2000 in complete mode. Still testing to see if this is the proper fix, but so far it looks good. 2004-08-16 17:51 we7u * src/db.c: Fixing the "Move" function so that you can drag/drop objects/items that are right on top of each other. The selection dialog will pop up so you can choose which one to move. 2004-08-14 09:43 we7u * src/main.c: Fixing object/item generation so that a space is prefixed to the comment field only in the case where multipoint polygons are present. The space is necessary in order to parse multipoint objects properly, but is not desired for other objects/items where it would limit the extent of the comment. 2004-08-12 17:26 we7u * src/map_gnis.c: Update to GNIS search code for new pipe-delimited file format that the USGS is distributing. 2004-08-12 17:25 we7u * INSTALL, README.MAPS, help/help-English.dat: Updates to the docs to match new RINO, Server Port, and other interface changes that were done recently. 2004-08-12 13:46 kd6zwr * src/x_spider.c: Moved some declarations up to the top of Server(). Inline decls cause problems on some compilers... (like my gcc 2.96 under linux). 2004-08-12 13:00 we7u * src/map_gnis.c: Updating the GNIS map code to handle the latest pipe-delimited files from the USGS. Still need to update the search code, but the display code appears to work fine now. 2004-08-12 10:03 we7u * src/interface.c: Added some debug code for tracking down errant raw packets in the AGWPE code. 2004-08-11 13:15 we7u * src/main.c: A bit of reformatting, plus sending to the x_spider server after raw packets have been converted to TAPR-2 format packets. 2004-08-11 10:40 we7u * src/: main.c, x_spider.c: Tweaks by Tom Russo for FreeBSD compatibility. Thanks! 2004-08-10 19:16 we7u * src/: hostname.c, main.h, sound.c, x_spider.c: More fun with process naming. 2004-08-10 12:59 we7u * src/x_spider.c: Added a note about future plans for process naming. 2004-08-10 12:51 we7u * src/: main.c, x_spider.c, x_spider.h: Code that changes the process name in "ps" listings for the x_spider daemon and client connections. Doesn't work on other operating systems, and doesn't work for "top" listings. 2004-08-09 11:32 we7u * src/x_spider.c: Disabling the Nagle algorithm and enabling SO_KEEPALIVE for the server port connections. 2004-08-07 11:12 we7u * src/interface.c: Modified AGWPE parsing routine and associated code. We've now turned off "monitor" mode and turned on "raw" mode in AGWPE. The "raw" packets get thrown into our standard KISS decoding routines, which gives us the possibility of supporting OpenTrac (a binary protocol) and digipeating on AGWPE ports in the future. The "monitor" mode decoding has been left for now, but later on we'll probably delete it. Also: Added output to STDERR for the AGWPE server version and for the port descriptions. 2004-08-06 12:57 we7u * src/db.c: Change to comment. No code changes. 2004-08-06 09:29 we7u * src/interface.c: Minor changes to comments and debug output messages. 2004-08-05 13:02 we7u * src/: db.c, festival.c, main.c, interface.c, sound.c, util.c, util.h: Re-wrote the agwpe parsing code. It should be more bulletproof now, but still has some debug stuff in it for NWS_ and NWS- messages. Fixed a segfault caused by one of the new strncpy() functions that I switched to in util.c:spell_it_out(). 2004-08-04 13:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the Modify Object/Item dialogs so that you must adopt an object/item that you don't own before you're allowed to delete it. Adopting or Modifying someone else's object causes you to transmit it as a live object owned by you. After that, you may delete it. If the client that previously owned it saw your live object, it'll know that you own it and that you can delete it. Without this adoption process, UI-View32 clients will hold on to an object that you're trying to kill. 2004-08-04 12:07 we7u * help/help-English.dat: Tweaking the note about AGWPE network authentication. We can use that now. 2004-08-04 11:54 we7u * src/: interface.c, interface_gui.c: Fixes for AGWPE. Network loging with authentication should work now. 2004-08-03 14:21 we7u * src/db.c: Fix to allow objects/items to get through the server port and get igated. 2004-08-03 13:04 we7u * src/util.c: Small tweak to valid_inet_name() where it is checking for the "aprsd" string. It didn't appear to be general enough to catch all possibilities. Now it should be. 2004-08-03 12:57 we7u * src/db.c: Changed one sizeof() to a strlen() for emergency messages. Fixing object/item timing intervals so that if the timing slider is reduced, the max interval is reduced for already existing objects as well. 2004-08-03 12:42 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing the displayed label for the object/item timing. It's a max interval now. The actual timing is under the control of an exponential decay algorithm. 2004-07-30 16:15 we7u * src/util.c: A fix for the csT bytes on compressed posits. Turns out we need to send the spaces, and the compressed posit field is a fixed length. 2004-07-30 15:24 we7u * src/db.c: Adding some debug output. 2004-07-29 21:06 we7u * src/sound.c: Replacing strcpy function with safer ones. 2004-07-29 21:02 we7u * src/: list_gui.c, locate_gui.c, location_gui.c, map_tif.c, map_tiger.c, maps.c, messages_gui.c, rotated.c, track_gui.c, util.c, view_message_gui.c: Replacing strcpy functions with safer ones. 2004-07-29 20:57 we7u * src/: color.c, color.h, dbfawk.c, draw_symbols.c, fcc_data.c, geo-find.c, geocoder_gui.c, hostname.c, igate.c, interface_gui.c, lang.c: Getting rid of strcpy functions. Replacing them with safer functions. 2004-07-29 17:02 we7u * callpass/callpass.c: Geting rid of strcpy() function call. 2004-07-29 14:15 we7u * src/db.c: Changed some strcopy() functions to xastir_snprintf() functions. 2004-07-29 13:48 we7u * src/util.c: Reformatting to match the rest of the code. No actual code changes. 2004-07-28 22:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.h, src/xa_config.c, src/db.c, src/main.c: Adding CWOP WX station filtering toggle. Letting Xastir display wind speed when wind course is not available. 2004-07-28 12:17 we7u * src/: db.c, igate.c, x_spider.c: Fixing message igating through x_spider connects. 2004-07-28 10:48 we7u * src/x_spider.c: Fix for FreeBSD courtesy of Tom Russo. Thanks! 2004-07-26 17:08 we7u * src/: db.c, x_spider.c: Per-client authentication for the x_spider listening port. Printf's for each client connect/disconnect, and each successful authentication. Non-authenticated clients can talk to each other and the server, and can receive data from the server, but can't sent anything through the server. Igating must also be turned on to get data from authenticated clients up to the internet connections. 2004-07-26 16:57 we7u * symbols/symbols.dat: Adding the new Rocket symbol that Bob. B. just added to the spec. 2004-07-26 16:55 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kam, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Reenabling the CWID stuff. Some countries evidently require it. 2004-07-26 14:02 we7u * src/x_spider.c: Changing the authentication comments slightly for x_spider. 2004-07-26 13:59 we7u * src/x_spider.c: Adding client authentication to the x_spider server. Clients cannot send data upstream until they authenticate. Clients can still receive data without authenticating or send data to other connected clients. 2004-07-26 13:57 we7u * src/util.c: Removing unused define. 2004-07-26 12:39 we7u * config/tnc-startup.sys: Adding another CWID command that will turn off that feature for some TNC's. 2004-07-26 12:21 we7u * config/: tnc-startup.paccomm, tnc-startup.pico: Correct CWID commands for Paccomm TNC's. 2004-07-26 11:49 we7u * config/: tnc-startup.kpc2, tnc-startup.kpc3: Correct commands to turn off CWID. 2004-07-26 11:44 we7u * config/tnc-startup.kam: The correct command for turning of CWID. 2004-07-26 11:16 we7u * config/tnc-startup.kam: Turning off CWID. 2004-07-26 10:04 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Adding "CWID off" command. 2004-07-25 07:19 rzg * help/help-English.dat: Updated the list of new features. 2004-07-24 15:49 we7u * src/: db.c, igate.c, interface.c, main.c, util.c: Tweaking the server stuff so that connected clients get igated through the "master" Xastir instance if igating -> Net is enabled. 2004-07-23 09:57 we7u * src/db.c: Ignore case when comparing newly received comment/status strings with previously received ones, to decide which ones to throw into the list. With a case-sensitive compare, we were getting two instances of similar comment/status strings cluttering up our lists, when it was really the same info being presented but in a different case. 2004-07-23 09:31 we7u * src/main.c: Cygwin fixes by KJ5O. Thanks! 2004-07-22 19:31 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h, src/x_spider.c, src/xa_config.c: GUI support for the new server port. 2004-07-21 18:56 we7u * src/: Makefile.am, db.c, igate.c, interface.c, main.c, main.h, x_spider.c, x_spider.h: Adding a listener socket for multiple clients. Currently this must be enabled by uncommenting a #define near the top of main.c. Adds a listening socket at port 2023 which allows any number of clients to connect. Spawns a listener for each active client, kills them when the client disconnects. All packets received or transmitted by Xastir go to these clients, all packets sent by the clients are received by Xastir and by all of the other connected clients. "telnet localhost 2023" to test out the functionality after compiling in the server support. 2004-07-21 11:38 gstueve * src/view_message_gui.c: Add macro so someone's comment can be answered. Don't try to put too many arguments into a fixed array. 2004-07-20 11:41 we7u * src/db.c: Sorting and display of status/comment records by date/time. 2004-07-20 11:14 we7u * src/db.h: Bumping max status/comment lines per station from 10 to 20. Am testing with 50 locally to see whether bumping it up more will seriously affect memory usage. Depending on the results, may bump these numbers up even more. 2004-07-19 19:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/x_spider.c: Adding date/timestamps to Status and Comment records. 2004-07-19 14:17 we7u * src/: alert.c, alert.h, db.c, db.h: Moving a couple of define's to the .h files and increasing the number of alerts and messages that we allocate when we run out. This hopefully will help to keep the number of large allocations down plus keep the larger allocations from ending up at the very end of the heap. If we keep a small increment, we realloc() more often plus the large blocks will end up closer to the end of the heap, meaning we won't be able to reduce our memory impact much later. 2004-07-19 09:13 we7u * config/: tnc-startup.aea, tnc-startup.d700, tnc-startup.kpc2, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.sys, tnc-startup.thd7, tnc-startup.tnc2-ui: Adding "HID off" where it was missed. Some TNC's may require slightly different commands for this. I don't have them to test with so I'll have to wait for users to let me know the proper commands. 2004-07-16 11:27 we7u * configure.ac, src/alert.c, src/db.c, src/main.c, src/map_gdal.c, src/xastir.h: Adding support for "libgc", which is a Boehm-Demers-Weiser garbage collection library. The advantage for us is that it can find/report memory leaks. Install it, then add "--with-libgc" to the configure line to compile it in. It will report memory leaks on the console. This patch fixes two leaks found by libgc, plus changes the increments used for relloc'ing alerts and messages. 2004-07-15 14:32 we7u * src/: awk.c, db.c, dbfawk.c, igate.c, main.c, map_gdal.c, map_shp.c, maps.c, rotated.c: Protection for malloc/calloc/realloc calls. Checking the return value for non-NULL. 2004-07-15 13:01 we7u * src/maps.c: Added some comments. 2004-07-15 12:58 we7u * src/: alert.c, db.c, igate.c, messages.c: Added/changed warning messages when realloc's fail. 2004-07-15 10:26 we7u * src/main.c: Reuven found a missing #ifdef for the RINO stuff. Thanks! 2004-07-15 10:16 we7u * src/messages.c: Reformatting to take out tabs. 2004-07-15 10:09 we7u * src/db.c: Changed some debug code that is used to test expire times for messages and stations. 2004-07-15 08:29 gstueve * src/messages.c: Make sure to look for Special groups and safety check group names. 2004-07-14 14:07 we7u * FAQ, INSTALL, acinclude.m4, configure.ac: Motif detection tweaks by Tom Russo. 2004-07-14 12:48 we7u * src/db.c: Reformatting and comment changes. No code changes. 2004-07-14 12:13 we7u * src/db.c: Better code for drawing callsign at each trackpoint. This draws the callsign at every single point. 2004-07-14 09:31 we7u * src/main.c: An attempt to fix the menu GPS Status so that it works. Still need an expiration mechanism for the data here. 2004-07-14 09:29 we7u * FAQ: Added an LDD note, inspired by Jack Twilley. 2004-07-13 14:02 we7u * src/db.c: Comment changes. 2004-07-13 12:21 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added a new button to the Station Filter dialog: "Label All Points". Doesn't actually label _ALL_ trackpoints, but labels most of them with the callsign. This is helpful to identify whose tracks belong to who. 2004-07-13 07:54 we7u * src/: alert.c, db.c, db.h, list_gui.c, main.c, main.h, messages.c, messages.h, messages_gui.c, track_gui.c, util.c: Combined MAX_CALL and MAX_CALLSIGN defines into MAX_CALLSIGN, reduced the size of it from 20 chars. Added MAX_COMMENT_LINES and MAX_STATUS_LINES, currently set to 10 each, which limit how many unique status/comment lines are saved per station. Added MAX_TACTICAL_CALL in order to separate that parameter from MAX_CALLSIGN, as the tactical call needs to be longer but didn't want to waste the memory for all callsigns by making them all long. Changed the alert memory allocation from 100 alert blocks to 25 alert blocks (finer grained malloc's). Added more comments. 2004-07-09 14:11 we7u * src/main.c: Throwing Base-91 Compressed APRS packets into our decoding instead of standard APRS packets. This keeps the resolution that the RINO's are capable of. Doesn't affect how the Object packets are transmitted: For that setting refer to the toggle on the File->Configure->Defaults dialog. 2004-07-09 10:32 we7u * src/main.c: Better timestamp for RINO-derived APRS Objects. Issues: currently sends localtime instead of UTC, plus the gpstrans files we're getting the timestamp from appear to have the download time/date instead of the waypoint creation time/date. These need to be fixed at some point. 2004-07-09 08:19 rzg * src/alert.c: Fixed read of unitialized data according to valgrind. 2004-07-08 16:34 rzg * src/main.c: Fixed comparisions of unitialized variables, and another small bug. 2004-07-08 14:49 we7u * src/main.c: Initializing some variables as they are defined. 2004-07-08 14:49 we7u * src/map_geo.c: Added some comments. 2004-07-08 14:48 we7u * src/interface.c: Reformatting. No code changes. 2004-07-08 14:48 we7u * src/draw_symbols.c: Initializing a variable as it is defined. 2004-07-08 12:38 we7u * src/main.c: Commenting out RINO debug fprintf() statements. 2004-07-08 12:07 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Implemented auto-download capability for the RINO waypoints. A new slider added to the File->Configure->Timing dialog. A setting of 0 disables the function. Anything else invokes GPSMan at the interval selected, downloading all waypoints from a RINO, and creating APRS objects out of those that have "APRS" as the beginning four characters of the waypoint name. 2004-07-08 08:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Initial support for Garmin RINO "contact" waypoints. A new entry on the Interface menu allows snagging waypoints from a RINO. Any that begin with the letters "APRS" will have those four letters removed and then a standard APRS object is created from them and starts transmitting out from Xastir over APRS. We're using non-compressed Objects so that they will be visible on Kenwood displays, at the expense of throwing away some of the position resolution. The menu link-in may change, as we'll eventually go to an automatic poll scheme of the RINO instead of this manual operation. Currently requires a connected RINO on a serial port and GPSMan support compiled into Xastir. 2004-07-07 11:15 we7u * INSTALL: Tweaked the instructions for GDAL ever so slightly. 2004-07-07 09:30 we7u * configure.ac: Added a comment from Tom Russo. We need to make some changes to the Motif detect so that we're assured we have working headers/libraries before we get to the compile stage. 2004-07-06 15:29 we7u * configure.ac: Replacing our Motif search code with better code from the "vim" project. This code is purported to find the most recent variant of Motif on the system and use that, if there's more than one on the system. It also looks quite a few more places for the libraries/headers than our old code. 2004-07-06 11:23 we7u * src/main.c: Added comments. 2004-07-02 13:19 we7u * src/locate_gui.c: Fixed one printf format that had too many format specifiers in it. 2004-07-01 17:20 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/gps.c, src/gps.h, src/main.c: Adding GPS Quality info to the command line and to a new View->GPS Status option. 2004-07-01 14:33 we7u * src/xa_config.c: Setting more reasonable lower defaults for a couple of timing parameters. 2004-07-01 14:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/locate_gui.c: FCC/RAC callsign lookup which doesn't depend on stations being on the screen. 2004-07-01 09:26 we7u * src/bulletin_gui.c: Fix by Tom Russo for FreeBSD. 2004-06-30 22:00 we7u * src/maps.c: Converting from a strcpy() to a memmove() due to another bug that Reuven found. strcpy() cannot handle overlapping strings, while memmove() can. 2004-06-30 21:16 we7u * src/main.c: Fixing memory leaks. 2004-06-30 21:13 we7u * src/db.c: Fixing memory leaks. 2004-06-30 21:09 we7u * src/: messages_gui.c, track_gui.c, view_message_gui.c: Fixing memory leaks. 2004-06-30 21:05 we7u * src/: list_gui.c, locate_gui.c, location_gui.c, messages.c: Fixing memory leaks. 2004-06-30 21:00 we7u * src/interface_gui.c: Fixing memory leaks. 2004-06-30 20:55 we7u * src/: bulletin_gui.c, geocoder_gui.c: Fixing memory leaks. 2004-06-30 14:00 we7u * src/db.c: Fixing a bug Reuven found: Doing an "if" based on the value of an uninitialized variable. 2004-06-30 13:53 we7u * src/db.c: Fixing an indexing bug that Reuven found (via "valgrind"). We can't go past index 0 if we've assigned '\0' to a string. 2004-06-30 13:36 rzg * src/: color.c, dbfawk.c, main.c: Minor memory leak fixes. 2004-06-30 13:32 we7u * src/list_gui.c: Fixing a memory leak that Reuven discovered. 2004-06-30 12:43 we7u * src/db.c: Fixing a bug found by Reuven in the GLL decode routine. 2004-06-30 10:54 we7u * src/: db.h, db.c: Moved multipoints into a separate record, allocating only when needed. This provides additional memory savings over the tweaks that went in yesterday, with no loss in speed/efficiency. 2004-06-29 20:45 we7u * src/: db.c, db.h: Tweaks to significantly reduce memory usage. 2004-06-29 12:42 we7u * src/wx.c: Fixing all the 2^16 constants. Ten of them were incorrect. 2004-06-29 11:41 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added language strings for CAD objects and tactical calls. 2004-06-28 09:56 we7u * src/main.c: Added a comment. No code changes. 2004-06-27 17:15 rzg * src/main.c: Fixed array size error, to fix stack smashing issue. 2004-06-25 16:24 we7u * config/: Makefile.am, tnc-startup.tnc2-ui, tnc-stop.tnc2-ui: Start/stop TNC files contributed by Alessio Sangalli, IW2NYD, for the TNC2-UI TNC used in Europe. 2004-06-24 14:23 we7u * FAQ: Added a bit about ImageMagick and color-depth. 2004-06-24 13:49 we7u * src/: db.c, main.c: Adding some debug stuff to the expire code. Tweaking the status line station readout so it will reflect the current number of stations in all cases. 2004-06-24 13:08 we7u * src/main.c: Erasing box after Measure operation. 2004-06-24 13:00 we7u * src/: db.c, main.c: Removing tac-call capability for objects/items. The saving/restoring of these on startup is a problem. Perhaps we can add the functionality back in later for these, but probably only if we own the objects/items ourselves. Even then, deleting the objects/items needs to be looked at carefully. 2004-06-24 12:29 we7u * src/: db.c, db.h, main.c, util.c: Fix for Move function. Also changed tactical call so that it takes up less memory. 2004-06-23 16:19 we7u * src/main.c: Rearranging the Station menu slightly so that it is harder to delete all stations by mistake. It's now at the bottom of the menu. 2004-06-23 12:54 we7u * src/main.c: Adding a define, commented out currently, which sets all flags properly for a 640x480 touch-screen. Has no effect unless comments are removed. 2004-06-23 12:25 we7u * src/: interface.c, main.c: Backing out the changes that were just made for the Serial TNC Aux GPS interface. Turns out the code was right all along. The user that is experiencing difficulties with a KAM+ must have some other sort of problem. 2004-06-23 11:10 we7u * src/interface.c: Serial TNC AUX GPS interfaces weren't parsing GPS data out of the datastream. This should fix it. More testing to come. 2004-06-23 11:05 we7u * src/main.c: Comment changes. 2004-06-23 10:30 we7u * src/main.c: Changing one debug printf() 2004-06-22 13:44 we7u * src/main.c: Fixing the code so that the SWAP_MOUSE_BUTTONS #ifdef works properly again. 2004-06-22 12:36 we7u * src/db.c: Adding tactical call button to Station Info dialog. This is required for cases where multiple calls are near the pointer, else we can't assign tactical calls. 2004-06-22 10:41 we7u * src/db.c: Fixed a memory leak in the expire routines, where status data was not getting free'd. 2004-06-22 10:20 we7u * src/db.c: Fixing bug in expire code introduced by newly-added tactical call code. 2004-06-21 14:10 we7u * src/: db.c, main.c, main.h, xa_config.c: Adding a toggle flag for selecting only stations with tactical callsigns. 2004-06-21 11:03 we7u * src/: db.c, util.c: Restoring of tactical calls from file when Xastir starts up or after all stations are cleared. Dummy records are created which then get coupled to the real info when the station gets heard on the air. Also tweaked the expire code so that stations with tac-calls don't get expired. They should still get cleared from the screen, but the station and all it's original data, including tac-call, should appear again when the station re-appears on frequency. That new addition to the expire code is not tested fully yet. 2004-06-21 09:08 we7u * src/: db.c, main.c, util.c, util.h: Logging of tactical calls to disk. Added Clear Tactical Calls and Clear Tactical History menu options. Restore of tactical calls from disk at startup is not coded yet. 2004-06-18 22:24 we7u * src/db.c: Adding the callsign or the object/item name as a label in the Assign Tactical Call dialog, so that we know what we're renaming. 2004-06-18 13:32 we7u * src/db.c: Instant update when changing a tactical call. 2004-06-18 13:01 we7u * src/db.c: Minor tweaks to the tactical call stuff. Allows 19 chars now for the name. 2004-06-18 12:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/main.c: Implementing Tactical Calls. Added to the right-click mouse menu. 2004-06-18 10:09 we7u * src/interface.c: Comment changes. 2004-06-18 10:07 we7u * src/interface.c: Mostly comment changes. Added "Counts" to the generic measurements table ( units[] ). 2004-06-18 08:46 we7u * src/interface.c: Changing some comments. 2004-06-18 08:38 we7u * src/interface.c: Minor comment change. 2004-06-18 08:35 we7u * src/interface.c: Minor tweaks to the OpenTrac classification messages. 2004-06-18 08:24 we7u * src/interface.c: Adding in catch-all clauses for OpenTrac elements that are new or not-yet-implemented. 2004-06-18 08:03 we7u * src/interface.c: Putting in more dummy routines for the unimplemented OpenTrac element decoding. 2004-06-18 07:30 we7u * src/main.c: Fixing the AUX-TNC type so that it actually tries to parse the GPS sentences. It didn't appear to do that with the earlier code, while other types of interfaces did parse them. 2004-06-18 06:51 we7u * src/interface.c: Adding parsing for more OpenTrac elements. Not much is done with the data yet, but the placeholders are there now. Added better reporting for various classes of unknown OpenTrac element types also. 2004-06-18 00:08 we7u * src/interface.c: Added some comments. 2004-06-17 16:33 we7u * src/interface.c: More very minor OpenTrac tweaks. 2004-06-17 15:46 we7u * src/interface.c: Minor tweaks so that the OpenTrac comment field gets cleared before we process each piece, plus adding a space before the displayname part of the OpenTrac comment. 2004-06-17 15:11 we7u * FAQ: Added another question/answer about problems caused by the LANG environment variable setting. 2004-06-17 12:28 we7u * src/interface.c: Limiting the comment field on the converted OpenTrac packets to 40 chars, which is the max for a Base-91 compressed APRS packet. 2004-06-17 12:18 we7u * src/interface.c: Converting strcat() to strncat() functions in the OpenTrac routines. 2004-06-17 12:03 we7u * src/interface.c: Changed some comments. No code changes. 2004-06-17 11:10 we7u * src/interface.c: Higher-resolution OpenTrac positioning. We now convert to Base-91 Compressed APRS packets before throwing them into our standard decoding. This should give us 1/100 sec lat/long resolution, instead of the 60' resolution we had before. This new code is untested as of yet. 2004-06-17 10:46 we7u * src/: util.c, xastir.h: Adding a higher-resolution lat/long format, so we can make better use of OpenTrac resolution. 2004-06-17 08:06 we7u * src/interface.c: Changing from issuing the "conv" command to issuing the "k" command to get the TNC into converse mode. One european TNC doesn't implement the "conv" command. 2004-06-16 16:27 we7u * config/: tnc-startup.d700, tnc-startup.thd7: Adding TXD settings to the Kenwood startup files. 2004-06-14 23:23 we7u * src/interface.c: Added a comment. 2004-06-14 22:31 we7u * config/: Makefile.am, tnc-startup.kpc2: Initial kpc2 startup file by Tom Russo. Thanks! 2004-06-14 20:10 we7u * src/util.c: Changing one debug fprintf. 2004-06-14 13:40 we7u * src/interface.c: Removing an error messaging having to do with the tnc-start/stop META tag. This error message gets thrown out at odd times if you happen to have META in a comment in those file. Not needed. 2004-06-14 13:14 we7u * README.win32: Liblcms is now a Cygwin package, so changing the instructions to match. Thanks to Henk de Groot for this info! 2004-06-14 12:53 we7u * config/Makefile.am: Adding a new stop file for the TH-D7A. 2004-06-14 12:49 we7u * config/: tnc-stop.thd7, tnc-startup.thd7: Changes to the tnc-startup.d7a startup file by Henk de Groot, PE1DNN. Also a new tnc-stop.d7a file from him. Thanks! 2004-06-11 12:45 we7u * config/Makefile.am: Adding the new D700 start/stop files. 2004-06-11 12:44 we7u * config/: tnc-startup.d700, tnc-stop.d700: Adding files that David Flood, KD7MYC, came up with to start/top a Kenwood D700A and put it into the proper modes in each case. 2004-06-10 19:26 we7u * src/interface.c: Tweaks to allow more control in the tnc-startup.sys file. Adds a pause and a no-ctrl-C capability. 2004-06-10 16:51 we7u * Davis/src/db2APRS.c: Memory leak update by Bruce Bennett, KB8ROP. Thanks! 2004-06-08 08:37 we7u * config/language-Dutch.sys: Updates by Han Sytsma. Thanks! 2004-06-07 14:13 we7u * configure.ac: Bumping the development rev. up to 1.3.3. 2004-06-07 13:01 we7u * INSTALL: A note about adding a flag to the configure command-line to help it find the Motif include files. 2004-06-07 11:11 we7u * src/alert.c: Fixing string overflow problem triggered by extreme number of compressed alerts. 2004-06-04 15:47 we7u * src/: rac_data.c, rac_data.h: Fixing a possible buffer overflow problem that Tom Russo found. Thanks! 2004-06-04 13:39 we7u * config/: tnc-startup.aea, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: More PID filtering stuff. 2004-06-04 12:42 we7u * config/: tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys: Adding PID filtering so that only 0xf0 PID's make it through in converse mode (APRS packets). 2004-06-04 10:36 we7u * src/fcc_data.c: Fix by Tom Russo. 2004-06-04 10:20 we7u * config/tnc-startup.kam: Adding PID OFF. 2004-06-04 09:53 we7u * config/tnc-startup.kpc3: Adding "PID off" so that other protocols don't show up in converse/monitor mode. 2004-06-03 22:49 we7u * src/main.c: Zoom-in box tweaks. These prevent the vectors from being drawn over again if a screen update has happened. Keeps extra line segments from appearing while doing the zoom-in box mouse operation. 2004-06-03 16:01 we7u * config/language-Dutch.sys: Updates by Han Sytsma, PE1FAM. Thanks! 2004-06-03 15:00 francais1 * config/language-French.sys: Updated somewhat 2004-06-03 14:36 we7u * src/main.c: Widening the zoom-in line width slightly. Looks very nice now/more visible. 2004-06-03 14:11 we7u * config/language-Italian.sys: Updates by Alessandro Frigeri, IK0YUP. Thanks! 2004-06-03 13:47 we7u * config/language-German.sys: Updates by Rolf Bleher, DK7IN. Thanks! 2004-06-03 09:49 we7u * src/main.c: Better zoom-in box operation. Much better! 2004-06-02 14:28 we7u * src/main.c: Added another variable which we check against in order to NOT draw the zoom-in box when we're in the menus. 2004-06-02 12:43 we7u * src/map_gdal.c: Fixing the out-of-bounds check after the coordinate conversion. 2004-06-02 11:19 we7u * src/main.c: Adding a visible selection outline to the zoom-in function. The outline updates once per second currently and doesn't clean up after itself, but they disappear fairly quickly anyway. 2004-06-02 09:41 we7u * configure.ac: Adding Davis stuff. 2004-06-02 09:40 we7u * Makefile.am: Adding Davis directory. 2004-06-02 09:38 we7u * Davis/src/: Makefile.am, db2APRS.c, defs.h: Moved these from xastir/src/Davis/src to xastir/Davis/src 2004-06-02 09:37 we7u * Davis/: AUTHORS, COPYING, ChangeLog, INSTALL, Makefile.am, NEWS, README, bootstrap.sh, configure.ac: Moved these from xastir/src/Davis to xastir/Davis 2004-06-01 20:28 we7u * src/Makefile.am: Removing Davis from the list of subdirectories for now. 2004-06-01 15:49 we7u * src/Makefile.am: Tweaks to include the Davis code in the released tgz files. 2004-05-30 22:34 we7u * src/: dbfawk.c, map_shp.c: More Tom Russo fixes, also removing some debug code that I added earlier. 2004-05-30 18:28 rzg * INSTALL, README.MAPS, help/help-English.dat: Updates to all the docs, some more README.MAPS cleanups/updates. 2004-05-28 17:45 we7u * src/map_shp.c: Correcting what I submitted earlier to match what Tom Russo sent me. My oops. 2004-05-28 16:02 we7u * src/: alert.c, map_shp.c: Tom Russo's tweak to allow red flag alerts in their current transmitted form to be displayed by Xastir. Thanks! 2004-05-28 15:44 we7u * symbols/Makefile.am: Adding new red_flag.xbm file to the mix. 2004-05-28 15:43 we7u * symbols/red_flag.xbm: New warning by Tom Russo. 2004-05-28 12:23 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: More tweaks from Tom Russo. This one is intended to supply a "BOGUS" default value for the key if the shapefile has NULL entries. 2004-05-28 12:16 we7u * src/main.c: Mostly comment changes. Also removing the exit when Festival can't be connected to (which I don't think worked anyway). 2004-05-28 12:03 we7u * src/map_shp.c: Changed an exit() to a return() for the case where dbfawk fails. 2004-05-28 12:03 we7u * src/: hostname.c, sound.c: Added some comments. 2004-05-28 11:34 we7u * src/map_shp.c: Comment change. 2004-05-28 11:09 we7u * src/map_shp.c: Here's a fix for the missing weather alert problem, when using dbfawk. Turns out the latest zone file from NOAA has an unexpected mostly-NULL entry for shape 144, which caused our compare to match on that shape in all cases. It's definitely an incorrect shapefile entry, but it caused a problem in our code as well which needed to be fixed. We now check again using the title length if we got a match due to the key length being 0. 2004-05-28 07:48 we7u * config/: nwsc_ddmmyy.dbfawk, nwsfz_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: Tweaks by Tom Russo to reset fill_style in each dbfawk file. Thanks! 2004-05-26 19:11 we7u * src/: awk.c, dbfawk.c, map_shp.c: More of Tom Russo's memory leak fixes. Thanks! 2004-05-26 14:14 we7u * src/: awk.c, dbfawk.c, map_shp.c: Minor comment changes. Changed to correct cleanup routine for one type of object. More memory leak fixes. 2004-05-26 12:15 we7u * src/map_shp.c: Adding some more "free" stuff before yet another return. 2004-05-26 09:11 we7u * src/xa_config.c: Changing default for weather alert updates to 60 seconds instead of 30. 2004-05-25 22:57 we7u * src/awk.c: Closing another small memory leak. 2004-05-25 21:42 we7u * src/map_shp.c: Handling another error condition. 2004-05-25 21:37 we7u * src/dbfawk.c: More comments. Handled a few error conditions. Perhaps closed a few minor memory leaks. 2004-05-25 16:17 we7u * src/map_shp.c: More comments. 2004-05-25 13:45 we7u * src/: awk.c, map_shp.c: More comments. 2004-05-25 13:01 we7u * src/: dbfawk.c, awk.c: Added some comments. 2004-05-25 13:00 we7u * src/rotated.c: Added some comments regarding malloc's/free's. 2004-05-25 00:30 we7u * src/dbfawk.c: More comments. 2004-05-24 23:53 we7u * src/dbfawk.c: Moving some free() code to the proper places. 2004-05-24 23:08 we7u * src/map_shp.c: More comments. 2004-05-24 21:34 we7u * src/dbfawk.c: Adding more comments. 2004-05-24 21:18 we7u * src/: dbfawk.c, map_shp.c: Adding comments/printf's regarding allocation/deallocation of memory. 2004-05-24 21:11 we7u * src/: awk.c, testawk.c: Adding comments regarding allocations and free'ing of memory. 2004-05-24 18:55 we7u * src/: dbfawk.c, map_shp.c: More memory leak fixes for dbfawk. Getting better! 2004-05-24 14:53 we7u * src/: map_shp.c, dbfawk.c: Adding some free() statements to exit points in map_shp.c, to de-allocate memory that was allocated earlier in the function via dbfawk calls. 2004-05-24 11:02 gstueve * src/main.c: Actually maintain count of visible alerts on screen for increasing alert count. 2004-05-24 10:51 we7u * FAQ: Added a few more notes about what do do for "missing Motif" messages. 2004-05-23 17:01 n2ygk * src/: dbfawk.c, dbfawk.h, map_shp.c: Tom's "bloatpatch" for memory leak. 2004-05-22 18:54 rzg * README.MAPS: Some formatting fixes, updated URL for quad index shapefile. 2004-05-22 12:42 we7u * acinclude.m4, configure.ac: Mods by Tom Russo to allow the --without flags to work properly for festival and gpsman. Thanks! 2004-05-21 11:49 jtwilley * configure.ac: applied Tom Russo's emergency patch - will examine later 2004-05-20 14:46 we7u * src/map_shp.c: Closing a small memory leak in the dbfawk stuff. More to come. Thanks to Tom Russo for finding this one. 2004-05-19 16:23 we7u * src/main.c: Fixing the local station so that compressed posits turn off ambiguity. 2004-05-19 16:08 we7u * INSTALL, README.MAPS, configure.ac, xastir.spec.in: Making dbfawk be compiled in by default. Added --without-* flags for all of the optional libraries so that they can be disabled. Made geotiff compilation dependent on libproj being present. Made dbfawk compilation dependent on shapelib and pcre being present. The tests for the libraries are skipped entirely if the proper --without-* flag is passed to configure. 2004-05-19 09:05 we7u * config/Makefile.am: Adding the fire alert dbfawk file to the distribution. 2004-05-19 09:04 we7u * config/nwsfz_ddmmyy.dbfawk: Adding a dbfawk file for Fire weather alerts. 2004-05-19 08:55 we7u * config/nwsz_ddmmyy.dbfawk: Latest dbfawk file for weather zone shapefile. 2004-05-18 13:28 we7u * config/nwsz_ddmmyy.dbfawk: Added a commented line which works with fire zone files. Can't add it in yet as it appears to be mutually exclusive with the other line before it which works for regular zone files. 2004-05-18 13:26 we7u * src/map_shp.c: Added a comment. 2004-05-18 12:54 we7u * README.MAPS, src/map_shp.c, src/maps.c: Adding support for fire zone maps. Works now for non-dbfawk compiles, but need to get dbfawk working with them as well. The WXSVR should eventually start sending these types of alerts to us on firenet. 2004-05-18 09:42 we7u * src/db.c: Had to move the variable declarations up in the code block, else it fails compile on FreeBSD. Thanks to Tom Russo for this fix. 2004-05-17 13:06 we7u * src/db.c: A small tweak to make the FCC/RAC lookup for objects/items look at the FROM callsign instead of the object/item names. Now we can look up who is sending the objects in our database. 2004-05-17 12:44 we7u * src/db.c: Fixing the weather alert by "Station Info" lookups so that it works for more objects from the weather server. 2004-05-17 11:45 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/wx.h, src/wx_gui.c: Adding the capability to finger the WXSVR if an object/item and has "WXSVR" in the path. This is from a new button "Fetch NWS Alert" in the Station Info dialog. It takes the place of the FCC/RAC button if the above conditions are met. 2004-05-13 10:17 we7u * configure.ac: Moving the ImageMagick check so that it is the absolute last check, so that it doesn't mess up the GDAL check either. Added comments stating that the IM check should stay as the last check. 2004-05-13 09:51 we7u * configure.ac: Moving the ImageMagick test to later in the configuration. It appears to mess up the tests for other libraries if it fails. Now only the GDAL test is below it. 2004-05-12 13:49 we7u * src/alert.c: Additional comments. 2004-05-12 12:33 we7u * scripts/overlay.pl: Correcting the math for lat/long. 2004-05-12 11:56 we7u * src/interface.c: Making sure that the AGWPE path is upper-case. 2004-05-12 11:45 we7u * src/interface.c: Fixing a bug in AGWPE path for objects/items. This bug was caused by a different use of variables between the output_aprs_data() and output_my_aprs_data() functions, and then copying code from one to the other without changing the variables. Variable names are now more common between them, so this problem should be less likely to occur in the future. 2004-05-12 09:44 we7u * scripts/overlay.pl: Changes to comments. 2004-05-12 09:16 we7u * scripts/: overlay.pl, Makefile.am: Adding overlay.pl, which creates either Xastir log file format or Xastir object.log format files from CSV files. Used to create object overlays (actually APRS Items in this case) out of spreadsheet data. 2004-05-11 10:07 we7u * README.win32: Added a comment about an error caused by line-wrap in the Shapelib Makefile. 2004-05-10 13:51 we7u * src/: main.h, main.c: Adding #ifdef's for "OLD_PTHREADS", which knock out the SIGUSR1 handler if "OLD_PTHREADS" is defined in "main.h". 2004-05-10 12:33 we7u * src/db.c: Proper code for randomizing the object/item transmit times a bit. 2004-05-10 09:39 we7u * scripts/Makefile.am: Adding a few of the newer scripts to the install portion. 2004-05-08 19:54 we7u * src/: main.c, db.c: Tweaking the object/item timing to make sure that any changes to an object cause the object to immediately go to the initial state of the decay algorithm. 2004-05-08 18:55 we7u * src/db.c: Fixing the random number modulus operations for transmitting objects/items. It appears however that the rand() and random() functions are broken on this system, always returning 0. 2004-05-07 14:09 we7u * src/db.c: Reducing the randomizing of object/item TX times from 33% of interval to 20% of interval. 2004-05-07 13:45 we7u * src/db.c: Randomizing object/item transmit a bit so that they don't get transmitted together when restarting with active objects/items. This causes them to diverse fairly well after about the third transmit iteration. 2004-05-07 13:21 we7u * src/util.c: Adding some comments. 2004-05-07 11:02 we7u * src/db.c: Fix for objects/items: If we're using the name of one that has already been killed, we now delete the old record completely before creating the new one. This keeps us from drawing tracklines from one to the other or keeping info that doesn't apply to the new object/item. 2004-05-07 09:19 we7u * src/util.c: Fixing the logging of objects/items. There were problems with removing spaces from Items which made them not found in the search, and problems with comments in front of lines in the log file. 2004-05-07 09:16 we7u * src/: db.c, db.h: Comment changes. No code changes. 2004-05-06 16:27 we7u * src/messages.c: Reducing the initial time interval between transmitted messages from 15 to 7 seconds. 2004-05-06 16:19 we7u * src/: db.h, messages.c: Minor comment changes. 2004-05-06 14:40 we7u * src/: db.h, db.c, main.c: Implementing the decaying algorithm for timing of object/item transmits, similar to how Bob Bruninga does it in aprsDOS. Also added a segfault fix for moving Items (same fix as done earlier for moving Objects). 2004-05-04 10:59 we7u * INSTALL: Bumping rev. numbers for some of the optional libraries. 2004-05-03 11:58 we7u * README.MAPS: Added some geodesy links. 2004-04-30 13:27 we7u * INSTALL: Adding more URL's to lists of internet servers. 2004-04-29 15:30 we7u * FAQ: Adding a section describing the fixes for the CVS hostname change at SourceForge. 2004-04-28 14:43 shadow * configure.ac: Test for linker support of -Wl,--no-keep-memory rather than assuming it's safe everywhere; MacOS 10.3.x doesn't support it. 2004-04-27 09:23 we7u * INSTALL: Added instructions for connecting to an internet server plus a pointer to the current list of servers. 2004-04-26 12:31 we7u * README.win32: Additions by Henk de Groot. Thanks! 2004-04-26 11:14 we7u * INSTALL, README.win32: Shapelib links updates, thanks to Wes Johnston for pointing this out. 2004-04-23 10:46 we7u * src/interface.c: OpenTrac patch by J. Lance Cotton, KJ5O. Thanks! 2004-04-23 10:35 we7u * src/igate.c: Refusing to gate OpenTrac packets (which have been converted to APRS-format by Xastir) to/from RF or the INET. 2004-04-21 16:01 we7u * src/main.c: Working version of the new Center & Zoom mouse menu function. 2004-04-21 14:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Starting to add a new mouse menu entry: "Center & Zoom". Non-functional so far but won't take much more work to finish it. 2004-04-15 14:19 we7u * README.win32: An update to the link-step memory-hog note. 2004-04-15 10:12 we7u * README.win32: Added a note about the link-stage being very memory hungry/taking a lot of time to complete on Cygwin. 2004-04-14 14:31 we7u * configure.ac: Adding the no-keep-memory flag to LDFLAGS which makes the link stage on Cygwin much faster. 2004-04-14 10:12 we7u * README.win32: Specifying a minimum set of xorg packages necessary for installing the X11 stuff. Thanks to Henk for figuring this out for us! 2004-04-12 14:21 we7u * configure.ac: Removing one line to make output prettier. 2004-04-12 14:14 we7u * README.win32: Updating the package names for X11 plus removing a few packages that are unnecessary. 2004-04-12 13:18 we7u * README.win32: Changing names of Cygwin packages to correspond to Cygwin's current naming scheme for the X11 server. 2004-04-12 12:40 we7u * README.win32: Removed the xwinclip package from the requirements per Henk de Groot. Added notes by James Cour, K1ZC, and Tim Baggett, AA5DF, regarding the network audio instructions. 2004-04-09 13:07 we7u * README.win32: Removing the "for future development" notes from the pcre descriptions. We use that library for dbfawk support. 2004-04-09 09:44 we7u * README.MAPS: Adding more notes that might make the initial user's decision easier as to which libraries to compile in for the desired functionality. 2004-04-08 09:14 we7u * config/: Makefile.am, tgr2shp.dbfawk: Adding Tom Russo's tgr2shp.dbfawk file to our standard set. Useful for the 2003 tiger data that just came out. 2004-04-06 21:13 we7u * INSTALL: Adding a note about needing "pcre" to compile in dbfawk support. 2004-04-06 09:21 we7u * src/main.c: Adding a command-line option to deselect all maps: "-m" 2004-04-06 08:08 we7u * src/map_shp.c: Fix by Tom Russo: If running with dbfawk, sets everything to defaults in case a dbfawk file fails to reset things when done. 2004-04-05 13:14 we7u * README.win32: Added a note about winclip. 2004-04-02 17:19 we7u * src/: geo.h, geocoder_gui.c: Extending the lengths of the input fields for the Find Address function. 2004-04-02 14:16 we7u * README.win32: Added a note by Henk regarind lcms. 2004-04-02 13:30 we7u * README.MAPS: Added the Wiki page. 2004-04-02 08:03 we7u * configure.ac: Bumping the rev number. 2004-04-01 09:11 we7u * src/geo-find.c: Getting rid of some more compiler warnings. 2004-04-01 07:25 we7u * src/geocoder_gui.c: Fixing a compiler warning. 2004-03-31 22:11 we7u * src/util.c: Better implementation of the higher resolution s2l routines. 2004-03-31 20:46 shadow * INSTALL, help/help-English.dat: document the find address feature 2004-03-31 20:26 we7u * src/util.c: Backing out the changes done earlier today. Will try again to implement higher resolution NMEA strings at a later date. 2004-03-31 20:16 shadow * README.MAPS: Add pointer to Census 2003 data. Add pointer to geocoder data files. 2004-03-31 10:56 we7u * src/util.c: Extending the NMEA sentence decoding to handle DD MM.MMMM format, which the new Tinytrak-3 chips can put out. That resolution ends up being 0.6 counts of our Xastir coordinate system, so we need to resolve down to that level to avoid losing much. 2004-03-30 14:58 we7u * src/db.c: Changing from circles to an 'X' for marking a found address. 2004-03-30 12:49 we7u * src/xa_config.c: Saving/restoring the Mark Destination button state for the Find Address function. 2004-03-30 12:44 we7u * src/: db.c, geo.h, geocoder_gui.c: Added a togglebutton that enables/disables the marking of the destination for the Find Address function. 2004-03-30 12:21 we7u * src/: db.c, geo.h, geocoder_gui.c: Initial attempt at marking the destination target for a Find Address query. There's not capability yet for removing the marking, but you can always seek another address and it will move to the new one. Will probably change to some other marking at some point (a big 'X' perhaps?), and need to find a way to remove the mark that makes sense. 2004-03-30 08:58 we7u * src/geocoder_gui.c: Minor re-arranging of the Find Address dialog's widgets. 2004-03-29 15:57 we7u * src/io-mmap.c: Adding an include to get rid of compiler warnings about memcpy(). 2004-03-29 15:40 we7u * src/: LICENSE.geocoder, geo-client.c, geo-find.c, geo.h, geocoder_gui.c, io-common.c, io-mmap.c, io.h, Makefile.am, main.c, main.h, xa_config.c: Geocoding support added by Derrick J Brashear, based off code written by Daniel Egenor that was released under GPL license. 2004-03-26 10:17 we7u * Makefile.am: Moving the .geo files into a subdirectory called "Online". 2004-03-25 08:35 we7u * src/gps.c: Enabling setuid priviledge at the point where settimeofday() is called. Thanks to William Baguhn, kc9asi, for pointing this out. 2004-03-24 17:29 shadow * src/macspeech.c: macspeech support, but i need to write autoconf gunk, it just pretends to be festival 2004-03-23 15:12 we7u * INSTALL, README.win32: Updating Cygwin instructions: com1 -> /dev/ttyS0 and similar for com2. 2004-03-23 14:59 we7u * acinclude.m4: Tweaking Cygwin serial ports to more standard port names. 2004-03-23 10:01 we7u * src/wx.c: Changes by Bruce Bennett. 2004-03-22 14:12 we7u * src/map_geo.c: Moving an #ifdef so that no compiler warnings are generated when ImageMagick support is missing. 2004-03-22 13:52 we7u * acinclude.m4: Fixes for Cygwin regarding comm ports. 2004-03-22 09:23 we7u * README.win32: Adding instructions to side-step the "detecting devices" hang on WinXP. 2004-03-21 12:58 rzg * help/help-English.dat: Added info on the comment field in interfaces; started a new tally of what changed since release. 2004-03-19 14:38 we7u * src/map_gnis.c: Removing trailing spaces while reading lines in from GNIS files. They are notorious for having many spaces at the ends of the lines. 2004-03-19 12:37 we7u * src/map_shp.c: The rest of the code needed for the XReadBitmapFile() call failure, in order to make sure everything keeps running. 2004-03-19 12:34 we7u * src/map_shp.c: Getting rid of the exit(1) that we were doing when the XReadBitmapFile() call was failing during long runtimes. It's annoying if the bitmap is not found but it shouldn't kill all of Xastir in that case. I'll be checking to see if further changes to the code are necessary though to prevent segfaults happening later in that part of the code. 2004-03-19 09:52 we7u * scripts/split_gnis.pl: Added an RCS tag. Still needs a copyright blurb. 2004-03-19 09:51 we7u * src/interface.c: Fixing the long transmit delay, which was in port_write at the final select() call. 2004-03-18 19:21 jtwilley * scripts/split_gnis.pl: Added split_gnis.pl to scripts directory. The split_gnis.pl script will take any number of state-wide GNIS files listed on the command line and create smaller files based on county names. 2004-03-18 15:14 we7u * src/maps.c: Adding S57 map format to Xastir's supported map types. File extension currently has to be ".s57" for these types of maps to be recognized by Xastir. 2004-03-18 10:11 we7u * scripts/ozi2geo.pl: Changed one comment. 2004-03-18 09:58 we7u * scripts/ozi2geo.pl: Initial attempt at a conversion script from OziExplorer .map format to Xastir's .geo format. This version works with the one example map I had to work with. More than likely more work will be needed on the script as more types of maps are tried. 2004-03-15 15:49 we7u * scripts/split_gnis.bash: Added a comment about "dos2unix". 2004-03-15 15:47 we7u * scripts/split_gnis.bash: Script written by William Baguhn, kc9asi. Splits a GNIS files into smaller pieces which are more quickly loaded by Xastir when zoomed in. 2004-03-15 09:08 we7u * USRadar.geo: Tweaks by Gerry Creager. 2004-03-12 20:54 we7u * USRadar.geo: Mods by Gerry Creager. 2004-03-10 20:11 we7u * src/interface_gui.c: Implementing GUI input fields for the Interface->Properties "comment" field for each interface. 2004-03-10 09:50 we7u * src/interface_gui.c: Minor comment change. 2004-03-09 14:59 we7u * README.MAPS: Another note from Tom Russo on converting between datums. 2004-03-09 13:18 we7u * src/interface_gui.c: Adding some bookmarks. Places that might need to be tweaked for MKISS. 2004-03-09 08:47 we7u * src/interface_gui.c: Wiping out old interface params from config file when an interface is deleted. 2004-03-09 08:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Minor tweaks to the MKISS GUI. Not functional yet. 2004-03-08 22:54 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Updated language strings for MKISS and interface comments. 2004-03-08 22:42 we7u * src/: db.c, interface_gui.c, xa_config.c: Adding new MKISS interface (not complete yet). Adding interface comment capability. 2004-03-08 22:32 we7u * src/interface.h: Adding new fields. Needed for MKISS interface and for adding comments to interfaces. 2004-03-08 13:16 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Updates to language strings for MKISS TNC's. 2004-03-08 13:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c: Initial stab at creating a new SERIAL_MKISS interface type. So far it's an identical copy of the SERIAL_KISS interface type, but that will change soon. Intent is to support multi-port KISS TNC's such as the Kantronics KAM. 2004-03-04 15:12 we7u * USRadar.geo, help/help-English.dat, src/color.c, src/color.h, src/map_geo.c, src/maps.h: Fix for the TRANSPARENT tag in .geo's: Wasn't working right on 16-bit versus 24-bit Xwindows servers. 2004-03-03 14:54 we7u * src/map_geo.c: Toporama map speedups made possible by Steve Dimse's changes on the server. 2004-03-02 13:19 we7u * README.win32: A note by Steve Peters, N1TYE, regarding the lcms library on Cygwin. 2004-03-02 09:56 we7u * src/map_geo.c: Terraserver is playing games, changing their URL again. Changing back to the original one we used to use, which works for us again. The newer URL was returning all black images. 2004-03-02 00:10 we7u * src/map_geo.c: Commenting out debug output. 2004-03-02 00:07 we7u * src/maps.c: Sending tab map files to draw_ogr_map(). 2004-03-01 23:50 we7u * Makefile.am, src/map_geo.c: Initial version of code to support Canadian Toporama maps, downloading them automatically over the 'net from mm.aprs.net, including the dynamically generated .geo files. 2004-03-01 23:47 we7u * CanadaTopo250k.geo, CanadaTopo50k.geo: Initial checkin. 2004-03-01 09:31 we7u * README.MAPS: Changing notes regarding where to find free DRG maps. 2004-02-29 18:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Tweaking the Interface Start/Stop dialog so that it is much more readable. 2004-02-29 12:31 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added two new trail sliders to the timing dialog. They both control whether trails are displayed, one based on max distance, one based on max time. If either max distance or max time are exceeded for new trails, that segment is not drawn. Does not affect trail points that have already been received, just new trail points. 2004-02-27 19:12 we7u * src/main.c: Modifying the Move function so that it drops through all the dialogs and doesn't require any OK buttons to be pressed to effect the move. This is useful for drawing the expected route of a SAR team and documenting it via Shapefiles. It's much faster to do so now. Downside: Unintentionally moving an object gets an automatic confirm, and you'll have to move it back manually or else edit the object.log file by hand and read it in again. 2004-02-27 18:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c: Adding a "Disable Posit Dupe-Checks" option to Configure->Defaults. Disables the 30-minute dupe-checks that Xastir does when each packet is received. Does not affect igate dupe-checks. 2004-02-27 17:26 we7u * src/: db.c, main.h, util.c: Turning off trail-point dupe-checking when reading in objects/items from file. This lets us show SAR teams leaving and returning to base later, without having the last trail segment missing. 2004-02-27 17:00 we7u * src/db.c: Updating some comments. 2004-02-27 15:42 we7u * help/help-English.dat: Adding notes about trails and why some segments don't display. 2004-02-27 14:58 we7u * src/db.c: Changing the distance at which Xastir will skip a track segment, from >1 degree lat/long to >2 degrees. Any track segment less than 2 degrees in N/S and E/W length will get drawn, as long as the time between posits is less than 45 minutes. If over 45 minutes, the segment gets skipped as well. 2004-02-26 15:25 we7u * src/interface.c: New code to avoid opening the same serial port twice for two different interfaces. 2004-02-26 15:19 we7u * src/db.c: Changing some debug code. 2004-02-26 13:48 we7u * INSTALL: Added a note about how to test the festival server by telnet'ing to it. 2004-02-26 12:30 we7u * src/: map_geo.c, map_tiger.c, track_gui.c: Fixing the problem where a failed internet download (map or tracklog) would cause an older version of the same to get displayed. We now delete the old filename from our ~/.xastir/tmp directory before attempting the download each time. 2004-02-26 12:07 we7u * src/: db.c, db.h: Adding a retry timeout for killed object/items. We'll now transmit killed objects 11 times before ceasing to transmit them. 2004-02-24 11:34 we7u * README: Additions by Alan Shackelford, NG3B. 2004-02-24 09:28 we7u * README.MAPS: More good info from Tom Russo, KM5VY. 2004-02-23 14:52 we7u * README.MAPS: Added the FIPS locator URL. Useful stuff! 2004-02-21 22:32 we7u * INSTALL: Updating some libtiff/libgeotiff notes. 2004-02-21 12:35 kd6zwr * src/map_shp.c: Add label levels for point style shapefiles when using dbfawk 2004-02-13 13:40 we7u * src/maps.c: Fixing the prime meridian line for UTM grid. Wasn't being drawn at all zoom levels. 2004-02-13 08:54 we7u * README.win32: Added a warning about KDE. 2004-02-12 14:18 we7u * src/: interface.h, interface.c: New method of waiting for data to get to serial TNC's before closing the port. Method and most of the code contributed by Erik G. Burrows, KG6HEA. Additional code by WE7U to prevent locking up with poorly-behaved serial devices. 2004-02-11 14:40 we7u * src/map_geo.c: Making transparent images work again after the raster_intensity changes a few weeks back. 2004-02-11 13:35 we7u * src/main.c: Fixing an annoying floating-point conversion bug in the Map Intensity menus. For 70% and 90%, they were reported as 60% and 80% in the menus. 2004-02-11 10:24 we7u * Makefile.am, USRadar.geo, src/map_geo.c, src/maps.h: Changing to an unsigned long for holding the transparency value. Adding USRadar.geo as an installed map ('cuz it's just way cool). 2004-02-10 14:18 we7u * src/db.c: Making the 'h' in timestamp be case-insensitive on receive. 2004-02-10 14:18 we7u * src/db.c: Making the 'h' in a timestamp be case-insensitive on receive. 2004-02-09 12:20 we7u * src/db.c: Making N/S/E/W and the timestamp 'Z' non case-specific. This was requested by Bob Bruninga on the APRSSIG mailing list recently (sometime in january 2004, before our last stable release). 2004-02-06 14:39 we7u * src/interface_gui.c: Changing default path from RELAY,WIDE to WIDE. 2004-02-06 13:33 we7u * configure.ac, src/main.c: Adding a list of the compiled-in libraries to the Help->About dialog. 2004-02-05 11:00 we7u * INSTALL, README.CVS, README.win32: Updating CVS instructions because SourceForge isn't handling compression currently. 2004-02-04 12:41 we7u * bootstrap.sh: Adding the CVS tag line. 2004-02-04 08:49 we7u * src/: main.c, map_shp.c: Changing some error messages to provide more detail. 2004-02-02 23:10 we7u * README.win32: Mods by David Flood, KD7MYC. Thanks! 2004-02-02 14:31 we7u * configure.ac: Bumping the patch number so we can separate development versions from most recent stable release. 2004-02-02 13:41 we7u * config/language-German.sys: Updates by Rolf, DK7IN. 2004-02-02 12:58 we7u * src/main.c: Updating the Help->About message. Thanks for reminding me Ren! 2004-02-02 08:37 we7u * configure.ac: Bumping the revision to 1.3.0. Getting ready for stable release. 2004-02-02 08:35 we7u * help/help-English.dat: Very minor changes to the What's New section. 2004-02-01 23:26 rzg * help/help-English.dat: Moved old "What's new" list out of the way. 2004-02-01 23:23 rzg * help/help-English.dat: What's new section. Could use proofreading and the addition of stuff I forgot. 2004-01-30 15:48 shadow * README: update README to reflect what's needed to get MacOS X with GDAL. 2004-01-30 13:51 we7u * xastir.spec.in: Correcting the path to the man pages. 2004-01-30 10:12 we7u * symbols/symbols.dat: Implemented Wheelchair, Shelter, and proposed Waypoint symbol. Also changed one description from "HF Gateway" to "Any Gateway (w/overlay char)". The "Any Gateway" symbol still needs to be changed into something which would display an overlay char nicely. The Shelter symbol may need to be changed into something more recognizable. 2004-01-29 17:47 n2ygk * xastir.spec.in: --with-dbfawk. Curt: toss this if you feel dbfawk is not cooked enough. 2004-01-29 08:53 we7u * INSTALL: Updating the gpsman/gpsmanshp instructions for systems with tcl8.4 instead of tcl8.3. 2004-01-28 10:42 we7u * AUTHORS: Got rid of reference to non-existent file. Add note stating we don't try to keep this file up to date. 2004-01-28 10:11 we7u * UPGRADE: Added more notes about migrating to latest Xastir. 2004-01-28 09:42 we7u * README.CVS: Added another note about sticky tags. 2004-01-26 12:50 we7u * INSTALL: Adding a note about the port names for Cygwin. 2004-01-26 08:18 we7u * src/: Makefile.am, alert.c, alert.h, awk.c, awk.h, bulletin_gui.c, bulletin_gui.h, color.c, color.h, datum.c, datum.h, db.c, db.h, dbfawk.c, dbfawk.h, draw_symbols.c, draw_symbols.h, fcc_data.c, fcc_data.h, festival.c, festival.h, gps.c, gps.h, hostname.c, hostname.h, igate.c, igate.h, interface.c, interface.h, interface_gui.c, lang.c, lang.h, list_gui.c, list_gui.h, locate_gui.c, location.c, location_gui.c, main.c, main.h, map_dos.c, map_gdal.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h, messages.c, messages.h, messages_gui.c, popup.h, popup_gui.c, rac_data.c, rac_data.h, rotated.c, rotated.h, snprintf.c, snprintf.h, sound.c, symbols.h, testawk.c, track_gui.c, track_gui.h, util.c, util.h, view_message_gui.c, wx.c, wx.h, wx_gui.c, x_spider.c, x_spider.h, xa_config.c, xa_config.h, xastir.h: Updating copyright notices. 2004-01-26 08:11 we7u * LICENSE, README.win32, callpass/Makefile.am, callpass/callpass.c, config/Makefile.am, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, config/tnc-startup.aea, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.paccomm, config/tnc-startup.pico, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, help/Makefile.am, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Portuguese.dat, help/help-Spanish.dat, m4/Makefile.am, scripts/Makefile.am, scripts/example_objects.log, scripts/fcc-get, scripts/xastir-fixcfg.sh, scripts/xastir-migrate.sh, symbols/Makefile.am, symbols/symbols.dat: Updating copyright notices. 2004-01-26 08:09 we7u * AUTHORS, DEBUG_LEVELS, INSTALL, Makefile.am, NEWS, README, README.CVS, README.MAPS, UPGRADE, acinclude.m4, bootstrap.sh, changes.txt, configure.ac, xastir.1, xastir.spec.in: Updating copyright notices. Adding a few more docs to the spec file. 2004-01-22 19:26 we7u * src/xa_config.c: Adding sys/stat.h call that is needed to compile this file on MacOSX. 2004-01-22 18:34 we7u * README.CVS: Updating the "unsticky" instructions for CVS. 2004-01-21 16:14 rzg * FAQ: Added a bit on support, fixed numbering, a typo, and copyright year. 2004-01-21 15:48 we7u * README.CVS: Added the "diff" line to .cvsrc note. Added "sticky" tags STABLE and RELEASE and explanations of how to use them. 2004-01-21 08:47 we7u * src/xa_config.c: Changing default for "Expand Dirs" in Map Chooser to 1. Better for new users. 2004-01-20 13:34 we7u * FAQ: Another note about ImageMagick dependencies and "spec" files. 2004-01-20 13:32 we7u * FAQ: Adding some notes about ImageMagick and failed dependencies. 2004-01-19 15:02 we7u * src/maps.c: Attempting to fix an indexing bug. New files are not picked up by indexing. This fix picks the later of ctime/mtime to use for the timestamp. Contributed by Reuven. 2004-01-19 13:33 we7u * src/: main.c, maps.c: Commented out some dead code in maps.c. Added new USR1 signal handler code by Tim Gimmel, KB4AMA. Just send a USR1 signal via "kill -USR1 " and Xastir will create a new snapshot. Useful for web page front-ends. 2004-01-16 12:25 gstueve * src/: alert.c, alert.h: Change numeric index references in flags to symbolic and fixed end-of-data to match sizeof data not fixed numeric values. 2004-01-16 12:18 gstueve * scripts/fcc-get: Update for new diretory layout with generic path name & add passive ftp. 2004-01-16 10:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.h, src/wx.c: Initial support for Davis Weather Monitor II, Wizard III, and Vantage Pro weather stations, written by Bruce Bennett. Thanks Bruce! 2004-01-15 13:28 we7u * src/xa_config.c: Attempting to recover from backup file renaming when things go wrong. We'll try to get as close to the original state of the files as we can. 2004-01-15 13:09 we7u * src/xa_config.c: More config file backup copies code. We now back out the renaming if the new config file can't be created, so we're left with the original config and two backups in that case. 2004-01-15 11:02 we7u * FAQ, src/interface.c, src/interface_gui.c, src/xa_config.c: Simplified the all interfaces up/down logic. It should work better now. Changed the config file backup code so that xastir.cnf.1 through xastir.cnf.3 are created. This should help insulate us a bit better from crashes, as we'll have more old copies of the config file to draw from if the main config file (xastir.cnf) gets trashed. 2004-01-15 08:56 we7u * configure.ac: Adding a line in for getting rid of duplicates in the LIBS variable. Commented out while testing so that it doesn't hurt any installations. 2004-01-14 15:07 we7u * src/main.c: Adding more sprintf's in cases of failure to create symlinks. 2004-01-14 12:07 we7u * configure.ac: Extending one comment. No code changes. 2004-01-14 12:00 we7u * src/main.c: Minor tweak to two fprintf strings. 2004-01-12 11:44 we7u * src/main.c: Changing back to a previous configuration for the end of the create_appshell() function. Attempting to get rid of this problem: "attempt to add non-widget child "DropSiteManager" to parent "xastir" which support only widgets" while not re-creating this problem: "Shell widget xastir has zero width and/or height". 2004-01-09 10:57 rzg * help/help-English.dat, src/maps.c: Map index checking now allows negative layer numbers. Minor helpfile updates 2004-01-09 08:11 we7u * src/map_gdal.c: More checks for invalid extents while indexing. If all 0's or outside indexes of the earth, we skip adding it to the index. 2004-01-08 13:38 we7u * src/main.c: Re-establishing the XtRealizeWidget() call in main that was commented out to help fix the "zero width or height" error on startup. Now we specify a minimum size in the XtVaAppInitialize() call that preceeds it, so the old problem shouldn't reoccur. 2004-01-08 13:34 we7u * src/main.c: Gives an initial size to the application. Makes it appear to come up faster. Whether or not it actually does is beside the point. May help to get rid of the initial sizing problem: "Error: Shell widget xastir has zero width and/or height". 2004-01-07 08:42 we7u * configure.ac: Minor tweaks to some AC_MSG_ERROR calls. 2004-01-07 08:42 we7u * INSTALL: Minor tweaks to the make instructions here and there. 2004-01-04 13:37 we7u * src/map_gdal.c: Correcting the limits for OGR indexing. 2003-12-30 07:38 we7u * src/maps.c: Changing startup STDERR output to show which library (Shapelib/OGR) is providing Shapefile support. 2003-12-26 09:26 we7u * src/interface.c: Bumping the read/write loop timeouts to 100ms. This should provide reasonable response time when killing ports, yet keep CPU usage low when no data is being read/written. 2003-12-26 08:17 we7u * src/interface.c: Bumping the timeout in port_write() select to 500ms. That timeout is used to jump out of the select() so that we can check whether the interface has gone down. It does not need to be very small, and in fact causes high CPU usage on freebsd systems if it's below about 1ms. Linux can handle somewhat smaller delays (100us is ok on Linux). 2003-12-24 17:07 rzg * help/help-English.dat: Whatsnew update, and tigermap.geo is back... 2003-12-23 17:49 we7u * src/: main.c, map_gdal.c, maps.c, xastir.h: Added another output line to the segfault handler. Minor tweaks to the OGR code. 2003-12-23 07:25 we7u * src/map_gdal.c: Added some comments. 2003-12-22 18:59 we7u * src/map_gdal.c: Starting to add map preferences code to the OGR map-drawing functions. 2003-12-20 16:18 we7u * src/main.c: Getting rid of a couple of messages used for cad object debug. Put them inside ifdef's. 2003-12-19 16:28 we7u * src/: map_geo.c, map_shp.c, map_tiger.c: Fixing raster_map_intensity for tiger and .geo maps. Changes in comments and remove of debugging code in map_shp.c 2003-12-19 13:33 we7u * src/map_geo.c: Minor tweak to make toposerver files work again and make the .geo code look like the tiger code w.r.t. image intensity. 2003-12-19 12:59 we7u * src/map_gdal.c: Improvements to the line drawing routines mostly. OGR stuff. 2003-12-19 12:59 we7u * src/maps.c: Major speed improvements to map_onscreen(), map_visible(), and map_visible_lat_lon() routines. 2003-12-19 12:58 we7u * src/main.c: Moved routines around. No code changes. 2003-12-18 16:04 we7u * src/map_gdal.c: Tweaks to OGR polygons. 2003-12-18 13:06 we7u * src/map_gdal.c: Working X11 Regions for drawing OGR "hole" or innner polygons. 2003-12-18 07:06 we7u * src/alert.c: Zero'ing out newly-added alert entries after each realloc() call. 2003-12-17 22:45 we7u * src/map_tiger.c: ImageMagick brightness code change by Jim Chandler, N0VH. 2003-12-17 22:40 we7u * src/map_gdal.c: Starting to add the framework for doing X11 Regions. Will allow doing "fill" and "hole" polygons as we currently do in the Shapelib code. 2003-12-17 13:07 we7u * src/map_gdal.c: More comments. 2003-12-17 12:58 we7u * src/map_gdal.c: Minor comment changes. 2003-12-17 12:56 we7u * src/map_gdal.c: More fill/hole polygon stuff. Currently drawing polygons with dashed lines for "hole" polygons, solid for "fill" polygons. This is if the use has decided not to fill the shapes. For filled shapes, the hole polygons aren't drawn at all currently. 2003-12-17 12:36 we7u * src/map_gdal.c: More comments. Starting to add polygon fill/hole differentiation code. 2003-12-17 12:06 we7u * src/map_gdal.c: More comments. 2003-12-17 10:24 we7u * src/map_gdal.c: Comment changes only. 2003-12-17 07:42 we7u * src/map_gdal.c: Fixing OGR polygons so they work again, still non-filled though. 2003-12-17 07:14 we7u * src/map_gdal.c: More comment changes. 2003-12-17 07:04 we7u * src/map_gdal.c: Changing default colors and changing a few comments. The colors won't stay, but they're useful at the moment for debugging. 2003-12-16 12:08 we7u * src/maps.c: Added some comments. 2003-12-16 10:16 we7u * src/interface.c: Fixes to make the OpenTrac tweaks compile properly. 2003-12-16 10:09 we7u * src/interface.c: Fixes to OpenTrac decoding by Scott Miller. 2003-12-16 08:19 we7u * src/alert.c: An attempt to skip over alert_list[] entries that are zeroed (title has '\0' as the first character) while doing an alert_match(). 2003-12-15 09:19 we7u * src/interface.c: Patch by Brian Heaton to prefix the port number to the incoming string we dump out via our segfault handler. 2003-12-15 07:56 we7u * README.MAPS: Added another SDTS note. 2003-12-13 10:36 we7u * INSTALL: Added another GDAL comment. 2003-12-13 10:33 we7u * src/map_gdal.c: Moved some XSet... calls down into the OGR drawing section. Above the indexing section they caused segfaults. We must not be calling the indexing functions with a valid widget? 2003-12-12 17:16 we7u * README.MAPS: Adding more map links for some new map formats. 2003-12-12 13:20 we7u * src/map_gdal.c: Faster OGR polygons. Transforming all of the points at once for each polygon. 2003-12-12 13:02 we7u * src/map_gdal.c: Faster OGR line drawing. Recognize more datums that we don't have to convert (faster again). 2003-12-12 12:31 we7u * src/map_gdal.c: Removing unneeded code. Adding more comments. 2003-12-12 12:24 we7u * src/map_gdal.c: Adding comments. 2003-12-12 12:20 we7u * src/map_gdal.c: Renaming OGR helper functions to make sure there aren't any clashes later with similar functions. 2003-12-12 12:17 we7u * src/map_gdal.c: Speeding up OGR Point drawing. Changing default point color to white. 2003-12-12 12:03 we7u * src/map_gdal.c: Faster OGR line/polygon drawing by checking extents on those datatypes that allow fast extent checking. 2003-12-12 12:02 we7u * configure.ac: Minor summary text change. 2003-12-12 08:23 we7u * src/map_gdal.c: Added TODO list for OGR and moved the Draw routines above the main OGR routine (getting rid of the prototypes). 2003-12-12 08:04 we7u * README.MAPS: Added a note about SDTS files. 2003-12-12 07:46 we7u * src/map_gdal.c: A bit of cleanup in the new OGR routines. 2003-12-12 07:30 we7u * src/map_gdal.c: Creating OGR Draw_Points() function which is similar to the Draw_Lines() and Draw_Polygons() functions. Skips drawing points that are outside the view. 2003-12-12 06:55 we7u * INSTALL: Changes to the GDAL/OGR notes. 2003-12-11 17:50 we7u * src/map_gdal.c: Optimizing Draw_Lines() and Draw_Polygons() functions in the OGR routines. We now check the extents of each feature and skip drawing it if it's not in our view. 2003-12-11 12:35 we7u * src/: main.c, map_gdal.c: Fixing map_interrupts so that they work properly and quickly. A few places were broken, including the new OGR code. 2003-12-11 11:42 we7u * src/map_gdal.c: Changed some variable names. Added some debug code, looking for sources of memory leaks. 2003-12-10 22:43 we7u * INSTALL: Added a new site for Shapelib. 2003-12-10 16:31 we7u * src/map_gdal.c: On-the-fly coordinate transforms while drawing. 2003-12-10 11:14 we7u * src/maps.c: Adding more map types that are accepted by OGR. 2003-12-10 10:18 we7u * src/map_gdal.c: Changed some comments. 2003-12-10 10:16 we7u * src/maps.c: Adding mif/mid (Mapinfo) to list of accepted map types for OGR. 2003-12-10 00:01 we7u * src/map_gdal.c: Minor reformatting. 2003-12-09 23:13 we7u * src/map_gdal.c: Added a comment. 2003-12-09 17:03 we7u * src/map_gdal.c: Better Polygons for OGR. 2003-12-09 12:27 we7u * src/map_gdal.c: Drawing of OGR polygons is now working. 2003-12-09 08:55 we7u * src/map_gdal.c: Slightly faster drawing code due to fewer sets of debug loops. More comments. 2003-12-09 00:22 we7u * src/: map_gdal.c, maps.c, maps.h: Added a new draw function for points. More tweaks to the OGR code. 2003-12-08 15:43 we7u * src/interface.c: Checking that I can stat a file and that it is a regular file before attempting to send a file of commands to the TNC. 2003-12-08 13:22 we7u * src/map_gdal.c: Adding indexing for files where spatial coordinate system is not known, but they still fall within the normal lat/long boundaries for file extents. We're assuming they're in geographic WGS84 coordinates in this case and allowing the indexing to complete. 2003-12-08 12:56 jtwilley * config/tnc-startup.null: Added a zero-byte file named 'tnc-startup.null' for those times when users do not want their TNC configurations changed by xastir. 2003-12-08 12:19 we7u * src/map_gdal.c: Comment updates. No code changes this time. 2003-12-08 12:10 we7u * src/map_gdal.c: Took out some debug stuff that messed with converting to nad27 datum for test runs. Generalized the code so that it works with projected coordinate systems. No computes file extents for state-plane coordinate systems. It should also work for UTM projected coordinate systems. 2003-12-07 23:50 we7u * src/map_gdal.c: For file extents (indexing): Datum translation is working now for geographic coordinate systems. Not implemented yet for projected coordinate systems. Haven't implemented datum translation for drawing yet. 2003-12-07 23:47 we7u * src/maps.c: Forcing shapefiles back to the old code for now. 2003-12-07 23:46 we7u * src/maps.c: More debug for map_driver stuff. 2003-12-07 12:23 we7u * src/interface.c: Reducing delay in port_write for checking queue. Down to 100us from 200ms. Makes writing to interfaces much snappier, but doesn't bog down CPU. Cranking up channel_data() busy wait from 1 to 2us. 2003-12-07 09:16 we7u * src/: main.c, xa_config.c: Fixing the 10% zoom in bug when at zoom level 1. 2003-12-06 12:10 we7u * src/map_gdal.c: Filling in a bit more for the OGR indexing code. 2003-12-06 09:20 we7u * src/interface.c: Reducing many of the usleep() delays while transmitting to serial TNC's. Users will have to rely on the new delay slider to add delays if they get into weird operation with any particular TNC. 2003-12-05 23:44 we7u * src/map_gdal.c: More changes to debug output. 2003-12-05 23:36 we7u * src/map_gdal.c: Partial map indexing working for OGR. Must be geographic coordinate system. Haven't implemented conversions from other datums or coordinate systems to geographic WGS84/NAD83 yet. 2003-12-05 22:33 we7u * src/map_gdal.c: Printing out extents now. Should have indexing implemented soon. 2003-12-05 22:02 we7u * src/map_gdal.c: More reformatting for debug purposes. 2003-12-05 19:11 we7u * src/map_gdal.c: Better formatting for OGR debug statements. 2003-12-05 17:36 we7u * src/map_gdal.c: Filling in more features. Slowly. 2003-12-05 14:07 we7u * src/xa_config.c: Changing the default serial_char_pacing to 1ms instead of 25ms. 2003-12-05 13:08 we7u * src/map_gdal.c: Working version of what I checked in last time. ;-) 2003-12-05 13:01 we7u * src/map_gdal.c: More good info in the OGR code. 2003-12-05 12:40 we7u * src/map_gdal.c: Fleshing out more details in the OGR driver. 2003-12-05 11:39 we7u * src/xa_config.c: Adding save/restore for serial character pacing. 2003-12-05 11:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/main.c, src/main.h, src/map_gdal.c: Speeding up OGR. Adding a new inter-character delay timing slider that affects serial-port TNC's. 2003-12-04 10:58 we7u * src/map_gdal.c: Changed some comments. 2003-12-04 10:08 we7u * src/map_gdal.c: Adding map interrupt capability to the OGR code. 2003-12-04 08:39 we7u * src/maps.c: Fixing up the callouts to GDAL/OGR. We direct Shapefile stuff to draw_shapefile_map() right now instead of GDAL/OGR. Tiger goes to GDAL/OGR. This can be changed via a define near the top of maps.c so that Shapefile goes to OGR as well. 2003-12-04 08:36 we7u * src/map_shp.c: Getting rid of duplicate definition of font_size. 2003-12-04 08:21 n2ygk * src/map_shp.c: fix the font_size fix to use FONT_DEFAULT 2003-12-04 00:43 we7u * src/maps.c: Adding more vector types. Currently commented out, but the GDAL/OGR code will eventually support them. 2003-12-04 00:36 we7u * src/main.c: Added more vector formats to the Vector button in Map Chooser. 2003-12-04 00:25 we7u * src/map_gdal.c: Several segfaults fixed. Handles polyline shapefiles and raw Tiger/Line polylines so far. 2003-12-03 23:23 we7u * src/map_shp.c: Fixing a compile problem for non-dbfawk compiles. 2003-12-03 17:08 n2ygk * src/: main.c, map_dos.c, map_pdb.c, map_shp.c, maps.c, maps.h, xa_config.c, xastir.h: multiple font_sizes in maps/config/map label font 2003-12-03 17:05 n2ygk * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: font_size 2003-12-03 14:18 we7u * README.MAPS: Added a note about Tiger/Line maps (coming soon). 2003-12-03 13:08 we7u * src/map_gdal.c: Added some comments. 2003-12-03 12:53 we7u * src/map_shp.c: Removing the debug OGR code for the moment. 2003-12-03 12:52 we7u * src/map_gdal.c: OGR drawing for Shapefile polylines is starting to work. Not pretty yet. Points/Polygons not working yet. 2003-12-03 12:51 we7u * src/maps.h: Adding a prototype for a function needed in draw_gdal.c 2003-12-03 12:07 we7u * src/map_gdal.c: More OGR library stuff. Am at the point where I have access to the points/polylines/polygons... 2003-12-03 08:19 we7u * src/: main.c, maps.h: Changing the Map Properties dialog so that it only shows maps that were selected in the Map Chooser. Also the Ok and Cancel buttons in the Map Chooser are greyed-out when the Properties dialog is active (necessary due to the way I implemented the new feature). 2003-12-03 00:18 we7u * src/main.c: Added some comments. 2003-12-02 23:42 jtwilley * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added "Select All" line to the other language files. 2003-12-02 23:04 jtwilley * config/language-English.sys, src/main.c: Added "Select All" button to "Map Properties" dialog. 2003-12-02 16:25 we7u * src/map_shp.c: Forgot an #ifdef. 2003-12-02 16:23 we7u * src/: map_gdal.c, map_shp.c, maps.c: Debug OGR code. Nothing truly functional yet. Just getting a feel for how to go about it. 2003-12-02 15:06 we7u * configure.ac: Broke libproj check out into its own section and summary line. We still need it checked in the libgeotiff section as well though, as we depend on proj there too. 2003-12-02 14:16 we7u * src/: map_gdal.c, maps.c: Changing some warning messages. 2003-12-02 14:02 we7u * src/map_gdal.c: Getting rid of compiler warnings. 2003-12-02 13:50 we7u * configure.ac: Moving the pcre summary next to the dbfawk summary at the end of configure. Reordered some of the rest as well, putting all of the map libraries together. 2003-12-01 13:13 we7u * src/x_spider.c: Adding an include to make a compiler warning disappear. 2003-12-01 12:56 we7u * INSTALL: Removing a note that is no longer needed. CVS GDAL has been tweaked to fix it. 2003-11-29 11:12 we7u * src/x_spider.c: Flushing out the feature set for x_spider. Not ready for prime-time yet, but getting closer. It now echoes anything received from one client out to all other connected clients. No provision yet for detecting disconnected clients and removing their pipe structures. 2003-11-29 00:44 we7u * src/x_spider.c: Filling in more details for x_spider. Not functional yet. 2003-11-29 00:10 we7u * src/: x_spider.c, x_spider.h: More of the x_spider server code filled in. Not functional yet. 2003-11-28 22:34 we7u * src/: Makefile.am, x_spider.c, x_spider.h: Initial code for x_spider server. This is an APRS multiplexer that will eventually allow multiple other clients (Xastir or otherwise) to connect to a running Xastir and TX/RX APRS data between them. This will allow the other clients to share the TNC, AX.25, and network ports that Xastir is hooked up to. The code is not functional in that capacity yet, but it is a nice multi-connect echo server as it stands. 2003-11-28 22:26 we7u * src/: map_gdal.c, maps.c: Adding prototype for draw_ogr_map(). No real code yet. 2003-11-28 22:10 we7u * src/main.c: Fix for the stupid "PACKAGE" warnings that the GDAL include file causes. Fix figured out originally by Jack for the ImageMagick stuff, duplicated by me in the GDAL include area. 2003-11-28 21:57 we7u * src/main.c: Slowing down the UpdateTime() loop iteration. Some systems (RedHat/FreeBSD) appear to use up a lot of CPU time if this is set to '1' or '0'. Setting it to '2'. Will crank it up some more if people still report high CPU usage. 2003-11-28 14:55 kd6zwr * src/: main.c, map_gdal.c, maps.c: Cleaning up GDAL init, starting gdal code. 2003-11-26 18:47 we7u * src/maps.c: Changing from strstr() to strncmp() for matching selected directories with files inside them. Much more exact. 2003-11-26 14:10 we7u * src/main.c: Clearing the selected bits in the in-memory map index before we try to resync with the selected_maps.sys file's idea of what maps are selected. 2003-11-26 12:04 we7u * INSTALL: Adding GDAL instructions (not that there's much that can be done with it yet, but it's still nice to see the future list of supported map formats on startup!). 2003-11-26 09:37 we7u * src/maps.c: Getting rid of compiler warning when XPM is not available. This fix makes sure that the snapshot thread doesn't even get defined in that case. 2003-11-26 09:00 we7u * src/testawk.c: Fixing another couple of compiler warnings. 2003-11-26 08:54 we7u * src/awk.c: Fixing more compiler warnings. Trivial stuff. 2003-11-26 08:43 we7u * src/maps.c: Getting rid of another compiler warning. 2003-11-26 08:35 we7u * src/map_tif.c: Getting rid of compiler warnings. 2003-11-26 08:29 we7u * src/maps.c: Getting rid of compiler warnings and removing dead code. 2003-11-26 08:25 we7u * src/map_tiger.c: Fixing a compiler warning, although I can't for the life of me figure out why the compiler is confused. Perhaps all of the #ifdef's confused it. 2003-11-26 08:14 we7u * src/map_shp.c: Fixing a compiler warning. 2003-11-26 08:01 we7u * src/interface.c: Changing one variable to unsigned to get rid of a compiler warning. We don't need a signed variable there anyway. 2003-11-25 18:19 we7u * src/main.c: Converting to square meters/feet when the CAD object's area is too small for miles/km. 2003-11-25 14:34 n2ygk * config/tgrlk.dbfawk: label color blue for water 2003-11-25 14:14 we7u * src/main.c: Making the End Draw Mode function write the CAD objects out to disk as well. This makes it possible to save open polygons (polylines) instead of only closed polygons. 2003-11-25 12:49 we7u * src/main.c: Persistent CAD Objects. They get save/restored to/from file now. 2003-11-25 10:32 we7u * src/db.h: Changing the saved polygon area from an int to a float. 2003-11-25 10:31 we7u * src/main.c: Leaving the calculations in square nautical miles until we're finished, then converting to what the user needs. Saving the area now in the object in units of square kilometers. 2003-11-25 10:01 we7u * src/main.c: Issuing a popup message with the area measurement. 2003-11-25 09:49 we7u * src/main.c: More corrections to the area calculation. 2003-11-25 09:33 we7u * src/main.c: Forgot to add in the minus signs again. Area should be closer to being correct now for polygons. 2003-11-25 09:25 we7u * src/main.c: Computing area of a polygon. Correctly now I think. 2003-11-25 07:29 we7u * src/main.c: More CAD Drawing stuff. We now only compute area on polygons with 3 or more points, and don't "close" a polygon unless it has 3 or more points. 2003-11-25 07:14 we7u * src/main.c: More CAD Drawing stuff. 2003-11-25 07:05 n2ygk * src/map_shp.c: update comments 2003-11-25 00:46 we7u * src/main.c: Beginnings of computing area for a drawn polygon. 2003-11-24 23:42 we7u * src/: db.c, db.h, main.c, main.h, util.c, util.h: First semi-functional implementation of CAD drawing functions. No persistent storage has been implemented yet. 2003-11-24 16:45 we7u * src/maps.h: Exporting another function I'll need later in another module. 2003-11-24 14:38 we7u * src/main.c: Renaming one function. 2003-11-24 14:33 we7u * src/main.c: Changing a few comments. 2003-11-24 13:55 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/datum.c, src/db.c, src/list_gui.c, src/main.c, src/main.h, src/maps.c, src/xa_config.c: Adding the capability to use the special UTM zones with a new UTM selection, instead of using them only for MGRS. Seems some areas use them for regular UTM as well. 2003-11-24 13:32 we7u * src/main.c: Added more comments and some function prototypes for CAD objects. 2003-11-24 12:49 we7u * src/main.c: Non-blocking xfontsel code. Main app keeps humming along now even when xfontsel is up and running. 2003-11-24 11:20 rzg * help/help-English.dat: Updates for recent changes. 2003-11-24 10:35 we7u * src/main.c: Added some comments to the xfontsel code. 2003-11-24 10:24 n2ygk * src/main.c: simplified implementation of xfontsel using popen. 2003-11-23 23:07 we7u * src/main.c: Added another comment regarding xfontsel and possible conversion to another thread. 2003-11-23 22:50 we7u * src/main.c: We now write the output of xfontsel back into the Map Label Font dialog via the use of an intermediate file we write to ~/.xastir/tmp. 2003-11-23 21:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added xfontsel option to map label font dialog. 2003-11-22 20:38 we7u * src/main.c: More temporary CAD drawing changes. These allow experimentation without the drawings disappearing. Drawings do not survive pan or zoom though. 2003-11-22 15:40 we7u * src/main.c: Added crosshair cursor for Measure/Move modes, and pencil cursor for CAD Draw mode. 2003-11-21 13:55 we7u * src/db.c: Fixing a pointer problem that Jack Twilley found. This one occurs when we're deleting expired stations from our database in time order. We weren't saving a pointer to the next time-ordered record before free'ing the memory for the first. 2003-11-16 22:14 we7u * src/main.c: Adding some comments. No code changes. 2003-11-16 15:33 we7u * README.MAPS: Added a note from Tom Russo regarding limitations of shpproj. 2003-11-13 10:37 we7u * src/main.c: Added an erase option for the CAD objects. Non-functional so far. 2003-11-13 10:11 we7u * src/main.c: Moving more menu stuff around. Making it harder to move my station using the mouse. Put Pan stuff in a submenu to make the main mouse menu shorter. 2003-11-13 09:52 we7u * src/main.c: More Draw CAD-mode stuff. 2003-11-13 09:29 we7u * src/main.c: More draw CAD objects stuff. Not ready for prime-time yet. 2003-11-13 08:16 we7u * src/main.c: Moving the "Move my station here" menu option to the very bottom, more out of the way. 2003-11-13 07:27 n2ygk * config/nwsc_ddmmyy.dbfawk, config/nwsmzddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrlpt.dbfawk, config/tgrlpy.dbfawk, config/tgrplc00.dbfawk, config/tgrwat.dbfawk, src/map_shp.c, src/maps.c, src/maps.h: Centered area polygon labels. Use light blue for area label color. 2003-11-12 13:23 we7u * INSTALL: Changing some instructions to use "su -c" instead of "su" and "exit". 2003-11-11 21:37 we7u * src/main.c: Very preliminary etch-a-sketch mode. Allows the operator to draw lines on top of the map display. Eventually this will be turned into something useful. Right now the lines disappear at the next screen refresh. 2003-11-11 07:03 n2ygk * config/: nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk, tgrlpt.dbfawk, tgrlpy.dbfawk, tgrplc00.dbfawk, tgrwat.dbfawk: "pattern" set to match X line attribute. Also some other minor tweaking. 2003-11-11 07:02 n2ygk * src/map_shp.c: add default dbfawk when signature not found. change "pattern" to just be the X line attribute pattern (0, 1, or 2). 2003-11-10 09:18 we7u * src/main.c: Changing the default symbol to a dot. Used to be the emergency symbol, which is probably not a good idea as a default. 2003-11-10 08:39 we7u * src/main.c: Saving/restoring comment and name fields when switching between different types of Create Object/Item dialogs. 2003-11-10 07:20 n2ygk * src/map_shp.c: Use 'fill_color' to fill polygons; 'color' for polygon border. 2003-11-10 06:57 n2ygk * config/: tgrlk.dbfawk, tgrlpt.dbfawk, tgrwat.dbfawk: fill_color 2003-11-10 06:56 n2ygk * config/: Makefile.am, tgrlpy.dbfawk, tgrplc00.dbfawk: More dbfawk's 2003-11-10 06:55 n2ygk * README.MAPS: use consistent style for variable names 2003-11-08 17:42 jtwilley * configure.ac, src/dbfawk.c, src/testawk.c: Tom Russo's patch to help dbfawk build under FreeBSD. 2003-11-07 22:57 we7u * src/main.c: Added some comments. 2003-11-07 22:49 we7u * src/main.c: Fixes for Map Chooser Properties buttons. The string offset was incorrect after the strings were shortened. Fixed now. 2003-11-07 13:46 we7u * src/maps.c: Fixing a problem whereby the weather alert filenames are guessed wrong if there are similarly-names zip files in the Counties directory. 2003-11-07 10:15 we7u * src/main.c: Fixing objects/items with respect to probability circles and multipoint polygons. We can now do compressed objects/items with these features, and we get a space before the multipoint string, as the spec requires. 2003-11-06 15:27 we7u * src/db.c: Changing the extract_multipoints() function so that it doesn't remove the multipoint string from the comment field of objects or items. This allows us to transmit the multipoint string every time we transmit the object/item. 2003-11-06 15:26 we7u * src/draw_symbols.c: Changed one comment. 2003-11-06 09:21 we7u * src/interface.c: OpenTrac bug-fix by Henk. Thanks! 2003-11-06 09:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Fixing Map Properties columns for other languages. 2003-11-06 09:02 we7u * config/language-English.sys, src/main.c: Making Map Properites even narrower. 2003-11-06 08:21 we7u * src/main.c: Reorganizing the buttons on Map Chooser->Properties so that the dialog will be narrower. 2003-11-06 07:56 we7u * src/main.c: Moving some of the Map menu into a submenu. Lesser-used stuff now resides in a Configure submenu off the Map menu. 2003-11-06 07:44 we7u * config/language-English.sys: Changing a few labels in the menus. Minor stuff. 2003-11-05 22:54 jtwilley * config/tnc-startup.aea: Moved 'EXP on' to the top of the file and commented out lines which produce errors on my AEA PK-232. 2003-11-05 10:35 we7u * src/maps.c: Fixing the high CPU-usage bug with XDrawLines() in draw_grid with UTM grids. 2003-11-05 10:10 we7u * src/maps.c: Added an interation max to the while loop in draw_grid(). Just in case. 2003-11-05 07:06 n2ygk * src/map_shp.c: Fix WX alerts 2003-11-04 15:24 we7u * src/map_shp.c: Patch submitted by Tom Russo, KM5VY. Allows dbfawk to control more than just color. 2003-11-04 15:00 we7u * src/main.c: Added a rather stupid fix for the problem: 'Error: attempt to add non-widget child "DropSiteManager" to parent "xastir"'. Making a couple of harmless Motif calls before calling XtVaCreateWidget in create_appshell(). 2003-11-04 14:24 we7u * src/map_geo.c: Wrapping a call with ifdef's for people that don't have ImageMagick compiled in. 2003-11-04 14:20 we7u * tigermap.geo: Adding this file so that Tigermap may be a normal option in the Map Chooser. 2003-11-04 13:46 we7u * src/main.c: Moving things around to different menus. Cleaning up the interface just a bit. 2003-11-04 11:28 we7u * src/xa_config.c: Remembering Tigermap config settings between sessions. 2003-11-04 09:17 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/map_tiger.c, src/xa_config.c, src/xastir.h: Making the regular Map Intensity controls work for the TigerMap intensity as well. Simplifying the user interface a bit. 2003-11-04 08:46 we7u * Makefile.am, src/main.c, src/main.h, src/map_geo.c, src/map_tiger.c, src/xa_config.c: Moving Tigermap enable to the Map Chooser (so that all maps are selected/deselected from one dialog). Removed the Enable button from the Tigermap config dialog. 2003-11-03 13:22 we7u * src/location_gui.c: Removing unnecessary db.h include. 2003-11-03 13:22 we7u * src/: bulletin_gui.c, datum.c, db.c, db.h, gps.c, interface.c, interface_gui.c, list_gui.c, locate_gui.c, main.c, messages.c, messages_gui.c, track_gui.c, util.c, util.h, view_message_gui.c, wx.c, xa_config.c: Fixed the problem with coordinate calc and inputting UPS coordinates. Moved some routines from db.c to util.c that were general-purpose string routines. Got rid of unnecessary db.h includes. 2003-11-03 12:59 we7u * src/main.c: Added a debug line. 2003-11-03 11:04 we7u * src/util.c: Fixing the "nice" formatting for UTM so that extra spaces aren't added on the status line for MGRS coordinates. 2003-11-03 10:59 we7u * src/: datum.c, db.c, list_gui.c, main.c, util.c, util.h: Cleaning up the MGRS_string stuff. Formatting the string nicely for the Coordinate Calculator. 2003-11-03 09:19 we7u * src/datum.c: Fixed utm_ups_to_ll() function for the south polar region. 2003-11-03 09:13 we7u * src/util.c: Switching back to original math. 2003-11-03 08:33 we7u * src/datum.c: Added a comment about the problems with utm_ups_to_ll() function in the south polar region. 2003-11-03 08:14 we7u * src/main.c: Adding MGRS to Coordinate Calculator as an output format. Still has problems in the south polar region, but other than that it appears to work properly. 2003-11-03 08:10 we7u * src/util.c: Switching to MGRS zones when doing MGRS conversions, and restoring the "coordinate_system" variable when done. Changed some math to make it more understandable what was going on. 2003-11-03 08:08 we7u * src/datum.c: Changed a comment. 2003-11-01 10:57 we7u * src/util.c: Correct 2-letter digraphs now for the UPS regions while using MGRS coordinates. 2003-10-31 21:15 we7u * src/util.c: Changing the formatting for MGRS. 2003-10-31 16:35 we7u * src/util.c: MGRS appears to be functional in the UTM area. Still needs work in the UPS (polar) areas. 2003-10-31 15:35 we7u * src/: datum.c, datum.h, db.c, list_gui.c, main.c, main.h, maps.c, util.c, util.h, xa_config.c: Initial code for implementing MGRS coordinates. Not quite ready for prime-time yet. 2003-10-31 15:34 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding a label for selecting MGRS coordinates. 2003-10-30 14:32 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding Max/Min Zoom headings to Map Chooser->Properties dialog for other language files. 2003-10-30 10:50 we7u * src/xa_config.c: More error-checking for lat/long as read in from the config file. In case someone hand-edits the station location and gets the format wrong. 2003-10-29 19:38 we7u * src/maps.c: Fixing the edges of the earth, UTM grid style. 2003-10-29 13:03 we7u * src/: datum.c, datum.h, maps.c: Fixing the UTM grid. Added "MGRS_grid" variable. If set, we draw the irregular grids and report UTM coordinates using those grids. If zero, we draw the regularly-spaced six-degree zones and report using those regular zones. 2003-10-29 12:50 we7u * src/maps.c: Correcting UTM grid for the civilian UTM grid (non-MGRS grid). 2003-10-29 12:27 we7u * src/main.c: Saving our place in the Map Properties dialog. No more scrolling trying to get back to where you were. 2003-10-29 11:59 we7u * src/main.c: Commenting out debug code. 2003-10-29 11:51 we7u * src/main.c: Commenting out a debug line. 2003-10-29 11:23 we7u * src/maps.c: Adding code to migrate from old map_index.sys format to the new format. Accepts either 8 or 10 parameters per line and writes out the new 10-parameter format if the 8-parameter format is found. Swapped the max_zoom and min_zoom parameters to further down the data line. 2003-10-28 22:26 jtwilley * config/language-English.sys, src/main.c, src/maps.c, src/maps.h: Added support for max/min zoom levels. Work still needs to be done on removing existing zoom-level-sensitive code and supporting other languages. 2003-10-28 16:35 we7u * src/main.c: Moved the "XtRealize" call down lower in the routine, after the size has been specified. This is to help get rid of the "Error: Shell widget xastir has zero width and/or height" problem that some users have been having. 2003-10-28 16:29 we7u * src/main.c: Moving the "manage" call for the main app down lower after the size of the widget has been specified. Attempting to get rid of the "Error: Shell widget xastir has zero width and/or height" problem that some users are still having. 2003-10-28 15:46 we7u * src/xa_config.c: Setting screen_height and screen_width to minimums of 40 and 100. 2003-10-28 15:20 we7u * src/main.c: Getting rid of the auto-clear function for the map chooser topo and vector buttons. They are now additive instead of exclusive. 2003-10-28 07:02 n2ygk * src/list_gui.c: Fix X crash when list width/height somehow get set to zero. 2003-10-27 17:40 rzg * INSTALL, README.MAPS: Minor updates. I'm still around. :-) 2003-10-23 12:48 uid74947 * src/maps.c: Another comment. 2003-10-22 17:30 we7u * src/maps.c: Comment changes. 2003-10-22 17:22 we7u * src/maps.c: More comments. 2003-10-22 17:19 we7u * src/maps.c: Changing the scale at which the UTM subgrid starts to be drawn. We weren't drawing it properly at scales of 2048 and up anyway. 2003-10-22 17:15 we7u * src/maps.c: More comment changes. 2003-10-22 16:44 we7u * src/maps.c: Adding comments. More checking for invalid numbers in draw_grid(). 2003-10-22 16:19 we7u * src/maps.c: Commenting out some debug lines. 2003-10-22 16:06 we7u * src/maps.c: Fixing another bug in draw_grid() that caused a segfault while drawing UTM grids. Added more debug and comments. The segfault fix causes some grid lines to get skipped but that's better than a segfault. 2003-10-22 14:39 we7u * src/maps.c: More comment changes. 2003-10-22 14:08 we7u * src/maps.c: Correcting some comments. 2003-10-22 13:53 we7u * src/maps.c: Correcting some comments based on input from Peter Dana. 2003-10-22 13:50 we7u * src/maps.c: Added another comment. 2003-10-22 12:50 we7u * src/maps.c: Adding lots of comments in the draw_grid() function. Trying to understand Olivier's code for drawing UTM grids, so it can be improved in the areas of major grid intersections, and in handling the irregular zone widths. 2003-10-22 11:43 we7u * src/maps.c: Changed some comments. 2003-10-22 09:33 we7u * src/maps.c: Last log message should have said: Changed/updated some comments. No code changes. Same for this log message. 2003-10-22 09:32 we7u * src/maps.c: [no log message] 2003-10-22 06:57 n2ygk * README.MAPS, config/tgrlpt.dbfawk, src/map_shp.c: dbfawk symbol support for point shapefiles 2003-10-21 08:22 n2ygk * src/map_shp.c: duh - sym[4] to fit the null at the end! 2003-10-21 08:21 n2ygk * src/map_shp.c: sym[3] to allow for overlay char too 2003-10-21 08:20 n2ygk * README.MAPS: document "roll your own shapefile maps" 2003-10-19 15:31 we7u * src/main.c: Added a comment. No code changes. 2003-10-19 15:28 we7u * src/maps.c: Changing the UTM/UPS grid so that only two zones each are drawn at the poles (in the UPS region). 2003-10-19 15:26 we7u * src/datum.c: Fixing the output zone number in the UPS regions to "00". 2003-10-17 23:13 we7u * src/maps.c: Tweaking the UTM grid so that it extends to the poles, now that I know what the UPS grid (near the poles) should look like. 2003-10-17 22:55 we7u * src/: datum.c, datum.h, main.c, map_geo.c, maps.c, util.c: Implemented proper UTM/UPS to Lat/Long conversions. Also fixed the coordinate calculator so it would accept UPS coordinates. 2003-10-17 21:49 we7u * src/: datum.c, datum.h, main.c, map_geo.c, maps.c, util.c: Implemented proper UPS output, when using UTM/UPS and near the poles. 2003-10-17 20:22 we7u * src/datum.c: Temporarily making the easting and northing for the UPS areas (near the poles) equal to all zeroes. This is to prevent someone thinking that the numbers we're showing are valid coordinates. We haven't been computing proper coordinates in the UPS areas. Am still working on the problem and hope to have valid UPS numbers by the end of the weekend. 2003-10-17 14:21 we7u * src/datum.c: Changed some comments. Added some output if we're trying to convert a UPS coordinate to Lat/Long. 2003-10-17 13:39 we7u * src/: datum.c, datum.h: Changed utm_letter_designator() to properly handle the zones for UPS grid. Still need to get the easting/northing numbers to work right, but the zone letters are now correct. 2003-10-17 12:50 we7u * src/datum.c: Modified utm_letter_designator() function so that 'Z' is displayed above 84N, and 'A' is displayed below 80S. It's better than it was, but we still need to implement full UPS coordinate systems in the pole regions. 2003-10-17 12:38 we7u * src/main.c: Tweaking TrackMouse() so that the coordinates stop changing when the mouse goes off the edge of the earth. 2003-10-17 08:21 n2ygk * src/map_shp.c: still incomplete attempt at handling fill styles. 2003-10-17 08:19 n2ygk * config/: Makefile.am, tgrlpt.dbfawk: add tgrlpt (Tiger/Line landmark points) 2003-10-17 08:18 n2ygk * config/tgrlk.dbfawk: add complete documentation of CFCC codes 2003-10-17 02:13 we7u * bootstrap.sh: Added a line to remove the autom4te.cache directory and contents. This sometimes gets in the way when running autoheader, and I have to delete it manually in that case. No more. 2003-10-16 16:38 we7u * src/map_geo.c: Excluding map indexing from being able to set the map refresh interval. 2003-10-16 16:09 we7u * src/: map_gdal.c, maps.c: Minor comment changes. 2003-10-16 15:59 we7u * src/: map_gdal.c, maps.c: Dumping out map types on startup. 2003-10-16 14:48 we7u * src/map_gdal.c: Changed comments. No code changes. 2003-10-16 14:44 we7u * configure.ac: Moving the GDAL stuff after shapelib and libgeotiff. We want GDAL to get linked AFTER the other libraries, at least until we get GDAL fully integrated. If GDAL is linked earlier than these other libraries, function calls get made to GDAL instead of the correct libraries. 2003-10-16 14:42 we7u * src/map_tif.c: Added more debugging output. 2003-10-16 14:39 we7u * src/maps.c: Added more debug info. 2003-10-16 14:11 we7u * src/map_gdal.c: Minor stuff, getting ready to try to open a file. 2003-10-16 12:40 we7u * src/map_gdal.c: Printing out OGR drivers as well now. 2003-10-16 12:33 we7u * src/map_gdal.c: Nicer formatting for the GDAL drivers. 2003-10-16 12:30 we7u * src/map_gdal.c: Better formatting for listing GDAL drivers. Starting to add code to list OGR drivers as well. 2003-10-16 11:58 we7u * src/map_gdal.c: Print out a list of all registered GDAL drivers upon Xastir startup. 2003-10-16 09:56 we7u * src/map_gdal.c: Moved the #warning text inside the #ifdef block. Will only see the warning if GDAL is installed and usable on your system. 2003-10-16 09:48 we7u * src/map_gdal.c: Minor changes to comments. Removed a #define that shouldn't have been committed. 2003-10-16 09:42 we7u * src/map_gdal.c: Added example code snippets from the GDAL tutorial. 2003-10-16 09:07 we7u * configure.ac, src/main.c, src/map_gdal.c, src/maps.h: More initial framework for GDAL integration. Now adds it to the list of supported libraries in "configure", and adds the library to the link line. 2003-10-16 08:30 we7u * src/Makefile.am: Adding map_gdal.c to the list of files. 2003-10-16 08:29 we7u * src/map_gdal.c: Adding initial file framework for integrating the GDAL library. No real code here yet. 2003-10-14 13:49 we7u * src/map_geo.c: Another #ifdef fix regarding raster_map_intensity. 2003-10-14 13:44 we7u * src/main.c: More #ifdef cleanup regarding raster_map_intensity. 2003-10-14 13:37 we7u * src/: main.c, maps.h, xa_config.c: Fixing #ifdef's, consistent with new uses of raster_map_intensity variable (used to be geotiff_map_intensity). 2003-10-13 14:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Implementing Henk de Groot's icon outline code. Added code to make the changes instantly visible in the drawing area. Thanks Henk! 2003-10-13 14:30 we7u * src/: main.c, map_geo.c, map_tif.c, maps.c, maps.h, xa_config.c: Attached geo files to the raster intensity variable, so they can be darkened from the menus now. Had to hard-code toposerver images to be 100% brightness though, as the colors get strange on that particular image. Other images can be fixed by adding the "modulate" tag to the .geo file, if this problem should surface elsewhere. 2003-10-13 13:22 we7u * src/maps.c: More efficient snapshot code: Moved the .geo code back into the separate thread now that the symbol-blanking bug is fixed. 2003-10-13 12:57 we7u * src/maps.c: Fixed snapshots so that .geo file creation works without blanking symbols on the screen. The code was leaving incorrect values in global variables that were later used by the symbol drawing code. 2003-10-13 10:57 we7u * src/: main.c, maps.c, xastir.h: Fixing the symbols-going-away-after-snapshot problem. Unfortunately it appears that the .geo code for snapshots is the problem. Will have to figure out why yet and then reinstate that part of the code. 2003-10-12 21:22 we7u * src/: main.c, maps.c, xastir.h: Attempting to fix the snapshot problem where stations disappear off the display. Created another Pixmap: pixmap_snapshot, and copy pixmap_final to it just before the snapshot thread is started. This should separate any accesses to the data so that no conflicts occur while making the snapshot. 2003-10-09 19:20 we7u * src/maps.c: Tweaking the width of the equator line in UTM grid (again). 2003-10-09 19:14 we7u * src/maps.c: Minor changes to equator/prime meridian again for UTM. 2003-10-09 18:41 we7u * src/maps.c: Changing line widths for the lat/long grid and the major UTM zones to width 2. This makes them more noticeable against the smaller UTM subgrid and against map lines. 2003-10-09 13:16 we7u * src/maps.c: Changing the color for lat/long grids as well so that they work with the gc_tint stuff and show up on maps well. 2003-10-09 13:09 we7u * src/maps.c: Changing to gc_tint for map grids so that the grid can always be seen on top of maps. 2003-10-09 12:52 we7u * src/maps.c: Switching to purple lines as they show up well on topo and terraserver maps. 2003-10-09 12:47 we7u * src/maps.c: Changing the smaller UTM grids to display in bright yellow. Easier to see on maps. 2003-10-09 09:18 we7u * src/maps.c: Initial attempt at finer UTM grids, using preliminary code by Olivier Calle (N7TAP). The code handles the irregular regions near/above Norway for the major UTM grid zones only (not for the minor grids yet). There are known problems near the zone boundaries with lines not getting drawn or incorrect lines getting drawn. For the most part, if you're inside a zone and not in the irregular zone area, this code works very well, and is very fast! 2003-10-09 09:03 we7u * src/: db.c, main.c, map_geo.c: Changing a few printf's to fprintf's. 2003-10-08 12:48 we7u * src/maps.c: Simplified code for drawing UTM grid. 2003-10-08 12:12 we7u * src/maps.c: Changing the UTM grid to dashed lines instead of solid. 2003-10-08 11:31 we7u * src/maps.c: Proper UTM grid, including irregular areas near Norway. Area from 84N to 90N and 80S to 90S is still in question, as that is in the UPS coordinate system area (the poles). Also, the UTM coordinates on the status line are incorrect when the mouse pointer is moved into these areas. 2003-10-08 10:16 we7u * src/maps.c: More draw_vector stuff. Both Xastir coordinate system and lat/long vector drawing functions work now. Still need to work on the "is it in the view" code, as it's not working correctly.. 2003-10-08 09:42 we7u * src/maps.c: Added more UTM grid comments. 2003-10-08 09:37 we7u * src/maps.c: Adding a new draw_vector() function, which I'll use for drawing the UTM grid shortly. Changed/added a bunch of comments in draw_grid() regarding UTM. 2003-10-07 12:59 we7u * src/maps.c: Changed some comments. 2003-10-07 11:51 we7u * src/maps.c: Tweaked the boundary checks before the XDrawLine call. Added/changed some comments regarding UTM grid. 2003-10-06 19:41 we7u * src/maps.c: Initial UTM grid attempt. This mod causes the six degree vertical lines to be drawn that define the major UTM zones. It will draw them if the map grid is enabled and UTM is the selected coordinate system. 2003-10-02 16:51 we7u * src/db.c: Fixing the Pmin/Pmax stuff so that it gets transmitted properly across the air. 2003-10-02 13:21 we7u * src/maps.c: Xastir now creates a snapshot.geo file corresponding to the snapshot.png file. 2003-10-02 10:08 we7u * README.win32: Added a note about removing the "-local" option for nasd. 2003-10-02 07:09 n2ygk * src/main.c: Duh. Hung Map_font off of Gamma_correct button. 2003-09-30 06:57 n2ygk * INSTALL, README.MAPS: document dbfawk 2003-09-28 15:39 n2ygk * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Add map label font selection (please translate these!) 2003-09-28 00:03 we7u * src/xastir.h: Minor tweak to fix a compile problem in main.c with sizeof(). 2003-09-27 07:18 n2ygk * config/language-English.sys, src/awk.c, src/awk.h, src/dbfawk.c, src/main.c, src/map_shp.c, src/maps.c, src/xa_config.c, src/xastir.h: Add user-selectable MAPS_LABEL_FONT. Add dbfawk-selectable label color. Add "skip" keyword to dbfawk to permit overriding bad shapefile dbf data. 2003-09-26 16:34 we7u * README.win32: Clarified that maps can go in the maps directory and subdirectories thereof. 2003-09-26 16:26 we7u * README.win32: Added a note about possible problems with IM-5.5.7. 2003-09-26 16:22 we7u * README.MAPS: Specified where the sound files go. 2003-09-26 10:06 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added an "Apply" button to the Map Chooser that applies the changes immediately without destroying the Map Chooser. 2003-09-26 09:16 we7u * README.win32: Added note about Perl 5.8 and page faults while compiling. 2003-09-19 16:48 we7u * README.win32: Added a note about ImageMagick being necessary to view .geo maps. 2003-09-19 16:41 we7u * README.win32: Added a Win2k note. 2003-09-19 16:34 we7u * README.win32: Minor edits. 2003-09-19 16:06 we7u * README.win32: Added to more XFree86 packages to the selections. 2003-09-19 15:40 we7u * README.win32: Better fix for the _reent bug. 2003-09-19 15:37 we7u * README.win32: Added another note about the _reent bug. 2003-09-19 10:58 we7u * README.MAPS: Minor changes to the download NOAA weather alert maps section. 2003-09-19 10:57 we7u * src/util.c: Caused the code to recognize "NWS_" as valid. Didn't appear to be doing so, which might have been knocking out a lot of compressed weather alerts. 2003-09-19 10:57 we7u * src/db.c: Changed some comments. 2003-09-19 10:56 we7u * src/alert.c: Minor changes to comments and added another possible case for SOLAR that can get parsed (don't know if it'll ever get used). 2003-09-18 12:38 we7u * src/main.c: Setting the initial symbol to be a hiker when creating new object/item with probability circle toggle enabled. 2003-09-18 12:04 we7u * src/: main.c, db.c: Working implementation of SAR probability circles. 2003-09-17 17:24 we7u * src/: db.c, db.h, draw_symbols.c, draw_symbols.h, main.c: Half of an implementation for drawing Search & Rescue probability circles. Have the encoding parts and display parts done. Next need to do the decoding so that the circles show up on the map. 2003-09-16 10:46 we7u * src/xastir.h: Adding preliminary support for the libgc garbage collection library. Disabled by default. This gives automatic garbage collection of unused memory space to Xastir. During long runtimes, this seems to improve memory usage a bit. 2003-09-16 10:13 we7u * src/map_geo.c: Fixing trans_skip for the non-ImageMagick case. 2003-09-15 11:49 we7u * README.win32: Very minor wording change in the CVS instructions. 2003-09-12 07:48 n2ygk * configure.ac, src/dbfawk.c, src/map_shp.c: properly conditionalize WITH_DBFAWK. More dbfawk tweaks in map_shp 2003-09-11 15:04 jtwilley * src/dbfawk.c: Added check for DBFAWK define. 2003-09-11 13:19 n2ygk * config/nwsc_ddmmyy.dbfawk, src/map_shp.c: Fix a stupid error in symtbl 2003-09-10 13:53 rzg * help/help-English.dat: whatsnew update 2003-09-10 13:27 kd6zwr * README.MAPS, help/help-English.dat, src/map_geo.c, src/maps.h: Changing TRANSPARENT geo tag to accept a user defined color to zap. 2003-09-09 06:56 n2ygk * config/nwsc_ddmmyy.dbfawk, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrwat.dbfawk, src/map_shp.c: more dbfawk tweaking 2003-09-08 07:37 n2ygk * config/nwsc_ddmmyy.dbfawk, config/nwsozddmmyy.dbfawk, config/nwsw_ddmmyy.dbfawk, config/nwsz_ddmmyy.dbfawk, src/map_shp.c: more dbfawk tweaks. WX alerts now search properly. 2003-09-05 14:25 we7u * src/main.c: Removed some unneeded comments. 2003-09-05 14:12 we7u * src/main.c: Taking out the Move/Measure menu prevention logic for the case where the mouse buttons are _not_ swapped. 2003-09-05 13:20 we7u * src/main.c: Preventing the mouse menu from coming up if SWAP buttons is enabled and we're doing the Move or Measure functions. 2003-09-05 12:47 we7u * src/main.c: Added another define that allows moving the mouse menu to button1. 2003-09-05 12:07 we7u * src/main.c: Swapping zoom/pan buttons so that zoom buttons are more often on the screen with a small window size. 2003-09-05 06:56 n2ygk * config/: Makefile.am, nwsc_ddmmyy.dbfawk, nwsmzddmmyy.dbfawk, nwsozddmmyy.dbfawk, nwsw_ddmmyy.dbfawk, nwsz_ddmmyy.dbfawk: First pass at handling WX alerts with dbfawk 2003-09-04 23:37 we7u * src/main.c: Added some notes about xmodmap for swapping mouse buttons in a touchscreen configuraton. 2003-09-04 15:48 we7u * config/language-English.sys: Making Z-In/Z-Out labels shorter to help fit on 640x480 LCD screen. 2003-09-04 15:28 we7u * src/main.c: Changing the optional SMALL system font. 2003-09-04 14:39 n2ygk * src/testawk.c: Make it compile even without DBFAWK 2003-09-04 14:22 we7u * INSTALL: Added a bit more about libgeotiff's private include directory. 2003-09-04 11:00 we7u * src/main.c: Another tweak for fixed-size small displays. This new define forces dialogs to pop up over the main application, near the left top corner. 2003-09-04 10:11 we7u * src/main.c: Adding an option for a much smaller default system font. Useful for smaller displays. 2003-09-04 10:10 we7u * config/language-English.sys: Making Zoom buttons smaller by shortening the string. Needed for smaller displays. 2003-09-04 09:40 we7u * src/: main.c, xa_config.c: Allowing much smaller screen sizes for Xastir. It should start up in roughly the same size as saved now also. 2003-09-04 09:18 we7u * src/main.c: Changing the minimum size for the main window down to 1/4 VGA. This allows it to be resized much smaller than before. Useful for fixed-size LCD displays. 2003-09-04 09:11 we7u * FAQ: Added a few more words about why stations might not appear on the screen. 2003-09-04 07:38 n2ygk * src/map_shp.c: more dbfawk tweaking 2003-09-03 17:01 we7u * INSTALL: Revised the libgeotiff instructions slightly. 2003-09-03 12:37 we7u * README.win32: Added "touch .cvspass" to the instructions. Some Windows boxes fail without this. 2003-09-03 11:26 kd6zwr * README.MAPS, help/help-English.dat: Documenting the new TRANSPARENT and CROP .geo file tags. 2003-09-03 08:19 n2ygk * configure.ac, src/Makefile.am, src/awk.c, src/dbfawk.c, src/dbfawk.h, src/map_shp.c, src/testawk.c: change to use WITH_DBFAWK. dbfawk now searches for mapfilename.dbfawk before looking in config/*.dbfawk, enabling map-specific special cases. 2003-09-03 00:28 kd6zwr * src/: map_geo.c, maps.h: Adding TRANSPARENT and CROP tags to the geo file. First cut at transparent, needs to be augmented to allow a list of colors to zap. 2003-09-02 16:43 jtwilley * configure.ac: Moved AM_INIT_AUTOMAKE and added arguments. Added documentation for AM_INIT_AUTOMAKE. 2003-09-02 14:05 n2ygk * config/tgrcty.dbfawk, src/map_shp.c: tgrcty: fix Louisiana FIPS code map_shp: start adding layer setting via dbfawk too 2003-09-02 10:50 we7u * README.win32: Added another comment about "nano" being more user-friendly than "vi", for people coming from a Windows background. 2003-08-30 13:41 jtwilley * src/awk.c: Added reference to to match dbfawk.c 2003-08-29 09:50 n2ygk * configure.ac, config/Makefile.am, config/tgrcty.dbfawk, config/tgrkgl.dbfawk, config/tgrlk.dbfawk, config/tgrwat.dbfawk, src/Makefile.am, src/awk.c, src/awk.h, src/dbfawk.c, src/dbfawk.h, src/gps.c, src/map_shp.c, src/testawk.c, src/tgrcty.dbfawk, src/tgrkgl.dbfawk, src/tgrlk.dbfawk: gps.c: handle spurious compile time warning everything else: add dbfawk support for shapefile maps. Enable with: ./configure --with-dbfawk 2003-08-22 21:37 we7u * src/interface_gui.c: Adding another #include, needed for usleep() call. 2003-08-21 15:01 we7u * src/db.c: Changed some comment formatting. 2003-08-21 14:10 we7u * src/interface_gui.c: Adding a delay after shutting down a port before it is brought up again. These delays are in the interfaces->properties menu when changing an interface that's running. 2003-08-21 12:31 we7u * src/: db.c, db.h: Added a new flag to WeatherRow called wx_storm. We wet it when we find any kind of a severe storm, then use that flag in our logic that decides how to draw things. This gets rid of wind barbs for some severe storms. 2003-08-21 11:01 we7u * scripts/inf2geo.pl: New revisions by ZL2UMF. Thanks! 2003-08-21 09:42 we7u * src/igate.c: We now drop generic queries heading to RF. Also tweaked the log reject messages to be more consistent. 2003-08-21 09:30 we7u * src/igate.c: Removed the '*' requirement for TCPXX*, so we now reject anything with TCPXX in it. Added NOGATE options for dropping packets to all igate functions. Added generic query rejection for gating to 'net. Still need to add it into the gate-to-rf code. 2003-08-20 12:55 we7u * symbols/symbols.dat: Changing the "smoke" symbol so that it shows a volcano instead of a smokestack. This is more inline with the reason the weather server puts out these symbols, and is more recognizable than the smokestack symbol anyway. 2003-08-20 11:05 we7u * src/main.c: Changing the network port check from 7.5 minutes down to one minute. This should reconnect ports more quickly if/when they go down. 2003-08-18 16:16 we7u * src/db.c: Removing a back-slash that got in there accidentally. 2003-08-18 15:46 we7u * src/db.c: Getting the sort order correct for inserting records into the station database. Didn't work well with the wrong order. 2003-08-18 11:09 we7u * src/db.c: Commenting out some speedup code in station_shortcuts_update_function() that may be causing problems at present. 2003-08-18 10:40 we7u * src/maps.c: Henk's fix to a pointer problem that I created recently. 2003-08-16 23:04 we7u * src/db.c: Fixing a bug in the hash table code which looks for station matches. Making the clear all stations function faster by clearing out the hash table first. 2003-08-15 18:40 we7u * src/maps.c: Making index_retrieve() faster by relying on alphanumerical ordering of the map files in the index list. We now save the pointer between runs, and start searching the list at the point we left off. 2003-08-15 18:12 we7u * src/main.c: Minor comment cleanup and removing dead code. 2003-08-15 18:04 we7u * src/main.c: Better pointers for Map Chooser select updates. 2003-08-15 17:53 we7u * src/main.c: Changing from n*n searches to n searches for updating selected bits when closing Map Chooser. 2003-08-15 17:12 we7u * src/interface.c: Bumping out of port_read less often. This is only to check whether the thread should be taken down anyway. If a packet is waiting for us to read it, we'll wake up out of the select() anyway. 2003-08-15 16:55 we7u * src/main.c: Rearranging some if statements to get a little more speed out of it. 2003-08-15 16:11 we7u * src/: main.c, maps.c, maps.h: Added caching of XmString values corresponding to the map filenames for the Map Chooser. The first time bringing up Map Chooser will be at the same speed as before. Second and succeeding invocations of the Map Chooser should be a bit faster because the XmString's are used from the map index records again instead of being created from scratch each time. 2003-08-15 12:30 we7u * src/interface.c: CPU-usage optimization tweak to port_read(). 2003-08-15 12:11 we7u * src/: interface.c, main.c: CPU-usage tweak for dtr_all_set calls. It was getting called constantly whenever an HSP port was enabled. 2003-08-15 11:51 we7u * src/maps.c: CPU-usage tweak to index_retrieve(). 2003-08-15 11:20 we7u * src/db.c: Yet another CPU-usage tweak. This one is to search_station_name(). It's more efficient now at finding stations in the linked list, using a hash table as a jumping-off point. 2003-08-14 15:02 we7u * src/map_shp.c: Changing the level at which shorelines get drawn. 2003-08-14 14:59 we7u * src/map_shp.c: Setting up more levels at which things won't be drawn. Will make things faster/less cluttered. 2003-08-14 14:46 we7u * src/map_shp.c: Optimizing shapefile vector drawing. We don't convert the coordinates for each point now unless we're going to draw the darn thing. 2003-08-14 13:52 we7u * src/maps.c: More speedups. 2003-08-14 13:27 we7u * src/map_shp.c: Added some comments. 2003-08-14 09:12 we7u * src/: main.c, maps.c, maps.h, xastir.h: First part of speeding up Shapefile drawing by staying with lat/long values as much as possible, rather than doing conversions to Xastir coordinate system at every step. The end goal is to do as little math as possible to put pixels on the screen. These changes give a slight speedup to shapefile drawing, noticeable only when loading lots of maps. 2003-08-13 16:26 we7u * src/map_shp.c: Reverting back to last version. Floats made CPU-usage worse in this case. 2003-08-13 15:49 we7u * src/map_shp.c: Speedups. Using floating point operations instead of unsigned longs. 2003-08-13 12:45 gstueve * .cvsignore, callpass/.cvsignore, config/.cvsignore, help/.cvsignore, m4/.cvsignore, scripts/.cvsignore, src/.cvsignore, symbols/.cvsignore: Ignore generated files within CVS base. 2003-08-13 12:38 we7u * src/draw_symbols.c: Made the symbol() routine more efficient. Uses much less CPU now. 2003-08-12 11:48 we7u * src/interface.c: More performance improvements. 2003-08-12 11:45 we7u * src/popup_gui.c: Another performance improvement. Only check for expired popups every two minutes. 2003-08-12 10:29 we7u * src/bulletin_gui.c: Another performance improvement. The timing was set up such that find_zero_position_bulletins() ran every time UpdateTime() was started. We now wait 15 seconds between each invocation. 2003-08-11 16:57 we7u * src/: db.c, messages.c: More optimizations for speed/CPU-usage. Hash table entry creation is now more efficient. Check_and_transmit_messages now gets skipped if we ran it already that second. 2003-08-11 16:15 we7u * src/main.c: Added a comment. 2003-08-11 16:05 we7u * INSTALL: Added RH9 ImageMagick instructions, courtesy of Wes Johnston. 2003-08-11 15:40 we7u * src/: db.c, main.c: Moved station # display code from db.c to main.c:UpdateTime() so that the number of stations will accurately reflect our count even when no packets are coming in. 2003-08-11 15:08 we7u * src/interface.c: Another performance/CPU-usage tweak. 2003-08-11 14:48 we7u * src/main.c: Another performance tweak. This one lets you handle multiple high-speed 'net connections and keeps up with the receive queues. 2003-08-11 14:07 we7u * src/interface.c: Performance enhancements. Helps Xastir to keep up with very fast network interfaces. 2003-08-11 13:24 we7u * src/main.c: Making UpdateTime() run more often, which helps us keep up with fast internet feeds. 2003-08-11 12:57 we7u * src/db.c: Changing how often we check for stations and messages to expire from our database. This should also reduce CPU usage. 2003-08-11 11:31 we7u * src/bulletin_gui.c: Another CPU-usage tweak. Running through all of the messages looking for new bulletins every 15 seconds instead of every 2. Keeps mscan_file() calls down a bit, which is using a lot of CPU if run often. 2003-08-11 07:04 n2ygk * src/: awk.c, awk.h, dbfawk.c, dbfawk.h, testawk.c: Save a newer snapshot of in-progress code. Still not baked. 2003-08-08 18:03 we7u * src/db.c: Implementing a 14-bit hash table for station record lookup. This appears to have a BIG effect on CPU usage. May be a bit before the codebase is stable again though, but the gains are definitely worth it. It gives us a feeling for what an SQL database will do for us. 2003-08-08 16:16 we7u * src/db.c: Implemented an array of pointers for the station linked list. Each entry represents one possible starting letter/number for the callsign. We use this to speed up the search for a particular record, which is our hardest hitter in terms of CPU-usage right now. This appears to reduce Xastir's CPU requirements by quite a bit, particularly when a lot of stations are in the database. 2003-08-07 13:47 we7u * src/draw_symbols.c: Backing out one change which broke the port activity symbols. They're working again now. 2003-08-07 10:01 we7u * src/Makefile.am: Taking out the awk/dbfawk stuff temporarily until it can be compiled on most systems again. 2003-08-06 17:54 we7u * src/maps.c: Another speedup. 2003-08-06 16:19 we7u * src/draw_symbols.c: Speeding up the loading of symbols. 2003-08-06 16:18 we7u * src/lang.c: Breaking out of a loop as soon as we get a non-match. 2003-08-06 10:43 we7u * README.win32: Added a note regarding Windows not allowing access to files at times. 2003-08-05 07:34 n2ygk * src/: Makefile.am, awk.c, dbfawk.c, dbfawk.h, testawk.c: more dbfawk utility functions. I'll be integrating this into map_shp.c RSN! 2003-08-04 16:13 we7u * src/main.c: Another small change which makes a difference in CPU usage. 2003-08-04 15:36 we7u * src/draw_symbols.c: Changing draw colors only when necessary. Found this one while profiling using gprof. May be more to change in this procedure to speed things up a bit.. 2003-08-02 10:00 we7u * src/main.c: Tweaked Coordinate Calculator so that it checks lat/long minutes/seconds values for negative numbers and >= 60.0. If out-of-range numbers are found, the error text is displayed in the dialog and a warning message is written to STDERR with a bit more detail on the problem found. Later this STDERR output should probably go to a popup or the main dialog instead, and language strings should be created for them. 2003-07-31 09:01 we7u * src/view_message_gui.c: Making the Close button larger. 2003-07-31 08:21 we7u * src/view_message_gui.c: Made the View->All Messages dialog resizable in both directions. 2003-07-31 06:00 we7u * src/bulletin_gui.c: Fixed View->Bulletins dialog so that it is resizable in both directions. 2003-07-27 22:20 we7u * src/: db.c, main.c: Improved Display Packet Data dialog. This one is resizable and very fast. Much better than the previous implementation. 2003-07-26 17:11 we7u * symbols/symbols.dat: Added the MODIS Earth Observation symbol. Added a comment specifying where to find the color definitions used for symbols. 2003-07-26 09:35 we7u * src/map_dos.c: Commented out some fprintf's that were getting quite verbose when certain Win/DOS maps were loaded. Warnings were that we were trying to call draw/fill polygon routines with 1 or 2 points. 2003-07-25 13:00 we7u * src/main.c: Cranked up the delay on REDRAW from 2 to 3 seconds. Changed the dead-reckoning code to schedule a map redraw instead of doing on itself (which probably duplicated some drawing). CPU usage seems to be down because of these changes. 2003-07-25 11:18 we7u * src/gps.c: Improved GPS parsing code. Fixed buffer overflow problems and restructured code. 2003-07-25 07:36 we7u * src/: gps.c, interface.c: Added line-terminations after strncpy() calls and a bunch of comments at those places as well. 2003-07-24 14:18 we7u * src/main.c: Adding more comments. 2003-07-24 14:14 we7u * src/: db.c, main.c: Adding uncompressed altitude extension to compressed objects/items. 2003-07-24 09:17 we7u * README.win32: Some very minor changes to the Cygwin instructions. 2003-07-24 06:33 n2ygk * src/: awk.c, testawk.c, tgrcty.dbfawk, tgrkgl.dbfawk, tgrlk.dbfawk: Add some samples dbfawk files. Remove incorrect "re" pointer. 2003-07-23 14:34 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, util.c: We now copy the map pixmap to the display if we're loading maps when the interrupt_drawing_now variable gets set. 2003-07-23 13:29 we7u * src/map_shp.c: Changing the quantites of labels drawn for each zoom level. 2003-07-23 12:17 we7u * src/: Makefile.am, map_geo.c, map_tiger.c, maps.c: Fixes for handling various combinations of Xpm/ImageMagick libraries installed/not-installed. Re-ordered the compile order for the source files to mostly alphabetical order. 2003-07-23 10:33 we7u * src/: db.c, location.c, main.c, main.h: Adding more map interrupt capability to tracking and button callback functions. 2003-07-23 09:20 we7u * README.win32: Added a note about spaces in filenames/directories/user accounts. 2003-07-22 13:13 we7u * src/map_shp.c: Fixing colors so that generated map files put into the maps/GPS directory will show up properly. 2003-07-22 11:15 we7u * README.win32: Changed View to Full for selecting packages. Added pcre and pcre-devel to the list. 2003-07-22 07:11 n2ygk * src/: awk.c, awk.h, testawk.c: add begin, end_rec. Add some dbf stuff to testawk.c 2003-07-21 09:51 we7u * src/awk.c: Initializing a pointer to NULL to get rid of another compiler warning. 2003-07-20 10:44 n2ygk * src/: awk.c, awk.h, testawk.c: Make awk.* cleanly compile with -Wall 2003-07-18 14:05 we7u * src/: main.h, main.c, maps.c: Setting up code so that the Disable All Maps toggle will immediately take effect while loading maps. 2003-07-18 13:58 we7u * configure.ac: Removing -Wall from configure.ac. Jack Twilley added the correct fix to acinclude.m4. 2003-07-18 13:52 jtwilley * acinclude.m4: Wrapped gcc-specific tests in an if test for gcc. Added -Wall to CFLAGS when using gcc. 2003-07-18 13:15 we7u * configure.ac: Adding "-Wall" to CFLAGS. Not sure if this is the perfect way to get it included into src/Makefile, but this method definitely works. 2003-07-18 12:49 we7u * src/gps.c: Adding a define necessary before including time.h, in order to get strptime() function defined on some versions of Linux. 2003-07-18 12:12 we7u * src/interface.c: Adding casts to first parameter of pthread_cleanup_push() so that after macro substitution the compiler is still happy with the 2nd parameter of _pthread_cleanup_push(). 2003-07-18 11:13 we7u * INSTALL: Removing tabs. 2003-07-18 06:14 rzg * help/help-English.dat: Moved some stuff around, AGWPE now a section, minor corrections. 2003-07-17 19:29 n2ygk * INSTALL, configure.ac, src/Makefile.am, src/awk.c, src/awk.h, src/testawk.c: Start adding support for my awk-like metadata for shapefiles: Tests for -lpcre, documentation of where to find pcre, and awk.c, awk.h which is the code that will be called once I get the nerve to do some serious hacking on map_shp.c:-) 2003-07-17 14:54 we7u * README.win32: Added another note about the .cvspass file. 2003-07-17 12:37 we7u * src/util.c: Fixing timezone for non Cygwin systems. #ifdef's were a bit wrong. 2003-07-17 12:25 we7u * README.win32: Adding a few more error messages that might occur while doing CVS operations. 2003-07-17 08:28 we7u * src/db.c: Making Tropical Storm/Tropical Depression/Hurricane wind speed rings disappear at the ghosting time. 2003-07-16 14:07 we7u * src/interface.c: Installing thread cleanup routines. These should take care of unlocking mutex's when the threads terminate for any reason. Should keep the rest of the program running. 2003-07-15 22:25 we7u * README.win32: Changing the note about creating the .cvsrc file. Trying to make it VERY CLEAR that a Unix-type editor must be used. 2003-07-15 15:58 we7u * src/util.c: Changing the begin_critical_section() functio (mutex locks). If a resource has already been locked, output a warning message and skip trying to lock again. This should allow Xastir to recover should locks or unlocks be tried twice or more in sequence. Warning messages will get printed, but the threads should continue to run. 2003-07-15 15:42 we7u * src/main.c: Adding the busy cursor in a couple of places so that we have a better indication of when map drawing is taking place. 2003-07-15 13:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Cranking up the GPS timing if it is set lower than 3 seconds. We also now present a popup to the user to notify them that the GPS timing has been changed. 2003-07-15 13:23 we7u * src/main.c: Adding a timeout for HSP ports for GPS listener mode. 2003-07-15 12:34 we7u * src/interface.c: First attempt at fixing some of the HSP interface's problems. This one will send strings other than GPGGA and GPRMC through the normal decoding sequence. That will at least process received TNC strings, which the previous code did not. 2003-07-15 11:13 we7u * src/util.c: Skip copying final pixmap to display if we have a map interrupt. 2003-07-15 11:08 we7u * src/map_tiger.c: Commenting out a bunc of the map interrupt code to see if it eliminates segfaults that some users are seeing. 2003-07-15 07:17 n2ygk * src/: alert.c, color.c, color.h, db.c, list_gui.c, main.c, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h, util.c, xa_config.c, xastir.h: Update to newer emacs c-basic-offset 2003-07-14 14:37 we7u * README.win32: Changed "diff" to "diffutils", as they apparently changed what package "diff" could be found in. 2003-07-14 14:26 we7u * README.win32: Adding a blurb about the final-final dialog for Cygwin installs that must have it's OK button pressed for the whole thing to finish. 2003-07-14 13:31 we7u * help/: help-English.dat, help-German.dat, help-Italian.dat, help-Portuguese.dat, help-Spanish.dat: Changing docs to match new /usr/local/share/xastir/* directories. 2003-07-14 13:24 we7u * FAQ, INSTALL, README.MAPS, README.win32, UPGRADE: Changing docs to match newer /usr/local/share directory structure. 2003-07-11 08:44 we7u * src/util.c: GMT -> Localtime fixes for both Unix and Cygwin. 2003-07-10 13:25 we7u * src/util.c: Timezone changes for Cygwin. 2003-07-10 12:06 we7u * src/interface.c: Changes for HSP. 2003-07-10 12:00 we7u * src/draw_symbols.c: Forcing expire of severe weather polygons at a 10 minute interval, ignoring the user-settable ghosting period for these objects. 2003-07-09 17:18 we7u * src/main.c: Changing one comment. 2003-07-09 17:18 we7u * src/interface.c: Changing some usleep's throughout. Mostly making them larger, having to do with starting/stopping interfaces. 2003-07-09 17:04 we7u * src/interface_gui.c: Backing out a few of the TAB_GROUP items. Don't work for some widgets. Cause segfaults. This version appears to work properly. 2003-07-09 16:34 we7u * src/interface_gui.c: Setting up tab groups for all of the interface GUI dialogs. 2003-07-09 15:55 we7u * src/interface_gui.c: Fixing tab groups for Interfaces->Properties dialog for internet servers. Probably more to come for other interface types. 2003-07-09 15:26 we7u * src/draw_symbols.c: Detaching multipoint object drawing from the "Include Expired Data" toggle. They now expire at the ghosting interval. 2003-07-09 15:02 we7u * src/xa_config.c: Making the default for displaying old data equal to zero now instead of 1. 2003-07-07 16:51 we7u * src/main.c: Causing display updates once per 60 seconds, even with no input triggers. 2003-07-07 16:19 we7u * src/map_shp.c: Adding in maximum zoom levels for various water features. They still need fine-tuning. 2003-07-07 14:30 we7u * src/db.c: Added a limit to the number of trackpoints displayed in Station Info. This prevents lockups when display Station Info on extremely long paths, for instance: TrackMe with GPS enabled, displaying Station Info on my own station. 2003-07-07 14:20 we7u * src/main.c: Added in the map interrupt stuff for drawing symbols/tracks. Maps and symbols/tracks now appear to be drawn & interrupted together. 2003-07-07 13:56 we7u * src/interface.c: Tweaks for HSP interfaces. DTR should be reset now after sending waypoint strings out to the GPS on an HSP port. 2003-07-07 13:23 we7u * src/main.c: Changed some comments. 2003-07-07 13:22 we7u * src/interface.c: Changed a comment. 2003-07-07 11:09 we7u * scripts/xastir-fixcfg.sh: Script now removes the map_index.sys file and moves the selected_maps.sys file to selected_maps.sys.backup 2003-07-07 10:57 we7u * src/maps.c: Changed some comments. 2003-07-07 10:17 we7u * scripts/icontable.pl: Changed path to match new Xastir directory structure. 2003-07-07 09:33 we7u * UPGRADE: Added instructions for migrating to Xastir's new directory structure. 2003-07-05 08:28 n0vh * scripts/fcc-get: Updated to reflect the new directory structure. 2003-07-04 15:17 we7u * scripts/xastir-migrate.sh: Changing script so that it deletes the old files and not the new. 2003-07-04 12:32 we7u * src/: db.c, location.c, main.c, main.h, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c: A better implementation of the interrupt-map-loading function. We still end up with tracks/stations drawn strangely when we first interrupt, but that's the next problem I'll tackle. 2003-07-04 10:10 rzg * help/help-English.dat: Listing the last few changes... 2003-07-04 02:11 we7u * src/main.c: Made some of the mouse and keyboard operations interruptible. 2003-07-03 14:30 we7u * src/: map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c: More map interrupting capability. Currently works for resizing quite nicely. 2003-07-03 13:23 we7u * src/: map_geo.c, maps.c: Adding in more map drawing interruption capability. 2003-07-03 12:13 we7u * src/: main.c, main.h, maps.c: Added some flags that get set by da_resize, which then immediately exits allowing X11 to continue. If interrupt_drawing_now is set, map drawing ceases after the map we're currently loading is finished. If request_resize is set, then a resize operation is started by UpdateTime. We can add checks for interrupt_drawing_now to other routines later in order to stop map drawing more quickly. Next is to do a similar thing for the da_input function, so that a keypress or mouse click can interrupt map loading. 2003-07-03 10:32 n2ygk * scripts/Makefile.am: eliminate duplicate config data 2003-07-03 10:07 n2ygk * xastir.spec.in: Patches are now integrated in the main trunk. 2003-07-02 14:49 we7u * scripts/: migrate-config.sh, migrate-dirs.sh: Removed these two files in favor of two new files by Alan. 2003-07-02 14:48 we7u * scripts/: xastir-fixcfg.sh, xastir-migrate.sh: Minor tweaks. Added Id tags for CVS and more directories. 2003-07-02 14:19 n2ygk * Makefile.am, configure.ac, config/Makefile.am, help/Makefile.am, scripts/Makefile.am, symbols/Makefile.am: Changed locations of shared xastir files. After make install you should run scripts/xastir-migrate.sh and scripts/xastir-fixcfg.sh. The former fixes the shared files directory. The latter fixes your personal xastir.cnf references to those shared files. 2003-07-02 14:03 n2ygk * scripts/: Makefile.am, xastir-fixcfg.sh, xastir-migrate.sh: Add xastir-fixcfg.sh and xastir-migrate.sh 2003-07-02 08:49 we7u * README.win32: Added a chmod command for creating a script for starting Xastir. 2003-07-02 07:11 n2ygk * src/map_dos.c: fix reversed cleanup of __LCLINT__ ifdef that was wrong. 2003-07-01 23:10 we7u * src/map_dos.c: Fixed some minor bugs w.r.t. DOS map decoding. 2003-06-30 14:37 we7u * src/maps.c: Fixing a naming problem for a variable. 2003-06-30 09:53 we7u * src/maps.h: Adding more prototypes needed by some of the map files that have been newly separated out from maps.c. 2003-06-30 09:52 we7u * src/maps.c: Commenting out an unused function. 2003-06-30 09:52 we7u * src/map_dos.c: Commenting out some unused variables. 2003-06-26 08:37 n2ygk * src/: Makefile.am, map_dos.c, map_geo.c, map_gnis.c, map_pdb.c, map_shp.c, map_tif.c, map_tiger.c, maps.c, maps.h: split maps.c into several map-specific files. 2003-06-25 12:00 we7u * src/main.c: Update tracking station call if TrackMe is enabled when we change our own station callsign. 2003-06-22 12:48 we7u * src/maps.c: Decoding school district types in shapefiles and displaying as a yellow border. 2003-06-20 19:06 we7u * src/main.c: More moving save station trail and GPSMAN functions to use the local users' ~/.xastir/gps and ~/.xastir/tracklogs directories. 2003-06-20 19:05 we7u * src/maps.c: Starting to move GPS and Save station trail functions so that they use ~/.xastir/gps and ~/.xastir/tracklogs directories. 2003-06-20 18:27 we7u * src/: maps.c, track_gui.c: Shortening the temp files to get rid of "xastir_" and the username. 2003-06-20 16:55 we7u * src/: main.c, track_gui.c, maps.c: Moving temporary files into the users ~/.xastir/tmp directory. 2003-06-20 16:10 we7u * src/maps.c: Changing default auto_maps for directories and .geo files to 0. 2003-06-20 15:52 we7u * scripts/: migrate-config.sh, migrate-dirs.sh: Migration scripts by Alan Crosswell, N2YGK. 2003-06-20 15:29 we7u * src/track_gui.c: Added some comments regarding the date/timestamp that's available on findu.com for track downloads. 2003-06-20 14:57 we7u * src/: db.c, draw_symbols.c, draw_symbols.h, main.c: Tweaks to display signpost symbol data next to symbol. Also allow letters now instead of just digits, as the spec appears to allow this. Next thing to bring us fully into compliance is to only show the signpost data at close-in zoom levels (minor), and perhaps also to show the data on top of the sign (also minor). 2003-06-18 11:40 we7u * src/main.c, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys: Fixes for the Map Chooser confusion regarding the clear and the map-type selection buttons. 2003-06-18 11:12 we7u * src/maps.c: Tweaks by Derrick J Brashear, KB3EGH, to handle non-USGS geotiff images properly. 2003-06-17 21:13 rzg * help/help-English.dat: Beginnings of new BETA section, list form... 2003-06-17 18:29 kd6zwr * src/maps.c: Adding check for raster maps that are too big or small for display. define FUZZYRASTER to enable. 2003-06-17 17:24 we7u * config/xastir.rgb, src/main.c: Making a color change that Henk wanted, so that yellow tracks can be seen on top of yellow map fills. 2003-06-17 17:02 we7u * src/maps.c: Added MAP_SCALE_CHECK define and associated code. Will skip maps whose extents are smaller than 4% of the view size. The define is commented out by default so that the check is not performed. 2003-06-17 12:48 we7u * src/xa_config.c: Added a comment. 2003-06-16 15:56 we7u * src/interface.c: Support for sequence numbers in OpenTrac packets. Can send multiple positions in one packet. 2003-06-16 13:48 we7u * help/help-English.dat: More details on the REFRESH .geo tag. 2003-06-16 11:50 we7u * src/interface.c: Fixing a small bug in the OpenTrac text output regarding symbols. 2003-06-16 11:49 we7u * src/: db.c, maps.c, util.c: Changing puts() calls to fprintf(). 2003-06-16 10:34 we7u * help/help-English.dat: Added the REFRESH tag description for .geo files. 2003-06-15 17:33 we7u * configure.ac: Bumping rev number past the last stable rev number. 2003-06-14 00:19 we7u * src/interface.c: Translating from OpenTrac symbols to APRS symbols. 2003-06-13 22:35 we7u * src/interface.c: Taking out devel code that's not working yet. 2003-06-13 18:47 kd6zwr * src/: main.c, main.h, maps.c: Added REFRESH tag to geo files. 2003-06-13 16:34 we7u * src/interface.c: Terminating the list with empty strings. 2003-06-13 16:08 we7u * src/interface.c: Adding a symbol translation table for OpenTrac. Not used in the code yet. 2003-06-13 15:22 we7u * src/interface.c: Initial OpenTrac decode routines. Implemented only for AX.25 interfaces to date. 2003-06-13 15:17 we7u * src/maps.h: Adding an export for a routine which will be needed in interface.c soon. 2003-06-13 14:15 we7u * configure.ac: Bumping rev up to 1.2.0 in preparation for stable release. 2003-06-13 13:42 rzg * help/help-English.dat: Adding a bit about the green and blue weather boxes (multipoints) 2003-06-11 11:15 we7u * help/: help-English.dat, help-Portuguese.dat: Fixed some of the FIXME's. 2003-06-11 10:42 we7u * help/: help-German.dat, help-Portuguese.dat: Changed "BETA" to "1.2". 2003-06-11 10:32 rzg * help/help-English.dat: Release will be 1.2 2003-06-08 09:15 we7u * src/gps.c: Removing tabs (again). 2003-06-07 15:43 kd6zwr * src/gps.c: fixing null pointer reference 2003-06-07 15:43 kd6zwr * src/db.c: fixing compiler warnings 2003-06-07 07:19 francais1 * config/language-French.sys: Updated 2003-06-07 00:29 we7u * config/language-Italian.sys: A few more translations by Marco Calistri, IK5BCU. 2003-06-06 17:34 we7u * src/draw_symbols.c: Changing tabs to spaces. 2003-06-06 17:19 we7u * src/main.c: Converting more tabs to spaces. 2003-06-06 17:12 we7u * src/track_gui.c: Changing more tabs to spaces. 2003-06-06 17:04 we7u * src/: interface.c, maps.c: Changing more tabs to spaces. 2003-06-06 16:57 we7u * src/: db.c, igate.c, popup_gui.c, wx_gui.c, xa_config.c: Removing tabs that snuck into the source code. Replaced with spaces. 2003-06-06 12:50 we7u * src/maps.c: Adding another error message in Snapshot thread. If we get a system() call error but errno is zero, this fprintf() will get triggered. 2003-06-06 12:49 we7u * src/db.c: Changes by Henk de Groot, PE1DNN. 2003-06-06 12:37 we7u * README.win32: More revisions to the note about modifier keys. 2003-06-05 17:02 we7u * README.win32: Added a few notes about the libraries which currently cannot be used with Cygwin. 2003-06-05 16:56 we7u * README.win32: Revising a few notes. Added a new section detailing how to keep Cygwin and Xastir up-to-date. 2003-06-05 13:55 we7u * src/maps.c: Checking errno in snapshot routine if the system call returns a possible error. 2003-06-05 13:11 we7u * acinclude.m4, src/maps.c: Reverting back to older snapshot method. Removing configure message regarding old ImageMagick versions, as even the old versions appear to currently work with the Tigermap intensity slider. 2003-06-05 10:54 we7u * src/db.c: Changes by Henk de Groot, PE1DNN. Fixes weather packet parsing problems for packets containing spaces or dots in place of data. 2003-06-05 10:05 we7u * README.win32: Added notes about X modifier keys and Cygwin web sites. 2003-06-05 09:53 we7u * README.win32: Adding more notes about Cygwin's network installer. 2003-06-04 15:35 rzg * help/help-English.dat: Fixing the formatting in a few spots and correcting an unlear statment. 2003-06-04 09:05 we7u * src/: maps.c, track_gui.c, util.c, util.h: Fixing a bug where we don't return from map routines properly on a libcurl error. 2003-06-03 14:49 we7u * src/main.c: Fixing a bug in the Map Chooser which occurs when deselecting files. It was putting a warning message to STDERR. 2003-06-03 14:31 we7u * FAQ: Added a note about color tinting using Hummingbird eXceed. 2003-06-03 14:01 we7u * README.win32: Added notes about totally black images for geotiff files and how to fix it. 2003-06-02 16:58 we7u * src/maps.c: Knocking out the snapshot code for the case where ImageMagick isn't present. When Jack is finished, he can take the #ifdef back out. 2003-06-02 16:23 jtwilley * src/maps.c: Use new acinclude.m4 logic to include correct ImageMagick header. 2003-06-02 16:20 jtwilley * acinclude.m4: Added extra header checks for ImageMagick. 2003-06-02 02:49 jtwilley * src/maps.c: Replaced XpmWriteFileFromPixmap + system("convert") with ImageMagick code 2003-05-30 22:47 we7u * src/maps.c: Fixing some ambiguous if/else bracing. 2003-05-30 22:43 we7u * src/db.c: Fixing some ambiguous if/else braces. 2003-05-30 15:51 jtwilley * acinclude.m4: Checked in fabulous new ImageMagick code. 2003-05-30 12:16 we7u * src/maps.c: Protecting some draw functions from getting called with too few vertices. 2003-05-30 11:54 we7u * src/rotated.c: Added code to skip XFillPolygon() call if the number of points is too few or negative. 2003-05-30 11:44 we7u * src/draw_symbols.c: Added some comments. No code changes. 2003-05-29 08:27 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Spanish.sys: Changing spacing slightly to align Map Properties dialog column headings. 2003-05-29 08:26 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-29 08:25 we7u * config/language-Italian.sys: Changes by Alessandro Frigeri, IK0YUP. 2003-05-28 17:12 we7u * README.win32: Added instructions for snagging/installing liblcms, needed by later versions of ImageMagick. 2003-05-28 16:21 we7u * src/maps.c: Terraserver changed to a new hostname. Changing to correspond. 2003-05-28 13:33 we7u * config/language-German.sys, help/help-German.dat: Changes by Rolf Bleher, DK7IN. 2003-05-28 13:24 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 12:58 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-28 12:57 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-28 11:49 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 11:18 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-28 11:09 we7u * config/language-German.sys: Translation of "Moisture" by Rolf Bleher, DK7IN. 2003-05-28 10:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: More translations. Also changing "meters" to "m". 2003-05-28 10:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Changing a few more hard-coded strings. 2003-05-27 18:00 rzg * help/help-English.dat: Grammar corrections. :-P 2003-05-27 16:44 we7u * INSTALL, README.win32: More ImageMagick notes. 2003-05-27 15:24 we7u * src/db.c: Fixed how we handle space/dot-filled temperature/humidity fields. 2003-05-27 13:43 we7u * src/main.c: Commenting out the new ifdef. Forgot to after testing. 2003-05-27 13:40 we7u * src/: main.c, interface_gui.c: Separated out the LARGE_FONT #ifdef's into two: USE_LARGE_SYSTEM_FONT and USE_LARGE_STATION_FONT. This is to help the visually impaired. Made the cursor position visible in more of the Interfaces->Properties dialogs. 2003-05-27 13:25 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-27 10:57 we7u * help/help-English.dat: Clarified the note about IMAGESIZE being required for .geo files with URL's, optional for local images. 2003-05-27 10:56 we7u * README.MAPS: Another note about IMAGESIZE being a required parameter for .geo files with URL's in them. 2003-05-24 22:52 we7u * src/: maps.c, popup_gui.c: Moved some code and added comments to make it very obvious that fonts are not to be loaded often. Causes memory leaks. 2003-05-24 21:58 we7u * src/main.c: Adding a method to switch to larger fonts, helpful to visually-impaired users. Uncomment the USE_LARGE_FONTS #ifdef at the top of main.c to enable these larger fonts. Off by default. 2003-05-24 00:57 we7u * src/main.c: Re-doing the widget geometry for the Configure->Audio Alarms dialog. It now works with large or small fonts. 2003-05-24 00:05 we7u * src/draw_symbols.c: Added some comments. 2003-05-23 16:30 we7u * src/maps.c: Fixing intensity slider for Tigermap by switching from LevelImage() call to ModulateImage() call. 2003-05-23 15:59 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-23 15:59 we7u * config/: language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-23 14:58 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-23 14:18 we7u * src/xa_config.c: Setting initial default for MAP_CHOOSER_EXPAND_DIRS to 1, so that the terraserver.geo and toposerver.geo files will appear by default for new users. 2003-05-23 13:32 we7u * terraserver.geo, toposerver.geo: Adding these files to the sources. 2003-05-23 13:32 we7u * Makefile.am: Auto-installing terraserver.geo and toposerver.geo in the maps directory. 2003-05-23 13:29 we7u * README.win32: More explanation of CVS errors when SourceForge is too busy. 2003-05-23 13:19 we7u * README.win32, help/help-English.dat: Added TOPOSERVER instructions. 2003-05-23 13:16 we7u * README.MAPS: Added the TOPOSERVER keyword and explanation. 2003-05-23 13:11 we7u * src/maps.c: On-line topo maps. I considered the utility of this versus not adding it until after release. This is just too useful for new (and old) users not to have put it in. Enjoy! Geo file with "TOPOSERVER" in it will get you online topo maps. 2003-05-23 12:06 we7u * src/main.c: Fixing SmartBeaconing dialog so that it's aligned properly. 2003-05-23 11:44 we7u * src/main.c: SmartBeaconing dialog now supports metric units. 2003-05-23 10:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/track_gui.c: Changing more hard-coded strings into language-specific strings. 2003-05-23 10:08 we7u * help/help-English.dat: More minor spelling on consistency changes. 2003-05-23 09:14 we7u * config/language-Portuguese.sys: Making the time periods correspond with the English file. 2003-05-22 22:14 we7u * help/help-English.dat: Lots of minor tweaks throughout the file. 2003-05-22 14:01 we7u * help/help-English.dat: Minor updates. 2003-05-22 13:20 we7u * README.MAPS: Updating the NOAA filenames for the alert shapefiles. 2003-05-22 12:37 we7u * README: Correcting spelling. 2003-05-22 12:33 we7u * README.MAPS: Added notes about setting up permissions for maps/GPS directory. 2003-05-22 12:22 we7u * AUTHORS, INSTALL, NEWS, README.MAPS: Tweaking docs here and there. 2003-05-22 12:02 we7u * DEBUG_LEVELS: Swapped the two sections. Most useful info at the top of the file now. 2003-05-22 11:58 we7u * DEBUG_LEVELS, FAQ, INSTALL, LICENSE, NEWS, README, README.CVS, README.MAPS, README.win32, UPGRADE: Adding/changing copyright notice. 2003-05-22 11:48 we7u * README.win32: Adding more notes. Reworking existing notes to make them more understandable to Windows-folk. 2003-05-22 09:32 we7u * INSTALL: Adding info regarding matching up the libtiff/libgeotiff versions. 2003-05-21 16:16 we7u * src/: db.h, main.c: Reversing the direction of the two Area Object lines, to correspond with dos/winAPRS and UI-View. 2003-05-21 16:16 we7u * src/draw_symbols.c: Added some comments. 2003-05-21 15:40 francais1 * src/: db.c, db.h, draw_symbols.c, draw_symbols.h: Fixed corridor > 127 bug (now works up to 999, which I believe is the spec limit) 2003-05-21 15:34 we7u * src/draw_symbols.c: Added some comments. 2003-05-21 14:18 we7u * src/draw_symbols.c: Implemented area object ellipse display exactly the same as circle display. This is what UI-View is doing. dos/WinAPRS don't implement ellipses at all. 2003-05-21 13:31 we7u * config/language-German.sys, help/help-German.dat: Changes by Rolf Bleher, DK7IN. 2003-05-21 12:56 we7u * src/maps.c: Canceling certain warning messages while indexing. 2003-05-21 12:30 we7u * README.CVS: Updates to match our current codebase and how we do things. 2003-05-21 12:22 we7u * src/main.c: Fixing the Map Properties strings so that they are auto-centered in the columns and truncated to the column widths. 2003-05-21 11:45 we7u * src/main.c: Truncating language strings in Map Properties columns (the "yes" string) so that it fits our column width. 2003-05-21 10:01 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-21 09:45 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-21 09:44 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-21 09:44 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-21 09:22 francais1 * config/language-French.sys: Translated added English 2003-05-20 17:15 we7u * src/: interface.c, main.c: Correcting some grammar. 2003-05-20 17:14 we7u * README.win32: Removing the Perl 5.6 restriction. Perl 5.8 appears to work properly now with Xastir and it's optional libraries. 2003-05-20 14:28 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-20 12:51 we7u * config/language-Italian.sys: Adding some missing strings. 2003-05-20 12:22 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing more hard-coded language strings. 2003-05-20 12:09 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixing hard-coded strings. Added missing GPS strings in Italian file. 2003-05-20 11:16 we7u * FAQ: Added two more questions/answers. 2003-05-20 10:34 we7u * src/: bulletin_gui.c, fcc_data.c, gps.c, interface.c, lang.c, main.c, maps.c, messages.c, rac_data.c, util.c, view_message_gui.c, wx.c, alert.h: Fixing up the and includes with the proper ifdef's. 2003-05-19 20:42 rzg * help/help-English.dat: Typo fixes pointed out by Rolf, minor other things. 2003-05-19 20:28 rzg * INSTALL, README.CVS, README.MAPS, UPGRADE: Adding copyright notices to the docs that lack. 2003-05-19 13:14 we7u * README.win32: Changes by Kirk Mefford, KC2ELO. 2003-05-19 12:52 we7u * src/main.c: Correcting the time.h include to make it sys/time.h. 2003-05-19 11:24 we7u * README.win32: Adding checkboxes. 2003-05-19 11:13 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-19 10:57 we7u * README.win32: Changes by Wes Johnston, edited slightly by me. 2003-05-19 10:35 we7u * INSTALL: Added another festival note from Alan Crosswell. 2003-05-19 09:59 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-05-18 11:29 we7u * config/language-Italian.sys: Changes by Marco Calistri, IK5BCU. 2003-05-16 17:07 we7u * src/maps.c: Removing the debug fprintf() statement. 2003-05-16 17:03 we7u * src/maps.c: Fix for wrong guessing of road widths for some types of Shapefiles. 2003-05-16 16:06 we7u * INSTALL: Shapelib instructions for MacOSX. 2003-05-16 14:44 we7u * README.win32: More detailed instructions for Shapelib integration. 2003-05-16 13:12 we7u * README.win32: More ImageMagick notes for Cygwin. Setting the MAGICK_HOME variable with the new X configuration. 2003-05-16 11:16 we7u * README.win32: Adding a note about the 'X' in the system tray. 2003-05-16 11:10 we7u * README.win32: Changing desktop shortcut to start from Cygwin home directory. 2003-05-16 11:02 we7u * README.win32: Updated Cygwin instructions to allow using Xwindows apps and Windows apps from the same desktop transparently. No Xwindows large box anymore! 2003-05-15 12:32 we7u * src/maps.c: Adding another helpful message for the case where a GEO file is being opened, but perhaps no support is compiled in for the map format. 2003-05-15 12:18 we7u * src/maps.c: Spit out appropriate error messages if various optional map libraries are not installed and the user tries to load unsupported map types. 2003-05-15 11:12 we7u * src/: maps.c, track_gui.c: Changing one warning message. 2003-05-15 08:09 we7u * configure.ac: Bumping the revision up to 1.1.5. 2003-05-15 07:47 we7u * Makefile.am: Getting rid of the last remnants of README.1ST. Adding other doc files. 2003-05-14 22:18 rzg * FAQ, README.1ST, README.win32: Docs cleanup take 5. 2003-05-14 22:07 jtwilley * Makefile.am, xastir.spec.in: Removed references to README.1ST and TODO 2003-05-14 21:02 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-14 20:59 we7u * src/main.c: Moving the time.h include outside the HAVE_IMAGEMAGICK ifdef's. 2003-05-14 19:14 rzg * README: Took last important bit from README.1ST, ready to trash it... 2003-05-14 17:14 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-14 17:08 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-05-14 16:30 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-05-14 16:29 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-05-14 16:06 francais1 * config/language-French.sys: Updated 2 strings to match English. 2003-05-14 16:02 we7u * config/language-English.sys: Updating the reindexing strings. 2003-05-14 15:50 we7u * AUTHORS, DEBUG_LEVELS, FAQ, INSTALL, NEWS, README, README.CVS, README.MAPS, UPGRADE, changes.txt: Adding/Changing to Id: RCS tag in files. 2003-05-14 15:41 we7u * README.MAPS: Updating a NOAA URL. 2003-05-14 13:47 we7u * config/language-Spanish.sys: Changed by Jose R. Marte A., HI8GN. 2003-05-14 12:44 francais1 * config/language-French.sys: Updated 2003-05-14 09:28 rzg * README.MAPS, help/help-English.dat: Docs- big cleanup take 4! 2003-05-14 09:14 rzg * INSTALL, README, README.1ST, UPGRADE: Docs- big cleanup take 3! 2003-05-14 08:42 rzg * INSTALL, README.1ST, README.CVS, README.MAPS: Docs- big cleanup take 2! 2003-05-14 08:40 rzg * TODO, UPDATES: Docs - big clean up take 1! 2003-05-13 14:56 jtwilley * README.win32: Added Kirk Mefford's suggestion re: creating .cvsrc file 2003-05-12 23:59 we7u * src/db.c: CPU Usage fixes. We no longer do complete symbol updates at a high rate. We update only the new symbol, then do cleanup at a 60-second rate sometime later. CPU usage drops a bit with this latest code. 2003-05-12 16:59 we7u * src/main.c: Slowed down UpdateTime() iterations so that the read/write threads would have time to do their thing. Cranked up the maximum packets processed by UpdateTime() in one iteration. Added a usleep() after processing each packet so that the read threads would have time to put another packet in the queue. CPU time has gone down by these changes, but we still appear to keep up with the incoming packets. 2003-05-12 16:56 we7u * src/interface.c: Speeding up the receive threads. They don't take any CPU time anyway, so this doesn't hurt CPU usage. They process one line then wait for the main thread to pick it up before they process the next line. 2003-05-12 13:59 we7u * src/main.c: Changing main.c:UpdateTime() to wait 15ms between each run instead of 10. This reduces CPU time a bit, yet still allows packets to get processed from the receive queues. 20ms appeared to be too slow. Will investigate adding longer delays between graphics updates in this routine, yet allowing packet processing to proceed at a fast pace. That should further reduce CPU cycles yet not get behind in the receive queues. At that point we might reduce the delay again between UpdateTime() runs. 2003-05-12 12:39 we7u * README.win32: Updating the list of Cygwin packages to include tcl/tk and Curl. 2003-05-11 22:18 we7u * config/language-Italian.sys: Another phrase translated by Marco Calistri, IK5BCU. 2003-05-11 08:06 we7u * config/language-Italian.sys: Adding a missing string. In English so far (until I get an Italian translation of it). 2003-05-10 16:42 we7u * src/maps.c: Fix by Magne Mhre, la1bfa, for segfault generated when Shapefiles can't be created on the file system, usually due to permissions problems in /usr/local/maps/GPS. 2003-05-10 00:31 we7u * src/alert.c: Converting one more strcpy to strncpy. 2003-05-10 00:15 we7u * src/alert.c: Fixing another killer packet bug in the alert code. 2003-05-09 14:13 we7u * config/language-English.sys: Changing one label slightly regarding reindexing. 2003-05-09 10:43 we7u * src/maps.c: Tweaks to maintain selected map properties when a full reindexing is requested. 2003-05-08 23:39 we7u * src/: maps.c, maps.h, main.c: Implementing an indexing scheme that takes care of finding updated files quickly, deleting records for deleted files, and wasting everything and starting from scratch to build a new index. This code can do all of that. 2003-05-08 23:32 we7u * README.win32: Removed an email address so that Kirk won't get spammed by the spambots. 2003-05-08 23:28 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changing/Adding Map Re-Index strings for menus. 2003-05-08 17:44 rzg * README.win32: Sound Alert information from Kirk Mefford kc2elo@softhome.net 2003-05-08 14:36 we7u * src/main.c: Changed a comment. 2003-05-08 12:31 we7u * src/db.c: Fixing the Station Info dialog so that the multipoint strings aren't shown. They're now removed from the string inside the extract_multipoint() function. 2003-05-07 22:26 we7u * src/alert.c: Fixing the alert matching so that a new alert will match a pre-existing CANCL packet in the list. This is in response to a bug on the bug-list. 2003-05-07 13:32 francais1 * src/maps.c: Fixed relative paths to images in .geo files 2003-05-06 21:32 kd6zwr * src/maps.c: Made IMAGESIZE tag optional for geo files, (imagemagic ping to autodetect size) Also allow absolute pathnames in geo files, as well as relative. 2003-05-06 14:49 we7u * src/db.c: Don't draw wind barbs for severe storm objects. 2003-05-06 13:33 we7u * src/db.c: Adding the other types of severe storms that the weather server can issue. This is part of the general hurricane bug fix on the bug list. 2003-05-06 13:19 we7u * src/db.c, src/db.h, symbols/symbols.dat: Moving wind speed into the proper field (so that it shows up in Station Info) for hurricanes. This is a partial fix for a bug on the buglist. Changing the tornado symbol so that it stands out more (thanks to Dale Huguley for that one). 2003-05-06 08:17 we7u * help/help-English.dat: Added a description of the weather watch box colors/patterns, courtesy of Dale Huguley. 2003-05-05 21:22 we7u * src/util.c: Correcting for daylight savings time when converting from zulu time to Unix epoch time. Also added some debug code. 2003-05-05 16:08 jtwilley * README.1ST: Minor correction to FreeBSD notes. 2003-05-05 13:36 we7u * src/alert.c: Changed some comments. No code changes. 2003-05-05 11:00 we7u * src/alert.c: Fixing another "killer packet" problem: If we got an uncompressed message that looked like a weather alert but was simply a test message, we segfaulted while trying to move uninitialized strings around. 2003-05-02 17:31 we7u * src/: db.c, alert.c: Rewrote weather alert handling so that compressed format weather alert packets are parsed/displayed correctly. 2003-05-02 11:03 kd6zwr * src/maps.c: Initialize a few variables to NULL to shut up -Wall 2003-05-02 10:43 we7u * help/help-English.dat: Added a note about IMAGESIZE now being a required keyword in .GEO files. 2003-05-02 01:44 we7u * src/db.c: Re-wrote relay_digipeat() so that it is more correct. It now appears to get to the correct part of the path before checking for my_call or RELAY. 2003-05-01 09:47 kd6zwr * src/: maps.c, maps.h: Changed reading in map index to much faster mode, and added a sort routine to make sure it is still sorted correctly. 2003-05-01 09:38 we7u * src/db.c: Reordered the widgets in the Station Info dialog so that it can be resized properly. This is to take another bug off the buglist regarding oversized Station Info dialog that can't be resized. It can now. 2003-04-30 23:38 we7u * README.1ST: Added some notes about tiger file types and NOAA weather alert shapefiles. 2003-04-30 21:19 we7u * src/maps.c: Working code for Shapefile polygon "holes"!!! 2003-04-30 13:22 we7u * src/util.c: Adding two more lower-case letters to those accepted by valid_path() for Q-constructs. 2003-04-30 13:10 we7u * src/maps.c: More debug stuff. More work on Shapefile holes in polygons. 2003-04-30 12:50 we7u * src/util.c: Added more debug statements to valid_path(). 2003-04-30 10:50 rzg * help/help-English.dat, FAQ: Qxx, and other minor updates to help and FAQ. 2003-04-30 09:02 we7u * src/maps.c: Comment changes. No code changes (yet!). 2003-04-29 14:37 jtwilley * src/main.c: Fixed warnings with libcurl. Started GDAL integration. 2003-04-29 13:24 we7u * src/maps.c: Changing/adding comments. 2003-04-29 13:02 we7u * src/maps.c: Implementing a better fill/hole ring-direction algorithm for Shapefiles. This one is snagged directly from Shapelib and used by permission of the author, Frank Warmerdam. 2003-04-28 23:03 we7u * src/maps.c: More tweaks to the Shapefile "hole" ring code. Not fully implemented yet, but added some speed improvements. Next is to implement a clip-mask in the form of regions. 2003-04-28 22:59 we7u * src/interface.c: Getting rid of an unused variable. 2003-04-28 21:59 rzg * README.1ST: Updates WTR igating weather alerts, minor spacing changes, and nicer libcurl URL. 2003-04-28 21:24 jtwilley * README.1ST: Added URL for libcurl. 2003-04-28 20:57 we7u * src/db.c: Changed the extract_GLL() function from using strtok() to split_string(). 2003-04-28 17:04 we7u * src/db.c: Converted extract_RMC() to using split_string() instead of strtok(). 2003-04-28 16:17 we7u * src/db.c: Removing unused variables. 2003-04-28 16:08 we7u * src/db.c: Re-wrote extract_GGA() to avoid a segfault with a killer packet. Need to re-write extract_RMC() and extract_GLL() in a similar manner. The fix is to get rid of strtok() and use util.c:split_string() instead. 2003-04-28 14:50 we7u * src/: interface.c, util.c, util.h: Moved split_string() function to util.c/util.h in preparation for using it from more places in the code (instead of just interface.c). 2003-04-28 11:47 we7u * src/maps.c: Making debug levels more consistent. 2003-04-28 11:43 we7u * src/maps.c: Adding new routine which can determine whether a Shape ring is a fill or a hole ring. This is part of the work to implement the "holes" properly for Shapefiles. 2003-04-28 10:27 we7u * config/language-Spanish.sys: Changes by Jose R. Marte A., HI8GN. 2003-04-27 20:45 we7u * src/maps.c: Adding more comments. 2003-04-26 23:38 we7u * src/maps.c: More comment changes. No code changes. 2003-04-26 23:15 we7u * README.1ST: Changed the location for the Tiger/Line->Shapefile downloads. 2003-04-26 18:21 we7u * src/maps.c: Working on the Shapelib drawing function "hole" problem. So far just adding comments and example code in comments. No code changes yet. 2003-04-25 17:32 we7u * src/maps.c: Adding more comments. 2003-04-25 17:09 we7u * src/maps.c: Added comments. 2003-04-25 15:49 we7u * config/language-Italian.sys: Another tweak by Marco Calistri, IK5BCU. 2003-04-25 15:45 we7u * src/maps.c: Changing to "Nonconvex" parameter for the rest of the XFillPolygon calls. This should speed up drawing a bit. 2003-04-25 15:30 we7u * src/maps.c: Changing XFillPolygons to use Nonconvex parameter, which speeds up map drawing for cases where the line doesn't cross its own path. Added some comments. 2003-04-25 15:29 we7u * config/: language-Dutch.sys, language-French.sys, language-Italian.sys, language-Spanish.sys: Correcting one bug left in the files due to a mistyped character. Checking in latest Italian translation by Marco Calistri, IK5BCU. 2003-04-25 13:36 we7u * README.win32, README.1ST: Added notes about libcurl. 2003-04-24 17:25 jtwilley * src/maps.c: Added code to support libcurl. Added code to remove PACKAGE_* warnings. 2003-04-24 17:24 jtwilley * src/track_gui.c: Added code to support libcurl. 2003-04-24 17:20 jtwilley * src/main.c: Added code to support libcurl. Added code to remove PACKAGE_* warnings. 2003-04-24 17:19 jtwilley * src/util.c: Added code for curl_fwrite and curl_getfile. 2003-04-24 17:15 jtwilley * src/util.h: Added declarations for curl_fwrite and curl_getfile. 2003-04-24 17:04 jtwilley * configure.ac: Added check for libcurl. 2003-04-24 15:25 we7u * src/: interface.c, maps.c: Adding comments. 2003-04-24 14:06 we7u * README.win32: Revising the Perl interpreter to install. There are problems with 5.8.0 yet. 2003-04-23 13:16 we7u * src/interface.c: Changing port_read() to a 50ms delay instead of 20ms. Last checkin was a slight oops. 2003-04-23 13:15 we7u * src/interface.c: Speeding up the port_read() and port_write() delays again. We were starting to get behind at processing packets from full-feeds, with 100ms delays. Changed to 50ms delays and we appear to catch up when we get a bit behind. The correct solution for this is to use select() to wait for data to process, instead of using it as a short sleep function. Something to change another day... 2003-04-22 23:08 we7u * src/maps.c: Minor revisions to the create_shapefile from APRS Trail functions. Maps are now saved in the /maps/GPS/ directory and are red dashed lines by default. They appear in the Map Chooser once re-index maps has been run. 2003-04-22 10:34 we7u * src/: db.c, main.c, main.h, maps.c, maps.h: The "Store Track" button on the Station Info dialog now saves the station track as a Shapefile map in /var/tmp/, if Shapelib has been compiled in. The Shapefile filename will contain the callsign and a date/timestamp. The original function of the button still remains as well: It also saves the info in the original text format. 2003-04-22 01:35 jtwilley * src/main.c: Added tnc_data_clean call to static TNC case. 2003-04-22 01:30 jtwilley * src/interface.c: Replaced broken routine in tnc_data_clean with working routine. 2003-04-21 15:45 we7u * src/interface.c: Changed port_write() so that it'll send blocks of characters across network interfaces, single chars with inter-character pacing across serial interfaces. 2003-04-18 17:21 we7u * xastir.spec.in: Updated spec input file. Starting to work. 2003-04-18 17:21 we7u * Makefile.am: Adding xastir/GNIS/ directory to install. Used for searching. 2003-04-18 15:37 we7u * README.win32: Updating library versions that we've tested with. 2003-04-18 13:59 we7u * README.1ST: Updating optional library versions that Xastir has been tested with. 2003-04-18 13:48 we7u * xastir.spec.in: Fixes so that man page gets installed correctly. 2003-04-18 12:47 we7u * xastir.spec.in: Tweaks to make the spec file more up-to-date. The changes fix several of the failures in building RPM's, but still fails building the man page. 2003-04-18 12:09 we7u * README.win32: Updating docs to latest Shapefile version tested. 2003-04-18 11:46 we7u * README.1ST: Updating version of Shapelib library to latest tested. 2003-04-17 15:08 we7u * src/igate.c: Added a comment. 2003-04-17 14:32 we7u * src/igate.c: Adding AGWPE devices to the dupe queues for igating. 2003-04-17 13:35 we7u * README.1ST: Adding another map link. 2003-04-17 10:24 we7u * README.1ST: Another GPSMan note. 2003-04-17 10:21 we7u * README.1ST: Updating the libgeotiff instructions. 2003-04-17 10:11 we7u * README.1ST, README.win32: Re-organization of the wetnet directories. Changed links in README's to match. 2003-04-17 09:56 we7u * README.1ST, README.win32: Changed from eskimo.com to wetnet.net for some of the optional map library download sites. 2003-04-16 17:12 we7u * src/igate.c: We now allow partial matches of NWS data, but the strings defined in the nws-stations.txt file must be at least three characters long in order to create a valid match. 2003-04-16 16:42 we7u * src/: interface.c, interface_gui.c, location_gui.c, maps.c: Fixing more possible scanf()/sscanf() buffer overflow conditions. 2003-04-16 16:40 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-16 16:27 we7u * src/igate.c: Fixing a possible buffer overflow condition where we're reading the nws-stations.txt file into an array. 2003-04-16 16:14 we7u * README.1ST: Miscellaneous maps notes. Put in eskimo.com as an alternate location for some of the map libaries. 2003-04-16 15:56 we7u * README.win32: Added more download sites for the optional map libraries. 2003-04-16 14:12 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-16 14:04 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-04-16 12:32 we7u * config/language-Spanish.sys: Adding the strings back in that were added yesterday but left out of the last translation. 2003-04-16 12:29 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-16 10:14 we7u * src/interface.c: Added comments. Added character pacing on write again for the DEVICE_NET_AGWPE interface. It's separate from the others so that it can be fine-tuned. 2003-04-15 17:24 we7u * src/interface.c: Adding some debug statements. 2003-04-15 15:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Putting in language strings instead of hard-coded English for Configure->Timing dialog. 2003-04-15 15:04 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Fixes for hard-coded English strings in Maps->Enable/Configure Tigermap dialog. 2003-04-15 14:34 we7u * src/main.c: Fixing Configure->Defaults dialog so that all of the widgets are visible in all of our supported languages. 2003-04-15 13:41 we7u * config/language-Dutch.sys: Changes by Han Sytsma, PE1FAM. 2003-04-15 13:00 we7u * src/interface_gui.c: Disabling relay digipeat for AGWPE interface until raw transmit packet frames can be implemented. 2003-04-15 12:52 we7u * src/db.c: Added a comment. 2003-04-15 12:51 we7u * src/interface.c: Comments. Changed test packet callsigns. 2003-04-15 09:04 we7u * config/language-German.sys: Changes by Rolf Bleher, DK7IN. 2003-04-15 08:41 we7u * config/language-English.sys: Committing changes for Rolf Bleher, DK7IN. 2003-04-15 01:21 we7u * src/interface.c: Fix to igate_path for AGWPE interfaces. 2003-04-14 09:32 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2003-04-13 08:51 rzg * help/help-English.dat: Various updates for new features, and typo fixes, more to come. 2003-04-11 18:32 we7u * src/: db.c, db.h, festival.c, festival.h, main.c, main.h, rotated.c, rotated.h, wx.c, wx_gui.c: Corrected some inconsistencies found by running the compiler at higher warning & pedantic levels. 2003-04-11 17:07 we7u * src/: maps.c, messages_gui.c, util.c: More minor cleanups. 2003-04-11 16:59 we7u * src/: bulletin_gui.c, db.c, gps.c, interface.c, interface.h, main.c, maps.c: Minor cleanups. Lots of them. 2003-04-11 16:58 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-11 15:36 we7u * config/language-Portuguese.sys: Tweaks to add missing strings. 2003-04-11 15:30 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2003-04-11 15:13 we7u * README.1ST: Another tweak by J. Lance Cotton. 2003-04-11 15:08 we7u * README.1ST: Added instructions for reprojecting Shapefiles, courtesy of Derrick J Brashear and J. Lance Cotton. 2003-04-11 14:07 we7u * src/: db.c, interface_gui.c: Setting up for relay digipeating using AGWPE interfaces. Untested. 2003-04-11 13:49 we7u * src/igate.c: Added AGWPE to igating code. 2003-04-11 13:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface_gui.c: Implemented the transmit radioport option for AGWPE interfaces. This can be adapted to other multi-port TNC interfaces later. 2003-04-11 13:26 we7u * src/interface.c: Backing out one change to avoid high CPU-usage in the port_write() function. Added comments to the port_read() and port_write() threads to hopefully eliminate this sort of problem in the future. 2003-04-11 11:17 we7u * src/interface.c: Added code to disable Nagle's algorithm for TCP/IP sockets : TCP_NODELAY setsockopt(). 2003-04-11 10:25 we7u * src/interface.c: Eliminated line pacing for network connections. Added more serial types to the character pacing code. 2003-04-10 17:10 we7u * src/interface.c: Fixing a lock problem and commenting out some debug packets for AGWPE. 2003-04-10 14:17 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Tweaking AGWPE labels. 2003-04-10 14:13 we7u * src/interface_gui.c: Removing filter options from AGWPE Properties dialog. Doesn't apply. 2003-04-10 14:05 we7u * src/interface_gui.c: Extending the length for AGWPE passwords. 2003-04-10 13:58 we7u * src/interface_gui.c: More AGWPE stuff. 2003-04-10 12:49 kd6zwr * src/maps.c: Fix for systems with both Xpm.h and XpmI.h 2003-04-10 12:46 we7u * src/interface.c: Getting rid of unused variables and old code. 2003-04-10 12:40 we7u * src/interface.c: Moved the unproto path selection into its own routine. More code changes to support agwpe. 2003-04-10 11:14 we7u * README.1ST: Specifying an alternate ftp site to get the radar geo's from. 2003-04-10 09:45 we7u * README.1ST, help/help-English.dat: Adding a few notes about the .GEO file format specifying that decimal degrees are used for lat/lon in these files. 2003-04-08 14:30 we7u * src/interface.c: Changing input parameter for send_agwpe_packet() to accept a digi path instead of a list of digi's. This will integrate into the Xastir method of specifiying paths more easily. 2003-04-08 13:33 we7u * src/interface.c: Changing the AGWPE login ID to be callsign minus SSID (removed SSID). 2003-04-07 23:17 we7u * src/interface.c: Initial transmit capability for AGWPE interfaces. Currently the path is hard-coded to RELAY,WIDE2-2, but that will change given time. The method of specifying the path differs greatly from Xastir's original method, plus the Properties GUI for AGWPE needs to be reworked to add in the optional path fields. 2003-04-07 10:26 we7u * src/interface.c: Commenting out some debugging printf's. 2003-04-06 13:25 we7u * src/main.c: The other small tweak needed in order to decode AGWPE packets. 2003-04-06 13:22 we7u * src/interface.c: AGWPE interface receive mode is not functional. Transmit is still being worked on. 2003-04-05 11:16 we7u * src/interface.c: More AGWPE code. We're getting packets sent in both directions now, although the login/password packet doesn't appear to be accepted properly yet. No decoding/encoding of real packets is implemented yet. 2003-04-04 16:55 we7u * src/xa_config.c: Fixing this so that it handles the correct types of interfaces. 2003-04-04 14:04 we7u * src/interface.c: Added some comments. 2003-04-04 13:50 we7u * src/interface.c: More AGWPE stuff. Not functional yet. 2003-04-04 12:52 we7u * src/interface.c: Send the login packet to AGWPE only if the passwd string has something in it. 2003-04-04 11:48 we7u * src/interface.c: More AGWPE interface code. Now sending login/password string and command to ask AGWPE to send us the monitored packets. Don't have transmit or the receive decode of those packets completed yet, but debug code is in place that looks for complete headers and packets and notifies us on reception. 2003-04-03 23:48 we7u * src/interface.c: More AGWPE stuff. Not functional yet. 2003-04-03 17:12 we7u * src/interface.c: More AGWPE work. Not functional yet. 2003-04-03 14:40 we7u * src/interface.c: Reformatting. No code changes. 2003-04-03 14:24 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.c, src/interface.h, src/interface_gui.c: Initial steps at adding network support for AGWPE. 2003-04-03 12:57 we7u * src/: main.c, maps.h: Adding my test_create_shapefile stuff back in, this time with the proper #ifdef's so that everybody can still compile the code whether they have shapelib installed or not. 2003-04-03 11:52 we7u * src/: main.c, maps.c: Spawning off a separate thread for doing the Snapshot() function. 2003-04-03 09:39 we7u * src/maps.c: Changing the Snapshot function so that it can reduce to 256 colors if necessary when converting from XPM to PNG. 2003-04-02 13:01 francais1 * src/interface.c: Enable suid privileges around bind to reset from callsign (RELAY digipeat bugfix with 2.2.19 kernels, I hope.) 2003-04-02 11:30 we7u * src/main.c: Disabling my test_create_shapefile_map entry. Some people can't get Xastir to compile with it in there, and it's test code anyway. 2003-04-01 16:27 we7u * src/: main.c, maps.c, maps.h: Testing of the shapefile creation function. Attached to the "Test" button on the menus. 2003-04-01 15:25 we7u * src/maps.c: Changed to comments. No code changes. 2003-04-01 13:13 we7u * src/interface.c: Adding some white space. No code changes this time. 2003-04-01 09:55 we7u * src/xastir.h: Enabling serial KISS tnc relay digipeat functionality by default. Initial testing shows that this portions of relay digipeat is working. AX.25 relay digipeat still needs a bit of work to get the source callsign to be set properly. 2003-04-01 01:09 we7u * src/: db.c, interface.c: Changes to make RELAY digipeating functional for Serial KISS TNC interfaces. May have fixed AX.25 interfaces as well. 2003-03-31 23:16 we7u * src/db.c: Better debug output for relay_digipeat() function. 2003-03-31 15:31 we7u * src/db.c: More debug messages for relay_digipeat() function. Again, will be removed later. 2003-03-31 14:59 we7u * src/db.c: Adding some debug output for relay digipeat. It'll be removed later when we get things working properly. 2003-03-28 17:05 we7u * src/db.c: More KISS variant comments. 2003-03-28 16:37 we7u * src/db.c: Added another kiss variant to the comments. 2003-03-28 16:34 we7u * src/db.c: Added some notes about KISS protocol variants. No code changes. 2003-03-28 11:13 we7u * src/maps.c: Changing point shapefiles so that if labels are turned off, the symbols still get drawn. 2003-03-28 10:33 we7u * src/: interface.c, db.c: Added comments. Now mask off the AX.25 P/F bit before checking the control byte for 0x03 (UI Frame). Now drop the Serial KISS packet if the final result is not 0x03. 2003-03-27 15:57 we7u * src/db.c: Taking out the control byte == 0x03 restriction for Serial KISS packets. MKISS TNC's encode the channel number in the control byte. 2003-03-27 15:46 we7u * src/db.c: Added a note to decode_ax25_header() function. 2003-03-27 15:42 we7u * README.1ST: Added a GPSMan install step to set the permissions on the /usr/local/xastir/maps/GPS/ directory so that files could be written there. 2003-03-27 15:33 we7u * src/db.c: Changing the Serial KISS interface to ignore packets if the control byte != 0x03 and the PID byte != 0x0f. This will make it co-exist on channels that might have other protocols on them (net/rom, tcp/ip, etc.). The AX.25 interface code already had the PID==0x0f restriction on it. 2003-03-27 14:32 we7u * README.win32: Changed "go.bat" to just "go". Less typing to get things rolling that way. 2003-03-27 14:16 we7u * README.win32: Added zip/unzip to the list of packages to install. Helps when installing some map files later. 2003-03-27 11:21 we7u * README.win32: Added some blank lines. 2003-03-27 11:17 we7u * README.1ST: Added notes about how to decompress the World shapefile. 2003-03-27 11:11 francais1 * FAQ: Added a lesstif/openmotif entry 2003-03-26 22:10 we7u * README.win32: More details for the user in terms of creating subdirectories while adding in the optional libraries. 2003-03-26 11:55 we7u * Makefile.am: Added the xastir/maps/GPS/ directory to the directories created during install. This directory is required for GPSMan to operate with Xastir properly. 2003-03-26 11:28 we7u * src/main.c: Updating about message to contain 2003 instead of 2002. 2003-03-26 10:41 we7u * src/main.c: Changing the method of parameter passing between GPS_operations() and gps_transfer_thread() in order to solve a user's problem. 2003-03-26 10:00 we7u * src/main.c: A few minor tweaks to GPS_operations and gps_transfer_thread, mostly to debug problems with parameter passing. 2003-03-24 15:28 we7u * README.win32: One more note to get libgeotiff working on Cygwin. Must rename the libtiff dll's in order to be compatible with the version of libgeotiff. 2003-03-24 13:36 we7u * README.win32: Removed warning note above the geotiff instructions: It is working again with the current instructions. 2003-03-24 12:52 we7u * README.win32: Some minor additions to the libproj install that helps the libgeotiff install to complete. 2003-03-23 18:46 we7u * README.win32: Added more notes to clarify places where some users were tripping up. 2003-03-23 18:45 we7u * README.1ST: Added asterisks next to the note about the Shapefile world map. 2003-03-22 00:28 we7u * src/interface.h: Reversed order of arguments for socklen_t typedef. 2003-03-21 16:50 we7u * README.win32: Taking out some old notes that aren't applicable anymore. 2003-03-21 16:49 jtwilley * configure.ac: Forgot to actually include -lax25 when detecting it 2003-03-21 16:48 we7u * README.win32: Another minor Cygwin tweak. 2003-03-21 16:28 we7u * src/util.c: Another minor Cygwin tweak. 2003-03-21 16:25 we7u * README.win32: More Cygwin tweaks. 2003-03-21 16:02 jtwilley * src/: interface.c, interface_gui.c: Changed references of HAVE_AX25 to HAVE_LIBAX25 to match new configure. 2003-03-21 12:44 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Removing the "Are You Sure?" button on exit (to keep peace with the other war-monger developers ;-) 2003-03-20 14:29 jtwilley * acinclude.m4, configure.ac, src/hostname.c, src/interface.c, src/interface.h, src/main.c, src/maps.c, src/maps.h, src/util.c, src/wx_gui.c, src/xa_config.c: Massive configuration overhaul -- moving functions from configure.ac to acinclude.m4 and beginning to streamline configure.ac, with attendant changes in various source files. 2003-03-18 14:59 we7u * src/: db.c, interface_gui.c, xastir.h: Tweaks to enable testing of RELAY digipeat with serial KISS TNC's. One define in xastir.h needs to be changed in order to enable it. 2003-03-18 14:39 francais1 * src/: db.c, interface_gui.c: Allowed selection of AX25 relay digipeat 2003-03-18 14:28 we7u * src/: gps.c, gps.h, main.c: Changing how GPS status messages are done. 2003-03-18 13:50 we7u * src/: gps.c, interface.c, main.c, xastir.h: Fixes for the GPS high-CPU usage. We now save GPRMC and GPGGA strings in global variables, dropping all other strings. At the GPS Check Interval, we decode up to two strings that we have saved most recently. 2003-03-17 14:58 we7u * configure.ac: Another ImageMagick tweak for Cygwin. 2003-03-17 12:39 we7u * configure.ac: Trying another small tweak for Cygwin. It's not currently recognizing the ImageMagick libraries installed in /usr/lib. 2003-03-16 23:29 we7u * src/main.c: We now call reload_object_item() after we clear all stations. This keeps locally-owned objects on our screen and in our in-memory database. 2003-03-16 21:54 we7u * README.1ST: Added a Festival note from J. Lance Cotton. 2003-03-14 21:59 we7u * src/main.c: Fixing an errand comment on a #endif statement. 2003-03-14 17:01 we7u * README.win32: Tweaking the Cygwin/ImageMagick notes. 2003-03-14 16:41 we7u * README.win32: More optional library notes. Trying to work through the problems with the latest ImageMagick/proj.4/libgeotiff libraries. 2003-03-14 13:10 we7u * README.win32: More notes about problems with geotiff maps and current Cygwin versions. 2003-03-14 11:51 we7u * README.win32: Adding more notes about the impure_ptr problem. 2003-03-14 11:43 we7u * README.win32: Changing the version of libgeotiff called out. 2003-03-14 11:41 we7u * README.1ST: Removed Cygwin info. It now tells Windows users to refer to the README.win32 file instead. 2003-03-13 10:29 we7u * README.1ST: Added a bit to the GPSMan notes. 2003-03-12 20:43 we7u * README.1ST: Minor fixes to the gpsman instructions. 2003-03-12 13:20 francais1 * src/interface.c: Fix to remove the star before the ax25_aton_entry call because it would call it a bad callsign. 2003-03-12 11:23 we7u * src/main.c, configure.ac, README.1ST: Added support for the production version of GPSMan. Have at it! 2003-03-11 17:02 we7u * README.win32: Minor cygwin changes. 2003-03-11 16:43 we7u * README.1ST, README.win32: Slight changes to Cygwin instructions. 2003-03-11 16:26 we7u * README.win32: Adding a Cygwin/Win32 specific README file to make it easier for Windows users to get up and running with Xastir. Initial check-in. 2003-03-07 17:31 we7u * README.1ST: More Cygwin changes. 2003-03-07 17:25 we7u * README.1ST: More Cygwin changes. 2003-03-07 16:36 we7u * README.1ST: More Cygwin notes. 2003-03-07 16:15 we7u * README.1ST: Correcting some Cygwin libproj notes. 2003-03-07 14:07 we7u * README.1ST: Minor change to library revision number for Cygwin. 2003-03-07 14:02 we7u * README.1ST: More Cygwin notes. 2003-03-07 13:46 we7u * README.1ST: Added notes regarding "make install-strip" option. 2003-03-07 13:10 we7u * configure.ac: libproj/libgeotiff fixes for Cygwin. 2003-03-07 11:07 we7u * README.1ST: Tweaked the comments about creating the terraserver .geo file. 2003-03-07 11:03 we7u * src/maps.c: Starting to add shapefile creation functions. Intend to use these to save station trails to map files eventually. 2003-03-06 14:41 we7u * configure.ac, src/main.c: Changed some comments. 2003-03-06 14:21 we7u * README.1ST: Added initial notes regarding gpsmanshp and GPSMan. 2003-03-06 14:04 we7u * configure.ac: Adding checks for GPSman and gpsmanshp.so. Not ready for prime-time yet, but should be soon. 2003-03-06 10:47 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/gps.c, src/interface.c, src/main.c: Added a popup when GPS data goes stale. We now allow one posit when GPS interfaces are first enabled before we consider the data stale and disable transmit of My Position. Removed the statusline messages that happen when we successfully decode GPRMC or GPGGA sentences: They were causing too much CPU time on Yellow Dog Linux (powerPC). 2003-03-05 16:39 we7u * src/interface.c: Fix the case where someone plays with a GPS interface and then turns it off again. Before this change, posits would be disabled unless GPS interface was re-enabled that had good data coming in, or unless the user restarted Xastir. 2003-03-05 15:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c: Language strings for GPS operations. Added more colors. Create default time/date filename if no filename given. 2003-03-05 14:04 we7u * src/main.c: Added a UI to the gps transfer code. Not enabled yet for users. 2003-03-05 13:54 we7u * src/maps.c: Minor changes to new GPS stuff. 2003-03-04 16:51 we7u * src/maps.c: Removing the color portion of the filename for GPS map labels. 2003-03-04 16:49 we7u * src/main.c: Changed a few comments. 2003-03-04 16:34 we7u * src/main.c: Minor updates to new GPS stuff. Not enabled for normal use yet. 2003-03-04 15:55 we7u * src/main.c: Converted to switch statement in new GPS transfer routines. Can now because it's an int. 2003-03-04 15:42 we7u * src/main.c: Separated the GPS transfer functions into their own thread. GPS transfers now run concurrently with the other threads, updating the map view when they complete. 2003-03-04 12:34 we7u * README.1ST: More Cygwin libproj and libgeotiff notes. 2003-03-04 11:13 we7u * README.1ST: Correcting spelling. 2003-03-04 10:51 we7u * src/: main.c, maps.c: More experimental GPSMan stuff. Not ready for release yet. 2003-02-28 17:52 we7u * README.1ST: More Cygwin libgeotiff notes. 2003-02-28 17:48 we7u * src/maps.c: Changing the line style for GPS info. 2003-02-28 17:38 we7u * README.1ST: More Cygwin notes. 2003-02-28 17:31 we7u * README.1ST: More Cygwin stuff: libgeotiff. 2003-02-28 16:30 we7u * src/maps.c: Rotating the labels to horizontal for GPS maps. Changing orange to lighter orange. 2003-02-28 16:20 we7u * src/maps.c: Chopping off the ".shp" portion of the GPS labels. 2003-02-28 16:00 we7u * src/maps.c: More label/color stuff for gps maps. 2003-02-28 15:48 we7u * src/maps.c: Adding labels to the GPS tracks/routes. 2003-02-28 13:39 we7u * src/maps.c: More GPS stuff. Not enabled yet. 2003-02-28 13:19 we7u * src/main.c: Turning off the new GPS stuff. 2003-02-28 12:48 we7u * src/main.c: More gps transfer stuff. Not ready for prime-time yet. 2003-02-27 16:40 we7u * configure.ac: Reversing the order of lib checking for libproj and libgeotiff. 2003-02-27 16:30 jtwilley * ChangeLog, configure.ac: Cleaned up XASTIR_TOCALL in configure.ac to no longer require SHORT_VERSION 2003-02-27 15:52 we7u * README.1ST: More Cygwin notes. libgeotiff stuff. 2003-02-27 15:31 we7u * README.1ST: More changes for Cygwin. Installation of Proj.4 now complete and documented. I'm still working on installation of libgeotiff. 2003-02-27 12:53 we7u * src/main.c: Preliminary support for GPSMan: Downloads track, creates Shapefile map, auto-imports and displays said map in Xastir. Requires pre-release GPSMan plus gpsmanshp.tgz file installed. Also requires that the "WE7U" define at the top of main.c be defined to put the new code into operation. 2003-02-27 09:39 we7u * configure.ac: Added a tweak to look for the Shapelib include file in subdirectory _not_ ending in /libshp/ 2003-02-26 10:09 we7u * src/: alert.c, alert.h: Removing dead code. Changed/added a few comments and debug messages. Removed prototypes from alert.h that aren't being used. 2003-02-26 09:38 we7u * configure.ac: Taking out extra X11 include path that was just added for linux recently. 2003-02-25 17:55 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c, db.h: Fixes for bulletin popups. 2003-02-25 13:45 we7u * src/db.c: Changes to comments only. 2003-02-25 12:50 we7u * src/: alert.c, alert.h, db.c, maps.c: Changing NWS weather alerts so that they are no longer stored in the message database and rescanned periodically. They now go straight to the alert_list. 2003-02-25 10:04 we7u * src/: bulletin_gui.c, bulletin_gui.h: Fixing another bug having to do with zero-distance bulletins popping up when the user settings tell Xastir not to. 2003-02-25 09:31 we7u * src/main.c: Added Map Display Bookmarks button to right-click mouse menu. 2003-02-24 23:03 we7u * configure.ac: Adding a path for Linux configure to help find Motif include files on some systems. 2003-02-24 22:30 kd6zwr * ChangeLog, src/db.c: Made my_station_gps_change update sec_heard to fix DR of my station. 2003-02-24 16:41 we7u * configure.ac: Adding /usr/X11R6/include/Xm as an include path for Motif/Lesstif for Slackware 8.1. May need additional things in order to link to the library as well. 2003-02-24 16:29 we7u * src/db.c: Added more comments. 2003-02-24 16:26 we7u * src/db.c: Added some comments. 2003-02-24 15:40 we7u * src/maps.c: Getting rid of unneeded code. 2003-02-24 15:40 we7u * src/db.c: Added some comments. 2003-02-24 15:26 we7u * src/: db.c, maps.c, maps.h: Starting to change the weather alert code to make it independent of the message database. Part-way to that goal. This version just relocates the weather alerts scan of the message database into the db.c code at the point where we received the alert. The next step is to just throw the alert onto the alert_list and skip the message database portion altogether. This current code appears to still be fully functional w.r.t. weather alerts. 2003-02-24 14:45 we7u * src/maps.c: Re-org of a bit of code w.r.t. weather alerts (no major changes though). Lots of comment changes. 2003-02-24 13:58 we7u * src/draw_symbols.c: Tweaks to watch boxes for Gerry Wheeler. 2003-02-24 13:35 we7u * src/maps.c: Removed dead code. Changed some comments. 2003-02-24 13:04 we7u * src/: alert.c, maps.c: Changes to comments only. 2003-02-24 12:46 we7u * src/: alert.c, main.c: Setting the proper variables so that a screen update happens in a timely manner after WX alerts expire. 2003-02-24 12:23 we7u * src/: alert.c, main.c, maps.c, wx_gui.c: We now expire wx alerts only in main.c:UpdateTime(), and only every 60 seconds. If any are expired, it schedules a screen update. 2003-02-24 11:41 we7u * src/: alert.c, alert.h, maps.c: More minor work on wx alerts. 2003-02-24 11:28 jtwilley * ChangeLog: Added entry for change made to src/interface.c 2003-02-24 11:25 jtwilley * src/interface.c: Changed timeouts to 100 milliseconds from 100 microseconds. 2003-02-24 10:25 we7u * src/: alert.c, alert.h, maps.c, wx_gui.c, xa_config.c: Moved alert expiration code into common alert_expire() function. 2003-02-23 08:58 we7u * src/alert.c: Making an int more global. Needed for wx alert expire code elsewhere. 2003-02-23 08:56 we7u * src/alert.h: Adding an extern int that other code needs now for wx alert expiration. 2003-02-23 08:48 we7u * src/alert.c: Changed a comment. 2003-02-23 08:44 we7u * src/maps.c: Another tweak to wx alert expiration. 2003-02-23 08:40 we7u * src/wx_gui.c: Another small tweak to expiration for wx alerts. 2003-02-23 08:37 we7u * src/util.c: Tweaking the alert expiration stuff some more. 2003-02-23 01:52 we7u * src/: alert.c, alert.h, maps.c, util.c, wx_gui.c: Fixed incorrect expiration times for weather alerts. Proper local expiration time is now computed and stored. View->WX Alerts dialog appears to update correctly as alerts come and go. Weather alert slots get re-used by new alerts properly. We might have incorrect expiration times for weather alerts twice a year when daylight savings time switches though. 2003-02-22 08:41 n0vh * src/main.c: Fixed the intensity slider since 0 was causing xastir to crash. Set the minimum to something reasonable. 2003-02-21 17:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a new button the Stations menu: Reload Object/Item History. 2003-02-21 16:58 we7u * src/sound.c: Adding some spacing. No code changes. 2003-02-21 15:53 we7u * src/: alert.c, alert.h, maps.c, wx_gui.c: Fixes to weather alerts. Should re-use weather alert slots in the array now, and should expire things properly as well. 2003-02-21 12:46 we7u * configure.ac: Modifying the error messages to make them consistent and provide useful info to the user. 2003-02-21 11:47 we7u * configure.ac: Taking out some commented-out code and some irrelevant comments. 2003-02-20 21:10 n0vh * src/main.c: Logging indicator now changes color to highlight that it's logging. 2003-02-20 20:31 n0vh * src/: main.c, main.h: Added a status text box at the bottom of the window that indicates that xastir is logging to disk. 2003-02-20 15:31 we7u * src/bulletin_gui.c: A few fixes for bulletins. Also added a callback for the togglebutton on the View->Bulletins dialog. 2003-02-20 14:34 we7u * src/db.c: Added a debugging message. 2003-02-20 14:18 we7u * src/main.c: Changing the "Test" function a bit. 2003-02-20 12:00 we7u * src/bulletin_gui.c: Changing time between receiving a new bulletin and checking whether it is within our range: From 15 seconds to 60 seconds. This actually delays our getting notice of each new bulletin, but helps to prevent popping up bulletins when a bulletin comes in and then a posit comes in later for that station (putting that station outside our range). The cause of the bulletin window popping up appears to be these inside-our-range/ outside-our-range-when-a-posit-comes-in bulletins. 2003-02-20 11:32 we7u * src/maps.c: Changed/added some comments. No code changes. 2003-02-20 10:31 we7u * configure.ac: Added more search paths for Solaris 8/9 binaries. 2003-02-20 02:10 we7u * bootstrap.sh: Added status messages. 2003-02-20 01:51 we7u * src/: alert.c, bulletin_gui.c, db.c, draw_symbols.c, gps.c, hostname.c, interface.c, interface_gui.c, list_gui.c, locate_gui.c, main.c, maps.c, popup_gui.c, rac_data.c, rotated.c, snprintf.c, track_gui.c, util.c, view_message_gui.c, wx_gui.c, xa_config.c: Added comments. 2003-02-20 01:45 we7u * src/: bulletin_gui.h, db.h, draw_symbols.h, festival.h, gps.h, hostname.h, igate.h, list_gui.h, main.h, maps.h, rotated.h, snprintf.h, track_gui.h, util.h, wx.h, xastir.h: Added comments. 2003-02-20 01:00 we7u * src/: maps.c, track_gui.c, util.c: More fixes for calling external programs. 2003-02-20 00:33 we7u * src/: maps.c, track_gui.c, util.c: Checking for existence of external programs before trying to invoke them. If they don't exist, we call "echo" instead (relatively harmless). 2003-02-19 23:56 we7u * src/: alert.c, wx_gui.c: Added code to clear out expired weather alerts so that later alerts can use that slot. Also caused the View->Weather Alerts dialog to skip empty slots. 2003-02-19 22:47 we7u * bootstrap.sh: Separating out the -a and -c params on the automake line, for Cygwin. 2003-02-19 17:22 francais1 * configure.ac: A little tweakage 2003-02-19 17:13 we7u * src/: maps.c, util.c: Changing code to use new paths computed via configure. 2003-02-19 17:07 we7u * configure.ac: Changing the quoting on some of the newer code I just added. 2003-02-19 16:46 we7u * configure.ac: Removing the "cat" checks as we don't use it currently. 2003-02-19 16:31 we7u * configure.ac: Path discovery for more utilities that we use from within Xastir. 2003-02-19 15:43 we7u * configure.ac, src/interface.c, src/maps.c, src/track_gui.c: Removing __CYGWIN__ #ifdef's. 2003-02-19 14:40 we7u * configure.ac, src/util.c: Getting rid of __FreeBSD__ #ifdef, replacing it with HAVE_GMTOFF test/ variable/#ifdef. 2003-02-19 13:55 we7u * configure.ac, src/gps.c, src/interface_gui.c: Getting rid of OS-specific #ifdef's related to settimeofday() function, where the GPS time can be used to set system time. 2003-02-19 13:15 we7u * configure.ac: Streamlined the ImageMagick checks. Added more comments. Temporarily commented out the "-Ldir -llibrary" MacOSX/ImagMagick line which is probably unnecessary. Will add it back if tests on MacOSX show it to be required. 2003-02-19 12:44 we7u * configure.ac: Streamlining geotiff and libintl code. Added comments here and there. 2003-02-19 11:44 we7u * configure.ac: Streamlining the X11 library checking code. 2003-02-19 10:51 we7u * configure.ac: A bit of housecleaning. Pretty'ing up the warning/error messages. Re-ordering the operating system-specific areas. 2003-02-19 10:00 we7u * configure.ac: Making all of the MacOSX comments have exactly the same spelling/case. Easier to grep for in the future. No code changes. 2003-02-19 09:35 we7u * configure.ac: MacOSX/ImageMagick fix. 2003-02-18 22:20 we7u * configure.ac: Removing two brackets that give Mandrake linux fits. 2003-02-18 14:11 kg4ijb * Makefile.am: bzip mod didn't propagate 2003-02-18 14:05 kg4ijb * src/Makefile.am: yikes!, automake_option was my bad, removed. 2003-02-18 13:33 we7u * src/Makefile.am: Moving the AUTOMAKE_OPTIONS to before the line continuation char. It doesn't work where it was put. Is it necessary? Should it be somewhere else in the file? 2003-02-18 13:16 we7u * configure.ac: Added some debugging info back in. Commented out so a typical user won't be bothered by it. 2003-02-18 12:49 kg4ijb * callpass/Makefile.am, config/Makefile.am, help/Makefile.am, symbols/Makefile.am, m4/Makefile.am, scripts/Makefile.am, src/Makefile.am: ID message 2003-02-18 12:44 kg4ijb * configure.ac: cleaned output and removed all libtool dependancies 2003-02-18 12:43 kg4ijb * Makefile.am: removed unecessary automake_options 2003-02-18 12:04 we7u * scripts/Makefile.am: Adding missing scripts. Fixing things so that "make dist" works properly. 2003-02-18 11:56 we7u * bootstrap.sh: Copying the files into the directory instead of making symlinks. 2003-02-18 11:36 we7u * Makefile.am, configure.ac: More fixes to allow "make dest" to work. 2003-02-18 11:04 we7u * Makefile.am: Adding a forgotten subdirectory that makes "make dist" fail if not present. 2003-02-18 10:57 we7u * Makefile.am: Removing the lt* files. 2003-02-18 09:34 we7u * src/: main.c, xa_config.c: Changing range for Tigermap intensity from 50-100% to 0-100%. 2003-02-18 08:23 we7u * configure.ac: Bumping revision up to 1.1.4 2003-02-16 22:53 we7u * README.1ST: Added a few notes after the lines calling out bootstrap.sh. 2003-02-16 21:25 we7u * configure.ac: Another tweak for ImageMagick on MacOSX. 2003-02-16 09:37 we7u * README.1ST: Added a note to the MacOSX section: Installing Xastir into /sw. 2003-02-16 09:30 we7u * configure.ac: Another ImageMagick fix for MacOSX. 2003-02-16 01:49 we7u * README.1ST: Added some more Solaris notes, courtesy of Chris Bell. 2003-02-16 01:35 we7u * configure.ac: Added check for sched_yield() function in librt (needed for Solaris). 2003-02-15 15:44 we7u * src/util.c: Changing back to a __solaris__ ifdef for now. 2003-02-15 14:35 we7u * configure.ac: Another fix for ImageMagick on MacOSX. 2003-02-15 14:30 we7u * configure.ac, src/hostname.c, src/interface.c, src/interface_gui.c, src/main.c, src/maps.c, src/snprintf.h, src/util.c, src/xa_config.c: Removing a lot of OS-specific #ifdef's, changing to function-specific #ifdef's instead. 2003-02-15 12:10 we7u * src/xa_config.c: Temporarily removing the CYGWIN #ifdef, to see if we have the proper configure.ac support for Cygwin now. 2003-02-15 12:09 we7u * src/gps.c: Cygwin change. Getting rid of CYGWIN tag and replacing with config.h stuff. 2003-02-15 11:39 we7u * configure.ac, src/gps.c, src/interface.c: More MacOSX fixes. Using variables in config.h now instead of #ifdef MACOSX. 2003-02-15 10:45 we7u * src/: gps.c, interface.c: Changing __MacOSX__ tag to MACOSX. 2003-02-15 09:59 we7u * configure.ac, src/gps.c, src/hostname.c, src/interface.c, src/main.c, src/maps.c, src/snprintf.h, src/util.c: MacOSX and Solaris fixes related to the new Autoconf stuff. 2003-02-14 19:55 kg4ijb * configure.ac: *BSD CFLAGS and pthread check 2003-02-14 17:15 we7u * configure.ac: Fix for finding Motif libraries on Solaris. 2003-02-14 16:11 we7u * configure.ac: Another MacOSX change. 2003-02-14 15:13 we7u * configure.ac: Another fix for MacOSX regarding Xm/Xm.h 2003-02-14 14:47 we7u * README.1ST: Cygwin/fvwm2 window manager instructions. 2003-02-14 13:55 we7u * configure.ac: Changing the old ImageMagick warning message slightly. 2003-02-14 13:39 we7u * configure.ac: Mac OSX/Fink ImageMagick fixes. Also moved the old version warning to the end of that section. 2003-02-14 12:59 we7u * configure.ac: Mac OSX/Fink mods to help find Shapelib. 2003-02-14 10:30 we7u * README.1ST: Added cvs update note to Cygwin section. 2003-02-14 10:15 we7u * configure.ac: Tweaking some comments. 2003-02-14 10:09 we7u * configure.ac: Adding an RCS tag so we can track revisions. 2003-02-14 09:50 kg4ijb * configure.ac: Fixed the tocall problem. Versioning only needs to be done in ac_init 2003-02-14 01:34 we7u * README.1ST: More Cygwin changes. 2003-02-13 15:39 we7u * README.1ST: More Cygwin updates. 2003-02-13 15:22 we7u * README.1ST: Updated to reflect new configure.ac stuff. 2003-02-13 14:46 we7u * configure.ac: Fixing the TOCALL. The "APX$SHORT_VERSION" thing doesn't work. :-( 2003-02-13 13:42 we7u * src/: interface.c, interface.h, interface_gui.c: Added "Networked Database" GUI code for Brenda Wallace to have as a front-end for her database code. 2003-02-13 13:40 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Adding strings for future networked database GUI. 2003-02-13 13:35 kg4ijb * ChangeLog: * bootstrap.sh - routine to rebuild autostuff environment 2003-02-13 13:31 kg4ijb * bootstrap.sh: builds necessary autostuff files in appropriate order 2003-02-13 13:12 kg4ijb * ChangeLog: [no log message] 2003-02-13 13:05 kg4ijb * symbols/Makefile.in: removed, locally generated 2003-02-13 13:00 kg4ijb * src/Makefile.in, scripts/Makefile.in, m4/Makefile.in, help/Makefile.in, config/Makefile.in, callpass/Makefile.in: removed files that are generated locally 2003-02-13 12:48 kg4ijb * ChangeLog, Makefile.in: removed remote files that are generated locally 2003-02-13 12:38 kg4ijb * acconfig.h, acinclude.m4: Removed old configure files and added new ac 2003-02-13 12:33 kg4ijb * configure.ac: * Removed old configure files and added new ac 2003-02-13 12:29 kg4ijb * config.guess, config.h.in, config.sub, configure, configure.in, install-sh, ltconfig, ltmain.sh, missing, mkinstalldirs: make way for new configure 2003-02-13 09:24 we7u * README.1ST: More changes to the Cygwin notes. 2003-02-12 15:00 we7u * src/: main.c, track_gui.c: Fixing some errant string lengths on some XtVaTypedArg calls. 2003-02-12 14:31 we7u * README.1ST: Slight changes to Cygwin notes. 2003-02-11 20:18 we7u * src/main.c: Correcting a slight misspelling. 2003-02-11 11:14 we7u * README.1ST: More CVS/Cygwin info. 2003-02-10 15:42 we7u * README.1ST: Changes to the Shapelib portion of the Cygwin notes. 2003-02-10 14:29 we7u * acinclude.m4: Formatting for better readability. No code changes. 2003-02-10 13:54 we7u * acinclude.m4, config.h.in, configure: Adding more error output for Shapelib file searches during configure. 2003-02-10 13:27 we7u * configure, configure.in: Small change to wording of Cygwin warning message. 2003-02-10 13:17 we7u * acconfig.h, config.h.in, configure, configure.in: Starting to add Cygwin support to autotools. 2003-02-10 12:20 we7u * src/db.c: Fix for 3rd-party packets being marked as local stations in Xastir. We now check the "third-party" variable at that stage of the code. 2003-02-10 10:54 we7u * src/db.c: A fix by Reuven w.r.t. setting the messaging-capable flag for the case of '@' packets. Curt added some run-time debug code for finding own object deletions that'll be in effect until we're sure the problem has gone away. 2003-02-10 03:26 we7u * src/maps.c: Adding Map Labels On/Off capability to pocketAPRS maps. 2003-02-07 17:35 we7u * README.1ST: Reformatted some Cygwin notes. 2003-02-07 17:33 we7u * README.1ST: More Cygwin. 2003-02-07 17:33 we7u * README.1ST: More Cygwin stuff. 2003-02-07 16:29 we7u * README.1ST: More Cygwin note changes. 2003-02-07 09:31 we7u * README.1ST: Updated Cygwin information regarding CVS and extra map libraries. 2003-02-06 12:29 we7u * README.1ST: Added general notes about how to configure/compile/install Xastir. Several people have mentioned to me that it's not clear how to go about this. 2003-02-06 11:45 we7u * src/: maps.c, track_gui.c: Specifying path to wget directly only on Cygwin systems. 2003-02-06 11:28 we7u * README.1ST: Adding notes about Cygwin/ImageMagick, which works by the way! 2003-02-06 10:11 we7u * README.1ST: Another Cygwin note. 2003-02-06 09:36 we7u * README.1ST: Tweaking the Cygwin/CVS note. 2003-02-05 23:57 we7u * src/: maps.c, track_gui.c: Adding a path for the "wget" executable. Hard-coding it to /usr/bin right now. 2003-02-05 17:13 we7u * README.1ST: More Cygwin stuff. 2003-02-05 14:57 we7u * README.1ST: Added Cygwin/Shapelib notes. 2003-02-05 11:38 we7u * README.1ST: More Cygwin. 2003-02-05 11:19 we7u * README.1ST: More Cygwin notes. 2003-02-05 10:33 we7u * README.1ST: More Cygwin notes. 2003-02-05 09:34 we7u * README.1ST: Added notes about Xastir on Cygwin. 2003-02-04 22:14 rzg * help/help-English.dat: Some updates to helpfile for config|timing and filtering. 2003-02-04 17:02 we7u * src/gps.c: Adding some more CYGWIN flags around variable definitions. This part of the code isn't used under Cygwin. 2003-02-04 11:30 we7u * src/interface.c: Changing default paths from "RELAY,WIDE" to "WIDE,WIDE2-2". 2003-02-04 00:43 we7u * src/maps.c: Getting rid of warning output that really isn't all that useful. 2003-02-04 00:06 we7u * src/main.c: Added zoom in/out buttons to toolbar. 2003-02-03 20:08 jtwilley * src/: alert.c, bulletin_gui.c, color.c, db.c, draw_symbols.c, fcc_data.c, gps.c, hostname.c, interface.c, interface_gui.c, lang.c, list_gui.c, locate_gui.c, location_gui.c, maps.c, messages.c, messages_gui.c, popup_gui.c, rac_data.c, rotated.c, sound.c, track_gui.c, util.c, wx.c, wx_gui.c, xa_config.c: Changed all printf's to write to stderr instead of stdout 2003-02-03 19:52 jtwilley * src/: igate.c, main.c: Changed all printf's to write to stderr instead of stdout 2003-02-03 17:19 we7u * src/igate.c: Changes to formatting and comments only. No code changes. 2003-02-03 17:03 we7u * src/main.c: Re-ordered the timing params on the Configure-Timing dialog to make more sense. 2003-02-03 16:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changing the label for the Configure->Timing dialog. 2003-02-03 16:19 we7u * src/main.c: Added another slider for setting the station removal time from the database. 2003-02-03 14:29 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/igate.c, src/main.c: Separated the timing sliders from the Configure->Defaults dialog, making a new Configure->Timing dialog out of them. 2003-02-03 13:12 we7u * src/main.c: Changing max posit rate to every 60 minutes instead of every 45. 2003-02-03 12:56 we7u * src/main.c: Added separate object/item TX timer and associated slider in Configure->Defaults. Now people with WX stations that want to transmit every 5 minutes can set their object/item TX rate separately. Also changed the posit rate slider to go from 0.5 to 45 minutes (30 seconds to 45 minutes). 2003-02-03 12:21 we7u * src/: db.c, main.c, main.h, util.c, xa_config.c: Separate TX timer for objects and items. New slider in Configure->Defaults for it as well. Probably needs more testing to assure that it's working correctly. 2003-02-03 11:38 we7u * src/: db.c, db.h, main.c, main.h: Added a slider for setting the dead-reckoning timeout value. 2003-02-03 11:21 we7u * src/main.c: Changed Configure->Defaults timing values to sliders. Makes the code much simpler plus gives the users more options in setting the values. 2003-02-02 23:21 jtwilley * acinclude.m4, config.guess, config.sub, missing, mkinstalldirs: Modified files to work with autoconf 2.53. There are some minor bugs still, but they are being worked on. 2003-02-02 23:19 jtwilley * COPYING: Changed example to be Y2K-compliant. 2003-02-02 23:19 jtwilley * ChangeLog: Updated autoconf files for new version. Fixed COPYING Y2K distraction. 2003-02-02 21:49 we7u * src/: db.c, db.h, draw_symbols.c, xa_config.c: Added DEAD_RECKONING_TIMEOUT value to xastir.cnf. The function is no longer tied to the ghosting interval. 2003-02-02 21:05 we7u * src/: db.c, db.h, xa_config.c: Added a global variable st_direct_timeout which is saved in the config file. This specifies the timeout value for the ST_DIRECT bit. 2003-02-02 08:42 we7u * src/db.c: Added comments around the ST_DIRECT bit setting/clearing code. Change the ST_DIRECT bit timeout from 1 minute to 1 hour. This gives stations that transmit only every 30 minutes (common) a chance to be seen as an ST_DIRECT station. As the comments show in that section of code, that timeout value will in the future probably change into a global variable that is set within the config file. 2003-02-01 23:22 we7u * src/db.c: Fixed a pointer-to-integer comparison (compiler warning). Reformatted the code per Xastir project specs. 2003-02-01 20:45 jtwilley * ChangeLog: Updated ChangeLog for solution for request ID #678322 2003-02-01 20:42 jtwilley * src/db.h: Added direct_heard variable to station data structure. This variable is set each time a direct packet is received from a station. 2003-02-01 20:40 jtwilley * src/db.c: Removed old support for direct stations and added new complete direct station support. Paths with WIDE and TRACE entries of all kinds are properly checked for directness. 2003-02-01 02:14 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h, src/interface.c, src/main.c, src/util.c: Partial fixes for GUI lockups due to lots of locally-controlled objects: Moved delays in interface routine so that they'd only take effect if the interface was up and transmit was enabled (both global and per-interface transmit controls). Added a statusline() the lets us know when we're retransmitting our objects/items. Delayed transmit of our items for 30 seconds after initial startup. We will still have delays each POSIT_interval when our objects get sent: Something like 2 seconds * number of up/tx-enabled interfaces * number of objects. 2003-01-31 17:04 we7u * src/draw_symbols.c: Added code to prevent wind barbs from getting drawn if their position is off-screen. 2003-01-30 17:17 we7u * src/db.c: Adding code to assure that locally-controlled objects don't expire. 2003-01-30 16:15 we7u * src/interface_gui.c: Reducing the length of the filtering input box to 190. 2003-01-30 14:48 we7u * src/interface.c: Checking for NULL pointer for filter_string. 2003-01-30 14:09 we7u * src/: interface_gui.c, interface.c: Changed to sending empty string instead of NULL if filter_string not specified when calling add_device(). 2003-01-30 13:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface.h, src/interface.c, src/interface_gui.c, src/xa_config.c: Implemented a user interface for specifying filter parameters for internet servers. 2003-01-30 11:48 kd6zwr * src/main.c: commented out some unfinished code that slipped out... 2003-01-30 11:45 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c, src/xastir.h: added toggle for skipping map index on startup, moved index-now button to map pulldown. 2003-01-29 16:12 we7u * src/db.c: Changed comments. No code changes. 2003-01-29 14:08 we7u * src/igate.c: Implemented passcode checking before sending packets to each inet server. 2003-01-29 12:14 we7u * src/: util.c, util.h: Adding hashing functions into the code. This will be used soon to verify igate transmit permissions. 2003-01-29 10:17 we7u * src/maps.c: Tweaking the Locate Map Feature code to handle GNIS files that aren't formatted correctly (missing double quotes on fields). 2003-01-28 13:12 we7u * symbols/symbols.dat: Made the 'X' smaller on the laptop. 2003-01-28 13:11 we7u * symbols/symbols.dat: Added laptop computer. Put X-windows on both of the new computers. ;-) 2003-01-28 13:05 we7u * symbols/symbols.dat: Created desktop computer symbol. 2003-01-28 12:49 we7u * symbols/symbols.dat: A better helicopter. Easier to recognize both with maps and without. 2003-01-27 23:51 we7u * symbols/symbols.dat: Second attempt at a Skywarn symbol. 2003-01-27 23:34 we7u * symbols/symbols.dat: Initial attempt at a Skywarn symbol. 2003-01-27 23:07 we7u * symbols/symbols.dat: Added blank symbols for /L, /l, and \y (desktop computer, laptop computer, Skywarn symbols). 2003-01-27 15:58 we7u * src/main.c: Tweaking the update symbol portion of Create Object/Item dialog: Invalid overlays won't update the symbol in the dialog. 2003-01-27 15:18 we7u * src/: db.c, main.c: Fixing the compressed posit overlay problems and the illegal overlay problems. 2003-01-27 13:15 we7u * src/: db.c, main.c: Fix for modify object/item dialog: Overlay characters. 2003-01-27 13:01 francais1 * symbols/symbols.dat: Shrunk box back down a bit 2003-01-27 12:08 we7u * src/db.c: Fixed Create_object_item_tx_string() such that the overlay characters for objects/items don't get lost on retransmit. 2003-01-27 10:48 we7u * symbols/symbols.dat: Made white square box larger and gave it single-pixel border. 2003-01-27 10:37 we7u * symbols/symbols.dat: Made the white circle symbol (used with overlays) bigger. 2003-01-27 00:53 we7u * symbols/symbols.dat: Changed the overlay circle (alternate table). Made it a bit bigger so that the overlayed characters are easier to read. 2003-01-26 23:13 we7u * symbols/symbols.dat: Added Incident Command Post symbol at "q" position. Square split diagonally, half white/half green. 2003-01-25 20:09 we7u * src/list_gui.c: View->Weather Stations: Didn't convert barometric pressure to inches mercury when english units selected. Now it does. 2003-01-23 20:57 we7u * src/xa_config.c: Correcting error messages for get_int() and get_long() functions. 2003-01-23 20:49 we7u * src/xa_config.c: Tweaked lower limit in xa_config.c for TIGERMAP_INTENSITY from 60 to 50. This was causing user problems, and should have been 50 to begin with. 2003-01-23 16:38 we7u * help/: help-Dutch.dat, help-English.dat, help-French.dat, help-German.dat, help-Italian.dat, help-Portuguese.dat, help-Spanish.dat: Updated copyright notice. 2003-01-23 16:34 we7u * src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/snprintf.c, src/snprintf.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/location_gui.c, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/db.c, src/db.h, AUTHORS, README, xastir.1, callpass/callpass.c, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, symbols/symbols.dat: Updating copyright notice. 2003-01-23 14:10 rzg * help/help-English.dat: Updates for most recent stations menu changes, copyright year. 2003-01-23 11:42 we7u * src/igate.c: Implemented NOGATE and RFONLY options in igate.c. If either of these are seen, the packet won't be gated into the internet. 2003-01-23 11:17 francais1 * src/main.c: Fixed up overlooking of old_data sensitiveness Removed unnecessary code 2003-01-22 17:21 francais1 * src/: main.h, main.c, db.c, xa_config.c: Added display selection for wind barb. No more storing 0,1,2 in config, split out to match the structs. 2003-01-22 17:18 francais1 * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added strings for change to weather display selection because I added wind barb display selection. 2003-01-22 12:07 we7u * src/xa_config.c: We now save/restore the filter togglebutton settings. 2003-01-20 18:12 francais1 * src/db.c: Fixed dead reckoning disappears when course or speed display disabled bug. 2003-01-18 17:09 rzg * help/help-English.dat: Updated for stations menu changes. 2003-01-17 10:28 francais1 * src/xa_config.c: Storing of speed/short and weather/temp_only was backwards 2003-01-17 09:22 we7u * src/db.c: Fixed direct stations query to also check ST_DIRECT to choose stations. Thanks Reuven for pointing that out! 2003-01-17 00:10 we7u * src/db.c: Added some comments about ST_DIRECT. 2003-01-16 22:58 we7u * src/db.c: Temporary tweak to the ST_VIATNC code: Changed from 20 to 50 the quantity of packets required from a 'net interface that will cause a reset of the ST_VIATNC bit in the station record. Later this should be changed to a timer. 2003-01-16 13:38 francais1 * src/db.c, src/main.c, src/main.h, src/xa_config.c, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys: Added Mine, Via Digi, Stations and Objects to Select 2003-01-16 10:19 francais1 * config/: language-French.sys, language-Spanish.sys: Tweaked French and Spanish a bit 2003-01-16 10:08 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Changed "Select Local" to "Select Direct". 2003-01-16 09:56 we7u * config/: tnc-startup.aea, tnc-startup.kam, tnc-startup.kpc3, tnc-startup.paccomm, tnc-startup.pico, tnc-startup.sys, tnc-startup.thd7: Added "PASSALL off" to the tnc startup files. 2003-01-16 09:22 we7u * src/: db.c, db.h: Changed ST_LOCAL flag to ST_DIRECT. Makes more sense. 2003-01-15 14:25 francais1 * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Update of data filtering and display menus 2003-01-15 12:12 we7u * src/main.c: Tweak to dead-reckoning. Moved the sec_last_dr_update variable to the main.c globals area. This should preserve the last time between runs of UpdateTime(). 2003-01-14 23:46 we7u * src/festival.c: Added some more error checking. 2003-01-14 13:08 we7u * src/: festival.h, festival.c: Fixed the non-connect to Festival Server problem. This problem existed when Festival was started up after Xastir. Now Xastir will try to connect to the server when speech is desired, but will not try a new socket connection any more often than every 60 seconds. 2003-01-14 09:19 we7u * src/maps.c: Print a warning in draw_geo_image_map() if the image file cannot be read for some reason (typically permissions problems). 2003-01-13 22:23 kd6zwr * src/main.c: Added error checking for setting my station postion from mouse popup menu. 2003-01-13 21:33 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added mouse popup menu item to set my station position 2003-01-12 22:22 we7u * src/: db.c, interface.c, interface.h, main.c: Added some debugging statements in the extract_weather functions. Added a new global string that holds the last packet processed by file read or channel_data functions. If a segfault occurs, this last packet is dumped to STDERR along with the segfault message. This might help in the future to find "killer" packets. 2003-01-12 08:22 we7u * src/maps.c: Changed wget parameters to more verbose keywords. No real code changes. 2003-01-11 18:28 rzg * help/help-English.dat, README.1ST: Updated helpfile for findu.com old code removal, minor readme changes. 2003-01-11 08:38 we7u * src/maps.c: Removed old dead findu.com code (older method of accessing it, no longer used) from maps.c 2003-01-11 08:30 we7u * src/track_gui.c: Fixed findu.com get station tracks. Was using hard-coded IP address before, now uses domain name in URL. 2003-01-09 17:15 we7u * src/db.c: Implemented a range scale display. 2003-01-08 13:55 we7u * FAQ: Added a question/answer about ImageMagick's CompressImageColormap() function call. 2003-01-07 21:13 kg4ijb * src/interface.c: Check for glibc version on socket call line ~840 2003-01-07 20:43 rzg * FAQ, README.1ST: Minor updates about -devel files, minor spacing changes to README.1ST. 2003-01-07 14:26 francais1 * Makefile.am, Makefile.in, xastir.spec.in: Removed creation of placeholder map directories. 2003-01-06 14:42 we7u * scripts/: Coordinate.pm, inf2geo.pl, permutations.pl, test_coord.pl, track-get.pl, waypoint-get.pl: Changed to inf2geo.pl to accomodate other image formats. Tweaks to other scripts regarding copyright notices only. 2003-01-06 14:22 rzg * help/help-English.dat, README.1ST: Finished off "What's new", updates to map properties help, addition of fcc-get script. 2003-01-06 09:07 kg4ijb * src/: festival.c, interface.c: remove deprecated params to socket 2003-01-06 08:54 gstueve * scripts/Makefile.am: Add helper script to retrieve FCC & RAC files for XASTIR use. 2003-01-06 08:42 gstueve * scripts/: Makefile.in, fcc-get: Add helper script to retrieve RCC & RAC data files for XASTIR use. 2003-01-05 11:54 kd6zwr * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Adding distance/bearing on status line. 2003-01-03 10:25 we7u * src/main.c: Dead code go bye-bye. 2003-01-02 13:48 we7u * src/maps.c: Adding more parameter checking after the sscanf in the map_index restore_from_file function. 2003-01-01 21:58 we7u * README.1ST: A few updates to the map directory portions. 2003-01-01 20:08 rzg * help/help-English.dat: More updates to "What's new", added instructions for rain gauge reporting size correction. 2002-12-31 13:57 we7u * src/: draw_symbols.c, maps.c, util.c: Speeding up get_line again (don't need all the filtering anymore since the Map Chooser bug was found). Fixing get_line() calls so that the arrays are long enough to contains what's read from file. 2002-12-30 11:06 we7u * src/maps.c: Fixing segfaults that could occur if GNIS files had short lines or lines containing control characters. Now checking for NULL returns from index() calls. 2002-12-29 16:36 rzg * help/help-English.dat: More updates to "whats new" section; typo fixes. 2002-12-29 15:04 rzg * README.1ST, help/help-English.dat: Round 1 of "pre-release" changes: Reorganized and cleaned up README.1ST, updated some portions as needed. Updated helpfile for map chooser changes. Still need more README work, especially doing something with all that security stuff and perhaps the OS specific stuff. And the helpfile "Whats new" needs to be written more nicely, I started but ran out of time. 2002-12-28 15:41 kd6zwr * src/maps.c: Changed the sscanf fix... cleared the string to all nulls before sscanf. The temp string broke solaris... *sigh*. This works everywhere now?? 2002-12-28 12:55 kd6zwr * src/maps.c: Added a temp string to avoid a sscanf bug(?) to prevent junk showing up in the map chooser window. 2002-12-27 14:18 we7u * src/util.c: Fixing tabs in util.c:get_line(). 2002-12-27 12:54 we7u * src/maps.c: Looking for control characters in the routine that parses the map_index.sys file and creates the in-memory map index. 2002-12-27 11:53 we7u * src/maps.c: More error-checking w.r.t. map indexing. 2002-12-26 17:09 we7u * src/maps.c: Checking for control characters as we're saving the map_index data to disk. 2002-12-26 16:33 we7u * src/maps.c: Looking for all control characters instead of just '\r' or '\n'. Added another warning message if control chars are found. Changed some comments. 2002-12-25 07:32 we7u * src/: draw_symbols.c, main.c, maps.c: Added error checking at the points where different xbitmap files were being loaded, and where symbols.data is loaded. Xastir will now output an error message before croaking if these files are not present. 2002-12-24 17:26 we7u * src/: maps.c, util.c: More filtering changes in and around get_line(). Intended to help with the weird characters Map Chooser problem. 2002-12-24 14:27 we7u * src/maps.c: Commenting out debug printf statements. 2002-12-24 12:00 we7u * src/maps.c: More error checking: Looking for control characters in file/directory names during map indexing. 2002-12-24 08:24 we7u * src/maps.c: Added some code to spit out warning messages to STDOUT if control characters other then '\n' are found in map_index.sys. 2002-12-23 00:16 we7u * src/maps.c: Initial implementation of the draw_filled flag in the map drawing routines which can make use of it. 2002-12-22 11:24 we7u * src/maps.c: Deleting dead code. Adding comments. Set a pointer to NULL after calling a routine that might free the memory space. 2002-12-22 10:54 we7u * src/maps.c: Changed function which reads map_index.sys in from disk so that it forces a sorted order for in-memory map list. 2002-12-21 23:29 we7u * src/maps.c: More error-checking while creating map indexes. 2002-12-21 08:25 we7u * src/maps.c: Added comments. Changed a few compares to read better. No real code changes. 2002-12-21 08:08 we7u * src/maps.c: Added more error-checking and debug output to the map indexing routines. 2002-12-21 00:27 we7u * src/: main.c, maps.c: Fully functional automaps selection from the Map Chooser->Properties dialog. 2002-12-21 00:08 we7u * src/main.c: More automaps stuff. Can now tweak the value in the map_index.sys file from the Map Chooser->Properties dialog. Back-end code still has to be written to use this information. 2002-12-20 23:46 we7u * src/: main.c, maps.c, maps.h: Adding automaps enable/disable to the Map Chooser->Properties dialog. More to do yet. 2002-12-20 22:38 we7u * src/maps.c: Added some debug lines. 2002-12-20 21:40 we7u * src/main.c: Moved some of the widgets to the bottom rowcol form in the Map Properties dialog. 2002-12-20 17:18 we7u * src/: main.c, maps.h: Map Chooser->Properties now brings up new dialog which allows setting map layers and draw_filled fields. draw_filled is not used yet in the code. 2002-12-20 12:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Changed to Dirs/Maps Selected in map chooser instead of just files. 2002-12-20 12:36 we7u * src/maps.c: Added some comments. 2002-12-20 12:07 we7u * src/main.c: Changing the manual map index button back to its original code, where it only updates the map index instead of re-indexing from scratch. This keeps the manually-tweaked map_level & draw_filled fields intact. The original reason for starting from scratch was to remove deleted maps. This happens anyway after two Xastir restarts, so starting the list from scratch isn't really needed anyway. 2002-12-20 11:52 we7u * src/maps.c: Fixes to re-indexing so that files and directories get good default values in the index. 2002-12-20 11:52 we7u * src/main.c: New stuff having to do with Map Chooser Properties button. Not fully implemented yet. 2002-12-20 11:51 we7u * src/maps.h: Added a prototype for a function that I need to use in main.c 2002-12-19 17:04 we7u * src/: main.c, main.h, maps.c: Initial attempt at sorting/drawing maps based on map layer. It works! Next step is to get some more GUI hooks for it so that the user can specify which maps go on which layer, and which layers to enable for drawing. 2002-12-19 12:36 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a count of how many maps are currently selected to the map chooser. Doesn't quite work the way I'd like yet, but it is useful. It shows how many maps are marked in the in-memory map index as selected. That quantity can change when you tweak things in the map chooser and then hit OK. 2002-12-18 22:03 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.h: More tweaks to the Map Chooser. Fully resizable now. Add new button at the top which will eventually be used to change map properties. Changed how the "None" button works, and renamed it to "Clear". 2002-12-15 23:56 we7u * src/maps.c: Yet another attempt to clean up garbage that some people are seeing in the map index. In this tweak I check the sscanf call to make sure that the proper number of fields have been parsed from each input line. If not, that record in the map_index is dropped. 2002-12-15 23:07 we7u * README.1ST: Tweaks by Tate, KC7ZRU. Thanks! 2002-12-15 23:03 we7u * src/main.c: Changed map re-indexing button so that it deletes the entire in-memory index, then re-creates it from scratch. It is slower than the old method, but guarantees that deleted/added maps will show up in the map chooser without have to restart Xastir to do it. 2002-12-15 21:41 we7u * src/festival.c: Change to some debug code. 2002-12-15 18:28 we7u * src/festival.c: Now doing a check in the festival code for duplicate strings. Only one string is held in the queue for 30 seconds. If the same string comes in, festival refuses to speak it. 2002-12-14 23:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added an "Expand Directories" button to the map chooser. 2002-12-14 21:34 we7u * src/: main.c, maps.c: Better implementation of map directory select/de-select in the Map Chooser. 2002-12-14 15:04 we7u * src/maps.c: A few small tweaks to how map_index strings get created for directories. 2002-12-14 00:16 we7u * src/main.c: Commented out a couple of debugging statements. 2002-12-13 23:52 we7u * src/: main.c, maps.c: First functional version of Map Chooser where clicking on a directory will select all maps below it. Still a few bugs left to squash, but it works! 2002-12-13 22:35 we7u * src/maps.c: Finished getting map directories to show up properly and in sorted order in the Map Chooser. They're selectable as well. Still have to write the code to recurse through these directories when selected/de-selected. Not fully functional yet. 2002-12-13 17:04 we7u * src/maps.c: Starting to implement storage of map directories in the map index. Not complete yet. 2002-12-13 12:04 we7u * src/main.c: Tweaks to comments. 2002-12-13 09:42 we7u * src/main.c: Including Chris Bell's new routines for directory-at-a-time map file selection. These routines are not integrated into Xastir yet. They need to be tweaked to fit into the new map_index method of map selection, and the Lesstif/Motif functions need to be combined into one function. This is a work in progress. 2002-12-10 14:51 we7u * src/db.c: Fix for dead-reckoning for compressed objects/items. 2002-12-10 14:13 we7u * FAQ: Added a note about the missing freetype library during linking. 2002-12-10 13:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a new "Re-index Maps" button to the configure menu. Useful for those instances where you've added a new map but don't want to restart Xastir in order to start using it. 2002-12-10 13:15 we7u * README.1ST: Added a note about James Jefferson's nice world map in Shapefile format. 2002-12-10 12:48 we7u * src/main.c: Fixed to map chooser. Changes now apply only to the in-dialog list until/unless the OK button is pressed. If Cancel or any other button is pressed, the changes do not take effect or get written to the selected_maps.sys disk file. 2002-12-09 09:18 we7u * README.1ST: Updating e-mail address. 2002-12-07 20:57 we7u * src/: draw_symbols.c, igate.c, maps.c, maps.h, util.c: Tweaks to help fix buffer overflows in several areas of the code. Some of them may have been caused by get_line() in util.c, which has been rewritten to prevent overflowing the string passed into it. Also added a new define: MAX_FILENAME, which is used to declare sizes of char arrays. 2002-12-07 00:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/locate_gui.c: Upon receipt of a Mic-E emergency packet: No longer bring up a popup dialog. Now bring up only a Locate Station dialog, but the titlebar has been changed to read "Emergency Locate!". 2002-11-26 16:35 we7u * src/xa_config.c: More water gage stuff. 2002-11-26 15:56 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Adding a display toggle for water gage objects. 2002-11-26 09:12 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-11-25 23:05 we7u * src/: bulletin_gui.c, db.c: Finishing up the bulletins-before-posits code. Now bulletins come up as soon as the posits for that station are received. 2002-11-25 17:10 we7u * src/: db.c, db.h: Start of trying to fix distance=0 bulletins for when posit comes in later. A bit more code to write, but this keeps track of whether or now the posit is currently known. 2002-11-25 13:19 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/bulletin_gui.c, src/main.c, src/main.h, src/xa_config.c: Something several of you have asked about in the past: A way to stop the popup and display of bulletins with zero distances. Two togglebuttons in this case control the same global variable: One toggle on the Configure->Defaults dialog, and another on the View->Bulletins dialog. 2002-11-25 10:40 rzg * help/help-English.dat: Updates for dead-reckoning, other minor changes. 2002-11-25 09:42 we7u * README.1ST: A bit more about installing festival from RPM's and changing the default voice. 2002-11-23 22:11 we7u * src/util.c: Tweaks to the speech stuff so that we don't add commas to the SSID portion of a callsign. This makes it speak -12 as "dash twelve". 2002-11-23 20:20 we7u * README.1ST: Added a blurb about festival and starting it in server mode. Useful for those that can't read the English help file (where it is also documented). 2002-11-23 08:18 we7u * src/util.c: Speech stuff now looks for a number in the text (before a dash). If found, it adds commas so that Festival will speak each letter. If not found, it feeds the string directly to Festival to let it try to pronounce it. 2002-11-23 00:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/festival.c, src/main.c, src/popup_gui.c, src/util.c, src/util.h: Changes to make Festival speak callsigns out letter by letter. 2002-11-22 17:16 we7u * scripts/inf2geo.pl: Tweaked to handle different cases for filenames, and to put the proper case into the GEO file for the GIF file. 2002-11-22 15:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Separated out more festival speech strings from the other language strings. Changed the "New Station" speech string to just "New" to speed things up a bit. 2002-11-22 11:20 we7u * README.1ST: Added the su & exit around the "make lib_install" for the Shapelib install. Thanks Bob! 2002-11-21 21:15 we7u * src/: maps.c, popup_gui.c: Code fixes for when required fonts can't be found. Error messages are output and Xastir recovers, instead of segfaulting. 2002-11-21 17:56 we7u * src/popup_gui.c: Changing to another font. 2002-11-21 17:44 we7u * src/xa_config.c: Deleting a duplicated variable. 2002-11-21 17:38 we7u * README.1ST: Added notes about the two new auto-identification methods. 2002-11-21 17:06 we7u * src/popup_gui.c: Correcting small error in variable name. 2002-11-21 16:53 we7u * src/popup_gui.c: Moved the Speech ID stuff to the beginning of the ID routine so that the spoken text and the screen ID will occur at roughly the same time. 2002-11-21 16:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/popup_gui.c, src/xa_config.c, src/xastir.h: Added station ID in the form of large text across the screen, and spoken station ID via festival. Occurs every 9.5 minutes if two new variables in the config file are enabled. 2002-11-21 10:20 we7u * src/util.c: Minor tweak to make sure that objects/items only get one hash mark added to the front of the line in the ~.xastir/config/object.log file. 2002-11-19 10:29 francais1 * src/: main.c, main.h, xa_config.c: Added "hidden" conf file value to adjust DR update rate Default is 30 s 2002-11-19 10:20 we7u * src/db.c: Fixes so that dead-reckoning and "Display Moving Stations" work properly even when we only have one position from a station. They are now classified with ST_MOVING flag if the speed is non-zero. 2002-11-19 09:59 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/draw_symbols.c, src/main.c, src/main.h, src/xa_config.c: Added new buttons to enable/disable the different dead-reckoning display objects. This allows users to get the display as cluttered or uncluttered as they like. 2002-11-19 09:10 we7u * src/xa_config.c: Changing default for dead-reckoning to ON. 2002-11-18 16:25 francais1 * src/: draw_symbols.c, main.c: Added call to draw_symbols in UpdateTime at least every 30 s if dead reckoning drawing is turned on. Tweaked dead reckoning graphics to draw the DR trail in a dashed line and draw an arc that gets larger as time from last posit grows until it turns into a circle. 2002-11-18 13:19 we7u * src/draw_symbols.c: Fixing the bug where weather stations hit the clear interval but wind barbs still get drawn. 2002-11-17 21:48 kd6zwr * src/main.c: added keysyms for pgup/pgdn on sun keyboards 2002-11-14 18:02 we7u * src/util.c: Code to handle disowning of object that other people take over, and to comment out our own objects from the object.log file when we delete them. This keeps us from retransmitting the objects when Xastir restarts. 2002-11-14 16:25 we7u * src/: main.c, util.c, util.h: More object stuff. More to do yet. 2002-11-14 15:50 we7u * src/: db.c, util.c, util.h: The start of code to allow disowning an object that someone else is assuming control over. Xastir already does this while running, but it doesn't write the data to the object.log file, so when it starts up, it owns the object again. 2002-11-14 14:07 we7u * src/db.c: Saving empty-string for speed instead of "0" if speed is unknown on a parsed packet. 2002-11-14 12:40 we7u * src/db.c: Unlinking DR functions from Display Course/Speed toggles. 2002-11-14 11:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Initial implementation of dead-reckoning by J. Lance Cotton, KJ5O. Thanks very much to him for doing this!!! 2002-11-13 15:31 we7u * src/maps.c: Forcing terraserver map extents in the index to be at the edges of the earth. Added more statusline messages for loading/indexing maps (more consistent now). 2002-11-13 14:13 we7u * src/maps.c: An attempt to fix the buffer overflow problems with map indexing. 2002-11-13 13:19 we7u * src/main.c: We now delete/recreate our own station record only if we change our callsign. All other changes just cause an update to the current record. 2002-11-13 12:43 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: New "Waiting for GPS data.." string. 2002-11-13 12:40 we7u * src/: db.c, interface.c, main.c, main.h: Implemented a countdown from when GPS data goes invalid. It is decremented each time a posit occurs. When it reaches zero, posits stop. Valid GPS data parsing will reset it back to the starting count. Also reduced the size of the tracked station circles in order to more easily read the station data. 2002-11-12 18:23 we7u * src/db.c: Added another blue circle for tracked stations. Now three concentric circles. 2002-11-12 18:17 we7u * src/db.c: Making a tracked station have both a yellow and red circle to make it easier to see against different map backgrounds. 2002-11-12 18:07 we7u * src/: db.c, interface.c, main.c, main.h: Added "my_position_valid" variable, initially set to 1. As soon as a GPS interface of any type is started up, this variable gets set to zero, and it holds off posits. Once the first valid GPS position is parsed, this variable is again set to 1, and posits proceed normally. As Xastir comes up, interfaces are brought up before the first posit, so if a GPS interface is enabled on startup, no posits will occur until the first GPS posit is parsed properly. This variable could be used later to disable posits when GPS data becomes unusable or stops coming in. This feature is not implemented yet though. 2002-11-12 15:23 we7u * src/db.c: Changed tracked stations circle from Red to Yellow to make it easier for partially colorblind people to see against a background of topo maps. 2002-11-12 14:56 we7u * src/db.c: Got rid of another bug off the buglist. Now only stations that are currently visible will be selected for Station Info operations. 2002-11-12 14:15 we7u * src/main.c: Changed the order of startup so that map indexing is completed before interfaces are brought up. 2002-11-12 10:56 we7u * src/maps.c: Changes intended to keep variables from going out-of-bounds. I'm attempting to get more DRG-Enhanced map formats working. These changes don't quite make them work, but they do make it better and catch some out-of-bounds problems. 2002-11-11 15:01 we7u * configure, configure.in, ltconfig: OpenBSD 3.1/IA32 patches by Yasholomew Yashinski. Thanks! 2002-11-09 18:04 kd6zwr * src/main.c: Fix for white foreground on solaris (uninitialized color) 2002-11-07 16:14 we7u * README.1ST: Added a note about MrSID file compression. 2002-11-07 16:10 we7u * README.1ST: Added some notes about DRG-E files. 2002-11-06 22:40 we7u * README.1ST: Added some "su" lines and some comments about "ginstall". 2002-11-06 15:15 we7u * FAQ: Added a section about geoTIFF's causing segfaults. 2002-11-06 12:47 we7u * README.1ST: Added a section describing the FGD file format portion that we use. 2002-11-01 16:56 we7u * src/maps.c: Changed one comment. 2002-10-31 16:27 we7u * src/maps.c: Added checks in the geoTIFF code for neat-line map boundaries being outside normal limits. If found, output warning message, reset the corner to something more reasonable, and continue on. 2002-10-31 13:52 we7u * src/: datum.h, maps.c: Converting from using proj.4 to using datum.h/datum.c in order to do our datum translations for geoTIFF maps. 2002-10-30 13:40 francais1 * src/: draw_symbols.c, main.c, xastir.h: Added support for 25% and 12.5% stipples when drawing station ambiguity. 2002-10-30 13:38 francais1 * symbols/: 13pct.xbm, 25pct.xbm, Makefile.am, Makefile.in: Added pixmaps for 25% and 12.5% stipples 2002-10-30 11:08 we7u * src/: db.c, draw_symbols.c, main.c: Fixed some conversion problems for speed/wind speed. Added some notes. Wind barbs are not shown properly in knots instead of mph. 2002-10-29 14:26 we7u * src/db.c: Tweaks to the wind direction/wind speed decoding for weather stations. We were missing speed/direction for many weather packets. Many more wind barbs are now showing up. 2002-10-28 22:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added a new toggle to the Defaults dialog for enabling/disabling warnings for modifier keys. 2002-10-25 15:04 we7u * README.1ST: Changing some notes regarding map permissions and running as the root user. 2002-10-25 13:34 we7u * README.1ST: Added a note about map and map directory permissions. Added warnings regarding running programs as the root user. 2002-10-24 17:32 rzg * help/help-English.dat: Updates for the Map and Station menu changes. 2002-10-23 16:12 we7u * src/draw_symbols.c: Cleanup of debug code & comments for the wind barb stuff. 2002-10-23 13:28 we7u * src/: db.c, draw_symbols.c, draw_symbols.h, main.c: Wind Barb implementation. Enable/Disable togglebutton has yet to be added to disable these. 2002-10-22 15:16 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-10-22 14:37 we7u * help/help-English.dat: Another item for your todo list. 2002-10-22 14:12 we7u * src/maps.c: Tweak to weather alert code to compensate for NULL fields in the NOAA shapefiles. Weather alerts should now appear in the proper places even if using newer NOAA files. 2002-10-21 23:35 rzg * README.1ST: Oops, didn't mean to revert that stuff... 2002-10-21 23:29 rzg * README.1ST, FAQ, help/help-English.dat: Minor fixes/updates to docs. 2002-10-20 22:53 francais1 * src/db.c: ST_VIATNC is what I really wanted... 2002-10-20 22:26 we7u * src/interface.c: Moved a variable inside the proper #ifdef statements. It was causing a compiler warning on systems without kernel AX.25 interface support. 2002-10-20 21:30 francais1 * src/: main.c, maps.c, maps.h: Enabled +/= and - to change the grid size a bit. 2002-10-20 20:15 francais1 * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Expanded "Display Stations" into "Display Local Stations" and "Display Non-Local Stations" 2002-10-20 18:06 francais1 * src/: db.c, interface.c, interface_gui.c: First pass at relay digipeating over an ax25 interface. Look for the define I_WANT_TO_TRY_AX25_RELAY_DIGIPEAT in db.c and interface_gui.c 2002-10-19 12:06 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added an ID string to the status line for the periods when no traffic is coming in. If the ID string doesn't appear for 9 minutes straight, it is forced onto the statusline for a few seconds in order to meet ID requirements. This is useful for beaming an Xastir image over amateur fast-scan television. Tweaked the Configure->Station callsign block so that all characters of a full callsign plus SSID are displayed. Tweaked the weather symbol display code so that " " and "..." are not taken to be a zero reading. 2002-10-18 15:42 we7u * src/maps.c: Changes in the GNIS map-reading code to accomodate the lack of consistency in how the GNIS files are formatted. 2002-10-18 14:04 we7u * README.1ST: Added a note from Chris about GNIS file. 2002-10-18 12:34 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Broke up Stations menu into submenus. 2002-10-18 10:13 we7u * src/main.c: Set default ON for new togglebuttons on stations menu. 2002-10-17 22:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h: Initial attempt at some station/object display filtering. What is coded so far works, but most of the variables are not saved in the config file yet. May need more togglebuttons & variables implemented yet. 2002-10-17 15:41 we7u * AUTHORS: Minor cleanups and added a few contributors. 2002-10-17 15:23 we7u * README.1ST: Move "Previous Install Notes" section to a later point in the file. 2002-10-17 15:05 we7u * src/db.c: Tweaks to get rid of compiler warnings for Debian/S390. Changed char's to int's and got rid of some casts. 2002-10-17 12:13 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-10-16 14:10 we7u * src/db.c: Added draw_symbol_filtered() function. Will eventually add code to this function which implements display filtering. 2002-10-15 14:28 we7u * src/: db.c, draw_symbols.c, draw_symbols.h: Implemented different colors for tropical storm/depression and hurricane packets, for the three different wind speeds: Green = gale force wind radius, yellow = tropical storm wind radius, red = hurricane wind radius. 2002-10-15 13:38 we7u * src/db.c: Converted storm circles from nautical miles to miles before calling draw_pod_circle. Ranges are now correct. Added a couple of comments as well regarding things yet to be done. 2002-10-11 16:25 we7u * src/wx.c: Added a comment about Dallas rain gauge. 2002-10-11 12:55 we7u * src/db.c: Initial attempt at drawing circles around storm objects (radius of winds). Need to convert from nautical miles to miles and perhaps change to a different method of drawing, but this works for now. 2002-10-11 12:54 we7u * src/wx.c: Commented out a debug line. 2002-10-11 12:53 we7u * src/draw_symbols.c: Added some comments. 2002-10-10 15:56 we7u * src/wx.c: Wind speed for Dallas one-wire WX station. 2002-10-10 15:21 we7u * src/wx.c: Correction to temperature conversion for Dallas WX station. 2002-10-10 15:19 we7u * src/wx.c: Support for wind direction for Dallas WX station (using OWW daemon for the data feed). 2002-10-10 13:40 we7u * src/interface.c: Now handle 0x00 characters in port_read, for the case where the One-Wire Weather daemon ("OWW") sends them to us. Temperature from a Dallas one-wire station is now initially coded and appears to be working. 2002-10-10 13:38 we7u * src/wx.c: Changed some comments and put one message under debug_level control. 2002-10-10 13:05 francais1 * src/util.c: phg_decode was missing the phg circle radius/2 stuff put into phg_decode. 2002-10-10 01:48 we7u * src/: db.h, wx.c: Initial support for Dallas One-Wire weather station. Xastir gets it's data from the OWW server. We currently only parse out the temperature, and it appears we only do that once when the network port is brought up. More functionality to be added later. 2002-10-08 22:52 we7u * src/: main.h, maps.c, maps.h, track_gui.c: Fixed bug where TrackMe button didn't get disabled when tracking was cleared from the menus. Map indexing now removes indexes for deleted files. Another ImageMagick API change is now handled in our code. 2002-10-08 21:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: We now check for modifier keys when the third mouse button press is detected and dump out a warning message asking the user to turn off the modifier keys. 2002-10-04 00:20 we7u * src/db.c: More correct parsing of Storm Data. 2002-10-03 17:31 we7u * src/db.c: Commenting out debug statements. 2002-10-03 17:29 we7u * src/: db.c, db.h: The start of decoding storm data. More to do in terms of units conversion and display, but the basic packet decoding is coded and working. 2002-10-03 16:06 we7u * src/maps.c: Added a comment. 2002-10-03 11:35 we7u * src/: maps.c, track_gui.c: Small tweaks to wget error messages. 2002-10-03 11:25 we7u * src/: main.c, maps.c, maps.h: Updates to map indexing. Starting to work as intended now. 2002-10-02 16:39 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/maps.c, src/xa_config.c, src/xastir.h: Added a Disable Raster Map togglebutton to the maps menu. Added "Indexing" text to the statusline as we're indexing maps. 2002-10-02 15:28 we7u * src/maps.c: Changed auto_maps to use the in-memory map index. Lot's of tweaks to sort the map index. Now use the .geo filenames instead of the http/ftp URL's. Got rid of shx/dbf filenames (using shp instead). This got rid of the triple-drawing of shapefiles that was ocurring with automaps. Added statusline() calls to all of the draw functions. 2002-10-01 10:43 we7u * src/maps.c: Added more error output for geoTIFF's, where proj may not have been installed correctly. 2002-09-30 16:50 we7u * src/interface_gui.c: Minor correction. This window was WAY too long when I defined 30 interfaces. The new length is more reasonable. 2002-09-30 16:06 we7u * src/: interface.h, interface_gui.c, main.c: Upp'ed the number of interface to 15. Tweaked the GUI and other portions of the code to handle whatever MAX_IFACE_DEVICES is set to. Xastir should theoretically be able to handle any number of interfaces now, but it's only been tested so far up to 15. 2002-09-30 00:19 we7u * README.1ST: Added a note about the 24kgrid file available from gisdatadepot. 2002-09-29 23:41 we7u * README.1ST: Added a more specific path for getting GNIS datafiles. 2002-09-29 22:04 we7u * README.1ST: Added a few more sources of Shapefile maps. 2002-09-26 16:11 we7u * src/maps.c: Fixes for Tigermap and GEO file segfaults. Saw segfaults with Tigermaps when "wget" returned a zero-length file. These changes fix this problem. 2002-09-26 13:39 we7u * src/db.c: Limiting the new togglebutton to work only on objects containing weather, not on all objects. 2002-09-26 13:29 we7u * src/: db.c, main.c: A better logical relation between the togglebuttons for the new "Display WX Object/Item" button. 2002-09-26 12:39 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Minor change to Display Weather Object strings. 2002-09-26 12:30 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Added a new toggle for enable/disabling weather objects. 2002-09-25 15:23 we7u * src/wx_gui.c: Widening some fields by one character width in Own Weather Data dialog. 2002-09-25 15:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/wx_gui.c: Changing barometric pressure display in inches Mercury to have two digits after the decimal point. 2002-09-25 01:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/wx.c, src/wx.h, src/wx_gui.c: Implemented English/Metric barometric pressure for Own Weather Station dialog and for Station Info dialog. 2002-09-25 00:49 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added another string for weather stuff. 2002-09-24 16:49 we7u * src/maps.c: Just adding some blank lines to delineate the different functions. More real code changes to come later. 2002-09-24 13:11 we7u * src/db.c: Better handling of weather stations and weather objects. We now try to parse the course/speed field _and_ the 'c' and 's' fields in all cases, and can handle some of the different field positions that some of the RAWS weather objects present to us. 2002-09-24 10:34 we7u * src/db.c: Changed wx_fuel_moisture so that a 00 reading equates to 100%. 2002-09-23 23:48 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h: Added parsing of Fuel Temperature and Fuel Moisture for RAWS weather objects, and the corresponding display in the Station Info dialog. 2002-09-23 22:53 we7u * src/db.c: Added some comments. 2002-09-23 11:46 we7u * help/help-English.dat: _Very_ minor spelling fixes. 2002-09-23 11:40 we7u * src/maps.c: Changes to the lat/long gridlines by Thierry Leconte: "Now, the code draw solid line and 3 types of dashed lines. Solid line is, as previously, for equator and Greenwich meridian. The 3 dashed line corespond to locator coord scheme : 1st dasher line for big square (2 first letters) 2nd dashed line for the 2 numbers 3rd dashed line for small square (2 last letter). Depending of the zooming, the code could draw 1,2 or the 3 line types." We might wish to change the sizes of the boxes, but the ideas behind it and the implementation are great! Thanks Thierry! 2002-09-23 11:29 rzg * help/help-English.dat: Updates for object persistance and a few more on the new features list to be documented at some point. I still exist. :-) 2002-09-23 10:38 we7u * src/: maps.c, util.c: Fixes by Tom Russo for map indexing of GNIS files and for reading in zero-length files. Thanks Tom! 2002-09-19 15:52 we7u * src/main.c: Changes by Thierry Leconte which make degrees/minutes symbols appear in the status line, and add the Maidenhead grid locator to it as well. Small changes by we7u to tweak the widths of the textfields on the status line. 2002-09-19 14:13 we7u * src/wx.c: More changes for Peet Bros. U2K weather station decoding by David L. Norris. 2002-09-19 13:57 we7u * src/: main.c, main.h, maps.c, xa_config.c: Getting rid of WIN_MAP variables once and for all. 2002-09-19 13:49 we7u * src/db.c: More careful string copying of callsigns in a couple of places. There was a possibility of overrunning the destination string before. 2002-09-19 13:27 we7u * src/db.c: Adjusting buffer lengths to handle longer packets. 2002-09-19 12:28 we7u * src/: main.h, xastir.h: Change to allow u2k complete record mode (long packets) to get through the decoding functions. 2002-09-19 12:16 we7u * src/wx.c: Another small tweak to rain totals for u2k. 2002-09-19 11:12 we7u * src/wx.c: Changes for Peet Bros. U2K weather station decoding by David L. Norris. 2002-09-19 09:32 we7u * src/maps.c: Commenting out the map index printf's in maps.c 2002-09-19 01:08 we7u * src/main.c: Adding new language string for TrackMe button. 2002-09-19 01:03 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added new language string for TrackMe button. 2002-09-19 00:56 we7u * src/: main.c, track_gui.c, track_gui.h, xa_config.c: Implemented new TrackMe button on the main window. State is saved in config file so that Xastir starts up in the correct mode. 2002-09-18 15:48 we7u * src/: main.c, maps.c, xa_config.c: Added more map types to the VECTOR button on map chooser. Now selects ".map", ".gnis", ".pdb", and ".shp" files. Changed default name of "winmaps.sys" file to "selected_maps.sys". This last change will only take effect on new installations, or if the winmaps.sys file is deleted. 2002-09-18 14:21 we7u * src/: main.c, maps.c: Map indexing, saving/restoring from files. This version is more space-efficient. We could do more speedups by doing a sort and binary search through the index, or using a hash. 2002-09-18 12:35 we7u * src/maps.c: Small tweak to correct code which creates the empty map index file. 2002-09-18 12:30 we7u * src/maps.c: Killing off the saving of the map index for now. Plan on implementing a more space-efficient storage. 2002-09-18 12:17 we7u * src/: maps.h, main.c, maps.c: Now saving/restoring the map index to a file. 2002-09-18 11:41 we7u * src/: main.c, main.h, maps.c, maps.h, xa_config.c: Initial implementation of map indexing, still need to save/restore the map index linked list to a file. Currently the indexing occurs _after_ the first map draw, then succeeding map draws check the index which speeds things up considerably. The plan is to write the index to a file, read it in _before_ the first map draw, and then re-index only when new files appear or files are changed in the map directory. 2002-09-12 10:48 we7u * src/main.c: Added the Station Last Heard button into the Sensitive enable/disable for Symbols in the menu. It was getting grey'ed out and not returning to the Sensitive state as the Symbols Enable button was toggled. 2002-09-12 09:56 we7u * src/maps.c: Fixes to draw_shapefile_map() to set a default line width, for cases where specific maps are not recognized later in the code. The problem was that other areas in the drawing code (probably tracklines) where causing map lines to get drawn in double or triple width at times. 2002-09-10 16:35 we7u * src/maps.c: Added a default line width setting to the start of the polyline drawing portion of draw_shapefile_map(). This is an attempt to get rid of the double line-widths that are sometimes seen on the screen. 2002-09-10 16:14 we7u * src/db.c: Fixing the new track detector for the save track function. 2002-09-10 15:14 we7u * src/: db.c, db.h: A bit of housekeeping. Renaming the TrackRow2 struct to TrackRow, since the old TrackRow is now deleted from the code. 2002-09-10 12:22 we7u * src/: db.h, db.c: Fixes for station track storage. 2002-09-10 10:04 we7u * src/main.c: Creating the .xastir/tracklogs directory automatically on startup. 2002-09-09 16:29 we7u * src/maps.c: Tweak to handle parsing of newer format bounding coordinates from USGS .fgd files. 2002-09-03 09:23 francais1 * src/list_gui.c: Bug 604044 All station names were ghosted. Fixed. 2002-08-29 17:44 we7u * src/maps.c: Changed some comments. 2002-08-29 14:01 we7u * src/main.c: Changing language list to alphabetical. 2002-08-29 08:49 we7u * src/: bulletin_gui.c, db.c, util.c: Putting several debug printf's under debug_level control. 2002-08-28 13:41 we7u * src/: db.c, util.c: Fix for bulletins popping up that are out of range. We were computing the distance from our station based on the destination callsign (BLNx) instead of the originating callsign. 2002-08-27 15:43 we7u * src/: util.h, util.c: Added higher precision timers in order to time code sections. 2002-08-27 15:42 we7u * config/language-Dutch.sys: Changed by Han Sytsma, PE1FAM. 2002-08-26 14:52 we7u * scripts/: coord-convert.pl, permutations.pl, test_coord.pl: Modifying each script to add a path to /usr/local/lib in order to find the Coordinate.pm module. 2002-08-26 12:08 we7u * src/db.c: Added a few comments. 2002-08-24 11:52 kd6zwr * src/maps.c: Explicitly defined shorts as unsigned to fix wrapping problems with palm maps. 2002-08-23 10:06 we7u * README.1ST: Added a note about Tiger 2000 maps converted to Shapefiles. 2002-08-22 15:43 we7u * src/maps.c: Added some casts. 2002-08-22 14:58 we7u * README.1ST: Updated the fcc/rac call lookup installation instructions. 2002-08-22 13:58 we7u * src/maps.c: More comments. 2002-08-22 12:47 we7u * src/maps.c: More comments. 2002-08-22 12:12 we7u * scripts/: Makefile.am, Makefile.in: Adding coord-convert.pl and permutations.pl to install. 2002-08-22 11:33 we7u * src/maps.c: Changing some comments. No code changes. 2002-08-22 09:51 we7u * src/maps.c: Adding some comments to the palm map routine. 2002-08-22 09:43 we7u * src/maps.c: Changed a single-letter variable to two letters to make it easier to grep for in the code. 2002-08-21 17:19 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c, main.c: Fixes for bulletins popping up. Now waits 15 seconds to see if a posit comes in before attempting to pop up the bulletins dialog. Added filtering for characters output by an extract_multipoints debug message. 2002-08-21 11:24 we7u * src/list_gui.c: Now grey out the object/item name as well if it has been deleted. In the View->Object & Item dialogs. 2002-08-21 11:17 we7u * src/db.c: Putting out debug message in order to debug possible bulletin problem. 2002-08-21 11:16 we7u * src/list_gui.c: We now show deleted objects/items in the "View" dialogs as ghosted. 2002-08-20 15:07 kd6zwr * src/main.c: Bumped up the test for debug level dialog. 2002-08-16 15:54 we7u * FAQ: More minor tweaks to the same section. 2002-08-16 15:50 we7u * FAQ: Minor addition to the "why can't I see stations" paragraph. 2002-08-15 16:57 we7u * src/maps.c: Moved the USGS Quad labels left by one square. They appear to be in the correct places now. 2002-08-15 14:27 we7u * config/tnc-startup.paccomm: New startup file for Pac-Comm TNC's with version 5.x firmware. 2002-08-15 10:22 we7u * scripts/coord-convert.pl: Added the capability to handle "48N 122W" and similar inputs. Fixed a bug in DD MM.MM conversions. 2002-08-14 15:04 we7u * src/db.c: An attempt to prevent Emergency popups about the same callsign from appearing more often than every 30 minutes. 2002-08-14 13:51 we7u * scripts/: coord-convert.pl, permutations.pl: Adding a blank line between user input and output lines. 2002-08-14 11:21 we7u * scripts/permutations.pl: And handling yet another format... 2002-08-14 11:15 we7u * scripts/permutations.pl: Tweaks to more properly format some inputs. 2002-08-14 10:55 we7u * scripts/permutations.pl: Tweaks to allow shorter lat/lon strings to be processed. 2002-08-14 10:12 we7u * scripts/permutations.pl: Added the capability to write APRS Items to a log file that can be sucked in by Xastir. 2002-08-14 09:52 we7u * src/db.c: Minor tweak to get rid of compiler warning. 2002-08-14 08:49 francais1 * src/util.c: Nasty lat/lon to/from UTM conversion bug. (Wasn't referencing correct ellipsoid.) Also made last 2 characters of grid square location lowercase since that seems more common. 2002-08-14 08:49 francais1 * src/main.c: Nasty lat/lon to/from UTM conversion bug. (Wasn't referencing correct ellipsoid.) 2002-08-13 17:12 we7u * scripts/permutations.pl: New script which will show various permutations for a lat/lon or UTM input. Eventually plan to have this script write a log file containing objects so that Xastir can plot each of the positions. This will be useful in quickly determining which of the formats is within the area of interest. Developed this for Search & Rescue applications. 2002-08-13 16:51 we7u * scripts/coord-convert.pl: Added a range check for the Easting value. Not exact, but better than nothing. 2002-08-13 15:34 we7u * scripts/coord-convert.pl: Added capability to use UTM as the input coordinate. 2002-08-13 14:36 we7u * scripts/: Coordinate.pm, test_coord.pl: Getting the dates right for the copyright. 2002-08-13 14:34 we7u * scripts/: Coordinate.pm, coord-convert.pl, test_coord.pl: Tweaks to headers. 2002-08-13 14:01 we7u * src/db.c: Commenting out debug statement. 2002-08-13 13:47 we7u * src/db.c: Fixed Mic-E decoding problem having to do with position ambiguity. We have to specifically test for 'L' in the destination field as it doesn't match the general bit patterns. Stupid spec anyway. 2002-08-13 11:39 we7u * src/: db.c, db.h, draw_symbols.c, draw_symbols.h: Severe storm objects by Gerry Wheeler, KG4NBB. Dale Huguley, KG5QD's weather server (on the 'net) generates severe storm objects and boundaries based on NWS data. These objects are now decoded and drawn by Gerry's new code additions. 2002-08-12 17:03 we7u * scripts/: Coordinate.pm, coord-convert.pl, test_coord.pl: Utility for converting between coordinates, written in Perl. Also has UMS coordinates. 2002-08-12 12:04 we7u * src/maps.c: Pre-pending the quad index to the quad name. 2002-08-12 11:36 we7u * src/maps.c: Fix for some labels on quad overlay shapefile. 2002-08-11 09:57 we7u * README.1ST: Changed the URL where the Mac OS X instructions reside. 2002-08-09 17:34 we7u * src/maps.c: Nicer labels for the quad names. 2002-08-09 17:26 we7u * src/maps.c: Initial support for USGS Quad overlay shapefile. 2002-08-09 16:33 we7u * README.1ST: A bit more about ldconfig. 2002-08-08 23:33 we7u * src/: util.c, util.h, wx.c: Changes to 30-second timestamps in logfiles: Now closely emulate the date/time string that the date(1) command generates. 2002-08-06 16:14 we7u * src/util.c: Getting rid of a message that appears if the .xastir/config/object.log file doesn't exist. 2002-08-06 13:42 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added a clear button for the object/item history file. 2002-08-06 13:00 we7u * src/: main.c, util.c, util.h, xastir.h: Implementation of persistent objects/items. Each new, deleted, or moved object/item is logged to "~/.xastir/config/object.log". This file is read in and each line processed on startup. This will also show tracklines for moved objects as each change is logged to the file. 2002-08-06 11:33 we7u * src/db.c: Adding "AA:" to the beginning of auto-response messages. 2002-08-06 09:52 francais1 * src/maps.c: IsPseudoClass in ImageMagick 5.3.1 doesn't quite act like I would have thought. Changed to different check. 2002-08-05 15:29 we7u * src/: messages_gui.c, view_message_gui.c: More tweaks regarding fonts. Seems we can set foreground color but not background on a couple of widgets. Trying to set background color causes a segfault. 2002-08-05 15:07 we7u * src/: messages_gui.c, view_message_gui.c: Move segfault fixes in new code. 2002-08-05 15:05 we7u * src/view_message_gui.c: Fix for segfault in newly introduced code. 2002-08-05 13:48 we7u * src/: bulletin_gui.c, draw_symbols.c, location_gui.c, main.c, messages_gui.c, track_gui.c, view_message_gui.c, xastir.h: Added defines for foreground and background font colors. This and the associated code changes should help to alleviate the problem where font colors would accidentally change during runtime due to color-ls being run in the starting Xterm. 2002-07-26 09:35 we7u * help/help-English.dat: Very minor changes to the new scripts section. 2002-07-26 09:30 we7u * src/messages_gui.c: Put another message under debug_level control. 2002-07-26 08:45 rzg * help/help-English.dat: Added scripts section, minor update to new features list. 2002-07-25 22:24 we7u * src/messages_gui.c: Commenting out some debug messages. 2002-07-25 20:29 we7u * src/: db.c, igate.c, igate.h, main.c: Implemented SENT and HEARD queues for igating->RF. Dupes are now eliminated. This includes if another igate beat us to getting a packet on RF: In that case we don't add to the traffic on RF by sending it out too. 2002-07-24 12:58 we7u * src/db.c: Fix for igating: We were testing the ST_VIATNC flag for a station first to see if it had been heard via a TNC interface. This flag gets reset if the last 20 packets were heard from non-TNC interfaces. We now check the heard_via_tnc_last_time timestamp to see if it's nonzero. This timestamp does _not_ get set to 0. The code in heard_via_tnc_in_past_hour() should work better for igating now. 2002-07-23 15:04 we7u * src/: interface_gui.c, xa_config.c: Changing txtail default value to from 10ms to 30ms. Should be proper for 1200 baud. 2002-07-23 14:37 we7u * README.1ST: Added Lindows to the list. 2002-07-23 14:27 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Turned "Full Duplex" KISS parameter into a togglebutton. 2002-07-23 13:43 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added TxTail parameter to the KISS properties dialog. 2002-07-23 13:07 we7u * src/messages_gui.c: Putting more debug messages under debug_level control. 2002-07-22 19:41 rzg * help/help-English.dat: Added mention of RELAY digipeating and fixed a formatting thing. 2002-07-22 11:08 we7u * configure, configure.in: Bumping it to version 1.1.3. Getting ready for another development release. 2002-07-22 10:41 we7u * src/: db.c, interface_gui.c: Commenting out debug message. Making Relay Digipeat togglebuttons insensitive until the code to implement them is functional. 2002-07-20 00:44 we7u * src/db.c: Don't relay from KISS interface if transmit for that interface is turned off. 2002-07-20 00:31 we7u * src/interface_gui.c: Changes to make RELAY digipeat insensitive when transmit is disabled for that interface. 2002-07-19 23:50 we7u * src/interface.c: Commenting out another debug statement. 2002-07-19 23:48 we7u * src/interface.c: Fixes to AX.25 interfaces that were broken earlier by KISS TNC changes. 2002-07-19 17:02 we7u * src/interface.c: Changes to serial lockfiles. Now closes port before removing lock. Attempts to close port and remove lock if open fails for any number of reasons. 2002-07-19 15:19 we7u * src/interface.c: Fixes for errant long packets. Code had the wrong number for the length of the incoming strings. 2002-07-19 13:51 we7u * src/: db.c, interface.c: Found an off-by-one error in incoming_data_length. Changed a lot of comments w.r.t. KISS interfaces. 2002-07-19 01:06 we7u * src/: db.c, db.h, interface.c, interface.h, main.c: More work on RELAY digipeating for Serial KISS TNC interfaces. Getting closer, but this version is still non-functional. 2002-07-18 17:02 we7u * src/: db.c, db.h, main.c: More preparation for later coding of the RELAY digipeat function. Not implemented yet. 2002-07-18 16:49 we7u * src/: db.c, main.c: More comments. 2002-07-18 16:48 we7u * src/interface.c: Fixing another double-lock problem. 2002-07-18 16:36 we7u * src/main.c: Added an important comment. 2002-07-18 16:34 we7u * src/interface.c: Fixing a double-lock problem that I introduced earlier today. 2002-07-18 14:55 we7u * src/interface_gui.c: Adding a debug_level statement in that was missing. 2002-07-18 14:47 we7u * src/interface_gui.c: Adding relay_digipeat stuff to the AX.25 interface GUI. 2002-07-18 14:40 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/interface.h, src/interface_gui.c, src/xa_config.c: Preliminary code including GUI support for RELAY digipeating on Serial KISS TNC interfaces. The back-end code is not implemented yet, so right now it looks pretty but doesn't do anything. The plan is to add similar support for AX.25 kernel interfaces. Regular serial TNC interfaces and NET interfaces don't need this capability. For regular serial TNC's RELAY digipeating is turned on/off in the config file for that interface. 2002-07-18 13:01 we7u * help/help-English.dat: Removed the serial port settings from the Serial KISS TNC descriptions. The port is set to 8N1 by default now and cannot be changed. 2002-07-18 12:59 we7u * src/interface_gui.c: Changed interface properties dialog when dealing with Serial KISS TNC interfaces: No longer is the user presented with serial parameter choices which are not allowed to be changed anyway. 2002-07-18 12:39 we7u * help/help-English.dat: Changed KISS interface description to agree with the code, which forces the N81 option for serial port parameters now. 2002-07-18 12:37 we7u * src/interface_gui.c: Forcing KISS interfaces to N81 for the serial port parameters. 2002-07-18 12:17 we7u * help/help-English.dat: Just spelling fixes. 2002-07-18 12:14 we7u * help/help-English.dat: A few minor additions/corrections to the KISS, TNC, and AX.25 interface descriptions. 2002-07-18 12:04 we7u * src/interface.c: Added some locks where a few were missing. Added code to send the KISS parameters down to the TNC when the port is first opened. 2002-07-18 10:45 rzg * help/help-English.dat: Updates for serial KISS TNC, message paths, igate paths, and more.. 2002-07-18 09:31 we7u * src/: db.c, db.h, interface.c, interface.h, interface_gui.c, main.c, messages_gui.c: Reorganized KISS parameter widgets in the dialog. Changed to string,length instead of relying on the terminating zero in the string for transmitting strings. This is due to the fact that KISS packets can have 0x00 in them as data. Fixed the problems with non-posit packet transmission and the Serial KISS TNC interface. 2002-07-17 18:01 we7u * src/: interface.c, interface.h, interface_gui.c, xa_config.c: Added kiss parameters to the properties dialog. 2002-07-17 16:17 we7u * src/main.c: Better behaved positioning of dialogs. They won't get positioned quite as far down the screen now. 2002-07-17 16:06 we7u * src/igate.c: Reformatted all of the igating routines. Added a specific check so that we don't re-inject TCPIP or TCPXX packets back into the internet (we don't want looping). The routines are much more understandable now and should be easier to maintain. 2002-07-17 13:54 we7u * src/interface.c: Changed/added comments. Deleted the section of code in port_read() that looked for AX.25 flag characters, as KISS packets should not normally contain them. We instead will try breaking apart the KISS packets based on \n and \r characters. 2002-07-17 13:05 we7u * src/: db.c, db.h: Changing to unsigned char for one parameter so that we can check all eight bits of each char. 2002-07-17 13:01 we7u * src/db.c: Lots of comment changes. Added check code to the decoding functions to look for and correct concatenated KISS packets. Currently the tacked-on packets will get deleted. This should get fixed in later revisions. 2002-07-17 12:25 we7u * src/interface.c: Reformatted, changed/added comments. No code changes. 2002-07-17 02:04 we7u * src/interface.c: Initial code to implement Serial KISS TNC transmit. 2002-07-16 17:00 we7u * src/interface.c: More preparation for doing KISS TNC transmit. Not finished yet. 2002-07-16 15:33 we7u * src/interface.c: Tweak to check for NULL in igate_path. Lot's of comment changes. 2002-07-16 14:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c: Fixed language string for KISS TNC dialog. Added comments. 2002-07-16 14:09 we7u * src/interface.c: A few more small tweaks to help with closing Serial KISS TNC interfaces. 2002-07-16 11:26 we7u * src/db.c: Added some comments. 2002-07-16 09:47 we7u * src/: db.c, db.h, interface.c, interface_gui.c, main.c: Initial implementation of Serial KISS TNC support. This one is receive-only. Still have to write the code to generate the outgoing AX.25 header for transmitting. This one may be unstable yet, but the instability should only affect Xastir instances with this port enabled. 2002-07-15 16:25 we7u * src/interface.c: Commented out some debugging code. 2002-07-15 16:24 we7u * src/: igate.c, interface.h, interface_gui.c, xa_config.c, main.c, interface.c: The start of code to implement serial port KISS tnc functionality (without using kernel-mode AX.25 ports). Not functional yet. 2002-07-15 16:03 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Just starting to add Serial KISS TNC capability. Not functional yet. 2002-07-15 01:02 we7u * src/interface.c: Fixed one problem with igate_path. Added a bunch of comments, reformatted some code, changed some variable names. 2002-07-13 10:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/main.c, src/messages.c, src/messages.h, src/messages_gui.c, src/wx.c, src/xastir.h: Implemented reverse path for messaging. Xastir now tries to figure out a reasonable return path when doing messaging. 2002-07-12 16:59 we7u * src/messages_gui.c: Adding some code in preparation for setting up individual return paths for messaging. This code figures out the return path from the last path received for that station, including dropping "RELAY" callsigns and asterisks and converting WIDEn-N callsigns to their original glory. Converts TRACE and TRACEn-N callsigns to WIDE and WIDEn-N as well. 2002-07-12 14:09 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/igate.c, src/interface.c, src/interface.h, src/interface_gui.c, src/main.c, src/messages.c, src/wx.c, src/xa_config.c: Implemented separate unproto path for igating. Change it via the properties dialog for affected interfaces. If nothing entered, it will round-robin between the other three interfaces or select a default path. 2002-07-12 12:15 we7u * src/db.c: Now have red circle around tracked station. 2002-07-12 11:08 we7u * src/: db.c, main.c: Added Maidenhead Grid Locator output to the Coordinate Calculator. 2002-07-12 09:52 we7u * src/main.c: Added mnemonics keys to the right mouse button menu. Now if you select it via the Maps menu you can still navigate through it via keyboard. Note that some of the options won't work properly without a mouse pointer pointing to an object on the screen, like Station Info. For those options needing to snag the mouse pointer, it appears to use whatever point the mouse pointer is on (as usual). If the pointer is outside the drawing area, all bets are off. 2002-07-11 17:20 we7u * src/db.c: Proper rounding of course when saving track data. 2002-07-11 16:54 we7u * src/db.c: Tweaking altitude/speed/course displays to skip over the first trackpoint, which is the same as our current data. We now look at the next oldest trackpoint to try to pull out slightly older data for display purposes. 2002-07-11 16:31 we7u * help/help-English.dat: A few changes to the SmartBeaconing parameter descriptions. 2002-07-11 16:22 we7u * src/db.c: Decoupling speed/course from each other for display purposes. 2002-07-11 16:10 we7u * src/util.c: Reducing PHG circles by 1/2, per Bob Bruninga's recommendations. 2002-07-11 15:46 we7u * src/db.c: Skipping first tracklog entry when filling in the Station Info dialog. It's the same as the first line or "Last Position". 2002-07-11 15:07 we7u * src/util.c: Small change to valid_path() to allow "qAC" and similar q-codes to pass through. This is a new addition from Dale Heatherington to the aprsd server for anti-looping purposes. 2002-07-11 14:45 we7u * src/db.c: Changed minimum length check for GGA/RMC strings and put one debug message inside debug_level logic. 2002-07-11 14:36 we7u * src/db.c: More general code for parsing RMC and GGA sentences. Now allows any number of digits after the decimal point for the lat/long fields. 2002-07-11 12:51 we7u * src/db.c: Tweak to make bad Mic-E positions not draw tracks. 2002-07-11 09:03 rzg * help/help-English.dat: Updates to new features list, added smartbeaconing help, other minor stuff. 2002-07-09 15:38 we7u * src/db.c: Expire code for trackpoints. Currently uses the station expire variable for choosing when to expire each trackpoint. Called from draw_trail() for each station. 2002-07-09 14:12 we7u * src/maps.c: Now outputs warning messages for Shapefile maps that have bad lat/lon values. This lets the user know which map files or which shapes within the file have problems. 2002-07-09 13:00 we7u * src/interface.c: Searching for excessively long packets earlier in the process. Now we drop them on the floor before the decode routines. 2002-07-09 11:12 we7u * src/db.c: Tweaked a debug line to output more data. 2002-07-09 10:55 we7u * src/: db.c, gps.c, interface.c, interface.h, main.c, util.c, wx.c: String lengths can be MAX_DEVICE_BUFFER length, currently defined to be 4096 characters, when going into the decode routines. These are fixes to handle these long line lengths in a graceful manner. 2002-07-08 20:17 rzg * src/db.c: Moving a newline in debugging code so it won't get lost. 2002-07-08 18:02 kd6zwr * src/maps.c: One more GNIS icon - parks. 2002-07-08 15:43 we7u * src/: alert.c, db.c, draw_symbols.c, interface.c, main.c, maps.c, messages.c, view_message_gui.c: Changing a bunch of comments. Mostly removing "we7u" bookmarks. 2002-07-07 18:30 rzg * README.1ST: Weather shapefiles are moving... 2002-07-04 11:26 we7u * src/: db.c, db.h, list_gui.c: Changes which implement dynamically-allocated tracklogs. Expiration and function which writes track to file need to be worked on yet. 2002-07-03 23:28 we7u * src/db.c: Slight reformatting and added a few comments. No real code changes. 2002-07-03 17:03 we7u * src/db.c: Commenting out some debug statements. 2002-07-03 16:59 we7u * src/db.c: Added a few comments. 2002-07-03 16:46 we7u * src/db.c: Found that the first trackpoint was getting skipped when displaying in Station Info dialog. Fixed it. We also now look in the first tracklog point for course/speed/altitude if any of these parameters are missing in the current data. Found other problems in tracklog indexing in db.c that need to be fixed yet. 2002-07-03 12:16 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/maps.c, src/xa_config.c: Added a new togglebutton that enables bulletin popup for new bulletins. Moved the smartbeacon enable button to its dialog. 2002-07-03 11:22 we7u * src/db.c: Reverting back to old Bulletin method for now. New method doesn't work right if bulletin received w/no posit, then posit is received later. 2002-07-03 11:14 we7u * README.1ST: Added a blurb about LD_LIBRARY_PATH variable being ignored when running Xastir as SUID root. 2002-07-03 11:10 we7u * src/: bulletin_gui.c, db.c: Fixed bulletins so that they don't pop up if distance is zero, unless the range setting is set to zero. It was getting much too annoying the other way when connected to a cached network feed. With the new code these things will cause bulletins to pop up: Distance non-zero and within range setting. Range setting set to zero. The user can also bring up the View->Bulletins dialog and it will still show the zero-range bulletins in any case. 2002-07-03 09:09 francais1 * src/maps.c: Applied, slightly tweaked and tested patch from Derrick Brashear which adds support for different PHOTOMETRIC geotiffs. 2002-07-02 16:25 we7u * src/: db.c, util.c, util.h: Added Maidenhead grid locators to Station Info dialog. Code by dl9sau which was derived from Wampes util/qth.c code by dk5sg. 2002-07-02 14:31 we7u * src/maps.c: Added more detailed debug messages for the case where lat/lon to be converted is outside the proper ranges. 2002-07-02 14:30 we7u * src/alert.c: Quieting some debug messages having to do with compressed weather alerts (which aren't implemented yet). 2002-07-02 12:40 we7u * src/main.c: Tweaked TigerMap config dialog so that strings in different languages would cause a resize of the dialog, and the dialog would be smaller/easier to use with smaller screen resolutions. 2002-07-02 11:10 n0vh * src/: main.c, maps.c, xa_config.c, xastir.h: Added code to allow the user to set the timeout for getting tigermaps from the menu. 2002-06-28 14:03 we7u * src/maps.c: Patch for corrupt fgd files by Derrick J Brashear. 2002-06-28 13:44 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/db.h: Separated out storage and display of comments/status. 2002-06-28 11:18 we7u * src/maps.c: Added an 'X' symbol and a nicely-drawn label for waypoing shapefiles. 2002-06-28 10:47 we7u * src/maps.c: Changes to make waypoint Shapefiles appear properly in Xastir. 2002-06-27 20:30 n0vh * src/main.c: More minor updates. 2002-06-27 20:21 n0vh * src/: main.c, track_gui.c: Clean up some of the tigermap menu items and reformatted them. 2002-06-27 13:12 we7u * README.1ST: Added notes regarding ld.so.cache to the Shapelib section. 2002-06-26 10:34 we7u * src/maps.c: Fix for missing IMAGESIZE tag in .geo file: We output an error message and skip loading that file. Someday we may wish to try to find out the imagesize via calls to the imagemagick or xpm libraries. 2002-06-26 09:46 we7u * src/db.c: Bulletins no longer cause a refresh of the Send Message dialogs. 2002-06-26 08:50 francais1 * src/: list_gui.c, list_gui.h, xa_config.c: Added a number of lists definition to the end of the list number definitions so that the code doesn't need touching every time you add a new list. Moved list number definitions to list_gui.h so that I can see them from xa_config.c. 2002-06-25 17:20 we7u * src/db.h: Added a line for is_my_call(). 2002-06-25 17:13 we7u * src/: list_gui.c, main.c, xa_config.c: New list for viewing objects/items that we own. 2002-06-25 17:12 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: New strings for new list. 2002-06-25 16:45 we7u * help/help-English.dat: Spelling. 2002-06-25 16:28 rzg * help/help-English.dat: Updated helpfile for recent changes. 2002-06-25 15:03 we7u * src/: bulletin_gui.c, bulletin_gui.h, db.c: Fixes for annoying bulletins. It should only pop up the bulletin dialog now when new bulletins come in that are within range. It's possible to receive a bulletin without having a posit from that station, then get a posit, making it outside the range. In this case you may get a popup without knowing why. It's better than what it was doing before though. 2002-06-25 12:41 we7u * src/: list_gui.c, main.c, xa_config.c: Added "View->Objects & Items" list. 2002-06-25 12:33 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Added string for new View->Objects & Items dialog. 2002-06-24 15:40 we7u * src/draw_symbols.c: Changed DF beam-heading objects to draw in red3. Using stippling the lines were not visible on some map backgrounds. Also narrowed the lines for pod_circles (not fully implemented yet). 2002-06-24 12:28 we7u * src/main.c: Added comments. No code changes. 2002-06-24 12:27 we7u * config/language-Portuguese.sys: Updates by David Quental, CT1DRB. Thanks! 2002-06-22 11:01 n0vh * src/track_gui.c: Update GUI so that the length of the track downloaded from FINDU can be selected. 2002-06-21 20:28 n0vh * src/maps.c: Commented all the findu code out from maps.c since it's now done from track_gui.c. It will be removed in the future. 2002-06-21 14:20 we7u * src/: draw_symbols.c, draw_symbols.h: Added draw_pod_circle() function. It has yet to be tied to a GUI anywhere. 2002-06-21 12:36 we7u * src/db.c: Added some comments. 2002-06-21 12:36 we7u * src/util.c: Added a comment. 2002-06-21 12:21 we7u * src/db.c: Leave my_last_speed in knots so it is consistent throughout the code. 2002-06-21 12:18 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Converted more strings to use langcode(). 2002-06-21 12:17 we7u * src/interface.c: Added some comments. 2002-06-21 12:15 we7u * src/gps.c: Added a commented-out debug statement. 2002-06-21 12:15 we7u * src/: draw_symbols.c, main.h: Added a comment. 2002-06-21 07:49 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Converted Coordinate Calculator to use langcode() strings. 2002-06-21 07:35 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added langcode() strings for the new Configure->SmartBeaconing dialog. 2002-06-21 07:02 we7u * src/main.c: Initial GUI for setting SmartBeaconing parameters. 2002-06-20 15:41 we7u * src/main.c: Adding bearing degrees to the Measure function. 2002-06-20 15:23 we7u * src/bulletin_gui.c: We now create the View->Bulletins dialog when bulletins come in. 2002-06-20 14:01 we7u * src/: igate.c, interface.c, messages.c: Added/modified some comments. 2002-06-20 12:47 we7u * src/interface.c: Added a 250ms delay after writing each waypoint. 2002-06-20 10:44 we7u * src/gps.c: Added some notes to the waypoint creation routine. 2002-06-20 10:36 we7u * src/gps.c: Fixed problem with lower-case characters when creating waypoints. 2002-06-19 17:17 we7u * src/: db.c, gps.c, gps.h, interface.c, interface.h: For those of you with Garmin GPS units: Set up the audio proximity alarm range for some distance around your station and Xastir will now create waypoints for each APRS station/object/item that it hears within that range. They'll appear on your Garmin map display as waypoints. Enjoy! You can delete the waypoints by type. They appear as the circle with the 'X' in the middle. You may want to change other waypoints to some other type before you play with this new Xastir feature. 2002-06-19 10:53 we7u * src/db.c: Fixed remove_leading_spaces() as it didn't work at all as coded. It liked to truncate after the first word. Also fixed some malloc sizes added recently. 2002-06-19 10:44 francais1 * src/db.c: strlen, not sizeof 2002-06-18 17:06 we7u * src/: db.c, db.h, list_gui.c: Additional memory savings for the node_path variable in the station database. Changed it to a pointer and allocate exact space for the string when stored or updated. 2002-06-18 16:19 we7u * src/: db.c, db.h, list_gui.c, main.c: More space savings. Turned comment into a pointer in the station record and allocate just the space we need for it. 2002-06-18 15:21 we7u * src/: db.c, db.h, list_gui.c, main.c: Changed to dynamically-allocated linked list of comment strings in the station database. This results in memory savings due to no empty strings being stored for stations without comment fields. It also shows all status and comment strings that have been seen for each station now in the Station Info dialog. We'll have loads of fun tracking MIC-E expansion on the internet servers now! 2002-06-18 11:55 we7u * src/draw_symbols.c: Simplifying the logic a bit. Same general idea. 2002-06-18 11:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c: Added "(tm)" everywhere "SmartBeaconing" was listed. 2002-06-18 11:07 we7u * AUTHORS, README.1ST: Notes and credit for the SmartBeaconing(tm) algorithm added. 2002-06-18 10:58 we7u * src/db.c: Changes to comments only. 2002-06-18 10:35 we7u * src/: db.c, draw_symbols.c: Changed they symbol time-since-heard color to white if over 24 hours. Added a bunch of comments for SmartBeaconing. 2002-06-17 16:16 we7u * src/db.c: Minor comment change. 2002-06-17 15:13 we7u * src/: db.c, main.c: Commenting out debug printf's. Changed some other comments. 2002-06-17 14:40 we7u * src/db.c: More comments. Another tweak to SmartBeaconing: If we've sped up a bit the code will now bring the next beacon in closer (in time), instead of waiting for the next slow beacon to reset to the slower interval. 2002-06-17 14:16 we7u * src/db.c: Added a few SmartBeaconing comments. 2002-06-17 13:11 we7u * src/: db.c, main.c: Another few SmartBeaconing tweaks. Setting defaults for variables to prevent multiple beacons as we get started. 2002-06-17 12:19 we7u * src/: db.c, main.c: A few SmartBeaconing tweaks. Commented out the experimental SmartBeaconing tweaks that caused a beacon when entering/exiting stop mode. Changed how other SmartBeaconing math was done. 2002-06-17 11:42 we7u * src/draw_symbols.c: Added color-coding for time-since-last-heard display. Green for 0-29 mins, Yellow for 30-59 minutes, Red for 60 mins to infinity. This is to help keep track of which stations are active and which haven't been heard for a while. 2002-06-17 10:16 we7u * src/db.c: Moved the "reversed symbol" message into a debug level. 2002-06-14 17:19 we7u * src/xa_config.c: Tweaking SmartBeaconing defaults to something more reasonable. 2002-06-14 15:51 we7u * src/xa_config.c: Saving SmartBeaconing parameters (all 7) in the config file. 2002-06-14 15:28 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/xa_config.c: Added Enable SmartBeaconing togglebutton, language strings for it, and save its state in the config file. More to do. 2002-06-14 14:15 we7u * src/: db.c, main.c, main.h: The beginnings of SmartBeaconing support. The working code is in there but the GUI interface is not coded yet. 2002-06-14 10:58 we7u * src/draw_symbols.c: Changed "time since last report" display to show "hr" and "min" based on time. 2002-06-13 16:42 we7u * src/db.c: Fix for compressed object/item comments getting eaten. 2002-06-13 15:53 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/draw_symbols.c, src/draw_symbols.h, src/main.c, src/main.h, src/xa_config.c: Added "Display Last Report Time" option to stations menu. 2002-06-13 14:07 we7u * src/db.c: Final fix for trail expiring on active objects/items. 2002-06-13 12:22 we7u * src/db.c: Fixes which check for locally controlled object/item which has moved. If it has, update the time-sorting of the record and update the timestamp in the station record. This should fix the problem where an expired object, when moved, stays ghosted. 2002-06-13 11:47 we7u * src/messages_gui.c: Making Send Message dialog wide enough so that spec-compliant-length messages won't wrap to a new line. 2002-06-13 11:21 we7u * src/: alert.c, maps.c: Converting a few more snprintf's to xastir_snprintf's. This change is necessary for those systems that don't have snprintf in their libraries. 2002-06-12 17:12 we7u * src/db.c: Added some notes regarding expiration of objects. 2002-06-12 16:29 we7u * src/: db.c, main.c, util.c: More fixes for compressed objects/items. Speed/course seem to be working now. 2002-06-12 16:23 we7u * help/help-English.dat: Minor changes regarding compressed objects/items. 2002-06-12 15:57 rzg * help/help-English.dat: Updates wrt. compressed objects/posits, and satellite ack mode. 2002-06-12 14:52 we7u * src/: db.c, main.c, util.c: A few fixes for compressed position objects/items. Adding course/speed to compressed objects/items as well. 2002-06-10 17:08 we7u * src/main.c: A minor tweak the position ambiguity togglebuttons having to do with switching compressed mode on and off. 2002-06-10 16:52 we7u * src/db.c: Disabling position ambiguity on receive end if a compressed posit is received for that station. 2002-06-10 16:46 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/main.h, src/xa_config.c: Moved the compressed_posit togglebutton to the Configure->Station dialog. Added a compress_objects_items togglebutton to the Configure->Defaults dialog. 2002-06-10 15:02 we7u * src/main.c: Fixes to give increased resolution for lat/lon when using compressed packets for objects/items. 2002-06-10 14:43 we7u * src/: db.c, util.c: Fixed compressed positions so that we can take advantage of the higher resolution. 2002-06-08 12:05 n0vh * src/xa_config.c: Added some missing #ifdef statements for tigermap data in the config file 2002-06-07 18:34 we7u * src/: db.c, main.c: Initial support for transmitting objects/items with compressed positions. They're not displaying in the proper positions on the map yet though. 2002-06-07 13:48 we7u * src/interface.c: Added debugging into to interface.c. Changed the way that we run through all interfaces when transmitting. 2002-06-07 13:42 we7u * src/util.c: Added support for lat/lon string conversions where we have more digits after the decimal point. 2002-06-07 11:10 we7u * src/: db.c, xastir.h: Bring up Locate Station window if an Emergency message is received. The operator has a choice whether to center on the station or just dismiss the dialog. 2002-06-07 09:48 n0vh * src/main.c: Load Tigermaps prior to disk maps so disk maps can be overlayed if desired. 2002-06-07 08:52 n0vh * src/main.c: Disable all maps now also functions with new TigerMaps routines. 2002-06-06 18:40 n0vh * src/maps.c: More code cleanup in the tigermap section. Still some optimizations to go. 2002-06-06 18:12 n0vh * src/xa_config.c: Updated to save the tiger_flag and tigermap_intensity in the users config file. 2002-06-06 17:02 we7u * src/db.c: Added a popup dialog for MIC-E emergency messages. Displays the callsign of the station in trouble. 2002-06-06 15:03 we7u * src/: messages.c, xa_config.c: Moved range checking for message_counter to xa_config. More efficient. Only needs to be done once when starting up. 2002-06-06 14:45 we7u * src/: messages.c, xa_config.c, xastir.h: Converted message_counter to a string. Changed message sequence numbers to be 2 characters within this range: 0-9A-Za-z. This prevents lockups when messaging with APRS+ stations. 2002-06-06 14:43 we7u * src/db.c: Removed old code. 2002-06-06 11:00 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/db.c, src/main.c, src/xastir.h: Implemented satellite ack mode, where the Reply/Ack protocol is used to send ack's through satellites, and ack's like "ack001" are disabled entirely. 2002-06-06 10:03 we7u * src/: db.c, db.h, messages.c: Changes which implement full Reply/Ack protocol. This should speed up messaging dramatically when involved in live QSO's with the APRS programs that support this protocol. This lists currently includes aprsDOS, APRS+, and Xastir. 2002-06-05 13:28 we7u * src/: db.c, db.h, messages.c: Marking timed-out messages in Send Message dialog properly. Small changes to Reply/Ack sequence numbers. 2002-06-04 16:13 we7u * src/: messages.c, xa_config.c: Switching to base-90 for message sequence numbers (all the way to lower-case 'z'). Also tweaked xa_config.c to help us avoid the message_counter rollover problem. 2002-06-04 15:47 we7u * src/messages.c: Changed from base-91 to base-89 format for message sequence numbers. This is to avoid use of the '{' character within the sequence. 2002-06-04 15:25 we7u * src/messages.c: Converted outgoing sequence numbers to 2-character base-91 encoding. Added a trailing '}' character to signify that we're Reply-Ack protocol capable. 2002-06-04 14:32 we7u * src/messages.c: Had to take out the '}' from the sequence number as it messed things up. 2002-06-04 14:20 we7u * src/: db.c, messages.c: Message sequence numbers are saved through restarts now. Added more comments. 2002-06-04 13:27 we7u * src/db.c: Changed several comments. Decoding of Reply/Ack protocol (free-ride ACK's) is now tested and working. This really speeds up live messaging. When encoding of the free-ride ACK's is implemented as well it'll speed up messaging even more. 2002-06-03 17:50 rzg * README.1ST, help/help-English.dat: Updates for tigermap changes and minor bits I missed in the previous update. 2002-06-03 13:30 we7u * src/db.c: Minor changes to Reply/Ack's. 2002-06-03 13:14 we7u * src/db.c: The beginnings of Reply/Ack protocol decode. Not fully tested. Encode not implemented yet. 2002-06-03 09:45 francais1 * src/maps.c: Fixed up imagemagick_options struct a bit. Removed some imagemagick_options stuff from draw_tiger_map because it is not being setup since there is no .geo file. Fixed draw_tiger_map intensity/levels bug. 2002-06-03 09:21 we7u * src/maps.c: Changing some line widths and colors back to what we had before the weekend. We're not trying to duplicate the TigerMap servers colors or look-and-feel. We need more subdued colors so that symbols and tracks show up better on top of the maps. The line widths are necessary in order to more quickly identify major roads without having to rely only on color. 2002-06-03 09:18 francais1 * src/maps.c: Removed extraneous ifdef 2002-06-03 08:38 we7u * src/gps.c: Fixes for decoding GPS NMEA sentences where there are 4 digits after the decimal point. Garmin GPS-35 and the NavMan both put out an extra digit. 2002-06-03 07:59 we7u * src/main.c: Fixed segfault bug in Config_tiger. 2002-06-03 07:23 we7u * src/maps.c: Added another #ifdef around a LevelImage() call. 2002-06-02 14:59 n0vh * config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/maps.c, src/xastir.h: Made more updates to support tigermap menu item. A file is no longer required. Also, I made display of tigermaps a separate subroutine. This should probably be done with some of the other items in draw_geo_image_map as well. N0VH 2002-06-02 14:54 n0vh * config/language-Dutch.sys: Made more updates to support tigermap menu item. A file is no longer required. Also, I made display of tigermaps a separate subroutine. This should probably be done with some of the other items in draw_geo_image_map as well. N0VH 2002-06-01 12:00 n0vh * src/: main.c, maps.c: Added Tigermap menu support. 2002-06-01 11:59 n0vh * src/xastir.h: Added some external vars to support Tigermap menus. 2002-06-01 11:54 n0vh * config/language-Spanish.sys: Added items to support Tigermap menus. 2002-06-01 11:52 n0vh * config/language-Italian.sys: Added items to support Tigermap menu. 2002-06-01 11:50 n0vh * config/: language-French.sys, language-German.sys, language-Portuguese.sys: Added items to support Tigermap menus. 2002-06-01 11:49 n0vh * config/language-English.sys: Added items to support Tigermap configuration menus. 2002-06-01 11:47 n0vh * config/language-Dutch.sys: Added new lines to support the Tigermap configuration menus. 2002-06-01 11:46 n0vh * README.1ST: Removed reference to putting TIGERMAP in a .geo file which no longer works. 2002-05-31 17:32 we7u * src/db.c: Initial attempt to handle Reply/Ack messaging protocol (on the receive side only). Only implemented for APRS messaging, not UI-View messaging. 2002-05-31 14:24 we7u * src/db.c: Fixes for last_ack timer. We now refuse to send ack's or auto_answer messages any faster than every 30 seconds, even if multiple interfaces are sending us copies of the same message. 2002-05-31 12:36 we7u * src/maps.c: Simplified the print properties dialog. Commented out unused options. 2002-05-30 08:04 n0vh * src/igate.c: More cleanup of the status messages written to the console. 2002-05-29 21:32 n0vh * src/igate.c: Cleaned up some of the status messages by adding a newline to the end. 2002-05-29 17:07 francais1 * src/maps.c: Imagemagick drawing speedup for some cases. 2002-05-29 16:59 francais1 * src/: util.c, util.h: Added a simple function to roughly time code execution. 2002-05-28 09:48 we7u * src/xa_config.c: Patch for incorrect lat/long limits by Henk de Groot, PE1DNN. Thanks Henk! 2002-05-24 17:07 we7u * src/: db.c, db.h: Attempting to get rid of duplicate ack's and autoreply messages. This attempt is at least partially successful. 2002-05-24 15:01 we7u * src/: db.c, util.c: Fixed spelling error in util.c. Fixes for incorrect sorting in Send Message window for the case where the remote client has restarted and is re-using sequence numbers: Xastir will now replace the older messages in the database and update the timestamp, which keeps the proper ordering for a QSO. Messages older than 8 hours with the same text will also get replaced and get a new timestamp. 2002-05-22 14:05 we7u * src/: gps.c, interface.c, interface_gui.c, xa_config.c: Mods for CYGWIN by Charles Suprin, AA1VS. 2002-05-21 14:33 we7u * src/db.c: Getting rid of unneeded extra message_update() calls. 2002-05-21 12:27 we7u * src/db.c: More messaging fixes. 2002-05-21 12:02 we7u * src/: messages_gui.c, db.c: Fixes for text corruption in Send Message window. Needs further testing. 2002-05-21 10:19 we7u * src/: util.c, view_message_gui.c: Fixing distance calculation such that it returns 0.0 if we haven't heard a posit from the remote station yet. 2002-05-21 09:18 we7u * src/view_message_gui.c: View->Messages history dump now obeys the distance limit set at the top of the form. 2002-05-20 14:49 we7u * src/: view_message_gui.c, xa_config.c: We now dump all currently active messages out to the view->messages window when it's first opened. Different format, but still useful. The format is easily tweaked later. Also changed the default VIEW_MESSAGE_LIMIT to 10000. This can be tweaked by the user in the ~/.xastir/xastir.cnf file. Max allowed by the code is now 99999. 2002-05-18 00:06 kd6zwr * src/maps.c: Draw symbols for GNIS files. 2002-05-17 16:55 we7u * src/interface.c: Temporary fix for CYGWIN. Disables use of HSP adapter. Better fix needs to be implemented. 2002-05-17 16:52 we7u * src/interface_gui.c: Mods for CYGWIN. 2002-05-17 15:56 we7u * src/: main.c, messages_gui.c: Added as another method to send a message in the Send Message dialog. 2002-05-17 15:26 we7u * src/db.c: Quick check for a zero time in the message database. If found, fill in with current time and print out a warning. 2002-05-17 14:14 we7u * src/db.c: Only cause a Send Message dialog update on the first ack. Subsequent ack's cause no update. 2002-05-17 11:37 we7u * src/db.c: Update message windows only when the first message or the first ack comes in, or when the message doesn't match the same sequence number message already stored. This helps to reduce flashing of the messages windows due to multiple copies of ack's/messages being received. 2002-05-17 00:01 we7u * src/db.c: Changes to eliminate dupes in Send Message dialog. Also changes to keep the message sequence more normal. 2002-05-16 16:29 we7u * src/: db.c, interface.c: Fixes for reverse video instantly on sending a message, before it's acked. 2002-05-16 15:35 we7u * src/db.c: Messaging fixes. Outstanding packets are now reverse video. 2002-05-16 14:47 we7u * src/: db.c, db.h, messages.c: The start of visual indicators for unacked messages. Not completely working yet, but doesn't break functionality either. 2002-05-16 09:38 we7u * src/: gps.c, interface_gui.c: Fixes for Mac OS X (no strptime call), and for non-linux systems. The "Set System Clock from GPS Data?" togglebutton should be grey'ed out now for non-linux systems. 2002-05-14 20:26 rzg * help/help-English.dat: Updated/rewrote .geo section for n7tap's new additions. 2002-05-14 11:56 francais1 * src/maps.c: Backed out previous change. 2002-05-14 09:56 n0vh * src/maps.c: [no log message] 2002-05-10 17:22 we7u * src/messages_gui.c: Allowing multiple messages to be queued up without having to wait for an ack for each one. 2002-05-10 17:21 we7u * src/messages.c: Allowing multiple messages to get queued up without having to wait for an ack for each one. 2002-05-10 17:20 we7u * src/db.c: Reformatted one line. No code changes. 2002-05-10 15:50 we7u * src/: messages.c, messages.h: Slightly better timing of messaging. Also free's up the queue after a message times out. More work to be done. 2002-05-10 15:22 we7u * src/db.c: Added some notes about a bug in messaging. 2002-05-10 08:08 francais1 * src/main.c: Added a missing if defined HAVE_IMAGEMAGICK 2002-05-09 22:59 we7u * src/: db.c, main.c, messages.c, messages_gui.c: Messaging in the Send Message dialog are now sorted by time. The window is also resizable now in both directions. The 5-second update of the window has been replaced by code which updates the window whenever new messages arrive. 2002-05-09 16:34 francais1 * src/maps.c: Fixes for older imagemagick versions. 2002-05-09 15:29 francais1 * src/: color.c, color.h, main.c, maps.c, maps.h, xa_config.c: Sped up drawing of DirectColor images on a DirectColor screen. It was very slow because it called XAllocColor for every pixel in a jpeg. It now uses saved information on the default display visual to pack the RGB into the correct bits for the pixel. I did this because I was finding some nasty color effects with the image intensity settings. I decided to leave image intensity around for geotiffs, but now use gamma correction from Imagemagick for all other image formats that go through imagemagick. There can now be a gamma setting in each .geo file and there is an overall adjustment which will subtract or add to the individual image gamma. While I was at it, I enabled the ability to specify several of the imagemagick enhancement functions in .geo files. 2002-05-09 14:31 we7u * src/main.c: Filling the drawing area with grey right away. Gets rid of garbage that shows up on the screen sometimes when starting Xastir. 2002-05-09 13:28 we7u * xastir.spec.in, scripts/Makefile.am, scripts/Makefile.in: Tweaks to make the appropriate scripts get installed in /usr/local/bin, with the appropriate execute permissions. 2002-05-09 13:07 we7u * help/help-English.dat: Correcting spelling of "finger". 2002-05-09 13:04 we7u * Makefile.am, Makefile.in: Adding the scripts directory as a target of the Makefiles. 2002-05-09 12:58 rzg * README, README.1ST, help/help-English.dat: Assorted helpfile updates: point shapefiles, weather stipples, and random work on README. 2002-05-09 12:55 rzg * FAQ: Changes "XASTIR" to "Xastir" to match other docs. 2002-05-09 12:34 we7u * configure, configure.in, xastir.spec.in: Tweaks to install scripts into /usr/local/xastir/script/ directory. 2002-05-09 12:33 we7u * scripts/: Makefile.am, Makefile.in: Adding Makefiles to install scripts into /usr/local/xastir/scripts/ directory. 2002-05-08 13:52 we7u * scripts/waypoint-get.pl: Here's the companion script to track-get.pl. This one will snag all of the waypoints out of a Garmin GPS and create an APRS item out of each one. The resulting file can be read in by Xastir as a log file to make the waypoints appear on the map screen. 2002-05-08 12:48 we7u * scripts/track-get.pl: Added another message at the end. 2002-05-08 12:38 we7u * src/: db.c, main.c, main.h: Fixes for some compiler warnings, by Chris Bell, KD6ZWR. 2002-05-08 12:04 we7u * scripts/track-get.pl: New Perl script which can fetch the tracklog from a Garmin GPS, then create a log file which can be read by Xastir. Read in the log file and you'll have a track on Xastir's map screen. Needs tweaks to Xastir in order to view more than 100 points of the track at a time. 2002-05-07 22:45 we7u * src/maps.c: GNIS code fixes by Chris Bell, KD6ZWR. 2002-05-07 11:40 we7u * src/: main.c, maps.h: Xastir will now do a PNG snapshot every time the "Enable PNG Snapshots" button is re-enabled. This beats waiting 5 minutes for the next snapshot while you're experimenting with things. 2002-05-06 22:19 we7u * src/maps.c: First implementation of Point-type Shapefiles. Seems to work fine so far. 2002-05-06 16:04 we7u * src/db.c: Reformatting a warning message to make sure that we only output printable chars to STDOUT. 2002-05-06 15:01 we7u * src/: db.c, util.c: Fixes for AEA formatted headers. They now should get converted properly to TAPR-2 style headers. What was missing was the re-arranging of the callsigns in the header to the correct order. 2002-05-05 17:53 we7u * src/maps.c: Changing default color for pedestrian trails, used if later code doesn't set the color explicitly. 2002-05-04 09:55 we7u * src/xa_config.c: Another tweak to limits checking. 2002-05-03 22:38 we7u * src/xa_config.c: Tweaking the value limits for list window sizes. 2002-05-03 16:52 we7u * src/maps.c: Fixing a segfault for non Tiger-based Shapefiles (like the NOAA interstates file). 2002-05-03 15:58 we7u * src/maps.c: Fix for incorrect line colors at times for Shapefiles. We also make city borders narrower as we zoom out. 2002-05-03 15:16 francais1 * src/list_gui.c: Added mouse scroll wheel support to list dialogs. Uses standard button4/5 method no modifier moves 2 lines shift moves 1 line control moves 10 lines 2002-05-03 13:52 we7u * src/maps.c: Changing colors of cities and borders around/between cities. 2002-05-03 12:28 we7u * src/maps.c: More subdued colors for the major roads. Cranked the width down a bit too. 2002-05-03 12:14 we7u * src/maps.c: Setting up more default colors. Pedestrian trails are now red. Dashed lines for trails, 4WD roads, ferry crossings. Glaciers are now white. 2002-05-03 10:22 we7u * src/maps.c: Getting rid of compiler warning by adding "color.h" as an include file. This is needed for the GetPixelByName() call I added. 2002-05-03 09:57 we7u * src/maps.c: Cleaning up properly with warning message for Point and Multipoint Shapefiles, which aren't implemented yet in Xastir. 2002-05-02 16:53 we7u * src/maps.c: This ones for Ken: Download and select plc00 files from GeographyNetwork to get the "designated places" boundaries filled in with PaleGoldenrod color. The code will also label these areas. Create the following subdirectories to get the layering right: county (cty00) designated_places (plc00) h2o (lkH and wat) misc (lkC) rail (lkB) roads (lkA) 2002-05-02 14:25 we7u * src/maps.c: Changing water back to Steel Blue. 2002-05-02 13:58 we7u * src/maps.c: More comments. Shortened another string "State Route" to "State" that occurs in the ESRI Tiger/Line Shapefiles. Changed the county polygon back to gray so that tracks show up better. 2002-05-02 12:28 we7u * src/maps.c: Added comments. Made some optimizations in the Shapefile code. Shortened some labels that get drawn. 2002-05-01 20:28 rzg * README.1ST: Update to README.1ST with more shapefile locations and other minor edits. 2002-05-01 15:43 we7u * src/maps.c: Changing how many labels appear at certain zoom levels with Shapefiles. 2002-05-01 15:12 we7u * src/maps.c: Optimization: Only doing floating point operations for label rotation when we know we're going to be drawing the label. Changes by Chris Bell to help alleviate upside-down labels. 2002-05-01 14:23 we7u * src/maps.c: Rotated labels for Shapefile maps. This be a good thing! 2002-05-01 12:11 we7u * src/maps.c: Better label drawing. Quantities of identical labels drawn in the viewport are now determined by zoom level. 2002-04-30 17:08 we7u * src/db.c: Fixing directed query responses. They now show up in a popup window. 2002-04-30 15:53 we7u * src/: main.c, xa_config.c, xa_config.h: get_int() and get_long() now check for min/max values, and assign a default value if the number is outside this range. Also prints a warning message if it has to assign the default. 2002-04-30 13:50 we7u * src/maps.c: Changing the levels at which smaller roads and labels for those roads get drawn. All roads are drawn at zoom 64 and lower. Labels for small roads start showing up at zoom 16 and lower. 2002-04-30 11:57 we7u * src/maps.c: Converting back to "convert" without path until we get configure support for figuring out the path. 2002-04-30 11:31 we7u * src/maps.c: Adding another path to convert. 2002-04-30 11:30 we7u * src/maps.c: Added path to "convert" command. Added checks around system() command. 2002-04-29 17:02 we7u * src/maps.c: Fixed some conversion problems when converting to screen coordinate system. 2002-04-29 10:40 we7u * src/maps.c: Implemented map levels for the Shapefile code. The togglebutton in the Maps menu now works for Shapefiles. 2002-04-27 16:47 we7u * src/maps.c: Setting up more zoom levels for Shapefile roads. 2002-04-27 16:03 we7u * src/maps.c: Created linked list for Shapelib labels already drawn. Keeps us from drawing 50 labels that all say the same thing. Added some zoom levels for labels of various types. 2002-04-27 12:52 we7u * src/maps.c: Getting rid of lesser roads at zoom levels 100 and above. 2002-04-27 07:59 we7u * src/maps.c: Reducing the width of water until I can figure out how Tigermap decided to determine their width. 2002-04-26 23:39 we7u * src/maps.c: A few color & width changes for shapefile maps. 2002-04-26 16:51 we7u * src/maps.c: Setting number of lanes (line width) for Tiger and Mapshots maps. 2002-04-26 11:27 we7u * src/maps.c: Changed paths to a brown color. 2002-04-26 11:14 we7u * src/maps.c: Corrected some of the headings. Split railroads out as a separate flag and a new color. 2002-04-26 10:16 we7u * src/: main.c, main.h, xa_config.c: Created a #define in main.h for enabling/disabling the "Transmit Raw WX data" togglebutton. The #define enabling this button is commented out. Most likely the only people interested in this button would be people debugging code for certain Peet Bros. weather stations where the raw data from them is allowed over the air by the APRS spec. 2002-04-26 08:53 francais1 * src/: main.c, maps.h, xa_config.c: Make map intensity menu show up in the correct cases. 2002-04-26 08:50 francais1 * src/maps.c: Make GNIS labels more readable 2002-04-25 16:04 we7u * src/maps.c: Fixing up mapshots maps for rivers/lakes. Also being proactive in trying to eliminate possible future segfaults in the Shapelib code. 2002-04-25 14:23 we7u * src/maps.c: Label fix for mapshots.com roads. 2002-04-25 13:18 we7u * src/maps.c: Changed fill color for land masses from darkgray to grey73 (a bit lighter, and the same color as the menus). 2002-04-25 11:56 we7u * src/maps.c: Added shapefile decoding of colors/types for mapshots.com county maps made from tiger data. 2002-04-25 10:52 we7u * src/maps.c: Added some comments. 2002-04-25 00:00 we7u * src/: maps.c, maps.h: Fixes for Shapefile segfaults: Can't retrieve a field that's higher than fieldcount, else segfault. 2002-04-24 16:00 we7u * src/: maps.c, maps.h: Fix for segfaults in Shapefiles. 2002-04-24 15:23 francais1 * src/maps.c: Tweaked some color problems with turning labels on. Tweaked river drawing slightly. 2002-04-24 15:09 francais1 * src/maps.c: Made gnis map files draw regardless of the labels setting since a gnis map is all labels, so if you picked it, you want it drawn, period. 2002-04-24 14:23 we7u * src/maps.c: Adding missing free() calls in draw_shapefile_map(). 2002-04-24 13:06 we7u * src/maps.c: Fixing segfault problem with Shapefile maps. 2002-04-24 11:28 francais1 * src/maps.c: IMHO, I've improved the guessing of what shapefile we are dealing with and also the drawing colors and style... 2002-04-24 11:24 francais1 * src/: draw_symbols.c, main.c, xastir.h: Changed name of pixmap_stipple to pixmap_2x2_stipple and made it load from an xbm 2002-04-24 11:23 we7u * src/maps.c: Minor change to get rid of compiler warning. Changed static variable to non-static. 2002-04-24 11:08 francais1 * symbols/: 2x2.xbm, Makefile.am, Makefile.in: Added bitmap for 50% stipple 2002-04-24 10:51 francais1 * src/: util.c, util.h: A couple new functions that will be useful for UTM grid 2002-04-24 10:50 francais1 * src/main.c: Added SteelBlue for drawing lakes, rivers (plain blue seemed pretty harsh and SteelBlue is a background color as well, so that it can be the ocean) 2002-04-24 09:58 we7u * src/xa_config.c: Commented out annoying debug statements that get in the way each time. 2002-04-24 09:54 we7u * src/: alert.h, maps.c: Speedups for weather alerts. Once we know what the bounding rectangle is for an alert, we stuff it into the alert struct. load_alert_maps() then uses that info to determine whether a shape is within the viewport, without having to snag that info from the Shapefile each time. 2002-04-24 09:20 we7u * src/maps.c: Removed old code. Put in warning printf for old weather alert stuff in routine that doesn't handle it anymore. Changed some comments. 2002-04-24 08:41 francais1 * src/maps.c: Added equator and central meridian drawing as a black line when a grid is asked for. Teasing for utm grid drawing. 2002-04-24 01:06 we7u * src/: alert.c, alert.h, maps.c: Added "index" field to alert records, initially set to -1. This gets filled in with the index into the Shapefile when the shape is searched for. This dramatically speeds up drawing of weather alerts 'cuz the search is skipped on the 2nd and later uses of the alert. 2002-04-23 23:03 francais1 * src/: main.c, maps.c, xastir.h: Initial support for using stipples for weather alerts with a description of the alert event. 2002-04-23 22:57 francais1 * symbols/: Makefile.am, Makefile.in, alert.xbm, flood.xbm, snow.xbm, tornado.xbm, wind.xbm, winter_wx.xbm, wntr_strm.xbm: Added bitmap files for use as weather map stipples 2002-04-23 22:08 francais1 * src/maps.c: Fixed indentation 2002-04-23 17:01 we7u * src/wx_gui.c: Detailed weather alerts now show up in their own resizable dialog. 2002-04-23 16:39 francais1 * src/main.c: Added support for zooming in and out with buttons 6 & 7 and for panning up and down with the scroll wheel. 2002-04-23 00:31 we7u * src/: alert.c, wx_gui.c: Cleaning up some debug messages I put in for the weather alert code. 2002-04-22 23:32 we7u * src/wx_gui.c: Added the capability to finger the weather server by double-clicking on a weather alert line in the View->Weather Alerts dialog. The output currently appears in the xterm that you start Xastir from. 2002-04-22 23:14 we7u * src/wx_gui.c: Changed View->Weather Alerts dialog to single-select mode. Added a callback and callback function for the double-click operation. 2002-04-22 22:46 we7u * src/wx_gui.c: Changed View->Weather Alerts dialog so that it can be resized. 2002-04-22 22:16 we7u * src/: alert.c, alert.h, db.c, wx_gui.c: Decoded SKY alerts. They now get associated with the proper weather alert packets. Tweaked View->Weather Alerts dialog to display them properly and added a horizontal scrollbar to that dialog. 2002-04-22 17:03 rzg * FAQ: Fixed the numbering.... 2002-04-22 16:57 rzg * FAQ, README.1ST, help/help-English.dat: Updates to FAQ, README.1ST. and help=English.dat, mostly with regard to the weather alert changeover to shapefile format. 2002-04-22 14:08 we7u * src/alert.c: Fix to weather alerts. Expired alerts will now be removed from the View->Weather Alert dialog after they've been expired more than one hour. 2002-04-22 09:57 we7u * src/alert.c: The start of adding "CIVIL" as another weather alert. Not completely functional yet. Also added more of Dale Hugueley's comments. 2002-04-22 09:47 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. Thanks! 2002-04-20 21:26 we7u * src/db.c: Slight reformatting. 2002-04-20 15:13 we7u * src/alert.c: Took out last patch. New alerts will now create a new entry, even if there is a cancel with the same zone that was received earlier. 2002-04-20 12:23 we7u * src/maps.c: Fix for changing line widths on shapefile maps. 2002-04-20 10:48 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. Thanks! 2002-04-20 10:34 we7u * README.1ST: Updated the APRS Server list. 2002-04-19 21:16 we7u * src/: alert.c, maps.c: Fixes for weather alerts. CANCL packets are starting to work now. 2002-04-19 16:27 we7u * src/: alert.c, alert.h, maps.c: Changed global variable "alert_tag" to "alert_status" so that it won't be confused with the alert struct "alert_tag" field. Added loads of comments. 2002-04-19 13:58 we7u * src/alert.c: More comments. 2002-04-19 12:30 we7u * src/alert.c: Updated some comments. 2002-04-19 09:29 we7u * src/wx_gui.c: Slight reformatting of View->Weather Alerts dialog. 2002-04-19 00:11 we7u * src/wx_gui.c: Reformatted View->Weather Alerts dialog slightly: Shorter lines and easier to read. 2002-04-18 23:42 we7u * src/: alert.c, alert.h, wx_gui.c: Added issue date/time to weather alerts and View->Weather Alerts dialog. 2002-04-18 21:42 we7u * xastir.1: Minor tweaks to eliminate redundancy, shorten the copyright years, make the words flow better. 2002-04-18 17:38 rzg * xastir.1: Minor formatting changes to look more manpage-like. 2002-04-18 16:39 we7u * src/maps.c: Speedup for weather alerts. Skip searching through Shapefiles if we already have a filename for the alert. 2002-04-18 15:59 we7u * xastir.1: Added the "-i" flag (private colormap) to the man page. 2002-04-18 15:46 francais1 * src/: main.c, maps.c: I don't believe we need to check if it is a symbolic link when we use stat, because it will follow the link. 2002-04-18 15:28 we7u * src/: color.c, db.c, main.c, maps.c, xa_config.c, xastir.h: Private colormap changes by Chris Bell, KD6ZWR. Change to weather alert timing by WE7U. 2002-04-18 12:58 we7u * config/language-Portuguese.sys: Changes by David Quental, CT1DRB. 2002-04-18 09:11 we7u * src/maps.c: Corrected some comments. Corrected some filename prefixes. Added the capability to use symbolic linked files as weather alerts (I think, not fully tested yet). 2002-04-18 09:10 we7u * src/wx_gui.c: Added "Expired:" tag to expired weather alerts in the View->Weather Alerts dialog. 2002-04-18 09:09 we7u * src/main.c: Added the capability to read symbolic links as maps (I think). Not fully tested yet. 2002-04-18 09:08 we7u * src/alert.c: Added some comments. 2002-04-17 16:57 we7u * src/alert.c: Changed some comments. 2002-04-17 16:48 we7u * src/: alert.c, main.c, maps.c, xa_config.c: More weather alert tweaks, including the beginning of compressed weather alert decoding. 2002-04-17 13:58 we7u * src/wx_gui.c: Reformatted weather alert expire date/time in View->Weather Alerts dialog. 2002-04-17 13:52 we7u * src/: alert.c, wx_gui.c: Fixed parsing problem for weather alerts where objects after a space were being parsed as new alerts. 2002-04-17 12:58 we7u * src/: alert.c, alert.h, db.c, wx_gui.c: Changing View->Weather Alerts dialog so that it displays the data we'll need for fingering the weather server to get additional data about a particular alert. 2002-04-17 11:36 we7u * src/maps.c: Fix for weather alerts disappearing at different zoom levels or while panning around. The problem had to do with the alert getting marked as being outside the viewport, then they wouldn't be looked at again. 2002-04-16 18:02 we7u * src/maps.c: closedir() to go with the opendir(). ;-) 2002-04-16 16:17 we7u * src/maps.c: Fixes for "too many open files" in shapefile weather alerts. 2002-04-16 14:16 we7u * src/: alert.c, db.c, maps.c: Fixes to regular shapefile maps. Cleanup after shapefile weather alert additions. 2002-04-16 12:44 we7u * src/maps.c: Fixes for county weather warning alerts. 2002-04-16 11:34 we7u * src/: alert.c, maps.c, xa_config.c: Shapefile wx alert changes. Starting to work for zones. More work to do on other types. 2002-04-16 09:17 we7u * src/maps.c: Fix for Shapefile weather alerts. Nearly there now. 2002-04-16 02:19 we7u * src/maps.c: More shapefile wx alert changes. 2002-04-16 01:03 we7u * src/maps.c: More weather alert shapefile coding done. 2002-04-15 21:30 we7u * src/maps.c: We now figure out the complete filename starting with the first few characters of the shapefile. We look in the directory to figure out a match for the zone. This should make it so that we can update the shapefiles at any time and won't have to change any configuration or code in order to use the new files. 2002-04-15 20:30 we7u * src/maps.c: Initial decoding for the different types of weather alerts. Soon we'll be able to match up real filenames to the zones and start drawing them. 2002-04-15 17:07 we7u * src/maps.c: Added some more comments. 2002-04-15 16:04 we7u * src/: alert.c, db.c, maps.c: I'm breaking the weather alerts by checking in this code, but have tagged the "stable" repository with a "we7u-safe" tag, so we can recover if things get broken too badly. Forward we go! I've also released xastir-1.1.2 in the development area of the Files section on SourceForge. That is the "we7u-safe" tagged version of the sources. 2002-04-12 15:49 we7u * src/wx.c: Changing to capital 'X' for the weather-station-type designator in our transmitted weather reports, per Bob Bruninga's ok on the APRSSPEC mailing list, 04/12/2002. 2002-04-12 14:50 we7u * src/maps.c: Shapefile wx alert small changes. We're not there yet. 2002-04-12 12:50 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Portuguese.sys, language-Spanish.sys: Tweaked one popup message. 2002-04-12 11:11 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: We now allow four different symbols for weather stations, but print a warning if trying to use an NWS symbol. If trying to run a weather station with a different symbol, the software will set the symbol to the standard weather symbol automatically. 2002-04-11 23:04 we7u * src/alert.c: Changed some comments. 2002-04-11 16:02 we7u * src/alert.c: More comments. 2002-04-11 14:49 we7u * src/alert.c: More comments. 2002-04-11 12:58 we7u * src/alert.c: Changed a comment. 2002-04-11 12:58 we7u * src/alert.c: Changed some comments. 2002-04-11 12:53 we7u * src/alert.c: More comments. 2002-04-11 12:52 we7u * src/alert.c: More comments added. 2002-04-11 12:46 we7u * src/alert.c: More comments added. 2002-04-11 12:01 we7u * src/alert.c: More comments. 2002-04-11 11:40 we7u * src/alert.c: More comments. 2002-04-11 11:27 we7u * src/alert.c: Reformatted some of the code, added comments. Preparing for Shapefile weather alert coding. 2002-04-11 10:13 we7u * src/alert.c: Fixed possible string overrun. Added a few comments. 2002-04-10 21:28 we7u * xastir.1: Updates by Jose Marte, HI8GN. 2002-04-10 16:59 we7u * src/alert.c: Added more comments. 2002-04-10 16:02 we7u * src/alert.c: Added a bunch of comments. 2002-04-10 14:35 we7u * src/db.c: Changed one output message to make it more correct. 2002-04-10 13:03 we7u * src/util.c: Fixing a compile warning for MacOS X. 2002-04-10 12:58 we7u * src/lang.c: Fixing a warning which shows up while compiling on MacOS X. 2002-04-10 12:00 we7u * Makefile.am, Makefile.in: Changed to more standard way of specifying man pages. 2002-04-10 10:21 we7u * configure, configure.in, src/wx.c: Bumped up to version number 1.1.2 to more easily see who's running the latest weather code. Added some comments to wx.c 2002-04-09 23:28 we7u * src/wx.c: Adding more casts back in. 2002-04-09 23:04 we7u * src/wx.c: Adding some necessary casts back in to the weather code. 2002-04-09 21:53 we7u * Makefile.am, Makefile.in: Tweaked Makefiles to install new Xastir man page. 2002-04-09 21:41 we7u * xastir.1: A few small tweaks. 2002-04-09 21:33 we7u * xastir.1: Initial man page by Jose R. Marte A., HI8GN. 2002-04-09 21:33 we7u * xastir.spec.in: Man page added by Jose R. Marte A., HI8GN. 2002-04-09 21:30 we7u * config/language-Spanish.sys: Updates by Jose R. Marte A., HI8GN. 2002-04-09 21:23 we7u * help/help-Spanish.dat: Updates by Jose R. Marte A., HI8GN. 2002-04-09 16:04 we7u * src/wx.c: Commented out the Peet Brothers U2000 Complete Record Mode parsing of today's rain total. It conflicts with the more generic method of calling compute_rain() from the incrementing long-term rain total. 2002-04-09 15:38 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/wx.c, src/xa_config.c: Preparation for correcting rain gauge measurements for various types of weather stations. 2002-04-09 13:34 we7u * src/: interface_gui.c, main.c: Moving "default:" cases to end of switch statements. 2002-04-09 09:35 francais1 * src/main.c: Force redraw on coordinate system change. This will make sense when I check in the UTM grid code. 2002-04-09 02:25 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/interface_gui.c, src/wx.c: Code to handle different types of rain gauges. Nearly complete. 2002-04-09 00:51 we7u * src/: db.c, wx.c: Added some comments. 2002-04-08 23:13 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Portuguese.sys, config/language-Spanish.sys, src/main.c: Added code to force the symbol to one of the two weather symbols that are legal in the APRS spec, for the cases where we're transmitting weather data. 2002-04-08 14:15 rzg * help/help-English.dat: Minor helpfile update. 2002-04-08 13:29 we7u * src/: main.c, main.h, maps.c: Fixed zooming-by-dragging, a mouse operation, so that the entire box that is dragged will appear in the final view. 2002-04-08 11:57 we7u * src/wx.c: Preparing to tweak Peet Bros code for 0.1mm and 0.01" rain gauges. No real code changes yet. 2002-04-07 11:48 we7u * config/language-Spanish.sys: Deleted duplicate lines. 2002-04-06 11:47 we7u * config/language-Italian.sys: Updated to correspond more closely with the English language file. 2002-04-06 11:11 we7u * config/: language-Dutch.sys, language-French.sys, language-German.sys, language-Spanish.sys: Keeping the other language files in sync with the English file. 2002-04-06 10:56 we7u * config/language-Portuguese.sys: Adding some missing strings. 2002-04-06 10:11 we7u * help/: Makefile.am, Makefile.in: Portuguese help file stuff. 2002-04-06 10:09 we7u * xastir.spec.in, help/help-Portuguese.dat, src/main.c: Potuguese help file stuff. 2002-04-06 09:56 we7u * config/Makefile.in: Adding Portuguese language. 2002-04-06 09:53 we7u * README.1ST, xastir.spec.in, config/Makefile.am, config/language-English.sys, config/language-Portuguese.sys, src/main.c: Tweaks to add Portuguese language to Xastir. 2002-04-06 08:06 we7u * config/language-Portuguese.sys: Thanks to David Quental for tranlating the language file to Portuguese! 2002-04-05 19:31 we7u * src/main.c: Tweak to make gps interval time switch as soon as the user changes it in the default menu. 2002-04-05 14:50 we7u * src/: main.c, main.h, maps.c: Modifying zooming in with the mouse such that it now figures out whether most of the mouse movement was in the horizontal or in the vertical direction, then computes the new zoom level based on that. Previous to this change zooming was calculated based only on vertical movement. 2002-04-05 11:14 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Changed the final exit label. 2002-04-05 08:25 gstueve * src/db.c: Reintroduce groups to the land of messaging. 2002-04-04 16:59 we7u * src/main.c: Tweaked one hotkey string that I forgot to. 2002-04-04 16:41 we7u * src/main.c: Fixed Map Chooser so that the list approriately shows what was most recently selected/de-selected via the buttons. 2002-04-04 15:37 we7u * src/main.c: Mapped the coordinate calculator to a button in the maps menu. 2002-04-04 01:39 we7u * src/main.c: Changed "About" text to say 1999-2002. 2002-04-04 01:24 we7u * src/db.c: Changed Station_data() code so that it's not destroyed and re-created each time if "Automatic Updates" are enabled. Broke out code that filled in the text into a separate function. 2002-04-03 23:33 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Implemented "Exit Now!" submenu off the File->Exit menu to make it harder to exit the program by mistake. It takes a deliberate effort now to do so. 2002-04-03 23:10 we7u * src/main.c: Changed Map Chooser so that only the OK and Cancel buttons will dismiss the dialog. 2002-04-03 22:56 we7u * src/maps.c: First attempt to make Shapefiles more bulletproof. Missing fields shouldn't cause segfaults anymore. 2002-04-02 23:13 we7u * src/rac_data.c: Added a popup to the RAC data search for the case where the callsign isn't found. 2002-04-02 22:25 we7u * src/fcc_data.c: Fixed severe wait when a U.S. callsign is not in the database. Also added a popup for the cases where the callsign isn't found. 2002-04-02 14:01 we7u * src/main.c: Coordinate calculator OK button is now grey'ed out until a successful calculation occurs. 2002-04-02 13:44 we7u * src/main.c: Added some debug_level statements for some printf's. 2002-04-02 13:37 we7u * src/main.c: Fixed truncation problems affecting accuracy in the last digits for the Coordinate Calculator dialog. 2002-04-02 13:21 we7u * src/main.c: Most of the coordinate calculator stuff is working now. Still a few minor truncation problems to track down and fix. 2002-04-02 09:32 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Now change title on Coordinate Calculator dialog based on which dialog called us. Also changed some strings to langcode strings for Coordinate Calculator and associated code. 2002-04-02 08:55 we7u * src/main.c: Added a bunch more comments having to do with the Coordinate Calculator. 2002-04-01 23:43 we7u * src/: main.c, wx_gui.c: Added linkages between Coordinate Calculator and the calling dialogs, in both directions. 2002-04-01 15:42 we7u * src/: main.c, util.c: Fixing coordinate calculator. Got rid of rounding errors by going to fixed-point arithmetic. Added comments to util.c. 2002-04-01 14:53 we7u * src/util.c: Switched to fixed-point arithmetic for lat/lon conversions to strings. Got rid of floating-point rounding errors. 2002-04-01 14:52 we7u * src/main.c: Added space between lat/lon values on status line. More readable. 2002-04-01 13:37 we7u * src/main.c: Changed Coordinate Calculator to use higher precision DD MM SS.S format. 2002-04-01 12:52 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/list_gui.c, src/util.c: Changed dd mm ss format to dd mm ss.s for more precision. It's more similar now to the precision of the other formats. 2002-04-01 12:28 we7u * src/util.c: Correct some comments. 2002-03-31 23:57 we7u * src/wx.c: Updated some comments. 2002-03-31 22:50 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/interface.h, src/interface_gui.c, src/xa_config.c: Added KD6VPE's changes to add tenth/hundredth rain gauge types to the weather interfaces. This is to support the two types of rain gauges for Peet Brothers weather stations. This patch implements a global variable and the interface widgets needed to manipulate it, but does _not_ implement the code to do anything with the variable yet. 2002-03-30 10:00 we7u * src/main.c: Changed Coordinate Calc help text so that it is obviously not good output data. 2002-03-30 09:23 we7u * src/main.c: Added some help text output to Coordinate Calculator if the user enters something that isn't recognized. 2002-03-30 01:17 we7u * src/main.c: Very minor changes to Coordinate Calculator. No additional functionality. 2002-03-30 00:12 we7u * src/main.c: More Coordinate Calculator stuff. UTM input is working now. 2002-03-29 18:40 we7u * src/main.c: Added some simulated output for what the Coordinate Calculator should display. 2002-03-29 15:47 we7u * src/main.c: More code for the Coordinate Calculator. 2002-03-29 15:00 we7u * src/main.c: Added Coordinate_calc button to Object Create/Modify. 2002-03-29 14:45 we7u * src/main.c: More coordinate calculator code. Not functional yet. 2002-03-29 10:43 francais1 * src/alert.c: Fixed errant tabs 2002-03-28 21:53 francais1 * src/alert.c: There were several strncpy's without a following str[last] = `\0` statement. One of them caused a segfault. This whole file probably needs looking over for such problems. I fixed a few I thought need the statement or in the case of some memmove's, seemed wrong to me. 2002-03-28 16:19 we7u * src/: lang.c, main.c: Fixed langcode segfault. Fixed a lang_hotkey that was wrong. 2002-03-28 15:52 we7u * src/main.c: The beginnings of a coordinate calculator for inputting coordinates in different formats. 2002-03-28 15:31 we7u * src/list_gui.h: Knocking off a compiler warning. 2002-03-28 11:28 we7u * src/: list_gui.c, main.c: View->Mobile Stations list now updates instantly when the coordinate system is changed. 2002-03-28 11:02 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/list_gui.c: Added multiple coordinate display capability to View->Mobile Stations dialog. 2002-03-28 10:41 francais1 * src/main.c: Added calls to TrackMouse for the map-moving key events so that the position status line gets updated. 2002-03-28 10:27 francais1 * src/main.c: Commented out code that clears mouse pointer location status line when we leave Xastir window because I believe we may be trying to write down that information in another window or some such action. 2002-03-27 16:54 francais1 * src/: db.c, main.c, util.c, xastir.h: Added and enabled DDMMSS coordinate format. 2002-03-27 16:21 we7u * src/db.c: Added dd.dddd and UTM capability to the Station Info dialog as well. 2002-03-27 14:26 we7u * src/main.c: Removed unused variables. Changed some comments. 2002-03-27 13:22 we7u * src/: main.c, util.c, util.h: Created convert_xastir_to_UTM_str() function to create a UTM string. 2002-03-27 12:59 we7u * src/util.c: Added some comments. 2002-03-27 12:49 we7u * src/main.c: Enclosed some calculations used only in debug mode inside if (debug_level) construct. Added a few comments here and there. 2002-03-27 10:21 we7u * src/db.c: Fixed a problem caused by the mass update to new debug levels: The station callsign was truncated in Station Info dialog if in debug level that wasn't 0 or 1. Also changed this dialog such that the characters which make up the symbol are always visible between the symbol and the callsign, whether in debug mode or not. I want to see this information. 2002-03-27 09:38 we7u * scripts/mapfgd.pl: Updates by Derrick J. Brashear, KB3EGH, to handle 1:63360 maps. 2002-03-26 23:57 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c, src/main.h, src/xa_config.c: Added a File->Configure->Coordinate System menu option which allows selecting between four different methods of displaying coordinates. Currently this only modifies the status bar display. Only three of the four options are currently implemented. 2002-03-26 15:43 we7u * src/main.c: Added timestamp output to stderr on segfault. 2002-03-26 15:36 we7u * src/: util.c, util.h, wx.c: Added 30 second timestamps to each logfile. Moved hour() and minute() routines from wx.c to util.c, renamed to get_hours() and get_minutes(). Added get_seconds() routine. Added code to wx.c:cycle_weather() routine to do the logfile timestamps. Cycle_weather currently runs every 30 seconds. 2002-03-22 23:20 we7u * xastir.spec.in: Trimmed down version that still works nicely. Installs /usr/local/bin/xastir as SUID root. 2002-03-22 22:34 we7u * xastir.spec.in: Fixed for binary RPM's. 2002-03-22 14:46 we7u * xastir.spec.in: Updated link to project sources. 2002-03-22 14:33 we7u * xastir.spec.in: Corrected misspelling. 2002-03-19 08:37 we7u * config/tnc-startup.kpc3: More tweaks to the kpc3 startup file by we7u. 2002-03-18 22:00 we7u * config/tnc-startup.pico: A few more pico changes by we7u. 2002-03-18 21:41 we7u * config/: tnc-startup.aea, tnc-startup.sys: Added "echo off" to two tnc startup files. This prevents echo'ed commands from showing up in the middle of tnc data. 2002-03-18 21:25 we7u * config/tnc-startup.pico: Changes hinted at by Jeff Brenton, KA9VNV. Changed into PicoPacket syntax by Curt, WE7U. 2002-03-18 21:07 we7u * config/tnc-startup.kpc3: Added changes suggested by Jeff Brenton, KA9VNV. 2002-03-18 10:00 we7u * config/language-Italian.sys: Fixes by Marco Calistri, IK5BCU. 2002-03-15 09:39 we7u * help/help-English.dat: Fixed minor spelling errors. 2002-03-15 09:35 we7u * README.1ST: Fixed minor spelling errors. 2002-03-14 20:58 rzg * README.1ST, help/help-English.dat: Updated helpfile and README.1ST. 2002-03-13 09:22 we7u * scripts/mapfgd.pl: Fixes by Derrick J. Brashear for "k" format maps. 2002-03-12 09:00 we7u * src/maps.c: Fixing some segfaults that can occur in the geoTIFF code if certain TIFF tags aren't present in the image. Thanks to Derrick J. Brashear for pointing this out. I used his patch with modifications. 2002-03-11 15:36 we7u * config/: tnc-startup.kam, tnc-startup.kpc3, tnc-startup.sys: Changed "mfilter off" to "filter off" for kam and kpc3. Added "filter off" to tnc-startup.sys as well. Both mfilter and filter are in that file, making it work for both types of TNC's. 2002-03-11 12:53 we7u * src/lang.c: Added a bit of bulletproofing for lang.c. 2002-03-11 10:49 we7u * config/: Makefile.am, Makefile.in, tnc-startup.aea: Added tnc-startup.aea file and tweaked Makefiles to install it. 2002-03-11 10:06 we7u * config/: tnc-startup.kam, tnc-startup.kpc3, tnc-startup.sys: Adding "mfilter off" to most tnc startup files. 2002-03-11 01:17 we7u * src/interface.c: Increased inter-character delay to 25ms. PicoPacket doesn't work with 20ms. This is only for writes on serial port TNC's. 2002-03-11 00:06 we7u * config/tnc-startup.pico: Fullduplex not recognized by my PicoPacket. Fulldup is. 2002-03-10 23:39 we7u * src/interface.c: Moved character write pacing to the proper routine. 2002-03-10 23:01 we7u * src/: interface.c, main.c, main.h: Setuid patches by Jack Twilley. Serial port throttling by we7u. 2002-03-08 14:48 we7u * src/interface_gui.c: Fix for Xastir blowing up when changing properties on a serial TNC interface. 2002-03-07 15:33 we7u * config/Makefile.in: Adding PicoPacket startup file. 2002-03-07 15:31 we7u * Makefile.in: Adding backslash back in at the appropriate point. 2002-03-07 15:30 we7u * acconfig.h, config.h.in, configure: Fixes for warning when running autoheader. 2002-03-07 15:03 we7u * config/tnc-startup.pico: A few more tweaks to the picopacket startup file. 2002-03-07 12:58 we7u * src/gps.c: Changed a few variables to globals. This is to allow two different GPS sentences to update the current info, then perform a screen update using the combined data. Fixed the code so that receipt of one valid GPS sentence doesn't disable decoding of the next. 2002-03-07 12:49 we7u * config/tnc-startup.pico: Swapped the order of the GPS string captures. 2002-03-07 12:49 we7u * src/interface.c: Added some debugging statements. 2002-03-07 10:56 we7u * config/tnc-startup.pico: Proper commands for a Pico. Tested. 2002-03-07 10:55 we7u * src/interface.c: Added a delay after sending each init string to a serial TNC. This is needed to allow the TNC enough time to process the command before sending the next. 2002-03-07 08:58 we7u * Makefile.am: Adding a backslash that was erroneously deleted from Makefile.am. Thanks to Jack Twilley for pointing this out. 2002-03-06 17:02 we7u * config/: Makefile.am, tnc-startup.pico: Added a startup file for a Paccomm PicoPacket. 2002-03-06 15:58 we7u * src/gps.c: Setting the time from GPS data now requires only that a $GPRMC string be received, the OS be Linux, and that the Xastir binary must be SUID root. It no longer requires the $GPGGA sentence to set the time. 2002-03-06 13:57 we7u * config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, src/main.c: Changed 20 & 10 second GPS update rates down to 15 & 5. 2002-03-06 13:13 we7u * src/db.c: Added station trails for the local station. Improved station/trail update rate for Track-Me mode. 2002-03-06 11:48 we7u * src/db.c: Added the capability to track ourselves. Uses the Track Station facility, so the map moves when we get too near the edge of the viewport. 2002-03-06 10:11 we7u * src/interface_gui.c: Added a missing mutex unlock that was preventing getting to the properties dialog for the new interface type. 2002-03-06 01:52 we7u * src/gps.c: Blanking out fields for which we don't have actual data values. 2002-03-06 01:44 we7u * src/interface.c: Added else clause s.t. it changes the type to "aprs data" if the nmea tests fail. 2002-03-06 01:29 we7u * src/interface.c: A few small tweaks to tnc_get_data_type(). Wasn't detecting NMEA data properly. 2002-03-06 01:17 we7u * src/gps.c: Updating local position after decoding each GPRMC or GPGGA string. 2002-03-06 01:03 we7u * src/gps.c: Now updates local position when either $GPRMC or $GPGGA are received. Both are not required except for setting time. Added #ifdef __linux__ around the settime call. 2002-03-06 00:30 we7u * src/interface.c: Modified tnc_get_data_type() function so that it doesn't call the decode_ax25_line() function. The latter function is destructive to its first parameter, which is the APRS packet. It was causing the packet to be destroyed before it could be parsed and added to the database. 2002-03-06 00:27 we7u * src/db.c: Corrected spelling error in debug output. 2002-03-06 00:25 we7u * src/main.c: Added a couple of comments. 2002-03-05 23:53 we7u * src/interface_gui.c: Added "Set Time" button to two more GPS interfaces. Took it away from the "Serial TNC" interface. 2002-03-05 22:42 we7u * src/main.c: Widening the debug_level form to handle up to debug level 2047. 2002-03-05 13:28 we7u * AUTHORS, ChangeLog, DEBUG_LEVELS, Makefile.am, README.1ST, acinclude.m4, config.guess, config.sub, configure.in, install-sh, missing, mkinstalldirs, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, scripts/icontable.pl, scripts/mapblast2geo.pl, scripts/mapfgd.pl, src/datum.c, src/datum.h, src/db.c, src/draw_symbols.c, src/festival.c, src/gps.c, src/interface.c, src/interface.h, src/interface_gui.c, src/list_gui.c, src/main.c, src/maps.c, src/messages.c, src/rotated.c, src/rotated.h, src/snprintf.c, src/snprintf.h, src/util.c, src/xa_config.c: Expanded tabs. 2002-03-05 00:18 we7u * src/: db.c, db.h, gps.c, igate.c, interface.c, interface.h, interface_gui.c, lang.c, main.c, maps.c, util.c, xa_config.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. Added new interface type "Serial TNC w/GPS on AUX port", which is for Kantronics KAM, KPC3+, and Paccomm PicoPacket TNC's that respond to -E for fetching GPS strings. Added new DEBUG_LEVELS file that describes the new standard levels. Added more debug statements througout the code. Added comments for GPGGA sentence. Added "dbadd" parameter to decode_ax25_line, if it's set on return, add the data to the database. Filter "cmd:" out of incoming data. Decode time/data from GPRMC and GPGGA strings, used to set system time to GPS time. Altitude units now decoded from GPGGA strings. Changed hard-coded device numbers to ennumerated values. New black background choice. Added "char *envp[]" to parameters for main. Still needed: Set time fixes for other operating systems. Smooth time transition instead of force to new value. "Set Time" button for remaining two GPS interface types. 2002-03-04 13:41 we7u * DEBUG_LEVELS: Added by Owen DeLong : Changing to bit-mapped debug levels. This file documents what each level is for. 2002-03-04 13:36 we7u * src/: track_gui.c, wx.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. 2002-03-04 13:33 we7u * src/: alert.c, hostname.c, maps.c, messages.c: Changes by Owen DeLong : Changing to bit-mapped debug levels. 2002-03-04 13:20 we7u * symbols/symbols.dat: Changes by Owen DeLong , KB6MER to support: New interface type. 2002-03-04 13:19 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Changes by Owen DeLong , KB6MER to support: New interface type, setting time via GPS, new Black map background color, more debugging messages. 2002-02-25 16:10 we7u * README.1ST: Minor tweaks to again test mailing list notification. 2002-02-25 16:06 we7u * README.1ST: Minor tweaks to test new mailing list. 2002-02-25 14:29 we7u * README.1ST: Added a blurb about the "--prefix" config option. 2002-02-25 12:43 francais1 * config.h.in, configure, configure.in, src/xa_config.h, src/xa_config.c: Changes to allow the use of --prefix with configure. By default should install and run from /usr/local/xastir as before. 2002-02-25 01:22 we7u * src/interface.c: Added a couple of debug messages. Fixed the AX.25 reconnect problem. Decreased several fixed waits. 2002-02-22 23:41 we7u * src/db.c: Added more debug output in decode_Mic_E function. One statement will print out even without debug mode if the symbol table and symbol characters are switched. 2002-02-19 16:28 rzg * help/help-English.dat: Updated helpfile. 2002-02-16 23:52 we7u * src/main.c: Changed "Measure" function to go to feet or meters if the total length is less than a mile or kilometer. 2002-02-16 21:21 we7u * src/util.c: FreeBSD time fix by Jack Twilley . 2002-02-15 21:51 we7u * src/main.c: Fixing the main window (actually the main popup!) so that it initially shows at the correct size, instead of resizing shortly after. 2002-02-15 15:55 we7u * src/maps.c: Fixed Shapefile maps so that they work with more shapefiles. Unknown shapes are drawn in black just like the roads. Lakes shapefiles have to start with "lk" in the filename now to be recognized and drawn as blue lakes. 2002-02-15 12:49 we7u * src/main.c: Reordering the management of the appshell popup in an attempt to get rid of the bug: "Shell widget has zero width or height" that occurs on some systems. 2002-02-14 14:37 we7u * src/xa_config.c: Changing default greying out of stations from 120 minutes down to 80 minutes. This works better for some of the satellites we can use for APRS, per Bob Bruninga's recommendations. 2002-02-14 09:33 we7u * src/: db.c, main.c, main.h, util.c, util.h, xa_config.c: Tracked station speech patches contributed by Alan Crosswell , n2ygk. 2002-02-14 09:08 we7u * config/: language-Dutch.sys, language-English.sys, language-French.sys, language-German.sys, language-Italian.sys, language-Spanish.sys: Tracked station speech patches contributed by Alan Crosswell , n2ygk. 2002-02-13 12:55 we7u * src/maps.c: Tiger map tweaks submitted by Jim Chandler, N0VH. 2002-02-13 11:14 we7u * src/wx.c: Added a comment at the top describing the weather stations we currently support. 2002-02-13 10:40 we7u * config.guess, config.sub, missing: Checking in latest versions of these files, snagged from: http://subversions.gnu.org/cgi-bin/cvsweb/autoconf/config/ 2002-02-13 09:36 we7u * configure, configure.in: Bumping the development version up to version 1.1.1 2002-02-13 08:44 we7u * missing, config.sub: Updated file sent to me by Jack Twilley . 2002-02-11 17:27 dk7in * scripts/: mapblast2geo.pl, update_langfile.pl: Old E-Mail deleted. 2002-02-11 16:08 dk7in * scripts/icontable.pl: Old E-Mail address deleted. 2002-02-11 15:21 we7u * scripts/mapfgd.pl: New script by Derrick J Brashear, KB3EGH. This one creates .fgd files from geotiff .tif files. Useful for topo maps you find on the net that don't come with .fgd files. 2002-02-11 14:22 we7u * src/maps.c: A tweak by Derrick J Brashear, KB3EGH, which avoids problems with user defined horizontal datums in geoTIFF. 2002-02-10 12:04 kg4ijb * Makefile.am: didn't get committed :/ 2002-02-10 01:06 we7u * callpass/Makefile: Removing Makefile. This is created automatically during the "configure" stage. 2002-02-09 16:56 kg4ijb * Makefile.in, configure, configure.in, callpass/Makefile, callpass/Makefile.am, callpass/Makefile.in, callpass/callpass.c, m4/Makefile.in: Moved callpass* to ./callpass. Automake doesn't handle recursives very well 2002-02-09 06:48 kg4ijb * config.h.in, configure, configure.in, m4/Makefile.in: Added config check for Xpm (hack) untill I can do something better. 2002-02-09 06:14 kg4ijb * configure, configure.in, m4/Makefile.in: updated release information 2002-02-07 20:45 kg4ijb * m4/Makefile.in: rebuilds 2002-02-06 16:58 we7u * Makefile.am: Added a forgotten root-level Makefile.am file. 2002-02-05 16:59 we7u * help/: help-English.dat, help-Dutch.dat, help-French.dat, help-German.dat, help-Italian.dat, help-Spanish.dat: Updated web page pointers. 2002-02-05 16:57 we7u * AUTHORS, FAQ, README, README.1ST: Updated web page pointers and CVS instructions. 2002-02-05 16:22 we7u * AUTHORS, FAQ, README, README.1ST: Tweaking web page addresses for the new sourceforge project address. 2002-02-04 21:00 we7u * src/lclint.script: Added more debug statements. Added new files to it. 2002-02-04 20:58 we7u * src/maps.c: Changed the ifdef's around that check for ImageMagick and XPM libraries. The proper pieces of code should be enabled/disabled now for whichever of these two libraries are found on the system. 2002-02-04 20:55 we7u * src/main.h: Undef'ing VERSION only when lclint is being run against the code. 2002-02-04 20:54 we7u * src/main.c: Added some debug statements. 2002-02-01 19:18 kg4ijb * src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/snprintf.h, src/snprintf.c, symbols/Makefile.am, symbols/Makefile.in, symbols/symbols.dat: Initial revision 2002-02-01 19:18 kg4ijb * src/list_gui.c, src/list_gui.h, src/locate_gui.c, src/location.c, src/location_gui.c, src/main.c, src/main.h, src/maps.c, src/maps.h, src/messages.c, src/messages.h, src/messages_gui.c, src/popup.h, src/popup_gui.c, src/rac_data.c, src/rac_data.h, src/rotated.c, src/rotated.h, src/sound.c, src/symbols.h, src/track_gui.c, src/track_gui.h, src/util.c, src/util.h, src/view_message_gui.c, src/wx.c, src/wx.h, src/wx_gui.c, src/xa_config.c, src/xa_config.h, src/xastir.h, src/snprintf.h, src/snprintf.c, symbols/Makefile.am, symbols/Makefile.in, symbols/symbols.dat: rc1 intital import 2002-02-01 19:15 kg4ijb * ABOUT-NLS, AUTHORS, COPYING, ChangeLog, FAQ, INSTALL, LICENSE, Makefile.in, NEWS, README, README.1ST, TODO, UPDATES, acconfig.h, acinclude.m4, changes.txt, config.guess, config.h.in, config.sub, configure, configure.in, install-sh, missing, mkinstalldirs, placeholder, stamp-h.in, xastir.spec.in, ltconfig, ltmain.sh, config/Makefile.am, config/Makefile.in, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, config/xastir.rgb, help/Makefile.am, help/Makefile.in, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, intl/Makefile.in, intl/VERSION, intl/bindtextdom.c, intl/cat-compat.c, intl/dcgettext.c, intl/dgettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/gettext.h, intl/gettextP.h, intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c, intl/libgettext.h, intl/libintl.h, intl/linux-msg.sed, intl/loadinfo.h, intl/loadmsgcat.c, intl/localealias.c, intl/po2tbl.sed, intl/po2tbl.sed.in, intl/textdomain.c, intl/xopen-msg.sed, m4/Makefile.am, m4/Makefile.in, m4/xmhtml.m4, po/Makefile.in, po/Makefile.in.in, po/POTFILES, po/POTFILES.in, po/cat-id-tbl.c, po/en.po, po/fr.po, po/nl.po, po/stamp-cat-id, po/xastir.pot, scripts/example_objects.log, scripts/icontable.pl, scripts/inf2geo.pl, scripts/mapblast2geo.pl, scripts/update_langfile.pl, src/Makefile.am, src/Makefile.in, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/datum.c, src/datum.h, src/db.c, src/db.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/lclint.script: Initial revision 2002-02-01 19:15 kg4ijb * ABOUT-NLS, AUTHORS, COPYING, ChangeLog, FAQ, INSTALL, LICENSE, Makefile.in, NEWS, README, README.1ST, TODO, UPDATES, acconfig.h, acinclude.m4, changes.txt, config.guess, config.h.in, config.sub, configure, configure.in, install-sh, missing, mkinstalldirs, placeholder, stamp-h.in, xastir.spec.in, ltconfig, ltmain.sh, config/Makefile.am, config/Makefile.in, config/language-Dutch.sys, config/language-English.sys, config/language-French.sys, config/language-German.sys, config/language-Italian.sys, config/language-Spanish.sys, config/tnc-startup.kam, config/tnc-startup.kpc3, config/tnc-startup.sys, config/tnc-startup.thd7, config/tnc-stop.sys, config/xastir.rgb, help/Makefile.am, help/Makefile.in, help/help-Dutch.dat, help/help-English.dat, help/help-French.dat, help/help-German.dat, help/help-Italian.dat, help/help-Spanish.dat, intl/Makefile.in, intl/VERSION, intl/bindtextdom.c, intl/cat-compat.c, intl/dcgettext.c, intl/dgettext.c, intl/explodename.c, intl/finddomain.c, intl/gettext.c, intl/gettext.h, intl/gettextP.h, intl/hash-string.h, intl/intl-compat.c, intl/l10nflist.c, intl/libgettext.h, intl/libintl.h, intl/linux-msg.sed, intl/loadinfo.h, intl/loadmsgcat.c, intl/localealias.c, intl/po2tbl.sed, intl/po2tbl.sed.in, intl/textdomain.c, intl/xopen-msg.sed, m4/Makefile.am, m4/Makefile.in, m4/xmhtml.m4, po/Makefile.in, po/Makefile.in.in, po/POTFILES, po/POTFILES.in, po/cat-id-tbl.c, po/en.po, po/fr.po, po/nl.po, po/stamp-cat-id, po/xastir.pot, scripts/example_objects.log, scripts/icontable.pl, scripts/inf2geo.pl, scripts/mapblast2geo.pl, scripts/update_langfile.pl, src/Makefile.am, src/Makefile.in, src/alert.c, src/alert.h, src/bulletin_gui.c, src/bulletin_gui.h, src/color.c, src/color.h, src/datum.c, src/datum.h, src/db.c, src/db.h, src/draw_symbols.c, src/draw_symbols.h, src/fcc_data.c, src/fcc_data.h, src/festival.c, src/festival.h, src/gps.c, src/gps.h, src/hostname.c, src/hostname.h, src/igate.c, src/igate.h, src/interface.c, src/interface.h, src/interface_gui.c, src/lang.c, src/lang.h, src/lclint.script: rc1 intital import Xastir-Release-2.2.4/DEBUG_LEVELS0000664000175000017500000001001515151324131015141 0ustar hibbyhibby This file has three parts. The first part describes the new structure for debug levels. The second part describes the debug_level definitions that were in the old code and which files they were in. The third part describes how to use use debugging at run time. The debug level structure was modified in February of 2002 by KB6MER. Questions/comments/flames can be sent to kb6mer@arrl.net Here's how things are after KB6MER tweaked it all... New Scheme: ----------- 1 General basic debugging (any system) 2 Messages, WX, Objects, and Items, Port Data Flow 4 X Object Debugging 8 X Window Object Debugging 16 Map Debugging (maps.c) 32 Language Debugging (maps.c) 64 Database Object Debugging 128 GPS Interface Detailed debugging 256 station and trail display detailed debugging 512 Map import/export function debugging 1024 Internet Transaction debugging 2048 ALOHA radius and Multipoint object debugging. 4096 Levels 4096 and above will require modification to the main.c:Change_debug_level_change_data() function to change the bounds checking, and are available for future use. ------------------------------------------------------------------ Old Scheme: ----------- Places where debug level is referenced in old code, and the levels referenced (if debug_level xx), where xx is >0, &1, etc. alert.c >0 bulletin_gui.c &1 db.c >=2 &1 &128 &32 &256 () gps.c &128 hostname.c &256 igate.c &2 interface.c &128 &2 &1 interface_gui.c &128 lang.c &32 main.c &4 <0/>255(need to change limits) &8 &128 &1 &15 maps.c &16 &2 >=2 &4 &1 &8 messages.c >1 &1 >5 messages_gui.c &2 track_gui.c >=2 util.c &1 wx.c >2 &1 xa_config.c &1 &2 ------------------------------------------------------------------ How to Use the Debug Levels Xastir debugging is turned on at run time by using the "-v" command line option and/or the File -> Configure -> Change Debug Level pull-down. As laid out above, in the source code, debugging output is turned on by a bitwise "and" (&) of the currently set DEBUG_LEVEL against a number appropriate to the module currently being executed. For example, in the "maps.c" the following lines appear: if ( debug_level & 512 ) fprintf(stderr,"Creating %s\n", xpm_filename ); The highest debug level for Xastir is 4095, and debug levels are additive. If you want to have "general basic debugging" and "GPS interface Detail" and "Map Debugging" you'd use: 1 + 128 + 512 = 641 xastir -v 641 Debug information typically is sent to "standard error" - which is normally File Descriptor #2 in Unix parlance. Using common Unix shells, such as Bash, you can "redirect" the output to be intermingled with the "standard output" (file descriptor #1). This allows you to get all of the normal output, plus all of the debug output in one stream, which can be "piped" to another command, such as grep. This can used to search for specific items in the debug output. For example, to check debug information to see whether or not map caching is working, you can turn on debug level 512, redirect stderr to stdout and the grep for map cache specific output: xastir -v 512 2>&1 |grep map_cache Another little trick, to be used when you're running programs that call other programs, or scripts that call other scripts/programs: (xastir -v 512 2>&1) | grep map_cache The parenthesis cause that portion to be run in a sub-shell, and then that sub-shell's STDERR is piped to STDOUT by the "2>&1" portion, so you get ANYTHING that went to STDERR or STDOUT from that command or anything that it calls. This is how you can get a "make" command to spit everything into one file. Of course you can also do: (xastir -v 512 2>&1) | tee xastir.log Which will pipe everything to your screen and to the xastir.log file. You could then type "tail -f xastir.log | grep map_cache" in another window and watch that subset of the error messages there. That way you won't miss anything. ------------------------------------------------------------------ Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/Davis/0000775000175000017500000000000015151324131014367 5ustar hibbyhibbyXastir-Release-2.2.4/Davis/.vimrc0000664000175000017500000000143315151324131015511 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/Davis/AUTHORS0000664000175000017500000000134015151324131015435 0ustar hibbyhibby Developers and Contributions _________________________________________________________________ First, thanks go out to the great folks at the xastir team - a wonderful APRS application set and helpful folks! Thanks also to Andreas Muller, author of meteo and a great resource for information and help. Elements of this software are taken from wx200d ver 1.2 by Tim Witham, and it is modeled after that application. Finally, thanks to the MySQL folks for the key element - the database. KB8ROP Bruce Bennett bruts@adelphia.net _________________________________________________________________ Copyright (C) 2003-2004 Bruce Bennett KB8ROP Xastir-Release-2.2.4/Davis/COPYING0000664000175000017500000004312715151324131015431 0ustar hibbyhibby GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 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. Xastir-Release-2.2.4/Davis/ChangeLog0000664000175000017500000000000215151324131016131 0ustar hibbyhibby Xastir-Release-2.2.4/Davis/INSTALL0000664000175000017500000002203215151324131015417 0ustar hibbyhibby Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. Xastir-Release-2.2.4/Davis/Makefile.am0000664000175000017500000000106215151324131016422 0ustar hibbyhibby # # Copyright (C) 2000-2026 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src #if DAVIS #MyWX = davis #else #MyWX = #endif #noinst_PROGRAMS = $(MyWX) # DISTCLEANFILES = EXTRA_DIST = aclocal.m4 AUTHORS bootstrap.sh ChangeLog config.h.in \ config.status configure.ac COPYING INSTALL NEWS \ README bootstrap.sh MAINTAINERCLEANFILES = configure config.status aclocal.m4 \ Makefile.in Makefile config.guess config.sub install-sh \ missing ChangeLog:: Xastir-Release-2.2.4/Davis/NEWS0000664000175000017500000000000115151324131015055 0ustar hibbyhibby Xastir-Release-2.2.4/Davis/README0000664000175000017500000001634515151324131015260 0ustar hibbyhibby Copyright (C) 2004 Bruce Bennett Portions Copyright (C) 2000-2026 The Xastir Group (Modified for the Xastir project under GPL license) Davis Weather Station support for Xastir - db2APRS OVERVIEW -------- This is a bridge utility between "meteo", a Davis Weather Station data storage & display application by Andreas Muller (see http://meteo.othello.ch) and "Xastir", the APRS package for Linux (see http://www.xastir.org). It allows your Davis weather data to be used by Xastir for local station data. You will need to obtain and install Xastir, mysql and meteo as outlined in the following sections. After Xastir and meteo are in working order, this utility can be run as a daemon to provide weather data to Xastir (or any other APRS-format application). "db2APRS" watches for new weather data in the database, retrieves the new data, formats it in APRS "position less" ASCII format and makes it available on a TCP port of your choosing. Xastir is capable of reading this data (see note under Xastir installation). INSTALLATION ------------ Steps in order: 1) Install mysql - initial tested version mysql-3.23.58 although version 4 is released and has some significant improvements - and version 4 *should* work (to be tested yet). If you use an RPM or DPK binary-image version, be sure to add the mysql-devel headers. For the latest image-version, see http://www.mysql.com and follow the links to the downloads. I used mysql-3.23.58-pc-linux-i686.tar.gz from that site. 2) Install meteo - tested versions meteo-0.9.4 and meteo-0.9.8 Version 0.9.9 is available and based on the change documented will work. See the instructions for installing & then setting up meteo that come with the tar ball. Obtain the latest meteo at http://meteo.othello.ch - the setup is rather involved but worth the efort. Some SQL/XML skills can help here, but are not absolutely required... 3) Install or update your installation for Xastir to the latest version ("http://github.com/Xastir/Xastir" project Xastir) 4) Install db2APRS - version 0.1.2 See instructions below. SETTINGS & STARTUP ------------------ 1) mysql - it is recommended by mysql to set up passwords, but for this usage it doesn't matter. In fact, it's a bit of a pain. TODO - db2APRS has the annoying fault of clearly displaying the password used for the mysql database for anyone to see via 'ps -ef'. Start mysqld before db2APRS, meteo and Xastir in your boot-time initializations. 2) meteo - my testing used a one minute data accumulation rate. Thirty seconds would more closely match Xastir, but the database growth rate would be twice as fast (about 600 Mbytes/year at 30 sec rate). Set your desired rate using the meteopoll command line options. I run the full meteopoll package with averaging, graphs and meteodequeue - but the only *required* element is meteopoll. Start the meteopoll daemon after mysqld is up. (meteodequeue is recommended - see the doc's that come with meteo and man pages). 3) db2APRS - see "db2APRS RUN OPTIONS" below. Start this daemon after mysqld and before Xastir. When meteopoll isn't running, you will get old weather data, time stamped by Xastir as new data. 4) xastir - start this last, if you are auto-opening the WX port. Set the weather port as a network weather station on "localhost", port number as chosen in "db2APRS RUN OPTIONS" (default is 1313). Make sure your station is set to one of the "w/weather data" and your Icon is set to a weather Icon. db2APRS RUN OPTIONS ------------------- The db2APRS utility takes standard short & long command line options, which can be displayed by "db2APRS -?". Here's the list: -h --help Show help info and exit. -v --verbose Useful with the -n switch, for trouble-shooting, not for normal operation. Tells you more than you really wanted to know, but I recommend that you use this switch while you try to initially set up db2APRS. -c --cport [port#] Choose which TCP/IP port data comes out from. If not used, port number 1313 is the default. HINT: "telnet localhost [port#]" is a handy way to verify db2APRS operation. -s --sensor [sensor group#] Indicate what group of sensors are the outdoor ones. If not supplied, sensor number 1 is the default. HINT: Tables "station" and "sensor" in the meteo database control what your "sensor" (which means sensor group) definitions are for your "station". -u --user [database user] Username for mysql database connection. If unspecfied defaults to "meteo" (which is per the meteo setup intended to be a read-only account for meteo). -p --password [db passwd] Password for mysql connection. If unspecfied, no password is supplied. NOTE: this password is unfortunately visible to anyone on your system running 'ps -ef'. TO BE FIXED. -b --database [database] Database name for mysql connection. If not supplied the default is "meteo". -n --nodaemon Run in the fore-ground as a program. Useful for debugging or initial setup, when used with -v. -r --repeat Keep going till killed - if not specified, one pass is performed and then db2APRS exits. The only case where this switch is *not* used is during initial setup/debug. Typical example: "./db2APRS -r -u meteo -p meteo" for normal use or "./db2APRS -r -n -v -u test -p password" for debugging. OPERATIONAL DETAILS ------------------- db2APRS connects to the specified mysql database, extracts the latest timestamp and compares it to the last timestamp it read. If newer, the outdoor weather data (extception: air pressure is taken as indoor=outdoor) bearing this timestamp is extracted and formatted in the APRS "position less" string format with a Davis and X-APRS tag on the end. Any connecting client is given this string at 25 second intervals, after new database entries are checked for. This daemon could run on any networked Linux machine instead of the machine hosting Xastir, if desired (it's a good way around lack of processing power, disk space or serial ports!). Note that the db2APRS daemon keeps providing data to Xastir even when no new entries in the database have been made. This could lead to errors in the timestamp on the data that Xastir is transmitting. BUILD db2APRS ------------- It's the usual: $ cd xastir/Davis $ ./bootstrap.sh $ ./configure $ make $ su -c 'make install' ACKNOWLEDGEMENTS & AUTHORS -------------------------- db2APRS is the product of Bruce Bennett, callsign KB8ROP It is freely available at no charge under the GNU GENERAL PUBLIC LICENSE (see "COPYING" document) NO WARRANTY, expressed or implied, use at your own risk. Please feel free to contact me with test results & comments at the above EMAIL address Code portions and style taken from wx200d by Tim Witham , et. al. meteo is the work of Andreas Muller , et. al. mysql is the product of MySQL - see http://www.mysql.com for team details. and finally, Xastir is the brain child of Frank Giannandrea et. al. (see http://www.xastir.org for current EMAIL addresses) Xastir-Release-2.2.4/Davis/bootstrap.sh0000775000175000017500000000100115151324131016733 0ustar hibbyhibby#!/bin/sh -e # # # Copyright (C) 2000-2026 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.4/Davis/configure.ac0000775000175000017500000000376415151324131016672 0ustar hibbyhibby# # Copyright (C) 2004 Bruce Bennett # Portions Copyright (C) 2000-2026 The Xastir Group # (Modified for the Xastir project under GPL license) # # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) AC_INIT(db2APRS, 0.2.0, bruts@adelphia.net) AM_INIT_AUTOMAKE(db2APRS, 0.2.0) AC_CONFIG_SRCDIR([src/db2APRS.c]) AM_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_INSTALL AC_PROG_CC # Checks for libraries. # Use MySQL's script for library config, if available MYSQL_CONFIG=mysql_config AC_MSG_CHECKING(for a fully installed MySQL) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then MYSQL_VERSION=`${MYSQL_CONFIG} --version` MYSQL_LIBS=`${MYSQL_CONFIG} --libs` LIBS=`${MYSQL_CONFIG} --libs` MYSQL_CFLAGS=`${MYSQL_CONFIG} --cflags` CFLAGS="$CFLAGS $MYSQL_CFLAGS" AC_SUBST(MYSQL_LIBS) AC_SUBST(MYSQL_CFLAGS) AC_MSG_RESULT(...found ${MYSQL_VERSION}) else AC_MSG_RESULT(MySQL is not fully installed) AC_MSG_CHECKING(if there at least are the needed MySQL client libs) AC_CHECK_LIB(mysqlclient,mysql_close) if test $ac_cv_lib_mysqlclient_mysql_close = no; then AC_MSG_ERROR(*** No MySQL client library found - See README ***) else AC_MSG_RESULT(found a usable libmysqlclient) fi fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then AC_MSG_RESULT(mysql.h path defined in CFLAGS) else AC_CHECK_HEADERS([mysql.h],MYSQL_INC="yes",AC_MSG_ERROR(*** MySQL include file mysql.h not found - See README ***)) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME # Checks for library functions. AC_FUNC_FORK AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_STRTOD AC_CHECK_FUNCS([memset select socket strrchr strtol]) AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT Xastir-Release-2.2.4/Davis/src/0000775000175000017500000000000015151324131015156 5ustar hibbyhibbyXastir-Release-2.2.4/Davis/src/.vimrc0000664000175000017500000000143315151324131016300 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/Davis/src/Makefile.am0000664000175000017500000000030115151324131017204 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # bin_PROGRAMS = db2APRS noinst_PROGRAMS = db2APRS_SOURCES = \ db2APRS.c defs.h db2APRS_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.4/Davis/src/db2APRS.c0000664000175000017500000011132415151324131016461 0ustar hibbyhibby/****************************************************************** * * * Copyright (C) 2004 Bruce Bennett * Portions Copyright (C) 2000-2026 The Xastir Group * * (see the files README and COPYING for more details) * * This file implements all of the database to APRS daemon. * * Davis/Data Base Weather --> APRS Weather Intended use: Create & provide APRS style packet string without position information from MySQL database weather information stored there by meteo-0.9.4 (See http://meteo.othello.ch for source) to xastir-1.2.1 (See http://www.xastir.org for source) Note: "meteo-0.9.x" is a weather data accumulator aimed at Davis weather stations, which stores weather data in a mysql database. It is configured in two places, an XML file (default name meteo.xml) and in the database named in the XML file (default database name is "meteo") Output is to the ip hostname:port required in the command line. ACKNOWLEDGEMENTS: Elements of this software are taken from wx200d ver 1.2 by Tim Witham , and it is modeled after that application. *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXARGS 20 /* maximum CGI args to parse */ #define TMPLEN 128 /* max length of CGI */ #define BUFLEN 32 /* max length of hostname:port */ #define POLL_INTERVAL 90 // default polling interval #define VALID_WINDDIR 0x001 #define VALID_WINDSPD 0x002 #define VALID_WINDGST 0x004 #define VALID_TEMP 0x008 #define VALID_RAIN 0x010 #define VALID_RAIN24H 0x020 #define VALID_HUMIDITY 0x040 #define VALID_AIRPRESS 0x080 #define VALID_RAINDAY 0x100 #define MTPS2MPH 2.2369 #define DEGC2DEGF 1.8 #define MM2IN100TH 3.937 #define INHG2HPA10TH 338.638 #define OUTDOOR_SENSOR 1 //---From the static table "mfield", which really should be dynamically read here--- // (but then I couldn't use a switch statement) #define TEMPERATURE 0 #define TEMPERATURE_MIN 1 #define TEMPERATURE_MAX 2 #define HUMIDITY 10 #define HUMIDITY_MIN 11 #define HUMIDITY_MAX 12 #define WETNESS 20 #define WETNESS_MIN 21 #define WETNESS_MAX 22 #define AIR_PRESSURE 30 #define AIR_PRESSURE_MIN 31 #define AIR_PRESSURE_MAX 32 #define SOLAR 40 #define UV 41 #define RAIN 50 // note: "51" is really rain total #define RAIN_PER_DAY 51 #define RAIN_PER_HOUR 52 #define WIND_SPEED 60 #define WIND_DIRECTION 61 #define WIND_GUST 62 #define WIND_X 63 #define WIND_Y 64 #define MOISTURE 70 #define WATERLEVEL 71 #define WATERLEVEL_MIN 72 #define WATERLEVEL_MAX 73 #define BATTERY 110 #define TRANSMITTER 111 #define DURATION 120 #define SAMPLES 121 struct dbinfo { char user[30]; char pswrd[15]; char name[30]; } db; char *progname; char *query; int *current = 0; int opt; MYSQL mysql; // Yeah, globals... MYSQL_RES *result; MYSQL_ROW row; char last_timestamp[20]; char last_datetime[20]; char death_msg[120]; int debug_level; char wxAPRShost[BUFLEN]; int wxAPRSport = PORT; int outdoor_instr = OUTDOOR_SENSOR; /****************************************************************** 1/4/2003 Usage brief *******************************************************************/ void usage(int ret) { if (query) { printf("Content-type: text/plain\nStatus: 200\n\n"); } printf("usage: %s [options] \n",progname); printf("VERSION: %s\n",VERSION); printf(" -h --help show this help and exit\n"); printf(" -v --verbose debugging info --> stderr\n"); printf(" -c --cport [port#] IP port for data output\n"); printf(" -s --sensor [sensor group#] from meteo, your OUTDOOR sensor set\n"); printf(" -u --user [database user] username for mysql - default meteo\n"); printf(" -p --password [db passwd] password for mysql - default none\n"); printf(" -b --database [database] database name - default meteo\n"); printf(" -n --nodaemon do not run as daemon\n"); printf(" -r --repeat keep running\n"); printf(" -i --interval [seconds] polling interval\n"); printf(" -m --metric data base is in metric units\n"); printf("options may be uniquely abbreviated; units are as defined in APRS\n"); printf("Specification 1.0.1 for positionless weather data (English/hPa).\n"); exit(ret); } /****************************************************************** 1/2/2003 Make an APRS string out of WX data *******************************************************************/ int APRS_str(char *APRS_buf, char *datetime, double winddir, double windspeed, double windgust, double temp, double rain1hr, double rain24hr, double rainday, double humidity, double airpressure, unsigned int valid_data_flgs, int Metric_Data) { int intval; char pbuf[10]; if (APRS_buf == NULL) { if (debug_level & 1) { fprintf(stderr,"err: Null string buffer for APRS string.\n"); } return -1; // Ooo!! *****Nasty Bad Exit Point Here**** } //timestamp first sprintf(APRS_buf, "_%s",datetime); // if (valid_data_flgs & VALID_WINDDIR) { intval = (winddir + 0.5); // rounding to whole degrees if (intval > 360) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction > 360\n"); } sprintf(APRS_buf, "c..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction negative\n"); } sprintf(APRS_buf, "c..."); } else { sprintf(pbuf, "c%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind direction flagged as invalid\n"); } sprintf(pbuf, "c..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDSPD) { if (Metric_Data) { intval = (windspeed*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windspeed + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind speed > 600 MPH\n"); } sprintf(pbuf, "s..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "s..."); } else { sprintf(pbuf, "s%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "s..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDGST) { if (Metric_Data) { intval = (windgust*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windgust + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind gust > 600 MPH\n"); } sprintf(pbuf, "g..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "g..."); } else { sprintf(pbuf, "g%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "g..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_TEMP) { if (Metric_Data) { intval = ((temp)*DEGC2DEGF + 0.5)+32; // converting & rounding to whole Deg F } else { intval = (temp + 0.5); // rounding to whole Deg F } if (intval > 200) // Let's be reasonable here - boiling? { if (debug_level & 1) { fprintf(stderr,"err: Temperature > 200 Deg F\n"); } sprintf(pbuf, "t..."); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Temperature < -99 Deg F\n"); } sprintf(pbuf, "t..."); } else { if (intval < 0) { sprintf(pbuf,"t%0.2d",intval); } else { sprintf(pbuf, "t%0.3d", intval); } } } else { if (debug_level & 1) { fprintf(stderr,"info: Temperature flagged as invalid\n"); } sprintf(pbuf, "t..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN) { if (Metric_Data) { intval = ((rain1hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain1hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // 10 in/hr? Garden Hose -> rain gauge? { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr > 9.99 inch\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "r%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN24H) { if (Metric_Data) { intval = ((rain24hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain24hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain in 24 hours { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/24Hr > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "p999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "p%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/24Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAINDAY) { if (Metric_Data) { intval = ((rainday)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rainday*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain per day { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/day > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "P999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/day negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "P%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/day flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_HUMIDITY) { intval = (humidity + 0.5); // rounding to whole percent if (intval > 100) // Unlike the space shuttle engines, 100 % is max { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported > 100%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 1) { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported < 1%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { if (intval == 100) // Report 100% as 'h00' { intval = 0; } sprintf(pbuf, "h%0.2d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Humidity flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_AIRPRESS) { if (Metric_Data) { intval = (airpressure*10.0 + 0.5); // rounding to whole tenth of a hPa } else { intval = (airpressure*INHG2HPA10TH + 0.5); // convering In-Hg to 1/10 hPa and rounding } if (intval > 20000) //two atmospheres - about 29 PSIA { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported > 2 Atmospheres%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported negative%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "b%0.5d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Air Pressure flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); strcat(APRS_buf,"xDvs\n"); // add X aprs and Davis WX station ID's and if (debug_level & 1) { fprintf(stderr,"\ninfo: APRS Version of WX - %s\n\n",APRS_buf); } return strlen(APRS_buf); } /****************************************************************** 1/2/2003 Get the latest set of Weather Data from the Data Base *******************************************************************/ int Get_Latest_WX( double *winddir, double *windspeed, double *windgust, double *temp, double *rain1hr, double *rain24hr, double *rainday, double *humidity, double *airpressure, unsigned int *valid_data_flgs) { long last_hour_timestamp; long int last_24_timestamp; long int last_day_timestamp; char query_buffer[240]; int nrows, row_cnt, item_count; int found_sensor; long local_offset; // could be as big as 12 hrs times 3600 seconds... // Find latest, see if it's new to us // --new to us is a simple timestamp follower, so upon startup // it will always read one set of data, assuming any exists if (mysql_query(&mysql, "SELECT MAX(timekey) from sdata")) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (mysql_num_rows(result) != 1 ) { sprintf(death_msg,"err: Latest timestamp query failed - exiting: number of results %d\n", mysql_num_rows(result)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } row = mysql_fetch_row(result); if ( row[0] == NULL ) { sprintf(death_msg,"err: NULL result for timestamp query\n"); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } // if no new data, exit with zero status if (!strncmp(last_timestamp, row[0], 11)) { if (debug_level & 1) { fprintf(stderr,"info: No new weather data recorded - exiting: no data\n"); } // release query buffer mysql_free_result(result); return 0; } strcpy(last_timestamp, row[0]); // For next pass & following query if ( debug_level & 1) { fprintf(stdout,"Timestamp: %s\n",last_timestamp); } // release query buffer mysql_free_result(result); sprintf(query_buffer,"SELECT value,sensorid,fieldid,from_unixtime(timekey,'%%m%%d%%H%%i%%S') FROM sdata WHERE timekey = %s", last_timestamp); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((nrows=mysql_num_rows(result)) < 1 ) { sprintf(death_msg,"err: Latest Weather Data query failed - exiting: number of results %d\n",nrows); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } // release query buffer mysql_free_result(result); return -1; } else { if (debug_level & 1) { fprintf(stderr,"info: Latest Weather Data query: number of types of readings %d\n",nrows); } } *valid_data_flgs = 0; item_count = 0; for (row_cnt = 0; row_cnt < nrows; row_cnt++) { row = mysql_fetch_row(result); strcpy(last_datetime,row[3]); if (atoi(row[1]) == outdoor_instr) // sensors are really groups of data { found_sensor = atoi(row[1]); if (debug_level & 1) { fprintf(stderr,"info: found an outdoor sensor: (%d) ",found_sensor); } switch (atoi(row[2])) // type of reading { case WIND_DIRECTION : *winddir = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDDIR; item_count++; if (debug_level & 1) { fprintf(stderr,"wind direction %f\n ",*winddir); } break; case WIND_SPEED : *windspeed = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDSPD; item_count++; if (debug_level & 1) { fprintf(stderr,"wind speed %f\n ",*windspeed); } break; case WIND_GUST : *windgust = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDGST; item_count++; if (debug_level & 1) { fprintf(stderr,"wind gust speed %f\n ",*windgust); } break; case TEMPERATURE : *temp = strtod(row[0],NULL); *valid_data_flgs |= VALID_TEMP; item_count++; if (debug_level & 1) { fprintf(stderr,"temperature %f\n ",*temp); } break; case HUMIDITY : *humidity = strtod(row[0],NULL); *valid_data_flgs |= VALID_HUMIDITY; item_count++; if (debug_level & 1) { fprintf(stderr,"humidity %f\n ",*humidity); } break; case AIR_PRESSURE : *airpressure = strtod(row[0],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } break; case RAIN_PER_DAY : if (debug_level & 1) { fprintf(stderr,"rain-per-day total (not used), now calculated...\n "); } break; case WIND_X : if (debug_level & 1) { fprintf(stderr,"wind x... not used \n"); } break; case WIND_Y : if (debug_level & 1) { fprintf(stderr,"wind y... not used \n"); } break; case DURATION : if (debug_level & 1) { fprintf(stderr,"duration... not used \n"); } break; case SAMPLES : if (debug_level & 1) { fprintf(stderr,"samples... not used \n"); } break; default : if (debug_level & 1) { fprintf(stderr,"unknown field %s\n",row[2]); } break; } } else // Must be indoor { if (debug_level & 1) { fprintf(stderr,"info: indoor sensor found\n"); } switch (atoi(row[2])) // type of reading { case AIR_PRESSURE : *airpressure = strtod(row[0],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } break; default : if (debug_level & 1) { fprintf(stderr,"unused field %s\n",row[2]); } break; } } } if (debug_level & 1) { fprintf(stderr,"loop ends\n"); } // release query buffer mysql_free_result(result); /* get rain figures */ /* */ /* hourly first */ last_hour_timestamp = atol(last_timestamp) - 3600; sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_hour_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain 1 hour query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain 1 hour store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rain1hr = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain last hour %f\n ",*rain1hr); } // *rain1hr = *rain1hr * 100; // AFTER metric conversion if needed *valid_data_flgs |= VALID_RAIN; item_count++; } else { *rain1hr = 0; *valid_data_flgs |= VALID_RAIN; //None, but valid if (debug_level & 1) { fprintf(stderr,"no rain recorded in last hour\n"); } } } // release query buffer mysql_free_result(result); /* Last 24 hours */ last_24_timestamp = atol(last_timestamp) - 86400; sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_24_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain 24 hour query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain 24 hour store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rain24hr = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain last 24 hours %f\n ",*rain24hr); } //*rain24hr = *rain24hr * 100; // After metric conversion, if needed item_count++; *valid_data_flgs |= VALID_RAIN24H; } else { *rain24hr = 0; *valid_data_flgs |= VALID_RAIN24H; // Zero is valid too if (debug_level & 1) { fprintf(stderr,"no rain recorded in last 24 hours\n"); } } } // release query buffer mysql_free_result(result); #define CALC_MIDNIGHT #ifdef CALC_MIDNIGHT // Timestamps are seconds since midnight Jan 1 1970, so an integer divide and multiply by // seconds in 24 hrs (86400) yields the latest midnight time stamp value. last_day_timestamp = (atol(last_timestamp) / 86400)*86400; if (debug_level & 1) { fprintf(stderr,"info: timestamp for prior midnight - %ld\n",last_day_timestamp); } // NOTE: Gcc warns that "found_sensor" could be uninitialized here. sprintf(query_buffer,"SELECT offset FROM station WHERE id = (SELECT stationid from sensor WHERE id = %d)", found_sensor); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: station time offset query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: station time offset store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { local_offset = atol(row[0]); if (debug_level & 1) { fprintf(stderr,"info: station time offset: %ld\n", local_offset); } } } mysql_free_result(result); #else /* since midnite */ /* we can get the timestamp for midnite from the avg table */ last_day_timestamp = 0; sprintf(query_buffer,"SELECT max(timekey) FROM avg WHERE fieldid = %d and intval = 86400", last_hour_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: midnite timekey query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: midnite timekey store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { last_day_timestamp = strtod(row[0],NULL); } } mysql_free_result(result); #endif if (last_day_timestamp > 0) { #ifndef CALC_MIDNIGHT last_day_timestamp += 115200; // add 8 hours for offset - this should really be queried #else last_day_timestamp -= local_offset; // From the database #endif sprintf(query_buffer,"SELECT round(sum(value),2) FROM sdata WHERE timekey > %ld and fieldid = %d", last_day_timestamp,RAIN); if (mysql_query(&mysql, query_buffer)) { sprintf(death_msg,"err: rain last day query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if (!(result = mysql_store_result(&mysql))) { sprintf(death_msg,"err: rain last day store failed - exiting: %s\n", mysql_error(&mysql)); if (debug_level & 1) { fprintf(stderr,"%s",death_msg); } return -1; } if ((mysql_num_rows(result)) > 0) { row = mysql_fetch_row(result); if (row[0] != NULL) { *rainday = strtod(row[0],NULL); if (debug_level & 1) { fprintf(stderr,"rain since midnite %f\n ",*rainday); } // *rainday = *rainday * 100; // AFTER metric conversion, if needed. item_count++; *valid_data_flgs |= VALID_RAINDAY; } else { *rainday = 0; *valid_data_flgs |= VALID_RAINDAY; // None is valid... if (debug_level & 1) { fprintf(stderr,"no rain recorded in last 24 hours\n"); } } } // release query buffer (where used) mysql_free_result(result); } if (debug_level & 1) { fprintf(stderr,"info: success - Weather Data number of reading types %d\n",item_count); } return item_count; } /****************************************************************** 1/5/2003 SIGPIPE signal handler *******************************************************************/ void pipe_handler(int sig) /* */ { signal(SIGPIPE, SIG_IGN); if (sig == SIGPIPE) // client went bye-bye { shutdown(*current, 2); close(*current); *current = -1; if (debug_level & 1) { fprintf(stderr, "info: %s - TCP client timed out", progname); } } } /****************************************************************** 1/5/2003 SIGTERM signal handler *******************************************************************/ void term_handler( int UNUSED(sig) ) { if (debug_level & 1) { fprintf(stderr, "info: %s - ordered to DIE, complying", progname); } // release query buffer & close connection mysql_free_result(result); mysql_close(&mysql); exit( 0 ); } /****************************************************************** 1/2/2003 Coordinating MAIN point *******************************************************************/ int main(int argc, char **argv) { const char *flags = "Hhvnmrc:u:p:d:s:i:"; char WX_APRS[120]; int data_len = 0 ; double winddir; double windspeed; double windgust; double temp; double rain1hr; double rain24hr; double rainday; double humidity; double airpressure; unsigned int valid_data_flgs; int Metric_Dat, dsts = 0; int pid, ss, fd[CONNECTIONS]; socklen_t clen = sizeof(struct sockaddr_in); int *max = 0; int not_a_daemon = 0, repetitive = 0, tcp_wx_port = PORT; int i, index = 0; struct sockaddr_in server, client; struct in_addr bind_address; fd_set rfds; struct timeval tv; int poll_interval = POLL_INTERVAL; int dly_cnt = 1; FILE *pidfile; const char *pidfilename = "/var/run/db2APRS.pid"; struct option longopt[] = { {"help", 0, 0, 'h'}, {"refresh", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"user", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"cport", 1, 0, 'c'}, {"sensor",1, 0, 's'}, {"nodaemon", 0, 0, 'n'}, {"interval",1, 0, 'i'}, {"metric",0, 0, 'm'}, {0, 0, 0, 0} }; debug_level = 0; strcpy(db.user,"meteo"); // set default values for database access strcpy(db.name,"meteo"); memset(db.pswrd,0,15); mysql_init(&mysql); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } while ((opt = getopt_long(argc, argv, flags, longopt, &index)) != EOF) { switch (opt) /* parse command-line or CGI options */ { case 'r': repetitive = 1; break; case 'v': fprintf(stdout,"Verbose mode set:\n"); debug_level = 1; break; case 'u': // mysql username strncpy(db.user,(char *)optarg,30); break; case 'p': // mysql password strncpy(db.pswrd,(char *)optarg,15); break; case 'd': // mysql database name strncpy(db.name,(char *)optarg,30); break; case 'n': /* do not fork and become a daemon */ not_a_daemon = 1; break; case 'c': /* port to use */ tcp_wx_port = strtol(optarg, NULL, 0); break; case 's': /* sensor number for outdoor data */ outdoor_instr = atoi(optarg); break; case 'i': /* polling interval in seconds */ poll_interval = atoi(optarg); break; case 'm': // Metric data from data base Metric_Dat = 1; break; case '?': case 'h': case 'H': usage(0); break; default : usage(1); } } if (debug_level & 1) { fprintf(stdout,"Starting..."); if (repetitive) { fprintf(stdout, " forever "); } else { fprintf(stdout, " one pass only "); } fprintf(stdout," with database user=%s, password=%s, for database=%s\n", db.user, db.pswrd, db.name); if (not_a_daemon) { fprintf(stdout," as a program "); } else { fprintf(stdout," as a daemon "); } fprintf(stdout, " using TCP port %d\n",tcp_wx_port); fprintf(stdout, "an with an outdoor sensor group number of %d\n",outdoor_instr); } if (!not_a_daemon) /* setup has worked; now become a daemon? */ { if ((pid = fork()) == -1) { syslog(LOG_ERR, "can't fork() to become daemon: %m"); exit(20); } else if (pid) { pidfile = fopen(pidfilename, "w"); fprintf(pidfile,"%d\n",pid); fclose(pidfile); exit (0); } syslog(LOG_ERR, "Started\n"); setsid(); for (i = 0; i < NOFILE; i++) { // NOTE: Gcc warns that "ss" could be uninitialized here. if ( i != ss) { close(i); } } } // Data base connection if (!(mysql_real_connect(&mysql, "localhost", db.user, db.pswrd, db.name, 0, NULL, 0))) { if (debug_level & 1) { fprintf(stderr,"err: Data Base connect for user:%s to database:%s failed - exiting: \n\t%s\n", db.user, db.name, mysql_error(&mysql)); } exit(9); } server.sin_family = AF_INET; bind_address.s_addr = htonl(INADDR_ANY); server.sin_addr = bind_address; server.sin_port = htons(tcp_wx_port); if ((ss = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - no socket", progname); } exit(10); } /* / April 2001 Minor change to allow quick * (re)start of daemon or client while there are pending * connections during the quit. To avoid address/port in use * error. */ i = 1; if (setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - setsockopt", progname); } } if (bind(ss, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - cannot bind to socket", progname); } exit(11); } if (listen(ss, CONNECTIONS) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - listen", progname); } exit(12); } if (debug_level & 1) { fprintf(stdout,"Sockets UP.\n"); } umask(0022); for (i = 0; i < CONNECTIONS; i++) { fd[i] = -1; } tv.tv_sec = 0; tv.tv_usec = 0; /* catch signals to close the database connection */ signal( SIGTERM, term_handler );/* termination */ #if defined(SIGPWR) /* SIGPWR is linux centric */ signal( SIGPWR, term_handler ); /* power failure */ #endif if (debug_level & 1) { fprintf(stdout,"Main Loop...\n"); } dly_cnt = 2; // initial delay do { if (!(dly_cnt--)) { dly_cnt = poll_interval; // Every 'dly_cnt' passes check for WX data update dsts = Get_Latest_WX(&winddir,&windspeed,&windgust, &temp,&rain1hr,&rain24hr,&rainday,&humidity,&airpressure, &valid_data_flgs); if ( dsts < 0 ) { if (debug_level & 1) { fprintf(stderr, "err: Get_Latest returned %d\n",dsts); } syslog(LOG_ERR,death_msg); exit(dsts); } // If no new data, make no new string either... if (dsts) { data_len = APRS_str(WX_APRS, last_datetime, winddir,windspeed,windgust, temp, rain1hr, rain24hr, rainday, humidity, airpressure, valid_data_flgs,Metric_Dat); if (!data_len) { if (debug_level & 1) { fprintf(stderr, "err: WX info formatting problem!"); } syslog(LOG_ERR,"WX Data format error\n"); exit(13); } } else { if (debug_level & 1) { fprintf(stderr,"Found no new data this pass...\n"); } } } FD_ZERO(&rfds); FD_SET(ss, &rfds); if (select(ss + 1, &rfds, NULL, NULL, &tv) > 0) { for (current = fd; (*current > 0) && (current < fd + CONNECTIONS - 1); current++); if (current > max) { max = current; } if ((*current = accept(ss, (struct sockaddr *)&client, &clen)) != -1) { write(*current, WX_APRS, data_len); } } if (dly_cnt == poll_interval) { if (debug_level & 1) { fprintf(stdout,"Updating clients:"); } for (current = fd; current <=max; current++) { if (*current > 0) { // active socket if (debug_level & 1) { fprintf(stdout," #"); } signal(SIGPIPE, pipe_handler); write(*current, WX_APRS, data_len); } } if (debug_level & 1) { fprintf(stdout," done\n"); } } sleep(1); } while (repetitive); mysql_close(&mysql); if (debug_level & 1) { fprintf(stdout,"Exiting normally.\n"); } syslog(LOG_ERR,"Terminated normally\n"); exit(0); } Xastir-Release-2.2.4/Davis/src/defs.h0000664000175000017500000000111015151324131016241 0ustar hibbyhibby // // Copyright (C) 2004 Bruce Bennett // Portions Copyright (C) 2000-2026 The Xastir Group // // // Dummy info here for now... // #define PORT 1313 #define CONNECTIONS 20 #define NOFILE 20 // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif Xastir-Release-2.2.4/FAQ0000664000175000017500000013562415151324131013666 0ustar hibbyhibby Xastir Frequently Asked Questions The latest version of this FAQ is always available from the Xastir project's Git repository on GitHub, at For more details please see our documentation wiki at The Questions ------------- 1. Background 1.1 What is Xastir? 1.2 How and why was Xastir created? 1.3 Why the name "Xastir"? 1.4 OK, so how does Xastir compare to other APRS(tm) clients? 1.5 How thoroughly tested is Xastir? 1.6 Whom do I contact for support? 1.7 Where can I submit Bug reports or feature requests? 1.8 Is there any more information on Xastir? 1.9 Where can I get Xastir? 2. General Technical Questions 2.1 "Why can't I...? Why won't...work?" What to do in case of problems 2.2 How do I submit a patch to the Xastir Development Group? 2.3 What's the best hardware/operating system/... 2.4 Why isn't there a binary for my platform? 3. Building Xastir 3.1 Why do I get error messages when running "bootstrap.sh"? 3.1a Why do I get strange warnings when I run bootstrap.sh? 3.1b Why are you even using a "bootstrap.sh" script when autoreconf exists? 3.2 Why won't Xastir compile with my system's cc? 3.3 I'm using gcc and I get some compilation errors, what is wrong? 3.4 Why isn't ImageMagick recognized and used during Xastir's "configure" stage? 3.5 Why does compilation of map_geo or map_WMS fail with "invalid operands to binary <<" errors? 3.6 Why doesn't configure find GeoTIFF libraries? I have them installed! 4. Running Xastir 4.1 Why do I get wrong texts in menus or other places when using a non-English language file? 4.2 I run Xastir under Linux, and I get an error about loading a shared library. 4.3 I run Xastir under Linux, and try to set up an ax25 device, but get a "Hard Fail" error on the interface. There is a "permission denied" error in the terminal from which I started Xastir. 4.4 I run Xastir, and get on the air, but nobody else sees me on their screens. 4.5 I run Xastir, and get on the air, but none of the other stations appear on my screen? 4.6 Who is this APX190 guy who all my stuff is getting sent to? Who are these RELAY, WIDE and TRACE people digipeating packets, and why are they putting different callsigns in the fields where their names used to be? Why doesn't anyone answer me when I connect to them? HELP!!! 4.7 When weather alerts come in, the counties on my map don't highlight. 4.8 I have GeoTIFF support compiled and working, but when I select a map, it gives me a -38 error converting the datum, and it doesn't display in the right place. 4.9 Xastir runs slowly/loads maps slowly. 4.10 Why does Xastir seg-fault sometimes when indexing or loading GeoTIFF images? 4.11 Why do I see "Character '\55' not supported in font"? 4.12 Why do I see strong blue tinting for the maps? 4.13 My config file got munged. How do I recover? 4.14 Why can't I set my position in Xastir correctly? 4.15 Why do I get black map images when I use ImageMagick? 4.16 Why does my MacOSX machine w/USB->Serial adapters hang? 4.17 Why do NumLock/ScrollLock/CapsLock interfere with mouse/keyboard operation? 4.18 How to I redirect serial ports from one computer to another? 4.19 I have Festival compiled in, but I can't get any speech, why? 4.20 ImageMagick gives me: "no decode delegate", why? 4.21 How do I get through an http proxy server with Xastir in order to fetch maps? 4.22 Can I run multiple copies of Xastir at once? 4.23 Some station or config settings are not getting saved, why? 4.24 Why are my colors messed up when running via VNC? 4.25 Xastir can't find "xastir.rgb" or some other file. What's wrong? 4.26 Why can't I see station trails as stations move around? 4.27 Why don't the maps I installed show up in the Map Chooser? 4.28 Dialogs are tiny bullet-shaped windows with no handles. Why? 4.29 What about using Xastir with a TNC-X with built-in USB on a Mac? 4.30 Why do I get "Bitmap not found? /usr/share/xastir/symbols/2x2.xbm" 5. Features 5.1 Why doesn't Xastir include ? 5.2 Why doesn't Xastir digipeat packets sent to the RELAY or WIDE1-1 aliases? 5.3 How do I take a snapshot of my current view? 5.4 What is that yellow circle on my map? 5.5 How can I restart Xastir remotely/from a script/command-line? The Answers ----------- 1. Background 1.1 What is Xastir? Xastir is an APRS(tm) client program that uses amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. 1.2 How and why was Xastir created? There were already several APRS(tm) client programs available to the Mac/DOS world when Frank Giannandrea, KC2GJS decided to develop a Unix client using X Window's and the Motif widget set. From its meager beginnings, Xastir is now a very robust client that meets the needs of the Ham community. 1.3 Why the name Xastir? Xastir is an acronym for X Amateur Station Tracking and Information Reporting. Besides it sounds much cooler that those other names ;) 1.4 OK, so how does Xastir compare to other APRS(tm) clients? Being actively developed by and for Hams, Xastir is constantly being improved upon to reflect the changing state of APRS(tm). Xastir has all the functionality you would find in any other APRS(tm) client, from any OS, and quite possibly some unique features. 1.5 How thoroughly tested is Xastir? Xastir is currently in use by hundreds of Hams from around the world. The Xastir Group maintains rigorous standards before releasing new versions of our client. When bugs do show up, we release patches and new versions as soon as they are available. 1.6 Whom do I contact for support? This FAQ may answer many of users frequent questions. However, there are two active mailing lists that users could use to help answer any other questions. Both mailing list are by subscription only and can be accessed through the Xastir web-site. See the top of this document for the addresses. You must be subscribed in order to post messages. 1.7 Where can I submit Bug reports or feature requests? The mailing lists are a good place to bring up bugs or feature requests. Note that you must be subscribed in order to post messages. See above. Another good place to document the request or bug in a more permanent manner is the GitHub tracker: http://github.com/Xastir/Xastir/issues 1.8 Is there any more information on Xastir? See the main Xastir web-site for more information. See the top of this document for the addresses. 1.9 Where can I get Xastir? Source code and binaries for several popular Linux distributions is available through the Xastir web-site 2. General Technical Questions 2.1 "Why can't I...? Why won't... work?" What to do in case of problems. If are having trouble running the Xastir software: 1. Check the FAQ! The latest version of the Xastir FAQ can be found on the Xastir web-site. See the top of this document for the addresses. 2. Ask on the "xastir" mailing list. Many Xastir users and developers can be found roaming its virtual halls, so it is suggested that you seek wisdom there. The chances are good that you'll get your question answered there. You must be subscribed in order to post messages. 2.2 How do I submit a patch to the Xastir Development Group? The Xastir Development Group encourages patches from outside developers. There are two main "types" of patches: small bug fixes and general improvements. Improvements, modifications, and additions should follow the instructions below: In general, the current method by which we accept user contributions is the github pull request. See README.GIT.md for some links explaining the process. 2.3 What's the best hardware/operating system? Anything that works for "you". 2.4 Why isn't there a binary for my platform? The developers make sure that the software builds and works correctly on the platforms available to them and available for continuous integration testing on Github (Ubuntu Linux, Mac OS, and FreeBSD at the moment); this does not necessarily mean that your platform is one of them. In addition, the Xastir Project is primarily source oriented, meaning that the distributing valid and build-able source code is the purpose of a release, not making sure that there is a binary package for all of the supported platforms. 3. Building Xastir 3.1 Why do I get error messages when running "bootstrap.sh"? The xastir build procedure requires automake 1.16 or later and autoconf 2.60 or later. Using anything older than those will not work. 3.1a Why do I get strange warnings when I run bootstrap.sh The various configure.ac, acinclude.m4, and Makefile.am files that are used by Xastir's autoconf'd build process were designed for automake 1.16 and autoconf 2.60. Using a much more recent version than those could result in warning messages because the tools aren't strictly backward compatible. Most of these warnings are harmless. 3.1b Why are you even using a "bootstrap.sh" script when autoreconf exists? Xastir dates back to the mid- to late-1990s, when autoconf did not have "autoreconf" and developers were expected to provide a bootstrap script. At this time, bootstrap.sh and "autoreconf -i" are basically the same and you can use either method. 3.2. Why won't Xastir compile with my system's cc? If Xastir won't compile on your system, it is probably due to one of the following causes: - The configure script doesn't recognize your system environment. This might be either because it's completely unknown or because the specific environment (include files, OS version, etc) isn't explicitly handled. If this happens, you may need to port the software to your OS yourself. - Your systems C compiler is garbage. Some operating systems include a default C compiler that is either not ANSI C-compliant or suffers from other deficiencies. The usual recommendation in cases like this is to acquire, install, and use gcc. - Your include files may be confused. In some cases, we have found that a compiler installation or system upgrade has left the C header files in an inconsistent state. Make sure that your include directory tree is in sync with the compiler and operating system. - You haven't installed all the necessary libraries and include files. Xastir depends on at least the X, and Motif include files. Be sure these are installed before trying to compile the application. Many Linux distributions name these packages -dev or -devel. A message like "*** Cannot find Motif include files" either means that you are missing the development package for Motif/OpenMotif, or that it is installed in a place where configure can't find it. If you have the Motif libraries and headers installed in a place where Xastir doesn't look for them, see the references to the "--with-motif-includes" and "--with-motif-libraries" configure options in the INSTALL file. - Your operating system or compiler may be out of version. Software vendors issue new releases for a reason; sometimes to add functionality, but more often to fix bugs that have been discovered. Try upgrading your compiler and/or your operating system. 3.3 I'm using gcc and I get some compilation errors, what is wrong? GCC parses your system header files and produces a modified subset which it uses for compiling. This behavior ties GCC tightly to the version of your operating system. So, for example, if you were running IRIX 5.3 when you built GCC and then upgrade to IRIX 6.2 later, you will have to rebuild GCC. Similarly for Solaris 2.4, 2.5, or 2.5.1 when you upgrade to 2.6. Sometimes you can type "gcc -v" and it will tell you the version of the operating system it was built against. If you fail to do this, then it is very likely that Xastir will fail to build. One of the most common errors is with readv, writev, or uio.h. This is not a bug with Xastir. You will need to re-install GCC. 3.4 Why isn't ImageMagick recognized and used during Xastir's "configure" stage? Xastir's configure script looks for a program called Magick-config in your default PATH. If it cannot find this program, it will skip building with Magick support. The first thing you should check is whether this program exists, and whether the directory where it lives is in your PATH. You might have forgotten to install both ImageMagick and the ImageMagick-devel RPM. Another possibility is that your particular RPM's might not contain all of the library dependencies that you need, like libcms or zlib. Check carefully through "config.log" to see if the ImageMagick detection code says something like: "ld: cannot find -llcms", "ld: cannot find -lz", or "ld: cannot find -ljpeg". Install the additional libraries that it needs, and perhaps development packages for them as well. NOTE: If the "spec" file for the ImageMagick/ImageMagick-devel RPM's had the proper dependencies listed, you would have been asked to install all of the dependent libraries before you could have even installed the ImageMagick RPM's. Encourage your vendor to fix the "spec" files for those RPM's to include all dependencies. 3.5 Why does compilation of map_geo or map_WMS fail with "invalid operands to binary <<" errors? This is a problem with ImageMagick. In short, your ImageMagick installation has been built with an option incompatible with Xastir. New versions of ImageMagick include experimental support for High Dynamic Range Images (HDRI). This support changes the data type of a Quantum (pixel value) from an 8- or 16-bit integer quantity to a floating point. Xastir assumes that all pixel values are integer types, and uses operations on those values based on that assumption. You have two choices for getting around this issue: rebuild ImageMagick without HDRI support, or use GraphicsMagick instead. 3.6 Why doesn't configure find GeoTIFF libraries? I have them installed! Some Linux systems place GeoTIFF header files in a directory the C compiler doesn't search by default, and so configure doesn't find them. This is commonly "/usr/include/geotiff". Add an option to configure to tell the C preprocessor to look there and all will be well: /path/to/configure CPPFLAGS="-I/usr/include/geotiff" 4. Running Xastir 4.1 Why do I get wrong texts in menus or other places when using a non-English language file? The development is done mainly with the English language file, so other languages may not be up to date. Those texts like IC>PULDNMBC02 are placeholders for missing entries in the language file. You can add the local meaning of that string in the English language file to your language file. And send it to the Xastir development team... 4.2 I run Xastir under Linux, and I get an error about loading a shared library. Xastir uses many shared libraries, including libax25, libproj, libtiff, libgeotiff, libz, libjpeg, etc. These errors indicate ld.so, the Linux dynamic linker, can't find the shared libraries. * First, check that all the libraries are installed. Check the INSTALL file for the locations to get these libraries if you've accidentally removed one of them. * Run "ldd /usr/local/bin/xastir". This will print out a list of libraries that Xastir is looking for and the locations they are expected to be at. * Check that the locations of the libraries are in /etc/ld.so.conf. This should probably be set up by your Linux distribution, but if you've added new library directories after install, you'll need to add them here. 4.3 I run Xastir under Linux, and try to set up an ax25 device, but get a "Hard Fail" error on the interface. There is a "permission denied" error in the terminal from which I started Xastir. As mentioned in INSTALL and helpfile, Xastir must be setuid root to use Linux ax25. This is required because Xastir needs the ability to edit its source callsign, and use other advanced options that the Linux ax25 stack restricts to root. 4.4 I run Xastir, and get on the air, but nobody else sees me on their screens. From a software standpoint, check that you have transmitting enabled on your interface, and that the disable transmission "all" and "my position" options in the Interfaces menu are not enabled. Check that ALTNET support in File|Configure|Defaults isn't enabled. Also check that your digipeater path is set reasonably; other hams in your area could probably help with this, as the exact settings depend on your setup and on your area's network. The other possibilities are hardware problems: Is the output level on your TNC or soundcard correct? Is PTT on your radio getting triggered? Is your TXdelay set reasonably? All of these possibilities are beyond the scope of this FAQ. An easy way to determine if your hardware works correctly is to try it on conventional packet. 4.5 I run Xastir, and get on the air, but none of the other stations appear on my screen? Did you set up your TNC startup files correctly to remove any extra data from the packet headers? Are you using the correct startup file? See INSTALL. Check that the Display Incoming Data windows is actually showing data coming in. If not, check your radio's volume/squelch levels and your cabling, both between the radio/TNC and between the TNC/Computer. Check that ALTNET support in File|Configure|Defaults is disabled. If activated, it only shows stations transmitting TO the callsign listed in the box. I sometimes set it to APX or APX190 in order to see who's running Xastir/who's running the _latest_ Xastir. Set it to "WEIRD" and you'll only see those transmitting to "WEIRD". Check all of your Stations|Filter Data and Stations|Filter Display settings. "Select Stations" and "Display Symbols" must be selected. 4.6 Who is this APX224 guy who all my stuff is getting sent to? Who are these RELAY, WIDE and TRACE people digipeating packets, and why are they putting different callsigns in the fields where their names used to be? Why doesn't anyone answer me when I connect to them? HELP!!! You must be used to conventional packet. APRS(tm) is inherently different from conventional packet. There are many online resources that explain the basics of APRS(tm), but I'll try to summarize here. APRS(tm) is an unconnected protocol, where you broadcast UI (unnumbered information) packets to the world. Since these packets aren't directed toward a specific user, the TO address of the packet is simply a summary of the software you're running. AP=APRS(tm), X=X Windowing System, 224=Version 2.2.4. RELAY, WIDE, TRACE, WIDEn-N, and TRACEn-N are aliases for generic digipeaters, although all but the WIDEn-N variants are now deprecated (should no longer be used). Some base stations have their TNC's configured to digipeat with the call of "WIDE1-1" (we used to use "RELAY" for these, but "WIDE1-1" has now taken its place). Newer digipeater software substitutes their own call for "WIDEn-N" to enable people to see who digipeated them. See the README.Getting-Started file for a bit more info on paths, including recommended paths for different types of stations. To talk to people, you send them messages from within Xastir, you don't "call" them like on typical packet. Most TNC's are set up to ignore classic packet "calls" so you won't get any response. When sending messages to people in your area, do check in their comments that they are people and not stand-alone digipeaters or similar. ;) Thanks to the worldwide APRSserv Internet system, you can send messages to any APRS(tm) user anywhere in the world, provided they're within range of an Igate. Most users are; if your area isn't and you have a 24/7 Internet connection, Xastir can be your area's Igate! (Please check your local laws, as Igating is illegal in some countries!) There are also experimental systems for sending messages via amateur radio satellites, but that is beyond the scope of this FAQ. 4.7 When weather alerts come in, the counties on my map don't highlight. First of all, did you download and install the new shapefile weather maps as described in the INSTALL file? (Running scripts/get-NWSdata automates this somewhat for you now) Did you compile with shapefile support? Check that Map|Enable Weather Alerts is enabled, and "Map|Disable All Maps" is _not_ selected . 4.8 I have GeoTIFF support compiled and working, but when I select a map, it gives me a -38 error converting the datum, and it doesn't display in the right place. If you compiled libgeotiff yourself from source, did you install libproj first? If you installed libgeotiff before libproj, go back and recompile libgeotiff after installing libproj. If you installed libgeotiff from a system package, this is probably not the problem. Check the datum of the GeoTIFF file, and make sure it is one of the ones supported by Xastir. The listgeo program included with libgeotiff can tell you the datum of a map. Xastir only supports display of GeoTIFF files in NAD27 or NAD83 UTM coordinates, or in WGS84 Geographic coordinates ("EPSG:4326"). If your file is in some other coordinate system you must warp it into EPSG:4326 before you can use it. See the Github Wiki on Advanced Mapping Topics. 4.9 Xastir runs slowly/loads maps slowly. There are many things that can effect the speed of your Xastir software, including the speed of the computer, the amount of memory available, the number of active interfaces, the complexity/type/number of maps you use, and the options you used to compile Xastir and helper libraries. The developers aren't aware of any specific cases in which there would be performance problems; generally these are limitations of your computer. 4.10 Why does Xastir seg-fault sometimes when indexing or loading GeoTIFF images? This is sometimes caused by a mismatch in versions of the GeoTIFF and TIFF libraries, and that mostly happens when you compile the libraries yourself from source code and don't keep the versions in sync. If your system has a package for GeoTIFF libraries you should probably just use it instead of building from source yourself. However, if you insist... The GeoTIFF code must use an API in the TIFF code that is non-public. Unfortunately this means that the GeoTIFF code must know more about TIFF than the normal application using the TIFF library. If the private TIFF include file included with the GeoTIFF code doesn't match your installed version of TIFF, you can run into seg-fault problems. Solutions for this include: 1) Installing TIFF from sources, or 2) Grabbing the sources for your installed version of TIFF, copying one include file from TIFF into the GeoTIFF sources and recompiling/installing GeoTIFF. Either of these solutions will make the GeoTIFF code recognize and use the proper structures in TIFF should prevent the seg-faulting. In the future we hope that either the GeoTIFF code will become part of the TIFF code, or that the private TIFF API will become public. Either of these changes should fix this problem for good. 4.11 Why do I see "Character '\55' not supported in font"? This message and similar have to do with localization and OpenMotif. For most of us this is a benign message and can be ignored. If you simply can't stand it any more set LANG="C" or LANG="en_US". In RH 9 the default LANG is set to en_US.UTF-8 and this is where the warnings are coming from. A quick way to address this on RedHat 8 and 9 is to edit your /etc/sysconfig/i18n config file. I believe the original file looks like: LANG="en_US.UTF-8" SUPPORTED="en_US.UTF-8:en_US:en" SYSFONT="latarcyrheb-sun16" Change the "LANG=" line to: LANG="en_US" and reboot. With the original setting you get some weird character mappings. For example, running "man ls", all of the dashes (-) disappeared from my screen until I changed the LANG setting. 4.12 Why do I see strong blue tinting for the maps? Strong blue (or perhaps other color) tinting of the image may be due to running the display over a Hummingbird eXceed session. Try running it locally and you should see the proper colors. Try changing the eXceed session to use more bits of color. 4.13 My config file got munged. How do I recover? Xastir saves previous revisions of the config file as "xastir.cnf.1" through "xastir.cnf.3". Look for them in the ~/.xastir/config directory. Kill Xastir, then copy one of the backup files to "xastir.cnf" in order to recover your previous settings. Xastir will use the "xastir.cnf" file the next time it starts up. Older Xastir versions saved only one copy of the config file as "xastir.bak". 4.14 Why can't I set my position in Xastir correctly? If your LC_NUMERIC environment variable is set to something other than "C", it can cause commas and periods to be swapped when Xastir tries to read/write files. We've tried to address this in the latest Xastir code, forcing LC_NUMERIC="C" inside Xastir itself. Another solution is to type this when starting Xastir (from a BASH shell. If you use another type of shell, modify the syntax accordingly): export LC_NUMERIC="C"; xastir & 4.15 Why do I get black map images when I use ImageMagick? There was a bug in versions of Xastir prior to the Git version of 4 December 2009 that caused this problem if ImageMagick (or GraphicsMagick) were compiled with QuantumDepth not equal to 16 (GraphicsMagick now defaults this parameter to 8). The bug was fixed, and current versions of Xastir should not have this problem. If you are running an older version than 4 December 2009, updating will likely solve this problem for you. If you are running a version higher than 1.9.7 or a git version checked out after 4 December 2009, then the problem lies elsewhere. It may be due to bugs in your particular version of ImageMagick, but more likely it's related to the color-depth of your X-Server. If you are using 8-bit, 24-bit, or 32-bit color-depth: Try 16-bit, which is the color-depth best supported by the Xastir code. 4.16 Why does my MacOSX machine w/USB->Serial adapters hang? Use ports such as /dev/cu.usbserial0 for USB to serial adapters on MacOSX. 4.17 Why do NumLock/ScrollLock/CapsLock interfere with mouse/keyboard operation? Because they are treated as modifiers by Motif. Just make sure those keys aren't active when interacting with Xastir. Xastir will warn you if they are. As an extreme measure, if you type these commands and then restart your window manager it may take care of your problem, but then those keys will be disabled and you won't be able to use in other applications: xmodmap -e "clear Lock" xmodmap -e "clear Mod2" xmodmap -e "clear Mod5" 4.18 How to I redirect serial ports from one computer to another? The most modern answer to this question for Linux is to use "socat". http://www.dest-unreach.org/socat/ Yet another is to use "netcat". "man nc" or "man netcat" should tell you about it. It redirects tcpip data seamlessly under Linux. On SuSE the docs for it are in /usr/share/doc/packages/netcat. Try a command line like this: cat /dev/ttyS0 | nc -l -p 3000 or cat /dev/ttyS0 | netcat -l -p 3000 That should make a listening socket at port 3000 which listens to the /dev/ttyS0 serial port. "telnet localhost 3000" should show you any data coming in on that serial port. Connect Xastir across the network to that listening socket to get the data. If you want to put your GPS on a remote serial port, use the gpsd daemon to do it. if you wish to put your weather station on a remote serial port, investigate using OWW (for Dallas weather stations), wx200d daemon for some Radio Shack/Huger/Oregon Scientific weather stations, or Meteo daemon for Davis weather stations. You may also connect to a remote AGWPE instance for using remote TNC's/soundcards. Note that AGWPE runs only on Windows. 4.19 I have Festival compiled in, but I can't get any speech, why? a) You must start the Festival server daemon before starting Xastir. Start it via this command : festival_server & or festival --server & b) If the server is running, but you get this: "festival_client: connect to server failed", then you may have some tweaks to do to your system files in order to allow Xastir (or anything else) to connect to Festival. Try this first to see whether anything can connect to Festival: telnet localhost 1314 If the server is running properly it'll let you connect. If it does, try typing: (SayText "Hello, World") If that doesn't work, check your audio mixer settings first, then proceed to c) below: c) Some people have an "/etc/hosts" file that has an incorrect line for localhost. You should have a line which has 127.0.0.1 at the start, and has "localhost" somewhere on that line as well. Like this: 127.0.0.1 localhost localhost.localdomain d) On one Debian box, it was an issue with "/etc/hosts.allow". See "man 8 tcpd" or "man 5 hosts_access" for detailed info about how to configure /etc/hosts.allow and /etc/hosts.deny. It's part of the tcpwrappers stuff that allows you to configure which hosts have access to which services on your system. 4.20 ImageMagick gives me: "no decode delegate", why? README.CYGWIN has a bit of info about this one, as it most often happens on Win32 systems. It has been seen on other systems as well though. The short answer is that you may have to set the environment variable "MAGICK_HOME" to the location where the ImageMagick modules reside. This is only necessary if ImageMagick doesn't have the location pre-compiled into it. The example for Win32 systems is: export MAGICK_HOME=/usr Added to the ~/.profile file, so that the BASH shell gets this defined each time you log in. The location "/usr" will probably be different on a non-Windows machine, so change the line above as required for your system. 4.21 How do I get through an http proxy server with Xastir in order to fetch maps? *) Install libcurl and/or wget. *) Set the HTTP_PROXY and FTP_PROXY environment variables in your ~/.profile file. Libcurl has additional options that can be set: HTTPS_PROXY, GOPHER_PROXY, and ALL_PROXY. *) Create and fill in the ~/.netrc and/or .wgetrc files with proper values. Set the permissions on it so that only you can read/write the file: "chmod 600 .netrc". Typical contents of the file are shown below: http_proxy = http://proxy.yoyodyne.com:18023/ ftp_proxy = http://proxy.yoyodyne.com:18023/ 4.22 Can I run multiple copies of Xastir at once? Yes, but you must keep the configuration directories separate for each copy by using a command-line flag. Xastir will create the new config directory and fill it with defaults if it doesn't already exist. Here's the method. Substitute your user name where it says "": xastir & # starts up first Xastir copy against ".xastir" directory xastir -c /home//.xastir2 & # starts up 2nd Xastir copy against ".xastir2" directory xastir -c /home//.xastir3 & # starts up 3rd Xastir copy against ".xastir3" directory To make the process easier if you use this method a lot, create aliases by editing your .profile (This assumes you're running BASH or Bourne shells): alias xastir2='xastir -c /home//.xastir2 &' alias xastir3='xastir -c /home//.xastir3 &' After sourcing your new .profile (The command is ". .profile" from your home directory) or logging out and back in again, you can type "xastir2" or "xastir3" as a command to start up the additional copies of Xastir. Older methods, may still be useful at times: Do this to allow more than one user to access your X display and to create additional users, each capable of running one Xastir session: xhost localhost This lets other users on your machine use the X11 display. Create another user (or two or three) using whatever facilities your system uses to do this. xterm & # Start up an xterm window in the background su 2nduser. # su to one of your new usernames xastir & # Start up Xastir as that user, in the background Optional: Set up your 1st Xastir instance with the server port enabled. Connect the 2nd instance to localhost:2023. This way one Xastir will get its feed from the other. You can start up a third Xastir in the same manner, starting with the "xterm &" command and then doing "su 3rduser" instead, then "xastir &" as that third username. Many Xastir sessions can all get their feed from one Xastir session, or they can be connected to different TNC's or server ports. 4.23 Some station or config settings are not getting saved, why? A few of the menu settings do not get saved. This is on purpose. If you are having more serious troubles, like for instance your station location setting isn't getting saved between Xastir runs, check your LANG setting (see question 4.13 above). 4.24 Why are my colors messed up when running via VNC? VNC may have a different colormap or colordepth than the system Xastir is running on. Here is one invocation that a user used which worked. Substitute the appropriate parameters for your system of course: vncserver :5 -name melecom -depth 24 -geometry 800x600 -pixelformat rgb565 4.25 Xastir can't find "xastir.rgb" or some other file. What's wrong? This could be one of several things. We'll check them in order: a) If you get this exact message: "Error! can not find color file: /xastir/config/xastir.rgb" Then it could be that you're not getting a variable defined on the compile line. This text or similar should appear for each file compiled: -DXASTIR_DATA_BASE=\"/usr/local/share/xastir\" If you're not seeing this, or the variable is defined to an empty string or is otherwise incorrect, you may need to upgrade/downgrade your autoconf or automake packages and rerun the Xastir install starting at the "./bootstrap.sh" stage. b) Did you run the "make install" stage as root or using "sudo" after you compiled Xastir? If not, Xastir couldn't install files it needs to run. c) Another possible problem is a corrupt or very old ~/.xastir/config/xastir.cnf file. Check for this by typing: cd mv .xastir .xastir.save xastir If it comes up ok this time, then either paths in your config file are incorrect or the config file is corrupt. If there's no change, go back to your original configuration by typing: cd rm -rf .xastir # NOTE: this will delete ~/.xastir and all contents! mv .xastir.save .xastir d) Yet another thing to check is the value in your LANG variable. It should be either "en_US" or "C" for Xastir to read/write config files correctly: echo $LANG If it is something else, start Xastir like this: export LANG=en_US; xastir -geometry -0-0 & You can create an alias in your shell for this so that you don't have to remember to type it each time. e) Perhaps you're trying to run an old Xastir executable that was compiled with different paths. Type this to see where the executable is trying to run from: which xastir -or- whereis xastir f) It's possible that your autoconf/automake packages need to be upgraded or downgraded. These packages are somewhat version dependent on each other, so it's likely that you'll have to do this upgrade or downgrade as a pair for things to work correctly. After the upgrade or downgrade, recompile Xastir starting at the "./bootstrap.sh" stage so that the configure and Makefile scripts are re-created. ./bootstrap.sh cd ../build ../Xastir/configure make Make sure that you now see a reasonable path for the XASTIR_DATA_BASE variable on each compile line. 4.26 Why can't I see station trails as stations move around? Enable Station->Filter Display->Display Trail File->Configure->Timing->"New Track Time" and "New Track Interval should be set above zero. Defaults for these are 45 and 1 respectively. If this problem and others occur, such as your latitude/longitude getting lost between runs, this might indicate a problem with your LANG variable. See question #4.26 above. 4.27 Why don't the maps I installed show up in the Map Chooser? Install the maps in the correct place, normally "/usr/local/share/xastir/maps/" or subdirectories below there. Make sure the map directories and files have read permissions for the user. Select "Map->Configure->Index: Add New Maps", then check in Map Chooser to see if the map is listed. If not, try the "Reindex ALL Maps" option. Verify that you have installed the map libraries necessary to handle the types of maps you're wishing to use: "Help->About". Also you can check the messages written to STDERR in the shell you start Xastir from. Check this file to see if map indexing found the file at all. It's the same file that Map Chooser reads to display the map selections: ~/.xastir/config/map_index.sys If the map is a raster map, you can check whether your installed ImageMagick or GraphicsMagick can display the image. For IM: display For GM: gm display If it's an internet-based map you're trying to download/display, verify in the Xterm that you have internet maps enabled using either libcurl or wget. Check manually whether curl or wget (whichever Xastir is using) can fetch a remote file. Check whether a file like ~/.xastir/tmp/map.gif or map.jpg shows up after you try to fetch a file, even if Xastir doesn't display it. See if one of the above "display" commands will display it if so. Check the File->Configure->Timing dialog for the "Internet Map Timeout" setting: Adjust it upwards if Xastir is timing out fetching the remove map. If all else fails, try removing the ~/.xastir directory and all contents. Warning: This will cause you to lose all of your personal Xastir configuration, including callsign, location, bookmarks, map levels and other map settings, etc. Once you've done this, verify that your LANG setting is either "C" or "en_US", with no additional characters in there, then start Xastir from that same shell with the correct LANG setting. Xastir should index all of your maps on startup. After it is complete, bring up the Map Chooser and all available maps should be listed. 4.28 Dialogs are tiny bullet-shaped windows with no handles. Why? This is caused by an interaction between "Motif" and "compiz". "compiz" is enabled in some versions of Ubuntu Linux with a "Desktop Effects" menu item. They changed the default to *ON* several releases ago. "compiz" is a window manager which enables eye-candy effects such as animated window opening/closing, 3-D effects, and so forth. To fix this problem, turn *OFF* "Desktop Effects" which will disable "compiz" and re-enable the default window manager. 4.29 What about using Xastir with a TNC-X with built-in USB on a Mac? You will need the device drivers from FTDI, downloadable from their website at http://www.ftdichip.com/Drivers/VCP.htm Note: the TNC-X packet datarate is fixed at 1200 baud, however the serial communication with the computer is configurable via internal jumpers. It's been observed that setting the com port to 1200 baud results in a deaf TNC-X. Setting the com port to 9600 baud works well, however. 4.30 Why do I get "Bitmap not found? /usr/share/xastir/symbols/2x2.xbm" The problem is that you probably have previously installed a binary version of Xastir from your system's repository --- and Linux packages are set up to install files in /usr (e.g. binaries to /usr/bin, libraries to /usr/lib/, and supporting files to /usr/share). But Git xastir, like almost all source packages, installs to /usr/local (/usr/local/bin, /usr/local/lib, /usr/local/share). When you de-installed your binary package and installed the source version, it removed the /usr/ stuff and installed the files in /usr/local/. Your configuration files for Xastir still point to the old locations, and Xastir is confused because files it's expecting aren't there. You have two approaches to fix this: 1) If you have not used Xastir a lot and don't have a whole lot of custom configurations (map selections, interface properties, etc.) then you can just move your ~/.xastir/config/xastir.cnf file and let Xastir regenerate a default set-up. Many people here recommend that approach because it's just a matter of one command: mv .xastir/config/xastir.cnf .xastir/config/xastir.cnf_old But this will blow away all your customizations, so it might not be the best choice. Note that you can still glean information from the old copy of the config file to help set up the new. 2) Change all references to "/usr/" in your configuration files to "/usr/local". Most of these will be in ~/.xastir/config/xastir.cnf so it's just a matter of editing that one file and changing them all. It is always an issue when you switch from a pre-compiled linux package to a source build. 5. Features 5.1 Why doesn't Xastir include ? Probably because someone hasn't taken the time to write the feature or enough people have complained loud enough that it wasn't there. The feature set of Xastir is user/developer driven. So get busy! 5.2 Why doesn't Xastir digipeat packets sent to the RELAY or WIDE1-1 aliases? If you're running serial-port connected TNC's, the "tnc-startup.*" files that get installed in /usr/local/share/xastir/config should set up your TNC to respond to these packets. Select Interfaces->Properties, then select the interface, click Properties, then select the Setup and Shutdown files at the bottom of that dialog. When an interface is brought up the Setup file will be downloaded to the TNC. "myalias WIDE1-1" is the command most TNC's accept for defining a digipeating alias. That command or similar should be in the Setup file that you use. Use "myalias WIDE1-1" with the new path scheme discussed on APRSSIG during early April, 2005: RELAY/WIDE/TRACE/TRACEn-n are deprecated (should not be used). If you're running kernel AX.25 interfaces, then you'll need to run another package to handle digipeating on these interfaces, perhaps digi_ned. 5.3 How do I take a snapshot of my current view? You can cause a snapshot to occur by enabling Snapshot in the File menu. It takes a snapshot every five minutes starting immediately when the togglebutton is first enabled. This means you can change views and disable/enable to take an immediate snapshot each time as well. You can also send a "SIGUSR1" signal from another process and Xastir will take a snapshot. The feature was added so that someone could press a button on a web page and cause Xastir to make a new snapshot. For Example, from the shell you can do: kill -SIGUSR1 `cat ~/.xastir/xastir.pid` Snapshots will are stored under ~/.xastir/tmp/ 5.4 What is that yellow circle on my map? Somewhere around a half-hour or an hour after you start Xastir with a connected TNC, you will begin to see a yellow circle surrounding your station at some zoom levels. This is your "ALOHA Circle," the circle containing approximately the number of stations that should saturate your local APRS channel. See https://www.aprs.org/aloha/ALOHAcir.txt for details. The short story is you should set your path so your packets don't travel farther than this circle's radius. This circle is shown when your station is in view and you are zoomed out far enough to contain the circle in the viewport. Its radius is recalculated once every half an hour from the stations you've heard on RF. Stations you hear from internet servers or other non-RF sources are not included in the calculation. The circle can be turned off from the Station->Filter Display menu but it will be enabled again each time you restart Xastir. 5.5 How can I restart Xastir remotely/from a script/command-line? Send a SIGHUP to the process. This will cause Xastir to save its configs, exit, then restart with the same environment and command-line parameters as it initially had. For Example, from the shell you can do: kill -SIGHUP `cat ~/.xastir/xastir.pid` NOTE: This SIGHUP trick doesn't work if you've configured Xastir with profiling ( "../Xastir/configure --with-profiling" ). ---------------------------------------------------------------- APRS(tm) is a Trademark of Bob Bruninga If you find other problems, or would like to point out other caveats to add to this FAQ, please point them out to the developers on the Xastir-dev mailing list. The addresses for the mailing lists may be found on the main Xastir web pages, which are listed at the top of this document. You must be subscribed in order to post messages. Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/INSTALL.md0000664000175000017500000007001115151324131014750 0ustar hibbyhibby# Installing Xastir # This file is meant to replace the original "INSTALL" file that has been distributed with Xastir for years. > [!NOTE] > This document makes a lot of references to the xastir.org wiki site, > which has been experiencing frequent downtime and may be unreachable > more often than not. Please look at the Wiki on GitHub > at https://Xastir/Xastir/wiki for replacement, up-to-date > documentation. We apologize for the inconvenience. General build process: 0. [Install all system packages required and any optional packages](#install-all-system-packages-required-and-any-optional-packages) 1. [Get the Xastir source code](#get-the-xastir-source-code) 2. [Bootstrap the source code to create the configure script](#bootstrap-the-source-code-to-create-the-configure-script) 3. [Create a build directory and run configure in it with any necessary options](#create-a-build-directory-and-run-configure-in-it-with-any-necessary-options) 4. [Build Xastir](#build-xastir) 5. [Install the code](#install-the-code) 6. [Start using Xastir](#start-using-xastir) 7. [Miscellaneous notes](#miscellaneous-notes) The procedure for building Xastir from source is fairly generic, and the most difficult part is assuring that you have all dependent libraries. ## Install all system packages required and any optional packages ## **The system-specific build instructions at http://xastir.org/index.php/Installation_Notes often have the exact command you need to install all required and optional packages on that system in one fell swoop, so you would do well to look at those notes before proceeding with the rest of this section.** ### Absolutely mandatory packages ### The packages you absolutely must have in order to build Xastir are: * autoconf * automake * gcc and all of its development headers * glibc and its development headers * openmotif or lesstiff and its development headers * the X11 window system and X development headers * make * git If you don't have at least these, you won't be able to build Xastir at all, and if this is all you have you'll get the most limited version of Xastir possible. On some operating systems the libraries and headers needed for compiling against them are in separate packages, and that's why we list "and its development headers" above. You should look at the system-specific build instructions at http://xastir.org/index.php/Installation_Notes for more detailed instructions on how exactly one goes about actually installing these packages if you are unfamiliar. Some of these packages may already be installed on your system by default, or may be installed in clusters by a meta package such as "build-essential" on Ubuntu, which installs the gcc compiler and all the libraries and headers it needs to function. ### Optional packages ### Installing these optional packages enables additional features in Xastir. You need both the library and development packages for any of these packages for which both are available. * gv and ghostscript (Enables map printing) * libXpm (enables creation of map snapshots for display and printing) * GraphicsMagick (Enables access to many formats of map images) * curl (Enables access to the web to download maps or other data) * shapelib (Enables display of vector maps in ESRI shapefile format) * pcre2 (Perl Compatible Regexps, enables control of how shapefile maps are displayed) * libgeotiff (Enables display of maps in Geotiff format, such as older topographic maps provided by the US Geological Survey) * ax25-apps, ax25-doc, ax25-tools, libax25 (enables Linux kernel mode AX.25 for sharing/access of KISS TNC devices) * festival (enables text-to-speech options) * Berkeley DB version 5 (enables caching of some online map imagery) or version 18.1 In some cases, there are alternatives that can provide the same features: * wget can be used instead of curl * ImageMagick 6 (NOT ImageMagick 7) can be used instead of GraphicsMagick, but GraphicsMagick is preferred * The older PCRE library (sometimes called PCRE3, even though the *current* version is PCRE2) can be used, but is long past its end of life. PCRE2 is preferred. Some of the packages listed above depend on other packages themselves, but the norm of modern package management systems is to install all the dependencies when the main package is installed. ## Get the Xastir source code ## There are two ways to get Xastir source code: 1. Get one of the source release "tarballs" from Github at https://github.com/Xastir/Xastir/releases and explode it. (Replace X.Y.Z with the release number below) ``` mkdir -p ~/src/XASTIR cp Xastir-Release-X.Y.Z.tar.gz ~/src/XASTIR cd ~/src/XASTIR tar xzvf Xastir-Release-X.Y.Z.tar.gz ``` This gets you ONLY the source code for one single release of Xastir. The source code will live in the directory `~/src/XASTIR/Xastir-Release-X.Y.Z` 2. An alternative to the above steps is to use git to download the Xastir sources: ``` mkdir -p ~/src/XASTIR cd ~/src/XASTIR git clone https://github.com/Xastir/Xastir.git ``` This will create a clone of the Xastir git repository in an "Xastir" subdirectory of the current directory. The Xastir source code will be in `~/src/XASTIR/Xastir` All done! You now have the latest development sources on your computer. Not only that, you have a complete copy of the entire project history and access to all prior releases. ## Bootstrap the source code to create the configure script ## Since Release 2.1.8 the Xastir project has not distributed source code that is ready to build out of the box, even in release tarballs. It must always be "bootstrapped" before proceeding. 1. If you are working from a tarball of source code and followed the path suggestions above: ``` cd ~/src/XASTIR/Xastir-Release-X.Y.Z ./bootstrap.sh ``` 2. If you grabbed a clone from git and followed the recommendations above: ``` cd ~/src/XASTIR/Xastir ./bootstrap.sh ``` In either case, you should see the following output: ``` > ./bootstrap.sh 5) Removing autom4te.cache directory... 4) Running aclocal... 3) Running autoheader... 2) Running autoconf... 1) Running automake... Bootstrap complete. ``` If you don't see "Bootstrap complete" at the end, it didn't work and the error messages output should guide you to the source of the problem (usually this only fails when you have not installed all the necessary autoconf/automake tools). This bootstrap procedure creates the "configure" script you need in the next step. ## Create a build directory and run configure in it with any necessary options ## In order to build Xastir, the configure script you just created must be run. Configure tries to work out what you've got installed and whether it can find all of the pieces it needs. In many cases on Linux you can get away with running it with no options at all and it'll find everything it needs. In some cases you might need to provide it with hints about where to find things like libraries and headers. And there are a number of configure options that allow you to control whether to skip some features you don't want, even if you've got all the pieces installed that would normally enable them. We strongly recommend doing configuration and building of Xastir in a "build directory" rather than right in the same directory as the source code. The reason for this is that doing so leaves the source code directory completely pristine, and only creates new stuff in the build directory. This makes it much easier to clean up and start over (you can simply delete the build directory), and also makes it easier to spot when something has accidentally been changed in the source tree. The examples below all have the same basic steps: create a new directory and move into it, then run configure in it. The only difference between them is whether you have to give any arguments to configure. ### The simplest example possible ### Create a new directory in which to build, and run configure in it: ``` mkdir ~/MyXastirBuildDirectory cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure ``` Here we're assuming you got Xastir source code from git and ran bootstrap.sh, and bootstrap.sh completed without error. This may be all you need, and if all you have done was install the minimum required libraries you should see configure exit with this message: ``` xastir X.Y.Z has been configured to use the following options and external libraries: MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : no RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : no GraphicsMagick/ImageMagick (Raster maps) .. : no pcre (Shapefile customization) ............ : no Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : no FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no xastir will be installed in /usr/local/bin. Type 'make' to build Xastir (Use 'gmake' instead on some systems). ``` If you've installed optional libraries and they were properly located by configure, then some of these "no" lines will have "yes" instead. ### Slightly more involved examples ### Some systems like to install the headers for "libgeotif" into "/usr/include/geotiff" instead of directly into "/usr/include". If that is the case, configure simply won't find them. In that case, one has to tell configure to tell the C preprocessor to add an additional place to look for header files. So on those systems one would have to do: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/include/geotiff" ``` On most Linux systems, that's the extent of the complexity you might need. ### When lots of stuff is in weird places ### Similarly, on systems like FreeBSD, third-party packages do not install *anything* into "/usr/include" or "/usr/lib" but rather into "/usr/local/lib" or "/usr/local/include". In that case, you'd have to tell the C preprocessor and linker to look in extra places, too: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ``` Note that systems like Macs often require add-on package managers like "homebrew" or "macports" which love to put headers and libraries in strange places where the C compiler and linker don't look by default. The techniques above apply there, too. You can stack up options, too, such as: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure CPPFLAGS="-I/usr/local/include -I/some/weird/place/include" LDFLAGS="-L/usr/local/lib -L/some/weird/place/lib" ``` ### A much more involved example ### On my own system, the Berkeley DB libraries are in a weird place, and GraphicsMagick will not work with the default system C compiler at all. So in my case, I have to run configure as: ``` cd ~/MyXastirBuildDirectory ~/src/XASTIR/Xastir/configure --with-bdb-incdir=/usr/local/include/db5 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++13 LIBS="-ldb-5.3" ``` Here, I'm telling it to look in special places when looking for Berkeley DB headers and libraries, to use a specific (non-default) compiler, to use specific compiler options (CFLAGS), and to use the Berkeley DB library "libdb-5.3" (LIBS) irrespective of any other that might be found on the system. It is critically important when building with Berkeley DB that the headers in the bdb-incdir are for the same version of Berkeley DB as the most recent version present in the library directory. If one has both Berkeley DB 5 and Berkeley DB 18.1 installed, Xastir will use the most recent version present, even if one has told it to use an older set of headers. The example above forces Xastir to use the older library even if a newer one is present, because it is also using the older header files per the setting of "--with-bdb-incdir". Since db5 is now very old and deprecated on FreeBSD, I can instead build Xastir with DB version 18.1, so long as I make sure to point to the right headers: ``` cd ~/MyXastirBuildDirectory ../Xastir/configure --with-bdb-incdir=/usr/local/include/db18 --with-bdb-libdir=/usr/local/lib CFLAGS="-O2 -g" CC=gcc13 CXX=g++13 ``` Here, all I've had to do is specify where the headers are. Since db18.1 is the most recent version installed configure will find and use it by default, so I don't need to specify LIBS in this case. ## Build Xastir ## Once configure has completed, has announced that it has really succeeded and that you can "make" the code, and all the options it shows as enabled are in fact the options you wanted enabled, then just build it (I'm assuming you're still in your build directory): ``` make ``` You should see a bunch of status updates about what it's doing and what file is being compiled, and when it's all done you should see no statement from "make" that it has aborted due to errors (you may see a handful of warnings, but you can safely ignore those). Once it's all done you can make a quick test to make sure a valid executable was created by typing: ``` ./src/xastir -V ``` which should respond with a version number, such as: ``` Xastir V2.1.9 (Release-2.1.8-47-g00ce2b88) ``` This particular version number indicates that we're building from a git clone, that it's Version 2.1.9, and that 47 code commits have happened since the prior release 2.1.8, and that the current git commit reference is 00ce2b88. You can ignore all that if you don't know what it means. The important thing that it produced a version number and not an error message. That's it, you've built Xastir with the options that configure said you enabled. ## Install the code ## You've built Xastir, but it still lives in your home directory somewhere. If you want it to be generally accessible on your system, you need to install it. You must be root to do this. ``` cd ~/MyXastirBuildDirectory sudo make install ``` Xastir will by default have installed itself into /usr/local/bin by this process (and its support files will generally have been installed into /usr/local/share/xastir). If you're running on a Linux system and have enabled AX.25 networking, you also need to do the following command to give the binary access to kernel AX.25 ports: ``` sudo chmod 4755 /usr/local/bin/xastir ``` ## Start using Xastir Xastir can now be run simply by typing its name at the command line. The default map (the only one you can view with the bare minimum install) is ugly and ancient, but if you enabled GraphicsMagick and curl then there are many online map options available immediately in the map chooser. I recommend `Online/OSM_tiled_mapnik.geo`. You will now have to get Xastir configured and connected to your TNC or an internet APRS server. * [Starting Xastir](#starting-xastir) * [Changing the language](#changing-the-language) * [Configuring Xastir](#configuring-xastir) * [Various ways to manipulate Xastir](#various-ways-to-manipulate-xastir) ### Starting Xastir: NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Assuming you want to start Xastir up in the English language, you can type (from an xterm window): xastir which will start up the program without giving you back a command-prompt in your xterm window (until Xastir exits), or you can type (from an xterm window): xastir & which will start Xastir in the background, giving you back your xterm for more commands. The typical way to start it is with "xastir &". Of course you can get fancier and attach it to your window manager's menus or create an icon on your desktop which starts it. Those are operating system/window manager-specific, so we won't cover how to do that here. The first time you start Xastir it will show a default map of the world plus pop up the File->Configure->Station dialog. Enter a callsign on that dialog and press the OK button. ### Changing the Language: If you want to start Xastir using some other language, you do that with command-line switches when you start Xastir. Once you use one of these switches, that language option becomes "sticky", meaning you won't have to enter that command-line switch again unless you wish to change languages. If you type "xastir -?", which is an invalid command-line option, you'll see this: ``` xastir: invalid option -- h Xastir Command line Options -c /path/dir Xastir config dir -f callsign Track callsign -i Install private Colormap -geometry WxH+X+Y Set Window Geometry -l Dutch Set the language to Dutch -l English Set the language to English -l French Set the language to French -l German Set the language to German -l Italian Set the language to Italian -l Portuguese Set the language to Portuguese -l Spanish Set the language to Spanish -l ElmerFudd Set the language to ElmerFudd -l MuppetsChef Set the language to MuppetsChef -l OldeEnglish Set the language to OldeEnglish -l PigLatin Set the language to PigLatin -l PirateEnglish Set the language to PirateEnglish -m Deselect Maps -p Disable popups -t Internal SIGSEGV handler enabled -v level Set the debug level -V Print version number and exit ``` Ignore those for now unless you need to change the Language. OK, Xastir should show up on your screen at this point. We're assuming that you're already running the X Window System environment at this point. If you're in command-line Linux/Unix only, Xastir won't run. If you've configured in ShapeLib capability, you'll need to run /usr/local/share/xastir/scripts/get-NWSdata as the root user in order to get the NOAA data files you'll need for the weather alerts. The script requires "wget" in order to work. Run this script periodically (once every six months perhaps?) to keep your weather alert maps up-to-date. If you're not in the U.S. or one of it's possessions then you can safely ignore this download. ### Configuring Xastir: * Note that the menus have a dashed line near the top. If you click on that dashed line it acts like a cut-line for the menu and detaches that menu from the main menu. You can then move that menu off to another area of your screen. You might try that with the File->Configure menu at this time. * Go to File->Configure->Station and set your callsign. Set up other parameters/comment fields on this dialog that may need setting. * Go to File->Configure->Defaults and set parameters there. You have the main parameters set now. Next is to enable some interfaces so that you can see some packets come across. Easiest might be the Internet interfaces, assuming the computer you're on has Internet access and is hooked up to it currently. * Run "callpass" in another Xterm window in order to generate your Pass-code number. Save that number as you'll need it for each Interface dialog where you might need to authenticate your callsign. Of course you can always run callpass again if you forget it! * Go to Interface->Properties then click on "Add". Click "Internet Server". Another dialog will come up that allows you to enter the Host, and the Port. Enter your Pass-code number here. People often check the "Activate on Startup?" and the "Reconnect on NET failure?" options on this box. You may also assign a comment to this interface which describes the interface better for you. Click "OK" to create the interface. If you checked "Activate on Startup?" then the interface will start as well and you'll be receiving packets. Browse "http://www.aprs2.net/" to find a reasonable set of servers to start with. Another possibility is to use "rotate.aprs2.net" port 14580, which theoretically should rotate among the available second-tier servers. See "http://www.aprs2.net" for more info. You'll need to put in a filter string, such as "r/35/-106/500" which shows you stations that are within 500km of 35dN/106dW (Thanks for that one Tom!). For additional filter settings check out: http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm * Start that interface from the Interface->Start/Stop dialog if it's not started already. You'll see icons in the lower right toggling and see callsigns in the lower left status box if packets are coming in. One thing about configuration: Most things don't get written to Xastir's config file until you choose either "File->Configure->Save Config Now!" or you exit Xastir. Map Selections however are immediate. * Creating/starting interfaces for other types of devices is similar. If you're wanting to create AX.25 kernel networking ports you'll have to refer to the HAM HOWTO documents and perhaps the linux-hams mailing list for help. For AGWPE connections refer to that AGWPE docs and mailing list. It's recommended that if you run a local TNC, you run it in KISS mode. You can do that via the Serial KISS TNC interface, or via AX.25 Kernel Networking ports. Some of the more esoteric types of interfaces may require some questions on the Xastir list. Don't be afraid to ask them as we've all been there before. ## Miscellaneous notes These notes don't really belong in the installation instructions, and will be removed shortly. They are properly part of Xastir operation, not installation, and will be documented in the [Operating](https://github.com/Xastir/Xastir/wiki/Operating) page on the Xastir Github wiki. ### Various ways to manipulate Xastir #### Context-Dependent Operations: The top row of this table refers to the mode of operation. The "Cursor" row describes what the cursor looks like when in that mode. Each following row describes what the operation on the left hand column performs. | | Normal | Draw-Cad | Measure | Move | |:-:|:-:|:-:|:-:|:-:| | Cursor| Arrow | Pencil | Crosshairs | Crosshairs | | LeftClick | | | | SelectObject | | LeftDrag | ZoomToArea | ZoomToArea | MeasureArea | MoveObject | | MiddleClick | ZoomOut | SetCADPoint | ZoomOut | ZoomOut | Alt-F, Alt-V, etc to bring up main menus via the keyboard. Use arrow keys to navigate menus and/or single letters corresponding to the "hot" letter (underlined letter) for each menu item. "ESC" to back out of the menu system. #### Global Operations: | Action | Function | |:--|:--| |LeftClick| Select Menu or GUI Item (when in menus or dialogs)| |LeftDblClick| FetchAlertText (when in View->Wx Alerts dialog)| |RightClick | OptionsMenu| |Home| Center the map on your home station| |PageUp| ZoomOut| |PageDown| ZoomIn| |ArrowUp| PanUp| |ArrowDown| PanDown| |ArrowLeft| PanLeft| |ArrowRight| PanRight| |"="| GridSize++| |"+"| GridSize++| |"Num+"| GridSize++| |"-"| GridSize--| |"Num-"| GridSize--| |"Space"| Activate current widget| |"Tab"| Rotate among widgets| |"Back-Tab"| Rotate among widgets backwards| #### Other Possible External Stimuli: If you send Xastir a signal (using "kill"), you can force it to perform some action based on which signal you send. * Send a SIGUSR1 to cause a snapshot to be taken. * Send a SIGHUP to cause Xastir to save/quit/restart. * Send a SIGINT, SIGQUIT, or SIGTERM to cause Xastir to quit. * Connect to TCP port 2023 if Server Port is enabled to send/receive packets. * Send to UDP port 2023 via the `xastir_udp_client` program to inject packets. ### A Note About the Map Directory: The map directory (/usr/local/share/xastir/maps/) is free-form, meaning you can have links in there, subdirectories, etc. Organize it in any way that makes sense to you. From within the Map Chooser you can select a directory name, which will select every map underneath that directory, so keep that in mind while organizing your maps. ### Enabling Weather Alerts: You must have Shapelib compiled into Xastir, which also requires the PCRE2 library and its development headers to be installed. Install NOAA shapefile maps as specified in [the Weather Alerts page](https://github.com/Xastir/Xastir/wiki/Weather-Alerts) on the Github wiki. These files must be installed into the /usr/local/share/xastir/Counties/ directory. You may use this script to download/install them for you: "/usr/local/share/xastir/scripts/get-NWSdata" which must be run as the root user, and requires "wget" to work. A neat trick: You can copy some of these maps into the /usr/local/share/xastir/maps directory somewhere (a new subdirectory under there is always fine), then you can select some of these maps as regular Xastir maps as well. ### Enabling FCC/RAC Callsign Lookup: Run the /usr/local/share/xastir/scripts/get-fcc-rac.pl script as root, which will download and install the proper databases into the /usr/local/share/xastir/fcc/ directory. At that point the callsign lookup features in the Station Info dialog and in the "Station->Find Station" menu option should be functional. ### Enabling Audio Alarms: Download and install sample audio files from Xastir's GitHub download site: git clone http://github.com/Xastir/xastir-sounds Copy the files to your Xastir sounds directory, for instance `/usr/local/share/xastir/sounds/` Install a command-line audio player. Call out the path/name of that player in the File->Configure->Audio Alarms dialog. Common ones are vplay and auplay, but there are many others. Enable the types of alarms you desire in that same dialog. You should be able to test it manually from a shell by typing the command in something like this: vplay filename Once you find a command that works, type it into Xastir's Audio Alarms dialog exactly the same except omit the filename. ### Enabling Synthesized Speech: This is currently available only on Linux/FreeBSD. * Install the Festival Speech Synthesizer. Configure/compile support for it into Xastir. Start up the Festival server before starting Xastir using `festival --server &`. Xastir should start up and connect to the server. Use the options in File->Configure->Speech to decide which things you'd like Xastir to speak to you about. Note that the Proximity Alert option in the File->Configure->Speech dialog uses the distances set in the File->Configure->Audio Alarms dialog. ### Enabling GPS Waypoint/Track/Route Download Support: Install GPSMan and gpsmanshp. Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. You'll see download options for each type on the Interface menu. Note that Xastir requires a version of gpsman at least as recent as 6.1. Older versions of gpsman may not work. ### Transmit Enable/Disable Options: Each interface has a separate transmit enable. The Interface menu also has a few global transmit enables. All of these must be enabled for a particular interface to transmit. Also, for Internet servers, you typically need to authenticate with the server using your callsign/pass-code before you're allowed to inject packets into the Internet stream which may get gated out to RF. If you just want to talk to other Internet users, you don't need a pass-code to authenticate to the servers. ### Igating Options: There are igating options on each local TNC interface. There are other global igating options on the File->Configure->Defaults dialog. The global option sets restrictions on all igating. ### Where stuff is kept: Per-user configurations are kept in each user's ~/.xastir directory, by default. In particular the ~/.xastir/config/xastir.cnf file is where most of the configs are kept. This directory can be optionally specified using the -c /path/dir command line option. Make sure you specify a directory, not a file! Xastir will create the directory and several subdirectories if they do not exist when you start up. A few executables are installed in /usr/local/bin/. Scripts are installed in /usr/local/share/xastir/scripts. Maps are installed in /usr/local/share/xastir/maps/. Lots of other directories are under /usr/local/share/xastir/. Xastir-Release-2.2.4/LICENSE0000664000175000017500000026034515151324131014340 0ustar hibbyhibby----------- Xastir Source ----------- *) The majority of the Xastir source code is under the GPLv2 license. This applies also to all supporting files, images, and configure files distributed in the Xastir source repository. See the file named "COPYING" for details about the GPLv2. There are a few exceptions, noted here: *) src/datum.h and src/datum.c were derived from public domain source code. The name and copyright are listed in that file. *) src/rotated.h and src/rotated.c are available under a permissive license to "use, copy, modify, and distribute ... for any purpose and without fee" provided a copyright notice and acknowledgement appears in all copies. The license text, copyright notice, and required acknowledgement are: /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ *) src/festival.h and src/festival.c are available under a license that permits unrestricted use and distribution, so long as the copyright notice is included and attributions maintained. The required list of enumerated Xastir modifications is in src/festival.c That license, the required copyright notice, and attribution are: /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS 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. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ ------------------------------- Xastir scripts ------------------------------- *) Except where explicitly noted in comments, the scripts in the scripts directory are all licensed under the GPLv2. Any script without explicit license information in its comments should be presumed to be GPLv2. Some of the programs in the scripts directory are provided under other open source licenses, and the licensing information will be present in script comments, which should be consulted for details: inf2geo.pl, mapfgd.pl, overlay.pl, ozi2geo.pl, permutations.pl, ridge_radar.pl --- These are stated to be "Released into the Public Domain" by their respective authors. ------------------------------- Third party library licenses ------------------------------- Xastir may be built optionally with a number of third party libraries. The licenses to these third party libraries are only relevant when distributing a binary that has been built to include those libraries. The remainder of this document consists of the license terms of these various third party libraries. *) libcurl ( is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2006, Daniel Stenberg, . All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. ------------------------------- ------------------------------- *) libdb () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: The following is the license that applies to this copy of the Berkeley DB software. For a license to use the Berkeley DB software under conditions other than those described here, or to purchase support for this software, please contact Sleepycat Software by email at info@sleepycat.com, or on the Web at http://www.sleepycat.com. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= /* * Copyright (c) 1990-2005 * Sleepycat Software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Redistributions in any form must be accompanied by information on * how to obtain complete source code for the DB software and any * accompanying software that uses the DB software. The source code * must either be included in the distribution or be available for no * more than the cost of distribution plus a nominal fee, and must be * freely redistributable under reasonable conditions. For an * executable file, complete source code means the source code for all * modules it contains. It does not include source code for modules or * files that typically accompany the major components of the operating * system on which the executable file runs. * * THIS SOFTWARE IS PROVIDED BY SLEEPYCAT SOFTWARE ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SLEEPYCAT SOFTWARE * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1990, 1993, 1994, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1995, 1996 * The President and Fellows of Harvard University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ ------------------------------- ------------------------------- *) GraphicsMagick () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: This file is part of the GraphicsMagick software distributed by the GraphicsMagick Group. [ Please note that the legal community considers 15 or more total lines of code or text (not necessarily contiguous) to be significant for the purposes of copyright. Repeated changes such as renaming a symbol has similar significance to changing one line of code. ] The licences which components of this software fall under are as follows. 1) In November 2002, the GraphicsMagick Group created GraphicsMagick from ImageMagick Studio's ImageMagick and applied this license: Copyright (C) 2002 GraphicsMagick Group, an organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("GraphicsMagick"), to deal in GraphicsMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of GraphicsMagick, and to permit persons to whom GraphicsMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of GraphicsMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall GraphicsMagick Group be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with GraphicsMagick or the use or other dealings in GraphicsMagick. Except as contained in this notice, the name of the GraphicsMagick Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in GraphicsMagick without prior written authorization from the GraphicsMagick Group. 2) In August 1999, ImageMagick Studio assumed the responsibility for the development of ImageMagick and applied a new license: Copyright (C) 2002 ImageMagick Studio, a non-profit organization dedicated to making software imaging solutions freely available. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall ImageMagick Studio be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the ImageMagick Studio shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the ImageMagick Studio. 3) From 1991 to August 1999, ImageMagick was developed and distributed by E. I. du Pont de Nemours and Company: Copyright 1999 E. I. du Pont de Nemours and Company Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files ("ImageMagick"), to deal in ImageMagick without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ImageMagick, and to permit persons to whom the ImageMagick is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of ImageMagick. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall E. I. du Pont de Nemours and Company be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with ImageMagick or the use or other dealings in ImageMagick. Except as contained in this notice, the name of the E. I. du Pont de Nemours and Company shall not be used in advertising or otherwise to promote the sale, use or other dealings in ImageMagick without prior written authorization from the E. I. du Pont de Nemours and Company. 4) This copyright is limited to some code (for locating an installed Ghostscript under Windows) in the file magick/nt_base.c which was incorporated from the gsview package: Copyright (C) 2000-2002, Ghostgum Software Pty Ltd. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this file ("Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of this Software, and to permit persons to whom this file is furnished to do so, subject to the following conditions: This Software is distributed with NO WARRANTY OF ANY KIND. No author or distributor accepts any responsibility for the consequences of using it, or for whether it serves any particular purpose or works at all, unless he or she says so in writing. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 5) The GraphicsMagick Base64Decode() and Base64Encode() functions are based on source code obtained from OpenSSH. This source code is distributed under the following license. Copyright (c) 2000 Markus Friedl. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 6) Many of the pattern images in coders/logo.c are derived from XFig, which is distributed under the following license: FIG : Facility for Interactive Generation of figures Copyright (c) 1985-1988 by Supoj Sutanthavibul Parts Copyright (c) 1989-2000 by Brian V. Smith Parts Copyright (c) 1991 by Paul King Any party obtaining a copy of these files is granted, free of charge, a full and unrestricted irrevocable, world-wide, paid up, royalty-free, nonexclusive right and license to deal in this software and documentation files (the "Software"), including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons who receive copies from any such party to do so, with the only requirement being that this copyright notice remain intact. 7) The documentation for the composition operators is copied from the rlecomp manual page, which is authored by Rod Bogart and John W. Peterson. Rlecomp is part of the Utah Raster Toolkit distributed by the University of Michigan and the University of Utah. The copyright for this manual page is as follows: Copyright (c) 1986, University of Utah This software is copyrighted as noted below. It may be freely copied, modified, and redistributed, provided that the copyright notice is preserved on all copies. There is no warranty or other guarantee of fitness for this software, it is provided solely "as is". Bug reports or fixes may be sent to the author, who may or may not act on them as he desires. You may not include this software in a program or other software product without supplying the source, or without informing the end-user that the source is available for no extra charge. If you modify this software, you should include a notice giving the name of the person performing the modification, the date of modification, and the reason for such modification. 8) The C++ API known as "Magick++", and which resides in the Magick++ directory, is distributed under the following license: Copyright 1999 - 2003 Bob Friesenhahn Permission is hereby granted, free of charge, to any person obtaining a copy of the source files and associated documentation files ("Magick++"), to deal in Magick++ without restriction, including without limitation of the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of Magick++, and to permit persons to whom the Magick++ is furnished to do so, subject to the following conditions: This copyright notice shall be included in all copies or substantial portions of Magick++. The copyright to Magick++ is retained by its author and shall not be subsumed or replaced by any other copyright. The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall Bob Friesenhahn be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with Magick++ or the use or other dealings in Magick++. 9) GraphicsMagick makes use of third-party "delegate" libraries to support certain optional features. These libraries bear their own copyrights and licenses, which may be more or less restrictive than the GraphicsMagick license. For convenience, when GraphicsMagick is bundled with (or compiled with) "delegate" libraries, a copy of the licenses for these libraries is provided in a "licenses" directory. ------------------------------- ------------------------------- *) Jasper () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: JasPer License Version 2.0 Copyright (c) 1999-2000 Image Power, Inc. Copyright (c) 1999-2000 The University of British Columbia Copyright (c) 2001-2003 Michael David Adams All rights reserved. Permission is hereby granted, free of charge, to any person (the "User") obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. The above copyright notices and this permission notice (which includes the disclaimer below) shall be included in all copies or substantial portions of the Software. 2. The name of a copyright holder shall not be used to endorse or promote products derived from the Software without specific prior written permission. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. ------------------------------- ------------------------------- *) Jpeg () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: In plain English: 1. We don't promise that this software works. (But if you find any bugs, please let us know!) 2. You can use this software for whatever you want. You don't have to pay us. 3. You may not pretend that you wrote this software. If you use it in a program, you must acknowledge somewhere in your documentation that you've used the IJG code. In legalese: The authors make NO WARRANTY or representation, either express or implied, with respect to this software, its quality, accuracy, merchantability, or fitness for a particular purpose. This software is provided "AS IS", and you, its user, assume the entire risk as to its quality and accuracy. This software is copyright (C) 1991-1998, Thomas G. Lane. All Rights Reserved except as specified below. Permission is hereby granted to use, copy, modify, and distribute this software (or portions thereof) for any purpose, without fee, subject to these conditions: (1) If any part of the source code for this software is distributed, then this README file must be included, with this copyright and no-warranty notice unaltered; and any additions, deletions, or changes to the original files must be clearly indicated in accompanying documentation. (2) If only executable code is distributed, then the accompanying documentation must state that "this software is based in part on the work of the Independent JPEG Group". (3) Permission for use of this software is granted only if the user accepts full responsibility for any undesirable consequences; the authors accept NO LIABILITY for damages of any kind. These conditions apply to any software derived from or based on the IJG code, not just to the unmodified library. If you use our work, you ought to acknowledge us. Permission is NOT granted for the use of any IJG author's name or company name in advertising or publicity relating to this software or products derived from it. This software may be referred to only as "the Independent JPEG Group's software". We specifically permit and encourage the use of this software as the basis of commercial products, provided that all warranty or liability claims are assumed by the product vendor. ansi2knr.c is included in this distribution by permission of L. Peter Deutsch, sole proprietor of its copyright holder, Aladdin Enterprises of Menlo Park, CA. ansi2knr.c is NOT covered by the above copyright and conditions, but instead by the usual distribution terms of the Free Software Foundation; principally, that you must include source code if you redistribute it. (See the file ansi2knr.c for full details.) However, since ansi2knr.c is not needed as part of any program generated from the IJG code, this does not limit you more than the foregoing paragraphs do. The Unix configuration script "configure" was produced with GNU Autoconf. It is copyright by the Free Software Foundation but is freely distributable. The same holds for its supporting scripts (config.guess, config.sub, ltconfig, ltmain.sh). Another support script, install-sh, is copyright by M.I.T. but is also freely distributable. It appears that the arithmetic coding option of the JPEG spec is covered by patents owned by IBM, AT&T, and Mitsubishi. Hence arithmetic coding cannot legally be used without obtaining one or more licenses. For this reason, support for arithmetic coding has been removed from the free JPEG software. (Since arithmetic coding provides only a marginal gain over the unpatented Huffman mode, it is unlikely that very many implementations will support it.) So far as we are aware, there are no patent restrictions on the remaining code. The IJG distribution formerly included code to read and write GIF files. To avoid entanglement with the Unisys LZW patent, GIF reading support has been removed altogether, and the GIF writer has been simplified to produce "uncompressed GIFs". This technique does not use the LZW algorithm; the resulting GIF files are larger than usual, but are readable by all standard GIF decoders. We are required to state that "The Graphics Interchange Format(c) is the Copyright property of CompuServe Incorporated. GIF(sm) is a Service Mark property of CompuServe Incorporated." ------------------------------- ------------------------------- *) Lesstif () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: The included files COPYING and COPYING.LIB.LESSTIF, as may apply. ------------------------------- ------------------------------- *) libpng () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: This copy of the libpng notices is provided for your convenience. In case of any discrepancy between this copy and the notices in the file png.h that is included in the libpng distribution, the latter shall prevail. COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: If you modify libpng you may insert additional notices immediately following this sentence. libpng versions 1.2.6, August 15, 2004, through 1.2.14, November 28, 2006, are Copyright (c) 2004, 2006 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.2.5 with the following individual added to the list of Contributing Authors Cosmin Truta libpng versions 1.0.7, July 1, 2000, through 1.2.5 - October 3, 2002, are Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-1.0.6 with the following individuals added to the list of Contributing Authors Simon-Pierre Cadieux Eric S. Raymond Gilles Vollant and with the following additions to the disclaimer: There is no warranty against interference with your enjoyment of the library or against infringement. There is no warranty that our efforts or the library will fulfill any of your particular purposes or needs. This library is provided with all faults, and the entire risk of satisfactory quality, performance, accuracy, and effort is with the user. libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are Copyright (c) 1998, 1999 Glenn Randers-Pehrson, and are distributed according to the same disclaimer and license as libpng-0.96, with the following individuals added to the list of Contributing Authors: Tom Lane Glenn Randers-Pehrson Willem van Schaik libpng versions 0.89, June 1996, through 0.96, May 1997, are Copyright (c) 1996, 1997 Andreas Dilger Distributed according to the same disclaimer and license as libpng-0.88, with the following individuals added to the list of Contributing Authors: John Bowler Kevin Bracey Sam Bushell Magnus Holmgren Greg Roelofs Tom Tanner libpng versions 0.5, May 1995, through 0.88, January 1996, are Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc. For the purposes of this copyright and license, "Contributing Authors" is defined as the following set of individuals: Andreas Dilger Dave Martindale Guy Eric Schalnat Paul Schmidt Tim Wegner The PNG Reference Library is supplied "AS IS". The Contributing Authors and Group 42, Inc. disclaim all warranties, expressed or implied, including, without limitation, the warranties of merchantability and of fitness for any purpose. The Contributing Authors and Group 42, Inc. assume no liability for direct, indirect, incidental, special, exemplary, or consequential damages, which may result from the use of the PNG Reference Library, even if advised of the possibility of such damage. Permission is hereby granted to use, copy, modify, and distribute this source code, or portions hereof, for any purpose, without fee, subject to the following restrictions: 1. The origin of this source code must not be misrepresented. 2. Altered versions must be plainly marked as such and must not be misrepresented as being the original source. 3. This Copyright notice may not be removed or altered from any source or altered source distribution. The Contributing Authors and Group 42, Inc. specifically permit, without fee, and encourage the use of this source code as a component to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. A "png_get_copyright" function is available, for convenient use in "about" boxes and the like: printf("%s",png_get_copyright(NULL)); Also, the PNG logo (in PNG format, of course) is supplied in the files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). Libpng is OSI Certified Open Source Software. OSI Certified Open Source is a certification mark of the Open Source Initiative. Glenn Randers-Pehrson glennrp at users.sourceforge.net November 28, 2006 ------------------------------- ------------------------------- *) PCRE () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: PCRE is a library of functions to support regular expressions whose syntax and semantics are as close as possible to those of the Perl 5 language. Release 6 of PCRE is distributed under the terms of the "BSD" licence, as specified below. The documentation for PCRE, supplied in the "doc" directory, is distributed under the same terms as the software itself. The basic library functions are written in C and are freestanding. Also included in the distribution is a set of C++ wrapper functions. THE BASIC LIBRARY FUNCTIONS --------------------------- Written by: Philip Hazel Email local part: ph10 Email domain: cam.ac.uk University of Cambridge Computing Service, Cambridge, England. Phone: +44 1223 334714. Copyright (c) 1997-2006 University of Cambridge All rights reserved. THE C++ WRAPPER FUNCTIONS ------------------------- Contributed by: Google Inc. Copyright (c) 2006, Google Inc. All rights reserved. THE "BSD" LICENCE ----------------- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the University of Cambridge nor the name * of Google Inc. nor the names of their contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------- ------------------------------- *) ZLIB () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: (C) 1995-2004 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. ------------------------------- ------------------------------- *) libXt.a () is available under the following license. Note that this license is only applicable to a distributed Xastir BINARY which includes this library: Licenses The XFree86 Project January 2002 1. XFree86 License XFree86 code without an explicit copyright is covered by the following copy- right/license: Copyright (C) 1994-2002 The XFree86 Project, Inc. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is fur- nished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CON- NECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the XFree86 Project shall not be used in advertising or otherwise to promote the sale, use or other deal- ings in this Software without prior written authorization from the XFree86 Project. 2. Other Licenses Portions of code are covered by the following licenses/copyrights. See indi- vidual files for the copyright dates. 2.1 X/MIT Copyrights 2.1.1 X Consortium Copyright (C) X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is fur- nished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. X Window System is a trademark of X Consortium, Inc. 2.1.2 The Open Group Copyright The Open Group Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of The Open Group shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from The Open Group. 2.2 Berkeley-based copyrights: 2.2.1 General Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH- ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2.2.2 UCB/LBL Copyright (c) 1993 The Regents of the University of California. All rights reserved. This software was developed by the Computer Systems Engineering group at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and contributed to Berkeley. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software devel- oped by the University of California, Lawrence Berkeley Laboratory. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes soft- ware developed by the University of California, Berkeley and its con- tributors. 4. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS- CLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2.3 NVIDIA Corp Copyright (c) 1996 NVIDIA, Corp. All rights reserved. NOTICE TO USER: The source code is copyrighted under U.S. and international laws. NVIDIA, Corp. of Sunnyvale, California owns the copyright and as design patents pending on the design and interface of the NV chips. Users and possessors of this source code are hereby granted a nonexclusive, roy- alty-free copyright and design patent license to use this code in individual and commercial software. Any use of this source code must include, in the user documentation and internal comments to the code, notices to the end user as follows: Copyright (c) 1996 NVIDIA, Corp. NVIDIA design patents pending in the U.S. and foreign countries. NVIDIA, CORP. MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WAR- RANTY OF ANY KIND. NVIDIA, CORP. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA, CORP. BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY DAM- AGES 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 SOURCE CODE. 2.4 GLX Public License GLX PUBLIC LICENSE (Version 1.0 (2/11/99)) ("License") Subject to any third party claims, Silicon Graphics, Inc. ("SGI") hereby grants permission to Recipient (defined below), under Recipient's copyrights in the Original Software (defined below), to use, copy, modify, merge, pub- lish, distribute, sublicense and/or sell copies of Subject Software (defined below), and to permit persons to whom the Subject Software is furnished in accordance with this License to do the same, subject to all of the following terms and conditions, which Recipient accepts by engaging in any such use, copying, modifying, merging, publishing, distributing, sublicensing or sell- ing: 1. Definitions. (a) "Original Software" means source code of computer software code which is described in Exhibit A as Original Software. (b) "Modifications" means any addition to or deletion from the sub- stance or structure of either the Original Software or any previous Modifications. When Subject Software is released as a series of files, a Modification means (i) any addition to or deletion from the contents of a file containing Original Software or previous Modifications and (ii) any new file that contains any part of the Original Code or previous Modifications. (c) "Subject Software" means the Original Software or Modifications or the combination of the Original Software and Modifications, or portions of any of the foregoing. (d) "Recipient" means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "Recipient" includes any entity which controls, is controlled by, or is under common control with Recipient. For purposes of this definition, "control" of an entity means (a) the power, direct or indirect, to direct or manage such entity, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 2. Redistribution of Source Code Subject to These Terms. Redistributions of Subject Software in source code form must retain the notice set forth in Exhibit A, below, in every file. A copy of this License must be included in any documentation for such Subject Software where the recipients' rights relating to Subject Software are described. Recipient may distribute the source code version of Subject Software under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, and (ii) the license terms include this Section 2 and Sections 3, 4, 7, 8, 10, 12 and 13 of this License, which terms may not be modified or superseded by any other terms of such license. If Recipient distributes the source code version under a different license Recipient must make it absolutely clear that any terms which differ from this License are offered by Recipient alone, not by SGI. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such terms Recipient offers. 3. Redistribution in Executable Form. The notice set forth in Exhibit A must be conspicuously included in any notice in an executable version of Subject Software, related documentation or collateral in which Recipient describes the user's rights relating to the Subject Software. Recipient may distribute the executable version of Subject Software under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, and (ii) the license terms include this Section 3 and Sections 4, 7, 8, 10, 12 and 13 of this License, which terms may not be modified or superseded by any other terms of such license. If Recipient distributes the executable version under a different license Recipient must make it absolutely clear that any terms which differ from this License are offered by Recipient alone, not by SGI. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such terms Recipient offers. 4. Termination. This License and the rights granted hereunder will terminate automatically if Recipient fails to comply with terms herein and fails to cure such breach within 30 days of the breach. Any sublicense to the Subject Software which is properly granted shall survive any termination of this License absent termination by the terms of such sublicense. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 5. No Trademark Rights. This License does not grant any rights to use any trade name, trademark or service mark whatsoever. No trade name, trademark or service mark of SGI may be used to endorse or promote products derived from the Subject Software without prior written permission of SGI. 6. No Other Rights. This License does not grant any rights with respect to the OpenGL API or to any software or hardware implementation thereof or to any other software whatsoever, nor shall any other rights or licenses not expressly granted hereunder arise by implication, estoppel or otherwise with respect to the Subject Software. Title to and ownership of the Original Soft- ware at all times remains with SGI. All rights in the Original Software not expressly granted under this License are reserved. 7. Compliance with Laws; Non-Infringement. Recipient shall comply with all applicable laws and regulations in connection with use and distribution of the Subject Software, including but not limited to, all export and import control laws and regulations of the U.S. government and other countries. Recipient may not distribute Subject Software that (i) in any way infringes (directly or contributorily) the rights (including patent, copyright, trade secret, trademark or other intellectual property rights of any kind) of any other person or entity or (ii) breaches any representation or warranty, express, implied or statutory, which under any applicable law it might be deemed to have been distributed. 8. Claims of Infringement. If Recipient at any time has knowledge of any one or more third party claims that reproduction, modification, use, distribu- tion, import or sale of Subject Software (including particular functionality or code incorporated in Subject Software) infringes the third party's intel- lectual property rights, Recipient must place in a well-identified web page bearing the title "LEGAL" a description of each such claim and a description of the party making each such claim in sufficient detail that a user of the Subject Software will know whom to contact regarding the claim. Also, upon gaining such knowledge of any such claim, Recipient must conspicuously include the URL for such web page in the Exhibit A notice required under Sec- tions 2 and 3, above, and in the text of any related documentation, license agreement or collateral in which Recipient describes end user's rights relat- ing to the Subject Software. If Recipient obtains such knowledge after it makes Subject Software available to any other person or entity, Recipient shall take other steps (such as notifying appropriate mailing lists or news- groups) reasonably calculated to inform those who received the Subject Soft- ware that new knowledge has been obtained. 9. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS, MER- CHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON- INFRINGING. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY SER- VICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THE- ORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIA- BILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT. 11. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of Recipient's use, modification, reproduction and distribution of the Subject Software or out of any representation or warranty made by Recipient. 12. U.S. Government End Users. The Subject Software is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 13. Miscellaneous. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unen- forceable, such provision shall be reformed so as to achieve as nearly as possible the same economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any litigation relating to this License shall be subject to the exclusive jurisdiction of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of California), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a con- tract shall be construed against the drafter shall not apply to this License. Exhibit A The contents of this file are subject to Sections 2, 3, 4, 7, 8, 10, 12 and 13 of the GLX Public License Version 1.0 (the "License"). You may not use this file except in compliance with those sections of the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043 or at http://www.sgi.com/software/opensource/glx/license.html. Software distributed under the License is distributed on an "AS IS" basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific language governing rights and limitations under the License. The Original Software is GLX version 1.2 source code, released February, 1999. The developer of the Original Software is Silicon Graphics, Inc. Those portions of the Subject Software created by Silicon Graphics, Inc. are Copy- right (c) 1991-9 Silicon Graphics, Inc. All Rights Reserved. 2.5 CID Font Code Public License CID FONT CODE PUBLIC LICENSE (Version 1.0 (3/31/99))("License") Subject to any applicable third party claims, Silicon Graphics, Inc. ("SGI") hereby grants permission to Recipient (defined below), under SGI's copyrights in the Original Software (defined below), to use, copy, modify, merge, pub- lish, distribute, sublicense and/or sell copies of Subject Software (defined below) in both source code and executable form, and to permit persons to whom the Subject Software is furnished in accordance with this License to do the same, subject to all of the following terms and conditions, which Recipient accepts by engaging in any such use, copying, modifying, merging, publica- tion, distributing, sublicensing or selling: 1. Definitions. a. "Original Software" means source code of computer software code that is described in Exhibit A as Original Software. b. "Modifications" means any addition to or deletion from the sub- stance or structure of either the Original Software or any previous Modifications. When Subject Software is released as a series of files, a Modification means (i) any addition to or deletion from the contents of a file containing Original Software or previous Modifications and (ii) any new file that contains any part of the Original Code or previous Modifications. c. "Subject Software" means the Original Software or Modifications or the combination of the Original Software and Modifications, or portions of any of the foregoing. d. "Recipient" means an individual or a legal entity exercising rights under the terms of this License. For legal entities, "Recip- ient" includes any entity that controls, is controlled by, or is under common control with Recipient. For purposes of this defini- tion, "control" of an entity means (i) the power, direct or indi- rect, to direct or manage such entity, or (ii) ownership of fifty percent (50%) or more of the outstanding shares or beneficial own- ership of such entity. e. "Required Notice" means the notice set forth in Exhibit A to this License. f. "Accompanying Technology" means any software or other technology that is not a Modification and that is distributed or made publicly available by Recipient with the Subject Software. Separate soft- ware files that do not contain any Original Software or any previ- ous Modification shall not be deemed a Modification, even if such software files are aggregated as part of a product, or in any medium of storage, with any file that does contain Original Soft- ware or any previous Modification. 2. License Terms. All distribution of the Subject Software must be made sub- ject to the terms of this License. A copy of this License and the Required Notice must be included in any documentation for Subject Software where Recipient's rights relating to Subject Software and/or any Accompanying Tech- nology are described. Distributions of Subject Software in source code form must also include the Required Notice in every file distributed. In addition, a ReadMe file entitled "Important Legal Notice" must be distributed with each distribution of one or more files that incorporate Subject Software. That file must be included with distributions made in both source code and exe- cutable form. A copy of the License and the Required Notice must be included in that file. Recipient may distribute Accompanying Technology under a license of Recipient's choice, which may contain terms different from this License, provided that (i) Recipient is in compliance with the terms of this License, (ii) such other license terms do not modify or supersede the terms of this License as applicable to the Subject Software, (iii) Recipient hereby indemnifies SGI for any liability incurred by SGI as a result of the distri- bution of Accompanying Technology or the use of other license terms. 3. Termination. This License and the rights granted hereunder will terminate automatically if Recipient fails to comply with terms herein and fails to cure such breach within 30 days of the breach. Any sublicense to the Subject Software that is properly granted shall survive any termination of this License absent termination by the terms of such sublicense. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 4. Trademark Rights. This License does not grant any rights to use any trade name, trademark or service mark whatsoever. No trade name, trademark or ser- vice mark of SGI may be used to endorse or promote products derived from or incorporating any Subject Software without prior written permission of SGI. 5. No Other Rights. No rights or licenses not expressly granted hereunder shall arise by implication, estoppel or otherwise. Title to and ownership of the Original Software at all times remains with SGI. All rights in the Origi- nal Software not expressly granted under this License are reserved. 6. Compliance with Laws; Non-Infringement. Recipient shall comply with all applicable laws and regulations in connection with use and distribution of the Subject Software, including but not limited to, all export and import control laws and regulations of the U.S. government and other countries. Recipient may not distribute Subject Software that (i) in any way infringes (directly or contributorily) the rights (including patent, copyright, trade secret, trademark or other intellectual property rights of any kind) of any other person or entity, or (ii) breaches any representation or warranty, express, implied or statutory, which under any applicable law it might be deemed to have been distributed. 7. Claims of Infringement. If Recipient at any time has knowledge of any one or more third party claims that reproduction, modification, use, distribu- tion, import or sale of Subject Software (including particular functionality or code incorporated in Subject Software) infringes the third party's intel- lectual property rights, Recipient must place in a well-identified web page bearing the title "LEGAL" a description of each such claim and a description of the party making each such claim in sufficient detail that a user of the Subject Software will know whom to contact regarding the claim. Also, upon gaining such knowledge of any such claim, Recipient must conspicuously include the URL for such web page in the Required Notice, and in the text of any related documentation, license agreement or collateral in which Recipient describes end user's rights relating to the Subject Software. If Recipient obtains such knowledge after it makes Subject Software available to any other person or entity, Recipient shall take other steps (such as notifying appro- priate mailing lists or newsgroups) reasonably calculated to provide such knowledge to those who received the Subject Software. 8. DISCLAIMER OF WARRANTY. SUBJECT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE SUBJECT SOFTWARE IS FREE OF DEFECTS, MER- CHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD ANY SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR ANY SER- VICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY SUBJECT SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SUBJECT SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SUBJECT SOFTWARE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF CERTAIN DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT TO THE EXTENT SO DISALLOWED. 10. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold SGI and its successors and assigns harmless from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of (Recipi- ent's use, modification, reproduction and distribution of the Subject Soft- ware or out of any representation or warranty made by Recipient. 11. U.S. Government End Users. The Subject Software is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 12. Miscellaneous. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unen- forceable by any judicial or administrative authority having proper jurisdic- tion with respect thereto, such provision shall be reformed so as to achieve as nearly as possible the same economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any liti- gation relating to this License shall be subject to the exclusive jurisdic- tion of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of Cali- fornia), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation that provides that the language of a contract shall be construed against the drafter shall not apply to this License. Exhibit A Copyright (c) 1994-1999 Silicon Graphics, Inc. The contents of this file are subject to the CID Font Code Public License Version 1.0 (the "License"). You may not use this file except in compliance with the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 2011 N. Shoreline Blvd., Mountain View, CA 94043 or at http://www.sgi.com/software/opensource/cid/license.html Software distributed under the License is distributed on an "AS IS" basis. ALL WARRANTIES ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE OR OF NON- INFRINGEMENT. See the License for the specific language governing rights and limitations under the License. The Original Software (as defined in the License) is CID font code that was developed by Silicon Graphics, Inc. Those portions of the Subject Software (as defined in the License) that were created by Silicon Graphics, Inc. are Copyright (c) 1994-1999 Silicon Graphics, Inc. All Rights Reserved. [NOTE: When using this text in connection with Subject Software delivered solely in object code form, Recipient may replace the words "this file" with "this software" in both the first and second sentences.] ******************************************************************************** XFree86's LICENSE document does not appear to be completely comprehensive. Many files appear to be licensed under the "SGI FREE SOFTWARE LICENSE B (Version 1.1 [02/22/2000])": SGI FREE SOFTWARE LICENSE B (Version 1.1 [02/22/2000]) 1. Definitions. 1.1. "Additional Notice Provisions" means such additional provisions as appear in the Notice in Original Code under the heading "Additional Notice Provisions." 1.2. "Covered Code" means the Original Code or Modifications, or any combination thereof. 1.3. "Hardware" means any physical device that accepts input, processes input, stores the results of processing, and/or provides output. 1.4. "Larger Work" means a work that combines Covered Code or portions thereof with code not governed by the terms of this License. 1.5. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.6. "License" means this document. 1.7. "Licensed Patents" means patent claims Licensable by SGI that are infringed by the use or sale of Original Code or any Modifications provided by SGI, or any combination thereof. 1.8. "Modifications" means any addition to or deletion from the substance or structure of the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to the contents of a file containing Original Code and/or addition to or deletion from the contents of a file containing previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.9. "Notice" means any notice in Original Code or Covered Code, as required by and in compliance with this License. 1.10. "Original Code" means source code of computer software code that is described in the source code Notice required by Exhibit A as Original Code, and updates and error corrections specifically thereto. 1.11. "Recipient" means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 8. For legal entities, "Recipient" includes any entity that controls, is controlled by, or is under common control with Recipient. For purposes of this definition, "control" of an entity means (a) the power, direct or indirect, to direct or manage such entity, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 1.12. "Recipient Patents" means patent claims Licensable by a Recipient that are infringed by the use or sale of Original Code or any Modifications provided by SGI, or any combination thereof. 1.13. "SGI" means Silicon Graphics, Inc. 1.14. "SGI Patents" means patent claims Licensable by SGI other than the Licensed Patents. 2. License Grant and Restrictions. 2.1. SGI License Grant. Subject to the terms of this License and any third party intellectual property claims, for the duration of intellectual property protections inherent in the Original Code, SGI hereby grants Recipient a worldwide, royalty-free, non-exclusive license, to do the following: (i) under copyrights Licensable by SGI, to reproduce, distribute, create derivative works from, and, to the extent applicable, display and perform the Original Code and/or any Modifications provided by SGI alone and/or as part of a Larger Work; and (ii) under any Licensable Patents, to make, have made, use, sell, offer for sale, import and/or otherwise transfer the Original Code and/or any Modifications provided by SGI. Recipient accepts the terms and conditions of this License by undertaking any of the aforementioned actions. The patent license shall apply to the Covered Code if, at the time any related Modification is added, such addition of the Modification causes such combination to be covered by the Licensed Patents. The patent license in Section 2.1(ii) shall not apply to any other combinations that include the Modification. No patent license is provided under SGI Patents for infringements of SGI Patents by Modifications not provided by SGI or combinations of Original Code and Modifications not provided by SGI. 2.2. Recipient License Grant. Subject to the terms of this License and any third party intellectual property claims, Recipient hereby grants SGI and any other Recipients a worldwide, royalty-free, non-exclusive license, under any Recipient Patents, to make, have made, use, sell, offer for sale, import and/or otherwise transfer the Original Code and/or any Modifications provided by SGI. 2.3. No License For Hardware Implementations. The licenses granted in Section 2.1 and 2.2 are not applicable to implementation in Hardware of the algorithms embodied in the Original Code or any Modifications provided by SGI . 3. Redistributions. 3.1. Retention of Notice/Copy of License. The Notice set forth in Exhibit A, below, must be conspicuously retained or included in any and all redistributions of Covered Code. For distributions of the Covered Code in source code form, the Notice must appear in every file that can include a text comments field; in executable form, the Notice and a copy of this License must appear in related documentation or collateral where the Recipient's rights relating to Covered Code are described. Any Additional Notice Provisions which actually appears in the Original Code must also be retained or included in any and all redistributions of Covered Code. 3.2. Alternative License. Provided that Recipient is in compliance with the terms of this License, Recipient may, so long as without derogation of any of SGI's rights in and to the Original Code, distribute the source code and/or executable version(s) of Covered Code under (1) this License; (2) a license identical to this License but for only such changes as are necessary in order to clarify Recipient's role as licensor of Modifications; and/or (3) a license of Recipient's choosing, containing terms different from this License, provided that the license terms include this Section 3 and Sections 4, 6, 7, 10, 12, and 13, which terms may not be modified or superseded by any other terms of such license. If Recipient elects to use any license other than this License, Recipient must make it absolutely clear that any of its terms which differ from this License are offered by Recipient alone, and not by SGI. It is emphasized that this License is a limited license, and, regardless of the license form employed by Recipient in accordance with this Section 3.2, Recipient may relicense only such rights, in Original Code and Modifications by SGI, as it has actually been granted by SGI in this License. 3.3. Indemnity. Recipient hereby agrees to indemnify SGI for any liability incurred by SGI as a result of any such alternative license terms Recipient offers. 4. Termination. This License and the rights granted hereunder will terminate automatically if Recipient breaches any term herein and fails to cure such breach within 30 days thereof. Any sublicense to the Covered Code that is properly granted shall survive any termination of this License, absent termination by the terms of such sublicense. Provisions that, by their nature, must remain in effect beyond the termination of this License, shall survive. 5. No Trademark Or Other Rights. This License does not grant any rights to: (i) any software apart from the Covered Code, nor shall any other rights or licenses not expressly granted hereunder arise by implication, estoppel or otherwise with respect to the Covered Code; (ii) any trade name, trademark or service mark whatsoever, including without limitation any related right for purposes of endorsement or promotion of products derived from the Covered Code, without prior written permission of SGI; or (iii) any title to or ownership of the Original Code, which shall at all times remains with SGI. All rights in the Original Code not expressly granted under this License are reserved. 6. Compliance with Laws; Non-Infringement. There are various worldwide laws, regulations, and executive orders applicable to dispositions of Covered Code, including without limitation export, re-export, and import control laws, regulations, and executive orders, of the U.S. government and other countries, and Recipient is reminded it is obliged to obey such laws, regulations, and executive orders. Recipient may not distribute Covered Code that (i) in any way infringes (directly or contributorily) any intellectual property rights of any kind of any other person or entity or (ii) breaches any representation or warranty, express, implied or statutory, to which, under any applicable law, it might be deemed to have been subject. 7. Claims of Infringement. If Recipient learns of any third party claim that any disposition of Covered Code and/or functionality wholly or partially infringes the third party's intellectual property rights, Recipient will promptly notify SGI of such claim. 8. Versions of the License. SGI may publish revised and/or new versions of the License from time to time, each with a distinguishing version number. Once Covered Code has been published under a particular version of the License, Recipient may, for the duration of the license, continue to use it under the terms of that version, or choose to use such Covered Code under the terms of any subsequent version published by SGI. Subject to the provisions of Sections 3 and 4 of this License, only SGI may modify the terms applicable to Covered Code created under this License. 9. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED "AS IS." ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ARE DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. SGI ASSUMES NO RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, SGI ASSUMES NO COST OR LIABILITY FOR SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY IS AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT SUBJECT TO THIS DISCLAIMER. 10. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES NOR LEGAL THEORY, WHETHER TORT (INCLUDING, WITHOUT LIMITATION, NEGLIGENCE OR STRICT LIABILITY), CONTRACT, OR OTHERWISE, SHALL SGI OR ANY SGI LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, LOSS OF DATA, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SGI's NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO RECIPIENT. 11. Indemnity. Recipient shall be solely responsible for damages arising, directly or indirectly, out of its utilization of rights under this License. Recipient will defend, indemnify and hold harmless Silicon Graphics, Inc. from and against any loss, liability, damages, costs or expenses (including the payment of reasonable attorneys fees) arising out of Recipient's use, modification, reproduction and distribution of the Covered Code or out of any representation or warranty made by Recipient. 12. U.S. Government End Users. The Covered Code is a "commercial item" consisting of "commercial computer software" as such terms are defined in title 48 of the Code of Federal Regulations and all U.S. Government End Users acquire only the rights set forth in this License and are subject to the terms of this License. 13. Miscellaneous. This License represents the complete agreement concerning the its subject matter. If any provision of this License is held to be unenforceable, such provision shall be reformed so as to achieve as nearly as possible the same legal and economic effect as the original provision and the remainder of this License will remain in effect. This License shall be governed by and construed in accordance with the laws of the United States and the State of California as applied to agreements entered into and to be performed entirely within California between California residents. Any litigation relating to this License shall be subject to the exclusive jurisdiction of the Federal Courts of the Northern District of California (or, absent subject matter jurisdiction in such courts, the courts of the State of California), with venue lying exclusively in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation that provides that the language of a contract shall be construed against the drafter shall not apply to this License. Exhibit A License Applicability. Except to the extent portions of this file are made subject to an alternative license as permitted in the SGI Free Software License B, Version 1.1 (the "License"), the contents of this file are subject only to the provisions of the License. You may not use this file except in compliance with the License. You may obtain a copy of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: http://oss.sgi.com/projects/FreeB Note that, as provided in the License, the Software is distributed on an "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. Original Code. The Original Code is: [name of software, version number, and release date], developed by Silicon Graphics, Inc. The Original Code is Copyright (c) [dates of first publication, as appearing in the Notice in the Original Code] Silicon Graphics, Inc. Copyright in any portions created by third parties is as indicated elsewhere herein. All Rights Reserved. Additional Notice Provisions: [such additional provisions, if any, as appear in the Notice in the Original Code under the heading "Additional Notice Provisions"] ------------------------------- ------------------------------- *) GDAL (). Not currently included in any Xastir binaries. This is a placeholder that we may use later. ------------------------------- ------------------------------- *) GV (). Not currently included in any Xastir binaries. This is a placeholder that we may use later. ------------------------------- ------------------------------- To maintain compliance with the above licenses: Hear ye, hear ye! Be it known that the sources for each of the optional libraries listed may be obtained from their normal download sites on the internet. The file you're looking at (LICENSE) is Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/LaCrosse/0000775000175000017500000000000015151324131015034 5ustar hibbyhibbyXastir-Release-2.2.4/LaCrosse/.vimrc0000664000175000017500000000143315151324131016156 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/LaCrosse/AUTHORS0000664000175000017500000000146115151324131016106 0ustar hibbyhibby Developers and Contributions _________________________________________________________________ First, thanks go out to the great folks at the xastir team - a wonderful APRS application set and helpful folks! Thanks also to Andreas Muller, author of meteo and a great resource for information and help. Elements of this software are taken from wx200d ver 1.2 by Tim Witham, and it is modeled after that application. Finally, thanks to the MySQL folks for the key element - the database. N0VH Jim Chandler jim@n0vh.org KB8ROP Bruce Bennett bruts@adelphia.net _________________________________________________________________ Copyright (C) 2003-2004 Bruce Bennett KB8ROP Copyright (C) 2005 Jim Chandler N0VH Xastir-Release-2.2.4/LaCrosse/COPYING0000664000175000017500000004312715151324131016076 0ustar hibbyhibby GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 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. Xastir-Release-2.2.4/LaCrosse/ChangeLog0000664000175000017500000000000115151324131016575 0ustar hibbyhibby Xastir-Release-2.2.4/LaCrosse/INSTALL0000664000175000017500000002203115151324131016063 0ustar hibbyhibby Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc will cause the specified gcc to be used as the C compiler (unless it is overridden in the site shell script). `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. Xastir-Release-2.2.4/LaCrosse/Makefile.am0000664000175000017500000000106215151324131017067 0ustar hibbyhibby # # Copyright (C) 2000-2026 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src #if DAVIS #MyWX = davis #else #MyWX = #endif #noinst_PROGRAMS = $(MyWX) # DISTCLEANFILES = EXTRA_DIST = aclocal.m4 AUTHORS bootstrap.sh ChangeLog config.h.in \ config.status configure.ac COPYING INSTALL NEWS \ README bootstrap.sh MAINTAINERCLEANFILES = configure config.status aclocal.m4 \ Makefile.in Makefile config.guess config.sub install-sh \ missing ChangeLog:: Xastir-Release-2.2.4/LaCrosse/NEWS0000664000175000017500000000000115151324131015522 0ustar hibbyhibby Xastir-Release-2.2.4/LaCrosse/README0000664000175000017500000001612015151324131015714 0ustar hibbyhibby Copyright (C) 2006 Jim Chandler Portions Copyright (C) 2004 Bruce Bennett Portions Copyright (C) 2000-2026 The Xastir Group (Modified for the Xastir project under GPL license) LaCrosse WS-23xx Weather Station support for Xastir - open2300db2APRS OVERVIEW -------- This is a bridge utility between "open2300", a LaCrosse Weather Station data storage & display application by Kenneth Lavrsen (see http://www.lavrsen.dk/twiki/bin/view/Open2300/WebHome) and "Xastir", the APRS package for Linux (see http://www.xastir.org). It allows your LaCrosse WS-23xx weather data to be used by Xastir for local station data. You will need to obtain and install Xastir, mysql and open2300 as outlined in the following sections. After Xastir and open2300 are in working order, this utility can be run as a daemon to provide weather data to Xastir (or any other APRS-format application). "open2300db2APRS" watches for new weather data in the database, retrieves the new data, formats it in APRS "position less" ASCII format and makes it available on a TCP port of your choosing. Xastir is capable of reading this data (see note under Xastir installation). INSTALLATION ------------ Steps in order: 1) Install mysql - initial tested version mysql-3.23.58 although version 4 is released and has some significant improvements - and version 4 *should* work (to be tested yet). If you use an RPM or DPK binary-image version, be sure to add the mysql-devel headers. For the latest image-version, see http://www.mysql.com and follow the links to the downloads. I used mysql-3.23.58-pc-linux-i686.tar.gz from that site. 2) Install open2300 - tested version open2300-1.10 See the instructions for installing & then setting up open2300 that come with the tar ball. Obtain the latest open2300 at http://www.lavrsen.dk/twiki/bin/view/Open2300/WebHome - the setup is rather involved but worth the efort. Some SQL/XML skills can help here, but are not absolutely required... The table setup for the mySQL portion of the open2300 database can be found in the weatherdump.sql file. My database is setup for degree F, inches of Mercury, inches of rain, and windspeed in knots. 3) Install or update your installation for Xastir to the latest version ("http://github.com/Xastir/Xastir" project Xastir) 4) Install open2300db2APRS See instructions below. SETTINGS & STARTUP ------------------ 1) mysql - it is recommended by mysql to set up passwords, but for this usage it doesn't matter. In fact, it's a bit of a pain. TODO - open2300db2APRS has the annoying fault of clearly displaying the password used for the mysql database for anyone to see via 'ps -ef'. Start mysqld before open2300db2APRS, meteo and Xastir in your boot-time initializations. 2) open2300 - my testing used a five minute data accumulation rate. Thirty seconds would more closely match Xastir, but the database growth rate would be twelve as fast (about 600 Mbytes/year at 30 sec rate). I run a cronjob every five minutes that calls mysql2300 to populate the data. See the open2300 documentation. 3) open2300db2APRS - see "open2300db2APRS RUN OPTIONS" below. Start this daemon after mysqld and before Xastir. I start it with the command "open2300db2APRS -r --password 4) xastir - start this last, if you are auto-opening the WX port. Set the weather port as a network weather station on "localhost", port number as chosen in "db2APRS RUN OPTIONS" (default is 1313). Make sure your station is set to one of the "w/weather data" and your Icon is set to a weather Icon. open2300db2APRS RUN OPTIONS --------------------------- The open2300db2APRS utility takes standard short & long command line options, which can be displayed by "open2300db2APRS -?". Here's the list: -h --help Show help info and exit. -v --verbose Useful with the -n switch, for trouble-shooting, not for normal operation. Tells you more than you really wanted to know, but I recommend that you use this switch while you try to initially set up db2APRS. -c --cport [port#] Choose which TCP/IP port data comes out from. If not used, port number 1313 is the default. HINT: "telnet localhost [port#]" is a handy way to verify db2APRS operation. -u --user [database user] Username for mysql database connection. If unspecfied defaults to "meteo" (which is per the meteo setup intended to be a read-only account for meteo). -p --password [db passwd] Password for mysql connection. If unspecfied, no password is supplied. NOTE: this password is unfortunately visible to anyone on your system running 'ps -ef'. TO BE FIXED. -b --database [database] Database name for mysql connection. If not supplied the default is "meteo". -n --nodaemon Run in the fore-ground as a program. Useful for debugging or initial setup, when used with -v. -r --repeat Keep going till killed - if not specified, one pass is performed and then db2APRS exits. The only case where this switch is *not* used is during initial setup/debug. Typical example: "./open2300db2APRS -r -u open2300 -p mysql2300" for normal use or "./open2300db2APRS -r -n -v -u test -p password" for debugging. OPERATIONAL DETAILS ------------------- open2300db2APRS connects to the specified mysql database, extracts the latest timestamp and compares it to the last timestamp it read. If newer, the outdoor weather data (extception: air pressure is taken as indoor=outdoor) bearing this timestamp is extracted and formatted in the APRS "position less" string format with a Davis and X-APRS tag on the end. Any connecting client is given this string at 25 second intervals, after new database entries are checked for. This daemon could run on any networked Linux machine instead of the machine hosting Xastir, if desired (it's a good way around lack of processing power, disk space or serial ports!). Note that the open2300db2APRS daemon keeps providing data to Xastir even when no new entries in the database have been made. This could lead to errors in the timestamp on the data that Xastir is transmitting. BUILD open2300db2APRS --------------------- It's the usual: $ cd xastir/LaCrosse $ ./bootstrap.sh $ ./configure $ make $ su -c 'make install' ACKNOWLEDGEMENTS & AUTHORS -------------------------- A large portion of this work taken from db2APRS (thanks Bruce!!) db2APRS is the product of Bruce Bennett, callsign KB8ROP It is freely available at no charge under the GNU GENERAL PUBLIC LICENSE (see "COPYING" document) NO WARRANTY, expressed or implied, use at your own risk. Please feel free to contact me with test results & comments at the above EMAIL address Code portions and style taken from wx200d by Tim Witham , et. al. mysql is the product of MySQL - see http://www.mysql.com for team details. and finally, Xastir is the brain child of Frank Giannandrea et. al. (see http://www.xastir.org for current EMAIL addresses) Xastir-Release-2.2.4/LaCrosse/bootstrap.sh0000775000175000017500000000100115151324131017400 0ustar hibbyhibby#!/bin/sh -e # # # Copyright (C) 2000-2026 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.4/LaCrosse/configure.ac0000775000175000017500000000402115151324131017322 0ustar hibbyhibby# # Copyright (C) 2004 Bruce Bennett # Portions Copyright (C) 2000-2026 The Xastir Group # (Modified for the Xastir project under GPL license) # # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.53) AC_INIT(open2300db2APRS, 0.1.0, jim@n0vh.org) AM_INIT_AUTOMAKE(open2300db2APRS, 0.1.0) AC_CONFIG_SRCDIR([src/open2300db2APRS.c]) AM_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_INSTALL AC_PROG_CC # Checks for libraries. # Use MySQL's script for library config, if available MYSQL_CONFIG=mysql_config AC_MSG_CHECKING(for a fully installed MySQL) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then MYSQL_VERSION=`${MYSQL_CONFIG} --version` MYSQL_LIBS=`${MYSQL_CONFIG} --libs` LIBS=`${MYSQL_CONFIG} --libs` MYSQL_CFLAGS=`${MYSQL_CONFIG} --cflags` CFLAGS="$CFLAGS $MYSQL_CFLAGS" AC_SUBST(MYSQL_LIBS) AC_SUBST(MYSQL_CFLAGS) AC_MSG_RESULT(...found ${MYSQL_VERSION}) else AC_MSG_RESULT(MySQL is not fully installed) AC_MSG_CHECKING(if there at least are the needed MySQL client libs) AC_CHECK_LIB(mysqlclient,mysql_close) if test $ac_cv_lib_mysqlclient_mysql_close = no; then AC_MSG_ERROR(*** No MySQL client library found - See README ***) else AC_MSG_RESULT(found a usable libmysqlclient) fi fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h syslog.h unistd.h]) if ${MYSQL_CONFIG} --libs > /dev/null 2>&1 then AC_MSG_RESULT(mysql.h path defined in CFLAGS) else AC_CHECK_HEADERS([mysql.h],MYSQL_INC="yes",AC_MSG_ERROR(*** MySQL include file mysql.h not found - See README ***)) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_HEADER_TIME # Checks for library functions. AC_FUNC_FORK AC_FUNC_SELECT_ARGTYPES AC_TYPE_SIGNAL AC_FUNC_STRTOD AC_CHECK_FUNCS([memset select socket strrchr strtol]) AC_CONFIG_FILES([Makefile \ src/Makefile]) AC_OUTPUT Xastir-Release-2.2.4/LaCrosse/src/0000775000175000017500000000000015151324131015623 5ustar hibbyhibbyXastir-Release-2.2.4/LaCrosse/src/.vimrc0000664000175000017500000000143315151324131016745 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/LaCrosse/src/Makefile.am0000664000175000017500000000034415151324131017660 0ustar hibbyhibby# # # Copyright (C) 2000-2026 The Xastir Group # bin_PROGRAMS = open2300db2APRS noinst_PROGRAMS = open2300db2APRS_SOURCES = \ open2300db2APRS.c defs.h open2300db2APRS_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.4/LaCrosse/src/defs.h0000664000175000017500000000114115151324131016712 0ustar hibbyhibby// // // Copyright (C) 2005 Jim Chandler // Portions Copyright (C) 2000-2026 The Xastir Group // // // Dummy info here for now... // #define VERSION "0.1.0" #define PORT 1313 #define CONNECTIONS 20 #define NOFILE 20 // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif Xastir-Release-2.2.4/LaCrosse/src/open2300db2APRS.c0000664000175000017500000006561315151324131020326 0ustar hibbyhibby/****************************************************************** * * * Copyright (C) 2005 Jim Chandler * Portions Copyright (C) 2000-2026 The Xastir Group * * Portions copied from Bruce Bennett's excellent Davis WX work * * (see the files README and COPYING for more details) * * This file implements all of the database to APRS daemon. * * LaCrosse/Data Base Weather --> APRS Weather Intended use: Create & provide APRS style packet string without position information from MySQL database weather information stored there by open2300 (See http://open2300.sourceforge.net/ for source) to xastir-1.2.1 (See http://www.xastir.org for source) Note: Open2300 is a weather data accumulator aimed at LaCrosse weather stations, which stores weather data in a mysql database. Output is to the ip hostname:port required in the command line. ACKNOWLEDGEMENTS: Elements of this software are taken from wx200d ver 1.2 by Tim Witham , and it is modeled after that application and from db2APRS by Bruce Bennett . *******************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAXARGS 20 /* maximum CGI args to parse */ #define TMPLEN 128 /* max length of CGI */ #define BUFLEN 32 /* max length of hostname:port */ #define VALID_WINDDIR 0x01 #define VALID_WINDSPD 0x02 #define VALID_WINDGST 0x04 #define VALID_TEMP 0x08 #define VALID_RAIN1HR 0x10 #define VALID_RAIN24H 0x20 #define VALID_HUMIDITY 0x40 #define VALID_AIRPRESS 0x80 #define VALID_RAINTOT 0x100 #define MTPS2MPH 2.2369 #define DEGC2DEGF 1.8 #define MM2IN100TH 3.937 #define INHG2HPA10TH 338.638 #define OUTDOOR_SENSOR 1 //---From the static table "mfield", which really should be dynamically read here--- // (but then I couldn't use a switch statement) #define TEMPERATURE 0 #define TEMPERATURE_MIN 1 #define TEMPERATURE_MAX 2 #define HUMIDITY 10 #define HUMIDITY_MIN 11 #define HUMIDITY_MAX 12 #define WETNESS 20 #define WETNESS_MIN 21 #define WETNESS_MAX 22 #define AIR_PRESSURE 30 #define AIR_PRESSURE_MIN 31 #define AIR_PRESSURE_MAX 32 #define SOLAR 40 #define UV 41 #define RAIN 50 // note: "51" is really rain total #define RAIN_PER_DAY 51 #define RAIN_PER_HOUR 52 #define WIND_SPEED 60 #define WIND_DIRECTION 61 #define WIND_GUST 62 #define WIND_X 63 #define WIND_Y 64 #define MOISTURE 70 #define WATERLEVEL 71 #define WATERLEVEL_MIN 72 #define WATERLEVEL_MAX 73 #define BATTERY 110 #define TRANSMITTER 111 #define DURATION 120 #define SAMPLES 121 struct dbinfo { char user[30]; char pswrd[15]; char name[30]; } db; char *progname; char *query; int *current = 0; int opt; MYSQL mysql; // Yeah, globals... MYSQL_RES *result; MYSQL_ROW row; char last_timestamp[20]; int debug_level; char wxAPRShost[BUFLEN]; int wxAPRSport = PORT; int outdoor_instr = OUTDOOR_SENSOR; /****************************************************************** 1/4/2003 Usage brief *******************************************************************/ void usage(int ret) { if (query) { printf("Content-type: text/plain\nStatus: 200\n\n"); } printf("usage: %s [options] \n",progname); printf("VERSION: %s\n",VERSION); printf(" -h --help show this help and exit\n"); printf(" -v --verbose debugging info --> stderr\n"); printf(" -c --cport [port#] IP port for data output\n"); printf(" -u --user [database user] username for mysql - default meteo\n"); printf(" -p --password [db passwd] password for mysql - default none\n"); printf(" -b --database [database] database name - default meteo\n"); printf(" -n --nodaemon do not run as daemon\n"); printf(" -r --repeat keep running\n"); printf("options may be uniquely abbreviated; units are as defined in APRS\n"); printf("Specification 1.0.1 for positionless weather data (English/hPa).\n"); exit(ret); } /****************************************************************** 1/2/2003 Make an APRS string out of WX data *******************************************************************/ int APRS_str(char *APRS_buf, double winddir, double windspeed, double windgust, double temp, double rain1hr, double rain24h, double raintot, double humidity, double airpressure, unsigned int valid_data_flgs, int Metric_Data) { int intval; char pbuf[10]; if (APRS_buf == NULL) { if (debug_level & 1) { fprintf(stderr,"err: Null string buffer for APRS string.\n"); } return 0; // Ooo!! *****Nasty Bad Exit Point Here**** } if (valid_data_flgs & VALID_WINDDIR) { intval = (winddir + 0.5); // rounding to whole degrees if (intval > 360) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction > 360\n"); } sprintf(APRS_buf, "c..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind direction negative\n"); } sprintf(APRS_buf, "c..."); } else { sprintf(APRS_buf, "c%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind direction flagged as invalid\n"); } sprintf(APRS_buf, "c..."); } if (valid_data_flgs & VALID_WINDSPD) { if (Metric_Data) { intval = (windspeed*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windspeed + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind speed > 600 MPH\n"); } sprintf(pbuf, "s..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "s..."); } else { sprintf(pbuf, "s%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind speed flagged as invalid\n"); } sprintf(pbuf, "s..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_WINDGST) { if (Metric_Data) { intval = (windgust*MTPS2MPH + 0.5); // converting & rounding to whole MPH } else { intval = (windgust + 0.5); // rounding to whole MPH } if (intval > 600) // Let's be reasonable here - center of a tornado?? { if (debug_level & 1) { fprintf(stderr,"err: Wind gust > 600 MPH\n"); } sprintf(pbuf, "g..."); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Wind speed negative\n"); } sprintf(pbuf, "g..."); } else { sprintf(pbuf, "g%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Wind gust flagged as invalid\n"); } sprintf(pbuf, "g..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_TEMP) { if (Metric_Data) { intval = ((temp)*DEGC2DEGF + 0.5)+32; // converting & rounding to whole Deg F } else { intval = (temp + 0.5); // rounding to whole Deg F } if (intval > 200) // Let's be reasonable here - boiling? { if (debug_level & 1) { fprintf(stderr,"err: Temperature > 200 Deg F\n"); } sprintf(pbuf, "t..."); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Temperature < -99 Deg F\n"); } sprintf(pbuf, "t..."); } else { if (intval < 0) { sprintf(pbuf,"t%0.2d",intval); } else { sprintf(pbuf, "t%0.3d", intval); } } } else { if (debug_level & 1) { fprintf(stderr,"info: Temperature flagged as invalid\n"); } sprintf(pbuf, "t..."); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN1HR) { if (Metric_Data) { intval = ((rain1hr)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain1hr*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // 10 in/hr? Garden Hose -> rain gauge? { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr > 9.99 inch\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "r%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_RAIN24H) { if (Metric_Data) { intval = ((rain24h)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (rain24h*100.0 + 0.5); // rounding to whole 1/100 inch } if (intval > 999) // Can't handle greater than 9.99 inches of rain in 24 hours { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/24Hr > 9.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "p999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: Rainfall/Hr negative\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "p%0.3d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Rainfall/24Hr flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_HUMIDITY) { intval = (humidity + 0.5); // rounding to whole percent if (intval > 100) // Unlike the space shuttle engines, 100 % is max { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported > 100%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 1) { if (debug_level & 1) { fprintf(stderr,"err: Humidity reported < 1%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { if (intval == 100) // Report 100% as 'h00' { intval = 0; } sprintf(pbuf, "h%0.2d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Humidity flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); if (valid_data_flgs & VALID_AIRPRESS) { if (Metric_Data) { intval = (airpressure*10.0 + 0.5); // rounding to whole tenth of a hPa } else { intval = (airpressure*INHG2HPA10TH + 0.5); // convering In-Hg to 1/10 hPa and rounding } if (intval > 20000) //two atmospheres - about 29 PSIA { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported > 2 Atmospheres%\n"); } sprintf(pbuf, "\0\0\0\0"); } else if (intval < 0) { if (debug_level & 1) { fprintf(stderr,"err: Air Pressure reported negative%\n"); } sprintf(pbuf, "\0\0\0\0"); } else { sprintf(pbuf, "b%0.5d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: Air Pressure flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0"); } strcat(APRS_buf,pbuf); // NOW THIS MAKES THE STRING NO LONGER A VALID APRS WX REPORT, but // we don't care: Xastir does NOT just transmit this string, it parses it // and re-recreates the correct string to transmit. We do this because // APRS doesn't have a "total rain" string in its weather report, but // Xastir likes to have that value around. if (valid_data_flgs & VALID_RAINTOT) { if (Metric_Data) { intval = ((raintot)*MM2IN100TH + 0.5); // converting & rounding to whole 1/100 inch } else { intval = (raintot*100.0 + 0.5); // rounding to whole 1/100 inch } // Can't handle greater than 99.99 inches of total rain if (intval > 9999) { if (debug_level & 1) { fprintf(stderr,"err: total Rainfall > 99.99 inch - reporting 9.99 inches\n"); } sprintf(pbuf, "T9999"); } else if (intval < -99) { if (debug_level & 1) { fprintf(stderr,"err: total Rainfall negative\n"); } sprintf(pbuf, "\0\0\0\0\0"); } else { sprintf(pbuf, "T%0.4d", intval); } } else { if (debug_level & 1) { fprintf(stderr,"info: total Rainfall flagged as invalid\n"); } sprintf(pbuf, "\0\0\0\0\0"); } strcat(APRS_buf,pbuf); strcat(APRS_buf,"xDvs\n"); // add X aprs and LaCrosse WX station ID's and if (debug_level & 1) { fprintf(stderr,"\ninfo: APRS Version of WX - %s\n\n",APRS_buf); } return strlen(APRS_buf); } /****************************************************************** 1/2/2003 Get the latest set of Weather Data from the Data Base *******************************************************************/ int Get_Latest_WX( double *winddir, double *windspeed, double *windgust, double *temp, double *rain1hr, double *rain24h, double *raintot, double *humidity, double *airpressure, unsigned int *valid_data_flgs, int *Metric_Data) { char query_buffer[160]; int nrows, item_count; int nfields; // Find latest, see if it's new to us // --new to us is a simple timestamp follower, so upon startup // it will always read one set of data, assuming any exists if (mysql_query(&mysql, "SELECT MAX(timestamp) from weather")) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if (!(result = mysql_store_result(&mysql))) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if (mysql_num_rows(result) != 1 ) { if (debug_level & 1) { fprintf(stderr,"err: Latest timestamp query failed - exiting: number of results %d\n", mysql_num_rows(result)); } // release query buffer mysql_free_result(result); return 0; } row = mysql_fetch_row(result); if ( row[0] == NULL ) { if (debug_level & 1) { fprintf(stderr,"err: NULL result for timestamp query\n"); } // release query buffer mysql_free_result(result); return 0; } // if no new data. exit with negative status if (!strncmp(last_timestamp, row[0], 14)) { if (debug_level & 1) { fprintf(stderr,"info: No new weather data recorded - exiting: negative data\n"); } // release query buffer mysql_free_result(result); return -1; } strcpy(last_timestamp, row[0]); // For next pass & following query if ( debug_level & 1) { fprintf(stdout,"Timestamp: %s\n",last_timestamp); } // release query buffer mysql_free_result(result); sprintf(query_buffer,"SELECT wind_angle, windspeed, temp_out, rain_1h, rain_24h, rel_hum_out, rel_pressure, rain_total FROM weather WHERE timestamp = %s", last_timestamp); if (mysql_query(&mysql, query_buffer)) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n\t --Query: %s\n", mysql_error(&mysql), query_buffer); } return 0; } if (!(result = mysql_store_result(&mysql))) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: %s\n", mysql_error(&mysql)); } return 0; } if ((nrows=mysql_num_rows(result)) < 1 ) { if (debug_level & 1) { fprintf(stderr,"err: Latest Weather Data query failed - exiting: number of results %d\n",nrows); } // release query buffer mysql_free_result(result); return 0; } else { nfields=mysql_num_fields(result); row=mysql_fetch_row(result); if (debug_level & 1) { fprintf(stderr,"info: Latest Weather Data query: number of types of readings %d\n",nfields); } } *valid_data_flgs = 0; item_count = 0; //WIND_DIRECTION : *winddir = strtod(row[0],NULL); *valid_data_flgs |= VALID_WINDDIR; item_count++; if (debug_level & 1) { fprintf(stderr,"wind direction %f\n ",*winddir); } //case WIND_SPEED : *windspeed = strtod(row[1],NULL); *windspeed = *windspeed * 1.15077945; // Convert from knots to mph *valid_data_flgs |= VALID_WINDSPD; item_count++; if (debug_level & 1) { fprintf(stderr,"wind speed %f\n ",*windspeed); } //case WIND_GUST : *windgust = strtod("0",NULL); //*valid_data_flgs |= VALID_WINDGST; No gust information from open2300 item_count++; if (debug_level & 1) { fprintf(stderr,"wind gust speed %f\n ",*windgust); } //case TEMPERATURE : *temp = strtod(row[2],NULL); *valid_data_flgs |= VALID_TEMP; item_count++; if (debug_level & 1) { fprintf(stderr,"temperature %f\n ",*temp); } //case RAIN_PER_HOUR : *rain1hr = strtod(row[3],NULL); *valid_data_flgs |= VALID_RAIN1HR; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall for 1 hr %f\n ",*rain1hr); } //case RAIN_PER_DAY : *rain24h = strtod(row[4],NULL); *valid_data_flgs |= VALID_RAIN24H; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall for 24 hrs %f\n ",*rain24h); } //case HUMIDITY : *humidity = strtod(row[5],NULL); *valid_data_flgs |= VALID_HUMIDITY; item_count++; if (debug_level & 1) { fprintf(stderr,"humidity %f\n ",*humidity); } //case AIR_PRESSURE : *airpressure = strtod(row[6],NULL); *valid_data_flgs |= VALID_AIRPRESS; item_count++; if (debug_level & 1) { fprintf(stderr,"air pressure %f\n ",*airpressure); } //case RAIN_TOTAL *raintot = strtod(row[7],NULL); *valid_data_flgs |= VALID_RAINTOT; item_count++; if (debug_level & 1) { fprintf(stderr,"rainfall since reset %f\n ",*raintot); } *Metric_Data = 0; // My station reports F, knots and inHG // release query buffer & close connection mysql_free_result(result); if (debug_level & 1) { fprintf(stderr,"info: success - Weather Data number of reading types %d\n", item_count); } return item_count; } /****************************************************************** 1/5/2003 SIGPIPE signal handler *******************************************************************/ void pipe_handler(int sig) /* */ { signal(SIGPIPE, SIG_IGN); if (sig == SIGPIPE) // client went bye-bye { shutdown(*current, 2); close(*current); *current = -1; if (debug_level & 1) { fprintf(stderr, "info: %s - TCP client timed out", progname); } } } /****************************************************************** 1/5/2003 SIGTERM signal handler *******************************************************************/ void term_handler( int UNUSED(sig) ) /* */ { if (debug_level & 1) { fprintf(stderr, "info: %s - ordered to DIE, complying", progname); } // release query buffer & close connection mysql_free_result(result); mysql_close(&mysql); exit( 0 ); } /****************************************************************** 1/2/2003 Coordinating MAIN point *******************************************************************/ int main(int argc, char **argv) { const char *flags = "Hhvnc:u:p:d:s:r"; char WX_APRS[120]; int data_len = 0 ; double winddir; double windspeed; double windgust; double temp; double rain1hr; double rain24h; double raintot; double humidity; double airpressure; unsigned int valid_data_flgs; int Metric_Data = 0, dsts = 0; int pid, s; socklen_t clen = sizeof(struct sockaddr_in); int fd[CONNECTIONS]; int *max = 0, dly_cnt = 1; int not_a_daemon = 0, repetitive = 0, tcp_wx_port = PORT; int i, index = 0; struct sockaddr_in server, client; struct in_addr bind_address; fd_set rfds; struct timeval tv; struct option longopt[] = { {"help", 0, 0, 'h'}, {"refresh", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"user", 1, 0, 'u'}, {"password", 1, 0, 'p'}, {"database", 1, 0, 'd'}, {"cport", 1, 0, 'c'}, {"nodaemon", 0, 0, 'n'}, {0, 0, 0, 0} }; debug_level = 0; strcpy(db.user,"open2300"); // set default values for database access strcpy(db.name,"open2300"); memset(db.pswrd,0,15); mysql_init(&mysql); progname = strrchr(argv[0], '/'); if (progname == NULL) { progname = argv[0]; } else { progname++; } while ((opt = getopt_long(argc, argv, flags, longopt, &index)) != EOF) { switch (opt) /* parse command-line or CGI options */ { case 'r': repetitive = 1; break; case 'v': fprintf(stdout,"Verbose mode set:\n"); debug_level = 1; break; case 'u': // mysql username strncpy(db.user,(char *)optarg,30); break; case 'p': // mysql password strncpy(db.pswrd,(char *)optarg,15); break; case 'd': // mysql database name strncpy(db.name,(char *)optarg,30); break; case 'n': /* do not fork and become a daemon */ not_a_daemon = 1; break; case 'c': /* port to use */ tcp_wx_port = strtol(optarg, NULL, 0); break; case '?': case 'h': case 'H': usage(0); break; default : usage(1); } } if (debug_level & 1) { fprintf(stdout,"Starting..."); if (repetitive) { fprintf(stdout, " forever "); } else { fprintf(stdout, " one pass only "); } fprintf(stdout," with database user=%s, password=%s, for database=%s\n", db.user, db.pswrd, db.name); if (not_a_daemon) { fprintf(stdout," as a program "); } else { fprintf(stdout," as a daemon "); } fprintf(stdout, " using TCP port %d\n",tcp_wx_port); } // Data base connection if (!(mysql_real_connect(&mysql, "localhost", db.user, db.pswrd, db.name, 0, NULL, 0))) { if (debug_level & 1) { fprintf(stderr,"err: Data Base connect for user:%s to database:%s failed - exiting: \n\t%s\n", db.user, db.name, mysql_error(&mysql)); } exit(9); } server.sin_family = AF_INET; bind_address.s_addr = htonl(INADDR_ANY); server.sin_addr = bind_address; server.sin_port = htons(tcp_wx_port); if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - no socket", progname); } exit(10); } /* / April 2001 Minor change to allow quick * (re)start of daemon or client while there are pending * conncections during the quit. To avoid address/port in use * error. */ i = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - setsockopt", progname); } } if (bind(s, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - cannot bind to socket", progname); } exit(11); } if (listen(s, CONNECTIONS) == -1) { if (debug_level & 1) { fprintf(stderr, "err: %s - listen", progname); } exit(12); } if (debug_level & 1) { fprintf(stdout,"Sockets UP.\n"); } umask(0022); for (i = 0; i < CONNECTIONS; i++) { fd[i] = -1; } tv.tv_sec = 0; tv.tv_usec = 0; if (!not_a_daemon) /* setup has worked; now become a daemon? */ { if ((pid = fork()) == -1) { syslog(LOG_ERR, "can't fork() to become daemon: %m"); exit(20); } else if (pid) { exit (0); } setsid(); for (i = 0; i < NOFILE; i++) { if ( i != s) { close(i); } } } /* catch signals to close the database connection */ signal( SIGTERM, term_handler );/* termination */ #if defined(SIGPWR) /* SIGPWR is linux centric */ signal( SIGPWR, term_handler ); /* power failure */ #endif if (debug_level & 1) { fprintf(stdout,"Main Loop...\n"); } dly_cnt = 1; //N0VH, change back to 1 do { if (!(dly_cnt--)) { dly_cnt = 25; // Every 'dly_cnt' passes check for WX data update if ((dsts = Get_Latest_WX(&winddir,&windspeed,&windgust, &temp,&rain1hr,&rain24h,&raintot, &humidity,&airpressure, &valid_data_flgs,&Metric_Data)) !=0 ) { if ( dsts > 0 ) { data_len = APRS_str(WX_APRS, winddir,windspeed,windgust, temp, rain1hr, rain24h, raintot, humidity, airpressure, valid_data_flgs, Metric_Data); if (!data_len) { if (debug_level & 1) { fprintf(stderr, "err: WX info formatting problem!"); } exit(13); } } } else { exit(dsts); } } FD_ZERO(&rfds); FD_SET(s, &rfds); if (select(s + 1, &rfds, NULL, NULL, &tv) > 0) { for (current = fd; (*current > 0) && (current < fd + CONNECTIONS - 1); current++); if (current > max) { max = current; } if ((*current = accept(s, (struct sockaddr *)&client, &clen)) != -1) { write(*current, WX_APRS, data_len); } } if (dly_cnt == 25) { if (debug_level & 1) { fprintf(stdout,"Updating clients:"); } for (current = fd; current <=max; current++) { if (*current > 0) // active socket { if (debug_level & 1) { fprintf(stdout," #"); } signal(SIGPIPE, pipe_handler); write(*current, WX_APRS, data_len); } if (debug_level & 1) { fprintf(stdout," done\n"); } } } sleep(1); // } while (repetitive); mysql_close(&mysql); if (debug_level & 1) { fprintf(stdout,"Exiting normally.\n"); } exit(0); } Xastir-Release-2.2.4/LaCrosse/weatherdump.sql0000664000175000017500000000214715151324131020106 0ustar hibbyhibby-- MySQL dump 8.23 -- -- Host: localhost Database: open2300 --------------------------------------------------------- -- Server version 3.23.58-log -- -- Table structure for table `weather` -- CREATE TABLE weather ( timestamp bigint(14) NOT NULL default '0', rec_date date NOT NULL default '0000-00-00', rec_time time NOT NULL default '00:00:00', temp_in decimal(4,1) NOT NULL default '0.0', temp_out decimal(4,1) NOT NULL default '0.0', dewpoint decimal(4,1) NOT NULL default '0.0', rel_hum_in tinyint(3) NOT NULL default '0', rel_hum_out tinyint(3) NOT NULL default '0', windspeed decimal(4,1) NOT NULL default '0.0', wind_angle decimal(4,1) NOT NULL default '0.0', wind_direction char(3) NOT NULL default '', wind_chill decimal(4,1) NOT NULL default '0.0', rain_1h decimal(4,2) NOT NULL default '0.00', rain_24h decimal(4,2) NOT NULL default '0.00', rain_total decimal(5,2) NOT NULL default '0.00', rel_pressure decimal(4,2) NOT NULL default '0.00', tendency varchar(7) NOT NULL default '', forecast varchar(6) NOT NULL default '', UNIQUE KEY timestamp (timestamp) ) TYPE=MyISAM; Xastir-Release-2.2.4/Makefile.am0000664000175000017500000001127615151324131015364 0ustar hibbyhibby # # Copyright (C) 2000-2026 The Xastir Group # AUTOMAKE_OPTIONS = gnu dist-bzip2 ACLOCAL_AMFLAGS = -I m4 D= `date +%G%m%d.%H%M%S` SUBDIRS = src config help scripts symbols callpass tests # DISTCLEANFILES = EXTRA_DIST = config.guess config.sub install-sh \ missing placeholder FAQ LICENSE README README.GIT.md \ README.CYGWIN CONTRIBUTING.md \ README.MAPS README.OSM_maps README.sudo testdbfawk.1 \ DEBUG_LEVELS bootstrap.sh INSTALL.md callpass.1 xastir.1 xastir_udp_client.1 \ worldhi.map \ Davis LaCrosse \ OSM_template \ CC_OpenStreetMap_logo.png CC_OpenStreetMap_txt.png \ COPYING COPYING.LIB.LESSTIF AUTHORS NaturalEarthVector MAINTAINERCLEANFILES = configure aclocal.m4 Makefile.in Makefile \ config.guess config.sub install-sh missing mkinstalldirs countydir=${pkgdatadir}/Counties county_DATA=placeholder fccdir=${pkgdatadir}/fcc fcc_DATA=placeholder gnisdir=${pkgdatadir}/GNIS gnis_DATA=placeholder mapdir=${pkgdatadir}/maps map_DATA=worldhi.map CC_OpenStreetMap_logo.png CC_OpenStreetMap_txt.png onlinedir=${pkgdatadir}/maps/Online online_DATA=OSM_tiled_cycle.geo OSM_tiled_mapnik.geo \ OSM_tiled_fosm.geo USTigermap.geo USTigermapBorders.geo nationalmapdir=${pkgdatadir}/maps/Online/nationalmap.gov nationalmap_DATA=WMS_USGS_Hydrography.geo WMS_USGS_ImageryOnly.geo \ WMS_USGS_ImageryTopo.geo WMS_USGS_ShadedReliefOnly.geo \ WMS_USGS_Topo.geo nwsradarmapdir=${pkgdatadir}/maps/Online/NWS nwsradarmap_DATA=NWSRadar_Alaska_CompositeRef.geo \ NWSRadar_Hawaii_CompositeRef.geo \ NWSRadar_CONUS_CompositeRef.geo geogratismapdir=${pkgdatadir}/maps/Online/geogratis.gc.ca geogratismap_DATA=National.geo Regional.geo Sub_national.geo Sub_regional.geo naturalearthmapdir=${pkgdatadir}/maps/NaturalEarth naturalearthmap_DATA=NaturalEarthVector/LICENSE.md NaturalEarthVector/README NaturalEarthVector/ne_50m_admin_0_countries_lakes.README.html NaturalEarthVector/ne_50m_admin_0_countries_lakes.VERSION.txt NaturalEarthVector/ne_50m_admin_0_countries_lakes.cpg NaturalEarthVector/ne_50m_admin_0_countries_lakes.dbf NaturalEarthVector/ne_50m_admin_0_countries_lakes.dbfawk NaturalEarthVector/ne_50m_admin_0_countries_lakes.prj NaturalEarthVector/ne_50m_admin_0_countries_lakes.shp NaturalEarthVector/ne_50m_admin_0_countries_lakes.shx NaturalEarthVector/ne_50m_coastline.README.html NaturalEarthVector/ne_50m_coastline.VERSION.txt NaturalEarthVector/ne_50m_coastline.cpg NaturalEarthVector/ne_50m_coastline.dbf NaturalEarthVector/ne_50m_coastline.dbfawk NaturalEarthVector/ne_50m_coastline.prj NaturalEarthVector/ne_50m_coastline.shp NaturalEarthVector/ne_50m_coastline.shx NaturalEarthVector/ne_50m_lakes.README.html NaturalEarthVector/ne_50m_lakes.VERSION.txt NaturalEarthVector/ne_50m_lakes.cpg NaturalEarthVector/ne_50m_lakes.dbf NaturalEarthVector/ne_50m_lakes.dbfawk NaturalEarthVector/ne_50m_lakes.prj NaturalEarthVector/ne_50m_lakes.shp NaturalEarthVector/ne_50m_lakes.shx NaturalEarthVector/ne_50m_rivers_lake_centerlines.README.html NaturalEarthVector/ne_50m_rivers_lake_centerlines.VERSION.txt NaturalEarthVector/ne_50m_rivers_lake_centerlines.cpg NaturalEarthVector/ne_50m_rivers_lake_centerlines.dbf NaturalEarthVector/ne_50m_rivers_lake_centerlines.dbfawk NaturalEarthVector/ne_50m_rivers_lake_centerlines.prj NaturalEarthVector/ne_50m_rivers_lake_centerlines.shp NaturalEarthVector/ne_50m_rivers_lake_centerlines.shx gpsdir=${pkgdatadir}/maps/GPS gps_DATA=placeholder sounddir=${pkgdatadir}/sounds sound_DATA=placeholder docdir=@docdir@ doc_DATA=AUTHORS FAQ ChangeLog LICENSE README README.GIT.md README.CYGWIN \ README.MAPS README.sudo COPYING INSTALL.md \ README.OSM_maps CONTRIBUTING.md \ COPYING.LIB.LESSTIF install-data-hook: cd $(DESTDIR)$(mapdir) && \ rm -f CC_OpenStreetMap.png && \ $(LN_S) CC_OpenStreetMap_logo.png CC_OpenStreetMap.png mandir=@mandir@ man_MANS=xastir.1 callpass.1 xastir_udp_client.1 testdbfawk.1 # Use tiles for these maps OSM_tiled_cycle.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL http://tile.opencyclemap.org/cycle/!' \ -e 's/-STYLE/-cycle/' \ < $(top_srcdir)/OSM_template >$@ OSM_tiled_mapnik.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL https://tile.openstreetmap.org/!' \ -e 's/-STYLE/-mapnik/' \ < $(top_srcdir)/OSM_template >$@ OSM_tiled_fosm.geo: OSM_template sed -e '/THIS IS A TEMPLATE FILE/d' -e's/^#OSM_TILED_MAP/OSM_TILED_MAP/' \ -e's!^#URL tileURL!URL https://map.fosm.org/default/!' \ -e 's/-STYLE/-fosm/' \ < $(top_srcdir)/OSM_template >$@ ChangeLog:: Xastir-Release-2.2.4/NEWS0000664000175000017500000000177515151324131014032 0ustar hibbyhibby News - Updated 29 April 2001 ------------------------------------------------------------------------ What's new, first read the following documents: INSTALL README ChangeLog All of these documents combined will fill you in on the latest changes to xastir in version 0.4.x. A lot of things have changed in this version so at a minimum read the ChangeLog text file. ChangeLog shows what's been added and fixed along the way. This version includes a "first try" at using the GNU Autotools for configuration. These scripts have not been thoroughly tested on all platforms. Any feedback is actively solicited. This version also includes several additional directories added in preparation for the implementation of GNU internationalization routines. CAUTION: 1. Before you start Xastir for the first time BACKUP your data files if this is an upgrade from a previous version. 2. DON'T USE YOUR OLD CONFIG FILE.. MAKE A NEW ONE......... Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/NWS-TEST.log0000664000175000017500000001151315151324131015251 0ustar hibbyhibby # Test log file for weather alerts. Bring this file into Xastir via # the Open Log File option and within 30-60 seconds you should see # the alerts light up. All except the first one listed here which # has a matching cancel: See that alert as cancelled in the # View->Weather Alerts dialog. # # If using this file during the early part of a month you must # change the date stamp ("30" here) to numbers closer to your # current date but into the future a bit. Note that these are UTC # date/times. You must be within XX days (mod 31) to see the # alerts, else Xastir assumes the date was from the previous month # and discards them. The alert must be within 0-10 days into the # future (UTC) in order to be displayed, per # util.c:time_from_aprsstring() # # Note: If commenting out sentences you'll need to use more than # just one a '#' mark. "####" seems to work fine (4 chars). # Test individual alerts, with only one area lit up per message. # Alert level tests, color specifies alert level: # ----------------------------------------------- # First we do an active alert and a cancel. This should not display # on the map, but CANCL messages show in the View WX Alerts dialog. # If the alert did show, it would be lighting up the San Juan # Islands (upper Puget Sound) in Blue. SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,WA_Z001, {OKoAB SEWWSW>APRS::NWS-CANCL:302119z,DENSE_FOG,WA_Z001, {OKoAB # # Blue "ALERT", WA, WA, lower left. SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,WA_Z020, {OKoAB # # Red "ALERT", WA, lower left. SEWWSW>APRS::NWS-WARN :302119z,DENSE_FOG,WA_Z021, {OKoAB # # Green "ALERT", WA, above Portland. "NWS- " works here also, # giving a Green alert just like "NWS-CURT ". SEWWSW>APRS::NWS-CURT :302119z,DENSE_FOG,WA_Z019, {OKoAB # # Red "ALERT", WA, along Columbia river. SEWWSW>APRS::NWS-CIVIL:302119z,DENSE_FOG,WA_Z024, {OKoAB # # K2DLS WA_Z023 no longer exists (08/25/17) # Yellow "ALERT", WA, along Columbia river. #SEWWSW>APRS::NWS-WATCH:302119z,DENSE_FOG,WA_Z023, {OKoAB # # Cyan "ALERT", WA, along Columbia river. SEWWSW>APRS::NWS-ADVIS:302119z,DENSE_FOG,WA_Z022, {OKoAB # Event type tests, embedded text changes with even type: # ------------------------------------------------------- # Blue "FLOOD", WA, lower middle. SEWWSW>APRS::NWS-TEST :302119z,FLOOD,WA_Z026, {OKoAB # # Red "SNOW", WA, bottom middle. SEWWSW>APRS::NWS-WARN :302119z,SNOW,WA_Z027, {OKoAB # # Yellow "TORNDO", WA, lower middle. SEWWSW>APRS::NWS-WATCH:302119z,TORNDO,WA_Z028, {OKoAB # # Cyan "WIND", WA, lower right. SEWWSW>APRS::NWS-ADVIS:302119z,WIND,WA_Z029, {OKoAB # # Green "WNTR STRM", WA, lower right. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,WA_Z030, {OKoAB # # Blue "WINTER WX", WA, lower right. SEWWSW>APRS::NWS-TEST :302119z,WINTER_WEATHER,WA_Z031, {OKoAB # # Red "ALERT", WA, lower right. SEWWSW>APRS::NWS-WARN :302119z,SVRTSM,WA_Z032, {OKoAB # # Green "ALERT", WA, lower right. SEWWSW>APRS::NWS-CURT :302119z,CURT,WA_Z033, {OKoAB # # "RED FLAG", Yellow/Cyan/Red respectively. WA, left edge. SEWWSW>APRS::NWS-WATCH:302119z,RED_FLAG,WA_Z650, {OKoAB SEWWSW>APRS::NWS-ADVIS:302119z,RED_FLAG,WA_Z651, {OKoAB SEWWSW>APRS::NWS-CIVIL:302119z,RED_FLAG,WA_Z652, {OKoAB # File type tests: # ---------------- # c_08au05.shp # z_06oc05.shp # Cyan "WNTR STRM", WA, upper middle. SEWWSW>APRS::NWS-ADVIS:302119z,WINTER_STORM,WA_C007, {OKoAB # # Green "WNTR STRM", WA, lower middle right. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,WA_Z034, {OKoAB # # fz20se05.shp # Red "RED FLAG", WA lower Puget Sound. SEWWSW>APRS::NWS-CIVIL:302119z,RED_FLAG,WA_Z654, {OKoAB # # mz12se05.shp # Yellow "WNTR STRM", WA, Whidbey Island. SEWWSW>APRS::NWS-WATCH:302119z,WINTER_STORM,PZ_Z134, {OKoAB # # K2DLS PZ_Z082 no longer exists (08/25/17) # oz15de04.shp # Green "WNTR STRM", WA, off west coast out in the Pacific. SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM,PZ_Z082, {OKoAB # # w_28de04.shp # Green "SNOW", ID & OR, around the Boise area. SEWWSW>APRS::NWS-CURT :302119z,SNOW,CW_ABOI, {OKoAB # # hz28au04.shp # Support for this filename is not implemented in Xastir. # Test multiple alerts in one packet, in WSSVR normal and compressed # format (dash/underline). # # Blue "ALERT" in OR, along coast SEWWSW>APRS::NWS-TEST :302119z,DENSE_FOG,OR_Z001,OR_Z002,OR_Z003,OR_Z004,OR_Z005 {OKoAB # # This one ends up yellow because "WATCH" is found later in the # string: #//////#SEWWSW>APRS::NWS-CURT :302119z,WINTER_STORM_WATCH_C,OR_Z011,OR_Z013 {OKoAB # But this one ends up Green. #//////#SEWWSW>APRS::NWS-CURT :302119z,DENSE_FOG,OR_Z011,OR_Z013 {OKoAB # # Blue "ALERT", upper portion of Idaho SEWWSW>APRS::NWS_TEST :302119z,DENSE_FOG,IDZ1-2-3-4-5-IDZ6>9 {OKoAB # NOTES: # ------ # CANCL=C=6=orange3 # TEST=T=4=RoyalBlue # WARN=R=1=red2 # CIVIL=R=1=red2 # WATCH=Y=2=yellow2 # ADVIS=B=3=cyan2 # ?=G=5=ForestGreen # # FLOOD # SNOW # TORNDO # WIND # WINTER_STORM # WINTER_WEATHER # RED_FLAG # SVRTSM (not implemented) # ? Xastir-Release-2.2.4/NWSRadar_Alaska_CompositeRef.geo0000664000175000017500000000102715151324131021371 0ustar hibbyhibbyWMSSERVER # # The National Weather Service has several WMS services to provide # weather radar images. Information about the various products available # can be had at https://opengeo.ncep.noaa.gov/geoserver/www/index.html # # This file allows the Quality Controlled Composite Reflectivity map # for Alaska URL https://opengeo.ncep.noaa.gov/geoserver/alaska/alaska_cref_qcd/ows?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&LAYERS=alaska_cref_qcd&STYLE=&FORMAT=image/png&TRANSPARENT=TRUE TRANSPARENT 0xFFFFFF REFRESH 600 Xastir-Release-2.2.4/NWSRadar_CONUS_CompositeRef.geo0000664000175000017500000000105415151324131021064 0ustar hibbyhibbyWMSSERVER # # The National Weather Service has several WMS services to provide # weather radar images. Information about the various products available # can be had at https://opengeo.ncep.noaa.gov/geoserver/www/index.html # # This file allows the Quality Controlled Composite Reflectivity map # for the Conterminous United States URL https://opengeo.ncep.noaa.gov/geoserver/conus/conus_cref_qcd/ows?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&LAYERS=conus_cref_qcd&STYLE=&FORMAT=image/png&TRANSPARENT=TRUE TRANSPARENT 0xFFFFFF REFRESH 600 Xastir-Release-2.2.4/NWSRadar_Hawaii_CompositeRef.geo0000664000175000017500000000103015151324131021371 0ustar hibbyhibbyWMSSERVER # # The National Weather Service has several WMS services to provide # weather radar images. Information about the various products available # can be had at https://opengeo.ncep.noaa.gov/geoserver/www/index.html # # This file allows the Quality Controlled Composite Reflectivity map # for Hawaii # URL https://opengeo.ncep.noaa.gov/geoserver/hawaii/hawaii_cref_qcd/ows?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&LAYERS=hawaii_cref_qcd&STYLE=&FORMAT=image/png&TRANSPARENT=TRUE TRANSPARENT 0xFFFFFF REFRESH 600 Xastir-Release-2.2.4/National.geo0000664000175000017500000000026315151324131015563 0ustar hibbyhibbyWMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=National Xastir-Release-2.2.4/NaturalEarthVector/0000775000175000017500000000000015151324131017076 5ustar hibbyhibbyXastir-Release-2.2.4/NaturalEarthVector/LICENSE.md0000664000175000017500000001103415151324131020501 0ustar hibbyhibby# Everything here is public domain. [Full terms of service »](http://www.naturalearthdata.com/about/terms-of-use/) All versions of Natural Earth raster + vector map data found on this website are in the public domain. You may use the maps in any manner, including modifying the content and design, electronic dissemination, and offset printing. The primary authors, _Tom Patterson_ and _Nathaniel Vaughn Kelso_, and all other contributors renounce all financial claim to the maps and invites you to use them for personal, educational, and commercial purposes. # Credits No permission is needed to use Natural Earth. Crediting the authors is unnecessary. However, if you wish to cite the map data, simply use one of the following. Short text: Made with Natural Earth. Long text: Made with Natural Earth. Free vector and raster map data @ naturalearthdata.com. Three logo options: ![Blue with white](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-color_sm.png) [Download Large Transparent PNG](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-color.png) [Download EPS](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV%20Logo%20color.zip) ![Black with white](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-Black_sm.png) [Download Large Transparent PNG](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-Black.png) [Download EPS](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV%20Logo%20Black.zip) ![White with transparent](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-White_sm.png) [Download Large Transparent PNG](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV-Logo-White.png) [Download EPS](http://www.naturalearthdata.com/wp-content/uploads/2009/08/NEV%20Logo%20White.zip) # Your due diligence All users of Natural Earth are highly encouraged to read about data sources and manipulation in the [Data Creation](http://www.naturalearthdata.com/about/data-creation/) section. The authors provide Natural Earth as a public service and are not responsible for any problems relating to accuracy, content, design, and how it is used. If you find an error or omission, please [report it](http://www.naturalearthdata.com/corrections/index.php?a=add) for future updates. # Releases The authors used data from The Washington Post, here is their release: Natural Earth is hereby granted a non-exclusive license to use the data being provided by The Washington Post for the sole purpose of creating a world base map. The Washington Post makes no claims as to the completeness, accuracy or content of the data, and makes no representation of any kind, including, but not limited to, any warranty as to the accuracy or fitness of the data for a particular use (nor shall the act of distribution constitute any such warranty). No responsibility is assumed by The Washington Post for any claims arising out of Natural Earth’s use of the data. The author’s used river and lake data (for Europe only) from the European Commission, Joint Research Centre, Institute for Environment and Sustainability, here is their release: Natural Earth is hereby granted a non-exclusive license to use the data being provided by European Commission, Joint Research Centre, Institute for Environment and Sustainability (JRC IES) for the sole purpose of creating a world base map. The EC JRC IES makes no claims as to the completeness, accuracy or content of the data, and makes no representation of any kind, including, but not limited to, any warranty as to the accuracy or fitness of the data for a particular use (nor shall the act of distribution constitute any such warranty). No responsibility is assumed by EC JRC IES for any claims arising out of Natural Earth’s use of the data. The author’s used road transportation data (for North America only) from XNR Productions, here is their release: Natural Earth is hereby granted a non-exclusive license to use the data being provided by XNR Productions for the sole purpose of creating a world base map. XNR makes no claims as to the completeness, accuracy or content of the data, and makes no representation of any kind, including, but not limited to, any warranty as to the accuracy or fitness of the data for a particular use (nor shall the act of distribution constitute any such warranty). No responsibility is assumed by XNR for any claims arising out of Natural Earth’s use of the data. Happy mapping! Xastir-Release-2.2.4/NaturalEarthVector/README0000664000175000017500000000021315151324131017752 0ustar hibbyhibbyThe shapefiles in this directory are all taken from the Natural Earth vector collection, https://github.com/nvkelso/natural-earth-vector. Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.README.html0000664000175000017500000011411415151324131026646 0ustar hibbyhibby Natural Earth » Blog Archive » Admin 0 – Countries - Free vector and raster map data at 1:10m, 1:50m, and 1:110m scales

Admin 0 – Countries

countries_thumb
There are 258 countries in the world. Greenland as separate from Denmark. Most users will want this file instead of sovereign states, though some users will want map units instead when needing to distinguish overseas regions of France.

Natural Earth shows de facto boundaries by default according to who controls the territory, versus de jure.

countries_banner

About

Countries distinguish between metropolitan (homeland) and independent and semi-independent portions of sovereign states. If you want to see the dependent overseas regions broken out (like in ISO codes, see France for example), use map units instead.

Each country is coded with a world region that roughly follows the United Nations setup.

Includes some thematic data from the United Nations, U.S. Central Intelligence Agency, and elsewhere.

Disclaimer

Natural Earth Vector draws boundaries of countries according to defacto status. We show who actually controls the situation on the ground. Please feel free to mashup our disputed areas theme to match your particular political outlook.

Known Problems

None.

Version History

The master changelog is available on Github »

Comments are closed.


Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.VERSION.txt0000664000175000017500000000000615151324131026703 0ustar hibbyhibby5.1.1 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.cpg0000664000175000017500000000000515151324131025510 0ustar hibbyhibbyUTF-8Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.dbf0000664000175000017500000315404215151324131025510 0ustar hibbyhibbyz! featureclaCscalerankNLABELRANKNSOVEREIGNTC SOV_A3C2ADM0_DIFN5LEVELN6TYPEC7TLCCHADMINCI#ADM0_A3ClGEOU_DIFNoGEOUNITCp#GU_A3CSU_DIFNSUBUNITC#SU_A3CBRK_DIFFNNAMECNAME_LONGC#BRK_A3CBRK_NAMEC BRK_GROUPCABBREVC. POSTALC;FORMAL_ENC?4FORMAL_FRCs#NAME_CIAWFC-NOTE_ADM0CNOTE_BRKC3NAME_SORTC#NAME_ALTC)MAPCOLOR7N7MAPCOLOR8N8MAPCOLOR9N9MAPCOLOR13N:POP_ESTN= POP_RANKNIPOP_YEARNKGDP_MDNOGDP_YEARNWECONOMYC[INCOME_GRPCuFIPS_10CISO_A2CISO_A2_EHCISO_A3CISO_A3_EHCISO_N3CISO_N3_EHCUN_A3CWB_A2CWB_A3CWOE_IDNWOE_ID_EHNWOE_NOTECADM0_ISOCdADM0_DIFFCgADM0_TLCChADM0_A3_USCkADM0_A3_FRCnADM0_A3_RUCqADM0_A3_ESCtADM0_A3_CNCwADM0_A3_TWCzADM0_A3_INC}ADM0_A3_NPCADM0_A3_PKCADM0_A3_DECADM0_A3_GBCADM0_A3_BRCADM0_A3_ILCADM0_A3_PSCADM0_A3_SACADM0_A3_EGCADM0_A3_MACADM0_A3_PTCADM0_A3_ARCADM0_A3_JPCADM0_A3_KOCADM0_A3_VNCADM0_A3_TRCADM0_A3_IDCADM0_A3_PLCADM0_A3_GRCADM0_A3_ITCADM0_A3_NLCADM0_A3_SECADM0_A3_BDCADM0_A3_UACADM0_A3_UNNADM0_A3_WBNCONTINENTCREGION_UNC SUBREGIONCREGION_WBCNAME_LENN"LONG_LENN$ABBREV_LENN&TINYN(HOMEPARTN+MIN_ZOOMN.MIN_LABELN1MAX_LABELN4LABEL_XN8 LABEL_YNC NE_IDNM WIKIDATAIDCWNAME_ARC_HNAME_BNC}NAME_DEC$.NAME_ENCR,NAME_ESC~,NAME_FACANAME_FRC6NAME_ELC!ONAME_HECpNNAME_HIC{NAME_HUC9pNAME_IDCpNAME_ITC,NAME_JACENNAME_KOC2NAME_NLC.NAME_PLCBNAME_PTC5 +NAME_RUC` ^NAME_SVC -NAME_TRC +NAME_UKC ^NAME_URCt CNAME_VIC 8NAME_ZHC 4NAME_ZHTC# 0FCLASS_ISOCS TLC_DIFFCk FCLASS_TLCCl FCLASS_USC~ FCLASS_FRC FCLASS_RUC FCLASS_ESC FCLASS_CNC FCLASS_TWC FCLASS_INC FCLASS_NPC FCLASS_PKC FCLASS_DEC! FCLASS_GBC0 FCLASS_BRC? FCLASS_ILCK FCLASS_PSCZ FCLASS_SACi FCLASS_EGCx FCLASS_MAC FCLASS_PTC FCLASS_ARC FCLASS_JPC FCLASS_KOC FCLASS_VNC FCLASS_TRC FCLASS_IDC FCLASS_PLC FCLASS_GRC# FCLASS_ITC/ FCLASS_NLC> FCLASS_SECM FCLASS_BDC\ FCLASS_UACt Admin-0 country13ZimbabweZWE02Sovereign country1ZimbabweZWE0ZimbabweZWE0ZimbabweZWE0ZimbabweZimbabweZWEZimbabweZimb.ZWRepublic of ZimbabweZimbabweZimbabwe153 9 14645468.0142019 2144020195. Emerging region: G205. Low incomeZIZWZWZWEZWE716716716ZWZWE2342500423425004Exact WOE match as countryZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWEZWE-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 8 8 5-99 10.02.5 8.0 29.925444-18.9116401159321441Q954زيمبابويজিম্বাবুয়েSimbabweZimbabweZimbabueزیمبابوهZimbabweΖιμπάμπουεזימבבואהज़िम्बाब्वेZimbabweZimbabweZimbabweジンバブエ짐바브웨ZimbabweZimbabweZimbábueЗимбабвеZimbabweZimbabveЗімбабвеزمبابوےZimbabwe津巴布韦辛巴威Admin-0 countryAdmin-0 country Admin-0 country13ZambiaZMB02Sovereign country1ZambiaZMB0ZambiaZMB0ZambiaZMB0ZambiaZambiaZMBZambiaZambiaZMRepublic of ZambiaZambiaZambia585 13 17861030.0142019 2330920197. Least developed region4. Lower middle incomeZAZMZMZMBZMB894894894ZMZMB2342500323425003Exact WOE match as countryZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMBZMB-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 6 6 6-99 10.03.0 8.0 26.395298-14.6608041159321439Q953زامبياজাম্বিয়াSambiaZambiaZambiaزامبیاZambieΖάμπιαזמביהज़ाम्बियाZambiaZambiaZambiaザンビア잠비아ZambiaZambiaZâmbiaЗамбияZambiaZambiyaЗамбіяزیمبیاZambia赞比亚尚比亞Admin-0 countryAdmin-0 country Admin-0 country13YemenYEM02Sovereign country1YemenYEM0YemenYEM0YemenYEM0YemenYemenYEMYemenYem.YERepublic of YemenYemenYemen, Rep.533 11 29161922.0152019 2258120197. Least developed region4. Lower middle incomeYMYEYEYEMYEM887887887RYYEM2342500223425002Exact WOE match as countryYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEMYEM-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 5 5 4-99 10.03.0 8.0 45.874383 15.3282261159321425Q805اليمنইয়েমেনJemenYemenYemenیمنYémenΥεμένηתימןयमनJemenYamanYemenイエメン예멘JemenJemenIémenЙеменJemenYemenЄменیمنYemen也门葉門Admin-0 countryAdmin-0 country Admin-0 country32VietnamVNM02Sovereign country1VietnamVNM0VietnamVNM0VietnamVNM0VietnamVietnamVNMVietnamViet.VNSocialist Republic of VietnamVietnamVietnam565 4 96462106.0162019 26192120195. Emerging region: G204. Lower middle incomeVMVNVNVNMVNM704704704VNVNM2342498423424984Exact WOE match as countryVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNMVNM-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 7 7 5 2 10.02.0 7.0 105.387292 21.7154161159321417Q881فيتنامভিয়েতনামVietnamVietnamVietnamویتنامViêt NamΒιετνάμוייטנאםवियतनामVietnámVietnamVietnamベトナム베트남VietnamWietnamVietnameВьетнамVietnamVietnamВ'єтнамویتنامViệt Nam越南越南Admin-0 countryAdmin-0 country Admin-0 country53VenezuelaVEN02Sovereign country1VenezuelaVEN0VenezuelaVEN0VenezuelaVEN0VenezuelaVenezuelaVENVenezuelaVen.VEBolivarian Republic of VenezuelaRepública Bolivariana de VenezuelaVenezuelaVenezuela, RB131 4 28515829.0152019 48235920145. Emerging region: G203. Upper middle incomeVEVEVEVENVEN862862862VEVEN2342498223424982Exact WOE match as countryVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVENVEN-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 9 9 4-99 10.02.5 7.5 -64.599381 7.1824761159321411Q717فنزويلاভেনেজুয়েলাVenezuelaVenezuelaVenezuelaونزوئلاVenezuelaΒενεζουέλαונצואלהवेनेज़ुएलाVenezuelaVenezuelaVenezuelaベネズエラ베네수엘라VenezuelaWenezuelaVenezuelaВенесуэлаVenezuelaVenezuelaВенесуелаوینیزویلاVenezuela委内瑞拉委內瑞拉Admin-0 countryAdmin-0 country Admin-0 country66VaticanVAT02Sovereign country1VaticanVAT0VaticanVAT0VaticanVAT0VaticanVaticanVATVaticanVat.VState of the Vatican CityHoly See (Vatican City)Vatican (Holy See)Holy See134 2 825.0 22019 -9920192. Developed region: nonG72. High income: nonOECDVTVAVAVATVAT336336336-99-992342498623424986Exact WOE match as countryVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVATVAT-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 7 7 4 4 10.05.010.0 12.453418 41.9033231159321407Q237الفاتيكانভ্যাটিকান সিটিVatikanstadtVatican CityCiudad del VaticanoواتیکانCité du VaticanΒατικανόקריית הוותיקןवैटिकन नगरVatikánVatikanCittà del Vaticanoバチカン바티칸 시국VaticaanstadWatykanVaticanoВатиканVatikanstatenVatikanВатиканویٹیکن سٹیThành Vatican梵蒂冈梵蒂岡Admin-0 countryAdmin-0 country Admin-0 country14VanuatuVUT02Sovereign country1VanuatuVUT0VanuatuVUT0VanuatuVUT0VanuatuVanuatuVUTVanuatuVan.VURepublic of VanuatuVanuatuVanuatu637 3 299882.0102019 93420197. Least developed region4. Lower middle incomeNHVUVUVUTVUT548548548VUVUT2342490723424907Exact WOE match as countryVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUTVUT-99-99OceaniaOceaniaMelanesiaEast Asia & Pacific 7 7 4 2 10.04.0 9.0 166.908762-15.3715301159321421Q686فانواتوভানুয়াতুVanuatuVanuatuVanuatuوانواتوVanuatuΒανουάτουונואטוवानूआटूVanuatuVanuatuVanuatuバヌアツ바누아투VanuatuVanuatuVanuatuВануатуVanuatuVanuatuВануатуوانواتوVanuatu瓦努阿图萬那杜Admin-0 countryAdmin-0 country Admin-0 country13UzbekistanUZB02Sovereign country1UzbekistanUZB0UzbekistanUZB0UzbekistanUZB0UzbekistanUzbekistanUZBUzbekistanUzb.UZRepublic of UzbekistanUzbekistanUzbekistan235 4 33580650.0152019 5792120196. Developing region4. Lower middle incomeUZUZUZUZBUZB860860860UZUZB2342498023424980Exact WOE match as countryUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZBUZB-99-99AsiaAsiaCentral AsiaEurope & Central Asia1010 4 5 10.03.0 8.0 64.005429 41.6936031159321405Q265أوزبكستانউজবেকিস্তানUsbekistanUzbekistanUzbekistánازبکستانOuzbékistanΟυζμπεκιστάνאוזבקיסטןउज़्बेकिस्तानÜzbegisztánUzbekistanUzbekistanウズベキスタン우즈베키스탄OezbekistanUzbekistanUzbequistãoУзбекистанUzbekistanÖzbekistanУзбекистанازبکستانUzbekistan乌兹别克斯坦烏茲別克Admin-0 countryAdmin-0 country Admin-0 country14UruguayURY02Sovereign country1UruguayURY0UruguayURY0UruguayURY0UruguayUruguayURYUruguayUry.UYOriental Republic of UruguayUruguayUruguay122 10 3461734.0122019 5604520195. Emerging region: G203. Upper middle incomeUYUYUYURYURY858858858UYURY2342497923424979Exact WOE match as countryURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURYURY-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 7 7 4-99 10.03.0 8.0 -55.966942-32.9611271159321353Q77الأوروغوايউরুগুয়েUruguayUruguayUruguayاروگوئهUruguayΟυρουγουάηאורוגוואיउरुग्वेUruguayUruguayUruguayウルグアイ우루과이UruguayUrugwajUruguaiУругвайUruguayUruguayУругвайیوراگوئےUruguay乌拉圭烏拉圭Admin-0 countryAdmin-0 country Admin-0 country36Federated States of MicronesiaFSM02Sovereign country1Federated States of MicronesiaFSM0Federated States of MicronesiaFSM0Federated States of MicronesiaFSM0MicronesiaFederated States of MicronesiaFSMMicronesiaF.S.M.FSMFederated States of MicronesiaMicronesia, Federated States ofMicronesia, Federated States of524 13 113815.0 92019 40120186. Developing region4. Lower middle incomeFMFMFMFSMFSM583583583FMFSM2342481523424815Exact WOE match as countryFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSMFSM-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific1030 6-99 10.05.010.0 158.234019 6.8875531159320691Q702ولايات ميكرونيسيا المتحدةমাইক্রোনেশিয়া যুক্তরাজ্যFöderierte Staaten von MikronesienFederated States of MicronesiaEstados Federados de MicronesiaمیکرونزیÉtats fédérés de MicronésieΟμόσπονδες Πολιτείες της Μικρονησίαςמיקרונזיהमाइक्रोनेशिया के संघीकृत राज्यMikronéziai Szövetségi ÁllamokMikronesiaStati Federati di Micronesiaミクロネシア連邦미크로네시아 연방MicronesiaMikronezjaMicronésiaМикронезияMikronesiska federationenMikronezyaМікронезіяمائیکرونیشیاMicronesia密克罗尼西亚联邦密克羅尼西亞聯邦Admin-0 countryAdmin-0 country Admin-0 country56Marshall IslandsMHL02Sovereign country1Marshall IslandsMHL0Marshall IslandsMHL0Marshall IslandsMHL0Marshall Is.Marshall IslandsMHLMarshall Is.M. Is.MHRepublic of the Marshall IslandsMarshall IslandsMarshall Islands255 3 58791.0 82019 22120186. Developing region4. Lower middle incomeRMMHMHMHLMHL584584584MHMHL2342493223424932Exact WOE match as countryMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHLMHL-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific1216 6 2 10.05.010.0 171.193609 7.0825681159321057Q709جزر مارشالমার্শাল দ্বীপপুঞ্জMarshallinselnMarshall IslandsIslas Marshallجزایر مارشالÎles MarshallΝησιά Μάρσαλאיי מרשלमार्शल द्वीपसमूहMarshall-szigetekKepulauan MarshallIsole Marshallマーシャル諸島마셜 제도MarshalleilandenWyspy MarshallaIlhas MarshallМаршалловы ОстроваMarshallöarnaMarshall AdalarıМаршаллові Островиجزائر مارشلQuần đảo Marshall马绍尔群岛馬紹爾群島Admin-0 countryAdmin-0 country Admin-0 country36United States of AmericaUS112Dependency1Northern Mariana IslandsMNP0Northern Mariana IslandsMNP0Northern Mariana IslandsMNP0N. Mariana Is.Northern Mariana IslandsMNPN. Mariana Is.N.M.I.MPCommonwealth of the Northern Mariana IslandsNorthern Mariana IslandsU.S.A.Northern Mariana Islands451 1 57216.0 82019 132320186. Developing region2. High income: nonOECDCQMPMPMNPMNP580580580MPMNP2342478823424788Exact WOE match as countryMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNPMNP-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific1424 6 3-990.05.010.0 145.734397 15.1881881159321361Q16644جزر ماريانا الشماليةউত্তর মারিয়ানা দ্বীপপুঞ্জNördliche MarianenNorthern Mariana IslandsIslas Marianas del Norteجزایر ماریانای شمالیîles Mariannes du NordΒόρειες Μαριάνες Νήσοιאיי מריאנה הצפונייםउत्तरी मारियाना द्वीपÉszaki-Mariana-szigetekKepulauan Mariana UtaraIsole Marianne Settentrionali北マリアナ諸島북마리아나 제도Noordelijke MarianenMariany PółnocneIlhas Marianas do NorteСеверные Марианские островаNordmarianernaKuzey Mariana AdalarıПівнічні Маріанські островиجزائر شمالی ماریاناQuần đảo Bắc Mariana北马里亚纳群岛北馬里亞納群島Admin-0 dependencyAdmin-0 dependency Admin-0 country36United States of AmericaUS112Dependency1United States Virgin IslandsVIR0United States Virgin IslandsVIR0United States Virgin IslandsVIR0U.S. Virgin Is.United States Virgin IslandsVIRU.S. Virgin Is.V.I. (U.S.)VIVirgin Islands of the United StatesVirgin IslandsU.S.A.Virgin Islands (U.S.)451 1 106631.0 92019 385520176. Developing region2. High income: nonOECDVQVIVIVIRVIR850850850VIVIR2342498523424985Exact WOE match as countryVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIRVIR-99-99North AmericaAmericasCaribbeanLatin America & Caribbean152811 3-990.05.010.0 -64.779172 17.7467061159321371Q11703جزر العذراء الأمريكيةমার্কিন ভার্জিন দ্বীপপুঞ্জAmerikanische JungferninselnUnited States Virgin IslandsIslas Vírgenes de los Estados Unidosجزایر ویرجین ایالات متحدهîles Vierges des États-UnisΑμερικανικές Παρθένοι Νήσοιאיי הבתולה של ארצות הבריתसंयुक्त राज्य वर्जिन द्वीपसमूहAmerikai Virgin-szigetekKepulauan Virgin Amerika SerikatIsole Vergini americaneアメリカ領ヴァージン諸島미국령 버진아일랜드Amerikaanse MaagdeneilandenWyspy Dziewicze Stanów ZjednoczonychIlhas Virgens AmericanasАмериканские Виргинские островаAmerikanska JungfruöarnaABD Virjin AdalarıАмериканські Віргінські Островиامریکی جزائر ورجنQuần đảo Virgin thuộc Mỹ美属维尔京群岛美屬維京群島Admin-0 dependencyAdmin-0 dependency Admin-0 country36United States of AmericaUS112Dependency1GuamGUM0GuamGUM0GuamGUM0GuamGuamGUMGuamGuamGUTerritory of GuamGuamU.S.A.Guam451 1 167294.0 92019 592020186. Developing region2. High income: nonOECDGQGUGUGUMGUM316316316GUGUM2342483223424832Exact WOE match as countryGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUMGUM-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific 4 4 4 2-990.03.010.0 144.703614 13.3541731159321359Q16635غوامগুয়ামGuamGuamGuamگوآمGuamΓκουάμגואםगुआमGuamGuamGuamグアム괌GuamGuamGuamГуамGuamGuamГуамگوامGuam关岛關島Admin-0 dependencyAdmin-0 dependency Admin-0 country34United States of AmericaUS112Dependency1American SamoaASM0American SamoaASM0American SamoaASM0American SamoaAmerican SamoaASMAmerican SamoaAm. SamoaASAmerican SamoaAmerican SamoaU.S.A.American Samoa451 1 55312.0 82019 63620186. Developing region3. Upper middle incomeAQASASASMASM016016016ASASM2342474623424746Exact WOE match as countryASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASMASM-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific1414 9 3-990.04.0 9.0-170.747153-14.3267101159321357Q16641ساموا الأمريكيةমার্কিন সামোয়াAmerikanisch-SamoaAmerican SamoaSamoa Estadounidenseساموآی آمریکاSamoa américainesΑμερικανική Σαμόαסמואה האמריקניתअमेरिकी समोआAmerikai SzamoaSamoa AmerikaSamoa Americaneアメリカ領サモア아메리칸사모아Amerikaans-SamoaSamoa AmerykańskieSamoa AmericanaАмериканское СамоаAmerikanska SamoaAmerikan SamoasıСхідне Самоаامریکی سموواSamoa thuộc Mỹ美属萨摩亚美屬薩摩亞Admin-0 dependencyAdmin-0 dependency Admin-0 country15United States of AmericaUS112Dependency1Puerto RicoPRI0Puerto RicoPRI0Puerto RicoPRI0Puerto RicoPuerto RicoPRIPuerto RicoP.R.PRCommonwealth of Puerto RicoPuerto RicoU.S.A.Puerto Rico451 1 3193694.0122019 10498820196. Developing region2. High income: nonOECDRQPRPRPRIPRI630630630PRPRI2342493523424935Exact WOE match as countryPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRIPRI-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1111 4-99-990.03.0 8.0 -66.481065 18.2346681159321363Q1183بورتوريكوপুয়ের্তো রিকোPuerto RicoPuerto RicoPuerto RicoپورتوریکوPorto RicoΠουέρτο Ρίκοפוארטו ריקוपोर्टो रीकोPuerto RicoPuerto RikoPorto Ricoプエルトリコ푸에르토리코Puerto RicoPortorykoPorto RicoПуэрто-РикоPuerto RicoPorto RikoПуерто-Рикоپورٹو ریکوPuerto Rico波多黎各波多黎各Admin-0 dependencyAdmin-0 dependency Admin-0 country52United States of AmericaUS112Country1United States of AmericaUSA0United States of AmericaUSA0United StatesUSA0United States of AmericaUnited StatesUSAUnited StatesU.S.A.USUnited States of AmericaUnited StatesUnited States of America451 1 328239523.01720192143322620191. Developed region: G71. High income: OECDUSUSUSUSAUSA840840840USUSA2342497723424977Exact WOE match as countryUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSA-99-99North AmericaAmericasNorthern AmericaNorth America2413 6-99 10.01.7 5.7 -97.482602 39.5384791159321369Q30الولايات المتحدةমার্কিন যুক্তরাষ্ট্রVereinigte StaatenUnited States of AmericaEstados Unidosایالات متحده آمریکاÉtats-UnisΗνωμένες Πολιτείες Αμερικήςארצות הבריתसंयुक्त राज्य अमेरिकाAmerikai Egyesült ÁllamokAmerika SerikatStati Uniti d'Americaアメリカ合衆国미국Verenigde Staten van AmerikaStany ZjednoczoneEstados UnidosСШАUSAAmerika Birleşik DevletleriСполучені Штати Америкиریاستہائے متحدہ امریکاHoa Kỳ美国美國Admin-0 countryAdmin-0 country Admin-0 country34United KingdomGB112Dependency1South Georgia and the IslandsSGS0South Georgia and the IslandsSGS0South Georgia and the IslandsSGS0S. Geo. and the Is.South Georgia and the IslandsSGSS. Geo. and the Is.S.G. & Is.GSSouth Georgia and the IslandsU.K.South Georgia and the Islands666 3 30.0 12017 020167. Least developed region5. Low incomeSXGSGSSGSSGS239239-099-99-992342495523424955Exact WOE match as countrySGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGSSGS-99-99Seven seas (open ocean)AmericasSeven seas (open ocean)Antarctica192910 3-990.05.0 9.0 -31.063179-55.6834021159320731Q35086جورجيا الجنوبية وجزر ساندويتش الجنوبيةদক্ষিণ জর্জিয়া ও দক্ষিণ স্যন্ডউইচ দ্বীপপুঞ্জSüdgeorgien und die Südlichen SandwichinselnSouth Georgia and the South Sandwich IslandsIslas Georgias del Sur y Sandwich del Surجزایر جورجیای جنوبی و ساندویچ جنوبیGéorgie du Sud-et-les Îles Sandwich du SudΝήσοι Νότια Γεωργία και Νότιες Σάντουιτςאיי ג'ורג'יה הדרומית ואיי סנדוויץ' הדרומייםदक्षिण जॉर्जिया एवं दक्षिण सैंडविच द्वीप समूहDéli-Georgia és Déli-Sandwich-szigetekGeorgia Selatan dan Kepulauan Sandwich SelatanGeorgia del Sud e isole Sandwich meridionaliサウスジョージア・サウスサンドウィッチ諸島사우스조지아 사우스샌드위치 제도Zuid-Georgia en de Zuidelijke SandwicheilandenGeorgia Południowa i Sandwich PołudniowyIlhas Geórgia do Sul e Sandwich do SulЮжная Георгия и Южные Сандвичевы островаSydgeorgien och SydsandwichöarnaGüney Georgia ve Güney Sandwich AdalarıПівденна Джорджія та Південні Сандвічеві островиجنوبی جارجیا و جزائر جنوبی سینڈوچNam Georgia và Quần đảo Nam Sandwich南乔治亚和南桑威奇群岛南喬治亞與南桑威奇Admin-0 dependencyAdmin-0 dependencyUnrecognized Admin-0 country35United KingdomGB112Disputed1British Indian Ocean TerritoryIOT0British Indian Ocean TerritoryIOT0British Indian Ocean TerritoryIOT1Br. Indian Ocean Ter.British Indian Ocean TerritoryB69Br. Indian Ocean Ter.I.O.T.IOU.K.Admin. by U.K.; Claimed by Mauritius and SeychellesBritish Indian Ocean Territory666 3 3000.0 42018 12020132. Developed region: nonG72. High income: nonOECDIOIOIOIOTIOT086086-099-99-992342484923424849Exact WOE match as countryB69B69IOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOTIOT-99-99Seven seas (open ocean)AfricaSeven seas (open ocean)Sub-Saharan Africa2130 6 5-990.05.0 9.5 71.348349 -6.1908261159320723Q43448إقليم المحيط الهندي البريطانيব্রিটিশ ভারত মহাসাগরীয় এলাকাBritisches Territorium im Indischen OzeanBritish Indian Ocean TerritoryTerritorio Británico del Océano Índicoقلمرو بریتانیا در اقیانوس هندTerritoire britannique de l’océan IndienΒρετανικό Έδαφος Ινδικού Ωκεανούהטריטוריה הבריטית באוקיינוס ההודיब्रिटिश हिंद महासागर क्षेत्रBrit Indiai-óceáni TerületWilayah Samudra Hindia BritaniaTerritorio britannico dell'oceano Indianoイギリス領インド洋地域영국령 인도양 지역Brits Indische OceaanterritoriumBrytyjskie Terytorium Oceanu IndyjskiegoTerritório Britânico do Oceano ÍndicoБританская территория в Индийском океанеBrittiska territoriet i Indiska oceanenBritanya Hint Okyanusu TopraklarıБританська територія в Індійському океаніبرطانوی بحرہند کا خطہLãnh thổ Ấn Độ Dương thuộc Anh英属印度洋领地英屬印度洋領地Admin-0 dependencyAdmin-0 dependency Admin-0 country36United KingdomGB112Dependency1Saint HelenaSHN0Saint HelenaSHN0Saint HelenaSHN0Saint HelenaSaint HelenaSHNSaint HelenaSt.H.SHSaint Helena, Ascension, and Tristan da CunhaU.K.St. Helena666 3 4534.0 42016 3120106. Developing region4. Lower middle incomeSHSHSHSHNSHN654654654-99-992342494423424944Exact WOE match as countrySHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHNSHN-99-99Seven seas (open ocean)AfricaWestern AfricaSub-Saharan Africa1212 5-99-990.05.010.0 -5.712620-15.9504871159320733Q192184سانت هيلانة وأسينشين وتريستان دا كوناসেন্ট হেলেনা, অ্যাসেনশন এবং ত্রস্তান দা কুনহাSt. Helena, Ascension und Tristan da CunhaSaint Helena, Ascension and Tristan da CunhaSanta Elena, Ascensión y Tristán de Acuñaسنت هلنا، اسنشن و تریستان دا کوناSainte-Hélène, Ascension et Tristan da CunhaΑγία Ελένη, Ασενσιόν και Τριστάν ντα Κούνιαסנט הלנה, אסנשן וטריסטן דה קונהसेंट हेलेना, असेंशन और त्रिस्तान दा कुन्हासेंट हेलेना, असेंशन और त्रिस्तान दा कुन्हासेंट हेलेना, असेंशन और त्रिस्तान दा कुन्हाSant'Elena, Ascensione e Tristan da Cunhaセントヘレナ・アセンションおよびトリスタンダクーニャ세인트헬레나 어센션 트리스탄다쿠냐Sint-Helena, Ascension en Tristan da CunhaWyspa Świętej Heleny, Wyspa Wniebowstąpienia i Tristan da CunhaSanta Helena, Ascensão e Tristão da CunhaОстрова Святой Елены, Вознесения и Тристан-да-КуньяSankta Helena, Ascension och Tristan da CunhaSaint Helena, Ascension ve Tristan da CunhaОстрови Святої Єлени, Вознесіння і Тристан-да-Куньяسینٹ ہلینا، اسینشن و ترسٹان دا کونیاSaint Helena, Ascension và Tristan da Cunha圣赫勒拿、阿森松和特里斯坦-达库尼亚聖赫勒拿、亞森欣與崔斯坦達庫尼亞Admin-0 dependencyAdmin-0 dependency Admin-0 country34United KingdomGB112Dependency1Pitcairn IslandsPCN0Pitcairn IslandsPCN0Pitcairn IslandsPCN0Pitcairn Is.Pitcairn IslandsPCNPitcairn Is.Pit. Is.PNPitcairn, Henderson, Ducie and Oeno IslandsPitcairn IslandsU.K.Pitcairn Islands666 3 54.0 12016 020167. Least developed region5. Low incomePCPNPNPCNPCN612612612-99-992342491823424918Exact WOE match as countryPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCNPCN-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific1216 8-99-990.05.0 9.0-128.317536-24.3645761159320729Q35672جزر بيتكيرنপীটকেয়ার্ন দ্বীপপুঞ্জPitcairninselnPitcairn IslandsIslas Pitcairnجزایر پیتکرنIles PitcairnΝήσοι Πίτκερνפיטקרןपिटकेर्न द्वीपसमूहPitcairn-szigetekKepulauan PitcairnIsole Pitcairnピトケアン諸島핏케언 제도PitcairneilandenPitcairnIlhas PitcairnОстрова ПиткэрнPitcairnöarnaPitcairn AdalarıПіткернجزائر پٹکیرنQuần đảo Pitcairn皮特凯恩群岛皮特肯群島Admin-0 dependencyAdmin-0 dependency Admin-0 country16United KingdomGB112Dependency1AnguillaAIA0AnguillaAIA0AnguillaAIA0AnguillaAnguillaAIAAnguillaAng.AIAnguillaU.K.Anguilla666 3 14731.0 62018 17520096. Developing region3. Upper middle incomeAVAIAIAIAAIA660660660-99-992342475123424751Exact WOE match as countryAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIAAIA-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 8 8 4-99-990.05.010.0 -63.026361 18.2429791159320703Q25228أنغويلاএ্যাঙ্গুইলাAnguillaAnguillaAnguilaآنگویلاAnguillaΑνγκουίλαאנגווילהअंगुइलाAnguillaAnguillaAnguillaアンギラ앵귈라AnguillaAnguillaAnguillaАнгильяAnguillaAnguillaАнгільяاینگویلاAnguilla安圭拉安吉拉Admin-0 dependencyAdmin-0 dependency Admin-0 country15United KingdomGB112Disputed1Falkland IslandsFLK0Falkland IslandsFLK0Falkland IslandsFLK1Falkland Is.Falkland Islands / MalvinasB12Falkland Is.Flk. Is.FKFalkland IslandsFalkland Islands (Islas Malvinas)U.K.Admin. by U.K.; Claimed by ArgentinaFalkland IslandsIslas Malvinas666 3 3398.0 42016 28220122. Developed region: nonG71. High income: OECDFKFKFKFLKFLK238238238-99-992342481423424814Exact WOE match as countryB12B12FLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKARGFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLKFLK-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean1227 8-99-990.04.5 9.0 -58.738602-51.6089131159320711Q9648جزر فوكلاندফকল্যান্ড দ্বীপপুঞ্জFalklandinselnFalkland IslandsIslas Malvinasجزایر فالکلندîles MalouinesΝήσοι Φώκλαντאיי פוקלנדफ़ॉकलैंड द्वीपसमूहFalkland-szigetekKepulauan FalklandIsole Falklandフォークランド諸島포클랜드 제도FalklandeilandenFalklandyIlhas MalvinasФолклендские островаFalklandsöarnaFalkland AdalarıФолклендські островиجزائر فاکلینڈQuần đảo Falkland福克兰群岛福克蘭群島Admin-0 dependencyAdmin-0 dependencyUnrecognized Admin-0 country15United KingdomGB112Dependency1Cayman IslandsCYM0Cayman IslandsCYM0Cayman IslandsCYM0Cayman Is.Cayman IslandsCYMCayman Is.Cym. Is.KYCayman IslandsCayman IslandsU.K.Cayman Islands666 3 64948.0 82019 551720185. Emerging region: G202. High income: nonOECDCJKYKYCYMCYM136136136KYCYM2342478323424783Exact WOE match as countryCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYMCYM-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1014 8 2-990.05.0 9.5 -81.240550 19.3198621159320707Q5785جزر كايمانকেইম্যান দ্বীপপুঞ্জCayman IslandsCayman IslandsIslas Caimánجزایر کیمنîles CaïmansΝησιά Καϋμάνאיי קיימןकेमन द्वीपसमूहKajmán-szigetekKepulauan CaymanIsole Caymanケイマン諸島케이맨 제도KaaimaneilandenKajmanyIlhas Caimãoострова КайманCaymanöarnaCayman AdalarıКайманові островиجزائر کیمینQuần đảo Cayman开曼群岛開曼群島Admin-0 dependencyAdmin-0 dependency Admin-0 country36United KingdomGB112Dependency1BermudaBMU0BermudaBMU0BermudaBMU0BermudaBermudaBMUBermudaBerm.BMThe Bermudas or Somers IslesBermudaU.K.Bermuda666 3 63918.0 82019 748420192. Developed region: nonG72. High income: nonOECDBDBMBMBMUBMU060060060BMBMU2342475623424756Exact WOE match as countryBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMUBMU-99-99North AmericaAmericasNorthern AmericaNorth America 7 7 5 4-990.04.0 9.0 -64.763573 32.2965921159320705Q23635برموداবারমুডাBermudaBermudaBermudasبرموداBermudesΒερμούδεςברמודהबरमूडाBermudaBermudaBermudaバミューダ諸島버뮤다BermudaBermudyBermudasБермудские ОстроваBermudaBermudaБермудські островиبرموداBermuda百慕大百慕達Admin-0 dependencyAdmin-0 dependency Admin-0 country36United KingdomGB112Dependency1British Virgin IslandsVGB0British Virgin IslandsVGB0British Virgin IslandsVGB0British Virgin Is.British Virgin IslandsVGBBritish Virgin Is.V.I. (Br.)VGBritish Virgin IslandsBritish Virgin IslandsU.K.British Virgin Islands666 3 30030.0 72019 50020172. Developed region: nonG71. High income: OECDVIVGVGVGBVGB092092092-99-992342498323424983Exact WOE match as countryVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGBVGB-99-99North AmericaAmericasCaribbeanLatin America & Caribbean182210 3-990.05.0 9.5 -64.636610 18.4266061159320739Q25305جزر العذراء البريطانيةব্রিটিশ ভার্জিন দ্বীপপুঞ্জBritische JungferninselnBritish Virgin IslandsIslas Vírgenes Británicasجزایر ویرجین بریتانیاîles Vierges britanniquesΒρετανικές Παρθένοι Νήσοιאיי הבתולה הבריטייםब्रिटिश वर्जिन द्वीपसमूहBrit Virgin-szigetekKepulauan Virgin Britania RayaIsole Vergini britannicheイギリス領ヴァージン諸島영국령 버진아일랜드Britse MaagdeneilandenBrytyjskie Wyspy DziewiczeIlhas Virgens BritânicasБританские Виргинские островаBrittiska JungfruöarnaBritanya Virjin AdalarıБританські Віргінські островиبرطانوی جزائر ورجنQuần đảo Virgin thuộc Anh英属维尔京群岛英屬維京群島Admin-0 dependencyAdmin-0 dependency Admin-0 country36United KingdomGB112Dependency1Turks and Caicos IslandsTCA0Turks and Caicos IslandsTCA0Turks and Caicos IslandsTCA0Turks and Caicos Is.Turks and Caicos IslandsTCATurks and Caicos Is.T.C. Is.TCTurks and Caicos IslandsTurks and Caicos IslandsU.K.Turks and Caicos Islands666 3 38191.0 72019 119720196. Developing region2. High income: nonOECDTKTCTCTCATCA796796796TCTCA2342496223424962Exact WOE match as countryTCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCA-99-99North AmericaAmericasCaribbeanLatin America & Caribbean2024 8-99-990.05.010.0 -71.752704 21.8166301159320737Q18221جزر توركس وكايكوسটার্কস ও কেইকোস দ্বীপপুঞ্জTurks- und CaicosinselnTurks and Caicos IslandsIslas Turcas y Caicosجزایر تورکس و کایکوسîles Turques-et-CaïquesΤερκ και Κάικοςאיי טרקס וקייקוסतुर्क और केकोस द्वीपसमूहTurks- és Caicos-szigetekKepulauan Turks dan CaicosTurks e Caicosタークス・カイコス諸島터크스 케이커스 제도Turks- en CaicoseilandenTurks i CaicosTurks e CaicosТёркс и КайкосTurks- och CaicosöarnaTurks ve Caicos AdalarıОстрови Теркс і Кайкосجزائر کیکس و ترکیہQuần đảo Turks và Caicos特克斯和凯科斯群岛土克凱可群島Admin-0 dependencyAdmin-0 dependency Admin-0 country36United KingdomGB112Dependency1MontserratMSR0MontserratMSR0MontserratMSR0MontserratMontserratMSRMontserratMonts.MSMontserratU.K.Montserrat666 3 4649.0 42019 4420066. Developing region4. Lower middle incomeMHMSMSMSRMSR500500500-99-992342488823424888Exact WOE match as countryMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSRMSR-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1010 6 6-990.05.010.0 -62.188252 16.7371701159320727Q13353مونتسراتমন্টসেরাটMontserratMontserratMontserratمونتسراتMontserratΜοντσερράτמונטסראטमॉण्टसेराटMontserratMontserratMontserratモントセラト몬트세랫MontserratMontserratMontserratМонтсерратMontserratMontserratМонтсерратمانٹسریٹMontserrat蒙特塞拉特蒙哲臘Admin-0 dependencyAdmin-0 dependency Admin-0 country46United KingdomGB112Country1JerseyJEY0JerseyJEY0JerseyJEY0JerseyJerseyJEYJerseyChannel IslandsJey.JEBailiwick of JerseyJerseyU.K.U.K. crown dependencyJersey666 3 107800.0 92019 508020152. Developed region: nonG72. High income: nonOECDJEJEJEJEYJEY832832832JGCHI2342485723424857Exact WOE match as countryJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEYJEY-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 6 6 4-99-990.05.010.0 -2.090146 49.2208081159320725Q785جيرزيজার্সিJerseyJerseyJerseyجرزیJerseyΤζέρσεϊג'רזיजर्सीJerseyJerseybaliato di Jerseyジャージー저지섬JerseyJerseyJerseyДжерсиJerseyJerseyДжерсіجرزیJersey泽西澤西Admin-0 countryAdmin-0 country Admin-0 country46United KingdomGB112Country1GuernseyGGY0GuernseyGGY0GuernseyGGY0GuernseyGuernseyGGYGuernseyChannel IslandsGuern.GGBailiwick of GuernseyGuernseyU.K.U.K. crown dependencyGuernsey666 3 62792.0 82019 346520152. Developed region: nonG72. High income: nonOECDGKGGGGGGYGGY831831831JGCHI2342482723424827Exact WOE match as countryGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGYGGY-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 8 8 6-99-990.05.010.0 -2.561736 49.4635331159320715Q25230غيرنزيগার্নসিGuernseyGuernseyGuernseyگرنزیGuerneseyΓκέρνσεϊגרנזיग्वेर्नसेGuernsey BailiffségGuernseyGuernseyガーンジー건지섬GuernseyGuernseyGuernseyГернсиGuernseyGuernseyГернсіگرنزیGuernsey根西根西Admin-0 countryAdmin-0 country Admin-0 country36United KingdomGB112Country1Isle of ManIMN0Isle of ManIMN0Isle of ManIMN0Isle of ManIsle of ManIMNIsle of ManIoManIMIsle of ManU.K.U.K. crown dependencyIsle of Man666 3 84584.0 82019 749120182. Developed region: nonG72. High income: nonOECDIMIMIMIMNIMN833833833IMIMY2342484723424847Exact WOE match as countryIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMNIMN-99-99EuropeEuropeNorthern EuropeEurope & Central Asia1111 5-99-990.05.010.0 -4.530069 54.2208331159320721Q9676جزيرة مانআইল অব ম্যানIsle of ManIsle of ManIsla de Manجزیره منîle de ManΝήσος του Μανהאי מאןआइल ऑफ़ मैनManPulau ManIsola di Manマン島맨섬ManWyspa ManIlha de Manостров МэнIsle of ManMan AdasıОстрів Менآئل آف مینĐảo Man马恩岛曼島Admin-0 countryAdmin-0 country Admin-0 country12United KingdomGB112Country1United KingdomGBR0United KingdomGBR0United KingdomGBR0United KingdomUnited KingdomGBRUnited KingdomU.K.GBUnited Kingdom of Great Britain and Northern IrelandUnited KingdomUnited Kingdom666 3 66834405.0162019 282910820191. Developed region: G71. High income: OECDUKGBGBGBRGBR826826826GBGBR -9023424975Eh ID includes Channel Islands and Isle of Man. UK constituent countries of England (24554868), Wales (12578049), Scotland (12578048), and Northern Ireland (20070563).GBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBRGBR-99-99EuropeEuropeNorthern EuropeEurope & Central Asia1414 4-99 10.01.7 6.7 -2.116346 54.4027391159320713Q145المملكة المتحدةযুক্তরাজ্যVereinigtes KönigreichUnited KingdomReino UnidoبریتانیاRoyaume-UniΗνωμένο Βασίλειοהממלכה המאוחדתयूनाइटेड किंगडमEgyesült KirályságBritania RayaRegno Unitoイギリス영국Verenigd KoninkrijkWielka BrytaniaReino UnidoВеликобританияStorbritannienBirleşik KrallıkВелика Британіяمملکت متحدہVương quốc Liên hiệp Anh và Bắc Ireland英国英國Admin-0 countryAdmin-0 country Admin-0 country14United Arab EmiratesARE02Sovereign country1United Arab EmiratesARE0United Arab EmiratesARE0United Arab EmiratesARE0United Arab EmiratesUnited Arab EmiratesAREUnited Arab EmiratesU.A.E.AEUnited Arab EmiratesUnited Arab EmiratesUnited Arab Emirates213 3 9770529.0132019 42114220196. Developing region2. High income: nonOECDAEAEAEAREARE784784784AEARE2342473823424738Exact WOE match as countryAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREAREARE-99-99AsiaAsiaWestern AsiaMiddle East & North Africa2020 6-99 10.04.0 9.0 54.547256 23.4662851159320329Q878الإمارات العربية المتحدةসংযুক্ত আরব আমিরাতVereinigte Arabische EmirateUnited Arab EmiratesEmiratos Árabes Unidosامارات متحده عربیÉmirats arabes unisΗνωμένα Αραβικά Εμιράταאיחוד האמירויות הערביותसंयुक्त अरब अमीरातEgyesült Arab EmírségekUni Emirat ArabEmirati Arabi Unitiアラブ首長国連邦아랍에미리트Verenigde Arabische EmiratenZjednoczone Emiraty ArabskieEmirados Árabes UnidosОбъединённые Арабские ЭмиратыFörenade ArabemiratenBirleşik Arap EmirlikleriОб'єднані Арабські Еміратиمتحدہ عرب اماراتCác Tiểu vương quốc Ả Rập Thống nhất阿拉伯联合酋长国阿拉伯聯合大公國Admin-0 countryAdmin-0 country Admin-0 country13UkraineUKR02Sovereign country1UkraineUKR0UkraineUKR0UkraineUKR0UkraineUkraineUKRUkraineUkr.UAUkraineUkraineUkraine516 3 44385155.0152019 15378120196. Developing region4. Lower middle incomeUPUAUAUKRUKR804804804UAUKR2342497623424976Exact WOE match as countryUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKRUKR-99-99EuropeEuropeEastern EuropeEurope & Central Asia 7 7 4-99 10.02.7 7.0 32.140865 49.7247391159321345Q212أوكرانياইউক্রেনUkraineUkraineUcraniaاوکراینUkraineΟυκρανίαאוקראינהयुक्रेनUkrajnaUkrainaUcrainaウクライナ우크라이나OekraïneUkrainaUcrâniaУкраинаUkrainaUkraynaУкраїнаیوکرینUkraina乌克兰烏克蘭Admin-0 countryAdmin-0 country Admin-0 country13UgandaUGA02Sovereign country1UgandaUGA0UgandaUGA0UgandaUGA0UgandaUgandaUGAUgandaUga.UGRepublic of UgandaUgandaUganda636 4 44269594.0152019 3516520197. Least developed region5. Low incomeUGUGUGUGAUGA800800800UGUGA2342497423424974Exact WOE match as countryUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGAUGA-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 6 6 4-99 10.03.0 8.0 32.948555 1.9725891159321343Q1036أوغنداউগান্ডাUgandaUgandaUgandaاوگانداOugandaΟυγκάνταאוגנדהयुगाण्डाUgandaUgandaUgandaウガンダ우간다OegandaUgandaUgandaУгандаUgandaUgandaУгандаیوگنڈاUganda乌干达烏干達Admin-0 countryAdmin-0 country Admin-0 country44TurkmenistanTKM02Sovereign country1TurkmenistanTKM0TurkmenistanTKM0TurkmenistanTKM0TurkmenistanTurkmenistanTKMTurkmenistanTurkm.TMTurkmenistanTurkmenistanTurkmenistan321 9 5942089.0132019 4076120186. Developing region3. Upper middle incomeTXTMTMTKMTKM795795795TMTKM2342497223424972Exact WOE match as countryTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKMTKM-99-99AsiaAsiaCentral AsiaEurope & Central Asia1212 6-99 10.03.0 8.0 58.676647 39.8552461159321309Q874تركمانستانতুর্কমেনিস্তানTurkmenistanTurkmenistanTurkmenistánترکمنستانTurkménistanΤουρκμενιστάνטורקמניסטןतुर्कमेनिस्तानTürkmenisztánTurkmenistanTurkmenistanトルクメニスタン투르크메니스탄TurkmenistanTurkmenistanTurquemenistãoТуркменияTurkmenistanTürkmenistanТуркменістанترکمانستانTurkmenistan土库曼斯坦土庫曼Admin-0 countryAdmin-0 country Admin-0 country32TurkeyTUR02Sovereign country1TurkeyTUR0TurkeyTUR0TurkeyTUR0TurkeyTurkeyTURTurkeyTur.TRRepublic of TurkeyTurkeyTurkey638 4 83429615.0162019 76142520194. Emerging region: MIKT3. Upper middle incomeTUTRTRTURTUR792792792TRTUR2342496923424969Exact WOE match as countryTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTURTUR-99-99AsiaAsiaWestern AsiaEurope & Central Asia 6 6 4-99 10.02.0 7.0 34.508268 39.3453881159321331Q43تركياতুরস্কTürkeiTurkeyTurquíaترکیهTurquieΤουρκίαטורקיהतुर्कीTörökországTurkiTurchiaトルコ터키TurkijeTurcjaTurquiaТурцияTurkietTürkiyeТуреччинаترکیThổ Nhĩ Kỳ土耳其土耳其Admin-0 countryAdmin-0 country Admin-0 country13TunisiaTUN02Sovereign country1TunisiaTUN0TunisiaTUN0TunisiaTUN0TunisiaTunisiaTUNTunisiaTun.TNRepublic of TunisiaTunisiaTunisia433 2 11694719.0142019 3879620196. Developing region3. Upper middle incomeTSTNTNTUNTUN788788788TNTUN2342496723424967Exact WOE match as countryTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUNTUN-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 7 7 4-99 10.03.0 8.0 9.007881 33.6872631159321327Q948تونسতিউনিসিয়াTunesienTunisiaTúnezتونسTunisieΤυνησίαתוניסיהट्यूनिशियाTunéziaTunisiaTunisiaチュニジア튀니지TunesiëTunezjaTunísiaТунисTunisienTunusТунісتونسTuy-ni-di突尼斯突尼西亞Admin-0 countryAdmin-0 country Admin-0 country35Trinidad and TobagoTTO02Sovereign country1Trinidad and TobagoTTO0Trinidad and TobagoTTO0Trinidad and TobagoTTO0Trinidad and TobagoTrinidad and TobagoTTOTrinidad and TobagoTr.T.TTRepublic of Trinidad and TobagoTrinidad and TobagoTrinidad and Tobago562 5 1394973.0122019 2426920196. Developing region2. High income: nonOECDTDTTTTTTOTTO780780780TTTTO2342495823424958Exact WOE match as countryTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTOTTO-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1919 5 2 10.04.5 9.5 -60.918400 10.9989001159321321Q754ترينيداد وتوباغوত্রিনিদাদ ও টোবাগোTrinidad und TobagoTrinidad and TobagoTrinidad y Tobagoترینیداد و توباگوTrinité-et-TobagoΤρινιντάντ και Τομπάγκοטרינידד וטובגוत्रिनिदाद और टोबैगोTrinidad és TobagoTrinidad dan TobagoTrinidad e Tobagoトリニダード・トバゴ트리니다드 토바고Trinidad en TobagoTrynidad i TobagoTrinidad e TobagoТринидад и ТобагоTrinidad och TobagoTrinidad ve TobagoТринідад і Тобагоٹرینیڈاڈ و ٹوباگوTrinidad và Tobago特立尼达和多巴哥千里達及托巴哥Admin-0 countryAdmin-0 country Admin-0 country34TongaTON02Sovereign country1TongaTON0TongaTON0TongaTON0TongaTongaTONTongaTongoTOKingdom of TongaTongaTonga211 8 104494.0 92019 51220196. Developing region4. Lower middle incomeTNTOTOTONTON776776776TOTON2342496423424964Exact WOE match as countryTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTONTON-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific 5 5 5 3 10.04.0 9.0-175.163014-21.2100261159321319Q678تونغاটোঙ্গাTongaTongaTongaتونگاTongaΤόνγκαטונגהटोंगाTongaTongaTongaトンガ통가TongaTongaTongaТонгаTongaTongaТонгаٹونگاTonga汤加東加Admin-0 countryAdmin-0 country Admin-0 country16TogoTGO02Sovereign country1TogoTGO0TogoTGO0TogoTGO0TogoTogoTGOTogoTogoTGTogolese RepublicRépublique TogolaiseTogoTogo313 5 8082366.0132019 549020197. Least developed region5. Low incomeTOTGTGTGOTGO768768768TGTGO2342496523424965Exact WOE match as countryTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGOTGO-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 4 4 4-99 10.05.010.0 1.058113 8.8072201159321303Q945توغوটোগোTogoTogoTogoتوگوTogoΤόγκοטוגוटोगोTogoTogoTogoトーゴ토고TogoTogoTogoТогоTogoTogoТогоٹوگوTogo多哥多哥Admin-0 countryAdmin-0 country Admin-0 country45East TimorTLS02Sovereign country1East TimorTLS0East TimorTLS0East TimorTLS0Timor-LesteTimor-LesteTLSTimor-LesteT.L.TLDemocratic Republic of Timor-LesteTimor-LesteTimor-LesteEast Timor224 3 1293119.0122019 201720197. Least developed region4. Lower middle incomeTTTLTLTLSTLS626626626TPTMP2342496823424968Exact WOE match as countryTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLSTLS-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific1111 4-99 10.04.0 9.0 125.854679 -8.8037051159321313Q574تيمور الشرقيةপূর্ব তিমুরOsttimorEast TimorTimor Orientalتیمور شرقیTimor orientalΑνατολικό Τιμόρמזרח טימורपूर्वी तिमोरKelet-TimorTimor LesteTimor Est東ティモール동티모르Oost-TimorTimor WschodniTimor-LesteВосточный ТиморÖsttimorDoğu TimorСхідний Тиморمشرقی تیمورĐông Timor东帝汶東帝汶Admin-0 countryAdmin-0 country Admin-0 country43ThailandTHA02Sovereign country1ThailandTHA0ThailandTHA0ThailandTHA0ThailandThailandTHAThailandThai.THKingdom of ThailandThailandThailand368 1 69625582.0162019 54354820195. Emerging region: G203. Upper middle incomeTHTHTHTHATHA764764764THTHA2342496023424960Exact WOE match as countryTHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHATHA-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 8 8 5-99 10.02.7 8.0 101.073198 15.4597401159321305Q869تايلاندথাইল্যান্ডThailandThailandTailandiaتایلندThaïlandeΤαϊλάνδηתאילנדथाईलैण्डThaiföldThailandThailandiaタイ王国태국ThailandTajlandiaTailândiaТаиландThailandTaylandТаїландتھائی لینڈThái Lan泰国泰國Admin-0 countryAdmin-0 country Admin-0 country33United Republic of TanzaniaTZA02Sovereign country1United Republic of TanzaniaTZA0TanzaniaTZA0TanzaniaTZA0TanzaniaTanzaniaTZATanzaniaTanz.TZUnited Republic of TanzaniaTanzaniaTanzania362 2 58005463.0162019 6317720197. Least developed region5. Low incomeTZTZTZTZATZA834834834TZTZA2342497323424973Exact WOE match as countryTZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZATZA-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 8 8 5-99 10.03.0 8.0 34.959183 -6.0518661159321337Q924تنزانياতানজানিয়াTansaniaTanzaniaTanzaniaتانزانیاTanzanieΤανζανίαטנזניהतंज़ानियाTanzániaTanzaniaTanzaniaタンザニア탄자니아TanzaniaTanzaniaTanzâniaТанзанияTanzaniaTanzanyaТанзаніяتنزانیہTanzania坦桑尼亚坦尚尼亞Admin-0 countryAdmin-0 country Admin-0 country14TajikistanTJK02Sovereign country1TajikistanTJK0TajikistanTJK0TajikistanTJK0TajikistanTajikistanTJKTajikistanTjk.TJRepublic of TajikistanTajikistanTajikistan362 5 9321018.0132019 811620196. Developing region5. Low incomeTITJTJTJKTJK762762762TJTJK2342496123424961Exact WOE match as countryTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJKTJK-99-99AsiaAsiaCentral AsiaEurope & Central Asia1010 4-99 10.04.0 9.0 72.587276 38.1998351159321307Q863طاجيكستانতাজিকিস্তানTadschikistanTajikistanTayikistánتاجیکستانTadjikistanΤατζικιστάνטג׳יקיסטןताजिकिस्तानTádzsikisztánTajikistanTagikistanタジキスタン타지키스탄TadzjikistanTadżykistanTajiquistãoТаджикистанTadzjikistanTacikistanТаджикистанتاجکستانTajikistan塔吉克斯坦塔吉克Admin-0 countryAdmin-0 country Admin-0 country13TaiwanTWN02Sovereign country1TaiwanTWN0TaiwanTWN0TaiwanTWN0TaiwanTaiwanTWNTaiwanTaiwanTWTaiwanSelf admin.; Claimed by ChinaTaiwan157 2 23568378.0152020 112700020162. Developed region: nonG72. High income: nonOECDTWCN-TWTWTWNTWN158158-099-99-992342497123424971Exact WOE match as countryTWNTWNTWNTWNCHNTWNCHNTWNTWNCHNCHNTWNTWNTWNTWNTWNTWNCHNCHNTWNTWNTWNTWNTWNTWNCHNTWNTWNTWNTWNTWNCHNTWN-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 6 6 6-99 10.04.5 8.0 120.868204 23.6524081159321335Q865تايوانতাইওয়ানRepublik ChinaTaiwanRepública de ChinaتایوانTaïwanΔημοκρατία της Κίναςטאיוואןचीनी गणराज्यKínai KöztársaságTaiwanTaiwan中華民国중화민국TaiwanRepublika ChińskaTaiwanТайваньTaiwanÇin CumhuriyetiРеспубліка КитайتائیوانĐài Loan中华民国中華民國Admin-1 states provinces1Admin-0 countryAdmin-1 states provincesAdmin-0 countryAdmin-1 states provincesAdmin-1 states provincesAdmin-1 states provincesAdmin-1 states provincesAdmin-1 states provinces Admin-0 country13SyriaSYR02Sovereign country1SyriaSYR0SyriaSYR0SyriaSYR0SyriaSyriaSYRSyriaSyriaSYRSyrian Arab RepublicSyriaSyrian Arab Republic262 6 17070135.0142019 9883020156. Developing region4. Lower middle incomeSYSYSYSYRSYR760760760SYSYR2342495623424956Exact WOE match as countrySYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYRSYR-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 5 5 5-99 10.03.0 8.0 38.277783 35.0066361159321295Q858سورياসিরিয়াSyrienSyriaSiriaسوریهSyrieΣυρίαסוריהसीरियाSzíriaSuriahSiriaシリア시리아SyriëSyriaSíriaСирияSyrienSuriyeСиріяسوریہSyria叙利亚敘利亞Admin-0 countryAdmin-0 country Admin-0 country14SwitzerlandCHE02Sovereign country1SwitzerlandCHE0SwitzerlandCHE0SwitzerlandCHE0SwitzerlandSwitzerlandCHESwitzerlandSwitz.CHSwiss ConfederationSwitzerlandSwitzerland527 3 8574832.0132019 70308220192. Developed region: nonG71. High income: OECDSZCHCHCHECHE756756756CHCHE2342495723424957Exact WOE match as countryCHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHECHE-99-99EuropeEuropeWestern EuropeEurope & Central Asia1111 6-99 10.04.0 9.0 7.463965 46.7191141159320491Q39سويسراসুইজারল্যান্ডSchweizSwitzerlandSuizaسوئیسSuisseΕλβετίαשווייץस्विट्ज़रलैण्डSvájcSwissSvizzeraスイス스위스ZwitserlandSzwajcariaSuíçaШвейцарияSchweizİsviçreШвейцаріяسویٹزرلینڈThụy Sĩ瑞士瑞士Admin-0 countryAdmin-0 country Admin-0 country33SwedenSWE02Sovereign country1SwedenSWE0SwedenSWE0SwedenSWE0SwedenSwedenSWESwedenSwe.SKingdom of SwedenSwedenSweden142 4 10285453.0142019 53088320192. Developed region: nonG71. High income: OECDSWSESESWESWE752752752SESWE2342495423424954Exact WOE match as countrySWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWESWE-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 6 6 4-99 10.02.0 7.0 19.017050 65.8591801159321287Q34السويدসুইডেনSchwedenSwedenSueciaسوئدSuèdeΣουηδίαשוודיהस्वीडनSvédországSwediaSveziaスウェーデン스웨덴ZwedenSzwecjaSuéciaШвецияSverigeİsveçШвеціяسویڈنThụy Điển瑞典瑞典Admin-0 countryAdmin-0 country Admin-0 country14eSwatiniSWZ02Sovereign country1eSwatiniSWZ0eSwatiniSWZ0eSwatiniSWZ0eSwatiniKingdom of eSwatiniSWZeSwatinieSw.ESKingdom of eSwatinieSwatinieSwatiniSwaziland362 5 1148130.0122019 447120196. Developing region4. Lower middle incomeWZSZSZSWZSWZ748748748SZSWZ2342499323424993Exact WOE match as countrySWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZSWZ-99-99AfricaAfricaSouthern AfricaSub-Saharan Africa 819 4-99 10.04.0 9.0 31.467264-26.5336761159321289Q1050إسواتينيইসোয়াতিনিEswatiniEswatiniSuazilandiaاسواتینیEswatiniΕσουατίνιאסוואטיניएस्वातीनीSzváziföldEswatinieSwatiniエスワティニ에스와티니SwazilandEswatiniEssuatíniЭсватиниSwazilandEsvatiniЕсватініاسواتینیEswatini斯威士兰史瓦帝尼Admin-0 countryAdmin-0 country Admin-0 country14SurinameSUR02Sovereign country1SurinameSUR0SurinameSUR0SurinameSUR0SurinameSurinameSURSurinameSur.SRRepublic of SurinameSurinameSuriname147 6 581363.0112019 369720196. Developing region3. Upper middle incomeNSSRSRSURSUR740740740SRSUR2342491323424913Exact WOE match as countrySURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSURSUR-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 8 8 4-99 10.04.0 9.0 -55.910940 4.1439871159321281Q730سورينامসুরিনামSurinameSurinameSurinamسورینامSurinameΣουρινάμסורינאםसूरीनामSurinameSurinameSurinameスリナム수리남SurinameSurinamSurinameСуринамSurinamSurinamСуринамسرینامSuriname苏里南蘇利南Admin-0 countryAdmin-0 country Admin-0 country13South SudanSDS02Sovereign country1South SudanSDS0South SudanSDS0South SudanSDS0S. SudanSouth SudanSDSS. SudanS. Sud.SSRepublic of South SudanSouth SudanSouth Sudan133 5 11062113.0142019 1199820157. Least developed region5. Low income-99SSSSSSDSSD728728728SSSSD -99 -99Includes states of 20069899, 20069897, 20069898, 20069901, 20069909, and 20069908 but maybe more?SSD1SDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDSSDS-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 811 7-99 10.03.0 8.0 30.390151 7.2304771159321235Q958جنوب السودانদক্ষিণ সুদানSüdsudanSouth SudanSudán del Surسودان جنوبیSoudan du SudΝότιο Σουδάνדרום סודאןदक्षिण सूडानDél-SzudánSudan SelatanSudan del Sud南スーダン남수단Zuid-SoedanSudan PołudniowySudão do SulЮжный СуданSydsudanGüney SudanПівденний Суданجنوبی سوڈانNam Sudan南苏丹南蘇丹Admin-0 countryAdmin-0 country Admin-0 country13SudanSDN02Sovereign country1SudanSDN0SudanSDN0SudanSDN0SudanSudanSDNSudanSudanSDRepublic of the SudanSudanSudan264 1 42813238.0152019 3051320196. Developing region4. Lower middle incomeSUSDSDSDNSDN729729729SDSDN -9023424952Almost all FLickr photos are in the north.SDZSDZSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDNSDN-99-99AfricaAfricaNorthern AfricaSub-Saharan Africa 5 5 5-99 10.02.5 8.0 29.260657 16.3307461159321229Q1049السودانসুদানSudanSudanSudánسودانSoudanΣουδάνסודאןसूडानSzudánSudanSudanスーダン수단SoedanSudanSudãoСуданSudanSudanСуданسوڈانSudan苏丹蘇丹Admin-0 countryAdmin-0 country Admin-0 country43Sri LankaLKA02Sovereign country1Sri LankaLKA0Sri LankaLKA0Sri LankaLKA0Sri LankaSri LankaLKASri LankaSri L.LKDemocratic Socialist Republic of Sri LankaSri LankaSri Lanka354 9 21803000.0152019 8400820196. Developing region4. Lower middle incomeCELKLKLKALKA144144144LKLKA2342477823424778Exact WOE match as countryLKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKALKA-99-99AsiaAsiaSouthern AsiaSouth Asia 9 9 6-99 10.03.0 8.0 80.704823 7.5810971159321025Q854سريلانكاশ্রীলঙ্কাSri LankaSri LankaSri LankaسریلانکاSri LankaΣρι Λάνκαסרי לנקהश्रीलंकाSrí LankaSri LankaSri Lankaスリランカ스리랑카Sri LankaSri LankaSri LankaШри-ЛанкаSri LankaSri LankaШрі-Ланкаسری لنکاSri Lanka斯里兰卡斯里蘭卡Admin-0 countryAdmin-0 country Admin-0 country42SpainESP02Sovereign country1SpainESP0SpainESP0SpainESP0SpainSpainESPSpainSp.EKingdom of SpainSpainSpain455 5 47076781.0152019 139349020192. Developed region: nonG71. High income: OECDSPESESESPESP724724724ESESP2342495023424950Exact WOE match as countryESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESPESP-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 5 5 3-99 10.02.0 7.0 -3.464718 40.0909531159320587Q29إسبانياস্পেনSpanienSpainEspañaاسپانیاEspagneΙσπανίαספרדस्पेनSpanyolországSpanyolSpagnaスペイン스페인SpanjeHiszpaniaEspanhaИспанияSpanienİspanyaІспаніяہسپانیہTây Ban Nha西班牙西班牙Admin-0 countryAdmin-0 country Admin-0 country12South KoreaKOR02Sovereign country1South KoreaKOR0South KoreaKOR0South KoreaKOR0South KoreaRepublic of KoreaKORRepublic of KoreaS.K.KRRepublic of KoreaKorea, SouthKorea, Rep.411 5 51709098.0162019 164673920194. Emerging region: MIKT1. High income: OECDKSKRKRKORKOR410410410KRKOR2342486823424868Exact WOE match as countryKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKORKOR-99-99AsiaAsiaEastern AsiaEast Asia & Pacific1117 4-99 10.02.5 7.0 128.129504 36.3849241159320985Q884كوريا الجنوبيةদক্ষিণ কোরিয়াSüdkoreaSouth KoreaCorea del Surکره جنوبیCorée du SudΝότια Κορέαקוריאה הדרומיתदक्षिण कोरियाDél-KoreaKorea SelatanCorea del Sud大韓民国대한민국Zuid-KoreaKorea PołudniowaCoreia do SulРеспублика КореяSydkoreaGüney KoreПівденна Кореяجنوبی کوریاHàn Quốc大韩民国大韓民國Admin-0 countryAdmin-0 country Admin-0 country12South AfricaZAF02Sovereign country1South AfricaZAF0South AfricaZAF0South AfricaZAF0South AfricaSouth AfricaZAFSouth AfricaS.Af.ZARepublic of South AfricaSouth AfricaSouth Africa234 2 58558270.0162019 35143120195. Emerging region: G203. Upper middle incomeSFZAZAZAFZAF710710710ZAZAF2342494223424942Exact WOE match as countryZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAFZAF-99-99AfricaAfricaSouthern AfricaSub-Saharan Africa1212 5-99 10.01.7 6.7 23.665734-29.7087761159321431Q258جنوب أفريقياদক্ষিণ আফ্রিকাSüdafrikaSouth AfricaSudáfricaآفریقای جنوبیAfrique du SudΝότια Αφρικήדרום אפריקהदक्षिण अफ़्रीकाDél-afrikai KöztársaságAfrika SelatanSudafrica南アフリカ共和国남아프리카 공화국Zuid-AfrikaPołudniowa AfrykaÁfrica do SulЮАРSydafrikaGüney Afrika CumhuriyetiПівденно-Африканська Республікаجنوبی افریقاCộng hòa Nam Phi南非南非Admin-0 countryAdmin-0 country Admin-0 country16SomaliaSOM02Sovereign country1SomaliaSOM0SomaliaSOM0SomaliaSOM0SomaliaSomaliaSOMSomaliaSom.SOFederal Republic of SomaliaSomaliaSomalia286 7 10192317.3142019 471920167. Least developed region5. Low incomeSOSOSOSOMSOM706706706SOSOM -9023424949Includes Somaliland (2347021, 2347020, 2347017 and portion of 2347016)SOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOM-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 7 7 4-99 10.04.0 9.0 45.192380 3.5689251159321261Q1045الصومالসোমালিয়াSomaliaSomaliaSomaliaسومالیSomalieΣομαλίαסומליהसोमालियाSzomáliaSomaliaSomaliaソマリア소말리아SomaliëSomaliaSomáliaСомалиSomaliaSomaliСомаліصومالیہSomalia索马里索馬利亞Admin-0 countryAdmin-0 country Admin-0 country15SomalilandSOL02Sovereign country1SomalilandSOL0SomalilandSOL0SomalilandSOL0SomalilandSomalilandSOLSomalilandSolnd.SLRepublic of SomalilandDisputedSelf admin.; Claimed by SomaliaSomaliland365 2 5096159.0132014 1783620136. Developing region4. Lower middle income-99-99-99-99-99-99-99-099-99-99 -99 -99Includes old states of 2347021, 2347020, 2347017 and portion of 2347016.SOM1SOLSOMSOMSOMSOMSOMSOLSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOMSOM-99-99AfricaAfricaEastern AfricaSub-Saharan Africa1010 6-99 14.04.5 9.0 46.731595 9.4438891159321259Q34754صوماليلاندসোমালিল্যান্ডSomalilandSomalilandSomalilandiaسومالیلندSomalilandΣομαλιλάνδηסומלילנדसोमालीदेशSzomáliföldSomalilandSomalilandソマリランド소말릴란드SomalilandSomalilandSomalilândiaСомалилендSomalilandSomalilandСомалілендصومالی لینڈSomaliland索马里兰索馬利蘭Unrecognized1Admin-0 countryUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedAdmin-0 countryUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognized Admin-0 country43Solomon IslandsSLB02Sovereign country1Solomon IslandsSLB0Solomon IslandsSLB0Solomon IslandsSLB0Solomon Is.Solomon IslandsSLBSolomon Is.S. Is.SBSolomon IslandsSolomon Islands141 6 669823.0112019 158920197. Least developed region4. Lower middle incomeBPSBSBSLBSLB090090090SBSLB2342476623424766Exact WOE match as countrySLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLBSLB-99-99OceaniaOceaniaMelanesiaEast Asia & Pacific1115 6-99 10.03.0 8.0 159.170468 -8.0295481159321249Q685جزر سليمانসলোমন দ্বীপপুঞ্জSalomonenSolomon IslandsIslas Salomónجزایر سلیمانÎles SalomonΝησιά Σολομώνταאיי שלמהसोलोमन द्वीपसमूहSalamon-szigetekKepulauan SolomonIsole Salomoneソロモン諸島솔로몬 제도SalomonseilandenWyspy SalomonaIlhas SalomãoСоломоновы ОстроваSalomonöarnaSolomon AdalarıСоломонові Островиجزائر سلیمانQuần đảo Solomon所罗门群岛索羅門群島Admin-0 countryAdmin-0 country Admin-0 country16SlovakiaSVK02Sovereign country1SlovakiaSVK0SlovakiaSVK0SlovakiaSVK0SlovakiaSlovakiaSVKSlovakiaSvk.SKSlovak RepublicSlovakiaSlovak Republic244 9 5454073.0132019 10507920192. Developed region: nonG71. High income: OECDLOSKSKSVKSVK703703703SKSVK2342487723424877Exact WOE match as countrySVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVKSVK-99-99EuropeEuropeEastern EuropeEurope & Central Asia 8 8 4-99 10.04.0 9.0 19.049868 48.7340441159321283Q214سلوفاكياস্লোভাকিয়াSlowakeiSlovakiaEslovaquiaاسلواکیSlovaquieΣλοβακίαסלובקיהस्लोवाकियाSzlovákiaSlowakiaSlovacchiaスロバキア슬로바키아SlowakijeSłowacjaEslováquiaСловакияSlovakienSlovakyaСловаччинаسلوواکیہSlovakia斯洛伐克斯洛伐克Admin-0 countryAdmin-0 country Admin-0 country16SloveniaSVN02Sovereign country1SloveniaSVN0SloveniaSVN0SloveniaSVN0SloveniaSloveniaSVNSloveniaSlo.SLORepublic of SloveniaSloveniaSlovenia232 12 2087946.0122019 5417420192. Developed region: nonG71. High income: OECDSISISISVNSVN705705705SISVN2342494523424945Exact WOE match as countrySVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVNSVN-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 8 8 4-99 10.05.010.0 14.915312 46.0607601159321285Q215سلوفينياস্লোভেনিয়াSlowenienSloveniaEsloveniaاسلوونیSlovénieΣλοβενίαסלובניהस्लोवेनियाSzlovéniaSloveniaSloveniaスロベニア슬로베니아SloveniëSłoweniaEslovéniaСловенияSlovenienSlovenyaСловеніяسلووینیاSlovenia斯洛文尼亚斯洛維尼亞Admin-0 countryAdmin-0 country Admin-0 country36SingaporeSGP02Sovereign country1SingaporeSGP0SingaporeSGP0SingaporeSGP0SingaporeSingaporeSGPSingaporeSing.SGRepublic of SingaporeSingaporeSingapore537 3 5703569.0132019 37206220196. Developing region2. High income: nonOECDSNSGSGSGPSGP702702702SGSGP2342494823424948Exact WOE match as countrySGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGPSGP-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 9 9 5 3 10.04.0 9.0 103.816925 1.3665871159321247Q334سنغافورةসিঙ্গাপুরSingapurSingaporeSingapurسنگاپورSingapourΣιγκαπούρηסינגפורसिंगापुरSzingapúrSingapuraSingaporeシンガポール싱가포르SingaporeSingapurSingapuraСингапурSingaporeSingapurСінгапурسنگاپورSingapore新加坡新加坡Admin-0 countryAdmin-0 country Admin-0 country14Sierra LeoneSLE02Sovereign country1Sierra LeoneSLE0Sierra LeoneSLE0Sierra LeoneSLE0Sierra LeoneSierra LeoneSLESierra LeoneS.L.SLRepublic of Sierra LeoneSierra LeoneSierra Leone141 7 7813215.0132019 412120197. Least developed region5. Low incomeSLSLSLSLESLE694694694SLSLE2342494623424946Exact WOE match as countrySLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLESLE-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1212 4-99 10.04.0 9.0 -11.763677 8.6174491159321251Q1044سيراليونসিয়েরা লিওনSierra LeoneSierra LeoneSierra LeonaسیرالئونSierra LeoneΣιέρα Λεόνεסיירה לאוןसिएरा लियोनSierra LeoneSierra LeoneSierra Leoneシエラレオネ시에라리온Sierra LeoneSierra LeoneSerra LeoaСьерра-ЛеонеSierra LeoneSierra LeoneСьєрра-ЛеонеسیرالیونSierra Leone塞拉利昂獅子山Admin-0 countryAdmin-0 country Admin-0 country16SeychellesSYC02Sovereign country1SeychellesSYC0SeychellesSYC0SeychellesSYC0SeychellesSeychellesSYCSeychellesSyc.SCRepublic of SeychellesSeychellesSeychelles583 1 97625.0 82019 170320196. Developing region3. Upper middle incomeSESCSCSYCSYC690690690SCSYC2342494123424941Exact WOE match as countrySYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYCSYC-99-99Seven seas (open ocean)AfricaEastern AfricaSub-Saharan Africa1010 4 2 10.05.010.0 55.480175 -4.6766591159321291Q1042سيشلসেশেলসSeychellenSeychellesSeychellesسیشلSeychellesΣεϋχέλλεςסיישלसेशेल्सSeychelle-szigetekSeychellesSeychellesセーシェル세이셸SeychellenSeszeleSeychellesСейшельские ОстроваSeychellernaSeyşellerСейшельські ОстровиسیشیلزSeychelles塞舌尔塞席爾Admin-0 countryAdmin-0 country Admin-0 country15Republic of SerbiaSRB02Sovereign country1Republic of SerbiaSRB0Republic of SerbiaSRB0Republic of SerbiaSRB0SerbiaSerbiaSRBSerbiaSerb.RSRepublic of SerbiaSerbiaSerbia332 10 6944975.0132019 5147520196. Developing region3. Upper middle incomeRIRSRSSRBSRB688688688YFSRB -9020069818Expired WOE also contains Kosovo.SRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRBSRB-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 6 6 5-99 10.04.0 7.0 20.787989 44.1899191159321267Q403صربياসার্বিয়াSerbienSerbiaSerbiaصربستانSerbieΣερβίαסרביהसर्बियाSzerbiaSerbiaSerbiaセルビア세르비아ServiëSerbiaSérviaСербияSerbienSırbistanСербіяسربیاSerbia塞尔维亚塞爾維亞Admin-0 countryAdmin-0 country Admin-0 country13SenegalSEN02Sovereign country1SenegalSEN0SenegalSEN0SenegalSEN0SenegalSenegalSENSenegalSen.SNRepublic of SenegalSenegalSenegal265 5 16296364.0142019 2357820197. Least developed region4. Lower middle incomeSGSNSNSENSEN686686686SNSEN2342494323424943Exact WOE match as countrySENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSENSEN-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 7 7 4-99 10.02.7 8.0 -14.778586 15.1381251159321243Q1041السنغالসেনেগালSenegalSenegalSenegalسنگالSénégalΣενεγάληסנגלसेनेगलSzenegálSenegalSenegalセネガル세네갈SenegalSenegalSenegalСенегалSenegalSenegalСенегалسینیگالSénégal塞内加尔塞內加爾Admin-0 countryAdmin-0 country Admin-0 country42Saudi ArabiaSAU02Sovereign country1Saudi ArabiaSAU0Saudi ArabiaSAU0Saudi ArabiaSAU0Saudi ArabiaSaudi ArabiaSAUSaudi ArabiaSaud.SAKingdom of Saudi ArabiaSaudi ArabiaSaudi Arabia616 7 34268528.0152019 79296620192. Developed region: nonG72. High income: nonOECDSASASASAUSAU682682682SASAU2342493823424938Exact WOE match as countrySAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAU-99-99AsiaAsiaWestern AsiaMiddle East & North Africa1212 5-99 10.01.7 7.0 44.699600 23.8069081159321225Q851السعوديةসৌদি আরবSaudi-ArabienSaudi ArabiaArabia Sauditaعربستان سعودیArabie saouditeΣαουδική Αραβίαערב הסעודיתसउदी अरबSzaúd-ArábiaArab SaudiArabia Sauditaサウジアラビア사우디아라비아Saoedi-ArabiëArabia SaudyjskaArábia SauditaСаудовская АравияSaudiarabienSuudi ArabistanСаудівська Аравіяسعودی عربẢ Rập Saudi沙特阿拉伯沙烏地阿拉伯Admin-0 countryAdmin-0 country Admin-0 country16São Tomé and PrincipeSTP02Sovereign country1São Tomé and PrincipeSTP0São Tomé and PrincipeSTP0São Tomé and PrincipeSTP0São Tomé and PrincipeSão Tomé and PrincipeSTPSao Tome and PrincipeS.T.P.STDemocratic Republic of São Tomé and PrincipeSao Tome and PrincipeSao Tome and Principe161 7 215056.0102019 41820197. Least developed region4. Lower middle incomeTPSTSTSTPSTP678678678STSTP2342496623424966Exact WOE match as countrySTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTPSTP-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa2121 6 3 10.05.010.0 7.021000 0.9709001159321273Q1039ساو تومي وبرينسيبসাঁউ তুমি ও প্রিন্সিপিSão Tomé und PríncipeSão Tomé and PríncipeSanto Tomé y Príncipeسائوتومه و پرینسیپSao Tomé-et-PrincipeΣάο Τομέ και Πρίνσιπεסאו טומה ופרינסיפהसाओ तोमे और प्रिन्सिपीSão Tomé és PríncipeSao Tome dan PrincipeSão Tomé e Príncipeサントメ・プリンシペ상투메 프린시페Sao Tomé en PrincipeWyspy Świętego Tomasza i KsiążęcaSão Tomé e PríncipeСан-Томе и ПринсипиSão Tomé och PríncipeSão Tomé ve PríncipeСан-Томе і Принсіпіساؤ ٹومے و پرنسپےSão Tomé và Príncipe圣多美和普林西比聖多美普林西比Admin-0 countryAdmin-0 country Admin-0 country36San MarinoSMR02Sovereign country1San MarinoSMR0San MarinoSMR0San MarinoSMR0San MarinoSan MarinoSMRSan MarinoS.M.RSMRepublic of San MarinoSan MarinoSan Marino231 6 33860.0 72019 165520182. Developed region: nonG72. High income: nonOECDSMSMSMSMRSMR674674674SMSMR2342494723424947Exact WOE match as countrySMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMRSMR-99-99EuropeEuropeSouthern EuropeEurope & Central Asia1010 4 5 10.05.010.0 12.441206 43.9339161159321255Q238سان مارينوসান মারিনোSan MarinoSan MarinoSan Marinoسان مارینوSaint-MarinΆγιος Μαρίνοςסן מרינוसान मारिनोSan MarinoSan MarinoSan Marinoサンマリノ산마리노San MarinoSan MarinoSan MarinoСан-МариноSan MarinoSan MarinoСан-Мариноسان مارینوSan Marino圣马力诺聖馬力諾Admin-0 countryAdmin-0 country Admin-0 country14SamoaWSM02Sovereign country1SamoaWSM0SamoaWSM0SamoaWSM0SamoaSamoaWSMSamoaSamoaWSIndependent State of SamoaSamoaSamoa334 6 197097.0 92019 85220197. Least developed region4. Lower middle incomeWSWSWSWSMWSM882882882WSWSM2342499223424992Exact WOE match as countryWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSMWSM-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific 5 5 5-99 10.03.0 8.0-172.438241-13.6391391159321423Q683سامواসামোয়াSamoaSamoaSamoaساموآSamoaΣαμόαסמואהसमोआSzamoaSamoaSamoaサモア사모아SamoaSamoaSamoaСамоаSamoaSamoaСамоаساموواSamoa萨摩亚薩摩亞Admin-0 countryAdmin-0 country Admin-0 country16Saint Vincent and the GrenadinesVCT02Sovereign country1Saint Vincent and the GrenadinesVCT0Saint Vincent and the GrenadinesVCT0Saint Vincent and the GrenadinesVCT0St. Vin. and Gren.Saint Vincent and the GrenadinesVCTSt. Vin. and Gren.St.V.G.VCSaint Vincent and the GrenadinesSaint Vincent and the GrenadinesSt. Vincent and the Grenadines115 7 110589.0 92019 82420196. Developing region3. Upper middle incomeVCVCVCVCTVCT670670670VCVCT2342498123424981Exact WOE match as countryVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCTVCT-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1832 7-99 10.05.010.0 -61.335900 13.0879001159321409Q757سانت فينسنت والغرينادينসেন্ট ভিনসেন্ট ও গ্রেনাডাইনSt. Vincent und die GrenadinenSaint Vincent and the GrenadinesSan Vicente y las Granadinasسنت وینسنت و گرنادینهاSaint-Vincent-et-les-GrenadinesΆγιος Βικέντιος και Γρεναδίνεςסנט וינסנט והגרנדיניםसन्त विन्सेण्ट और ग्रेनाडाइन्सSaint Vincent és a Grenadine-szigetekSaint Vincent dan GrenadineSaint Vincent e Grenadineセントビンセント・グレナディーン세인트빈센트 그레나딘Saint Vincent en de GrenadinesSaint Vincent i GrenadynySão Vicente e GranadinasСент-Винсент и ГренадиныSaint Vincent och GrenadinernaSaint Vincent ve GrenadinlerСент-Вінсент і Гренадиниسینٹ وینسینٹ و گریناڈائنزSaint Vincent và Grenadines圣文森特和格林纳丁斯聖文森及格瑞那丁Admin-0 dependencyAdmin-0 dependency Admin-0 country16Saint LuciaLCA02Sovereign country1Saint LuciaLCA0Saint LuciaLCA0Saint LuciaLCA0Saint LuciaSaint LuciaLCASaint LuciaS.L.LCSaint LuciaSaint LuciaSt. Lucia343 4 182790.0 92019 212220196. Developing region3. Upper middle incomeSTLCLCLCALCA662662662LCLCA2342495123424951Exact WOE match as countryLCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCALCA-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1111 4 4 10.05.0 9.5 -60.980094 13.8923711159321019Q760سانت لوسياসেন্ট লুসিয়াSt. LuciaSaint LuciaSanta Lucíaسنت لوسیاSainte-LucieΑγία Λουκίαסנט לוסיהसेंट लूसियाSaint LuciaSaint LuciaSaint Luciaセントルシア세인트루시아Saint LuciaSaint LuciaSanta LúciaСент-ЛюсияSaint LuciaSaint LuciaСент-Люсіяسینٹ لوسیاSaint Lucia圣卢西亚聖露西亞Admin-0 countryAdmin-0 country Admin-0 country36Saint Kitts and NevisKNA02Sovereign country1Saint Kitts and NevisKNA0Saint Kitts and NevisKNA0Saint Kitts and NevisKNA0St. Kitts and NevisSaint Kitts and NevisKNASaint Kitts and NevisSt.K.N.KNFederation of Saint Kitts and NevisSaint Kitts and NevisSt. Kitts and Nevis141 8 52834.0 82019 105320196. Developing region2. High income: nonOECDSCKNKNKNAKNA659659659KNKNA2342494023424940Exact WOE match as countryKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNAKNA-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1921 7 4 10.05.010.0 -62.757975 17.3365581159320983Q763سانت كيتس ونيفيسসেন্ট কিট্স ও নেভিসSt. Kitts und NevisSaint Kitts and NevisSan Cristóbal y Nievesسنت کیتس و نویسSaint-Christophe-et-NiévèsΆγιος Χριστόφορος και Νέβιςסנט קיטס ונוויסसन्त किट्स और नेविसSaint Kitts és NevisSaint Kitts dan NevisSaint Kitts e Nevisセントクリストファー・ネイビス세인트키츠 네비스Saint Kitts en NevisSaint Kitts i NevisSão Cristóvão e NevisСент-Китс и НевисSaint Kitts och NevisSaint Kitts ve NevisСент-Кіттс і Невісسینٹ کیٹز و ناویسSaint Kitts và Nevis圣基茨和尼维斯聖克里斯多福與尼維斯Admin-0 countryAdmin-0 country Admin-0 country13RwandaRWA02Sovereign country1RwandaRWA0RwandaRWA0RwandaRWA0RwandaRwandaRWARwandaRwa.RWRepublic of RwandaRwandaRwanda523 10 12626950.0142019 1035420197. Least developed region5. Low incomeRWRWRWRWARWA646646646RWRWA2342493723424937Exact WOE match as countryRWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWARWA-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 6 6 4-99 10.03.0 8.0 30.103894 -1.8971961159321219Q1037روانداরুয়ান্ডাRuandaRwandaRuandaروانداRwandaΡουάνταרואנדהरवाण्डाRuandaRwandaRuandaルワンダ르완다RwandaRwandaRuandaРуандаRwandaRuandaРуандаروانڈاRwanda卢旺达盧旺達Admin-0 countryAdmin-0 country Admin-0 country52RussiaRUS02Sovereign country1RussiaRUS0RussiaRUS0RussiaRUS0RussiaRussian FederationRUSRussiaRus.RUSRussian FederationRussiaRussian Federation257 7 144373535.0172019 169987620193. Emerging region: BRIC3. Upper middle incomeRSRURURUSRUS643643643RURUS2342493623424936Exact WOE match as countryRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUSRUS-99-99EuropeEuropeEastern EuropeEurope & Central Asia 618 4-99 10.01.7 5.2 44.686469 58.2493571159321201Q159روسياরাশিয়াRusslandRussiaRusiaروسیهRussieΡωσίαרוסיהरूसOroszországRusiaRussiaロシア러시아RuslandRosjaRússiaРоссияRysslandRusyaРосіяروسNga俄罗斯俄羅斯Admin-0 countryAdmin-0 country Admin-0 country13RomaniaROU02Sovereign country1RomaniaROU0RomaniaROU0RomaniaROU0RomaniaRomaniaROURomaniaRom.RORomaniaRomaniaRomania143 13 19356544.0142019 25007720192. Developed region: nonG73. Upper middle incomeROROROROUROU642642642ROROM2342493323424933Exact WOE match as countryROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROUROU-99-99EuropeEuropeEastern EuropeEurope & Central Asia 7 7 4-99 10.03.0 8.0 24.972624 45.7332371159321199Q218رومانياরোমানিয়াRumänienRomaniaRumaniaرومانیRoumanieΡουμανίαרומניהरोमानियाRomániaRumaniaRomaniaルーマニア루마니아RoemeniëRumuniaRoméniaРумынияRumänienRomanyaРумуніяرومانیہRomania罗马尼亚羅馬尼亞Admin-0 countryAdmin-0 country Admin-0 country15QatarQAT02Sovereign country1QatarQAT0QatarQAT0QatarQAT0QatarQatarQATQatarQatarQAState of QatarQatarQatar362 4 2832067.0122019 17583720196. Developing region2. High income: nonOECDQAQAQAQATQAT634634634QAQAT2342493023424930Exact WOE match as countryQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQATQAT-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 5 5 5-99 10.04.0 9.0 51.143509 25.2373831159321197Q846قطرকাতারKatarQatarCatarقطرQatarΚατάρקטרक़तरKatarQatarQatarカタール카타르QatarKatarCatarКатарQatarKatarКатарقطرQatar卡塔尔卡達Admin-0 countryAdmin-0 country Admin-0 country32PortugalPRT02Sovereign country1PortugalPRT0PortugalPRT1PortugalPR10PortugalPortugalPR1PortugalPort.PPortuguese RepublicPortugalPortugal171 4 10269417.0142019 23878520192. Developed region: nonG71. High income: OECDPOPTPTPRTPRT620620620PTPRT2342492523424925Exact WOE match as countryPR1PR1PRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRTPRT-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 8 8 5-99 10.03.0 8.0 -8.271754 39.6066751159321187Q45البرتغالপর্তুগালPortugalPortugalPortugalپرتغالPortugalΠορτογαλίαפורטוגלपुर्तगालPortugáliaPortugalPortogalloポルトガル포르투갈PortugalPortugaliaPortugalПортугалияPortugalPortekizПортугаліяپرتگالBồ Đào Nha葡萄牙葡萄牙Admin-0 countryAdmin-0 country Admin-0 country13PolandPOL02Sovereign country1PolandPOL0PolandPOL0PolandPOL0PolandPolandPOLPolandPol.PLRepublic of PolandPolandPoland371 2 37970874.0152019 59585820192. Developed region: nonG71. High income: OECDPLPLPLPOLPOL616616616PLPOL2342492323424923Exact WOE match as countryPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOLPOL-99-99EuropeEuropeEastern EuropeEurope & Central Asia 6 6 4-99 10.02.5 7.0 19.490468 51.9903161159321179Q36بولنداপোল্যান্ডPolenPolandPoloniaلهستانPologneΠολωνίαפוליןपोलैंडLengyelországPolandiaPoloniaポーランド폴란드PolenPolskaPolóniaПольшаPolenPolonyaПольщаپولینڈBa Lan波兰波蘭Admin-0 countryAdmin-0 country Admin-0 country12PhilippinesPHL02Sovereign country1PhilippinesPHL0PhilippinesPHL0PhilippinesPHL0PhilippinesPhilippinesPHLPhilippinesPhil.PHRepublic of the PhilippinesPhilippinesPhilippines322 8 108116615.0172019 37679520195. Emerging region: G204. Lower middle incomeRPPHPHPHLPHL608608608PHPHL2342493423424934Exact WOE match as countryPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHLPHL-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific1111 5-99 10.02.5 7.0 122.465000 11.1980001159321169Q928الفلبينফিলিপাইনPhilippinenPhilippinesFilipinasفیلیپینPhilippinesΦιλιππίνεςהפיליפיניםफ़िलीपीन्सFülöp-szigetekFilipinaFilippineフィリピン필리핀FilipijnenFilipinyFilipinasФилиппиныFilippinernaFilipinlerФіліппіниفلپائنPhilippines菲律宾菲律賓Admin-0 countryAdmin-0 country Admin-0 country12PeruPER02Sovereign country1PeruPER0PeruPER0PeruPER0PeruPeruPERPeruPeruPERepublic of PeruPeruPeru444 11 32510453.0152019 22684820195. Emerging region: G203. Upper middle incomePEPEPEPERPER604604604PEPER2342491923424919Exact WOE match as countryPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPERPER-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 4 4 4-99 10.02.0 7.0 -72.900160-12.9766791159321163Q419بيروপেরুPeruPeruPerúپروPérouΠερούפרוपेरूPeruPeruPerùペルー페루PeruPeruPeruПеруPeruPeruПеруپیروPeru秘鲁秘魯Admin-0 countryAdmin-0 country Admin-0 country14ParaguayPRY02Sovereign country1ParaguayPRY0ParaguayPRY0ParaguayPRY0ParaguayParaguayPRYParaguayPara.PYRepublic of ParaguayParaguayParaguay636 2 7044636.0132019 3814520195. Emerging region: G204. Lower middle incomePAPYPYPRYPRY600600600PYPRY2342491723424917Exact WOE match as countryPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRYPRY-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 8 8 5-99 10.03.0 8.0 -60.146394-21.6745091159321195Q733باراغوايপ্যারাগুয়েParaguayParaguayParaguayپاراگوئهParaguayΠαραγουάηפרגוואיपैराग्वेParaguayParaguayParaguayパラグアイ파라과이ParaguayParagwajParaguaiПарагвайParaguayParaguayПарагвайپیراگوئےParaguay巴拉圭巴拉圭Admin-0 countryAdmin-0 country Admin-0 country12Papua New GuineaPNG02Sovereign country1Papua New GuineaPNG0Papua New GuineaPNG1Papua New GuineaPN10Papua New GuineaPapua New GuineaPN1Papua New GuineaP.N.G.PGIndependent State of Papua New GuineaPapua New GuineaPapua New Guinea423 1 8776109.0132019 2482920196. Developing region4. Lower middle incomePPPGPGPNGPNG598598598PGPNG2342492623424926Exact WOE match as countryPN1PN1PNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNGPNG-99-99OceaniaOceaniaMelanesiaEast Asia & Pacific1616 6-99 10.02.5 7.5 143.910216 -5.6952851159321173Q691بابوا غينيا الجديدةপাপুয়া নিউগিনিPapua-NeuguineaPapua New GuineaPapúa Nueva Guineaپاپوآ گینه نوPapouasie-Nouvelle-GuinéeΠαπούα Νέα Γουινέαפפואה גינאה החדשהपापुआ न्यू गिनीPápua Új-GuineaPapua NuginiPapua Nuova Guineaパプアニューギニア파푸아뉴기니Papoea-Nieuw-GuineaPapua-Nowa GwineaPapua-Nova GuinéПапуа — Новая ГвинеяPapua Nya GuineaPapua Yeni GineПапуа Нова Гвінеяپاپوا نیو گنیPapua New Guinea巴布亚新几内亚巴布亞紐幾內亞Admin-0 countryAdmin-0 country Admin-0 country14PanamaPAN02Sovereign country1PanamaPAN0PanamaPAN0PanamaPAN0PanamaPanamaPANPanamaPan.PARepublic of PanamaPanamaPanama446 3 4246439.0122019 6680020196. Developing region3. Upper middle incomePMPAPAPANPAN591591591PAPAN2342492423424924Exact WOE match as countryPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPANPAN-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 6 6 4-99 10.04.0 9.0 -80.352106 8.7219801159321161Q804بنماপানামাPanamaPanamaPanamáپاناماPanamaΠαναμάςפנמהपनामाPanamaPanamaPanamaパナマ파나마PanamaPanamaPanamáПанамаPanamaPanamaПанамаپاناماPanama巴拿马巴拿馬Admin-0 countryAdmin-0 country Admin-0 country46PalauPLW02Sovereign country1PalauPLW0PalauPLW0PalauPLW0PalauPalauPLWPalauPalauPWRepublic of PalauPalauPalau251 12 18008.0 62019 26820196. Developing region3. Upper middle incomePSPWPWPLWPLW585585585PWPLW2342492723424927Exact WOE match as countryPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLWPLW-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific 5 5 5 2 10.05.010.0 134.580157 7.5182521159321171Q695بالاوপালাউPalauPalauPalaosپالائوPalaosΠαλάουפלאוपलाउPalauPalauPalauパラオ팔라우PalauPalauPalauПалауPalauPalauРеспубліка ПалауپلاؤPalau帕劳帛琉Admin-0 countryAdmin-0 country Admin-0 country12PakistanPAK02Sovereign country1PakistanPAK0PakistanPAK0PakistanPAK0PakistanPakistanPAKPakistanPak.PKIslamic Republic of PakistanPakistanPakistan223 11 216565318.0172019 27822120195. Emerging region: G204. Lower middle incomePKPKPKPAKPAK586586586PKPAK2342492223424922Exact WOE match as countryPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAKPAK-99-99AsiaAsiaSouthern AsiaSouth Asia 8 8 4-99 10.02.7 7.0 68.545632 29.3283891159321153Q843باكستانপাকিস্তানPakistanPakistanPakistánپاکستانPakistanΠακιστάνפקיסטןपाकिस्तानPakisztánPakistanPakistanパキスタン파키스탄PakistanPakistanPaquistãoПакистанPakistanPakistanПакистанپاکستانPakistan巴基斯坦巴基斯坦Admin-0 countryAdmin-0 country Admin-0 country34OmanOMN02Sovereign country1OmanOMN0OmanOMN0OmanOMN0OmanOmanOMNOmanOmanOMSultanate of OmanOmanOman141 6 4974986.0122019 7633120196. Developing region2. High income: nonOECDMUOMOMOMNOMN512512512OMOMN2342489823424898Exact WOE match as countryOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMNOMN-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 4 4 4-99 10.04.0 9.0 57.336553 22.1204271159321151Q842سلطنة عمانওমানOmanOmanOmánعمانOmanΟμάνעומאןओमानOmánOmanOmanオマーン오만OmanOmanOmãОманOmanUmmanОманعمانOman阿曼阿曼Admin-0 countryAdmin-0 country Admin-0 country13NorwayNOR02Sovereign countryNorwayNOR0NorwayNOR0NorwayNOR0NorwayNorwayNORNorwayNor.NKingdom of NorwayNorwayNorway538 12 5347896.0132019 40333620192. Developed region: nonG71. High income: OECD-99-99NO-99NOR-99578-99-99-99 -9023424910Does not include Svalbard, Jan Mayen, or Bouvet Islands (28289410).NORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNORNOR-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 6 6 4-99 10.03.0 7.0 9.679975 61.3570921159321109Q20النرويجনরওয়েNorwegenNorwayNoruegaنروژNorvègeΝορβηγίαנורווגיהनॉर्वेNorvégiaNorwegiaNorvegiaノルウェー노르웨이NoorwegenNorwegiaNoruegaНорвегияNorgeNorveçНорвегіяناروےNa Uy挪威挪威UnrecognizedUnrecognized Admin-0 country13North KoreaPRK02Sovereign country1North KoreaPRK0North KoreaPRK0North KoreaPRK0North KoreaDem. Rep. KoreaPRKDem. Rep. KoreaN.K.KPDemocratic People's Republic of KoreaKorea, NorthKorea, Dem. Rep.353 9 25666161.0152019 4000020167. Least developed region5. Low incomeKNKPKPPRKPRK408408408KPPRK2342486523424865Exact WOE match as countryPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRKPRK-99-99AsiaAsiaEastern AsiaEast Asia & Pacific1115 4-99 10.03.0 8.0 126.444516 39.8852521159321181Q423كوريا الشماليةউত্তর কোরিয়াNordkoreaNorth KoreaCorea del Norteکره شمالیCorée du NordΒόρεια Κορέαקוריאה הצפוניתउत्तर कोरियाÉszak-KoreaKorea UtaraCorea del Nord朝鮮民主主義人民共和国조선민주주의인민공화국Noord-KoreaKorea PółnocnaCoreia do NorteКНДРNordkoreaKuzey KoreКорейська Народно-Демократична Республікаشمالی کوریاCộng hòa Dân chủ Nhân dân Triều Tiên朝鲜民主主义人民共和国朝鮮民主主義人民共和國Admin-0 countryAdmin-0 country Admin-0 country12NigeriaNGA02Sovereign country1NigeriaNGA0NigeriaNGA0NigeriaNGA0NigeriaNigeriaNGANigeriaNigeriaNGFederal Republic of NigeriaNigeriaNigeria325 2 200963599.0172019 44812020195. Emerging region: G204. Lower middle incomeNINGNGNGANGA566566566NGNGA2342490823424908Exact WOE match as countryNGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGANGA-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 7 7 7-99 10.01.7 6.7 7.503220 9.4397991159321089Q1033نيجيرياনাইজেরিয়াNigeriaNigeriaNigeriaنیجریهNigeriaΝιγηρίαניגריהनाईजीरियाNigériaNigeriaNigeriaナイジェリア나이지리아NigeriaNigeriaNigériaНигерияNigeriaNijeryaНігеріяنائجیریاNigeria尼日利亚奈及利亞Admin-0 countryAdmin-0 country Admin-0 country13NigerNER02Sovereign country1NigerNER0NigerNER0NigerNER0NigerNigerNERNigerNigerNERepublic of NigerNigerNiger453 13 23310715.0152019 1291120197. Least developed region5. Low incomeNGNENENERNER562562562NENER2342490623424906Exact WOE match as countryNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNERNER-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 5 5 5-99 10.03.0 8.0 9.504356 17.4461951159321087Q1032النيجرনাইজারNigerNigerNígerنیجرNigerΝίγηραςניז'רनाइजरNigerNigerNigerニジェール니제르NigerNigerNígerНигерNigerNijerНігерنائجرNiger尼日尔尼日Admin-0 countryAdmin-0 country Admin-0 country15NicaraguaNIC02Sovereign country1NicaraguaNIC0NicaraguaNIC0NicaraguaNIC0NicaraguaNicaraguaNICNicaraguaNic.NIRepublic of NicaraguaNicaraguaNicaragua141 9 6545502.0132019 1252020196. Developing region4. Lower middle incomeNUNININICNIC558558558NINIC2342491523424915Exact WOE match as countryNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNICNIC-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 9 9 4-99 10.04.0 9.0 -85.069347 12.6706971159321091Q811نيكاراغواনিকারাগুয়াNicaraguaNicaraguaNicaraguaنیکاراگوئهNicaraguaΝικαράγουαניקרגואהनिकारागुआNicaraguaNikaraguaNicaraguaニカラグア니카라과NicaraguaNikaraguaNicaráguaНикарагуаNicaraguaNikaraguaНікарагуаنکاراگواNicaragua尼加拉瓜尼加拉瓜Admin-0 countryAdmin-0 country Admin-0 country12New ZealandNZ112Country1New ZealandNZL0New ZealandNZL0New ZealandNZL0New ZealandNew ZealandNZLNew ZealandN.Z.NZNew ZealandNew ZealandNew Zealand334 4 4917000.0122019 20692820192. Developed region: nonG71. High income: OECDNZNZNZNZLNZL554554554NZNZL2342491623424916Exact WOE match as countryNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZLNZL-99-99OceaniaOceaniaAustralia and New ZealandEast Asia & Pacific1111 4-99 10.02.0 6.7 172.787000-39.7590001159321135Q664نيوزيلنداনিউজিল্যান্ডNeuseelandNew ZealandNueva ZelandaنیوزیلندNouvelle-ZélandeΝέα Ζηλανδίαניו זילנדन्यूज़ीलैण्डÚj-ZélandSelandia BaruNuova Zelandaニュージーランド뉴질랜드Nieuw-ZeelandNowa ZelandiaNova ZelândiaНовая ЗеландияNya ZeelandYeni ZelandaНова Зеландіяنیوزی لینڈNew Zealand新西兰新西蘭Admin-0 countryAdmin-0 country Admin-0 country34New ZealandNZ112Dependency1NiueNIU0NiueNIU0NiueNIU0NiueNiueNIUNiueNiueNUNiueAssoc. with N.Z.Assoc. with N.Z.Niue334 4 1620.0 32018 1020036. Developing region3. Upper middle incomeNENUNUNIUNIU570570570-99-992342490423424904Exact WOE match as countryNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIUNIU-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific 4 4 4 3-990.04.0 9.0-169.862565-19.0459561159321133Q34020نييويনিউয়েNiueNiueNiueنیوویNiueΝιούεניואהनिउएNiueNiueNiueニウエ니우에NiueNiueNiueНиуэNiueNiueНіуеنیووےNiue纽埃紐埃Admin-0 dependencyAdmin-0 dependency Admin-0 country34New ZealandNZ112Dependency1Cook IslandsCOK0Cook IslandsCOK0Cook IslandsCOK0Cook Is.Cook IslandsCOKCook Is.Cook Is.CKCook IslandsAssoc. with N.Z.Assoc. with N.Z.Cook Islands334 4 17459.0 62016 24420106. Developing region3. Upper middle incomeCWCKCKCOKCOK184184184-99-992342479523424795Exact WOE match as countryCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOKCOK-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific 812 8 3-990.04.0 9.0-159.785675-21.2159931159321129Q26988جزر كوكকুক দ্বীপপুঞ্জCookinselnCook IslandsIslas Cookجزایر کوکÎles CookΝήσοι Κουκאיי קוקकुक द्वीपसमूहCook-szigetekKepulauan CookIsole Cookクック諸島쿡 제도CookeilandenWyspy CookaIlhas CookОстрова КукаCooköarnaCook AdalarıОстрови Кукаجزائر ککQuần đảo Cook库克群岛庫克群島Admin-0 dependencyAdmin-0 dependency Admin-0 country15NetherlandsNL112Country1NetherlandsNLD0NetherlandsNLD0NetherlandsNLD0NetherlandsNetherlandsNLDNetherlandsNeth.NLKingdom of the NetherlandsNetherlandsNetherlands422 9 17332850.0142019 90705020192. Developed region: nonG71. High income: OECDNLNLNLNLDNLD528528528NLNLD -9023424909Doesn't include new former units of Netherlands Antilles (24549811, 24549808, and 24549809)NLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLDNLD-99-99EuropeEuropeWestern EuropeEurope & Central Asia1111 5-99 10.04.010.0 5.611440 52.4222111159321101Q55هولنداনেদারল্যান্ডসNiederlandeNetherlandsPaíses BajosهلندPays-BasΟλλανδίαהולנדनीदरलैण्डHollandiaBelandaPaesi Bassiオランダ네덜란드NederlandHolandiaPaíses BaixosНидерландыNederländernaHollandaНідерландиنیدرلینڈزHà Lan荷兰荷蘭Admin-0 countryAdmin-0 country Admin-0 country35NetherlandsNL112Country1ArubaABW0ArubaABW0ArubaABW0ArubaArubaABWArubaArubaAWArubaArubaNeth.Aruba422 9 106314.0 92019 305620176. Developing region2. High income: nonOECDAAAWAWABWABW533533533AWABW2342473623424736Exact WOE match as countryABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABW-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 5 5 5 4-990.05.010.0 -69.972795 12.5174001159321097Q21203أروباআরুবাArubaArubaArubaآروباArubaΑρούμπαארובהअरूबाArubaArubaArubaアルバ아루바ArubaArubaArubaАрубаArubaArubaАрубаاروباAruba阿鲁巴阿魯巴Admin-0 dependencyAdmin-0 dependency Admin-0 country35NetherlandsNL112Country1CuraçaoCUW0CuraçaoCUW0CuraçaoCUW0CuraçaoCuraçaoCUWCuraçaoCur.CWCuraçaoCuracaoNeth.Curaçao422 9 157538.0 92019 310120196. Developing region2. High income: nonOECDNTCWCWCUWCUW531531531CWCUW -9024549810Expired subunits of Netherlands Antilles (23424914).CUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUWCUW-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 7 7 4 4-990.05.010.0 -68.920578 12.1450391159321099Q25279كوراساوকিউরাসাওCuraçaoCuraçaoCurazaoکوراسائوCuraçaoΚουρασάοקוראסאוकुराकाओCuraçaoCuraçaoCuraçaoキュラソー퀴라소CuraçaoCuraçaoCuraçaoКюрасаоCuraçaoCuraçaoКюрасаоکیوراساؤCuraçao库拉索古拉索Admin-0 dependencyAdmin-0 dependency Admin-0 country13NepalNPL02Sovereign country1NepalNPL0NepalNPL0NepalNPL0NepalNepalNPLNepalNepalNPNepalNepalNepal223 12 28608710.0152019 3064120197. Least developed region5. Low incomeNPNPNPNPLNPL524524524NPNPL2342491123424911Exact WOE match as countryNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPLNPL-99-99AsiaAsiaSouthern AsiaSouth Asia 5 5 5-99 10.03.0 8.0 83.639914 28.2979251159321121Q837نيبالনেপালNepalNepalNepalنپالNépalΝεπάλנפאלनेपालNepálNepalNepalネパール네팔NepalNepalNepalНепалNepalNepalНепалنیپالNepal尼泊尔尼泊爾Admin-0 countryAdmin-0 country Admin-0 country36NauruNRU02Sovereign country1NauruNRU0NauruNRU0NauruNRU0NauruNauruNRUNauruNauruNRRepublic of NauruNauruNauru376 9 12581.0 62019 11820196. Developing region4. Lower middle incomeNRNRNRNRUNRU520520520-99-992342491223424912Exact WOE match as countryNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRUNRU-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific 5 5 5 3 10.05.010.0 166.932644 -0.5202611159321123Q697ناوروনাউরুNauruNauruNauruنائوروNauruΝαουρούנאורוनौरुNauruNauruNauruナウル나우루NauruNauruNauruНауруNauruNauruНауруناوروNauru瑙鲁諾魯Admin-0 countryAdmin-0 country Admin-0 country13NamibiaNAM02Sovereign country1NamibiaNAM0NamibiaNAM0NamibiaNAM0NamibiaNamibiaNAMNamibiaNam.NARepublic of NamibiaNamibiaNamibia411 7 2494530.0122019 1236620196. Developing region3. Upper middle incomeWANANANAMNAM516516516NANAM2342498723424987Exact WOE match as countryNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAMNAM-99-99AfricaAfricaSouthern AfricaSub-Saharan Africa 7 7 4-99 10.03.0 7.5 17.108166-20.5752981159321085Q1030ناميبياনামিবিয়াNamibiaNamibiaNamibiaنامیبیاNamibieΝαμίμπιαנמיביהनामीबियाNamíbiaNamibiaNamibiaナミビア나미비아NamibiëNamibiaNamíbiaНамибияNamibiaNamibyaНамібіяنمیبیاNamibia纳米比亚納米比亞Admin-0 countryAdmin-0 country Admin-0 country13MozambiqueMOZ02Sovereign country1MozambiqueMOZ0MozambiqueMOZ0MozambiqueMOZ0MozambiqueMozambiqueMOZMozambiqueMoz.MZRepublic of MozambiqueMozambiqueMozambique421 4 30366036.0152019 1529120197. Least developed region5. Low incomeMZMZMZMOZMOZ508508508MZMOZ2342490223424902Exact WOE match as countryMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZMOZ-99-99AfricaAfricaEastern AfricaSub-Saharan Africa1010 4-99 10.03.0 8.0 37.837890-13.9432301159321073Q1029موزمبيقমোজাম্বিকMosambikMozambiqueMozambiqueموزامبیکMozambiqueΜοζαμβίκηמוזמביקमोज़ाम्बीकMozambikMozambikMozambicoモザンビーク모잠비크MozambiqueMozambikMoçambiqueМозамбикMoçambiqueMozambikМозамбікموزمبیقMozambique莫桑比克莫三比克Admin-0 countryAdmin-0 country Admin-0 country13MoroccoMAR02Sovereign country1MoroccoMAR0MoroccoMAR0MoroccoMAR0MoroccoMoroccoMARMoroccoMor.MAKingdom of MoroccoMoroccoMorocco223 9 36471769.0152019 11970020196. Developing region4. Lower middle incomeMOMAMAMARMAR504504504MAMAR2342489323424893Exact WOE match as countryMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMAR-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 7 7 4-99 10.02.7 8.0 -7.187296 31.6507231159321035Q1028المغربমরক্কোMarokkoMoroccoMarruecosمراکشMarocΜαρόκοמרוקוमोरक्कोMarokkóMarokoMaroccoモロッコ모로코MarokkoMarokoMarrocosМароккоMarockoFasМароккоمراکشMaroc摩洛哥摩洛哥Admin-0 countryAdmin-0 country Admin-0 country17Western SaharaSAH02Indeterminate1Western SaharaSAH0Western SaharaSAH0Western SaharaSAH1W. SaharaWestern SaharaB28W. SaharaW. Sah.WSSahrawi Arab Democratic RepublicWestern SaharaSelf admin.; Claimed by MoroccoWestern Sahara474 4 603253.0112017 90720077. Least developed region5. Low incomeWIEHEHESHESH732732732-99-992342499023424990Exact WOE match as countryB28B28SAHMARSAHSAHSAHSAHMARSAHSAHSAHSAHSAHSAHMARMARSAHMARSAHSAHSAHSAHSAHMARMARMARSAHSAHMARSAHSAHSAH-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 914 7-99 14.76.011.0 -12.630304 23.9675921159321223Q6250الصحراء الغربيةপশ্চিম সাহারাWestsaharaWestern SaharaSahara Occidentalصحرای غربیSahara occidentalΔυτική Σαχάραסהרה המערביתपश्चिमी सहाराNyugat-SzaharaSahara BaratSahara Occidentale西サハラ서사하라Westelijke SaharaSahara ZachodniaSara OcidentalЗападная СахараVästsaharaBatı SahraЗахідна Сахараمغربی صحاراTây Sahara西撒哈拉西撒哈拉Admin-0 dependencyAdmin-0 dependencyUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognized Admin-0 country16MontenegroMNE02Sovereign country1MontenegroMNE0MontenegroMNE0MontenegroMNE0MontenegroMontenegroMNEMontenegroMont.MEMontenegroMontenegroMontenegro414 5 622137.0112019 554220196. Developing region3. Upper middle incomeMJMEMEMNEMNE499499499MEMNE2006981720069817Exact WOE match as countryMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNEMNE-99-99EuropeEuropeSouthern EuropeEurope & Central Asia1010 5-99 10.05.010.0 19.143727 42.8031011159321069Q236الجبل الأسودমন্টিনিগ্রোMontenegroMontenegroMontenegroمونتهنگروMonténégroΜαυροβούνιοמונטנגרוमॉन्टेनीग्रोMontenegróMontenegroMontenegroモンテネグロ몬테네그로MontenegroCzarnogóraMontenegroЧерногорияMontenegroKaradağЧорногоріяمونٹینیگروMontenegro黑山蒙特內哥羅Admin-0 countryAdmin-0 country Admin-0 country13MongoliaMNG02Sovereign country1MongoliaMNG0MongoliaMNG0MongoliaMNG0MongoliaMongoliaMNGMongoliaMong.MNMongoliaMongoliaMongolia355 6 3225167.0122019 1399620196. Developing region4. Lower middle incomeMGMNMNMNGMNG496496496MNMNG2342488723424887Exact WOE match as countryMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNGMNG-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 8 8 5-99 10.03.0 7.0 104.150405 45.9974881159321071Q711منغولياমঙ্গোলিয়াMongoleiMongoliaMongoliaمغولستانMongolieΜογγολίαמונגוליהमंगोलियाMongóliaMongoliaMongoliaモンゴル国몽골MongoliëMongoliaMongóliaМонголияMongolietMoğolistanМонголіяمنگولیاMông Cổ蒙古国蒙古國Admin-0 countryAdmin-0 country Admin-0 country16MoldovaMDA02Sovereign country1MoldovaMDA0MoldovaMDA0MoldovaMDA0MoldovaMoldovaMDAMoldovaMda.MDRepublic of MoldovaMoldovaMoldova354 12 2657637.0122019 1196820196. Developing region4. Lower middle incomeMDMDMDMDAMDA498498498MDMDA2342488523424885Exact WOE match as countryMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDAMDA-99-99EuropeEuropeEastern EuropeEurope & Central Asia 7 7 4-99 10.05.010.0 28.487904 47.4349991159321045Q217مولدوفاমলদোভাRepublik MoldauMoldovaMoldaviaمولداویMoldavieΜολδαβίαמולדובהमॉल्डोवाMoldovaMoldovaMoldaviaモルドバ몰도바MoldaviëMołdawiaMoldáviaМолдавияMoldavienMoldovaМолдоваمالدوواMoldova摩尔多瓦摩爾多瓦Admin-0 countryAdmin-0 country Admin-0 country66MonacoMCO02Sovereign country1MonacoMCO0MonacoMCO0MonacoMCO0MonacoMonacoMCOMonacoMco.MCPrincipality of MonacoMonacoMonaco112 12 38964.0 72019 718820182. Developed region: nonG72. High income: nonOECDMNMCMCMCOMCO492492492MCMCO2342489223424892Exact WOE match as countryMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCO-99-99EuropeEuropeWestern EuropeEurope & Central Asia 6 6 4 5 10.05.010.0 7.398291 43.7396521159321043Q235موناكوমোনাকোMonacoMonacoMónacoموناکوMonacoΜονακόמונקוमोनैकोMonacoMonakoPrincipato di Monacoモナコ모나코MonacoMonakoMónacoМонакоMonacoMonakoМонакоموناکوMonaco摩纳哥摩納哥Admin-0 countryAdmin-0 country Admin-0 country12MexicoMEX02Sovereign country1MexicoMEX0MexicoMEX0MexicoMEX0MexicoMexicoMEXMexicoMex.MXUnited Mexican StatesMexicoMexico617 3 127575529.0172019 126887020194. Emerging region: MIKT3. Upper middle incomeMXMXMXMEXMEX484484484MXMEX2342490023424900Exact WOE match as countryMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEXMEX-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 6 6 4-99 10.02.0 6.7-102.289448 23.9199881159321055Q96المكسيكমেক্সিকোMexikoMexicoMéxicoمکزیکMexiqueΜεξικόמקסיקוमेक्सिकोMexikóMeksikoMessicoメキシコ멕시코MexicoMeksykMéxicoМексикаMexikoMeksikaМексикаمیکسیکوMéxico墨西哥墨西哥Admin-0 countryAdmin-0 country Admin-0 country15MauritiusMUS02Sovereign country1MauritiusMUS0MauritiusMUS0MauritiusMUS0MauritiusMauritiusMUSMauritiusMus.MURepublic of MauritiusMauritiusMauritius135 7 1265711.0122019 1404820196. Developing region3. Upper middle incomeMPMUMUMUSMUS480480480MUMUS2342489423424894Exact WOE match as countryMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUSMUS-99-99Seven seas (open ocean)AfricaEastern AfricaSub-Saharan Africa 9 9 4 2 10.04.0 9.0 57.565848-20.2995061159321079Q1027موريشيوسমরিশাসMauritiusMauritiusMauricioموریسMauriceΜαυρίκιοςמאוריציוסमॉरिशसMauritiusMauritiusMauritiusモーリシャス모리셔스MauritiusMauritiusMauríciaМаврикийMauritiusMauritiusМаврикійموریشسMauritius毛里求斯模里西斯Admin-0 countryAdmin-0 country Admin-0 country53MauritaniaMRT02Sovereign country1MauritaniaMRT0MauritaniaMRT0MauritaniaMRT0MauritaniaMauritaniaMRTMauritaniaMrt.MRIslamic Republic of MauritaniaMauritaniaMauritania332 1 4525696.0122019 760020197. Least developed region5. Low incomeMRMRMRMRTMRT478478478MRMRT2342489623424896Exact WOE match as countryMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRTMRT-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1010 4-99 10.03.0 8.0 -9.740299 19.5870621159321075Q1025موريتانياমৌরিতানিয়াMauretanienMauritaniaMauritaniaموریتانیMauritanieΜαυριτανίαמאוריטניהमॉरीतानियाMauritániaMauritaniaMauritaniaモーリタニア모리타니MauritaniëMauretaniaMauritâniaМавританияMauretanienMoritanyaМавританіяموریتانیہMauritanie毛里塔尼亚茅利塔尼亞Admin-0 countryAdmin-0 country Admin-0 country35MaltaMLT02Sovereign country1MaltaMLT0MaltaMLT0MaltaMLT0MaltaMaltaMLTMaltaMaltaMRepublic of MaltaMaltaMalta141 8 502653.0112019 1498920192. Developed region: nonG72. High income: nonOECDMTMTMTMLTMLT470470470MTMLT2342489723424897Exact WOE match as countryMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLTMLT-99-99EuropeEuropeSouthern EuropeMiddle East & North Africa 5 5 5 3 10.04.0 9.0 14.433005 35.8928861159321065Q233مالطاমাল্টাMaltaMaltaMaltaمالتMalteΜάλταמלטהमाल्टाMáltaMaltaMaltaマルタ몰타MaltaMaltaMaltaМальтаMaltaMaltaМальтаمالٹاMalta马耳他馬耳他Admin-0 countryAdmin-0 country Admin-0 country13MaliMLI02Sovereign country1MaliMLI0MaliMLI0MaliMLI0MaliMaliMLIMaliMaliMLRepublic of MaliMaliMali141 7 19658031.0142019 1727920197. Least developed region5. Low incomeMLMLMLMLIMLI466466466MLMLI2342489123424891Exact WOE match as countryMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLIMLI-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 4 4 4-99 10.03.0 7.0 -2.038455 18.6927131159321063Q912ماليমালিMaliMaliMalíمالیMaliΜάλιמאליमालीMaliMaliMaliマリ共和国말리MaliMaliMaliМалиMaliMaliМаліمالیMali马里馬利共和國Admin-0 countryAdmin-0 country Admin-0 country45MaldivesMDV02Sovereign country1MaldivesMDV0MaldivesMDV0MaldivesMDV0MaldivesMaldivesMDVMaldivesMald.MVRepublic of MaldivesMaldivesMaldives231 7 530953.0112019 564220196. Developing region3. Upper middle incomeMVMVMVMDVMDV462462462MVMDV2342489923424899Exact WOE match as countryMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDVMDV-99-99Seven seas (open ocean)AsiaSouthern AsiaSouth Asia 8 8 5 2 10.04.0 9.0 73.507554 4.1744411159321053Q826المالديفমালদ্বীপMaledivenMaldivesMaldivasمالدیوMaldivesΜαλδίβεςהאיים המלדיבייםमालदीवMaldív-szigetekMaladewaMaldiveモルディブ몰디브MaldivenMalediwyMaldivasМальдивыMaldivernaMaldivlerМальдівиمالدیپMaldives马尔代夫馬爾地夫Admin-0 countryAdmin-0 country Admin-0 country13MalaysiaMYS02Sovereign country1MalaysiaMYS0MalaysiaMYS0MalaysiaMYS0MalaysiaMalaysiaMYSMalaysiaMalay.MYMalaysiaMalaysiaMalaysia243 6 31949777.0152019 36468120196. Developing region3. Upper middle incomeMYMYMYMYSMYS458458458MYMYS2342490123424901Exact WOE match as countryMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYSMYS-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 8 8 6-99 10.03.0 8.0 113.837080 2.5286671159321083Q833ماليزياমালয়েশিয়াMalaysiaMalaysiaMalasiaمالزیMalaisieΜαλαισίαמלזיהमलेशियाMalajziaMalaysiaMalaysiaマレーシア말레이시아MaleisiëMalezjaMalásiaМалайзияMalaysiaMalezyaМалайзіяملائیشیاMalaysia马来西亚馬來西亞Admin-0 countryAdmin-0 country Admin-0 country56MalawiMWI02Sovereign country1MalawiMWI0MalawiMWI0MalawiMWI0MalawiMalawiMWIMalawiMal.MWRepublic of MalawiMalawiMalawi134 5 18628747.0142019 766620197. Least developed region5. Low incomeMIMWMWMWIMWI454454454MWMWI2342488923424889Exact WOE match as countryMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWIMWI-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 6 6 4-99 10.04.0 9.0 33.608082-13.3867371159321081Q1020مالاويমালাউইMalawiMalawiMalauiمالاویMalawiΜαλάουιמלאוויमलावीMalawiMalawiMalawiマラウイ말라위MalawiMalawiMalawiМалавиMalawiMalaviМалавіملاویMalawi马拉维馬拉威Admin-0 countryAdmin-0 country Admin-0 country13MadagascarMDG02Sovereign country1MadagascarMDG0MadagascarMDG0MadagascarMDG0MadagascarMadagascarMDGMadagascarMad.MGRepublic of MadagascarMadagascarMadagascar652 3 26969307.0152019 1411420197. Least developed region5. Low incomeMAMGMGMDGMDG450450450MGMDG2342488323424883Exact WOE match as countryMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDGMDG-99-99AfricaAfricaEastern AfricaSub-Saharan Africa1010 4-99 10.02.7 7.0 46.704241-18.6282881159321051Q1019مدغشقرমাদাগাস্কারMadagaskarMadagascarMadagascarماداگاسکارMadagascarΜαδαγασκάρηמדגסקרमेडागास्करMadagaszkárMadagaskarMadagascarマダガスカル마다가스카르MadagaskarMadagaskarMadagáscarМадагаскарMadagaskarMadagaskarМадагаскарمڈغاسکرMadagascar马达加斯加馬達加斯加Admin-0 countryAdmin-0 country Admin-0 country16North MacedoniaMKD02Sovereign country1North MacedoniaMKD0North MacedoniaMKD0North MacedoniaMKD0North MacedoniaNorth MacedoniaMKDNorth MacedoniaN. Mac.NMRepublic of North MacedoniaNorth MacedoniaNorth Macedonia537 3 2083459.0122019 1254720196. Developing region3. Upper middle incomeMKMKMKMKDMKD807807807MKMKD2342489023424890Exact WOE match as countryMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKDMKD-99-99EuropeEuropeSouthern EuropeEurope & Central Asia1515 7-99 10.05.010.0 21.555839 41.5582231159321061Q221مقدونيا الشماليةউত্তর মেসিডোনিয়াNordmazedonienNorth MacedoniaMacedonia del Norteمقدونیه شمالیMacédoine du NordΒόρεια Μακεδονίαמקדוניה הצפוניתउत्तर मैसिडोनियाÉszak-MacedóniaRepublik Makedonia UtaraMacedonia del Nord北マケドニア북마케도니아Noord-MacedoniëMacedonia PółnocnaMacedónia do NorteСеверная МакедонияNordmakedonienKuzey MakedonyaПівнічна Македоніяشمالی مقدونیہBắc Macedonia北马其顿北馬其頓Admin-0 countryAdmin-0 country Admin-0 country16LuxembourgLUX02Sovereign country1LuxembourgLUX0LuxembourgLUX0LuxembourgLUX0LuxembourgLuxembourgLUXLuxembourgLux.LGrand Duchy of LuxembourgLuxembourgLuxembourg173 7 619896.0112019 7110420192. Developed region: nonG71. High income: OECDLULULULUXLUX442442442LULUX2342488123424881Exact WOE match as countryLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUXLUX-99-99EuropeEuropeWestern EuropeEurope & Central Asia1010 4 5 10.05.710.0 6.077620 49.7337321159321031Q32لوكسمبورغলুক্সেমবুর্গLuxemburgLuxembourgLuxemburgoلوکزامبورگLuxembourgΛουξεμβούργοלוקסמבורגलक्ज़मबर्गLuxemburgLuksemburgLussemburgoルクセンブルク룩셈부르크LuxemburgLuksemburgLuxemburgoЛюксембургLuxemburgLüksemburgЛюксембургلکسمبرگLuxembourg卢森堡盧森堡Admin-0 countryAdmin-0 country Admin-0 country35LithuaniaLTU02Sovereign country1LithuaniaLTU0LithuaniaLTU0LithuaniaLTU0LithuaniaLithuaniaLTULithuaniaLith.LTRepublic of LithuaniaLithuaniaLithuania633 9 2786844.0122019 5462720192. Developed region: nonG73. Upper middle incomeLHLTLTLTULTU440440440LTLTU2342487523424875Exact WOE match as countryLTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTULTU-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 9 9 5-99 10.04.0 9.0 24.089932 55.1037031159321029Q37ليتوانياলিথুয়ানিয়াLitauenLithuaniaLituaniaلیتوانیLituanieΛιθουανίαליטאलिथुआनियाLitvániaLituaniaLituaniaリトアニア리투아니아LitouwenLitwaLituâniaЛитваLitauenLitvanyaЛитваلتھووینیاLitva立陶宛立陶宛Admin-0 countryAdmin-0 country Admin-0 country16LiechtensteinLIE02Sovereign country1LiechtensteinLIE0LiechtensteinLIE0LiechtensteinLIE0LiechtensteinLiechtensteinLIELiechtensteinLiech.FLPrincipality of LiechtensteinLiechtensteinLiechtenstein242 9 38019.0 72019 687620182. Developed region: nonG72. High income: nonOECDLSLILILIELIE438438438LILIE2342487923424879Exact WOE match as countryLIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIELIE-99-99EuropeEuropeWestern EuropeEurope & Central Asia1313 6 6 10.05.010.0 9.559439 47.1114051159321021Q347ليختنشتاينলিশটেনস্টাইনLiechtensteinLiechtensteinLiechtensteinلیختناشتاینLiechtensteinΛίχτενσταϊνליכטנשטייןलिक्टेन्स्टाइनLiechtensteinLiechtensteinLiechtensteinリヒテンシュタイン리히텐슈타인LiechtensteinLiechtensteinLiechtensteinЛихтенштейнLiechtensteinLihtenştaynЛіхтенштейнلیختینستائنLiechtenstein列支敦士登列支敦斯登Admin-0 countryAdmin-0 country Admin-0 country13LibyaLBY02Sovereign country1LibyaLBY0LibyaLBY0LibyaLBY0LibyaLibyaLBYLibyaLibyaLYLibyaLibyaLibya122 11 6777452.0132019 5209120196. Developing region3. Upper middle incomeLYLYLYLBYLBY434434434LYLBY2342488223424882Exact WOE match as countryLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBYLBY-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 5 5 5-99 10.03.0 8.0 18.011015 26.6389441159321017Q1016ليبياলিবিয়াLibyenLibyaLibiaلیبیLibyeΛιβύηלובलीबियाLíbiaLibyaLibiaリビア리비아LibiëLibiaLíbiaЛивияLibyenLibyaЛівіяلیبیاLibya利比亚利比亞Admin-0 countryAdmin-0 country Admin-0 country14LiberiaLBR02Sovereign country1LiberiaLBR0LiberiaLBR0LiberiaLBR0LiberiaLiberiaLBRLiberiaLiberiaLRRepublic of LiberiaLiberiaLiberia234 9 4937374.0122019 307020197. Least developed region5. Low incomeLILRLRLBRLBR430430430LRLBR2342487623424876Exact WOE match as countryLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBRLBR-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 7 7 7-99 10.04.0 9.0 -9.460379 6.4471771159321015Q1014ليبيرياলাইবেরিয়াLiberiaLiberiaLiberiaلیبریاLiberiaΛιβερίαליבריהलाइबेरियाLibériaLiberiaLiberiaリベリア라이베리아LiberiaLiberiaLibériaЛиберияLiberiaLiberyaЛіберіяلائبیریاLiberia利比里亚賴比瑞亞Admin-0 countryAdmin-0 country Admin-0 country16LesothoLSO02Sovereign country1LesothoLSO0LesothoLSO0LesothoLSO0LesothoLesothoLSOLesothoLes.LSKingdom of LesothoLesothoLesotho152 8 2125268.0122019 237620197. Least developed region4. Lower middle incomeLTLSLSLSOLSO426426426LSLSO2342488023424880Exact WOE match as countryLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSOLSO-99-99AfricaAfricaSouthern AfricaSub-Saharan Africa 7 7 4-99 10.04.0 9.0 28.246639-29.4801581159321027Q1013ليسوتوলেসোথোLesothoLesothoLesotoلسوتوLesothoΛεσότοלסוטוलेसोथोLesothoLesothoLesothoレソト레소토LesothoLesothoLesotoЛесотоLesothoLesothoЛесотоلیسوتھوLesotho莱索托賴索托Admin-0 countryAdmin-0 country Admin-0 country15LebanonLBN02Sovereign country1LebanonLBN0LebanonLBN0LebanonLBN0LebanonLebanonLBNLebanonLeb.LBLebanese RepublicLebanonLebanon444 12 6855713.0132019 5199120196. Developing region3. Upper middle incomeLELBLBLBNLBN422422422LBLBN2342487323424873Exact WOE match as countryLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBNLBN-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 7 7 4 4 10.04.0 9.0 35.992892 34.1333681159321013Q822لبنانলেবাননLibanonLebanonLíbanoلبنانLibanΛίβανοςלבנוןलेबनानLibanonLebanonLibanoレバノン레바논LibanonLibanLíbanoЛиванLibanonLübnanЛіванلبنانLiban黎巴嫩黎巴嫩Admin-0 countryAdmin-0 country Admin-0 country15LatviaLVA02Sovereign country1LatviaLVA0LatviaLVA0LatviaLVA0LatviaLatviaLVALatviaLat.LVRepublic of LatviaLatviaLatvia476 13 1912789.0122019 3410220192. Developed region: nonG73. Upper middle incomeLGLVLVLVALVA428428428LVLVA2342487423424874Exact WOE match as countryLVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVALVA-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 6 6 4-99 10.04.0 9.0 25.458723 57.0668721159321033Q211لاتفياলাতভিয়াLettlandLatviaLetoniaلتونیLettonieΛετονίαלטביהलातवियाLettországLatviaLettoniaラトビア라트비아LetlandŁotwaLetóniaЛатвияLettlandLetonyaЛатвіяلٹویاLatvia拉脱维亚拉脫維亞Admin-0 countryAdmin-0 country Admin-0 country14LaosLAO02Sovereign country1LaosLAO0LaosLAO0LaosLAO0LaosLao PDRLAOLaosLaosLALao People's Democratic RepublicLaosLao PDR111 9 7169455.0132019 1817320197. Least developed region4. Lower middle incomeLALALALAOLAO418418418LALAO2342487223424872Exact WOE match as countryLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAOLAO-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 4 7 4-99 10.04.0 9.0 102.533912 19.4318211159321011Q819لاوسলাওসLaosLaosLaosلائوسLaosΛάοςלאוסलाओसLaoszLaosLaosラオス라오스LaosLaosLaosЛаосLaosLaosЛаосلاؤسLào老挝寮國Admin-0 countryAdmin-0 country Admin-0 country14KyrgyzstanKGZ02Sovereign country1KyrgyzstanKGZ0KyrgyzstanKGZ0KyrgyzstanKGZ0KyrgyzstanKyrgyzstanKGZKyrgyzstanKgz.KGKyrgyz RepublicKyrgyzstanKyrgyz Republic577 6 6456900.0132019 845420196. Developing region5. Low incomeKGKGKGKGZKGZ417417417KGKGZ2342486423424864Exact WOE match as countryKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZKGZ-99-99AsiaAsiaCentral AsiaEurope & Central Asia1010 4-99 10.03.0 8.0 74.532637 41.6685401159320977Q813قيرغيزستانকিরগিজস্তানKirgisistanKyrgyzstanKirguistánقرقیزستانKirghizistanΚιργιζίαקירגיזסטןकिर्गिज़स्तानKirgizisztánKirgizstanKirghizistanキルギス키르기스스탄KirgiziëKirgistanQuirguistãoКиргизияKirgizistanKırgızistanКиргизстанکرغیزستانKyrgyzstan吉尔吉斯斯坦吉爾吉斯Admin-0 countryAdmin-0 country Admin-0 country36KuwaitKWT02Sovereign country1KuwaitKWT0KuwaitKWT0KuwaitKWT0KuwaitKuwaitKWTKuwaitKwt.KWState of KuwaitKuwaitKuwait222 2 4207083.0122019 13462820196. Developing region2. High income: nonOECDKUKWKWKWTKWT414414414KWKWT2342487023424870Exact WOE match as countryKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWTKWT-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 6 6 4-99 10.05.010.0 47.313999 29.4136281159321009Q817الكويتকুয়েতKuwaitKuwaitKuwaitکویتKoweïtΚουβέιτכוויתकुवैतKuvaitKuwaitKuwaitクウェート쿠웨이트KoeweitKuwejtKuwaitКувейтKuwaitKuveytКувейтکویتKuwait科威特科威特Admin-0 countryAdmin-0 country Admin-0 country16KosovoKOS02Disputed1KosovoKOS0KosovoKOS0KosovoKOS0KosovoKosovoKOSKosovoKos.KORepublic of KosovoKosovoKosovo223 11 1794248.0122019 792620196. Developing region4. Lower middle incomeKV-99XK-99-99-99-99-099KVKSV -9029389201Subunit of Serbia in WOE still; should include 29389201, 29389207, 29389218, 29389209 and 29389214.SRB1KOSKOSKOSSRBSRBSRBKOSSRBSRBKOSKOSSRBKOSKOSSRBKOSKOSSRBKOSSRBKOSKOSSRBKOSSRBKOSSRBKOSKOSKOSKOSSRB-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 6 6 4-99 10.05.010.0 20.860719 42.5935871159321007Q1246كوسوفوকসোভোKosovoKosovoKosovoکوزوووKosovoΚοσσυφοπέδιοקוסובוकोसोवो गणराज्यKoszovóKosovoKosovoコソボ共和国코소보KosovoKosowoKosovoРеспублика КосовоKosovoKosovaКосовоکوسووہKosovo科索沃科索沃Unrecognized1Admin-0 countryAdmin-0 countryAdmin-0 countryAdmin-1 regionUnrecognizedUnrecognizedAdmin-0 countryAdmin-1 regionUnrecognizedAdmin-0 countryAdmin-0 countryAdmin-0 countryUnrecognizedAdmin-0 countryUnrecognizedAdmin-0 countryAdmin-0 countryUnrecognizedAdmin-0 countryUnrecognizedAdmin-0 countryAdmin-0 countryUnrecognizedAdmin-0 countryUnrecognizedAdmin-0 countryUnrecognizedAdmin-0 countryAdmin-0 countryAdmin-0 countryAdmin-0 countryUnrecognized Admin-0 country56KiribatiKIR02Sovereign country1KiribatiKIR0KiribatiKIR0KiribatiKIR0KiribatiKiribatiKIRKiribatiKir.KIRepublic of KiribatiKiribatiKiribati576 12 117606.0 92019 19420197. Least developed region4. Lower middle incomeKRKIKIKIRKIR296296296KIKIR2342486723424867Exact WOE match as countryKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIRKIR-99-99OceaniaOceaniaMicronesiaEast Asia & Pacific 8 8 4 2 10.05.010.0-157.384577 1.8204371159320981Q710كيريباتيকিরিবাসKiribatiKiribatiKiribatiکیریباتیKiribatiΚιριμπάτιקיריבטיकिरिबातीKiribatiKiribatiKiribatiキリバス키리바시KiribatiKiribatiKiribatiКирибатиKiribatiKiribatiКірибатіکیریباتیKiribati基里巴斯吉里巴斯Admin-0 countryAdmin-0 country Admin-0 country42KenyaKEN02Sovereign country1KenyaKEN0KenyaKEN0KenyaKEN0KenyaKenyaKENKenyaKen.KERepublic of KenyaKenyaKenya527 3 52573973.0162019 9550320195. Emerging region: G205. Low incomeKEKEKEKENKEN404404404KEKEN2342486323424863Exact WOE match as countryKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKENKEN-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 5 5 4-99 10.01.7 6.7 37.907632 0.5490431159320971Q114كينياকেনিয়াKeniaKenyaKeniaکنیاKenyaΚένυαקניהकीनियाKenyaKenyaKenyaケニア케냐KeniaKeniaQuéniaКенияKenyaKenyaКеніяکینیاKenya肯尼亚肯亞Admin-0 countryAdmin-0 country Admin-0 country53KazakhstanKA111Sovereignty1KazakhstanKAZ0KazakhstanKAZ0KazakhstanKAZ0KazakhstanKazakhstanKAZKazakhstanKaz.KZRepublic of KazakhstanKazakhstanKazakhstan616 1 18513930.0142019 18166520196. Developing region3. Upper middle incomeKZKZKZKAZKAZ398398398KZKAZ -9023424871Includes Baykonur Cosmodrome as an Admin-1 states provincesKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZKAZ-99-99AsiaAsiaCentral AsiaEurope & Central Asia1010 4-99 10.02.7 7.0 68.685548 49.0541491159320967Q232كازاخستانকাজাখস্তানKasachstanKazakhstanKazajistánقزاقستانKazakhstanΚαζακστάνקזחסטןकज़ाख़िस्तानKazahsztánKazakhstanKazakistanカザフスタン카자흐스탄KazachstanKazachstanCazaquistãoКазахстанKazakstanKazakistanКазахстанقازقستانKazakhstan哈萨克斯坦哈薩克Admin-0 countryAdmin-0 country Admin-0 country14JordanJOR02Sovereign country1JordanJOR0JordanJOR0JordanJOR0JordanJordanJORJordanJord.JHashemite Kingdom of JordanJordanJordan534 4 10101694.0142019 4450220196. Developing region3. Upper middle incomeJOJOJOJORJOR400400400JOJOR2342486023424860Exact WOE match as countryJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJORJOR-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 6 6 5-99 10.04.0 9.0 36.375991 30.8050251159320935Q810الأردنজর্ডানJordanienJordanJordaniaاردنJordanieΙορδανίαירדןजॉर्डनJordániaYordaniaGiordaniaヨルダン요르단JordaniëJordaniaJordâniaИорданияJordanienÜrdünЙорданіяاردنJordan约旦約旦Admin-0 countryAdmin-0 country Admin-0 country32JapanJPN02Sovereign country1JapanJPN0JapanJPN0JapanJPN0JapanJapanJPNJapanJapanJJapanJapanJapan535 4 126264931.0172019 508176920191. Developed region: G71. High income: OECDJAJPJPJPNJPN392392392JPJPN2342485623424856Exact WOE match as countryJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPNJPN-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 5 5 5-99 10.01.7 7.0 138.442170 36.1425381159320937Q17اليابانজাপানJapanJapanJapónژاپنJaponΙαπωνίαיפןजापानJapánJepangGiappone日本일본JapanJaponiaJapãoЯпонияJapanJaponyaЯпоніяجاپانNhật Bản日本日本Admin-0 countryAdmin-0 country Admin-0 country14JamaicaJAM02Sovereign country1JamaicaJAM0JamaicaJAM0JamaicaJAM0JamaicaJamaicaJAMJamaicaJam.JJamaicaJamaicaJamaica124 10 2948279.0122019 1645820196. Developing region3. Upper middle incomeJMJMJMJAMJAM388388388JMJAM2342485823424858Exact WOE match as countryJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAMJAM-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 7 7 4-99 10.04.0 9.0 -77.318767 18.1371241159320931Q766جامايكاজ্যামাইকাJamaikaJamaicaJamaicaجامائیکاJamaïqueΤζαμάικαג'מייקהजमैकाJamaicaJamaikaGiamaicaジャマイカ자메이카JamaicaJamajkaJamaicaЯмайкаJamaicaJamaikaЯмайкаجمیکاJamaica牙买加牙買加Admin-0 countryAdmin-0 country Admin-0 country12ItalyITA02Sovereign country1ItalyITA0ItalyITA0ItalyITA0ItalyItalyITAItalyItalyIItalian RepublicItalyItaly678 7 60297396.0162019 200357620191. Developed region: G71. High income: OECDITITITITAITA380380380ITITA2342485323424853Exact WOE match as countryITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITAITA-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 5 5 5-99 10.02.0 7.0 11.076907 44.7324821159320919Q38إيطالياইতালিItalienItalyItaliaایتالیاItalieΙταλίαאיטליהइटलीOlaszországItaliaItaliaイタリア이탈리아ItaliëWłochyItáliaИталияItalienİtalyaІталіяاطالیہÝ意大利義大利Admin-0 countryAdmin-0 country Admin-0 country14IsraelIS112Disputed1IsraelISR0IsraelISR0IsraelISR1IsraelIsraelISRIsraelIsr.ISState of IsraelIsraelIsrael325 9 9053300.0132019 39465220192. Developed region: nonG71. High income: OECD-99ILILISRISR376376376ILISR2342485223424852Exact WOE match as countryISRISRISRISRISRISRISRISRISRISRPSXISRISRISRISRISRPSXISRISRISRISRISRISRISRISRISRISRISRISRISRISRPSXISR-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 6 6 4-99 10.03.0 8.0 34.847915 30.9111481159320895Q801إسرائيلইসরায়েলIsraelIsraelIsraelاسرائیلIsraëlΙσραήλישראלइज़राइलIzraelIsraelIsraeleイスラエル이스라엘IsraëlIzraelIsraelИзраильIsraelİsrailІзраїльاسرائیلIsrael以色列以色列Admin-0 countryAdmin-0 countryUnrecognizedUnrecognizedUnrecognized Admin-0 country15IsraelIS112Indeterminate1PalestinePSX0PalestinePSX0PalestinePSX0PalestinePalestinePSXPalestinePal.PALWest Bank and GazaPartial self-admin.Palestine (West Bank and Gaza)325 8 4685306.0122019 1627620186. Developing region4. Lower middle income-99PSPSPSEPSE275275275GZWBG2828940828289408Exact WOE match as countryPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSXPSX-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 9 9 4-99-997.04.5 9.5 35.291341 32.0474311159320899Q23792فلسطينফিলিস্তিন অঞ্চলPalästinaPalestinePalestinaفلسطینPalestineΠαλαιστίνηארץ ישראלफ़िलिस्तीनी राज्यक्षेत्रPalesztinaPalestinaPalestinaパレスチナ팔레스타인PalestinaPalestynaPalestinaПалестинаPalestinaFilistinПалестинаفلسطینPalestine巴勒斯坦巴勒斯坦地區Admin-0 dependencyAdmin-0 dependencyAdmin-0 countryAdmin-0 countryAdmin-0 countryAdmin-0 country Admin-0 country43IrelandIRL02Sovereign country1IrelandIRL0IrelandIRL0IrelandIRL0IrelandIrelandIRLIrelandIre.IRLIrelandIrelandIreland232 2 4941444.0122019 38869820192. Developed region: nonG71. High income: OECDEIIEIEIRLIRL372372372IEIRL2342480323424803Exact WOE match as countryIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRLIRL-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 7 7 4-99 10.03.0 8.0 -7.798588 53.0787261159320877Q27جمهورية أيرلنداপ্রজাতন্ত্রী আয়ারল্যান্ডIrlandIrelandIrlandaایرلندIrlandeΔημοκρατία της Ιρλανδίαςאירלנדआयरलैण्डÍrországRepublik IrlandiaIrlandaアイルランド아일랜드IerlandIrlandiaRepública da IrlandaИрландияIrlandİrlandaІрландіяجمہوریہ آئرلینڈCộng hòa Ireland爱尔兰愛爾蘭Admin-0 countryAdmin-0 country Admin-0 country13IraqIRQ02Sovereign country1IraqIRQ0IraqIRQ0IraqIRQ0IraqIraqIRQIraqIraqIRQRepublic of IraqIraqIraq143 1 39309783.0152019 23409420196. Developing region4. Lower middle incomeIZIQIQIRQIRQ368368368IQIRQ2342485523424855Exact WOE match as countryIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQIRQ-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 4 4 4-99 10.03.0 7.5 43.261810 33.0940301159320887Q796العراقইরাকIrakIraqIrakعراقIrakΙράκעיראקइराकIrakIrakIraqイラク이라크IrakIrakIraqueИракIrakIrakІракعراقIraq伊拉克伊拉克Admin-0 countryAdmin-0 country Admin-0 country32IranIRN02Sovereign country1IranIRN0IranIRN0IranIRN0IranIranIRNIranIranIRNIslamic Republic of IranIranIran, Islamic Rep.434 13 82913906.0162019 45399620185. Emerging region: G203. Upper middle incomeIRIRIRIRNIRN364364364IRIRN2342485123424851Exact WOE match as countryIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRNIRN-99-99AsiaAsiaSouthern AsiaMiddle East & North Africa 4 4 4-99 10.02.5 6.7 54.931495 32.1662251159320881Q794إيرانইরানIranIranIránایرانIranΙράνאיראןईरानIránIranIranイラン이란IranIranIrãoИранIranİranІранایرانIran伊朗伊朗Admin-0 countryAdmin-0 country Admin-0 country32IndonesiaIDN02Sovereign country1IndonesiaIDN0IndonesiaIDN0IndonesiaIDN0IndonesiaIndonesiaIDNIndonesiaIndo.INDORepublic of IndonesiaIndonesiaIndonesia666 11 270625568.0172019 111919020194. Emerging region: MIKT4. Lower middle incomeIDIDIDIDNIDN360360360IDIDN2342484623424846Exact WOE match as countryIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDNIDN-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 9 9 5-99 10.01.7 6.7 101.892949 -0.9544041159320845Q252إندونيسياইন্দোনেশিয়াIndonesienIndonesiaIndonesiaاندونزیIndonésieΙνδονησίαאינדונזיהइंडोनेशियाIndonéziaIndonesiaIndonesiaインドネシア인도네시아IndonesiëIndonezjaIndonésiaИндонезияIndonesienEndonezyaІндонезіяانڈونیشیاIndonesia印度尼西亚印度尼西亞Admin-0 countryAdmin-0 country Admin-0 country12IndiaIND02Sovereign country1IndiaIND0IndiaIND0IndiaIND0IndiaIndiaINDIndiaIndiaINDRepublic of IndiaIndiaIndia132 21366417754.0182019 286892920193. Emerging region: BRIC4. Lower middle incomeININININDIND356356356ININD2342484823424848Exact WOE match as countryINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDINDIND-99-99AsiaAsiaSouthern AsiaSouth Asia 5 5 5-99 10.01.7 6.7 79.358105 22.6868521159320847Q668الهندভারতIndienIndiaIndiaهندIndeΙνδίαהודוभारतIndiaIndiaIndiaインド인도IndiaIndieÍndiaИндияIndienHindistanІндіяبھارتẤn Độ印度印度Admin-0 countryAdmin-0 country Admin-0 country13IcelandISL02Sovereign country1IcelandISL0IcelandISL0IcelandISL0IcelandIcelandISLIcelandIcelandISRepublic of IcelandIcelandIceland144 9 361313.0102019 2418820192. Developed region: nonG71. High income: OECDICISISISLISL352352352ISISL2342484523424845Exact WOE match as countryISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISLISL-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 7 7 7-99 10.02.0 7.0 -18.673711 64.7792861159320917Q189آيسلنداআইসল্যান্ডIslandIcelandIslandiaایسلندIslandeΙσλανδίαאיסלנדआइसलैण्डIzlandIslandiaIslandaアイスランド아이슬란드IJslandIslandiaIslândiaИсландияIslandİzlandaІсландіяآئس لینڈIceland冰岛冰島Admin-0 countryAdmin-0 country Admin-0 country15HungaryHUN02Sovereign country1HungaryHUN0HungaryHUN0HungaryHUN0HungaryHungaryHUNHungaryHun.HURepublic of HungaryHungaryHungary461 5 9769949.0132019 16346920192. Developed region: nonG71. High income: OECDHUHUHUHUNHUN348348348HUHUN2342484423424844Exact WOE match as countryHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUNHUN-99-99EuropeEuropeEastern EuropeEurope & Central Asia 7 7 4-99 10.04.0 9.0 19.447867 47.0868411159320841Q28المجرহাঙ্গেরিUngarnHungaryHungríaمجارستانHongrieΟυγγαρίαהונגריהहंगरीMagyarországHongariaUngheriaハンガリー헝가리HongarijeWęgryHungriaВенгрияUngernMacaristanУгорщинаہنگریHungary匈牙利匈牙利Admin-0 countryAdmin-0 country Admin-0 country15HondurasHND02Sovereign country1HondurasHND0HondurasHND0HondurasHND0HondurasHondurasHNDHondurasHond.HNRepublic of HondurasHondurasHonduras252 5 9746117.0132019 2509520196. Developing region4. Lower middle incomeHOHNHNHNDHND340340340HNHND2342484123424841Exact WOE match as countryHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHNDHND-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 8 8 5-99 10.04.5 9.5 -86.887604 14.7948011159320827Q783هندوراسহন্ডুরাসHondurasHondurasHondurasهندوراسHondurasΟνδούραהונדורסहौण्डुरसHondurasHondurasHondurasホンジュラス온두라스HondurasHondurasHondurasГондурасHondurasHondurasГондурасہونڈوراسHonduras洪都拉斯宏都拉斯Admin-0 countryAdmin-0 country Admin-0 country15HaitiHTI02Sovereign country1HaitiHTI0HaitiHTI0HaitiHTI0HaitiHaitiHTIHaitiHaitiHTRepublic of HaitiHaitiHaiti217 2 11263077.0142019 1433220197. Least developed region5. Low incomeHAHTHTHTIHTI332332332HTHTI2342483923424839Exact WOE match as countryHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTIHTI-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 5 5 5-99 10.04.0 9.0 -72.224051 19.2637841159320839Q790هايتيহাইতিHaitiHaitiHaitíهائیتیHaïtiΑϊτήהאיטיहैतीHaitiHaitiHaitiハイチ아이티HaïtiHaitiHaitiРеспублика ГаитиHaitiHaitiГаїтіہیٹیHaiti海地海地Admin-0 countryAdmin-0 country Admin-0 country14GuyanaGUY02Sovereign country1GuyanaGUY0GuyanaGUY0GuyanaGUY0GuyanaGuyanaGUYGuyanaGuy.GYCo-operative Republic of GuyanaGuyanaGuyana314 8 782766.0112019 517320196. Developing region4. Lower middle incomeGYGYGYGUYGUY328328328GYGUY2342483623424836Exact WOE match as countryGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUYGUY-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 6 6 4-99 10.04.0 9.0 -58.942643 5.1243171159320817Q734غياناগায়ানাGuyanaGuyanaGuyanaگویانGuyanaΓουιάναגיאנהगयानाGuyanaGuyanaGuyanaガイアナ가이아나GuyanaGujanaGuianaГайанаGuyanaGuyanaГаянаگیاناGuyana圭亚那圭亞那Admin-0 countryAdmin-0 country Admin-0 country16Guinea-BissauGNB02Sovereign country1Guinea-BissauGNB0Guinea-BissauGNB0Guinea-BissauGNB0Guinea-BissauGuinea-BissauGNBGuinea-BissauGnB.GWRepublic of Guinea-BissauGuinea-BissauGuinea-Bissau353 4 1920922.0122019 133920197. Least developed region5. Low incomePUGWGWGNBGNB624624624GWGNB2342492923424929Exact WOE match as countryGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNBGNB-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1313 4-99 10.05.010.0 -14.524130 12.1637121159320799Q1007غينيا بيساوগিনি-বিসাউGuinea-BissauGuinea-BissauGuinea-Bisáuگینه بیسائوGuinée-BissauΓουινέα-Μπισσάουגינאה ביסאוगिनी-बिसाऊBissau-GuineaGuinea-BissauGuinea-Bissauギニアビサウ기니비사우Guinee-BissauGwinea BissauGuiné-BissauГвинея-БисауGuinea-BissauGine-BissauГвінея-Бісауگنی بساؤGuiné-Bissau几内亚比绍幾內亞比索Admin-0 countryAdmin-0 country Admin-0 country13GuineaGIN02Sovereign country1GuineaGIN0GuineaGIN0GuineaGIN0GuineaGuineaGINGuineaGin.GNRepublic of GuineaGuineaGuinea637 2 12771246.0142019 1229620197. Least developed region5. Low incomeGVGNGNGINGIN324324324GNGIN2342483523424835Exact WOE match as countryGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGINGIN-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 6 6 4-99 10.03.0 8.0 -10.016402 10.6185161159320795Q1006غينياগিনিGuineaGuineaGuineaگینهGuinéeΓουινέαגינאהगिनीGuineaGuineaGuineaギニア기니GuineeGwineaGuinéГвинеяGuineaGineГвінеяجمہوریہ گنیGuinée几内亚幾內亞Admin-0 countryAdmin-0 country Admin-0 country13GuatemalaGTM02Sovereign country1GuatemalaGTM0GuatemalaGTM0GuatemalaGTM0GuatemalaGuatemalaGTMGuatemalaGuat.GTRepublic of GuatemalaGuatemalaGuatemala333 6 16604026.0142019 7671020196. Developing region4. Lower middle incomeGTGTGTGTMGTM320320320GTGTM2342483423424834Exact WOE match as countryGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTMGTM-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 9 9 5 4 10.03.0 8.0 -90.497134 14.9821331159320815Q774غواتيمالاগুয়াতেমালাGuatemalaGuatemalaGuatemalaگواتمالاGuatemalaΓουατεμάλαגואטמלהग्वाटेमालाGuatemalaGuatemalaGuatemalaグアテマラ과테말라GuatemalaGwatemalaGuatemalaГватемалаGuatemalaGuatemalaГватемалаگواتیمالاGuatemala危地马拉瓜地馬拉Admin-0 countryAdmin-0 country Admin-0 country16GrenadaGRD02Sovereign country1GrenadaGRD0GrenadaGRD0GrenadaGRD0GrenadaGrenadaGRDGrenadaGren.GDGrenadaGrenadaGrenada243 6 112003.0 92019 121020196. Developing region3. Upper middle incomeGJGDGDGRDGRD308308308GDGRD2342482623424826Exact WOE match as countryGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRDGRD-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 7 7 5-99 10.04.0 9.0 -61.680461 12.1131561159320813Q769غريناداগ্রেনাডাGrenadaGrenadaGranadaگرناداGrenadeΓρενάδαגרנדהग्रेनाडाGrenadaGrenadaGrenadaグレナダ그레나다GrenadaGrenadaGranadaГренадаGrenadaGrenadaГренадаگریناڈاGrenada格林纳达格瑞那達Admin-0 countryAdmin-0 country Admin-0 country33GreeceGRC02Sovereign country1GreeceGRC0GreeceGRC0GreeceGRC0GreeceGreeceGRCGreeceGreeceGRHellenic RepublicGreeceGreece222 9 10716322.0142019 20985220192. Developed region: nonG71. High income: OECDGRGRGRGRCGRC300300300GRGRC2342483323424833Exact WOE match as countryGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRCGRC-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 6 6 6-99 10.02.7 8.0 21.725680 39.4927631159320811Q41اليونانগ্রিসGriechenlandGreeceGreciaیونانGrèceΕλλάδαיווןयूनानGörögországYunaniGreciaギリシャ그리스GriekenlandGrecjaGréciaГрецияGreklandYunanistanГреціяیونانHy Lạp希腊希臘Admin-0 countryAdmin-0 country Admin-0 country13GhanaGHA02Sovereign country1GhanaGHA0GhanaGHA0GhanaGHA0GhanaGhanaGHAGhanaGhanaGHRepublic of GhanaGhanaGhana531 4 30417856.0152019 6698320196. Developing region4. Lower middle incomeGHGHGHGHAGHA288288288GHGHA2342482423424824Exact WOE match as countryGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHAGHA-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 5 5 5-99 10.02.7 8.0 -1.036941 7.7176391159320793Q117غاناঘানাGhanaGhanaGhanaغناGhanaΓκάναגאנהघानाGhánaGhanaGhanaガーナ가나GhanaGhanaGanaГанаGhanaGanaГанаگھاناGhana加纳迦納Admin-0 countryAdmin-0 country Admin-0 country12GermanyDEU02Sovereign country1GermanyDEU0GermanyDEU0GermanyDEU0GermanyGermanyDEUGermanyGer.DFederal Republic of GermanyGermanyGermany255 1 83132799.0162019 386112320191. Developed region: G71. High income: OECDGMDEDEDEUDEU276276276DEDEU2342482923424829Exact WOE match as countryDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEUDEU-99-99EuropeEuropeWestern EuropeEurope & Central Asia 7 7 4-99 10.01.7 6.7 9.678348 50.9617331159320539Q183ألمانياজার্মানিDeutschlandGermanyAlemaniaآلمانAllemagneΓερμανίαגרמניהजर्मनीNémetországJermanGermaniaドイツ독일DuitslandNiemcyAlemanhaГерманияTysklandAlmanyaНімеччинаجرمنیĐức德国德國Admin-0 countryAdmin-0 country Admin-0 country15GeorgiaGEO02Sovereign country1GeorgiaGEO0GeorgiaGEO0GeorgiaGEO0GeorgiaGeorgiaGEOGeorgiaGeo.GEGeorgiaGeorgiaGeorgia513 2 3720382.0122019 1747720196. Developing region4. Lower middle incomeGGGEGEGEOGEO268268268GEGEO2342482323424823Exact WOE match as countryGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEOGEO-99-99AsiaAsiaWestern AsiaEurope & Central Asia 7 7 4-99 10.04.0 9.0 43.735724 41.8700871159320779Q230جورجياজর্জিয়াGeorgienGeorgiaGeorgiaگرجستانGéorgieΓεωργίαגאורגיהजॉर्जियाGrúziaGeorgiaGeorgiaジョージア조지아GeorgiëGruzjaGeórgiaГрузияGeorgienGürcistanГрузіяجارجیاGruzia格鲁吉亚喬治亞Admin-0 countryAdmin-0 country Admin-0 country16GambiaGMB02Sovereign country1GambiaGMB0GambiaGMB0GambiaGMB0GambiaThe GambiaGMBGambiaGambiaGMRepublic of the GambiaGambia, TheGambia, The141 8 2347706.0122019 182620197. Least developed region5. Low incomeGAGMGMGMBGMB270270270GMGMB2342482123424821Exact WOE match as countryGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMBGMB-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 610 6-99 10.05.010.0 -14.998318 13.6417211159320797Q1005غامبياগাম্বিয়াGambiaThe GambiaGambiaگامبیاGambieΓκάμπιαגמביהगाम्बियाGambiaGambiaGambiaガンビア감비아GambiaGambiaGâmbiaГамбияGambiaGambiyaГамбіяگیمبیاGambia冈比亚甘比亞Admin-0 countryAdmin-0 country Admin-0 country14GabonGAB02Sovereign country1GabonGAB0GabonGAB0GabonGAB0GabonGabonGABGabonGabonGAGabonese RepublicGabonGabon625 5 2172579.0122019 1687420196. Developing region3. Upper middle incomeGBGAGAGABGAB266266266GAGAB2342482223424822Exact WOE match as countryGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGABGAB-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa 5 5 5 3 10.03.0 8.0 11.835939 -0.4377391159320693Q1000الغابونগ্যাবনGabunGabonGabónگابنGabonΓκαμπόνגבוןगबॉनGabonGabonGabonガボン가봉GabonGabonGabãoГабонGabonGabonГабонگیبونGabon加蓬加彭Admin-0 countryAdmin-0 country Admin-0 country12FranceFR112Country1FranceFRA0FranceFRA0FranceFRA0FranceFranceFRAFranceFr.FFrench RepublicFranceFrance759 11 67059887.0162019 271551820191. Developed region: G71. High income: OECDFR-99FR-99FRA-99250250FRFRA -9023424819Includes only Metropolitan France (including Corsica)FRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRAFRA-99-99EuropeEuropeWestern EuropeEurope & Central Asia 6 6 3-99 10.01.7 6.7 2.552275 46.6961131159320637Q142فرنساফ্রান্সFrankreichFranceFranciaفرانسهFranceΓαλλίαצרפתफ़्रान्सFranciaországPrancisFranciaフランス프랑스FrankrijkFrancjaFrançaФранцияFrankrikeFransaФранціяفرانسPháp法国法國Admin-0 countryAdmin-0 country Admin-0 country44FranceFR112Dependency1Saint Pierre and MiquelonSPM0Saint Pierre and MiquelonSPM0Saint Pierre and MiquelonSPM0St. Pierre and MiquelonSaint Pierre and MiquelonSPMSt. Pierre and MiquelonSt. P.M.PMSaint Pierre and MiquelonSaint Pierre and MiquelonFr.St. Pierre and Miquelon759 11 5997.0 52017 21520162. Developed region: nonG73. Upper middle incomeSBPMPMSPMSPM666666666-99-992342493923424939Exact WOE match as countrySPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPMSPM-99-99North AmericaAmericasNorthern AmericaNorth America2325 8 3-990.05.010.0 -56.332352 47.0403441159320647Q34617سان بيير وميكلونসাঁ পিয়ের ও মিকলোঁSaint-Pierre und MiquelonSaint Pierre and MiquelonSan Pedro y Miquelónسن پیر و میکلنSaint-Pierre-et-MiquelonΣαιν-Πιερ και Μικελόνסן-פייר ומיקלוןसन्त पियर और मिकलानSaint-Pierre és MiquelonSaint Pierre dan MiquelonSaint-Pierre e Miquelonサンピエール島・ミクロン島생피에르 미클롱Saint-Pierre en MiquelonSaint-Pierre i MiquelonSaint-Pierre e MiquelonСен-Пьер и МикелонSaint-Pierre och MiquelonSaint Pierre ve MiquelonСен-П'єр і Мікелонسینٹ پیئر و میکیلونSaint-Pierre và Miquelon圣皮埃尔和密克隆聖皮埃與密克隆群島Admin-0 dependencyAdmin-0 dependency Admin-0 country34FranceFR112Dependency1Wallis and FutunaWLF0Wallis and FutunaWLF0Wallis and FutunaWLF0Wallis and Futuna Is.Wallis and Futuna IslandsWLFWallis and Futuna IslandsWlf.WFWallis and Futuna IslandsWallis and FutunaFr.Wallis and Futuna759 11 11558.0 62018 6020166. Developing region4. Lower middle incomeWFWFWFWLFWLF876876876-99-992342498923424989Exact WOE match as countryWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLFWLF-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific2125 4 3-990.04.7 9.0-178.137436-14.2864151159320649Q35555واليس وفوتوناওয়ালিস ও ফুটুনাWallis und FutunaWallis and FutunaWallis y Futunaوالیس و فوتوناWallis-et-FutunaΟυαλίς και Φουτουνάואליס ופוטונהवालिस और फ़्यूचूनाWallis és FutunaWallis dan FutunaWallis e Futunaウォリス・フツナ왈리스 푸투나Wallis en FutunaWallis i FutunaWallis e FutunaУоллис и ФутунаWallis- och FutunaöarnaWallis ve Futuna AdalarıВолліс і Футунаوالس و فتونہWallis và Futuna瓦利斯和富图纳瓦利斯和富圖納Admin-0 dependencyAdmin-0 dependency Admin-0 country36FranceFR112Dependency1Saint MartinMAF0Saint MartinMAF0Saint MartinMAF0St-MartinSaint-MartinMAFSaint-MartinSt. M.MFSaint-Martin (French part)Saint MartinFr.St. Martin (French part)759 11 38002.0 72019 56220166. Developing region2. High income: nonOECDRNMFMFMAFMAF663663663MFMAF5604230556042305Exact WOE match as countryMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAFMAF-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 912 6 4-990.05.010.0 -63.049399 18.0813021159320639Q126125تجمع سان مارتينসেন্ট-মার্টিনSaint-MartinSaint MartinSan Martínسنت مارتین فرانسهSaint-MartinΆγιος Μαρτίνοςסן מרטןसेंट मार्टिन की सामूहिकताSaint-MartinSaint MartinSaint-Martinサン・マルタン생마르탱Sint-MaartenSaint-MartinSão MartinhoСен-МартенSaint MartinSaint MartinСен-Мартенسینٹ مارٹنSaint-Martin法属圣马丁法屬聖馬丁Admin-0 dependencyAdmin-0 dependency Admin-0 country36FranceFR112Dependency1Saint BarthelemyBLM0Saint BarthelemyBLM0Saint BarthelemyBLM0St-BarthélemySaint-BarthélemyBLMSt-BarthélemySt. B.BLSaint-BarthélemySaint BarthelemyFr.St-Barthélemy759 11 9961.0 52017 25520162. Developed region: nonG71. High income: OECDTBBLBLBLMBLM652652652-99-995604230456042304Exact WOE match as countryBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLMBLM-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1316 6 4-990.05.710.0 -62.833193 17.9019871159320633Q25362سان بارتيلميসেন্ট-বার্থেলেমিSaint-BarthélemySaint BarthélemySan Bartoloméسنت بارثلمیSaint-BarthélemyΆγιος Βαρθολομαίοςסן ברתלמיसेंट बार्थेलेमीSaint-BarthélemySaint-BarthélemySaint-Barthélemyサン・バルテルミー島생바르텔레미Saint-BarthélemySaint-BarthélemyColetividade de São BartolomeuСен-БартелемиSaint-BarthélemySaint BarthélemyСен-Бартельміسینٹ بارتھیملےSaint-Barthélemy圣巴泰勒米聖巴瑟米Admin-0 dependencyAdmin-0 dependency Admin-0 country34FranceFR112Dependency1French PolynesiaPYF0French PolynesiaPYF0French PolynesiaPYF0Fr. PolynesiaFrench PolynesiaPYFFr. PolynesiaFr. Poly.PFFrench PolynesiaFrench PolynesiaFr.French Polynesia759 11 279287.0102019 549020166. Developing region2. High income: nonOECDFPPFPFPYFPYF258258258PFPYF2342481723424817Exact WOE match as countryPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYFPYF-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific1316 9 2-990.03.5 8.5-149.461570-17.6280811159320643Q30971بولينزيا الفرنسيةফরাসি পলিনেশিয়াFranzösisch-PolynesienFrench PolynesiaPolinesia Francesaپلینزی فرانسهPolynésie françaiseΓαλλική Πολυνησίαפולינזיה הצרפתיתफ़्रान्सीसी पॉलिनेशियाFrancia PolinéziaPolinesia PrancisPolinesia franceseフランス領ポリネシア프랑스령 폴리네시아Frans-PolynesiëPolinezja FrancuskaPolinésia FrancesaФранцузская ПолинезияFranska PolynesienFransız PolinezyasıФранцузька Полінезіяفرانسیسی پولینیشیاPolynésie thuộc Pháp法属波利尼西亚法屬玻里尼西亞Admin-0 dependencyAdmin-0 dependency Admin-0 country13FranceFR112Dependency1New CaledoniaNCL0New CaledoniaNCL0New CaledoniaNCL0New CaledoniaNew CaledoniaNCLNew CaledoniaNew C.NCNew CaledoniaNouvelle-CalédonieNew CaledoniaFr.New Caledonia759 11 287800.0102019 1077020166. Developing region2. High income: nonOECDNCNCNCNCLNCL540540540NCNCL2342490323424903Exact WOE match as countryNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCLNCL-99-99OceaniaOceaniaMelanesiaEast Asia & Pacific1313 6-99-990.04.6 8.0 165.084004-21.0646971159320641Q33788كاليدونيا الجديدةনতুন ক্যালিডোনিয়াNeukaledonienNew CaledoniaNueva Caledoniaکالدونیای جدیدNouvelle-CalédonieΝέα Καληδονίαקלדוניה החדשהनया कैलेडोनियाÚj-KaledóniaKaledonia BaruNuova Caledoniaニューカレドニア누벨칼레도니Nieuw-CaledoniëNowa KaledoniaNova CaledóniaНовая КаледонияNya KaledonienYeni KaledonyaНова Каледоніяنیو کیلیڈونیاNouvelle-Calédonie新喀里多尼亚新喀里多尼亞Admin-0 dependencyAdmin-0 dependency Admin-0 country36FranceFR112Dependency1French Southern and Antarctic LandsATF0French Southern and Antarctic LandsATF0French Southern and Antarctic LandsATF0Fr. S. Antarctic LandsFrench Southern and Antarctic LandsATFFr. S. and Antarctic LandsFr. S.A.L.TFTerritory of the French Southern and Antarctic LandsFr.French Southern and Antarctic Lands759 11 140.0 12017 1620166. Developing region2. High income: nonOECDFSTFTFATFATF260260260-99-992828940628289406Exact WOE match as countryATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATFATF-99-99Seven seas (open ocean)AfricaSeven seas (open ocean)Sub-Saharan Africa223510 2-990.04.0 9.0 69.122136-49.3037211159320631Q129003أراض فرنسية جنوبية وأنتارتيكيةফ্র. এস. অ্যান্ড অ্যান্টার্কটিক ল্যান্ডFranzösische Süd- und AntarktisgebieteFrench Southern and Antarctic LandsTierras Australes y Antárticas Francesasسرزمینهای جنوبی و جنوبگانی فرانسهTerres australes et antarctiques françaisesΓαλλικά Νότια και Ανταρκτικά Εδάφηהארצות הדרומיות והאנטארקטיות של צרפתदक्षिण फ्रांसीसी और अंटार्कटिक लैंडFrancia déli és antarktiszi területekDaratan Selatan dan Antarktika PerancisTerre australi e antartiche francesiフランス領南方・南極地域프랑스령 남방 및 남극Franse Zuidelijke GebiedenFrancuskie Terytoria Południowe i AntarktyczneTerras Austrais e Antárticas FrancesasФранцузские Южные и Антарктические территорииFranska sydterritoriernaFransız Güney ve Antarktika TopraklarıФранцузькі Південні і Антарктичні територіїسرزمین جنوبی فرانسیسیہ و انٹارکٹیکاVùng đất phía Nam và châu Nam Cực thuộc Pháp法属南部和南极领地法屬南部和南極領地Admin-0 dependencyAdmin-0 dependency Admin-0 country36FinlandFI112Country1AlandALD0AlandALD0AlandALD0ÅlandÅland IslandsALDÅlandÅlandAIÅland IslandsFin.Aland414 6 29884.0 72019 156320162. Developed region: nonG71. High income: OECD-99AXAXALAALA248248248-99-991257786512577865Exact WOE match as countryALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALDALD-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 513 5 5-990.05.010.0 19.869671 60.1564671159320621Q5689جزر أولاندঅলান্দ দ্বীপপুঞ্জÅlandÅlandÅlandجزایر الندÅlandΏλαντאולנדऑलैण्ड द्वीपसमूहÅlandÅlandIsole Ålandオーランド諸島올란드 제도ÅlandWyspy AlandzkieÅlandАландские островаÅlandÅlandАландські островиجزائر ایلانڈÅland奥兰奧蘭Admin-0 dependencyAdmin-0 dependencyUnrecognizedUnrecognized Admin-0 country13FinlandFI112Country1FinlandFIN0FinlandFIN0FinlandFIN0FinlandFinlandFINFinlandFin.FINRepublic of FinlandFinlandFinland414 6 5520314.0132019 26929620192. Developed region: nonG71. High income: OECDFIFIFIFINFIN246246246FIFIN2342481223424812Exact WOE match as countryFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFINFIN-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 7 7 4-99 10.03.0 8.0 27.276449 63.2523611159320623Q33فنلنداফিনল্যান্ডFinnlandFinlandFinlandiaفنلاندFinlandeΦινλανδίαפינלנדफ़िनलैण्डFinnországFinlandiaFinlandiaフィンランド핀란드FinlandFinlandiaFinlândiaФинляндияFinlandFinlandiyaФінляндіяفن لینڈPhần Lan芬兰芬蘭Admin-0 countryAdmin-0 country Admin-0 country16FijiFJI02Sovereign country1FijiFJI0FijiFJI0FijiFJI0FijiFijiFJIFijiFijiFJRepublic of FijiFijiFiji512 2 889953.0112019 549620196. Developing region4. Lower middle incomeFJFJFJFJIFJI242242242FJFJI2342481323424813Exact WOE match as countryFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJIFJI-99-99OceaniaOceaniaMelanesiaEast Asia & Pacific 4 4 4-99 10.03.0 8.0 177.975427-17.8260991159320625Q712فيجيফিজিFidschiFijiFiyiفیجیFidjiΦίτζιפיג'יफ़िजीFidzsi-szigetekFijiFigiフィジー피지FijiFidżiFijiФиджиFijiFijiФіджіفجیFiji斐济斐濟Admin-0 countryAdmin-0 country Admin-0 country12EthiopiaETH02Sovereign country1EthiopiaETH0EthiopiaETH0EthiopiaETH0EthiopiaEthiopiaETHEthiopiaEth.ETFederal Democratic Republic of EthiopiaEthiopiaEthiopia441 13 112078730.0172019 9591220197. Least developed region5. Low incomeETETETETHETH231231231ETETH2342480823424808Exact WOE match as countryETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETHETH-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 8 8 4-99 10.02.0 7.0 39.088600 8.0327951159320617Q115إثيوبياইথিওপিয়াÄthiopienEthiopiaEtiopíaاتیوپیÉthiopieΑιθιοπίαאתיופיהइथियोपियाEtiópiaEthiopiaEtiopiaエチオピア에티오피아EthiopiëEtiopiaEtiópiaЭфиопияEtiopienEtiyopyaЕфіопіяایتھوپیاEthiopia埃塞俄比亚衣索比亞Admin-0 countryAdmin-0 country Admin-0 country16EstoniaEST02Sovereign country1EstoniaEST0EstoniaEST0EstoniaEST0EstoniaEstoniaESTEstoniaEst.ESTRepublic of EstoniaEstoniaEstonia321 10 1326590.0122019 3147120192. Developed region: nonG71. High income: OECDENEEEEESTEST233233233EEEST2342480523424805Exact WOE match as countryESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTESTEST-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 7 7 4-99 10.03.0 8.0 25.867126 58.7248651159320615Q191إستونياএস্তোনিয়াEstlandEstoniaEstoniaاستونیEstonieΕσθονίαאסטוניהएस्टोनियाÉsztországEstoniaEstoniaエストニア에스토니아EstlandEstoniaEstóniaЭстонияEstlandEstonyaЕстоніяاستونیاEstonia爱沙尼亚愛沙尼亞Admin-0 countryAdmin-0 country Admin-0 country14EritreaERI02Sovereign country1EritreaERI0EritreaERI0EritreaERI0EritreaEritreaERIEritreaErit.ERState of EritreaEritreaEritrea312 12 6081196.0132020 206520117. Least developed region5. Low incomeERERERERIERI232232232ERERI2342480623424806Exact WOE match as countryERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERIERI-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 7 7 5-99 10.04.0 9.0 38.285566 15.7874011159320581Q986إريترياইরিত্রিয়াEritreaEritreaEritreaاریترهÉrythréeΕρυθραίαאריתריאהइरित्रियाEritreaEritreaEritreaエリトリア에리트레아EritreaErytreaEritreiaЭритреяEritreaEritreЕритреяاریتریاEritrea厄立特里亚厄利垂亞Admin-0 countryAdmin-0 country Admin-0 country14Equatorial GuineaGNQ02Sovereign country1Equatorial GuineaGNQ0Equatorial GuineaGNQ0Equatorial GuineaGNQ0Eq. GuineaEquatorial GuineaGNQEq. GuineaEq. G.GQRepublic of Equatorial GuineaEquatorial GuineaEquatorial Guinea414 8 1355986.0122019 1102620197. Least developed region2. High income: nonOECDEKGQGQGNQGNQ226226226GQGNQ2342480423424804Exact WOE match as countryGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQGNQ-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa1017 6-99 10.04.0 9.0 8.990200 2.3330001159320801Q983غينيا الاستوائيةবিষুবীয় গিনিÄquatorialguineaEquatorial GuineaGuinea Ecuatorialگینه استواییGuinée équatorialeΙσημερινή Γουινέαגינאה המשווניתभूमध्यरेखीय गिनीEgyenlítői-GuineaGuinea KhatulistiwaGuinea Equatoriale赤道ギニア적도 기니Equatoriaal-GuineaGwinea RównikowaGuiné EquatorialЭкваториальная ГвинеяEkvatorialguineaEkvator GinesiЕкваторіальна Гвінеяاستوائی گنیGuinea Xích Đạo赤道几内亚赤道幾內亞Admin-0 countryAdmin-0 country Admin-0 country16El SalvadorSLV02Sovereign country1El SalvadorSLV0El SalvadorSLV0El SalvadorSLV0El SalvadorEl SalvadorSLVEl SalvadorEl. S.SVRepublic of El SalvadorEl SalvadorEl Salvador146 8 6453553.0132019 2702220196. Developing region4. Lower middle incomeESSVSVSLVSLV222222222SVSLV2342480723424807Exact WOE match as countrySLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLVSLV-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean1111 6-99 10.05.010.0 -88.890124 13.6853711159321253Q792السلفادورএল সালভাদোরEl SalvadorEl SalvadorEl SalvadorالسالوادورSalvadorΕλ Σαλβαδόρאל סלוודורअल साल्वाडोरSalvadorEl SalvadorEl Salvadorエルサルバドル엘살바도르El SalvadorSalwadorEl SalvadorСальвадорEl SalvadorEl SalvadorСальвадорایل سیلواڈورEl Salvador萨尔瓦多薩爾瓦多Admin-0 countryAdmin-0 country Admin-0 country12EgyptEGY02Sovereign country1EgyptEGY0EgyptEGY0EgyptEGY0EgyptEgyptEGYEgyptEgyptEGArab Republic of EgyptEgyptEgypt, Arab Rep.467 2 100388073.0172019 30309220195. Emerging region: G204. Lower middle incomeEGEGEGEGYEGY818818818EGEGY2342480223424802Exact WOE match as countryEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGYEGY-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 5 5 5-99 10.01.7 6.7 29.445837 26.1861731159320575Q79مصرমিশরÄgyptenEgyptEgiptoمصرÉgypteΑίγυπτοςמצריםमिस्रEgyiptomMesirEgittoエジプト이집트EgypteEgiptEgitoЕгипетEgyptenMısırЄгипетمصرAi Cập埃及埃及Admin-0 countryAdmin-0 country Admin-0 country13EcuadorECU02Sovereign country1EcuadorECU0EcuadorECU0EcuadorECU0EcuadorEcuadorECUEcuadorEcu.ECRepublic of EcuadorEcuadorEcuador152 12 17373662.0142019 10743520196. Developing region3. Upper middle incomeECECECECUECU218218218ECECU2342480123424801Exact WOE match as countryECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECUECU-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 7 7 4-99 10.03.0 8.0 -78.188375 -1.2590761159320567Q736الإكوادورইকুয়েডরEcuadorEcuadorEcuadorاکوادورÉquateurΕκουαδόρאקוודורईक्वाडोरEcuadorEkuadorEcuadorエクアドル에콰도르EcuadorEkwadorEquadorЭквадорEcuadorEkvadorЕквадорایکواڈورEcuador厄瓜多尔厄瓜多爾Admin-0 countryAdmin-0 country Admin-0 country15Dominican RepublicDOM02Sovereign country1Dominican RepublicDOM0Dominican RepublicDOM0Dominican RepublicDOM0Dominican Rep.Dominican RepublicDOMDominican Rep.Dom. Rep.DODominican RepublicDominican RepublicDominican Republic525 7 10738958.0142019 8894120196. Developing region3. Upper middle incomeDRDODODOMDOM214214214DODOM2342480023424800Exact WOE match as countryDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOMDOM-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1418 9-99 10.04.5 9.5 -70.653998 19.1041371159320563Q786جمهورية الدومينيكانডোমিনিকান প্রজাতন্ত্রDominikanische RepublikDominican RepublicRepública Dominicanaجمهوری دومینیکنRépublique dominicaineΔομινικανή Δημοκρατίαהרפובליקה הדומיניקניתडोमिनिकन गणराज्यDominikai KöztársaságRepublik DominikaRepubblica Dominicanaドミニカ共和国도미니카 공화국Dominicaanse RepubliekDominikanaRepública DominicanaДоминиканская РеспубликаDominikanska republikenDominik CumhuriyetiДомініканська Республікаجمہوریہ ڈومینیکنCộng hòa Dominica多米尼加多明尼加Admin-0 countryAdmin-0 country Admin-0 country16DominicaDMA02Sovereign country1DominicaDMA0DominicaDMA0DominicaDMA0DominicaDominicaDMADominicaD'incaDMCommonwealth of DominicaDominicaDominica452 12 71808.0 82019 58220196. Developing region3. Upper middle incomeDODMDMDMADMA212212212DMDMA2342479823424798Exact WOE match as countryDMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMADMA-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 8 8 6 4 10.04.0 9.0 -61.344958 15.4588291159320543Q784دومينيكاডোমিনিকাDominicaDominicaDominicaدومینیکاDominiqueΔομινίκαדומיניקהडोमिनिकाDominikai KözösségDominikaDominicaドミニカ国도미니카 연방DominicaDominikaDominicaДоминикаDominicaDominikaДомінікаڈومینیکاDominica多米尼克多米尼克Admin-0 countryAdmin-0 country Admin-0 country15DjiboutiDJI02Sovereign country1DjiboutiDJI0DjiboutiDJI0DjiboutiDJI0DjiboutiDjiboutiDJIDjiboutiDji.DJRepublic of DjiboutiDjiboutiDjibouti124 8 973560.0112019 332420197. Least developed region4. Lower middle incomeDJDJDJDJIDJI262262262DJDJI2342479723424797Exact WOE match as countryDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJIDJI-99-99AfricaAfricaEastern AfricaMiddle East & North Africa 8 8 4-99 10.04.0 9.0 42.498825 11.9763431159320541Q977جيبوتيজিবুতিDschibutiDjiboutiYibutiجیبوتیDjiboutiΤζιμπουτίג'יבוטיजिबूतीDzsibutiDjiboutiGibutiジブチ지부티DjiboutiDżibutiDjiboutiДжибутиDjiboutiCibutiДжибутіجبوتیDjibouti吉布提吉布地Admin-0 countryAdmin-0 country Admin-0 country13DenmarkDN112Country1GreenlandGRL0GreenlandGRL0GreenlandGRL0GreenlandGreenlandGRLGreenlandGrlnd.GLGreenlandGreenlandDen.Greenland413 12 56225.0 82019 305120182. Developed region: nonG72. High income: nonOECDGLGLGLGRLGRL304304304GLGRL2342482823424828Exact WOE match as countryGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRLGRL-99-99North AmericaAmericasNorthern AmericaEurope & Central Asia 9 9 6-99-990.01.7 6.7 -39.335251 74.3193871159320551Q223جرينلاندগ্রিনল্যান্ডGrönlandGreenlandGroenlandiaگرینلندGroenlandΓροιλανδίαגרינלנדग्रीनलैण्डGrönlandGreenlandGroenlandiaグリーンランド그린란드GroenlandGrenlandiaGroenlândiaГренландияGrönlandGrönlandГренландіяگرین لینڈGreenland格陵兰格陵蘭Admin-0 dependencyAdmin-0 dependency Admin-0 country36DenmarkDN112Dependency1Faroe IslandsFRO0Faroe IslandsFRO0Faroe IslandsFRO0Faeroe Is.Faeroe IslandsFROFaeroe IslandsFaeroe Is.FOFøroyar Is. (Faeroe Is.)Faroe IslandsDen.Faeroe Islands413 12 48678.0 72019 311620182. Developed region: nonG72. High income: nonOECDFOFOFOFROFRO234234234FOFRO2342481623424816Exact WOE match as countryFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFROFRO-99-99EuropeEuropeNorthern EuropeEurope & Central Asia101410 3-990.04.0 9.0 -7.058429 62.1856041159320549Q4628جزر فاروফ্যারো দ্বীপপুঞ্জFäröerFaroe IslandsIslas Feroeجزایر فاروîles FéroéΝήσοι Φερόεςאיי פארוफ़रो द्वीपसमूहFeröerKepulauan FaroeFær Øerフェロー諸島페로 제도FaeröerWyspy OwczeIlhas FeroeФарерские островаFäröarnaFaroe AdalarıФарерські островиجزائرفاروQuần đảo Faroe法罗群岛法羅群島Admin-0 dependencyAdmin-0 dependency Admin-0 country14DenmarkDN112Country1DenmarkDNK0DenmarkDNK0DenmarkDNK0DenmarkDenmarkDNKDenmarkDen.DKKingdom of DenmarkDenmarkDenmark413 12 5818553.0132019 35010420192. Developed region: nonG71. High income: OECDDADKDKDNKDNK208208208DKDNK2342479623424796Exact WOE match as countryDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNKDNK-99-99EuropeEuropeNorthern EuropeEurope & Central Asia 7 7 4-99 10.03.0 8.0 9.018163 55.9669651159320547Q35الدنماركডেনমার্কDänemarkDenmarkDinamarcaدانمارکDanemarkΔανίαדנמרקडेनमार्कDániaDenmarkDanimarcaデンマーク덴마크DenemarkenDaniaDinamarcaДанияDanmarkDanimarkaДаніяڈنمارکĐan Mạch丹麦丹麥Admin-0 countryAdmin-0 country Admin-0 country15CzechiaCZE02Sovereign country1CzechiaCZE0CzechiaCZE0CzechiaCZE0CzechiaCzech RepublicCZECzechiaCz.CZCzech Republicla République tchèqueCzechiaCzechiaČesko112 6 10669709.0142019 25068020192. Developed region: nonG71. High income: OECDEZCZCZCZECZE203203203CZCZE2342481023424810Exact WOE match as countryCZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZECZE-99-99EuropeEuropeEastern EuropeEurope & Central Asia 714 3-99 10.04.0 9.0 15.377555 49.8823641159320535Q213التشيكচেক প্রজাতন্ত্রTschechienCzech RepublicRepública Checaجمهوری چکTchéquieΤσεχίαצ'כיהचेक गणराज्यCsehországRepublik CekoRepubblica Cecaチェコ체코TsjechiëCzechyChéquiaЧехияTjeckienÇek CumhuriyetiЧехіяچیک جمہوریہCộng hòa Séc捷克捷克共和國Admin-0 countryAdmin-0 country Admin-0 country16Northern CyprusCYN02Sovereign country1Northern CyprusCYN0Northern CyprusCYN0Northern CyprusCYN0N. CyprusNorthern CyprusCYNN. CyprusN. Cy.CNTurkish Republic of Northern CyprusSelf admin.Self admin.; Claimed by CyprusCyprus, Northern314 8 326000.0102017 360020136. Developing region3. Upper middle income-99-99-99-99-99-99-99-099-99-99 -9023424995WOE lists as subunit of united CyprusCYP1CYNCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYNCYPCYPCYPCYPCYPCYPCYPCYP-99-99AsiaAsiaWestern AsiaEurope & Central Asia 915 6-99 10.06.010.0 33.692434 35.2160711159320531Q23681قبرص الشماليةউত্তর সাইপ্রাসTürkische Republik NordzypernTurkish Republic of Northern CyprusRepública Turca del Norte de Chipreجمهوری ترک قبرس شمالیChypre du NordΤουρκική Δημοκρατία της Βόρειας Κύπρουהרפובליקה הטורקית של צפון קפריסיןउत्तरी साइप्रसÉszak-CiprusRepublik Turki Siprus UtaraCipro del Nord北キプロス・トルコ共和国북키프로스Noord-CyprusCypr PółnocnyRepública Turca do Chipre do NorteТурецкая Республика Северного КипраNordcypernKuzey Kıbrıs Türk CumhuriyetiТурецька Республіка Північного Кіпруترک جمہوریہ شمالی قبرصBắc Síp北塞浦路斯土耳其共和国北賽普勒斯土耳其共和國Unrecognized1Admin-0 countryAdmin-0 breakaway and disputedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedAdmin-0 countryUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognized Admin-0 country15CyprusCYP02Sovereign country1CyprusCYP0CyprusCYP0CyprusCYP0CyprusCyprusCYPCyprusCyp.CYRepublic of CyprusCyprusCyprus123 7 1198575.0122019 2494820196. Developing region2. High income: nonOECDCYCYCYCYPCYP196196196CYCYP -9023424994WOE lists as subunit of united CyprusCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYPCYP-99-99AsiaAsiaWestern AsiaEurope & Central Asia 6 6 4-99 10.04.5 9.5 33.084182 34.9133291159320533Q229قبرصসাইপ্রাসRepublik ZypernCyprusChipreقبرسChypreΚύπροςקפריסיןसाइप्रसCiprusSiprusCiproキプロス키프로스CyprusCyprChipreКипрCypernKıbrıs CumhuriyetiКіпрقبرصCộng hòa Síp塞浦路斯賽普勒斯Admin-0 countryAdmin-0 country Admin-0 country13CubaCU111Sovereignty1CubaCUB0CubaCUB0CubaCUB0CubaCubaCUBCubaCubaCURepublic of CubaCubaCuba353 4 11333483.0142019 10002320185. Emerging region: G203. Upper middle incomeCUCUCUCUBCUB192192192CUCUB2342479323424793Exact WOE match as countryCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUBCUB-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 4 4 4-99 10.02.7 8.0 -77.975855 21.3340241159320527Q241كوباকিউবাKubaCubaCubaکوباCubaΚούβαקובהक्यूबाKubaKubaCubaキューバ쿠바CubaKubaCubaКубаKubaKübaКубаکیوباCuba古巴古巴Admin-0 countryAdmin-0 country Admin-0 country16CroatiaHRV02Sovereign country1CroatiaHRV0CroatiaHRV0CroatiaHRV0CroatiaCroatiaHRVCroatiaCro.HRRepublic of CroatiaCroatiaCroatia545 1 4067500.0122019 6075220192. Developed region: nonG72. High income: nonOECDHRHRHRHRVHRV191191191HRHRV2342484323424843Exact WOE match as countryHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRVHRV-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 7 7 4-99 10.04.0 9.0 16.372410 45.8057991159320833Q224كرواتياক্রোয়েশিয়াKroatienCroatiaCroaciaکرواسیCroatieΚροατίαקרואטיהक्रोएशियाHorvátországKroasiaCroaziaクロアチア크로아티아KroatiëChorwacjaCroáciaХорватияKroatienHırvatistanХорватіяکروشیاCroatia克罗地亚克羅地亞Admin-0 countryAdmin-0 country Admin-0 country53Ivory CoastCIV02Sovereign country1Ivory CoastCIV0Ivory CoastCIV0Ivory CoastCIV0Côte d'IvoireCôte d'IvoireCIVCôte d'IvoireI.C.CIRepublic of Ivory CoastRepublic of Cote D'IvoireCote D'ivoireCôte d'Ivoire463 3 25716544.0152019 5853920196. Developing region4. Lower middle incomeIVCICICIVCIV384384384CICIV2342485423424854Exact WOE match as countryCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIVCIV-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1313 4-99 10.02.5 8.0 -5.568618 7.4913901159320507Q1008ساحل العاجকোত দিভোয়ারElfenbeinküsteIvory CoastCosta de Marfilساحل عاجCôte d'IvoireΑκτή Ελεφαντοστούחוף השנהבकोत दिव्वारElefántcsontpartPantai GadingCosta d'Avorioコートジボワール코트디부아르IvoorkustWybrzeże Kości SłoniowejCosta do MarfimКот-д’ИвуарElfenbenskustenFildişi SahiliКот-д'Івуарکوت داوواغBờ Biển Ngà科特迪瓦象牙海岸Admin-0 countryAdmin-0 country Admin-0 country15Costa RicaCRI02Sovereign country1Costa RicaCRI0Costa RicaCRI0Costa RicaCRI0Costa RicaCosta RicaCRICosta RicaC.R.CRRepublic of Costa RicaCosta RicaCosta Rica324 2 5047561.0132019 6180120195. Emerging region: G203. Upper middle incomeCSCRCRCRICRI188188188CRCRI2342479123424791Exact WOE match as countryCRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRICRI-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean1010 4-99 10.02.5 8.0 -84.077922 10.0651001159320525Q800كوستاريكاকোস্টা রিকাCosta RicaCosta RicaCosta RicaکاستاریکاCosta RicaΚόστα Ρίκαקוסטה ריקהकोस्टा रीकाCosta RicaKosta RikaCosta Ricaコスタリカ코스타리카Costa RicaKostarykaCosta RicaКоста-РикаCosta RicaKosta RikaКоста-РикаکوسٹاریکاCosta Rica哥斯达黎加哥斯大黎加Admin-0 countryAdmin-0 country Admin-0 country12Democratic Republic of the CongoCOD02Sovereign country1Democratic Republic of the CongoCOD0Democratic Republic of the CongoCOD0Democratic Republic of the CongoCOD0Dem. Rep. CongoDemocratic Republic of the CongoCODDemocratic Republic of the CongoD.R.C.DRCDemocratic Republic of the CongoCongo, Democratic Republic of theCongo, Dem. Rep.444 7 86790567.0162019 5040020197. Least developed region5. Low incomeCGCDCDCODCOD180180180ZRZAR2342478023424780Exact WOE match as countryCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCODCOD-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa1532 6-99 10.02.0 7.0 23.458829 -1.8581671159320513Q974جمهورية الكونغو الديمقراطيةগণতান্ত্রিক কঙ্গো প্রজাতন্ত্রDemokratische Republik KongoDemocratic Republic of the CongoRepública Democrática del Congoجمهوری دموکراتیک کنگوRépublique démocratique du CongoΛαϊκή Δημοκρατία του Κονγκόהרפובליקה הדמוקרטית של קונגוकांगो लोकतान्त्रिक गणराज्यKongói Demokratikus KöztársaságRepublik Demokratik KongoRepubblica Democratica del Congoコンゴ民主共和国콩고 민주 공화국Congo-KinshasaDemokratyczna Republika KongaRepública Democrática do CongoДемократическая Республика КонгоKongo-KinshasaDemokratik Kongo CumhuriyetiДемократична Республіка Конгоجمہوری جمہوریہ کانگوCộng hòa Dân chủ Congo刚果民主共和国剛果民主共和國Admin-0 countryAdmin-0 country Admin-0 country14Republic of the CongoCOG02Sovereign country1Republic of the CongoCOG0Republic of the CongoCOG0Republic of the CongoCOG0CongoRepublic of the CongoCOGRepublic of the CongoRep. CongoCGRepublic of the CongoCongo, Republic of theCongo, Rep.213 10 5380508.0132019 1226720196. Developing region4. Lower middle incomeCFCGCGCOGCOG178178178CGCOG2342477923424779Exact WOE match as countryCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOGCOG-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa 52110-99 10.04.0 9.0 15.900500 0.1423311159320515Q971جمهورية الكونغوকঙ্গো প্রজাতন্ত্রRepublik KongoRepublic of the CongoRepública del Congoجمهوری کنگوRépublique du CongoΔημοκρατία του Κονγκόהרפובליקה של קונגוकांगो गणराज्यKongói KöztársaságRepublik KongoRepubblica del Congoコンゴ共和国콩고 공화국Congo-BrazzavilleKongoRepública do CongoРеспублика КонгоKongo-BrazzavilleKongo CumhuriyetiРеспубліка Конгоجمہوریہ کانگوCộng hòa Congo刚果共和国剛果共和國Admin-0 countryAdmin-0 country Admin-0 country36ComorosCOM02Sovereign country1ComorosCOM0ComorosCOM0ComorosCOM0ComorosComorosCOMComorosCom.KMUnion of the ComorosComorosComoros214 10 850886.0112019 116520197. Least developed region5. Low incomeCNKMKMCOMCOM174174174KMCOM2342478623424786Exact WOE match as countryCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOMCOM-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 7 7 4 2 10.04.0 9.0 43.318094-11.7276831159320521Q970جزر القمرকোমোরোসKomorenComorosComorasمجمعالجزایر قمرComoresΚομόρεςקומורוकोमोरोसComore-szigetekKomoroComoreコモロ코모로ComorenKomoryComoresКоморыKomorernaKomorlarКоморські Островиاتحاد القمریComoros科摩罗葛摩Admin-0 countryAdmin-0 country Admin-0 country12ColombiaCOL02Sovereign country1ColombiaCOL0ColombiaCOL0ColombiaCOL0ColombiaColombiaCOLColombiaCol.CORepublic of ColombiaColombiaColombia213 1 50339443.0162019 32361520196. Developing region3. Upper middle incomeCOCOCOCOLCOL170170170COCOL2342478723424787Exact WOE match as countryCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOLCOL-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 8 8 4-99 10.03.0 7.0 -73.174347 3.3731111159320517Q739كولومبياকলম্বিয়াKolumbienColombiaColombiaکلمبیاColombieΚολομβίαקולומביהकोलम्बियाKolumbiaKolombiaColombiaコロンビア콜롬비아ColombiaKolumbiaColômbiaКолумбияColombiaKolombiyaКолумбіяکولمبیاColombia哥伦比亚哥倫比亞Admin-0 countryAdmin-0 country Admin-0 country32ChinaCH112Country1ChinaCHN0ChinaCHN0ChinaCHN0ChinaChinaCHNChinaChinaCNPeople's Republic of ChinaChinaChina444 31397715000.01820191434290320193. Emerging region: BRIC3. Upper middle incomeCHCNCNCHNCHN156156156CNCHN2342478123424781Exact WOE match as countryCHNCHNCHNCHNCHNCHNCHNTWNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHNCHN-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 5 5 5-99 10.01.7 5.7 106.337289 32.4981781159320471Q148الصينগণচীনVolksrepublik ChinaPeople's Republic of ChinaChinaجمهوری خلق چینRépublique populaire de ChineΛαϊκή Δημοκρατία της Κίναςהרפובליקה העממית של סיןचीनी जनवादी गणराज्यKínaRepublik Rakyat TiongkokCina中華人民共和国중화인민공화국Volksrepubliek ChinaChińska Republika LudowaChinaКитайская Народная РеспубликаKinaÇin Halk CumhuriyetiКитайська Народна Республікаعوامی جمہوریہ چینTrung Quốc中华人民共和国中華人民共和國Admin-0 countryAdmin-0 countryUnrecognized Admin-0 country34ChinaCH112Country1Macao S.A.RMAC0Macao S.A.RMAC0Macao S.A.RMAC0MacaoMacaoMACMacaoMac.MOMacao Special Administrative Region, PRCMacauCn.ChinaMacao SAR, China444 3 640445.0112019 5385920196. Developing region2. High income: nonOECDMCMOMOMACMAC446446446MOMAC2007001720070017Exact WOE match as countryMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMACMAC-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 5 5 4-99-990.04.0 9.0 113.556038 22.1297351159320475Q14773ماكاوমাকাওMacauMacauMacaoماکائوMacaoΜακάουמקאוमकाउMakaóMakauMacaoマカオ마카오MacauMakauMacauМакаоMacaoMakaoАоминьمکاؤMa Cao澳门澳門Admin-0 dependencyAdmin-0 dependencyAdmin-1 region Admin-0 country34ChinaCH112Country1Hong Kong S.A.R.HKG0Hong Kong S.A.R.HKG0Hong Kong S.A.R.HKG0Hong KongHong KongHKGHong KongH.K.HKHong Kong Special Administrative Region, PRCHong KongCn.ChinaHong Kong SAR, China444 3 7507400.0132019 36571120196. Developing region2. High income: nonOECDHKHKHKHKGHKG344344344HKHKG2486569824865698Exact WOE match as countryHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKGHKG-99-99AsiaAsiaEastern AsiaEast Asia & Pacific 9 9 4-99-990.04.0 9.0 114.097769 22.4488291159320473Q8646هونغ كونغহংকংHongkongHong KongHong Kongهنگ کنگHong KongΧονγκ Κονγκהונג קונגहांगकांगHongkongHong KongHong Kong香港홍콩HongkongHongkongHong KongГонконгHongkongHong KongГонконгہانگ کانگHồng Kông香港香港Admin-0 dependencyAdmin-0 dependencyAdmin-1 region Admin-0 country42ChileCHL02Sovereign country1ChileCHL0ChileCHL0ChileCHL0ChileChileCHLChileChileCLRepublic of ChileChileChile515 9 18952038.0142019 28231820195. Emerging region: G203. Upper middle incomeCICLCLCHLCHL152152152CLCHL2342478223424782Exact WOE match as countryCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHLCHL-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 5 5 5-99 10.01.7 6.7 -72.318871-38.1517711159320493Q298تشيليচিলিChileChileChileشیلیChiliΧιλήצ'ילהचिलीChileChiliCileチリ칠레ChiliChileChileЧилиChileŞiliЧиліچلیChile智利智利Admin-0 countryAdmin-0 country Admin-0 country13ChadTCD02Sovereign country1ChadTCD0ChadTCD0ChadTCD0ChadChadTCDChadChadTDRepublic of ChadChadChad618 6 15946876.0142019 1131420197. Least developed region5. Low incomeCDTDTDTCDTCD148148148TDTCD2342477723424777Exact WOE match as countryTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCDTCD-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa 4 4 4-99 10.03.0 8.0 18.645041 15.1429591159321301Q657تشادচাদTschadChadChadچادTchadΤσαντצ'אדचाडCsádChadCiadチャド차드TsjaadCzadChadeЧадTchadÇadЧадچاڈTchad乍得查德Admin-0 countryAdmin-0 country Admin-0 country14Central African RepublicCAF02Sovereign country1Central African RepublicCAF0Central African RepublicCAF0Central African RepublicCAF0Central African Rep.Central African RepublicCAFCentral African Rep.C.A.R.CFCentral African RepublicCentral African RepublicCentral African Republic566 9 4745185.0122019 222020197. Least developed region5. Low incomeCTCFCFCAFCAF140140140CFCAF2342479223424792Exact WOE match as countryCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAFCAF-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa2024 6-99 10.04.0 9.0 20.906897 6.9896811159320463Q929جمهورية أفريقيا الوسطىমধ্য আফ্রিকান প্রজাতন্ত্রZentralafrikanische RepublikCentral African RepublicRepública Centroafricanaجمهوری آفریقای مرکزیRépublique centrafricaineΚεντροαφρικανική Δημοκρατίαהרפובליקה המרכז-אפריקאיתमध्य अफ़्रीकी गणराज्यKözép-afrikai KöztársaságRepublik Afrika TengahRepubblica Centrafricana中央アフリカ共和国중앙아프리카 공화국Centraal-Afrikaanse RepubliekRepublika ŚrodkowoafrykańskaRepública Centro-AfricanaЦентральноафриканская РеспубликаCentralafrikanska republikenOrta Afrika CumhuriyetiЦентральноафриканська Республікаوسطی افریقی جمہوریہCộng hòa Trung Phi中非共和国中非共和國Admin-0 countryAdmin-0 country Admin-0 country14Cabo VerdeCPV02Sovereign country1Cabo VerdeCPV0Cabo VerdeCPV0Cabo VerdeCPV0Cabo VerdeRepublic of Cabo VerdeCPVCabo VerdeC.Vd.CVRepublic of Cabo VerdeCabo VerdeCabo Verde114 11 549935.0112019 198120196. Developing region4. Lower middle incomeCVCVCVCPVCPV132132132CVCPV2342479423424794Exact WOE match as countryCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPVCPV-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1022 5-99 10.04.0 9.0 -23.639434 15.0747611159320523Q1011الرأس الأخضرকাবু ভের্দিKap VerdeCape VerdeCabo Verdeکیپ وردCap-VertΠράσινο Ακρωτήριοכף ורדהकेप वर्देZöld-foki KöztársaságTanjung VerdeCapo Verdeカーボベルデ카보베르데KaapverdiëRepublika Zielonego PrzylądkaCabo VerdeКабо-ВердеKap VerdeYeşil Burun AdalarıКабо-Вердеکیپ ورڈیCabo Verde佛得角維德角Admin-0 countryAdmin-0 country Admin-0 country12CanadaCAN02Sovereign country1CanadaCAN0CanadaCAN0CanadaCAN0CanadaCanadaCANCanadaCan.CACanadaCanadaCanada662 2 37589262.0152019 173642520191. Developed region: G71. High income: OECDCACACACANCAN124124124CACAN2342477523424775Exact WOE match as countryCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCANCAN-99-99North AmericaAmericasNorthern AmericaNorth America 6 6 4-99 10.01.7 5.7-101.910700 60.3242871159320467Q16كنداকানাডাKanadaCanadaCanadáکاناداCanadaΚαναδάςקנדהकनाडाKanadaKanadaCanadaカナダ캐나다CanadaKanadaCanadáКанадаKanadaKanadaКанадаکینیڈاCanada加拿大加拿大Admin-0 countryAdmin-0 country Admin-0 country13CameroonCMR02Sovereign country1CameroonCMR0CameroonCMR0CameroonCMR0CameroonCameroonCMRCameroonCam.CMRepublic of CameroonCameroonCameroon141 3 25876380.0152019 3900720196. Developing region4. Lower middle incomeCMCMCMCMRCMR120120120CMCMR2342478523424785Exact WOE match as countryCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMRCMR-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa 8 8 4-99 10.03.0 8.0 12.473488 4.5850411159320509Q1009الكاميرونক্যামেরুনKamerunCameroonCamerúnکامرونCamerounΚαμερούνקמרוןकैमरुनKamerunKamerunCamerunカメルーン카메룬KameroenKamerunCamarõesКамерунKamerunKamerunКамерунکیمرونCameroon喀麦隆喀麥隆Admin-0 countryAdmin-0 country Admin-0 country13CambodiaKHM02Sovereign country1CambodiaKHM0CambodiaKHM0CambodiaKHM0CambodiaCambodiaKHMCambodiaCamb.KHKingdom of CambodiaCambodiaCambodia636 5 16486542.0142019 2708920197. Least developed region5. Low incomeCBKHKHKHMKHM116116116KHKHM2342477623424776Exact WOE match as countryKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHMKHM-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 8 8 5-99 10.03.0 8.0 104.504870 12.6475841159320979Q424كمبودياকম্বোডিয়াKambodschaCambodiaCamboyaکامبوجCambodgeΚαμπότζηקמבודיהकम्बोडियाKambodzsaKambojaCambogiaカンボジア캄보디아CambodjaKambodżaCambojaКамбоджаKambodjaKamboçyaКамбоджаکمبوڈیاCampuchia柬埔寨柬埔寨Admin-0 countryAdmin-0 country Admin-0 country13MyanmarMMR02Sovereign country1MyanmarMMR0MyanmarMMR0MyanmarMMR0MyanmarMyanmarMMRMyanmarMyan.MMRepublic of the Union of MyanmarBurmaMyanmar225 13 54045420.0162019 7608520197. Least developed region5. Low incomeBMMMMMMMRMMR104104104MMMMR2342476323424763Exact WOE match as countryMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMRMMR-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 7 7 5-99 10.03.0 8.0 95.804497 21.5738551159321067Q836ميانمارমিয়ানমারMyanmarMyanmarBirmaniaمیانمارBirmanieΜιανμάρמיאנמרम्यान्मारMianmarMyanmarBirmaniaミャンマー미얀마MyanmarMjanmaMyanmarМьянмаMyanmarMyanmarМ'янмаمیانمارMyanma缅甸緬甸Admin-0 countryAdmin-0 country Admin-0 country16BurundiBDI02Sovereign country1BurundiBDI0BurundiBDI0BurundiBDI0BurundiBurundiBDIBurundiBur.BIRepublic of BurundiBurundiBurundi225 8 11530580.0142019 301220197. Least developed region5. Low incomeBYBIBIBDIBDI108108108BIBDI2342477423424774Exact WOE match as countryBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDIBDI-99-99AfricaAfricaEastern AfricaSub-Saharan Africa 7 7 4-99 10.04.0 9.0 29.917086 -3.3328361159320387Q967بورونديবুরুন্ডিBurundiBurundiBurundiبوروندیBurundiΜπουρούντιבורונדיबुरुण्डीBurundiBurundiBurundiブルンジ부룬디BurundiBurundiBurundiБурундиBurundiBurundiБурундіبرونڈیBurundi布隆迪蒲隆地Admin-0 countryAdmin-0 country Admin-0 country13Burkina FasoBFA02Sovereign country1Burkina FasoBFA0Burkina FasoBFA0Burkina FasoBFA0Burkina FasoBurkina FasoBFABurkina FasoB.F.BFBurkina FasoBurkina FasoBurkina Faso215 11 20321378.0152019 1599020197. Least developed region5. Low incomeUVBFBFBFABFA854854854BFBFA2342497823424978Exact WOE match as countryBFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFABFA-99-99AfricaAfricaWestern AfricaSub-Saharan Africa1212 4-99 10.03.0 8.0 -1.363880 12.6730481159320405Q965بوركينا فاسوবুর্কিনা ফাসোBurkina FasoBurkina FasoBurkina FasoبورکینافاسوBurkina FasoΜπουρκίνα Φάσοבורקינה פאסוबुर्किना फासोBurkina FasoBurkina FasoBurkina Fasoブルキナファソ부르키나파소Burkina FasoBurkina FasoBurkina FasoБуркина-ФасоBurkina FasoBurkina FasoБуркіна-Фасоبرکینا فاسوBurkina Faso布基纳法索布基納法索Admin-0 countryAdmin-0 country Admin-0 country14BulgariaBGR02Sovereign country1BulgariaBGR0BulgariaBGR0BulgariaBGR0BulgariaBulgariaBGRBulgariaBulg.BGRepublic of BulgariaBulgariaBulgaria451 8 6975761.0132019 6855820192. Developed region: nonG73. Upper middle incomeBUBGBGBGRBGR100100100BGBGR2342477123424771Exact WOE match as countryBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGRBGR-99-99EuropeEuropeEastern EuropeEurope & Central Asia 8 8 5-99 10.04.0 9.0 25.157090 42.5087851159320409Q219بلغارياবুলগেরিয়াBulgarienBulgariaBulgariaبلغارستانBulgarieΒουλγαρίαבולגריהबुल्गारियाBulgáriaBulgariaBulgariaブルガリア불가리아BulgarijeBułgariaBulgáriaБолгарияBulgarienBulgaristanБолгаріяبلغاریہBulgaria保加利亚保加利亞Admin-0 countryAdmin-0 country Admin-0 country16BruneiBRN02Sovereign country1BruneiBRN0BruneiBRN0BruneiBRN0BruneiBrunei DarussalamBRNBruneiBruneiBNNegara Brunei DarussalamBruneiBrunei466 12 433285.0102019 1346920196. Developing region2. High income: nonOECDBXBNBNBRNBRN096096096BNBRN2342477323424773Exact WOE match as countryBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRNBRN-99-99AsiaAsiaSouth-Eastern AsiaEast Asia & Pacific 617 6 2 10.04.0 9.0 114.551943 4.4482981159320451Q921برونايব্রুনাইBruneiBruneiBrunéiبرونئیBruneiΜπρουνέιברונייब्रुनेईBruneiBrunei DarussalamBruneiブルネイ브루나이BruneiBruneiBruneiБрунейBruneiBruneiБрунейبرونائی دار السلامBrunei文莱汶萊Admin-0 countryAdmin-0 country Admin-0 country12BrazilBRA02Sovereign country1BrazilBRA0BrazilBRA0BrazilBRA0BrazilBrazilBRABrazilBrazilBRFederative Republic of BrazilBrazilBrazil565 7 211049527.0172019 183975820193. Emerging region: BRIC3. Upper middle incomeBRBRBRBRABRA076076076BRBRA2342476823424768Exact WOE match as countryBRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRABRA-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 6 6 6-99 10.01.7 5.7 -49.559450-12.0986871159320441Q155البرازيلব্রাজিলBrasilienBrazilBrasilبرزیلBrésilΒραζιλίαברזילब्राज़ीलBrazíliaBrasilBrasileブラジル브라질BraziliëBrazyliaBrasilБразилияBrasilienBrezilyaБразиліяبرازیلBrasil巴西巴西Admin-0 countryAdmin-0 country Admin-0 country14BotswanaBWA02Sovereign country1BotswanaBWA0BotswanaBWA0BotswanaBWA0BotswanaBotswanaBWABotswanaBwa.BWRepublic of BotswanaBotswanaBotswana657 3 2303697.0122019 1834020196. Developing region3. Upper middle incomeBCBWBWBWABWA072072072BWBWA2342475523424755Exact WOE match as countryBWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWABWA-99-99AfricaAfricaSouthern AfricaSub-Saharan Africa 8 8 4-99 10.04.0 9.0 24.179216-22.1026341159320461Q963بوتسواناবতসোয়ানাBotswanaBotswanaBotsuanaبوتسواناBotswanaΜποτσουάναבוטסואנהबोत्सवानाBotswanaBotswanaBotswanaボツワナ보츠와나BotswanaBotswanaBotsuanaБотсванаBotswanaBotsvanaБотсванаبوٹسواناBotswana博茨瓦纳波札那Admin-0 countryAdmin-0 country Admin-0 country15Bosnia and HerzegovinaBIH02Sovereign country1Bosnia and HerzegovinaBIH0Bosnia and HerzegovinaBIH0Bosnia and HerzegovinaBIH0Bosnia and Herz.Bosnia and HerzegovinaBIHBosnia and Herz.B.H.BiHBosnia and HerzegovinaBosnia and HerzegovinaBosnia and Herzegovina111 2 3301000.0122019 2016420196. Developing region3. Upper middle incomeBKBABABIHBIH070070070BABIH2342476123424761Exact WOE match as countryBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIHBIH-99-99EuropeEuropeSouthern EuropeEurope & Central Asia1622 4-99 10.04.5 6.8 18.068410 44.0910511159320417Q225البوسنة والهرسكবসনিয়া ও হার্জেগোভিনাBosnien und HerzegowinaBosnia and HerzegovinaBosnia y Herzegovinaبوسنی و هرزگوینBosnie-HerzégovineΒοσνία και Ερζεγοβίνηבוסניה והרצגובינהबॉस्निया और हर्ज़ेगोविनाBosznia-HercegovinaBosnia dan HerzegovinaBosnia ed Erzegovinaボスニア・ヘルツェゴビナ보스니아 헤르체고비나Bosnië en HerzegovinaBośnia i HercegowinaBósnia e HerzegovinaБосния и ГерцеговинаBosnien och HercegovinaBosna-HersekБоснія і Герцеговинаبوسنیا و ہرزیگوویناBosna và Hercegovina波斯尼亚和黑塞哥维那波士尼亞與赫塞哥維納Admin-0 countryAdmin-0 country Admin-0 country13BoliviaBOL02Sovereign country1BoliviaBOL0BoliviaBOL0BoliviaBOL0BoliviaBoliviaBOLBoliviaBoliviaBOPlurinational State of BoliviaBoliviaBolivia152 3 11513100.0142019 4089520195. Emerging region: G204. Lower middle incomeBLBOBOBOLBOL068068068BOBOL2342476223424762Exact WOE match as countryBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOLBOL-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 7 7 7-99 10.03.0 7.5 -64.593433-16.6660151159320439Q750بوليفياবলিভিয়াBolivienBoliviaBoliviaبولیویBolivieΒολιβίαבוליביהबोलिवियाBolíviaBoliviaBoliviaボリビア볼리비아BoliviaBoliwiaBolíviaБоливияBoliviaBolivyaБолівіяبولیویاBolivia玻利维亚玻利維亞Admin-0 countryAdmin-0 country Admin-0 country15BhutanBTN02Sovereign country1BhutanBTN0BhutanBTN0BhutanBTN0BhutanBhutanBTNBhutanBhutanBTKingdom of BhutanBhutanBhutan561 8 763092.0112019 253020197. Least developed region4. Lower middle incomeBTBTBTBTNBTN064064064BTBTN2342477023424770Exact WOE match as countryBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTNBTN-99-99AsiaAsiaSouthern AsiaSouth Asia 6 6 6-99 10.04.0 9.0 90.040294 27.5366851159320453Q917بوتانভুটানBhutanBhutanButánبوتانBhoutanΜπουτάνבהוטןभूटानBhutánBhutanBhutanブータン부탄BhutanBhutanButãoБутанBhutanBhutanБутанبھوٹانBhutan不丹不丹Admin-0 countryAdmin-0 country Admin-0 country15BeninBEN02Sovereign country1BeninBEN0BeninBEN0BeninBEN0BeninBeninBENBeninBeninBJRepublic of BeninBeninBenin122 12 11801151.0142019 1439020197. Least developed region5. Low incomeBNBJBJBENBEN204204204BJBEN2342476423424764Exact WOE match as countryBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBENBEN-99-99AfricaAfricaWestern AfricaSub-Saharan Africa 5 5 5-99 10.04.0 9.0 2.352018 10.3247751159320399Q962بنينবেনিনBeninBeninBenínبنینBéninΜπενίνבניןबेनिनBeninBeninBeninベナン베냉BeninBeninBenimБенинBeninBeninБенінبیننBénin贝宁貝南Admin-0 countryAdmin-0 country Admin-0 country16BelizeBLZ02Sovereign country1BelizeBLZ0BelizeBLZ0BelizeBLZ0BelizeBelizeBLZBelizeBelizeBZBelizeBelizeBelize145 7 390353.0102019 187920196. Developing region4. Lower middle incomeBHBZBZBLZBLZ084084084BZBLZ2342476023424760Exact WOE match as countryBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZBLZ-99-99North AmericaAmericasCentral AmericaLatin America & Caribbean 6 6 6-99 10.05.010.0 -88.712962 17.2020681159320431Q242بليزবেলিজBelizeBelizeBeliceبلیزBelizeΜπελίζבליזबेलीज़BelizeBelizeBelizeベリーズ벨리즈BelizeBelizeBelizeБелизBelizeBelizeБелізبیلیزBelize伯利兹貝里斯Admin-0 countryAdmin-0 country Admin-0 country12BelgiumBEL02Sovereign country1BelgiumBEL0BelgiumBEL0BelgiumBEL0BelgiumBelgiumBELBelgiumBelg.BKingdom of BelgiumBelgiumBelgium321 8 11484055.0142019 53309720192. Developed region: nonG71. High income: OECDBEBEBEBELBEL056056056BEBEL2342475723424757Exact WOE match as countryBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBELBEL-99-99EuropeEuropeWestern EuropeEurope & Central Asia 7 7 5-99 10.04.0 9.0 4.800448 50.7853921159320389Q31بلجيكاবেলজিয়ামBelgienBelgiumBélgicaبلژیکBelgiqueΒέλγιοבלגיהबेल्जियमBelgiumBelgiaBelgioベルギー벨기에BelgiëBelgiaBélgicaБельгияBelgienBelçikaБельгіяبلجئیمBỉ比利时比利時Admin-0 countryAdmin-0 country Admin-0 country14BelarusBLR02Sovereign country1BelarusBLR0BelarusBLR0BelarusBLR0BelarusBelarusBLRBelarusBela.BYRepublic of BelarusBelarusBelarus115 11 9466856.0132019 6308020196. Developing region3. Upper middle incomeBOBYBYBLRBLR112112112BYBLR2342476523424765Exact WOE match as countryBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLR-99-99EuropeEuropeEastern EuropeEurope & Central Asia 7 7 5-99 10.03.0 8.0 28.417701 53.8218881159320427Q184بيلاروسياবেলারুশBelarusBelarusBielorrusiaبلاروسBiélorussieΛευκορωσίαבלארוסबेलारूसFehéroroszországBelarusBielorussiaベラルーシ벨라루스Wit-RuslandBiałoruśBielorrússiaБелоруссияBelarusBeyaz RusyaБілорусьبیلاروسBelarus白俄罗斯白俄羅斯Admin-0 countryAdmin-0 country Admin-0 country15BarbadosBRB02Sovereign country1BarbadosBRB0BarbadosBRB0BarbadosBRB0BarbadosBarbadosBRBBarbadosBarb.BBBarbadosBarbadosBarbados415 3 287025.0102019 520920196. Developing region2. High income: nonOECDBBBBBBBRBBRB052052052BBBRB2342475423424754Exact WOE match as countryBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBURYBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRBBRB-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 8 8 5 3 10.04.5 9.5 -59.568966 13.1637091159320449Q244باربادوسবার্বাডোসBarbadosBarbadosBarbadosباربادوسBarbadeΜπαρμπάντοςברבדוסबारबाडोसBarbadosBarbadosBarbadosバルバドス바베이도스BarbadosBarbadosBarbadosБарбадосBarbadosBarbadosБарбадосبارباڈوسBarbados巴巴多斯巴貝多Admin-0 countryAdmin-0 country Admin-0 country13BangladeshBGD02Sovereign country1BangladeshBGD0BangladeshBGD0BangladeshBGD0BangladeshBangladeshBGDBangladeshBang.BDPeople's Republic of BangladeshBangladeshBangladesh347 7 163046161.0172019 30257120197. Least developed region5. Low incomeBGBDBDBGDBGD050050050BDBGD2342475923424759Exact WOE match as countryBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGDBGD-99-99AsiaAsiaSouthern AsiaSouth Asia1010 5-99 10.03.0 8.0 89.684963 24.2149561159320407Q902بنغلاديشবাংলাদেশBangladeschBangladeshBangladésبنگلادشBangladeshΜπανγκλαντέςבנגלדשबांग्लादेशBangladesBangladeshBangladeshバングラデシュ방글라데시BangladeshBangladeszBangladeshБангладешBangladeshBangladeşБангладешبنگلہ دیشBangladesh孟加拉国孟加拉Admin-0 countryAdmin-0 country Admin-0 country14BahrainBHR02Sovereign country1BahrainBHR0BahrainBHR0BahrainBHR0BahrainBahrainBHRBahrainBahr.BHKingdom of BahrainBahrainBahrain111 9 1641172.0122019 3857420196. Developing region2. High income: nonOECDBABHBHBHRBHR048048048BHBHR2342475323424753Exact WOE match as countryBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHRBHR-99-99AsiaAsiaWestern AsiaMiddle East & North Africa 7 7 5 2 10.04.0 9.0 50.554816 26.0559721159320413Q398البحرينবাহরাইনBahrainBahrainBaréinبحرینBahreïnΜπαχρέινבחרייןबहरीनBahreinBahrainBahreinバーレーン바레인BahreinBahrajnBahreinБахрейнBahrainBahreynБахрейнبحرینBahrain巴林巴林Admin-0 countryAdmin-0 country Admin-0 country14The BahamasBHS02Sovereign country1The BahamasBHS0The BahamasBHS0The BahamasBHS0BahamasBahamasBHSBahamasBhs.BSCommonwealth of the BahamasBahamas, TheBahamas, The112 5 389482.0102019 1357820196. Developing region2. High income: nonOECDBFBSBSBHSBHS044044044BSBHS2342475823424758Exact WOE match as countryBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHSBHS-99-99North AmericaAmericasCaribbeanLatin America & Caribbean 7 7 4-99 10.04.0 9.0 -77.146688 26.4017891159320415Q778باهاماسবাহামা দ্বীপপুঞ্জBahamasThe BahamasBahamasباهاماBahamasΜπαχάμεςאיי בהאמהबहामासBahama-szigetekBahamaBahamasバハマ바하마Bahama'sBahamyBahamasБагамские ОстроваBahamasBahamalarБагамські ОстровиبہاماسBahamas巴哈马巴哈馬Admin-0 countryAdmin-0 country Admin-0 country15AzerbaijanAZE02Sovereign country1AzerbaijanAZE0AzerbaijanAZE0AzerbaijanAZE0AzerbaijanAzerbaijanAZEAzerbaijanAze.AZRepublic of AzerbaijanAzerbaijanAzerbaijan165 8 10023318.0142019 4804720196. Developing region3. Upper middle incomeAJAZAZAZEAZE031031031AZAZE2342474123424741Exact WOE match as countryAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZEAZE-99-99AsiaAsiaWestern AsiaEurope & Central Asia1010 4-99 10.04.0 9.0 47.210994 40.4023871159320381Q227أذربيجانআজারবাইজানAserbaidschanAzerbaijanAzerbaiyánجمهوری آذربایجانAzerbaïdjanΑζερμπαϊτζάνאזרבייג'ןअज़रबैजानAzerbajdzsánAzerbaijanAzerbaigianアゼルバイジャン아제르바이잔AzerbeidzjanAzerbejdżanAzerbaijãoАзербайджанAzerbajdzjanAzerbaycanАзербайджанآذربائیجانAzerbaijan阿塞拜疆亞塞拜然Admin-0 countryAdmin-0 country Admin-0 country14AustriaAUT02Sovereign country1AustriaAUT0AustriaAUT0AustriaAUT0AustriaAustriaAUTAustriaAust.ARepublic of AustriaAustriaAustria313 4 8877067.0132019 44507520192. Developed region: nonG71. High income: OECDAUATATAUTAUT040040040ATAUT2342475023424750Exact WOE match as countryAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUTAUT-99-99EuropeEuropeWestern EuropeEurope & Central Asia 7 7 5-99 10.03.0 8.0 14.130515 47.5188591159320379Q40النمساঅস্ট্রিয়াÖsterreichAustriaAustriaاتریشAutricheΑυστρίαאוסטריהऑस्ट्रियाAusztriaAustriaAustriaオーストリア오스트리아OostenrijkAustriaÁustriaАвстрияÖsterrikeAvusturyaАвстріяآسٹریاÁo奥地利奧地利Admin-0 countryAdmin-0 country Admin-0 country12AustraliaAU112Country1AustraliaAUS0AustraliaAUS0AustraliaAUS0AustraliaAustraliaAUSAustraliaAuz.AUCommonwealth of AustraliaAustraliaAustralia122 7 25364307.0152019 139656720192. Developed region: nonG71. High income: OECDASAUAUAUSAUS036036036AUAUS -9023424748Includes Ashmore and Cartier Islands (23424749) and Coral Sea Islands (23424790).AUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUSAUS-99-99OceaniaOceaniaAustralia and New ZealandEast Asia & Pacific 9 9 4-99 10.01.7 5.7 134.049720-24.1295221159320355Q408أسترالياঅস্ট্রেলিয়াAustralienAustraliaAustraliaاسترالیاAustralieΑυστραλίαאוסטרליהऑस्ट्रेलियाAusztráliaAustraliaAustraliaオーストラリア오스트레일리아AustraliëAustraliaAustráliaАвстралияAustralienAvustralyaАвстраліяآسٹریلیاÚc澳大利亚澳大利亞Admin-0 countryAdmin-0 country Admin-0 country55AustraliaAU112Dependency1Indian Ocean TerritoriesIOA0Indian Ocean TerritoriesIOA0Indian Ocean TerritoriesIOA0Indian Ocean Ter.Indian Ocean TerritoriesIOAIndian Ocean Ter.Ind. Oc. Ter.IOTAuz.Indian Ocean Territories122 7 2387.0 42016 3520162. Developed region: nonG72. High income: nonOECD-99-99AU-99AUS-99036-099-99-99 -9023424869Grouping of Christmas Island (23424869) and Cocos or Keeling Islands (23424784)AUS1IOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOAIOA-99-99AsiaAfricaSeven seas (open ocean)East Asia & Pacific172413-99-990.05.0 9.5 105.672590-10.4907891159320363Q4824275أقاليم المحيط الهندي الأستراليةঅস্ট্রেলীয় ভারত মহাসাগর অঞ্চলAustralische Territorien im Indischen OzeanAustralian Indian Ocean TerritoriesTerritorios Australianos del Océano Índicoسرزمینهای اقیانوس هند استرالیاTerritoires extérieurs australiens de l'Océan IndienΑυστραλέζικο Έδαφος Ινδικού Ωκεανούטריטוריה של האוקיינוס ההודיहिंद महासागर के ऑस्ट्रेलियाई क्षेत्रAusztrál Indiai-óceáni TerületWilayah Samudra Hindia AustraliaAustralian Indian Ocean Territoriesオーストラリア領インド洋地域호주령 인도양 지역Australische territoria van de Indische OceaanAustralijskie Terytorium Oceanu IndyjskiegoTerritórios australianos do Oceano ÍndicoАвстралийские территории в Индийском океанеAustralienska indiska oceanens havsområdeAustralian Indian Ocean TerritoriesАвстралійські території в Індійському океаніآسْٹْریلِیَن انڈین اوشین تیریتورییسVùng lãnh thổ Ấn Độ Dương thuộc Úc澳屬印度洋領地澳屬印度洋領地Unrecognized1Admin-0 dependency Admin-0 country55AustraliaAU112Dependency1Heard Island and McDonald IslandsHMD0Heard Island and McDonald IslandsHMD0Heard Island and McDonald IslandsHMD0Heard I. and McDonald Is.Heard I. and McDonald IslandsHMDHeard I. and McDonald Is.H.M.Is.HMTerritory of Heard Island and McDonald IslandsAuz.Heard Island and McDonald Islands122 7 0.0 12019 020167. Least developed region5. Low incomeHMHMHMHMDHMD334334-099-99-992828941128289411Exact WOE match as countryHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMDHMD-99-99Seven seas (open ocean)AfricaSeven seas (open ocean)Sub-Saharan Africa2529 7-99-990.04.5 9.5 73.505210-53.1034621159320361Q131198جزيرة هيرد وجزر ماكدونالدহার্ড দ্বীপ এবং ম্যাকডোনাল্ড দ্বীপপুঞ্জHeard und McDonaldinselnHeard Island and McDonald IslandsIslas Heard y McDonaldجزیره هرد و جزایر مکدونالدîles Heard-et-MacDonaldΝήσοι Χερντ και Μακντόναλντהאי הרד ואיי מקדונלדहर्ड द्वीप और मैकडोनाल्ड द्वीपHeard-sziget és McDonald-szigetekPulau Heard dan Kepulauan McDonaldIsole Heard e McDonaldハード島とマクドナルド諸島허드 맥도널드 제도Heard en McDonaldeilandenWyspy Heard i McDonaldaIlha Heard e Ilhas McDonaldОстров Херд и острова МакдональдHeard- och McDonaldöarnaHeard Adası ve McDonald AdalarıОстрів Герд і острови Макдональдجزیرہ ہرڈ و جزائر مکڈونلڈĐảo Heard và quần đảo McDonald赫德岛和麦克唐纳群岛赫德島和麥克唐納群島Admin-0 dependencyAdmin-0 dependency Admin-0 country55AustraliaAU112Dependency1Norfolk IslandNFK0Norfolk IslandNFK0Norfolk IslandNFK0Norfolk IslandNorfolk IslandNFKNorfolk IslandNfk. I.NFTerritory of Norfolk IslandNorfolk IslandAuz.Norfolk Island122 7 2169.0 42011 3220166. Developing region4. Lower middle incomeNFNFNFNFKNFK574574574-99-992342490523424905Exact WOE match as countryNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFKNFK-99-99OceaniaOceaniaAustralia and New ZealandEast Asia & Pacific1414 7-99-990.04.5 9.5 167.954531-29.0330421159320365Q31057جزيرة نورفولكনরফোক দ্বীপNorfolkinselNorfolk IslandIsla Norfolkجزیره نورفکÎle NorfolkΝόρφολκנורפוקनॉर्फ़ोक द्वीपNorfolk-szigetPulau NorfolkIsola Norfolkノーフォーク島노퍽섬NorfolkNorfolkIlha NorfolkНорфолкNorfolkönNorfolk Adasıострів Норфолкجزیرہ نارفولکĐảo Norfolk诺福克岛諾福克島Admin-0 dependencyAdmin-0 dependency Admin-0 country55AustraliaAU112Dependency1Ashmore and Cartier IslandsATC0Ashmore and Cartier IslandsATC0Ashmore and Cartier IslandsATC0Ashmore and Cartier Is.Ashmore and Cartier IslandsATCAshmore and Cartier Is.A.C.Is.AUTerritory of Ashmore and Cartier IslandsAuz.Ashmore and Cartier Islands122 7 0.0 12019 020197. Least developed region5. Low incomeAT-99AU-99AUS036036-099-99-992342474923424749WOE Admin-1 states provinces match.AUS1ATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATCATC-99-99OceaniaOceaniaAustralia and New ZealandEast Asia & Pacific2327 7-99-990.04.5 9.5 123.586368-12.4325711159320353Q133888جزر أشمور وكارتييرআসমর এবং কার্টিয়ে দ্বীপপুঞ্জAshmore- und CartierinselnAshmore and Cartier IslandsIslas Ashmore y Cartierجزیرههای آشمور و کارتیرÎles Ashmore-et-CartierΆσμορ και Καρτιέ Νησιάאיי אשמור וקרטייהएशमोर और कार्टियर द्वीप समूहAshmore- és Cartier-szigetekKepulauan Ashmore dan CartierIsole Ashmore e Cartierアシュモア・カルティエ諸島애시모어 카르티에 제도Ashmore- en CartiereilandenWyspy Ashmore i CartieraIlhas Ashmore e CartierОстрова Ашмор и КартьеAshmore- och CartieröarnaAshmore ve Cartier AdalarıОстрови Ашмор і Картьєجزائر ایشمور و کارٹیرQuần đảo Ashmore và Cartier阿什莫尔和卡捷群岛亞什摩及卡地爾群島Unrecognized1Admin-0 dependency Admin-0 country16ArmeniaARM02Sovereign country1ArmeniaARM0ArmeniaARM0ArmeniaARM0ArmeniaArmeniaARMArmeniaArm.ARMRepublic of ArmeniaArmeniaArmenia312 10 2957731.0122019 1367220196. Developing region4. Lower middle incomeAMAMAMARMARM051051051AMARM2342474323424743Exact WOE match as countryARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARMARM-99-99AsiaAsiaWestern AsiaEurope & Central Asia 7 7 4-99 10.05.010.0 44.800564 40.4590771159320333Q399أرمينياআর্মেনিয়াArmenienArmeniaArmeniaارمنستانArménieΑρμενίαארמניהआर्मीनियाÖrményországArmeniaArmeniaアルメニア아르메니아ArmeniëArmeniaArméniaАрменияArmenienErmenistanВірменіяآرمینیاArmenia亚美尼亚亞美尼亞Admin-0 countryAdmin-0 country Admin-0 country12ArgentinaARG02Sovereign country1ArgentinaARG0ArgentinaARG0ArgentinaARG0ArgentinaArgentinaARGArgentinaArg.ARArgentine RepublicArgentinaArgentina313 13 44938712.0152019 44544520195. Emerging region: G203. Upper middle incomeARARARARGARG032032032ARARG2342474723424747Exact WOE match as countryARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARGARG-99-99South AmericaAmericasSouth AmericaLatin America & Caribbean 9 9 4-99 10.02.0 7.0 -64.173331-33.5011591159320331Q414الأرجنتينআর্জেন্টিনাArgentinienArgentinaArgentinaآرژانتینArgentineΑργεντινήארגנטינהअर्जेण्टीनाArgentínaArgentinaArgentinaアルゼンチン아르헨티나ArgentiniëArgentynaArgentinaАргентинаArgentinaArjantinАргентинаارجنٹائنArgentina阿根廷阿根廷Admin-0 countryAdmin-0 country Admin-0 country16Antigua and BarbudaATG02Sovereign country1Antigua and BarbudaATG0Antigua and BarbudaATG0Antigua and BarbudaATG0Antigua and Barb.Antigua and BarbudaATGAntigua and Barb.Ant.B.AGAntigua and BarbudaAntigua and BarbudaAntigua and Barbuda225 5 97118.0 82019 166120196. Developing region3. Upper middle incomeACAGAGATGATG028028028AGATG2342473723424737Exact WOE match as countryATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATGATG-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1719 6 4 10.05.0 9.5 -61.790612 17.3522491159320345Q781أنتيغوا وباربوداঅ্যান্টিগুয়া ও বার্বুডাAntigua und BarbudaAntigua and BarbudaAntigua y Barbudaآنتیگوا و باربوداAntigua-et-BarbudaΑντίγκουα και Μπαρμπούνταאנטיגואה וברבודהअण्टीगुआ और बारबूडाAntigua és BarbudaAntigua dan BarbudaAntigua e Barbudaアンティグア・バーブーダ앤티가 바부다Antigua en BarbudaAntigua i BarbudaAntígua e BarbudaАнтигуа и БарбудаAntigua och BarbudaAntigua ve BarbudaАнтигуа і Барбудаاینٹیگوا و باربوڈاAntigua và Barbuda安提瓜和巴布达安地卡及巴布達Admin-0 countryAdmin-0 country Admin-0 country13AngolaAGO02Sovereign country1AngolaAGO0AngolaAGO0AngolaAGO0AngolaAngolaAGOAngolaAng.AOPeople's Republic of AngolaAngolaAngola326 1 31825295.0152019 8881520197. Least developed region3. Upper middle incomeAOAOAOAGOAGO024024024AOAGO2342474523424745Exact WOE match as countryAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGOAGO-99-99AfricaAfricaMiddle AfricaSub-Saharan Africa 6 6 4-99 10.03.0 7.0 17.984249-12.1827621159320323Q916أنغولاঅ্যাঙ্গোলাAngolaAngolaAngolaآنگولاAngolaΑνγκόλαאנגולהअंगोलाAngolaAngolaAngolaアンゴラ앙골라AngolaAngolaAngolaАнголаAngolaAngolaАнголаانگولاAngola安哥拉安哥拉Admin-0 countryAdmin-0 country Admin-0 country36AndorraAND02Sovereign country1AndorraAND0AndorraAND0AndorraAND0AndorraAndorraANDAndorraAnd.ANDPrincipality of AndorraAndorraAndorra141 8 77142.0 82019 315420192. Developed region: nonG72. High income: nonOECDANADADANDAND020020020ADADO2342474423424744Exact WOE match as countryANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDANDAND-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 7 7 4 5 10.05.010.0 1.539409 42.5476431159320327Q228أندوراঅ্যান্ডোরাAndorraAndorraAndorraآندوراAndorreΑνδόρραאנדורהअण्डोराAndorraAndorraAndorraアンドラ안도라AndorraAndoraAndorraАндорраAndorraAndorraАндорраانڈوراAndorra安道尔安道爾Admin-0 countryAdmin-0 country Admin-0 country13AlgeriaDZA02Sovereign country1AlgeriaDZA0AlgeriaDZA0AlgeriaDZA0AlgeriaAlgeriaDZAAlgeriaAlg.DZPeople's Democratic Republic of AlgeriaAlgeriaAlgeria516 3 43053054.0152019 17109120196. Developing region3. Upper middle incomeAGDZDZDZADZA012012012DZDZA2342474023424740Exact WOE match as countryDZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZADZA-99-99AfricaAfricaNorthern AfricaMiddle East & North Africa 7 7 4-99 10.02.5 7.0 2.808241 27.3974061159320565Q262الجزائرআলজেরিয়াAlgerienAlgeriaArgeliaالجزایرAlgérieΑλγερίαאלג'יריהअल्जीरियाAlgériaAljazairAlgeriaアルジェリア알제리AlgerijeAlgieriaArgéliaАлжирAlgerietCezayirАлжирالجزائرAlgérie阿尔及利亚阿爾及利亞Admin-0 countryAdmin-0 country Admin-0 country16AlbaniaALB02Sovereign country1AlbaniaALB0AlbaniaALB0AlbaniaALB0AlbaniaAlbaniaALBAlbaniaAlb.ALRepublic of AlbaniaAlbaniaAlbania141 6 2854191.0122019 1527920196. Developing region4. Lower middle incomeALALALALBALB008008008ALALB2342474223424742Exact WOE match as countryALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALBALB-99-99EuropeEuropeSouthern EuropeEurope & Central Asia 7 7 4-99 10.05.010.0 20.113840 40.6548551159320325Q222ألبانياআলবেনিয়াAlbanienAlbaniaAlbaniaآلبانیAlbanieΑλβανίαאלבניהअल्बानियाAlbániaAlbaniaAlbaniaアルバニア알바니아AlbaniëAlbaniaAlbâniaАлбанияAlbanienArnavutlukАлбаніяالبانیاAlbania阿尔巴尼亚阿爾巴尼亞Admin-0 countryAdmin-0 country Admin-0 country13AfghanistanAFG02Sovereign country1AfghanistanAFG0AfghanistanAFG0AfghanistanAFG0AfghanistanAfghanistanAFGAfghanistanAfg.AFIslamic State of AfghanistanAfghanistanAfghanistan568 7 38041754.0152019 1929120197. Least developed region5. Low incomeAFAFAFAFGAFG004004004AFAFG2342473923424739Exact WOE match as countryAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFGAFG-99-99AsiaAsiaSouthern AsiaSouth Asia1111 4-99 10.03.0 7.0 66.496586 34.1642621159320319Q889أفغانستانআফগানিস্তানAfghanistanAfghanistanAfganistánافغانستانAfghanistanΑφγανιστάνאפגניסטןअफ़्गानिस्तानAfganisztánAfganistanAfghanistanアフガニスタン아프가니스탄AfghanistanAfganistanAfeganistãoАфганистанAfghanistanAfganistanАфганістанافغانستانAfghanistan阿富汗阿富汗Admin-0 countryAdmin-0 country Admin-0 country15KashmirKAS02IndeterminateSiachen GlacierKAS0Siachen GlacierKAS0Siachen GlacierKAS1Siachen GlacierSiachen GlacierB45Siachen GlacierJammu and KashmirSiachenSGClaimed by Pakistan and IndiaKashmir376-99 6000.0 52013 1520136. Developing region4. Lower middle income-99-99-99-99-99-99-99-099-99-992342492823424928Exact WOE match as country-99-99B45INDINDINDINDINDINDINDPAKINDINDINDINDINDINDINDINDINDINDINDINDINDPAKINDINDINDINDINDINDINDIND-99-99AsiaAsiaSouthern AsiaSouth Asia1515 7-99 15.06.5 9.5 77.129553 35.3406061159320963Q333946نهر سياتشن الجليديসিয়াচেন হিমবাহSiachen-GletscherSiachen GlacierGlaciar de Siachenیخچال سیاچنglacier de SiachenΠαγετώνας Σιατσένקרחון סיאצ'ןसियाचीनSiachen-gleccserSiachen Glacierghiacciaio Siachenシアチェン氷河시아첸 빙하SiachengletsjerLodowiec SiachenGlaciar de SiachenСиаченSiachen GlaciärenSiachen BuzuluСіаченسیاچن گلیشیرSông băng Siachen锡亚琴冰川錫亞琴冰川UnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognizedUnrecognized Admin-0 country34AntarcticaATA02Indeterminate1AntarcticaATA0AntarcticaATA0AntarcticaATA0AntarcticaAntarcticaATAAntarcticaAnt.AQBy treatyMultiple claims held in abeyance by treatyAntarctica451-99 4490.0 42019 89820136. Developing region2. High income: nonOECDAYAQAQATAATA010010010-99-992828940928289409Exact WOE match as countryATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATAATA-99-99AntarcticaAntarcticaAntarcticaAntarctica1010 4-99 10.04.0 9.0 35.885455-79.8432221159320335Q51القارة القطبية الجنوبيةঅ্যান্টার্কটিকাAntarktikaAntarcticaAntártidaجنوبگانAntarctiqueΑνταρκτικήאנטארקטיקהअंटार्कटिकाAntarktikaAntartikaAntartide南極大陸남극AntarcticaAntarktydaAntártidaАнтарктидаAntarktisAntarktikaАнтарктидаانٹارکٹکاChâu Nam Cực南极洲南極洲Admin-0 dependencyAdmin-0 dependency Admin-0 country36NetherlandsNL112Country1Sint MaartenSXM0Sint MaartenSXM0Sint MaartenSXM0Sint MaartenSint MaartenSXMSint MaartenSt. M.SXSint Maarten (Dutch part)Sint MaartenNeth.St. Maarten (Dutch part)422 9 40733.0 72019 118520186. Developing region2. High income: nonOECDNTSXSXSXMSXM534534534SXSXM -9023425000Expired subunits of Netherlands Antilles (23424914).SXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXMSXM-99-99North AmericaAmericasCaribbeanLatin America & Caribbean1212 6 4-990.05.010.0 -63.070133 18.0408801159321103Q26273سينت مارتنসিন্ট মার্টেনSint MaartenSint MaartenSan Martínسینت مارتنSaint-MartinΆγιος Μαρτίνοςסנט מארטןसिंट मार्टेनSint MaartenSint MaartenSint Maartenシント・マールテン신트마르턴Sint MaartenSint MaartenSão MartinhoСинт-МартенSint MaartenSint MaartenСінт-Мартенسنٹ مارٹنSint Maarten荷属圣马丁荷屬聖馬丁Admin-0 dependencyAdmin-0 dependency Admin-0 country56TuvaluTUV02Sovereign country1TuvaluTUV0TuvaluTUV0TuvaluTUV0TuvaluTuvaluTUVTuvaluTuv.TVTuvaluTuvaluTuvalu138 5 11646.0 62019 4720197. Least developed region3. Upper middle incomeTVTVTVTUVTUV798798798TVTUV2342497023424970Exact WOE match as countryTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUVTUV-99-99OceaniaOceaniaPolynesiaEast Asia & Pacific 6 6 4 5 10.05.010.0 179.209587 -8.5137171159321333Q672توفالوটুভালুTuvaluTuvaluTuvaluتووالوTuvaluΤουβαλούטובאלוतुवालूTuvaluTuvaluTuvaluツバル투발루TuvaluTuvaluTuvaluТувалуTuvaluTuvaluТувалуتووالوTuvalu图瓦卢吐瓦魯Admin-0 countryAdmin-0 countryXastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.dbfawk0000664000175000017500000000631115151324131026203 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # This file is meant to be used with the ne_50m_admin_0_countries shapefile # from natural-earth-vector (https://github.com/nvkelso/natural-earth-vector) BEGIN { dbfinfo="featurecla:scalerank:LABELRANK:SOVEREIGNT:SOV_A3:ADM0_DIF:LEVEL:TYPE:TLC:ADMIN:ADM0_A3:GEOU_DIF:GEOUNIT:GU_A3:SU_DIF:SUBUNIT:SU_A3:BRK_DIFF:NAME:NAME_LONG:BRK_A3:BRK_NAME:BRK_GROUP:ABBREV:POSTAL:FORMAL_EN:FORMAL_FR:NAME_CIAWF:NOTE_ADM0:NOTE_BRK:NAME_SORT:NAME_ALT:MAPCOLOR7:MAPCOLOR8:MAPCOLOR9:MAPCOLOR13:POP_EST:POP_RANK:POP_YEAR:GDP_MD:GDP_YEAR:ECONOMY:INCOME_GRP:FIPS_10:ISO_A2:ISO_A2_EH:ISO_A3:ISO_A3_EH:ISO_N3:ISO_N3_EH:UN_A3:WB_A2:WB_A3:WOE_ID:WOE_ID_EH:WOE_NOTE:ADM0_ISO:ADM0_DIFF:ADM0_TLC:ADM0_A3_US:ADM0_A3_FR:ADM0_A3_RU:ADM0_A3_ES:ADM0_A3_CN:ADM0_A3_TW:ADM0_A3_IN:ADM0_A3_NP:ADM0_A3_PK:ADM0_A3_DE:ADM0_A3_GB:ADM0_A3_BR:ADM0_A3_IL:ADM0_A3_PS:ADM0_A3_SA:ADM0_A3_EG:ADM0_A3_MA:ADM0_A3_PT:ADM0_A3_AR:ADM0_A3_JP:ADM0_A3_KO:ADM0_A3_VN:ADM0_A3_TR:ADM0_A3_ID:ADM0_A3_PL:ADM0_A3_GR:ADM0_A3_IT:ADM0_A3_NL:ADM0_A3_SE:ADM0_A3_BD:ADM0_A3_UA:ADM0_A3_UN:ADM0_A3_WB:CONTINENT:REGION_UN:SUBREGION:REGION_WB:NAME_LEN:LONG_LEN:ABBREV_LEN:TINY:HOMEPART:MIN_ZOOM:MIN_LABEL:MAX_LABEL:LABEL_X:LABEL_Y:NE_ID"; dbffields="NAME_LONG:MAPCOLOR9:MIN_ZOOM:MAX_LABEL:LABEL_X:LABEL_Y";} # Defaults: thin black lines, 13% stippled, display all the way out to max # zoom, don't display below 1000 zoom, stop labeling above 50000 zoom, # use black labels in large font, take label location out of DBF fields BEGIN_RECORD {key=""; lanes=1; color=8; name=""; filled=1; fill_style=2; fill_stipple=0; pattern=0; display_level=2147483647; min_display_level=1000; label_level=50000; label_color=8; symbol=""; font_size=3; label_method=1; label_lon=0.0; label_lat=0.0;} # Get the label text from the shapefile record /^NAME_LONG=(.*)$/ {name="$1";} # Color each polygon based on its "MAPCOLOR9" value. Use the Set1 colors /^MAPCOLOR9=1$/ {fill_style=2; fill_stipple=0; fill_color=127;} /^MAPCOLOR9=2$/ {fill_style=2; fill_stipple=0; fill_color=128;} /^MAPCOLOR9=3$/ {fill_style=2; fill_stipple=0; fill_color=129;} /^MAPCOLOR9=4$/ {fill_style=2; fill_stipple=0; fill_color=130;} /^MAPCOLOR9=5$/ {fill_style=2; fill_stipple=0; fill_color=131;} /^MAPCOLOR9=6$/ {fill_style=2; fill_stipple=0; fill_color=132;} /^MAPCOLOR9=7$/ {fill_style=2; fill_stipple=0; fill_color=133;} /^MAPCOLOR9=8$/ {fill_style=2; fill_stipple=0; fill_color=134;} /^MAPCOLOR9=9$/ {fill_style=2; fill_stipple=0; fill_color=135;} # the smaller the MIN_ZOOM value, the farther out you have to be to see # the feature rendered (i.e. far enough out to want to see a whole country # shaded) /^MIN_ZOOM=0$/ {min_display_level=1000;} /^MIN_ZOOM=4.*$/ {min_display_level=900;} /^MIN_ZOOM=5.*$/ {min_display_level=500;} /^MIN_ZOOM=7.*$/ {min_display_level=350;} # the smaller the MAX_LABEL value, the farther out you have to be to # stop showing those labels. /^MAX_LABEL=5.(.*)$/ {label_level=60000;} /^MAX_LABEL=6.(.*)$/ {label_level=40000;} /^MAX_LABEL=7.(.*)$/ {label_level=30000;} /^MAX_LABEL=8.(.*)$/ {label_level=20000;} /^MAX_LABEL=9.(.*)$/ {label_level=10000;} /^MAX_LABEL=10.(.*)$/ {label_level=5000;} # label location taken from DBF record /^LABEL_X=(.+)$/ {label_lon=$1;} /^LABEL_Y=(.+)$/ {label_lat=$1;} Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.prj0000664000175000017500000000021715151324131025537 0ustar hibbyhibbyGEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_admin_0_countries_lakes.shp0000664000175000017500000623275015151324131025555 0ustar hibbyhibby' fhfffVf@`T@Y99@f6܀@@@I/8333I?@f62?@LX6?@N6hfff>@lJ6,>@@L6u>@9T60>@hfffJ6=@hfff&/6=@4333s%6`=@Y16hffff]=@hfff168333P=@`(6<=@Y6Y=@43336L=@hfff& 6 =@43336=@433335 =@5̌ =@43335̌=@5<@ 5Y<@5l<@hfff&583333<@5.<@5̬ <@43335<@5;@5L;@[5;@4333B5hfff;@l5`;@4333s5L;@4hfff&;@,4L;@433334l;@43334;@433334;@ه4hfff;@hfffƀ4hfff;@{4 x;@̌y4G;@̌z4LF;@a4A;@hffff;483338;@4333S%4-;@4;@ 4̬:@y3:@̌3y:@hfff38333=:@3hfff+:@̉3:@4333^3`9@3̌9@4333S2y9@L29@ 29@929@4333329@q2@}9@Y2o9@hfff&<2hffffb9@Y$2W9@2LH9@̌ 2hfff>9@43331Y99@L183333=9@43331@B9@hfff&1hfffs9@Y19@y19@1ٽ9@433319@4333183339@hfffF1#:@hffff1YU:@hfff1ٓ:@hfff2hfff:@ 28333S;@Y1hfff& ;@hfff1;@1̬;@hfff18333);@,12;@,1Y:;@hfff1glH;@)R慭1AO9Z;@`@1hfffFh;@̌1 t;@hffff1Lv;@43331 s;@43331hfffp;@43331hfffft;@y18333s;@ 1̌;@Ly18333;@t1;@̌s1y;@hfffa18333S;@@K1;@hfffA1hfff;@:18333s;@hfff51;@4333,1@;@ (19;@4333S%18333;@91hfff;@L1Y;@ 1hffff;@9 1;@4333 1 <@43331hfff<@ 1̬<@919<@hfff&0<@4333s0hfff<@`08333<@4333s0<@l0&<@0=<@L08333SW<@43330a<@0hfff&k<@hfff&08333St<@Y0v<@08333su<@̌0hffffy<@433309<@433330<@L0hfff<@Y0<@L0hfff<@433330<@̬0 <@hfff&0<@433330<@hfffF08333<@43330,<@4333S0@<@hfff&0<@l0<@0<@433308333s<@L0y<@hfff08333<@hfff&08333<@hffff0<@43330Y<@y0 <@0hfff<@4333S08333<@90,<@4333l08333S<@`N08333S<@l$0hfff&<@@ 0<@/<@8333s/8333 =@hffff/8333I=@̌/|=@d/hfffƺ=@ J/8333=@I/,@>@8333sI/hffffe>@@I/e>@/h>@/8333p>@/8333S>@/8333S>@0y@@I/,@>@8333sI/8333=@I/hfffƺ=@ J/|=@d/8333I=@̌/8333 =@hffff/<@8333s/<@/hfff&<@@ 08333S<@l$08333S<@`N0,<@4333l08333<@90<@,0db<@[408333s<@hfff&0̌<@4333~0 <@l0hfffF<@083333<@4333S0̬<@hfff09<@hfffF0q<@0d<@hfff0hffff_<@hfffƒ08333Y<@4333S08333sP<@0@J<@0LL<@4333S08333H<@0hfff><@@083334<@0̬,<@08333-<@0+<@43330"<@`083333<@L0<@@0 <@L0hfffF<@0̌;@0;@ 08333;@433330 ;@0;@0̬;@ 0hffff;@̌0hfff&;@̬08333;@ 0hfffF;@4333s0;@hfff0;@0;@Y0ٷ;@0;@0;@09;@0;@̬ 1,;@433318333S;@43333183333;@4333s1hfff;@hfff1;@&18333x;@ ?1Ln;@L1_;@̌c1 X;@u1Y_;@̬z1^;@ 1Z;@L1V;@1hfffQ;@L1J;@̔1hffffA;@ 18333+;@4333s1L;@l1y;@̬1,;@hfff1̌;@183333 ;@l18333;@Y18333S;@Y1hfff:@ 2ٓ:@hfff2YU:@hfff1#:@hffff183339@hfffF19@43331ٽ9@433319@19@y1hfffs9@Y1@B9@hfff&19@hffff18333s9@̌183338@ 18@̌1`F8@hfff&{1hfff&:8@4333S}18333s 8@Y17@hffff1L7@4333s18333sa7@1.7@4333sy183336@hfff&I18333Ӹ6@hfffF1hfffƋ6@hfff0u6@̬0N6@hfff0hfff16@̠08333&6@0L 6@hfffFC083335@@/83335@r/5@8333s.hfff5@hfff&*.5@م-5@̌,83335@@=,hfff5@8333+hfff5@*5@LP*5@*hfff56@*8333x6@*̌6@* 7@*8333V7@*hfffƢ7@*7@*7@)hfff7@)83337@8333)hfff7@)83337@̌|)7@8333E)7@hffff)hfff7@hfff&(7@̌(y7@L<(Y7@'833337@8333'7@83333s'83337@̌E'7@hfff,'8@ '8@&8333 8@̌& 8@̌&̌8@&83338@^&7@8333s&l7@Y%83338@%83338@8333s%y8@L%8333"8@L &/8@Y&hfffQ8@$&]8@B&8333se8@hfff&`8@&U8@&`8@̌&8333sw8@83333&8@&83338@8333&hffff8@8333&l8@8333s&y8@hfff&&8333s9@hfff&&8333S/9@hffff|&>9@l&I9@l&Q9@Ly&8333J9@hfff&YH9@Y&R9@hffff'8333sY9@?'8333i9@X'u9@Lf' 9@'l9@}'9@hfff'833339@hfff'hfff:@'̬:@8333s'8333V:@'n:@L'̬:@8333'̺:@8333'8333:@83333'8333:@'L:@8333':@83333'8333:@83333'8333;@S' ;@Y;'l;@0'(;@̌('hfffF2;@5'8333<;@hfff&'8333sl;@'̬|;@((̌;@d(hfff;@@t(8333;@(;@̏(;@ّ(<@(<<@(8333[<@(8333i<@@ )8333s<@hfff')8333sy<@hfff&?)<@|)hfff<@)̌<@L)hfffF<@)hfff<@)<@)<@hfff&=*8333<@hfffm*9<@@*hfff=@ټ*8333=@L*̬3=@8333*8333@=@ٽ*a=@L*@{=@83333*=@8333s*=@hffff*Y=@٘*̥=@8333*٦=@hfff&*=@Y*8333s=@L*=@*hfff=@L*=@U*=@8333)=@8333s)̬=@8333s@)hfff=@8333(=@(̌=@O(hfff=@T(hfff&=@̌e(L=@hfffg(=@t(8333}=@hfff(8333=@(@=@8333(L|=@@(8333sm=@(X=@@(83330=@̌(y=@(83333<@(<@8333=(<@@(<@8333'hfff<@hfff&'hfff{<@̟'̌n<@̌e'83333h<@hfff>'hfff&b<@hfff&"'8333s[<@L&yg<@8333s&hffffx<@8&<@%8333S<@̚%̌<@hfffV%@<@8333%<@8333s$<@@$<@2$<@hffff#L<@#̬<@̌[#`<@hfff&#8333sf<@̌"8333f<@s"{<@V"8333ӝ<@%"hffff<@"@<@!hfff&<@83333!<@Y!8333<@8333f!9<@83333.!<@̌ hfff<@ 833337=@ {=@ hfff&=@ hfff& >@ S>@83333 m>>@^Up ̒>@L 8333>@ >@٩ hffffz>@ hfffu>@ r>@8333 hfffv>@ ~>@!8333>@!8333S>@!8333>@ !L>@!>@hffff(! >@(!̞>@Y!>@!8333>@hffff!8333s>@83333! >@@!8333s>@!!Y>@(!8333>@}!hfff?@8333! ?@hfff&!̌?@hffff! ?@!8333"?@s!hfff&?@hffffp!hffff*?@hfff&z!8333-?@hfff{!hffff0?@8333u!2?@M! 5/?@eL8!Y?@6!s?@N!?@83333m!hffff?@hffff!?@!8333s?@L!83333?@hfff&!hfff?@8333s!l?@8333!?@ !,?@hffff!?@8333 "L?@hfff"hfff@@""̜@@̌%"hfffF@@L@"(@@ E"4333s7@@ P"Y>@@hfffl"M@@"`@@"n@@"u@@"0v@@83333"̼y@@hfff"l}@@hffff #hfff}@@8333%#|@@hfff>#hfffք@@hfff&E#hfffF@@F#`@@̌4#4333@@5# @@@#9@@8333]#@@hfff#̼@@hfff#@@8333s#hfff&@@8333s#@@8333s$`@@hfff=$4333@@@f$4333@@hfff&x$@@$@@Y$hfff&@@hfff&$̬@@83333%\@@Y.%|@@8333%@@%hfff&@@%y@@hffff%4333s@@hffff%@@%@@Y%Y@@+&̜@@P&9@@̌&Y@@&ɝ@@&@@'@@''hfff@@hfff8'hfff@@8333a' @@'hfff@@'L@@hfff9(@@ٝ(\@@̨(hfff@@(4333@@ (ٽ@@̌( @@(@@()@@8333)4333Â@@B)4333|@@g) y@@ٛ)9|@@)@@)hfff~@@)L|@@hfff&+*4333#}@@YQ*{@@83333s*4333#x@@̃*)s@@̶* m@@*43333h@@hffff+4333a@@+U@@L.+hfffV@@8+b@@hfff&P+4333f@@`+4333Cg@@hfffk+hfffd@@v+a@@hfff+g@@L+o@@+u@@̌+{@@hfff&+}@@,~@@Y ,0@@hfff& ,l@@hfff&,4333C@@+4333@@+4333ә@@,Y~@@+,o@@8333>,F@@̌u,"@@hffff,hfff@@,@@hfff,l?@83333,?@,?@-8333?@'-T?@F-!?@hfffc-hfffF>@8333-`>@hffff-hfff>@hfff-83333r>@hfff-Y;>@ -hfff8>@hffff.9>@@".̌@>@].@N>@hfff.Y>@ .@a>@/hffffe>@@I/AO9Z;@`@1glH;@)R慭1YI;@@18333V;@hfff&1YZ;@433331AO9Z;@`@1(hfffFFE@0333S(@lAK@43332@hfffJ@0@lJJ@ix0@hffff9J@)d0@4333)J@dfff&K0@`J@+0@hfffFJ@hfff/@lJ@l/@hfffJ@O/@, J@,/@I@hfffF/@hfffVI@hfff&.@4333I@Y.@0@ [@dfff)0@` [@P0@i[@0@[@0@[@p0@hfffN[@hffff/@L[@0333/@4333[@/@4333$[@`+/@hfff&+[@.@/[@l.@4[@.@|9[@l\.@(<[@.@pA[@ -@hfffnE[@̬n-@E[@-@H[@̬,@@L[@y,@DM[@O,@TN[@1,@O[@Y,@iS[@+@pR[@0333+@O[@+@!P[@Y.+@pR[@*@hffffQ[@hfff*@S[@9p*@X[@ *@![[@0333s)@Z[@`fff&p)@y\[@3)@iX[@lW)@yU[@)@Q[@`fffk)@4333N[@`fffJ)@S[@`fffF(@{Z@`ffff#@hfff.uZ@`$@43333Z@X#@hfff&Z@033330#@1Z@03333#@4333SZ@`fffF"@hfffƊZ@ "@`Z@/"@YZ@!@TZ@,!@Z@`fffR%@BZ@@g%@CZ@0333w%@PBZ@`ffff%@lAZ@0333%@BZ@%@4JZ@̌%@1RZ@0333%@4333#TZ@%@̼XZ@0333S%@YZ@9%@\Z@ %@hfffdZ@0333%@lZ@0333%@4333SpZ@%@4333sZ@`fff&%@̜vZ@`fff&%@4333xZ@̌%@4333 |Z@03333%@hfff^Z@ %@4333SZ@03333%@hfff~Z@%@4333kZ@ %@Z@L&@LZ@&@hfff^Z@`fffF(&@yZ@Y}&@vZ@̬&@wZ@̬&@vZ@`&@hfffvuZ@`fffF'@uZ@3'@hfff~vZ@ E'@4333xZ@K'@L{Z@LN'@43333}Z@l]'@4333cZ@'@hfffZ@`fff'@hfffNZ@̬j'@Z@]'@̌Z@_'@hffffZ@`fffFe'@IZ@ z'@̼Z@'@|Z@'@Z@Y'@aZ@9'@hfffάZ@`ffff'@Z@(@Z@̬'(@hfff>Z@ Z(@,Z@ٍ(@4333Z@`fff(@hfffZ@`fff(@ Z@Y(@,Z@`(@4333Z@`ffff(@iZ@`fff(@pZ@0333(@̌Z@y)@Z@li)@̼Z@`fff)@Z@)@lZ@̌*@Z@ls*@Z@hfff&*@4333Z@ +@Z@0333N+@hfffZ@+@Z@l+@,Z@ ,@Z@hfffF#,@hfff6Z@0333@,@Z@,@4333SZ@hfffƼ,@4333Z@hfff,@Z@l-@AZ@hfffL-@hfff>Z@i-@Z@ -@Z@_-@LZ@0333-@hfffZ@0333-@4333Z@ .@Z@03333.@̼Z@hfff<.@hfffZ@03333a.@Z@̬.@Z@hfff.@Z@.@iZ@.@hfffZ@/@Z@hfffZ@"6@Z@6@xZ@5@hfffZ@dfffv5@Z@dfff6@4333ӲZ@4333c5@Z@dfff5@hfff6Z@̌5@$Z@dfff5@iZ@dfff5@DZ@5@Z@P5@lZ@43335@iZ@5@yZ@5@hfffZ@l5@4333+Z@,5@hfffZ@)5@Z@5@TZ@)5@4333#Z@dfffv5@@Z@ 5@̄Z@]!@hfffZ@l\!@YZ@f!@hfff&Z@`!@Z@,r!@4333éZ@f!@̄Z@]!@4333Z@Y$@\Z@0333S$@Z@`ffff$@Z@03333$@LZ@0333s$@yZ@03333$@4333Z@Y$@hffffZ@43334@Z@4@hffffZ@4@hfff>Z@<4@hfffZ@̌4@Z@dfff4@hffffZ@43334@4333Z@75@4333[Z@dfffv5@4333Z@5@hfffZ@<<5@4333{Z@D5@4333Z@l85@4333Z@75@\Z@dfff64@4333Z@4@̌Z@I4@Z@4@hfff6Z@I5@HZ@dfff5@DZ@04@\Z@dfff64@Z@<4@\Z@94@HZ@4@Z@dfff4@Z@94@ Z@94@Z@̼4@̴Z@43334@Z@<4@pWR?M0333[(@7 '3iNF"@xN 6"@@xNC"@!tN["@$lN03333b"@2333#iN0333Sj"@2333 dNo"@2333#aN0333n"@0^Nh"@2333+eNZ"@iNF"@O0333C&@̜O,&@ffffO%@tOl%@,O,%@P`fff%@yP`fff%@L P`fff%@3333P%@33333PL%@P0333%@PP0333&@P )&@̬ P,&@ P&@8P`fff&@P0333&@xP #&@QOU&@O0333C&@MP%@ QP%@`WP%@ZP03333%@ffffXP%@YSP%@NP`fffF%@MP%@2333N0333!@̬N̬!@2333ۈN`fff!@ffffvN!@ffffxN,"@9uN$"@rN0333S"@0sN0333S"@lN!@2333CnN03333!@LuNl!@2333N0333!@ffff>N@!@2333sM`fff @M @ffffM0333S @Mb @M0333R @ffff&Nl @ffffN`fff@2333#N@2333c,Nj@0NO@ffffAN0333@@ffff6GŇ@NN`fff@!SN0333b@[N$@\N`fff@ffffON t@2333MŇH@ffffnQN@QN`fff&@ffffJN0333@BN`fff&@2333;Ň@92N@2333+,N@)N03333@9)N@^@-N0333@2N @KN`fffm@UNL9@[N@iN`ffff'@oN%@tN@xNY@N @iN0333s@2333N03333@Ň@NZ@ffff>N0333 @TN@@ffff~NY@yN0333s@iN@2333˜NL@̦N03332@ffffNL@2333;N@fffffN`ffff@zN`fff@ffff^N`fff@![N`fff&@2333VNL@HQN0333S@`MN0333s@2333KMN`fff&@TPN0333@ffffVN0333N@^N0333@̬jN0333@tNL@2333{NL@\N$@̤N@N@ffffΚN@@٣NL@2333 N`ffff@\N`fff@N0333&@N@q OY@Od@4O@|@aO@ffffO@POb@O?Ox?ffffO??3333P?DPx?ffffJPT?YP?3333 Px?xPH?P@ffff&?3333P>?ffff!P@ffff?fffff%P?3333*P?.P ?Y4P3333?3333?:P?3333AP?FP̺?3333JP[?PP?WP?ZPK?L^P?ffffcP?3333dP?xaP3333?9dPffff?ffffBiP3333 ?̜kPffffx?mPL?sP?A{P̞?P?؃P!?"@3333s=R03333E"@@Rz"@̼CR`fff"@HR0333r"@\LR`ffffc"@̌URU"@pWR`ffffc"@ffffVR`fff&t"@RR"@ffffZNR "@ffff IR#@DR V#@3333k@R #@=R9$@3333/Q#'@3333CQ03333&@3333Q03333&@ffffrQ0333sa&@3333Q`fff&E&@Q&@ffff>Q0333S%@3333Q`fffF%@0Q`fffƫ%@LQ0333s%@ Q0333P%@̌Q03333$@Q`fffơ$@QU$@ffff*Q0333S7$@8R0333#@Q0333sH#@3333{Q@#@Q0333"@Q"@Q`fff"@Q"@ffff^Q̌D"@3333Q %"@ffffQ̌"@XQ"@Q0333S@"@3333sQ`fff&R"@$Q`fffq"@ffff~QL"@Q`fff#@3333_Q`i#@3333;Q#@3333CQy$@Q`fffI$@ffffQ $@ffffQ@$@Q%@$Q`>%@3333Q0333%@3333Q٫%@ Q`fff%@3333Q%@3333Qj&@3333Q0333Ӆ&@Q&@$@3333CHP#$@}AP@'$@3333kN@!@Hpfff(@3333D@(@ffffD@(@ffffD@@333s(@3333D@pfff(@3333KD@@333s(@ffffD@@333s(@ffffD@(@ffffD@d@hfff=4hfff0,d@̌'0d@43330d@L&0hfffd@'0d@04333d@hffff/hfffbd@hfff&/hfffd@hfff/hfffd@Y/43333d@̌0Le@`0@e@,0e@hfff0T e@̬04333e@`0hfffe@43330e@hfff0hfffe@hfff0Te@ 0e@43330`e@hfff04333{e@0hfff~e@0y e@hfff&0hfff e@@0Le@`0hfff~ e@hfff&V0hfffe@hfffX0e@P0d@4333E0hfffd@̌:0d@L20hfffe@hffff.0hfff>e@hfff0Xe@̬0̈e@9;0hfffe@4333C0̈ e@yL0hfff~ e@hfff&V0De@̊1te@hfffF1e@hfff&1e@L1 e@hfff1 e@1 e@hfff1e@1hfffve@433314333e@̌1e@hfff1e@43331e@`1̄ e@19 e@@1 e@4333S1De@̊1)d@83333.d@8333. d@8333s.4333d@83333.pd@.e@.)d@83333.e@/4333Ge@/̼e@8333/hfffe@\/hfffe@8333s.4333e@83333/e@/4e@ /e@/ e@L.e@.,e@L.Ue@.e@hfff&-]e@ -4333e@d. e@L.d@r/ld@ /d@^/4333d@>/d@@J/d@r/4333d@,hfffbd@̌,d@,d@hfff&,$d@e, d@@V,4d@H,hfff*d@^,4333d@,̤d@+,d@̌+4333od@+d@hfff+d@+dd@@k+4333d@hfff+hfffd@+hfffd@+4333_d@ +d@hfff+̤d@+hfffQ@3333 D@)=Q@! D@$:Q@3333D@3Q@qD@̼2Q@D@hfff2Q@̴D@43334Q@3333C@I7Q@3333C@7Q@(C@43336Q@3333 C@hfffF5Q@1C@ 3Q@ffff^C@1Q@̼C@hfff&1Q@C@hfff0Q@3333C@hfff/Q@ C@hfff+Q@3333SC@(Q@`C@'Q@3333#C@4333%Q@ffffFC@q Q@ C@hfffQ@3333C@Q@C@dQ@3333C@̬Q@ffff.C@Q@ffff6C@hfff&P@C@P@C@P@`C@xP@fffffC@iP@C@hfffFP@C@`P@C@4333P@̼C@P@,C@tP@M@ffff(E@E@4333M@3333k>E@4333L@:E@ L@33335E@43333L@*E@L@3333E@9L@LE@4333L@E@''L@'#E@`L@ffff^!E@hfff6L@ffff*E@hfffL@3333&E@4333cL@E@L@D@[OZL@1D@PL@D@hffff{L@3333D@~L@̬D@4333SL@̬D@ЉL@3333D@4333L@ffffD@hfff6L@ffff֬D@4333#L@hD@9L@TD@LL@D@{L@D@0nL@XD@hfffcL@ܤD@l=L@3333{D@L@ɧD@K@ffff>D@K@D@4333K@3333D@K@dE@ K@ffffE@ K@(/F@ox`5M@?"5F@/M@.F@si'M@ȔF@"JM@`lF@ &)M@9j/MF@NM@?)F!CF@_^M@8:F@`BH!M@P:7F@5,.M@t<]6F@t=M@Gp@F@t@mCM@ HF@b|HM@EjbF@[OM@P"hF@k3HM@Fܐ$uF@82DKM@ϓ3~F@H9EM@o0F@I$Z!TWM@I ڜF@ڏ*PM@ EáF@N,cVM@SŬԺF@e`YM@nF@LgM@̌F@xM@ F@̬M@̴F@YM@IF@hfffM@ܖF@M@qF@hffffM@ffffF@4333M@3333}F@4333M@1uF@pN@lF@ N@YdF@)N@ffff[F@|;N@3333SF@,MN@ffffKF@^N@3333BF@pN@@:F@4333N@h2F@\N@,F@lN@ffffF@4333N@̔F@N@ F@IN@9E@PN@HE@4333N@E@4333N@ffffVE@̜N@3333E@N@ffffE@hfff6 O@3333E@4333sO@9E@:O@E@hfff6QO@lE@PlO@̼E@O@3333E@O@aE@O@ffff~E@O@E@O@HE@P@ffffE@\ P@iE@\P@3333E@\P@̌E@P@3333+E@&P@ffffE@0-P@̔E@3P@3333E@43339P@3333{E@43333@P@E@hfffnEP@ffffnE@JP@AE@PQP@qE@tWP@ffffE@_P@E@hfffdP@3333CE@jP@DE@oP@ffffn|E@dsP@@pE@4333yP@ffffuE@\P@0zE@4333kP@3333~E@P@3333oE@hfffP@!bE@4333P@ffffvME@0P@3333D@BQ@ffffΡD@(DQ@D@IQ@ffffnD@OQ@D@4333WQ@3333˾D@YQ@\D@4333+dQ@̄D@|jQ@D@prQ@AD@p}Q@̄D@hfffQ@ffffD@tQ@ffffD@ Q@̔E@Q@ffff E@LQ@ffffF E@Q@ E@dQ@̜E@@Q@E@hffffQ@ E@hfffƭQ@ffffE@hfffQ@3333E@Q@ffffE@Q@E@1Q@@C@Q@C@Q@DC@Q@3333C@4333Q@C@hfffQ@3333 C@Q@YC@Q@̼D@\Q@D@4333{Q@3333C D@4333{Q@ffffD@YQ@ffff~D@4333Q@D@$Q@9 D@hfffVQ@3333D@4333Q@)D@yQ@3333kC@Q@C@1Q@@C@hfffQ@C@0Q@C@,Q@ffffnC@Q@C@Q@C@4333#Q@C@4333Q@3333#C@hfffQ@fffffC@hfffQ@C@4333éQ@3333wD@̌Q@zD@4333Q@ffff6D@̜Q@,D@43333Q@D@hffffQ@̬}D@4333ۧQ@3333wD@4333éQ@3333wD@ 8MhffffwA=tJ>pJ@̴J̼@yJhfff@2333kJ<AJĀJ0APK,BA2333KUA"K\UA2333.K]Affff~sKhffffwA,K4333rA2333sKrApK`gA)KIcAtKgALhfff6tALhffftAffffL\sA̤1Lhfff6nAffffF;L@cAffffvmL̜VAٕLhfff9ALY9A L=AffffLL9AyL1A LI'AMhfff A93M@8M @ffff4M4333#@2333;-MI@.MhfffV@fffff%M@\Mhfff@MhfffF@ M4333{@ M4333cr@ffffM`@2333M4333H@M`<@M43333)@2333SM@M@M<@2333M@M̌?1M?pMhffff?D M4333?2333kM?MY?2333L?ffffvL?<M̈?M4333~?ffffFMhfffj?2333cLhfffL?YL2?(L?ffff^L4333?2333Lhfff>2333sL>2333L>L>ffffLhfffF>ffffLL>dLhfff~>9Llb>PLhfffK>L:>L43330>LB>!LG>2333sĽH>LC>lL$>0Lhfff&>wL>ffffjL4333s>`\L/> 4Ľr>̌L>̌ L>̼L4333>ffffK4333S>\L>LhfffF?LhfffF?2333K4333?K4333?dKhffff ?K4333>\K4333S>ffff&Khfff>2333CK`>ffffFK̬>0K>ffffVK@>2333Khfff>2333ۮK4333 ?9K?KhfffF$?̴Khfff&/?K9?ffff6K4333G?2333K`P?̜KlG?rKhfff&d?8KK43333|?CK?$=Kl?Y/K?2333;K?2333 K?J?ffffJ?1J?ffff.J@JhfffF@Jy @ffffJ@J<&@Jhfff3@̤Ji@@ffffnJ4333cJ@J P@=tJhU@J4333V@țJhfffZ@ffffJhfff]@J`a@ Jhfffe@2333Jj@\Jp@`J4333v@J z@̄Jz@ffffJ @̼J4333@ffffJ`@aJy@XJ@ffffJ<@2333J @hJhfffv@̜J4333ý@QJ@2333J @|6?J!g@J@2333Jhfff@iJ@ffffVJ@2333J`@pJ@ 4333Aa@`fff@hfff_d@`fff/#@1&hfffv_d@̌M@hfff_d@`fff@]d@4@y]d@̌E@^d@ W@hfffv_d@̌M@̐Da@Y#@%Ba@̌"@4333Aa@9"@̸Ba@9"@Ca@0333#@Da@*#@hfffEa@`fff/#@Fa@,#@4333Ea@`fff#@̐Da@Y#@hfffb@b@hfffvb@U@b@03333Z@4333;b@a@4333gb@g@hfffVb@m@4333sb@`ffff@b@Y@ab@ @$b@̏@b@Y@b@̌s@hfffb@b@4b@`ffff@b@@db@`fff&@̄b@Y@̰b@Y@8b@L@4333#b@03333@4b@@4b@`ffff@4333c@03333A@5c@*@hfffc@4@%c@@c@Y@Pc@@c@03333@mc@`fff@c@@hfffc@`fff&k@4333c@03333A@ d@3@8xe@YV&@/ (hfffR4e@R@3e@3@2e@`fff&5@43333e@03333L@4e@Yl@4e@@i6e@@7e@@hfff>7e@@5e@`fff@hfffR4e@R@e@`ffff<@e@,@e@6@hfffe@`fffI@̼e@LX@,e@03333J@e@`ffff<@yre@`ffff1@se@@@4333ve@0333@8xe@@`we@ @0ve@`fff&@ue@L @4333se@Y@re@`fff@yre@`ffff1@4333Cce@̌@4333Cge@ Y@le@q@hfffke@a@ie@S@lhe@`ffffF@ge@`ffffF@yfe@LK@hfffce@`fffo@$ae@ٟ@̜ae@`fff@4333Cce@̌@}d@`N&@d@J&@d@`fffN&@|d@`fff&U&@4333kd@YV&@d@T&@}d@`N&@ hfff$b@9,@:b@2@.'43336b@433332@43335b@2@4b@̬2@4b@2@6b@dfff62@̜6b@\2@43336b@433332@6b@V0@hfff6b@dfffU0@5b@dfffU0@hfffZ4b@Y0@14b@4333`0@A6b@0a0@hfff7b@\0@6b@V0@y(b@0333P,@&b@9,@4333%b@0333=,@ %b@F,@hfff$b@hfffS,@p'b@a,@hfff~(b@hfffF\,@y(b@0333P,@8b@dfff62@T7b@43332@A9b@'2@hfff9b@43333,2@:b@4333#2@8b@dfff62@8b@,D.@7b@hfff6.@X6b@ :.@5b@ @.@hfff6b@9n.@)9b@hfff.@L:b@.@<9b@r.@9b@hffffY.@8b@,D.@15b@hfff-@43333b@-@hfff2b@hffff-@hfff2b@hfff.@hfff3b@.@43334b@0333s.@15b@hfff-@ 3333AP43331@ffff&%P̜b2@ 6PT2@:P@R2@3333AP^2@ffffJ+@ ̼b@*@hfffbb@ك*@5b@hfff*@b@*@4333b@*@hfffJb@ +@hfffb@hfff>+@4333b@0333:+@b@03332+@4333b@$+@b@*@̼b@*@XAZe83333,.Rẽ,=We̳,Xe83333,AZe̟,3333WeL, Vẽ,.Re,~Te,=We̳,DP1@3333RP̬2@E)2HPdfffq2@MPl2@`P4333m2@ffffPx2@Px2@=xPq2@3333[pPf2@ffff>hP4333a2@gP >2@ffffmP/2@rP 2@ffffbuP̬2@!~Pp1@P1@ffffP1@LP01@ٔP43331@%PY1@̰P̬1@LPdfffV1@3333oP1@3333P1@P1@̄P)1@ffffPdfff1@Py1@P43331@(P '2@ Pdffff92@P̌H2@3333KPdfffR2@ffffPdfffV]2@P4333d2@ffffPo2@3333'P2@IQXahpy "(/6@GPXdny",Pffff`ICL@ffff>`iAL@O`AL@3333ɝ`!CL@ffffV`3333HL@`̬ML@ffff`ffffQL@ffffܛ`3333#YL@`3333eL@`̤WL@ffff(``QL@,`̴IL@K`FL@ܖ`qEL@ffff`ICL@`ffffL@3333`@L@̆`4!L@`3333+L@ffff4`3333.L@`,2L@`̌8L@ݜ`:L@`h9L@ffff`33337L@!`4L@;`33331L@`3333.L@ `ffffn+L@̰`ffff(L@k`ffff$L@`ffffL@`LM@ffff<` M@`pM@`ffffM@+`<%M@ffff`'M@`*M@`3333$M@`LM@#bffff&+N@$b(N@̚'b!)N@)b+N@$bX3N@3333G#b1N@#bffff&+N@bM@ffffbM@ffffTbiM@<bM@S b3333M@3333bN@bffffM@3333 bffffM@bM@ffffb\N@_bqN@3333bN@abN@biN@3333A}b N@ffffb\N@cL.N@5c-N@$cffff&4N@b3333{@N@b>N@dbcL@ffff8L@ffff‰`3333BL@`iGL@Ɗ`33333ML@r`PL@`3333+QL@:`(SL@ffff`bL@v`eL@ffffv`@iL@`̔rL@ffff`ffffwL@ך`zL@ffff`ffff6L@3333c`$L@:`3333L@ffff` L@3333`ffffL@3333?`ffffL@ffff´`ffff6L@`L@N`3333L@`L@ffff`L@`ffffL@̾`yL@`L@~`8L@ffff `ffffL@ffff*`3333L@3333[`L@3333ɦ`ffffL@8`XL@`3333[L@ffff`TL@`L@ffff`ffffL@3333`L@з`3333cL@H`3333L@`3333#L@`< M@`ffffnM@`M@r`ffff%M@ffff`3333;M@n`ffff?M@ffff`3333SBM@(`3333AM@4`?M@(`)5M@2`#M@̮`M@ffff>`AM@3333`Y&M@̈`/M@ffff<`ffff>1M@`:M@3333)`RM@`_M@ffff`bM@ffffr`eM@8`3333kM@`ffffΉM@`M@ffffx`ffffM@ffff*`|M@3333`M@`1M@33335`3333èM@}`3333M@W`M@`̜M@3333`M@3333`M@3333[`4M@̰`ffffntM@9`̌cM@ffff`UM@`|KM@ffff`AM@`+M@3333`D'M@`3333#M@3333`xM@`M@ffff` M@̞`ffff.&M@f`$0M@L`ffff4M@3333`ffffv2M@̸`93M@̮`ffff^;M@3333`IM@3333w`̴OM@taeM@3333aa3333+iM@q`rM@ffff`ffffsM@affffoM@ffffaTrM@ffff8a3333M@3333GaM@3333a(M@ffffa0yM@a\rM@ainM@3333ahM@̲adM@ffffa̔bM@:a3333aM@ adM@3333+ aiM@paTlM@ffffHafffffnM@[a3333tM@ffffapxM@3333affff}M@aiM@ a̴M@}a{M@ffffVa3333wM@̜a3333kvM@!affffoM@ffff:!affffnM@3333aqM@!affffpM@3333a3333lM@3333affffgM@.affffdM@affffN`M@ffffa^M@ affffYM@3333 a3333WM@zaOM@ffff< affffOM@0affffMM@Jaffff@M@a33339M@ffffa,1M@affff.M@&a,M@a3333)M@̤a3333cM@pa3333;M@]a3333"M@ǎ*M@3333M"affff2M@ffffh1adJM@ffff1a3333KM@33332aPM@33333affffvRM@'5axTM@8aZM@;ǎdM@3333=affffflM@>a rM@ffff@axM@GaffffM@GKa,M@3333qNaM@ffff0Qa3333M@QaM@Pa|M@zPaN@b3333C>N@ffffbAN@3333bffffCN@|b3333DN@bFN@ffffЃbffffIN@3333bHN@3333}bBN@~b>N@bffff9N@xb33336N@ffff"b5N@ffffЅbP2N@bffff.N@ffffb\)N@3333b3333C"N@RbyN@3333׆bffffN@3333ׇb3333N@RbffffN@̨bffffN@ffffȍb3333M@b3333M@1bffffM@3333[b3333cM@^b3333+M@ffffbyM@3333bPM@bM@"bpM@ffff>bN@bIN@bM@©bN@b N@ffffFb N@ԭb!N@bffffM@̒byM@3333#bffffM@̜b(M@&bpM@bM@ضb̴M@nb3333M@bffffM@ b3333 M@btM@3333b!M@+bhM@̂b3333sM@bDM@b3333SM@ffffVb̄M@EbM@|bM@biM@b̄M@bffffM@bDM@obM@ffffb|M@bdM@bffffM@JbM@3333bffffM@b3333M@ffffb3333;M@b3333M@3333bM@`b3333M@7b3333M@ffffvb3333SM@b\M@33333b̼M@3333bpM@Cb3333M@bM@3333b!M@ffffb@M@ffffbbffffM@bffff~M@ffffbffffޫM@Nb3333sM@2b3333M@)b)M@hbɽM@bffffM@3333cbM@bM@|b3333M@bffffM@b3333 M@bM@3333gb@M@3333gb\M@3333qbM@ffff$bffffFM@Mb3333M@bM@3333bM@ffffb N@ffffrbN@b!#N@b̴;N@3333)b3333FN@ffff\bffffvTN@hb\N@Lb_N@3333b̬kN@buN@bN@,bffffN@b3333~N@3333}bDzN@bfffffwN@b3333wN@fffffb3333+{N@3333=b3333yN@bpN@3333gbffff.pN@HbYqN@3333bwN@3333b|{N@bffff6N@b̔N@ffffbffffN@bܘN@bLN@ffffbN@9bN@̈b\N@̔bN@ffffbiN@bN@߭bN@bffff6N@?b@N@\bN@3333bffffN@3333?bN@8bN@ffff|b3333KN@bffffFN@bffffnN@&bDN@b3333N@Ab`N@ffffbffffN@bN@3333bffff^N@3333bffff΁N@bd}N@|b3333tN@3333bmN@b̤jN@b`N@b^N@bffff]N@3333b3333SWN@cCN@ cqiM@.cffff`M@33333cffffSM@Z6c,PM@I:c3333SMM@3333;cffff>KM@̢@c?M@Ac33338M@ffffAcffff2M@Bc3333.M@?Ic&M@ffffIc%M@ffffFcffff$M@GcM@GchM@ffffIcM@ffffMc3333M@ffffBRcM@3333Rc M@Rc M@ffff8`cffffM@3333-ccL@3333dcL@jcPL@3333?mcffffvL@pc3333#L@3333rcffffL@3333sc̼L@fffftcffff&L@Swc4L@3333xc3333L@ zcffffL@cL@2cdL@ŁcIL@ffffcL@cQL@cL@c3333L@3333OcL@ffff(cħL@1cffffL@c3333˞L@Ќc8L@ffff4cffffvL@ cffff~L@cTL@ cffffFL@ΖcffffL@cL@3333]c3333|L@3333cLyL@̌cffffxL@3333c3333tL@ffff"c3333nL@tciL@cgL@ffffc|gL@̬cffffnhL@|cgL@3333c)eL@3333c@aL@3333c3333+VL@cffff6QL@3333cXPL@ffffcQL@ciSL@ϻcffffRL@ffffc3333KL@cFL@NcffffEL@cffffDL@ffff½cffffBL@nc9AL@3333Ec3333SAL@c!@L@c4=L@Gc :L@Bc7L@ffff2c*L@3333cffff(L@*ca'L@ffffc̼(L@3333[c&L@c#L@$c L@3333ScL@cffffL@cDL@ffffdK@̰dK@3333gdK@3333dK@DddK@ffffd3333kK@0dK@dffffK@d@K@3333 dK@3333 d3333cK@U d K@̤d̄K@3333 dffffK@3333[d̼K@dffffK@@dffffL@ffffxdL@3333dL@ffff dL@ffff d4(L@d33332L@zd7L@3333c3333GL@3333c3333#XL@cbL@3333cffffnL@ffff`c3333pL@ffff`cxlL@̢chL@c3333eL@̮cdL@̚cffffeL@3333OciL@3333cqL@cxL@cL@3333%c3333 L@3333cL@(c3333{L@3333Ec!L@3333/cܫL@FcffffL@ffffvciL@ffffctL@ffffcL@3333c)L@3333QcffffL@cL@ffffcL@3333!cL@Ȯc3333L@*cTL@ffffcPL@Jc4L@3333qcL@ȵc̬L@OcL@3333c8L@cffffL@ffffcM@±cM@ffff*c M@2c3333M@ffffܪcM@ffffcffffM@̠cy M@Ȱc,M@cffff5M@c3333c@M@Rc RM@ffff0c@^M@JcA_M@Kc3333bM@3333cY{M@ffffc0M@Ԟc3333~M@cffffVpM@Mcffff_M@cQM@cNM@̮cffff&RM@xcq_M@c,dM@clM@=cxM@̞cM@ffffc1M@cffffn}M@c}M@3333c̄M@cM@vc3333SM@cp~M@ffffcffffvM@Vc̜yM@3333c|M@3333cffffsM@ceM@ffffc\M@3333cBM@ffffdWN@>dYN@3333/BdXN@jDdWN@eFd1QN@3333{Hd0LN@Nd̄2N@0Sd3333&N@3333Udl"N@̆Qd3333N@Pd|N@Pd33333N@$QdN@CRdM@qWd0M@3333\dM@3333gdiN@ffff}dImN@3333zdpN@3333tdQpN@rd̔sN@udxN@wd |N@dffffnN@3333!d3333[oN@ffff d4wN@duN@̬dfffffwN@d3333{N@3333dffffN@d3333N@ΛdffffNN@ffffd̴N@wdffffN@hdN@dN@3333ͤd3333N@3333dN@dffffN@3333 dffffNN@d3333#N@ffffΧdfffffN@dffff.N@dN@d,N@3333#dN@3333/d3333N@`d$N@dN@3333d$N@d3333cN@dN@ffffdN@dffff޾N@ d3333N@3333þd3333N@dN@3333dN@;ddN@3333adffffNN@ffff2d3333#N@33337dN@̴dffffN@dN@3333dN@dN@dffffN@̮dN@dDN@dffffN@33335dN@ffffηdO@d3333 O@3333Sdffff&O@9d̜O@Cd`O@AdTO@*?dO@ffff,0dO@3333(d̜O@0#diO@ďO@rd3333[O@d3333O@3333d3333O@3333d3333P@dP@3333 'daP@W,d(P@/d3333P@ffffD-d!P@-&d !P@!d4"P@ffffd%P@3333d9'P@d̤+P@cd\0P@bdffff2P@d33335P@"d33339P@ffff*$dffff:;P@3333%d3333#;P@ffff.d33332P@I4d2P@L8d=4P@3333;d/P@3333Ede+P@3333Jd8'P@XTdffffP@3333Vd)P@3333Yd3333P@ \d !P@fffffdffff)P@̰id3333&P@gd $P@ed"P@ad3333C!P@XcdP@ffffdd P@hdiP@̎od0#P@vd%P@d3333_%P@#dy P@Gd}!P@ffffzd!P@dffff P@ndP@Ȝd3333{P@RdP@kdffffP@3333Gdffff P@dL%P@3333gd (P@gd̘.P@Ld3333 3P@d4P@IdL;P@̠dP@dP@ffffd$P@3333IdćP@ffff(d4P@ffff(deP@3333dIP@3333dP@3333d3333P@dffffvP@ffffָd3333kP@add,P@LdEP@+MdP@Md3333P@̨Rd3333/P@]XdTP@`d3333P@qd̐P@wdP@ydXP@ffff*~d̐P@dP@ffffZd3333Q@̴dffff Q@̌dQ@dQ@bd3333Q@3333)dQ@̚dQ@xd(Q@3333dQ@@dQ@NdQ@3333-d5Q@d$Q@3333d3Q@̰d8Q@Mdffff7Q@hdffffz8Q@ffffxd9Q@̬d3333;Q@ffff΄d=Q@{dXBQ@ffff$qd3333JQ@ffffhdffffVQ@̐fd3333YQ@edYXQ@*edXQ@33331dd]Q@ffffbdgQ@w^d̄pQ@ffff6KdffffQ@FBdffffQ@K?dhQ@0Q@-d̤Q@ dTQ@ cffff6Q@cؑQ@^c3333Q@pcQ@cffffQ@ffffcПQ@cQ@ffff`cQ@c3333Q@3333c̔Q@ffffdQ@cffffZQ@ffffc9Q@ffffjcQ@"cQ@ffffcffff>Q@dcffffQ@cQ@c)Q@ cffffQ@fciQ@cMQ@c3333#Q@Xc|Q@cԵQ@cQ@c Q@3333ac=Q@ffffdc̈Q@@cQ@%c̸Q@ciQ@ c3333Q@c3333cQ@c3333CQ@&cQ@ c̨Q@yc3333Q@̨tcffffQ@̊rcQ@ffffNtcQ@3333yc̴Q@̰caQ@WcffffQ@3333'c3333Q@3333{c3333kQ@ffffvcݶQ@ffffrcWc`Q@ffff YcQ@3333.bffffBQ@'b,Q@P&bffffQ@ffffb3333~Q@3333W b3333Q@3333 bffffvQ@affffQ@ affff~Q@la3333Q@aQ@ffffapQ@̦a)Q@a |Q@̀awQ@`aMqQ@ذamQ@ aiQ@֪adiQ@DaffffjQ@a4jQ@affffiQ@a3333VQ@a3333?DQ@a1Q@aQ@a$ Q@aqP@affffP@affff P@a3333WP@aP@aP@aP@a<333+P@aP@aTP@aAO@aO@a0333sO@a wO@axfffQO@a@,O@aO@aqN@a N@a8333N@aM@a̔M@ffffa4M@3333a|M@aԣM@ffffa3333úM@! a`M@3333a3333{M@ffffaxfff6M@ffffL a3333kM@affffM@`M@{`HM@:`M@`$M@ffffX`xfffM@`M@ffff,`|M@ffff`pfff~M@H`M@43333`hfffM@`ffffM@4333`M@`M@4333`M@`M@ffff `33333M@`,M@`|M@ffff`HxM@̀`sM@`lM@6`3333eM@4333`aM@C`ffff>ZM@̐`pLM@|`q@M@֬`4M@`$+M@4333Ϩ`hfffM@ffffڣ`3333 M@ `xL@V`AL@`L@ `3333L@`L@(`L@4333`xfff^L@n`iL@`3333L@Њ`3333+L@ffff`3333+L@ffff`fffffL@4333`zL@ffffV`3333mL@~`3333hL@{`3333{eL@Z|`ffff^L@̨z`WL@ffff`z`̄KL@3333t`LLL@4333gr`xfffLL@o`3333CGL@̾j`(@L@af`9L@3333b`3L@ffff]`ffffv0L@W`+L@4333T`!L@ffffDO`8333L@ffff8M`ffffL@F` L@!C` L@ffffA`YL@@`3333L@3333s@`3333K@@`K@;od}K@ffff ld3333chK@jd@dK@hdffffaK@edffff_K@ffffRdd̔\K@3333bdWK@bdUK@ukd3333+^K@pd̴QK@rdffffPK@ffffXd|OK@3333{d0MK@d!IK@d=K@d3333S9K@Ԏd33336K@d3K@3333͗d(4K@Yd̤5K@dffff;K@3333d3333EK@3333d3333HK@gdMK@ d3333TK@3333d3333XK@dpK@Pd3333tK@d3333tK@ˆd4sK@ffffdAzK@ffff{dK@ydHK@ffffpsdK@ffffqd؄K@3333YpdԁK@;od}K@3333é`K@`K@`K@`9K@3333`xK@Ѯ`ffff6K@ffffʯ`3333KK@`3333K@ffffδ`xK@R`K@ffff`3333K@K`ffffK@ffff"`3333{K@`3333K@`K@3333é`K@3333j`8K@3333g`yK@lg`ffffsK@j`qK@l`xrK@3333Cn`dtK@ffffn`wK@m`̌K@ffffjo`3333K@Hq`4K@r`IK@3333 s`̜K@q`ffffK@}r`̴K@̂r`؟K@r`ffffΡK@gp`K@l`ffffNK@3333j`8K@ffff`L@3333A`̼K@`K@̺`3333K@1`ffffK@ˋ`IK@`ffffK@u`aK@ffff`L@p`ffff6L@K`L@` L@`ffffL@ffff^`ffff^L@3333`L@(`ffffL@?`ffff~)L@0`*L@'`?L@ `fffff>L@ffff`1L@$`3333CL@ffff`L@3333U_`̜K@r``̌K@b`ffff&K@3333f`hK@3333ah`!K@3333j`ffff^K@3333k`ffffK@ffffvm`PK@nn`|K@m`(K@ffffRn`3333SK@3333/o`ffffίK@̲p`K@t`3333CK@ffff(w`3333K@fffffx`9K@y`ffffK@z`K@3333{`HK@Mx`dK@̸t`3333K@s`tK@h`IK@̎g`xK@ffffc`ffffK@_`3333#K@3333^`3333K@^`̴K@3333U_`̜K@`3333sL@3333`p|L@n`3333L@E`qL@D`̴|L@3333`wL@ffff`̬pL@3333k`3333lL@Ӟ`3333+dL@3333`ffffF[L@`VL@ffff:`RL@!`ffffOL@`tOL@ffff<`tWL@Χ`ffffeL@̆`@jL@3333`hL@`3333dL@`3333\L@E`9XL@`RL@3333`9NL@`HL@`̜CL@`a?L@3333ɥ`33332N@zFb3333/N@jMb3333)N@ Sb\"N@3333Sb#N@ffffTbffff*N@3333Ub3333+.N@~Vb33332N@3333{Vb3333K4N@rUb`7N@cSb;N@Qb3333=N@3333Lbffff9N@ffffwbM@3333{b@M@3333{bM@3333zb3333sM@xbM@zwbM@jsbN@nb3333k N@jbN@3333fb'N@eb3333-N@3333cby.N@̢`bffff*N@̦^b$N@3333_bffff N@0jb3333 N@3333kbffffN@ffff lbffffM@lb(M@ffffRnbM@3333Wob3333M@ffffobM@Iqb3333 M@Dsb3333M@3333tb3333CM@fffffubpM@ffffwbM@ffffub9N@ubI6N@vbffff3N@ffffubffff-N@vb"N@mwblN@3333QxbYN@6ybffffN@3333zb3333N@3333Kzb3333N@ybffffN@{biN@̆|b3333S&N@3333[{b$)N@3333zbffff,N@zbffff/N@lyb:N@xb;N@xb8N@Sxb)8N@wbD9N@~vbP>N@vbffff>N@ffffub9N@ffff}biN@ffffցbhN@bQjN@b3333lN@0brN@@b3333CuN@33335bIvN@ffff~b8sN@.~b pN@ffff}biN@: c3333L@K$cًL@%cffffL@ffff'cL@t)cffffL@+c̤L@V+c3333L@ffff )cL@3333c3333kL@c3333L@ffff c3333L@c3333L@: c3333L@c>M@3333c3333C=M@cffff.AM@3333_cffffVEM@3333[cHM@ffffc3333+OM@ cHOM@ c8NM@3333k c(LM@ cIM@ c3333;EM@c>M@3333'cL@(c3333CL@ffffp)c,L@:+cTL@.cfffffL@0cL@ffff0cffffVL@d/c3333KL@ffff+cfffffL@H)cffffL@3333'cL@rcK@3333[scK@uc3333[K@ffff$wcffffK@ffffwcffff6K@scK@scPK@XrcffffK@ rcffff~K@rcK@Uc7L@ Xc4L@Xc33335L@ffffXcffffN8L@YXcffffNK@3333ecK@c̼K@ffffc3333SK@ffffcXK@Tc̄K@c3333{K@d3333 K@$dK@d3333KK@ffffڽd3333K@ffff*d K@dK@ffffJdffffK@bdK@dffffK@Rd3333{K@d3333K@ffffdffff~K@ffffvdxK@3333dYK@,d K@̜da K@d3333 K@dK@ZdK@3333dK@3333۳dffff~K@dl K@d3333#K@̞d3333k$K@dffff#K@3333dfffffK@"dK@3333 d1K@ffffd(K@dK@ffffhdffffIM@dGM@?"dHM@33335$dUM@̴"dUM@3333d3333C^M@ffffdeM@ffffdeM@ffffhdffffIM@ffffe3333:N@Րe$2N@fffffe3N@e+N@3333meI&N@ea*N@Xe*N@3333e<;N@ffff^e!?N@ffffeffffHN@ffffe̬MN@̆e@N@ffffe3333:N@3333#Ee3333L@rHeL@tKe̼L@3333YLe3333#L@3333_LeL@Ce3333L@3333#Ee3333L@ffff$6effffvlJ@̨6ePgJ@ 7e3333keJ@33334eEL@ffff8eML@*8eIQL@, f`I@ffff0 fI@̬ f3333CI@3333= fI@3333 f9I@f3333I@, f`I@fffffPJ@3333qf3333I@fffff̌J@fffffJ@f,J@3333f J@zf3333 J@f J@ffffeTJ@5e̴J@fffffPJ@$fffffI@%f3333I@3333['fffffI@ffff<,f8I@ffff0/f3333I@{2f3333I@4fI@ffffr5f̼I@3333]5fPI@*f3333[I@;(fI@ffff&fffffI@3333S%fhI@33335$f3333I@#fI@ffff"fqI@"f3333I@ffff#f3333I@R$fII@$fffffI@hfffjRf@HI@`Pf@ffffI@IOf@̤I@43333Of@ffffI@LPf@QI@hfffBRf@ I@4333oSf@I@hfffjRf@HI@4333snf@I@hfffhf@̤I@̠]f@|I@Wf@I@Tf@3333kI@hfff&Vf@ffffI@hfff]f@3333I@hfffbf@3333I@ef@ffff&I@4333kif@ffff޵I@Lmf@PI@4333snf@I@ e@ffff.J@ e@ffff-J@e@2J@e@3J@e@8J@4333e@9J@4333 e@ffff@J@ոe@`?J@Էe@3333+9J@ e@ffff.J@ffff`3333L@P`L@W` L@`L@̨`kL@ffffJ`̌aL@`[L@``LL@`L@ffff`L@3333ѻ`L@T`xL@v` L@`L@ۿ`̤L@3333` L@&`xL@Z`ffffL@ffff`L@`lM@`3333M@`3333KM@Z`M@`fffffM@̜`QL@`8L@`3333+L@`̜L@`qL@w`L@(`ffffƹL@3333`1L@(` L@`3333L@3`iL@3333S`ɒL@`3333KL@3333`3333sL@`ffff^L@`ffffƋL@ffff`L@3333`ffffL@m`L@`ȵL@`3333L@`ffffL@`̬L@ffff>`ffff6L@!`\L@`ffff M@ffff>`M@`ffffM@ `3333!M@`3333*M@3333`d-M@ffff`3333(M@ffffv`M@`M@3333_`3333CM@`M@`M@3333`3333[M@.`ffffM@z`ffffM@`L@N`M@ffffz`3333 M@`M@`3333M@6`D M@3333`M@̌`ffffM@`L@`3333L@ffffH`ffffL@E`ffffL@f`lL@`3333cL@ffff`L@R`L@3333`L@ffff`3333kL@`ffffL@3333`iL@ `lL@ffff`L@`LL@3333y`3333KL@ffff`iL@3333`|L@ffff$`L@3333%`)L@`ffffvL@saXL@ffff āL@aL@2apL@ayM@daI M@ffffa3333 M@3333 aPM@M aM@a(M@a3333 M@a3333M@3333a\M@`(M@3333Q`XM@33337`3333M@/`ffff^"M@3333_`3333CM@`3333k+L@3333 `̬(L@~`(L@3333`#L@X`L@`3333L@j`3333L@ffff`yL@3333=`ffff L@`ffff L@>`\K@`K@`ffffK@3333`(K@č`K@ffff>`pK@3333߆`iK@̆`̄K@ffffH`TK@x`K@ffff\`ffffK@ffff`̔K@`K@`ffffVK@3`K@ffff`pK@3333_`нK@ffff`ffffK@`K@ `XK@``K@`3333K@ffff`ffffNK@3333`K@O`K@)`̄K@>`3333K@3333`TK@ffffH`|K@3333K`YxK@`asK@3333`ffff.oK@ffffr`ffffjK@3333c`gK@`\K@ffff`H[K@ffffL`4[K@ffff`^K@`3333fK@` tK@؋`3333 vK@3333`ffffxK@3333`ffffyK@ffff`ffffyK@`tK@Ԓ`3333K@`ffffK@`fffffK@ffffJ`ɒK@t`̴K@ڕ`ffffvK@ffff`كK@`4K@4` K@ffff`̄K@3333ˣ`K@L`K@`3333SK@`ffff&K@3333`K@`ffffK@ffff`xK@`3333{K@ffffޢ`iK@̧`ffff6K@3333`ffffK@ffff`ffffNK@Ϋ`0K@ffff`3333K@ffff`xK@~`K@ĵ`K@B`3333K@̰`3333K@ffff0`|K@M`K@,`0K@N`K@3333ߩ`xK@ffff`K@`K@3333A`dL@3333`L@ffff<`K@3333`̬K@·`K@ffff*`ffffK@,` L@`̤L@3333i`L@`L@(`3333{(L@`3333k+L@̪`(lL@`IcL@ffff`dL@ffff`L]L@̠`ASL@`LL@`@NL@ffff^`̄JL@ffffF`$>L@ڻ`1L@N`d%L@ffff`L@d`YL@` L@ο` L@`3333;L@(`ffffL@` L@3333` L@`L@3333A`ffff4L@3333`i:L@`AL@I`ffff>JL@ffff`NL@3333M`̬\L@`ffff_L@3333`YkL@`ffffuL@`ffffVwL@ffff`3333rL@`AoL@̪`(lL@W c3333.M@3333/ c-M@ c4M@ c4M@Ucy.M@c/M@3333c3333'M@,cA'M@b8(M@.b'M@pbffffFM@ffff4cffffM@}cM@KcM@c3333M@'cdM@ c$ M@ffffc8 M@3333 cM@3333 cM@ffff cM@3333 c3333#M@ffff2 cM@sc3333M@ffff4c M@cffff.M@ffffHcM@$cM@pc M@c3333M@qcM@ffffc M@3333cM@c1L@3333qcL@ffff)c3333M@4,c) M@̴#cM@ffff<c&M@̦c̜%M@cH#M@3333c#M@3333c<,M@c33332M@ffffcL5M@̖c̬9M@c 9M@dcffff6M@Oc)3M@W c3333.M@d,J@exJ@ e3333sJ@EeffffΊJ@.effffJ@effffJ@eJ@ffffZeQ{J@ffffe3333{zJ@"effffjJ@ffff"ejJ@V"e̜nJ@*eptJ@eyJ@3333effffJ@weJ@ffffe(J@e3333 J@NehJ@3333effffJ@re̼J@3333OeJ@ eJ@ffff, eHJ@ e3333ۦJ@ffff e4J@ffff eIJ@ e3333SJ@ffffn eJ@4 eJ@-e3333CJ@ffffXe3333KJ@̊d3333sJ@dJ@d3333J@dJ@3333d3333J@d,J@̰dQJ@3333Odffff>J@3333dJ@3333+d`J@3333d33333J@dffffJ@dffffFJ@3333cd`J@33335dJ@d3333J@udJ@3333dJ@Od9J@3333dJ@3333dHJ@ffffXdffff6J@6dffffnJ@ffffd J@ffffxdJ@3333dffffJ@3333;dJ@ffffd3333CJ@d4J@ffffdpJ@3333dܬJ@d̤J@3dffffƫJ@̸dJ@Zd`J@d3333[J@3333dJ@d4J@ldffffFJ@dffffnJ@dqJ@3333dyJ@ffffpd3333{J@3333ddJ@dJ@d3333[J@Zd3333cJ@ffffdfffffJ@[dJ@̀ddJ@̜d3333;J@d3333J@33333dJ@3333d̴J@d3333J@ffffdAJ@3333dJ@wdJ@ffff"dJ@3333d3333sJ@IdffffFJ@3333adJ@ffffd3333J@dJ@3333dJ@8dJ@ffffLdAJ@ffff(d3333+J@3333}dHK@d3333K@dqJ@̰dQJ@̴eqJ@ffffneffff> J@e J@3333Ǡeffff J@e! J@3333eJ@ffffne3333J@ʫeffffJ@ffffeQJ@eJ@̾e3333+J@ffff effffJ@ffffĽe< J@̪e3333C J@ffff¿eJ@ effffJ@3333ieY J@effff&J@efffffJ@̴eqJ@3333e3333{J@e8I@3333ueffffJ@ffffeJ@eJ@3333Oeffff J@ffff^effffFJ@3333-effffJ@e3333J@ffffHep"J@e3333%J@e3333(J@e+J@e`0J@ge5J@ue/J@ffffex*J@ffffe%J@e|J@33339eJ@e̤J@ffffeffffNJ@ffffe J@3333e3333{J@fffffI@fffffffffI@&f0I@ fI@ f̌I@yf3333+I@fffffffffI@ZfpI@3333f$I@fI@f3333I@fDI@3333fffff.I@fI@̐f3333I@f̄I@Xfffff6I@3333f3333I@̘fffffI@̦f̴I@fffffI@3333!fI@3333;f!I@ffff9fffffI@4f3333I@27f̜I@33338fI@ffffv:f3333I@3333!d̬5@ffff8ddfff6@3333d06@fffftddfffF5@dL5@ddfff5@dP5@0c4@cdfff4@&c4@3333c`4@ffffcdfff4@3333#cdfff4@-c43334@3333%cdfff4@ffffcdfff4@0c4@hfff^Rxfff~F@ffffrRF@3333RF@RF@HfRF@ffffKRF@1RȀF@ffffbR؀F@QF@3333QF@Q̤F@ffffQ!F@3333Q3333SF@ffffQ̤F@3333QF@ffffQ3333+F@3333sQ3333F@3333GQffff6F@xQF@\QffffF@ffffQħF@ffffQffffޮF@%QгF@ffff6QF@QiF@%Q3333ӶF@LQIF@ffffFQܿF@Q3333F@3333+QffffnF@ܝQyF@3333Qffff~F@ffffQ̤F@3333WQF@Q3333F@`Qffff6F@̜Q3333kF@|QXG@ّQ33333G@Q G@Q+G@LQt8G@ffffrQ$IG@ffff~QffffZG@ffffwQkG@mQXG@ffffNhQiG@,^Q̌G@VQG@ffffVSQtG@3333OQ3333CG@\IQffffG@ffff6CQ3333G@DQHG@CQffffG@33333@Q3333CG@3333;Q G@33338QffffG@ 5QffffG@*QqG@ffffQ̔G@3333QxG@QG@Q`G@ffffQHG@1Qffff.G@PtG@ffffPG@aPffffwG@8P3333cG@ PNG@ffffP3333?G@̸P0+G@ffffP3333G@UPdG@8PF@3333PF@Pffff&F@PF@ffffPF@3333PF@ffffPF@3333PF@1PF@̹R>P0WF@3333;P3333F@ffffPffffF@PffffF@3333PpF@3333P̴F@8P#XF@̰P33333F@|PdF@)PF@PF@8P!F@PffffF@3333P3333F@ffff P3333F@3333cP`F@PF@̐P3333F@ffff>PPF@3333P3333F@ffffPffffF@|Pffff>F@-PF@ffffPffff~F@3333SPffffF@P3333F@P̤F@P3333KF@PF@XP3333ˑF@3333P3333;F@ffff&P̜~F@ffffJPxF@PIqF@P3333oF@tPlF@3333+PiF@=PyVF@LP33333YF@LP TF@PRF@3333WPIF@ffffPGF@P3333HF@3333PJF@3333P3333IF@ P:F@̜Pffffn;F@P5F@QP3F@Q11F@3333Q3333+8F@Q>F@3333 QA@F@ Q3333AF@ffffQAF@Q@F@EQF@̈=Q7F@1=Qffff,F@DQF@`DQ| F@HQF@xNQDE@ VQffffF@ffff[QhE@ffff^QE@TaQE@̨bQffff6E@̠cQ3333E@ffffeQ3333{E@ffffgQE@hQ3333sE@iQ8E@fffflQffff>E@nQffffE@pQ3333+E@lqQ3333E@ffffrQE@hsQE@rQE@sQ3333E@uQ3333E@3333wQffffE@<{QE@3333[~QE@ffff^~QffffE@ffff}Q3333sE@QE@qQE@3333;QE@9QffffE@3333Q$E@QxE@3333SQffffE@Q4E@D@ffffΞQffffD@ffffQaD@QffffvD@QffffD@3333QD@3333߬QD@YQffff6D@3333QD@Q̤D@3333QD@3333QD@̄Q3333sD@iQ3D@I}R*D@4~R D@ARffffD@ЁRX D@!Rffff&C@RC@`R C@ffff"RffffC@$RC@3333RC@ERC@3333kR3333C@(RC@ Rffff>C@3333RPC@3333KRffff.C@qRC@\R٫C@RfffffC@ RffffvC@3333R3333sC@̴RffffC@3333WR3333C@زRffff>C@RffffvxC@3333RyC@ffffR C@hRffffC@3333kRC@ffff6RC@ffffR3333C@R3333cC@ffffRC@̌RffffC@3333;RC@R C@3333/R0C@RC@ffffR4C@RlC@̤RffffFC@3333R3333C@RC@RffffC@RqC@̸RffffC@3333#R3333C@3333RC@8R3333sC@ffffNRC@ffffR C@DRC@hRC@RC@R{C@RhC@̬RffffcC@`R̄\C@8R3333PC@RKC@RLC@R3333JC@LRl@C@3333{R33336C@HRffff1C@ffffR.C@ffffR3333{4C@ffffR3333s6C@xRffff3C@3333R11C@ffffR)&C@=Rffff C@mR3333C@̬RC@R3333SC@3333+R3333B@3333R3333B@3333kRffffB@RB@R3333B@RlB@RB@RqB@ffffR)B@RġB@3333gRB@3333R@B@ffffRB@ R3333#B@1R3333B@ R3333B@tR\B@3333R1C@ffffR C@ffffRC@3333 RC@eRC@3333R3333cC@ffffJRp!C@R(C@RX.C@ffffR-C@R3333'C@R3333K%C@ffffR|*C@mSP)C@LSffff%C@3333GS#C@tS(C@ S@.C@S7C@3333SP?C@S3333LC@ffff S0OC@ffff:SMC@3333SMC@S3333PC@̤S̄OC@33333 StZC@ SaC@SbC@Sffff\C@SffffZC@8S3333hC@ffffSLiC@3333 Sffff&mC@ffff: S1uC@iSffffxC@)SLtC@SyC@S33333C@ffffS,C@ffff S~C@3333S3333C@ffffS̼C@ S$C@SffffC@ S3333SC@ffffSffff6C@ffffvR3333C@R C@RC@33333SffffC@ffffRԺC@ffffvR3333C@ffffRdC@3333RffffC@3333_R3333C@3333gS3333C@S3333C@qStC@ffff*S33333C@9SpC@ S̜C@ SC@ffffFS̵C@S$C@pS3333C@SPC@,S3333C@8S3333C@SC@SffffC@ffffSffffC@3333S\C@S̜C@$SyC@3333$ŠC@QSPC@]S!C@ffffStC@3333GS3333C@"S3333C@3333#SYC@4!Sffff&C@SxC@@!SrC@ffff SkC@Y!SffffdC@\"Sffff_C@ SffffDC@XS3333EC@ffffHSffff6SC@3333sCSXZC@)AŠcC@AS3333qC@3333BSLcC@ES\C@JSVC@ffffPSLC@)RS̼CC@3333TS2C@|QSffff-C@NSffff+C@GS`/C@ffffBS-C@:S9C@E)S$C@3333+#S C@1SffffnC@3333S3333KB@S`B@SffffB@S̬B@3333S\B@ffffS|B@SB@̄S3333SB@̼2SB@5S3333B@(S̬A@&S33333A@`#SffffA@ S̜A@8$S3333A@&S̔A@A'STA@1(S3333cA@1S3333~A@33337S3333A@3333DS3333˓A@e>S9A@33339S1|A@/SqxA@3333;S3333~A@ffff.SwA@%SkA@!S|cA@'ŠbA@@-SffffF`A@.Sffff~ZA@2S!ZA@ffffV9SYA@3333+CS3333CYA@HS̜ZA@PSNA@RS,MA@VSdOA@3333XSXA@ffffbZS3333]A@mZS3333KA@3333YS3333GA@ffffNXShCA@!aSffff9A@iS3333-A@3333lSffff~*A@ pSy$A@wSA@xS3333kA@a{SI@@{Sffff@@D{S\ A@ffff}SA@~S(@@ffffڀSffff@@S3333s@@Sffff@@ffffڵSffff@@ffffSP@@S@@3333gS@@@AS@@̌S|@@ffff~S3333ӳ@@S`@@S3333@@ffffST@@Sq@@ffffSffff~@@3333S@@3333[S3333ct@@ffff S3333i@@̄Sd@@Sg@@1SffffF]@@4SdU@@dTYO@@ThK@@ffff T3333K@@3333T3333I@@,TD@@8T@@@̀T3333B@@3333$TPD@@ffff(TA@@!T<@@ffffZT6@@ffffT-@@3333 Tffff)@@%Tffff$@@&T3333{%@@ (T3333)@@l)Tffff2@@`+T0@@3333+T,@@e-T$+@@\3TY9@@3T3333.@@33330T0&@@3333.Tffff!@@ffff,Ty@@ffffn,T̜@@33330T33333@@̜2T3333@@Y6T̔@@t8T@@7T@@;Tffff?@ffffBT\?@MET2333?@@GT?@FTffffF?@)DT@?@3333;DT?@LFT?@`JT2333c?@ffffLTffffF?@KT̼?@JTi?@JT@ffffNaT>@ aT2333C>@@`T@>@ffffB]T >@XTE>@3333UTffff&$>@OTffff6=@̰FTt=@9T2333 =@$Tp<@3333!Tp|<@3333W$T,m<@1%T\]<@p%TffffE<@$TL.<@3333"T<@=T2333;@T9;@ffff 'Tffffv-<@'T2333R<@&T܅<@̀(T̜<@)T2333s<@3333*T_<@ffffb,TPX<@.Tv<@̨.Tffff&<@,T<@,Tffff֙<@1T<@1Tffff֮<@X1T2333<@3TI<@̤5Tffff<@`4Tffff<@a2Tffff<@/Ta<@+T̬E<@3333)TP.<@xT5;@ T@;@̬T2333s:@4Tffff:@̤T:@T!:@ffffT`9@̸Tdfff9@% T9@, T9@T43339@@TY9@TdfffVm9@|TT9@Tdfff:9@#T;9@3333#/Tdfff(9@ffff.7T-9@@T"9@ffffGTdfffV#9@ffffJT:9@(JTD9@̴HTdfffFO9@@FT4333Q9@=Tl99@0TO9@3333CTV9@@GT4333^9@NTY9@VTY9@3333[WT9@ffff^dT<9@ffffmT9@3333sTfffff%:@uwT\o:@{T̬w:@3333_}Tl}:@PyT:@uT2333:@3333kxT):@ffffzTffff:@3333~T2333S:@hT23333:@̈T2333S:@TP:@HT<:@ـT):@ T2333:@3333T:@ffffʊTffff:@T:@3333TP:@T:@̨Ť:@3333?TffffF;@T̬f;@Ts;@Tffff;@3333T;@TI;@UT2333;@Ti;@ffffT;@Tffff;@ffffT ;@T0;@QT̼;@T\;@3333T0;@ffff6T;@T2333;@ffff.Ť;@ffffT;@T;@LT;@ȭT̬;@3333T;@ffffT;@3333T;@T2333;@T<<@HT`|<@3333T<@8T<@T23333<@@U2333>@ffffUl>@Uffffv=@U=@UI=@3333U=@33333#U=@<3Uffff=@8U2333=@3333>U̾=@AU=@KU9=@iTU2333#=@ffffXU=@|ZU=@|ZU̬=@ffffXU=@UUy=@3333'TU2333=@3333SU@=@VU0=@ffffF`U=@@kUffff6>@3333gU>@ffffgU%>@ujU0>@iUffff<>@fUiI>@AkUG>@ioU>>@̌oUffff3>@3333_pU*>@rUffff,>@3333vU23336>@5U U>@U,f>@]Um>@U2333g>@ЈU q>@ffffUv>@xUffff6~>@ffffUi{>@3333U~>@3333U2333w>@ɦUl>@3333U2333#g>@U2333S_>@UV>@ffffzU_>@Ǔe>@3333ULn>@ĽU|>@ؿU>@3333+U̍>@U>@ffffU>@3333U>@Uffff&t>@Ǔe>@UV>@3333sUffffVK>@ U,O>@fffffU2333#]>@̰Uffffd>@U<^>@3333UffffC>@aV;>@ffff U A>@3333U2333SB>@U2333J>@ UX>@3333ULh>@ffffrUffffj>@(Us>@ffffU>@ffffU|>@Vffff>@3333Vfffff>@V2333>@uV2333Sj>@3333V]>@3333V\>@dV̜_>@3333K,VZ>@y4Vh>@ffff7V2333j>@33339VffffFj>@uCVffffF^>@PNVffffU>@ffffPVW>@TVfffffX>@ffffb\V 9>@eV|*>@ffff}VD>@VffffY>@V|^>@3333kVa>@3333?VG>@3333oV#>@@8V2333s>@̠V,>@8yV9 >@sV>@3333{qV #>@ffff2oVffff,>@̸jV%>@jVffff>@mV >@ffffqV2333 >@,tV>@ffffoV =@mhV`=@ffffeV@=@ffffdV>@̤_V2333>@YV >@ZV>@̨YVI=@3333VVffff=@8WV=@3333VV=@%]V=@ffffaV=@eV̬=@cV2333=@̸gV2333=@`jVffff=@kV2333ì=@lV2333c=@3333#nV=@0kVffff=@$eVl|=@`Vk=@OVLU=@KVU=@ffffzGV̌?=@ffff.DV7=@AV3=@ffff^AV$=@ffffGV2333C=@̈HV =@IV@=@3333LV2333 =@OV2333=@(UV<@ffffXV9<@VV=@XV2333=@\\V23331=@daV?=@dV|D=@ffffgViM=@ kVffffQ=@3333mVP=@ffffrVLU=@sVpa=@ffff^tVffffj=@$xV@u=@ffff.V2333=@ffffJV =@ffff Vz=@3333sV̜v=@YVpn=@`V9V=@VK=@3333KV`==@|V.=@Vffff"=@ffffV=@ffffʏV!=@MV|A=@DV̌K=@(V̼L=@̄V2333E=@\V&=@V!=@,V1=@VI=@VR=@33333VT=@ffffV2333cQ=@VffffY=@V2333u=@Vfffff=@Vp=@ffffV=@ffff.Vy=@V,=@%Vffff=@ V=@3333V,=@)Vffff=@W=@ffff"W=@W=@3333KW=@W=@`W2333×=@W̌=@ffff*W٘=@̤2Wy=@KWi=@ RWffff=@XW=@xlW=@qW=@tW2333=@hwWp=@xW\=@3333KvW=@3333sW=@ffffzqW=@8qW=@rW,=@ffffuW=@|W2333=@ffffxW=@xWy=@`W=@ĤW |=@W`b=@ffffW2333k=@ffffWffffF=@W\=@3333W =@3333ϱW@=@\W=@|W=@DW=@WL=@3333W =@ݾWl=@ffffvW̳=@ffffW=@Wu=@ٸW^=@,WlB=@ffffWffff*=@̼WI=@̀W<@3333W<@W<@3333W23333<@ffffW<@ffffNX9<@ Xy<@ffffX,}<@3333wXffff<@̴Xffffơ<@\XI<@3333Xffff<@ffffX23333<@X<@X0<@ffff!Xffff<@ffff#X9<@$X9<@&X)<@ffff(X2333s<@!X}<@ffffnX̬z<@3333X2333u<@HX2333g<@3333#X]<@I+X`W<@1Xk<@ffff2X2333#R<@3X`8<@ffff5X23331<@9XffffV(<@3333:X2333s/<@3333;Xi9<@=Xffff0<@@X)<@%FX2333(<@JX2333$<@IXffffF<@ffff IX̌<@ffff2BXffff<@DXp;@JX,;@PX̼;@WX;@YX;@[X2333S;@ffffzRX̬;@YXXYk;@ffff\X T;@̴^X Q;@3333aX`P;@kXe;@ffff.qX u;@PlX2333I;@ _Xffff<;@ffff^^XffffF,;@q^X,;@ffffaX ;@cX2333:@ffffaX2333S:@ffff_Xffffv:@]Xffff:@[X`|:@YX2333e:@̰MX`:@IX:@HX̜:@\IX4333#9@RX 9@̬UX4333C9@ffffbVX9@VX9@ffff XX09@-\X 9@eX43339@ffffJsX2333 :@LX:@ffffXffffv:@33333X.:@X|9:@ffffJX2333<:@@XffffF:@Xffff&W:@ffffXa:@ffffX2333#f:@Xir:@3333Xl:@X:@3333X :@3333[X|:@3333cX2333c ;@33337X;@8X2333;@3333KX;@,X̌+;@ X2333;;@XffffI;@̤X W;@Xffffe;@ffffXffffw;@3333WX`;@Xɢ;@EXܺ;@Xffff;@3333Y@ <@ffff*YffffF,<@)Y><@ffffY2333S<@Ym<@HYffff|<@3333;Yffff<@Y<<@ffff.#Y2333C<@(Y <@3333'*Y̌=@3333K0Y.=@$;YP=@3333 AY2333f=@xBYffffu=@ffff~BYu=@lSY2333S=@XXY=@3333/\Y=@`Y=@3333bYffff=@bY=@edY)=@$gYffffv=@ffff&pYP=@3333kY2333=@pY2333C=@ffff6Yffff=@Yp=@ffffY=@3333{Y2333=@3333[Y=@Y٤=@`Yffffq=@ffff.YP=@3333gY B=@ffffYfffff7=@@33335Zr>@ffff:ZffffV>@̤>Z\>@HFZffffv>@3333QZ>@`Z2333>@3333tZ2333=?@ffffZ2333e?@yZps?@]Zp?@4Z2333ӭ?@Z2333?@Zffff?@Z)?@3333Zffffv?@$Z?@ffff6Z ?@HZffffV?@YZ?@lZ?@}Zffff6?@ffff [2333?@ [ffff?@̤ [?@3333 [ q?@ [ffffVT?@X$[,T?@3333:[T?@Q[2333S?@4h[S?@3333~[S?@ffffr[ffffVS?@[)S?@[S?@ [ffffx?@d[ffffƞ?@ffff\̬?@<\?@qZ\3333;@@x\,@@ffff&\ffff.@@\A@@ffffn\3333KH@@ffffb\[@@3333\4Z@@3333\ffffvW@@T\T@@\3333Q@@\D@_ffffLD@(_3333ZD@@_^D@ffff_3333+]D@ _ZD@_ffff&YD@3333W __D@, _bD@=_4cD@3333_ffff6eD@3333 _9iD@̄_!|D@ffff_D@ffffb_,D@ffff_ѺD@_̔D@ffffr _D@_3333D@\ _̼D@ _D@̼_3333E@=_&E@_0E@ffff_ffffJE@3333g_UE@"_ hE@_3333wE@_̔E@ffff._3333E@̄_!E@_ffffE@ffff _0E@_3333۷E@ffffn_qE@3333O_ E@ _fffffE@̄ _3333E@\_ F@X_*F@ _ffffv6F@0_BF@_RF@_̌cF@^ffffNF@3333^F@ffffz^F@̄^ffffF@^ffffG@ffffj^3333G@P^G@̠^3333G@X^QG@^`G@ffffb^G@^ffffG@3333^ffffG@̔^ffffnG@ffff^G@^iG@^ffffG@3333^IG@^3333"G@3333^D"G@ffff^a&G@3333S^ffffF"G@l^ffff~&G@_#G@3333_3333/G@ffff6_>G@ffff_3333sMG@ _̼BG@^ffff^7G@d^DDG@^3333{TG@3333K^ffffZG@ffff_T_G@4_lnG@^I{G@3333^3333~G@_̃G@ffff&_G@y_3333 G@_33333zG@x _ffffG@ _G@ _G@3333_ɳG@_ffffNG@q_aG@'_3333G@p*_G@,_iH@̄+_$H@p-_0H@|(_0H@u_&H@3333; _H@ffffR_H@3333s^H@^LH@ffff^ffffH@\^H@ffff^QH@̌^q H@T^a H@3333+^ H@^ffff H@Ա^̜H@3333^\H@8^ H@X^H@|^DG@ffff^G@ѱ^̄G@P^ G@3333^ffffNG@^ffffG@=^ffffG@3333c^G@ffff^3333kG@^3333G@3333^G@ffff^3333G@^ffff.G@ffff^G@ffff*^ffffVG@ffffF^(G@^G@^3333[G@^G@l^ffffG@^3333KG@t^3333G@^̌G@^G@^G@ffff^LG@|^G@^G@̰^iG@^yG@^H@0^3333?H@3333^ffffv>H@3333˟^ffff@H@^DH@ffff^GH@Р^UH@3333^3333aH@^̔cH@!^cH@\^0bH@3333˩^ffffaH@ffff^3333eH@<^0mH@3333{^3333H@^3333H@^3333H@Yu^3333H@Z^(333H@ffff>^3333H@|#^(333H@ffff2^3333H@]3333H@3333]H@T]H@3333 ]H@]H@3333wd]H@-I]H@-]H@]H@P\H@ffff\H@̼\H@ffffr\H@(\H@3333n\H@̔S\H@3333K8\H@\H@3333\H@m[H@$[H@ٯ[H@[H@hfffFy[H@][H@hfffB[xfffH@h'[ffffH@4333 [xfffH@ZffffH@4333ZxfffH@AZffffH@4333ZxfffH@ZffffH@dhZxfffH@MZffffH@1ZxfffH@hfffZxfffH@QVffffuG@IV3333~G@ffffEV0G@@V3333G@{G@QVqqG@xVkG@Vffff6hG@ffffVfG@XVffff.hG@V3333kG@VmG@3333VoG@3333 VyG@ffff VHzG@DVffffwG@ffff"U0tG@UffffqG@UkG@U3333iG@3333U3333{WG@UPPG@UXNG@3333?UKG@ffff.UEG@3333U CG@U3333AG@|UBG@3333/UEG@3333UCG@xU=G@ffff~U0G@U̼>G@uUffff;G@٩U33339G@̨U33339G@U CG@řU3333;KG@ffffΎUTG@3333sUWG@ffffUVG@|UYG@|sU$ZG@ffffngUdXG@A\U3333sZG@3333QUP`G@HUffffcG@@UIdG@ffff=UffffbG@ffff?Uffff^G@@UffffWG@ffffAU33333NG@AUHG@ffffBUEG@CUffffCG@ffff2BU̼@G@:U3333;?G@y6UG@(U3333=G@3333%U8G@!U7G@ffffU3333k;G@%Uffff>G@UI@G@U@G@U>G@U $G@ U̜G@3333CUyG@ffffUG@UG@3333UffffG@3333UXG@8UffffG@UG@UI G@UG@3333TffffG@9T3333+G@ŤF@xTF@̤T3333F@UF@̠UG@̠UF@3333GUF@aU33333F@\!UffffNF@\"UyG@1#UffffG@33337%UG@3333k(U̼G@-+U3333CG@d.UF@-UF@l.U3333F@̜-UF@3333-UlF@.UDF@q0UpF@Q3U3333F@ffff2>UffffF@pFUG@PUI G@3333XU G@̤^U G@ffffcU G@XgUffffG@LmUiF@duUfffffF@yU3333kF@ffffzzUxF@e}UhF@3333U9F@ffffއUffffF@3333_U3333F@dUF@3333UF@|U\F@ffffU|F@ffff¡UhF@3333+U)F@yU@F@ԧUtF@ffffΧUffffF@ffff>UF@$U3333#F@@UF@UF@3333/UffffNF@3333U3333F@3333ˣU4F@LU̴F@ UffffF@$UffffF@HUF@ffffUF@3333;U3333F@3333UxF@̘UF@UHF@ffffUF@YUF@U3333F@U3333F@ffff&UffffF@ffff޾UiF@ffffRUffffF@3333U3333F@ffffnUiF@ffffNU3333F@3333UF@U̼F@TUF@U̬F@ffffjU3333۟F@ffffU3333F@U3333ÖF@3333UF@U̔F@ U!F@UffffF@3333#U3333xF@̠U3333CtF@UpF@ffffUaF@UffffXF@3333VOF@33333V3333IF@UFF@tU̜GF@|U3333KF@xUOF@3333gUfffffSF@3333kU̔XF@MU(eF@ffffUffffflF@9UfffflF@3333UfffflF@3333U3333oF@ffffUnF@̄UffffiF@ffffU3333{fF@ffffUffffNcF@U4\F@ffffU3333TF@33337U3333LF@3333#UAF@Uffff^1F@PU%F@UyF@D@ffffUD@U3333#D@33333U3333D@fffffUD@UffffVD@4UffffD@(U̼D@UD@UffffD@ffffBU3333;D@ffffzUffffD@ffffҤUlD@ffffJU E@ffffU3333E@3333U'E@,Ut5E@UffffCE@U33333SE@UbE@-UAsE@3333UE@AU3333;E@UE@ŕUE@3333כUE@ffffU3333E@UffffE@ffff2U3333E@UE@ffffUDE@3333UiE@3333WUF@ffff:Up F@ffffUF@3333UffffF@UQ*F@̔U7F@UFF@̈U3333PF@3333U̜UF@3333UyYF@3333+U0\F@ Uffff_F@̨UeF@ffff&UpF@̰U3333KuF@ffffFUffff6uF@ffff U\wF@|U3333{F@EzU|F@ffffvU3333{F@3333/rUffffF@fffflUdF@ffffvgUF@33337dUpF@̘cUffffF@eUffffF@UpF@ffff&=U(F@3333>Uffff.F@F@TffffnF@ffffTF@Tffff^F@TffffFF@lTF@TɟF@3333[TffffVF@UTF@0TF@}TɑF@3333;TF@XTF@ffffTF@T3333+F@ffff.TF@ffffBT3333F@ffffT$F@ffffT~F@ffffT{F@ffffT3333CoF@,TdF@TxWF@̴ThRF@3333oT3333;GF@T5F@(T33330F@pTffff>*F@ffffT!F@T|#F@1T#F@T"F@ffff TffffF@T̄F@3333KTtF@ TXF@3333T3333{F@ATF@ffff6TF@ffffT)E@ffff>T4E@3333TE@T̼E@ffff"TffffE@ ThE@ffffT̬E@ETE@ Tffff6E@ffffT|E@TxE@T3333;E@ffffTffffFE@ffffTffffE@TE@3333TffffE@̘T3333E@T3333SE@|THE@TffffE@ffff*TE@TffffE@dTffff.E@ffffrT4F@TF@3333T3333F@4TF@ffffjT3333sF@ԭT1E@tTffffVE@0T4E@ T3333ˣE@Tffff^E@̤TE@T9E@@T^E@ffffTffffOE@ITffffnGE@3333T̄IE@QTLE@T̜TE@TWE@T4YE@3333T3333CXE@dTUE@|TQE@)TffffnNE@ThKE@ffffҵTHE@TffffnBE@Tffff8E@ffffTffffn2E@3333CT0E@ffffTffffn,E@ffffTL)E@T$E@T3333#E@33337TE@3333T̬ E@LT3333CE@3333TffffvE@3333[T(D@T3333;D@T3333#D@pTD@TD@SE@3333=S3333áE@E@3333{ SE@ SE@l SE@ SE@Sffff>E@ffffS E@qS3333E@33337S3333CE@SE@!S3333{E@ASE@ SffffE@! S3333E@S3333+E@PSffffE@SffffE@ShF@ffff: S4E@ffffN SffffnF@ SF@Q SF@3333 S3333+ F@ S F@S3333F@ffffSF@SF@ffffS3333 F@8S3333sF@ffffBR2F@ffffRffff7F@̤R̼:F@3333WRffff=F@ԺR'&>F@4333R?F@hfffRbF@4333{RxfffsF@R,|F@4333ӶRF@̰RF@hfff^Rxfff~F@ Rffff6~D@,%RffffuD@!RuD@ffffRffffwD@,Rp|D@eRD@ RD@ffff RffffD@RD@@R3333D@ffffQćD@R3333srD@eR pD@ffff#R3333iD@D+R33333eD@ffff0RcD@3333oLR̼SD@NRdSD@ffffPRTD@̼gRLD@ffffqRffffKD@ffffyRffffID@HsRffffOD@%sR3333 RD@fffftRffffSD@3333xRhSD@t{RffffLD@RdJD@ RQD@33337RqWD@3333}R\D@ExRTeD@ffffvpRffffjD@ffff~lR\oD@ffffiRDkD@$iRpD@ffffgRffffsD@dRffffuD@1_RuD@33337\RvD@ZRffffvxD@ffffWRffffxD@QRLvD@KRwD@3333GR3333{zD@)BR̤{D@3333 5Rl|D@(R~D@3333"RtD@RD@3333RffffD@ffffZRffffD@ Rffff6~D@ Qffff*F@Q(F@3333Qffff&)F@Qd"F@ffff*QffffF@̰Qp#F@YQ̬%F@4Q.F@5Qffff7F@)Qffffn:F@<Q8F@8 Q3333.F@ Qffff*F@ffff RBD@RdBD@3333 R3333ND@ffffnRHTD@fffffRSD@PRffffND@RKD@݈R3333[ED@ffff RBD@ffffQ3333+D@ffffBQD@Q3333D@QѯD@ffffQiD@lQffffD@3333QD@ffffQ3333+D@3333sQD@ffffQxD@(QD@\QffffD@QffffD@ffffQ\D@QD@QD@3333sQD@ffff~QffffD@ffffQffffD@ffffQffffD@3333QffffD@3333Q3333 D@ffffʂQD@3333QD@Q9D@ffff~QffffD@3333RffffA@ffffRA@ffffR3333A@3333RA@3333RA@3333RffffA@3333R3333A@hRffff>A@ffff*R\A@TRA@9R`A@R3333;A@ffffFR!A@9R3333sA@RffffA@ffff6Rffff6A@ffffRlA@̘RA@3333R3333A@3333 RXA@̬Rffff6A@RA@3333[RIA@3333 RXA@< SLRA@!SPA@S`A@eSuA@E Sffff.xA@SfffffA@< SLRA@aT t:@T2333sm:@3333GTYr:@̋T {:@3333TL:@ffffވTz:@mTv:@aT t:@\Tfffff:@tT\~:@Ť:@3333ӊT2333c:@T`:@\Tfffff:@pTl$9@(%TI8@3333#TdfffV9@T9@3333/T9&9@T-9@3333T;9@3333{TdfffL9@3333T\W9@tTX9@pTl$9@V0=@,V|=@ffffVffff=@lW<=@4V٤=@Vffff=@V2333Ә=@!V=@ffffFV =@3333V=@V0=@3333@X;@ffffNBX0;@5?Xffff&;@ffff>X̌<@ffff9X2333<@6Xffff"<@ffff5X̼<@3333:X<@3333@X;@0X'<@E3X&<@\0X23333<@+X:<@;@XX T;@RX;@ffffRHXffffv;@CXp;@ffffPX̌;@VXL;@ffffWY%=@̼Wffff"=@ɷWffffFJ=@ܴW`W=@ WV=@3333[W̼@=@ffffWY%=@JX(:@3333KX:@QXlT:@YX :@3333ZXffff;@XXL2;@ffffzVX,:@LXL:@JX(:@3333^ffff.A@^A@ffffB^ffff6A@m^4A@̈^a A@̜^A@3333^ffff.A@]̛@@]@@3333]@@]@@]@@̤]ffff&@@ffffJ]@@]̛@@l]ffffi@@ffff&]h@@H]ak@@١]w@@ť]ffffn@@3333]ffff.@@ffffz]ffffz@@ffff]3333l@@l]ffffi@@^̜@@ffffJ^3333@@ffff ^3333@@3333^ffffA@̘^dA@]@@]ffff@@^̜@@x]33333 A@ffffr]̤A@l]A@3333']3333A@3333]A@]@@]Y@@]ffffA@]ffffA@x]33333 A@D]`@@ ]3333@@]ffff@@]ffff@@ ]ffff@@}]ffffִ@@x]@@ͣ]3333K@@ ]@@q]i@@ffff]@@]!@@D]`@@ffff^3333VH@4^3333SSH@ffffƳ^ffffPH@3333^33333PH@̄^TH@3333˹^UH@ĸ^`NH@3333^LH@^8PH@ffff.^3333{SH@^ffffVH@^ffff~ZH@t^ZH@ffff^3333VH@3333^@H@3333'^;H@3333 ^>H@^AH@^ffff^CH@ffff^KH@`^ffffMH@ffffN^NH@^DH@3333^@H@^ H@ffff^AH@ffff.^@ H@x^3333#G@ffffv^3333+G@^3333+G@T^xG@^ffff6G@3333^dG@^3333G@ffff^ G@إ^3333H@ffff^3333 H@ͦ^tH@٧^aH@^H@3333/^AH@t^ffffH@3333^H@ffff^^#H@Ъ^ffff,H@3333;^ffff.1H@^0H@3333^ffff.H@ffffF^)H@3333^%H@L^3333H@^DH@ffff^\H@3333?^H@^ H@aQD@(QffffD@QD@3333QD@PQ1D@QiD@aQD@ffffR3333#C@R3333C@4R|C@ԆR3333C@ffffR3333#C@PR3333B@9RB@ffffvRA C@3333R3333C@DR(&C@R3333C@RD C@PR3333B@"S3333SA@ffffb$SffffSA@ffff&STA@]*S3333WA@!+SffffYA@3333'SffffXA@"S3333SA@mUTdfff8@XWT4333C8@ffffBXT43338@ffffBXT8@ZŤ8@ffffZT8@̠TT`8@xTT8@mUTdfff8@5T̼8@3333K6T̼8@5T`8@)3Tdfff8@@2T43338@ffffZ2T08@5T̼8@(Tdfff68@*T8@3333 (T8@U'T8@(Tdfff68@BT8@ffffETp8@ffffHT43338@tET43338@̌;Tl8@ffffJ?TdfffV8@BT8@ZT>@]TP>@^Tfffff>@_T>@\T>@ZT>@DdT43338@ffffjhT 8@ffffeT 8@cTl8@ffffbTy8@bT98@DdT43338@ TffffFG;@ Tl4;@Tffff&`;@Tffff;@ffffT̼;@TTfffff;@T;@ TffffFG;@ffff*rTi8@ffffsTdfff֊8@ffffsT̎8@!qT43338@ffffFoTP8@XoT43338@ffff*rTi8@ffff8Vl=@d@$Vl4>@0*V9>@3333-V2333>>@3333C.VffffC>@$V:>@#VffffF7>@̐V@>@ffff2 V;>@3333V;>@=V̌=>@Vffff6A>@V2333F>@̐V@>@UNVffff>@NV >@ffff>QV̌>@3333UVffff>@SVffff&>@hRV>@QV`>@KV,+>@|MVP >@UNVffff>@4Vffff=@33336V=@4V=@3333{7Vffff>@33334V>@4V=@4Vffff=@3333:U2333=@3333@UL=@xGU=@(CUffffF=@@U=@ 8U̼=@33333Uffff=@-/U=@3333:U2333=@̘^4G@4^G@^3333ӗG@^G@\^ffffG@^)G@X^G@̘^4G@9^G@̄^ffffG@^iG@3333?^ffffG@3333S^lG@^3333G@ffff^3333ӭG@p^G@ffff"^G@^G@3333K^3333G@9^G@3333ӟ^3333G@3333+^G@3333^̔G@ܤ^3333KG@^3333[G@أ^PG@3333/^3333G@ffff^dG@̀^aG@3333ӟ^3333G@^ffff67H@ffff^5H@ffff^33337H@^|:H@ffff^ >H@a^DH@^3333FH@^9FH@)^<@H@ffff"^ffff9H@^ffff67H@ffff'QF@P*QF@,QaF@ffff,QF@5,QffffF@P+Q3333 F@3333)QF@ffff'QF@@VG@ffffNVPG@eV3333KG@0Vffff>G@Vffff.G@VxG@V3333G@8Vffff&G@@VG@ffffN:VffffG@!=VG@ffffr=ViG@ffff;VG@3333;VG@ffff>VG@9EVG@JVffffG@ffff~LVG@3333LVffffG@JVyG@ffffJV3333cG@ffffLV3333cG@TLVG@ffffbIVG@ffffZ0V@ H@ffff%VIH@3333V̄H@VffffnH@4%V,H@ffff2&V1 H@%Vffff6 H@'VaH@ffffN:VffffG@3333UG@ffffRV9G@V3333sG@ffffUG@dUffffnG@ffffVG@33333VG@ffffbV3333ӖG@3333'VXG@VdG@ffffVxG@V`G@ffffVG@3333V3333G@3333VffffG@ffff.V3333ӐG@ffffVffffvG@VG@3333 VpG@̸VYG@TV3333{G@VG@$VXG@h'V3333KG@&V̛G@3333#Vffff֢G@<VG@VffffG@ V3333{G@ffffU3333G@0UG@UлG@lUG@3333UG@ U)G@U33333'G@3333U3333{$G@eUa!G@̸UyG@UffffG@ U#G@3333 Uffff&G@ffff Uh)G@ U)G@ffff~U3333+G@u U3333;,G@ Uffff.G@h U01G@3333 Uffff8G@Ufffff>G@3333 UffffDG@ UYEG@ UCG@ffffUT@G@̐ Ux:G@x U3333{4G@U\.G@ffff~U3333+G@`S3333~E@SXE@ffff>SE@SE@3333;S!E@3333SffffΆE@|S3333kE@SE@ySffff~~E@`S3333~E@tUF@<U3333F@33333U3333sF@ $UF@̨#UF@tUU3333CF@ffffUiF@mU)F@ЃU3333˒F@3333[UF@HUF@8U3333F@(ULF@ffffҶU3333{F@(UffffF@UЫF@U@F@ffff޽U$F@UyF@HUF@$UĦF@ffffRUܥF@U9F@3333{UٞF@U4F@U3333KF@mUF@UF@UDF@3333cU̴F@|U̜F@UF@UF@ffffUF@ffff*U3333F@ffffJU3333ÈF@ U4F@mU}F@ffff>UyF@|UtxF@ U3333vF@UjF@ffff6UiF@Uffff^kF@3333sUnF@|U3333sF@3333UhwF@`U!zF@1U3333F@UffffnF@UF@3333'UDF@ffffUAF@3333U̼F@U3333F@$UĦF@ЩViG@\VhG@̌VfffffG@yVDdG@ffff"VbG@V3333bG@ VAeG@%V$hG@V3333[oG@ffff&Vffff6oG@Vffff~mG@ЩViG@4333;C4333?M`fffB:hfffJ?̜C:43337M`fffB:4333?M0333Sj:L8Mhfffvs:)5Mhffff: 1MM:0M`fffG:l3M̜C:43337M9BhffffKdfffƀBKdfffvB4333c KlB4333 KgB KIaB KdfffZBhfff KdfffMBLKdfffRB4333!K@EBKl9By'K4B4333&K4333c1B4333#K)Bhfff& K4333$B4333$K)B4333#.KB0KdfffB:K\ BFK<BHKyAhfffHKA4333GKAQKdfffAZK8AaKAleKdfff.AjK B4333nK4333B,mK8 B4333cKdfff'BXKdfff9B IKl-NJffff.1NhfffJ23339N4333Jffff=NJ2333ANJ2333WNJffffgNJ{NhfffVJaNhfff&IKNI9NhfffFI*NhfffvI2333$NIffffNI2333{NId#NIffff*N4333Iffff0NI2333@NhfffIJN9ICN4333#Iffff;N#NININiI N٫ILN̬IaMhfffJM JMJffffvM43333JMJ2333M,JiMJ2333+M JaMhfffJ<ffffZTE3@Sdfff3@$ ffffWTPY3@UTYT3@RT4333cW3@ffff:RT\3@YHTdfffX3@3333FT N3@`NTM3@3333QT4333G3@pSTE3@YTdfffFG3@ffffZT_3@ffffYTb3@ffffWTPY3@SL3@HSٳ3@TT43333@3333Ty3@ffffT3@ffffnT4333î3@uT433333@ffffZT4333ô3@3333ST3@ T3@ffffzS4333#3@hS3@SL3@ffffS@3@3333SY3@3333Sٳ3@S|3@fffffS43333@@S3@ Sdfff3@S43333@S93@ffffS@3@X87P3333;!@@*Pffff1@@̼.P%@@|4P3333;!@@6P3333!@@87Pffff#@@3333[1P3333c'@@t,Pffff1@@*P33330@@̼.P%@@|,P,f2@ffffP2@3333KPv2@Pu2@Pu2@fffffP0y2@DPY2@3333Py2@3333KPv2@ffff%P g2@3333*P,f2@|,P4333ci2@)PIq2@l$P@r2@"P)p2@ffff%P g2@lPdfff2@ffffPdfff2@P,2@P2@P̌2@P43332@TPL2@P2@lPdfff2@Rp5@3333Q5@ TQdfff5@Qp5@1QL5@%Qdffff5@@Q5@Q4333#5@ffffQ\5@3333Q̜5@TQdfff5@PQdfff&5@pQ4333s5@ffff&QI5@ffffQ\5@ffffQdfff5@8R43335@ffffRP5@ffffQ5@3333Q5@PQdfff&5@LR43335@ffff R5@ffff R43335@< R5@ffff R5@4 R5@ARdfffV5@xR 5@R5@LR43335@P̌O4333c0@O@0@Odfff0@ffffO4333c0@ffff^O43330@̌Odffff0@ffff~O0@O@0@Odfff0@`̼H@LH@ 3333&H@L$H@n̼H@@ffffH@LSH@3333H@H@@ffffH@3333&H@PL+H@3333H@3333LH@aH@333H@L+ffffH@@ffffVH@*ffffH@3333LH@ 3333$3333K@Zffff4K@ 333K@u3333K@l K@`fff&3333K@ 3333$Y K@ 333s4K@K@u3333+"K@80K@`fffffff4K@ 33333K@@@2K@Zq"K@ 333K@ 333K@ `fff&J ̼I@?3333{jN@ FTai HUaj@ffffWffffI@@fffaI@I@ffffvI@ I@LX I@333 I@I@L 3333I@3333{I@3333I@ vI@ 3333I@ٱLI@ 3333]xI@\I@OI@̌3333I@@ I@ 3333g3333kI@3333I@ 333)I@YI@`ffffI@@ffffnI@`ffffAI@ I@ffffI@ 3333ZyI@3333[J@>PJ@YAJ@ 3333333#J@ 3333333)J@`fff&fQ2J@3M@DffffBM@`fff&̄HM@ HJM@ٲPKM@ =TIM@`fff&FM@HAM@̼AM@#GM@ 3333333HM@`fff̤AM@`fff&3333SGM@LffffIM@@ffffK 3333MM@@fff ffffNM@333 33333SM@333lAQM@^NM@333t\KM@3333AM@33337M@3333ffffV4M@ l0M@@fff ffff)M@333I ̬M@333333333M@L@ffffL@ 333s$ffffL@3333AyL@@ffffffffL@L@LPL@3333L@@fffffffffL@L@ L@@fff8 L@3333[ ffffL@@fff4L@IffffL@̒9L@333̜L@ffff&L@333L@ffffb̜L@aL@ffffr33333L@}̬L@[L@L@)3333#L@3333]L@333̤L@@ffff L@nL@i]L@3333{QL@̽GL@rAL@3=L@ā9L@p6L@3333 $1L@z ffff.L@ 3333.L@33331L@2L@8̼(L@@fffdp L@$L@L@m A L@@ffff$ L@@fff L@@fff 33333L@ 3333L@P0 L@ ffffL@ L@cK@@fff3333K@@fff\L@@ffffffff~L@3333-̔K@"3333kK@H3333K@,K@ffff|K@3333K@ffff\8K@3333aK@ffffcK@3333ZK@ffffxffffSK@ffffLLEK@|@K@ffff33332K@׿̼#K@dfffͿffffVK@K@ĿQ K@PʿK@ſJ@`fffffffJ@?J@hfff?J@8333?J@y?J@`fff擿J@ಿ3333cJ@@ƿ̼J@HѿffffNJ@2333ݿ3333J@ffff*⿙J@̬J@2333 ߿J@ҿffffJ@l?J@X?J@?yJ@4333?aJ@hfff?؃J@ٿ?\|J@?3333sJ@?3333gJ@!?3333gJ@q?iJ@?mJ@4333?xJ@?{J@4333?ffff}J@t?L|J@gfffZ?zJ@?zJ@3333W?XvJ@3333?ffff^rJ@?y`J@3333u?VJ@? JJ@?I@?I@gfff?$I@4333?I@gfffR?3333I@?ffff~I@4333;?3333#I@4333+?I@?3333I@5?ffffI@?̳I@?3333{I@u?I@3333=?3333 I@3333?3333I@?ffffI@?I@ffff?ɧI@ffff\?LI@3333?ffffI@? I@P?`|I@?3333vI@4333?̌wI@gfff?YqI@?I@VџI@ I@SffffƼI@@ffffI@@fffffffI@@fffvI@PI@@ffffWffffI@$J@3333æJ@̌23333#J@LVԡJ@ 3333J@LJ@~,J@`fffɖJ@L3333J@6ffffVJ@ExJ@3333J@`fffBhJ@$J@d̜M@@fffKffffvM@3333M@IffffM@AffffM@LpM@d̜M@3333ffffAN@3333K@N@LMN@3333~0\N@ffff[N@WN@ffff𿚙9TN@ffffSN@ffffRN@̏KN@3333CN@3333ffffAN@DN@3333;N@ffff>N@3333x5N@3333t5N@8N@ 0N@#ffff~N@q3333N@̦N@3333̔N@ffff0N@󿚙QM@ffffffffM@xM@M@N@3333k̬N@̤N@3333*N@ffffAN@33331N@3333N@ffff3333cN@DN@3333SN@CffffNN@!N@̞)$N@:1&N@3333p%N@ffff̜*N@ffff1;N@3333=N@&I?N@3333;BN@ffffCN@3333LN@ffffNN@MN@DN@ffffgN@3333ffffvfN@p3333[N@ffffj3333WN@WN@3333@YN@q_N@ffff fN@ffffN̼gN@ffffphN@$gN@Y3333{jN@fffffffffjN@ffffgN@Q eM@@fff ffffcM@; ffffdM@ |kM@@fff4 ffffpM@@ffff( ffffntM@ uM@@fff, sM@3333 mM@@fff ffffiM@@ffff 3333#hM@333D fffffM@Q eM@@ffffo^M@3333^M@3333`M@HLiM@jM@@fff+ffffiM@NYfM@@ffffo^M@u3333˃M@̐3333M@ffffM@~M@ffff}M@XzM@XfffftM@ffffVrM@qM@@ffffL@>̬FL@YG3333HL@9̤LL@ 3333%QNL@ 333sLRL@ffff.SL@ 3333i̤RL@LffffNL@`ffff3333kDL@X3333BL@ ffff>L@̌3333,L@K@ _̬K@;3333{K@`fff8K@Z)K@@K@`ffff8K@:@K@K@L53333;K@L%K@53333K@`fffUffffK@$K@`fff&AK@̌K@`fffffffnK@ 333tK@ 3333333K@dK@ 333K@`ffff`ffffK@>K@K@K@Y3333CK@ 3333333K@̌*DK@=TK@`ffffHK@ 333IQK@L*3333{K@`fffK@K@L@3333L@2 L@̌ fffffL@̌,L@Y0L@Y3333CK@ 333s.M@`fffM,M@M@Y3333 M@`fff73333 M@3333 M@ ffff M@3333KM@`ffffM@Pffff~L@ 333̜L@ 333/L@@j3333L@ 3333ffffL@`fffL@ 333L@ L@ 333sU)L@`fff̴L@3333cL@`ffffmffff6L@`fffthL@L@ 333s:hM@`fff&5LM@ 333ffffvM@L3333M@`fff&'A M@N M@Z4 M@`fffa3333M@LWQM@.M@tM@Y ffffFM@YM@ffff^M@?M@`fffffff>M@IM@`fff&ffffV$M@&M@3333+)M@@-3333 1M@L0I>M@`fff&\@M@ 333ffff>M@`fff7M@ 333s.M@3333{{L@`fff&<yL@̌bffff&zL@ffffF|L@3333KL@JxL@`fffL@̌ 8L@ ~L@3333{{L@ 33333333L@`fff3333L@ 333TL@ 3333DL@̊9L@`fff_ffffL@@E3333KL@`ffffL@ 333lL@XL@ 3333333 L@`ffffffffL@.L@ 333L@ȅL@L@ffffL@ 3333#L@`fffPL@L@ 333sJ3333L@sfffffL@ 3333L@`fff3333sL@3333˴L@`ffff L@ffffL@tL@`fffffffƽL@`fffflffffξL@UL@ṲL@ vL@wffffL@9L@@nYL@L93333L@3333[L@ 3333L@ 33333333L@3333kL@_ffff6L@3333CL@@HQL@ L@L@`ffff3333sL@ffffL@L@LffffL@`fffLL@ 333(L@3333kL@3333ÎL@ + L@c̼L@`fffL@`fffL@3333[L@̠4L@`ffffȰL@/L@̌ffffL@,L@3333ÎL@`fff3333{L@`fffyL@L&zL@,ffffv|L@ffffހL@`fffflL@ 333s L@ffff}L@`fff3333{L@@3333[ K@ 3336$ K@`fffftffff K@@3333K@$K@L1TK@`ffffK@`fff& K@`ffff3333K@̤K@ K@5pK@ 333n3333c"K@z3333%K@L *K@/K@`fffffff4K@`fff2A4K@ 333|-K@ 333s&K@Y0#K@ 3333K@ 333hK@:K@LLK@ 333k̄K@@3333K@-K@miK@ K@ 333skffffK@ 3333333S$K@ffff%K@̌< ffff5K@`fff&J :K@`fff< =K@0333 AK@,ffffIK@ffff&LK@ 33333333NK@GQK@`ffffAUK@̌xWK@ 333s3333cYK@`fff}3333[K@`ffff0\K@ 3333ZK@̌0]K@m3333s_K@3LbK@@iK@DpK@ 3333333sK@ lK@ 3333333K@`fffffffƋK@`fffHK@ gffff.K@QK@`fff\K@Lffff.K@`fffL K@3333ØK@ 333sٞK@L3333K@K@@3333ӛK@`fff$K@`ffff̃K@ zffffFuK@ 3333hK@`K@̌\K@ 3333WK@ 333ffffRK@6ffffTK@Yffff&VK@T3333TK@POK@ 3333333FK@ 333ffff@K@8K@:K@ 3333F̜AK@v3333DK@ 3333ffff^FK@3333+=K@ 3330K@ 3333/K@ 3333;|/K@Ym3333"K@ xK@N0K@`fff&kK@K@@fffff K@K@`ffffzK@@3333[ K@ 񿙙YXI@cffffSI@3333NI@3333#3333LI@ffff^KI@TKI@>3333UI@3333CUI@3333@ffffZI@ffff,]I@3333cI@N3333 ^I@ 񿙙YXI@!I@6@1L@2333s:@ &L@43339@hfff.L@4333Ñ9@/L@9@1L@̬8@,-L@)8@4333#(L@i8@I"L@8@43333L@4333S8@hfffL@dfff8@4333 L@8@,L@ 8@4333L@Y8@43333K@43338@hffffK@@8@L@\8@4333#L@`8@4333L@dfff8@hfffFK@4333c8@9K@dfff8@4333sK@8@4333SK@I8@K@<8@4333SK@43338@K@8@hfffK@8@hfffK@̓8@4333SK@}8@hfffK@ll8@K@0b8@ K@̌Y8@4333cK@ >8@\K@98@K@433378@K@4333$8@K@8@K@98@4333sK@ 8@K@`8@)K@,8@ K@7@hfffK@7@4333K@7@yK@7@ K@̬7@hfffK@7@K@dfff7@K@̄7@hfff6K@0c7@hfffK@07@hfffK@dfff7@K@dfffF6@hfff֘K@6@ɗK@@6@IK@6@YK@6@43333K@43336@hfffK@dffff6@4333vK@dfffƤ6@hfffgK@4333s6@|SK@96@`(G@`A@M333s/G@|A@ffff8G@C3333A@4"G@|A@G@lA@wfffNG@lA@:333k G@̼mA@aF@ tA@|F@6A@9F@ $yA@KEF@8|k]fA@U&\7F@ŇeA@M_7F@+5WA@( F@XBA@( F@8E9A@cHF@Xb&O-A@@kG@A@kH G@WkA@v~ G@p_kA@!, G@`@@@.G@Cy@@OiG@8'@@@9!fG@ @@Q G@ٿ@@ G@qfff@@`G@@@fffG@<333@@qfff~G@̌x@@G@ f@@G@nfff=@@|fff G@9*@@ G@@333@@h!G@?@$G@?@~fff$G@ ̬?@fff)G@wfff?@|fffN,G@љy?@,G@3?@̤.G@̬@@}fff1G@mfff@@ 7G@k333?@1;G@m333?@K333cG@@?@A333#G@̬?@@333kG@{fff?@M333vG@Y333?@sfff^\G@W333s?@N333+SG@Y333?@PG@o3333?@D333;RG@ə9?@fffUG@9?@offf~cG@M3333?@E333^G@fff&g?@|PG@3R?@offffNG@fff#?@fffOG@͙>@FG@ә>@̌@.G@>@&G@1 >@"G@z333>@| G@l3333~>@ G@d3338>@F@fff&/>@G333F@x333>@7333#F@d333=@}fffNF@9=@̴F@`=@F@=@yF@fff=@\F@xfff=@F@=@4F@=@F@8333=@DF@hfff=@ffff.F@8333S=@ffffvF@Yg=@F@99=@3333F@hfff=@F@8333<@F@hfff<@ѧF@ <@F@@<@3333F@8333<@)F@<@ffff>F@<@؞F@<@F@hfffs<@fffffF@8333SQ<@ffffnF@hffff6<@F@C<@F@8333sO<@ѿF@̬x<@3333F@<@DF@8333s<@QF@hfff<@DF@l<@F@}<@8F@8333<@ffff.F@hfff<@̜F@8333<@ffffF@ <@F@y<@DF@<@dG@<@ffffVG@=@ffffG@<@3333$G@9<@ffff^.G@l<@I6G@Y<@:G@hfff =@ffff?G@8333s%=@qCG@̬/=@CG@hffff3=@3333@G@`4=@ffff0G@L9=@@0G@,A=@A2G@ N=@;G@V=@8G@8333d=@7G@n=@\:G@8333su=@:G@8333}=@33337G@=@14G@l=@ 3G@ =@X5G@8333=@p9G@=@ 8G@=@ffff,G@hfff=@3333.G@`>@\0G@hfff>@fffff3G@̌!>@(6G@=@DG@L=@PG@hfffF=@̤\G@hfff=@ffff&dG@=@jG@@=@3333qG@hfff=@3333+xG@l=@d{G@8333=@̔G@@=@G@ك=@G@̂=@3333cG@8333=@G@=@G@hfff=@G@=@ffff6G@hffft=@tG@hfff&b=@G@8333sU=@G@Y3=@G@hfff(=@3333SG@hfff"=@ffffG@y=@3333G@&=@YG@/=@LG@83335=@3333G@ 6=@33333G@1=@3333G@ =@ffffvG@=@3333G@8333s =@ffffG@,<@lG@8333S<@ffffG@hfff<@qG@<@ffffNH@hfff<@3333{H@̇<@<H@̌v<@ffff H@hfff&q<@ H@Ll<@H@83333c<@H@,W<@|H@8333S<@H@X<@DH@J<@H@hfff(<@ffffvH@hfff<@ffff H@<@%H@ <@ )H@;@*H@;@.H@;@H5H@hfff;@9H@;@;H@;@ffff6@3333I@hfff&)>@3333+I@833338>@I@O>@ffff&I@YU>@3333I@8333s>@I@hffff>@I@8333>@I@>@ffff~I@>@3333I@83333>@QI@̌>@I@8333s>@TI@y>@0I@8333>@I@8333Ӫ>@4I@Y>@̔I@>@ffffI@ >@J@L?@ J@ +?@ffffJ@7?@ffffnJ@8333X?@| J@?@ffff J@l?@ J@L?@ J@hfff&?@3333 J@L?@J@4333S@@3333J@hfff@@yJ@@@ffff J@43333$@@J@hfffv.@@"J@hfff2@@̼%J@̼7@@3333S'J@4333A@@ffff~'J@̜R@@#J@9g@@ffffV J@)s@@ J@@@3333+J@@@A-J@hfffֹ@@*J@4333@@3333*J@@@!,J@@@fffff(J@hfff@@0 J@hfffA@ffffJ@yA@dI@2A@I@̌3A@I@̌0A@ffffI@̜A@3333I@A@ffffI@hfffA@ffffI@A@I@hfffA@3333I@A@ffffI@pA@I@lA@ffff~I@43333#A@3333I@#A@I@<A@pI@`A@I@A@4I@>A@XI@4333NA@I@,[A@3333 I@4333SaA@̬I@,oA@8I@~A@3333әI@43333A@ I@ًA@ I@4333ÎA@xI@H@4333C@ffff.H@C@@I@hfffC@ffffI@!C@3333I@9C@fffffH@hfffFC@0H@RC@H@icC@1H@̌uC@H@̌C@H@hfffC@ffffH@`C@H@C@ffffH@|C@ffffH@hfffƦC@3333H@)C@ffffH@'G@@?@3333/G@?@ffff&G@8333s?@3333"G@@@G@# |ُ=@̄hfff6}A@@, +F?@ffff,?@ffff̬{?@ffffhfff&N?@ffffhfff ?@ffff >@ffff@>@ffff𿠙>@hfff&>@ffff8333>@𿠙9>@ffffhfffF>@񿠙>@̌>@Lx>@ffff̌i>@ffff񿠙9\>@1 R>@@3333hfffG>@ffff5>@@3333hffff&>@@3333#>@8333=@&=@̄hffff=@v8333=@ffff:=@ffffL=@ffff^8333=@18333=@4y=@@3333hffff=@@3333񿠙ُ=@ffffF =@3333c@=@33338333=@3333濠٥=@ VA=@V483333=@`ӿ=@4333ƿ8333s=@"y6=@ F&Ǿ83333=@4333hfff=@8333Ӯ=@,?=@? =@2333K?̌=@3333?̬=@?9=@?=@̐?=@3333_?`=@33337? >@?8333.>@&?y=>@?83333R>@?8333Sz>@3333?~>@?>@c?}>@@ffff@?}>@3333?>@@ffff?83333>@3333?>@? >@X?>@3333u?>@?8333>@?8333>@?>@?hfff>@@ffff+?>@3333o??@3333?83333 ?@?!?@g?8333s*?@?8333D?@3333?M?@?8333sR?@@ffff?W?@3333X?Y^?@3333b?,c?@?Yf?@T?,c?@@Lb?@ 333@@e?@L>@x?@`ffff@̌y?@ 3334@Yn?@`ffff@ X?@S@M?@ 333@@rlIC?@2YF@@`fff9@>@4@hfff>@@ٺ>@>@>@l@>@ 333@>@ 3333&@hfff>@w@hfffF>@@Y>@@hfff>@U@>@N @>@B @>@ 333 @ >@E @83333>@ @̬>@ @@>@`ffffZ @>@ @L ?@ @'?@`fffH@83338?@I@[?@ @z?@q @8333?@ 333k @?@ @L?@k@8333?@`fff)@hffff?@ 3333 @?@L @,@@L} @ @@; @hffff@@`ffff( @@@`ffff9 @,@@ @l@@`fff5 @*@@L @4333sD@@`fff @hfffV@@@Y^@@.@hfffFk@@Lc@hfff@@ @@@2@4333@@`fff@4333@@`ffff @@@L@4333@@`ffff~@@@@@@@hfffA@@hfffA@L@A@@ A@@0"A@ @I2A@ 3333 @hfff8A@`ffff4 @̌8A@ @ 3A@ 3333M @ 4A@ 3333 @4333S9A@N @4333BA@ 333@iKA@`fffe@4333\A@L@ _A@@cA@@@hA@`ffff@`lA@@nA@ 333@sA@`ffff@hfffqA@`fffW@tA@`ffff@hffff{A@@ }A@@ffff?hfff6}A@`?|A@?̌{A@3333K?yxA@?rA@@ffff?lA@?gA@̪?LdA@3333?4333fA@]?9fA@?dA@?hfff]A@m?hfffSA@? MA@̀?4333DA@?=A@?hfff4A@?4333s%A@fffff?4333"A@3333?A@]?LA@*?P A@ffffz?4333A@?_٭@@o#R?@@2333?0@@?L@@ffff?9@@y?@@@?hfff@@@@?y9@@̬?hfff8@@?4@@?4333#1@@?,@@̍?$@@ ?hfff!@@ffffthfff@@́?hffff@@Y4333@@8333󬿜)@@)@?@4333?@hfffFĿ8333?@hfffǿhfff?@hfff˿hfff@@Pп?@̌Կ?@gfff޿8333s?@0 ?@Hhffff?@ffff8333s?@h?@+F?@ffffhfff@@̤?4333@@2333?̜@@ ?p@@|?@@پ?4333ӡ@@2333c?hfff@@23333?hfff@@ffffv?hfff@@P?hfffF@@?hfff@@ffff?@@?@@m?hfff@@̤? &@@ٿ"@@<޿@@@@4333+߿hfffF@@IܿI@@gfffnٿhfff@@gfff6׿hfff@@4333տhfffV @@gfffԿY @@̔ҿI@@Hп4333 @@Ϳ@@Ϳ4333S@@ ο4333@@ӿ@@Aտl"@@̔ҿ(@@տ &@@ٿ$hfff6?J@ܕA@hfffFP@̤cE@hfffJ@3333fC@4333ӌJ@`C@J@rC@`J@C@4333ӆJ@\C@̋J@3333 C@J@3333ۄC@hfffJ@3333fC@K@ffff>D@L@ɧD@l=L@3333{D@hfffcL@ܤD@0nL@XD@{L@D@LL@D@9L@TD@4333#L@hD@hfff6L@ffff֬D@4333L@ffffD@ЉL@3333D@4333SL@̬D@~L@̬D@hffff{L@3333D@PL@D@[OZL@1D@hfffֆL@ffffD@L@D@hfff֎L@̜D@4333SL@ffffD@4333L@ffffD@D@4333L@D@YL@TE@L@3333cE@yL@q E@IL@ffff&E@''L@'#E@4333L@E@9L@LE@L@3333E@43333L@*E@ L@33335E@4333L@:E@4333M@3333k>E@ M@ffffF>E@43333M@;E@hfffM@ffffN9E@hfff6$M@6E@4333)M@3E@l/M@3333c,E@hfffF0M@ffff'E@43332M@p%E@97M@3333c%E@:M@Y%E@M@ffff(E@ =M@+E@hfff5M@ffff4E@4333$M@ffff~CE@ M@ffffIE@̼M@ffff.ME@hffffM@dPE@lM@IUE@4P@B@43332P@ffffB@433330P@ffff~{B@(+P@ffff`B@&P@3333FB@hfff6$P@33336B@̴ P@3333+B@P@B@ P@B@hfffP@lB@IP@B@hfffP@ffff6B@hfffP@̌B@4333O@ffffB@hffffO@̔B@)O@A@,O@A@̜O@A@hfffO@A@4333O@PA@hfffO@3333A@4333O@$A@LO@8A@O@A@hfffFO@3333A@hfffƊO@ffffA@@O@A@y}O@`A@4333mO@A@\O@3333A@4333XO@ffffA@hfff&NO@؝A@B@hfffYK@ffff.B@QK@B@JK@YB@hfff:K@3333+B@`&K@3333CB@hfffK@ffffB@4333J@B@J@B@hfffJ@̴B@iJ@ffffB@J@C@4333SJ@$C@ J@3C@hfffJ@AC@J@ffffOC@hfffJ@^C@4333SJ@nC@0J@yC@PJ@ffffNC@J@1C@J@3333C@0J@3333ӚC@ J@̤C@ J@C@̼J@!C@ J@C@hfff&J@3333۫C@hfffJ@̌C@ J@3333C@J@`C@J@ffffNC@)J@C@ J@ffffNC@J@C@J@3333CC@43333J@3333C@̌J@C@4333CJ@$C@4333sJ@3333C@J@C@J@dC@`J@fffffC@hfff&J@ffffnC@̼J@C@J@C@̼J@DC@hffff~J@iC@yJ@ffffC@̌J@ C@{J@̼C@rJ@C@gJ@D@I_J@!D@]J@ 3D@4333sdJ@3333ED@lJ@3333WD@4333qJ@ffffnD@4333xJ@D@4333J@zD@J@3333qD@hfffJ@iD@4333J@̜gD@̜J@0dD@9J@yeD@J@`jD@J@hD@J@3333_D@4333J@4UD@\J@SD@` K@ZD@4333K@ffff6\D@4333C$K@3333XD@9*K@)XD@L0K@̼XD@ +K@aD@4333(K@3333jD@/K@oD@hfffFK@jD@TK@ffffmD@WK@oD@4333ZK@rD@4333\K@3333yD@hfff[K@D@4333ZK@3333D@4333UK@3333D@KK@ffffƘD@l$K@ffffD@,K@ffff>D@4333# K@3333{D@K@YD@4333cJ@3333D@hfffJ@)D@YJ@3333 E@J@ffffE@LJ@E@J@tE@yJ@aE@yJ@y E@4333J@ E@܍J@E@)|J@D@sJ@D@LhJ@D@hfffqJ@ffffD@pJ@̌D@4333CjJ@3333ëD@PnJ@3333D@lJ@3333D@̬iJ@̌D@hfff_J@ffffƮD@NJ@D@hfff6?J@3333D@43333YJ@D@loJ@E@J@3333E@hfff&J@E@4333J@YE@J@ffff!E@J@&E@4333J@ffff6*E@K@ffff*E@|K@*E@4333K@&E@"K@ffff#E@hfffD@%@9@lA@hF@ E@28333S9@3333sD@9@ D@@9@dD@̬9@ D@83339@D@9@ffffvD@ 9@3333D@8333S9@3333sD@ID@D@hfffE@LD@hfff#E@̼D@4333.E@D@4333;E@LD@4333AE@3333+D@HE@ffffD@4333KE@ D@̬ME@ffffD@YWE@D@hfff`E@D@dE@(D@,iE@ffffD@tE@D@PE@)D@4333E@PD@E@3333ۤD@ E@ffffD@E@3333CD@LE@ffff~D@E@̴D@4333E@ffffVD@E@D@yE@D@hfffE@ D@@E@ffffD@hfffFE@HD@B@hfffEF@3333sB@HF@B@IF@̴B@\IF@B@yIF@3333B@4333SMF@WB@C@WB@hffftC@3333XB@ bC@XB@,XC@[B@IC@eB@8C@ffff^nB@hfff&1C@3333pB@hfff&'C@YrB@C@fffffsB@ B@ffffeB@4333B@ffffaB@43333B@1_B@4333B@3333VB@ٷB@XRB@ܩB@3333RB@B@SB@yB@SB@ ~B@YB@̌xB@3333aB@hffffcB@ffffveB@LTB@fB@pPB@3333cB@hffffLB@ffffYB@EB@@B@DB@̌:B@RB@3333!B@QB@3333B@GB@B@=B@@B@43335B@3333 B@ 0B@3333B@|,B@3333sB@B@A@B@A@B@̼A@LB@lA@A@|A@4333CA@QA@|A@3333A@̌A@\B@A@'B@A@33334B@B@BB@ B@YTB@hfffB@_B@ B@3333SgB@LB@mB@4333CB@fffftB@A@ffff~lB@A@cB@A@aB@A@ffff\B@4333A@ffffSB@A@3333kLB@4333SA@IB@̌A@3333CQB@xA@3333\B@hfffgA@ffffNfB@ZA@̌hB@LA@idB@Y&A@ffffVMB@A@ffff+B@9@@%B@@@3333KB@@@ffffnB@̌@@B@̼@@ffff. B@v@@@ B@̼e@@B@4333SD@@ B@Y0@@B@4333S$@@I"B@hfff@@|9B@@@̄DB@hfff&?@pNB@@Z?@fB@=?@ffff.iB@hfffF>@lB@>@ffffnB@>@ fB@>@ffffNCB@̌>@ffff9B@{>@3333'B@83333r>@3333"B@hfff&c>@3333#B@K>@3333$B@L;>@ffffV'B@L>@3333B@ =@3333B@hffff=@ffffB@,Y=@!!B@@9=@)B@̬$=@2B@=@3333BB@hfff=@KB@=@ffffQB@ =@3333XB@9<@[B@Y<@8VB@ <@pVB@<@ffffYB@{<@3333fB@M<@ffffgB@83332<@WB@̌<@̼RB@<@ffff6QB@<@UB@<@0`B@hfff;@D^B@hfff;@YVB@Y;@̔WB@83333t;@([B@hfffw;@_B@;@3333#aB@;@dB@9;@ffffgB@`<@ffff~jB@@<@3333uB@8333s9<@B@ ><@B@9"<@ffffƃB@;@3333B@8333SY;@B@O;@ffff}B@8333SC;@}B@?;@!B@L;@C@8333S:@̔5C@,:@-C@:@*C@hfffF:@33333C@83333:@̔5C@:@1C@hfff:@̼/C@@;@ffff65C@$;@9C@l:@3333S9C@hfff&:@=C@y:@ffff^GC@:@ffff.PC@hfff:@TC@:@ZC@hfffF:@8^C@:@LcC@;@̄qC@Y:@3333uC@:@̔wC@:@3333#vC@:@{C@:@ȁC@l:@3333CC@hfff:@̎C@hfff&:@\C@̌:@hC@8333:@yC@83333:@3333C@83333:@8C@83333:@3333[C@:@ C@{:@ffffC@Y:@ffffC@8333:@3333ӻC@8333:@C@8333:@3333C@':@ C@Y&:@C@l.:@3333C@9P:@33333D@8333y:@@D@8333:@3333;3D@;@33332D@hfff&;@ffff9D@H;@Q:D@lP;@33335D@hfff&U;@ffff0D@y;@3333(D@`;@ffff*D@8333;@,D@9;@0D@Y;@=D@hfff;@3333;AD@;@AD@8333S;@ffff>D@̬;@;D@;@7D@;@0D@l;@X/D@J<@ffff3D@Y<@00D@hfff&<@2D@8333=@33331D@ =@3333K6D@Y<@3333;D@hfff<@=D@Y<@q@D@8333<@3333[DD@@<@ffffPD@ =@ffffSD@8333=@̬ZD@L=@y^D@hffff=@3333KaD@8333=@LaD@`]=@ffffgD@B=@tlD@hfff&=@3333 xD@ =@Q{D@hfff =@D@@=@3333D@hfff&=@D@%=@3333KD@R=@ffff&D@Y=@ffffND@LX>@4D@`>@܊D@@A?@ffffƍD@X?@ffff6D@@u?@ffffD@ @@3333kD@9'@@3333cD@hffffE@@8D@,y@@$D@4333s@@ffffE@а@@@E@4333A@YD@`A@yD@4333ӀA@E@4333ӓA@ffffE@ A@D@A@ffff~D@A@D@hfffƚA@ffffD@A@@D@lA@(D@̼A@3333[D@43333A@8D@B@ffff^D@B@D@4333#B@ffffD@43333B@ffff&D@D@hfff0C@ffffVvD@IGC@wD@4333mC@3333CD@4333C@D@iC@3333}D@C@̴{D@hfffD@3333}D@pD@̴xD@4333!D@ {D@XD@D@hfffhD@YD@zD@ffffD@4333D@ffffnD@ D@9D@ID@;@ E@K;@ffff. E@hfff\;@4E@̌y;@33333D@;@D@8333s;@iD@@;@ D@hfff&;@3333D@9;@pD@;@3333D@8333;@ID@8333<@ D@&@:>@pffff'@B@Y'@I@@@'@@@@3333&@̜{@@&@r@@pffff&@ffffd@@pffff&@@R@@L'@1C@@pffff'@ffff<@@̌'@33334@@L&@0,@@pfff&V&@ @@pfff&@3333@@%@3333S @@ %@ffff@@@333]%@2333?@7%@ffff?@pfff0%@?@Y%@2333s?@$@l?@@333$@p?@$@Y?@Yd$@ɕ?@Q$@?@:$@v?@pffffX$@@@?@|$@9?@$@>@$@l>@n$@>@@$@|>@$@>@@333s#@2333l>@@#@ffff&c>@pffff#@̜W>@pfffF#@ffffFH>@ #@:>@"@2333#w>@pfff"@2333>@"@9>@pffff"@ffff ?@@333r"@_?@ R"@?@pffff4"@̜?@̌"@3333C @@@333 "@| @@pfff&!@ffff&@@pfff]!@̼'@@!@ffff6@@@333 @̔E@@ @ Y@@l @ffffv@@9 @@@@333& @fffff@@L@@@ @ffff֝@@fff@ffff^@@@3333@`@@@9@@@3333#@@@@3333@ffff@@@ffff@@@3333@ffffN A@7@A@@3333 A@ffffZ@̄4A@@3333@ffff;A@Y @AA@@3333? @ffff.HA@@333b @RA@} @ffff]A@pffff @3333jA@ @`}A@̟ @ԊA@ @A@@ @YA@ @A@@333s @ffffA@٢ @A@ِ @A@~ @A@} @ffffnA@ @ffffB@ @)B@̌ @/B@ @ffff5B@ @Q:B@pfffj @`?B@Lj @lBB@pfff&v @3333EB@@ @ffffPB@@333s @`aB@@333s!@dB@3!@ffffjB@2!@3333#qB@@3333'!@ffffwB@pfff!@B@pfff&"@3333B@@333H"@B@@`#@B@̌#@ffffFB@L#@̌B@̌#@B@pffff#@B@#@3333SB@@333#@@B@@#@ffff>B@L#@B@pfff#@ffffB@,$@)B@̌d$@YB@pfff`$@ffffVB@ $@nB@pfff&$@dB@$@̬]B@L %@3333KeB@$%@pB@L%@3333wB@%@ffffB@&@HB@@333s'&@̼{B@@&@oB@@333&@̴kB@@3333%@3333_B@pfff%@ffff?B@pfffH%@ffff5B@pfff& %@3333c)B@$@ B@$@3333kB@@333%@ffff&B@.%@A@`%@ffffVA@@%@3333A@@3333&@!A@Y&@3333A@pfff&&@A@pfff&&@A@=&@A@pffff%@ffffNA@%@1qA@a%@VA@%@EA@f$@3333K,A@<$@#A@@3333!$@ffffA@$@ffffA@$@4A@pffffQ$@ffff@@L$@8@@$@@@pfff&m%@1@@h%@ @@ r%@@@%@3333k@@%@P@@%@3333+@@L+&@ @@@333L&@3333C@@̃&@@@@3333&@ffff@@v&@3333â@@g&@ffff@@@333w&@ffff@@&@К@@&@ɜ@@Y'@I@@Y&@|`A@L?&@AWA@YN&@ffffN_A@&@iA@pfff&@fffffA@Y&@|`A@L%@l@@%@@@%@X@@%@@@̑%@@@%@ffff@@@333q%@̔@@w%@̄@@̌}%@@@ %@Q@@pfff& &@3333c@@@3333&@3333 @@@&@|@@@333s%@3333{@@L%@l@@'J2333N!$@2333CCN&@&ffff`N`ffff[&@2333gN0333SV&@2333fN0333j&@ffffZN0333&@ HN`fff&@2333CCN&@2333EN`fff&@ffff`N`ffff[&@̌N`fffD$@ffffNN0333'$@`N!$@ffffŇ+$@2333N`ffff#$@2333N`fff&b$@N|$@N$@N$@|N0333%@8N4%@ٿNG%@_@c"hfffnF_@83333a"I_@8333>"I_@"hfffG_@hfff"lF_@ "I>_@hfff ";_@Y":_@hfff&"hfff;_@̌!A_@ٷ!hG_@j!dK_@8333K!hfffT_@.!pX_@&!ys_@ y_@ _@Y _@ _@@ 4333_@8333s _@83333 hfff_@hfff ٽ_@hfff hfff_@L _@8333 4333s_@ 4333_@Y T_@*!4333_@83333n!_@!hfff_@hffff!4333c_@8333s!)_@L!4333{_@L!_@ !4333_@L!̬_@L"̌|_@8333s?"4333Cy_@hfffC"u_@hfffB" o_@hffffR"Z_@83333"tM_@"\D_@#4333S_@hfff"hfff _@hfff&"q_@8333sa" _@hfff&z"hfffn_@8333"4333 _@hfff&"p_@"_@"̜_@hfff"d_@hfff"_@83333"4333[_@83333"4333S_@hfff"+:hfffWX@ @hfffiZ@dfffl4@ B )/4;ЦY@`Z'@Y@0333$'@Y@:'@Y@`fffU'@iY@`fff&b'@ЦY@`Z'@PY@9'@̄Y@0333'@43333Y@`fffF'@ Y@`fff'@4333SY@,'@hfff~Y@=(@Y@M(@hY@`fffH(@43333Y@L%(@4333#Y@ (@PY@9'@hfff.X@0333@X@LP@X@YQ@43333X@!@hfffX@0333@ɐX@L@IX@E @̜X@`fff&U @hfffvX@`fff8 @hfff֛X@+ @hfffX@0333@hfff.X@0333@hfffY@Q4@4333[Y@dfffA4@Y@4333>4@$ Y@4333E4@ Y@V4@hfffY@dfff`4@YY@b4@Y@4333#W4@hfffY@=4@hfffvY@ /4@@!Y@̌-4@hfff"Y@4333!4@"Y@43334@hfff Y@3@hfffY@3@4333sY@3@4333Y@3@hfff Y@3@(Y@fff3@̜/Y@dfffƃ3@43333Y@̼3@6Y@dfffƕ3@9Y@3@4333=Y@\3@hfffIY@dfffF3@MY@`3@!NY@4333|3@̤LY@4333S3@NY@dfff&63@QY@43333@0333SRY@pfff&2@NY@43332@JY@I2@hfffFY@dfff2@hfffCY@z2@CY@pfff&q2@Z@03333,@>Z@0333s,@hfff>8Z@,@43331Z@ ,@$Z@0333,@XZ@9,@4333Z@,@yZ@,@hfffY@@,@4333Y@,@`Y@l,@4333{Y@0333,@lY@,@Y@,@̬Y@,@Y@,@4333Y@L,@Y@L,@1Y@F,@4333Y@,@Y@hfff+@hfffY@ +@̴Y@0333o+@ܢY@hfffQ+@1Y@0333@+@Y@++@lY@"+@hfffY@+@hfffvY@y+@4333+Y@0333*@4333;Y@b*@ Y@'*@̌Y@0333*@hY@)@Y@`fffW)@LY@#)@4333Y@̬(@\Y@@(@1Y@L(@43333Y@`fff(@$Y@-(@Y@0333v'@ĻY@0333i'@4333cY@`h'@hfffY@`fff'@Y@'@԰Y@`(@Y@03333L(@hfffY@0333g(@ɤY@P(@4333Y@7(@țY@`fff[(@hfffY@0333S(@̔Y@`fff(@hfffY@ (@Y@̩(@hfffY@0333(@43333Y@0333S)@4333s|Y@ )@hfffxY@/)@|uY@G)@PnY@0333`)@y\Y@`fff<)@hfffEY@`fffX)@ =Y@0333>)@t9Y@N)@@7Y@0333m)@hfff^9Y@`fff)@9Y@*@̌X@A#@4333sX@`fffF"@hfffX@"@@X@̇"@xX@ls"@4X@lm"@4333SX@"@yX@`fff"@)X@`fffc"@hfffX@9"@4333{X@̬W!@TX@̬-!@Y@0333!@hfffFY@, @ Y@ @4333+ Y@0333 @hfffv Y@L!@4333Y@0333s @Y@y @hfffY@`fff@< Y@`ffffY@"Y@Y@hfffY@@IY@0333s@XY@*@4333Y@`fff&6@)Y@4@4333Y@YV@Y@`fff@PY@`fff&@lY@@ Y@@I Y@`fffe@ Y@̌@Y@@4333Y@Y@XY@@@̄%Y@03333@,Y@0333S@2Y@̌@$AY@q@IY@`fff&@4333SSY@@YY@`fff&@hfff_Y@ v@PgY@ @hfff&sY@@xY@ @`Y@@Y@c@{Y@@4333zY@@@wY@M@4333rY@ @ nY@@4333kkY@@iY@/@|fY@03333@dY@`fff@hfffcY@̌@hfffYY@h@4333sPY@L(@̴NY@L@43333LY@̬@4333sIY@@4333KGY@ @4333;EY@@̜AY@`fff@4333>Y@̌@?Y@b@hfffDY@0333s@EY@"@DY@ @lCY@`ffff@AY@03333@H?Y@@hfff7Y@L@A4Y@S@2Y@`ffff@I0Y@@-Y@03333@I(Y@@hfff$Y@@4333Y@3@4333Y@@ Y@@P Y@0333@Q Y@@Y@`ffff@Y@@X@`fff@4333X@0333@X@l@̼X@@hfffX@ @dX@ @4X@`fff&l@X@`ffffQ@X@`ffffV@4333X@`fff&}@9X@>@X@`fffy@̼X@L@X@L@4333X@@DX@`fff&@TX@`fff@hfffַX@@ @yX@ @hfffX@0333s @X@, @X@`fffF @X@ @hfffVX@l~ @X@@[ @hfffX@_ @̌X@0333s @hfff>X@ @hfffX@Y!@yX@`fff&!@ܔX@!@ėX@"@\X@0333S"@̌X@0333s#@hfffX@̬#@hfffX@ya$@4333X@03333$@̯X@$@,X@$@X@03333%@hfffvX@`fffF?%@hfffvX@`ffffR%@\X@j%@hfffƸX@%@X@`fff%@4333+X@`fff5&@hfffX@`ffff&@TX@'@hfffX@9'@X@`fffB'@X@0333_'@43333X@0333'@XX@'@xX@`fff-(@X@`ffffa(@̬X@9(@̤X@`fff&(@4333;X@(@X@`fff)@hfffX@@0)@X@`fffFN)@X@z)@4333X@̌)@4333X@03333)@hfffX@*@X@5*@hfffX@0333X*@hfffFX@0333Sw*@X@l*@X@&+@X@0333n+@̄X@@+@X@0333+@X@hfff,@(X@0333x,@4333{X@hfffF,@hfffX@ ,@̜X@4-@AX@d-@hfffX@hfff&-@X@̬-@4333cX@yK.@9X@h.@܎X@0333{.@PX@ .@X@.@X@.@4333cX@̌.@̤X@@.@,X@.@|X@/@X@hfff/@̼X@0333/@X@ 0@YX@I.0@dX@<0@ܸX@PL0@ٸX@dfffZ0@4333X@d0@xX@dfffj0@X@0N0@IX@dfffT0@hfffX@Ƀ0@$X@)0@4333{X@`0@X@4333s0@(X@ 0@hfffX@dfff0@4333kX@%1@,X@i=1@ X@_1@y{X@dfff1@rX@dffff1@nX@̜1@hfff6mX@1@̴lX@4333c1@4333[oX@p1@nX@4333 2@4333iX@y,2@hfffgX@ B2@hfffvhX@4333SJ2@4333[fX@M2@hfffaX@K2@\X@4333\2@\XX@~2@hfffWX@2@iYX@|2@ _X@dfff~2@`X@l2@4333dX@Y2@4333jX@̬2@4333nX@p2@̼oX@43332@ApX@2@0mX@2@̴mX@2@4333ssX@dffff!3@rX@D3@hfffFtX@u3@hfffzX@dfffƗ3@pX@Y3@hfffX@3@4333#X@ 3@4333X@3@LX@а3@4333˒X@3@4333×X@l3@hfffX@dfffƱ3@4333X@3@hfffX@dffff3@4333sX@I3@ X@43333@4333X@3@PX@3@1X@43333@4333SX@4333 4@4333X@4@X@p4@hfff^X@4@X@y4@(X@dfff4@X@433334@̌X@4@hfffX@I4@X@\&4@4333X@04@43333X@B4@4333X@ Z4@hfff^X@\4@hfffX@4333W4@X@ R4@hfffX@PS4@hfff~X@`W4@X@lb4@4333X@dfffl4@4333X@Yj4@4333;Y@,a4@hfffY@Q4@hfffY@0333d#@ Y@`fff&\#@̤Y@`ffffl#@X@`fff~#@X@L#@Y@0333S#@̬Y@̌#@hfffY@0333d#@hfffY@ ,#@Y@0333#@pY@@"@X@"@X@"@!X@0333#@X@y)#@Y@Y'#@hfffY@ ,#@pX@0333s@8X@@4333X@`fff&c@4333X@@@4333X@@H@pX@0333s@4333X@Y@hfffX@ @X@03337 @̬X@Y @4333X@Y@hfffX@Y"@ X@`fff"@X@0"@4333X@B"@hfffFX@9G"@X@`fff&)"@hfffX@Y"@X@ ^@hfffX@@XX@@iX@`fff1@pX@@4333X@̋@X@ ^@,=@8333n'hfffV;D@ffff3""̌C@̲YC@@333hfffC@,C@C@4333CC@̭9C@@3333dC@@333uhfffC@)C@hfffVC@@333hffffC@@3333UC@pffff,C@ǐC@LC@?4333#C@hfffvC@@3333v4333sC@@3333̌C@̲C@pfff|C@hfffC@4333C@pfff0C@C@pfffC@4333C@̷43333C@pffffC@pffffy̼C@pfffft43333C@LC@C@pfffu@@"n@@"`@@"M@@"Y>@@hfffl"4333s7@@ P"(@@ E"hfffF@@L@"̜@@̌%"hfff@@""L?@hfff"?@8333 ",?@hffff!?@ !l?@8333!hfff?@8333s!83333?@hfff&!8333s?@L!?@!hffff?@hffff!?@83333m!s?@N!Y?@6! 5/?@eL8! /?@hffff4!&?@hfff&!hfffF#?@L!̌$?@ hfff?@ ?@hfff& hfff>@hfffy hfff&>@La >@8333R 8333S>@hfff&G >@8333= hfff>@@2 >@hffff& >@@ L>@pffff>@9>@phfff>@pfff*8333>@Y>@̀>@hfff>@83333>@pffffvL>@pfffm >@pffffj>@C@>@,>@pfffyt>@l8333e>@@[>@pfffL>@vhfff.>@@3333 *>@@33338333#>@>@hfff>@L8333=@pffffhfff&=@hfff=@hfff=@pfffzy=@&ٸ=@hfff=@pfff̌=@@333a=@=@@333hffff=@L83333=@@=@̌=@pfffhfff=@pffff=@q8333s=@=@=@pffffhfff&=@=@@3333hfff=@pfffj8333=@@333 hfff=@y=@pfff=@@333 =@p=@pfff)hfffƿ=@@33383333=@ =@pffff=@=@pfff,=@̅l=@@333'83333=@@3333-=@bK=@=@=@@333:̬%>@pffffWhfff/>@ffffD>@83333Y>@= a>@ hfffff>@@3333; l>@ hfff>@ hfffơ>@ffffY hfff>@ hffff>@ffff hfffF>@ffff ̌>@y L>@ffff2 >@̚ hfff>@ffffhfff&>@>@>@>@ffff8333>@ffff{ك>@@3333Wt>@@3333%n>@̌l>@p>@'8333Ss>@,y>@83333o>@ffffEl>@"hfff&q>@ffff>@i>@ffff3hfff>@,>@>@ffff83333>@@333383333>@hfff&>@@3333>@hffff>@%Y>@@3333Z8333>@zhfff>@ffff>@@3333hfff>@ffff >@V8333>@@3333Yhfffơ>@@33338333>@T`x>@@3333 z>@Ť>@񿠙>@hfffF>@񿠙9>@ffff8333>@hfff&>@ffff¢>@@>@ffff >@ffffhfff ?@ffffhfff&N?@ffff̬{?@ffff,?@ffff+F?@ffff`?@(?@X83333?@4𿠙Y?@C𿠙Y?@̲𿠙y?@xl?@ffff̌?@ffffhffff?@ ?@@3333?@@3333!?@@3333̬?@7hfff?@ffffhfff&?@ffffhfffF?@0?@@333383333?@@3333@?@<hfff&?@@3333 ?@?@?@8333?@,?@ffffShfff?@@3333bhfff&?@@3333hfff?@ffffhfff?@q?@@3333d8333s?@ffffp@@ ?@@3333j?@8333s?@_@@@3333!̬@@K@@@@33333@@4333S @@'hfff@@@33339@@hfff@@z@@C<$@@ffffBhfff(@@ffffn-@@& 2@@@3333aL8@@B@@̠hfffD@@hfffD@@)F@@`R@@U@@@3333W@@ffff4333Y@@ffff,`@@hfffg@@i@@@3333Y43333h@@,4333Sn@@|l@@aa@@c@@ffffHLa@@4333c@@ffff43333r@@9{@@hfffFy@@̋,q@@Phfff6r@@hfff6t@@ffff4333x@@@3333]@@6@@ffffHhfff@@@333343333@@@@@-̜@@hfffV@@@33334333S@@ffffp4333@@@3333hfff6@@ffff̌@@@@A̬@@Y@@4333@@@3333W43333@@K4333S@@@@ffffhfffƝ@@l@@/hfff@@ffffBhfffƴ@@4333@@@33334333@@̬4333Ӿ@@> @@ffffhfff@@̤ @@4333c@@hfff֮@@Gi@@̌@@'@@@3333@@-@@ l@@@33337`@@̬@@ffff"|@@@@@3333y@@ffff0@@ffff@@4@@ffff8)@@,@@@33334333c@@}4333@@> @@@@@3333y4333@@n4333@@ffff"hfff@@@3333š@@@@@@3333Ɍ&A@@m%5𿜙A@ffffZ ,A@B󿜙iGA@@3333)4333bA@}A@hfffFA@̌A@@3333hfffA@ffff A@KhffffB@>̬!B@ffff2&4333C@8333sU&hffff~C@hfffU&eC@83333u&9MC@̰&4333>C@&hfffV(C@L&C@8333&hfff6C@8333s&B@hfff&4333SB@hfff&&4333sB@&hfff&B@&hfffB@L)'hfffVB@hfffY'B@k'4333B@_'4333B@YK'4333B@83333/'L}B@L"'4333oB@$'4333bB@8'@VB@Y^'4333cBB@8333n' 'B@hfffi'|B@hffffW'hfffvB@83337'hfff B@'hfffA@&A@hfff&43333A@8333s'4333A@*'Q@3333 D@4333=Q@ffffND@Q;Q@3333sD@hfff62Q@DD@(Q@D@hfff'Q@D@\(Q@3333cD@4333)Q@aD@D@Q@3333D@DQ@D@C@hfffnQ@3333SC@4333Q@ffffC@(Q@ffffC@PQ@C@)Q@(C@hfffQ@̼C@Q@C@hfffvQ@̄C@hfffQ@3333C@Q@ffffC@Q@DC@1Q@̄C@Q@C@`Q@0C@hfff6Q@IC@hfffQ@ffffC@ Q@9C@Q@$C@Q@YC@qQ@ffff>C@Q@̔C@̔Q@ffffFC@lQ@3333C@̼R@3333C@4333cR@3333çC@hfffn R@`C@R@C@R@3333C@aR@ C@R@ffffC@`R@ffffC@hfff$R@HC@(R@hC@hfff7R@!C@4333B@oR@3333B@4333iR@3333B@)hR@3333{B@hfffiR@ffffFB@mR@3333+B@hfffnR@B@hfffnR@B@hfffjR@B@|hR@ffffB@4333fR@B@hfff^R@`B@XR@3333+B@4333MR@IB@P9R@ffff>B@4333s0R@3333B@4333*R@B@hfffR@}B@4333 R@DsB@IQ@3333bB@TQ@ffffXB@hfffQ@ffffWB@Q@4YB@WB@0C@3333YB@C@3333^B@D@̼iB@hfff9D@3333#B@4333SZD@B@hffffhD@؍B@̼zD@B@4333D@ffffB@D@B@hfffvD@B@D@iB@,D@$B@4333D@B@E@`B@|E@B@4333E@ B@E@ B@`"E@fffffB@ (E@3333cB@4333-E@ffffB@hfff-E@)B@,E@B@`E@ffff{B@ E@3333iB@̬D@3333^B@D@pLB@9D@HB@YD@AB@hfffVD@q;B@4333D@1B@4333D@"B@9D@B@pD@d B@lD@0A@4333#D@̬A@D@A@4333SD@A@4333ӦD@3333{A@ɟD@A@4333D@3333A@̌D@A@D@gA@D@ffffnbA@̬D@`NA@hfffV~D@33336A@wD@3333{1A@@XD@*A@43335D@PA@̜D@A@C@@@@C@Y@@YC@\@@4333CC@3333@@4333cC@̤@@BC@I@@̌ C@3333@@4333#C@X@@hfffB@8j@@B@]@@hfffB@ffffK@@4333cB@ffff;@@hB@̜(@@hfffV=B@@.@@/B@ffff1@@4333c$B@ffff:@@ B@`?@@̜B@3333SD@@lA@ffffVU@@hfffA@\[@@hfffA@^@@хA@Jh@@Τ,*A@|N@p@@T ?A@Ahx@@Ҫ@@#_gA@Ƞ@@m;{A@d|eB@@SfqA@vĪ@@*+8vA@) R@@F@$@HG@#@lG@@333s@#@ȻG@7#@ffff&G@#@G@@333"@G@"@3333{G@@333"@G@@3333#@G@)#@XG@pffff=#@3333[G@@333s}#@G@̰#@G@@333#@|G@pffff#@ffffxG@pffff#@3333SqG@YD$@fffflG@ \$@anG@pfff$@ ~G@@333s$@q{G@$@ sG@$@ffffnG@pfff$@^G@$@ UG@pffff$@ffff6OG@̌$@3333JG@$@hFG@pfff$@ffffFG@pffff$@LHG@d$@OG@pffffF$@3333NG@̌,$@LG@Y$@EG@$@=G@Y$@T9G@@333)$@33335G@pfff&8$@q.G@B$@$G@YJ$@3333s G@@333A$@ffff~G@@)$@ffff.G@$@yG@#@)G@pfff#@P.G@#@3333/G@Y#@3333K,G@pffffG#@%G@(#@ffff%G@@333#@1'G@L"@̤,G@"@$7G@@333"@̼=G@@333s"@ffff=G@ٛ"@ffffn?G@@3333"@3333F@!@TF@@3333!@F@Y!@3333F@L!@G@!@ G@̌H!@ffff.G@!!@tG@@333 @yG@ @4$G@ @ffff3G@pfff @H7G@Y @9G@̽ @8G@٘ @33333G@v @̬+G@1 @"G@) @ G@pfff&A @3333G@@ @G@L @̤G@@ G@h@ffffFF@&@ffffF@^@qF@'@4F@ffff@3333F@O@F@@F@9@F@@F@@3333F@@1G@̖@G@n@q G@9@G@@3333#G@ffffD@9#G@#@0(G@@A/G@@333@ 4G@L@85G@P@33337G@@3333@33337G@I@d2G@L@3333*G@@3333(G@@3333{'G@@I G@@3333@ffffG@@333X@G@@8G@@3333[G@L@3333{G@%@yG@@3333b@3333#G@@333v@8+G@@3333~@ffffv0G@@333=@ffff6G@E@:G@m@ffffBG@̄@3333HG@@ffff6NG@$@ffffnWG@@`G@L@jG@@3333vG@@3333@3333cyG@@ffffG@fff@dG@@tG@ffffH@3333G@fff@33333G@@G@@HG@@3333sG@@333@ G@@(@3333{TO@G(@T\O@@=(@iO@7(@uO@@3333H(@3333SyO@@333o(@O@ J(@O@G(@iO@@333'@ffffVO@l(@O@@333Y(@HO@(@O@)@O@@3333S)@aO@La)@̌O@pfff)@P@pfff)@3333;P@@3333h*@ffffP@pffff*@P@pffffW+@P@+@P@pffff,@3333P@pffff ,@P@LH,@3333 P@K,@̨P@pffff=,@P@',@ffffP@@+@ffff P@@333L+@8%P@+@ffff2P@@333:,@Q@833334@3333=Q@83334@fP@83336@gP@hfff6@\eP@"6@|dP@hfff%6@ffffbcP@833336@3333aP@̌5@ffffbP@833335@̈`P@833335@ffff^P@5@[P@,5@3333#[P@@5@YP@hfffƐ5@ffffZP@Y5@XP@5@3333VP@83335@1UP@83335@ffffBTP@ٜ5@$SP@83335@ffffPP@ 5@ffffJPP@hffffr5@̈TP@ i5@PTP@8333p5@RP@5@OP@hfffƋ5@3333?MP@hfff5@ffffJJP@5@ HP@hfffl5@@P@83333K5@=L@pfffO-@̌L@-@9L@L,@ffffL@,@ffffK@,@3333K@n,@3333K@pfffg,@TK@̌,@tK@@333,@̌K@@333X,@IJK@@333(,@33333K@ٜ+@3333۶K@̌*@ffffVK@̌)@K@)@̤K@pfff)@@K@@)@iK@)@ffffK@pfff)@3333K@L)@,K@L)@K@pffff/)@̜L@ )@ffffnL@@(@0%L@)@%L@pfffi)@L@@333s)@ffffL@@333s)@!L@|)@fffff,L@a)@41L@P)@d8L@ً)@ffffV:L@)@9L@)@ffffAL@@333s)@OL@)@SL@pffffo)@TL@@3333%)@aiL@(@tL@M(@ L@@(@ffff6L@L'@L@'@ffffL@pfff&'@lL@pfff'@L@Lx'@L@Lu'@L@ h'@L@'@(M@ &@ffff&M@@333&@̄+M@@333&@ffff0M@&@@/M@ &@H6M@ &@@YO;4333s@@433339&?@hfff&9?@hfff9@@4333:@@43333:̬@@ 7:L@@H:0@@X: @@hfff&s: @@ :4333s@@hfff:4333s @@hfff&:,@@hfff:hfff?@hfffF:?@:83333?@4333s,;Y?@LN;?@YO;83333x?@hfffK;hfff&F?@hfff=;9?@;hfff&>@4333s: >@:hfff>@hfff:Y>@hfff:>@:>@t:hfff>@i:>@8:hfff?@hfff:̌?@ 983335?@hfff9U?@l98333a?@433339hfffFj?@ 98333?@hfff9?@L98333?@9?@hfff&93My?JL@ffffKo@ffffK`fff&'@2333s*K`fff@9K @233339K@ffff @9K @ffffK @Kn @K @K`fff@2333K 333@ffffK@ K 333@t3K 3333@ffff&>K 3333T@DK@HK@hMK 333@NK 3333@TK̞@DYK`fff@YK/@q\K@(bKL@2333mK 3333@2333#pK`ffff@vK@{Kc@D}K@ffffK`ffff@Kc@2333KLP@ Kh@ffffKLa@̜KL@K@2333SK`ffff@XKY@2333K?@fffffK@K"@ffffK`fff)@K 333 @2333+K`fff@2333L`ffff$@ffffLL@< L@L`ffffe@L@l L`fff@L`fffC@!K@)KQ@K@ffff?ffffK33333?ffffNK?̌Ly?2333L@ffff*?2333c1L3333?ffff9L?=L?BL̘?ffffHL`ffff @HPL @(ZL 333J@laLL@hL 3333@ffffkL7@ffffvqL@2333;wL 333)@xL@Y}L@L`fffA@L 3333@̴L@ffff^L!@̼LLS@fffffL@tL`ffff%@LL4@L@2333CL@2333ۚL@|L@̜LL@2333L`fff@ffffL@ffffޟL`ffff# @2333LP @ffff6L 3333 @L 3333 @ffffަLL @yL`fff @ L`fff @2333˾L @YL @ffff&L 333 @L( @2333Lc @!L# @4L̴ @̔L`ffffh @2333LLL@0L@ M@2333Mh@M @`M`fff&@LYf@\L@L0333@ffffL0333N@IL03333@ffffL0333@2333L@aLH@L@ffff&L03333@LY@AL`ffff@L@ L0333@2333L@L0333@ffff^L`fff@2333#L2@L`ffffl@xL̠@ L̶@2333ۚL@LY@ffffL@ffffL0333@2333ˣL0333@ffffƨL`ffffW@\L0333~@ffffL@2333L`fff@ffffL1@PL@ffffL@@iL`fff@2333cLLQ@@L03333@2333#|L0333@ffff;L@@(L@2333CǨ.@K@Ǩ.@xK @K@Ǩ@̌K@2333KL@ffffjK @ffff-K0333@8K`fffl@KL;@K@Ko@L KL@ffffKo@4 H%8@ @YA@9r(@F@@@@@@4333@@`ffff~@@@L@4333@@`ffff @4333@@`fff@@@2@hfff@@ @hfffFk@@Lc@Y^@@.@hfffV@@@4333sD@@`fff @*@@L @l@@`fff5 @,@@ @@@`ffff9 @hffff@@`ffff( @ @@; @,@@L} @?@L @hffff?@ 3333 @8333?@`fff)@L?@k@?@ @8333?@ 333k @z?@q @[?@ @83338?@I@'?@`fffH@L ?@ @>@ @@>@`ffffZ @̬>@ @ >@LD @hfff>@̕ @>@`ffff @,>@' @̥>@ 333 @83333>@`ffff @83333>@`fff8 @8333>@ @8333s>@ 3333L@ >@@8333k>@ 3333@hfff1>@@y>@`fff@=@0333@hfff=@O@hfff=@@hfffF=@Y@8333S=@L@9x=@r@hfffb=@Y@83339=@L@hfff&=@@8333=@`fff@y<@@ <@@<@`ffff@Y<@}@8333sm<@0333K@^<@LF@O<@`fff&Z@L?<@`fffd@,1<@`ffff@ <@@8333<@`fff@ ;@ @hfff;@̌E@8333s;@d@;@`fff&@;@@ ;@@hfff;@Lb@8333};@@8333sp;@`fff&(@@g;@o@U;@̾@A;@(@hfff;;@Y@hfff:;@@@6;@`fffy@hffff.;@Y@$;@L@Y;@@9:@0333sk@hfff:@03333@8333:@03333@:@0333@hfff:@`fffF@̌r:@`ffff@hfffk:@@8333sZ:@03333a@S:@@O:@@@\:@̌@H:@@Y+:@ @@:@ }@Y :@`fff&@83339@B@ 9@03333@8333sa9@`ffffU@hffffG9@@̬09@@l.9@:@=9@̌@8333S?9@0333@L39@L;@9@@8333s8@lF @8@0333b @t8@z @ `8@0333S @J8@03333 @Y58@ @8333.8@ @̌88@l7!@18@`fffN!@%8@T!@8333)8@d!@̬68@ !@L8@`fff!@,8@!@y8@`ffff!@hfff8@y"@y8@y"@hfff8@0333["@̨8@u"@83338@ "@8333s8@0333S"@Y8@0333"@hfff8@0333S"@Y8@#@8@y8#@hfff8@#@8333S8@#@8@L#@9@L$@hfff&9@;$@9@ Z$@ 9@x$@hfff&9@l$@9@`fff$@8333369@$@I9@0333$@L9@L$@83339@ $@9@03333$@9@$@99@g$@L9@0333V$@hfff&:@03333?$@:@0333$@hfffF:@0333s $@hffff+:@̌#@hfff&:@9 #@:@"@`:@"@8333s:@`ffff.#@;@`fffF:#@;@-#@;@`fff4#@hfff;@`fff3#@ ;@0333"@hfff <@@"@83333<@0333"@8333S<@0333"@hfff<@ "@̬<@0333S#@hfff<@90#@hfff<@ 0#@hfff<@`ffff8#@8333S=@lY#@ >=@`fffo#@ y=@`fff#@8333=@0333S#@=@#@=@0333S!$@̢=@`-$@hfff=@l>$@9=@ $@hfff>@`fff$@y>@9#@hfffF>@@|#@`>@`v#@hfff>@ t#@y>@Lx#@>@}#@l>@#@>@9#@>@̄#@̌'?@#@83339?@9#@hfff?@9q$@hfff?@ $@?@,$@8333?@`fffF$@?@`fffI%@?@03333S%@3@@0333&@5@@-&@4333s6@@Y:&@hfffV-@@l~&@`+@@`fff&@*@@L&@,@@,)'@hfff&,@@̌]'@+@@yc'@4333S+@@0333k'@*@@n'@@ @@0333s(@L^@@0333(@^@@`fffF(@l^@@`fff(@)^@@(@̌\@@0333/(@[@@LG(@[@@M(@[@@`ffffT(@,\@@̬`(@9\@@0333Sg(@4333#\@@j(@[@@0333sm(@hfff\@@ p(@hffff\@@9r(@4333@@@o(@hfff@@ E(@I@@'@l@@0333'@̬@@`fffb'@@@@`ffff]'@4333@@`fffN'@@@`ffffF'@p@@0333S>'@hfff@@`fffF;'@4333c@@0333S6'@Y@@.'@ @@`fffF%@@@0333%@hfff@@l%@4333@@%@4333Ӑ@@0333%@hfff@@}%@hfff@@y%@,@@P%@@@03333N%@@@J%@4333ú@@`fff%@43333@@e$@@@`fff\$@hfff@@0333S$$@y@@$@̬@@03333$@@@̬$@@@#@hfff@@#@@@l#@L@@`fffƼ#@L@@9#@43333@@,#@hfff@@`fffư#@̌@@lo#@@@`fff@#@4333@@`fff#@̌@@`fff&#@|@@"@@@@"@4333C@@"@hfff@@0333S"@ @@`fff"@4333 A@L"@ A@L"@ A@̌"@4333 A@o"@hfff A@ "@ A@0333!@hfff A@LZ!@ A@*!@P A@,!@hfffA@0333 @hfff@@0333 @|@@ @@@y @@@`fff @hffff@@@ @@@ @@@0333 @hfff&@@̌ @Y@@ @̜@@Y@@@@@@`ffffy@hfffV@@K@@@`fff @hfff6@@@hfff@@@@@@4333C@@@4333@@ @,@@@̜A@x@A@0@9A@`fff&@hfffA@V@#A@`fff@>A@0333@ HA@̌@4333QA@@hfffZA@`fff&@hfff_A@E@hfffFkA@Y3@rA@`fff@zA@`fff&.@hfff}A@`fffn@hfffA@@|A@L@ A@`fff&S@PA@L @YA@@ЊA@Y?@lpA@03333p@hfffQA@@0A@̌{@4333A@`fff&@@@@5hfffF5@T!@4333NC@433336@ A@L"@4333 A@L"@ @@`fff"@hfff@@0333S"@4333C@@"@@@@"@|@@"@̌@@`fff&#@4333@@`fff#@@@`fff@#@̌@@lo#@hfff@@`fffư#@43333@@,#@L@@9#@L@@`fffƼ#@@@l#@hfff@@#@@@#@@@̬$@̬@@03333$@y@@$@hfff@@0333S$$@@@`fff\$@43333@@e$@4333ú@@`fff%@@@J%@@@03333N%@,@@P%@hfff@@y%@hfff@@}%@4333Ӑ@@0333%@4333@@%@hfff@@l%@@@0333%@ @@`fffF%@Y@@.'@4333c@@0333S6'@hfff@@`fffF;'@p@@0333S>'@@@`ffffF'@4333@@`fffN'@@@@`ffff]'@̬@@`fffb'@l@@0333'@I@@'@hfff@@ E(@4333@@@o(@hffff\@@9r(@hfff\@@ p(@[@@0333sm(@4333#\@@j(@9\@@0333Sg(@,\@@̬`(@[@@`ffffT(@[@@M(@[@@LG(@̌\@@0333/(@)^@@(@l^@@`fff(@^@@`fffF(@L^@@0333(@@ @@0333s(@*@@n'@4333S+@@0333k'@+@@yc'@hfff&,@@̌]'@,@@,)'@*@@L&@`+@@`fff&@hfffV-@@l~&@4333s6@@Y:&@5@@-&@3@@0333&@?@03333S%@?@`fffI%@8333?@`fffF$@?@,$@hfff?@ $@hfff?@9q$@83339?@9#@̌'?@#@>@̄#@>@9#@l>@#@>@}#@y>@Lx#@hfff>@ t#@`>@`v#@hfffF>@@|#@y>@9#@hfff>@`fff$@9=@ $@hfff=@l>$@̢=@`-$@=@0333S!$@=@#@8333=@0333S#@ y=@`fff#@ >=@`fffo#@8333S=@lY#@hfff<@`ffff8#@hfff<@ 0#@hfff<@90#@̬<@0333S#@hfff<@ "@8333S<@0333"@83333<@0333"@hfff <@@"@ ;@0333"@hfff;@`fff3#@;@`fff4#@;@-#@;@`fffF:#@8333s:@`ffff.#@`:@"@:@"@hfff&:@9 #@hffff+:@̌#@hfffF:@0333s $@:@0333$@hfff&:@03333?$@L9@0333V$@99@g$@9@$@9@03333$@83339@ $@L9@L$@I9@0333$@8333369@$@9@`fff$@hfff&9@l$@ 9@x$@9@ Z$@hfff&9@;$@9@L$@8@L#@8333S8@#@hfff8@#@8@y8#@Y8@#@hfff8@0333S"@Y8@0333"@8333s8@0333S"@83338@ "@̨8@u"@hfff8@0333["@y8@y"@hfff8@y"@y8@`ffff!@,8@!@L8@`fff!@̬68@ !@8333)8@d!@%8@T!@8333S 8@0333a!@hfff7@`k!@hfff7@`fffw!@L7@!@̌7@0333!@hfffF7@!@,7@0333!@83333}7@0333!@yv7@0333"@w7@:"@7@"@hffff7@`ffff"@̌7@0333S:#@7@0333k#@8333s7@0333S#@hfff7@`ffff$@hffft7@9Y$@8333O7@$@A7@`ffff$@6@%@hfffF6@03333%@,6@%@83336@&@ 6@0333Sb&@Y6@̈&@833336@0333&@Y6@y&@̌6@`fff&@hfff6@03333&@hfff6@ &@6@`fff&'@8333S6@`fff('@l6@V'@6@0333'@y6@(@hffff}6@`fff(@8333x6@0333"(@y6@,B(@lo6@0333(@hfffc6@ (@j6@)@83333Z6@`fff&R)@;6@@k)@hfff6@c)@,6@X)@5@03333[)@5@0333f)@hfff5@{)@hfffF5@)@5@)@`5@*@5@`fff9*@8333s(6@n*@36@hfff*@hffff:6@*@̌;6@,*@̬86@y*@36@+@hfff&'6@@+@̌6@u+@@6@+@8333 6@hfffF+@8333S,6@9+@C6@+@8333H6@0333+@V6@hfff,@`c6@l,@̌6@@A,@6@R,@96@ h,@83336@`y,@hfffs6@hfff,@yp6@,,@l6@hfff,@8333Sf6@hfff&-@̬a6@-@̌j6@+-@w6@hfffFD-@833336@0333SS-@6@L`-@6@hfffq-@83336@hfffƓ-@6@0333-@hfff6@-@hffff6@0333S-@Y6@.@6@y1.@̬6@S.@6@y.@833336@hffff.@83336@0333/@Y7@l@/@7@0333g/@8333S>7@d/@@u7@̌m/@7@0333}/@L7@l}/@,7@03333h/@7@hfffFm/@hfff7@lq/@7@0333s/@7@03333/@7@_0@hfff7@0@8333s7@0D1@Y7@`1@@7@4333(2@hfff&7@4333Ú2@ 7@4333 3@83337@4333#3@83337@3@83337@ 3@83337@3@83337@dfff3@:8@3@@y8@dfff3@l8@3@̌8@dfff3@`8@L3@hfff&8@3@83338@433334@8@4@8@<4@8@4@hfff8@`5@83338@5@\9@5@̌9@5@Y :@43335@hfff&:@5@8333:@5@E;@5@̌;@dfff5@8333S <@5@hfff&k<@5@8333<@5@.=@dfff5@hfff=@5@Y=@5@ T>@5@>@43335@?@5@̌5?@5@B?@dfff6@hfff[?@I06@yf?@433336@v?@dfff16@8333s|?@dfff%6@hffffw?@̬6@9o?@5@hfff&?@5@hfff&?@43335@#@@5@4333M@@5@w@@5@@@43335@@@dfff5@@@ 5@̌A@ 5@̌IA@5@̌sA@43335@̌A@dfff5@̌A@5@A@5@̌B@ 5@EB@4333#5@oB@)5@pB@5@hfffvB@dfff&5@4333cB@dfffvS5@B@4333/5@B@5@B@5@B@dfff 5@hfff֛B@5@hfffFB@5@B@dfffV4@4333B@4@B@4333c4@ B@dfff4@ B@e4@B@dfff4@̜B@3@̟B@dfff3@hfffFB@̌3@4333SB@43332@ B@2@B@2@iB@2@B@P2@y C@dfffh2@hffffC@4333SU2@4333C@?2@hfffF C@C2@<$C@dffffI2@̜*C@433382@yIC@̬2@4333NC@L2@BC@4333C1@43336C@1@hfff2C@4333C1@Y1C@4333S1@hfff/C@43331@hfffv,C@1@%C@43331@hfff6"C@1@4333s C@43331@ C@`1@<C@dfff1@4333C@l1@ C@dfffƆ1@<C@̬1@̜B@dfff1@hfffB@ ~1@hfffvB@4333cx1@4333B@,w1@hfff&B@@u1@B@dfffk1@B@dfffF^1@B@4333U1@4333B@R1@LB@4333I1@B@43331@̜B@1@4333B@̜1@ٟB@1@4333B@ 1@B@1@hfff&B@43331@4333cB@4333C1@hfff|B@dfff0@hfffF}B@43330@hfffwB@0@4333qB@0@hfffsB@4333u0@hffftB@4333K0@hfffiB@ 0@ hB@hfff/@̼\B@hfff/@VB@hfffs/@4333sHB@hffff.@BB@0333.@6B@C.@\9B@0333S-@4333C:T@̌ "@hfff;T@`ffff!@4333>T@0333!@hfffAT@!@LT@R!@NT@7!@hfffMT@L!@hfffNT@0333!@4333QT@ @`UT@0333 @WT@`fff @[T@03333n @[T@0333K @hfff[T@< @hfffjT@@!@pkT@Y@HkT@@̴kT@`fff@̌nT@@rT@0333@@uT@0333@wT@@'@ xT@0333@!wT@`fff@4333ctT@Y@4333#qT@ u@̜mT@`fff& @4333hT@Y@QXT@0333@ST@@hfff&>T@Z@X.T@̌@4333T@`fff&@T@ @T@ٜ@hfffvT@`fff&u@4333S@̌V@S@03333Q@S@@W@4333S@/@LS@! @S@Y] @S@`fff @4333S@`fff @$S@0333s @S@ @hfff>S@̬ @tS@ @hfffFS@ b!@dS@y{!@4333cS@`!@4333sS@`ffff!@hfff&T@0"@`T@k"@4333T@Y"@T@0333"@hfffT@'#@̌ T@`fff#@iT@0333S"@YT@L"@̌T@"@iT@@"@T@#@|T@8#@hfffT@L#@S@0333f#@hfffS@0333|#@4333S@0333ӕ#@hfffS@#@7)2y;@I@E@  ,8È?ffffVC@#?TTC@ffff?3333UC@~?3333UC@ffffn?[C@̬?̬^C@3333?TbC@3333? [C@{?YC@̀?ffffVC@) @!C@ @3333C@̼ @3333C@* @ffff~C@ffff @pC@̱ @PC@@3333Q @ffffFC@@3333 @ C@X @C@@3333 @|C@< @C@@3333@C@ffff3@ffff&C@f@IC@(@3333C@@PC@̚@dC@@1C@ffff@C@@3333+C@@ffffC@'@3333+C@@9C@ffff@yC@G@3333kC@=@3333CC@E @9C@ @C@P @LC@V @0C@̖ @ffffC@ @AC@E @C@) @!C@@333,@C@fff@ffffFC@̽@C@@C@̽@C@ffff@3333D@@D@<@̜ D@@3333@$D@@333B@hC@I@C@@333,@C@?uC@3333?3333mC@ffff?3333pC@̒?sC@?|C@?}C@3333?C@?XC@?ffff~C@?0C@ffff?C@?\wC@?uC@ffff3333#E@E@ffff E@gLE@(E@̼E@33333333CE@33333333E@ffff3333;E@ffffE@YpE@3333E@_E@3333̴E@N,E@ЄE@̤9E@iE@E@3333ffffE@3333E@̴E@yE@ffff^yE@g3333KxE@3333ktE@DfE@fE@2333޿PfE@ٿpgE@2333տffffjE@(ӿ̤iE@2333cпfE@Hʿ̄dE@_E@ܴZE@03334XE@hfff?3333\E@Y?XE@hfff?̼XE@$?ffffYE@̐?WE@gfff6?DXE@4333?ffffYE@4333?tfE@4333o?jE@L?,lE@gfffv?DkE@3333)?̴cE@3333?3333^E@3333U?H[E@3333?ZE@3333?hXE@ffff?ffffFLE@3333?1FE@ffff?CE@ffff??E@? ;E@ffff.?ffff7E@?̜7E@?8E@b?\:E@3333?3333?E@L?l@E@?:E@?6E@33339?ffffF2E@?3333-E@C@@-E@ffff@3333k1E@ffff@5E@@1E@@3333@3333C,E@6@̔+E@=@Y.E@@3333\@ffffN2E@ffff@I4E@@ffff4E@ffff@6E@!@`:E@@ffff;E@k@ffff>9E@7 @3333+7E@ @07E@@3333 @ffff/E@M @ffff+E@@3333t @$E@̿ @3333S!E@T @ E@4 @3333E@f @hE@ @9E@ @ffff E@ @D@, @ffff6D@ @3333;D@|@ffffD@@3333*@ffffD@@3333@ɤD@? D@3333K?|D@̆?D@$? rD@gfff?3333SiD@y?3333fD@?ffffv\D@gfff~?ffffWD@4333?3333PD@4333?ND@?̤OD@4333?ND@hfffF?ffff(D@hfffF?̤ D@ ?D@6B@ 3333/B@Q,B@qDB@)B@ffffVB@@ffffFB@q B@4B@QB@;ffffN B@3333CB@`fff)ffffB@̌*B@ 333ffff6B@LdCB@`fffLHB@`ffffaLB@YQB@`fff&3333K]B@ 3333PlB@`fff sB@tB@`fffHItB@ 3333333sjB@@1zB@ىܘB@pB@t3333B@̷3333B@ fffffB@`fff&B@`fffB@`ffffɶB@ 333B@B@8B@B@@+ffffB@`fffC@@JC@`ffffC@`fff̜C@̌ C@ 33333333C@ 333l3333+C@@_̌:C@W0@C@L9ffffHC@@%ffffSC@L ffffv[C@ 3333bC@iC@`fff&/tC@`ffff~C@`fff9C@,̴C@̌ffffNC@9HC@WC@`ffffs9C@C@ffffC@̌$ffffC@ C@xAC@̌0PC@%3333cC@1C@ 3333C@3333D@`ffffffffFD@AD@`ffff!ffff~D@ 3333D@ 33334 D@offff~&D@=3333+D@I)0D@Ld33334D@h̼8D@W=D@Qffff>OD@FSD@ 333W̄cD@LnlpD@3333+D@ffffބD@D@`ffffɍD@ 333tD@CD@̜ D@L(ffff>D@ 3333 D@D@̼D@ 333D@ 333s;33333D@3333+D@L3333 D@ 3333+D@`ffff<ffffD@5D@`fff:3333D@`fff&MD@yD@D@ 333D@ 3333UiD@LvffffD@ 3333ffffD@e3333kD@`fffffffD@ 3333`D@ DD@ffffD@`fffD@̤D@LffffD@`fff D@LsD@`fff&ffffD@ 333D@`fffffffnD@ 3333333D@3333 D@Y0 8D@0333N ffffD@X D@\ !D@0333s 3333D@9m 3333D@̌B 3333SE@0333SG E@X E@̌h QE@m E@9 ffffE@`fff& 3333E@!E@`fff-!E@̬]!ffffE@`fff!tD@`ffff!̤D@0333!33333D@@!y E@!E@a!#E@Yu!̼$E@0333!3333$E@0333!*E@!-E@`fffu!33334E@`ffff!7E@̟!3333+E@, 3333E@`fff E@0333s 9E@9F ̄E@`ffff E@ 3333iffff~E@`fffE@`E@ 333ffffE@`fffE@@ E@ 333s>E@LffffE@x3333E@E@3333KE@ Rffff&E@cE@̩ffffE@LCffffE@kA@x_@QA@_@)A@4333C_@iA@L_@ffffA@(_@|A@4333#_@̜A@4333C_@3333A@hfff_@̬A@_@3333kA@_@iA@1_@̜A@hfff_@ffffA@p_@A@y_@̼A@a_@B@4333_@3333B@hfff6_@q B@hfff_@DB@_@0B@Ԣ_@̬+B@4333S_@7B@hfff_@3333#=B@l_@ffffJB@hfff6_@ffffXB@hfff_@VB@_@YSB@4333Î_@9XB@4333_@ffffXB@hfffF_@ffffbB@hfff_@3333{oB@_@ffffzB@p_@ |B@4333+_@B@_@B@4333_@zB@4_@fffffyB@hfff_@LlB@з_@iB@4333C_@XnB@P_@sB@̄_@ffff>xB@l_@3333zB@̜_@|B@d_@ffff&B@4333_@@B@į_@ffffƘB@_@B@hfff_@B@hfff_@3333;B@ _@̌B@4333_@B@!_@ffffB@hfff_@ffffB@_@3333SB@_@3333B@_@3333B@hfff`@ffff6fA@`@Q^A@`@hA@`@nA@`@TwA@``@ A@`@̼A@hfff`@ffff6fA@4333`@ffff&gA@`@ZA@_@3333ZA@hfffF_@bA@hffff_@$^A@hfff_@3333^A@hfff_@3333hA@4333C_@oA@hfff_@3333uA@_@ffffNrA@43337`@ffffvpA@4333`@ffff&gA@_@l/A@܊_@ffffv-A@_@ffff1A@4333_@ 3A@܇_@33338A@_@0DA@hfff֏_@3333HA@_@EA@P_@̼?A@x_@̔6A@_@l/A@4333S_@PB@hfff_@fffffB@hfff~_@ B@_@3333B@_@ B@4333_@B@X_@LB@hfff_@3333+B@4333S_@PB@1_@,A@hfffF_@%A@_@'A@Y_@,A@_@ffff1A@̬_@̬2A@1_@,A@4333#_@NA@4333k_@3333JA@0_@PA@`_@PWA@4333#_@NA@_@ ?B@ؙ_@6B@_@3333;B@[`@pB@4333#Z`@ffff>B@Y`@DB@Z`@3333B@4333\`@B@]`@ffffB@P]`@ffff>B@_@@@ _@3333˙@@`_@@@_@Ԝ@@p_@3333+@@_@@@4333Ì_@@@̜_@ffff@@4333_@P@@_@@@̬_@@@_@и@@_@@@ܷ_@3333@@4333c_@ffffƢ@@4333;_@@@_@@@9 8333r0@@{GB@4333s%6cmhffff]=@hfff16`=@Y16=@4333s%6=@hfff&/60>@hfffJ6u>@9T6,>@@L6hfff>@lJ6?@N62?@LX68333I?@f6 K?@hfffft6L?@hfffz6Y?@6Yk?@96yw?@hfffF7 ?@̌G7?@m7̬?@y{7hfff?@̌78333?@783333?@97Y?@hffff78333?@hffff7?@L 88333s?@y<8Y?@̌T88333s?@``8`?@u88333?@hffff8?@43338Y?@hfff9̬?@4333sC9?@hfff\9 ?@hfffơ9?@ 9hfff?@hfff9?@hfff&98333?@9?@L98333?@hfff9hfffFj?@ 98333a?@433339U?@l983335?@hfff9̌?@ 9hfff?@hfff:>@8:hfff>@i:>@t:>@:Y>@hfff:hfff>@hfff: >@:hfff&>@4333s:9?@;hfff&F?@hfff=;83333x?@hfffK;?@YO;Y?@LN;83333?@4333s,;?@:hfff?@hfffF:,@@hfff:4333s @@hfff&:4333s@@hfff:̌@@`:@-@@4333:hfff&=@@hfff:\K@@4333:hffffc@@:lq@@l:l@@hfff;YZ@@ q;T@@y;4333sD@@ 3@43333>>@hfff&o>hfffx>@>hfffI>@Y>=@4333sR?̌=@l?83333=@lx?{=@? =@hffff@ <@%@ s<@4333O@6<@hfffvb@8333S;@hfff@;@I@ ];@hfff&@8333;@hfff@:@̌@8333m:@9@8333S9@ @L9@Y@hfff9@@`9@lA9@hfffA,z9@A8333s+9@@9@@83338@hfffA8@A8333s8@hfffVA.8@Ahfff7@4333@hfff7@@8333Y7@4333AhfffD7@4333c A83336@hfffAL6@PAhfffƍ6@IAj6@4333A>6@A5@4333/A5@/ǍY5@@4A?5@4Ahffff5@̬.Ahffff4@ /Ahfff4@y1AY4@P8Ahfff4@hfffF;AhfffFo4@AAhfffF4@4333dA 3@)cA3@`Ǎ3@l`A9d3@hfffMAYL3@NAR3@IA̬T3@hfff?AhfffG3@7A>3@hfff4A,&3@\5A,3@,A2@,A2@).A83332@.A92@4333%Ahfff2@ Ǎ2@ A 2@ Ǎ2@4333 Al2@43333 A2@hfff A̬2@ A2@ ALv2@4333A,v2@hffff,A i2@hfff%A Z2@ AYU2@ AZ2@43333@ w2@4333@t2@4333@n2@@9O2@@B2@@hfff(2@@hfff&2@@1@@Y1@@83331@4333{@1@i@833331@`@1@4333Z@Y 2@hfff6c@ 2@4333_@9@2@yS@hfffFS2@4333@@8333sT2@"@̌O2@̬@52@4333?hfff)2@?hfffF1@b?l1@?X1@q>hffff01@̌>833330@hfffFg=L0@hffff=8333{0@9<8333r0@<8333|0@hfff1@;<O1@hfff:<8333[1@D<b1@lZ3@4333<@H3@4333<`E3@< P3@<@h3@hfff<{3@`<833333@̬<@ >̬<@=l=@4333==@hfffF=9=@=hffff$=@4333s=83331=@4333Ӧ=?=@l=hfff&K=@ =LY=@hfff&q=c=@Q=hfffd=@ E=8333^=@7=V=@hfff)=hfff&M=@=B=@ =8333-=@4333s ==@hfff& P;@ >Z;@(>hfffY;@4333S?>83333];@yG>8333sc;@P>h;@hfffFS>8333sn;@hfffV>8333};@,]>̬;@hfffa>̌;@hfffFi>8333;@hffffw>hfff;@4333ӊ>;@>;@4333>hfff<@l>̌<@̌>̬<@hfff>8333 <@l>#<@,s>-<@h>P<@7>`d<@hfff%>hffffp<@y$>hfff<@!><@>hffff<@4333 ><@hffff >hfff<@>:4333s{D@ 4333I@`fff'@0D@ D@D@(hfffD@@33331D@@33334333ӎD@ffffhfffF}D@hfff6}D@Q}D@4333ӿ4333|D@"?)|D@ ?̼{D@@hfff{D@#@4333s{D@`ffff@hfffF}D@L@hfffFD@@D@ @hfffD@L @hffffD@ 333i@hfff&D@`ffff@)D@ @hfffE@@@<E@@hfffv-E@Y@4333SeE@+@hfffmE@L@hfffrE@q@)wE@@ E@@@hfffE@0333@E@`ffff@hfffE@\@E@k@4333#E@L@E@@4333E@Y@F@@L/F@̌@|QF@@tF@@4333cxF@`fff@F@|@ F@Y@F@L@̬F@`fff&@YG@L@4333#6G@03333@UG@0333@P|G@`fff@4333sG@@hfffG@@@hfffG@̌ @hfff6G@@9H@q @"H@ @6H@0333[!@NH@!@4333eH@`fff&w"@4333xH@L"@4333xH@0333 #@xH@#@xH@l#@xH@0333$@ xH@̬m%@ xH@0333%@4333#xH@0333S&@4333H@̬&@4333H@y&@0H@&@hfffI@'@̬;I@t'@CI@y'@hffffQI@9'@ieI@`fff'@|I@'@I@0333S'@̬I@0333s}'@I@P'@4333sI@'@ɊI@٫&@hfffI@L'&@I@0333SP%@̐I@1%@lI@Y%@4333I@ $@I@`fff$@4333I@$@hfffI@,$@I@$@I@`fffF%@4333I@%@٥I@0333S$@@I@0333S$@4333I@`$@9I@`fff$@4333SI@`ffff$@I@0333$@I@03333$@ wI@̫$@sI@$@hfffoI@,#@jI@`fffk#@iI@9"@4333WI@y{"@QI@03337"@43337I@`fffư!@)I@9=!@4333$I@0333!@) I@Lf @H@`fff@pH@Y@H@@hfffH@0@̜H@L@4333H@@܋H@`fff@PH@̱@4333SH@@@4333H@̌@hfffG@0333@hfffvG@@|pG@I @̌G@@4333F@z@uF@@ffff?hfff*F@@ffffA?0F@̱?E@s?ܻE@ffff?hfff&[E@|ƿ,QE@ пhfffGE@4333Կ;E@8ݿ 3E@ffffRhfffE@翜 E@elD@3333#D@4333D@hPD@@3333A󿜙D@hfffD@A0D@ ;hfffTE@@4333#xH@`fff&@O4333#xH@0333S&@ xH@0333%@ xH@̬m%@xH@0333$@xH@l#@xH@#@4333xH@0333 #@4333xH@L"@4333eH@`fff&w"@NH@!@6H@0333[!@"H@ @9H@q @hfff6G@@G@@ G@@hfff6}G@@4333uG@` @hfffRG@< @4333%G@Lx @F@ @F@L @ F@.!@`rF@f!@hfffPF@y!@43333'F@@!@F@!@E@`fff"@4333E@03333M"@lE@"@`E@0333s"@4333ýE@L"@yE@`fff"@̦E@7#@hfffE@0333S#@@E@̌#@4333ӈE@9#@4333E@0333s$@tE@H$@kE@g$@hE@`fffƃ$@PdE@@$@4333\E@`fff$@UE@"%@hfffTE@033333%@lTE@`fff&>%@̬aE@`fff%@hfffgE@`fff&%@4333snE@0333s%@sE@`fff%@vE@`fff%@9E@c&@hffffE@@&@|E@`fff&@yE@`&@E@`fff&&@hfff&E@̌%@@F@%@#F@$@y1F@`fffF$@4333xF@$@9F@̬L%@4333F@%@F@%@4333#G@`%@ G@%@:G@`fffw%@4333SHG@0333}%@|G@%@4333sG@`fff&3&@hfffֳG@Y&@hfffG@Y&@43333G@Y9&@hfffvH@YG&@,8H@̌&@IIH@&@4333SVH@03333&@sH@&@4333#xH@0333S&@< hfffuc@'d@oO "3?KYry3c@ !4333{c@ !43337c@83333 4333;c@ c@hffff 4333c@L c@83333 hfffc@ c@ !d@̌T'd@\'hfffd@Z'4333d@.'4333Od@$'`d@Y('d@hffffB'd@̌T'4333Cd@%̴d@ٌ%d@Y%4333d@%d@8333%hd@̮%8d@hfff&%Pd@̑%4333Kd@%d@8333s%d@8333g%d@@Y%4333d@R%d@\%0d@b%(d@̌}%4333Cd@%pd@'5d@'-d@@' d@hfff'\ d@l'd@8333S'd@8333I'43333d@83338'd@L0'd@('hfffVc@8333s'c@L&d@hfff&yd@Y&\d@Ld'0d@'pd@'1d@Y@#hfff1d@hfff&w#̸1d@#4333K/d@a#(.d@p#-d@]#4333/-d@hffff3#X-d@ #4333,d@8333s"4333+d@8333"-d@hfff"1d@Y@#c@@?"hfffc@@"c@@:"hfffFc@hfff&8")c@hffff&"|c@ "4333'c@8333s!4333c@8333"hfffc@L "4333Oc@Y"|c@0"c@@?"ad@8333!8d@hfff"d@"8 d@L"hfff d@G"4333 d@\" d@R"d@YV"̔d@̌S"d@83333?"4333d@ +"4333_d@Y)"d@hffff"ad@8333!hfffnc@| pc@hfff c@@!Uc@hffff#!c@83333%!8c@Y9!c@ !c@ вc@ c@8333 4333۱c@83333 hfff"c@@ hfff>c@8333 c@hfff pc@83333 hfffc@̌ Pc@Yl hfffJc@̌R hfffc@Y1 hfffޭc@L4333c@pfff)c@  c@hffffT 4333״c@o hfffnc@| lc@٤!̸c@̦!c@hffff!c@83333[!c@!c@@!lc@٤!tc@L^!Mc@8333!c@ y!4333#c@hffffV!c@hfff,!c@!!hfffc@83333!c@hfff!4333c@83333!`c@!4333;c@!0c@6!hfffc@>!Pc@K!tc@L^!hfffrc@Lm!4333sc@t!4333c@hfffff!4333˦c@L!!4333{c@83333 !4333 c@hffff $c@ hfff&c@@ Ec@83333!4333c@hfff&!c@hfff&M!hfffrc@Lm!4333c@@3333hffffc@LTc@c@@333v4333c@9Yc@c@4333c@Kxc@Ls4333c@pffffc@@3333Ic@c@4333c@@33334333Sc@W 4333c@d Dc@Y% hfffZc@̌ c@L@c@̘c@@1 4333Sc@W c@Y7 ̤c@? Qc@hfff&< hfffc@Y c@Šc@@333xIc@lhfffc@̇c@4333kc@hfff& c@hfff) c@Y7 zc@c̨wc@|hfffuc@[4333vc@ wc@L4333{c@L,zc@c4333c@̌!̔c@̌!4333c@8333!4333c@u!4333c@8333si!ذc@hfffd!c@Lh!c@x!4333c@̌!4333c@"4333c@"4333d@Y"X d@"hfffd@̌#d@-#d@b# d@n#4333kd@hfff#4d@#4333d@8333#d@hfff#hfffd@8333s#id@#hfffF d@#4333d@8333#Qc@@#c@hfff#,c@s#hfffc@ F#hfffc@8333s#c@"pc@hfff&"c@Y"hfffc@̌"4333c@"!c@̌!0c@hffff!4333c@ c@L Tc@Y Uc@hfff&h c@d 4333c@hfff4 5c@ Xc@hfffc@pfffc@@333c@@333Ehfffc@L c@hfffRc@O4333c@-c@jc@@333hfffc@(hfffVc@Yc@@3333hfffVc@pffff-c@c@hfffc@ hfffc@hffff hc@hfff (c@L !c@̌!4333c@LR̘c@pffffv4333c@pfff4333۪c@4333'c@pc@@333]hfffʧc@i@c@pffffKc@̸Dc@̤hfff֏c@pfff 4333c@pffff4333{c@4333Wc@oUc@pffffhfff~c@pffffc@pffffHc@@3333c@t0c@@3333c@@3333,c@<4333sc@@3333A4333c@LR4333d@ d@Y9!d@hffffT!d@e!8d@!8d@̬!d!d@̵!%d@8333s!̌&d@Y/"hfff&d@hfffC"hfff6(d@Lb"E(d@@"hfff+d@ ",d@%#+d@83338#L*d@-#&d@hfff&"T!d@8333" d@"4333d@LP"̴d@!4d@=!d@!d@پ d@ d@@ d@83333 xd@ 4333d@ 6d@L$hfff:d@hffff$hfffB=d@8333s$4333@d@hfff&$4333_Cd@Y$Ed@%0Id@k%43337Id@hffff%hfffKd@%Id@ %pFd@%Cd@%]Ad@ّ%H@Y3@H@̌w3@3333+H@C3@Y H@hfff2@H@2@ H@hfff2@@G@83332@3333CG@,2@3333+G@2@3333;G@hffff2@G@y2@tG@hfffF%2@G@̬1@)G@ 1@̔G@1@3333G@ {1@̜G@9Q1@ffffG@83333M1@ffff&G@F1@ffffH@8333,1@3333H@%1@3333H@1@H@`1@ H@0@3333[H@̌0@ffff1H@0@8H@̌0@3333s@H@0@̄FH@hfff0@ffffVKH@0@ffffLH@90@̤VH@833331@cH@"1@kH@@01@33333nH@L1@kH@̌{1@iH@1@kH@,1@ffffqH@83331@vH@hfff1@ffffN|H@1@ffffH@83331@H@hfff 2@̬H@2@ffffVH@83332@ffffFH@hfff&2@3333H@8333!2@ffffH@83333)2@H@hffff]2@ H@8333b2@̔H@8333sj2@ H@y2@ffffH@و2@3333{H@83332@H@2@ffffH@2@3333;H@2@ffff.H@ 2@aH@,2@ȿH@ 2@aH@hfff2@H@@&3@33333H@ @3@ffffvH@hffffM3@ffff.H@b3@$H@ q3@H@z3@ffffH@hfff3@̜H@8333ӗ3@3333;H@l3@QH@Y3@ H@hfff3@H@hfff3@ffffޱH@ 3@3333H@y3@ffffƨH@3@ffffH@8333s3@3333H@83333@)H@`3@ffffH@8333s3@H@hfff3@ffffVH@4@4H@̌4@H@hfff)4@H@̌<4@8H@8333sM4@ɮH@\4@PH@g4@)H@83333l4@8H@yy4@H@و4@3333˰H@4@3333#H@4@YH@̬4@H@8333S4@HH@4@ffffH@L5@H@8333S5@H@"5@aH@95@H@Y5@H@5@3333H@L5@3333H@5@ffffH@5@HH@̌6@H@hfff&6@њH@36@̜H@y6@hH@hfff6@ffffNH@>8pfff*@ԶF@hfff&0@nG@hfff&0@?G@ym0@ CG@9R0@ffffnDG@M0@̼BG@hfff&B0@3333AG@<0@ffff=G@@0@ffff1G@9:0@/G@@0@0G@hfff0@/G@,0@ffff'G@/@#G@@333/@!G@̌/@3333G@̌h/@3333KG@E/@G@7/@G@pffff//@3333G@1/@3333 G@U/@4G@pfffY/@F@ V/@F@pfffM/@3333[F@pfff?/@F@.@F@ٍ.@ffffF@.@ffffF@.@xF@.@F@̌.@3333kF@@3333.@33333F@.@QF@@.@3333KF@̭.@ȻF@@333{.@F@̌8.@3333F@-@F@-@F@@333-@ѻF@ -@ffff6F@w-@ffffF@̌L-@ffff&F@7-@F@/-@\F@@#-@ F@pffff-@F@pfff-@0F@,@̼F@pffff,@F@pfff,@IF@̌R,@F@+,@)F@L+@4F@+@ffffnF@@333+@ffffƽF@ +@3333F@pfff+@ԶF@;+@ffffF@pfff'+@)F@LF+@F@̌p+@ffff6F@L+@ffff~F@+@3333F@ٿ+@3333F@̌+@F@q+@qF@@333S+@`F@@333*+@3333F@pfff#+@F@Y:+@F@3+@iF@@333+@̤F@@333*@YF@pfff*@ffff.G@ *@G@+@h G@@333;+@ G@E+@1G@C+@G@pfff+@)G@*@G@L*@̜G@̌*@,G@*@3333G@pfff*@|!G@̌*@̤(G@*@A/G@pffff +@!5G@@3333F+@i9G@\+@@;G@pfffff+@BG@pfff|+@AG@pfff+@pAG@̌+@?G@ ,@=G@@3332,@ ;G@و,@i8G@,@ffff6G@̌,@3333C5G@-@a5G@-@)3G@'-@33334G@pfff1-@7G@@\-@Q;G@@333s-@3333?G@-@̴EG@pffff-@LJG@Y-@ffffMG@-@ffff~NG@Y.@ PG@o.@LRG@pfff.@PG@@3333/@3333SG@pfffC/@fffffYG@@/@ZG@pfff/@3333 [G@L/@̼VG@/@ffff>YG@/@YZG@pfff&/@3333fG@hfff 0@3333#lG@83330@nG@H0@3333mG@N0@3333iG@hfffQ0@)dG@U0@ffff^\G@^0@ffff6ZG@8333sb0@$WG@a0@QG@ k0@MG@8333s0@3333BG@hfff&0@?G@?`̜Y@??Y@3333'? Y@M?yY@??̜Y@@ffff5?4333#Y@@ffff?YY@3333'?,Y@̧?hfff~Y@F?Y@?Y@M?@ ٕ*L@$9#@~t$`ffff @L$ @$`fff& @9$9` @0333s$0333P @0333%`fff&@ @`fffF$%l$ @03333<%0333@K% @0333a%@0333%`fff&'@ &`fff&@+&`fff&@ U&0333A@ &03333@&0333`@& @'L@0333S'0333@`fffw'0333Z@'0333@y(^@`fff(̌@(@̌(.@Y)0333@`fff(Y@Y)0333s@0333#)`ffff@,e) @Y)*@`fff)YF@ )03333m@̬)@ @0333)`ffffJ @`fff *f @`fffFL*m @Lg*0333 @`fff*`fff @*`fff @h*0333 @P*0333s @`fff+*y @ )̌ !@l))!@`fff)0333sB!@)P!@ )0333:!@,-*`@!@`fffF>*0333s-!@]*`'!@0333t*Ld!@s*,!@0333i*̬!@`$*0333s!@0333s*`fff&!@0333N*!@0333*̌!@ٕ*03333"@w*`fff#"@0333S[*,"@B*Y"@0333'*`fff#"@Y*`fff5"@L)9K"@`fff)0333ӆ"@`fff)"@)`fffF"@l^)`fff"@`fffM)0333#@̌>)`fff3#@ 5)D#@.)W#@)0333h#@y ) #@)l#@ (#@03333( #@H(03333#@0333s'0333s#@y'l#@̌k'`fff#@&̬#@&9#@Li&#@\&`fff#@9;&0333#@L&#@%R#@`fffƺ%l#@`ffff%L"@̌a%`fff"@̌]%`fff&"@0333`%0333"@`fffFq%0333c"@%`fff>"@y~%`fff0"@`fff&t%0333)"@`;%L"@`fff&6%`fff&!@03336%03333!@% !@`fffF%`fff`!@%0333R!@`fffA%Y!@Z% @g%y @l%`fff @_%0333 @`fff&N% @@5%0333 @̌% @,$`ffff @0333$@ @Y$0333 @$`ffff @Y )̾@)@6)`fff@9)̌H@0333s)0333|@;)@)0333m@`ffff)`ffffT@0333S)0333#@Y )̾@AX4333K@pffff$K@@3333<)K@@333K@pffff$4333SK@@333K@YK@pfff4333K@pfffohfffVK@@3333<)K@@333Bp2@ffffE@83336@G@ ,\5@iF@5@!eF@٘5@`F@٢5@ZF@5@ WF@hfff5@3333CUF@hfff6@XOF@83336@ffff^EF@8333s36@GF@hfffY6@3333VF@hffff6@fffffZF@`6@3333SSF@̌6@MF@6@3333HF@hffff6@3333GF@6@3333GF@8333Ӎ6@)EF@6@3333>F@~6@̼7F@ه6@a0F@83336@ffffN+F@6@(F@6@3333$F@6@F@6@pF@6@0F@hffff6@F@y6@F@83336@3333 F@8333x6@ffffNF@k6@3333F@hfff&f6@E@̌]6@YE@^6@E@ c6@̼E@8333e6@3333sE@8333o6@ffff.E@`y6@ffffE@hfff6@iE@6@,E@l6@ffffE@6@TE@6@ffff~E@ 6@LE@83336@E@6@ffff.E@96@lE@L6@E@Y6@ffffVE@hfff6@,~E@hfffƴ6@$qE@6@qpE@8333Ӆ6@fffffoE@w6@ffffkE@8333sp6@TeE@83333w6@`E@v6@ZE@̬o6@ffffPE@x6@3333EE@833336@@E@L6@=E@hfff6@q8E@r6@-E@ l6@*E@8333X6@0(E@@Q6@ffff.)E@F6@,E@`=6@-E@̌%6@)E@8333S 6@ffff&E@@5@(E@8333s5@9)E@`5@y'E@̌5@&E@@5@D"E@hfffF5@ffffE@5@ffffE@hfff5@#E@ل5@ *E@̬5@,E@ 5@1E@y5@,6E@ 5@8LE@̌5@dSE@5@̼UE@L5@3333KWE@5@3333;WE@d5@ffff.`E@,g5@pjE@R5@ffffoE@8333<5@tE@95@dzE@hfff 5@E@5@̼E@4@َE@hfff4@iE@,4@33333E@hfff4@3333cE@hfff4@tE@83334@3333kE@l4@E@Y4@E@hfff4@lE@83334@ffff֖E@94@E@Y4@ȌE@hfff4@E@4@`E@y4@yE@Yu4@XvE@|4@̄pE@hfffx4@mE@hfff&X4@iE@Y4@(mE@hfffW4@IrE@D4@̼wE@*4@{E@̬3@3333sE@hfff3@3333[E@3@ E@hfffƫ3@E@L3@33333E@833333@3333+E@hfff&j3@E@YL3@E@83@E@L23@E@ 13@E@13@3333CE@hfff&A3@E@M3@E@@\3@ffffE@Lf3@ffffE@hfffs3@E@z3@ffff.E@~3@IE@|3@ffffE@83333]3@!E@A3@ffffE@>3@ffffE@D3@E@hfff&N3@ffff&E@`X3@E@ s3@0E@̬3@YE@l3@3333kF@8333s3@F@83333@h F@ n3@ffffF@V3@F@hfffF;3@#F@&3@&F@ 3@ffffF*F@8333S3@3333.F@ 3@5F@hfff!3@=F@&3@CF@ 93@ffffNF@J3@0YF@U3@cF@Y[3@mF@@Y3@pF@ P3@rF@<3@ffffuF@̬!3@ffff&sF@hfff 3@oF@83333@AoF@2@ffffsF@8333s3@ffffuF@ 3@quF@3@3333tF@83333@vF@3@̤|F@3@F@83333!3@3333kF@y!3@ffffvF@ #3@ffffF@43@yF@8333M3@iF@Yc3@$F@hffff3@33333F@hfffff3@33333F@a3@̄F@,Z3@iF@̌T3@PF@E3@̔F@83333@ F@833333@3333#F@83333@F@hfff3@HF@8333s3@3333F@3@|F@hfff&2@lF@2@F@2@F@2@0F@2@F@2@F@̬2@,F@hfff2@3333CF@hfff2@8F@hfff3@F@83333 3@F@83333@8G@Y3@G@8333s%3@ffffVF@Y53@F@83333G3@ffff^G@̌T3@ffffG@8333d3@`G@k3@@G@ u3@ffff. G@3@G@ 3@G@y3@qG@,3@̬G@ 3@3333G@8333S)4@)G@54@!G@hfff=4@ffff G@hfff&M4@|G@[4@F@ p4@3333kF@Y4@3333#F@hfffƔ4@3333KF@4@3333F@83334@F@8333S4@3333cF@833334@ffffF@4@ F@hffff4@F@4@3333{F@4@̼F@ 4@yF@94@3333F@Y4@)@003334)@p0+)@0A)@`fffF0 W)@L0g)@0@)@03330`fff)@i0 *@\0L=*@`fff0N*@Ln0̌P*@0333s:00333R*@`fffv00333Q*@`fff&/P*@/y*@̀/@*@̌P/,*@0333.0333*@̌.*@03333}.0333*@l.Y*@b. +@`M.+@Y1.L+@ .0333+@̌-*@`fff-hfff*@0333ӝ-*@`fffX-0333*@̌,̬*@Y~,x*@,*@+̬*@`fffF+*@`fff+hfff*@l+@+@@K,+@`fffe, +@Y,̌*@̬,hfff&*@,hfff+@0333-0333+@`fffF$-y;+@R-hfffI+@03333-0333V+@ -hfff+@`fff .̬+@y7.̟+@.hfff+@̌.9t+@0333/hfff&,+@U/03333-+@i0/+@ O01+@033300333,+@y0 a+@٥0+@0333Ӿ0L+@`fffV00333S+@0 +@̼00333,@<0,@09,@0,@0 ,@90/,@i0̬j,@L00333s,@0333S10333S,@`fff+1H-@B10333f-@`fffX1hffffu-@ k1lr-@q1M-@ 1-@li1-@̬%10333-@0hfff.@0hfffx/@`fff0@/@`fff0̬/@`fffz043330@`fffp0\40@0333g0433390@̬[04333N0@0333cM0s0@0=043330@+0 0@0dfffF0@03330̬0@/}0@0333S/0|0@=/0@̌/|0@̌.0@k.dfff&0@,>.dfff0@̬9.0@`..I0@`fffF.dfff0@9 .0@03333-I0@`fffF-̭0@0333s-L0@̒-Y0@`fffF-0@`fff,̌0@+,9k0@9+dfffO0@0333+A0@+30@`fff+%0@+dfffV#0@`ffff+),0@ n+dfff6+0@̌^+| 0@@?+I0@l+$0@0333+̜"0@ *<0@0333S*dfff0@*4333S0@*dfff&0@0333*l/@0333*,/@*f/@0333i*;/@`fffH*hfff4/@`fff5*$/@ 2* /@(*Y/@*hfffF.@)/@)0333.@0333)L.@,)L.@̬)Y.@̌),|.@Y)0333sr.@`ffff)0333_.@0333sx)03333C.@Q)hfff*.@L).@0333s(hfff-@@(,-@`fff(L-@̬(9-@D NA@,_0@ K@@@(isB@b9@hfffpB@b9@ gB@4333cs9@hfffaB@dfff&9@l\B@dfff9@CB@9@̌@B@dfff&9@LDB@P9@FB@dfff69@\KB@̬9@_B@ 9@4333SvB@l9@hfff6zB@dfff&j9@isB@b9@lD@433330@4333SE@dfffƵ0@@E@0@`E@dfff0@̬E@43330@E@i0@hffffE@̬0@43333E@0@YE@dfffF0@ E@4333S0@ E@٤0@0 E@dfff0@iD@I0@D@,0@D@\0@hfffVD@0@hfffvD@433330@D@dfff0@hfffFD@4333c0@4333#D@dfff1@iD@`0@hfffVD@0@D@dffff0@43333D@dfffV0@,D@0@lD@433330@4333#I@43332@I@2@I@43332@4333I@<2@yI@̜2@hfffZI@dfffF2@y-I@2@I@92@H@2@H@4333ç2@H@2@`H@2@4333nH@dfff~2@hfffKH@dfff\2@l(H@ :2@ H@,(2@hfffH@1@hfffG@dfff1@hffffG@1@4333G@ɘ1@0G@dfffr1@@G@P1@̌G@43331@PG@dfffv1@)G@4333s0@`G@Y0@4333|G@dfff0@4333pG@91@hfffcG@L61@4333#]G@C1@LWG@D1@AG@l@1@'G@dfff6;1@ G@@1@F@dfffFG1@hfffF@4333SM1@ F@Q1@IF@g1@̬F@4333cl1@4333F@lm1@hfff&yF@m1@hfff_F@4333n1@4333EF@4333g1@hffff-F@4333j1@hfffF@dffff1@ F@4333]1@ F@4333^1@hfffE@̜V1@`E@ S1@hfffE@Y1@4333E@X1@4333CE@4333]1@4333E@l1@4333sE@x1@hfffE@̬1@4333E@43331@E@)1@LE@l|1@̬E@t1@pE@\1@ٗE@ S1@4333SE@dfff6D1@hfffVE@@=1@hfffE@|41@hffffE@1@hfff&E@1@E@dfff&0@4333E@dfff0@̜E@43330@ٗE@`0@ E@|0@iE@dfff0@hfffƇE@,0@LE@dfff0@@~E@4333S0@PfE@,_0@eE@s0@hfff]E@0@\E@@0@4333sYE@0@RE@dfff&0@hfffFE@4333S0@hfffEE@̬0@@B@2333%>@B@23333P>@0B@T>@B@ Y>@4333sB@Pq>@4333sB@>@B@ffffV>@hfffB@ffff6>@PB@?@,B@ffff%?@yB@Z?@4333zB@2333}?@B@\?@hfff&B@9?@ B@2333C?@4333CC@?@0C@2333?@4333bC@L?@,{C@2333?@C@@@̜C@@@0C@ffff @@ C@q@@D@?@hfffF/D@`?@L=D@2333?@ygD@ffff?@D@ɝ?@D@0}?@4333D@iT?@\D@i8?@hfff E@2333?@$E@>@hfffGE@>@mE@ffff~>@43333E@|R>@lE@>@ E@fffff=@ F@̌=@,.F@lo=@lXF@3=@hfff[F@1=@pF@ffff*=@ܿF@̬!=@F@=@-G@L=@hfffDG@2333=@hfff\G@=@}G@ =@4333ÑG@2333=@4333sG@2333S<@G@|<@G@ffffF<@4333G@2333à<@G@|<@̜G@2333<@YH@<@hffff"H@`<@43338H@<@?H@r<@4333BH@2333Z<@,PH@!<@ cH@ffff;@̌gH@Y;@jH@;@4333SgH@;@ fH@l;@hffftH@ ;@ H@p;@)H@9;@hffffH@2333#~;@iH@ p;@ H@|O;@H@2333S.;@4333H@&;@hfffH@2333:@9H@23333:@,I@2333:@<I@ffff֨:@hfff I@):@`I@:@ I@2333:@4333sI@ٛ:@I@:@,I@t:@̬I@g:@`I@N:@hfffI@̼:@PI@ffff:@I I@2333c:@hfffI@2333s:@ I@i:@` I@9@̬I@̼9@hfffFI@|9@hfffI@4333s9@$I@9@4333C:I@l9@hfffAI@4333N9@iGI@09@\UI@̼8@\I@8@hffffI@ 8@hfffmI@8@4333vI@Y8@hfff{I@8@I@43338@4333I@̌8@ɖI@433338@LI@4333s8@4333SI@y8@4333I@ 8@̌I@8@YI@dfffz8@I@4333#W8@hfffI@Q8@hfffI@dfffN8@4333sI@LI8@I@4333CI8@I@dfffB8@N`fff&*@N`fff*@2333N0333*@2333N*@ffffVNY*@̘N*@N`fff *@N@)@̪N0333c)@N0333c)@@N0333se)@Ng)@|N@h)@ffffΪNk)@ N`fff&p)@N`fff&u)@ԩN9x)@Ňx)@̌Nv)@LN0333q)@NYn)@N0333sk)@ffffNf)@̪N0333c)@Ih\Nhffffo+@qN/,@ ffffrN٤+@yNhffffo+@2333ÇN0333+@\N,+@2333#Nhfff+@2333N,@xNL%,@@ffffX8333=@48333=@1L=@ffff^=@ffff8333=@ffff:hffff=@v=@̄8333=@&>@hffff&>@@3333#5>@@3333hfffG>@ffff R>@@3333񿠙9\>@1̌i>@ffffLx>@ffff̌>@ z>@T`x>@@33338333>@Thfffơ>@@33338333>@@3333Y >@Vhfff>@ffff>@@3333hfff>@ffff8333>@zY>@@3333Zhffff>@%>@hfff&>@@333383333>@83333>@@3333>@ffff>@hfff>@,>@ffff3hffff>@@3333*8333s{>@@33338333h>@`E>@ffff;>@.>@@3333l$>@Ohfff>@@3333Uhfff>@J83333=@ffff =@ffff8333=@c=@@3333Q@=@@3333̌=@!8333=@[=@W8333v=@whfffc=@x̌Y=@U L=@ffffb83332=@ffff =@,=@8333S=@Q̬=@<@t<@83333<@q̌<@̒ch<@ͺHhfff<@ffffv<@ffffhfff& =@=@ffff̬=@l &=@@33338y==@ǨA=@ H=@@3333hfffV=@ffffw̌[=@ 8333I=@?=@@$A8=@)ZhfffD=@hfffZ=@Hhffff=@ffffw=@@3333}̬=@ffff8333=@4LxfD@f@3333vT@e3 +4=GU_fs{Y[7du(GU^{",7?JXbp(3GXw -BUku+:F^o{5=b@IE@=b@E@>b@E@1>b@ffffE@=b@3333{E@=b@ffffE@4333 S@`/X@̀S@hfffN5X@3333S@t5X@S@08X@S@`?X@ffffS@hfffBX@3333/S@dCX@]S@Y>X@3333#S@hfff6X@3333 S@4333Y@3333OS@hfffX@̀S@hfffNX@S@4333+X@ffff.S@`Y@S@hfff Y@S@8Y@S@4333Y@3333OS@4333c0S@\R@43333*S@ \R@S@ffffz^R@QS@̀aR@hfffS@ycR@4333 S@cR@4333c0S@\R@pT@ЅR@8T@̜R@T@لR@4333kT@YR@T@dR@yT@R@4333T@TR@4333T@R@T@ffffR@pT@ЅR@43330U@3333gR@x-U@ffffR@4333sU@ffffR@U@R@̔"U@3333cR@4333+U@ffffʠR@7U@ffffR@43330U@3333gR@̩U@;R@,U@R@ U@|R@hfffVU@ffffR@U@3333'R@U@)R@hfffVU@3333+R@IU@ffffJR@hfffU@tR@̌U@3333/R@)U@R@IU@ffffҽR@U@ffffR@̩U@;R@4333M@̈ST@iM@̴RT@ \M@TT@NM@UT@hfff6QM@WT@hfffpM@YT@M@tYT@4333M@ffffnWT@4333M@TT@4333M@̈ST@yf0eP@3333@e$P@EeP@3333Lel{P@3333MQe3333cwP@ffffRetP@3333SQetmP@QejP@ffffRUe3333gP@3333\e iP@ `ejP@ce3333{lP@lge(oP@3333letsP@3333}mesP@pnerP@lepP@ielP@3333Mdeffff2hP@ffffaeffff2cP@3333cce̴`P@ffffpeeffff"`P@fe-`P@keaP@neffffbP@Jye3333`P@3333}e_P@3333O~effff`P@3333~ebP@33335eHdP@|effffdP@ffffeDeP@PegP@3333e3333jP@ffffre)lP@ePlP@effffkP@3333ϑe3333+gP@Seffff_P@3333e3333_^P@ffff^e\P@ffffȉę\P@3333seffff*]P@3333ņeffff6[P@̢e`SP@eQP@ffff.eOP@3333We3333NP@3333me33333NP@ffffeffffNP@3333'effff*MP@ffff(eQ@yf0LF@a`@pTF@ ``@i`F@^`@dfF@i_`@3333lF@hfffa`@ffffqF@hfffb`@3333{tF@4333Kg`@uF@h`@3333wF@Ln`@}F@o`@ffffF@̄r`@̴F@s`@3333{F@t`@IF@4333w`@ffffF@py`@3333F@hfffB{`@ffff֩F@}`@ F@H`@3333;F@_€`@5M F@(`@dF@̌`@4F@|`@F@hfffz`@{F@4333`@lF@5`@3333 _F@d`@DVF@`@3333PF@`@̔MF@Ԉ`@HF@hfff`@CF@`@iNF@hfff`@ [F@ŗ`@xF@`@F@α`@ sF@hfff֚`@3333ӇF@p`@F@`@ԃF@``@3333F@`@3333F@`@8F@̠`@$F@`@ffffVF@4333`@3333F@`@3333F@``@ffff>F@4333`@fffffF@hfff`@3333[F@4333_`@@F@9`@3333F@hfff`@̼F@4333k`@|F@4333`@3333F@t`@F@4333`@DF@`@$G@`@G@l`@3333G@`@G@hfff`@̴G@`@ffffG@hfff`@'G@4333+`@3333+G@4333`@.G@``@7G@4333`@3333?G@`@NG@`@I[G@<`@mG@x`@pG@H`@3333yG@`@33333}G@a`@ԈG@x`@dG@hfff`@ܘG@43337`@ffffG@]`@ffffG@4`@3333#G@hfffR`@YG@hfffN`@G@`@G@=`@G@x`@3333CG@4333W`@G@`@ffffG@D`@3333G@L`@̜G@4333`@3333G@4333[`@̔G@4333`@G@`@3333G@`@H@4333_`@̜ H@hfff`@aH@4333k`@H@`@H@I`@ H@`@ffff.)H@̘`@3333{-H@`@ffff6/H@4333c`@/H@hfff`@.H@4333`@ #H@4333`@ffffH@X`@ffffH@`@p H@4333`@ffff H@`@ffff H@̤`@ffff>H@`@3333SG@4333`@TG@`@@G@a`@ffffG@4333`@ffff^G@=`@̄G@hfff*`@`G@4333˄`@ffffG@ y`@3333G@q`@LG@4333n`@ffff~G@8j`@)G@hfffc`@LG@hfff``@G@^`@3333G@]`@AG@4333K]`@G@([`@G@qW`@ffffvH@V`@ffffVH@0Y`@ffff H@̼Y`@ffff+H@hfffnX`@1H@hfffW`@ffff7H@U`@=H@S`@ffffIH@4333Q`@ffffMH@R`@ffffWH@S`@bH@4333Q`@3333;nH@hfff^K`@nH@EF`@!rH@0A`@3333s|H@\9`@tH@y5`@ffffH@2`@H@1`@fffffH@/`@ıH@hfff.`@ٱH@4333O,`@ٱH@4+`@aH@hfff)`@3333KH@4333'`@xH@%`@ѰH@#`@XH@"`@H@hfff `@H@hfff`@ffffvH@8`@\H@hfff`@3333SH@P`@3333[H@`@H@4333`@H@4333`@H@hfff`@ffffH@_@H@_@H@4333_@H@4333+_@ffffH@_@ffffNH@@_@H@(_@H@y_@ffffH@_@, I@hfff_@I@L_@8&I@̔_@,I@y_@a2I@_@33336I@hfff_@ :I@_@A?I@8_@iFI@43333_@OI@hfff_@ffffZI@_@3333+jI@hfffN_@1~I@0_@ьI@hfffV_@ffffI@и_@tI@hfff_@tI@\_@ffffNI@A_@I@4333_@ĴI@P_@YI@̌_@I@_@I@4333c_@|I@4333_@I@٬_@I@hfff֩_@I@̬_@I@_@J@(_@0J@D_@$J@hfff_@tJ@4333_@̬$J@)_@33333'J@_@3333s*J@hfffޕ_@ffffV.J@hfff_@3333+3J@4_@8J@_@ffff=J@q_@3333sBJ@hfff_@EJ@_@3333cIJ@hfff_@3333NJ@|_@ffffNRJ@4333_@4VJ@ك_@3333XJ@hfff_@[J@_@ffff^J@hfffF_@IbJ@4333C|_@|fJ@w_@ffffoJ@r_@3333rJ@n_@3333rJ@k_@$wJ@l_@hzJ@Dl_@yJ@i_@iJ@$f_@3333[J@b_@J@ [_@J@pN_@9J@D_@J@4333#>_@AJ@hfff:_@J@t8_@3333J@3_@!J@4333(_@ffffJ@_@dJ@_@ffffJ@hfff_@J@4333_@`J@ _@J@^@3333J@4333k^@hJ@hfff^@J@4333^@iJ@9^@3333cJ@4333S^@J@4333#^@J@^@ffffJ@^@̴J@I^@̴J@^@J@4333^@ffff~J@T^@33333J@hfff^@J@^@ɹJ@̜o^@J@4333Y^@̔J@?^@lJ@-^@ffffJ@hfff^@{J@hfff ^@kJ@ ^@3333dJ@hfff^@ffff[J@4333S^@3333QJ@hfff ^@ffffMJ@4333 ^@APJ@Y!^@NJ@hfff)^@HJ@,^@ffff.?J@)^@̬2J@hfff*^@3333c&J@hfff/^@LJ@/^@3333[ J@̜+^@̌I@̬ ^@̜I@4333+^@3333I@H^@3333I@4333]@I@4333 ]@ffff.I@l]@I@hfff]@ɍI@hfff]@3333ۃI@4333]@0yI@]@3333{nI@]@ffffcI@hfff]@ffffYI@]@3333#QI@hfff]@ffffGI@`]@=I@hfff]@\7I@y]@3I@H]@ffff0I@L]@L-I@)]@̴#I@hfff]@I@]@I@p]@ffffI@]@3333KH@a]@ffff>H@hfff]@H@]@̬H@hfffw]@H@t]@3333H@4333l]@ffffH@^]@H@O]@3333H@4333cA]@3333H@8]@pH@4333+]@qH@4333k(]@3333CH@hfffF#]@H@y]@1H@ ]@0I@̜]@aI@4333C\@H@\@H@\@H@\@iH@x\@H@\\@̴H@\@tH@hfffF\@3333I@hfff6\@̼I@4333K\@ffffnI@\@I@1\@3333sI@t\@I@\@3333 I@4333\@ #I@1\@ffff I@hfff\@4I@dx\@ I@n\@I@d\@ffffI@4333\\@ffffH@4333kT\@H@J\@ H@E\@̤H@hfffC\@H@̌:\@H@̜3\@H@,\@ffffH@̬\@3333#H@4333\@ffffH@\@LH@hfff[@@H@hfffV[@H@4333[@H@[@ffff.H@4333[@33333H@y[@3333۫H@4333[@̌H@[@3333H@[@DH@l[@LH@4333c[@̜H@[@H@a[@(H@[@H@4333ˌ[@ЕH@hfff[@QH@hfffp[@H@hfffa[@3333H@ ][@ffffH@hfff&O[@ffffުH@:[@H@.[@ffffH@hfffF'[@QH@p![@ffffH@4333 [@̼H@4333 [@,H@hfffF[@H@)[@H@̜[@H@Z@ffffH@4333Z@3333sH@Z@H@Z@̬H@Z@\H@Z@QH@4333[Z@H@aZ@ffffH@hfff6Z@3333KH@hfffZ@̤H@(Z@9I@4333Z@ I@hfff>Z@,I@4333Z@I@4333Z@3333(I@4333äZ@ffff*I@̔Z@ffff(I@Z@&I@HZ@*I@hfffZ@/I@4333xZ@33333I@4333SlZ@33335I@bZ@3333{8I@̌XZ@3333Z@33331I@+Z@+I@4333+&Z@(I@Z@0'I@hfffZ@<#I@4333Z@3333sI@ Z@I@ Z@ffffI@XY@!I@4333Y@ffffI@hfff^Y@I@IY@I@Y@̼I@4333Y@I@Y@I@4333{Y@3333I@hfffY@3333!I@YY@ffff6%I@hfffY@3333{&I@Y@*I@Y@3333.I@4333Y@ffff1I@hfffY@ ;I@4333 Y@ICI@ Y@DI@Y@EI@tY@JI@IY@Y@3333cI@hfffY@)I@4333#Y@ffff>I@4333~Y@I@hffftY@I@dY@̻I@]Y@YI@hffffXY@I@|SY@ļI@INY@3333I@hfffvEY@I@9Y@XI@|-Y@ffffI@Q"Y@3333SI@4333Y@I@hfffY@3333kI@hfff6Y@YI@X@̴I@lX@I@X@I@9X@ffff>I@X@0I@ X@ffff6I@hfffFX@3333I@X@ffffvJ@1X@J@QX@ J@)X@3333J@PX@J@\X@ffffI@hfffX@I@hfffX@̌I@4333X@3333I@hffffX@ffffNI@X@9I@43333X@ I@4333X@I@ыX@,I@X@I@hX@I@hfffNX@3333CI@|X@I@hfff{X@ffffI@Y{X@I@hfffzX@3333I@4333KzX@$I@|uX@̜I@tX@~I@4333vX@xI@hfffzX@ffffqI@}X@ffffvmI@̴}X@hI@}X@3333sbI@4333X@YI@X@3333RI@ X@IMI@HX@ffffHI@X@QGI@4333X@ADI@4333X@T>I@X@$6I@X@ffff&I@̌X@$I@4333X@I@hfff·X@̤ I@hfffX@ffff I@@X@3333I@{X@ffffH@hfffvX@0H@hfffFrX@ffffH@ nX@H@iX@H@eX@3333H@̜bX@3333H@hfffZX@3333H@hfffWX@H@YMX@3333H@4333HX@H@@FX@3333 H@$CX@9H@hfff?X@H@̌-X@ffffH@(X@H@L&X@pH@"X@ffff>H@hfff^ X@H@X@̬H@dX@H@)X@XH@4333X@ H@hfff&X@H@1X@ffffH@0X@H@TW@ffffH@4333W@H@W@3333H@hfffW@I@̄W@I@LW@ffffH@LW@H@4333sW@3333H@hfffFW@0H@hfffW@yH@hfffW@H@4333W@H@!W@̼H@hfffW@H@4333W@ffffI@W@I@4333W@3333+I@W@I@4333;W@I@XW@ I@4333#W@A I@̟W@I@XW@ffff6I@̜W@ffffI@4333W@dI@43333W@ffff&I@pW@33333I@hfff^W@tAI@W@8GI@لW@3333SII@YW@HI@rW@II@hfff^jW@ffffJI@ hW@3333JI@`W@yLI@XW@3333MI@PQW@3333NI@hfff>NW@3333MI@FW@LMI@@W@SI@ >W@33333[I@4333=W@Y_I@hfff>V@3333H@U@̼H@4333?U@QI@4333S?U@I@4333#;U@3333C I@5U@ I@hfff&U@I@U@I@U@̜I@U@̜I@U@$I@4333s U@ffff7I@4333C U@BI@4333[U@hMI@hfff&U@3333VI@|T@(cI@hfffT@̴hI@T@ffffqI@hfff6T@ffffwI@hfffT@ffffNI@̄T@ffffNI@AT@ffff~I@T@zI@4333;T@rI@ѺT@QrI@T@YrI@T@3333KoI@YT@iI@hfff&T@bI@̜T@!]I@4333T@ffff^I@T@ffff\I@hfffFT@ZI@{T@bI@!pT@aI@hT@3333^I@]T@3333^I@̜[T@̴bI@hfff\T@ffffniI@4333\T@ffff~oI@@ZT@3333stI@XT@ffffnzI@lTT@3333{I@GT@ yI@4333DT@|I@hfffDT@I@1GT@3333CI@hfffIT@3333ÒI@$HT@tI@hfffAT@ėI@=T@3333KI@;T@3333I@hfff&8T@ffffI@ 4T@II@hfff/T@ffffI@)T@I@&T@3333I@hfff>#T@I@lT@3333әI@̬T@xI@T@tI@T@3333ۋI@T@I@T@ yI@T@̤uI@hfffNT@YvI@T@̴tI@$T@ffffmI@hfffT@̄kI@̜T@TgI@8T@ aI@hfffS@$cI@S@LzI@S@3333{I@yS@aI@S@ffffI@̄S@ffffI@hfff~S@J@,S@3333-J@hfffnS@QJ@̬S@wJ@$S@(J@ wS@tJ@)sS@J@mS@J@^S@ؿJ@yHS@ffffJ@hfff4S@LJ@$S@̤J@hfff S@!J@hfffS@3333K@YS@3333K@4333S@K@S@dK@)S@K@hfff,S@3333[K@hfff~2S@33333)K@hfff5S@8K@0S@33337K@d'S@̌1K@"S@,K@hfffS@*K@S@ffff'K@hfffS@!K@\R@K@XR@K@ R@ K@4333R@y K@4333{R@K@R@K@!R@,J@R@hJ@hfffVR@J@4333KR@J@R@J@4333cR@J@̜R@J@R@J@̌R@ffffFJ@yR@ffff~J@hfffƙR@J@R@3333kJ@R@̌J@pR@J@dR@3333CJ@vR@3333SJ@4333nR@(J@hfff&iR@3333J@4333^R@J@4333 ZR@IJ@WR@)J@)WR@3333J@4333TR@ffffJ@IRR@J@SR@ffffJ@YR@ffffJ@xcR@$J@4333skR@J@4333mR@3333J@mR@lK@hfffjR@ K@̌gR@K@eR@K@\`R@J@\XR@ffff>J@4333QR@QJ@hfffNR@J@4333GR@J@:R@̼ K@l/R@K@4333'R@1K@4333K%R@K@$R@3333 K@hfff$R@3333;K@Y&R@3333K@%R@3333{J@!R@ffffJ@R@ffffJ@R@3333sJ@4333R@ffffK@R@K@hfffR@9K@9R@"K@ R@ffff)K@hfffR@3333{'K@43333R@ffffK@IR@3333SK@4333Q@YK@hfffVQ@K@Q@DK@hfffQ@)K@`Q@X!K@̼Q@.K@9Q@3333K:K@0Q@DK@Q@ffffLK@Q@ffff[K@yQ@yK@@Q@aK@̔Q@lK@Q@ffffޱK@43335Q@ffffޭK@-Q@|K@hfff!Q@8K@Q@3333K@4333SQ@K@43333 Q@K@4333kQ@K@hfffQ@ffffK@hffff Q@3333cK@ Q@}K@Q@3333zK@(P@3333zK@P@ffffxK@`P@3333oK@P@`mK@xP@ffffjK@4333KP@3333dK@IP@3333s^K@4333P@3333[K@@P@lUK@}P@3333kTK@4333zP@ffffXK@LmP@1OK@hfff^P@OK@[P@KK@43333XP@@HK@8TP@FK@1OP@ffffBK@LLP@ffffv8K@JP@̤.K@EP@3333+K@̴?P@33333/K@P;P@2K@43333P@,/K@)P@ffff-K@4333!P@3333[.K@̄P@,1K@4333 P@x,K@hfffP@ffff&K@dP@ffff#K@@P@0"K@lO@DK@PO@\K@hfffO@!K@O@hK@4333O@3333sK@hfffvO@K@|O@K@43333O@3333K@hfffvO@x K@PO@ffffK@LKO@K@?O@K@hfff&O@ffffVK@LO@ffffnJ@)N@)J@N@ffff&J@N@YJ@hfffN@ffffNK@4333N@ffff~K@hffffN@ffff^J@|N@J@|N@J@|N@qJ@iN@J@hfff&~N@ffff&J@`}N@̔J@̜N@3333J@̼N@ffffJ@hfffN@XJ@yN@$J@N@ffffFJ@4333sN@J@yN@3333J@hffffN@33333J@пN@ J@4333SN@XJ@4333N@̜J@LN@3333J@̗N@ffffJ@hfff֔N@3333J@N@J@̧N@9J@N@̤J@N@yJ@hfffvN@ffff>J@4333N@3333CJ@O@ffff΍J@` O@YJ@hfff O@J@O@{J@4333N@xJ@̼N@3333[zJ@4333N@|J@LN@@}J@LN@|J@|N@~J@4333N@y|J@hfffրN@xwJ@xN@nJ@hfffVrN@3333hJ@4333fN@3333S_J@ cN@VJ@ iN@HJ@`}N@2J@LN@ffff+J@4333xN@#J@ jN@J@UN@ffffNJ@?N@3333J@hfffv6N@3333J@N@3333#J@4333cN@I@N@tI@4333N@I@4333#N@I@1N@I@̌5N@I@|;N@YI@PN@I@̜|N@ffffI@hfff&N@̬I@hfffN@ffffI@yN@I@hfffN@ffffI@N@̌I@4333N@fffffI@N@I@hfffN@~I@ٱN@ffff6nI@ N@,cI@̜xN@ffffYI@QN@TI@hfffAN@UI@`6N@ffffVI@$N@!ZI@hfffN@bI@YN@ffffjI@N@fffflI@̬N@3333{kI@4333CM@ffffNfI@4333M@XXI@M@JI@hfff&M@EI@4333M@ffff?I@M@3333kAI@M@JI@`M@YMI@hfffM@iOI@M@ffffRI@L@I@̬)L@wI@lL@lI@` L@\cI@\L@T[I@K@ffffSI@K@MI@hfffK@3333JI@iK@MI@9K@(UI@K@3333S_I@hfffK@ToI@oK@ffff~xI@4333]K@I@ RK@3333{I@hfffVIK@~I@hfffEK@yI@hffffHK@̤tI@MK@pI@hfffQK@cI@43333SK@TI@lQK@KI@PLK@|FI@4333GK@̔DI@9BK@DEI@YI@4333sdH@ffffI@4333hH@ I@kH@ffffI@hfffgH@0H@hfff&aH@3333H@LH@ffffH@hfff7H@ H@*H@3333H@hfffH@IH@hfff6H@)H@hfffH@3333 I@G@3333#$I@hfffVG@a0I@G@4I@hfffvG@̌3I@G@-I@,G@(I@ɩG@3333#I@G@ffffI@G@3333I@ɥG@|I@ɟG@I@hfffG@33333H@~G@ffff&H@qG@ffff6H@\iG@IH@fG@H@,mG@H@ zG@TH@4333SG@ffffH@4333G@G@0H@8G@̬gH@ G@ _H@ G@4333WH@ G@WH@ffffG@ ZH@F@4333_H@F@4333c]H@3333F@hfffFXH@ffffF@hfffQH@F@hffffKH@F@hfffDH@F@hfffV>H@F@ H@ffffF@`H@ffffVF@4333H@IF@4333CG@ffffF@G@ffff>F@̼G@F@,G@F@G@F@yG@0F@4333G@3333KF@\G@3333F@LG@F@G@F@hfffG@ffffF@G@ffff־F@̌G@@F@,G@ffffnF@G@F@G@3333F@hfffG@ffffޛF@G@!F@YG@3333F@̬G@|F@G@ffffsF@G@3333hF@hfffG@@kF@`G@3333#pF@}G@̬iF@̌zG@3333+dF@̬kG@[F@̬`G@ TF@[G@GF@hfffZG@l@F@hfffF\G@9F@4333c`G@5F@hfff6uG@ffff1F@hfffG@+F@4333G@ffff~!F@lG@F@LG@33333 F@hfffFG@ffff&E@G@3333E@E@4333G@3333۰E@|G@E@hfffG@E@IG@|E@4333G@E@hfffG@3333{E@4333CG@̤sE@4333G@gE@hfff&G@!WE@hfffG@RE@4333CG@ffffNE@4333C H@ffffF-E@4333CH@)E@&H@D E@ 1H@ D@43336H@DD@hfff=H@3333D@4333SIH@D@4333cBH@D@ 7H@D@2H@3333 D@)&H@3333D@hfff6H@ D@,H@ffffD@YG@D@9G@3333;D@@G@D@G@3333D@4333G@QD@G@ffff&D@lG@TD@hfffFG@QD@@G@ffffD@0G@D@LG@33333D@p~G@D@hfff&wG@D@̬iG@(D@_G@3333D@\XG@iD@NG@ID@ IG@iD@̬FG@D@4333DG@iD@hfff7G@3333 D@̬4G@3333D@hfffF"G@D@9G@̴D@4333sG@3333D@43333G@ffffE@F@E@hfffF@ E@IF@3333E@F@ffffVE@̼F@@E@0F@3333 E@F@ffff-E@ F@ffff G@4333?C@ffff G@Y(C@G@4333 C@y2G@ B@1G@B@4G@B@3333DG@B@lQG@hfffB@ QG@hfffB@3333OG@iC@hXG@pC@3333YG@hfff+C@3333VG@ @C@3333TG@hfffv>C@]G@hfff&8C@3333hG@̼PC@oG@fC@sG@9C@G@hfffC@ffffG@C@3333G@C@G@LC@G@ C@iG@ C@آG@4333vC@|G@hfffUC@lG@hfffFC@ffff>G@yRC@)G@hfff6^C@0G@hfffaC@|G@4333IC@3333G@ >C@xG@pC@̴G@YC@3333[G@hfffC@ffffnG@PC@3333;G@hfff!C@TG@#C@(G@#C@iG@C@3333ӤG@C@G@hfffC@G@0C@G@4333#C@ԯG@hfff C@XG@ !C@aG@$C@3333G@hfff6/C@3333G@hffffAC@3333G@RC@H@hffffC@3333H@C@3333H@4333B@3333kH@4333#B@ffff I@4333sB@3333I@B@3333[%I@,B@̜+I@ B@33334I@B@t5I@B@ffff2I@hfffB@1.I@̐B@ffff,I@hfff~B@ffffv+I@)aB@3333[%I@4333#YB@̄I@IOB@I@4333GB@I@?B@ffff#I@hfff6/B@ffff%I@,'B@ffff#I@hfff&B@'I@@B@/I@hfffB@3333K4I@B@5I@4333A@33337I@A@3I@A@XI@A@4I@`A@I@<A@pI@#A@I@43333#A@3333I@lA@ffff~I@pA@I@A@ffffI@hfffA@3333I@A@I@hfffA@ffffI@A@ffffI@̜A@3333I@̌0A@ffffI@̌3A@I@2A@I@yA@dI@hfffA@ffffJ@hfff@@0 J@@@fffff(J@@@!,J@4333@@3333*J@hfffֹ@@*J@@@A-J@@@3333+J@)s@@ J@9g@@ffffV J@̜R@@#J@4333A@@ffff~'J@̼7@@3333S'J@hfff2@@̼%J@hfffv.@@"J@43333$@@J@@@ffff J@hfff@@yJ@4333S@@3333J@L?@J@hfff&?@3333 J@L?@ J@l?@ J@83333?@3333J@̰?@ffff>J@`?@!J@?@t$J@̓?@'J@?@6J@hfff?@(DJ@̬?@EJ@8333?@ffffQJ@?@pYJ@@?@]J@?@ffff.aJ@?@,fJ@Yq?@PnJ@`Z?@3333{wJ@̌K?@~J@@B?@3333#J@̌M?@3333ˇJ@8333S]?@ɑJ@lc?@J@j?@J@ ?@3333J@8333?@J@Y?@3333J@hfff?@̒J@hfff?@J@@@3333sJ@,@@3333J@hfff @@ffffnJ@6@@J@4333<@@J@I@@J@|R@@J@hfff&Z@@ J@Z@@3333J@lZ@@J@hfffW@@\J@<@@3333J@8@@$J@l6@@3333J@9@@J@9@@J@hfff@@J@?@J@ ?@ffff^J@8333?@̼J@8333s?@pJ@hfffF?@ffffJ@y?@K@8333s?@ffffK@?@(K@?@3333;K@8333Sg?@K@8333L?@ffffV%K@>?@!2K@L/?@33339K@hfff&?@3333>K@?@0BK@hfff'?@33333NK@8333&?@3333 PK@ ?@SK@8333>@3333YK@>@AdK@>@3333+gK@8333>@33333nK@8333s>@ffffuK@hfff>@ixK@L>@ffffvK@L>@@̜K@>@K@>@̬K@>@3333KK@,>@ffffFK@>@!K@̌>@ffff޲K@hfff>@ffff>K@hfff&>@ffffK@>@ffffVK@ >@3333K@>@K@>@K@̌>@ffffK@hfff&>@HK@83333>@3333K@8333y>@hK@t>@ffffK@;>@0K@ >@K@=@1K@8333=@K@=@ffffK@=@̜K@@=@ffffK@L=@ffff&K@8333s{=@K@i=@K@yZ=@fffffK@hfff_=@K@e=@ffffK@hffffe=@3333K@`=@(K@8333sH=@3333K@`=@̴L@ =@L@̌<@DL@8333s<@ffffK@hfff<@IK@ٰ<@ffffVL@ <@L@`<@ffff L@83333h<@d L@`d<@ L@P<@L@hfffH<@(L@%<@3333KL@`,<@\L@3<@T!L@83331<@d(L@8333S+<@̄1L@`<@ffff^AL@hffff<@EL@<@LL@;@RL@;@3333ZL@`;@3333^L@̬;@ffff~iL@@;@lL@ ;@1}L@hfff;@ffffL@hfffF;@3333KL@hfff;@\L@̌;@L@;@̴L@ ;@3333L@;@L@9;@ffffL@hfff;@3333L@ق;@3333 L@@x;@3333L@Z;@L@8333Z;@pL@,_;@hL@hfffff;@YL@8333};@3333L@hfffƃ;@L@hfffƊ;@3333SL@;@ffffL@hfff;@L@L;@3333sL@;@3333+L@8333Ӹ;@ffffL@hffff;@L@hfff;@M@Exm;@_RM@hfff;@ffff^M@;@L@8333;@L@;@L@83333;@L@;@ffffL@ <@3333L@8333S+<@ffffL@83333&<@L@8333<@M@;@M@y;@4M@;@ffffM@;@YM@̌;@ffff~M@8333;@3333 M@,;@8'M@8333s;@7M@8333S;@19M@ ;@>M@L;@!IM@;@fffftM@ٮ;@d}M@:;@*JF}M@8333;@M@y;@M@;@M@,;@M@83333<@ffffM@ <@ffffM@8333<@M@ <@ĭM@̬&<@M@ "<@M@<@M@83333<@M@`<@M@ <@ffffM@8333<@M@<@ M@8333!<@̬M@hffff6<@M@hfffU<@̤M@yl<@ffffM@83333t<@9M@hfff<@ffffM@<@ffffM@hffff<@AM@<@M@<@M@hfffF<@iM@l=@fffffM@@=@M@8333%=@M@8333s=@3333SM@`>@M@hfff&(>@M@83333,>@3333M@Y>@TN@ =@`N@L=@xN@=@N@=@ffffN@8333^=@̄N@8333=@N@ <@p*N@hfff<@ 0N@8333<@=N@}<@3333#EN@Y<@>N@<@|EN@̌<@4NN@<@ffffSN@hfffF<@VN@hfff-<@ffffIN@83333;@DN@hfff&<@x_N@Lh<@ffffrN@t<@ffffuN@8333s<@zN@8333<@\N@83333<@̄N@83333<@3333N@l@=@ffff֤N@ ~=@ܸN@8333S=@)N@̬=@ffffN@hfff=@N@̌>@N@8333sN>@N@z>@3333O@̐>@TO@̌>@q)O@/?@ffff=O@ I?@ffffHO@hfffa?@XO@8333o?@XcO@8333?@TqO@Y?@uO@`?@HzO@o?@O@83333V?@ffffO@Y??@)O@L.?@O@̌>@3333{O@>@pO@hfff&k>@̄O@,>@1O@8333=@O@ >@O@83335>@3333O@8333Sj>@HO@>@QP@̬>@ffffP@hfff&>@ P@hfff>@ P@hfff|>@3333#P@d>@3333P@̬>@ffffnP@ >@`P@8333=@!P@L=@#P@>@A)P@L >@ ,P@9>@ffff.P@hfff>@ffff0P@=@y3P@=@ 6P@83333=@ffffZ:P@̬=@ffff=P@8333ә=@ @P@Y=@3333BP@8333S=@$EP@8333=@FP@8333=@HIP@=@KP@=@ffffMP@83333=@TNP@hfffƜ=@ffffOP@hfff=@ffffOP@=@3333PP@=@̐UP@`=@L^P@hfff=@fffffdP@hfffF=@gP@8333S=@hP@8333=@xjP@l>@jP@hffff>@̠kP@L>@3333{nP@hffff>@ffffVrP@hfff=@xP@hfffF=@ԅP@8333=@TP@=@P@=@P@9=@ffff֖P@Y=@$P@v=@3333P@hfff_=@}P@8333K=@3333P@8333=@YP@8333=@ffffP@̬=@̈P@hfffF=@$P@L>=@ffff.P@@c=@P@=@ffffP@hfff&=@ffffJP@8333=@ P@8333=@P@̬=@P@8333S=@AP@83333=@ffffvP@hfffX=@Q@ =@̌Q@hffff<@% Q@hffff<@|Q@x<@AQ@8333z<@h"Q@hfff<@3333_1Q@8333<@4Q@<@33335Q@̬<@6Q@<@d7Q@t<@33337Q@j<@9Q@hfff<@h;Q@83333<@=Q@ <@ffff@Q@@<@hAQ@Y=@ffff2CQ@+=@DQ@5=@5FQ@`Z=@QQQ@hffffc=@SQ@,=@WQ@y=@ffffYQ@Y>@[Q@!>@ffff]Q@)>@ffff`Q@/>@̼bQ@L2>@(eQ@hfff(>@PhQ@ .>@hQ@@:>@hQ@83333a>@leQ@̌>@bQ@8333>@3333aQ@Y>@ubQ@̌>@3333cQ@hfff&>@fQ@8333>@ffffiQ@hfff>@$rQ@̬ ?@3333;qQ@hfffs?@ffff"lQ@hfff?@fffflQ@̌?@$nQ@?@5tQ@ ?@3333?uQ@y?@sQ@@@uuQ@hfff&?@}zQ@ ?@}Q@ 2@@̘wQ@`H@@sQ@x@@ffffpQ@@@33337nQ@̜@@jQ@P@@3333hQ@ u@@fffffQ@̌`@@fQ@@@3333#kQ@hfff @@|hQ@hfff@@3333/fQ@P*@@xcQ@Y0@@^Q@4333Q@@3333S_Q@ q@@ffff~]Q@@@ffff^Q@@@̄\Q@hfffx@@̈XQ@L}@@ffffWQ@@@`[Q@4333C@@3333o\Q@hfff&@@3333g[Q@Y@@4XQ@@@-TQ@ܴ@@QQ@4333@@IQ@4333#@@ffffzGQ@4333@@eDQ@̬@@HFQ@4333÷@@XHQ@4333C@@RQ@@@3333SQ@\A@ffff TQ@hfff&-A@3333cSQ@hfffnA@̘NQ@9A@(NQ@4333A@NQ@ٝA@3333PQ@A@̠QQ@A@ELQ@4333#OB@8@Q@4333B@L,Q@hfff-C@Q@7C@ffffQ@4333TC@Q@PZC@Q@pjC@3333Q@4333C@3333Q@4333cC@Q@hfffC@-Q@hfffC@a Q@hfffC@3333 Q@4333C@TQ@4333D@Q@4333sD@HP@0D@=P@LCD@ffffP@ TD@ffffP@hfffbD@P@4333{D@P@̇D@mP@4333#D@̴P@4333#D@P@D@3333P@D@3333kP@YD@P@hfffFD@P@0D@P@4333BD@P@9 D@ffff2P@C@3333sP@4333SC@3333kP@43332C@ P@IB@ffffP@iB@3333KP@̼B@3333gP@}B@qP@̌bB@ɒP@/B@XP@A@TP@hfffA@3333oP@̌iA@P@NA@УP@hfff=A@8P@43332A@ffff>P@hfff&7A@ffffNP@9A@P@4333A@ffffP@4333c@@3333;P@9@@P@hfff6@@33337P@@@3333P@4333@@ffffP@9@@3333P@@@@!P@|l@@`P@Pq@@P@w@@ffffP@03@@P@83333?@TP@hfff?@3333OP@@@3333?P@+@@XP@ @@@3333?P@Y;@@̤P@W@@3333P@̼m@@ͯP@4333cn@@3333+P@v@@P@@@P@@@P@i@@ffffP@4333ӛ@@ffffP@@@ffffP@4333C@@3333+P@hfff@@TP@@@̜P@ @@33333P@hfff&@@3333P@9@@33333P@@@3333P@lA@ffffjP@,3A@8P@̌XA@3333|P@hfffdA@TwP@hfffeA@3333?tP@4333scA@3333+qP@ ^A@mP@hfff[A@jP@NA@ffff`P@hfffEA@ffff:]P@hfff4A@TYP@DA@QP@hfffUA@ffffJP@fA@ffff?P@iA@i:P@4333jA@ffff63P@4333yA@a0P@hfffsA@ffffF/P@mA@ffff:-P@LoA@3333#P@hfffA@,P@\A@4P@LA@1P@4333A@ffff6P@A@ffffvP@B@ P@hfff&B@33333P@hfff.B@ffff.P@\[B@O@4333|B@3333kO@hfffB@3333O@B@O@4333SB@3333[O@hfffB@|O@ C@3333P@hfffC@3333P@4333B@@ P@4333B@|P@B@qP@B@hP@B@P@B@0P@4333B@$P@,B@ffffNP@ybB@3333+P@hfffOB@0P@4333JB@33332P@̜CB@3333;6P@lDB@ffffF@ffffP@43337F@3333۲P@43336F@P@43333F@DP@Y%F@`P@hfff F@P@|E@ffffP@hfff&E@IP@E@P@̜E@P@F@P@F@P@4333F@3333Q@`F@4Q@F@ffff Q@43333F@=Q@hfffF@3333Q@hfffE@ffff&Q@4333ӭE@̰(Q@hfffE@+Q@hfffE@+Q@iE@ffff+Q@hfff&F@ #Q@pF@"Q@F@%Q@|F@ffff"Q@,F@3333Q@hfffFG@Q@7G@3333Q@WG@P@`XG@3333SP@hfff6G@3333P@LG@\P@̬F@|P@4333F@ffffP@@xF@ffffP@ysF@pP@@xF@3333sP@hfffƑF@8P@hfffF@P@4333SF@ffffNP@4333SF@3333P@hfff6F@P@ G@P@&G@P@i9G@ffffjP@hfff?G@ffff6P@4333FG@ffffjP@lXG@մP@̌G@ffffP@4333G@uP@4333G@P@PG@P@lG@P@@G@P@G@3333P@hfffG@3333cP@̬#H@P@SH@3333P@hfffjH@P@`pH@ffffP@aH@P@ YH@3333P@̌`H@3333WP@kH@P@zH@̤P@H@̴P@43333H@3333+Q@I@8 Q@5I@ Q@hfffYI@UQ@`kI@eQ@ I@@Q@hfffI@Q@I@|Q@4333SI@3333{"Q@ J@̤"Q@|J@ "Q@hfff$J@fffffQ@J@ffffQ@|J@Q@,!J@uQ@@)J@Q@hfff2J@ffffQ@K@ffff?Q@)0K@ffff=Q@J@M;Q@J@:Q@,J@ffff8Q@4333J@ffff7Q@@Q@hfffVM@3333c@Q@M@ffff>>Q@M@\9Q@hfff6M@`6Q@lM@A/Q@0M@3333W-Q@|M@ffff>,Q@`M@q'Q@̬M@pQ@hfffƧM@ffffQ@YM@xQ@4333M@̀Q@M@3333WQ@M@XQ@M@Q@ M@ffff*Q@M@ Q@̼M@3333&Q@M@4-Q@4333N@,Q@̜>N@3333.Q@QN@ffff^2Q@hfffVhN@3333K9Q@wN@3333'?Q@hfffmN@PIQ@UN@ffffGQ@,+N@@]Q@hfffN@eQ@4333c#N@iQ@4333GN@3333OlQ@hN@tQ@\tN@33337vQ@ N@ffff~vQ@N@pQ@PO@3333oQ@4333CO@8kQ@0 P@8bQ@hfff%P@[Q@l;P@3333TQ@\9P@OQ@BP@DQQ@TP@3333LQ@aP@KQ@hfffoP@xHQ@4333tP@DQ@lP@3333SBQ@hffffP@ffff=Q@P@P@Q@PP@ffffQ@4333P@Q@`P@3333Q@ P@3333Q@P@Q@9P@3333GQ@P@Q@,P@ffffQ@4333P@Q@P@ffffbQ@hfff6P@3333WQ@P@3333Q@P@3333Q@hfff6P@Q@4333SP@3333Q@P@5Q@(P@Q@P@ffffQ@̌P@3333CQ@̬P@ffff^Q@hffffP@Q@4333;Q@3333Q@4333 Q@Q@&Q@R@5Q@3333R@BQ@*R@ YQ@3333'=R@(gQ@>R@plQ@>R@`mQ@5=R@)jQ@3333;R@IiQ@q9R@@oQ@33338R@xQ@|8R@Q@̬9R@Q@8R@4333Q@y:R@|Q@9R@hfff~Q@u4R@hfffvR@ffff5R@R@̔2R@(R@/R@3R@@,R@d2R@R@00R@ffffR@hfff'R@R@hfff$R@R@R@Q@4333R@3333Q@LR@Q@hfff^Q@Q@Q@ffffQ@Q@EQ@4333R@̠Q@4%R@Q@hfff-R@Q@4333.R@Q@,R@DQ@)R@љQ@hfff#R@Q@4333 R@̘Q@hfff!R@ffff Q@\&R@rQ@hffff'R@ffff^Q@4333#R@8XQ@4333!R@3333IQ@!R@3333'EQ@$R@3333=Q@i+R@7Q@hfff3R@,4Q@4LR@<-Q@4333cR@$Q@4333dR@ffff"Q@hfffeR@3333Q@hfff]R@Q@ QR@Q@HR@3333 Q@HHR@Q@4333KR@ffffFP@̼IR@\P@hfffFDR@P@P@hfffQ@P@Q@3333P@4333+Q@ffffrP@4333SQ@ĪP@YQ@3333۬P@4Q@3333P@hfff^Q@DP@Q@=P@iQ@̠P@4333#Q@P@Q@3333GP@hfff|Q@ffffP@4333#xQ@P@4333coQ@ffff"P@MQ@P@ EQ@8P@@Q@tP@hfffFCQ@ P@EQ@3333OP@hfff6IQ@P@pLQ@P@hfff^ZQ@P@lQ@3333P@~Q@̰P@Q@P@PQ@3333wP@Q@P@43333Q@\P@Q@ffffʏP@4333SR@ffff6P@̔R@AP@4333R@3333kP@hfffR@P@UR@3333P@hfff`R@P@rR@3333P@xR@pP@hfffR@P@ĄR@̀P@DR@tP@@R@ P@4333cR@pP@hfffαR@P@R@̴Q@yR@ Q@R@eQ@ R@3333Q@ȞR@3333+*Q@R@0Q@R@ffff&7Q@4333R@̬9Q@S@ffffr>Q@9S@t?Q@4333cS@>Q@&S@ffffr9Q@4333 /S@̸1Q@hfff&GS@(&Q@4333COS@ Q@̴PS@ffff2Q@hfffOS@9P@)KS@3333P@hfffTS@P@QYS@3333P@eS@ffff6P@4kS@P@aqS@3333P@4333S@P@4333S@P@ S@P@hfffθS@=P@4333S@eP@ȣS@3333P@QS@ffffjP@hfffeS@3333P@IaS@33337P@LbS@}Q@̌jS@3333/ Q@ppS@3333;Q@wS@Q@S@3333Q@4333[}S@!Q@ zS@Q@ArS@Y(Q@̤iS@33339Q@]S@9Q@4333US@ffffZ=Q@hfffF)S@3333GQ@S@3333 OQ@R@PQ@R@EOQ@lR@qGQ@hfff&R@EQ@4R@@IQ@hfff~R@ffffVGQ@uR@ffff*IQ@̤qR@LQ@yR@ZQ@4333KuR@@`Q@4333sjR@ffff~gQ@cR@3333CmQ@eR@dsQ@!uR@ffff>Q@hfff{R@ffffvQ@4333;R@ffffQ@R@ Q@hfffR@ԩQ@nR@eQ@hfffdR@3333Q@hfffv`R@Q@`WR@3333wQ@IR@3333Q@̄ER@yQ@hfffjR@Q@ |R@3333Q@4333R@LQ@LR@3333Q@hfffvR@R@R@D R@hR@ R@R@3333R@hfff6R@R@R@3333#R@4333R@̤'R@hffffR@ffffr-R@4333[R@3R@4333[R@̨5R@LR@̤6R@R@33336R@4333R@2R@dR@3333+R@R@0%R@R@3333 R@R@3333CR@zU@XR@|U@33337]R@hfffU@_R@U@9aR@U@8bR@U@hdR@U@\gR@U@mR@hfffU@`pR@hfffU@3333sR@4U@3333GuR@U@%vR@4333kU@U@xR@hfffnU@ffff:R@rU@IR@hfff^xU@`R@ăU@3333R@hfffU@yR@U@W@ffffS@hfffFW@3333S@PW@ffffRS@4333WW@ffffrS@iW@3333wS@uW@|S@̌W@S@٘W@S@hfffnW@S@hfff֤W@ffff S@hfffvW@DS@hfffW@3333S@ W@S@W@=S@X@3333?S@4333W@ffffS@W@R@4333W@R@4333W@DR@̌ X@3333[S@p&X@ffffZR@i"X@R@X@ R@D8X@ffffR@hfff&MX@ffff2S@qVX@3333#S@4333_X@R@hX@S@hfffjX@ffffS@hfffzX@̬S@HX@ffffS@tX@ffff S@4333X@ffff S@hfff^X@S@\X@ffffVS@X@H S@X@ffff^ S@4333X@3333S@hffffX@DS@qX@ffffS@hfffNX@3333S@X@4R@̌X@R@LX@3333gR@4333X@R@X@R@43333X@\R@|X@R@4333X@3333S@yX@3333_S@4333{X@3333S@X@̘S@ X@ffffS@X@3333S@̤X@̜ S@X@,S@4333X@ffffZS@Y@ffffS@6Y@̜!S@4333CY@3333S@4333SY@ffffS@AfY@S@4333kY@ffffS@MY@H"S@4333+@Y@!S@d;Y@#S@hffff@Y@]'S@4333[FY@ffff-S@hfff@Y@2S@:Y@4S@9Y@̤9S@4333[?Y@d?S@4333KY@AS@hfffRY@FS@!aY@LS@ Y@`S@iY@hS@43333Y@3333iS@4333Y@qhS@hfffZ@3333nS@ Z@nS@4Z@iS@hfff=Z@fS@hfffSZ@ffff&cS@tmZ@aS@@yZ@I_S@~Z@\S@ЃZ@ffffXS@nZ@3333VS@̜XZ@8OS@\:Z@ffff.KS@hfffZ@}HS@ Z@FS@hfff~TZ@ES@hfffViZ@qFS@mZ@@S@hffftZ@3333?S@hfffNZ@ffffBS@̬Z@CS@ Z@@S@(Z@BS@4333CZ@33333BS@Z@l?S@Z@L;S@,Z@4S@8Z@.S@Z@ffff$S@Z@%S@hfffZ@%S@xZ@ S@Z@ S@4333ӴZ@S@Z@ffff!S@4333Z@ S@8Z@m!S@hfffZ@u$S@4333Z@H*S@[@3333-S@ [@8/S@[@ .S@4333([@ffff.S@4333W[@3333/S@4333~[@3333-S@,[@0S@Y[@ffffF.S@hfff[@ffff+S@p[@'S@P[@̠&S@4333[@3333k#S@4333\@S@4333\@ffffS@T[@YS@4333# \@ffff"S@4333\@S@4333s\@!S@hfff'\@S@+\@S@hfff/\@ffff S@3\@LS@43333.\@S@*\@mS@i4\@S@B\@MS@F\@S@I\@3333+ S@9D\@ffff S@4333;?\@XS@E\@̄S@4333sQ\@3333S@dW\@ffffr S@`[\@,S@hfffd\@R@v\@ffffR@hfffw\@R@4333o\@3333R@̬g\@ffffR@4333Sd\@`R@_\@R@a\@R@^\@3333R@Y\@ffffbR@hfffH\@3333R@D(\@3333wR@\@dR@\@ffffR@hfff\@!R@.\@5R@)=\@ffffR@hfffVJ\@ffffR@̌O\@!R@V\@1R@c\@!R@yn\@3333R@Dg\@R@1;\@ffffR@I \@ffffR@[@\R@4333#[@$R@4333#[@R@[@ԝR@t[@nR@4333;m[@oR@j[@33337sR@4333q[@fffffxR@w[@3333{R@hfff^[@R@4333[@R@4333[@ffff|R@[@ffff|R@`[@aR@[@R@<[@3333ӁR@p[@3333OR@[@}R@4333+[@xR@[@tR@p[@ffffoR@l \@3333_mR@\@3333mR@2\@oR@6\@ffffZqR@4333#<\@3333{uR@5\@ffff}R@hfff;\@ffff|R@B\@|zR@hfffK\@uR@4333T\@ffffFmR@4333Z\@ffffriR@4333SW\@LeR@4333 J\@i]R@Q\@ffffYR@4333k_\@ffff&VR@4_\@IIR@`^\@CR@4333W\@HR@]@ffff*>R@D&^@ffff>R@?^@3333;R@̬V^@ffff">R@o^@3333>R@̴x^@3333=R@^@l9R@hfff^@3333[8R@hffff^@-8R@4333K^@33339R@ ^@:R@hfffƮ^@ffff;R@ ^@3333>R@hfff^@AR@`^@AR@^@̼=R@4333C^@=R@hfffF^@@R@^@3333{ER@4333^@ffff:IR@hffff^@KR@4333^@YKR@4333^@ffff^LR@^@ffffPR@^@ffff:VR@̼^@ffffYR@hfff^@ffff[R@hfff^@3333bR@4333^@ffffhR@hfffn^@jR@^@hR@^@lR@8_@ffffmR@hfff_@3333OpR@4333"_@pR@hfff2_@mR@hfff~g_@QaR@hfffNf_@ffff\R@r_@3333]R@4333x_@_R@_@ffffaR@I_@cR@_@XbR@4333_@3333g`R@ē_@̬]R@y_@ZR@_@ffff:YR@x_@XR@\_@3333oUR@_@[R@!_@ffffaR@_@ cR@a_@^R@ _@\R@_@=[R@hfff`@ffffYR@̈`@VR@ `@(UR@t`@3333?SR@@`@ffffQR@`@3333PR@``@NR@p`@,LR@`@3333HR@hfff:`@GR@!`@FR@8#`@0GR@!`@BR@P`@3333?>R@4333`@ffff^a@Q@?a@ffff"Q@(?a@3333Q@va@Q@hfff"wa@3333Q@̬qa@3333OQ@4333ka@3333Q@|ta@Q@4333{a@ffff R@4333sa@` R@a@ffff> R@La@ffffj R@hfffsa@qR@4333+pa@ffffJ R@hfffma@ffffv R@̤ea@ffffv R@da@R@da@ffffR@(oa@3333R@Q@-b@Q@(b@AQ@hfff$b@ffffVQ@ "b@DQ@!b@ffffQ@|"b@ffffQ@\"b@,Q@hfff b@Q@4333b@33337Q@4333k"b@EQ@&b@Q@9b@ffffQ@XBb@Q@hfffKb@3333Q@\b@ R@db@̰R@`hb@R@4333mb@R@݌b@3333R@b@ffff&R@ b@ R@̄b@3333R@Ѿb@Q@b@Q@hfffb@ffffRQ@1b@Q@4333b@Q@4333b@Q@b@Q@hfffb@Q@b@̼Q@4333b@0Q@̜b@3333Q@b@3333Q@mb@ffff~Q@4b@ffff*Q@b@]Q@hfffb@Q@1b@IQ@Pb@Q@hfff^b@ffff"Q@b@Q@Pb@3333Q@ b@Q@hfffb@Q@4333Kb@9Q@b@YQ@hfffb@3333Q@4333b@]Q@Pb@Q@c@}Q@hfffb@(Q@hfffbb@Q@Hc@hQ@c@3333{Q@.c@3333;Q@i9c@QQ@4333?Mc@]Q@`c@0Q@sc@xQ@|c@Q@c@Q@Pc@Q@4333/c@3333Q@xc@3333׻Q@8c@3333Q@4333Kc@Q@c@3333Q@-c@dQ@̬c@Q@4d@ѓQ@xc@3333+Q@xc@)Q@4333c@ffff6Q@hfffc@\Q@4333Wc@wQ@c@Q@hfff*d@ffff9Q@ $d@)Q@d@&Q@dd@t"Q@X#d@$Q@]'d@)Q@4333+d@4Q@/d@d6Q@2d@ffff9Q@2d@DQ@\/d@LQ@\/d@4SQ@hfff.1d@ffffJXQ@hfff>>d@3333bQ@PEd@$gQ@Ld@ffffiQ@hfff:^d@ffffkQ@qfd@ffffmQ@od@ffff^lQ@vd@fffflQ@E~d@ oQ@4333d@nQ@ld@fQ@Xd@3333geQ@`d@bQ@@d@_Q@Ld@ffff_Q@4333Wd@|cQ@d@aoQ@4333kd@3333nQ@4333gd@3333lQ@hfffe@ffff hQ@e@dQ@\e@\Q@hfff e@`QQ@ e@TOQ@e@NQ@4333Ge@tJQ@)e@3333EQ@D-e@3333:Q@3e@ffffN2Q@Be@3Q@4Qe@33334Q@hfff_e@ffffBQ@_e@3333HQ@H\e@3333PQ@hfffVe@XQ@Re@UeQ@hfff&Ee@hQ@pFe@kQ@Ke@pQ@Pe@vQ@Pe@ffff|Q@Oe@ffffQ@hfff[e@%Q@ge@3333߄Q@hfffe@Q@e@}Q@Лe@zQ@͡e@3333[wQ@e@tQ@hfffNe@3333#{Q@ e@̘|Q@xe@yQ@hfffVe@wQ@8e@lxQ@4333#e@3333vQ@ue@3333 wQ@ e@yQ@|e@LyQ@pf@3333wQ@hfff" f@3333/qQ@̔f@XiQ@,f@$gQ@=f@_Q@4333+Nf@\Q@%[f@XQ@]f@,WQ@]f@TQ@l^f@ffffRQ@hf@ffffPQ@{f@@Q@f@>Q@f@MDP@yzf@0BP@tf@:P@Xnf@4P@df@2P@YVf@d(P@Pf@3333&P@!If@ffff+P@7f@-P@̜2f@1P@*f@3333;P@4333(f@=P@%f@3333@P@0f@ffff>EP@hffff@hBP@8 f@3333DP@ f@3333CP@xf@AP@f@u@P@f@ffffAP@1!f@ffff?P@4333#f@f@̬+P@df@'P@f@(P@!f@.P@hffff,f@1P@-f@33330P@4333.f@(/P@-f@̨$P@hfff-f@ffffrP@6f@̀P@>f@9P@hfffnAf@ P@-Df@ffffP@4333?Ef@P@XGf@ffffRP@Jf@3333P@4Lf@ffffP@DOf@3333/P@1Of@ffffP@qNf@ffffP@4333'Qf@O@4333Tf@ffffO@(Vf@O@hWf@3333cO@Uf@3333KO@Tf@3333KO@Nf@3333O@hfffNf@3333{O@4333Tf@@O@4333Vf@O@4333gUf@PO@Uf@ffff~O@4333Wf@O@,Yf@O@Xf@PO@`Yf@)O@d]f@3333;O@|]f@)O@hfff`f@ffff&O@hfffjf@XO@4333olf@ؒO@hffflf@3333O@4333jf@iO@hfffNhf@O@4333if@LxO@1lf@qO@Ypf@pnO@Arf@cO@Arf@XO@Eof@yNO@N@e@ȥN@Me@N@hfffe@`N@e@3333˗N@̬e@lN@̘e@N@e@N@4333ӆe@N@4333'e@4uN@e@IsN@`}e@3333nN@ze@ffff.kN@Xwe@3333kN@oe@\N@`^e@BN@Ye@̌?N@hfffvSe@33337N@4333Re@d2N@Re@3333+N@dPe@8!N@̌Me@ffffN@Le@@N@4333;Ke@ffffM@hfffDe@8M@q?e@ffffN@=e@X N@̸N@d@|=N@$d@ffff-N@d@DN@hfffNd@3333CN@ d@DN@)d@N@̴d@ffff N@4333[d@ M@4333d@,M@̄d@3333M@hfffVd@̤M@d@ffffM@hfffnd@̬M@4333ϐd@N@d@ffffN N@4333d@ffffnN@ d@̤M@d@3333M@hfffRd@M@d@8N@hfff6}d@ffffN@hfffxd@3333CN@wd@ffffN@vd@d@ M@@d@L@DAd@L@hfff"Cd@L@QFd@!L@hfff*Md@L@̌Ld@\L@hfffLd@ffffL@Nd@3333L@Pd@L@Td@`L@Vd@L@dd@,L@9gd@3333+L@fd@L@4333fd@ffffL@4333{cd@LL@^d@ffffL@Xd@ffffƭL@dXd@\L@hfff^Xd@9L@Yd@(L@4333Zd@ffffL@PYd@ pL@4333Yd@ffffgL@hfff2[d@`L@]d@\L@|ad@3333^L@4333Ked@\L@5hd@XL@gd@3333CHL@hid@ffffN9L@̼jd@3333L@\hd@<L@hffffd@L@ad@L@_d@3333SL@Zd@fffffL@Td@3333L@hfffVd@Y*L@\d@!3L@4_d@y9L@hfff:ad@BL@hfff6^d@AL@\d@L@Rd@3333;:L@4333Od@ffff3L@4333Pd@ffff^!L@Nd@$L@̰Jd@L@̬Dd@3333kL@Bd@y L@=d@K@8d@K@hfff*7d@K@4333W7d@3333ӭK@hfff9d@HK@`:d@ȑK@?d@ffffK@Bd@lqK@`Cd@ffffF`K@>d@ffff&XK@87d@8DK@hfff3d@BK@h)d@BK@($d@3333LK@d@JK@d@3333KEK@̌d@ffff&7K@hfff> d@$K@ad@ffff6K@4333Sd@K@4333c@3333K@c@ffffNJ@hfffc@J@Ac@xJ@hfffc@ffffJ@c@ffffNJ@c@̼J@d@0J@d@ffffJ@Qc@3333J@̰c@fffffJ@c@lJ@4333[c@ffffJ@4333wc@ffffJ@hfffc@XtJ@c@3333wJ@4333wc@J@c@fffffJ@4333c@$J@c@̌zJ@c@ vJ@4333{c@3333oJ@c@ffffXJ@hfffbc@ffff6PJ@4333c@3333:J@c@3333 1J@c@ 'J@̜c@ J@Pc@I@Xc@3333{I@ c@lI@c@lI@̬c@XI@xc@3333;I@hfffc@؀I@c@|I@-c@ffffI@Ԗc@3333I@4333wc@ I@dc@3333I@c@̬I@4333c@мI@̬c@ffffI@4333c@3333.J@c@33333AJ@Pc@)PJ@c@ffff_J@c@ffffnJ@)c@ԀJ@h~c@DJ@|c@J@4333vc@BK@sc@nK@4333 rc@|K@qc@3333K@4333tc@3333K@hfffvc@ffff> L@pc@XL@Ѐc@A`L@(c@3333 dL@c@ffffL@4333Oc@|L@)c@$L@Ac@L@՞c@L@Xc@L@̜c@̤L@Tc@̼L@hfffc@3333L@4333c@ffffL@4333c@3333CL@c@ffffnL@ic@ffffNL@4333Sc@M@0c@33333L@c@<M@hfffc@ffff&M@hfffFc@ffff M@ac@M@c@3333$M@hfff.c@3333C6M@c@|BM@hfffc@ffff&NM@|c@YM@c@fffffM@c@ffffFM@hfff6 d@pM@̄d@M@d@3333M@hfff^d@N@4333Xd@3333 N@Vd@N@hfff^Vd@N@qSd@4N@4Pd@ffffN@Ld@N@4333Fd@4N@0!d@@{N@Hd@3333CrN@d@l`N@ld@3333^N@ d@ZN@1 d@aUN@hfffd@QN@̬d@iXN@4333od@d]N@9d@pjN@ d@3333CN@ d@3333N@d@N@ d@3333N@hfffBc@xN@4333Kc@3333szN@̴c@ɁN@`c@ffffvN@4333?c@3333N@hfffBc@YN@c@ffffvN@4d@N@hfffd@N@( d@̌N@I d@ffffVN@hfff d@3333{N@d@N@4333d@N@c@3333N@̬c@N@c@ffffN@c@ffffnN@pc@3333N@hfffc@ffffN@tc@ N@`c@N@hfffc@3333N@c@N@c@ffffN@hfff>c@ffffvN@c@3333N@c@3333CN@ܫc@N@c@|N@c@XN@Lc@3333N@ĕc@̄N@hfff&c@N@qc@ffff^N@4333c@ٓN@hfffʁc@pN@hfffN{c@ycN@hfffvc@XWN@̰mc@aFN@_c@ffff60N@̀Rc@) N@hfffNc@ M@yLc@9M@`Ic@3333M@Hc@|M@hfffHc@ffffFM@Fc@M@4333Dc@ffffM@Fc@M@Hc@ѼM@qKc@M@Rc@!M@_c@̌M@Uec@M@dc@ffffM@hfff"ec@ffffVM@̈`c@ M@\Zc@M@4333Vc@ffffM@Nc@M@Lc@3333 M@Gc@ffffM@Y@c@3333M@̈M@hfffb@̴M@hfffb@ffffM@̜b@lM@4333b@|M@Ab@M@b@̼M@b@3333#M@4333b@iM@Зb@ЯM@xb@33333M@hfffޞb@@M@@b@0M@@b@3333M@b@3333M@a@AJ@Ha@3333J@ La@3333cJ@4333Oa@ffffJ@Pa@J@hfff.Ra@a@3333EI@hfff"a@̼I@ a@ I@a@̌ I@a@I@̴a@DI@hfffΎa@3333H@ݎa@̬H@\a@ffff~H@̌a@ffffNH@4333ˍa@ffffnH@Ōa@H@̨a@DH@(a@`H@4333ka@\H@4333a@ffffH@a@ffffVH@4333a@h{H@,a@bH@ua@CH@a@6H@4333a@q)H@Xxa@H@ua@ H@pa@ffffG@ka@̔G@Xea@3333CG@4333 `a@G@4333Ra@3333SG@4333Pa@|G@Pa@ffffqG@La@ffff^_G@Ja@ffffEG@Fa@A;G@4333gCa@ G@̜8a@F@43335a@F@4333-a@3333F@$a@ffff^F@hfffa@F@4333a@ffff>F@Ta@4}F@a@3333;iF@ a@YUF@a@GF@a@3333>F@`@L8F@`@/F@`@YE@hfff`@ E@x`@E@4333S`@E@1`@3333KE@X`@E@4333#`@1E@`@dE@U`@ffffFyE@4333`@3333;jE@hfffƲ`@3333jE@4333`@ffffaE@hfff`@ffff6YE@hfff`@̄\E@`@lgE@̐`@3333gE@hfff`@eE@`@3333pE@hfffr`@oE@4333g`@3333stE@̸`@qE@4333`@̌E@`@!E@hfffv`@ffff^E@4333`@9E@P~`@ffff6E@4333{`@ffff.E@4333|`@3333ەE@4333k`@أE@=`@E@ ~`@ffffE@hfffny`@̬E@4333w`@E@hfffp`@3333E@l`@AiE@\i`@bE@g`@DYE@e`@!PE@4333``@̔RE@4333C^`@$QE@hfff2X`@ffff.VE@4333V`@TE@Z`@BE@4333[W`@3333)E@hfffU`@&E@4333G@ffff6T@4333#G@33334T@4333#H@4T@0,H@ffffj4T@ 9H@3T@FH@1T@WH@-T@WH@3333(T@PH@ffffF(T@̬H@3333*T@G@fffff0T@hfffFG@0T@G@|/T@4333G@3333,T@4333G@3333++T@hfffG@&T@`G@3333['T@̌G@ffff&T@iG@#T@VG@#T@OG@ffff"T@AG@3333oT@hffff0G@<T@G@3333T@G@ffffT@hfffG@"T@ F@ffffr$T@hfffF@]"T@4333ӱF@#T@F@Q&T@hfffsF@3333'T@F@ffff)T@)G@ /T@IfG@U0T@4333G@33334T@G@ffff6T@4333G@ffff6T@#I@X;T@97I@L:T@fI@:T@hfffvuI@8T@hfff6I@̨/T@hfffI@h/T@I@ffff,T@hfffI@3333&T@zI@3333"T@#I@!T@IH@T@H@ffff6T@hfffH@8T@H@T@4333rH@̠T@gH@3333T@VH@4T@0XH@T@4333vH@3333T@4333zH@T@4333~H@3333T@`H@ffffF T@ }H@h T@)rH@ T@fH@P T@hfffvJH@̀ T@FH@3333 T@,DH@ T@;H@ T@p1H@!T@hffffH@3333T@hfffF H@T@LH@]T@PG@T@`G@ffff:T@4333G@ffff*T@G@ T@ G@ffff T@LG@PT@9G@3333T@G@ffffT@G@ T@4333ӟG@̈ T@~G@ffff T@hfffFlG@ffff.T@|^G@}T@|RG@8T@4333G@3333wT@G@ T@G@!T@hfffH@3333"T@0'H@#T@3H@3333g$T@|;H@3333#T@4333PH@ T@R@4333wN@yR@4333#jN@R@\N@dR@4333SN@R@4333SDN@3333R@L@ffff&R@IL@AR@)pL@R@hfff&jL@ffffR@̜gL@R@hffflL@}R@hfff~L@R@43333L@̐R@L@3333R@̬L@3333R@hfffL@R@hfffL@ffffR@hfffFL@mR@ M@R@I M@R@hfffvM@pR@̌5M@R@̌SM@3333R@pM@̴R@4333SM@ffffR@4333#M@3333R@\M@ R@hfffM@̈R@N@3333R@ N@ffffBS@#N@(S@hfffMN@S@4333]N@̨S@̌fN@3333gS@xN@S@hfffN@ffffS@hfffN@S@N@ S@hffffN@S@hfffN@S@ЙN@ S@4333N@ffffS@N@S@`O@ffffvS@LR@L@33339R@4333L@3333G6R@4333L@33333R@ L@2R@K@33332R@K@ 1R@hfffK@-.R@K@*R@hfffK@3333W&R@|K@3333$R@K@$#R@\K@ R@K@R@hfffK@(R@K@ffff.R@hfffK@ffffR@PK@3333R@YK@3333 R@K@3333R@K@R@ K@Q@LK@Q@K@ffff"Q@̌K@3333'Q@K@|Q@hfffL@ffffQ@):L@3333Q@rL@TQ@hffffL@Q@hfffL@̴Q@9L@3333Q@ L@̤Q@R@YJ@3333@R@0J@FR@hfffVJ@qIR@hfff&J@KR@hfffƭJ@3333_NR@J@AOR@J@PR@iJ@RR@J@ffff"SR@hfff K@QR@hfffK@RR@)K@ffff*SR@VK@ffffWR@hffffK@3333XR@hffffxK@3333XR@K@ffffVR@K@3333SR@4333!X@ffffDT@ $X@AT@hfff^,X@̠?T@Q0X@M=T@yZX@5T@hffflX@4T@W@,T@PW@2T@x1W@11T@%W@1T@ 'W@33333T@hfffv-W@7T@0W@(9T@4333W@3333QT@W@PT@W@MT@X@ffffVLT@hfff X@KT@hfff&X@ffffZFT@4333!X@ffffDT@4333+kX@ T@yX@T@4333#X@ffffvT@zX@=T@̴sX@4S@4333pX@US@ hX@mS@eX@̘S@̴iX@ffffS@hfff^nX@ffffS@wX@S@!X@3333S@|X@S@X@̘S@X@S@43333X@T@ X@ffffT@,X@3333WT@4333kX@T@X@ T@X@ S@hfffFX@3333S@PX@ffff>S@X@S@`X@|S@̔X@US@4333Y@S@̜X@@S@hfffX@S@̌X@S@hfffX@5S@YX@US@X@S@(X@ffffzS@43333X@S@hfff.X@S@X@S@4333cX@3333S@X@S@X@ffffS@hfffX@3333S@̬X@S@PX@ffffS@4333X@TS@ X@S@4333#X@ffff"S@4333X@hS@yX@S@̜X@3333S@!X@dS@4333sX@ffff^S@PX@3333kS@X@S@xX@3333S@hfffyX@ffffڳS@lX@3333S@̌cX@ffffS@OX@S@̴;X@ŻS@7X@3333S@43333X@ S@̄X@1S@4333;X@S@W@3333S@4333W@S@W@3333GS@hfffW@3333[S@hfffW@,S@hfffNW@3333_S@W@3333S@W@(S@lW@S@W@PS@4333۞W@S@W@ffffS@W@S@̌pW@S@4333^W@S@lQW@ffffVS@DW@3333S@hfffYW@lS@9vW@S@qW@ffffbS@tW@ffffS@9W@HS@4333 W@T@)W@ffff:T@W@ffffT@0W@ffff2T@W@T@W@ffffT@W@̨T@W@ffffT@hfffW@ffff T@hffff X@ffff2T@X@3333 T@X@T@hfffGX@3333 T@hfffeX@ T@4333+kX@ T@Y@@S@4333cY@ffffJS@4333Y@S@Y@3333S@4333cY@xS@hfffY@3333÷S@ٯY@żS@Y@3333S@4333ӼY@S@Y@S@hfffY@S@̼Y@ffffS@Y@S@@Y@S@hfff>Y@3333S@AZ@S@Z@S@hfffZ@̈S@Z@̰S@hfffZ@S@hfffZ@ffffRS@hfff(Z@3333sS@4333c8Z@ffffS@@Z@S@XIZ@hS@MZ@ffffS@4333cPZ@S@SZ@ffffS@hfffUZ@3333S@TZ@ffffS@I5Z@3333S@y/Z@ffffS@hfff>!Z@YS@ Z@qS@ Y@3333S@43333Y@`S@Y@ffffS@Y@3333'S@Y@S@Y@`S@̌Y@$S@PlY@pS@MY@HS@hfffBY@ffff&S@4333"Y@ffff S@4333CY@fffff~S@X@<}S@X@x~S@X@3333 S@`X@pS@4333X@3333_S@4333X@mS@4333cX@S@hfff6Y@̰S@hfffY@XS@Y@S@hfffn Y@@S@4333 Y@ffffJS@hfffvY@S@Y@ffffjS@,Y@xS@hfffY@4S@!Y@3333kS@'Y@S@ 8Y@ffff&S@4333+=Y@ffffvS@x9Y@3333S@6Y@tS@T7Y@@S@9Y@S@=Y@3333kS@AY@}S@\DY@(S@XCY@3333S@hfffIY@ffff S@̌LY@S@hfffSY@3333S@bY@HS@cY@ffffS@eY@mS@,iY@ S@pY@ffffS@tY@S@`zY@S@hfffVY@S@9Y@(S@Y@3333cS@XY@S@Y@S@hY@mS@4333Y@ffffS@Y@S@̌Y@S@Y@8S@DY@$S@4333[Y@S@4333#Y@3333[S@Y@@S@4333a@ R@hfffބa@R@Ȉa@ffffR@4333sa@3333R@a@%R@hfff~a@qR@Da@ffff6R@a@R@a@]R@ta@ffffR@hfff6a@R@a@R@hfffa@!R@a@ffffzR@ha@YR@a@ffffR@4333 a@3333KR@a@S@̈a@3333S@a@ffffS@ a@S@4333a@R@la@ffffBR@a@R@a@ffffR@a@̠R@4333a@R@hfffa@ffffFR@4333+(b@ffffzR@)b@R@̄+b@3333R@ b@XR@4333b@̠R@Ab@eR@hfffb@R@Eb@ffff6R@ b@R@b@R@b@R@4333a@`R@̬a@MR@4333sa@3333{R@a@ffffR@hfff>a@$R@Xa@R@4333ca@ffffR@̀a@ffffR@4333a@R@a@3333R@a@3333;R@4333#a@ffffR@hfffa@3333#R@hfffa@DR@hfffa@HR@a@HR@\a@!R@xa@3333'R@̼a@3333R@Ma@̘R@a@ffffR@a@R@4333a@R@a@R@ a@R@a@3333R@hfff2a@dR@a@3333R@43333a@ܼR@a@pR@4333a@ffffR@a@ffffR@4333a@R@$a@pR@؎a@ɶR@hfffa@4R@hfffZa@DR@4333Cxa@ffffR@ua@3333R@4333csa@̄R@qa@ܹR@dpa@ffffR@4333ma@3333R@4333kja@R@fa@8R@,ca@R@hfffj_a@R@4333[a@ܬR@Ba@ R@4333 @a@R@H=a@R@43335a@R@-2a@̘R@M.a@xR@&a@3333R@43333 a@ffff R@4333a@MR@4333Sa@R@pa@aR@P%a@ffff.R@E)a@PR@4333&a@3333{R@hfff(a@ffffR@x+a@ffffR@6a@̜R@hfff2a@ffffR@ 0a@8R@1a@ffff"R@43334a@ffff>R@8a@S@D?a@3333S@Hb@33333R@Jb@3333R@Nb@R@43333Qb@P@ A@CP@A@3333CP@A@EP@4333A@3333IP@A@JP@A@ffffJP@4333SA@̤LP@hfffvA@3333KP@Y[E@P@yVE@ P@=E@3333 P@4333:E@MP@;E@ffffFP@4333FE@P@4333PE@P@iXE@3333P@Y[E@P@sJ@\Q@@J@Q@yJ@ffff:Q@J@3333{Q@hfffJ@3333Q@4333CJ@8Q@hfff&J@)Q@)J@3333Q@J@Q@|J@پQ@hfffJ@3333Q@4333J@ffffQ@̌yJ@ffffnQ@jJ@ffff~Q@dJ@3333[Q@4333^J@Q@hfffEJ@3333Q@hfffv6J@PQ@ %J@MQ@4333J@d@aXK@@e@QHK@d@3333Q@d@3333Q@4333'd@ffffvQ@4333 d@3333wQ@d@ Q@hfffZd@3333ǻQ@4333d@3333Q@4333d@Q@d@3333Q@hfff.d@9Q@̄-d@9Q@.d@3333=Q@.d@?Q@hfff+d@BQ@4333%d@8EQ@hfff^$d@ffffGQ@$d@LQ@D%d@YUQ@hfff"d@ffffYQ@4333#d@^Q@X*d@ffffbQ@-d@ fQ@hfff*0d@hQ@0d@hQ@3d@ffffeQ@43333d@3333`Q@hfffJ1d@[Q@4333+d@yZQ@hfff:+d@3333WQ@+d@RQ@,d@qLQ@,d@FQ@/d@ffffAQ@43330d@ >Q@433370d@];Q@hfff.d@9Q@Yc@ffffS@)c@}S@c@0 S@c@0 S@̔c@x S@̸c@ S@c@u S@Yc@ffffS@hfffΤb@<*S@b@|)S@4333Wb@3333S+S@4333b@/S@b@ 2S@hfffb@ffff/S@b@T+S@hfffΤb@<*S@4333>a@}Q@43336a@ffffQ@̜3a@Q@`0a@`Q@hfff.a@Q@4333,a@Q@+a@yQ@4333(a@-Q@̄"a@$Q@ "a@Q@hfff"a@Q@$$a@Q@a%a@Q@)a@Q@4333#:a@Q@q;a@PQ@=a@̼Q@4333>a@}Q@4333Z@`S@Z@HS@4333Z@ffffS@Z@3333OS@4333Z@3333S@Z@3333S@TZ@S@Z@3333S@Z@S@4333Z@`S@\@̼'S@4333{(\@d#S@4333K*\@̜ S@hfffN'\@S@%\@S@$\@S@hfff"\@S@D\@ffffS@\@ffffn"S@ \@(#S@,\@3333&S@4333[@3333(S@hfff\@̀(S@4333\@3333'S@9\@4)S@\@̼'S@4333"X@S@4333K'X@ffffS@̼%X@(S@hfff&X@S@4333sX@ S@hfffX@\ S@<X@ffffS@hfffX@3333 S@ W@A S@hfffnW@d S@W@ffff S@̜W@ffffS@PW@S@4333 W@S@QW@3333S@ X@fffffS@4333SX@3333S@4333"X@S@DX@̴AS@9X@3333w@S@hfffn X@3333?S@X@)@S@4333W@e>S@4333W@fffff?S@4333W@]AS@LW@̼@S@LW@4AS@W@CS@W@ffff>FS@!X@3333'MS@hfff#X@IS@#X@3333KHS@(X@ffffDS@DX@̴AS@`V@LS@4333+SV@ffffKS@yKV@3333oMS@IV@NS@LV@hQS@RV@3333KSS@pgV@SS@hfff~kV@QS@̜jV@IPS@`V@LS@hfffFR@ffff7R@4333ۨR@H7R@4333R@d8R@4333ӛR@3333:R@R@l>R@iR@`AR@R@ffffDR@̴R@3333FR@)R@YHR@dR@3333GR@4333kR@FR@R@DR@hfffR@BR@lR@>R@@R@y;R@hfffR@:R@hfffFR@ffff7R@Q@)H@7Q@H@1Q@hffftH@ffff/Q@`UH@.Q@433338H@33333Q@p(H@PQ@#H@̔BQ@#H@3333/FQ@%H@KQ@4333(H@3333;QQ@4H@3333VQ@PH@[Q@hfff&lH@_Q@hfffzH@`Q@4333ӜH@`Q@hfffH@SQ@iI@tPQ@4333!I@KQ@ٯO@ffff,T@4333O@,T@hfffFO@3333-T@hfffVaO@0T@BO@4T@KO@6T@hO@49T@4333ӎO@=T@O@3333>T@O@3333>T@ P@?T@hfff P@IBT@x P@ffffFT@`P@ffff>IT@P@ffff6KT@4333$P@LT@T3P@LT@hfffAP@JT@KP@8IT@4333SP@,FT@4333sXP@CT@4333 WP@ffff@T@WP@=T@hfff[P@̐;T@hfff?P@h4T@#P@X0T@ٯO@ffff,T@hffffL@3333T@iL@̨T@hfff6L@T@L@ffff T@hfffL@h T@hffffL@ffffT@L@̔T@hfff֗L@\T@̬L@ffff~T@lL@T@L@̜T@L@lT@=M@ffffT@`|M@T@hfff֎M@T@4333M@3333T@2M@fffffT@hfffV$M@3333T@4333$M@T@4333 M@ffff T@4333M@ T@hffffL@3333T@yO@l5T@hfff&O@33332T@̌O@.T@O@+T@4333 O@|'T@4333sN@3333w&T@43333N@ffff%T@yN@<"T@N@M T@N@ffffT@4333s\N@T@#N@̤T@9M@̌T@,M@T@hfffVM@ffffR T@hfffM@`!T@4333M@ffff$T@43333M@'T@yM@ffff-T@`M@ffff1T@4333SM@ffff&2T@M@A4T@M@33335T@ N@3333O6T@4333N@5T@hfff#N@3333K3T@4333=N@x3T@hN@ffff4T@hfffN@57T@yN@%9T@N@33338T@, O@ffffv7T@yO@l5T@hfffN@ffffT@LmJ@T@4333×J@hT@4333#J@T@hfffFJ@qT@9J@ffffT@4333J@,T@4333J@̜T@4333J@ffff>T@̼J@ffff T@4333L@uT@4333L@IT@9L@i T@PL@T@4333CL@3333T@4333S~L@3333T@̬L@T@4333K@T@̬K@T@̜K@3333s T@L@ T@4333K@|T@ L@T@SL@$T@hfffZL@@T@hfffxL@3333oT@4333L@uT@hfffL@ffffbT@lL@i`T@ M@ffff^T@7M@̴]T@,HM@3333ZT@/M@XT@L@ffffWT@L@hST@hfffM@3333OPT@L@LT@hfffL@JT@L@̬HT@iL@lKT@43333iL@ffff:OT@UL@̰LT@AL@33337KT@hfff.L@ffffnKT@4333L@UNT@̼K@LT@LK@̘NT@hfffK@ffffST@hfffK@UT@4333L@eST@3L@XT@\L@[T@̌|L@̬`T@hfffL@3333bT@L@AbT@lL@ffffbT@L@3333#dT@hfffL@ffffbT@hfff\K@lGT@@K@EAT@hfffL@AT@4333sGT@hfff\K@lGT@4333SO@3333fT@hfffO@ffff.fT@hfffFqO@fT@YIO@hT@DO@hiT@4333AO@3333/jT@ O@ffffzkT@Y$O@8mT@eO@3333nT@4333O@kT@9O@jT@hfff&O@ffffiT@4333SO@3333fT@%M@mT@L@lT@hfffL@xmT@4333cL@4nT@L@oT@4333L@ffffsT@9M@tT@4333M@3333vT@IM@tT@̬M@3333qT@M@3333pT@%M@mT@hfff+W@ffffS@43333W@3333;S@hfff W@S@V@̘S@V@xS@V@ffffS@V@S@̬V@3333T@4333CV@ffff&T@ V@XT@ W@T@%W@3333S@^W@3333;S@hffffsW@S@fW@ES@4333sXW@3333+S@IW@4S@H;W@ffffS@hfff+W@ffffS@LV@ IT@4333CV@DT@4333s~V@=GT@zV@̄IT@̬yV@JT@yV@MT@V@ffffLT@̔V@KT@LV@ IT@Ta@3333R@4333;a@3333zR@hfffa@zR@܅a@3333KR@@a@3333ˋR@1a@ffff&R@a@ffffvR@ a@ R@,a@R@8a@R@a@3333ۋK@Aa@3333ӆK@Ea@K@̘Fa@3333KK@hfffCa@ffff~K@@a@PsK@?a@ iK@>a@ffffdK@;a@_K@I9a@4YK@hfff7a@TK@(5a@ffffSK@0a@̴iK@hfff.a@3333oK@(a@leK@t'a@1eK@hfff(a@ rK@L,a@ffffK@-a@ K@e1a@K@y2a@8K@hfff"=a@ffffK@>a@3333ۋK@l&e@ffff&eQ@Me@ffffdQ@4333# e@̄jQ@hfffe@3333mQ@d@3333qQ@Hd@ttQ@hfff>d@3333uQ@ d@wQ@d@3333yQ@e@d~Q@He@Q@t e@Q@hfff+e@|xQ@hfffv-e@vQ@-e@ffffBuQ@a-e@ffffqQ@4333*e@@qQ@hfff)e@ffffoQ@m(e@fc@!I@fc@ &I@tjc@%I@hfffmc@9/I@uc@3333K3I@hfffxc@=I@P|c@WI@ c@3333`I@c@bI@hfffc@UI@8c@ffffGI@lc@33339I@y}c@ffff&I@Bc@(eH@`Ac@^H@@c@3333`H@?c@bH@4333Bc@3333jH@4333 Dc@sH@hfff^Fc@sH@4333OGc@0rH@̌Fc@mH@Bc@(eH@hffftc@4iI@hfffqc@gI@hpc@,kI@xoc@PoI@nc@tI@1rc@̜wI@xtc@3333tI@hffftc@4lI@hffftc@4iI@<#c@G@̸!c@aG@! c@3333SG@4333c@,G@hfff!c@G@̈"c@̄G@<#c@G@c@ffffrG@b@dG@!b@dG@hfff&b@ffffjG@b@$mG@̨b@3333;oG@hfffFc@3333G@hfffNc@3333#G@hfffc@3333[G@hfff> c@33333G@c@ffffrG@b@ffff.F@hfff>b@F@hfffNb@3333F@4333Ob@ffff~F@4333{b@3333#F@4333˾b@ffffG@b@̤G@(b@QG@4333b@G@b@3333G@=b@3333sF@b@F@b@ffffFF@Db@ffff>F@b@ffff.F@4333/b@F@Db@3333F@db@F@4333+b@3333F@=}b@~F@4333yb@3333zF@ ub@3333}F@hfffsb@xF@sb@3333{qF@rb@3333jF@ib@̼VF@4333fb@3333FF@hfff&cb@DF@\b@3F@4333]b@̬AF@,_b@iHF@hfffdb@TF@db@3333bF@gb@3333mF@hfffmb@xF@qb@ffffF@ ub@F@4333xb@iF@hfffV|b@F@{b@pF@}b@F@~b@YF@4333ˁb@̌F@)b@ F@`b@ffff&F@b@ F@̜b@̤F@b@3333cF@b@HF@pb@8F@ib@3333[F@hfffb@ffffF@ɚb@lF@Mb@xF@4333/b@F@Vb@4E@4333Ub@E@ySb@E@Sb@E@4333Sb@E@4333cZb@$E@hfffJ\b@!E@\b@ffffE@Vb@4E@̤Fb@3333?F@dKb@Y6F@4333+Rb@`8F@̄Pb@/F@Mb@ffff0F@hfffzIb@ffff#F@̈Eb@3333c"F@Cb@3333{F@@=b@ffffF F@db@ffff"F@hfffCb@@F@̤Fb@3333?F@X\@̠R@V\@3333R@hfff&S\@LR@P\@tR@,L\@PR@>\@̘R@3\@ffffR@43332\@R@ \@\R@\@ffffrR@`[@R@hfff&[@xR@8[@̘R@|[@ffffR@[@R@hfffN[@HR@[@R@hfff[@4R@Q[@ffffŸR@|\@ffffR@h\@ffff"R@<\@R@QR\@9R@X\@̠R@hfffS@3333S@S@`S@S@)S@ WS@3333S@(cS@S@eS@3333S@3S@TS@)S@S@̼(S@S@IS@S@hfff S@ffff S@S@ffff S@LS@3333CS@ S@ffffS@hfffS@3333S@̴T@H6T@hfffNS@3T@pS@m5T@S@I6T@S@;T@S@ffffv=T@S@l>T@T@R@̤S@3333:R@lS@<1R@S@4.R@T@3333R@\T@R@hfff.T@3333oR@yT@R@4T@ffffR@~T@R@yT@R@4333wT@AR@hffflT@R@iT@}R@4333eT@ffff.R@hfffbT@3333R@ `T@R@4333mT@R@hfffuT@ R@L{T@F@8333<@)F@@<@3333F@ <@F@hfff<@ѧF@8333<@F@hfff=@F@99=@3333F@Yg=@F@8333S=@ffffvF@hfff=@ffff.F@8333=@DF@hffff=@3333F@=@iF@hfff=@d}F@=@ffff.uF@=@kF@Y =@`F@=@@fF@8333=@oF@9 =@|vF@hffff=@ffff|F@ <@F@9<@{F@9<@ffffuF@<@ffffgF@8333<@ffff_F@Y<@[F@8333<@̄QF@hfffF<@ffffMF@<@3333SHF@`<@IF@ <@@F@<@ffff/F@9<@%F@<@ffffE@9<@E@ٕ<@E@hffffl<@E@ `<@TE@83338<@E@ <@DE@;@̔E@`;@aE@8333;@hE@8333;@xE@;@E@;@F@hfffl;@F@hfff;@̴F@@;@lF@hfff:@ffffF@@}:@ F@@7:@ffffF@83339@ffffnE@9@(E@hfff9@3333E@@9@E@(9@E@hfff8@̄E@9n8@ffffE@ :8@E@hffff7@E@و7@AE@97@3333E@hfffF6@E@ 6@E@@6@3333E@hfffF6@TE@L6@\E@@6@,F@@7@3333 F@L7@3333 F@hfff6@3333KF@8333s6@F@6@pF@6@F@6@3333$F@6@(F@83336@ffffN+F@ه6@a0F@~6@̼7F@6@3333>F@8333Ӎ6@)EF@6@3333GF@hffff6@3333GF@6@3333HF@̌6@MF@`6@3333SSF@hffff6@fffffZF@hfffY6@3333VF@8333s36@GF@83336@ffff^EF@hfff6@XOF@hfff5@3333CUF@5@ WF@٢5@ZF@٘5@`F@5@!eF@,\5@iF@[5@PnF@hffffb5@ffff^oF@83333q5@3333oF@5@ffffpF@hfffF5@IsF@5@̜uF@8333x5@3333xF@8333h5@ffffzF@8333`5@|F@hffff[5@~F@YZ5@ffff&F@_5@̼F@Ye5@؂F@8333k5@8F@9o5@ffffF@hfffw5@F@hfff}5@ffffF@}5@ffffF@hfff&w5@F@8333sn5@̤F@a5@@F@95@3333F@%5@XF@83335@3333F@5@(F@4@3333îF@4@F@hfffF4@3333F@833334@F@4@3333F@Y4@!G@83333 5@G@hfff&5@ffff&$G@hfff&5@&G@+5@$-G@15@ffff2G@C5@ffff4G@hffffC5@P9G@8333@5@A>G@hffffK5@ffffFIG@Q5@MG@\5@tOG@9i5@RG@@5@ffff&ZG@ z5@ffffn`G@8333~5@ffffeG@̌5@ffffnpG@83335@\{G@hfffƦ5@ffffրG@8333S5@ffffG@hfffƸ5@3333ۊG@83335@ffffG@̌5@G@833335@G@L5@G@5@ffffG@5@̤G@ 6@G@hfff6@8G@`/6@̄G@>6@3333#G@hffffJ6@)G@Y6@<@33339G@3<@|,G@<@G@hfff<@ffff~F@8333<@F@8333<@3333F@̌"<@F@(<@ffffFF@hfff(<@F@!<@3333kF@ <@ffffnF@ <@3333F@hfff<@F@)<@3333F@hffff6<@F@N(hfff`I@̌8@I@<':@"LI@4333s8@ɖI@433338@4333I@̌8@I@43338@hfff{I@8@4333vI@Y8@hfffmI@8@hffffI@ 8@kI@43338@4333clI@y8@cI@l-9@hfff`I@dfff6f9@hfffaI@q9@̼fI@@9@0oI@ٜ9@sI@\9@hffffI@@9@hfff֍I@:@4333I@<':@̱I@:@4333I@43339@@I@9@4333sI@9@ I@4333S9@PI@s9@I@dfffc9@I@4333H9@ I@%9@I@ 9@ I@8@hfffFI@8@hfffƶI@43338@I@dfff&8@LI@4333s8@OppH?3333R@@ffffE@  01ffff.o@@0333 1ffffnh@@03333k@@0333#03333c@@y0ffffa@@0Z@@`03333R@@̬1ffffT@@0333+1fffff\@@91(b@@0333=1Xg@@01ffff.o@@`fff!tD@̬]!ffffE@`fff-!E@!E@`fff& 3333E@9 ffffE@m E@̌h QE@X E@0333SG E@̌B 3333SE@9m 3333D@0333s 3333D@\ !D@X D@0333N ffffD@Y0 8D@3333 D@ 3333333D@`fffffffnD@ 333D@`fff&ffffD@LsD@`fff D@LffffD@̤D@`fffD@ffffD@ DD@ 3333`D@`fffffffD@e3333kD@ 3333ffffD@LvffffD@ 3333UiD@ 333D@D@yD@`fff&MD@`fff:3333D@5D@`ffff<ffffD@ 3333+D@L3333 D@3333+D@ 333s;33333D@ 333D@̼D@D@ 3333 D@L(ffff>D@̜ D@CD@ 333tD@`ffffɍD@D@ffffބD@3333+D@LnlpD@ 333W̄cD@FSD@Qffff>OD@W=D@h̼8D@Ld33334D@I)0D@=3333+D@offff~&D@ 33334 D@ 3333D@`ffff!ffff~D@AD@`ffffffffFD@3333D@ 3333C@1C@%3333cC@̌0PC@xAC@ C@̌$ffffC@ffffC@C@`ffffs9C@WC@9HC@̌ffffNC@,̴C@`fff9C@`ffff~C@`fff&/tC@iC@ 3333bC@L ffffv[C@@%ffffSC@L9ffffHC@W0@C@@_̌:C@ 333l3333+C@ 33333333C@̌ C@`fff̜C@`ffffC@@JC@`fffC@@+ffffB@B@8B@B@ 333B@`ffffɶB@`fffB@ 333s3333B@`fff&V3333B@@B@`fffF ܉B@ ffffΌB@2!B@lz!̌B@`ffff!B@`fff! B@!!B@@!AB@٠!$B@!B@l!B@03333!B@`fff!ffffB@!C@03333!ffff^&C@ !,9C@,V!P6C@w!=C@`fff!3333SBC@`fff&!ffffFAC@`!̌AC@`fff&1"D:C@_"ffff8C@03333m"3333[9C@ h"DC@03333"TC@ [" XC@`fff/",YC@ "_C@@!fffffC@@"ffffsC@L!C@L!C@`fff&!qC@!ffffC@."ffffjC@`fffE"3333_C@,"<[C@`fff"TYC@`fff"ZC@"̌]C@"ffff>fC@0333",mC@`fff"zC@`fff&"YC@`fff"3333ßC@`fff"3333cC@"LC@`fff"C@"C@K"3333sC@0333"C@!ffffD@!ffffnD@0333!D@̾!)!D@y!ffffMD@0333v!QSD@`fff^!3333S`D@0333Y!PuD@`fffO!ffffƃD@0333Q!3333 D@`ffffY!ffffƓD@ z!pD@!ffffD@`fff&!3333sD@`fffƂ!dD@Y!3333CD@0333s!ffffD@`fff!D@`fff!tD@9zB@03339̄xB@9tyB@(9xB@29ffffB@)9`B@993333B@Y 9ffffB@9zB@#?ffffC@l.?C@0333A? C@pH?qC@hfffB?ffffC@)3?3333C@|#?ffff^C@#?ffffC@0333C;\RC@hffff;(QC@hfffM;̜TC@hfff\;3333SYC@b;ffffbC@Y;dC@yB;fffffC@0333 ;eC@̼ ;^C@ ;ffffVC@0333C;\RC@I;ffffGC@l;3333EC@0333!I@Y0@3333SI@833330@I@0@ffffI@8333S0@I@̬0@3333I@٭0@y I@0@3333 I@0@3333I@8333|0@3333I@Y0@0,I@̌U0@ffff.I@8333J0@/I@8333;0@q2I@50@<6I@=0@33333:I@8333SH0@3333=I@L[0@@I@ a0@)BI@ld0@TEI@8333sk0@lII@i0@ffffJI@hfff&\0@OI@@H0@3333SI@0@PI@0@INI@/@ffffVQI@pfff/@3333UI@@333/@̤VI@@333s/@ffffZI@ v/@ffff^I@@333I/@3333_I@̌.@̜eI@ .@eI@@333s.@gI@ .@AlI@ٍ.@ffffqI@pffff.@zI@@.@ffffI@-@ffffցI@ -@pI@-@vI@@-@3333{qI@pfff-@AnI@pffff-@3333mI@pfff-@oI@-@ffffI@-@,I@.@YI@-@ffffFI@-@I@-@ffffNI@ s-@ffffI@l-@I@@3333z-@ffffFI@pfff&s-@3333I@\-@ffff^I@@333s?-@I@ 4-@3333I@̌Y-@I@b-@I@s-@3333J@ -@ J@L-@y J@h-@3333J@b-@4J@pfff&i-@ffffJ@\-@ J@@3333;-@#J@%-@ffff6(J@@333-@ .J@@333#-@ffff.7J@pfff&=-@ffffCJ@@3333-@3333RJ@pfff,@)dJ@A,@ipJ@G,@hwJ@pfff&c,@̼}J@,@lJ@@333,@3333J@pffff,@yJ@,@ffffJ@@,@IJ@@333,@9J@L,@J@@,@3333J@̌,@dJ@pfff,@J@*-@ffffJ@pfff$-@3333J@@333-@J@@!-@3333sJ@pfff-@ffff^J@pfff,@3333J@pffffm,@tJ@e,@3333J@@l,@̤J@pfff,@IJ@@333,@\J@@333sn-@XK@pfff.@K@/@ K@8333 0@"K@8333/0@3333+%K@hfffF=0@*K@8333J0@I.K@hfff&`0@33337K@L0@3333FK@̬0@ffffVLK@1@pSK@ C1@a]K@1@hK@2@jK@R2@IkK@2@|bK@`2@WK@83332@QK@hfff2@(UK@hffff2@^K@̬o2@3333S_K@L2@ffffAK@l2@(7K@ 2@ffffN/K@2@,K@9h3@3333k1K@hffff3@7K@3@ffff:K@3@99K@3@̌7K@L54@33335K@,4@ 4K@#5@ffff&2K@Y5@00K@ +6@.K@Y6@,K@hfff&6@3333-K@6@2K@6@1K@ 6@.K@7@ffff,K@,7@)K@ 7@&K@hffff7@T&K@+7@ffff$K@hfffFH7@3333K@^7@K@ t7@\K@9{7@ K@hfff{7@3333K@hfffFz7@ffffJ@8333|7@3333KJ@8333S7@3333J@ 7@ffffJ@83337@YJ@7@ffffJ@7@3333sJ@83337@hJ@Y7@bJ@7@ZJ@@7@UJ@hfffz7@FJ@83333i7@3333BJ@hfffM7@6J@@47@@+J@hffff.7@3333K'J@8333,7@$J@l27@3333 J@S7@ffffJ@Yu7@3333J@L7@J@83337@1 J@ 7@J@hfff7@3333+J@̬7@3333I@7@̜I@,7@I@8333Ӕ7@ffffI@y7@I@hfff&7@8I@83337@3333KI@Q'& >]@`fff=@_@\4@03c6'.5DKSjx :LSels}F^@43332@IP^@<2@4333e^@``2@m^@T2@hfffv^@K2@̤|^@I2@hfffv^@4333S2@^@dfff&_2@4333c^@|2@(^@)2@hfff^@dfffvu2@0^@g2@)^@R2@hfffΒ^@;2@4333C^@9(2@|^@4333s2@^@1@^@dfff1@hfff6^@`1@(^@4333So1@8^@0e1@0^@IX1@̘^@N1@$^@dfff=1@^@-1@^@dfff'1@9^@dfff1@^@1@4333^@4333s0@@^@0@t^@io0@̴^@Y0@hfff^@P/0@a~^@l(0@yr^@43330@k^@dfff0@f^@0333/@hfffc^@L/@e^@Y/@f^@s/@f^@0333V/@e^@0333?/@Y_^@/@hfff\^@0333S.@\Z^@hfff.@4333Y^@.@Y^@.@hfff[^@n.@b^@0333-@hfffFj^@9-@k^@hfff-@l^@y-@h^@ ]-@0h^@̌)-@i^@hfff,@hfffp^@hfffw,@q^@ V,@4333;s^@L:,@̜v^@L ,@Yz^@0333s ,@^@+@<^@̌+@̌^@@+@hfff^@+@hffff^@ +@^@hfff,@hfff^@,9,@Ȍ^@K,@43333^@Y,@hfff^@0333a,@hfff^@,@i^@ ,@4333#^@0333,@̴^@ّ,@ɶ^@hffff,@ɻ^@L`,@hfff^@(,@4333^@+@hfff^@03333+@̤^@+@hfff^@ٓ+@hfff^@ +@^@hfff~+@^@@+@4333^@hfff+@^@l+@4333^@0333 ,@^@0333,@(^@̬,@4333^@+@^@hfff+@^@hfffF+@hfffv^@hfff+@4^@+@4333^@hffff+@^@hfffq+@4333^@̬h+@,^@J+@4333^@`+@^@*@4333^@*@hfffn^@*@4333C^@b*@@^@8*@4333^@`fff;*@!^@ 3*@l_@Y*@_@ *@4333# _@0333S*@_@0333)@4333_@Y")@̌^@0)@hfff.^@ a)@hfffF^@`fff&)@̴^@03333)@^@@)@I^@)@Y^@`fff)@4333^@9)@^@0333)@^@0333*@hfff^@0333*@hfff^@03332*@^@`n*@hfff.^@*@4333C^@hfffF*@4333s^@,*@4333[^@0333/+@4333C^@hfff<+@^@`y+@^@0333+@^@+@ ^@hfff&+@4333^@+@^@0333+@D^@0333+@4333^@hfffh+@4333^@LP+@(^@+@^@hfff+@hfff^@l*@4^@*@d^@`ffffc*@^@ *@̠^@0333*@hfffޟ^@ *@4333 ^@L*@^@̌ +@4333#^@hfffK+@^@hfff+@q^@0333+@4333o^@hfffF+@Dl^@+@hfff.i^@+@`^@03333+@\^@+@\^@yl+@hfffV^@YL+@hfffM^@0333G+@F^@hfff[+@d@^@hfff&+@4333;^@0333+@hfff5^@+@.^@0333+@hfff(^@hfff+@4333'^@+@y'^@hfffF`,@!)^@},@ ,^@,@4333;^@y,@hfff<^@̬-@hfff><^@hfffFJ-@hfff8^@yn-@|3^@-@hfffN-^@-@(^@-@4333[%^@03333-@hfff"^@@-@4333K%^@0333s0-@̬%^@Y,@#^@,@^@`,@^@ ,@Y^@0333,@`^@0333s7-@4333+^@hffff^-@ ^@,-@ ^@-@^@̙-@A^@-@^@-@X^@hfff:.@Q^@`u.@hffff]@03333.@4333]@.@]@hfff/@i]@/@]@/@]@hffff/@hfff6]@)0@]@43330@q]@PA0@4333]@dfffM0@4333+]@S0@hfff]@4333I0@4333]@ =0@ ]@dfff&70@4333#^@@/0@^@43330@9 ^@43333 0@\^@) 0@^@43330@^@ 0@^@43333)0@^@̼80@^@|f0@^@|0@4333{^@<0@hfff^@ 0@4333+^@43330@4333^@1@Y^@E1@hfffV^@|`1@4333+^@dfff6p1@^@1@^@`1@4333S ^@4333)2@4333C#^@C2@h%^@dffff^2@a&^@43332@hffff-^@4333Ë2@4^@y2@7^@4333S2@43333;^@ɕ2@IC^@2@F^@43332@S]@0333 @M]@ @N]@0333 @`P]@!@dV]@Ym!@̼Z]@`fff!@4333a]@ !@e]@`fff!@̬o]@L2"@x]@9{"@hfff{]@`fff"@~]@"@hfff]@ "@Y]@"@4333]@4#@4333#]@Y#@]@$@|]@5$@hfff]@9C$@hfff]@`fff$@]@̌$@(]@̌$@]@$@4333S]@`$@hfff^]@`fff%%@4333]@_%@]@%@hfff]@%@]@%@hfff]@&@]@l&@]@`&@i]@`fff&@4333]@&@hfff6]@LP&@hfff]@`fff4&@hfff]@L&@̴]@`fff%@hfffn]@,j%@]@y%@hfff]@,%@]@$@]@9$@ ]@0333s$@4333]@0333$@9]@$@]@`fffM$@]@̌3$@A]@`fffF$@hfff]@`fff#@4333k]@ #@hfff]@ #@Q]@`ffff#@hfff]@#@t]@0333s"@I]@0333S"@hfff֛]@0333"@`]@`fff&g"@̬]@V"@̔]@`fff3"@q]@0333!@T]@0333!@hfffx]@0333!@q]@ u!@4333k]@ [!@hfffd]@0333H!@b]@03330!@a]@!@hfff^]@0333!@hffffZ]@ @S]@0333 @^@:'@hfff6^@ '@4333{^@@7'@4333^@0'@^@'@hfff^@`fff&@@^@0333&@4333^@9'@!^@03333'@4333^@0333&@9^@`fff&&@hfff^@ْ&@^@d&@hfff^@`fff;&@^@`fff&@0^@ &@4333c^@`fff%@hfff^@`fff%@^@l%@hfffF^@̥%@^@0333%@i^@@b%@hfff^@>%@4333^@̬&%@P^@03333%@A^@`fff$@hfff}^@`fff$@ |^@$@4333{^@$@~^@0333F%@4333;~^@0333e%@|^@`fffƃ%@}^@L%@4333S^@L%@A^@1&@у^@&@^@,I'@|^@\'@I^@̌r'@hfff6|^@@'@ y^@'@z^@l'@̬}^@0333s'@hfffށ^@0333s'@hfff^@̵'@4333^@`fffF'@̌^@`fffg'@^@:'@`^@0333 "@4333#^@0333S"@^@ "@^@`fffF7"@hfffv^@"@p^@ "@^@"@^@"@^@03333"@L^@`fffFc#@^@`ffff#@<^@#@,^@L#@|^@Y#@|^@̌#@^@0333#@^@,$@i^@@$@t^@l$@̌^@`$@I^@0333%@^@Y%@^@4%@hfffV^@̌e%@^@ %@^@ %@hfff^@0333%@^@%@1^@03333%@l^@`fff%@hfff^@%@^@0333ӡ%@4333S^@%@hfff^@0333R%@4333^@`fff&*%@4333 ^@$@^@$@4333^@?$@ ^@9$@^@#@hfff^^@#@i^@`fffm#@^@0333Q#@hfff^@Y6#@̼^@`fffƶ"@^@̌"@4333^@"@hfff^@@o"@4333^@`fff&>"@Q^@-"@`^@0333 "@hfff$_@`fff&@<)_@&@4333[._@`fff&@̌4_@`fff&@̄;_@`fff&@̜?_@`fff&@4333A_@`ffffl&@hfffB_@@E&@4333B_@`%@@_@`fffF%@)B_@%@hfff^E_@0333sq%@)H_@0333^%@J_@`F%@4333L_@0333s+%@hfffL_@$@̤P_@$@hfff.Q_@̌$@hfff6P_@0333$@I_@y$@hfffH_@x$@ I_@a$@hfffF_@`fffo$@B_@$@43333?_@03333$@P@_@`fffd$@A_@`fff;$@4333A_@0333$@hfffv;_@1$@4_@D$@1_@ V$@43332_@0333$@2_@0333$@hfff6/_@`fff&$@3_@L]%@3_@̬v%@Y2_@0333%@hfffF/_@l%@i*_@`fff%@hfffn'_@`fff%@hfff. _@0333%@4333_@%@Y_@L&@l_@̽&@hfff._@̬&@_@&@)_@`fff'@_@̬'@hfff_@&@4333 _@`fff&@hfff#_@@&@hfff$_@`fff&@TO_@`fffF)@S_@(@hfffT_@@(@hfff~T_@`fffƤ(@4333V_@`fff(@)Z_@ّ(@^_@(@Hb_@b(@hfff6`_@`fffE(@4333`_@0333(@8]_@0333'@hfff]_@ '@__@0333sm'@`_@0333O'@y__@L0'@hfff^`_@`fff'@4333e_@`fff&@f_@`ffff&@De_@&@̴d_@y&@hfff&h_@w&@hfffm_@`T&@o_@̬%&@o_@`ffff&@)k_@=&@43333h_@C&@4333[_@`fff9&@S_@H&@N_@`fffFJ&@I_@&@E_@ &@1B_@&@<_@0333S&@:_@`fff'@hfff>_@`fffF'@4333?_@g'@hfff?_@`fff'@;_@`'@8_@ '@̌4_@`fffF'@hfff2_@'@/_@'@P+_@0333 (@$_@9(@!_@̌((@hfff_@9N(@_@|(@_@(@_@#)@hfff6$_@l )@5_@0333)@̜I_@`fff&%)@TO_@`fffF)@-^@*@X0^@hfff&*@̔:^@̌+@>^@0333*@̔A^@*@4333E^@L*@hfffG^@03333*@L^@Y*@43333R^@̌*@hfffV^@*@L\^@y`*@ta^@,C*@yb^@-*@X_^@`fff *@4333c^^@)@4333^^@)@b^@F)@4333;a^@ +)@P]^@0333)@4333cZ^@(@4333Z^@ (@4333Y^@0333(@_@v@Y;_@Y@(_@`fff&@hfff_@z@hfff _@@_@`fff&@hfff._@Y!@_@̌@9^@0333s@hfff^@@hfff^@̌@4333_@t@hfff_@L@ _@ @4 _@@ _@T@9 _@0333@̬ _@03333@Y_@O@4333^@@^@0333s@^@@$@̜^@`ffffE@^@S@h^@T@hfff^@L;@hfff^@@4333^@L@|^@Y@^@L@ ^@@@h^@`fff&@̤^@M@^@ @^@`fff@0^@@@!^@u@T^@`ffff/@hfff^@@@4333^@@hffff^@`fff;@̬^@@^@0333@p^@0333s @hfffޟ^@`fff@\^@L@hfff^@>@hfffv^@`ffff\@^@@hfffF^@L@hfff^@0333s@H^@`fff@ā^@`fff@hfff}^@0333s@hfffy^@M@,{^@L@hfffn^@0333s@^@Lt@Y^@@̬^@@p^@0333=@4333^@@4333^@̌ @^@ @^@`fff/ @^@`fff&D @4333{^@0333sD @P^@P @4333ÿ^@`fffp @,^@`fff @^@L @ ^@0333 @<^@, @4333#^@, @4333k^@03333!@hfff^@9!@hfff^@ $!@T^@03333;!@^@h!@hfff^@0333\!@4333^@K!@hfff^@=!@4333#^@l!@Y^@̌ @4333^@̌ @(^@̬` @hfff^@LJ @43333^@0333 @)^@`fff& @^@A @^@`ffffQ @43333 _@`fff&g @hfff _@`fffu @4333s_@0333 @ _@ @_@0333S!@_@l!@_@ 3!@_@0333s6!@4333'_@ !@4333._@@ !@0_@,a!@4333[2_@̌!@3_@!@̜7_@!@h<_@0333!@B_@0333!@hfffI_@̼!@hfffFK_@!@4333kM_@`fff "@O_@ "@ X_@!@4333__@̌"@4333#b_@`fff&H"@hfff`_@@"@hfff~Z_@V#@)^_@y#@hfffVa_@̬#@hfffi_@O#@4333x_@#@}_@0333s"@a_@0333S"@4333^@03333"@4333;^@̌"@9^@Y"@hfff^@'#@hfff^@L#@^@`fff&#@4333^@G$@^@$@^@`fff$@hfff~^@%@8^@`fffFv%@4333^@y%@,^@0333&@hfff^@`fff(&@4333^@`F&@hfff^@0333_&@|_@ &@̴_@9o&@hfffV_@6&@̌_@0333s&@\_@&@i_@%@4333_@`fff&%@H_@0333+%@Q_@$@^@$@hfff^@0333$@y^@ q$@^@0333A$@,^@Y $@4333^@#@hfff^@-#@4333^@03333"@z^@ 2@v^@2@t^@̼2@hfffw^@̜2@hfffw^@2@4333x^@dfff2@`|^@̬3@9^@dfff2@z^@ 2@hfffVa^@\3@b^@dfffvE3@hfff6^^@E3@X^@dfffT3@W^@dfff6[3@X^@43333a3@Y^@|^@̌Z4@z^@4333\4@<|^@dfff&t4@p^@dfffz4@hfff^@)x4@q}^@]4@43333x^@)4@u^@dfffF4@r^@4@r^@4333#4@4333Cv^@\4@|w^@dfff4@43333x^@)4@43333J^@0333sM@M^@@R^@@hfffY^@`fff&@Z^@`fff@hfffNZ^@`ffff@R^@z@hfffM^@Y@PE^@0333s@0A^@@;^@0333@hfff8^@@|9^@@iB^@Lb@43333J^@0333sM@E]@@A]@`fff:@ >]@`ffff@4333s>]@`fff @hfff?]@ @hfffD]@`ffff# @E]@@4333]@0333$@4333]@$@]@l%@]@G%@]@`fff5%@^@`fff#%@4333]@0333%@4333]@0333$@hffff^@U(@hfff ^@`fffN(@hffff ^@`fffU(@4333^@̌p(@̬^@0333H(@^@`fff'(@!^@Y(@̔^@0333s(@ ^@ (@h^@'@̬^@9(@@]@0333s#(@Y]@`fff[(@4333k]@`fffe(@]@|(@4333]@`fff(@4333S]@L(@]@`fff(@4333c]@y(@hfff]@`(@]@0333s(@hfff^@@e(@hffff^@U(@4333{^@h'@]@V'@y]@`fffa'@]@ {'@4333]@`fff'@]@l'@]@0333s'@8]@`fff'@]@@'@L^@'@hfff^@'@hfff^@`fff'@hfff^@`fff&'@4333{^@h'@^@`fff$@̧^@`fff$@8^@ $@t^@0333$@^@,$@hffff^@03337%@ ^@c%@^@q%@4333 ^@`fffFz%@^@03333{%@4333^@̬i%@hfff.^@`fff&O%@^@$@^@`fff$@&_@ #@d%_@@#@\ _@́#@_@~#@_@`fffN#@_@̬B#@hfff_@2#@^@y?#@^@Y#@hfff^@0333#@L^@#@I^@0333#@4333+^@#@4333_@$@_@`ffff$@ _@9E$@|_@Q$@_@`H$@4333_@YB$@_@@$@ _@`fff!$@$_@̬ $@hfff#_@`fff&#@4333C%_@#@&_@ #@hfff^@@I^@0333@4333C ^@Y@ ^@@4333^@̌@p^@ @^@@Q]@0333sQ@)]@`fff=@4333]@03333G@4333]@Y@]@`fff@^@0333 @4333 ^@`ffffT@P ^@@\@hfff^@`fff"@hfff^@@^@@4333s^@@4333c}^@̩@Px^@@hfffw^@@@@s^@0333st@@u^@@hfffz^@0333s@4333^@@p^@@@̴^@0333h@^@0333Q@܌^@@^@@̃_@L#@hfff_@`fff#@p_@0333S#@_@`fff#@_@0333S$@I_@#@@_@@#@4333_@#@4333 _@0333#@4333È_@#@̃_@L#@,l_@03333#@4333 k_@#@4333i_@`#@4333e_@0333#@4b_@ .$@4333__@`fff<$@ha_@ b$@4333a_@0333$@!e_@03333$@hffff_@Y$@xi_@`fff$@̬j_@Y$@k_@$@4333ci_@`fff}$@4333m_@$$@k_@`fff&#@Ql_@`fff#@,l_@03333#@\^@Y+@hfffv^@̬]+@4333^@0333+@\^@hfffF+@hfff^@`+@^@0333S+@ ^@,+@\^@Y+@̌z^@hfff+@~^@hfff&+@^@0333+@T^@hfff&*@hfffކ^@y*@ԇ^@0333*@^@̌*@hfff^@x*@P^@0333h*@hfffx^@@*@u^@@*@)t^@0333S*@pw^@!+@̌z^@hfff+@^@0333(@^@03336(@4333s}^@b(@~^@}(@{^@̬(@hfff{^@(@9|^@0333S(@4333S^@(@^@0333s2)@̤^@ M)@H^@`fff&N)@hfffV^@`fff9)@l^@9)@^@0333(@4333^@9(@̜^@9(@^@0333s(@hfff^@`fff(@^@(@43333^@(@^@0333(@^@9(@4333^@(@4333^@9(@ ^@0333)@^@0333f)@̌^@03333)@hfff^@0333s)@x^@`fff)@L^@`fff*@̼^@ *@H^@6*@^@y;*@^@ :*@43333^@0333)@ ^@0333)@^@`ffff(@^@`fff(@t^@ (@^@$)@̔^@@D)@hfff^@̌Y)@4333[^@8)@^@`ffff(@^@ (@!^@0333V(@̔_@'@_@`fff'@_@@'@^@`fffF'@A^@'@A^@0333s'@i^@03333'@4333^@Y(@0^@(@^@#(@4333+^@03333.(@^@̬d(@Q^@n(@hfff^@0333sc(@4333^@(@^@'@^@'@y^@03336(@4333^@0333(@^@y(@Y^@`fffF(@!^@*)@^@0333)@^@)@hfff^@(@^@Y(@^@ (@_@0333C+@hfff_@"+@_@@.+@4333_@`,+@9 _@hfff&+@hfff_@ 6+@|_@hfffS+@4333_@+@_@+@hfff _@hffff ,@4333 _@y,@d_@',@4333_@+@̌_@+@4333_@+@\_@ +@4333_@[+@_@0333C+@9^@,@hfff^@,@43333}^@hfffO,@|^@\,@4333|^@hfffi,@4333c}^@ u,@9^@,@$^@0333.@L^@0333-@^@y-@4333^@9-@~^@03333-@4333c^@0333ӄ-@hfffV^@hfffS-@hfff{^@hfffO-@Hz^@@U-@{^@m-@{^@hfff&y-@4333{^@-@x^@-@0w^@-@t^@Y-@u^@hfff.@0~^@.@$^@0333.@<_@`fffF6%@hfffv_@03333%@4333k_@0333i%@_@a%@x_@0333\%@h_@C%@<_@`fffF6%@Q_@#@iR_@̌#@,J_@9 $@4333H_@`O$@AK_@YM$@N_@9;$@Q_@#@^@0333@̬^@@d^@0333q@4333^@`fff&B@^@̌C@4333^@̒@hfff^@@^@ٖ@̌^@̻@^@0333@hfff6r_@@hfff6q_@@Hm_@0333(@hfffk_@0333J@m_@@4333#r_@̅@hfff6r_@@&_@&@_@&@q_@@'@_@0333T'@hfff_@c'@4333 _@_'@($_@`fffG'@4333'_@`'@&_@&@3_@`fffI"@1_@̌*"@̜*_@C"@hfff(_@`fffY"@)_@s"@Q-_@l|"@(/_@|"@43332_@0333Sa"@3_@`fffI"@$P^@3@O^@43333@̌L^@ 3@K^@dfff3@(L^@#3@̤M^@/3@O^@̜$3@$P^@3@!]@ '@]@&@hfff]@@&@)]@Y&@]@`fffF&@]@`fff&&@p]@`fff&@4333]@&@]@`fff'@!]@ '@4333s^@ &@43333^@,M&@hfff&^@̌M&@I^@~&@4333s^@&@4333s^@ &@^@)@^@ (@4333^@0333)@܏^@`fff&)@4333ˑ^@0333/)@hffff^@0333-)@^@)@~_@`fff/#@|_@"#@4333{_@03333>#@̴|_@yz#@}_@`fff#@̌_@^#@~_@`fff/#@hfff6_@`fff0'@5_@,'@3_@y'@1_@Y)'@/_@,Q'@hfff._@@n'@t2_@]'@43334_@0333@'@hfff6_@`fff0'@̼V]@`fffm @hfff^R]@a @lQ]@́ @Q]@`fffF @U]@0333 @4333V]@ @̼V]@`fffm @hfff^@y"@43333^@`D"@4333S^@`fff4"@4333^@lB"@̔^@Yb"@hfff^@Yn"@@^@Ym"@^@Y"@^@"@hfff^@y"@Rp3333UTyX23333+Q`}Q5~Qpffff4@QOiQUffff>Q%ffffƋQL1ffffNQpffff4HQpfffffffQLQ@333ffffQ̜Q@333ffff.Q@3333333+QlQQpffff.PQpffff3333;Qffff QffffFQ Q]QffffQQ\Q6QpffffLHR@3333333oRpfff̔Rpfff$Rpfff3333&R ,RDffff>5R`8R@333}:RT9R:R53333_=R>R[ffff>R3333[DR(lJR̻fffffMRpffff3333ORd33337MR@3333JRpfff HR`HRffffHR3333[KRaORATRLffff_R̷3333slRŪpRffffqRpfff3333sRQrRLffffpRpfff3333KnR 3333nR@333<3333oRpffffW3333sRpffff]vRLfffffyR~|{Rx3333}R3333}R@333|RLX}R~R$!Rpffff9~RW|RpfffqAyR̜tR@333qR3333nRL!mRpfffPnRpfffftqR@33333333qRpfff3333nRpffff̰kŘ ffffFiRL% gR8333sJ gR@b dR8333 $cR@ $cR =_R [Rhfff 3333{YR WRhffff ffffVR@!VRL"!3333[SRN!MRLp!GR̠!3333DR!ffffV>R!ffff>R="ER "3333gMRhfff"@R"4R"&R8333s"ffffR"ffffBR83333#3333[R#3333Rhfff&B#3333R`#3333R8333s# Rhfff&#ffffv R#3333 Rhfff$ffff& Rhfff$Q$Q$̸Qhfff&#ffff:Q#`Q8333s#Q83333# Q #Q̌V#=Qhfff&@#3333Q8333$# Q83333 #3333èQ"Qhffff"Q"}Q"3333Q@#XQ8333=#MQh#Q8333#3333èQ#ffffΨQ̌#ݨQ8333\$3333Q$3333Q ,%3333Q%Q@&-Qhfff&% Q%3333ۜQ8333 &3333Q&3333Qhfff&"&Qhfff &Qhffff&ffff>Q%ffffv}Q%3333uQhfff%3333#kQ%eQL%]QhffffV&3333+WQ8333&ffff~PQhffff'ffffKQO'BQY';Q83333"(e4Q8333s(3333+Q).Q)33330Qhfff&7)̔0Q_)3Q̌u)7Qhfff)ffff;Qhfff)>Q)>Q)9>Q*>Qhfff&*3333AQY0+aCQ8333I+ffffDQ]+yAQ+ffffZ>Q8333+3333;Q,9QL0,̼7QhfffV,3333W8Qe,1>Qx,I@Q8333,3333@Qhfff&,`CQ,GQ,iJQ-LQhfff&%-OQ83331-ffff&PQW-ffffQQhfff}-WQ83333-3333WQhffff-3333WQ -ffff*UQ8333.KQe. KQhfff&y.ffffFPQ8333s.ffffRSQ.(WWQ#1/YQhffff.\Q.bQ.hQhfff.kQ@.yoQ̉.3333pQhfff.ffffsQ .3333OuQ.3333uQ .vQ .ffff~zQ8333. |Qhfff&.3333{{Q.wQhfff/`tQhfffF/ffffsQ c/3333[tQb/pwQQ/zQ̌D/4}QJ/3333~Qhfff&\/ffffQhffffi/Q̌w/QQ/ffffQ/Q/̠Qhfff&/3333}Q@/{Q̌/3333KyQ̌/ffff xQ/vQ@/ffffvQ /muQ83333/3333WuQhfff&/ffffuQ/3333vQ8333/vQ8333s/)vQ̌/auQ/3333sQ / rQ/ffffoQhfff/mQhfff&/=lQ/jQhfff/ffff&hQ8333/cQY/ffffF_Qhfff&03333\Q̌0\Q90\Q03333+_Q4333S)03333^Q4333.0ffff[Q/0̠YQL30qWQ433390TQ9>01QQ9@03333/NQ A0\KQ4333?0ffffHQl;0HQl80BQ70Ԗ>Qa=0T@Q@0BQ4333G0BQ4333sQ0yBQL]0QCQj0HFQhfff{03333DQ`0)CQhfff0kgBQS~L0tBQ03333SAQhffff0}CQ03333{HQ̌0LQ0ffffQQhffff03333kXQY13333ZQ@ 1 \Q1ffff6`Q43331gQ@313333SiQ?1ffffhQ`K1dQ9U13333gaQ4333c1`Qu1`Q@13333`Q̌1eQ13333kQY13333sQ91̈vQ,13333uQ13333[sQhffff1]sQ1uQ2I{Q42ȃQ4333H23333ËQ@S2QLS2(QhffffU2ĚQyX2ffffvQG2QQ4333s 2DQ13333Q,1̐Q13333[Qٞ1Qhfffl1Q4333]1QYK1̐Qhfff213333Q̬&1Qhffff13333Rhfff10RL033333Rhffff0ffffRhfffF02R4333S03333K=RY0PRyc0ffffYRhfffM0ffffnR30tR '0iR83333/ݗR/3333Rhfffe/Rhfff.1Rhfff.ffffR83333[.aRhfff/.3333'Rhffff-ffff6Rhfff-RhffffD-3333gS,S,5 S t,3333Shfff&D,ffffS+Shfff+ffffrS+3333S + S+PS *YSL8*3333# S)̈#S)ffff(St)33330Shfff )A5Š(3333?S@p(pBS8333sX(3333DS83336(ffffIShfff(ffffJS'NShfffS'SS'ffffhSY&ffffhSc&jSL &oShffff%S8333s$S-$3333Shfff#ЖSM#S" S83333P"̈S83333!3333KS{!ȰShfff;!9Shfff& Sk Shfff& Spffff$SWS̈S@333.SDffffSLSpffffffffT@33333T!CT3333IT:KTJTLETpfff?3333w?Tq;T]ffff~8T@3333 q8TL\ffffT@3333/TpffffOS@333ffffSffffS̀SSSS(3333S@3333333+SS@3333\ffff.S(SffffS@3333Spffff!SpffffffffS̡lS@3333~ԺSoffffSLF@S@3333ffffS3333#SffffSpfff^Spfff?ffff*SɩS@3333QSL٫S@33333333{S@333MxSS3333+S*ffff:S@3333̔S̔Sffff7%SݚS7Sffff ̘Se yS@3333 9S@3333s ffffS- ̬S@3333 0S@33331 S@3333} ffffbS |S xS $S MSu 3333S2 tS@3333 3333S@3333 4SffffE XS |S@3333`wSffff,jSLffffj`S@33333333 WS@3333zUJSffff^8Sffffffffv+S@3333Sffffu S3333kS3333S3333RKffffRffffRR3333R3333R#RffffRTRffffHRRffff3333oRRuffff&R̠ffffR俙RffffRR5ffff.R4333+ڿffffRԿmRϿR̜ɿ3333sR,ĿR4333s\R4333sffffvRĿ3333R¿ffffR43333¿4RhfffF`R`R`3333R٩RཿQR4333ÿRhfffȿffffRhfffɿRhfffʿPR̜ɿ3333RLϿXRӿDRtտffffrRgfff׿ffffR4333ۿ3333Rgfff޿ŝR̐ffffR̔ffffR 濙RRffff3333gRffff:3333+R̰ďR3333￙R3333{R@3333u(R3333S{Rffff>wR%̨sR|ffffoR@3333mjR@3333ffffgRdRlffff^aR23333_RaR83333_R-\Rffffffff^VR̊ QR@3333[UNRffff3333LRHKR3333KIRHR@JR@3333@ KR̪3333IR9\DRffffV?R̷3333;̴-R@3333#@*Rffff(R@3333̌%R3333 R)QRffffn3333?R@3333F3333 R@33334R qR̘ffffQ̜Q@3333OQffff`QT)Q8QuffffQ@3333Q;3333QYhQ@33334Q̭Q@3333AQ3333QffffQQ$QffffxQ?3333ۤQX3333QĚQffffNQ<3333ےQk̤Q@33333333Qffffffff"QD$Q Q̼QffffiQQ̲КQffffN ɧQ@3333 Q@ffff2QOffffQffffQffff3333QDQ̌ffffQ̃Q`QffffQ̸Qpffff3Qpffff^Qpfff}QS 2333SSOhfffƍ;2333KhfffFI32333sMhfff&*42333M<42333M K4ffff MLU42333{Mb4@M4333sj4IMhfff&w4!M̌4pL,4QLhfffF423333L42333#L4LY4IL4qL433334ALy42333CL44Lhfff4Lhfff&4DLy4L43333"5L45xL D5PL`M5ffffLhfffZ5Lk5ffffLy~5Lhfff5L5̌LhfffF5ffffFL5L5L`52333Lhfff5dLhfff&523333Ľ5QL433362333+L 62333[L43336ffffL"6Ll$6L43336LLhffff62333#Lhfff!62333L4333.6LhfffF062333cL26YL 76ffff~L168L 762333ӃL̬>6wL4333sE6fffflLC69cLhfffB6YLhfffF;6ffffQL <6@JL4333.6pFL"6 CL@6Q9L623332L6 -L-6L#Ll:6ffff~LC6LLG62333L4333H6ffffKG62333KN6KN6XKZ62333kKi6K@6K43336ffffK433336Khfff6TK̬6K4333s62333KK6|K43336|Ky7K@7K'72333+K @7K4333Q7K\7\Khffffj7yK@v72333SK4333S7ffffK7\K43337̼K̯7Khfff7Khfff7M:7Mhfff:-M:I)M̌:ffff*M,:(M:ffff"ML:ffffnMhfff&:2333MhfffF:lMhffff:|MhfffF:ffffM4333:2333CMz:Mhfffa:2333;M4333N:M9C:\M`@:M43339:9M .:̌ My#:Ľ :L̬:pL9L,9(L9Lٹ9̜L4333s9L̪92333LhfffF9,L9LhfffFy9(L4333g92333kL4333T9,L"92333L 9xMhfff&82333[ M,82333'Mhfff8.M43338ffff6Mhfff82333BMhfff8̬\M`8M43338̼M43333t82333M4333c8ffffMLD8c@4333c@@333Tc@lc@pfffhfffzb@@3333Lhfffb@uc@4333c@m4333wc@Lb@b@pffffBb@i$Xb@hfff$4333/b@x$4333b@$`b@ $hfffFb@Y$ b@8333$̤b@$`b@$b@83333 %hfffb@%pb@F%b@ L%b@pfffb@7?b@@3333(hfff2Ab@pfffJAb@hfff@b@uc@@3333 c@ ̸c@[ hfffbc@<c@pc@Wuc@@3333 ,c@@3333c@c@4333b@@3333+b@0b@4333cc@Y,c@@3333hfff~b@@3333lb@@3333mb@ffff"yb@ffff8xb@b@4333b@̦Ab@5b@hfff~b@@33334333b@L $4333b@Y $8b@#hfff.b@hffff#|b@#4333cb@8333c$b@YQ$b@hffff/$hfffzb@83333#̬b@hfff#b@#Db@8333s#b@ k#hfff"b@x#b@ٚ#b@#ib@Y#4333b@L $ b@"hfffb@ #4333b@83333#4333b@L"Qb@hfff"hfffb@hfffi"hfff>b@@"lb@8333"b@" b@"4333kb@̌w!b@!hfffzb@hffft!b@H!4333b@hfff0!hfffb@hfff&#!(b@83333 !4333{b@8333 hfffb@ 4333b@8333s b@83333 !4333ob@"!4333kb@̌w!Hc@ &4333Hc@8333&XGc@&Cc@8333& Bc@8333&4333@c@8333&@c@hfff&&Cc@hfff&&ACc@8333s&̜Gc@&Hc@ &4333a@hfff aa@83333 a@8333s La@83333 4333a@ 4333a@hfff& hfffa@ 4333a@hfff eb@Lcb@pfff`b@^0`b@pffff:x`b@1db@pffffhffffb@gb@@333eb@L)bb@\lb@ffff3mb@1hffffmb@@3333̔mb@hfff6nb@nb@xUlb@jb@@3333̤ib@@3333hffffb@ťdb@@3333U4333 bb@@3333̤]b@@3333hfffWb@04333_Vb@@3333vUTb@cQRb@|Qb@@3333Qb@; Qb@fffflSb@Sb@"Ub@hfffRXb@̤m[b@@3333-)bb@\b@ffffKb@ffffgMb@@3333H@b@db@hfffb@žb@ffffHb@ffff=Db@hfffb@ffffhffffb@@33334333sb@@3333ThfffFb@b@ffffKb@8333s"hb@hffff"4333b@"Yc@LXc@@3334333Wc@DVc@4333Wc@pffff.hfffVWc@Xc@0Zc@pfff4333[c@pfff_c@pfff(cc@{ec@Tfc@@3333PHgc@vhfffVjc@kc@nc@hfffpc@pfffrc@pfffhfffntc@hfff~wc@.hfffRzc@4333;|c@pfff4333}c@B̤~c@LhfffTc@4333Tc@@33334333Rc@BpRc@@3333hfffRc@HQc@q`Sc@#hfff>Tc@@33334333Uc@L7 Vc@DWc@LYVc@hfffTc@UTY@3333LS2#@3333WS Q!@(YS0333J!@\S!!@^S03333 @ZS @ffffXS @VS @ffffRS`fff_ @ffffMSY @3333LS@ffffMS`fff@RS0333@ffffVSX@33337WS @3333sVS@3333sbSC@ffffeS,@3333gSB@ffff&jSى@4mS@nS@oS0333@3333pS@33333qS@oS%@pSL@3333uS0333s@̬yS@{S@3333S,@4S@3333S9 @3333S $ @0S`fffF" @dS/ @PSF @3333S~ @S @S̬ @ISY @ffffS̑ @|S`fffu @ffffZuS`ffffM @̬pS9D @ffffvS0333n @̀S @̨S0333S @]S0333s @3333[SL @5S̬ @ffffFS0333 @ffffS`fff @dSL @hS`fff @S @̌S`fff!@3333ӘS`fff @S0333S @ffffFS @3333;S @S @3333 S0333 @ffffSA!@̼Slm!@ffffުS|!@tS!@ffffBS`fffF!@IS03333!@!S0333s!@3333Š!@S`fffF "@AS0333"@tS̬!@ffffNS0333S!@Sy!@3333S0333!@S!@S0333Sl!@8S`fffFG!@3333S`fff0!@ T`fff @ffff T @̘Tٓ @T` @`Tm @T`fffG @QT0333s' @3333/T @eT0333@3333Th@T @T03333f@T @ffffNT@Tٻ@3333cTٳ@IT0333@ffffT0333sL@ffffŤ@3333*T@6TY@9T@:T@3333?BT03333@ffffDTY@3333FTY@JT`fffj@3333{KT`fff:@ffffLT0333s@NT{@-QT@3333WT@D`T@ffff>kT`fff& @3333olŤ$ @nTlF @ffffwT0333T @ffffJ~T n @0T r @3333;Tc @3333[T0333u @T@ @YT @3333T`fff& @}T٤ @ffffT`ffff @ffffnT ~ @T03332 @3333GT,$ @TB @lT03333f @3333T @3333T̡ @T @ؿTL @$T03333 @Ť @T !@ĶT`fffFE!@̰T {!@ffffrT0333S!@ffffT!@\T0333!@̔T`fff!@3333oT`fffF!@T`fff!@hT"@ffff.T`fff"@3333WTl"@ffff&T"@4T`fff&"@T`fffF"@ T#@T@$#@DT/#@LT#@8T#@3333T #@T#@ffffnT#@T@'#@T`fff #@3333Tl"@ffff>Ť"@ffffT̬"@ffffTk"@pTa"@TLn"@ffff T,b"@،T0333V"@T`fffH"@̠T "@T!@T`fff!@9yT`fff!@tT`!@3333qT!@33337uTY"@yT8"@3333?yT`fffG"@uT`fff<"@]sT0333%"@̔mT0333 "@3333bTl!@̴VT`fff!@ffff MT̒!@ DT0333!@̬5T@!@3333K+T03333 "@#T0333)"@ffff"Tyk"@3333S"@̐S"@S0333"@3333GS`ffff"@ffffS#@ffffS2#@S0333s##@3333SY#@3333/S0333#@SY#@fffffS"@S`"@ffffS"@3333GS`fff"@LSx"@,uS""@3333lS`ffff!@3333WS Q!@ffff~Sl @ffffºSv @S @ffffFS @ffffzS`fff& @S @3333S`fff @3333˶S @̴S @3333Sٚ @ffff~Sl @fTT@ffffjT`ffffO@IqT@{@vT03333@3333vT0333@vT@ffffsT^@%pŤ|@nT|@jT@xmT03333@ffffvlT03333@ffffBgTL@fTT@T"@̤T "@3333T0333"@ffffT "@ffffTL"@T"@0S`fff& @Slk @)S0333 @)S@ @uS0333s @0S`fff& @VQd`@,@4333`@03333@ e`@ 3335@d`@,@Qd`@ 3333@`d`@P@d`@n@e`@|@4333f`@`fffq@hfffe`@ 3333V@e`@ 3335@ `@03333@`@Lq@43333`@@̀`@`ffff@hfff`@03333`@0`@̌v@hfffz`@̌~@hfff`@03333@4333`@03333@4333?`@Y@$`@@ `@03333@W4333kN@7@CS@B@;1S@3333A@4S@1A@hfffv8S@ffffƷA@`;S@ffff^A@hfff>S@3333A@I@S@!A@CS@A@hfffAS@3333A@hfff@S@~A@9S@(xA@43332S@9sA@4333{0S@\pA@/S@|lA@,S@dA@4333 &S@0^A@4333 S@^A@4333;S@`A@ S@xUA@S@UA@ R@hNA@,R@ffffGA@4333cR@d@A@R@Y@A@hfffR@3333DA@hfffR@LA@R@3333QA@̔R@3333QA@4333R@3333RA@4333{R@VA@hfffR@pfff[A@hfffޟR@3333]A@9R@aA@R@pfffF\A@4333R@ WA@̄}R@̤SA@̄xR@CA@gvR@hfff>A@sR@6A@rR@i0A@hfffsR@̤)A@,{R@$A@4333;~R@IA@~R@|A@ |R@A@yR@3333 A@yR@ A@{R@3333A@4333|R@hA@4R@yA@`R@pA@hfffƏR@ffff@@hfffR@@@̍R@3333{@@R@Y@@R@@333@@hfff~~R@3333S@@~R@@333{@@AR@3333@@hfffvR@̼@@hffffR@@@R@@@ R@I@@R@8333+@@9R@@@R@@@YR@P@@hfff>R@@@@$R@8333[@@R@@@hfff6R@@@dfff&R@@@dfffnR@8333~@@R@v@@hfffR@0n@@̌R@̼g@@R@db@@R@b@@hfffR@i`@@yR@̬b@@4333sR@3333`@@,R@M@@R@lB@@4333R@4?@@|R@:@@0R@);@@R@`fff5@@R@/@@hfff^R@(@@XR@̼#@@R@xfff@@4333CR@xfff@@R@i @@4333R@p @@4333SR@ffff?@R@pfff?@hfffR@̌?@R@?@4333R@2333?@@XR@ffff>@R@>@̍R@>@4333R@ >@hfffyR@@333so>@yR@d>@hfff~xR@ffff&Z>@,{R@H>@̼{R@8>@̼xR@y)>@sR@pfff>@jR@>@4333]R@ =@lXR@23333=@hfffNTR@2333=@PR@ffffV=@4333NR@fff=@hfff6HR@)]=@8@حQ@<8@4Q@?8@4333Q@pG8@4333Q@4333T8@)Q@4333b8@hfffQ@dfffk8@PQ@4333i8@Q@dfff6[8@IQ@I8@0333+Q@Pfff=8@YQ@ 18@4333{Q@+8@sQ@L*8@hfffmQ@0,8@hfffhQ@dfff98@cQ@E8@a\Q@ F8@0333 OQ@̬D8@hfffGQ@dfffD8@LCQ@LI8@4333?Q@E8@hfff9Q@J8@4333C7Q@9D8@43335Q@dfffC8@433333Q@ O8@hfff1Q@PP8@03330Q@pfffN8@hfffV/Q@J8@.Q@D8@X.Q@pfff7@4333%Q@4333s7@hfffFQ@̜7@hffffQ@l7@Q@7@Q@7@ Q@y7@hfff Q@dfff7@dQ@7@hfffVQ@7@hfff^Q@dfff&7@Q@y7@P@ 7@ P@dfff7@4333kP@7@P@̜7@P@dfff7@TP@|7@ P@7@4333;P@dfff7@̄P@̬8@ P@dfff6 8@hfff^P@8@`P@4333s8@P@,8@yP@LC8@yP@dfff&^8@P@8@pP@̼8@hfffP@dffff8@P@8@hfffnP@9@hfffP@99@yP@dfff`9@4333+P@|9@hfffnP@I9@P@9@P@43339@4333cP@̍9@dP@dfffF~9@ЖP@43339@hfffP@,|9@hfffP@r9@əP@4333cr9@4333P@:@hffff O@yQ:@ O@ffffv^:@4333O@fffff[:@4333O@ffff^:@;@YO@2333@;@,uO@7;@4333gO@̼:;@aO@ @;@Y`O@D;@aO@L;@4333aO@2333S[;@4333fO@q;@gO@<;@4333#dO@;@^O@ffff<@aO@3<@hfffaO@Y><@_O@̼@<@[O@ffff@<@4333CHO@23333<<@7O@ffff&]<@0-O@,j<@hfffO@2333z<@9O@2333}<@hfffN@<@hfffN@<@N@ffff<@N@2333<@N@̌=@@N@ffffC=@4333sN@T=@N@2333c_=@yN@=@`N@ffff֩=@4333kN@2333=@N@ٿ=@N@i=@ O@ɇ=@/O@ffffl=@=O@h=@hfffO@|=@IO@n=@QP@ffffVd=@̌P@ j=@ P@u=@P@ffffƁ=@43333P@Y=@Y!P@2333=@hfff-P@0=@43334P@l=@:P@2333=@FP@9=@̌KP@=@$^P@̦=@4333jP@=@4333}P@fffff=@TP@=@̎P@=@\P@ffff=@hfffP@2333=@яP@2333# >@4333CP@>@ P@ffff1>@̌P@ffff6R>@4333CP@2333À>@\P@>@43333P@2333>@4333kP@ffff>@ԟP@>@hfffFP@ >@!P@?@4333P@ ?@hfffήP@1?@4333P@C?@(P@?@4333cP@23337?@4333P@P@ t?@P@?@P@?@YP@ffffV?@Q@?@TQ@fffff?@hfffN Q@?@ Q@?@xQ@ffff?@hfff^Q@ffff&?@4333S!Q@L?@@&Q@?@hfff+Q@|?@̬-Q@2333C?@2Q@|?@̜7Q@\?@L>Q@٪?@QEQ@ ?@hfffKQ@̌?@QQ@2333?@4333kPQ@ffff@@4333sOQ@ffff~7@@hfffRQ@C@@WQ@K@@YQ@3333cW@@YQ@3333a@@]Q@j@@`Q@@@hfffVdQ@ffff6@@ mQ@ @@4333zQ@fffff@@hfffƅQ@3333[@@hfffQ@ffff@@0Q@<@@Q@33333@@hfffQ@t@@Q@$@@hfffwQ@ffff@@xQ@ffffA@Q@A@4333;Q@@@ؔQ@ffff@@4333Q@@@4333۩Q@@@LQ@ffff@@LQ@\A@Q@dA@4333Q@ffffA@Q@"A@ Q@I/A@xQ@07A@hfffQ@ffff>>A@̽Q@3333CA@4333 Q@ffffFA@43333Q@LA@@Q@ffff>WA@4333sQ@cA@4333Q@oA@4333Q@ffffntA@ Q@{A@Q@3333A@Q@3333A@Q@IA@hfffQ@lA@̼Q@3333A@Q@ffffA@Q@A@Q@ A@4333Q@iA@pQ@ffff6A@Q@A@4333Q@ffffA@8Q@3333{A@4333Q@xA@\Q@A@qQ@A@Q@!A@Q@ffffB@Q@3333cB@Q@ffffB@Q@B@hfffQ@%B@Q@X0B@hfffQ@ffff7B@Q@6B@4333sQ@ffffF7B@Q@8>B@Q@`DB@hfffR@ffffQB@ R@ffffYB@R@3333 ^B@R@ffff_B@R@ffffbB@"R@fB@'R@0jB@ 1R@jB@?R@mB@yGR@,oB@PZR@3333pB@hfffnR@3333qB@9qR@qB@zR@,mB@hfffR@3333[iB@|R@iB@hfffvR@rB@hfffR@}B@hfffR@ffffւB@pR@B@LR@3333B@hfffR@B@hfffֵR@3333S}B@R@yB@hfffR@3333{B@4333sR@3333[~B@4333KR@3333|B@0R@tB@hfffR@qB@hfff&R@ffff~^B@tR@ffff\B@R@1aB@4333R@^B@4333kR@3333XB@hfffR@)SB@4333R@LB@hfffR@3333BB@4333R@3333:B@\R@33330B@hfffR@̜B@R@$B@R@3333S B@4333cR@DB@|R@@B@4333S@A@S@3333A@̜S@A@hfffv S@A@a S@A@4333S@A@S@(A@! S@iA@H#S@3333A@$S@A@p(S@\A@.S@ffffA@1S@3333A@X4333#I@0@43333M@9[:@ l\M@84@\TM@ 44@ RM@54@4333RM@\V4@dM@ 4@43333qM@94@4333yM@4333#4@hfffjM@dfffl4@bM@PD4@l\M@84@hfffJ@0@43333J@̼0@p{J@|0@̬sJ@9 1@hfffkJ@,1@yfJ@dfffD1@hfffV]J@dfffL1@WJ@e1@4333#RJ@4333s1@hfffvLJ@dfff1@FJ@dfff1@4333#AJ@)1@hfffv;J@̼1@5J@P1@4333#0J@2@hfffv*J@4333s22@$J@4333L2@4333#J@dfffe2@yJ@dfff&2@J@2@4333#J@L2@yJ@2@J@4333s2@4333#I@43332@,J@ 3@43333%J@3@9;J@dffff(3@8@ K@̌Y8@K@0b8@hfffK@ll8@4333SK@}8@hfffK@̓8@hfffK@8@K@8@4333SK@43338@K@<8@4333SK@I8@4333sK@8@9K@dfff8@hfffFK@4333c8@4333L@dfff8@4333#L@`8@L@\8@hffffK@@8@43333K@43338@4333L@Y8@,L@ 8@4333 L@8@hfffL@dfff8@43333L@4333S8@I"L@8@4333#(L@i8@,-L@)8@1L@̬8@4333>L@4333c8@RL@dffffx8@hfffcL@dfffU8@tL@4333s&8@L@7@4333#L@97@@L@̼7@̜L@dfffV7@iM@p7@)M@43337@4333S2M@@7@@M@I7@IM@7@4333bM@dffff7@IjM@e7@̬tM@̌U7@}M@dfff<7@4333ӃM@l!7@M@6@̧M@6@hfffM@,6@M@6@ M@Ћ6@`M@L6@43333M@k6@hfffM@ N6@hffffM@L86@hfff&M@dfff 6@hfffM@̌5@@M@dfffF5@̌M@43335@M@4333so5@̈M@J5@hfffrM@5@`XM@4@`DM@4@43334@L@4333#4@̬L@`3@L@43333@iL@̬3@L@`3@4333cL@dfffn3@L@@3@)L@\%3@4333L@`3@hfffL@433332@L@dfff62@hfffƶL@̜2@L@2@hfffzL@2@iL@dfff2@SL@\2@FL@|*2@hfff1L@1@"L@dffff1@4333K@i1@4333K@dfff1@4333SK@1@K@1@|K@dfff61@hfffK@^2"ffffM@̌@@̔T@ 7F[g8u[hfffF4@\BQ@8333}4@!BQ@4@ffffVAQ@hfffFH4@;Q@LV4@9Q@Y4@Q6Q@hfffQ4@ffffB0Q@8333s=4@+Q@%4@ffff&Q@hfff3@̰"Q@8333s=4@Q@8333S4@Q@hfffF3@3333Q@3@3333/Q@83333@Q@LB3@Q@y 3@̈Q@hfffF2@ffff Q@83332@ Q@`2@ffff#Q@8333M2@#Q@)2@!Q@hfff%2@Q@'2@3333GQ@9-2@3333 Q@ 2@ffffQ@2@3333Q@̬1@P@83331@Q@S1@̤Q@hfff+1@Q@0@HP@hfff0@ffff6P@0@3333P@hfffu0@PP@N0@QP@̌10@TP@ 0@@P@8333H0@P@8333S\0@ P@,o0@P@8333k0@P@Lg0@̄P@<0@}P@@333/@4P@@3333/@UP@̌.@YP@@333.@̔P@@333.@!P@N.@ffff:P@.@̸P@-@ffff։P@pfff&-@3333GP@L8-@ffff{P@@3333E-@vP@pfffD-@rP@ 1-@3333oP@Y-@ffff^iP@,@3333KSP@@,@3333PP@@333s,@3333JP@@333:,@(@3333{TO@pfff:(@3333KO@pffff(@ffff$O@L(@\O@(@ffffnO@pfffw(@ N@̌O(@AN@̌(@̤N@@(@XN@@33331)@IN@ك)@ N@@333)@N@@3333)@(N@ )@dN@)@DN@pffft)@3333ۍN@i)@N@@333])@ffffN@pffff(@PN@(@N@(@XN@(@1rN@(@ffffFXN@̌)@EN@pffff-)@9N@ )@`-N@)@'N@)@3333N@pfff(@3333 N@(@ N@(@ffffM@pfffV(@M@$(@M@'@ffffM@@'@̌M@@3333'@(M@pfff&'@M@YP#@P|M@pfff<#@yM@pfff&#@lwM@@333"@̬mM@pfff"@ gM@Y"@_M@@3333z"@^M@@3333c"@ffff[M@@3333["@fffffVM@Y!@HM@@333 !@y&M@ٟ @3333M@ U @M@pfff& @M@@< M@@ffffM@@M@@M@@ffff M@@ M@̔@tM@@3333@IM@@3333KM@6@M@@M@@3333@p M@@ffffM@@333\@t M@ffff8@M@Ll@3333M@@̬M@@M@@333@!M@ffffx@"M@L@4!M@ffff@L"M@8@0M@@ffffV7M@@ffffCM@X@iOM@@333@ffff\M@@LiM@fff8@3333|M@fffr@ffffM@j@zM@ffffe@doM@@oM@L@3333xM@t@ffffM@H@3333M@e@yM@ffff@l~M@@ffffM@@M@@ffffVM@@3333ӗM@̿@3333M@@333@HM@fff3@ M@@333@3333M@9@ffffM@L@M@@ffffM@@3333@3333kM@ffff@̬M@@ M@a@ffff>M@@3333@8M@@ffffM@A@ffffFM@@ffffM@s@3333KM@ffff@ffffΔM@̆@M@@M@@3333;M@@33338@@M@@3333@M@@ffffFM@ffff@ffffFM@ffffQ@3333M@@333@M@x@3333M@@QM@@M@@xM@@333<@dM@fff@ffffM@V@M@ @iM@@yM@ffff"@ffffM@ffff@N@G@ N@r@N@@333k@3333#N@fff@3333N@e@ffff.-N@@3333+4N@ffffK@(.N@@XN@@3333N@̤@/N@@3333@ffff5N@&@ :N@@ffff6=N@@AN@@3339@@N@Lc@̤5N@@Q,N@@3333h@3333#%N@@PN@@HN@@ffffN@4@3333[N@@HN@ffff:@1M@ffff@̬M@fffi@3333KM@@3333@M@@̌M@@ffff6M@L@M@ffffq@3333{M@ffffk@M@z@ffffM@@3333M@@HM@@N@@A N@@ N@@3333N@ffff@ N@@N@ffff@N@K@IN@ffff@N@@333$@TN@@y'N@ffff@ 9N@@3333@ffff>N@/@ON@fff@XN@[@ffffXN@@ON@fff@HN@v@hQN@L2@ZN@ @mN@@3333@3333wN@@3333N@@333a@!N@@N@'@ N@ffff@ffff.N@@N@+@\N@@ɊN@p@N@@3333;N@@3333N@ffff@)N@@@N@'@yN@O@{N@/@N@)@3333N@.@̬N@k@3333N@@pN@fffb@yN@ffff@N@@3333@N@S@ffffN@fff@XN@@33331@XN@@)N@@333@ffff>N@@3333@̌N@ffff-@ffff^N@̠@qN@fffp@3333SN@fff@N@Lf@3333N@,@LN@ffff@ɓN@@333@3333#N@T@iN@L@N@@N@ffffL@3333ۍN@Lm@N@@3333@3333N@@333@XN@@N@@3333N@@LN@Z@$N@@̤N@@̌N@e@aN@@ffffN@@N@@3333@N@ffff@lN@@333@AN@w@TN@@ffffN@L,@ffffN@@3333@N@fff@YN@L@TN@@333@N@ffff@N@L@N@ffff@!N@ffff@ N@L@N@ffff@ffff~N@b@iO@@xO@@333@ffff&O@fff,@3333O@Ln@3333kO@@3333O@fff@3333O@"@3333'O@ffff@0O@ffff/@<1O@@@5O@L@4O@@3333@ffff0O@U@,O@@(-O@R@!4O@fffz@ffff.6O@@;O@@3333[9O@ @I5O@ffff@(4O@Ly@<9O@@333@=O@@3333@̌BO@ffff@3333JO@ffffi@9NO@@ NO@@3333y@ffffOO@@ffffQO@@3333@9PO@"@MO@@3333{EO@G@3333+FO@̜@1HO@L@JO@@ffffNO@@RO@L'@ffffVO@8@I\O@pfff0 @̬]O@L @bO@@3333@3333@fff@L`O@q@A`O@@I]O@@333@YO@@@\O@L @3333eO@@̌sO@@wO@@333@̔zO@ffff@3333O@I@̼O@@O@@333@3333KO@q@pO@3 @̤O@l @lO@ @ffff{O@ ?!@QlO@pfff7!@ffffpO@Y @fffffO@pffffx @̄O@pfffP @̬O@@333s^ @ffffFO@ @ffffO@ )!@O@pffffE!@ѫO@@3333H!@0O@0!@3333O@ @3333KO@pfff @ffffO@@333 @3333ۿO@ @ffff~O@'!@3333O@pfffX!@O@L!@̬O@̌E"@O@@333P"@3333{O@&"@ O@+"@QO@pfffO"@3333˺O@@333"@O@ #@O@Y4#@ffffO@d#@O@#@O@@333s#@3333O@@#@3333KO@Y#@O@ $@ffffO@@)$@3333cO@̌`$@ffff6O@$@3333O@̌.%@ffff>O@@333h%@ffffVO@@3333%@3333 O@i%@ffffO@pfffX%@lO@Ys%@O@@333%@YO@@333%@ffff^O@Y<&@ffffO@s&@O@̽&@O@pfff&&@9O@&@O@m&@fffffO@pfffY&@ffffO@ٖ&@ffff^O@L&@0P@&@P@&@ P@Ym&@P@&&@3333{O@%@ffffO@@333%@fffffO@@3333&@0O@pfff%@ffffO@pfff$@O@@3333$@O@#@O@#@O@pfff&#@O@@333#@O@P#@AO@@333s0#@O@@333s"#@3333cO@:#@̼O@j#@̴O@#@3333{O@#@O@$@ffffRP@@333x$@3333 P@!%@P@%@P@Y%@$P@L.&@T'P@pffffs&@|+P@pfff&@ffff+P@@3333 '@/P@ D'@33334P@'@ffff^4P@@333&@x1P@@333&@ffffN0P@pffff&@5P@pfff&&@ffff9P@̌&@t>P@Q(@tKP@t(@MIP@@333(@̀EP@L)@\FP@ z)@̸MP@)@ffffUP@)@QTP@@n)@ QP@)@LP@(@KP@L(@3333_LP@(@hOP@ن(@dPP@@3333f(@OP@̌D(@QP@̌>(@0WP@i(@ffff_P@@333(@\dP@̌(@ThP@pffffA)@sP@@333`)@yP@@3333)@|P@L)@3333C|P@@333*@33333}P@)@ffff:P@)@lP@L)@mP@@3333*@ffffP@LY+@̄P@@333+@%P@pfff+@ԏP@,@3333 P@@+@ffffvP@\+@ffffP@@333s*@3333P@@3333*@ffff*P@@*@ffff&P@<*@3333ÎP@pfff"*@ffffP@5*@P@b*@`P@@l*@3333P@pfff*@3333P@*@3333˭P@Y +@3333wP@>+@ffff޲P@@333s+@P@@+@ffffֲP@+@pP@h+@P@M+@ P@ t+@P@pfff+@}P@pfff+@P@@333s ,@P@@3337,@P@@i,@ffffP@@,@,P@,@!P@̌3-@ P@-@ffffrP@.@P@.@P@pfff.@qP@-@,P@)-@P@pffff,@aP@pfff&,@ffff^P@̌,@P@-@ffffP@@3333(-@̴P@̌-@P@-@P@@333=.@P@ .@P@.@XP@@.@P@/@3333P@Y0/@ffffNP@&/@hP@ b/@ffff^P@R/@P@.@ffffP@@.@P@Y.@P@@333o.@P@@333s.@3333OP@ .@P@.@ffffP@pfff.@3333P@-@tP@ -@1P@pffff-@P@ -@P@.@3333+P@D.@@P@.@P@@.@3333P@pffff/@3333GP@pfff&>/@̰P@pfff&6/@9P@.@3333;Q@@333.@UQ@̡.@fffffQ@@.@̔Q@@3333P/@̄ Q@ٳ/@̨ Q@hfff0@3333Q@ 0@ffff Q@hfff0@3333 Q@0@Q@B0@P@8333O0@iP@83333B0@Q@hfffO0@HQ@hfffF_0@Q@Yd0@Q@Q0@3333Q@B0@@ Q@,0@Q@,40@EQ@Lc0@ffffQ@l0@Q@l0@̼Q@̌0@3333Q@83331@Q@ V1@3333CQ@z1@HQ@hfff1@HQ@91@3333Q@1@ffffQ@z1@3333[Q@m1@Q@31@dQ@0@ffffQ@y0@3333gQ@̬0@"Q@8333s0@ffff%Q@0@ (Q@y0@+Q@8333!1@a,Q@ d1@(3Q@8333s}1@=8Q@ً1@ffff@Q@`1@3333gFQ@2@JQ@83332@̘KQ@L2@3333NQ@hfff&2@TQ@02@[Q@B2@ffff^Q@ K2@h^Q@8333`2@ffff&\Q@̌{2@YWQ@@2@TQ@hfff2@ TQ@y2@ffffzUQ@2@8XQ@ٟ2@[Q@L2@e_Q@̌2@MaQ@@2@3333aQ@2@ffff~aQ@2@cQ@3@̜eQ@hfff3@3333gQ@8333 3@DjQ@23@oQ@3@̀sQ@83333@ffffrQ@,3@ffff:gQ@hfffƣ3@ffff>`Q@93@3333#[Q@3@ffff>`Q@Y3@33337nQ@hfff3@fffftQ@hfff4@ffffxQ@y%4@dyQ@94@3333W{Q@S4@|Q@Z4@{Q@ c4@3333wQ@,U4@3333SkQ@8333V4@3333wgQ@8333F4@3333KbQ@83333 4@3333VQ@8333 4@ffffJUQ@8333s4@ffffUQ@24@WQ@|4@bQ@L4@PaQ@4@5bQ@Y4@leQ@4@hQ@`4@3333OlQ@hfffƋ4@xvQ@@4@}zQ@ 4@zQ@4@zQ@95@xQ@)5@xQ@8333@5@4Q@8333n5@؀Q@5@|Q@83335@xQ@hfff5@$tQ@hfff5@iuQ@5@EQ@5@ffff:Q@5@HQ@f5@ffff*Q@hfffX5@TQ@8333[5@Q@5@}Q@5@ffffQ@5@ffffƒQ@ 6@Q@,86@ɓQ@lR6@Q@b6@ffffƑQ@8333k6@3333Q@@6@Q@hfff6@ffffʕQ@83336@̄Q@6@3333'Q@hfff 7@̄Q@L-7@܁Q@hfffB7@ffffQ@Z7@~Q@8333sf7@DQ@lO7@Q@9I7@Q@@T7@3333CQ@ a7@ffff֏Q@hfffF7@Q@̬7@Q@ 8@Q@I8@dQ@hfff[8@tQ@hfffk8@Q@Lg8@3333Q@hfffD8@tQ@8333sC8@ffffQ@q8@3333Q@8333s8@Q@hfff8@ffffQ@hfff8@Q@ 9@ffffnQ@8333+9@3333ϷQ@C9@Q@LS9@\Q@hfff&`9@Q@o9@\Q@9@̤Q@8333S9@Q@@9@Q@hfff9@ffffQ@ 9@ffffFQ@hffff9@̼Q@w9@Q@hfffF9@ffffZQ@833359@ffffRQ@y%9@̼Q@hfff8@3333Q@83338@33337Q@9 9@ffffQ@969@Q@9k9@ffffQ@8333sx9@̕Q@83339@ffffQ@;:@ffffQ@hfffƁ:@3333kQ@L:@$Q@hfff:@̠Q@:@lQ@hfff:@3333ӪQ@hfff:@Q@̠:@AQ@hfff:@8Q@:@3333 Q@hfffƕ:@=Q@hfff:@Q@hfffF:@ffffQ@@;@Q@8333%;@̘Q@hfff/;@ffffQ@83333O;@mQ@hfff;@tQ@@;@Q@D;@=Q@9<;@3333Q@hfffT;@ffffʿQ@٘;@Q@hfffƻ;@,Q@hfff;@Q@hfffF$<@Q@ld<@3333kQ@a<@̤Q@̬S<@дQ@E<@Q@8333s;@Q@hfff;@3333cQ@8333;@3333Q@833337<@Q@8333E<@Q@hfff3<@Q@hfff0<@,Q@*<@Q@*<@hQ@hffff1<@Q@8333G<@љQ@8333SO<@3333[Q@8333o<@ffffQ@|<@ffffQ@<@ffffQ@8333<@3333۵Q@<@3333KQ@83333=@ffffQ@83337=@Q@83333R=@Q@e=@Q@=@3333Q@8333Ӹ=@ɪQ@̼=@eQ@hfff=@3333Q@=@pQ@̬>@Q@<>@ѧQ@3>@Q@83336>@ŢQ@ l>@Q@̌>@Q@hfff&>@Q@>@Q@8333>@Q@ x>@Q@8333SC>@3333Q@hfff=@,Q@<@ffffNQ@hfff<@Q@8333=@3333~Q@=@e|Q@8333=@wQ@=@]tQ@̢=@qQ@8333ӱ=@3333oQ@hfff=@nQ@hfff=@%oQ@>@mQ@'>@oQ@.>@uQ@8333<>@ffff.wQ@LY>@iuQ@8333e>@ffffnQ@hfffm>@9nQ@|>@3333rQ@83333>@rQ@hfff>@rQ@hfff>@$rQ@8333>@ffffiQ@hfff&>@fQ@̌>@3333cQ@Y>@ubQ@8333>@3333aQ@̌>@bQ@83333a>@leQ@@:>@hQ@ .>@hQ@hfff(>@PhQ@L2>@(eQ@/>@̼bQ@)>@ffff`Q@!>@ffff]Q@Y>@[Q@y=@ffffYQ@,=@WQ@hffffc=@SQ@`Z=@QQQ@5=@5FQ@+=@DQ@Y=@ffff2CQ@@<@hAQ@8333S<@CQ@hfff&<@GQ@hfff<@ffffRKQ@`=@ffffnRQ@1=@xWQ@hfff&==@ffff6YQ@YU=@E^Q@@$=@jQ@hfff<@nQ@hffffi<@tQ@hfffD<@wQ@ <@0~Q@8333;@ffffQ@8333s;@ffff&Q@y;@Q@Y;@q}Q@hfff4;@zQ@hfff ;@zQ@8333;@ffffyQ@,:@fffff{Q@:@3333{Q@8333:@H{Q@:@zQ@hfffN:@3333 rQ@':@mQ@̌:@ffffBlQ@8333:@iQ@hfff&9@eQ@hfff9@tWQ@hffff9@3333RQ@hfff9@NQ@hfff9@3333DQ@83339@ffff^?Q@̌9@3333:Q@hfffF9@33338Q@{9@\8Q@l[9@ffff27Q@hfff?9@̐4Q@@,9@ffff0Q@@9@3333(Q@8@%Q@l8@&Q@hfff8@)Q@8333}8@3333,Q@U8@-Q@8333s'8@ffff0Q@8333S7@3Q@7@3Q@hfff7@0Q@7@-Q@hffffv7@ffff^+Q@8333R7@̈)Q@8333$7@ )Q@Y7@(+Q@6@,Q@,6@.Q@83333i6@ffff.Q@hfffb6@1Q@hfffL6@ffff6Q@hffff6@?Q@L5@BQ@5@3333IQ@,5@3333SQQ@5@ffffQQ@8333v5@ffffQQ@LD5@QQ@$5@3333OQ@5@MQ@y 5@KQ@ 5@,EQ@5@|CQ@83335@BQ@hfff4@ffffDQ@hfff4@ffffrDQ@hfffF4@\BQ@@333@3333ӊN@{@4N@@33332@ffffN@@3333L@ЖN@Lr@ИN@ffff@̄N@@N@@333@3333ӊN@fffW@ffff^'N@@3333[@)N@fff@PN@@$N@@3333@ffff"N@@3333+N@ffff@ffff4N@@3333@@9N@ffff@9N@ffff3@1N@fffW@ffff^'N@hfff=@ffffrQ@hfff&=@3333qQ@hfff=@rQ@83333=@3333uQ@=@yQ@=@yQ@83333=@3333wQ@ >@uQ@hfff=@ffffrQ@'@hP@'@ fP@'@̰fP@'@ahP@̙'@kP@@3333'@-mP@'@fffflP@pfff(@|kP@'@hP@ @dO@Y @O@ @O@ @̬O@@333j!@O@w!@O@!@ffffO@L!@ffffO@@3333!@O@@333!@3333 O@ @dO@4 @ffff6O@pffff @ O@@O@fffB@IO@L7@3333O@fff@3333O@pfff% @3333CO@@333E @ffff6O@pfff&H @ffffO@4 @ffff6O@hfffp7@5Q@k7@4Q@c7@@Q@ N7@0Q@8333s7@Q@6@̴Q@6@lQ@@6@̨Q@83336@3333ǣQ@6@3333Q@6@Q@hfffn6@ffffQ@8333[6@ffffQ@83333+6@Q@hfffF6@@Q@5@ffffQ@hfff+6@Q@̌;6@ffffQ@̬Y6@3333Q@hfffk6@3333Q@6@ffffQ@̬6@ffffQ@̬6@̀Q@hffff47@0Q@G7@Q@hfffFe7@Q@hfffp7@5Q@9@Q@9@Q@9@ffffQ@:@3333Q@%:@3333Q@@":@3333Q@9@hQ@83339@Q@9@3333 Q@9@}Q@hffff{9@@Q@P9@3333/Q@8333P9@dQ@hffffl9@*@)Q@ 2*@,Q@L2*@ffff6P@@3333&*@P@̌)@P@ j.@\6Q@ -@33338Q@pfff-@|:Q@@3333.@<9Q@Y.@@Q@pfff&4.@3333@Q@A.@@@Q@pfffY.@>Q@ j.@\)@ffffևP@')@ffffP@(@ĂP@v&@ffffj7P@pfff[&@ffff5P@ &@7P@@%@5P@z%@33337P@%@ffff;P@ &@3333>P@pfffC&@y>P@ ~&@3333:P@v&@ffffj7P@hfffƀ1@(fQ@̌1@bQ@hffff1@ffffcQ@1@dQ@1@bQ@l1@l`Q@ 2@Q`Q@` 2@H]Q@hfff2@TYQ@hffff2@`VQ@,1@ UQ@83331@ffffQQ@`1@ffffLQ@hfff1@ffffKQ@8333s1@DJQ@hfff|1@̘LQ@R1@ffffRHQ@83333)1@̨AQ@ 1@@Q@1@BQ@0@pDQ@y0@ffffDQ@0@ffffFQ@83330@0GQ@hfff0@3333HQ@`0@33333LQ@`0@8RQ@833330@$UQ@8333s1@)WQ@@1@ffffYQ@`\1@ffffjXQ@e1@3333ZQ@_1@ffff\Q@:1@ffff^Q@@1@ffff>`Q@hfff[1@̼aQ@ t1@ffffaQ@̬{1@udQ@|1@3333eQ@hfffƀ1@(fQ@L/@3333#Q@@333s/@x#Q@@3333/@)Q@@0@+Q@hfff0@ffff-Q@ 0@/Q@0@(3Q@̌&0@5Q@@:0@6Q@̌F0@ffff7Q@83333T0@8Q@l0@5Q@z0@3333c3Q@ 0@-Q@0@3333(Q@hfffV0@X$Q@hfff10@ffffv"Q@hffff 0@̬Q@Y/@ffffQ@@3333/@Q@پ/@3333;Q@/@-Q@/@ffff.Q@@333s]/@Q@.@Q@̮.@Q@̌.@4Q@@3333.@Q@@3333`.@Q@@33332.@ffffQ@L.@Q@̌-@3333Q@B-@ Q@@333,@h Q@ك,@5 Q@@333,@qQ@pfff&,@Q@@333+-@3333Q@0.@@Q@@.@i'Q@.@ffff3Q@pfff /@33337Q@/@d:Q@pfff&.@:Q@.@̠>Q@L.@BQ@̌L/@|HQ@pfff{/@JQ@ /@QQ@@/@TSQ@L 0@TSQ@hfff&!0@QQ@hffff0@MQ@@/@5GQ@/@̌AQ@pfff/@|=Q@/@$:Q@/@m4Q@/@.Q@ٔ/@}'Q@L/@3333#Q@9!̴Q@0333s"ffffJQ@2"ffffQ@`fff!ffffQ@`fff !ffffQ@ Q@0333 3333_Q@L3333{Q@0333 Q@̚ 3333˾Q@LE!0Q@9!̴Q@hfff&83@ffffR@93@R@hfff2@HR@hfff&2@R@y2@R@8333.3@%R@8333B3@3333R@8333SF3@3333;R@hfff&83@ffffR@@:@S@:@`S@hfffu:@S@`h:@ffff2S@̬t:@3333߳S@:@3333S@:@US@8333;@S@@:@S@4333SC@@T@?@ffff6T@`{?@T@4333s@@3333 T@@@3333T@hfff&@@ffffT@̌@@ffff T@@@@ffff T@4333SC@@T@̬5@ S@5@S@ 6@S@833356@3333S@̬L6@ffffS@hfffs6@ffffƍS@ 6@3333[S@hfff&6@ S@hfff7@ES@hfffZ7@S@8333s7@̐S@Y]7@ffffS@hfff&7@3333S@7@tS@T7@M}S@7@3333xS@ 7@XwS@=8@yS@L8@3333guS@8@lpS@9!8@ jS@8@\hS@y7@cS@Y7@3333_S@8333s7@3333]S@8333S7@̰YS@a7@3333WXS@83337@̤XS@hfff&6@3333WS@hfffF6@SS@@6@ffffQS@6@QS@Lm6@8TS@hfffx6@0US@8333|6@ WS@hfffFq6@ffffz[S@̭6@ffff`S@̌6@̄bS@8333s6@lcS@̞6@,cS@r6@dS@8333e6@|dS@,A6@aS@̌6@3333`S@,5@_S@hfff 5@8\S@4@3333k]S@hfff4@ffff.dS@y35@gS@`@5@mS@̌U5@dqS@Ln5@sS@5@̠zS@833335@3333{S@55@ffff^S@8333 5@ɃS@L4@S@8333S4@3333#S@@4@ffff֔S@l4@3333ךS@l_4@ffff^S@Y:4@̔S@\4@ffffS@ 5@S@lt5@ffff>S@̬5@ S@4@3333T@4@HT@5@T@hfff5@3333 T@Y5@0 T@5@T@83335@ffffzT@833306@ffffT@,J6@ffff&T@Y`6@̼T@8333Sq6@- T@9r6@T@j6@dT@hffffs6@ffffT@6@3333T@ 6@hT@hfff6@ffffT@6@T@ 7@UT@Y@7@ffffT@P7@33337T@hfff@7@`T@97@TT@8333S7@3333 T@8333sZ7@ffffr T@ 7@8 T@7@T@83337@ffff~T@$8@T@;8@fffffT@G8@3333T@,L8@T@8333g8@3333T@83338@T@8@3333KT@8@HT@833338@ffff>T@833338@̴T@hfffx9@3333T@9@l T@L9@ T@9@5 T@o:@3333; T@`:@= T@hffff;@T@%;@ffffT@2;@S@8333s;@ffffbS@8:@3333[S@:@}S@9@S@83339@$S@hfff&9@3333S@83333=9@S@hfff&%9@S@hfff8@̀S@hfff&8@US@hfff&b8@MS@A8@S@hfff"8@ffffS@7@3333oS@@7@(S@Y6@3333S@hfff6@3333S@6@3333S@83336@\S@8333S5@3333cS@8333s4@ffffvS@94@5S@hfff4@AS@hfffFf4@S@8333 4@US@8333s3@)S@83333@S@hfff&3@̌S@833333@S@4@S@hfff/4@3333wS@8333S~4@3333S@4@1S@8333ӯ4@ffffBS@4@S@8333u4@S@4@S@ 3@̠S@Y3@S@hfffff3@S@,2@ S@2@S@8333m2@S@ S2@S@hfffH2@ffffS@`A2@xS@92@ffffS@2@ffffS@ 2@XT@hfffX2@T@hfff&!2@ffffT@1@( T@hfff2@ T@2@ffffb T@@2@0 T@$3@T@hfffW3@3333sT@3@ffffr T@Z3@ T@13@T@,(3@QT@hfff-3@8T@hfffC3@̀T@8333S3@T@hfff3@T@hfffF3@ffffT@`3@T@8333s3@ffffT@83333@T@3@T@hfffF3@ffffT@3@̔T@hfff3@(T@83334@̄T@\4@̨T@8333y4@T@hfff4@T@4@3333T@hffff0@S@hfff0@S@83330@ffffS@83330@aS@hffff0@3333_S@,81@5S@hfff1@ffffS@L1@S@hfff1@4S@hfff1@ffffS@1@S@̌1@3333sS@1@ffff"S@hfff1@ffffS@ 1@S@833331@3333S@l1@S@hfffE2@pS@8333SU2@S@e2@3333S@ٔ2@̔S@2@ffff>S@hfff2@ffffzS@83332@ffffNS@2@S@̬2@S@83332@3333gS@8333S2@S@hfff2@S@83332@S@L2@ffffS@2@3333wS@hfff3@ S@}3@ffff>S@93@eS@3@̘S@ 4@S@L4@S@hfff)4@ffffRS@Lu4@ES@l4@3333S@hffff4@S@,4@3333ϾS@hffff4@3333S@83335@S@O5@3333S@@Z5@hS@hfffc5@3333cS@8333s>5@3333ìS@hfff5@HS@̌4@3333S@8333c4@3333+S@3@ffffڧS@@3@3333S@̬3@3333CS@Y3@ffffS@8333sa3@̴S@hfff&3@HS@@3@iS@2@S@hfff&2@S@93@3333wS@2@33337S@8333s2@3333S@Y2@̐S@2@ffffS@8333sp2@ffffS@@n2@eS@Lp2@ffffJ|S@lg2@rS@hfff\2@ffffkS@yL2@3333eS@Y:2@ffffraS@,#2@3333s`S@1@3333_S@83331@3333YS@hfffFq1@ffffjNS@@Y1@ffff JS@ '1@!CS@01@ffff@S@?1@3333>S@Y$1@ffffF9S@hfff0@3S@0@1S@ 1@ffff.S@ 1@,*S@hffff0@3333&S@8333S0@3333%S@@v0@3333&S@hfffX0@D)S@8333<0@,S@83330@D/S@hfff&0@0S@@333/@33338S@?.@ffffrES@z-@dJS@L,@̼LS@L,@OS@~,@ffffRS@pffffJ,@ffffzUS@,@ffffYS@pfff&,@ffff~\S@+@ffff`S@Y ,@bS@$,@ffffdS@Y,@eS@,@̈dS@L1-@mbS@c-@ffffaS@@333s-@lS@40@rS@0@sS@hfff1@ sS@0@ffffuS@0@xyS@Y0@3333WzS@hfff&0@UxS@`0@33337vS@/@ffff6vS@@333+/@wS@̌.@vS@1.@3333sS@-@qS@@33335-@ qS@ .,@ffff^qS@+@rS@ +@̤vS@+@xS@pfffm+@zS@@333s\+@́S@@333so+@S@L+@ffffƄS@pfff+@pS@@333+@yS@@333s,@3333GS@L,@3333SS@ ,@S@L-@S@̮.@$S@@333 /@S@pffffe/@̐S@@Q/@S@@333sP/@3333#S@Y/@ffffS@@3333/@S@y&0@S@hfff0@mS@1@S@hfff,1@ffffS@hfff0@S@̬0@lS@0@3333S@ 0@ffffS@r0@ffff:S@8333S0@9S@Y0@xS@̇0@S@@r0@ݨS@8333S(0@pS@Y/@S@\/@ffff*S@@333.@IS@L.@4S@ .@ffffvS@pfff&.@3333S@pfff.@ffffS@Y.@pS@.@(S@@333.@3333[S@@.@3333S@Ys.@ffffޮS@LF.@3333S@Y.@TS@-@S@pffff-@̘S@@333-@(S@@333|-@$S@pfff`-@$S@'-@ffffS@@3333,@9S@@333-@ffffZS@pfff-@(S@,@ffffS@,@̄S@Y-@̐S@F-@̈S@,@S@,@S@z,@ԓS@̌8,@ffffVS@@333+@ffffS@YO+@̰S@pfffL*@33333S@Y)@DS@@3333)@33333S@@333)@ffff~S@LT)@S@(@S@ (@3333S@F(@S@pffff'@S@pfff&'@ffff&S@@3333'@٭S@~'@ffff S@pfff'@ffffS@ٸ'@=S@8'@ffffS@&@3333ӼS@̌&@ES@Y'@S@(@3333S@(@3333S@(@S@(@ؽS@(@lS@@333,(@hS@@333s(@S@@333'@ffffS@@333'@S@'@(S@'@S@@(@3333S@+(@3333S@pfff'@3333S@['@ffffS@('@$S@;'@3333#S@ '@ffffS@&@S@̌j&@LS@pfff6&@S@pffff%@3333S@%@iS@@333%@ffffS@@3333%@3333S@pfffy%@ffffJS@@3333s%@S@Yy%@9S@%@S@Y%@ffff.S@Y_%@3333S@@]%@3333S@pfff&~%@yS@pfff%@3333S@Y%@3333S@pffff&@̨S@M&@3333S@^&@S@L&@3333;S@@333&@)S@g'@̄S@4(@4S@ i(@S@Y(@S@̌}(@S@@3333p(@S@Y(@8S@@333s4)@|S@́)@ffffS@ 7*@3333;S@b+@ffffS@ +@HS@@333+@3333S@+@S@pffff+@$S@+@3333S@*@S@Y)@ffffrS@pfff&n*@3333S@pfff*@S@pffff*@S@*@3333#S@3+@3333CS@@333n+@3333wS@٪+@3333 S@+@̼S@pfff&,@ffffS@,@̄S@ ,@yS@@333,@S@pfff& ,@yS@pffff,@3333{S@Y[,@̘S@@333s,@ffffvS@@333/-@ffffS@pfff-@ S@.@8S@pfff.@S@L.@S@R/@S@@3333/@3333'S@̌/@0@ffff*T@b0@]T@hfff&0@PT@hffff0@S@pfff&&@S@&@3333S@@3333&@S@̌;'@hS@'@S@ '@ffff2S@'@ffffS@(@3333S@;(@ffffS@'@dS@Y'@ffffS@L,'@ؘS@@333&@S@f&@=S@>&@ffffS@pffff%@3333CS@pfff%@S@A%@3333?S@%@S@%@ɹS@@333%@̸S@@333%@3333+S@@333s?&@33337S@LN&@]S@ (&@S@YO&@3333S@pfff&&@S@ٽ2@ffffBT@hffff2@T@hfff)2@qT@42@<T@̬J2@3333T@83332@3333KT@ٽ2@ffffBT@ =@3333_S@lX=@S@hfff&=@S@Y=@3333S@O=@̈S@8333<@3333SS@~<@ȸS@8333 <@ S@;@S@<@$S@_<@TS@,j<@S@ق<@S@`<@ffff"S@ =@3333_S@Z"P_@ B@hfffU`@3333E@ `@OC@ `@ffffMC@`@3333 CC@$`@`5C@e`@ffff-C@hffff`@ffff)C@4333?`@ffff~'C@_@t&C@8_@3333c'C@hfff_@(C@hfff_@(C@_@ 'C@_@(C@_@3333&C@_@ffffV$C@hfff_@C@)_@yC@@_@3333 C@hfffF_@ffffNB@̬_@fffffB@_@B@_@ffff~B@_@3333B@4333_@$B@_@ffffB@̬_@ffffnB@_@ B@hfffN_@B@x_@B@8_@ffffVB@D|_@B@9q_@ B@4333{l_@9B@hfffFk_@xB@8e_@3333SB@\_@xB@hfffZ_@ B@hfffV_@ffffB@YW_@ffffB@4333S_@B@hfffF_@B@hfffA_@B@H?_@9B@\L_@ffffC@O_@ffffFC@4333;M_@p C@hJ_@ C@hfff?_@ffff C@ :_@3333kC@43331_@ffff C@8,_@C@7_@C@hfff~8_@%C@4333[8_@3333+C@Q>_@t=C@PD_@3333CGC@S_@3333+UC@̔Z_@WC@y__@3333VC@|c_@ffffWC@hfffF__@(]C@hfff&[_@_C@!S_@_C@hfffJ_@3333gC@J_@ffffoC@8Z_@C@qZ_@3333éC@W_@̼C@W_@hC@hfffK_@C@hF_@C@43337_@C@hfff1_@C@I/_@C@._@3333{C@,_@C@(_@3333C@4333&_@C@̬#_@1C@_@C@P_@C@_@C@,_@̄D@hfff_@X D@_@@D@-_@(D@h1_@ffff1D@43338_@3333:D@hfffN<_@̤:D@?_@|;D@4333@_@?D@A_@ffffCD@4333D_@3333FD@hfffK_@qKD@ T_@3333RD@hfffZ_@xTD@b_@ _D@f_@̴cD@Ii_@̴cD@0j_@eD@ l_@YkD@̜n_@nD@,r_@ffffoD@hfffw_@4rD@L_@3333sD@hfffF_@ffff|D@hfff_@D@@_@D@4333;_@3333D@ _@3333D@4333[_@!D@_@ D@4333c_@ԭD@hfffޠ_@ffffnD@_@ffffnD@4333_@3333D@4333{_@3333 D@4333_@D@hfff._@D@hfff_@D@i_@ffffD@9_@ffffD@4333ӹ_@D@4333_@ffff~D@q_@3333D@_@3333D@hfffv_@hD@8_@D@_@3333D@_@3333D@T_@D@hfff_@D@hfff_@D@hfff_@4D@4333_@QD@4333_@ffffD@4333k`@ffffnD@`@33333D@4333`@3333ӱD@`@D@h`@lD@(`@ffffD@4333O `@ D@A `@D@@`@3333D@`@3333D@8`@3333sD@`@D@4333`@D@ `@D@4333`@ffffD@hfffr`@fffffD@ `@|E@ `@HE@ `@`E@hfff`@3333E@`@4E@`@E@̌`@E@`@ffffE@x"`@9E@4333G$`@E@A&`@ffffE@hfff&`@"E@&`@ffff(E@(`@ffff-E@ *`@4E@̴+`@88E@hfff-`@33337E@/`@̄4E@hfff0`@<1E@)2`@02E@4333S3`@33337E@4`@ffff8E@T6`@\9E@7`@`@qE@4333C?`@|E@hfff@`@ffff6{E@̤B`@|E@hfffC`@ffff^zE@4333D`@uE@̰G`@ffff&rE@hfffG`@oE@G`@ffffV_E@uI`@̬WE@4333K`@PE@hN`@tJE@O`@ffffIE@P`@DE@4333Q`@3333D@4333?`@6D@`@3333-D@q`@̤(D@4333`@TD@\`@3333D@4333 `@3333c D@hfff `@D@4333g`@3333+D@_@pC@hfff~_@ffffC@\_@C@_@ C@hfff_@ C@!_@C@hfffv_@ffffNC@hfffF_@3333SC@hfff_@ѯC@4333_@C@@_@̜C@hfff_@C@hfff._@ffffVC@4333_@C@P_@ĊC@0_@rC@`@hC@43333`@dC@4333`@3333c_C@4333 `@(WC@ `@OC@9_@̤C@T6_@C@hfff&6_@C@hfff8_@C@;_@C@9_@̤C@[ z}@ @A-@hfff+@l4@03333@@0333@̏@@@@fff@`fff@O@`fff@4@03333@@333s6+@h+@pfff+@hfff*@Y+@Y*@ ,@03333(*@@333Q,@9)@@3333W,@0333S )@@333Z,@(@pfff^,@(@e,@(@@333,@`fff(@@333,@03333(@@333 -@0333(@@333s)-@0333q(@̌,-@9k(@L=-@LM(@A-@`fff7(@<-@`fff&'@1-@'@pfff-@u'@)-@̬.'@&-@'@-@ &@,@l&@pfff,@`ffff&@g,@L&@YI,@@&@ ,@0333s}&@+@yl&@+@G&@Yf+@ %@+@5%@*@9$@@*@`fffW$@@3333*@`fff$@pfff*@̌#@|*@0333#@@z*@`fffƠ#@@q*@0333SJ#@e*@`fff #@Y*@L#@@333 *@`fff"@pfff)@@"@Y)@`ffff"@@)@lW"@)@0333 "@@333)@0333!@)@!@Yv)@`fff}!@M)@`fffU!@Y*)@̌?!@(@0!@pffff(@`fff @w(@̌ @Yv(@lt @O(@@pfff (@@@(@`fff@@3333(@`fff[@@333s'@Y@L'@Ya@pfff'@@'@@pfff'@L@ '@03333w@@333'@̌9@pfffP'@`ffff@)'@03333@@ '@`fff&k@@333s'@@pfff'@@&@c@@333&@"@@3333&@L@y&@Y@N&@0333s@6&@0333@(&@`fff@pfff&@`fff@@333s&@@̌%@03333@pffff%@0333@pfffy%@@pffff6%@@@(%@;@%@Y&@ %@̸@@333$@`fff@̌$@̂@ $@́@@3333i$@@_$@0333@pfffU$@03333@I$@Y@pfff$@@#@̌6@@3333#@"@L#@`ffff @s#@@pfffQ#@ @pfff%#@0333@"@0333@pffff"@Y~@pfff&"@LG@@z"@@"@L @̌!@@!@@@3333!@̄@pfff!@`fff@!@03333@pffffn!@0@@333G!@@@+!@T@!@Y@pffff!@@!@@ @`fff&@̌ @LA@pfff& @̌L@pffff @`fff&@@333w @@@@333 @ٟ@ @;@ @03338@4@@@333@0333@@3333C@`ffff>@@`fff@@0333@@333 @03333a@fff@̌8@@3333#@0@@333@r@L@@ffffN@Y@Y@L@@Yv@ffff@@@333 @ٖ@ffff@ @@333x@0333@L[@ @L@@&@@@@fff$@`fff@@3333+@^@,@`ffff@q@L~@@3333@_@L@`fff^@@3333@`ffff\@x@̀@h@@fffQ@`ffff@fff7@]@@`fffS@@3333@`fff&U@3@`fff&7@@<@@V@fff@|@@@@@@L+@@ @ffffN@)@@0333Z@@3333@ @1@`fff@fffY@@fff6@@@`fffZ@fff@̌@@@fff@0333@@@ffff@̌@@0333@fffz@0333@ffft@ @x@Y@@v@fff@0333@ @@fff2@@@`ffff@@`ffff@@Y"@@`ffffI@(@YO@L@LL@@`ffffr@@0333@@333f@@~@M@@@3333O@@@3338@@fff@0333@@03333i@s@0333@l@@L_@@+@`fff0@@333q@0333@̈@`ffff@@333@0333d@fff@@@ @@@3333 @L@ffff @@@ffff^ @`fff@ffff@U@ffff @Ld@ @ @q @@@3333 @0333s@.@@̦@z@@0333@@b@@`fff@ffff2@@@`fff&@@Li@ffff@@ffff@L@ @̌E@@3333@`fff@@̌@ffff @`fff@E@ @H@L@@`fff*@@3333@ w@ffff@0333s@ffff@0333sN@}@0333~@ffff@ @@3333@`fffƋ @@` @@@ @@`:!@@`fff!@2@"@@3333/@l"@\@*"@@3333@`ffff`"@@3333/ @`fff&"@ @9"@@3333Q @`fffF"@ @!#@̢ @`fffU#@ @0333#@ @`fff&#@= @`#@ffff @,#@@3333u @̌#@ @0333S$@* @R$@̜ @`ffff$@ @$@@3333 @̌$@@3333, @`ffff$@@3333q @`fff$@ffff@L$@,@0333$@@3333E@,$@@7%@@3333@N%@@%@ @l%@ @%@@3333 @(&@ @=&@@ @`fff&O&@ffff @̌Z&@ @0333s&@ @&@ffffn @`fffC'@ffff @d'@9 @0333v'@ffffQ @`'@- @l'@ @̧'@ @L'@ @'@ @0333'@ffff @`fff(@ @9g(@& @(@ffff, @Y)@ffff'@̌>)@@3333@0333ӌ)@@333'@̌)@Y@`ffff*@@Y*@ffff@*@@̌+@@hfffK+@fff<@0333Sg+@̨@hffffw+@K@+@̯@̌+@Lg@hfffF|+@@333@0333+@Lr@y+@̩@hfff+@@hfff+@LZ@+@@333@S+@@0333X+@3@LQ+@@ 5+@ffff@hfff*@\@y*@@*@7@ 7*@{@`fff&*@@333@03333*@@3333@)@:@*@l@`fff*@@3333@03333,*@L@y9*@ffffn@6*@'@*@ffffR@̌*@@333@@*@pfff0 @0333*@ @̌*@L!@)@L!@`fff)@@3333g"@)@Y;#@ )@#@@E*@$@̌i*@̌^$@L*@̌u$@*@pfff$@0333*@@333%@9*@pfff&@ *@̌'@Y*@c'@l*@pfff'@03333b*@pffff<(@L.*@Y(@%*@pfff&(@0*@@3333)@c*@@O)@03333*@)@*@L)@hfff*@*@̬+@@c*@hffff%+@̥*@yW+@*@Lg+@@333s6+@h+@\?d'@pfff&/@43337@@333s6+@h+@*@Lg+@̥*@yW+@@c*@hffff%+@*@̬+@L)@hfff*@)@*@@O)@03333*@@3333)@c*@pfff&(@0*@Y(@%*@pffff<(@L.*@pfff'@03333b*@c'@l*@̌'@Y*@pfff&@ *@@333%@9*@pfff$@0333*@̌u$@*@̌^$@L*@$@̌i*@#@@E*@Y;#@ )@@3333g"@)@L!@`fff)@L!@)@ @̌*@pfff0 @0333*@@333@@*@ffffR@̌*@'@*@ffffn@6*@L@y9*@@3333@03333,*@l@`fff*@:@*@@3333@)@@333@03333*@{@`fff&*@7@ 7*@@*@\@y*@ffff@hfff*@@ 5+@3@LQ+@@0333X+@@333@S+@LZ@+@@hfff+@̩@hfff+@Lr@y+@@333@0333+@Lg@hfffF|+@̯@̌+@K@+@̨@hffffw+@fff<@0333Sg+@@hfffK+@@̌+@ffff@*@@Y*@Y@`ffff*@@333'@̌)@@3333@0333ӌ)@ffff'@̌>)@ffff, @Y)@& @(@ @9g(@ffff @`fff(@ @0333'@ @'@ @L'@ @̧'@- @l'@ffffQ @`'@9 @0333v'@ffff @d'@A @,'@@3333 @03333'@@3333 @'@d @0333'@# @'@ffff2 @0333s<(@ffff@`fffF(@@3333@0333S(@@3333q@`fff(@@ (@ffffs@`fff&(@0@0333(@@0333(@@3333@̌(@@q(@@y`(@@3333M@`fff'@@L'@@3333@Y'@@3333@E(@@3333@0333S(@ffff@`ffff(@w@`fffF(@ffff@ (@@`fff(@ffff@@(@ffff@(@ffff@(@@3333@̬)@@3333G@E)@@3333@ g)@@3333@̌m)@#@0333n)@ffffL?03333j)@fffft?yA)@3333?:)@̼?Y=)@ ?0333SE)@?YZ)@ffff?`fff&)@ffff?0333*@ffff ?0333 *@?0333s*@4333#?9W*@A?hfff&*@?̺*@:?y*@?*@8? *@? *@3333I?̌*@I?+@gfffJ?̌)+@?8+@?@+@4333'?0333L+@?YY+@?^+@?hfff&h+@4333?0333+@x?+@?',@hfff?,G,@4333{?},@?y,@ ?,@?0333,@?LN-@4333?̐-@hfff?hfff-@hfff?̬-@hfffF?hffff-@Q?-@hfff?@-@4333?hfff-@Q?-@̸?L-@?0333@.@?hffff.@3333?̬.@?y.@@hffff.@]@ .@ffff@hfff.@@3333@0333.@@ .@@3333<@hfff.@@3333{@.@P @@.@ @0333s.@* @Y.@@3333 @̌H/@@3333@Y/@ffff@hfffFg/@@0333/@/@ /@B@,/@@,/@@3333@ 0@@3333@dfffV10@@3333|@4333[0@@0@@dfffV0@@4333s0@L@43330@L@dfffI1@L@ 1@@̜1@ffff@4333#2@@i2@@P2@@333@43332@@̌$3@ffff@G4333; e@<9Ḡe@5Ghfff^e@`1G e@\.Gye@,-Gd@4333/Gd@.G4333d@4333Gd@4333G4333Cd@4333G4333d@GAd@LGhfffd@G5d@Gd@Ghd@4333SGd@GUd@hfffFhd@̌Fhfff^d@Gd@hfffVG4333Cd@LF4333{d@4333Fd@hfffF4333d@IFd@`FHd@̌Fd@yFid@hfffFd@4333#F4333{d@hfffF4333d@hfff&F4333d@yFhfffd@4333F4333kd@)F̴d@F4333d@4333cF|d@4333F4333d@hfffFd@pFpd@hfff6Fd@ Fd@hfff֧F4333d@YF4333d@ F4333d@Fhfffd@LFd@4333Fhfffd@4333F\d@)Fhfffd@F4333d@hfffF d@yFd@̜Fd@4333ӏFd@Fd@ FMd@hfffFd@)Fd@F9d@4333S{F$d@iF4333d@zFUd@ uFmd@oFd@LkFd@4333fF̄d@̼bF|d@4333^F4333Wd@hfffRF4333/d@)LFd@hfffOFhfffd@hfffUFd@PFd@KFhd@hfff@Fhfffe@-F4333Ge@F4333 e@ F4333e@Fe@pE4333e@̌Ehfffe@Ee@E "e@hfffEY$e@0E%e@EX$e@El%e@hfffvE4333W*e@E|0e@4333E4333+5e@̬E8e@E4333:e@̼Ehfff^:e@4333E̸:e@EDhfff2e@hffffBDqe@EDe@|MDhfffe@yUD4333Se@\De@cDЛe@iD4333e@4333lDhfffZe@zD4333e@Dhfff2e@ɗD̰e@DDe@̌nDe@uD(e@4333pD4333e@hfffeDhfffe@_De@hfff_Dܾe@4333C[De@hfffdDDe@̌nDd@4333Fhfffd@B43337e@YNBhfffe@,SBe@4333cB4333e@eBhfffe@̬kBe@hfff6mBhfff2e@oBhfffe@hfffftBYe@nB4333we@,mBe@4333tBe@4333S|Be@4333#Bhfffre@f@4333SB4333K@f@hfffBHf@B4333Kf@)B4333;Of@4333sB(Qf@hfffB4333Pf@BhfffNNf@\B4333Lf@BKf@hfffCJf@hfff8C̐Hf@̌FCEf@QC4333Bf@4333XCf@Chfff>f@Be@ MBe@4333CHBe@`ABLe@hfff9B4333e@3BTe@ 0BLe@4333S)B4333e@hfff#Be@Bhfffe@4333Bhfffe@Be@ Be@43333Bhfffe@4333Bhfff*e@̬Be@4333B4333Ce@PAe@4333#AhfffZe@4333SBe@Bhfffe@ %B4333Se@)Bhfffe@@0Bhfffe@ 2Be@ .Bhfffe@\Bhfff>e@4333B0e@4333sAhfff^e@A4333e@̼Ae@A e@٨A̜e@4333AUe@9Ae@`Ae@Ahfffڬe@hfffA4333 e@4333A e@AIe@4333CAQe@4333AȨe@yALe@hffffA e@hfffAe@hfffFAhfff e@hfff֏Ae@4333Ae@sAhfffe@4333cfA4333e@PA4333e@4333C:Ae@i7Ahe@6A4333מe@DAhfffe@YLAe@RAye@IgḀe@hfff&mAhfffe@4333sA4333e@hfffwA%e@hfff?Jx'e@,FJ$e@IJhfffn"e@4333FJhfffF!e@hfffCJhfff e@i?J"e@?J$e@>J%e@hfff?J4333d@yaId@@lI4333d@LlIXd@LiI4d@4333dIld@4333cId@hfffhIhfffd@hfff&iItd@4333cgILd@̬aI\d@VILd@YIIhfff>d@DI4d@hfffCI4333#d@EI4333d@GILd@4333II̴d@hfffVNI̤d@4333SI d@XIhfffd@y[Ild@`I4333d@yaI3333f4333E3333fhfffEfhfffE33337 f4333E f43333E3333 fhffffEfPEf4333sE̎fhfffEfhfffvE3333fE3333 f43333EU fE̬ f<F̮ f43333F3333}fhfff F3333fFJfhfffF"f F#fF5fFf Ef4333SEf EffffNfEf4333E fhfffvEZf4333EZfEfE3333f4333Ef,)FfP*Ff4333#FffffVfLF3333f̼Ff\"Ff,)F3333UeY)!ffffze8333s*!ehfff$!3333ϏeL!3333ě!e!e!3333eě"!3333UeY)!3333ee"3333 fe8333s"3333-fe8333s"ffe"̊fehfff"tfeL"8fe8333s"fe8333s"3333ee"_XX>eL#3c9eL29e@3ehfff3ffff=e2;e2ffff:eL2c9ehfff 39e@3`pc?5ffffc/5 ffffc?5̸c?5c=5c4333<5chfff:5c4333S35ffffc/5ffffc@05chfffF55ffffc=5ffffc?5a Ql(@@J@<@ffff`I@dFT@zS`I@0@̔`I@@9aI@L@(cI@@3333@3333+cI@@3333@)gI@̎@3333kI@@ffffnI@L@PwI@@yI@@ffffzI@@~I@fffE@I@O@I@/@I@ffff@I@ffffo@fffffI@ffff)@I@ @33333I@L@|I@@I@L>@ffff>I@L@̴I@Lf@YI@@3333K@3333I@fff<@I@@333@3333 I@ffff@I@@1I@ffffd@ffffI@ffffH@ffffI@C@fffffI@>@3333I@#@3333I@@ܾI@@3333@3333I@fffZ@I@ffff @3333kI@@3333üI@@3333ۺI@@3333I@@333@I@@333~@I@7@ffffFI@@xI@@3333@dI@@333@3333I@@3333@fffffI@ffff @ffffI@ @I@* @3333;I@ffff @8I@@3333 @I@c @hI@ @3333KI@@I@@333@ffffVI@@333@tI@@333@ffff^I@@I@@333@xI@ffffR@3333I@fff@DI@@ffffI@̡@I@̉@!I@@3333@I@@̄I@@333@I@fffV@ffff>I@fff@ffffJ@@̌J@L@1J@ffff@3333'J@?@ffff8J@@ffffgJ@@oJ@@3333@|xJ@@3333[@vJ@L@DtJ@@333>@ffffzJ@o@YJ@@333@fffffJ@ @dJ@~@ffffJ@@333?@3333J@@333i@(J@A@ffffJ@C@xJ@L@ J@ffff@J@ffff;@yJ@@!J@@ffffJ@@J@̷@̬{J@fffw@qJ@4@T_J@!@`SJ@ @QJ@ffff@)QJ@@ffffOJ@L@LJ@@3333kIJ@@3333[FJ@@3333@CJ@@ffff?J@@d;J@T@̜8J@@3333@3333[8J@ffff@8J@fff@5J@$@33330J@ffff!@ffffn*J@@ "J@@333@ffffNJ@k@aJ@3@<J@@ J@fff@D J@@HJ@@J@@3335@ffffvI@3@3333I@@I@@I@@ffffNI@@3333@I@}@ffff>I@@3333l@ffffI@@33330@I@@̼I@x@iI@\@ffffNI@@I@@ffffI@L@ffffI@6@AI@[@3333I@L]@I@@iI@fff@̔I@@I@@ffffI@@3333@3333kI@@333M@I@L@yI@ffffT@ I@t@\I@@3333@I@@ffffޒI@@AI@@9I@@3333y@̅I@n@3333ۃI@x@I@@3333@3333}I@@|I@@yI@1@3333sI@@ffff`I@@xI@@3333I@@333@ffffNI@)@I@ffff7@̔I@ffff@ffff6I@ffffA@ٝI@ @ffffI@fffft @II@ffff @I@# @ffffI@ @I@u @tI@9 @ffffI@ffff @3333CI@ @XI@h @ffff^I@@3333 @ I@ffff @@I@@3333@`I@L @ffffI@@3333r@)I@@xI@ffffU@`J@fff@J@@J@@333@33333J@fff)@3333J@ffffU@`J@@3333J@@J@L@9J@@ffffJ@@J@L@мJ@@̄J@@3333J@@3333o@lJ@fff@ffffJ@@333@̄J@@333@̴J@@3333o@lJ@M@`J@@3333@3333[J@@ffff&J@@9J@:@ffffƸJ@T@3333J@M@`J@ffff@ J@&@J@@3333@3333J@@3333@̜J@@J@@333@ffffvJ@ffff@ J@̗@ffffI@fff/@3333I@@3333E@pI@fffL@3333 I@@3333CI@ffff@I@ @I@ @ffffI@ @fffffI@P@3333I@̗@ffffI@ffff@J@@3333#J@@ffffJ@@333@J@4@J@ffff@J@, Q`fffJ(@3333GQl(@Q *(@ffffbQW(@Qi(@LQ`ffft(@Qك(@Q(@ Q`ffffv(@, Q`fffJ(@xO4333~1@{O̜y1@ffff}Odfffz1@2333O01@2333OdfffƇ1@2333[}Ol1@2333c|O1@2333{O`1@xO4333~1@ȝOdfff1@O̜1@2333O1@ffffFO01@ffffOܦ1@2333O1@2333 OdfffV1@ȝOdfff1@4@ffff;J@@6J@{@ffff0J@@33331@ffff)J@@3333&J@@&J@@3333@*J@L@ffff-J@@3333{0J@@3333>J@@3333(@3333cGJ@fff@ffff6KJ@@3333@ffffJJ@0@DHJ@ffffQ@DJ@@3333V@I@J@4@ffff;J@x@ffffHJ@W@MJ@@PJ@z@ITJ@s@WJ@x@3333`J@L@3333dJ@@ffffhJ@@3333lJ@ffff0@ffff>lJ@fff@mJ@@ffffoJ@@sJ@̗@ffff^J@L@HJ@ffff@|J@@̼{J@@333E@33333vJ@L`@ffffnqJ@ffffx@kJ@̨@3333dJ@ffff@|]J@@̼UJ@L@4PJ@C@ffffOJ@ffff=@dHJ@G@̜BJ@@333F@ffff9J@?@!7J@%@3J@ffff@.J@fff(@ ,J@C@P%J@@3333@ffff> J@@3333.@ffff6J@fffz@ >J@x@ffffHJ@bh3333;Q0333(@3333SyQl:)@ 3333yQl(@3333SyQ0333(@L|Q`fff(@DQ@)@3333;Q )@AQ03331)@3333?Ql:)@H~Q")@3333[zQ(@3333yQl(@ch3333+JQ`fffF(@0Q0333(@ 0Q(@i3Q`fffF(@?QH(@IQ̘(@3333+JQ0333(@̔GQ(@DQ (@3333@Q0333sv(@4Q,Q(@0Q(@dhhfffNT@<\:@hfffV V@23333c>@dfffV@;@hfff V@2333;@ V@ffffv;@h V@̿;@V@ffffv;@XV@@;@4333V@̬h;@U@I";@U@ ;@4333V@:@ V@̬:@hfffV V@̌:@4333#V@ :@4333V@Pfffn:@V@ e:@U@2333a:@YU@o:@U@ffffm:@U@,f:@hfffU@̬g:@xU@ffffFl:@dU@<\:@̬U@d:@0333U@pfffn:@lU@ffff:@ U@0:@̰U@@333#q:@4333U@`o:@4333ˢU@~:@hfffU@i:@hfffnU@ :@hfffvU@ffff:@HU@:@xU@<:@4333vU@ffff:@rU@:@0oU@ffffƣ:@hfffFmU@p:@4333lU@:@iU@9:@adU@ :@hfff6]U@ffff:@RU@2333:@`OU@ffff:@hfffFLU@<:@$KU@0333:@4333IU@̼:@hfffHU@i:@hfffEU@:@IAU@ffff:@4333;U@I:@+U@ ;@)U@y;@)U@2333#4;@)U@`fff?;@ 'U@ffffvL;@hfffU@P333#Y;@̴U@`fffm;@0333U@};@dfffU@/v;@4333kT@2333co;@4333 T@`;@hfffT@\e;@hfffNT@2333t;@hfffT@ w;@4333T@q;@̤T@ffffi;@4333T@^;@T@f;@T@q;@4333T@w;@T@܄;@hfff~T@;@YT@fffff;@PT@2333;@4333T@;@iT@̬;@)T@l;@hfff^T@̌;@hfff6T@;@dfff~|T@Pfff6;@hffffyT@;@vT@;@hfffvpT@;@̬hT@;@4333_T@<@ST@ffff&-<@4333KOT@=<@43333MT@ffffJ<@JT@2333U<@AT@h<@Y9T@2333w<@ 0T@)<@y.T@̍<@hfff*T@2333<@%T@L<@$!T@I<@4333T@2333â<@T@ٚ<@T@̬<@T@<@T@,<@4333 T@̬<@hfffT@pfff<@hfffNT@<@iT@P333<@YT@2333=@ T@2333=@T@@3331=@aT@iQ=@PT@`l=@HT@2333s=@T@2333=@4333##T@Y=@9'T@2333=@+T@̌=@y4T@̌>@H6T@ffff#>@dfff:T@@333,>@=T@ffff.>@@T@*>@hfffCT@ffffV>@GT@l >@hfffVKT@ffff6 >@4333SPT@2333>@4333ZT@lV>@iT@23333c>@hfffvT@ffff\>@hfffƂT@ffffS>@TT@̼>>@T@2333(>@,T@|>@ T@Y>@4333#T@ffff=@4333T@=@̬T@2333=@T@9=@4333T@ffff֜=@ T@=@4333T@lp=@9T@lN=@XT@/=@4333T@ffff0=@hfffT@9:=@hfffT@̌G=@hU@@=@|U@P8=@hfff.U@2333(=@< U@P =@4333U@i<@U@<<@IU@<@U@<@4333)U@٨<@P+U@<@hfff-U@ffffv<@0U@I<@3U@i<@6U@<@lDU@2333<@hfffHU@ffffF<@hfff.JU@̜<@@JU@fffff<@hfffGU@{<@4333EU@L_<@hfffGU@2333P<@4333MU@J<@HZU@F<@ikU@ffffG<@4333pU@|8<@hfffuU@ffff"<@zU@\;@}U@;@hfffU@;@4333U@I;@ԄU@̜;@ U@fffff<@ĈU@ffffF<@hfff&U@y<@4333U@ffff<@U@2333;@(U@̼;@ U@ffff;@U@;@|U@<@4333SU@`<@1U@L<@hfffU@ffff<@hfffU@ffff<@U@;@4333ûU@;@IU@̼;@ U@̜;@4333U@i;@̴U@ffff;@U@2333c;@U@;@U@ffffF;@hfffU@ffff;@̼U@ ;@hfff~V@ffff&;@dfffV@;@eXhfffd@4333d@Q߿4333d@ d@4333Sd@|hfffd@ffff8@2!8@2̬8@4333s'27@̬:2@7@E28333S7@l2̬7@ s2hfff7@u27@4333s2hffff7@b28333u7@hfff&;28333sL7@2hffff@7@2hfff&87@183337@4333s283336@433332hfffu6@26@225@D2hfff;5@̌N2`4@Q2l4@@24@433324@ V3hfff4@̌383334@'494@l4hffff4@4̌4@hfffF`583334@54@@583334@ 64@ 6|4@ 6833344@ 6833333@ 6hfffF3@>6Y3@6l3@63@@73@c783333@7hfff3@`73@?83@hfff&83@83@83@`293@@93@:3@:3@:3@4333k;3@4333;3@4333sO<3@hfffs<3@ s3@43331@;<`41@hfff2<@01@!<@&1@ @4333:lD@$8333I?@f68333m?@L6L?@L'6ټ?@5?@5hfff@@43335@@43335/@@U54@@4333O543337@@ L54333C-@@4333"54333<@@94=@@4333344333#=@@hfff4hfff?@@hfff4C@@43334hfffV@@ 44333c@@̌\4Po@@744333@@ 3@@ 3܀@@43333|@@3q@@hfff3hfffVj@@hfff3c@@hfffc3\j@@=3l@@hfff'3hfffl@@3i@@ 34333b@@93hfff[@@y3Y@@2Y@@4333S2i\@@43332`m@@29q@@2@08333S>@/8333p>@/h>@/e>@/hffffe>@@I/@a>@/Y>@ .@N>@hfff.̌@>@].9>@@".hfff8>@hffff.Y;>@ -83333r>@hfff-hfff>@hfff-`>@hffff-hfffF>@8333-!?@hfffc-T?@F-8333?@'-?@-?@,l?@83333,@@hfff,hfff@@,"@@hffff,F@@̌u,o@@8333>,Y~@@+,4333ә@@,,@@ ,@@83333,̬@@@,hfffv@@hfff"-4333C@@̌-@@-hfffv@@-4333#@@hffff,4333SA@8333s, A@ ,A@8333,*A@83333,0A@,̬@A@@2-hfffCA@hfff&v-̌FA@@-`GA@hfff&.GA@hfff&H.9EA@83333.̬7A@L.hfff5A@83333"/4333-A@i/9$A@/A@hfff/hfffA@hffff/hfff$A@L/ 0A@43330hfff3A@̌043332A@!02A@30L5A@,?0|8A@@F0CA@4333Q0lNA@yn0 aA@,0ywA@hfff0hfffA@09A@y0YA@hfff0A@L0A@4333S1hfffFA@ 1A@hffff14333A@4333 1hfffƙA@̌!14333A@4333S1,A@43331A@0iA@hfff04333ӖA@hfffƒ0hffffA@l0hfffA@@04333A@`0PA@hfffF?0hfffFA@4333s104333A@)0hfffA@9 0̼A@hfff0̬A@0hfffFA@/4333A@Y\/hfffFA@.hfffA@.4333A@.hfffFA@-A@@-pA@W-`A@Y,hfffA@8333f,A@ ,̬A@83333+hfffƁA@8333sI+4333tA@8333s+Vxk!nA@Kh +hfffFnA@*4333ClA@hffff*4333gA@hfff&*`fA@*̼gA@hfffH*hfffvfA@̌*bA@)bA@)`gA@)hfffFeA@83333I)XA@@(YA@@([A@(i[A@8333(hfffZA@hfffr(YA@8333sf(\A@83333P(hfffdA@833330(|jA@(̬mA@hffff( rA@'hfffwA@hfff'|zA@83333x'izA@VrC''zA@('`A@L&'A@*'hfffƹA@-'A@hfff5'C@&9MC@̰&eC@83333u&hffff~C@hfffU&4333C@8333sU&)C@>&hfff6C@8333& C@%4333C@%hfffC@hfff&%̌C@@%hfffFD@`%y,D@hffff%hfffV;D@$4333#BD@"%LND@8333R% GD@8333n%I>D@%pLD@L%BD@8333%@D@83333%pCD@ &4333ED@!&hfff>D@[&43335D@&3D@&;D@&p7D@̌P',?D@Y'hfffVAD@' DD@Y(0@D@hfff&=(,AD@83333(hfffBD@(Y>D@(0FD@ )YJD@hffffE)9ID@L)4333FD@83333)L9D@@)43337D@83333)7D@Y)HD@hfff&)`ID@̌*@HD@;*hfffHD@hffffr*hfffFD@hffff*̜JD@*hfffED@*4333sGD@+GD@=+hfffKD@hfff+@LD@hfff>, MD@8333U,4333#SD@e,[D@m,hfffF[D@̔,QD@8333,YQD@Y,4333RD@-4333]D@hffff,43333cD@8333,hD@hffff,4333gD@83333-iD@Y#- iD@E-lD@8333o-hfffjD@@-4333ScD@Y-YD@ -WD@8333.XD@hffff!.43333RD@83333*.4333OD@hfff&;.SD@hfffb.4333SSD@.̌GD@hffff.,(D@hfff&/D@8333/ D@hffff/ D@y04333 D@0hfffC@90 C@4333s@01 C@hfffF1,C@hfffFR14333sB@hfffd14333B@1LB@l1yB@hfff1B@Y1`A@̬\A@Q3333SA@3333̼MA@ffffNGA@?A@;A@t7A@3333/A@OA@3333@@ffffo@@m3333@@ffff?@@3333@@ɨ@@ffffx@@3333k@@)ffffVp@@33333td@@ffffZ@@|V@@3333M@@񿙙F@@ffff 񿙙;@@3@@ffffffff6+@@1̴"@@ffff@@ffff󿙙 @@gd @@$ @@)ffff @@ffffi @@@@@@L3333@@/ffff@@@fffA @@L @@@@@ffffrq@@@ffffffff?@@fff?@#2333?@333 \?@3333 Я?@ 9?@3333%ffff?@33332333s?@?@@fff?@@ffff)?@_ffffo?@3333P\?@@ffffO?@3333fffffA?@̪23332?@~ffff*?@+l)?@@ffff "?@La 2333?@ ffff?@@fff <?@U >@333 >@@ffff`>@>@Y@>@J>@2333#>@z2333Ӛ>@ 3333i>@2333#w>@`ffff?S>@ 333s*>@ 333,2333>@̌=@̌_=@y=@`ffff=@ffff=@ 333=@ 3333n=@`fff=@@2333=@`fff2333#=@ffff=@ 333 ܹ=@ =@@Cffff=@dffff6=@̜=@@ffffv=@l2333=@ 3333a =@ّ̜=@ ffff֜=@̌,=@`fff&fffff~=@ 333l=@`ffffid=@ `=@yY=@̼,=@`fffffff!=@`fffƇ 2333<@0333S <@0333s 2333S<@!2333<@Q!ffff<@Y[!|<@]!<@]! x<@]!R<@]!̬<@]!;@]! ;@! ;@0333!;@!ffff&;@0333!ffff;@y!ffffu;@0333!2333j;@!fffff\;@!ffffN;@y!ffff&@;@!ffff0;@!ffff&;@!ffff;@03333!ffff;@"ffff&;@9+"ffff&;@j"ffff;@9"ffff&;@"ffff&;@y"ffff;@"ffff ;@##ffff:@X#ffff&:@x#fffff:@#ffff:@#ffff:@9#ffff:@$ffff&:@9"$ffff:@?$fffff:@a$fffff:@$fffff:@$ffff:@9$ffff:@@%ffff:@N%ffff&;@%ffff&;@%ffff;@y%ffff;@&fffff:@L&ffff:@&ffff&:@&ffff&:@&ffff&:@9&ffff:@9&ffff&:@&ffff&:@&fffff:@&ffff&:@'fffffx:@9'fffff:@+'fffff\:@@F'ffffK:@y^'ffff6:@f'ffff):@o'ffff:@'ffff&:@'ffff&:@'ffff :@(ffff:@0333(9@9(dfff9@)(dfff9@)(dfff9@3(dfff9@C(dfff&9@yW(dfff9@f(dfff&9@@v(dfffk9@(4333B9@9(dffff9@(dffff8@@(dffff8@(dfff8@)dfff&8@@)dfff&8@B)dfff&8@l)dffff8@9)dfff&8@)dfff&8@L)L8@y)dffffx8@@*dffff8@>*dfffL8@R*dffff88@@v*dfff&8@*dfff&8@9*dfff&7@@*dfff7@@*dfff&7@)+dfff7@yR+dfff7@+dffff7@y+dfff&7@@+dfff7@+dfff7@9+dfff&7@ ,dfff&i7@,dfff&W7@3,dfff7@>,dfff6@9H,dfff6@W,dfff6@a,dfff&6@a,dffffs6@l,dfff^6@@q,dffffO6@,dfff=6@@,dfff06@,dfff6@,dfff6@,dffff 6@ -5@y)-dfff&5@C-dffff5@>-dfff&5@8-dfff&5@@H-dfff&5@yW-dfff5@-dfff&5@-dffffs5@9-dfffp5@@M.dfffp5@.dffffs5@.dffffs5@8/dffffx5@y/dfff}5@y/dfff&5@ 0dfff&5@00dfff&{5@̼0dfff&{5@ 0dffffx5@|0dfff&n5@03331dfffk5@14333k5@L0dffff5@033304333(6@0@`ffff?#ffffFZ>@LN#2333r>@ً#fffff>@03333#2333>@@#ɷ>@03333#ffff>@̬#2333?@ #2333l?@0333Y#2333?@`fff"ffff @@"3333@@̌"0>@@}"ffffFI@@`fff&!u@@L1!@@0333!P@@03333 3333@@?@@`fff&H@@ @@`fff3333A@iffffVcA@̌0A@̔A@`fffqA@}A@ffffVA@`fffffffA@̌A@Y3333A@Y3333cA@A@`fffkA@LYA@`ffff3333kA@`fffQ3333A@(A@MYA@̋ ffff֣A@ 9A@@ffff( A@@fff 3333A@33333333A@!A@@fffyA@ffffVA@@ffffhA@A@3333\A@@fffffffNA@3333lA@cffffΏA@ffffVA@i@I1`4@@]! ;@14333k5@03331dfffk5@|0dfff&n5@ 0dffffx5@̼0dfff&{5@00dfff&{5@ 0dfff&5@y/dfff&5@y/dfff}5@8/dffffx5@.dffffs5@.dffffs5@@M.dfffp5@9-dfffp5@-dffffs5@-dfff&5@yW-dfff5@@H-dfff&5@8-dfff&5@>-dfff&5@C-dffff5@y)-dfff&5@ -5@,dffff 6@,dfff6@,dfff6@@,dfff06@,dfff=6@@q,dffffO6@l,dfff^6@a,dffffs6@a,dfff&6@W,dfff6@9H,dfff6@>,dfff6@3,dfff7@,dfff&W7@ ,dfff&i7@9+dfff&7@+dfff7@@+dfff7@y+dfff&7@+dffff7@yR+dfff7@)+dfff7@@*dfff&7@@*dfff7@9*dfff&7@*dfff&8@@v*dfff&8@R*dffff88@>*dfffL8@@*dffff8@y)dffffx8@L)L8@)dfff&8@9)dfff&8@l)dffff8@B)dfff&8@@)dfff&8@)dfff&8@(dfff8@@(dffff8@(dffff8@9(dffff9@(4333B9@@v(dfffk9@f(dfff&9@yW(dfff9@C(dfff&9@3(dfff9@)(dfff9@)(dfff9@9(dfff9@0333(9@(ffff:@'ffff :@'ffff&:@'ffff&:@o'ffff:@f'ffff):@y^'ffff6:@@F'ffffK:@+'fffff\:@9'fffff:@'fffffx:@&ffff&:@&fffff:@&ffff&:@9&ffff&:@9&ffff:@&ffff&:@&ffff&:@&ffff&:@L&ffff:@&fffff:@y%ffff;@%ffff;@%ffff&;@N%ffff&;@@%ffff:@9$ffff:@$ffff:@$fffff:@a$fffff:@?$fffff:@9"$ffff:@$ffff&:@9#ffff:@#ffff:@#ffff:@x#fffff:@X#ffff&:@##ffff:@"ffff ;@y"ffff;@"ffff&;@9"ffff&;@j"ffff;@9+"ffff&;@"ffff&;@03333!ffff;@!ffff;@!ffff&;@!ffff0;@y!ffff&@;@!ffffN;@!fffff\;@0333!2333j;@y!ffffu;@0333!ffff;@!ffff&;@0333!;@! ;@]! ;@]!};@]!23333I;@]!;@]!:@]! :@Y]!i:@@]!E:@@]!ffff:@L]!9@0333s!9@0333$"9@03333"9@"9@C#9@`ffff#dfff9@$dfff9@,a$dfff9@0333$dfff9@%dfff9@`%dfff9@`fff%dfff9@`fff&>&dfff9@̌&43339@0333&43339@Y\'43339@'43339@Y(43339@Y(dfffV9@Y(y9@Y(9@Y(dfffw9@Y(T9@Y(29@Y(433339@Y(Y8@Y(8@Y(dfff8@Y(Ƀ8@Y(`8@Y(4333>8@Y(98@Y(`7@Y(43337@Y(7@Y(43337@ (4333w7@̬*(yo7@s(4333`7@(iQ7@`ffff)4333sJ7@`fff=)dfffvE7@̬z)dfffV17@)7@ *7@`fff=*4333S6@yN* 6@@U*43336@O*dfffv6@03336*̌6@L0*~6@l,*b6@,(*̬B6@#* 6@ *5@9*43335@`*̼5@*4333s5@ *w5@L*|U5@U*4333sU5@ *4333cU5@`fff@+PU5@0333+D@Y4@3333kE@_13@3333CE@ 13@E@L23@E@83@E@YL3@E@hfff&j3@E@833333@3333+E@L3@33333E@hfffƫ3@E@3@ E@hfff3@3333[E@̬3@3333sE@*4@{E@D4@̼wE@hfffW4@IrE@Y4@(mE@hfff&X4@iE@833374@@fE@L14@`E@hfffF!4@@aE@hfff 4@IaE@̌4@3333]E@83334@WE@4@ffffPE@4@ffffNGE@`4@ FE@8333 4@3333cFE@hffff3@3333@E@3@@>E@3@3333E@8333w3@3333+5E@Lf3@3333+E@[3@8'N$E@8333K3@!E@,3@|#E@L3@#E@hffff73@IE@+%PW3@< E@hfff\3@E@hfff&Z3@3333E@8333s\3@ffffD@8333sX3@̜D@hfffW3@ffff>D@/3@lD@L3@ffffE@2@ffffE@hfff2@d0E@y2@ffff2E@hfff&2@)6E@Y2@33338E@8333s2@33338E@83332@6E@y2@i7E@hfffz2@̔=E@hfff&p2@BE@8333o2@̤GE@83333t2@AHE@hfffz2@3333#JE@83332@`OE@2@ RE@83332@3333KVE@Lw2@|cE@t2@3333 lE@q2@ffff{E@u2@3333E@ }2@ffffE@hfff2@3333E@833332@3333E@hfffF2@3333E@hfff&2@3333ӘE@2@3333E@̿2@3333KE@2@TE@hfffF2@E@hfffF2@3333sE@̌2@E@83333@ffffnE@hffff 3@̼E@L2@E@83332@̔E@`2@iE@hffff2@3333kE@@3@)E@3@DE@3@̌E@8333*3@E@13@3333CE@kU@9D@hfffv]@3333J@U@ffffƔH@hfff^U@H@4333U@H@V@3333H@@V@̄H@GV@,H@̄KV@ H@LV@@H@̜OV@3333CH@hfff&SV@9H@QYV@ffffFH@hffff^V@̌H@eV@H@iV@ffffH@jV@H@hV@aH@4iV@ffffH@oV@3333[H@1xV@ H@̌~V@ffffH@QV@ffffI@pV@ I@4333V@9 I@hfff^V@I@V@YI@YV@\I@V@ffffNI@V@ffffvI@V@4!I@V@)'I@4333V@p)I@4333V@̜.I@aV@ffff.5I@V@6I@hfffV@9I@W@33333[I@@W@SI@FW@LMI@hfff>NW@3333MI@PQW@3333NI@XW@3333MI@`W@yLI@ hW@3333JI@hfff^jW@ffffJI@rW@II@YW@HI@لW@3333SII@W@8GI@hfff^W@tAI@pW@33333I@43333W@ffff&I@4333W@dI@̜W@ffffI@XW@ffff6I@̟W@I@4333#W@A I@XW@ I@4333;W@I@W@I@4333W@3333+I@W@I@4333W@ffffI@hfffW@H@!W@̼H@4333W@H@hfffW@H@hfffW@yH@hfffFW@0H@4333sW@3333H@LW@H@LW@ffffH@̄W@I@hfffW@I@W@3333H@4333W@H@TW@ffffH@0X@H@1X@ffffH@hfff&X@H@4333X@ H@)X@XH@dX@H@X@̬H@hfff^ X@H@"X@ffff>H@L&X@pH@(X@H@̌-X@ffffH@hfff?X@H@$CX@9H@@FX@3333 H@4333HX@H@YMX@3333H@hfffWX@H@hfffZX@3333H@̜bX@3333H@eX@3333H@iX@H@ nX@H@hfffFrX@ffffH@hfffvX@0H@{X@ffffH@@X@3333I@hfffX@ffff I@hfff·X@̤ I@4333X@I@̌X@$I@X@ffff&I@X@$6I@4333X@T>I@4333X@ADI@X@QGI@HX@ffffHI@ X@IMI@X@3333RI@4333X@YI@}X@3333sbI@̴}X@hI@}X@ffffvmI@hfffzX@ffffqI@4333vX@xI@tX@~I@|uX@̜I@4333KzX@$I@hfffzX@3333I@Y{X@I@hfff{X@ffffI@|X@I@hfffNX@3333CI@hX@I@X@I@ыX@,I@4333X@I@43333X@ I@X@9I@hffffX@ffffNI@4333X@3333I@hfffX@̌I@hfffX@I@\X@ffffI@PX@J@)X@3333J@QX@ J@1X@J@X@ffffvJ@hfffFX@3333I@ X@ffff6I@X@0I@9X@ffff>I@X@I@lX@I@X@̴I@hfff6Y@YI@hfffY@3333kI@4333Y@I@Q"Y@3333SI@|-Y@ffffI@9Y@XI@hfffvEY@I@INY@3333I@|SY@ļI@hffffXY@I@]Y@YI@dY@̻I@hffftY@I@4333~Y@I@4333#Y@ffff>I@hfffY@)I@hfff>Y@3333cI@Y@I@Y@3333ÍI@4333sY@|I@tY@ffff|I@yY@3333csI@4333ÍY@3333+jI@4333 Y@ffffFeI@4333Y@dbI@4333CY@ffff[I@iY@0UI@IY@Z@33331I@FZ@1I@hfffKZ@6I@QZ@:I@̌XZ@3333Z@,I@4333Z@ I@(Z@9I@hfffZ@̤H@hfff6Z@3333KH@aZ@ffffH@4333[Z@H@Z@QH@Z@\H@Z@̬H@Z@H@4333Z@3333sH@Z@ffffH@̜[@H@)[@H@hfffF[@H@4333 [@,H@4333 [@̼H@p![@ffffH@hfffF'[@QH@.[@ffffH@:[@H@hfff&O[@ffffުH@ ][@ffffH@hfffa[@3333H@hfffp[@H@hfff[@QH@4333ˌ[@ЕH@[@H@a[@(H@[@H@4333c[@̜H@l[@LH@[@DH@[@3333H@4333[@̌H@y[@3333۫H@4333[@33333H@[@ffff.H@4333[@H@hfffV[@H@hfff[@@H@\@LH@4333\@ffffH@̬\@3333#H@,\@ffffH@̜3\@H@̌:\@H@hfffC\@H@E\@̤H@J\@ H@4333kT\@H@4333\\@ffffH@d\@ffffI@n\@I@dx\@ I@hfff\@4I@1\@ffff I@4333\@ #I@\@3333 I@t\@I@1\@3333sI@\@I@4333K\@ffffnI@hfff6\@̼I@hfffF\@3333I@\@tH@\\@̴H@x\@H@\@iH@\@H@\@H@4333C\@H@̜]@aI@ ]@0I@y]@1H@hfffF#]@H@4333k(]@3333CH@4333+]@qH@hfff%]@H@̼]@ffffH@4333]@ffffΕH@8 ]@3333˄H@I]@3333wH@43333]@ffffkH@]@!dH@4333 \@]@3333G@9]@G@hfff]@|G@d]@9G@hfff]@ G@̜]@G@]@!G@]@G@4333]@G@]@G@i]@yG@4333]@33333G@hfffv]@ffffG@]@tG@hfffv]@I}G@hfff6]@3333 tG@hfffv]@mG@hfff]@ffffNeG@hfffV]@ffff]G@]@ VG@hfff]@HPG@9]@MG@]@ffffNMG@hfffV]@ffff6PG@<]@NG@`]@QG@4333]@XG@A]@^G@4333]@ffffNaG@̔]@_G@D]@XG@̄]@YG@hfff&]@XG@]@ZG@]@[G@ ]@3333VG@]@3333SUG@Dz]@ffffFOG@t]@3333DG@po]@3333SBG@4333j]@3333BG@hfffg]@FG@c]@LKG@ \]@ KG@Y]@3333IG@Y]@DG@hfffV]@7G@V]@ffff2G@hfffVU]@ffffV.G@8Q]@ffff-G@4333I]@3333s-G@̤>]@ffffN.G@43336]@1G@hfff^2]@ffff60G@hfff,]@ffff6)G@4333']@3333(G@$]@%G@!]@3333G@x]@3333SG@4333]@\ G@hfff]@DF@ ]@ffffF@]@AF@hffff]@3333F@hfff ]@3333F@]@ffffF@]@ffffF@\@ffff&F@\@tF@hfff\@F@hfff\@AF@ \@F@4333\@ffffF@h\@3333F@Ժ\@3333kF@H\@ffffF@<\@ffffF@٣\@3333F@\@3333F@$\@|F@0\@ȢF@4333Ӛ\@ffffF@\@1F@hfff\@aF@4333#\@ffffN|F@\@ffffxF@4333{\@fffftF@!x\@ffffrF@4333#p\@iF@i\@aF@e\@3333s_F@`\@̔aF@)]\@3333;bF@4333CS\@TeF@̌L\@̼eF@)C\@gF@4333;-\@qF@1&\@ffffvuF@\@fffffF@4333S\@3333sF@\@F@9\@ffffF@hfff\@3333sF@y[@33333F@[@|F@̜[@sF@4333[@iF@ [@!VF@[@HF@4333S[@3333{AF@L[@5F@hfff[@3333/F@hfff~[@3333C)F@hfff[@"F@4333C[@F@[@ffff F@4333[@3333CF@[@3333E@hfffV[@E@[@PE@X[@PE@[@E@43333[@E@Y[@E@[@E@4333[@ffffE@[@ffffE@9[@3333E@hfff[@ɼE@[@,E@[@33333E@hfffv[@3333E@4333s[@E@4333[@ؘE@[@ffff.E@Y[@tE@)[@~E@hfffV[@rE@̌[@ lE@hfff~[@3333#hE@[@cE@|[@_E@[@ZE@hfff[@ffffTE@hfffv[@ME@̬l[@3333FE@f[@YAE@\\[@\:E@U[@8E@lH[@d8E@7[@ffff6E@+[@3333C5E@"[@33336E@`[@7E@ [@A9E@[@ffff6E@̔Z@33333E@4333Z@3333S3E@hfffZ@̴,E@hfffZ@()E@Z@'E@HZ@$E@\Z@̼!E@Z@E@43333Z@E@LZ@ffffE@hfffwZ@3333;D@@dZ@3333D@aZ@hD@hfffTZ@̬D@̜LZ@xD@4333cGZ@ffffD@Z@9D@7Z@fffffD@43331Z@D@4333Z@PD@4333Z@AD@Z@ffffND@4333Y@3333D@4333Y@3333+D@Y@̌D@Y@D@Y@3333E@4333Y@E@ФY@ E@hfffY@<E@D~Y@E@PxY@3333k%E@mY@;E@^E@)MX@eE@P5X@PaE@(X@ffff6_E@4333X@4\E@̌X@ffff_E@4333X@fffflE@4333+X@vE@ X@3333ہE@4333#X@ffffNE@hffffW@ffffnE@4333W@3333SE@4333W@E@W@E@hfffW@3333CE@LW@4E@4333W@3333E@)W@3333;E@W@3333F@hfffW@ F@hfffW@l F@hfffW@3333F@yW@y!F@4333kW@#F@0W@4!F@lW@3333&F@W@,F@4333W@3333{G@hfff6V@ffffG@\V@@G@V@dH@̼:V@d H@hfff5V@ H@4333+V@H@$V@ffff.H@hfffF$V@(H@!V@ffff61H@hfff~V@33333H@hfffV@lU@ffffFH@U@3333H@U@ffffƔH@l8333s:@F@̌!>@ffff&=H@8333s:@3333C!H@8333:@ffff%H@:@ffff1H@̌:@3333/H@,;@3333#/H@:;@3333/H@@V;@3333c7H@`g;@333335H@Yu;@ffff8H@;@ffff&=H@;@ffff6@(6G@hfff>@fffff3G@`>@\0G@hfff=@3333.G@=@ffff,G@=@ 8G@8333=@p9G@ =@X5G@l=@ 3G@=@14G@8333}=@33337G@8333su=@:G@n=@\:G@8333d=@7G@V=@8G@ N=@;G@,A=@A2G@L9=@@0G@`4=@ffff0G@hffff3=@3333@G@̬/=@CG@8333s%=@qCG@hfff =@ffff?G@Y<@:G@l<@I6G@9<@ffff^.G@<@3333$G@=@ffffG@<@ffffVG@<@dG@y<@DF@ <@F@8333<@ffffF@hfff<@̜F@8333<@ffff.F@}<@8F@l<@F@hfff<@DF@8333s<@QF@<@DF@̬x<@3333F@8333sO<@ѿF@C<@F@hffff6<@F@)<@3333F@hfff<@F@ <@3333F@ <@ffffnF@!<@3333kF@hfff(<@F@(<@ffffFF@̌"<@F@8333<@3333F@8333<@F@hfff<@ffff~F@<@G@3<@|,G@̌><@33339G@9<@AG@L=<@ffffRG@hffff4<@3333kZG@hffff&<@3333ceG@`<@<}G@hffff;@G@8333;@G@hffff;@3333G@;@!G@9;@G@83333;@ffffG@ ;@G@w;@G@s;@G@@V;@3333G@hfff&G;@ffffG@hfff?;@ G@;;@ffffG@&;@G@8333;@H@ ;@$H@8333:@H@hfff:@ffffH@̌:@ffff H@:@!H@8333s:@3333C!H@mP̂@E@@3333@̬E@@3333@ffffE@̂@E@@3333@iE@@ffffE@ffff@̬E@ffff@xE@@3333@ffffE@n]@-@U[@@hr{5H]DD@@5]3333G@@̔#]I@@D]ffff~L@@\@3333QZ>@HFZffffv>@̤>Z\>@ffff:ZffffV>@33335Zr>@3333+Zfffff">@3333+Z2333=@ffff'Z2333=@A Z|=@Z=@3333Z܊=@3333 Zz=@Zb=@XYR=@ffffY2333J=@ffff~Yffff4=@Y=@ffff~YI=@Y<@ffffY =@ffffvY!=@<@ffff*YffffF,<@3333Y@ <@Xffff;@EXܺ;@Xɢ;@3333WX`;@ffffXffffw;@Xffffe;@̤X W;@XffffI;@ X2333;;@,X̌+;@3333KX;@8X2333;@33337X;@3333cX2333c ;@3333[X|:@3333X :@X:@3333Xl:@Xir:@ffffX2333#f:@ffffXa:@Xffff&W:@@XffffF:@ffffJX2333<:@X|9:@33333X.:@ffffXffffv:@LX:@ffffJsX2333 :@eX43339@-\X 9@ffff XX09@VX9@ffffbVX9@̬UX4333C9@RX 9@\IX4333#9@ffffJX4333C9@dNX9@$[X̬;9@t`X9@3333jXdfffc8@mX 7@nXdfff7@oX7@nX4333s7@qX`N7@oX@6@̈pX43336@DtX̼6@ffffvX6@uX̜6@3333uX43336@ffffrXG6@pX6@leX5@ffff_Xp5@ WXl5@ TXp5@3333UXp5@XX_5@0ZXdfffE5@[X4333C[5@)[X w5@̠XX5@ffffXX43335@8]XdfffƜ5@eX43335@ffff>pX43336@hX5@3333?fX05@ffffBdX5@ffff`X\z5@`Xn5@ `Xdfffe5@3333VX5@ffffzLX43334@KX4@GXp4@3333[-X4333304@0X3@3333Xdfff63@ffff.X y3@XX3@3333Xdfff23@ffffX 3@W4333 3@3333oW̬2@Wdfff62@W2@hW2@3333W2@̌W02@Wɰ2@3333W2@ffffW4333C2@W43332@W`2@ffffW2@3333W4333c2@W43332@W̼2@Wdfff6Y2@W4333,2@lW*2@3333W|*2@W12@wWM2@pW[2@YcW43333n2@ffffNW̜q2@ffff&HWdffffl2@8Ww2@81W,2@3333.W43332@ffffr-Wdfff2@3333W02@9W2@̤ W4333S2@3333W4333S2@ffffRV4333C2@XVdfffF2@YV43332@TV<2@xVL2@dVyx2@aVyr2@,Vt2@0Vdfff2@Vܟ2@3333V|2@3333Vdfff2@V2@V\2@dVdfffv2@V̌2@V433332@3333V@2@MVY2@ffffV2@3333V 3@V4333#3@3333V4333&3@PV,Z3@\Vٺ3@3333V43333@tVp3@xV`3@Vdfff4@ VY94@̜VdfffFa4@Vl4@3333WVdfff4@ٛV4@Vi5@̴V43335@3333xV̬@5@3333wtVLF5@<8V4333j5@/Vr5@3333o%Vdfff5@ffffV4333Ñ5@V 5@3333 Vdfff65@ Vi5@ V5@lV5@pV43335@̄U̬5@U,5@U4333x5@ffffUlr5@ffffU@u5@U0z5@U43335@ U43335@ffffzU@5@3333UІ5@U4333c5@3333U,5@U5@UdfffV5@ffffU5@8U5@9U̜5@YU|v5@U4333k5@3333KUdfff;5@ffffrUdfff635@dU&5@1UdfffV5@3333WU43334@3333GUdfffV4@U4@(U܁4@U<;4@ffffUdfff&4@U3@̤U43333@EǓ3@ffffU3@pUdfff3@}Ǔ3@3333U3@ffff*U3@LU̍3@ffffU3@3333U 3@ffff U4333#3@3333/UdfffV3@ffffUp3@Uq3@3333U4333l3@IUlj3@)Ua3@(U43333Z3@U4333B3@U @3@@U)R3@3333UdfffFQ3@U̬I3@U 3@3333Ul2@ffffU2@Udfff6r2@ffffvUi[2@3333UD2@ffffrUF2@3333kUp2@V{2@̜V4333C2@ffffV43332@V43332@̸V2@Vdfff2@ V<2@ V43332@V2@Vx2@Vy{2@V z2@x!Vdfff&r2@%V`J2@3333/VdfffV2@33333V,1@33336Vdfff1@u9V 1@T[dfff9@8[09@8[4333û9@;[dfff9@̈@[Y9@aE[4333s9@3333L[9@@P[ٛ9@yS[dfff9@3333X[dfff&9@=[[ffffV:@ffffV[2333s#:@ffffRQ[<>:@L[2333#N:@)J[2333#B:@xG[2333@:@]I[2333CN:@3333M[2333Z:@fffffO[g:@O[0s:@ffffQ[̬:@3333^[ٵ:@Dk[2333c:@ffffNp[2333:@u[ffff&:@y[ffff&:@z[i:@={[ffffV;@ffffj|[P;@̼[ffff);@%[;;@[R;@=[ffffFe;@[@4\ffffL>@<\>@̰C\>@G\ffff>@E\ffff&>@F\ffff?@3333G\P ?@F\?@̨D\ffff?@3333B\ffffF?@B\2333-?@ffffZE\ 5?@ffffK\l@\2333>@ffffޫ\ffff>@\2333Á>@\ffff<>@P\2333(>@3333;\2333>@љ\=@ؗ\=@x\=@ffff\ =@ u\p=@Yp\2333^=@ffffb\,=@ffffvb\=@3333_\<<@pX\Y<@ U\<@pU\<@ffffT\)<@P\<@(M\|<@ffffE\2333<@ffff&B\x<@9=\2333t<@7\l<@`7\2333Y<@̔7\J<@2\ffff5<@33333\<@/\;@ffff0\;@ffff.\2333s;@ffff^#\P;@\;@ffff\2333X;@@ \/;@H\\%;@@\@;@3333\|;@̔\2333:@[ffff:@5[2333:@A[̜:@L[|:@3333[:@3333[:@3333G[:@[ffffv:@[23333:@u[ffff&:@[ffffF:@3333[2333:@ffff[h:@[ffffY:@[C:@A[ :@$[l9@[09@ffff[dfff9@4[dfff9@3333[k9@ffff6[$9@\[̜8@[ 8@X[8@[8@ffff[8@ffff2[iW8@[433368@[4333.8@[dfffF*8@33337[dfff!8@[8@ffffz[4333#8@3333[433318@[YB8@ffffΔ[4333SN8@p[dfffV8@3333Ӑ[43333X8@u[4333,8@~[8@)y[4333s8@s[4333c7@q[i7@ym[dfff7@Lk[\7@`[7@3333Z[z7@3333Z[4333g7@P][67@_[(7@Yh[4333#7@ffffn[Y6@̬t[43336@{[6@fffff[6@[dffff7@3333[lW7@3333[i7@3333{[dfff7@ffff6[ܚ7@Q[7@[43337@P[4333c7@P[43338@ffff[9T8@[iq8@̴[I8@ffff[܍8@\[43338@[ɒ8@[̼8@I[8@̤\ 8@ffff\8@9\ 9@\R9@\|9@x\dfff9@\9@U\`9@ffff\9@ \9@$\23336:@3333!\2333F:@3333#*\ffffQ:@TA\P:@G\l:@ffff*I\:@I\<:@3333+M\2333c:@lQ\|:@A[\:@ffffNf\ffff:@l\ffff:@lp\:@ffffu\l:@ffff{\9:@ffff\:@3333 \ ;@3333\̼$;@ffffV\2333s(;@3333\7;@3333\H;@\P`;@\\n;@̭\ ;@\;@\l;@ \2333;@U\2333;@̴\ffffv;@3333{\;@\;@ffffڗ\Y;@<\|;@\̬;@X\ffff;@\ffffַ;@Ȉ\2333;@p\;@̤\2333;@9\;@\23333;@3333#\p;@3333+\2333s;@\9;@3333ۋ\fffff<@3333\8<@ffff\m<@P\<@ffffʓ\ܺ<@3333\ffff6=@3333\)H=@\2333Z=@\ib=@\`m=@ffff\,=@-\ffff=@ \2333=@ffff\̌=@3333\=@\̌>@33333\M>@\\>@3333\j>@]ffffF>@3333C]>@ffff]>@ffff]2333s>@] ?@] ?@3333W]3?@X]i\?@3333']2333?@`*]̜?@*]ٲ?@ffff6.] ?@,]`?@)]ffff?@'] ?@3333']?@E6]2333S?@y:]i@@9B]3333 '@@ffff D]3333+@@5H]DD@@3333#UdfffM4@3333sU̬E4@ffff>Ua4@3333U4333c}4@aU04@3333U 4@ٰU<4@ffffRU@4@3333óUw4@3333#UdfffM4@$Z`5@ZL5@٦Z̼5@ffffZdfff5@3333Zdfff5@3333;ZP5@TZdfff&5@ffffZ5@$Z`5@ffff[н2@3333c[i2@3333[2@ffff[43332@ffffR[dfff2@3333K[<2@ffff[н2@P[43339@|[<8@ť[dfffv8@3333[dfff8@[ 9@[9@,[|9@[ 9@P[43339@I\` =@3333kJ\ffff=@P\2333=@_\N=@(e\i=@ffff f\2333sv=@̔e\2333=@ffff`\ffffV=@ffffZ\fffff|=@ X\j=@W\2333V=@L\ffffFM=@3333cK\ffff!=@I\` =@3333\2333<@3333\ <@ffff\̜<@ffff\ffffv8<@̈\W<@ffff\L^<@3333\S<@\,<@3333\2333<@3333 \\=@\2333<@̼\<@ffff \<@!\<@\*=@3333\2333#4=@ffff>\̌==@\4=@3333\@ =@3333 \\=@]2333#<@E]\<@3333]=@])=@ffff]ffff0=@].=@]i!=@ffff] =@ԏ] =@]2333#<@ffffU4333C=5@Udfff05@U`25@ U;5@3333/U`G5@LU̬G5@UC5@ffffU4333C=5@Vdffff2@Vy2@3333;Vdfff2@V,2@8V2@YV2@3333V4333#2@Vdffff2@ffffs[̬&8@t[dfff%8@0x[\38@y[dfffT8@3333x[dfffFX8@r[4333.8@3333r[)8@ffffs[̬&8@l\2333?@3333\̌?@ffff\ffffV?@ffff6\0?@Y\I?@a\2333?@3333\fffff?@l\2333?@3333k[ffffF:@[ 9@3333 [\9@[9@ffff[dfff9@`[9@̴[fffff :@[:@[`:@3333k[ffffF:@ffff[4333d8@ffff[̬X8@\̌8@33337[dfff8@ffff[8@ffff[4333d8@ffff\43338@3333\و8@l \y8@3333; \dfffƺ8@x \\8@ffff\dfff&8@ffff:\|8@4 \ I9@m\p99@ffff \̬8@3333{ \P8@3333{ \dfff8@U\dfffƺ8@\l8@Q\i8@ffff\43338@oL@`4`L@l3\L@ |4,L@`4L@43334hfffL@43333s4L@ym4̼L@ h4YL@lV4`L@hfff:4@L@ /44333CL@$4L@4333S44333L@hfffF3 L@l3\L@433334`L@l64L@4333S4L@l^44333sL@4333So4\L@ |4p "`1}-@YJ23333I;@A0333_0ٴ3@0333p03@Iw0y3@z0ٵ3@k0L3@̬d0i3@W03@0333_0ٴ3@̬(9-@`fff(L-@@(,-@0333s(hfff-@L).@Q)hfff*.@0333sx)03333C.@`ffff)0333_.@Y)0333sr.@̌),|.@̬)Y.@,)L.@0333)L.@)0333.@)/@*hfffF.@(*Y/@ 2* /@`fff5*$/@`fffH*hfff4/@0333i*;/@*f/@0333*,/@0333*l/@*dfff&0@*4333S0@0333S*dfff0@ *<0@0333+̜"0@l+$0@@?+I0@̌^+| 0@ n+dfff6+0@`ffff+),0@+dfffV#0@`fff+%0@+30@0333+A0@9+dfffO0@+,9k0@`fff,̌0@`fffF-0@̒-Y0@0333s-L0@`fffF-̭0@03333-I0@9 .0@`fffF.dfff0@`..I0@̬9.0@,>.dfff0@k.dfff&0@̌.0@̌/|0@=/0@0333S/0|0@/}0@03330̬0@0dfffF0@+0 0@0=043330@0333cM0s0@̬[04333N0@0333g0433390@`fffp0\40@`fffz043330@`fff0̬/@`fff0@/@`fff&0lI0@`fff6{0It0@v00@X0)0@50L11@033330̼1@03330P1@`fff 0 92@0l2@l&0ٷ2@̌603@PN0`'3@`fffy0H3@03330\3@̌y0d3@ _0dfffi3@`fff&N0<3@0333q0 y3@̌H043333@0333;0@4@̼=0)$4@50Y:4@pU0dfffvj4@`fffn04@̬z0dfff4@ɇ043334@0l4@ 04@\0Y4@`fffv0`4@`fffF0 5@̌04333c5@̜043335@̌0) 5@L 1`4@`14@ 1 5@03331dfffv$5@0IT5@04333ST5@`ffff04333cT5@0333`0dfffvT5@&0T5@/T5@,a/̬T5@.T5@`v.T5@.4333T5@0333-dfffT5@`fff&-dfffU5@,U5@Y+,,U5@0333+8@Y(`8@Y(Ƀ8@Y(dfff8@Y(8@Y(Y8@Y(433339@Y(29@Y(T9@Y(dfffw9@Y(9@Y(y9@Y(dfffV9@Y(43339@'43339@Y\'43339@0333&43339@̌&43339@`fff&>&dfff9@`fff%dfff9@`%dfff9@%dfff9@0333$dfff9@,a$dfff9@$dfff9@`ffff#dfff9@C#9@"9@03333"9@0333$"9@0333s!9@L]!9@@]!ffff:@@]!E:@Y]!i:@]! :@]!:@]!;@]!23333I;@ 2333,;@0333S 2333;@ = 2333C:@2333:@ 3332333:@`ffff82333S:@w2333:@ 33332333f:@`fff2333cJ:@62333.:@uffff:@ 3334333s9@`ffff4333#9@34333Ӽ9@@s43339@ 333433339@Y|l9@dfffFF9@ 3332̬"9@YJ8@ 43338@`fff&43338@dfff8@&̬8@Y`8@EL8@`fff'dfff8@ 333 D8@4333S8@`ffff̬7@@43337@YF7@ 333x7@[ 6@>4333c6@!G6@L43336@`fff&i5@5@٬I5@ 333p 5@rdfff4@`ffffU4@ 33338dfffvJ4@  4@`fff4333#3@|3@4333K3@`ffff) 3@L43332@l܌2@ 333N43333M2@1̌ 2@`fff43331@91@LN1@ 33331@@0@43330@ )q0@̌piH0@@43330@̌,/@ .@@.@.@ 3330333.@W .@( .@ 333s .@L .@`fff& .@l .@<hfff.@ 333 hfff.@hfff.@̬W hfff.@ hfff.@`fff(!hfff.@0333!.@`!.@`fffZ".@`"0333s/@"hfff& /@"0333Z/@L"0333U/@`ffff"?/@9"0333S&/@0333s"/@0333".@'#.@#̌.@#`.@0333SB$0333s.@03333c$hfff.@03333$.@$9.@$,.@0333S,%hfff.@`fffd%hffff.@`fffv%03333.@0333S%@.@̌% M.@%`M.@& r.@0333V&.@03333&0333/@0333&03333@/@`' F/@`fff1'%/@ Z',/@03333'.@̘'y.@0333S'`}.@9'@B.@`fff'hfff-@'-@ ( -@)(`-@5(}-@̬(9-@qY\,@A@pfff!-@3333 B@pfff!-@ffff&A@-@A@@333s,@,A@pffff,@ffffA@ٳ,@4333c6@[ 6@ 333x7@YF7@@43337@`ffff̬7@4333S8@ 333 D8@`fff'dfff8@EL8@Y`8@&̬8@dfff8@`fff&43338@ 43338@YJ8@`ffff43338@8@@ffffM4333h8@̮ 433328@ 433337@@ffffq4333c7@43337@4V7@*43337@3333 6@P6@33334333{6@ffffjD6@ӿ 6@ffff?43335@4333 ?@5@?pi5@4333?25@T?,5@?5@?4333c4@?,4@̦?4333C4@W?l4@̤?̬4@3333?94@3333-?<4@[?dfffvu4@?`4@3333 ?4333T4@Q?L4@ffff?E4@@3333@p?4@@3333?@dfff54@?@Y4@@3333@dfff4@W@03@v@,3@@3@@dfff3@ @dfff3@@3333 @)3@ @P3@@3333 @43333@ @dfffv3@ @!`&@0333sT!̬'@@l!L<'@Yw!`ffffF'@9!`fffK'@!0333X'@!@'@!0333S'@`fff!03337(@0333!s(@0333s!(@ "(@̬="`(@Yn"9(@"`fff(@"`ffff(@l"`fff(@̌"l(@"`ffff(@"(@,"`fffƐ(@Y"`fffƂ(@Y"@(@@"0333u(@,#l](@ Q#`fffFI(@0333m#(@ #0333S(@03333#(@0333s$;(@̌U$Z(@$l(@`fff$la(@پ$[(@$G(@0333-%`fff'@<%`fff'@0333I%'@Z%'@ k%`fff&'@`fffFx%9'@l|%'@%̌(@%M(@% i(@0333S&@j(@0333!&0333sW(@,B&`fff0(@Yk& (@y&0333(@@&`fff(@L&@5(@ &yU(@ '0333e(@&̌~(@`fff&&0333s(@ &`(@`& (@s4333sXR@ @aR@@ ZR@ @LYR@ @4333sXR@ @4333XR@+ @4333YR@`ffffO @`[R@Q @hfffV\R@1 @hfff[R@L @ZR@ @`R@@4333_R@`fff@^R@@hfffF^R@̮@4333^R@`fff@_R@@4333C`R@@@4333#aR@@aR@`fff&@̼aR@03333@4333kaR@@8aR@Y@`R@@t\X@3333?4333 ]@h@ vY@@Y@`ffff@Q Y@@P Y@0333@ Y@@4333Y@@4333Y@3@hfff$Y@@I(Y@@-Y@03333@I0Y@@2Y@`ffff@A4Y@S@hfff7Y@L@H?Y@@AY@03333@lCY@`ffff@DY@ @EY@"@hfffDY@0333s@?Y@b@4333>Y@̌@̜AY@`fff@4333;EY@@4333KGY@ @4333sIY@@43333LY@̬@̴NY@L@4333sPY@L(@hfffYY@h@hfffcY@̌@dY@`fff@|fY@03333@iY@/@4333kkY@@ nY@@4333rY@ @wY@M@4333zY@@@{Y@@Y@c@`Y@@xY@ @Y@L@ĕY@`fff&@43333Y@@s@4333Y@`ffff@Y@LA@Y@̌@hfff6Y@@@4333Y@0333s @̜Y@0333f@ Y@̌@Y@0333@Y@@4333+Y@ 3333'@Y@`ffff^ @hfffY@ 3333* @|Y@L @4333{Y@ 333 @ Y@w@ Y@L@4333cY@ 3332@4333Y@̤@DY@`ffff@Y@@ Z@̐?hfffvZ@̰?Z@3333?Z@7?I Z@?4333[Z@?Z@#?pZ@3333?Z@z?hfffZ@D?Y@@ffff?pY@?tY@F?Y@%?hfffFY@?4333sY@1?0Y@3333S?̼Y@E?YY@?Y@3333?hfffY@?hffffY@@ffff?Y@@ffff?hfffY@V@QY@`fff@xY@`ffff@rY@ 333@4333CaY@x@ ZY@@|VY@ 3333@RY@`fff@̬VY@@!UY@# @1SY@ 333 @4333cGY@ 333 @hfffAY@`ffff @4333{6Y@ 3336@ 2Y@`ffff@-Y@̺@4333s0Y@@2Y@0333@0Y@̌c@hfffN*Y@`fff&@T'Y@`ffff~@T'Y@`fff@LY@Y-@Y@Y@Y@`fff@Y@@Y@`fff@4333# Y@L@Y@@4333d]@0333@4333cb]@@4333\]@@4333Q]@2@pF]@`fff&Y@5]@L\@,]@k@(]@@[@4333%]@̌Z@hffff#]@p@ ]@0333{@]@;@]@03333O@]@03333j@hfff]@@s@4333]@0333k@a]@`fff)@4333[\@ e@hfff\@`ffffd@hfff\@LU@4333\@@q\@`fff@)\@0333S@hfff&\@`fff@a\@@hfff\@L @\@ @hfff\@ 333 @4333;\@`fff @hfffF\@ 333 @\@ 3333 @X\@L @\@b @\@`ffff @\@LF@hfff\@`fff@\@@hfff\@5@(\@ 333@hfff\@ 333(@hfff\@@\@`ffffT@hfff\@@ \@@hfff\@@4333+\@`fff@P\@ 3333@4333\@@hfffv\@/@hfff\@@\@ 333@hfff\@@hfff\@ 333'@T\@@,\@@hfff\@L@hfffn\@ 333i@hfff6\@&@(\@3333?4333\@?43333\@M?\@@ffff?hfff\@̜?\@?L\@?hfffv\@@ffff?Q\@:?\@@ffffy?̠\@@ffff;?hfffƘ\@3333?̔\@̈?\@[@3333:?[@\?[@?[@3333?Y[@?|[@?[@l? [@G?X[@?hfff^[@3333?[@:?[@ ?,[@3333?X[@ ?̜[@?x[@@ffff?y|[@h?9x[@]?4333[t[@?hfffo[@^?4333i[@?h[@3333m?d[@?!c[@̒?hfff~b[@V?@h[@`ffff8@pl[@@ffff8?hfffn[@?Yw[@3333;?4333[@@ffff{?L[@@ffff-?̼[@?[@8?Y[@?[@2?hfff6[@? [@@ffffU?hfffF[@?([@G?L[@j?4333K[@1?I[@@ffffU?hfff[@3333/?hfff[@@ffff?hfff[@?4333[@@ffff#? [@?hfff[@?[@o?̬[@?hfff[@̂@)[@ 3333@hfff^[@̔@4333[@`@Y[@ @[@`ffff|@[@ 3330@|[@`ffff@hfff[@`ffff@h[@`ffff @[@d@0[@@hfff^[@@[@ 333@4333[@ 3333@4333[@@4333\@LQ@0/\@L@:\@ 333 @9?\@K @B\@L @H\@ @|T\@`fff} @̌\\@ 333 @4333m\@0333s@!{\@ @hfff|\@`fff'@8\@̮@4333c\@`ffff@hfff~\@`fff.@̀\@ M@hfffn\@_@hfff\@`fff^@hfff\@B@hfffΊ\@@X\@Y@̴\@03333@h\@@k@\@7@4333\@ @\@@̜\@0333s@Ƞ\@Lt@\@@2@hfff\@̌@ܩ\@̌&@hffff\@b@̬\@٬@hfff޳\@`fff@$\@@0\@k@hfffƵ\@`fff@hfff^\@ @\@ @\@L6@4333\@@ɯ\@L@0\@0333@T\@5@hfffv\@l@hfff\@L@\@H@hfff\@0333@L\@`fffT@\@̏@4333\@0333t@\@̌c@\@ i@hfffn\@ v@\@`fff@\@L@\@03333@hfff\@@\@w@hfff\@Y@hfff\@`fff&@hfff^\@0333s@D\@2@|\@_@@\@@\@03333@\@0333sR@\@@̜\@LD@hfff\@`fffi@\@ 2@\@0333#@i\@!@\@%@4333#\@@t@\@Y@4333]@̌@4333 ]@Y@4333]@`fff@]@03333@4333s"]@0333T@/]@̌@̬1]@@P5]@`fff@4333c6]@̌N@43335]@@3]@`fff@p2]@`fffl@hfff3]@n@4333s:]@@0A]@0@D]@٪@9H]@`fff&@hfffN]@̌@(P]@L@4333O]@`ffffU@QP]@@"@R]@`fff&@XX]@0333r@4333_]@03333I@g]@0333 @4333Si]@ @4333j]@@hffffl]@`fffff@̄l]@@4333kg]@@@hfffi]@YK@@i]@`fff@g]@L@4333`]@`fff@Tt]@@Ty]@@hfff>]@6@4333]@ @i]@03333s@]@ T@4333{]@`ffff&@d{]@`fff@P~]@03333@hfff]@03333@A]@L@]@@H@0]@`ffffG@]@`ffff9@4]@ @]@`ffff@ ]@0333@]@L^@̬]@0333;@D]@L@)]@٫@43333]@03333@4333k]@@@L]@̌@4333[]@0333v@4333 ]@;@]@@4333]@@hfff]@`fff@hfffv]@`ffff@hffff]@0333s@4333]@03333@I]@Y@p]@0333@4333{]@L @̬]@@܋]@`ffffP@]@@]@03333@hfff]@0333@hfff]@@]@Y@]@ s@L]@W@4333]@C@]@&@hfff]@@@Qy]@@ @lo]@`fffY@4333l]@ _@hfffi]@7@̤f]@@4333d]@0333@hfff.Z@@ Z@L@hffff Z@`ffff@4333CZ@L#@hfff Z@@4333 Z@L@IZ@1@hfff.Z@@hfff~Y@-@Y@`ffff@9 Y@`fff!@ Y@@hfffY@@Y@0333s@Y@`fff@hfff~Y@-@hfffFX@`fff@4333X@03333o@X@L>@iX@033330@X@@@@hfffX@@X@ @X@`fffY@hfffX@0333w@\X@`ffff@yX@@4333X@0333s@hfffX@0333@hfffFX@`fff@I]@@@)E]@ v@C]@`fff&@D]@0333 @hffffI]@Y@hfffP]@h@Q]@)@4333Q]@@QO]@03333@I]@@@4333cTY@`ffff@(QY@`ffff@PY@@̌QY@ 3333C@4333SY@@UY@a@4333cTY@`ffff@[@R@[@ 3337@[@ 3333@9[@`fff@X[@%@[@@hfff6[@ 333@[@L@Y[@`fff@[@R@x]@@̴o]@0333@i]@ @̬j]@`fff@`j]@03333@Pm]@0333 @4333p]@`ffff@x]@@u U@@̌!1hfffFA@@"/ *4333\A@hfff8(4333WA@<(TA@3(pUA@Y(hfffWA@̌(4333[A@hffff(hfff^A@8333(4333`A@(`A@@(|_A@@-(4333\A@hfff8( RA@(hfffOA@"(LJA@8333!(4333SEA@̌ (FA@hfff'4333KA@83333'hfffOA@83333' RA@(4333ә@@,4333@@+4333C@@+l@@hfff&,0@@hfff& ,~@@Y ,}@@,{@@hfff&+u@@̌+o@@+g@@L+a@@hfff+hfffd@@v+4333Cg@@hfffk+4333f@@`+b@@hfff&P+hfffV@@8+U@@L.+4333a@@+43333h@@hffff+ m@@*)s@@̶*4333#x@@̃*{@@83333s*4333#}@@YQ*L|@@hfff&+*hfff~@@)@@)9|@@) y@@ٛ)4333|@@g)4333Â@@B))@@8333)@@( @@(ٽ@@̌(4333@@ (hfff@@(\@@̨(@@ٝ(L@@hfff9(hfff@@' @@'hfff@@8333a'hfff@@hfff8'@@''@@'ɝ@@&Y@@&9@@̌&̜@@P&Y@@+&@@Y%@@%4333s@@hffff%y@@hffff%hfff&@@%@@%|@@8333%\@@Y.%̬@@83333%hfff&@@hfff&$@@Y$@@$4333@@hfff&x$4333@@@f$`@@hfff=$@@8333s$hfff&@@8333s#@@8333s#̼@@hfff#@@hfff#9@@8333]# @@@#4333@@5#`@@̌4#hfffF@@F#hfffք@@hfff&E#|@@hfff>#hfff}@@8333%#l}@@hffff #̼y@@hfff"0v@@83333"u@@"w@@hfff"̬|@@@"4333@@hfff"hfff֜@@@#Y@@ #@@L7#@@L=#hfff@@ 7#L@@@2#4333@@8#hfffV@@8333sS#hfff@@W#4333@@hfff&X#4333@@Q#<@@l#@@# @@#hfff@@#y@@#hfff@@Y $ A@Y2$4333SA@̌P$A@ $ A@̌$A@hfff$hfffF!A@hfff&$lA@@$A@$LA@%hfffA@hfff%A@ "%hfffFA@hfff-%A@83333:%A@̌%&4333SA@2&A@hfffB&A@hfffU&A@t&4333!A@̌&hfff%A@8333&L)A@YN'4333(A@['hffffA@hfff'̌A@83333'A@'4333A@' A@8333'4333A@()A@j(4333A@hfff(hfffv A@8333(̬ A@()A@hfff&(A@̌(43333A@hfff&( A@8333H)`A@83333^)@A@m)!A@hfffu)"A@hfff)4333#"A@hfff)4333C#A@hfff&)4333S&A@)hfff(A@)<*A@)4333,A@8333P*I+A@hfff*(A@hfff* (A@Y*4333)A@@*4333s4A@hfff&+̜:A@$+?A@̌"+EA@3+yMA@V+OA@8333s+@LA@+hfffIA@8333+EA@L+hfffDA@+EA@hffff,HA@6,hfffLA@LQ,QA@c,VA@m,YA@hfff&y,pZA@hfff&,`]A@83333,bA@L,hA@hfffn,4333iA@8333d,hA@[,4333iA@8333L,lA@̌9,mA@8333%,4333lA@8333,4333mA@Y,pA@hfff&,sA@ ,hfffwA@L,xA@@$,@yA@D,̬zA@8333K,4333ÁA@P,4333#A@8333sZ,A@ٓ,hfffA@,04333+4333H@i+̬ H@Lp+9+H@G+3H@8333s+4333@H@*OH@*4333eH@8333*hffftH@hfff&)uH@)hfffvrH@q)ImH@hffff8)hfffdH@(hffffH@L(hfff&sH@(4333CwH@(4333H@8333(H@((H@ )(4333H@8333s?(4333CH@`(hfffH@y(iH@hffff(hfffH@@(+H@L*+H@* H@@*yH@* H@*hfff"H@h*'H@e*,H@*+H@L*H@hfff&0yH@hfff&1hfffH@hfff043333H@`04333I@0H@hfff&0wr4@lD@8333s7@-E@Q5@ffffE@hfffF5@ffffE@@5@D"E@̌5@&E@`5@y'E@8333s5@9)E@@5@(E@8333S 6@ffff&E@̌%6@)E@`=6@-E@F6@,E@@Q6@ffff.)E@8333X6@0(E@̌6@!E@,6@3333k E@̬6@E@6@IE@96@ffff.D@6@D@hfff6@ffff6D@83336@3333D@7@3333D@8333s7@D@83336@̄D@6@̔D@6@3333 D@6@ffff.D@̬6@ffff~D@L6@D@̌6@ٖD@hfff6@D@Y~6@3333+D@f6@3333ˏD@<6@ܓD@9/6@ffffND@̌#6@D@L5@3333ÐD@83335@D@̌5@yD@hfff5@3333rD@hffff5@9oD@̬u5@sD@8333sg5@fffftD@R5@ffffnD@hfff%5@3333{nD@5@ffffmD@4@lD@hffff4@ffffoD@4@sD@hfff4@ffff~uD@hfff4@sD@83334@vD@83334@D@L4@D@`4@\D@,}4@D@̬|4@D@ ~4@D@r4@D@y4@D@hfff&4@D@@4@3333CD@8333S4@ffffnD@4@aD@83334@D@4@D@hfff4@ID@4@D@4@D@4@YE@833334@ E@L5@E@y$5@fffffE@45@E@A5@̼ E@`I5@ E@,L5@ffffE@T5@E@c5@3333#E@83335@3333E@5@ffffE@xffff@H@@fffffI@.Lw@|I@fffn@ I@ffffp@fffffI@@ffffH@@3333#H@@3333@3333H@ffffL@@H@@H@@4H@@H@ffff@H@L@LH@@ffffH@ffff@H@d@H@`@3333H@@ H@@ffffFH@ffff@ܿH@z@3333H@fffK@1H@@333 @H@@1H@@3333@ H@@H@@3333K@ffffH@@333(@ffffH@C@3333H@@333Y@ffffH@m@qH@@H@7@H@fff&@3333#H@ffff@ffffvH@@3333@3333H@@H@fff@H@fff@ffffH@'@ H@E@I@@333w@ I@@333@fffffI@8@I@@3333[@I@@333p@I@Lw@|I@yY4@LJ@8333:@4L@ 833334@3333K@Y4@K@5@3333sK@5@K@5@3333K@hffff5@K@5@K@5@ffffnK@ 5@ܬK@833334@3333K@hfff&6@3333-K@l6@33333K@ 6@3333?K@96@ffffHK@̬6@PK@6@3333SkK@ 6@ffffoK@̌6@vK@6@@|K@96@K@̬X6@9K@L#6@K@hfff6@ffff&K@5@K@hfffƮ5@ffffK@5@K@8333sr5@K@hfffc5@DK@,L5@١K@Y<5@ffffΡK@<5@ffffK@y35@K@hfff<5@ffff>K@+5@K@5@ffffK@hfff 5@L@ 5@L@̌P5@L@L5@3333C(L@hfff5@)L@ 6@L3L@hfff6@4L@̬]6@I2L@@6@33330L@83336@3333K0L@hfff&6@ffff2L@6@0L@ 7@3333{)L@̬7@3333S*L@hfff&27@ffff.L@ٜ7@3333*L@7@*L@ 7@$*L@8@3333%L@hfff8@3333!L@,^8@9$L@@y8@\$L@l8@%L@83338@ffff0L@83338@̬2L@L8@4L@,8@2L@8@̬)L@hfff9@ffffL@49@ffffL@83339@L@hfffƩ9@3333k L@Y9@ffffFK@8333:@ffffVK@hfff:@K@hfff5:@3333K@H:@ffffK@̬f:@ffffK@:@K@8333:@qK@@:@3333K@ :@3333K@:@\K@83333x:@3333K@hfff&u:@ffff֫K@~:@̴K@hffff:@9K@:@̌K@8333:@K@:@ffffK@̬:@ɜK@:@3333#K@hfff:@K@8333J:@ffffޑK@83333@:@K@83333;:@K@@7:@3333sK@,:@3333kK@:@,{K@hfff9@@pfffF#@ffffFH>@pffff#@̜W>@@#@ffff&c>@@333s#@2333l>@$@>@@$@|>@n$@>@$@l>@$@>@|$@9?@pffffX$@@@?@:$@v?@Q$@?@Yd$@ɕ?@$@Y?@@333$@p?@$@l?@Y%@2333s?@pfff0%@?@7%@ffff?@@333]%@2333?@ %@ffff@@%@3333S @@pfff&@3333@@pfff&V&@ @@L&@0,@@̌'@33334@@pffff'@ffff<@@L'@1C@@pffff&@@R@@pffff&@ffffd@@&@r@@@3333&@̜{@@@'@@@Y'@I@@@333sP'@8@@'@ffff@@L(@m@@pfff(@ j@@́)@f@@@333F*@r@@pfff&*@3333u@@+@i@@pfffK+@@f@@@333+@Ye@@@333O,@Z@@pffffy,@33333W@@,@pF@@-@3333kA@@pffffZ.@2@@pfff.@'@@ٷ.@p@@pfff.@?@.@?@pfff&.@2333#?@ 1/@ffff?@@333si/@)m?@/@i\?@0@2333C?@8333ss0@0:?@83330@6?@hffffY1@?@1@ffffv>@hfff1@ffff>@02@>@y2@ij>@2@YJ>@̬3@ D>@̬J3@I>@3@i>@3@ffff}>@`4@>@̌4@ffff>@hfff&4@ ?@ $4@ 2?@83334@L?@ 4@ i?@83333@ffffV?@hfff&3@I?@833333@2333?@4@ffff @@4@@@^4@3333#7@@4@3333CJ@@83335@Dc@@Q5@3333c@@l5@3333Kf@@̢5@w@@̬5@3333x@@hfff5@ffffNt@@/6@u@@83333W6@p@@6@e@@ 6@^@@6@W@@833337@33333O@@83333!7@\9@@hfffF7@ffff2@@833337@l*@@LI7@ffff^@@833337@P@@7@H@@ 8@̼@@83333!8@ffff.@@8333z8@?@83338@3333 @@hfff8@?@`8@ffff&?@hffff9@2333#?@8333s9@Y?@hfff&9@̬?@̬9@|?@hfff9@23333?@9@ffff?@83338@pm?@L8@ffffU?@hfff&8@2?@hfff8@̬?@83338@,>@8333S8@>@ 8@2333>@L8@َ>@hfff8@ u>@8@ffff&@>@hfff8@y3>@,8@̬!>@8@2333=@83338@ =@̬8@=@hfff8@2333S`=@8@L9=@83338@.=@83338@2333<@83338@ffff<@83338@<@83338@̜H<@83338@ <@83338@2333;@83338@ffff&;@83338@b;@83338@,);@83338@̬:@83338@0:@83338@2333|:@83338@ffff6C:@83338@ :@83338@<9@83338@9@83338@4333C]9@83338@dfff#9@83338@I8@83338@̰8@83338@Pw8@83338@4333=8@83338@dfffV8@83338@7@83338@\7@83338@W7@83338@`7@83338@43336@83338@dffff6@83338@q6@83338@l86@83338@5@hfff8@`5@8@4@8@<4@8@4@83338@433334@hfff&8@3@`8@L3@̌8@dfff3@l8@3@@y8@dfff3@:8@3@83337@dfff3@83337@3@83337@ 3@83337@3@83337@4333#3@8333S7@43333@̬7@4333C3@hfff6@433344@hffff6@4333cq4@5@43334@5@dfff4@8333s4@4333'5@%4@dfffc5@hfff&3@dfff65@03@dfff5@2@dfffV6@9;2@dfffU6@83331@dfffv6@8333E1@dfff6@L0@dfff 7@hfffP0@dfff&H7@/@q7@A/@dfff&I7@pfff.@4333#)7@@-@dfff6@@3333-@ 6@-@4333S6@pfff&v,@4333S6@Yn,@43336@f,@̬6@@333+@6@2+@7@pffff*@ .7@)@J7@@(@4333f7@̌'@43337@'@7@@333'@7@?'@4333#8@pfff'@4333sJ8@pfff'@yP8@pffff7&@o8@L_%@dfff&8@$@z8@@333$@P|8@̦$@̼8@$@L8@@333o$@8@@3333=$@L8@pffff$@ 9@ $@0B9@Y$@4333U9@pfff#@П9@)#@9@"@0:@@"@ffff%:@@3333"@>:@"@pU:@@333^#@0p:@#@L:@@3333#@|:@@333#@2333:@#@2333s:@@#@ffffv ;@L#@ffff&8;@~#@2333T;@̌#@;@#@2333#;@pffff#@ffff <@#@i<@pffff#@̌<@@3333#@2333c=@L#@L-=@pfff}#@2333s^=@pffffX#@ffff&=@G#@=@pfff#@2333=@@3333"@`=@ٞ"@>@̌"@ffff->@ #@:>@|p'g@L!@'L@& @&0333`@ &03333@ U&0333A@+&`fff&@ &`fff&@0333%`fff&'@0333a%@K% @03333<%0333@`fffF$%l$ @0333%`fff&@ @0333s$0333P @9$9` @$`fff& @L$ @$`ffff @0333Sw$`fffF @yK$ !@2$!@&$ @0333 $ @`fff#0333 !@`#L!@Y#0333!@x#l @ o#0333 @g# @`fff&^#`fff @S#0333s @0333SI#@ @`ffff8# @# @Y #03333 @` # @Y#@Z @"`P @9"`fff6 @"̬ @"`fff @0333"`fff&@̌"L@`ffff"w@03333"0333-@"0333@`fff"`fff@"I@̬"03333 @`ffff"`fff&@y"٩@`fff"@`fff"`ffff@"@̆"̂@,n"LU@X"@`fffE"@03333<"@"`fff@! @`fff!03333@y!̌@! @`fff!̌J@`fff!Y@̉!@{!@w!,@yu!k@`fffj!0333@Q!`fff@03336!0333s@`(!L@ !@`ffff !W@ `fff;@@ `fff&0@0333 @`fffF 0333@ K@̚ @`fff& @0333s q@`fffF 4@l @`fff5!@-!L@@!L@ Y@Y @0333s @0333 0333g@ 0333F@`h 0333)@0333C 0333s&@L# ̌1@`fff&%@ 333@ l@@U03333N@`fff&4'@`fff/@`fff@`ffff@@@^@`ffffa@ 33303333j@L]@`fff0333@3@Y`fff& @ 3333Y@`fff&LL@@`fff&@ o@̌FR@G@W@`ffff]@I@ 333sL J@LI0333@ .g@٣w@ 3333`fff@ `fff&\@̬C"03337@"@ O#`fff&@$O@$Y@03331%@Lj%0333@9%=@0333%@@0333S&:@L&@'L@}@ ;@l>hfffd=@<Mhfff<@><@hffff >hffff<@4333 ><@>hfff<@!>hffffp<@y$>`d<@hfff%>P<@7>-<@h>#<@,s>8333 <@l>̬<@hfff>̌<@̌>hfff<@l>;@4333>;@>hfff;@4333ӊ>8333;@hffffw>̌;@hfffFi>̬;@hfffa>8333};@,]>8333sn;@hfffV>h;@hfffFS>8333sc;@P>83333];@yG>hfffY;@4333S?>Z;@(> P;@ >`=;@>̌1;@=hffff!;@=;@4333=@ ;@=8333;@hfff&=`;@l=5;@=hffffK;@4333=Y[;@̌t=hfffl;@,\=@u;@M=8333};@F=8333;@4333s<=;@%=8333;@hfff =L;@hfff<8333;@<;@4333<<@̬<̌;<@hfffhfff<@>~hfffA@@@JB@VA@>hfffA@PA@hfffVB@ffffvPA@̼!B@QA@%B@VA@4333#1B@ffff6TA@l7B@ffffNA@1B@HA@4333)B@̴AA@9*B@3333?A@00B@a?A@P:B@3333;A@@B@X7A@JB@QA@DB@1A@:B@ffffFA@ 6B@aA@l-B@3333sA@ &B@̴@@#B@p@@ $B@t@@p.B@t@@.B@p@@̜,B@@@hfffF$B@@@hfffB@ffffv@@,B@t@@ B@q@@iB@X@@9A@ffffV@@hfffA@@@A@3333s@@`A@@@iB@@@iB@3333@@B@@@A@l@@A@ @@hfffA@@@@A@3333C@@̜A@4@@A@T@@4333A@3333@@IA@4@@,A@̞@@hfff&A@@@)A@@@ A@3333K@@4333A@@@A@ffff.@@hfffA@ffffƋ@@hfffA@ffff@@ٓA@3333{@@ A@ffff&@@,A@A@@A@q@@4333cA@3333@@PA@ffffA@A@ffffA@4333A@7A@A@$?A@,A@FA@hfffA@PA@x83335@qK@3<@ffffM@8333:@qK@:@K@̬f:@ffffK@H:@ffffK@hfff5:@3333K@hfff:@K@8333:@ffffVK@Y9@ffffFK@hfffƩ9@3333k L@83339@L@49@ffffL@hfff9@ffffL@8@̬)L@,8@2L@L8@4L@83338@̬2L@83338@ffff0L@l8@%L@@y8@\$L@,^8@9$L@hfff8@3333!L@8@3333%L@ 7@$*L@7@*L@ٜ7@3333*L@hfff&27@ffff.L@̬7@3333S*L@ 7@3333{)L@6@0L@hfff&6@ffff2L@83336@3333K0L@@6@33330L@̬]6@I2L@hfff6@4L@ 6@L3L@hfff5@)L@L5@3333C(L@̌P5@L@ 5@L@83335@$!L@ 5@3333{QL@@5@piL@hfffA5@dwL@Y5@3333CL@8333g5@ĐL@hfffk5@0L@̌u5@ffffFL@̌5@ffffL@@5@ffffL@@;6@YL@6@̴L@83336@YL@ 6@4L@̬ 7@0L@hfff#7@3333sL@̌I7@|L@8333ӥ7@3333K|L@`7@ffffL@hfff 8@ffffvL@H8@ffffL@8333a8@L@9g8@L@\8@L@83333M8@ffff^L@8333R8@pL@\8@ffffL@yu8@4L@8@L@8@ffffL@L8@ffffM@l9@ffffM@,9@M@̌:9@L@ B9@L@E9@33333M@hfffD9@ M@YH9@4M@ W9@ M@@9@̬L@9@L@̌9@L@833339@,L@9@IL@hfff:@IL@hfff:@̌L@ 7:@L@LL:@L@Lv:@L@Y:@L@:@3333[L@Y:@L@L:@L@̌;@L@hfff/;@L@S;@3333CL@Z;@L@@x;@3333L@ق;@3333 L@hfff;@3333L@9;@ffffL@;@L@ ;@3333L@;@̴L@̌;@L@hfff;@\L@hfffF;@3333KL@hfff;@ffffL@ ;@1}L@8333;@ffff>lL@٧;@ffffkL@Y;@nL@@;@K@̌u;@K@Ym;@)K@hfff&O;@ffffK@8333s ;@PK@:@ffffK@̌:@K@:@K@hfffƞ:@ffffK@8333:@qK@ H4333[Y@hfff+@Z@~6@(Y@4333a6@hfffY@PfffH6@IY@̜-6@TY@03336@43333Y@05@HY@5@Y@ 5@hffffY@dfffv5@4333Y@ 5@hfff^Y@5@Y@5@DY@̌5@YY@̬5@hfffY@dfffF5@8Y@5@Y@5@4333Y@fff5@4333Y@43335@hfffƼY@l5@4333cY@P5@hfffY@ܑ5@hfff6Y@5@̸Y@p5@4333ӷY@dffffV5@yY@4333D5@Y@35@Y@4333C4@|Y@433334@0333Y@P3334@Y@43334@̤Y@4333s4@Y@4@Y@<4@4333sY@dfff4@TZ@P3334@|Z@ 4@ Z@4@`Z@033334@Z@dfffֻ4@!Z@ 4@4333S%Z@̌4@$Z@4@"Z@ 4@Z@P3334@Z@Y|4@Z@q4@Z@̼l4@Z@dfffi4@0333'Z@ _4@4333*Z@T4@\*Z@I4@4333S+Z@dfff94@,Z@44@43334Z@033374@4333C6Z@433334@8Z@I+4@w;Z@@33334@4333c;Z@43334@!6Z@y3@4333+4Z@l3@P3Z@ 3@/Z@dfff63@%Z@dffff3@hfff"Z@L3@Z@|3@4333#Z@L3@Z@̬3@ Z@dfff֬3@Z@3@LZ@l3@hfffZ@{3@4333Z@4333k3@hfffY@pfff]3@hfff^Y@ W3@Y@0333N3@hfffY@̼D3@hZ@;3@4333Z@23@Z@2@hfff&!Z@ 2@@'Z@4333S2@0333-Z@̬2@?Z@4333s2@hfff^GZ@ɭ2@`IZ@`fff2@hfffNIZ@dfff2@4333CGZ@43332@EZ@ 2@hfff~EZ@9s2@TGZ@g2@4333sJZ@dfffV2@|QZ@@<2@XUZ@̌02@YZ@4333-2@4333S]Z@'2@0aZ@43332@eZ@43331@@fZ@43331@$hZ@̜1@@lZ@ 3331@4333qZ@1@hfffyZ@dfffV1@hfffN~Z@lr1@hffffZ@Pj1@@Z@71@hfffVZ@$1@4333CZ@dfff1@ȝZ@Y0@$Z@@0@Z@i0@(Z@00@Z@dfff0@hfffZ@0@̨Z@Pfff0@4333Z@~0@̌Z@u0@TZ@s0@Z@dfff}0@hfffFZ@0@xZ@0@4333#Z@4333e0@Z@dffffZ0@ Z@@333O0@hfffvZ@4333G0@Z@`fff"0@Z@43330@hZ@@0@hfff^Z@4333 0@@Z@hfff/@hfffZ@@/@Z@/@hfffZ@`/@hfffZ@/@!Z@~/@4333Z@,[/@Z@hfffZ@i-@Z@yT-@4333Z@03333 -@PZ@0333S-@4333Z@L/-@Z@$-@9Z@,@Z@Y,@hfffZ@,@hfffZ@0333,@Z@`3333,@ Z@,@qZ@hfff,@yZ@,@$Z@0333,@hfff>Z@hfff,@hfffZ@@333,@YZ@0333s,@4333Z@-@hfffZ@L-@Z@ (-@4333Z@0333-@Z@,@hfff&Z@0333,@lZ@0333,@4Z@,@4333Z@hfff,@Z@,@hfff~Z@,@4333CZ@,@0Z@0333A,@0333Z@fff&,@hfffFZ@hfff+@4333yZ@Y+@hfff6uZ@hfff+@hfffpZ@ ,@XoZ@+,@bZ@0333O,@!YZ@03336,@iVZ@8,@4333;RZ@̬R,@OZ@̬f,@@MZ@̄,@KZ@`,@4333KZ@hfffF,@OZ@Y,@hfffUZ@Y,@ [Z@y,@p^Z@l-@_Z@l.-@4333`Z@̌R-@yaZ@hfffƯ-@bZ@l-@4333#bZ@L.@4333c_Z@0333SA.@4333c_Z@`.@``Z@fff.@`Z@hfffƸ.@dZ@0333.@hffffgZ@.@4333hZ@,/@hfffiZ@@fff&P/@gZ@`f/@hfffcZ@hfff{/@]Z@0333/@YZ@hfff/@4333WZ@fff/@ XZ@hffff/@ZZ@@333/@)UZ@4333 0@̄IZ@43330@CZ@dfff)0@hfffAZ@<0@43334@4333[Y@dfffA4@hfffY@Q4@LY@I_4@ Y@Ж4@Y@43334@hfffY@43334@0333Y@4@4333Y@ 4@4333+$Y@94@hfff'Y@ 4@'Y@dfff4@(#Y@\4@l!Y@43334@P"Y@ 4@4333C$Y@dfff 5@hfffF'Y@05@0*Y@`!5@-Y@Y@5@l0Y@ P5@4333s4Y@pP5@\;Y@]5@$EY@w5@4333HY@dfffF5@hfffLY@dfff5@9KY@4333Sh5@(MY@ b5@4333NY@W5@hfffMY@9G5@\NY@dfffF95@OY@@33325@4333RY@4333#/5@4333c\Y@dfff;5@hfffbY@;5@hfff^eY@45@gY@dfff6/5@jY@l+5@4333mY@p&5@nY@ (5@$rY@@333C45@NQ@C@T@ĞE@]pyPQ@3333D@hffffQ@ D@ Q@"D@Q@$D@4333Q@9#D@hfffFQ@D@hfffNQ@D@hfff&Q@D@PQ@3333D@Q@D@̬Q@D@QQ@D@4333sQ@D@4333Q@ffffD@hfffQ@D@)Q@!D@hfff&Q@ffff%D@hfffR@̜+D@hffffR@$8D@X R@3333+:D@hfffR@):D@R@$8D@AR@L6D@R@i3D@R@̴6D@4333R@ffffF;D@R@ffffBD@hfffR@ED@|R@ffffVHD@4333R@ffffID@Q$R@ffffCD@&R@ACD@hfff~+R@ffffGD@/R@MD@hfff1R@@SD@9GR@̜dD@4333HR@3333gD@tHR@ jD@\?R@nD@4333C;R@kD@hfffv7R@kD@hfff.5R@3333[nD@!*R@YoD@̴'R@ qD@a R@}D@YR@lD@LR@D@R@D@4333 R@3333ӁD@ R@QD@ R@ffffD@̔ R@)D@4333 R@dE@Q@3333+bE@4333sQ@3333cE@hfffQ@hE@̬Q@ffff&iE@hfffFQ@ME@6R@3333GE@hfff6LR@pCE@4333RR@ffff@E@9TR@ffff;E@XZR@33335E@̌_R@3333[4E@[R@KE@\R@YE@cR@3333[E@4333+gR@!E@mR@@E@̴xR@E@|R@ffffE@̄R@$E@hfffVR@ؘE@R@ffffFE@aR@ĞE@IR@E@4333ӧR@1E@4333SR@4}E@ R@3333sE@pR@!kE@hfffR@DhE@R@LjE@R@iwE@R@xE@R@vE@hfff S@|E@4333OS@tE@hfffWS@sE@d]S@ffffsE@`S@4sE@hfffgS@|sE@hfffNsS@ffffrE@4333{S@3333mE@S@3333nE@S@̌oE@̌S@̬nE@4333S@3333jE@S@9eE@hfffS@0cE@4333S@3333#bE@S@aE@4333S@3333KcE@̌S@(aE@hfffS@@UE@S@3333kME@S@3333 FE@hS@3333=E@hfff^S@:E@LS@3333s:E@4333kS@ 8E@4333S@4E@T@&E@hffff T@3333SE@4333T@ffffE@T@E@ T@E@hfff T@ffff&E@8S@3333E@S@tD@S@ffffD@@S@ffffD@hfffS@D@S@33333D@S@ D@hfffS@D@4333âS@3333ӺD@XS@qD@1S@D@4333SS@D@)S@ffffD@hfffS@ffffD@hfff6}S@|D@,tS@ffffD@ nS@D@4333;eS@3333D@,RS@ffffցD@hfffKS@`D@$?S@3333D@:S@D@̼4S@̼}D@hfffV-S@hD@P*S@3333cD@4333(S@_D@'S@TD@$S@ID@hfffV!S@pAD@4333S@9D@hfff^S@1D@4333cS@ffff-D@S@3333#7D@0 S@ffffF4D@hfff S@00D@S@33331D@hfffFS@3333/D@hfffR@&D@hfffVR@$'D@4333R@$*D@4333R@ BD@XR@3333{MD@hfffR@ffffPD@TR@3333SPD@lR@y=D@ R@ :D@IR@9D@hffffR@3333+?D@4333sR@ffff=D@R@:D@HR@6D@R@(,D@hfff&R@ *D@4333#R@9*D@4333R@'D@C@Q@YC@Q@$C@ Q@9C@hfffQ@ffffC@hfff6Q@IC@`Q@0C@Q@C@1Q@̄C@Q@DC@Q@ffffC@hfffQ@3333C@hfffvQ@̄C@Q@C@hfffQ@̼C@)Q@(C@PQ@C@(Q@ffffC@4333Q@ffffC@hfffnQ@3333SC@hfffQ@ffff>C@YQ@ffffC@4333Q@ffff.C@Q@3333{C@4333Q@tC@dQ@C@4333Q@ffffC@Q@ffff^C@Q@C@hfff.}Q@3333C@iqQ@3333CC@jQ@ffffC@4333SfQ@qC@hfff]Q@3333C@hfffYQ@(C@ SQ@,C@QQ@3333;C@NQ@3333kC@OQ@ffffC@QQ@yC@SQ@C@4333cWQ@9C@̤[Q@3333sC@4333{^Q@C@9_Q@C@$^Q@C@^Q@D@_Q@D@aQ@t D@pQ@9D@}Q@3333D@4333Q@D@Q@3333k D@@Q@D@4333Q@LD@Q@ffffC@4333Q@,C@YQ@̼C@Q@ffffC@D@PQ@3333D@1Q@@C@Q@C@yQ@3333kC@4333Q@)D@hfffVQ@3333D@$Q@9 D@4333Q@D@YQ@ffff~D@4333{Q@ffffD@4333{Q@3333C D@\Q@D@Q@̼D@Q@YC@hfffQ@3333 C@4333Q@C@Q@3333C@Q@DC@Q@C@1Q@@C@hfffQ@C@hfffQ@fffffC@4333Q@3333#C@4333#Q@C@Q@C@Q@C@,Q@ffffnC@0Q@C@hfffQ@C@Q@3333C@Q@DC@Q@C@4333KQ@C@4333۟Q@3333C@hfffQ@C@PQ@xC@1Q@C@УQ@@C@#H@2333ӟ=@H@=@H@ffff=@@H@P=@l H@ffff=@H@I=@hfffH@ffff=@`H@ffff=@hfffH@ffff=@LH@ffff=@hfffH@ffff=@hfff&H@2333=@4333,H@\=@hfffv,H@P=@̌+H@ٱ=@@#H@2333ӟ=@43338H@<@hffff"H@`<@YH@<@̜G@2333<@G@|<@4333G@2333à<@G@ffffF<@G@|<@4333sG@2333S<@4333ÑG@2333=@}G@ =@hfff\G@=@hfffDG@2333=@XG@yB=@ybG@2333X=@4333sG@=@|G@@=@hfffG@=@G@2333=@4333G@=@G@@>@4333G@ >@iG@fffff>@hfffG@2333>@hffffG@>@G@y>@G@̜>@hfffFG@=@G@ffff&=@H@ffff=@hfff H@0=@lH@<=@\H@̌=@4333s H@@=@0H@ffff=@G@=@4333G@ffff|=@hfffG@̼j=@G@̜d=@43333G@]=@G@]=@4333G@2333b=@hfffH@Z=@ H@ffffF=@ H@23335=@hfffH@<@` H@<@l+H@fffff<@hfff/H@<@1H@<@43338H@<@X̌4@ID@5@3333kE@Hhfff&X4@iE@hfffx4@mE@|4@̄pE@Yu4@XvE@y4@yE@4@`E@hfff4@E@Y4@ȌE@94@E@83334@ffff֖E@hfff4@lE@Y4@E@l4@E@83334@3333kE@hfff4@tE@hfff4@3333cE@,4@33333E@hfff4@iE@4@َE@5@̼E@hfff 5@E@95@dzE@8333<5@tE@R5@ffffoE@,g5@pjE@d5@ffff.`E@5@3333;WE@L5@3333KWE@5@̼UE@̌5@dSE@ 5@8LE@y5@,6E@ 5@1E@̬5@,E@ل5@ *E@hfff5@#E@5@ffffE@83335@3333E@c5@3333#E@T5@E@,L5@ffffE@`I5@ E@A5@̼ E@45@E@y$5@fffffE@L5@E@833334@ E@4@YE@4@D@4@D@hfff4@ID@4@D@83334@D@ٔ4@ffffnD@L4@̬E@م4@3333E@hfffF|4@E@hfffh4@1#E@hfff&Y4@ffff'E@8333=4@3333c+E@̌/4@33336E@4@(CE@`4@ FE@4@ffffNGE@4@ffffPE@83334@WE@̌4@3333]E@hfff 4@IaE@hfffF!4@@aE@L14@`E@833374@@fE@hfff&X4@iE@ffffNehfff&e@`ffffc@ .:CNUcjs4333e@ @e@`ffff@4333ce@`ffff@̞e@ 3330 @hfffʞe@ 333$ @4333e@ @e@`fffh@hfffe@ 333@e@ 333C@e@`ffffE@hfffve@@4333ce@@4333+e@m@e@`fffh@e@?e@3333)?hfffe@*?؝e@?e@@ffff?4333ge@?4333e@@ffff?he@Z?e@?e@@ffffz?ȟe@h?4333e@̣?e@?e@?4e@?]e@u?hfffre@@ffff?e@@ffffz? e@5?Ģe@ffff&?4333e@G?4333e@I?4333e@? e@?e@3333꿚e@鿚Ye@|e@̴ e@3333'俚1e@e@hfff e@ 俚1e@̌hfffe@84333Ge@hfffe@de@60e@ffff4333e@ffffhfffe@e@#e@[e@ffffhfffe@dhfff:e@3333y?\e@j?hfffe@@ffff?hfffe@?e@@ffff3?e@?|e@@ffff?8e@@ffff?4333ge@?e@?hfff:e@3333y?hfff1e@뿚U1e@0e@3333뿚0e@H<1e@1e@hhfff1e@뿚݆epffff ffffepffffffff4epffffffffʅe@3333 e@33333333effffNe@3333ffffʆeTeHeLOee3333߆e@333݆epffff beffff beffff% ffffceffff be@3333 ffffbebebeffff ffffvgegeL3333%he@333ffff`hebhehe@33333333gekgeffffvgejeL3333 epfffffffepffff33337eLe@3333e3333eL^e̼e@33333333eL3333MeffffNe3333eLjeL^cZffff^c`3333_cpfffW_cHw`c@333383333{`c@333313333_c'ffffp^c0^c*f^cL9^cZ3333 b&Nbhfff&ffffb &ffffb&ffff6b̌&ffffb&ffffb &Pbhfff&&3333 b&ffff{c@3333333c|cffffB}c̆}cpffffy3333}c@3333nk}cn3333%}cp{crffff{czffff{c@333c@ffff?c@ffff?ffffc3333?qc̙?̆cn?c@ffff?3333Cc+?ffffc@ffff?3333c?c3333#?c<@$cL3@Lc3333?c@ffff?c`ffffc@ffffLc 333@c`ffff_@c`ffffg@zc̅@ c̔@c@3333uc@UcL @3333cL @c`fff@c`ffff@̂cL2@3333cV@c`ffffc@Rve!GueHxteffff}tete3333te@3333uueffffffffueffffffffFveffffXve3333uetentexte@3333ffff ueffffcffffueMffffve;3333veffff/3333ve:1we@3333@Hweffff1ffff4we$3333weffffRve!J@@hfff&D@@ ID@ffffDzD@V|D@4333D@JD@l4333ӑD@4333D@@3333 D@ID@ffffD_٭@@o#R?4333A@?P A@ffffz?LA@*?A@]?4333"A@3333?4333s%A@fffff?hfff4A@?=A@?4333DA@? MA@̀?hfffSA@?hfff]A@m?dA@?9fA@?4333fA@]?LdA@3333?gA@̪?lA@?rA@@ffff?yxA@?̌{A@3333K?|A@?hfff6}A@`? }A@@ffff?hffff{A@@tA@`ffff@hfffqA@`fffW@sA@`ffff@nA@ 333@`lA@@@hA@`ffff@cA@@ _A@@4333\A@L@iKA@`fffe@4333BA@ 333@4333S9A@N @ 4A@ 3333 @ 3A@ 3333M @̌8A@ @hfff8A@`ffff4 @I2A@ 3333 @0"A@ @ A@@A@@hfffA@L@hfffA@@@@@4333A@`fff&@0A@̌{@hfffQA@@lpA@03333p@ЊA@Y?@YA@@hfffơA@`fff@A@0333@ФA@L@4333A@`fffu@`A@`ffff@hfffFA@03333@A@`fff&@\A@@`@LA@@@A@@pA@0333@A@l@A@L@̬A@`ffff;@ A@KhfffA@ffff̌A@@3333hfffFA@}A@4333bA@iGA@@3333) ,A@B󿜙A@ffffZɌ&A@@m%5hfffA@𿜙A@3333hfffA@0pA@3333hfffA@ffff"쿜 A@ffff̼A@1A@3333hfff& A@3333`A@gfff޿A@Aܿ@#A@4333{ܿ *A@gffffݿhfff0A@\ݿ`6A@࿜i:A@߿D@y6Q@ُD@,/Q@\D@4333k*Q@3333{D@a%Q@)pD@4333#Q@ffff&jD@hfff#Q@aD@hfff%Q@3333 [D@q&Q@yTD@hfff$Q@3333OD@Q@MD@Q@IOD@hfffQ@3333SD@A Q@3333c\D@0Q@̄`D@ Q@ffffgD@hfffQ@(nD@Q@zD@<Q@D@Q@؇D@4333CQ@QD@4333sP@̤D@4333P@)D@hP@3333D@hfffP@3333D@4333 P@D@4333P@̬D@P@3333D@hffffP@ȔD@yP@D@P@9D@P@3333D@4333kP@ffffD@4333˪P@D@LP@D@P@ffffFD@̤P@D@lP@D@hfffP@D@P@XD@4333 P@D@\P@$E@̜P@E@P@\ E@؀P@E@hfffP@3333K(E@0P@3333;M@/sF@хM@yE+F@ÛclM@S'F@"Z&hM@FF@,DžNkM@F@=&[M@z^_F@14"SM@_RiF@RQM@_F@ՎJM@`ĬtF@4333GM@ffffF@hfff9M@ffff~F@4333C%M@4F@hfffM@F@4333L@HF@hfffVL@PF@L@1F@hfff&L@ffffަF@L@DF@hfff{L@D@̬K@|D@hffffK@ȧD@K@D@K@D@hfffVK@٢D@K@D@hfffK@hD@K@ffffFD@4333K@3333D@hfffƔK@ffffD@ K@D@hfffyK@ffffD@@wK@D@̬sK@̤D@ImK@3333D@hfffVK@3333 E@hfffLG@YH@ffff&IG@hfffH@ffffHG@H@EG@hfffH@DG@yH@3333sBG@H@ffff&>G@YH@4G@hfffH@7G@4333SH@ffff^1G@H@(+G@hfffH@ffff,G@zH@8G@cH@AG@NH@HG@4333KH@ffffIG@hfffFEH@̄MG@,AH@1SG@L@H@lYG@`BH@ffff]G@yGH@`G@yMH@ bG@4333RH@aG@hfffXH@P^G@`cH@ZG@qH@3333KZG@4333yH@ffff\G@zH@ffff&cG@yjH@3333;zG@p[H@܌G@4333LH@3333G@FH@ffffG@4H@ffffnG@I#H@3333G@`H@G@4333H@iG@4333G@ffff^G@4333G@ffffG@G@ffffG@4333G@3333cG@lG@ffffG@ܙG@pG@̼G@9G@G@ffffNG@hfffFG@3333H@I@YH@H-I@@UH@qFI@4333PH@lNI@SH@XOI@ ^H@ffffMI@ygH@LI@hffftH@RI@4333H@\I@hffffH@mI@4333H@3333wI@YH@tI@H@3333I@IH@I@@H@I@hfffVH@L@I@HL@3333I@4333cOL@̌}I@)eL@3333 I@lL@ԅI@L@XI@L@̜I@L@(yI@L@ffffqI@hffffL@rI@L@3333kvI@hfffL@}I@hfffL@I@L@dI@`L@3333I@hfffM@ЈI@\M@@I@ M@ffffvI@-M@3333+I@4333FM@3333K|I@UM@$oI@43333hM@\^I@qM@3333XI@~M@3333VI@J@N@yJ@N@̤J@̧N@9J@N@J@hfff֔N@3333J@̗N@ffffJ@LN@3333J@4333N@̜J@4333SN@XJ@пN@ J@hffffN@33333J@yN@3333J@4333sN@J@N@ffffFJ@yN@$J@hfffN@XJ@̼N@ffffJ@̜N@3333J@`}N@̔J@hfff&~N@ffff&J@iN@J@|N@qJ@|N@J@|N@J@hffffN@ffff^J@4333N@ffff~K@hfffN@ffffNK@N@YJ@N@ffff&J@)N@)J@LO@ffffnJ@hfff&O@ffffVK@?O@K@LKO@K@PO@ffffK@hfffvO@x K@43333O@3333K@|O@K@hfffvO@K@4333O@3333sK@O@hK@hfffO@!K@PO@\K@lO@DK@@P@0"K@dP@ffff#K@hfffP@ffff&K@4333 P@x,K@̄P@,1K@4333!P@3333[.K@)P@ffff-K@43333P@,/K@P;P@2K@̴?P@33333/K@EP@3333+K@JP@̤.K@LLP@ffffv8K@1OP@ffffBK@8TP@FK@43333XP@@HK@[P@KK@hfff^P@OK@LmP@1OK@4333zP@ffffXK@}P@3333kTK@@P@lUK@4333P@3333[K@IP@3333s^K@4333KP@3333dK@xP@ffffjK@P@`mK@`P@3333oK@P@ffffxK@(P@3333zK@Q@3333zK@ Q@}K@hffff Q@3333cK@hfffQ@ffffK@4333kQ@K@43333 Q@K@4333SQ@K@Q@3333K@hfff!Q@8K@-Q@|K@43335Q@ffffޭK@4333>Q@ffffޱK@hfffOQ@ffffK@_Q@ffffK@`oQ@XK@wQ@qK@~Q@3333{K@Q@K@̬Q@3333˔K@hfffƒQ@K@hfffƗQ@3333+K@4333Q@hK@ Q@$K@J@\`R@J@eR@K@̌gR@K@hfffjR@ K@mR@lK@4333mR@3333J@4333skR@J@xcR@$J@YR@ffffJ@SR@ffffJ@IRR@J@4333TR@ffffJ@)WR@3333J@WR@)J@4333 ZR@IJ@4333^R@J@hfff&iR@3333J@4333nR@(J@vR@3333SJ@dR@3333CJ@pR@J@R@̌J@R@3333kJ@hfffƙR@J@yR@ffff~J@̌R@ffffFJ@R@J@̜R@J@4333cR@J@R@J@4333KR@J@hfffVR@J@R@hJ@!R@,J@R@K@4333{R@K@4333R@y K@ R@ K@XR@K@\R@K@hfffS@!K@S@ffff'K@hfffS@*K@"S@,K@d'S@̌1K@0S@33337K@hfff5S@8K@hfff~2S@33333)K@hfff,S@3333[K@)S@K@S@dK@4333S@K@YS@3333K@hfffS@3333K@hfff S@!J@$S@̤J@hfff4S@LJ@yHS@ffffJ@^S@ؿJ@mS@J@)sS@J@ wS@tJ@$S@(J@̬S@wJ@hfffnS@QJ@,S@3333-J@hfff~S@J@̄S@ffffI@S@ffffI@yS@aI@S@3333{I@S@LzI@hfffS@$cI@8T@ aI@̜T@TgI@hfffT@̄kI@$T@ffffmI@T@̴tI@hfffNT@YvI@T@̤uI@T@ yI@T@I@T@3333ۋI@T@tI@̬T@xI@lT@3333әI@hfff>#T@I@&T@3333I@)T@I@hfff/T@ffffI@ 4T@II@hfff&8T@ffffI@;T@3333I@=T@3333KI@hfffAT@ėI@$HT@tI@hfffIT@3333ÒI@1GT@3333CI@hfffDT@I@4333DT@|I@GT@ yI@lTT@3333{I@XT@ffffnzI@@ZT@3333stI@4333\T@ffff~oI@hfff\T@ffffniI@̜[T@̴bI@]T@3333^I@hT@3333^I@!pT@aI@{T@bI@hfffFT@ZI@T@ffff\I@4333T@ffff^I@̜T@!]I@hfff&T@bI@YT@iI@T@3333KoI@T@YrI@ѺT@QrI@4333;T@rI@T@zI@AT@ffff~I@̄T@ffffNI@hfffT@ffffNI@hfff6T@ffffwI@T@ffffqI@hfffT@̴hI@|T@(cI@hfff&U@3333VI@4333[U@hMI@4333C U@BI@4333s U@ffff7I@U@$I@U@̜I@U@̜I@U@I@hfff&U@I@5U@ I@4333#;U@3333C I@4333S?U@I@4333?U@QI@i>U@̼H@ @U@3333sH@DU@3333+H@̼HU@H@4333sMU@H@4333NU@3333H@hfffRU@3333H@WU@H@hfff_U@|H@YxU@H@U@ffff.:H@U@<6H@uU@3333;4H@hfffoU@I1H@LlU@'H@4333iU@ H@hfffhU@H@cU@3333H@aU@33333G@cU@̌G@hfffeU@|G@4333eU@0G@4333iU@ffff޲G@hfffjU@PG@hfffjU@G@dU@ G@hfffaU@ffffG@hfff_U@!G@hfffVU@3333G@NU@G@4333GU@ {G@@U@atG@6U@kG@P2U@TjG@hfff/U@3333nG@ .U@|E@ME@00R@ffffQE@*R@TE@4333"R@VE@hfffR@3333`E@4333[ R@ffff^aE@hfffFQ@dE@lQ@]E@hfffQ@ffffnUE@Q@3333KE@tQ@DE@ Q@3333:E@4333Q@ffff5E@$Q@̄+E@$Q@%E@Q@E@ @G@e8V3N@ 1AG@K՗/N@5TNG@m$N@zeYG@@<6N@,2IG@5M@ 8G@N@8J-G@ޘ,N@X"3G@P&/JN@g%G@Vx\N@G/G@MiN@޻G@"L`N@ʒG@ @B@ffffV>@4333sB@>@4333sB@Pq>@B@ Y>@0B@T>@B@23333P>@B@2333%>@оB@>@B@̼=@hfffB@@=@vB@ffff=@̬`B@2333=@ZB@ffff=@KB@ffff=@@A@2>@hfffA@2333cb>@A@k>@hfffFA@ >@IA@i>@ A@`>@A@ffff6>@hfffA@ffffv>@9A@ffff!?@pA@ffff6?@IA@2333;?@hfff6A@)S?@ A@LS?@̬A@2333z?@4333A@ffff?@A@ ?@̌A@?@hfffA@2333#?@4333sA@0 @@9A@3333s@@hfffA@2@@hfffA@XO@@4333SA@R@@A@U@@@4333CP`@=>@hfffBN`@2333C>@4333kL`@`c>@O`@,w>@T`@2333c>@4333U`@]>@S`@2333SC>@hfff^`@̜e>@[`@ffffb>@[`@q>@^`@9>@P^`@2333ӫ>@d``@2333>@hfffFa`@2333>@hfffa`@ffff>@̤b`@ffffv>@hfffa`@y>@4333_`@̬>@hfff^`@̜e>@B`@fffff@@@`@@@?`@4@@>`@33333@@@`@3333[%@@}@`@ffff&(@@hfffV?`@P,@@hfff@`@3333<@@P@`@B@@hfff^E`@ffffFE@@4333KF`@>@@hfffbF`@+@@B`@fffff@@(`@3333A@&`@ A@4333%`@A@&`@3333 )A@*`@3333s$A@̸*`@3333A@(`@3333A@4333W,`@D-A@̰+`@3333'A@̄)`@x+A@̈(`@3333k/A@hfff*`@BA@hfffN*`@ffff&JA@m*`@3333MA@4333o.`@WA@hfff/`@ffffUA@]/`@!SA@4333/`@NA@hfff6/`@,EA@4,`@ffffN5A@4333W,`@D-A@hfffJ`@ffffVd@@`@`@@hfffZ`@b@@4333`@3333Sc@@`@ffffa@@$`@ffffX@@`@yS@@H`@3333R@@4333K`@Q@@`@ffffK@@,`@hM@@`@pP@@`@̼T@@hfffJ`@ffffVd@@1L`@<6@@\I`@̬5@@1H`@3333+7@@G`@<;@@K`@3333{C@@N`@3333B@@dM`@ffff:@@1L`@<6@@Ta@3333F@hfffa@yF@ma@F@a@̔F@ a@F@Сa@3333F@A@hfff`@ffffA@4333`@3333@@`@L@@hfffƍ`@ffff6@@<`@3333@@4333'`@@@̄`@3333k@@`@̌@@hfff`@@@4333k`@@@`@Q@@4333`@3333@@6`@9?@hfff5`@?@hfff6`@?@19`@?@e9`@2333?@6`@9?@a@2333ӝ:@pa@̜:@ma@ffff:@hfffa@:@,a@:@xa@ffff:@a@2333ӝ:@`a@F@hfffba@3333SF@,b@ffffF@hfff>b@ F@4333kb@3333E@b@E@4333b@E@b@YE@hfffb@E@@#b@DF@*b@̼*F@4333+b@)F@+b@$F@4333C+b@iF@'b@ F@4333 $b@HE@<#b@E@x$b@E@&b@3333E@(b@@E@*b@E@-b@ E@̜/b@ffffΣE@hfff2b@E@hfff5b@ffffƱE@hfff 8b@E@:b@fffffE@87b@ffffE@3b@IE@hfff21b@E@)0b@LE@,b@3333E@hfff+b@ffffE@\'b@XE@$b@`E@ b@ E@|b@ffffE@b@1E@4333/b@4yE@̄b@xE@hfff b@~E@Pb@|E@a@pE@4333ca@3333_E@4333a@3333LE@hfffa@ffff5E@a@ffff)E@̠a@4E@xa@TE@ a@3333 E@4333a@E@a@ffffE@4333a@E@a@ffff&E@4333Ca@!E@a@aa@ffffJE@4333a@FE@hfffa@3333+E@Ya@ffff.E@4a@@E@hfffa@ffffGE@̼a@!IE@hfffa@ffffHE@`a@GE@Ua@3333[>E@8a@7E@hfffZa@3333#0E@hfffa@*E@ta@̌%E@Ta@E@a@ffffE@|a@0E@a@ffffE@4333{a@E@1a@(D@hfffra@̌D@Ԥa@ D@̄a@AD@a@3333cD@hfff a@3333#D@ a@TD@a@dD@a@`D@4333a@ D@Ѝa@D@Qa@xD@̤a@ffff^D@a@,D@a@D@,a@̤D@4333Ka@3333D@a@D@hfffa@ffffD@a@D@xa@3333D@сa@ffffE@ŀa@ffff E@̤|a@3333SE@za@#E@Dza@̜1E@4333za@\9E@hfff{a@ffffvJE@|a@SE@4333k~a@UE@4333{a@ffffWE@4333a@]E@,a@3333eE@a@nE@ԍa@ zE@̐a@3333cE@a@3333kE@4333#a@YE@hfffa@̦E@̔a@IE@̴a@ffffE@4333a@̄E@hfff6a@LE@a@E@la@E@4333קa@E@4333{a@ffffE@a@3333ˣE@1a@԰E@4333a@E@a@AE@La@3333E@8a@E@a@|F@%a@ffff!F@a@3333/F@Ya@3333=F@a@[F@hfffa@txF@a@ffffF@a@ffffF@a@3333àF@a@F@a@33333F@`a@\F@hfffa@ffffF@4333a@)F@hfffa@ܽF@a@8F@4333ca@3333F@hfffa@ffffF@}a@ffffF@Pa@F@a@3333hF@Pa@ffffUF@4333ga@xDF@`@a\@@H;`@̔O@@8`@ffffI@@9`@R@@t:`@\@@hfff&9`@ d@@6`@p@@hfff^5`@ffffv@@15`@Y@@43335`@̬@@43338`@ffff&~@@:`@3333Cr@@4333<`@3333 m@@?`@m@@=`@ffffv~@@hfff<`@܂@@43339`@3333@@H5`@3333@@2`@ffff>@@hfff3`@@@hfff5`@@@x6`@ffff@@4333;`@0@@p;`@@@:`@@@l:`@@@i=`@3333@@hfffNB`@@@4333OC`@@@-D`@@@`E`@̔@@H`@@@hfffK`@ffff6@@N`@3333@@N`@@@4333{O`@@@lU`@ffff.@@hfffV`@@@hfffZ`@y@@^`@ffff@@hfffJ``@ffffN@@a`@ @@hfffe`@!@@p`@ A@`@|A@hffff`@A@T`@A@`@ffff@@@`@@@`@̄@@̤`@ffff@@4333`@Y@@`@@@4333`@ffffn@@`@@@@̔`@i@@`@̤@@`@̴@@`@3333c@@T`@@@`@ffff@@9`@h@@hfff&`@3333@@`@3333@@̨`@̤@@hfff:`@̜@@4333`@@@4333`@}@@E`@ffffk@@hfff֛`@ffff`@@̼`@A`@@hfff&`@Qc@@`@a@@`@̄s@@4333C`@3333u@@؏`@3333Su@@4333Ï`@3333@@̰`@@@9`@0@@D`@0@@4333+`@3333 @@4333{`@@@]`@3333@@@`@@@4333`@fffff@@5`@@@4333`@@@hfff`@Y@@4333`@@@4333 `@̄@@`@@@hfff6`@@@`@@@4333'`@3333@@`@P@@]`@<@@4333`@ffff@@4333`@@@`@@@ܚ`@A@`@33333 A@4333`@H A@`@@@4333G`@@@-`@3333s@@`@@@1`@@@4333`@̄@@`@1A@hfff`@A@4333`@<A@H`@ffff6A@hfff`@ffffA@`@aA@4333k`@ffffF'A@X`@̌,A@m`@-A@`@ffff(A@p`@ A@hfffVa@3333D@a@ID@4333a@ffffγD@pa@ffff&D@̬a@TD@A@`@3333{;A@hfff.`@ffff7A@@`@q7A@`@3333S1A@hfff`@,A@hfff`@ffff&A@4333`@0*A@ɘ`@3333 A@hfff`@A@hfff`@ffff$A@4333{`@3333;-A@`@)A@hfff`@ffffA@hfffv`@A@`@@@`@\@@4333`@@@lx`@3333A@hfffw`@A@B@4333w!a@ B@hfffna@3333B@a@3333B@a@B@hfffa@lB@ a@zB@h a@3333rB@̈ a@)kB@#a@cB@'a@h`B@hfff)a@3333{`B@hfff*a@3333bB@q/a@ffff^vB@4333s0a@yB@8=a@DB@Ca@ffffVB@hfffFa@1B@F@pfff& "@@F@pfff"@3333F@ "@F@@333s!@ffffF@̌"@G@@333s "@ffffG@Y$"@ G@pfff&h"@G@̌"@̴$G@"@2G@@3333"@3333D@8333.1@3333[@D@1@AD@0@:D@0@)D@l0@D@̬0@ C@0@C@hfff0@C@hfff0@ffffC@0@̤C@8333S1@C@y1@3333{C@8333,1@C@91@̬uC@83330@3333KxC@hffff0@qC@0@3333kfC@0@ffff~[C@0@,?C@̬0@\4C@LH0@C@hfff$0@ffff C@0@3333cC@̌0@ffffB@@333r/@4B@pfffJ/@aC@@I/@3333sC@f/@3333!C@ /@&C@@/@3333=C@/@̔NC@/@3333UC@/@ffff6[C@hfff0@3333C^C@`20@ffff.aC@50@ffffvxC@0@ C@L0@ّC@ 0@3333CC@@333s/@1C@/@ffff^C@@333b/@ffffC@+/@3333D@pfff&.@̬D@̖.@ffffD@-@D@-@3333!D@@333-@'D@pfff-@Q0D@@3333-@3333#@D@@333-#@ D@#@PwD@pfff%#@ffffuD@C#@ffffpD@@3333 @̤C@ @{C@̸ @3333C@ @̤C@̻ @ffff֎C@ @C@@3333 @̤C@@333s @D@pffff @@D@Li @̬D@@333r @D@pfff @D@@333 @D@ @D@L @D@@333s @D@(@ffffD@@333s(@ffffD@@333s(@ffffD@pfff(@3333KD@@333s(@3333D@(@ffffD@@333s(@aE@)@3333E@pfff)@E@(@E@@3333(@E@L(@qE@@333s(@aE@hhffffA@23333z=@T ?A@4@@j̜A@4@@*+8vA@) R@@SfqA@vĪ@@m;{A@d|eB@@#_gA@Ƞ@@Y2ǀA@>Ҫ@@.H/A@Oâ@@хA@ .@@mA@x @@`A@ϺӍ@@4˖+A@rK֊@@@A@ffff6>@ A@`>@IA@i>@hfffFA@ >@A@k>@hfffA@2333cb>@A@2>@ A@ffffF$>@A@ffffV=@hfffֆA@̜=@A@|=@|A@ffff=@sA@23333z=@hfffVoA@\=@4333CeA@ffff=@hfff^A@fffff=@LTA@23331>@CA@0r>@hfffFBA@2333>@hfff>A@ffff>@4333S3A@>@ *A@>@hffffA@2333S5?@hfff,A@J?@4333,A@\?@hfffFCA@?@hfffCA@?@=A@?@4333=A@?@hfffVA@L?@4333fA@!@@vA@N@@A@ffffi@@܉A@{@@hfffA@ffff@@hfffA@ffffƋ@@A@ffff.@@4333A@@@ A@3333K@@)A@@@hfff&A@@@,A@̞@@IA@4@@4333A@3333@@A@T@@̜A@4@@\A@2333S5?@9A@hD@@2 =A@?@hfffCA@?@hfffFCA@?@4333,A@\?@hfff,A@J?@hffffA@2333S5?@43333A@2333J?@\A@ffffR?@43331A@{?@=A@?@hfffA@2@@9A@3333s@@4333sA@0 @@hfffA@2333#?@̌A@?@A@ ?@4333A@ffff?@̬A@2333z?@PA@{?@iA@3333+J@ TJ@!J@Yp3333J@aJ@3333J@ 333J@Y<J@SJ@`ffffffffJ@ 333s̴J@ 333 J@ 333@3333J@\`J@`fffffffI@hI@ZXI@}I@YI@ ̬I@@J !I@`fffq PI@03333 lI@ I@ 3333I@`fffF )I@ٱ I@0333ӫ I@ I@ $I@`fff I@03333-!`I@ x!ffffnI@y!ffffI@̗"ffffƿI@0333ӥ"̤I@"xI@"I@#ffffI@y#3333I@0333#ffff޽I@0333k#ffffFI@0333# I@ #ffff.I@(#9I@L#3333I@0333$9I@0333=$3333I@̌#$I@0333S#I@ #I@0333#3333I@#I@2#I@ +$I@`ffffl$LI@`fff{$ffffI@$3333CI@`fff$33333I@0333v$̼I@̬J$J@̌$̴J@`#8 J@#̼J@`#ffff~J@$J@$DJ@`fff$̤J@$|J@l$ffff"J@C$3333$J@$Q#J@y#1!J@`fff#3333kJ@0333S#3333 J@#ffffN%J@ٴ#0J@`fff#̬3J@L#8J@0333#;J@0333C#FJ@03333,#3333GJ@"JJ@"OJ@ !ffffVJ@!,[J@`fff!`J@ 2"UJ@Y"DQJ@"NJ@L"ffff>PJ@@#̴SJ@`fff.#3333cRJ@03333=#ffffOJ@Y#K@0333u ffff@K@b AJK@0333SD ffffRK@ MK@ !1WK@,n!3333]K@0333L!daK@!8dK@,!̜gK@`fff& pjK@, qK@ {K@Y ̜K@̦ 9K@ ٍK@ K@F xK@  K@K@ 333s63333K@̌ȗK@ ɟK@ԠK@`fff3333;K@tffffK@ 333GK@:̤K@WȊK@ K@\4K@̌H|K@`ffffV3333;K@`fff3333K@̌ffffK@ffffK@ 3333 ИK@L̼K@LK@5ffff>K@v3333K@ 3333<3333ӮK@0K@ K@ 333=AK@3333sK@93333ӖK@K@`fffffffƋK@`4333cC@L=@4333EH@B@4333-E@ffffB@Y:E@yB@hfffVQE@B@^E@3333SB@hfff&cE@B@@oE@ffffުB@4333wE@B@hfff֋E@ffffB@4333E@$B@̬E@3333B@4333CE@ffffFB@hfffE@LB@4333E@0B@E@ffffB@E@̜B@4333SE@xB@F@!B@hfffFF@ffffB@hfffF@3333B@F@8B@̌F@3333B@̬F@B@F@B@hfffF@̄B@4333sF@}B@4333$F@0}B@̬)F@`B@4333s3F@|B@|?F@ffff&B@4333sHF@AB@MF@B@̬UF@8B@]F@(B@aF@3333;B@aF@HB@43333fF@,B@pF@PfB@4333vF@ bB@}F@l^B@hfffvF@dYB@YF@ffffVTB@4333ÃF@|LB@F@ffffVCB@̆F@ffff^@\H@2333c>@H@>@H@ >@H@23333w>@hfffvH@)u>@4333H@ffffj>@YH@2333Z>@4333H@2333CR>@4333#H@P>@`*H@2333I>@0H@:>@`3H@ffff60>@̜1H@(>@hfff3H@>@7H@ >@@=H@>@4333EH@\=@4333#:H@@=@4333c-H@=@4333#H@y >@P H@ >@4333G@ffff>@hfffFG@=@G@̜>@G@y>@hffffG@>@hfffG@2333>@iG@fffff>@4333G@ >@G@@>@4333G@=@G@2333=@hfffG@=@|G@@=@4333sG@=@ybG@2333X=@XG@yB=@hfffDG@2333=@-G@L=@F@=@ܿF@̬!=@pF@ffff*=@hfff[F@1=@lXF@3=@,.F@lo=@ F@̌=@ E@fffff=@lE@>@43333E@|R>@mE@ffff~>@hfffGE@>@$E@>@hfff E@2333?@\D@i8?@4333D@iT?@D@0}?@D@ɝ?@ygD@ffff?@L=D@2333?@hfffF/D@`?@D@?@ C@q@@0C@ffff @@̜C@@@yC@ffff6@@̬C@,@@C@d*@@LC@ '@@hfff}C@|<@@hffffC@ ?@@4333c~C@Z@@uC@3333w@@)lC@P@@4333cC@̤@@4333CC@3333@@YC@\@@@C@Y@@C@@@̜D@A@43335D@PA@@XD@*A@wD@3333{1A@hfffV~D@33336A@̬D@`NA@D@ffffnbA@D@gA@̌D@A@4333D@3333A@ɟD@A@4333ӦD@3333{A@4333SD@A@D@A@4333#D@̬A@lD@0A@pD@d B@9D@B@4333D@"B@4333D@1B@hfffVD@q;B@YD@AB@9D@HB@D@pLB@̬D@3333^B@ E@3333iB@`E@ffff{B@,E@B@hfff-E@)B@4333-E@ffffB@F@4333#9@O@`C@]L@:@hfff& L@:@hfff&K@|:@4333sK@ffffv:@K@ffff:@hfffK@ffffF:@YK@2333:@hfffK@ffff:@B@lK@B@hfff6sK@3333B@̬K@̄B@4333ÜK@̜B@K@3333C@ K@ C@K@ C@pL@ C@L@ C@IL@d C@4333"L@3333K C@4333&L@3333# C@|)L@ffffvC@hfff.L@3333{C@hffff8L@C@4333EL@3333C@UL@ C@hfff&cL@ C@ tL@DC@L@C@hfffƘL@3333C@LL@C@pL@C@lL@ffffn C@L@ffff6C@L@ffffB@hfffFL@ffffB@@L@ffffNB@L@B@4333L@B@L@0B@4333L@LB@ M@3333;B@|!M@9B@(M@B@1M@3333SB@hfff7M@3333B@hfffvFM@ffffB@9SM@fffffB@4333YM@B@`hM@|B@hfffwM@(B@4333ӞM@B@hfffM@ B@M@\B@٩M@ffffB@ M@B@hfffM@B@A@̜aN@N@! A@hfffvCN@ffff@@43333>N@ @@4333cAN@@@4333sIN@ffffN@@SN@3333@@9gN@3333@@hffftN@@@`uN@3333@@mN@fffff@@)bN@@@[N@i@@GN@̤@@GN@ffff@@IN@X@@RN@ffffe@@ZN@L@@hfff&jN@@@4333iN@@@eN@2333?@dN@?@4333fN@ffff?@4333SeN@?@ iN@2333~?@4333SmN@ffff{?@,N@|s?@YN@k?@N@ffffa?@hfffN@ I?@9N@2333?@N@>@`N@>@̜N@p>@4333sN@]>@4333SN@ >@4333kN@2333=@`N@ffff֩=@yN@=@N@2333c_=@4333sN@T=@@N@ffffC=@N@̌=@N@2333<@N@ffff<@hfffN@<@hfffN@<@9O@2333}<@hfffO@2333z<@0-O@,j<@7O@ffff&]<@4333CHO@23333<<@[O@ffff@<@_O@̼@<@hfffaO@Y><@aO@3<@^O@ffff<@4333#dO@;@gO@<;@4333fO@q;@4333aO@2333S[;@aO@L;@Y`O@D;@aO@ @;@4333gO@̼:;@,uO@7;@YO@2333@;@O@2333s>;@̠O@95;@O@ffff&;@O@2333;@O@2333;@O@ffff:@ O@ffff:@O@`:@4333ӗO@l:@4333O@2333c:@43333O@ffffV:@hfffO@:@dO@ffff֤:@43333`O@:@hfffvQO@:@98O@:@I1O@:@'O@}:@:@4333N@ffff9:@̬N@P*:@N@9@N@dfff9@lN@433339@hfffN@9@hfffN@4333S9@N@@9@N@9@hfffN@@I9@@N@39@@) I@23332>@hfffH@5>@hfffH@i>@ H@fffff!>@4333H@2333N>@H@\U>@@H@_>@hfffFH@2333e>@PH@2333#h>@\H@`>@hfffH@i>@̼H@x>@H@i>@@H@̬>@H@2333Ss>@YuH@2333e>@4333rH@S>@PtH@=>@hfffuH@2333>@`oH@>@̌jH@ffff >@UH@@>@9LH@̜=@4333EH@\=@@=H@>@7H@ >@hfff3H@>@̜1H@(>@`3H@ffff60>@0H@:>@`*H@2333I>@4333#H@P>@4333H@2333CR>@YH@2333Z>@4333H@ffffj>@hfffvH@)u>@H@23333w>@H@ >@H@>@\H@2333c>@ G@ffff>@G@̜?@G@9$?@G@̌f?@G@2333?@B@4333KF@B@hfffGF@PB@2F@$B@ +F@ffffB@F@B@ F@3333;B@LF@B@L"F@C@)*F@ C@,F@C@hfff/F@C@0F@ffff C@̌9F@̬(C@hfff9F@*C@hfff&7F@3333-C@0F@ffffN/C@(F@ffff/C@hfff6&F@q1C@9%F@ffff5C@ &F@fffffGC@#F@RC@hfff F@ffffYC@hfff"F@3333kC@F@ffff~nC@F@wC@F@HC@4333SF@$C@F@33333C@F@ԍC@F@C@hfffF@ffffC@ F@C@4333 F@ffffFC@\F@ɧC@4333SF@ffffC@F@PC@F@LC@F@ffff޳C@hfffF@ɲC@*F@C@hfff1F@C@\:F@XC@4333#BF@C@hfff&KF@`C@\F@3333CC@dF@ffffVC@hF@AC@IkF@ffffC@hfffF@ffff6C@,F@3333sC@yF@C@4333F@̌C@hffffF@C@4333àF@3333C@4333F@БC@4333ӱF@ffffFC@hffffF@̀C@F@̄|C@F@ffff6tC@hfffG@3333[pC@hfffG@G@fffftC@4333GG@3333sC@@dG@0C@ mG@C@4333~G@C@`G@ffff^C@G@̤C@4333SG@AC@4333G@ɿC@yG@̌C@G@C@hfff6G@C@yG@3333C@hfffVH@C@$H@3333cC@<)H@C@ H@pC@iH@3333C@4333sH@3333C@\ H@ܞC@ H@ffffC@H@C@hfff#H@C@@%H@ffffC@4333c%H@iC@hfff6#H@ffff.C@H@ffffN}C@̼H@̴zC@iH@ffffwC@yH@fffftC@G@0qC@̌G@HmC@H@ffffhC@43333H@\C@4333H@8XC@4333s!H@ffff6RC@'H@ffffNC@0H@̄MC@l5H@ KC@KH@ffff4C@YQH@ 3C@kH@7C@43333oH@ffff7C@4333soH@ffff>2C@`sH@3333cC@ivH@C@zH@B@hfffH@ffffVB@\H@3333sB@H@B@̬H@ffffB@,H@3333B@ H@B@hfffH@B@4333I@B@I@̴B@hffffI@xB@@+I@B@@DI@B@hfffvI@̴gB@,I@ _B@I@NB@hfffVJ@̔OB@4333J@33333oB@4333CJ@wB@,J@wB@J@3333pB@J@33333mB@hffffJ@3333hB@J@ffffhB@,J@ffffhB@4333K@lB@ K@ffff^sB@43333K@3333yB@J@3333CB@4333J@B@uH9W@% I W f s   ' B M Y m }  9 E P \ n    ) 2 ; E O U \ n x '/8BJS]dmsz^X@q?lX@?TrX@U?hfffyX@J?̤{X@ffff*?4333yX@K?xX@3333?tX@?hfffkX@3333?hfffkX@?hffffX@3333?̄]X@ ?YX@M?4333WX@3333?SX@@ffff?EX@?OX@3333?4333TX@̴?UX@@ffffr?VX@̢?^X@q?|X@ffffrX@@3333X@ffffX@ffffhfff>X@̜ X@ffff.4333X@ffff*DX@ffffhfffX@LX@33334333X@ffff𿜙)X@hfff~X@@3333q@X@%X@\X@hfffvX@4333X@@3333 `X@|X@ffffr4333)]@L:! ]@Y!#]@8333s!%]@8333!$]@hfff!̌]@8333!Q]@!hfff]@ !\@8333!hfff\@hffff!4333\@L|!hfff\@!hfff]@̇!]@hffff}!]@9!]@8333 ]@hfff& y]@y 4333]@̌h h)]@ ,]@8333 4333.]@ 4333.]@ 4333)]@L:!\@8333sO )\@hfffj 8\@hfff& 4333\@8333s T\@ hfff\@@!\\@@;!\@S!\@ك!\@Y!\@!hfffn\@!hfffF\@8333!4333\@hfff!\@8333!\@d!4333\@LB!hfff\@hffff%!hfff\@hfff& \@hffff hfffή\@8333 hfff>\@8333 \@ٰ \@̌ hfff\@8333m \@hfff&U 4333k\@hfff&= hfffF\@8333; hfff\@hffffA P\@] \@_ \@LY 4333\@hfff! 9\@̌" hfff\@; \@8333sO Z@ Z@4333#Z@YZ@@3333\Z@ffff4333kZ@aZ@@33334333Z@9Z@CqZ@̡4333+Z@*hfffZ@@3333}hfffZ@ffff4333Z@4333Z@@3333hfffZ@qZ@ffff;Z@@3333hfffnZ@ܕZ@Z@'hfffZ@4333Z@ffff4333{Z@zZ@ffff%|Z@hfffzZ@1wZ@R4333sZ@u4333KrZ@ffffs4333#mZ@hfffVfZ@@3333`cZ@̡UZ@@3333RZ@OZ@HZ@@3333WHZ@9LZ@zZ@ffff~Z@ffffZ@}Z@^@pffff4hfff^@hfff^@pffffJ^@@333^@̤^@@333hfff^^@^@@3333hfff&^@@333S^@4333#^@@33330^@̍ɾ^@@33334333^@L4333K^@@3333^@pffff^@pfff^@U^@hfff^@pffffhfff^@^@ѻ^@@3333)^@pfff4333^@i^@L^@pffff4333^@@3333̫^@@3333H^@Lp^@@333-^@^@ ^@L4333^@RЮ^@@3333 hfff^@@3333 ^@4333˲^@@3335q^@4333^@\^@@3333S̜^@@3333y^@L4333s^@@3333hfff^@@3333i^@^@pffff4I^@pfff4333^@pfffWhfff^@̌4333C^@P^@̅hfff^@W4333×^@Lhfff^@hfff^@@3333Ghfff^@\^@Ghfff^@h^@pfffb̜^@^@<^@^@yX^@@3333^@LL^@I^@pfff9[@`ffff @hfff~ [@9 @l[@`fff @ [@$@ [@`ffff-@[@F@[@{@[@@[@@hfff&[@`fff@9[@+@ [@L@[@Y@4333[[@`ffff@$[@ 333@hfff[@@0[@@9[@`ffff @4333C [@@3333hfffF [@̴ [@ffff$ Y[@@3333 [@ Z@@3333 Z@@3333U 4333;Z@ Z@̰4333Z@Z@@3333I hfff6Z@ 4333SZ@̬ Z@4333Z@wZ@hfff^Z@Z@ffff\hfffZ@HZ@eZ@@3333̤Z@̇hfffZ@>4333Z@@3333z4333[@ [@ffff[@̣4333C [@@3333A`@`@4333`@ffff`@p4333`@`@943333a@ffff4333a@ffffN4333 a@hfff a@@3333񿚙 a@@3333򿚙Ea@oa@xa@@3333H`@4333`@@33334333k`@t`@ffffV꿚`@84333`@14333`@3333x`@ffff`@ffffh`@ffff濚A`@,`@x`@E<`@@3333+4333sa@zx a@hfffa@ffffhfff"a@a@̬a@@3333ghfffa@4333a@@3333?4333o a@La@ffffL)a@@33334333a@/`@hfff`@`@,`@xhfffZ`@p_`@٧4333``@8333sh`@,ÿ$j`@hfff&ʿi`@ο4333j`@̔ҿ=h`@h׿f`@׿e`@$ֿ c`@ տ,``@gfff׿I^`@4333տ\`@gfff.ѿhfffY`@̿4333U`@hfffS`@lT`@L¿4333V`@ǿ\X`@gfffҿhfffY`@gfffVӿ4333Z`@ӿhfff\`@4333 ֿhfff\`@ڿX`@hܿdV`@ٿ V`@4333ҿhS`@տeR`@(׿Q`@4333s׿O`@ѿJ`@пhfffG`@hfffʿ4I`@ÿpI`@K`@hfffhfffM`@hfff6O`@hfffƮQ`@hfff汿hfffR`@@W`@̌hfffZ`@phfff`@j@x `@G@Q`@@`@ 3333a@hfff `@ 3333@4333`@`ffff@hfff2`@@D`@`fff@`@@`@@`@@hfff`@j@`@`@8`@f4333{_@ffffl_@ _@I_@%_@@3333QH_@p4333;_@ffffB_@̜4333c_@Q̌_@_@ffff `@hfff`@̨`@hfff_@@3333l_@ffffhfff~_@R|_@@3333hfffy_@9w_@4333w_@Ihfff{_@̘hfff}_@̜_@@3333hfffv~_@@3333X4_@@3333hfff_@@3333̌_@̢4333;_@ffff*p_@hfff6}_@ffffu_@4333^_@ffff [_@ffff4333C[_@X_@@3333}hfffv\_@hfffVa_@ffffn_@@3333̌_@̢ >_@ID_@@33334333#F_@ffffH_@ffff0TI_@hfffL_@hhfffL_@|hfffP_@U4333S_@hfff~T_@T_@H_@@33339hfffn@_@h5_@O(_@̦Q!_@@3333̼_@ _@`_@_@ffff_@@3333Ohfff~*_@, >_@I4333kj`@i`@̌ 4333e`@c`@L4333c`@4333b`@u`d`@ hd`@Lf`@Pf`@whfffRh`@i`@,k`@4333'm`@L\4333Gn`@pfffBqo`@@333 q`@pfffp`@q`@4333t`@slv`@hfffw`@hffft`@Lv`@pffff4333s`@@3333r`@4333o`@@33334333'o`@Ll`@z k`@j`@4333kj`@4333C_@pfff _@@3334333_@X_@4333_@;)_@zhfff6_@@3333hfff_@@3334333_@@3333_@@3333_@hfff|_@̤t_@hfffs_@@3333̼s_@̅hfffu_@LD4333k~_@Lhfffv_@̬_@@333_@_@pffffn4333_@I|_@4333C_@pfffhfff$_@H `&_@Lg Q+_@ V $0_@8333Q $;_@U 8C_@8333[ G_@h hfffnH_@hfff& 1F_@hfff hfffn_@hfff \_@̌ _@ 4333C_@8333s 0_@̌ _@] ̌ _@YE hfff$_@H 4333``@ffff hfff^`@~4333 [`@Y`@ffff̨W`@򿚙V`@hfffV`@`U`@|̈U`@ffff\`@3333{^`@ffffJhfffa`@\]b`@hfffza`@4333``@ffff hfffX@@`'X@@hfff5X@ @=X@@|EX@0333s@0LX@L@\X@0333@4333`X@@cX@@eX@0333s@4333;mX@)@4333#zX@@}X@`fff&@X@`fff&@4333SX@0333s@hfffX@@hfff~X@ J@pX@03333@4333X@_@СX@@(X@l@X@@4333+X@@ɱX@L@X@̮ @̬X@`ffff @`X@L} @hfffX@`fffv @hfffX@@4333 X@(@\Y@Z@$Y@L.@Y@@4333Y@ 333J@̬Y@ 3333@@Y@ 3333@hfff!Y@`ffff@&Y@@4333+Y@`fff@hfffF4Y@?43338Y@,?43338Y@g@H4Y@@hfffV4Y@̍@5Y@@!8Y@ 3333D@hfff;Y@[@BY@L@iNY@`ffff@@SY@ 3333@4333VY@33331?YY@@ffff?^Y@?dY@?4333kY@@ffff?9rY@3333?hfffFY@?hfffFY@?Y@@ffff$?4333Y@@ffffD?4333KY@L?LY@̰?Y@?Y@?@Y@ffff?\Y@3333?Y@3333A? Y@ffff?AY@|?4333{Y@̔?4333SY@ffff?43333Y@̴?Y@2333K?hfffVY@?hfff.Y@3333??Y@ffff?4333Y@ffff?Y@ffffp?4333cY@8?hfffY@3333? Y@? Y@}?Y@2333S?YY@ ?hfff6Y@ Y@lY@̌ȿXY@hfffοqY@4333cѿhfffY@gfff.׿̴Y@ڿhfffY@4333ݿY@3333῜Y@3333kY@ffff&hfffY@ffffvhfff&Y@`쿜)Y@TᅵZ@W̴ Z@ffff4333{Z@4333Z@@3333hffffZ@0hfff>Z@Z@ffff̜Z@0!Z@.!Z@ffffhffff$Z@I+Z@2Z@S6Z@ffff 6Z@_hfff4Z@4333c2Z@C*Z@l)Z@ffffp4333[(Z@Xhfff)Z@,Z@hfff/Z@@333388Z@Y:Z@@3333#!>Z@AZ@@3333hfffVRZ@hYZ@ 4333_Z@p@eZ@4333yZ@@3333hfffւZ@Z@I ̼Z@̼ (Z@ffff yZ@G ̤xZ@@3333 vZ@ vZ@@3333 PyZ@<̌{Z@`{Z@ uZ@@333|hfff6uZ@̦̼xZ@@33337hfffxZ@hfffFxZ@@333,xZ@ 4333;tZ@̴`sZ@oZ@pfffELkZ@@3333EhfffgZ@2dZ@pfff hfffcZ@pffff4333saZ@pfff\VZ@@3332tSZ@@333G43333HZ@@33334EZ@pffff4333sAZ@L;Z@hfff(Z@pfff'Z@I'Z@pfff4333C+Z@Chfff+Z@4333c(Z@@333&Z@LhfffZ@pffff6hfffZ@ĽZ@' Z@hfffFZ@@3333hfff6Y@QLY@!hfffY@DAY@IY@pfffY@bкY@iY@̛hfffΗY@4333Y@ffffe )Y@@3333 XtY@@3333 iY@ eY@V 4333ZY@0pWY@wSY@ffff43333MY@OhfffGY@̳qX@`fff @hfff69X@: @4333C3X@ @!X@"@hfffvX@̇@X@@X@J@4333;W@ @W@٥@W@`fff @̤W@u@hffffW@@9W@"@ W@̌b@W@`fff@̌W@0333s@4333SW@@̔W@YB@W@_@YW@`fff@hfffW@@@W@0333o@0W@03333Q@W@@X@g@X@Y-@hfffX@`ffff@hfffX@@4333^@833339!hfff^@hffffK!q^@hfff\!^@8333ss!̴^@hfff&x!4333^@z!4333^@hfffu!hfff^@L}!̬u^@!@o^@hfff!i^@hfff&!4333g^@hfff&!ie^@hfff&!_^@ٟ!Z^@83333!4333U^@8333s!hfff6L^@!H^@!4333E^@!AB^@8333!hfff>^@L!43331^@!4333;#^@̌!4333s^@!̼^@̍!hfff^@̞!43333]@!4333C]@!]@8333!̴]@83333e!hfff]@8333>!\]@$!@]@8333 !hfffn]@@ ]@8333 ]@hfff hfff]@ Y^@L 4333^@hffff ^@ 1^@8333s 4333^@@ #^@ hfff'^@{ i-^@ hfff0^@ hfff8^@@ hfff@^@hfff& G^@ ̴Q^@8333 hfffW^@ !4333s\^@'!hfff_^@+!c^@̌&!g^@hffff !̼k^@!o^@hffff!9w^@hfff Yz^@ 4333}^@ I^@ 4333K^@L hfff֐^@8333?!^@8333A!hfff^@3!ܝ^@"!4333^@8333!^@8333s 4333^@8333 ^@ ^@̴ hfffn^@ٛ 4333Ӻ^@q ̌^@83333_ hfff^@@ ^@/ ^@ 6 ̜^@M a^@ hfff&^@L ^@ ̼^@hfff& ^@Y 1^@!4333{^@1!4333^@833339!^@ٿ"^@hfff"hfff&^@@#^@8333#^@4#^@8333K#X^@83333O#d^@̌J#< ^@Y#hfff#^@hfff&p#|(^@hfff#4333,^@hffff#42^@#I5^@83333$x3^@̌7$̬,^@i$(^@8333t$4333#^@hfffx$4333^@̌$@^@hfff$Y^@ |$D ^@8333sf$4333S^@hfff>$hfff]@Y$]@#]@#x]@ #]@hffff#]@̊#4]@hfff&#x]@8333i#hfff]@̌V#]@8333=#̌]@L%#\]@hfff #]@8333"4333]@hffff"]@"]@"!]@Y"X]@8333s"4333]@"4333s]@"4333K]@Y"4333S]@hfff"^@ٿ"4333]@8333 hfff]@hfff ]@ ]@hfff& hffff]@ hfffV]@8333s )]@8333 4333]@ hfffF]@8333s ]@8333s ]@̌ Բ]@ ]@ hfffF]@hffff 8]@hfff hfff]@ ]@83333!]@3!x]@hfffA!L]@V!4333]@k! ]@v!hffff]@!,]@{!hfff]@m!й]@g!hfff]@l!̼]@̌x!hffff]@!4333[]@hfff!̌]@hfff&!I]@8333!4333]@83333!hfff]@L!]@8333!]@!4333S]@!hfffv]@8333s!]@Lh!@]@hffffY!]@!(]@Y!4333k]@@!hfff]@!hfffw]@hfff!r]@!4333n]@!`]@"4333X]@Y"4333T]@@"hfffP]@hffff "tM]@8333s"QJ]@8333s#"C]@83332"4333S=]@'"7]@hfff"hfffv2]@@"hfff&1]@83333!i1]@hfff!̤3]@83333!hfff2]@LT!H3]@hfff&2!q5]@!8]@@!=]@!4333D]@̌ ̌J]@ PN]@ 4333V]@hffff []@8333 4333Kd]@L 4333g]@L ,i]@83333!k]@hffff !4333m]@L*!hfffs]@l!)y]@hfffh! ~]@t!]@8333L!hfff.]@hfffM!]@ /!4333#]@!hfffn]@L ]@8333 $]@L ~]@8333 hfff&t]@hfff& q]@َ Ao]@h hfffVp]@̌L w]@hfff3 z]@- ̄]@> ̤]@L 4333]@و 4333]@8333 43338_@?hfff,_@3333k?4333(_@3333?4333%_@?hfff _@?\_@ffff?_@ffffz?4333_@? _@X?|_@?hfff>^@?^@ ?^@8?hfff^@3333S?^@3333?|^@?H^@?̿^@?hfff6^@ffff?^@?hfff^@?4333u^@?An^@3333?f^@?a^@ffff?@[^@3333?@^@D?0:^@?4333,^@ffffx?hfff%^@?p^@ffffT?hfffV^@?hfff^@ ?hfffN ^@3333/?hfff&^@Q?4333^@Y?hfffN^@hfff^@ɿhfff^@ӿ^@gfffۿhfff^@3333<^@hffff^@D^@ffff쿜9^@ !^@𿜙&^@"hfff*^@.^@3^@̜:^@ (B^@@3333I^@ffffn4333M^@fffffQ^@4333[^@?hfffVM^@33333?R^@3333?V^@?Y^@?)\^@3333n?A^^@}?`^@?hfff>c^@@ffffF?e^@@ffff?4333w^@j?^@?^@J?(^@̀?4333^@3333?̌^@̜?hfff^@?hfff^@33333?q^@3333?^@ ?A^@3333#?^@̲?0^@ffff?^@6?4333_@3333[?4333K_@3333?("_@?4333$_@@ffff?i&_@@ffffG?43333)_@?/_@?i2_@3333{?7_@@ffff7?̜<_@3333?P?_@@ffff7?G_@?̌J_@@ffffL?hfffN_@@ffff ?0N_@̨?I_@̈?̄G_@?4333A_@3333?=_@@ffffR?43338_@?hfffZ@aZ@@333|Z@̬Z@4333Z@@3333Z@pfff[@hfff[@/4333 [@(I[@[@pffff![@pfff$4333[@![@hfffn"[@&[@@333a+[@)hfff1[@@333;9[@;,A[@pfffDR[@whfffY[@p `[@=e[@^4333t[@4333{[@̩4333K[@L4333[@4333[@Ľ[@pfff4333ۗ[@H[@hfffV[@̖Y[@9[@@3334333#[@G٬[@)[@@3330[@Ll[@pffff9[@4333 [@pfff[@hfff[@@3333[@L̼[@[@̔[@̗0[@ [@4[@Y[@L9hfff\@̒\@̞\@pfff\@@3334333"\@@333%\@3(\@L̄)\@ 0\@pffffhfff2\@743332\@2\@@3335hfff@\@hfffO\@pffff_\@@3333hfffo\@pfffx\@4333c\@Lhfff\@@3333hfff~\@1\@+hfffn\@hfff^\@Y 4333\@̆ h\@hfff& 4333Ø\@8333s \@Y!Ԟ\@hfff&5!\@^!Y\@Yt!\\@ !4333c\@hfff&{!hfff\@hfff&i!hfff\@8333sK!\@8333:!8\@@!hfff.|\@#!4333Sl\@ hfff6P\@̒ hfffH\@ hfff6A\@ t9\@ 4333c1\@ q+\@ %\@ \@ hfff^\@٥ 4333[@83333 4333[@ 4333[@hfffz ![@hffffg ܦ[@L y[@pfffv[@LPhfffR[@4333cL[@hfff&?[@6[@pfffp/[@4333$[@@3333hfff&![@@333[@0y[@-[@!Z@4333{Z@pfffZ@̊4333CZ@LDZ@pfff*[@3333:?4333C[@?hfff[@/?[@?hfff\@3333K?4333;\@?hfff \@3333i?4333 \@@ffff?4333 \@?\@@ffff]@@]@ 3333@@}]@G@x]@ 3333@4333cx]@ 3333|@4333r]@7@43333u]@@hfffVw]@~?4333k{]@@ffff?$]@:? ]@>?0]@̩?]@?]@?]@@ffff? ]@m?]@3333a?y]@?9]@ffff?]@3333?̌]@?]@?4333 ]@@ffff?Xz]@3333?|]@?̌~]@?hfff}]@3333w?4333{]@ffff?v]@d\@l a\@y ,Z\@ W\@ hfffU\@ ,B\@w,>\@@3333 43330\@̓ 4333k&\@@33334 i\@ <\@ffff 4333\@@3333 [@< 4333[@k 4333[@@3333j ̜[@B hffff[@ffff\ [@@3333v ̬[@@3333u[@ffffhfff[@ffffhfffv[@![@h[@̬[@ffffhfff[@@3333xhfff[@̦hfff[@@3333rhfff[@[@c[@[@̑hfff[@D[@[@[@*4333ê[@ ̼[@!)[@ffffxhfffv[@\[@4333c[@4333[@f4333[[@ffffhfff[@hfff.[@̄[@ffff$hfffn}[@hfff}[@[@HP[@@3333i4333;[@ahfff~[@e |[@hfffw[@dr[@ffff.𿜙k[@333374333 ][@XU[@3333|R[@P[@ffffXQ[@l4333S[@応qW[@3333[4333W[@l4333sP[@ffffzhfffFJ[@̬߿hfffVH[@ܿG[@ٿ4333G[@gfffп4333I[@ǿ4333J[@<¿tL[@L4333{P[@`fff?4333O[@̌?N[@dfff?K[@0333?I[@ffffv?D[@ffff.?4333s<[@3333?hfff;[@ ?9[@h?̬:[@ffff4?Y=[@@ffff'?A[@E?E[@3333?4333kH[@?hfff&F[@@ffff!?0D[@@ffff?@[@?̌C[@?4333D[@3333?4333J[@?4333{Q[@I?\T[@3333#?9X[@@ffff?@h[@`ffff8@_@$?4333_@n?4333c_@̠?4333_@?hfffv_@3333?_@@ffff?`@?hfff`@@ffff?$`@@ffff?hfff`@@ffff? `@?hfff`@i?hfff `@G?A`@?4333`@3333)?̐`@q?`@@ffffk?`@@ffff?|`@̳?hffff`@@ffff?4333w`@V?hfff `@3333? `@?4333;`@ffff?4333W`@3333{? `@3333q?4333`@3333?`@C?`@?!`@?`@?`@3333?`@,?`@ffff?4333K`@?I`@3333?hfff `@x?4333`@3333?d`@3333?4333_@33333?)_@ ?_@3333?4333_@?_@h?a_@D?_@Y?̔_@Ͽ`@gfff߿`@i̴ `@3333꿚 `@̐hfff`@3333x`@4|`@X`@_@4333ۿ̜_@Pؿi_@9ӿ4333C_@hfffο0_@Ŀhfff_@hfffv4333_@١?hfff_@2333?4333[_@p?4333_@?p_@?4333_@ffffV?`_@ffff?̬_@?I_@?q_@3333y?_@$?hfffN_@?l_@@ffff=?hfff_@?`_@z?8_@3333'?̴_@%?hfff_@3?hfffn_@?_@3333u?_@L@hfff_@e@hfff*`@@hfff^`@ 333A@`@@_@@ffff!?_@3333?_@S?4333_@@ffff?Y`@33338?hfff`@V?`@@ffffT?``@N?hfff6_@3333?_@̚?_@8?4333_@3333E?_@?4333[_@^?_@$?hfff&8`@@3333?`@@33334333OC`@4333I`@!L`@@3333`@" 4333;`@ 4`@ p1`@ `0`@̠ 43330`@ 0`@@3333x 4333.`@@3333 hfff*`@E &`@@3333$ q#`@@3333 `@̛ 4333w`@o `@ffff, hfff`@ ̜`@ `@@3333 `@ hfff `@ffffg `@@3333, hfffr`@w `@̗ `@̄ hfffj `@T `@ t`@ `@_ 9`@ffffB ̠`@y `@ h`@@3333m hfff`@ffff _@ _@ffff _@ffff a_@- 4333c_@@3333 4333k_@@3333B 0_@ ̠`@zhfffZ`@ffff<`@̼L`@ffff$`@4333`@̠!`@@3333`"`@@3333)̸#`@̔%`@whfff(`@+`@ffff̬-`@ffffShfff~/`@@3333I`1`@R433373`@shfff&8`@@3333_@_@T hfff_@ffff _@ffff8 4333_@| hfffv_@ffff ̌_@ _@ _@ffff hfff_@- q_@^ 8_@̬_@ffffC4333Ӳ_@@3333Pa_@ffff_@̖_@ffff,P_@ffff 4333_@ffff i_@ 4333c_@. hfff_@@3333^ ,_@ _@@3333] 4_@ffff hfff_@hfff_@ffff/ _@ffffhfff_@4333_@_@hfff;_@̌!:_@hfff&";_@Y"I>_@hfff "lF_@ "hfffG_@hfff"I_@"I_@8333>"hfffnF_@83333a">_@c"4333s=_@8333sm"Y=_@hffff"=_@hfff"hfff?_@hfff"hfff&B_@"\D_@#hfff?_@8333s!#4333=_@T#5_@#hfffV-_@ #̄&_@hffff#hfff _@,$\_@L$_@8333V$4333C _@]$hfff&^@8333$4333^@hfff$4333^@$9^@83333$̴^@L$L^@n$|^@hfffU$4333+^@8333A$^@@($\^@$hfff^@#^@#̜^@i#hffff^@:#^@"^@8333"4333S_@hfff"4333[_@83333"_@83333"d_@hfff"̜_@hfff"_@"p_@"4333 _@hfff&"hfffn_@8333" _@hfff&z"q_@8333sa"$_@̌O"hfffV)_@;"4333S-_@hfff"8_@!hfff;_@̌!4333`@hfff`@̠`@pffffD(`@pfffhfff`@`@L3hfffB`@pfffff0`@@333hfff`@@3333hfff`@@3333.hfff`@P(`@pffffY4333g`@v`@pfffVe`@`@hfffv`@̯̜`@\`@pffff@hfff`@4`@@333`@ hfff`@hfff`@U<`@Lhfff`@@3333`@L`@hfff`@pfff:̰`@@3334`@D`@hfff`@̬`@@3333 `@@3333(`@LSl`@i4333`@-`@pfff4333`@ 4333#`@]43333`@d`@pffffBT`@ehffff`@`@U`@l`@pfff4333`@`@hfff:`@`@@3334333`@4333`@pffff``@hfff~`@4333+`@@333CH`@-`@pfff!Qa@ 4333{Ia@8333s 4333s?a@̌ hfff;a@hffff 6a@ 4a@8333 5a@@ :a@=@a@hfffBa@ChfffEa@@3333tIa@4333gQa@@333hfffXa@̏Ya@\a@pfff ^a@Zhfff_a@4333\a@Lhfff&Ya@@ 4333Sa@̌e !Qa@ hfff&a@hfff&a@hfff&a@r4333'a@ffffm(a@ (a@ )a@ffffN hfff*a@ 4333+a@4333+a@@333,a@pfff,a@-a@@3333hfff.a@pffffX4333/a@(0a@0a@pfff0a@1a@Lihfff2a@943333a@ 43333a@pffffb5a@a@@3333ra@la@@3333\4a@4a@LJ5a@hfff6a@@33343337a@pfff8a@8a@- 8a@8333 9a@ hfff:a@e!4333;a@8333!4333;a@ 6"Sa@4Sa@Ua@̋hfff[a@o4333Ya@pffff)@Wa@@3334333WVa@@333̌Ta@pfff=̰Pa@@333 Na@_Ka@pffffy4333{Ia@4333 Ja@̌Ka@pfff_ Ia@@333Z4333cFa@pffff:4333Ga@hfffJa@pfffHa@@333TEa@Da@@333Ba@@3333Ba@@3333Ba@4333kBa@pfff.hfffAa@pffff̄?a@pfff4333=a@{`Y@3333[?4333Y@?4Y@W?Y@3333C?Y@?4333 Y@ffff?hY@ffffZ@33334333Z@@tZ@gfffݿYZ@ؿhffffZ@TؿhfffZ@|ؿDZ@ٿYZ@4333kտ4333#Y@DֿhfffY@ؿhfffY@4333ֿY@ ӿ!Y@ ͿY@4333ͿTY@̴ѿY@gfffVԿ4333#Y@Dֿtm[@򿜙`[@ffff̬][@phffff[[@󿜙\[@̴hfffv^[@hfffVg[@Tl[@4333o[@@3333̬p[@̮ p[@Rtm[@ v\@pfffkhffft\@zi\@pffffrb\@ ^\@@3334333L\@J\@LI\@ H\@hfffB\@pfff0\@t.\@J433331\@Lhfff7\@PD\@a~\@~hfff\@@3333P\@x\@@33332 v\@pfffk`@@33334333[`@&4333`@hfff`@hfff~`@ffffRt`@4333`@3333Sᅳ`@@3333}𿚙`@`@@3333hfff_@4333߿_@_@hfff_@|ڿ_@ѿ4333#_@gfff^п_@43333ҿ1_@dԿ_@gfffٿhfff_@4333߿I_@iԿ̬_@ݿ_@ffffhfff&_@濜y_@8_@,@_@PT_@_@ hfff_@3333G쿜_@$_@ffff_@3333_@̜_@ffff _@ffffhfff_@33334333[_@043333_@ffff4333_@tݿhfff_@ٿhfff_@gfff~տ_@9տ!_@ڿx_@տ_@ӿI_@iԿ`@@333hfff `@@333hfff~`@$`@H`@L|4333`@>hfffn`@E`@dԣ`@M4333`@`@@333ԙ`@@3333g`@hfff`@hfffΕ`@hfffZ`@l͕`@hfff*`@mT`@o`@pfff`@̼`@'ԙ`@@3333g`@e 4333`@ffff 4333#`@ ̔`@ hfff`@̔ 4333`@j `@} `@ffff _@+_@ 43333_@@3333 \_@ffffo ̄`@ `@@3333 u`@@3333 `@ `@ffff P `@ `@ `@e 4333C_@L"@hfff_@`fff @̄_@@hfff_@0333H@I_@@_@0333@4333_@Y!@hfff6_@0333s`@_@̩@x_@ 1@_@&@hfff^_@Y@_@0333s}@4333_@*@@_@L@4333C_@L"@hfffj_@} @hfffh_@L> @̼`_@`ffff @ a_@e @4333`_@`fff @]_@`fff @4333#]_@ 3333y @^_@ 333 @b_@] @4333{e_@ @0i_@`fff @hfffj_@} @4333[`@83333 hfffX`@hfff& 4333Z`@hfff ̤``@. b`@? ̤e`@8333B hffffa`@̌l 4333]`@} 4333[`@83333 :`@8`@ 6`@ 2`@pffff(3`@LS|3`@@33364`@pfff-:`@pffffGhfff:`@@333:`@4333_@2 hfff_@83333G )`@ E `@hffffW `@ _@hffffa Q_@= 4333_@2 hfffNK`@ffff K`@@3333M`@L`@<-L`@@3333qhfffL`@4333gM`@ffffK`@J`@I`@@3333G`@aED`@̂B`@:hfff^<`@ffff$8`@O43337`@?`@ffff$hfffbC`@4333cF`@@3333,J`@ffffhfffNK`@ffff Y@@3333LY@̬Y@@3333qhfffY@LJ4333ӉY@%4333Y@'4333˗Y@@3333w4333Y@Y@@33334Y@v Y@̠ hfff&Y@ffff LY@@3333E @Y@4333Y@t4333 Y@y Y@̴̏ Y@HY@DY@Y@OhfffY@ffffY@ffff! 4Y@v  Y@hfff~Y@@3333Y@̎4333{X@(X@1hfffX@ X@9X@44333Y@ Y@p Y@X@4333CX@@3333X@AX@ffffdX@JX@ffffX@hhfffX@4X@"hfffX@́hfffX@l4X@ffffFX@dX@̔X@u⿜ѓX@῜X@ݿ̴X@gfffFؿ)X@gfffӿhfffVX@̿4333X@IX@}?hfffX@@333X@hfffvſ4333ӢX@|пIX@LؿdX@̬X@L@X@ 3333@X@@hfffX@o@hX@@W@@hfffNW@ @W@ 333>@W@!@hfffW@@4333kW@@W@T@TW@@W@L@@X@@hfffNX@`ffff@̄ X@`ffffJ@̴X@@4333[X@@hffffX@S@̬X@L@^@~^@pfffw^@@333fhfffs^@Lhffft^@4333v^@4333w^@qw^@Lbyz^@Jhfff}^@pffffMhfff^@@3333^@^@^@hfff^@hfff^@@3333̬^@ffff8^@:4333^@ffff4333^@󿜙Q^@&^@hfff^@f4333^@ffff(^@@3333|^@@3333^@^@1^@@3333;^@̒^@@3333X^@@3333=hfff^@̴^@ffff^@@33334333^@p^@+^@@3333e^@^@4333C^@@3333^@ffff<^@󿜙!^@@3333hfff^@򿜙Qw^@ ڿ z^@ܿhffffx^@43333v^@Y߿4333cp^@i߿1n^@߿̔k^@i^@ffffk^@̤޿o^@ ڿs^@4333ڿQw^@ ڿ!^@10^@4333^@pfff|^@^@hfff^@@3333a4333^@Ľ^@pfff0"^@hfff&#^@!^@1!\@hfff\@\@pffff8\@pfffd\@pfffq4333\@Zhfff\@pfff[4333\@{̌\@4333\@@3333$\@@3333!\@i]@]@pffff74333]@]@@3333,]@ffff p]@@3333 ]@̩ 4333]@ffff Q]@@3333 4333C]@@3333 hfff]@( hfffV]@@3333 4333]@ ]@@3333G ]@ d]@4333]@@3333i]@4333^@̌%hfffƶ^@%^@Y%a^@@% ^@ %hfff^@e%T^@hfffG%^@L %̼^@8333$^@hfff$^@hfff&$̄^@"%l^@>%4333^@8333sM%4333^@e%^@%hfffV^@8333%4333^@̌%X_@8333 4333s_@Y _@Y 4333c _@!4_@8333s!4333_@@ `^@ ,^@L _@hfff& hffff_@8333 !_@Y 4333_@ T_@hfff&h _@Lg `_@j |_@hfff&u X_@8333 0^@ 4333+^@hffff ^@L D^@L ^@8333 I^@!^@83333 !!^@!d^@83333"!hfffF^@̌!4333^@8333&!I^@Y,!hfff^@@!hfff6^@!^@8333!^@ ^@ t^@ hfff6^@8333s hfffF^@hfff ^@ I^@ 4333^@̇ hfff^@@ p^@hfff& ^@a ^@@m Y^@z 0^@ Q^@hfff hfff^@ ^@ hfff^@8333 hfff^@8333 4333^@8333 ^@̌x ^@ Q^@hfff hfff`@2%`@L<4333G`@@3334333`@P`@hfff`@2!Y@?Y@?@Y@?0Y@$?Y@3333?QY@@ffff#?Y@3333)?!Y@?Y@?`Y@?4333Y@3333?\Y@? Y@?Y@3333?Y@?QZ@?P Z@?HZ@?xZ@\?hfffZ@?4333Z@33335? Z@?Z@(?QZ@?,Z@y?hfff,Z@?)Z@ ?'Z@0333c?&Z@`?4333Z@̴?hfff"Z@̔?4333;*Z@0333c?,Z@y?AZ@A @(Z@ 333@4333Z@L @܌Z@ @QZ@ 3333 @4333[Z@ @AZ@A @pZ@@mZ@@1mZ@`ffff@hfffNmZ@L@mZ@`fff@LlZ@ 3333@LlZ@@4333nZ@ 333K@pZ@ 333@rZ@ 333@hffftZ@@̌uZ@`fff@sZ@L;@pZ@@8[@L>@5[@@hfffV2[@@hfff~7[@`ffff@8[@`fff@8[@L>@=[@5[@p3[@$8[@@3333<=[@ffff=[@4333KZ@@333324333Z@g1Z@ffff4Z@hfffZ@ffff\Z@ffff4333Z@4333KZ@@333324333Z@ Z@3Z@hfffZ@4333Z@4333Z@ffffvZ@1HZ@x4333Z@ h\@@3334333s\@L43333\@@3333 \@pfffchfff\@LRT\@@3333Ǩ\@Rh\@@3334333 .\@>4333,\@b&\@pfff_%\@pfff6)\@pffff),\@̌.\@4333 .\@>hfff.PZ@̏0LZ@pffff4333#IZ@GZ@@333uhfffNLZ@@333.qNZ@̬PZ@QZ@pfff>hfff.PZ@̏4333cUX@`fff@4333UX@m@hNX@D@hfffFX@ 3333@hfffJX@@hfff.PX@`ffff@hfffRX@L@ UX@ 33330@4333cUX@`fff@,W@`fff?@W@0333"@ W@03331@hfffW@َ@|W@̠@W@L@W@́@lW@`fff^@,W@`fff?@hfff>^@D^@_^@@3333$^@̎4333^@ 4333^@!^@ffff@^@fffft4333s^@ hfff>^@D4333^@@333s@^@pfff^@^@4333#^@>^@@333^@^@hfff^@pfff)4333^@@333sI^@Il^@ffffl^@hfff^@̲$^@ I^@I4333^@ffff4333 ^@b^@hfff~^@ ^@ffff^@\4333^@ffff4333]@hffff{!1]@@!̬]@x!̴]@LK!@]@L,!]@!]@8333 4333]@ ]@L ]@hfff& 4333#]@L ]@ ]@hfff !̌]@Y!4333S]@-!hfff]@hfffA!4333k]@8333W!4333]@hffff{!]@Lz 4333]@hfffz hfffV]@Yf X]@P ]@G A]@@G hfff6]@8333Z ]@hfffd ]@hffffr ]@Lz \@hfff&!hfff>\@!hfff\@Y|!\@Ln!\@Y!hfff\@W!@\@hfff&m! \@hfff&!i]@ @̴o]@0333@x]@@hfffz]@0333\@{]@7@(o]@@h]@`ffff|@i]@ @4333#j]@> @Ti]@`ffff @c]@ 3333 @hffffb]@L @c]@ 333t @h]@} @4333k]@B @4333#j]@> @H_@_@\_@pfff9^@pfff4333s^@Lx_@̛H_@^@4333^@~I^@@3333x4^@Shfff^@1̼^@^@^@1^@y+^@@3334333)^@v(^@@333hfff/^@=2^@@1^@y4333c]@ hfff&b]@hffff 4333c_]@̌ a`]@83333 4333^]@z d_]@hfff] 4333b]@M j]@hfffK j]@hfff` 4333c]@ $]@@3333 ]@ hfff]@P L]@c 4333S]@3 $]@@3333 _@ffffR?_@3333E?hfff_@3333?T_@3333?̼_@?x_@?̤_@ffff?_@ffffR?`@ `@@3333̸`@9`@K4333`@84333`@?h`@j`@D`@hfff`@2`@`@@333D`@@333qܮ`@D`@\`@4333'\`@ffff4333Z`@̜L`@̐ N`@ehfffN`@<4333O`@P`@3333hfffQ`@p꿚9R`@LS`@t꿚UT`@$W`@QZ`@3333 4333Y`@3333{\`@迚 T`@3333hfff6R`@N`@4333#߿P`@ܿ R`@8ܿhfffS`@ڿS`@̴ڿU`@ۿU`@gfff޿ T`@3333̐1`@ǿhfff.0`@Lȿ/`@4333+`@)`@@?X1`@4333̐1`@ǿ_@xhfff_@hfff_@z?d_@?_@ٿ?4333_@@?4333_@?_@x_@?4333_@33331?_@P?9_@̚?|_@3333?0_@?4333S_@ffffx?_@?_@?9_@_@ffff_@33334333_@Y远a_@hfff_@3333H_@D远9_@hfff`@` 4333 `@ 4333`@ `@̳ 4333`@ffff `@ `@ffff T`@@3333" 1`@@33332 hfff`@` `@ `@ffff ̴ `@R 4333s`@@3333 )`@T `@ _@L@1_@@Q_@`ffffm@̨_@0333*@_@0333s@hfffV_@W@ _@L@̄_@%@y_@ 3333@,_@`ffffE@4333ñ_@`fff@ٱ_@̾@|_@@ٶ_@@hfff_@ 3333L@̄_@%@4333Z_@6@lY_@L @4333 W_@@4333Y_@`ffffq@4333[_@`ffffE@4333\_@@Y_@@4333Z_@6@l`@pfffhfff`@pffff̨}`@pffffM|`@Tz`@x`@pffffhfffx`@w4333}`@kl`@pfffq`@@333`@4333`@`@̉y`@@3333Uhfff`@pffffF`@L]4333`@t4333W`@Lq`@@333_@~̼_@_@@3333J_@ i_@hfffV_@pffffP_@@3333c_@~4333^@8333$^@̬$hfff^@@$L^@W$\^@hfffG$̜^@Z$4333^@Lc$^@Lt$4333^@8333$4333x^@@.%Qu^@L4%yn^@8333s%%m^@%hfffr^@%|w^@8333$|^@8333$^@$hfff~^@̌%4333x^@@.%9`@q`@4333s`@U`@fhfffB`@pffffLX`@LK9`@̔`@ `@@3334`@!`@pfff4333;`@4333S`@@3334333`@L~<`@@333̔`@9_@~4333_@)`_@ffff!d_@ hfff_@ffff9_@~_@ffff hfffF_@ _@ hfff6_@@3333N 4333_@ |_@ _@ffff ̌^@hfff&!4333^@@5!Ѹ^@8333,!4333ӹ^@8333!4333^@ ̬^@̌ ^@83333 4333^@8333 ^@ ^@Y ̌^@hfff&!/ Q@`fff@UX@yA@LV]dmx Q@y7@Q@7@Q@7@hffffQ@l7@hfffFQ@̜7@4333%Q@4333s7@X.Q@pfff7@.Q@D8@hfffV/Q@J8@03330Q@pfffN8@hfff1Q@PP8@433333Q@ O8@43335Q@dfffC8@4333C7Q@9D8@hfff9Q@J8@4333?Q@E8@LCQ@LI8@hfffGQ@dfffD8@0333 OQ@̬D8@a\Q@ F8@cQ@E8@hfffhQ@dfff98@hfffmQ@0,8@sQ@L*8@4333{Q@+8@YQ@ 18@0333+Q@Pfff=8@IQ@I8@Q@dfff6[8@PQ@4333i8@hfffQ@dfffk8@)Q@4333b8@4333Q@4333T8@4333Q@pG8@4Q@?8@حQ@<8@4333Q@@333>8@hfffQ@C8@Q@X8@hffffQ@4333\8@hfffQ@l\8@Q@lf8@hfffQ@0333n8@hffffQ@q8@IQ@dfff|8@̬Q@8@Q@dffff8@|Q@dffff8@hfff&Q@dffff8@Q@8@4333SQ@dfff8@4333ۼQ@@8@,Q@ 9@4333;Q@433349@dfffQ@T9@4333Q@P333Cl9@Q@433339@Q@̼9@YQ@ 9@4333sQ@9@`Q@p9@̴Q@l9@ДQ@̌9@Q@9@iQ@9@Q@4333s9@Q@l:@|Q@6:@̌Q@X:@ Q@x:@4333sQ@ffff:@hfffVQ@L:@̃Q@):@TzQ@ :@oQ@ffff:@pfQ@:@q`Q@ :@^Q@`:@^Q@:@hfff_Q@2333C:@hfff^bQ@y;@YdQ@P333,;@gQ@2333c:;@4333SjQ@ffffC;@4333cnQ@ P;@\yQ@@y;@0Q@ٱ;@@Q@Y;@iQ@ffff;@4333Q@2333#;@aQ@L;@hfff֙Q@i<@DQ@<@hfffnQ@;@4333CQ@;@4333Q@;@4333CQ@;@1Q@;@Q@;@hfffQ@ffff;@4333Q@ffff;@Q@@333;@Q@;@hfffQ@2333C;@4333Q@fffff;@4333Q@ffff& <@̬Q@2333c-<@9R@X<@x R@k<@R@ِ<@R@<@R@|<@ (R@i<@9R@\=@@sR@pfff>@̼xR@y)>@̼{R@8>@,{R@H>@hfff~xR@ffff&Z>@yR@d>@hfffyR@@333so>@4333R@ >@̍R@>@R@>@XR@ffff>@R@̬>@R@?@ R@?@R@2333?@4333R@ffff!?@!R@2333/?@R@@@@YR@P@@R@@@9R@@@R@8333+@@ R@I@@R@@@hffffR@@@hfffvR@̼@@AR@3333@@~R@@333{@@hfff~~R@3333S@@R@@333@@R@Y@@̍R@3333{@@hfffR@@@hfffƏR@ffff@@`R@pA@4R@yA@4333|R@hA@{R@3333A@yR@ A@yR@3333 A@ |R@A@~R@|A@4333;~R@IA@,{R@$A@hfffsR@̤)A@rR@i0A@sR@6A@gvR@hfff>A@̄xR@CA@̄}R@̤SA@4333R@ WA@R@pfffF\A@9R@aA@hfffޟR@3333]A@hfffR@pfff[A@4333{R@VA@4333R@3333RA@̔R@3333QA@R@3333QA@hfffR@LA@hfffR@3333DA@R@Y@A@4333cR@d@A@,R@ffffGA@ R@hNA@S@UA@ S@xUA@4333;S@`A@4333 S@^A@4333 &S@0^A@,S@dA@/S@|lA@4333{0S@\pA@43332S@9sA@9S@(xA@hfff@S@~A@hfffAS@3333A@CS@A@JS@A@RS@ffff&A@[S@@333A@̔dS@3333{A@4333lS@̼A@)sS@yA@\sS@3333A@hfffsS@A@vS@3333A@hfffFyS@yA@|S@pfff^A@4333S@A@4333S@iA@ S@ffffA@hfffS@IA@ȀS@!A@لS@DA@$S@hfff&yA@S@bA@ S@3333SA@S@ffffMA@S@3333kGA@hfffS@3333SBA@hfffְS@9A@YS@ffff1A@hfffS@ -A@hfffS@̼&A@hfffS@ !A@hfffS@ffff6A@S@0A@1S@9 A@ԮS@A@S@ffffA@S@̜@@)S@ffff@@hfffS@ffff>@@QS@ffff@@\S@ffff.@@4333S@@@4333S@8333[@@hfffS@ffffN@@AS@ @@43333S@hfff@@hfffS@@@S@ffff֍@@̔S@@@4333S@ffff@@PS@0@@S@y@@iS@3333n@@(S@xfffg@@hfffS@ a@@S@ffffY@@4333S@1H@@S@@@@ S@3333#@@@S@̤?@@hfff&S@ffff<@@IS@1@@ٿS@̼.@@кS@-@@S@33334@@\S@;@@9S@?@@hfff&S@yG@@4333۬S@3333kL@@4333kS@3333J@@S@I@@hffffS@3333cG@@S@E@@S@0333B@@S@̼;@@hfff>S@2@@4333#S@q&@@S@<@@̼S@ffff@@`S@3333@@pS@?@S@@0S@ffff>@4333S@>@4333S@>@S@@333>@S@>@S@ >@4333+S@ffff>@hfff6T@,>@ T@23333>@p T@\>@A T@ >@4333 T@ffff>@< T@2333>@4333T@2333>@hfff6T@l>@"T@v>@&T@r>@+T@23333j>@4333/T@2333C\>@7T@@333cJ>@?T@2333<>@@T@*>@=T@ffff.>@dfff:T@@333,>@H6T@ffff#>@y4T@̌>@+T@̌=@9'T@2333=@4333##T@Y=@T@2333=@HT@2333s=@PT@`l=@aT@iQ=@T@@3331=@ T@2333=@YT@2333=@iT@P333<@hfffNT@<@hfffT@pfff<@4333 T@̬<@T@,<@T@<@T@̬<@T@ٚ<@4333T@2333â<@$!T@I<@%T@L<@hfff*T@2333<@y.T@̍<@ 0T@)<@Y9T@2333w<@AT@h<@JT@2333U<@43333MT@ffffJ<@4333KOT@=<@ST@ffff&-<@4333_T@<@̬hT@;@hfffvpT@;@vT@;@hffffyT@;@dfff~|T@Pfff6;@hfff6T@;@hfff^T@̌;@)T@l;@iT@̬;@4333T@;@PT@2333;@YT@fffff;@hfff~T@;@T@܄;@4333T@w;@T@q;@T@f;@4333T@^;@̤T@ffffi;@4333T@q;@hfffT@ w;@hfffNT@2333t;@hfffT@\e;@4333 T@`;@4333kT@2333co;@dfffU@/v;@0333U@};@̴U@`fffm;@hfffU@P333#Y;@ 'U@ffffvL;@)U@`fff?;@)U@2333#4;@)U@y;@+U@ ;@4333;U@I:@IAU@ffff:@hfffEU@:@hfffHU@i:@4333IU@̼:@$KU@0333:@hfffFLU@<:@`OU@ffff:@RU@2333:@hfff6]U@ffff:@adU@ :@iU@9:@4333lU@:@hfffFmU@p:@0oU@ffffƣ:@rU@:@4333vU@ffff:@xU@<:@HU@:@hfffvU@ffff:@hfffnU@ :@hfffU@i:@4333ˢU@~:@4333U@`o:@̰U@@333#q:@ U@0:@lU@ffff:@0333U@pfffn:@̬U@d:@dU@<\:@xU@ffffFl:@hfffU@̬g:@U@,f:@U@ffffm:@YU@o:@U@2333a:@V@ e:@4333V@Pfffn:@4333#V@ :@hfffV V@̌:@ V@̬:@4333V@:@U@ ;@U@I";@4333V@̬h;@XV@@;@V@ffffv;@h V@̿;@ V@ffffv;@hfff V@2333;@dfffV@;@TV@;@V@;@ V@;@̜V@ffff;@4333CV@<@V@2333<@hfff"V@<@$V@pfff<@'V@2333<@hffff0V@) <@o3V@pfff<@5V@2333C;@4333S6V@`;@5V@2333s;@/V@;@43330V@ n;@G5V@P333\;@ 9V@P;@l8V@ffff&L;@0V@ffff7;@H/V@2333,;@1V@\";@4V@Y;@0333s5V@;@43336V@2333#:@4333:V@ffff:@hfffBV@2333s:@|IV@ :@AUV@@:@hfffXV@:@`^V@̬:@4333bV@Pfff:@4333eV@i:@fV@ :@4333fV@:@ gV@,:@mV@2333ö:@4333pV@:@\|V@2333S:@hfffއV@,:@0V@ffff:@4333V@:@4333#V@:@hfffV@:@ԣV@:@4333V@̼:@hfffVV@̌:@ĶV@:@V@̬:@hfffVV@9:@PV@:@,V@:@ V@̬:@0333V@P:@W@ffff-=@0333W@$=@W@0&=@4333CW@2333=@W@ =@W@0 =@W@2333 =@W@ffff =@7W@0=@W@2333#=@hfffW@P333&=@4333W@23334=@hfffvW@ffffVP=@̤W@2333d=@4333CX@yr=@X@2333l=@9X@2333a=@hfffv X@E=@ X@>=@̔X@B=@hfffX@ 333?=@hfffX@ffff5=@PX@ffffF)=@4333 X@ =@X@2333=@ X@ffff<@hfffX@0<@a X@2333<@03333X@fff=@4333X@ =@X@P333=@X@ffff<@03333#X@ `<@,%X@<@QX@ffffF<@4333X@<@X@0<@X@2333w<@X@̜m<@0333X@|i<@xX@2333b<@4333sX@ffff^<@hfffX@0^<@`X@g<@&X@̼u<@)X@0333#s<@hfff1X@ffff]<@P5X@ffff\<@hfff>X@2333sV<@4333DX@2333s^<@IIX@ W<@dfffRX@<<@4333TX@7<@4333SX@̼'<@`SX@0333<@̴UX@fff<@UX@y;@4333sUX@;@SX@ffff6;@xNX@;@JX@<;@dfff.CX@;@hfff=X@@333ò;@̔9X@2333Ӥ;@hfff8X@23333;@̌8X@̃;@9X@p;@0333FX@ );@FX@̌;@pBX@ ;@=X@ ";@hfffV8X@ffff-;@3X@0333K;@4333.X@T;@4333*X@V;@̌X@2333CG;@dfff6 X@0333B;@hfffX@23337;@4333#W@ ;@W@ ;@hfffW@;@AW@ P:@W@̌:@hfffW@:@W@23333:@9@dW@979@AW@pfff19@hffffW@4333#*9@7W@y#9@ W@ 9@IW@y 9@4333sW@dfffV8@aW@i8@W@<8@W@8@$W@`fffFy8@W@dffffR8@W@8@hfffW@7@4333+W@`7@ɄW@@7@W@dfff&7@vW@43337@`pW@dfff7@̼kW@̬8@hW@`8@dW@o7@_W@ 7@\W@pfff7@VW@8@TW@p8@0333SW@8@WW@07@hfffZW@̜7@hfffZW@,7@4333 YW@4333V7@lWW@!7@\VW@7@hfffSW@dfff7@9PW@dfff7@ MW@y 7@JW@433337@IW@P6@hffffJW@p6@PGW@4333C6@ EW@ܷ6@̤EW@6@FW@6@hfff^JW@pfff6\6@dJW@J6@̬IW@ ;6@hfffGW@dfff46@̄DW@̜56@BW@/6@hAW@L%6@4333=W@dfff6@4:W@)5@̬6W@6@hfff^1W@43336@$.W@dfff!6@,W@dfff!6@hfff.+W@4333#6@)W@ 6@X(W@dfff6@0333$W@0333c5@4333#W@L 6@ "W@ i6@̜ W@43336@4333sW@dfffv6@W@43336@̌W@4333c6@)W@43336@$W@43336@hfffW@7@\W@ >7@4333cW@dfffR7@̄W@4333~7@W@7@ W@7@ W@̸7@!W@43337@W@@3337@V@fff&7@hfff~V@̜7@|V@dfff&7@hfffV@433337@4333V@dfffx7@V@l\7@DV@̌I7@V@dfff57@hfffV@)7@V@@333 7@yV@<7@hfffV@6@lV@dfff6@V@7@4333+V@)$7@4333V@,37@V@67@V@27@yV@dffff!7@V@dfff7@V@7@V@dfff7@,V@7@hfff>V@dfff_7@V@7@DV@ 7@QV@L7@V@43337@V@8@iV@|8@hfff~V@8@!V@ 8@V@<8@V@I8@V@ '8@V@08@V@48@pV@58@(V@,8@ V@28@V@̼B8@hfffV@dfffVS8@V@4333S[8@W@4333^8@4333W@pfff_8@qW@b8@hfffW@dfffvh8@̄W@4333s~8@̬ W@̌8@W@`8@W@fffF8@̜W@8@W@@333#8@4333W@I8@\W@0333s8@hffffW@dfffV8@W@ @8@W@43338@hfffW@9@ W@dffff9@hfff.W@4333c+9@V@ )9@4333V@4333c$9@4333cV@&9@0333V@ -9@4333sV@,9@4333V@P333(9@V@4333#B9@qwV@ K9@TuV@4333J9@tV@,N9@AsV@ V9@hfffrV@Pfff6`9@4333tV@dffff9@,sV@ 9@4333tV@9@hfffnmV@`fff+:@jV@̼6:@hfffgV@ffff67:@|eV@/:@dV@!:@eV@:@1cV@Y:@]V@9@WV@:@4333RV@ :@hfffKV@ :@hfffFV@fff3:@hfffFV@N:@hfffFDV@|`:@1AV@`fffi:@>V@Pffffk:@V@@I:@4333>V@9@:@4:@`9V@B:@hfff4V@@:@03330V@`fffG:@8.V@ffff&H:@4333+V@̬J:@+V@\Z:@'V@@n:@4333+!V@̌:@4333V@P:@̬V@i:@4333#V@9:@hfff~V@{:@V@pfffx:@0333V@`fffo:@V@f:@0V@ffff^:@1V@O:@`V@A:@ V@Pfff-:@dfff V@P:@AV@:@4333;V@43339@iV@@333c9@4333V@4333S9@p V@9@0V@09@<V@̼9@4333V@ 9@( V@y9@4333%V@~9@91V@}9@2V@t9@4V@0333]9@̴6V@4333cU9@lV@̂6@43333CV@LF6@4333CV@̬/6@4333KCV@6@AV@5@T@fffF/@̼:T@@333/@X7T@/@4T@fff&/@ 2T@`333/@L-T@`333/@a)T@ @/@T@`fff/@T@`fffk/@xT@ 333.@8333kT@@fff%.@PT@`333-@pfff T@'-@p T@fff,@4333 T@fff,@T@,@hfff&T@fffl,@1 T@,,@\T@ffff+@T@fff+@0333T@fff&_+@lfffT@Y*@T@`fff +@T@@fff&6+@ T@333sm+@T@ffff6+@PT@`333+@̔T@*@T@ *@T@ 333sa)@( T@l(@hffffT@`333s(@S@̌x(@S@ @'@pfff^S@`ffffa'@4333CS@̌&'@hfffS@`333&@hfffS@ &@\S@@fff&@8333#S@@ffff&@tS@fff&@PS@d&@iS@fff%@̤S@fff&$@qS@`333ӛ$@lfffS@@333s$@4333S@$@pfffS@fffƨ$@hfffS@fff$@!S@l$@4333;S@Y$@S@@fff$@0333ÿS@]#@(S@̬!#@8333ӺS@"@S@"@dfffFS@̬"@S@,"@S@"@pfffS@"@TS@b"@S@@333"@S@@"@S@`fff5"@S@!@QS@ !@̴S@fffS!@hfffS@!@كS@@fff @LqS@`3333a @̔eS@@B @ aS@( @4333KSS@ffffJ @8DS@ @=S@@fff @'S@@333!@4333k#S@9!@S@y."@1S@YR"@8333S@`fff`"@S@`ffffj"@S@@y"@pfffS@y"@pfffS@YZ#@8333S@̬#@8S@#@S@#@8333S@,j#@ S@l#@S@y #@\S@̌#@,S@ #@<333S@@3333 $@AS@l $@̄ S@,$@T S@S$@ S@f$@S@l$@pfff&S@333$@<333 R@333s%@hfffR@y&@<333SR@9&@YR@`333&@R@@h'@ R@ٟ'@8333#R@'@̴R@ 333 (@hfffR@@333s(@4333R@ !)@R@l)@<333cR@fff&)@PR@'*@8333R@̌+@R@@*+@R@333U+@R@fff+@R@,@dfffޝR@`333sV,@8333R@n,@4333kR@,@hfffvR@L,@qR@&-@R@̌L-@lfffFR@ 333j-@lfffR@-@R@333-@|R@fffF&.@xR@fff.@@sR@@.@̤{R@@.@dfffvR@fff.@hffftR@ /@dqR@`ffff%/@LuR@Q/@hfffnR@YP/@<333kR@333j/@fR@/@w^R@0333 0@ ]R@&0@4333UR@u0@hfffNOR@@33321@IR@fff1@IR@`fff61@CR@ 1@̜?R@P3332@pfff6>R@_B2@\R@\2@4333[@R@ffff3@pfff6>R@@'3@̤9R@`fff3@4333k5R@2@d3R@L3@`3R@83@2R@@3@3R@pfffL3@hfff.?R@fffG3@l2R@\3@0R@pfffi3@i0R@`fffVs3@)3R@P3333@.R@ 3@0333,R@P3333@4333C+R@fffF3@̼*R@3@`-R@4@d8R@,4@433339R@94@@8R@4@43335R@fff4@4R@`ffff5@lfff4R@5@0R@!5@P,R@y-5@'R@9_5@+R@̌o5@pfff/R@`fffx5@lfff*R@`ffft5@@'R@9v5@-R@ 5@3R@03335@pAR@5@03333GR@5@>R@pffff5@hfff5R@5@"R@0333S5@8333%R@5@8)R@5@,R@5@̄'R@033335@l!R@5@d#R@@333(6@0(R@36@\-R@ 56@3R@;6@,R@|C6@%R@03333G6@pfff.R@P333?6@IR@,E6@<333 R@ E6@hfffR@@333>6@̜R@p06@R@6@4333R@P3336@Y R@5@8333 R@@3335@pfffR@5@aR@03335@hfffR@i5@ R@95@hfffv R@l5@lR@fffF5@AR@5@pfffR@\95@R@'5@̌Q@pfffv4@_Q@4@8333Q@fff&4@LQ@4@ Q@̌4@8333 Q@`fff4@hfff&Q@<5@<3333Q@pfff-5@pfffoQ@pfffv5@bQ@pfff5@8333XQ@5@DLQ@@3335@@Q@ `26@<333>Q@PJ6@>Q@b6@lfffNCQ@P333o6@hHQ@j6@hfffnLQ@ V6@IOQ@L6@8333QQ@fffI6@hfff&cQ@̌h6@pfffiQ@Lg6@nQ@fffw6@<333ktQ@pfffs6@`Q@pfff66@<333cQ@ 3336@XQ@6@Q@fff6@0Q@`ffff6@ܠQ@ 3337@Q@`fffF 7@PQ@7@ЛQ@̼7@\Q@fff7@̌Q@fff66@Q@ 3336@8333Q@̌6@DQ@fff66@Q@p6@4333cvQ@@6@lfffVoQ@0333s6@jQ@P333S6@OQ@96@8333K4Q@ 7@)Q@ 07@lfff!Q@@3333]7@Q@L7@0333 Q@`fff&7@<333#(Q@7@hfff1Q@0333#7@)Q@7@Q@|7@1Q@7@Q@7@ Q@P333Ә7@I Q@7@ Q@y7@hfffxW@S@4333 uW@`fff@dmW@0333@jW@0333s@jW@@kW@@4333tW@L@vW@@hfff~{W@@hfffxW@S@4333nW@ m@hW@`fff& @9fW@`ffffF@PgW@0333n@hfffiW@ @QlW@0333s@4333nW@ m@IW@ @4333JW@0333l @`GW@o @DW@`fffƌ @hfffDW@ @4FW@ @IW@ @4333S\W@`fff@\WW@@4333UW@`ffff@SW@`fff&@hUW@̌ @XW@, @[W@`fff&@\W@0333@4333S\W@`fff@\bW@ @\_W@0333 @4333^W@`fff @1^W@ @^W@03333% @̄]W@7 @hfff6]W@X @hfff_W@`fffs @hfffbW@0333sm @hfff`W@Q @\bW@ @hffff2W@E"@hfff/W@ C"@-W@`fffT"@hfff-W@`fffh"@D/W@v"@hfff0W@|"@I2W@`fff&{"@43333W@`fffX"@hffff2W@E"@hfff. W@%@@W@ %@hfffW@`fffF%@4333#W@M%@̔W@0333%@W@`fffF%@W@`fff&%@ W@%@t#W@%@$W@0333h%@hfff. W@%@\,W@`fff&&@@)W@&@ &W@&@(W@&@(W@̬'@),W@`fffF&@4333+W@̌&@\,W@`fff&&@A.W@y'@,W@l'@hfff*W@0333'@hfff$W@o'@#W@'@4333+"W@,'@A$W@l'@&W@`fff&'@p(W@(@)W@0333s9(@4333K+W@b(@hfffv,W@m(@4333;1W@`n(@4333s2W@s(@1W@`fff(@4333.W@(@4333.W@0333(@ .W@ )@.W@03333;)@hfff0W@0333V)@\/W@,)@433330W@L)@hfff3W@)@,5W@Y*@hfff3W@`fffF*@ 7W@ v*@hfff6W@Y*@,;W@*@AW@0333s+@CW@hfffF+@DDW@y*@DW@hfff&*@hfffAW@ *@DW@0333*@4333;DW@0333sq*@BW@LO*@L@W@-*@4333W@@'@$=W@@(@4333?W@`fffF(@AW@(@-W@0333Ӻ)@4333+W@0333)@+W@`fff)@q,W@)@4333{-W@0333S)@hfff.W@`fff)@-W@0333Ӻ)@1R@̬g&@y1R@`ffffd&@p1R@0333m&@ 2R@0333|&@43332R@`fff&@2R@Y&@hfff2R@̬{&@l2R@̌n&@1R@̬g&@PDR@`fffƉ @iCR@l @|BR@ @4333AR@́ @AR@`fff& @4333AR@0333 @hfff~BR@ @4333CR@0333 @DR@ٜ @hfffER@ @YER@@ @4333ER@ @PDR@`fffƉ @@`fffy8ffffO@+3333P@0333/P@`.3333cP@Y{.P@`fff&S.3333P@-P@0333S-iP@\-ffffP@03331-3333kP@03330-3333P@@g-P@0333-ffff6P@ -1P@Y.ffffbP@<.ffff P@;.ffffP@`fffF.P@-lP@`fff-ȃP@{-@P@ye-3333KP@`fffFY-ffffZP@`fffV-ffffn}P@``-hyP@L-\uP@-ffffqP@y-pP@ك-\pP@9,ffffrP@,drP@,MqP@,3333GoP@`fff,ffffrmP@`fff,ffffkP@ , jP@`,ffffdP@`fffƚ,)hP@yU,3333iP@0333+mgP@0333s+eP@ +bP@`fffi+\P@`fffU+̈YP@j+lXP@`fff+WP@ +̴VP@0333+TP@r+3333RP@0333N+3333RP@@H+QP@0333sG+ffffzPP@@L+ffff*OP@W+3333CNP@03333j+MP@+ffffRLP@`)+3333'IP@+ffffGP@+@FP@̬#+\DP@2+LBP@M+AP@0333+@P@@+3333?P@٧+P=P@+3333:P@0333+-7P@@+3333'2P@,3333{/P@03333E,3333-P@ ,\.P@,,/P@`fff&,3333[+P@`fffF,3333(P@̌,t&P@,Q%P@y,t"P@`ffff,P@-ffffP@`fffA-3333P@@-3333OP@0333-uP@ .P@.P@l.ffffP@0333s/ffffN P@y0ffffP@l<0aP@0333w03333KO@0O@\0ffffO@03333O@Y1pO@)1O@033313333CO@1XO@033331tO@i13333SO@1ffffO@Y13333O@i13333O@|2O@`fff$2̜O@0333823333O@@2O@`fffC23333#O@D2ffffO@`fff82O@`fffM2$O@0333S2ffffO@ @33333O@|3@O@<3ffffO@03333O@24$O@0333f4̌O@y~43333O@`ffff4ffffO@0333}4O@Px4O@@p4O@)_4O@\4O@i4O@0333sv4dO@̗4 O@033343333cO@ 4O@ܺ4̌O@`fff4ffffO@03335PO@`fff"5O@'53333O@033353333O@ 5LO@0333'5ffffO@ ?5̼O@9c5O@r5O@`_6O@\63333+O@`fff63333O@i63333+O@6O@033336=P@л6P@63333SP@03336ffffP@0333c6,P@P6P@03336O@`fff06ffffP@6̐P@@6̄P@y53333 P@̬5ffff P@05% P@53333;P@5P@,5ffffVP@0333#5ffffvP@̜v5DP@03335ffffvP@̌5ffffvP@033353333P@ 63333P@ 6P@6qP@5P@0333#5ffffBP@,6qP@6P@I5 P@г5ffffB&P@ܝ5ffff 'P@033335ffff(P@`fff5(P@ɬ5t)P@`fff5$P@0333#6"P@0333(6|"P@A6$P@H6ffff%P@ S6ffff'P@0333Q6l)P@;6-P@`?6.P@N6.P@w62P@`ffff6|2P@0333X7ffff4P@y733333P@73333k0P@7ffffN/P@7ffff 0P@733331P@0333c73333;4P@03338ffffB7P@83333_9P@`fff73333:P@0333#7%;P@`fffv7ffffj:P@<|7̈P@0333L23333P@ .2ffffFP@01,P@1MP@0333c1ffffP@ 13333+~P@1̸}P@1̜~P@w1ffffP@j1ffffP@0333U1P@,'13333P@1ffff2P@13333P@033330ffffP@0ffff.P@0P@0lP@03333P@)|0ffffP@`fffo0)P@`fffm0БP@i03333P@L~03333˞P@0333?03333wP@0 03333P@`fff/P@̬/P@/P@0333sm/3333P@0333g/IP@0333sK/P@0333/P@83330@3333cF@l6@FH@!6@3H@hfff&:6@33334H@,;6@4H@8333@6@$4H@D6@1.H@̬E6@3333-H@̌K6@)H@8333Q6@$H@hfffY6@ffff H@l6@$H@hfff&6@IH@6@(H@hfff&6@\ H@6@3333C H@6@3333 H@hfff6@H@@6@0 H@83336@H@8333s6@H@83336@G@hfff&6@3333G@l6@@G@ 6@ffffG@@6@ffffFG@6@ffffG@6@9G@}6@3333G@j6@ffffG@Y6@6@3333#G@`/6@̄G@hfff6@8G@ 6@G@5@̤G@5@ffffG@L5@G@833335@G@̌5@G@83335@ffffG@hfffƸ5@3333ۊG@8333S5@ffffG@hfffƦ5@ffffրG@83335@\{G@̌5@ffffnpG@8333~5@ffffeG@ z5@ffffn`G@@5@ffff&ZG@9i5@RG@\5@tOG@Q5@MG@hffffK5@ffffFIG@8333@5@A>G@hffffC5@P9G@C5@ffff4G@15@ffff2G@+5@$-G@hfff&5@&G@hfff&5@ffff&$G@83333 5@G@hfffF4@ffff>!G@4@̄G@hfffƼ4@ffffG@83334@3333G@4@ffffG@94@̤G@4@ffffG@83334@ffff^G@G4@ffffG@hfff=4@ffff G@54@!G@8333S)4@)G@ 3@3333G@,3@̬G@y3@qG@ 3@G@3@G@ u3@ffff. G@k3@@G@8333d3@`G@̌T3@ffffG@83333G3@ffff^G@Y53@F@8333s%3@ffffVF@Y3@G@83333@8G@83333 3@F@hfff3@F@hfff2@8F@hfff2@3333CF@y2@3333CF@@2@ffffF@hfffƸ2@ffffF@2@(F@̌2@F@2@F@8333o2@8F@[2@3333cF@hffffJ2@F@8333C2@3333F@1@F@1@,F@ٴ1@3333F@1@ffff&F@hffff1@ffffF@y1@|F@hfffh1@̼F@hfffO1@F@>1@ffff G@L&1@ffffG@`1@G@0@x G@0@ffffn+G@0@L5G@hfff0@>G@hfff&0@?G@8333s0@3333BG@ k0@MG@a0@QG@8333sb0@$WG@^0@ffff6ZG@U0@ffff^\G@hfffQ0@)dG@N0@3333iG@H0@3333mG@83330@nG@hfff@0@h|G@8333T0@HG@hfffl0@̜G@8333t0@ffffހG@8333v0@G@z0@hG@|0@ffffG@ ~0@3333G@{0@G@9p0@̬G@j0@G@8333p0@YG@lv0@ffffG@83333o0@G@`q0@3333#G@hfffƃ0@ȳG@ 0@3333[G@0@IG@0@G@833330@̜G@hfffƣ0@G@n0@G@k0@TG@9x0@G@hffff0@3333G@ 0@G@hfffF0@G@0@G@`0@G@833330@ffffG@83330@G@0@@G@833330@G@ 1@G@̬ 1@3333G@ 1@3333G@83331@ffff&G@9 1@̼G@hfff1@PG@1@XG@%1@3333H@8333,1@3333H@F1@ffffH@83333M1@ffff&G@9Q1@ffffG@ {1@̜G@1@3333G@ 1@̔G@̬1@)G@hfffF%2@G@y2@tG@hffff2@G@2@3333;G@,2@3333+G@83332@3333CG@hfff2@@G@2@ H@hfff2@H@C3@Y H@̌w3@3333+H@Y3@H@8333s3@ffff>H@3@ffffH@̌3@3333H@`3@H@ 3@H@L3@H@ 4@3333kH@8333sU4@%H@y4@`?H@8333s}4@qCH@hfff4@\FH@4@EH@,4@̄BH@95@@H@hfffF25@3333[AH@hfffa5@FH@̌s5@FH@833335@BH@,5@3333s?H@hfffF5@Y;H@5@5H@ 5@3333c3H@83335@ffffn0H@83335@\,H@Y5@ffffF+H@6@Y2H@!6@3H@4WV`)@T43330@T0333s-@T .@ffffVT9-@ffffT̬-@T-@T`-@3333Thffff-@ThfffƖ-@9T̊-@ffff6Uy-@3333U0333-@3333kU0333S-@ffffRUhfffFv-@ffff Up-@P Us-@3333OUhfff~-@U z-@U0333se-@3333U_-@3333Uhfffi-@1U,b-@3333U0333I-@h"ULD-@3333W)UyR-@̴.U@m-@2U̬-@7U-@ ?U@-@dBU_-@CUJ-@ffffVBU 7-@CUy*-@GUhfff&$-@3333SJU -@ALU̬,@̤LU,@|KUhfffƯ,@UMUhfff,@0RU0333S,@WUr,@^Uhfff7,@3333eU0333s,@̤kU0333+@nU+@3333nǓ+@nUhfff+@8pU@+@YrUY+@ffff~Ul+@U̬,@ffffU ,@U9+@3333?Uhfff+@3333;UhfffF+@ Uhfff+@ffffU+@Uhfff+@3333Uhfff~+@QUe+@ݰU@E+@U*@|U0333s*@̬U*@ffffU@*@U0333s*@ĺUyr*@qU[*@̸U,<*@ffff^U*@̘U*@U)@U`)@HU`+*@3333kU@A*@3333WULn*@U*@ Uhfff*@MU0333*@3333Ul*@UUY*@=U*@U`*@3333+U*@3333UY*@iU0333+@ffff U0333 +@̌U )+@UhfffL+@U+@U+@XU̬+@ffffU9+@lU`+@ffffzV,+@ffff&V0333+@ffff Vhfff+@Vhfff+@$V03333+@ffffV0333+@V`+@V +@3333G V̬+@ V9+@ffffR%V0333,@*V0333,@I-Vl,@/V%,@$6V?,@ffff7VS,@3333@Vhffff,@AV ,@CVhfff,@ffffGV̌,@3333JVy,@UV,@4WV,@̸UVhfff,@YRVY-@ffffJV6-@aJVhfffV-@MLV0333ӓ-@3333;NVl-@0MV-@ffffJVl.@ IVhfff%.@}>V I.@̀=V N.@5Vhfff.@ffff+V0333.@!"V`.@TVhffff;/@3333_Vhfffc/@̜V@u/@dVf/@ffff~V/@ffffVhfff/@ Uhfff/@3333U9/@3333U@/@U/@U,/@)U0333/@(Uhfff&/@LU9/@U0333S/@3333sUhfff/@ŞUhfff&/@3333ӖU/@̘U03333/@3333cU0333/@{Uhfff&/@ }U43330@U00@,rU0@^Ǔ/@yJU/@ffffCU̬/@Q>U0333/@Y)Uhffff/@#U/@U/@)U /@3333CU0333/@ffffbU̱/@A!Uپ/@3333U,/@T̬.@ffffT.@ffffBT /@LU0333/@ U .@3333U9.@UhfffF.@U0333.@U,.@3333[T.@̸T.@ffffNT.@3333T0333p.@T@p.@T.@̼T0333.@LT0333Sp.@ffffTq.@DThfff.@ET.@ffff^T.@̠Tz.@Thffff(.@pThfff.@T0333s-@U`0@3333#UL0@XU@M0@̤U4333\0@ U4333i0@3333Upp0@ffffZUm0@U`0@wUdfff&v0@3333|U4333Sg0@̀}Un0@ffff&{U{0@4xU43330@\uUɂ0@3333 vU|0@wUdfff&v0@Rdfff 2@LQ4@p[d3333Qٷ3@yQ,3@̈Q|3@ffff>Qdfffl3@4QS3@ffffQ,I3@lQ)23@LQ)3@ Qy!3@}Qdfff 3@Q̬2@TQdfff2@Q<2@Q2@̐Q2@Q@2@tQ92@(Q@2@ffffR2@3333/Q92@Q̌j2@3333Q`W2@3333/Q4333SE2@Qdfff642@,Qdfff 2@ffffQ2@̌Q4333/2@!RdfffF62@R4333:2@ffff: RL82@h#RY52@%R/2@(R-2@ffffV0R'2@33338R&2@ffff>JR433342@lQR;2@ffffXRL@2@3333`R>2@8iR4333:2@oR433302@tR,2@̴uRdfff2@3333xR 2@3333SRdfff$2@3333wR433372@tRD2@њRX2@pRd2@R43333s2@̘R2@4R2@3333Rdfff2@lR 2@ffffv~Rdfff2@33333wRP2@kR2@eR2@̴:Rt2@̄2RPo2@3333S/R0q2@3333,Rw2@9*R2@ffff'R2@ffffRdfff2@R2@0R̬2@@Rɬ2@ffffRY2@3333)Rdfff2@3R4333S3@p/R!3@ffff&1R=3@y/R4333W3@-Rp3@ffffB7R̬3@`CRY3@1TRdfff&3@]YR3@ffff\Rܸ3@ffffYR43333@ffff.TRdfff3@MR93@GR`3@8Rdfff3@(R3@R433333@R3@3333Q3@lQ\3@3333Qٷ3@ffff~3Rdfff2@33334Rdfff2@DRy2@ARR2@̰QR<2@3333JR2@lDR2@:R2@ffff~3Rdfff2@*R 4@3333'R4@3333(R`3@X/R4@6R4333 4@88Rdfff4@ffff9R 4@ffffv=R4@:R4@ffff~6R4@2Rdfff4@*R 4@ ffffN33338?=L@!@ffff^N`fff@zN`fff@fffffN`ffff@2333;N@ffffNL@̦N03332@2333˜NL@iN@yN0333s@ffff~NY@TN@@ffff>N0333 @NZ@Ň@2333N03333@iN0333s@N @xNY@tN@oN%@iN`ffff'@[N@UNL9@KN`fffm@2N @-N0333@9)N@^@)N03333@2333+,N@92N@2333;Ň@BN`fff&@ffffJN0333@QN`fff&@ffffnQN@2333MŇH@ffffON t@\N`fff@[N$@!SN0333b@NN`fff@ffff6GŇ@ffffAN0333@@0NO@2333c,Nj@2333#N@ffffN`fff@ffff&Nl @M0333R @Mb @ffffM0333S @M @2333sM`fff @ffff>N@!@̄M0333!@2333M`ffff @M0333ӭ @ffffMl @M̌ @2333CM`fff @2333 M @M03333& @gM@@̼YM03333m@4PM/@2333kAM@=MM@2333=M '@̜JM`fff_@MM @ffffNM@2333#VM`fff&@LMY@HML@2333K@M@ffff5Mg@23333&M`ffff@ MLQ@0 MLH@L$@|L`fffd@L03333@2333#LS@L`fff@ L0333@YL`fffc@hL@@ffffFL`fff&B@ffffL1@2333L`fff@ffffL@\L0333~@ffffƨL`ffffW@2333ˣL0333@ffffL0333@ffffL@LY@2333ۚL@ L̶@xL̠@L`ffffl@2333#L2@ffff^L`fff@L0333@2333L@ L0333@L@AL`ffff@LY@ffff&L03333@L@aLH@2333L@ffffL0333@IL03333@ffffL0333N@L0333@\L@LYf@`M`fff&@M @2333Mh@ M@0L@2333LLL@̔L`ffffh @4L̴ @!L# @2333Lc @L( @ffff&L 333 @YL @2333˾L @ L`fff @yL`fff @ffffަLL @L 3333 @ffff6L 3333 @2333LP @ffffޟL`ffff# @ffffL@2333L`fff@̜LL@|L@2333ۚL@2333CL@L@LL4@tL`ffff%@fffffL@̼LLS@ffff^L!@̴L@L 3333@L`fffA@Y}L@xL@2333;wL 333)@ffffvqL@ffffkL7@hL 3333@laLL@(ZL 333J@HPL @ffffHL`ffff @BL̘?=L?2333CCL?2333#HL?NL3333?LXL?bL@ffffF?kL?|L?IL@ffff?ЄL?܋L`fff @8L@DL?ffffFLY?2333L@ffffj?2333L ?2333ӴL?ffffLa?2333L?ffffLD?2333LF?L33333?L3333?!Lh?L`?`L@ffff0?M?pMS? M:?4ME?(M?ffff~M3333?#M@ffff0?8(Mx?2333+Mf?l.M3333?0M{?2M3333?M@ffff?2333s?M?̄AM?2333sMM@ffffw?WM3333?2333{]M?2333dMV?0iM33338?fffffnMB?2333SuM@ffff?{M?ٌM?M3333?2333Mo?2333+M!?XMp?ffff^M@ffff?M33333?ffff^M}?2333SM?ffffM3333?M3333z?iM?M?2333Mi?9Mf?2333+M@2333M`ffff1@M̝@ML@2333M@ffffFM@yM@tM@2333 M`fff@MC @2333cM 3333 @ffffML0 @M @\M 3333 @ffffMU @M 3333 @M@ffff^M 333@ffffML@2333M`fffw@dM@M@2333cM0333@yM@@2333M0333@M03333@ffffM̌&@Mj@M@@ffffvM`fff@2333MY@2333M@ffff.M@2333N0333@9N0333s @ffffN "@ NLG@Nd@2333N`fff@NL@lN03333@@2333NL@2333M@ffffMT@ffff N0333s@ N`fff@ffff.Ň@2333CŇ@ffffN`fff&@*N@2333S4N03333@:N@IN@`SN0333s@ffff^N`fff@90Y%@X+ \)@boy90̬(@,0̌(@`fffv0(@0333j0@(@W0̌(@0333=0(@$003333(@٭/03333(@L&/0333(@.̌-)@`ffffd. \)@0333-[)@0333j- [)@̲,0333SZ)@03333!,Y)@`u+ Y)@w+`fff/)@X+(@`]+l(@0333sj+(@u+`fffƏ(@+0333S(@+`fff(@`ffff+`ffff~(@`fff+03333n(@0333+9[(@`ffff+`fff&I(@L+`fff/(@0333+`fff(@y+0333(@v+0333s'@`fffu+0333'@,w+x'@ +`fffFT'@>,M'@,Q'@٧,0333sB'@`fff,`fff'@`fff5-0333'@̬]-Y'@`fffp-&@-&@̌-0333$&@-%@`fff.Y%@0.`fff&@0333.̬H&@̌1.0333G&@0333\.`fff&@q.0333&@0333n.P&@ن.`R&@̌.0333M&@`fffF.9o&@.L&@.@&@`ffff.0333&@.&@`.̌&@.̌&@.0333&@0333.l&@0333S.`fff%'@S.0333s)'@03333%.03332'@̬>.R'@0333u._'@`fff&.V'@`fff&.>'@0333s.;'@/0333r'@ /`fff'@03333.`fff'@.Y'@0333k.'@`fff&D.̌'@03334.0333'@$.'@0333(. '@9.`fff'@L`.`fff'@.'@`fff/'@`fff&M/'@`fff/`fff'@,/'@03333/'@`fff&/`fff&'@`fff/0333S'@p#0`fff'@9F0'@S0l(@Q0I(@`fff6A0i(@̜>0`ffffy(@0333O0l|(@0333o0`fffh(@90̬(@P0l&@100333&@0333#;0@0&@`fff<00333:&@033310B&@`fff-0B&@$0lU&@03330a&@0333c0`fffe&@<0d&@0333 0,<&@|0 +&@P0l&@0333/9*&@0333s/`fff&@̌/03333&@/,&@L/0&@/`fff\&@/0333b&@y/R&@/0333K&@0333/9*&@`fffFs/0333Sn&@`fffFs/YY&@0333/0333S]&@@/c&@`ffff/0333&@Yo/&@`fffX/̗&@0333Q/̬&@U/`fff&@_/w&@`fffFs/0333Sn&@Y/0333'@`fff& / '@@=/`fff&'@/9<'@`fff.C'@`fff.0333"'@l /0333'@Y/0333'@/&@/l&@0333/&@0L&@03330 '@/0333S2'@`fff/-'@/&@ /'@ 0'@90'@%0`fff&'@`fff'0'@0'@ /'@ 9.@̌ Y)@\$`ffff @Y$0333 @0333$@ @,$`ffff @̌% @@5%0333 @`fff&N% @_%0333 @l%`fff @g%y @Z% @`fffA%Y!@%0333R!@`fffF%`fff`!@% !@03336%03333!@`fff&6%`fff&!@`;%L"@`fff&t%0333)"@y~%`fff0"@%`fff>"@`fffFq%0333c"@0333`%0333"@̌]%`fff&"@̌a%`fff"@`ffff%L"@`fffƺ%l#@%R#@L&#@9;&0333#@\&`fff#@Li&#@&9#@&̬#@̌k'`fff#@y'l#@0333s'0333s#@H(03333#@03333( #@ (#@)l#@y ) #@)0333h#@.)W#@ 5)D#@̌>)`fff3#@`fffM)0333#@l^)`fff"@)`fffF"@`fff)"@`fff)0333ӆ"@L)9K"@Y*`fff5"@0333'*`fff#"@B*Y"@0333S[*,"@w*`fff#"@ٕ*03333"@0333* ("@*0333SW"@*o"@*"@`fff*`fff"@`*03333"@0333"+9#@a+0333S#@0333sP+9G#@@Q+#@`ffff+ٳ#@,a+`fff#@l+̌#@`fff+0333#@`fff+@#@`fff+#@03333 ,$@0333S,0333:$@ ,0333SH$@,,,`fff&A$@@W,A$@0333,`fff&$@8-`fff%@,:-0333S<%@,-`fffFx%@/-̌%@Z-`%@c-`ffff{%@`fffƃ-`%@`fffF-%@`fffƬ-0333%@-`fff%@-%@03333-Y%@Y.0333ӛ%@9.L%@`fff.Y%@-%@̌-0333$&@-&@`fffp-&@̬]-Y'@`fff5-0333'@`fff,`fff'@٧,0333sB'@,Q'@>,M'@ +`fffFT'@,w+x'@`fffu+0333'@v+0333s'@y+0333(@0333+`fff(@L+`fff/(@`ffff+`fff&I(@0333+9[(@`fff+03333n(@`ffff+`ffff~(@+`fff(@+0333S(@u+`fffƏ(@0333sj+(@`]+l(@X+(@w+`fff/)@`u+ Y)@*0333S)@*`fffN)@`ffft*yG)@`fffF*̌G)@0333s**`D)@*`fff:)@ *))@(*0333)@`*(@*̌(@`fff)(@)Y)@`fff)`fff)@)@ )@9)`(@0333m)`fff(@=)(@`fff)`ffff(@,((@0333S( (@(0333(@M(0333(@0333((@0333'(@'L(@%'`fffF(@&(@`& (@ &`(@`fff&&0333s(@&̌~(@ '0333e(@ &yU(@L&@5(@@&`fff(@y&0333(@Yk& (@,B&`fff0(@0333!&0333sW(@0333S&@j(@% i(@%M(@%̌(@l|%'@`fffFx%9'@ k%`fff&'@Z%'@0333I%'@<%`fff'@0333-%`fff'@$G(@پ$[(@`fff$la(@$l(@̌U$Z(@0333s$;(@03333#(@ #0333S(@0333m#(@ Q#`fffFI(@,#l](@@"0333u(@Y"@(@Y"`fffƂ(@,"`fffƐ(@"(@"`ffff(@̌"l(@l"`fff(@"`ffff(@"`fff(@Yn"9(@̬="`(@ "(@0333s!(@0333!s(@`fff!03337(@!0333S'@!@'@!0333X'@9!`fffK'@Yw!`ffffF'@@l!L<'@0333sT!̬'@`fff>!`&@03333#!`fff&@ &@ `fff&@ ̬&@`fff& `fffƭ&@ `fff&@0333S &@`ffff !x&@0333s"!Z&@S!Y&@YU!&@J! %@`6!0333S%@`fff !L%@ `fff&@ 0333S&@ 03333%@ `fffF%@ٜ %@0333 `ffff%@0333 %@`ffff 03333<%@`fff 0333$@`fffv @$@ ̤$@Y̌$@`fffu$@`ffff03333S$@ `fff&@$@' Y"$@0333E L $@0333sO `fffF#@̬J 0333s#@`fffJ Y#@ F "@`ffff- "@ "@`fff"@ 333"@ "@`fff`"@̌[M"@3`fff:"@`fff`ffff)"@"@ 333`fff!@`fff`fffF!@ْ!@"0333p!@9I!@̌ !@̌ @L @ 333 @L& @YK0333s @y` @ @`fff& @`fffU 9 @k l @0333Sy L @} @ `fff @,o yp @H `fff\ @Y. ̌T @ `fffV @0333 03333J @  03333( @@ 9 @% @0333@ ̌x@0333S< K@; @0333si `ffff\@v :@ \@`fff& Lh@ `fff;@`ffff !W@ !@`(!L@03336!0333s@Q!`fff@`fffj!0333@yu!k@w!,@{!@̉!@`fff!Y@`fff!̌J@! @y!̌@`fff!03333@! @"`fff@03333<"@`fffE"@X"@,n"LU@̆"̂@"@`fff"`ffff@`fff"@y"٩@`ffff"`fff&@̬"03333 @"I@`fff"`fff@"0333@03333"0333-@`ffff"w@̌"L@0333"`fff&@"`fff @"̬ @9"`fff6 @"`P @Y#@Z @` # @Y #03333 @# @`ffff8# @0333SI#@ @S#0333s @`fff&^#`fff @g# @ o#0333 @x#l @Y#0333!@`#L!@`fff#0333 !@0333 $ @&$ @2$!@yK$ !@0333Sw$`fffF @$`ffff @ Wy+@̜V1@s W@-@` WY$-@ WB-@< Wa-@3333K W̅-@ W-@ffff Wy-@% WY-@3333; W.@QW0333 .@W&.@ W0333y.@ffff W̌.@ffff WL.@AW.@3333CV h/@qV`/@$Vdfff0@ffffV 0@ffffVdfff0@V 0@V00@hV90@ffffV̜0@ffffnV)0@3333ϜVB0@VY0@Vd0@ffff&Vdfffp0@٤V4333w0@̔V0@V̬0@V I.@ IVhfff%.@ffffJVl.@0MV-@3333;NVl-@MLV0333ӓ-@aJVhfffV-@ffffJV6-@YRVY-@̸UVhfff,@4WV,@3333XV0333,@ffffZV,@ffff`V,@bV,@ffffdV,@dV0333,@cV0333,@cVhfff{,@3333dVhfffs,@ffffjV̌],@3333mVYH,@oVl',@rVhfff,@uV03333,@ffffwVY,@T|Vhfff+@V+@Vhffff+@3333džVhfff+@Vy+@VhfffF+@ئVhfff+@XVhfff+@ffff&V+@V:,@lVt,@ W@-@`ffffN0333S(@2333NYy(@ ffffNy(@ffffN0333S(@̼N`fffF(@N`fff7(@̄N^(@NYy(@2333N0333Sr(@ffffFN(@ffffNy(@>3@̜wA@Y;<@4D@( !,8CW)3:CMTblt%83333;@ffffFB@;@DB@;@ffffJB@hfff&;@3333MB@9;@3333CQB@;@RB@̬;@ffffOB@y;@̔JB@83333;@ffffFB@4@1C@4@I"C@4@3333C@83334@0C@4@ffff^ C@hfff4@ C@,4@3333SC@hfff4@ C@hfff4@ffff C@~4@3333C@̬4@C@,y4@C@s4@C@d4@ffffC@@Z4@ffffC@,Z4@aC@h4@3333+C@`o4@-C@@{4@3333(C@hfff4@*C@`4@2C@4@p:C@,4@3333ZB@ه8@̌WB@8333sS8@3333SB@LX8@3333\B@[8@D_B@l8@A[B@@s8@ffffN]B@u8@̬_B@hfff&8@3333aB@`8@3333+B@8@B@Y8@ffffB@l8@3333 B@833338@!B@83338@3333#B@`8@3333+B@8@3333;B@8333S8@B@8333S8@B@l8@yB@98@3333sB@8@ffffB@@8@B@l8@fffffB@Y8@̼B@hfff8@3333B@83338@B@8@B@8@B@8@3333;B@A9@B@89@ffff~B@hfff(9@B@L 9@ffffB@,9@ffffB@8@̤B@8333 9@ B@9@B@833399@B@A9@B@̌8@uB@8@3333cuB@,8@zB@hfffƫ8@B@8333s8@ĂB@8333S8@ B@`8@yB@̌8@uB@8333:@C@9@̬C@8333S9@$C@83339@3333"C@9@̼&C@9@@-C@9@@5C@9@3333AC@9@yIC@83333:@MC@hfffF:@ffffEC@ ):@ffff6EC@hfff&$:@3333;>C@L&:@ffff;C@83333(:@ffff&C@Y:@3333#C@hffff:@C@8333:@C@i:@3333+C@̌d:@3333C@8333:@C@hfff:@C@y:@@C@:@ffffC@8333:@:@C@E:@IC@ -:@ffffޘC@hfff:@D@ 9@`;D@̌9@6D@ p9@C@`f9@3333C@@_9@ffffC@hffff[9@pC@yL9@ffff.C@lC9@ffffVC@8333s@9@\C@?9@3333sC@L99@@C@hfff49@C@hffff/9@3333;C@` 9@̴C@9@3333C@83339@ffffvC@hffff 9@C@9@C@8333;9@D@hfff&I9@hC@Y9@ C@hfff_9@D@r9@tD@ p9@C@g9@ffffB@N9@ܴB@ P9@B@ Y9@,B@hfffv9@LB@u9@9B@g9@ffffB@hfff8@3333B@̌|8@ffffB@l8@B@8333p8@3333B@{8@B@8333s8@ffffB@833338@ffffvB@hfff8@3333B@;@3333A@hfffF;@3333CA@hfff;@̜A@,;@A@;@3333B@;@B@`;@ffffB@@;@\B@8333;@3333s#B@;@33333,B@hfff+<@ffff6B@Y;<@7B@hfff:<@d/B@$<@B@8333S<@B@y<@\B@,;@B@;@3333A@,7@A@̬7@3333A@hffff8@A@8@A@hfff8@3333A@*8@0A@28@3333A@8@3333cA@hfff8@ffffvA@hfff8@A@8333-8@ѺA@`A8@3333A@A8@)A@`F8@hA@P8@A@Z8@3333A@hfffq8@ٮA@و8@̼A@8@xA@hfff8@`A@9@ffffvA@83339@hA@K9@pA@hfffy9@1A@8333ӑ9@ffffA@9@ffffA@9@ffffƩA@833339@ffffA@9@DA@83339@A@L9@A@83339@A@,:@ffffA@*:@A@I:@ffffA@Q:@ffffVA@8333sL:@aA@hfffG:@aA@lA:@ffff.A@̌>:@A@hffff*:@aA@8333 :@ЁA@hffff9@9A@hffff9@A@̬49@zA@8@̜wA@hfffƾ8@ffffyA@8333s8@ffffցA@833338@ffffvA@y8@fffffA@Y8@3333ÎA@8333v8@ffffA@̌7@hA@833337@A@833337@3333A@Y7@A@7@A@hfffƏ7@ȥA@,7@1A@7@3333sA@8333ӛ7@3333{A@hffff7@3333A@833337@A@hfff&7@3333kA@ 7@hA@hfff7@A@8333S7@ffff.A@7@1A@,7@A@hfff&R:@D@i:@!D@hffffv:@D@~:@ffffD@hffff:@D@8333Ӕ:@ffffD@:@ffffD@:@lD@83333:@TD@8333S:@3333D@hfffT:@D@`S:@ffffVD@8333T:@3333kD@hfff&U:@3333;D@hfffZ:@̴D@hfffZ:@D@T:@,zD@=:@ qD@-:@3333iD@8333:@_D@:@^D@ :@ffff]D@:@3333sbD@ 9@3333 lD@,9@3333qD@hfffFS9@xD@hfff@9@fffffwD@9@3333SD@833339@{D@8@3333mD@8@3333KoD@y8@wD@ z8@PyD@@b8@tD@<8@dD@83338@ffff\D@833337@_D@hfffF7@_D@hfffF7@VD@Y7@aPD@7@ffffED@7@3333=D@hfff7@33335D@7@3D@83338@d4D@y68@)D@J8@3333D@hfffW8@D@;8@3333D@hfff(8@#D@Y8@3333&D@hfff7@-D@7@3333/D@Y7@4*D@8333s7@̤$D@7@AD@hfff7@ffffD@̬7@D@833338@ffff&D@Y7@D@83336@3333CD@6@KD@6@JD@6@3333DD@hfff&6@ffffn?D@6@6D@hfff6@.D@6@a#D@6@ffffFD@6@D@83336@yC@hfffF6@C@83336@3333+C@y7@3333C@;7@C@I7@C@hfffS7@3333cC@hfff77@\C@'7@C@83337@ffffC@83333+7@C@hffff)7@ffffC@,6@`C@6@ffff6C@hfff6@C@83336@C@`6@ffffFC@,6@C@83337@3333ۄC@833336@ffffNyC@y6@hsC@hfffF6@sC@hfffƘ6@ffffqC@83336@ oC@`6@3333lC@6@lC@hfff&6@3333sfC@833337@ffff^C@@#7@UC@@7@3333TC@8333s^7@DCC@8333ӑ7@̤>C@7@-C@hfff7@)C@̌7@33333#C@`8@C@hfffF8@C@8333s8@HB@83338@B@83338@3333#B@,8@B@ 8@B@7@B@7@ffffB@7@)B@7@YC@hfff7@1C@8333s7@ffffvC@8333k7@B@833317@B@`7@B@hfff& 7@B@L 7@ffffnB@ 7@33333B@̬%7@B@̬%7@ffffB@833327@3333cB@@C7@ffff6B@X7@|B@le7@ffff6B@hfffh7@QB@hfffFu7@3333B@}7@`B@@}7@XB@hfff@7@3333KB@37@̜B@Y)7@3333B@7@B@83337@dB@7@3333B@hfff6@0B@6@ B@hffff6@B@83336@dB@6@XB@6@9B@6@B@8333s7@@mB@83337@1cB@ 7@RB@7@FB@)7@3333[9B@Y7@ffff9B@7@T>B@6@CB@83336@3333WB@hfff6@dB@6@eB@6@ffffcB@83333}6@HB@L}6@49B@m6@ffff6@(C@L6@ffff~C@hfff&6@C@83336@B@̬6@B@6@B@6@C@hfff6@̄C@l6@̌ C@@7@3333c C@ '7@ffffV C@.7@C@ &7@C@83337@$C@7@ffffC@83336@ffffC@6@C@6@3333 C@6@!C@6@ffff%C@Y6@ffff&,C@8333k6@!8C@b6@Y1C@hfffQ6@̬-C@8333:6@)-C@ 5@33334C@5@.C@83335@q-C@l5@P-C@8333S5@3333*C@x5@3333#)C@c5@333334C@[5@ffffC@lT5@Q6C@hfffM5@/C@.5@3333;,C@5@<1C@L5@3333k@C@4@ffffSC@̌4@3333KcC@4@\gC@4@oC@4@vC@hfff4@ffffvxC@5@LqC@83335@rC@'5@ffffvC@%5@ffffV}C@L5@ffffփC@̌5@!C@5@\C@94@̴C@4@C@4@C@4@3333C@Y4@C@w4@̬C@M4@ffffީC@14@C@8333s4@C@8333S4@ffffC@hfff4@C@L4@|C@̌!4@C@833344@ffffC@̌?4@C@hfffE4@C@I4@C@9K4@ C@`N4@C@83333]4@XC@hfffa4@̼C@8333a4@C@ X4@C@8333O4@3333C@hfffO4@ffff^C@hfffV4@3333C@9b4@33333D@8333sh4@TD@t4@dD@4@D@833334@̔ D@L4@ffffD@94@lD@l4@D@hfffƷ4@ffffv%D@l4@ffff*D@ 4@)2D@Y4@9D@83334@;D@@4@H?D@5@HD@hfff5@̬OD@83335@ffffNTD@hfff4@[D@̬4@ @̌K @0333SR @@ffffNW @ j @tl @333!@0333ә!@!@1`fff!@@fff "@333"@3333 8"@o"@d0333"@L0333s"@@ffff`fff"@3333} "@0333s"@L`#@333 P#@>}#@,#@#@Ď*$@Nb$@!0333y$@7,$@L$@@ffff0333ӹ$@K`fff$@LT`ffff$@`fff$@0333%@333Q`fffF/%@3333Bt%@@ffffy%@333,%@L0333s%@@ffff`fff%@9%@%@i`fffF%@3333%@3333b̌&@ &@̸0333%@`fff&&@3333&@,%@̰0333%@r濘Y%@%@0333%@ `fffF%@ffffr`fff%@x߿`fff&@ffffݿ0333&@ffffۿ/&@Qٿ+&@ ֿ`fff-&@Կ<&@ffff*ӿ0333sU&@03333;&@n@G@.@̄K@5,]"@G@LA"@G@pfff&!@G@!@3333G@̌!@G@ !@G@L!@ffffG@@333s!@YG@pffft!@3333G@YI@fff@3333?I@@BI@@ffffEI@@`LI@@3333@QI@Lz@VI@@]I@@ffff`I@1@3333sI@@yI@@|I@@3333@3333}I@x@I@n@3333ۃI@@3333y@̅I@@9I@@AI@@ffffޒI@@3333@I@t@\I@ffffT@ I@L@yI@@333M@I@@3333@3333kI@@ffffI@@I@fff@̔I@@iI@L]@I@[@3333I@6@AI@L@ffffI@@ffffI@@I@\@ffffNI@x@iI@@̼I@@33330@I@@3333l@ffffI@}@ffff>I@@3333@I@@ffffNI@@I@@I@3@3333I@@3335@ffffvI@@J@@HJ@fff@D J@@ J@3@<J@k@aJ@@333@ffffNJ@@ "J@ffff!@ffffn*J@$@33330J@fff@5J@ffff@8J@@3333@3333[8J@T@̜8J@@d;J@@ffff?J@@3333@CJ@@3333[FJ@@3333kIJ@L@LJ@@ffffOJ@ffff@)QJ@ @QJ@!@`SJ@4@T_J@fffw@qJ@̷@̬{J@@J@@ffffJ@@!J@@333@٩J@6@3333J@L@3333#J@@333m@3333KJ@ffff@J@$@ffff6J@L@@J@ @iJ@̌U @ffffJ@̌7 @ܻJ@f @YJ@̌} @J@َ @ffffnJ@pffff @J@@333 @J@ @ffffJ@@ @ffffJ@̌ @ffffvJ@@333!@HJ@@3333!@3333J@̌!@3333J@@333&!@3333SJ@pfffK@@333sW$@9K@l$@X4K@̌$@33338K@̌v%@3333{(K@@333s%@ffff0K@&@0K@@333 &@#K@pffff&@0K@%@ffff K@̌%@AK@pfff%@fffffJ@pffff5&@,K@&@J@&@|J@@333f'@K@@333'@ffffK@9(@3333K@YV(@K@@333(@3333S$K@(@3333k,K@&)@3333;K@pfff)@ 9K@)@6K@pfff*@̜4K@K*@0$K@pffff*@K@r+@̜K@+@pK@pfff&+@3333;J@+@3333J@ ,@3333;J@,@ffffJ@̌,@dJ@@,@3333J@L,@J@@333,@9J@@,@IJ@,@ffffJ@pffff,@yJ@@333,@3333J@,@lJ@pfff&c,@̼}J@G,@hwJ@A,@ipJ@pfff,@)dJ@@3333-@3333RJ@pfff&=-@ffffCJ@@333#-@ffff.7J@@333-@ .J@%-@ffff6(J@@3333;-@#J@\-@ J@pfff&i-@ffffJ@b-@4J@h-@3333J@L-@y J@ -@ J@s-@3333J@b-@I@̌Y-@I@ 4-@3333I@@333s?-@I@\-@ffff^I@pfff&s-@3333I@@3333z-@ffffFI@l-@I@ s-@ffffI@-@ffffNI@-@I@-@ffffFI@.@YI@-@,I@-@ffffI@pfff-@oI@pffff-@3333mI@L-@kI@@333s-@ffffhI@Yr-@HhI@Q-@3333jI@pfff&:-@3333mI@pffff?-@ffffuI@0-@̔uI@̌-@3333;zI@pffff-@9I@-@3333CI@ ,@\I@@333,@ffffքI@,@ffffƃI@,@I@)@`:I@)@ffffF5I@pfff)@ffff4I@̌)@3333 6I@pfff)@)7I@@333i)@ffff^4I@pffffE)@33332I@)@3333[2I@(@ffff,I@(@"I@(@TI@(@9I@Yv(@XI@Y(@$I@ E(@'I@2(@ffff'I@.(@&I@@333-(@`"I@@333sA(@QI@Y(@I@@333s](@3333I@pffffj(@3333{ I@̌(@3333kI@@333(@H@L(@ffffNH@pfff&)@H@pffff)@PH@(@1H@(@@H@(@3333kH@@333(@̬H@(@IH@(@3333H@pfff&)@H@̌)@̔H@C)@ H@\)@ffffH@pfff~)@H@@333s)@(H@Y)@LH@pfff& *@3333KH@@333G*@DH@pffft*@3333KH@ٓ*@yH@*@ȇH@@333s*@ H@pffff*@!}H@pfff*@PzH@pffff+@ffffzH@@333^+@8pH@@3333+@qhH@pfff&+@3333+bH@+@ffff_H@L+@WH@+@3333OH@+@1KH@pfffr+@lEH@pffffb+@1DH@@333Y+@3333BH@pfff&*@yJH@*@1IH@@333s*@3333CHH@*@3333s2H@̿*@A.H@L*@fffff*H@@3333n*@̤&H@pfffG*@%H@ **@ffff6#H@)@3333H@pfff)@ffffH@L)@ H@pfff&)@ H@pfff&)@ffffG@@3333)@G@̌)@dG@ )@ffffvG@)@fffffG@@3333)@ffff>G@)@ffffG@@3333*@pG@@333*@3333G@̌*@!G@pfff&*@ffffG@Y*@1G@pfff)@3333G@)@3333G@pffff)@fffffG@̐)@ffff6G@@333)@3333G@pfff)@3333G@@333)@G@pfff&_)@̬G@@0)@G@ )@lG@@(@3333G@(@3333CG@@333(@ffffG@pffff(@3333G@pfff&k(@G@d(@3333G@Yh(@G@ _(@LG@o'@G@%'@ffff^G@&@G@@3333&@3333[G@̌&@G@̌&@3333cG@l&@G@pfffa&@lG@pfffE&@ffffVG@&@QG@@3333%@ffffG@%@ffffG@@333%@8G@%@G@%@ffffG@@333{%@ffffG@@Q%@3333 G@@3333$@YG@$@G@Y$@AG@$@`G@$@3333ۮG@pfff&$@ffffG@@3333{$@ffff^G@@333]$@G@_$@G@̌f$@̄G@LQ$@G@pffff1$@ffffG@@333!$@YG@&$@ٶG@pfff$@3333{G@@333s$@ffffG@@333s#@ffffG@pfff#@G@@333s#@3333G@pfff&n#@G@K6c#@G@I#@ffff~G@pfff&#@G@pfff"@̜G@pfff&v"@G@C"@ffffG@@3339"@G@]"@G@k+@0K@pfffw+@`(K@pfff&j+@#K@0+@I+K@*@0+K@@*@K@̌*@xK@La*@ffff)K@S*@.K@ P*@ffff2K@\*@ffff&AK@@333sZ*@EK@v*@JK@z*@QK@@333s*@3333;YK@@333s*@3333YK@@333s*@ffff&SK@*@NK@pfffE+@3333IK@@333P+@GK@pffffW+@DK@pfff4+@|>K@@3333)+@3333c;K@pfff&4+@3333k6K@k+@0K@@l,@̤J@e,@3333J@pffffm,@tJ@pfff&X,@3333J@,@yJ@+@̄J@pfff+@0J@pfff+@J@@333+@̤K@+@K@ +@ K@̧+@IK@pfff,@lK@@l,@̤J@̐&@5K@@3333B&@@5K@@3333$&@ffff^:K@&@3333;K@@&@3333AK@+&@ffffFDK@w&@)@K@&@8K@̐&@5K@̌ @3333dK@ @0bK@pffff @3333CtK@@333s @̄K@pfff& @ffffK@pfff @3333K@pfff @ffff>~K@ @ffffvK@ @ffff.sK@YB!@$rK@3!@nK@ٱ @ffff~lK@̌ @3333dK@-!@9[K@ !@ffffXK@Y @tXK@ @h[K@ @̌^K@@333 @3333`K@!@QaK@%!@ffff_K@-!@9[K@89C@D@hfffVG@ffffE@@E@ffffD@hfffE@ D@yE@D@E@D@4333E@ffffVD@E@̴D@LE@ffff~D@E@3333CD@ E@ffffD@E@3333ۤD@4333E@PD@PE@)D@tE@D@,iE@ffffD@dE@(D@hfff`E@D@YWE@D@̬ME@ffffD@4333KE@ D@HE@ffffD@4333AE@3333+D@4333;E@LD@4333.E@D@hfff#E@̼D@hfffE@LD@4333 E@ffff>D@D@qD@iD@XD@4333D@3333cD@4333D@\D@D@D@ID@D@|F@̄D@gF@33333D@gF@џD@̜lF@ffff.D@4333kF@ffffD@LHF@ffffD@̌@333s"@"@@33333"@Spfff"@ffff@3333"@Yh"@ffff!"@@!@$񿠙!@fffff!@ffffF@!@<h!@@333!@̌!@3333̌!@ffff ̌!@3333Opffff"@`)"@ffffpfffE"@Xpfff"@4333{ֿ"@8333ӭ̌"@dfff?̌"@3333w?@333"@?pffff"@?@333"@y?"@?@333"@2333s? &#@? z#@?@333#@`fff?#@2333?$@?̌#@$?pfff#@2333?#@?@333"@)?@3333"@ffff&?L"@̪?@333"@?"@ffffF?@333#@?#@?3#@*?pffff<#@r?pfff&@#@ffff6?@333s@#@3333?&#@̸?.#@?@333E#@3333?YZ#@2?h#@G?pffff#@2?̓#@3333i?#@?#@3333?@#@3333?@333#@?pfff#@3333?$@@ffff?[$@?$@ ?pfff,%@?%@3333?pfffB&@?@333&@?Y&@?̪&@?pfff&&@3333t?̌&@?&@@ffff?L&@`fffV@ &@`fff@pfff&@`ffff@pffff&@e@@3333'@`fffj@pfff&'@H@Y6(@L@̌N(@`ffffF@(@ 3333^@@)@ 3333@@pfff3)@@T)@`fff @pfff&)@`ffff@C*@L@p*@ 3333 @@3333*@ 3333@L*@`fffJ@̤Ny^5hffffK@ffffnI@ 1=S[jy@333"@gE@̌"@LTE@L"@3333NE@#@JE@pffff #@̼FE@pfff#@E@@333#@3333E@Y"@xD@@"@ffffD@pfff&"@D@"@3333D@pffff"@ffffFD@"@3333D@L_"@DD@̌"@D@@!@D@pfff&!@D@@333s!@PD@٨!@XD@ !@3333D@ !@D@!@YD@o!@ffffvD@@333o!@D@@333s!@iD@{!@3333kD@pfffX!@D@pffff>!@!D@@333:!@D@̌N!@ffffnD@@333g!@̄E@pffff!@< E@H!@!E@@333,!@ffffE@pfff!!@E@@7!@!E@Y!@3333[$E@@333s@!@+E@L/!@ ,E@!!@-E@,!@Q1E@@333G!@6E@m!@ffff^FE@@3333!@ME@pffff!@RE@Y"@TE@@-"@@E@@3333=@ffffE@ffff@ffffE@̥@ffffE@@333~@E@_@lE@L;@ffff޳E@&@aE@(@E@@3333@ȯE@̃@̌E@@ffff>E@@3333@3333kE@@dE@@333@xE@s@E@fffL@yE@fff5@E@ffffI@3333E@@E@@3333G@ffffE@@3333 @3333E@M @ffffVE@j@3333#uE@@3333X@@kE@@3333@KE@@3333 @;E@ @07E@7 @3333+7E@k@ffff>9E@@ffff;E@!@`:E@ffff@6E@@ffff4E@ffff@I4E@@3333\@ffffN2E@=@Y.E@6@̔+E@@3333@3333C,E@@1E@ffff@5E@ffff@3333k1E@C@@-E@?3333-E@33339?ffffF2E@?6E@?:E@L?l@E@ffffl?HCE@?3333CGE@?IE@[?ffff^ME@3333?HQE@?DRE@W?3333OE@ffff?ffffFLE@3333?hXE@3333?ZE@3333U?H[E@3333?3333^E@3333)?̴cE@gfffv?DkE@L?,lE@4333o?jE@4333?tfE@4333?ffffYE@gfff6?DXE@̐?WE@$?ffffYE@hfff?̼XE@Y?XE@hfff?3333\E@03334XE@ܴZE@_E@Hʿ̄dE@2333cпfE@(ӿ̤iE@2333տffffjE@ٿpgE@2333޿PfE@fE@DfE@3333ktE@g3333KxE@ffff^yE@yE@̴E@3333E@3333ffffE@E@iE@̤9E@ЄE@N,E@3333̴E@_E@3333E@YpE@ffffE@ffff3333;E@33333333E@33333333CE@̼E@(E@gLE@ffff E@E@ffff3333#E@ffffE@)E@3333ffffF@󿙙GF@ffffTF@3333;LXF@3333r3333aF@4\F@ffff3333WF@ffffffffVUF@ffff3333F@b3333۫F@Kffff&F@"F@3333q꿙F@ffffG@@ffffG@=ذG@3333۴G@@fffkffffFG@|G@333nffffvG@SYG@)ffffG@_G@@ffffG@3333LG@ffffG@@ffffG@G@LE 3333G@ G@ G@ ffffNG@* ffff6G@3333 3333G@ fffffG@54G@`ffffHffffG@G@?TG@PG@@ffffG@ffffH@L3333 H@ 333 a H@`fff|H@YQH@ ffffH@ hH@`ffff-̜H@O %H@`ffff̤'H@ffffN&H@3333%H@ 3333ffff&H@5l,H@`fff&u-H@ffff/H@`ffff/H@V3333-H@`fff3333{.H@3333{4H@ 9H@ 3333EH@ 3333333[OH@L<ZH@@ffffXH@@fff ZH@3333^ bH@ ffffhH@ kH@4eH@WLH@@fffffffDH@̑3333RH@333RH@JH@3333KQH@}3333;YH@̜UH@2̴PH@RH@SH@3333KYH@3333 3333gH@ffffTH@ ffffH@̼H@,H@H@ffffH@3333H)H@ffffiffffvH@H@ffff#H@3333=3333H@ffffXH@H@ffff7ffffH@33333333SH@33333333 H@3333࿙aH@ĿH@@fff憿DH@l?dH@hfff?dH@?H@?LH@?H@?\H@43333?H@hfff?H@?tH@gfff?H@?ffffH@?T I@9?@I@ffff?I@|?H I@3333?%I@E?^I@?hI@?HqI@ffffH?wI@?~I@̐@3333I@3@ffffnI@I@ffffVI@@3333@~I@@ffffFzI@ffff@̴tI@@3333@ffffpI@ffffZ@gI@@3333@`I@̷@3333@@3333@ffff[I@@3333`@]I@.@)bI@@cI@@3333= @_I@t @]I@@3333 @3333TI@ @3333KI@/ @ DI@ @@I@ @ffff?I@ffff @=I@ @:I@V @3333)I@̃ @,'I@@3333 @,)I@ @+I@O@i,I@ffff@ffffV+I@@+I@@3333-@!)I@̲@̌I@@333@3333cI@@ffffI@@hI@@I@@ I@L@3333I@fff@ffffI@@I@L@3333H@fff@\H@L@H@y@H@.@H@fff@PI@L@I@@l I@ffff@I@LF@3333I@@3333q@dI@)@3333H@@333]@ffffH@e@ffffnH@ffffx@H@fff@ffffH@@H@>@ffffH@@YH@@3333@9H@@ffffH@@33335@3333SH@j@ffffVH@@H@@dH@ffff+@iH@@333p@̜H@@H@@333(@ffffH@@3333K@ffffH@@H@@3333@ H@@1H@@333 @H@fffK@1H@z@3333H@ffff@ܿH@@ffffFH@@ H@`@3333H@ffff@̤H@@H@#@̄H@fffC@PH@L@3333H@@3333n@3333;H@@ffffH@fff@3333H@ffffH@3333CH@fffe@ٙH@@H@L@H@@ffffH@@333@̏H@%@lH@LC@3333H@@3333x@3333SH@@333@3333H@fff@@̔H@fff@H@ffff@3333{H@@ffffH@q@H@ffff2@\H@pfff @fffffH@L) @1~H@ E @ffff|H@G @ffffvqH@? @oH@fff@iYH@Z@iQH@fff-@ffffEH@@3333{4H@@#H@ffffw@H@@3333V@3333;H@o@TH@_@G@'@ffffG@@AG@C@3333G@ffffv@ffffG@ffffF@jffffF@|F@3333F@88G@83333sG@XG@ffffF@4333F@) F@L)9F@)4333F@̌)LF@̌)F@)4333sF@ g)4333ӋF@YN)@F@k)4333SF@ m)F@)hfff&F@ )4333F@hfff&)hfffF@hfff&)4333F@)K@V5K@y^5`K@[5lK@ F5K@hfff75̝K@43335K@5٧K@4333s4K@y4YK@,4K@4̜K@5hffffK@y#5hfffFK@ G5K@V52333iN,,@ffffkN0333,@YnN@,@ sN0333,@(Nhfff&,@`Nhfff-@N03333-@2333sN,4-@YN0333>-@NhfffN-@ Nٛ-@ffffNNy-@$Nl-@ffffNNhfff&-@xN-@yN03333-@̬vNhfff-@ffffuNx-@2333wN0333S_-@qNJ-@2333[oN9:-@2333iN,,@N:0@N4333#80@ffffN`:0@ffffN4333L0@2333Ndfff6\0@2333N o0@\NIz0@PN43330@ffffN4333w0@̴Ndfffi0@N\0@NA0@N:0@ffffvNdfff0@N0333/@N̬/@4N43330@̤N M0@1N)W0@N4333Z0@N4333sS0@2333kNJ0@2333NYE0@2333Ndfff&:0@,N9 0@ffffvNdfff0@Nhfff/@2333Nhfff/@ffffƧN0333/@Nhfff/@K 3333T@t3K 3333@ K 333@ffffK@2333K 333@K`fff@K @Kn @ffffK @9K @2333K> @J`ffff @K @aK @ffff~ K̥ @pK'@ffffFK`fff@̴ K`ffff5@,K`ffff7@2333+K`ffff@@/K @ffff2KY@2K03333@@5KY@h8KL@̌9K`fff@6KU@Y8K@ffffN@4333{I`fff(@0I@4333Ip@4333I`fff@4333I`fff@dfffI 33337@I @I 333 @I, @JL @J`fff @ffff^J`ffff, @"J @)J 3333t @ffff-J@ffff-Ji@̼2J@ffff5J;@Y:J@GJ`ffff.@̜GJ̕@JJ 3333;@2333SJ`fffg@ffffYJ@ffffFdJ@ioJ"@̤sJ 3333@{J`fffw@ffff>J 3333t@J@ J̰@iJ@HJ 333@2333J\@ffffΪJ̷@ٮJ@ffffFJL<@ffff&J`ffff@0J`ffff@2333J`fffW@2333 J`fffw@J@ffffFJ 333@J@ffff.J`fff@4J`fff9@$JL@| K 33334@ffffK`fff@lK 333@ffff.K:@2333%K`fff;@p7K@ffffAK 333@ffffvFK 3333X@KK@NK 3333@ffff1L\`G@̔L3333G@ 2333KLffffaG@L\`G@2333#L33333bG@ffffL,fG@LTgG@LgG@̔LfG@2333L3333cG@2333KLffffaG@0"L3333SkG@ffffV-LeG@@1L3333hG@I0LlG@*Lffff>uG@ffff*L3333wG@ffff1L3333G@`0LffffvG@̬.L3333G@$LffffG@#L3333{G@ffffN(LzG@%L0sG@2333 L4nG@0"L3333SkG@ffff8FfY,3333fq*#fhffff*3333f̌*ffff@f8333s*ffffzf83333|*fq*3333fL*#fhffff*ffff~Af,ffffNCfY,3333Ef8333,ffff8Ff̂,ffffEfv,3333Df83333|,ffff\Cf,eAf@,ffff~Af,POdfff2@4Odfff2@ffffnOdfff2@Odfff2@O92@2333Odfff2@,O43332@4O43332@ffffnOdfff2@pffffpO 1@\fO1@ |jO`1@hlO 1@mOdfff61@HoO 1@ffffpO1@ffffoO1@ffffnO43331@\fO1@LgO1@hO̬1@|jO`1@eb94g ahfff&!)28?IPajpyffffb4333S0ffffbhfffF0"b0eby03333/b433303333b̌0b0ffffb4333S0 bhfff1 b433331^bhfff1b1-bL1ffff޼b43333x1b4333Sy1 b|1 bhfff13333b43330bb03333b0>b0bY0ffff(b@0b@03333b43330Jbhfff1b43331Ԥbhfff13333ѥb1$b43331Kb̌1ffffb1jb43331ffffbhfff&1@b1Rb4333s1̐b1ffffBb43331ffff"b1bhfffƖ1Jbhfff13333`a8333c#[ǎ~#yZa8333{#[a8333#`a83333#[ba#ffffJda8333#SeaY#3333`a8333c#3333aa#Idahfff$Kda@#ffffpca8333#3333ba8333#3333aa#Ta%Va%Vahfff$̒TaL$Sa $ffffd@Y6(d@433364333#d@4333B6 d@hfffR6d@4333sZ6d@[6d@L`6hfffBd@C6d@?6d@̌A6d@hfffF;64333Sd@926hfffZd@4333'64333d@43336̔d@` 6d@ 54333d@hfff54333۽d@4333s5Yd@43335ͷd@5سd@hffff54333d@4333s5d@5hfffd@hfff54333Sd@̬S5d@43333J5hfff^d@354333d@44333d@hfff4̌d@@4d@@44333d@4hfffnd@z4hfffބd@9j44333d@4333Y4d@ N4d@4333SG41d@;4Ld@@,4d@9$4yd@?4ld@̌6hd@@6hfff&d@@643333d@6d@Y60d@6d@hfffF6ld@̌6tc@O34333c@hfffFU3c@,34333c@Y34c@=3tc@O3Ye@4333n5hfffe@r54333se@q5e@hfff54e@hfff5d@@54333d@433354333d@hfff5!d@ 5d@hfffd5d@4333s_5d@V5̄d@hfff^5d@,h5Ye@4333n54333d@44333d@hffff4d@4d@hfff4d@4333Ss4d@4333i4d@4333k44333wd@@s4d@@z45d@4Dd@ٕ4d@hfff4d@4333s44333d@4d@ )5d@43333+5hfffd@hfff5Hd@hfff54333Sd@L4 d@,44333d@4333s4d@43334]d@ 4pd@l4d@`44333d@l44333d@Y4̈d@hfff4dd@94d@,44333d@hfff&5d@hfffF5d@ )54333cI@ȞQ@hfff)GwcoKQ@hfffHPQ@hfffƎHTQ@HQ@hfffF4@\BQ@hfff4@ffffrDQ@hfff4@ffffDQ@83335@BQ@5@|CQ@ 5@,EQ@y 5@KQ@5@MQ@$5@3333OQ@LD5@QQ@8333v5@ffffQQ@5@ffffQQ@,5@3333SQQ@5@3333IQ@L5@BQ@hffff6@?Q@hfffL6@ffff6Q@hfffb6@1Q@83333i6@ffff.Q@,6@.Q@6@,Q@Y7@(+Q@8333$7@ )Q@8333R7@̈)Q@hffffv7@ffff^+Q@7@-Q@hfff7@0Q@7@3Q@8333S7@3Q@8333s'8@ffff0Q@U8@-Q@8333}8@3333,Q@hfff8@)Q@l8@&Q@8@%Q@@9@3333(Q@@,9@ffff0Q@hfff?9@̐4Q@l[9@ffff27Q@{9@\8Q@hfffF9@33338Q@̌9@3333:Q@83339@ffff^?Q@hfff9@3333DQ@hfff9@NQ@hffff9@3333RQ@hfff9@tWQ@hfff&9@eQ@8333:@iQ@̌:@ffffBlQ@':@mQ@hfffN:@3333 rQ@:@zQ@8333:@H{Q@:@3333{Q@,:@fffff{Q@8333;@ffffyQ@hfff ;@zQ@hfff4;@zQ@Y;@q}Q@y;@Q@8333s;@ffff&Q@8333;@ffffQ@ <@0~Q@hfffD<@wQ@hffffi<@tQ@hfff<@nQ@@$=@jQ@YU=@E^Q@hfff&==@ffff6YQ@1=@xWQ@`=@ffffnRQ@hfff<@ffffRKQ@hfff&<@GQ@8333S<@CQ@@<@hAQ@ <@ffff@Q@83333<@=Q@hfff<@h;Q@j<@9Q@t<@33337Q@<@d7Q@̬<@6Q@<@33335Q@8333<@4Q@hfff<@3333_1Q@8333z<@h"Q@x<@AQ@hffff<@|Q@hffff<@% Q@ =@̌Q@hfffX=@Q@83333=@ffffvP@8333S=@AP@̬=@P@8333=@P@8333=@ P@hfff&=@ffffJP@=@ffffP@@c=@P@L>=@ffff.P@hfffF=@$P@̬=@̈P@8333=@ffffP@8333=@YP@8333K=@3333P@hfff_=@}P@v=@3333P@Y=@$P@9=@ffff֖P@=@P@=@P@8333=@TP@hfffF=@ԅP@hfff=@xP@hffff>@ffffVrP@L>@3333{nP@hffff>@̠kP@l>@jP@8333=@xjP@8333S=@hP@hfffF=@gP@hfff=@fffffdP@`=@L^P@=@̐UP@=@3333PP@hfff=@ffffOP@hfffƜ=@ffffOP@83333=@TNP@=@ffffMP@=@KP@8333=@HIP@8333=@FP@8333S=@$EP@Y=@3333BP@8333ә=@ @P@̬=@ffff=P@83333=@ffffZ:P@=@ 6P@=@y3P@hfff>@ffff0P@9>@ffff.P@L >@ ,P@>@A)P@L=@#P@8333=@!P@ >@`P@̬>@ffffnP@d>@3333P@hfff|>@3333#P@hfff>@ P@hfff&>@ P@̬>@ffffP@>@QP@8333Sj>@HO@83335>@3333O@ >@O@8333=@O@,>@1O@hfff&k>@̄O@>@pO@̌>@3333{O@L.?@O@Y??@)O@83333V?@ffffO@o?@O@`?@HzO@Y?@uO@8333?@TqO@8333o?@XcO@hfffa?@XO@ I?@ffffHO@/?@ffff=O@̌>@q)O@̐>@TO@z>@3333O@8333sN>@N@̌>@N@hfff=@N@̬=@ffffN@8333S=@)N@ ~=@ܸN@l@=@ffff֤N@83333<@3333N@83333<@̄N@8333<@\N@8333s<@zN@t<@ffffuN@Lh<@ffffrN@hfff&<@x_N@83333;@DN@;@4DN@Y;@ffff?N@l;@>N@`v;@;N@=;@3333DN@̌4;@EN@Y;@8CN@:@Y"N@hfff&9@3333;"N@ 9@ffff*N@Y9@&N@̬t9@p!N@8333D9@N@hfff'9@N@hfff&8@(N@hfffF8@DN@8@N@8@N@8333r8@N@8333W8@3333kN@8333s8@,N@hfffƸ7@3333M@7@M@̬v7@O@I6@HO@hfffF>6@ffffO@8333E6@ffff6O@8333X6@O@hfffP6@|O@8333Q6@O@hfffe6@ffff޾O@83336@P@hffff_9@3333@P@\9@3333+DP@W9@PFP@A9@3333+IP@@L9@̐OP@8333N9@3333VP@ Y9@^P@hfff=9@ffffbP@8@3333CjP@hfff8@ffffjP@hfffƬ8@jP@8@tpP@̌8@ffff:uP@hfffƠ8@vP@8333s8@3333vP@Y8@tP@g8@3333qP@<8@sP@'8@sP@hfff5@+N@hfff5@*N@83335@0N@@5@3333[3N@83335@33334N@5@9N@hfff5@ffff&N@L5@i=N@̌>5@3333SCN@65@3333KMN@hfff95@pON@D5@3333QN@ M5@3333;LN@ls5@CN@L5@N@̬5@ffff N@5@3333N@l5@ffffN@hfff5@3333sN@hfffF5@N@L5@N@٠5@ N@hffff5@ N@l|5@3333;N@5@N@hffff5@ffffN@8333S5@N@5@N@٠5@ N@hfff&8@l?P@8@L=P@ 8@̠>P@8@ffffBP@83338@DP@98@EP@y8@ffffCP@`8@ffffzBP@L8@ffffAP@hfff&8@l?P@ f43335f@83333(9gryf@hfff&+0${f@9M04333gyf@^0wf@@r0sf@0 rf@ 0hfff.rf@Y0hfffNvf@hfffơ0zf@0Q|f@0}f@0hfff}f@90|f@hffff04333{|f@0}f@43330Dzf@hfff04333vf@Y0rf@y0nf@Y04333kmf@y0lf@0hfffkf@ 0Xjf@4333ӷ0if@ٵ0yff@4333s0hfffaf@hfffF08`f@4333s0i^f@l04333G\f@43330Yf@0̜Vf@hfff0HUf@hfff04333kTf@0QSf@433304333Of@43330pPf@0XQf@4333S04333+Rf@43330̬Rf@433330LTf@hfff0hfffUf@hffff04333Wf@Y04333Yf@hfff0[f@@0̼^f@{0bf@p00gf@g0dif@ f0hfff~kf@@a04of@LK0qf@?0Ttf@hfff&90vf@hfff&50hfff>yf@433380${f@60f@hfff&'0f@hfff&+04333Hf@9_14333Hf@̌j14333If@4333so1Jf@@p1hfff&Mf@hfff1hfffPf@hfff1hfffRf@hfffƦ1Sf@43331eRf@4333ӿ1hfffRSf@1Sf@1]Uf@43332Sf@hfff24333Of@2Nf@4333#2̌Mf@2Jf@"2Gf@/2 Ef@ @2 Bf@@24333>f@C24333;f@@A2hfff8f@4333382]4f@Y.2hfff.f@4333%24333C,f@hfff2H*f@2hfffn(f@1((f@91hfffr(f@ 14333*f@1hfff+f@1+f@91X,f@hfff&1hfff&-f@433314333-f@1hfff,f@1hfff,f@43331$0f@ 1hfff3f@hfffv1,:f@4333sc1hfff>f@hfff&e1Df@V1Ff@ P1Gf@@T14333Hf@9_1ffff2f0fhfff0fhffff0f0fhfff0f0ffff|fL03333{f433330ffffPzf0{f̬0ffff2f0f@̌0̠}f@43331|f@0hfff}f@@0f@hfff&0f@0f@̌0̜Of@`24333Of@`3|Kf@̬ 3Jf@343337If@433334333Ff@hfff3 Ff@3Ef@30Ef@3hfff@f@4333&3>f@ 3hfff@f@3Af@hffff3TCf@433334333Ef@hfff&34333Ff@92If@2hfffJf@924333sMf@hffff2̜Of@`2ffff_fhfff1̖`fhfff13333Aafhfff1 bf13333bf43331af1_fhfff1ffff_fhfff1aXf;2Xf@2yZf82"[f32NYf4333/23333kXf12aXf;23333 Hfhfff1If1ffffnKf1iJf433331ffffHf1%Hf433313333 Hfhfff1^fE13333k_fN1 `fK17_f<1ffff_f4333s61ffffz`f4333.1̐`fL)13333)`f%1}^f.1z]fY51ffffF]f91]fhfff?1^fE1Qf*3{Qf,3\Rf9*3Sf&3ffff(Sf#3Rfl3ffff*Rf3ffffQf3Rfhffff3pRf 3^Rfhfff$3Qf4333s'3LQf43333(3Qf*3ffffyf2yfhfffF2yf23333zf2zf433332ffff{fhfff2'{fhfff23333={f3ffff{f̬23333{fy2{f43332f{fy2ffffzf2ffffyf2hfff~'f@hfff%1%f@4333)1&f@43331'f@433331=(f@ 1hfff2)f@4333s 14333(f@1hfff~'f@hfff%1mf@hfff]1hfffrlf@4333d1kf@4333A14333 mf@A1mf@hfffE14333Onf@hffffN1mf@hfff]1-kf@433332jf@hfffF2hf@433324hf@1hfffhf@1hfffif@̬1jf@4333S1̘kf@43332-kf@4333324333{Zf@1Xf@,1Wf@̌10Yf@ٟ1Zf@l1H[f@hffff14333{Zf@1}f0f@0fhfff&}0ffff2~fq0ffff|fyn0̬}fhfffz0}f0̘~f43333&0f4333+0f4333'0fhfff&'03333fhfffF 0:~fhfffF 0̘~f43333&0f@@04333f@̌0hffff@̬0f@hfff&}0f@@04333#f@)4333"f@)hfff f@)43333 f@8333s( f@()"f@83333(4333#f@8333($f@Y(4333#f@)hfff&e@5hfffe@43335e@̳5hfffe@5Ue@5hfffe@ 5hfff&e@5Vf43334ffffVfhfff4Vf4#Wf43334TWf4`Wf 4HWf,4/WfL4Wf4Vfhfff4Vf43334 @@ @hfff6G@`-@.YA@@PA@L @ A@`fff&S@|A@L@hfffA@@hfff}A@`fffn@zA@`fff&.@rA@`fff@hfffFkA@Y3@hfff_A@E@hfffZA@`fff&@4333QA@@ HA@̌@>A@0333@#A@`fff@hfffA@V@9A@`fff&@A@0@̜A@x@,@@@4333@@ @4333C@@@@@@hfff@@@hfff6@@@@@`fff @hfffV@@K@@@`ffffy@@@@̜@@Y@Y@@ @hfff&@@̌ @@@0333 @@@ @hffff@@@ @@@`fff @@@y @|@@ @hfff@@0333 @hfffA@0333 @P A@,!@ A@*!@hfff A@LZ!@ A@0333!@hfff A@ "@4333 A@o"@ A@̌"@ A@L"@hfff& A@`fff#@hffffA@u#@\A@0333#@hfffA@L#@P%A@?$@hfff'A@a$@L(A@̀$@I#A@`ffff%@hfff,A@9Q%@97A@`%@hfffAA@̌%@43333IA@`fff%@hfffMA@`fff%@hffffVA@ %@bA@ ~%@yhA@0333%@pA@%@9wA@`fffƺ%@4333cvA@%@ |A@0333R&@zA@0333&@4333A@&@4333A@='@hfffA@ '@`A@0333'@PA@'@hfffA@`fffO(@̌A@`fff(@LA@)@A@Y?)@4333A@0333sR)@ A@`fff^)@iA@i)@4333 B@0333s)@hfffB@)@4333SB@0333S)@̌B@)@B@`fff/*@)B@̊*@4333#B@*@hfffF'B@hfff*@4333S,B@0333s +@2B@̌@+@99B@ +@43338B@0333+@CB@,@lEB@03333,@VB@y,@gB@L,@ixB@hfff,@4333#B@@,@ B@,@B@,@B@hfff,@4333B@Y,@B@0333S,@hfffFB@0333,@B@0333P,@B@hfffI,@B@0333SL,@B@hfff&,@̬B@,@B@j-@,B@`-@4333B@-@4333SC@hffffy-@4333C@g-@,C@\-@C@̌[-@YC@L-@@0C@,@97C@0333s,@@C@L,@gC@0333,@4333sC@y,-@ C@hfffA-@C@hfffA-@hfffVC@)-@LC@03333-@YC@0333s,@4333C@,@C@0333-@4333C@-@lC@9-@hfffVC@,@C@,@4333C@,@4333D@0333,@D@,@YD@,@43333-D@,@ CD@Ls,@bD@I,@hD@,9,@4333#xD@Y+@D@hfffx+@4333sD@hfff*@D@`*@D@,^*@hfffD@@ *@D@)@hfffE@`fff&)@0E@)@E@R)@%E@0333#)@4333s0E@(@4333#E@`fff(@hfffE@̬D(@yD@ '@̌D@9'@hffffD@0333r'@hfffvD@@_'@D@-'@D@`ffff&@D@`fff&`&@,D@%@4333D@`%@̌D@%@̬E@%@hfffFE@0333%@p'E@̬&@;E@&@4333cGE@Y)&@hfffSE@(&@^E@0333&@9dE@&@ lE@0333%@vE@`fff%@sE@`fff%@4333snE@0333s%@hfffgE@`fff&%@̬aE@`fff%@lTE@`fff&>%@hfffTE@033333%@UE@"%@4333\E@`fff$@PdE@@$@hE@`fffƃ$@kE@g$@tE@H$@4333E@0333s$@4333ӈE@9#@@E@̌#@hfffE@0333S#@̦E@7#@yE@`fff"@4333ýE@L"@`E@0333s"@lE@"@4333E@03333M"@E@`fff"@F@!@43333'F@@!@hfffPF@y!@`rF@f!@ F@.!@F@L @F@ @4333%G@Lx @hfffRG@< @4333uG@` @hfff6}G@@ G@@G@@hfff6G@@hfffG@̌ @hfffG@@@4333sG@@P|G@`fff@UG@0333@4333#6G@03333@YG@L@̬F@`fff&@F@L@ F@Y@F@|@4333cxF@`fff@tF@@|QF@@L/F@̌@F@@4333E@Y@E@@4333#E@L@E@k@hfffE@\@E@`ffff@hfffE@0333@ E@@@)wE@@hfffrE@q@hfffmE@L@4333SeE@+@hfffv-E@Y@<E@@hfffE@@@)D@ @hfff&D@`ffff@lD@@D@̴@̬D@̑@4333ӨD@`ffff@hfffFD@`ffff@D@ 3333@)D@@D@:@4333oD@`fff@4333aD@@̬CD@`fff@4333s(D@0333T@D@`ffff@C@@)C@ 333@)C@`ffff @C@`fff @IC@ @ܜC@ @lC@ @{C@ 3333* @Y`C@x @4333MC@ @9C@ 333 @hfffC@ 333 @hfff C@0 @4333B@L @hfffB@@B@ 3333@hfffB@q@ɓB@`fff@sB@Y@4333lB@@liB@0333s@FB@@"B@`ffff@| B@@B@Y@hfffFA@`fff@̼A@0333z@)@hfffnE@>)@4333iE@#)@!@̣ @F!@Y @ Z!@ 3333 @@333x!@@L&@`fffV@&@@ffff?̌&@?pfff&&@3333t?̪&@?Y&@?@333&@?pfffB&@?%@3333?pfff,%@?$@ ?[$@?$@@ffff?pfff#@3333?@333#@?@#@3333?#@3333?#@?̓#@3333i?pffff#@2?h#@G?YZ#@2?@333E#@3333?.#@?pfff2#@? #@3333?"@3333?"@@ffff:?@"@? "@?pfff&+#@̤?pfffC#@@ffff ?K#@? p#@@ffff?@3333#@?@3333#@ 333@#@o@#@`fffa@pfff&#@ 33334@#@`ffff@#@̴@@333#@W@@3333$@W@pfff&%@LW@@333%@ 3333W@@333s1&@W@L&@`fffV@h3333džVS*@U,@J4WV,@UV,@3333JVy,@ffffGV̌,@CVhfff,@AV ,@3333@Vhffff,@ffff7VS,@$6V?,@/V%,@I-Vl,@*V0333,@ffffR%V0333,@ V9+@3333G V̬+@V +@V`+@ffffV0333+@$V03333+@Vhfff+@ffff Vhfff+@ffff&V0333+@ffffzV,+@lU`+@ffffU9+@XU̬+@U+@U+@UhfffL+@̌U )+@ffff U0333 +@iU0333+@3333UY*@3333+U*@U`*@Uhfff*@ffffU*@ffff2Uhfffr*@3333U\*@V`ffffV*@ VS*@ffffV0333Sm*@%Vhfff*@+V *@)V0333*@8%Vl}*@V0333d*@ V,^*@}7Vhfff*@QVhfff*@|aV̬+@xsVhfff+@~Vhfff]+@Vy+@3333džVhfff+@Vhffff+@V+@T|Vhfff+@ffffwVY,@uV03333,@rVhfff,@oVl',@3333mVYH,@ffffjV̌],@3333dVhfffs,@cVhfff{,@cV0333,@dV0333,@ffffdV,@bV,@ffff`V,@ffffZV,@3333XV0333,@4WV,@hfff8@5@oB@̬?@oB@)5@EB@4333#5@̌B@ 5@A@5@̌A@5@̌A@dfff5@̌sA@43335@̌IA@5@̌A@ 5@@@ 5@@@dfff5@@@43335@w@@5@4333M@@5@#@@5@hfff&?@43335@hfff&?@5@9o?@5@hffffw?@̬6@8333s|?@dfff%6@v?@dfff16@yf?@433336@hfff[?@I06@B?@dfff6@̌5?@5@?@5@>@43335@ T>@5@Y=@5@hfff=@5@.=@dfff5@8333<@5@hfff&k<@5@8333S <@5@̌;@dfff5@E;@5@8333:@5@hfff&:@5@Y :@43335@̌9@5@\9@5@83338@5@83338@l86@83338@q6@83338@dffff6@83338@43336@83338@`7@83338@W7@83338@\7@83338@7@83338@dfffV8@83338@4333=8@83338@Pw8@83338@̰8@83338@I8@83338@dfff#9@83338@4333C]9@83338@9@83338@<9@83338@ :@83338@ffff6C:@83338@2333|:@83338@0:@83338@̬:@83338@,);@83338@b;@83338@ffff&;@83338@2333;@83338@ <@83338@̜H<@83338@<@83338@ffff<@83338@2333<@83338@.=@8@L9=@hfff8@2333S`=@̬8@=@83338@ =@8@2333=@,8@̬!>@hfff8@y3>@8@ffff&@>@hfff8@ u>@L8@َ>@ 8@2333>@8333S8@>@83338@,>@hfff8@̬?@hfff&8@2?@L8@ffffU?@83338@pm?@9@ffff?@hfff9@23333?@̬9@|?@hfff&9@̬?@99@ffff?@a9@ffffF?@̬9@2333?@8333u:@?@hfff:@ix?@?;@̼`?@@;@2333s6?@;@ffff1?@y;@1?@8333;@?@̃<@ ?@8333<@2333S>@hfff<@2333S>@8333s=@̌>@8333(=@ffff>@hffffG=@>@8333m=@l>@8333s=@2333?@hfff=@<:?@hfff >@2333C?@hfff >@2333sA?@9>@ffff&B?@hfff&C>@Q?@8333O>@fffff[?@X>@g?@hfff&e>@ffff&u?@,>@ffffy?@l>@?@Y>@?@ >@j?@8333S>@2333cg?@hffff>@̜p?@8333s?@yv?@hfff?@?@L ?@p?@9?@2333s?@hfff1?@l?@@?@Pu?@hfffF?@̬t?@?@̼?@8333?@?@?@?@i@@PW?@̼ @@0X?@hffff?@2333{?@9?@i?@hffff?@ffffJ?@?@|=?@hfff@@2333s8?@hffff@@)'?@hfff @@2333?@p@@y?@4333$@@l3?@4333@@??@̬@@23333K?@4333 @@K?@i)@@̌A?@43333D@@?@9M@@?@W@@2333?@`m@@2333#?@hffffs@@fffff?@@@ +?@@@P ?@@@2333?@`@@ffff!?@P@@2333c!?@hfff@@2333S.?@A@M?@\A@ffffR?@43333A@2333J?@hffffA@2333S5?@ *A@>@4333S3A@>@hfff>A@ffff>@hfffFBA@2333>@CA@0r>@LTA@23331>@hfff^A@fffff=@4333CeA@ffff=@hfffVoA@\=@sA@23333z=@̜lA@n=@4333C^A@ffffFE=@OA@ffff<@hfff&9A@y[<@̬6A@2333C<@)3A@<@hfff(A@2333;@,A@;@hfffA@0;@P@@23333 <@ @@lA<@4333C@@c<@hfff@@ffffV<@ٙ@@<@4333@@<@@@p<@4333@@2333=@po@@ffffFI=@hfffg@@ffffff=@4333#b@@23333s=@Y\@@2333=@hfffR@@fffff=@iH@@ffffV=@̌<@@=@hfff>@@=@L4@@2333ӿ=@ .@@2333s=@2@@ffff=@4333SH@@ffffb=@̬L@@iR=@̬Q@@2333.=@P@@2333<@hfffVT@@<@id@@`<@,j@@<@4333m@@p<@r@@2333<@@@9q<@@@2333S5<@hfff@@2333 <@Y@@ffffv;@hfff@@;@hfff@@2333;@`@@|;@hfff&@@9n;@@@@2333SW;@̜@@ffffD;@hfff@@ffffV/;@P@@ ;@4333@@ffff&:@hfffVA@:@hfff&*A@<:@hfffVHA@9@4333VA@Iq9@hfff6mA@#9@٘A@4333y8@4333ӲA@E8@)A@'8@hfffA@dfff8@hfffVA@43337@hfffA@I7@4333A@L7@9A@7@4333A@dfff7@A@7@A@Iq7@TpffffeffffT̪3333T%T̠Tpffff3333CThTpfffWTffff T3333CT̔Tz T@3333Gffff^TL 3333T@33333333ThT@3333T@3333Tffffdl T@3333?x T T@3333MT@3333 T 3333Tffff< ffffT T@3333 ̴Tffff- T fffffT@3333 Te Tffff@ 3333Tffff fffffT 3333; T@3333 lT@33331 ̴T@3333 3333SC 3333S3333S@33337ffffSffffSffffS@3333ffffSWISffffS-Sffff*3333WScS?S?̨S@ffff?SL?ffffS3333?S3333I? S@ffff?,S3333?S?S@ffff?̼S@ffff.?S̼?Sffff?ffff^Sffff?3333uSi?lS?kS?3333iS(?|fSffff?aS!?3333^Sffff?ffff]Sffff^?ffff[S0?]YS5?3333RS?3333JSA?MGS?(@S?3333:S3333/?5Sffff?ffff"1Sffff?P/S ?.Sffffj?l+S)?&S?S2333#?XS?S3333s?tS3333??S3333?S?QS3333?XS?̬S ?dRffff?ffffNR2333S?̴Rٶ?ffffR?R̬4RhfffFlT̤ TTxT3333kT@3333T~PTffff3333S T3333+TY3333Sd-STffffffffTffffTfffflT0S@ffff ?̽S?xS?ffffS3333?ffffS?0S@ffff ?ffffnV̰ffffƘV3333ffffV3333V3333Vffff࿙=V߿܋V3333oῙUV忙Vffff0V3333;ffffnV̰3333ZV3333'XbVyffffdVfV3333;3333fV3333obVu3333^V3333c[V`TV3333lRV3333濙QV濙PV3333O3333RVffff&3333VV3333o3333ZV3333'3333CVgfff~ݿV4333޿ffffViܿaV4333ٿVgfffӿ3333cV4ҿ3333sV\п3333V4333Կ̘Vڿ3333CVgfff~ݿ!Vffffp̸Vx@V@3333ffffV@3333󿙙Vffff̄Vffff2DV@3333!Vffffp3333kV?qV 3333GV̌̿3333oVgfffڿ3333׼Vffff3333V3333k3333_V 4V3333忙-VV3333cVffffP3333VE𿙙VffffVffff̴V̌TV鿙aVffffBVffff㿙VVgfff߿V׿̠VaҿffffrV@3333333V33333Vhfff槿VLffff2V3333a?ffffV?lV? V2333?Vdffff?3333kV?3333V`տVP׿3333dzVտVgfff^ѿ̀VȿVĿ̸VLȿiVѿ3333V`տffffRdfff1@̴Q3@p,Qdfff 2@Qdfff642@3333/Q4333SE2@3333Q`W2@Q̌j2@3333/Q92@ffffR2@(Q@2@tQ92@Q@2@̐Q2@Q2@Q<2@TQdfff2@Q̬2@}Qdfff 3@ Qy!3@LQ)3@lQ)23@ffffQ,I3@4QS3@ffff>Qdfffl3@̈Q|3@yQ,3@3333Qٷ3@ Q03@0Q3@ffffQ@3@lQ3@ffffQdfff63@DQ3@Q3@Q 3@ffff>Qdfff3@Q3@ffff^Q4333#3@AQ43333@ffffQ43333@3333Q3@Qdfff3@ffffQp3@̀Q43333@hQdfffV3@HQ٢3@ffffQdfffF3@<}Q3@ yQ3@ffff6xQ)y3@3333tQ]3@ffffRoQL3@TQdfffS3@NQdfffE3@PQdfff93@TQy33@3333CaQdfffF63@fQ43@3333gQdfff)3@gQ)3@̈`Q̌3@LYQ 3@3333QQI 3@3333oJQI3@BQ`3@9Q 2@3333+Q2@Qdfff2@hQЫ2@̴Q̌2@ffffQ2@xQj2@̐Qdfffa2@$Q[2@ffff.'QdffffN2@ffff**Qdfff82@ffff+Qdfff72@$.Q72@ffff1Q D2@3333s4QV2@ffff;Q4333sh2@DQ43333f2@QQp2@hYQ̌k2@ffff>aQij2@3333CiQdfffo2@ffffRqQ̌q2@ffff^yQj2@,Qdfff_2@ Q|X2@QF2@Q4333s@2@3333Q72@0QD2@ffffBQ4333V2@̐QyX2@(QJ2@QE2@ffffzQdfff@2@3333CQp92@IQ 2@Q2@3333Q1@ffffQ43331@3333SQdffff1@Qdfff1@,Q1@3333kQ43331@ffffnQ 1@!Qdfff61@Q1@ffffQ@1@̘Qdffff2@,Qdfff 2@hffffN`t.@2333#Nhfff&D/@ ffffN.@ N`t.@ffff6N.@ffffN /@ffff&N4/@2333Nhfff&D/@ffffŇ+/@|N̬ /@2333#N .@ffffN.@D@%@4333sE@j)@8|E@`fff&@hffffE@@&@9E@c&@vE@`fff%@ lE@0333%@9dE@&@^E@0333&@hfffSE@(&@4333cGE@Y)&@;E@&@p'E@̬&@hfffFE@0333%@̬E@%@̌D@%@4333D@`%@,D@%@D@`fff&`&@D@`ffff&@D@-'@hfffvD@@_'@hffffD@0333r'@̌D@9'@yD@ '@hfffE@̬D(@4333#E@`fff(@4333s0E@(@L4E@ (@9E@ )@\=E@)@hfffUE@(@4333ZE@(@)@qE@>)@E@S)@E@j)@E@`fff&R)@9E@(@@E@(@4333sE@@a(@̬E@.(@E@0333 (@4333ӢE@`ffff'@hfff&E@y'@hfffFfE@0333z'@QE@`fff'@BE@0333$'@hfffEE@03333'@JE@Y&@̌SE@`fff'@hfffeE@'@̬tE@Y,'@yE@L-'@4333E@!'@|E@`fff&@F83333[4RaM@&`T@$3\gr~=ffff&T@03333333T@0333?̰T@ ?ffffvT@0@T@hfff6?T@?3333wT@0333b>3333T@̬=ffffT@,=3333T@hfff&<T@;T@hfff;LT@ $:,T@`fff933337T@\80T@`ffffx83333'T@0333s,83333'T@`ffff7T@0333c7ffffT@0333ӱ7lT@,h7T@`6T@p5٭T@5ffffT@ 5ffffT@I53333T@03335 T@0333s5ffffT@x63333T@97ȔT@73333_T@0333S=PT@0333=fffffT@,=ffffT@̜=ffff&}T@9=(|T@`<̼T@; T@0333 ;3333T@&9ffffT@0333Ӗ8xT@`fffK8lT@03337ffffzoT@03337yqT@d7tT@O7̨xT@?7|T@ .73333ST@̌7T@6T@96dT@`fffV5̄T@`fffV5eT@*53333~T@\!5ffff{T@033335wT@5ffffrT@`fff%5}lT@0333;5|fT@5\T@@5IVT@03335,RT@Pj6ffffHT@6DFT@̌73333O;T@`fffF273333;6T@0333#4733332T@0333#71T@ 6L5T@@67T@`6h:T@033363333KAT@l5ffff6CT@0333#s53333gKT@`fffv$5yNT@`fff4QT@4ST@`fff4ffffdT@0333C3hT@93ffffhT@)'3`T@٪2_T@t2ffff_T@,2]T@)1<\T@`fffv13333g[T@t1tYT@91[T@`fff(1\T@033303333bT@0hT@`fff[0̨nT@LD0@pT@`fff0qT@0333/ErT@l/YuT@.̐uT@yt.tT@`fff{,fffftT@0333h+rT@y)nT@l(ffffkT@b(3333iT@`fff'ffffdT@l'3333+`T@&ffff^T@&<]T@'3333#[T@0333sv(ffffST@`fff&(NT@@*ffffET@*pBT@̛+0AT@ e,@T@,3333?T@0333,ffffJ>T@0333,ffffr:T@`fffu,7T@z,ffffF5T@,33331T@0333-0T@0333sc.,.T@/)T@/)T@`fffQ0ffff)T@`fff0ffff$T@y0 T@m0T@/ffff^T@/IT@0333*0T@ }0 T@P0 T@1, T@01 T@0333s[1 T@ 1D T@)23333 T@L2@ T@l3T@̼43ffffT@m3ffff~T@ك33333sT@`fff33333C T@ 4 T@p&4T@24ffffS@l.4S@0333s#4ffffjS@4S@0333C3`S@3ffffS@03333XS@9d3S@`Z3S@H3̸S@`fffK3S@̬Z33333OS@9f3AS@0333cn33333{S@i33333SS@0333H3ffffS@033393S@`fff&33333S@`3ffffS@`fff3S@`fff23333S@03332ffffjS@03S@ C33333S@3)S@03333S@Y3ffffS@03333ffffbS@ 3LS@33333S@ 4S@,34$S@Le43333 S@`fff43333sS@<"53333'S@`fff6$53333S@̌43333#S@`fff4S@153333OS@̜B5S@O5ffff"S@0333e5S@`fff5ffffzS@`fff5pyS@`5rS@`fffƺ5XmS@033335iS@03333a5̤lS@0333!58vS@03334\zS@0333c43333yS@Q4ffff*wS@33333ksS@l3qS@̌}3ffffnS@d3ffffjkS@L33333gS@K3teS@w3ffff6dS@,33333dS@`fff3jS@|)4ffff&lS@pp4XjS@I4gS@v4̠\S@`;4WS@03333EUS@l3RS@)m3ffffOS@L33333;NS@!3NS@`fffF23333QS@2RS@Pq2PS@V23333MS@J2̀HS@M2ffff@S@`fffVV2:S@0333ce23333 7S@033321S@033320S@03332ffff"1S@`fff252S@0333#24S@`fff(3ffff5S@@37S@l3:S@y4];S@|4ffff:S@,48S@̼4ffff5S@\5ffff,S@5(,S@I5/S@l/6ffff2S@`fffU62S@`fff6.S@63333-S@L6+S@`fffq6(S@`6ffff.'S@|K6ffff~&S@033363333%S@5$S@03335ffffS@5S@|5fffffS@`fffj5S@y/5ffff&S@,4tS@`fff4S@`fffV4YS@`fffvo4S@G4S@`fff4S@`fff3̸S@,3R@3ffffnR@`fff3R@L33333{R@`fffV|3ffff"R@0333z3DR@Pv3R@0333sn3HR@`fffFf3̤R@]33333R@0333`3R@ m3R@3̈R@ 33333R@i3R@`fff33333R@4LR@24R@`fff&|4R@`fff43333 R@`fff5ffffR@?5R@h5%R@95R@l5̌R@̜;6R@`fff63333?R@03335@R@5,R@03335R@54R@0333u5ؿR@#53333cR@03335R@\4ffffR@033343333kR@p4ffffR@0333#4ffffR@4̔R@`fff4 R@03334ffff&R@ 53333ߪR@ 5ݩR@43333R@0333s43333R@ 4ffffR@`fffj4iR@643333;R@0333#3iR@3ffffR@̬3R@`ffffm3uR@yI3R@93R@=3̜R@`fffE3R@P3ffffR@^3-R@|w33333?R@p3ffffR@, 4R@`fffA4R@`fff;4R@033334ffffʈR@0333#!5R@5ffffvR@`fffv5ffffR@5ݖR@5R@0333c54R@̌5QR@5R@03335ffffR@\-6!R@0333SR6\R@`fffU6TR@`fffvC63333oR@033376ffffR@`fff26ffff*R@0333S86R@0333cJ6R@`fff6T6ffff҅R@0333U63333R@0333CE6R@0333"6dR@5$~R@\L5̘}R@5=|R@`fff^4IvR@`fffV4utR@r43333iR@y43333_R@43333]R@lS59]R@I5̠[R@0333s53333VR@`/6EQR@X63333;QR@6(VR@0333;7tYR@`fff7ffffbR@`(8pR@0333W8kR@`fffs89hR@8fR@`8fffffR@8gR@83333iR@9nR@Y9fffftR@0333s9̀vR@9uR@lm9rR@G9UoR@̬8!eR@@8bR@8̸`R@93333_R@̌O9[R@9s9YR@Y9RR@|9QR@0333:1PR@`fff&+:PR@ h:3333TR@hfff:HVR@ :ffffJXR@9E;[R@\+;ffffWR@hfff:3333QR@hfff:3333OR@Y:LLR@hfff:JR@0333:JR@hfff;3333sKR@C;3333KKR@x;ffff:JR@hfffƏ;HR@hfffV;4GR@{;̰ER@i;TDR@Y;3333WDR@̜0;yHR@;HR@0333:GR@n:JR@`fff3:]LR@\:̸LR@`fff&f9ffffQR@D9ffff*WR@9`YR@0333S8[R@`fff!833333ZR@0333#7}YR@7ffffFTR@̬t7̔PR@|>7ffff^LR@63333JR@06`ER@@s6?R@163333=R@L 6:R@03336!.R@63333(R@`fff&6̌R@̼G6R@@=6R@K6ffffR@\6 R@03336TR@@57ffffR@03337 R@`fff7R@̬83333R@[8+R@`fff8:R@`fffF8hBR@83333BR@03338ffff@R@+9̼>R@A9$;R@`9333336R@:2R@̬4:ffff2R@Y:-R@z:ffff^+R@`d:3333+R@5:p,R@̌:4.R@ 93R@[933333R@<95R@88R@`fff68ffff9R@88R@0333c87R@`ffff8H%R@`8h R@@83333KR@`fff 9R@`fff&49ffff&R@,94R@83333R@`fff8R@`fff8R@j8IR@`fff>8R@`fff67 R@L7ffffR@yJ73333/R@̬6ffffQ@`fffV63333Q@6hQ@033336|Q@`fff^6DQ@`fffC6ffff>Q@̬5̨Q@i6Q@O6!Q@ w6Q@0333Ӏ63333Q@0333}6ffff:Q@z6ffffQ@`fffj6ffffQ@`fffY63333Q@̌L63333Q@;6Q@i+6ffffQ@ 5ffffQ@03335̜Q@̬5̘Q@0333ӫ5ffff.Q@̌5Q@`fff5Q@̬5ͶQ@ 53333Q@5ffffʥQ@̅5Q@0333#5Q@5aQ@̼633333Q@`fffVb6Q@pb63333נQ@\f6Q@f6)Q@l6Q@o6ffff Q@̬63333Q@`fff6Q@`fff6,Q@03336ffffQ@а6Q@L6ٜQ@07QQ@S7ܜQ@03337Q@̬7̐Q@`!8̠Q@:8Q@`fffD83333Q@0333`8ffff^Q@8ffffNQ@83333OQ@̌93333_Q@`fffFA93333SQ@ r9(Q@`fff9Q@9ffffQ@ 6:Q@0333C:UQ@;3333[Q@0333S;Q@̌);ffffQ@hffff;3333Q@: Q@hfffs:Q@`fff:Q@̼93333Q@9(Q@ 9ffffQ@`fff93333Q@03339Q@̜:Q@0333S(:8Q@0333s:3333Q@ɷ:ԼQ@<;yQ@U;ffffQ@0333S;̔Q@;Q@MQ@?=3333Q@m=Q@̬=Q@hfffV=Q@=3333Q@hfff >3333gQ@ 2> Q@pQ>3333_ Q@0333S>3333Q@<>eQ@ >d Q@Y>Q@>Q@0333>Q@ +?Q@0333ck?8Q@0333?Q@@ffffQ@)@Q@dfff&(@ffffQ@4333"@ffffQ@@ffffQ@dfff@3333wQ@4333@ffffQ@$$@ffffjQ@4333c-@hQ@.@ffff Q@@3333Q@dfff@3333 Q@@ffffnP@,#@P@L/@3333P@p9@P@u@P@<@xP@؍@ P@@P@̔@ffffP@@UP@@P@@ P@@@3333P@dfff@\P@̔@P@@ffff&P@@ffffNP@4333 AuP@`AP@4333k"AP@$(A̰P@ 6ATP@~P@C3333yP@dfff2C3333~P@4333BCffffP@8CzP@C3333uP@dfffCsP@ČmP@QCgP@4333cCgP@CeP@C̘cP@dfff6DcP@̄DpaP@dfffCWP@C3333UP@dfffClRP@CPPP@CIP@dfffDFP@dffff D CP@4333sUDFP@dfffpD3333?EP@dfffΊDtFP@YD3333CBP@̌D4?P@dfff{D33337P@dfff&jDffff28P@dfffSD̔:P@4333BD4P@4333c7D+P@4333#D$&P@DffffR"P@4333SD3333P@̤#D P@4333#=D3333 P@iYDffffP@WDP@dD1P@dfff~Dffff P@)DffffP@D3333P@dfff^DP@dffffDffffZ P@D3333P@{Dffff P@iD3333g P@4333ODffffnP@SDO@GD̔O@4333sFDO@bDffff&O@9cDffffNO@4333tDO@E3333CN@E3333CM@tEffffM@dfff6EM@dEffffM@EHM@ EaM@F|M@dfff~ FYM@aF`M@4333FYM@l"F3333KM@dffff*F3333kM@1FM@43334FM@4333 :FN@3FN@̜F3333N@4333FHN@F3333#N@dfff,Fffff6N@DFffffN@NF!N@dfffgF3333cN@4333FN@aF%N@4333F̼/N@4333F0N@FffffF5N@4333|Fffff:N@@mFffffDN@_FSN@`FUN@dfffF3333@N@4333CFffff.:N@̴F33338N@F;N@dfffFiBN@F3333[EN@F3333+JN@dfffF3333LN@GNN@4333+GdcN@4333cG3333c|N@̄F3333N@F N@F0N@4333cFN@̜FPN@4333FN@dfff6FN@GdN@%G܂N@̌JG${N@[GsN@ gGffffnN@dfffoGhN@dffff}GiN@4333GgN@G4dN@4333SGqfN@yG3333kN@dfffGylN@dfffGffffiN@4333GjN@G3333kfN@dfffnG`]N@G\N@Hi\N@4333 H_N@$HffffvbN@HffffFgN@4333CHffffmN@dfffGffffyN@GffffN@GN@̴HffffN@4333HN@dfffv1H3333N@dffff0HN@d6HN@dfff6HN@dfffV?H3333ÜN@iGH3333N@pLH3333N@dfffvH3333N@t{HffffN@\~HN@LHffffN@4H3333;N@H3333N@4333sHN@H3333N@4333H3333N@dfff֧HN@H3333N@4333sHTN@̬HN@ H$N@̜H(N@H3333O@4333H O@4333jH33333 O@4333 H O@4333kHiO@Hffff O@4333H3333O@̜HffffNO@HN@dfffH3333+O@yH O@xHPO@HO@dfffH"O@,H̬$O@H)O@I.O@dfffI4O@$I̬;O@(IIffff^ P@4333?IP@:I3333P@7IP@=IffffzP@4333K\I3333KP@AI- P@`IP@IP@YIP@iI5P@dfffIffffP@LI3333 P@4333I P@4333SIP@dfffI̤P@4333I#P@Į$P@ tI3333S$P@dfffjIffff#P@mIy'P@4333lIffffB)P@WI3333g+P@>I\,P@t-I3333+P@l"IX'P@@ITP@dfff&IP@Iy P@dfff I3333o%P@Iffff -P@dfff&I3333?0P@A&I1P@,BIffff1P@dfffRI̜6P@VI33338P@4WI\;P@gIQCP@XmI3333KGP@JyP@ J٠P@2333J]P@ȷJѧP@JP@J,P@̬Jffff>P@ffffJffffP@23333MJ3333P@2333>JhP@97JP@̄1JdP@7JqP@GJffff.P@fffftJffff P@ J3333׺P@J̤P@ȸJ-P@ffffJffffP@Jffff"P@4J̬P@JP@8J3333P@!JffffP@J̔P@ffffJpP@|JP@ffffNUJ3333P@AJ̸P@1Jffff&P@\IffffzP@ Iffff^P@̬IP@9I̼P@IZIP@dfffNIP@QIP@IdP@I3333P@4333IP@qI%P@4333|IP@dfff&I3333WP@,IIP@4333I8P@IP@ffffV JffffP@2333#,JP@EJXP@,VJP@rJ|P@2333c}J3333P@2333JP@2333CJUP@2333J3333#P@HJP@JP@JP@2333JffffP@,JP@ffffJ|Q@fffffJL Q@ffff>Jffff Q@ffffqJ3333 Q@7JffffR Q@|JQ@dfffIQ@dffffIQ@YIQ@dfffnImQ@aI3333' Q@I3333 Q@dI Q@IffffzQ@IQ@dfffI3333Q@dfffIQ@IQ@aI3333/Q@0I3333Q@dfffμIffffbQ@4333IyQ@IQ@iJ!Q@2333s0J Q@dYJ̼Q@ffff_JQ@cJQ@J`Q@JQ@2333 JQ@0JQ@LJffffnQ@ J'Q@irJffffV*Q@2333cMJ\-Q@&J3333,Q@I#Q@4333Iffff:"Q@dfffFI#Q@IL&Q@4333I̠'Q@ yḬ+Q@4333{fI2Q@4333cgII4Q@dfffރI3333g0Q@dfffI3333[/Q@I3333[/Q@I3333MM̨R@ffff#Mffff6R@MmR@ffff0M3333+R@2333BMR@TMR@2333pMR@qMR@ffffMhR@M3333R@M\R@NffffR@2333oN8S@Nffff S@N̄ S@xN S@` OffffS@2333?O3333S@ffff_O3333#S@fffffiO̼S@ffffOlS@IOS@,OS@̜OS@O S@O3333_ S@3333PS@HPiS@ffffPAS@PtS@3333"Pffff2S@3333K,P3333 S@]:Pffff S@EPffff S@ TPffff^ S@̬WP3333[S@<]P3333OS@dP3333; S@3333kP S@DrP S@ xP@S@3333}PxS@PffffS@3333'P S@3333ϝPS@hP3333W S@S@ffffnlQ3333S?S@]Q6S@ffff>Q3S@=Q̘4S@Q33336S@Q33337S@Q`9S@\Q:S@Qt;S@ffffQ?S@ QAS@QffffDS@̌QffffGS@QQIS@8Qffff:KS@3333QhLS@jQNS@̜>QLS@ffff/Q̤SS@%QUS@̬Q3333KXS@3333PffffXS@P3333OWS@3333+PffffUS@PQS@3333×P SS@ffffP3333cVS@3333P(YS@єP3333]S@ P`S@̜P dS@̀P3333ggS@Q3333_S@EQ4^S@3333LQ̠]S@|VQ]S@3333~Q cS@QXeS@ffffQhS@3333_Q3333/lS@DQlS@ffffQffffmS@XQffffsS@33337Q5uS@3333SQuS@dQuS@DQ33333sS@3333QrS@3333Q̨rS@ffffbQffff tS@3333Q@uS@3333QffffxS@QffffyS@(R{S@% Rffff>}S@3333R3333cS@ffff%RtS@2RS@3333[4RpS@4%RܑS@ffff$RffffS@ +RuS@3333-R0S@̀+RffffS@=RٞS@QR3333GS@R`S@3333QS@QS@DQ S@QܨS@3333CQS@ffffQ3333+S@ffffQdS@ffffN~QűS@̔?QS@3333;QyS@!;QqS@@Q3333S@AQXS@5QS@!QlS@ffffRQffff6S@3333PXS@LP$S@P3333{S@̰PS@\PS@PffffS@ffff҄P̐S@}PxS@tPffffS@3333cPS@3333ZPffffS@3333kRPS@|GPffffS@P?Pffff*S@9PfffffS@5P3333S@̴2Pffff T@y(P̘T@ffffPffffT@3333w PffffZT@3333# P,T@ffffP̌T@(P T@3333"P3333T@ffff/P3333T@>P3333GT@33337NPT@ffffFYPT@3333kcPffffT@ffffsPffffT@~P3333T@PT@3333P3333#T@ffffPT@hPT@PT@3333 P3333 T@P8T@\PT@=PT@̼PffffnT@3333 P!T@ԗP3333c%T@3333P(T@ffff}P̈)T@3333CsP8*T@3333KiP+T@VPffff1T@ffffCPffff5T@3333g,P3333=T@ffff P@T@ffffO̜CT@iO3333CT@OBT@O3333@T@O8T@2333Offff8T@8O TLffffT@=ffff&T@ffff]Jffffv|Q@2JffffBwQ@JsQ@aJrQ@IoQ@IK`[Q@K[Q@ffffJffff[Q@2333CJ]Q@2333sJh_Q@2333;J3333g`Q@J̔bQ@2333J(bQ@23333J3333gcQ@ K0dQ@̜?KdQ@]K3333gQ@fKffffZhQ@nKjQ@ffffuKmQ@ffffkK̸yQ@dKffff|Q@UK}Q@y.K {Q@2333K)KH|Q@2333SK3333Q@ffffcK\Q@gKffffrQ@ffffVjKffffQ@LjK3333OQ@dhK3333Q@2333dKQ@\ZKdQ@/KffffNQ@KQ@J)Q@2333J$Q@,JQ@ffff]Jffffv|Q@I\cQ@ЕIaQ@ܙIaQ@4333IQcQ@dfffNI$kQ@`InQ@4333ӨIusQ@dfff֬I̴vQ@̼I}zQ@4333I%{Q@YxI(zQ@VIffffNvQ@TYI3333uQ@`I sQ@4333tImpQ@dfff{I3333jQ@4333+}IffffgQ@dfff6|IPeQ@I\cQ@J̜Q@|J1Q@2333J3333sQ@xJ̬Q@J,Q@ffffFJQ@QJ3333CQ@JQ@J3333Q@̔JQ@JQ@PJQ@J`Q@LJffffNQ@pJffffQ@J̜Q@)K2R@@KffffJ.R@K+R@ffffK`$R@ffffKffff$R@2333+K%R@K'R@K̀'R@ffff.K(R@K̼)R@`GHT@\G3333#T@GYT@٢G3333 T@4333dG3333T@3GLT@FffffT@puFT@_FT@`cF3333T@nFffffZT@̬n93333Q@e9ffff2Q@`fffd93333kQ@f9Q@k9ffffڲQ@w9ffffQ@Pa9eQ@`fffZ93333Q@X93333_Q@f9ũQ@03339TQ@L9̬Q@ :Q@`fff7:3333Q@F:Q@0333V:3333Q@̚:ffffjQ@0333;Q@hfff;ffffQ@0333;ffffQ@hfff @ffff~PK@@3333F.@3333SL@ *@!@3333#)@|K@@333s$)@̬K@pfff&)@K@)@|K@@333s(@K@pfff&(@ffff>K@pfff|(@K@n(@ffffK@(@ffffK@@3333(@\K@(@K@(@YK@ .(@K@̌!(@3333K@pffff%(@ffff}K@@#(@3333[tK@(@\hK@'@bK@Y{'@)uK@z'@y|K@@h'@3333K@d'@IK@N'@K@pfff&@3333K@L&@|K@ٞ&@3333SK@&@3333+K@pffffW&@K@pfff&a&@K@̌A&@3333sK@@3333=&@tK@@333=&@K@$&@̌K@&@|K@@3333%@3333[K@pffff&@K@pfffr&@K@ &@DK@&@3333SK@pffff&@̌K@L&@ K@ &@3333K@pffffA'@3333{K@Ld'@ffff6K@L]'@,K@a'@PK@@3333'@K@@333'@LK@@333s'@K@L'@3333kK@'@ffffK@'@̬K@Y'@K@'@K@L(@̬L@p(@0L@(@L@@(@̌ L@@3333 )@̬ L@L()@33333L@7)@9L@)@K@@333 )@K@@3333#)@|K@z#@3333iK@@3333s#@3333iK@̌R#@jK@L;#@ffff~mK@Y"@3333kK@"@4gK@̌"@lgK@pfff&_"@fffflK@L!@ffffrK@pfff!@XsK@pffffW!@sK@@3333W!@3333sK@pfffR!@33333~K@F!@ԅK@Y%!@0K@@333V!@K@YM!@ffffK@Y;!@K@̰ @QK@pfffC @ffffK@\ @YK@g @ffffK@@3333> @L@B @)L@@333S @ffffML@pfffv @OL@ @NL@@ @`HL@!@GL@7!@3333AL@pfffW!@q?L@pfffo!@3333EL@pfffx!@PPL@@333!@ffff^L@@3333!@,cL@Y""@̜eL@G"@ffff`L@̌d"@YL@Yk"@ygL@"@L@̌8"@ffffL@L!@L@̌!@qL@@!@ffff\L@4!@ffffZL@ @UL@ @ffff&[L@Y @3333`L@Y @\hL@@333s @mL@pfff @~L@@333L@!@ffffL@̌!@ffffFL@"@L@"@L@"@PL@#@L@Y#@%@ffffL@@333%@̤L@$@Y#L@Y$@33333 L@@3333$@@L@ t$@L@@333]$@ffffK@Q$@IK@@3336$@ffffK@pfff$@3333#K@@333#@K@̌#@3333K@ $@ffffvK@#@ffff&K@L#@K@pfff#@3333SK@pfff#@K@pfffR#@3333[K@pfff.#@!K@L@#@K@G#@K@̌W#@K@YI#@4K@@333s#@K@L"@K@ %#@0K@@333sJ#@3333K@Y`#@K@@333v#@{K@i#@3333vK@z#@3333iK@LJ%@ffffK@pfff_%@`K@pfffy%@!K@@333s%@33333K@%@K@pfff%@K@ %@3333K@pffff?%@ffffK@@333$@ffff>K@Y$@@K@@#@3333K@L#@LK@@3333#@LK@̷#@K@pfff#@3333K@ #@̄K@$@0K@ $@3333K@$@K@%@ffffnK@>%@qK@LJ%@ffffK@ &@!rK@pfff'@0jK@@333P'@̤jK@pfffz'@YgK@'@3333CbK@pfff&'@VK@Y\'@̬SK@,'@3333TK@@3333&@ffff~PK@@3333&@bK@Y&@YrK@&@dxK@Y&@yK@ &@!rK@w%@`K@pfff&a%@ffff^_K@LB%@̼iK@L>%@3333lK@̌b%@ffffsK@z%@3333#{K@pfff%@ffffK@%@4K@@333%@ffffK@@333s%@3333K@̇%@3333[fK@w%@`K@@3333)@ffff{K@pfff)@ffffyK@ (@{K@@333s^(@I@\*@XAI@@333y*@3333II@*@II@@333*@ KI@*@3333CNI@̿*@̔OI@pffff*@ffffMI@L*@LI@@333*@NI@ +@ffffXI@ +@1ZI@g+@ffff[I@ +@qaI@@3333+@3333fI@pffff1,@PiI@Lg,@!I@,0@0,I@0@ffff5I@L0@6I@83330@3333C5I@hfff&1@l0I@Lj1@̜ I@Yv1@̜ I@1@!I@1@a$I@hfffƳ1@Q'I@Y1@9&I@hfffF1@I@83331@ffffI@1@(I@hfff1@3333I@hfff1@ffffI@Y1@ffff I@ 1@DI@̬1@I@1@H@83331@3333sH@1@H@2@I@@2@3333I@̬ 2@ffffI@8333s2@ffffI@hffff2@3333H@̌42@|H@,D2@3333H@hfff&N2@H@83333Y2@H@hfff&2@H@2@ffffH@2@H@2@H@92@H@83332@ffffH@L2@3333#H@ 2@aH@x9[@@3333 A@,GA@ffffA@,4333A@YA@̜@@DA@@@A@hfff@@3333A@@@A@i@@3333+A@4333@@ffffA@hfff@@ffffƄA@4333s@@IA@hfff@@A@I@@3333A@hfff@@3333 A@`@@A@\@@3333A@L@@ A@ @@3333ӔA@̬@@A@ɟ@@ffffA@4333s@@)A@@@ffffA@43333~@@ffffA@4333u@@ffff>A@Io@@qA@\d@@юA@0\@@3333A@9[@@A@b@@lA@p@@A@4333v@@A@hfffx@@A@̏@@٭A@hffff@@ffffA@@@ffffA@hfff@@TA@ A@3333A@4333A@A@"A@A@4A@̌A@,GA@ffffA@I;A@A@4333@@aA@hfff6@@A@43333@@A@4333A@YA@hfff&@@HA@lA@aA@89[@@A@0\@@3333A@\d@@юA@Io@@qA@4333u@@ffff>A@43333~@@ffffA@@@ffffA@4333s@@)A@ɟ@@ffffA@̬@@A@ @@3333ӔA@L@@ A@\@@3333A@`@@A@hfff@@3333 A@I@@3333A@hfff@@A@4333s@@IA@hfff@@ffffƄA@4333@@ffffA@i@@3333+A@@@A@hfff@@3333A@@@A@̜@@DA@4333A@YA@hfffA@ԅA@lA@3333~A@@@Y|A@hfffF@@3333{A@hfff&@@3333|A@hfff@@$|A@@@9gA@@@`A@hfff@@ffff[A@@@YYA@Ɏ@@YA@@@`VA@0@@ffffQA@@@LA@4333@@HA@̌x@@ffffIA@hfffu@@XQA@o@@TA@4333`@@3333RA@4333X@@ffffSA@hfff@@@fffffZA@y9@@ffff^]A@hfff4@@ffffcA@(@@ffffzA@hfff&@@ffffA@ 2@@`A@<@@̄A@)G@@A@S@@aA@9[@@A@ 8U3@R07@1)̘uT̼)7@dT43337@EWT43333!7@ffffPTdfff&(7@ffffbQT 7@ffffnKTdfffF7@AIT7@}@T7@)T4333c7@ffffB'Tp7@3333;#T@7@dT6@ffffZT43336@TY6@ffff T 6@T<6@3333oS|6@3333S6@3333S43336@ffffrS43336@ffffNS96@ffff&S6@33337Sdfff6@ffffSr6@̤SYh6@ffffSLc6@̸S`e6@xS4333d6@S ^6@S[6@3333S]6@(S43336@~S43335@\wŠ5@hS 5@3333bSL5@_S5@3333k`S5@dSI5@ffffReSdfff5@3333_S4333#5@USY5@3333+SSdfffV5@ffff6NS4333#5@9IS4333ä5@KS5@ffffOS5@3333oWSdfff֜5@@QS43335@3333/PSdfff{5@ffffNMSdfffz5@IS43335@PFSɖ5@e;Su5@ffff5SdfffFf5@33337S4333c]5@7SdfffT5@0Sdfff\5@x.S[5@,Sdfff&W5@3333o)SdfffH5@3333O#SE5@!S F5@3333Sdfff6:5@ffffS)"5@R@5@DRl5@3333R43335@!R43334@Ř4@mR4@9Rp4@`R4@ffffR4@0Rdfffv4@3333_R4@3333#Rdfffƻ4@3333Rdfffv4@R̜4@ffffR4@lR433334@|R4@ffffڮR̼4@eR4@3333נR4333sb4@RT4@uR@Q4@RS4@R̼O4@RJ4@R`;4@ffff։Rdfff&+4@ffffR4@ffff.Rdffff4@`RI4@R43334@3333gRdfff4@ R93@4Rdfff3@3333sR43333@Rdfff3@ffffR433333@R4333#4@XR3@3333 R4333s3@3333R43333@3333SR 3@Rdfff3@R3@$ S`3@ffff.Sdfff3@!S3@33331S3@8S3@3333?S3@̐MS3@̤]S43333@mS3@pcSdfff4@MSdfffL4@ISdfffX4@̤FS4333Sh4@ES4333s4@FS}4@LSY4@ffff&MS`4@NS̤4@ffff>VS 4@]S43334@3333eS4@3333vS4@S4333#4@ffffrS 4@ffffSp4@SP4@ S5@hS 5@ffffbSK5@ffffSi5@S5@ffffS̼5@3333S4333s5@Sdfff5@S 5@S̕5@ffffBS5@ffffTI5@ffffTdfffF5@ffffT43335@%T43336@T6@3333TP6@T4333C6@=T 6@HBTdfff6@QET43336@3333wGT\"6@ IT46@3333KTD6@LT433336@G@0@L5G@0@ffffn+G@0@x G@`1@G@L&1@ffffG@>1@ffff G@hfffO1@F@hfffh1@̼F@y1@|F@hffff1@ffffF@1@ffff&F@ٴ1@3333F@1@,F@1@F@8333C2@3333F@hffffJ2@F@[2@3333cF@8333o2@8F@2@F@̌2@F@2@(F@hfffƸ2@ffffF@@2@ffffF@y2@3333CF@hfff2@3333CF@̬2@,F@2@F@2@F@2@0F@2@F@2@F@hfff&2@lF@3@|F@8333s3@3333F@hfff3@HF@83333@F@833333@3333#F@83333@ F@E3@̔F@̌T3@PF@,Z3@iF@a3@̄F@hfffff3@33333F@hffff3@33333F@Yc3@$F@8333M3@iF@43@yF@ #3@ffffF@y!3@ffffvF@83333!3@3333kF@3@F@3@̤|F@83333@vF@3@3333tF@ 3@quF@8333s3@ffffuF@2@ffffsF@83333@AoF@2@ffffnF@ 2@ffffqF@83332@3333uF@2@ffff>yF@hfff2@ffff}F@2@dF@2@F@}2@F@hfffl2@ffffF@̌[2@ffffnF@8333H2@0F@72@3333F@ #2@HF@ 1@ffff&F@1@QF@1@3333F@83331@F@̬1@ffffFF@L1@F@ً1@F@̬1@hF@x1@F@R1@F@9B1@ԕF@51@F@ 1@F@,0@fffffF@8333s0@33333F@ه0@̼F@t0@̼F@8333s]0@xF@K0@!F@hfff&;0@hF@hfffF(0@ffff>F@@0@DF@pfff&/@3333F@/@̜F@L/@F@/@F@pfff/@ffffF@y/@ffffmF@pfff&y/@ffffbF@/@IWF@̌ 0@DF@y0@BF@Y!0@3333.@ffff F@̌^.@ffff"F@@333sv.@ffff"F@̌.@$F@L.@ffff%F@pfff&.@"F@@.@*F@pfff&.@ffff1F@@333s-@,MF@Y-@qZF@@-@̼hF@pfff&-@ffffV|F@̌-@ffff^F@C-@F@-@3333F@@333,@3333˫F@,@.@ F@@3333&.@̤F@@333!.@ffff.F@Lv.@F@ٞ-@}F@_-@QzF@@333A-@9F@9-@AF@-@F@,@3333#F@@3333,@F@ -@3333˒F@pffff$-@ĜF@̌B-@ɖF@g-@ffffF@@333sz-@aF@ٞ-@}F@@333-@$aF@-@[F@pffff-@`F@@[-@3333bF@R-@`fF@LX-@̄iF@̌a-@lF@pfff&-@3333#lF@ -@3333#iF@@333-@$aF@`.@*F@@S.@3333'F@pfff&2.@-F@.@ffffN2F@-@7F@Y-@0>F@@333-@EF@Y-@ffffUF@{-@3333CYF@̌-@SF@@333-@3333#OF@-@0NF@L.@aDF@9.@ffff7F@z.@3333,F@Ym.@|,F@`.@*F@pfff`.@E@@333g.@0E@@g.@E@@333L.@ffffE@̌E.@!E@Y-@F@pfff-@F@@333-@F@pfff`.@E@pfff&.@ffffE@.@3333#E@.@E@.@3333E@@.@`F@pfff&.@ffffE@pfff,@|TF@@333,@̄OF@,@UF@,@aF@@333,@@sF@pfff,@`xF@@3333,@ffffn}F@,@ffffF@Y,@3333F@,@ffffF@pffff,@ffffnF@,@\F@,@F@L,@0|F@@333,@AoF@pffff,@\F@ ,@XF@pfff,@|TF@1@pbE@hfff1@̤YE@X1@3333+eE@c1@9fE@8333n1@3333sfE@1@pbE@8333o2@̤GE@hfff&p2@BE@hfffz2@̔=E@y2@i7E@@U2@CE@ )2@(QE@hfff1@fE@1@(kE@B1@ffff{E@ 1@E@` 1@ffffFE@hfffF81@PE@@1@3333lE@hfff1@rE@1@ffff.uE@L1@|sE@`1@3333+lE@91@YgE@hffff 2@^E@2@dXE@8333M2@LE@X2@KE@8333o2@̤GE@ J`fff5!g@ r%@&`ffff@Z@ t@ @`ffff@`ffff03333S$@0333S$@L_$@A y$@ @$@$@?̬$@!`fff$@`fff,$@0333$@$@L`fff&$@`fffs̄$@ 333̌s$@`ffffk03333h$@ 333( J$@YI$@ 33330333O$@`ffff9Z$@ 333e$@̌0333$@`$@`fff&`fffF$@̬$@`fffU`fffƶ$@Lٶ$@`fff$@`ffff$@`fff&%@0333'%@D%@ٝP%@`fff&B@,%@ 3333Y%@`fffF%@L %%@`fff&L%@0333W%@ٝ`fff^%@`ffffvb%@`ffff r%@@0333o%@ 33331%@%@$@@0333$@@`fff&$@`fff& $@0333$@0333$@v$@x`g$@`ffff#c$@`fffflz$@@ٌ$@YL$@ 333$@`0333s$@ 333$@ 3339@$@ $@Y$@ 333s`fffƠ$@ ̬$@0333ӕ$@@f0333{$@20333A$@`fff$@ 333303333#@`fff`fff#@B̬#@Y#@ـYm#@@lr#@`fff[#@ 333`fffK#@ 3333TJ#@̌|#@@#@3333 #@@ffff03333#@3333S#@3333 @#@ 0333#@LQ 0333#@ y#@I `fffƲ#@33330333#@LWq#@_#@̕03338#@5#@Ly#@333`fff"@"0333s"@̼ "@0333s"@3333} "@@ffff`fff"@L0333s"@d0333"@o"@3333 8"@333"@@fff "@1`fff!@!@0333ә!@333!@tl @ j @@ffffNW @0333SR @̌K @333> @* @3333`fff @Y` @@ffffQL@b@0333F@@fff@333+0333s@33330333s@0333 @@fff@0333@3333Mk@@fffY ̌@@fff :@3333 @ Y@ @@ $@ `fff@̚ d@33330333W@s@3`fff0@`ffff@L@3330333s@̑ z@@ffffYf@3333 `fff@@ffffm@QP@3333O0333s@\0333@0333@@ffff(@33330333y@3333'0333@5`fff&@@Y `fff@6 `fffd@ k@ 0333sW@ `fff@ ̅@@03333,@ {`fff&=@m`fff4@6@ǒ@ 333u`fff @̌?@&`fff@`ffff0333@L`fff@`ffffL@@@`fff&!L@W@Yx`ffff@`fff&̌@`ffffk @L?̅@LB[@ 33303333 @ 3333?0333@1 @ 333sa@ `fff@Y;-@ 333`fff@L @ .g@LI0333@ 333sL J@`ffff]@I@W@G@̌FR@ o@`fff&@@`fff&LL@ 3333Y@Y`fff& @3@`fff0333@L]@ 33303333j@`ffffa@@@^@`ffff@`fff@`fff/@`fff&4'@@U03333N@ l@ 333@`fff&%@L# ̌1@0333C 0333s&@`h 0333)@ 0333F@0333 0333g@0333s @Y @ Y@@!L@-!L@`fff5!@l @`fffF 4@0333s q@`fff& @̚ @ K@`fffF 0333@0333 @@ `fff&0@ `fff;@`fff& Lh@ \@v :@0333si `ffff\@; @0333S< K@0333@ ̌x@% @@ 9 @  03333( @0333 03333J @ `fffV @Y. ̌T @H `fff\ @,o yp @ `fff @} @0333Sy L @k l @`fffU 9 @`fff& @ @y` @YK0333s @L& @ 333 @L @̌ @̌ !@9I!@"0333p!@ْ!@`fff`fffF!@ 333`fff!@"@`fff`ffff)"@3`fff:"@̌[M"@`fff`"@ "@ 333"@`fff"@ "@`ffff- "@ F "@`fffJ Y#@̬J 0333s#@0333sO `fffF#@0333E L $@' Y"$@ `fff&@$@`ffff03333S$@@zU,$ @Ta&@T@'#@ffffnT#@T#@3333T #@8T#@LT#@DT/#@T@$#@ T#@T`fffF"@4T`fff&"@ffff&T"@3333WTl"@ffff.T`fff"@hT"@T`fff!@3333oT`fffF!@̔T`fff!@\T0333!@ffffT!@ffffrT0333S!@̰T {!@ĶT`fffFE!@T !@Ť @$T03333 @ؿTL @T @3333T̡ @3333T @lT03333f @TB @3333GT,$ @T ] @3333T0333S @T`fffƴ @3333KT!@dT`fff&-!@ffffJT`fff&T!@ Tyo!@T`fffi!@ffffT =!@ffffT`fff!@Ty @T @Tl @ffffT @T`fffF @T @3333T:!@T03333u!@3333GT̬!@3333oTl!@T"@)T0333L"@PT`fff"@3333U`fffF"@3333;U"@U`ffff #@8%U##@3333+*UK#@*Ug#@()U,#@-U#@ffffAU@;$@3333LUd$@OU0333{$@PU`ffff$@3333#OU6$@IJU$@ffff=U#@ffff":U`fff#@33338U0333S#@@U`ffff#@ffffCU,V#@ffffDU033334#@TGU)#@3333IUy=#@!TU03333#@gU #@kU#@rU`fffD$@`vU`fff$@(uU$@mU %@tjUYE%@jU \%@jU0333s}%@mU`fffƔ%@MuU,%@zǓ%@3333xU0333%@$pU0333s%@̘oU&@3333oU&@9nU!&@lU)&@1lU`fff1&@iU`N&@gU0333s^&@3333ceUa&@ffffzbU`fff&U&@3333WU6&@tKU0333s&@0:U%@3U`fff&@,U&@ffff(UY&@ffffNU%@U%@ffffJU0333%@3333[U,%@ffff U%@̔ Uy%@ffff Ǔ%@(U`fff&%@Tx%@ffffŤ|%@̠T`%@,Ty%@ffffT%@T`fffF%@̤T`fffF%@T,x%@Ť$@ffff2Ty$@TL$@3333T`fff#@qT#@ܳTx#@ѱTV#@ T`ffff;#@T@'#@`pffffm(@Y*@rlIC?@?@m>>@^Up S>@83333 hfff& >@ hfff&=@ {=@ 833337=@ hfff<@ <@̌ 9<@83333.!8333<@8333f!<@Y!hfff&<@83333!@<@!hffff<@"8333ӝ<@%"{<@V"8333f<@s"8333sf<@̌"`<@hfff&#̬<@̌[#L<@#<@hffff#<@2$<@@$<@8333s$@<@8333%̌<@hfffV%8333S<@̚%<@%hffffx<@8&yg<@8333s&8333s[<@L&hfff&b<@hfff&"'83333h<@hfff>'̌n<@̌e'hfff{<@̟'hfff<@hfff&'<@8333'<@@(<@8333=(83333<@(y=@(83330=@̌(X=@@(8333sm=@(L|=@@(@=@8333(8333=@(8333}=@hfff(=@t(L=@hfffg(hfff&=@̌e(hfff=@T(̌=@O(=@(hfff=@8333(̬=@8333s@)=@8333s)=@8333)=@U*hfff=@L*=@*8333s=@L*=@Y*٦=@hfff&*̥=@8333*Y=@٘*=@hffff*=@8333s*@{=@83333*a=@L*8333@=@ٽ*̬3=@8333*8333=@L*hfff=@ټ*9<@@*8333<@hfffm*<@hfff&=*<@)hfff<@)hfffF<@)̌<@L)hfff<@)<@|)8333sy<@hfff&?)8333s<@hfff')8333i<@@ )8333[<@(<<@(<@(;@ّ(;@̏(8333;@(hfff;@@t(̌;@d(̬|;@((8333sl;@'8333<;@hfff&'hfffF2;@5'(;@̌('l;@0' ;@Y;'8333;@S'8333:@83333':@83333'L:@8333'8333:@'8333:@83333'̺:@8333'̬:@8333'n:@L'8333V:@'̬:@8333s'hfff:@'833339@hfff'9@hfff'l9@}' 9@'u9@Lf'8333i9@X'8333sY9@?'R9@hffff'YH9@Y&8333J9@hfff&Q9@Ly&I9@l&>9@l&8333S/9@hffff|&8333s9@hfff&&y8@hfff&&l8@8333s&hffff8@8333&83338@8333&8@&8333sw8@83333&`8@̌&U8@&`8@&8333se8@hfff&]8@B&hfffQ8@$&/8@Y&8333"8@L &y8@L%83338@8333s%83338@%l7@Y%7@8333s%hfffF7@ %83337@hffff%y7@&hfffF7@hfff&Y7@ %hfffv7@L%8333sf7@8333% (7@L&&hfff7@-&83336@)&6@&6@&8333s|6@hffff,&d6@hfffQ&P6@8333e&`G6@hffffc&8333A6@S&hfff96@8333s>&y76@&̌-6@%46@8333%G6@hffff%N6@8333a%H6@hffff%H6@$lM6@$hfffFF6@hfff$26@$83336@#5@s#L5@@0#,5@"Y5@@V"833335@!hfff5@c!Y5@hfff hfff5@L9 83335@@3333vhffff5@h8333s5@Y5@P5@@3333BhfffF5@8hfffƂ5@/05@#833334@@3333 4@pffff83334@L,4@@33338333s4@@333|hfffF4@ 4@8333s{4@̩hfff04@Y3@pfff 3@ 3@&83333@pfff{3@@3333hfff|3@z3@Yk3@@333:hfff&_3@̞8333^3@@W3@hfff$3@ hfff2@ 2@hfffF2@ 2@pffff8333|2@U2@hfff& hfff12@83333 8333 2@3 @2@7 1@hfff" `1@̌$ 83331@8333s. `1@83332 91@& Li1@>1@L~8333'1@pffff 1@8333S1@s0@0@̠@0@?`0@pffffhfff&0@833330@Ly0@8333s0@Lb0@@33330@@33330@Luhfff0@4̕0@pfff0@8333sn0@̙8333P0@pffffvhffff0@@333u@3333t/@t.@@333y-.@@333-@@3333P-@@3333,@@333a,@@:,@pfffu+@m@333s+@@333kLL+@pffffr@3333*@rpffff*@t@333*@pffff^*@lpfff"*@u@333*@@3333X)@jL)@̂\)@pfff@333s)@Lpfff(@(@L(@̔{(@@333:pffffm(@pfff@333(@pffffpfff(@@3333(@pfff)@@333 )@̲@333s )@̌(@pffffs (@\pfff&(@@3333Ipffff)@%pfff%)@@1)@pfffY)@̨)@L)@Y*@@333@%*@,*@pffffh@333E*@jN*@@3333{YZ*@@333sp*@@3333*@pffff*@LQ@333s*@Y@333*@L8@333s+@pfff@333Q+@pfff^+@@3333f+@@3333yLj+@L,pfff&o+@pffffpffffz+@Y+@L@333+@pfff+@L+@L@333+@L,@̌D,@@t,@@333npfff,@pffff7@333s,@2L,@z@333,@L,@Lpfff,@L,@WL,@pfff,@L,@@3333S,@jY,@@333upfff,@h-@LlD-@L@333sj-@pfff-@b-@pffff6.@̈.@; .@@.@pfffL /@Z@3/@@333Y/@ffff@333/@ffffypfff/@@3333!8333%0@ 00@@3333 hfff70@>̬30@̷ 10@; 70@@3333l F0@o0@_l0@@3333qY0@.83330@`0@\@0@@3333hfff0@@3333=̌1@`G1@¢1@迠1@`1@4333ѿ1@8333Ӫ@1@?1@1?1@k?hfff1@?2@?2@̎?hfff2@?y2@ 3333@,62@Q@W2@L>@̬}2@ 3333e@ 2@ 3333@hfffF2@ 333n @@2@ @2@n @92@`ffff@83332@`ffffw@hfffF2@@2@̌b@,2@̇@2@@̌3@̐@R3@0333sH@@3@̌@3@L|@y3@0333s[@3@ @4@`ffff@833394@̌Q@d4@`fff@̌|4@̌*@4@@4@@4@ @̬4@ @hfff& 5@`fff&T@8333:5@0333s5@8333D5@J@hfffY5@>@5@0333@5@`fff& @5@@8333l6@03333@ s6@ٞ@9v6@@8333s6@`fff@6@@@833336@0333]@y6@03333@8333S6@@@,6@0333@̬7@@hfff87@@P7@0333s@j7@ @ 7@@̌7@L@833337@0333C@7@ w@L:8@@Q8@@hfffo8@03333 @8@`ffff@y8@̌@83339@`fff@8333?9@`fff&@yH9@03333@@8333sf9@ @l9@?@9@"@hfff9@@l,:@@@8333:@@W@:@`fffI@8333s:@`fff?@:@M@hfffF;@̼@hffff;@̌@l;@@@g;@o@8333sp;@`fff&(@8333};@@hfff;@Lb@ ;@@;@@;@`fff&@8333s;@d@hfff;@̌E@ ;@ @8333<@`fff@ <@@,1<@`ffff@L?<@`fffd@O<@`fff&Z@^<@LF@8333sm<@0333K@Y<@}@<@`ffff@ <@@y<@@8333=@`fff@hfff&=@@83339=@L@hfffb=@Y@9x=@r@8333S=@L@hfffF=@Y@hfff=@@hfff=@O@=@0333@y>@`fff@hfff1>@@8333k>@ 3333@ >@@8333s>@ 3333L@8333>@ @83333>@`fff8 @83333>@`ffff @̥>@ 333 @,>@' @>@`ffff @hfff>@̕ @ >@LD @̬>@ @83333>@ @ >@E @>@ 333 @>@B @>@N @hfff>@U@Y>@@hfffF>@@hfff>@w@>@ 3333&@>@ 333@>@l@ٺ>@>@hfff>@@>@4@@>@`fff9@?@@ ?@ 3333@hfff?@N@9#?@O@hfff&-?@)@1?@ 333@@?>@3333?83333>@3333?ٶ>@@3333?83333>@3333E?>@̄?z>@v?p>@?,c>@@ffff?Lf>@?j>@@ffff?8333s>@%?hfffw>@?8333Sz>@3333?83333R>@?y=>@?8333.>@&? >@?`=@33337?=@3333_?=@̐?9=@?̬=@?̌=@3333? =@2333K?=@?=@,?hfff=@8333Ӯ83333=@4333"y6=@ F&Ǿ̤=@hfff=@,8333=@ǿj=@gfffտ \=@ܿ8333S=@3333̬U=@ffffz]=@ffffz@k=@ffff&s=@lhfff=@3333㿠y=@3333;VA=@V4࿠٥=@ 8333=@3333@=@3333 =@3333c쿠ُ=@ffffFhffff=@@3333񿠙y=@@33338333=@4̬=@ffffw=@@3333}hffff=@ffffhfffZ=@HhfffD=@@$A8=@)Z2=@ffffL9=@hffff=@\8333<@f<@ffffhfff<@ <@@33339hfffF<@~,<@ffffhfffF<@@3333̬<@@3333ML<@̬<@@3333ch<@ͺȞ<@̒83333<@q<@<@t̬=@=@@=@e8333=@ffff9'=@ffff8333s9=@m9=@ Y6=@@ N5=@] ,2=@@3333 ,=@ 8333S(=@ hffff$=@ffffC #=@ffff 8333%=@ffff @#=@ 83333=@8333s=@M=@=@ffff8333s=@* =@^=@l=@=@=@@3333% =@Dhfff"=@@333_9%=@pfffV7=@@333xhfffF:=@pfffH>=@Bhfff&A=@g3=@L3=@L 8333S+=@@3333hfff%=@=@X83333=@@3333=@ =@L7=@,(=@@3339=@L|9_=@@3333w^=@pffff8333sW=@pfff@U=@̥9W=@L W=@`T=@@33316=@@333hfff0=@hfff/=@8333s1=@pfff&7=@Zhfff?=@o E=@J=@̳8333O=@@333̌l=@8333o=@L hfff&t=@Lhfffy=@{=@&z=@@3333=@@3333Y=@L̬=@J8333s=@@3333=@@hfff=@@3333a8333S>@@3338333>@Lhfff%>@pffff2hfff&5>@L83336>@pfff:L4>@X83338>@C>@LG>@@333d`K>@}8333^>@hffffe>@@333hfff&q>@w>@ >@hfff @>@8333 >@hfff: >@hfff\ m>>@^Up 0pfffB&@pffffhfffF2@ @CpfffB&@TLa&@ x&@̆ &@! @3333'@) '@@33333 _'@t w'@ffff pfff'@ '@̒ '@S '@ ̭'@ @333s'@ffff@ '@@3333 '@\ '@ L'@ffff pfff&'@D '@@3333 Ln'@ffffj `'@ j'@@3333pfff'@@3333'@ffff@3333l'@~@333Y'@@3333G'@Y'@@'@@3333(pffff0'@@3333^@3334'@ffff&'@@3333-''@@33336'@@333T'@t'@ffff(pfff'@̌'@@3333'@!(@M̌(@̣Y(@̌(@Z(@ffff(@@3333@3333(@ffffapffff(@ffff@(@@333(@fffffL.)@:A)@Fpffffm)@@3333L)@)@)@ipfff)@́@3333Q*@@333*@= *@)@333<+@:@i+@@333w+@+@ffffOpfff+@E+@@3333+@@+@ffffp+@@3333+@,,@@3333@333sB,@XLf,@fffff,@gpffffS,@pffffS,@Lg,@ffffp@333z,@@3333,@pfff,@A,@@3333,@=@333,@ffffbL,@ZL,@ffff~,@f@,@ffff@333,@@3333󿠙,@@,@3333,@ ,@,@Y@333s,@̘@,@ݿi,@Yۿ@333K,@)׿pfff4,@gfffҿ̌#,@Iѿ+@ ϿY+@hfffʿ@+@@+@dfffF?pfff+@l?̌+@,?@3333+@̤?@333 ,@`?̌!,@z?,,@+?@v,@̢?@333,@ffff?,@?ٮ,@?,@.?@333s,@?,@,?,@?,@3333?@,@q?pfff&,@?z,@3333)?\,@@ffff?pfff!,@U?pfff+@3333?@q+@?@333 +@?pfff*@H?Y*@3333?n*@?Ya*@w?pffft*@?pfff~*@? r*@F?^*@?LS*@^?pfff&X*@?@k*@?̓*@̻@L*@`fffJ@pfff&+@ 333F@pfff+@`ffffB@,@`ffffE@@333,@`ffffH@,@`fff<@pffff(-@̗@V-@@@3333m-@`fff@pffft-@ 333@-@@-@̤@-@@ -@ 3333@L.@ 3333@.@@3.@@@333Q.@`fffH@@3333h.@2@.@3333?@333s.@?.@N?Y3/@4?@333{/@̣?pffff/@?L/@)?833330@? 0@@ffff?0@m?"0@@ffff?̌"0@3333?0@@ffff?83330@`ffff,@0@ 333@0@ 333W@83333-0@`ffff@.0@@8333.0@)@8333s@0@A@8333Q0@W@f0@ 333@8333w0@`ffff@hfffu0@,@Yw0@@hfffz0@@ z0@ 3333R @ 0@ 333 @hfff0@ @hfff0@`ffff @Y0@ @`0@H @̬0@LJ @hfff1@t @hfff91@ @hffffL1@ @ p1@z @}1@ @hfff1@K @1@`ffff @`1@Ln @91@w @̬1@j @2@h @2@{ @2@h @83333)2@ @hfff12@ @8333<2@`ffffW @8333sQ2@ @8333sy2@`fff @83332@ 3333 @hfffƍ2@`fff @@2@ @hfffF2@ 333n @ 2@ 3333@̬}2@ 3333e@W2@L>@,62@Q@y2@ 3333@hfff2@?2@̎?2@?hfff1@?1@k?1@1?@1@?1@8333Ӫ`1@4333ѿ1@ῠ1@`G1@̌1@hfff0@@3333=@0@@3333`0@\83330@Y0@.l0@@3333qo0@_ F0@ 70@@3333l 10@;̬30@̷hfff70@>00@@3333 8333%0@ pfff/@@3333!@333/@ffffyY/@ffff@3/@@333L /@Z@.@pfff .@̈.@;pffff6.@-@-@b@333sj-@pfffD-@L-@Llpfff,@hY,@@333u,@jL,@@3333Spfff,@L,@,@Wpfff,@LL,@L@333,@L,@z@333s,@2pfff,@pffff7@t,@@333ňD,@,@@333+@L+@L+@L@333+@pfffY+@Lpffffz+@pfff&o+@pffffLj+@L,f+@@3333ypfff^+@@3333@333Q+@@333s+@pfff@333*@L8@333s*@Ypffff*@LQ@3333*@@333sp*@YZ*@N*@@3333{@333E*@j,*@pffffh@%*@*@zY)@5)@@)@@3333@333)@pfffYp)@̌H)@pfff)@Ypfff(@z(@(@pfff(@pfffh(@ĽU(@Y@333'(@pffff (@pffffpffff(@'@LY'@v@3333'@@'@̏'@̴'@pffffC V'@@333pfff&@&@@333pfffB&@T44333E@̌(lCF@hfff&#"@̈6R03333E"@2R7"@3333o.R0333S!@ffff*R0333SA!@!R @̨R0333 @3333R @ffffNR9N @3333R0333, @Rl @RL@iRL=@ffffR`fff&@3333R0333s@4R@YR@AR @3333R@3333K R`fff&{@3333 R0333@dR03333c@lR`ffff!@!Q@Q0333@̼Q0333!@AQ@Q@3333;Q`ffff@QL@ffffQ0333sO@-Q03333\@QT@ffffFQ)@3333QL@̘Q0333@Q0333@ffff Q`fff@DQ@Q0333s@ffffyQ @3333KoQ@@fQ03333I@\Q`fff&@ffffV[Q0333~@ffffVQ̌@SQ`fff@)QQf@3333sLQv@EQ̼@3333;Q0333@ffff"/Q̌@1QL@( Q@@ffffP@P(@P#@3333[P@P@ffff.P`fffz@ffffP`fff&@TPL@PU@hP`ffff@3333P03333<@tP@@uP@3333P0333@xP0333@P`fff&@̼P0333s@̼P @P@Pم@P0333"@ P@ffffPX@XP@P&@EP`fff @ffffP`ffff @@P̵ @P 333S @ffffP`fff @P 333 @P̔ @3333P @lP$@ffffP 333@3333PLY@ P@Pf@̘PLY@0P'@ffffZP@33338RD3333;wR%3333S{R(R3333{R@3333u𿙙RďR33333333+R̰3333gRffff:Rffff鿙RffffR ffffR̔⿙ŝR̐3333Rgfff޿ffffR4333ۿffffrRgfff׿DRtտXRӿ3333RLϿPR̜ɿRhfffʿffffRhfffɿRhfffȿQR4333ÿRཿ3333R٩R``R`4RhfffFR̬ffffR?̴Rٶ?ffffNR2333S?dRffff?̬S ?XS?QS3333?S?S3333?tS3333??S3333s?XS?S2333#?&S?l+S)?.Sffffj?P/S ?ffff"1Sffff?5Sffff?3333:S3333/?(@S?MGS?3333JSA?3333RS?]YS5?ffff[S0?ffff]Sffff^?3333^Sffff?aS!?|fSffff?3333iS(?kS?lS?3333uSi?ffff^Sffff?Sffff?S̼?̼S@ffff.?S@ffff?S?,S3333? S@ffff?S3333I?ܸSb?̠S?ffffJS ?S@ffff?S@ffffa?ffff:S3333?3333;S 3333s@}SLt@ffffޥS`ffff@8S 333c@xS 333@ffffS 3333@S 3333@S@ffffS@DS 333@ffffS 3333X@ffff.SL@ffff{S 333@ffffyS 3333@wS@tS@sS@̴qS`ffffL@jS`fff@3333jSZ@lS@dlSQ@3333shSh@cS@LaS 3333H @8^S @ffffZS @VS`fff @3333TSL @OS̮ @ffffDS`ffffN@ffffHS?@JS`fff@MS@PSL%@OS0333)@3333QS`fff;@VS̎@X[S`fff=@3333[S@3333YS@(ZS0333@3333SaS`fff@ffff`S0333s@̈\S@4@3333ZS0333c@VSٗ@3333US`ffff@3333TS`@3333SRS @ffffSS#@US`fffZ@xWS`ffffN@VSY@WSK@ffffYS`fff&@4bS&@ffffTSٳ@OS`fff@3333VS@@3333 ^S@ffffF^S$@ffff*\S@@|YS@WS@ffffWS`ffffM@ffff\S`fff@aS@fS`ffffY@UiSz@̔kS0333s@psŠ@̬yS@3333uS0333s@pSL@oS%@33333qS@3333pS@oS0333@nS@4mS@ffff&jSى@3333gSB@ffffeS,@3333sbSC@3333sVS@33337WS @ffffVSX@RS0333@ffffMS`fff@3333LS@ffffMSY @ffffRS`fff_ @VS @ffffXS @ZS @^S03333 @\S!!@(YS0333J!@3333WS Q!@ffffVSF!@PS`fff @THS @?S, @;S,K @9S`fffA @̄6S0333S. @33337S @a:S @-;Š@ffffb9S@3333{7S@3333W2S0333@ffff/S @i1S @d4S @ffff7S`fff!@:S%!@8S`=!@X3S`fffH!@ffff,S0333c!@Sl!@S"@ffffS`fffF"@R"@3333[R"@3333R"@R0333#@RP#@R`fffu#@ffffR`fff&#@ffffR`fffF#@3333#Rl@$@xR i$@̼R y$@R`fff&X$@URlI$@R`fffd$@pŖ$@R`fff&%@3333R`fff8%@R0333St%@ffffR`fff%@R`fff%@3333Ry&@ R,8&@ffffR`ffff%@ffff"RL%@R`fff%@ffff6R03333%@R0333s%@ffff R%@tR%@Ṙ%@iR%@ffff2Ř%@ffffR5&@ЌR &@%R`fffF&@ȃR`ffff&@ffff6zR`fff&&@rR`fff&&@ffffRkR&@ffffTRl&@ffff2.Rl'@̜Ry'@RL'@3333 R0333(@Ř`(@ffffR0333z(@ffffQz(@Q(@3333Q@(@3333Q`fff(@@^@i>@̔~^@ffffV>@4333 ~^@2333$>@4333^@ffff#>@4^@i>@^@ >@^@2333=@4333 ^@2333ӭ=@ъ^@ffff=@\^@=@4333^@fffff=@^@2333=@^@@=@^@fffff=@4333 ^@2333ӭ=@ٙ^@2333s=@8^@=@hfff^@I=@<^@Y=@hfffv^@=@4333^@2333C=@ٙ^@2333s=@]@t9@]@4333#i9@]@dfffn9@4333]@dfff~9@hfffF]@43339@4333]@4333C9@hfff>]@9@]@dfff69@ ]@̌9@ ]@|9@]@P9@̬]@dfffF9@]@9@hfffF]@dfffz9@]@t9@hfff[@5@[@5@a[@dfffF5@[@ 5@|[@5@@[@̼4@[@43335@[@l4@4333[@L5@[@4333s5@ԓ[@4333#5@hfff[@5@hfffP^@ <@4333J^@<@4333kH^@ffff<@4333H^@"<@hfff&M^@2333S4<@O^@i.<@P^@,%<@hfffP^@ <@c\@6@4333d\@dfff6@_\@ 6@]\@dfff6@D[\@6@Y\@ 6@]\@6@Pa\@ 6@c\@6@43332\@43335@Y1\@43335@|/\@95@.\@5@̜-\@̬5@̬0\@dfff5@ 2\@43335@43335\@dfff5@47\@̬5@4\@P5@hfff>3\@43335@43332\@43335@43333)\@5@4333"\@dfffV5@!\@5@hfff#\@̼5@4333s)\@4333ӵ5@43333)\@5@@Z@ 5@4333#Z@dfffv5@TZ@)5@Z@5@hfffZ@)5@4333+Z@,5@hfffZ@l5@yZ@5@iZ@5@lZ@43335@Z@P5@DZ@5@iZ@dfff5@$Z@dfff5@hfff6Z@̌5@Z@dfff5@4333ӲZ@4333c5@Z@dfff6@hfffZ@dfffv5@xZ@5@Z@6@hfff>Z@"6@hfffީZ@=6@̼Z@4333I6@hfffZ@4333S6@hfffnZ@yW6@4333SZ@9e6@9Z@Y6@hfffFZ@6@̄Z@dfff6@hfffZ@4333C6@ Z@6@Z@dffff6@Z@6@̬Z@6@4333ۜZ@dfff6@4333Z@ 6@4333ۑZ@43336@hfffZ@43336@hfffƋZ@43336@Z@dfffV6@aZ@̼6@Z@6@hfff}Z@6@yZ@6@4333uZ@<6@rZ@dfff&6@;@PX@2333l;@̬X@̌;@4333cX@L;@IX@̥;@hfffX@@;@4333+X@2333;@X@I;@hfffnX@;@ X@2333ӌ;@̌X@\;@lX@ffffƩ;@YX@2333;@4333X@2333#<@TX@l$<@X@ffff/<@lX@ffff&6<@{X@ffffVP<@hfffxX@2333C[<@4333[wX@2333]<@AtX@9[<@8qX@,[<@nX@9h<@tlX@ffff&x<@4333+jX@<@YfX@\<@lbX@̜<@4333#`X@2333t<@4333^X@ffffl<@̜[X@Z<@VX@ffff&A<@4333TX@7<@dfffRX@<<@IIX@ W<@4333DX@2333s^<@hfff>X@2333sV<@P5X@ffff\<@hfff1X@ffff]<@)X@0333#s<@&X@̼u<@`X@g<@hfffX@0^<@4333sX@ffff^<@xX@2333b<@0333X@|i<@X@̜m<@X@2333w<@X@0<@4333X@<@QX@ffffF<@,%X@<@03333#X@ `<@X@ffff<@X@P333=@4333X@ =@03333X@fff=@a X@2333<@hfffX@0<@ X@ffff<@X@2333=@4333 X@ =@PX@ffffF)=@hfffX@ffff5=@hfffX@ 333?=@̔X@B=@ X@>=@hfffv X@E=@9X@2333a=@X@2333l=@4333CX@yr=@̤W@2333d=@hfffvW@ffffVP=@4333W@23334=@hfffW@P333&=@W@2333#=@7W@0=@W@ffff =@W@2333 =@W@0 =@W@ =@4333CW@2333=@W@0&=@0333W@$=@hfff>W@ffff-=@hfffְW@ffff3=@W@i@=@TW@ L=@W@O=@W@Y7=@ĒW@ffff%=@aW@ffffV=@4333#W@P333<@!W@2333<@ـW@2333S<@P~W@\<@hfffyW@<@pW@@333Ӻ<@hfffjW@2333<@4333WW@p<@ PW@ffff&<@8MW@@<@JW@2333#~<@GW@f<@<@!V@G<@V@2333SM<@~V@O<@hfffvyV@LK<@HtV@̜A<@oV@,0<@hfffiV@ffff(<@\bV@<@4333^V@Y<@hfffVYV@I;@4333sQV@I;@DJV@ffff;@̌FV@2333;@AV@2333;@̤@,T@|>@T@2333(>@TT@̼>>@hfffƂT@ffffS>@hfffvT@ffff\>@iT@23333c>@4333ZT@lV>@4333SPT@2333>@hfffVKT@ffff6 >@GT@l >@hfffCT@ffffV>@@T@*>@?T@2333<>@7T@@333cJ>@4333/T@2333C\>@+T@23333j>@&T@r>@"T@v>@hfff6T@l>@4333T@2333>@< T@2333>@4333 T@ffff>@A T@ >@p T@\>@ T@23333>@hfff6T@,>@4333+S@ffff>@S@ >@S@>@S@@333>@4333S@>@4333S@>@0S@ffff>@S@2333c>@S@p?@S@fffv?@hfffS@?@0333S@@333=?@4333S@2333g?@S@m?@hfffS@2333j?@TS@ T?@4333S@2333SV?@S@2333T?@ S@0M?@S@,K?@S@pM?@hfffS@@333R?@̌S@2333o?@4333S@x?@4333SS@?@4333cS@9?@@S@?@aS@?@S@Pfff6?@S@S@2@@S@̼;@@S@0333B@@S@E@@hffffS@3333cG@@S@I@@4333kS@3333J@@4333۬S@3333kL@@hfff&S@yG@@9S@?@@\S@;@@S@33334@@кS@-@@ٿS@̼.@@IS@1@@hfff&S@ffff<@@S@̤?@@ S@3333#@@@S@@@@4333S@1H@@S@ffffY@@hfffS@ a@@(S@xfffg@@iS@3333n@@S@y@@PS@0@@4333S@ffff@@̔S@@@S@ffff֍@@hfffS@@@43333S@hfff@@AS@ @@hfffS@ffffN@@4333S@8333[@@4333S@@@\S@ffff.@@QS@ffff@@hfffS@ffff>@@)S@ffff@@S@̜@@S@ffffA@ԮS@A@1S@9 A@S@0A@hfffS@ffff6A@hfffS@ !A@hfffS@̼&A@hfffS@ -A@YS@ffff1A@hfffְS@9A@hfffS@3333SBA@S@3333kGA@S@ffffMA@ S@3333SA@S@bA@$S@hfff&yA@لS@DA@ȀS@!A@hfffS@IA@ S@ffffA@4333S@iA@4333S@A@|S@pfff^A@hfffFyS@yA@vS@3333A@hfffsS@A@\sS@3333A@)sS@yA@hfffVnS@3333A@̤dS@dA@HaS@A@4333\S@A@hfffRS@3333 A@4333ES@A@@8S@A@1S@3333A@.S@ffffA@p(S@\A@$S@A@H#S@3333A@! S@iA@S@(A@4333S@A@a S@A@hfffv S@A@̜S@A@S@3333A@4333S@A@|R@@B@4333cR@DB@R@3333S B@R@$B@hfffR@̜B@\R@33330B@4333R@3333:B@hfffR@3333BB@4333R@LB@hfffR@)SB@4333kR@3333XB@4333R@^B@R@1aB@tR@ffff\B@hfff&R@ffff~^B@hfffR@qB@0R@tB@4333KR@3333|B@4333sR@3333[~B@hfffR@3333{B@R@yB@hfffֵR@3333S}B@hfffR@B@LR@3333B@pR@B@hfffR@ffffւB@R@B@hfffޟR@3333SB@4333R@̔B@їR@0B@hfffƣR@IB@ЪR@3333#B@R@ffff6B@4333KR@B@R@B@hfffƵR@ffffΜB@4333 R@ffffB@4333úR@B@R@3333B@hfffR@ B@R@ffff^B@H@hfffU@@H@)U@CH@4333{U@YQH@4333U@U@ffffFH@4333kU@ffffH@U@H@U@ffff{H@4333U@ffffyH@LU@3333uH@U@pH@U@jH@V@dH@ CV@3333SH@hffffGV@lG@LV@ffffG@UV@ffff.H@4333^V@H@hfffcV@H@hV@\G@\lV@G@pnV@ffffG@qV@3333G@4uV@aG@DzV@3333G@4333[}V@3333sG@ɁV@XG@4333sV@G@4333CV@3333G@4333V@iG@9V@ffffG@ V@̌G@)V@G@G@hfff~V@ffffG@V@G@4333cV@dG@,V@ffff֌G@4333˭V@ffff~G@4333#V@~G@̬V@,zG@hfffFV@ffffqG@hfffV@_G@ܿV@ffffTG@hfffFV@ALG@V@tHG@4333+V@ffffCG@,V@1G@ĺV@)G@hfffVV@̤"G@̤V@G@4333˿V@p G@V@̔G@lV@ffffF@hfffƸV@F@hfffV@TF@V@@F@4333kV@3333F@V@ffff.F@4333[V@3333;F@qV@F@V@F@ذV@qF@4333V@ffffF@$V@F@hfff~V@3333ӘF@V@3333F@43333V@ԛF@V@3333ӘF@1V@F@V@ffffF@9V@F@̤V@3333F@hffffV@3333ˉF@8V@3333ӈF@̔V@F@W@ĈF@ W@3333F@ W@$F@ %W@hF@l2W@3333F@:W@̔F@hfffRW@}F@ aW@xF@4333jW@3333SsF@hfffVpW@|jF@wW@3333\F@hfffN}W@dVF@W@̔RF@XW@ffff~BF@4333W@3333{^E@4333X@ffffWE@حX@QE@X@NE@X@3333HE@yX@PE@hfffX@3333VE@hfffY@3333UE@8!Y@3333NE@q1Y@Z@9D@]@ffffN.G@4333I]@3333s-G@8Q]@ffff-G@hfffVU]@ffffV.G@V]@ffff2G@hfffV]@7G@Y]@DG@Y]@3333IG@ \]@ KG@c]@LKG@hfffg]@FG@4333j]@3333BG@po]@3333SBG@t]@3333DG@Dz]@ffffFOG@]@3333SUG@ ]@3333VG@]@[G@]@ZG@hfff&]@XG@̄]@YG@D]@XG@̔]@_G@4333]@ffffNaG@A]@^G@4333]@XG@`]@QG@<]@NG@hfffV]@ffff6PG@]@ffffNMG@9]@MG@hfff]@HPG@]@ VG@hfffV]@ffff]G@hfff]@ffffNeG@hfffv]@mG@hfff6]@3333 tG@hfffv]@I}G@]@tG@hfffv]@ffffG@4333]@33333G@i]@yG@]@G@4333]@G@]@G@]@!G@̜]@G@hfff]@ G@d]@9G@hfff]@|G@9]@G@hfff>]@3333G@ ]@G@]@G@hfffV]@G@4333]@G@1]@@G@hfffV]@̼G@hfff]@3333G@hfffV]@G@i]@3333H@hfff]@lH@4333~]@3333G@u]@3333G@,q]@3333sG@hfffNk]@3333CG@4333c]@G@ ]]@G@4333X]@ffff~G@4333sV]@3333{G@LR]@3333KG@̜L]@G@hfffvD]@8G@<]@G@̬9]@1G@̬0]@TG@)]@G@ ]@ffffvG@4]@ G@L]@G@4333]@G@]@G@4333\@ G@|\@G@4333\@ffff~G@̌\@3333CG@4333s\@G@\@ffffG@4333\@H@\@ffffH@hfffF\@ffffH@4333\@T,H@4333\@T:H@4333\@3333IH@4333 \@H@]@3333KH@p]@ffffI@]@I@hfff]@I@)]@̴#I@L]@L-I@H]@ffff0I@y]@3I@hfff]@\7I@`]@=I@hfff]@ffffGI@]@3333#QI@hfff]@ffffYI@]@ffffcI@]@3333{nI@4333]@0yI@hfff]@3333ۃI@hfff]@ɍI@l]@I@4333 ]@ffff.I@4333]@I@H^@3333I@4333+^@3333I@̬ ^@̜I@̜+^@̌I@/^@3333[ J@hfff/^@LJ@hfff*^@3333c&J@)^@̬2J@,^@ffff.?J@hfff)^@HJ@Y!^@NJ@4333 ^@APJ@hfff ^@ffffMJ@4333S^@3333QJ@hfff^@ffff[J@ ^@3333dJ@hfff ^@kJ@hfff^@{J@-^@ffffJ@?^@lJ@4333Y^@̔J@̜o^@J@^@ɹJ@hfff^@J@T^@33333J@4333^@ffff~J@^@J@I^@̴J@^@̴J@^@ffffJ@4333#^@J@4333S^@J@9^@3333cJ@4333^@iJ@hfff^@J@4333k^@hJ@^@3333J@ _@J@4333_@`J@hfff_@J@_@ffffJ@_@dJ@4333(_@ffffJ@3_@!J@t8_@3333J@hfff:_@J@4333#>_@AJ@D_@J@pN_@9J@ [_@J@b_@J@$f_@3333[J@i_@iJ@Dl_@yJ@l_@hzJ@k_@$wJ@n_@3333rJ@r_@3333rJ@w_@ffffoJ@4333C|_@|fJ@hfffF_@IbJ@_@ffff^J@hfff_@[J@ك_@3333XJ@4333_@4VJ@|_@ffffNRJ@hfff_@3333NJ@_@3333cIJ@hfff_@EJ@q_@3333sBJ@_@ffff=J@4_@8J@hfff_@3333+3J@hfffޕ_@ffffV.J@_@3333s*J@)_@33333'J@4333_@̬$J@hfff_@tJ@D_@$J@(_@0J@_@J@̬_@I@hfff֩_@I@٬_@I@4333_@I@4333c_@|I@_@I@̌_@I@P_@YI@4333_@ĴI@A_@I@\_@ffffNI@hfff_@tI@и_@tI@hfffV_@ffffI@0_@ьI@hfffN_@1~I@_@3333+jI@hfff_@ffffZI@43333_@OI@8_@iFI@_@A?I@hfff_@ :I@_@33336I@y_@a2I@̔_@,I@L_@8&I@hfff_@I@_@, I@y_@ffffH@(_@H@@_@H@_@ffffNH@4333+_@ffffH@4333_@H@_@H@_@H@hfff`@ffffH@4333`@H@4333`@H@`@H@P`@3333[H@hfff`@3333SH@8`@\H@hfff`@ffffvH@hfff `@H@"`@H@#`@XH@%`@ѰH@4333'`@xH@hfff)`@3333KH@4+`@aH@4333O,`@ٱH@hfff.`@ٱH@/`@ıH@1`@fffffH@2`@H@y5`@ffffH@\9`@tH@0A`@3333s|H@EF`@!rH@hfff^K`@nH@4333Q`@3333;nH@S`@bH@R`@ffffWH@4333Q`@ffffMH@S`@ffffIH@U`@=H@hfffW`@ffff7H@hfffnX`@1H@̼Y`@ffff+H@0Y`@ffff H@V`@ffffVH@qW`@ffffvH@([`@G@4333K]`@G@]`@AG@^`@3333G@hfff``@G@hfffc`@LG@8j`@)G@4333n`@ffff~G@q`@LG@ y`@3333G@4333˄`@ffffG@hfff*`@`G@=`@̄G@4333`@ffff^G@a`@ffffG@`@@G@4333`@TG@`@3333SG@̤`@ffff>H@`@ffff H@4333`@ffff H@`@p H@X`@ffffH@4333`@ffffH@4333`@ #H@hfff`@.H@4333c`@/H@`@ffff6/H@̘`@3333{-H@`@ffff.)H@I`@ H@`@H@4333k`@H@hfff`@aH@4333_`@̜ H@`@H@`@3333G@4333`@G@4333[`@̔G@4333`@3333G@L`@̜G@D`@3333G@`@ffffG@4333W`@G@x`@3333CG@=`@G@`@G@hfffN`@G@hfffR`@YG@4`@3333#G@]`@ffffG@43337`@ffffG@hfff`@ܘG@x`@dG@a`@ԈG@`@33333}G@H`@3333yG@x`@pG@<`@mG@`@I[G@`@NG@4333`@3333?G@``@7G@4333`@.G@4333+`@3333+G@hfff`@'G@`@ffffG@hfff`@̴G@`@G@l`@3333G@`@G@`@$G@4333`@DF@t`@F@4333`@3333F@4333k`@|F@hfff`@̼F@9`@3333F@4333_`@@F@hfff`@3333[F@4333`@fffffF@``@ffff>F@`@3333F@4333`@3333F@`@ffffVF@̠`@$F@`@8F@`@3333F@``@3333F@`@ԃF@p`@F@hfff֚`@3333ӇF@α`@ sF@ܙ`@3333 F@4`@3333sF@4333`@3333F@܌`@3333F@]`@ F@hfffF`@ffffF@_€`@5M F@H`@3333;F@}`@ F@hfffB{`@ffff֩F@py`@3333F@4333w`@ffffF@t`@IF@s`@3333{F@̄r`@̴F@o`@ffffF@Ln`@}F@h`@3333wF@4333Kg`@uF@hfffb`@3333{tF@hfffa`@ffffqF@i_`@3333lF@^`@dfF@ ``@i`F@a`@pTF@b`@ffff>LF@hfffd`@ffff`@qE@hfff<`@3333E@;`@{E@:`@ffffvrE@43338`@fffffcE@8`@LZE@43337`@IME@7`@B@]@3333cB@]@xB@(]@B@d]@3333B@4333]@B@̬]@ٓB@]@ffffnB@Q]@ܥB@]@B@ ^@\B@^@̴B@`^@B@hfffv^@B@8^@ffffB@^@3333B@0^@ffffB@4333#C^@3333B@ N^@B@hfffX^@3333B@hfffV`^@B@h^@B@@t^@3333sB@}^@B@hfff^@tB@^@3333B@4333^@3333B@4333ӊ^@3333cB@̜^@B@^@8B@̌^@̔B@^@B@^@B@hfff^@ffff.B@hfff^@̤B@hfff^@B@1^@قB@^@ffffVB@4333C^@1yB@@^@3333#uB@ѕ^@ffffjB@̌^@3333jB@^@lB@^@̔pB@^@ffffvB@d^@̴zB@4333+^@A|B@{^@zB@4333j^@ffffkB@pZ^@3333^B@8I^@TB@qC^@ANB@4333[?^@LB@98^@LQB@3^@QB@2^@MB@|8^@3333DB@43339^@ffff>B@T9^@8B@hfff66^@6B@̬1^@h:B@-^@ffff4B@+^@̜+B@̔+^@̌B@4333(^@B@^@3333@@^@̴@@hfffN ^@@@hffff'^@ɾ@@/^@I@@7^@@@hfffn9^@ffffk@@6^@ffffa@@43336^@T@@4333[?^@̔H@@hfffR^@:@@hfffU^@h6@@Y^@3333/@@Y^@fffff@@\^@@@d_^@@@hfff&k^@@@p^@,?@hfffFu^@ffffV?@hfffv^@2333?@qw^@?@hfffp^@2333?@4333k^@P?@hfffV^@?@ Q^@?@TI^@2333?@hfffN>^@?@43332^@@@hfffF*^@` @@I!^@̌ @@ ^@ffffV?@Q^@?@4333^@2333?@L^@?@4333C ^@ffff?@<^@̼?@^@@@4333-^@ffff?@$0^@@?@4333k2^@?@<^@ ?@4333C^@,?@M^@ɠ?@hfffvV^@@|?@Hj^@Q?@Lr^@2333)?@hu^@ffff?@0x^@>@hfff>q^@>@hfff6k^@ >@4333a^@I>@Z^@0>@hfffS^@ >@?^@>@ <^@@x>@p9^@2333d>@43334^@Z>@Q(^@d>@^@Ic>@hfff^@ffffH>@t ^@ffff=>@^@2333?>@̬^@ffffVC>@^@ffffV?>@hfff^@ffffM>@(^@ffff">@43339^@ )>@43333J^@@M>@4333P^@M>@U^@IH>@[^@ffff:>@4333ck^@ffff=@s^@=@p|^@2333=@4333^@@=@hfffN^@=@y^@=@Lk^@2333s=@hfffd^@y=@hffff`^@ |=@0l^@Ђ=@t^@ɚ=@x^@ffff=@<|^@=@}^@}=@̼z^@"=@v^@!=@̜r^@ffff9=@4333m^@A=@4333i^@2333s<=@(b^@<=@,_^@2333s1=@hfff\^@!=@hfffVa^@2333S=@hfffj^@ffff=@k^@<@hfffi^@y<@b^@<@hffffj^@ffff<@4333Sh^@ffff<@e^@<@9a^@2333<@i^^@23333<@pb^@fffff<@f^@]<@ g^@J<@4333`^@2333S<@V^@:<@lQ^@8<@M^@X<@4333SI^@S<@LF^@`J<@DB^@2333C(<@Y=^@y <@hfff9^@<@4^@l<@/^@̌<@0^@9;@P5^@2333;@P5^@ffff6;@+^@̜;@4333S*^@;@̌*^@2333;@%^@̬;@4333C(^@l{;@&^@2333i;@̌"^@Q;@hfff^@A;@̜^@';@hfff^@;@hfff^@:@<^@:@̌^@:@^@2333C:@]@:@hfffv]@ffffF:@I]@ٮ:@]@ffffv:@]@ffff:@4333+]@0:@]@̬:@y]@:@]@2333S:@x]@:@4333]@L:@̤]@2333:@]@:@]@ffff:@]@ffff:@hfffv]@2333:@9]@:@1]@@s:@]@ffffj:@]@ffff^:@4333c]@̌U:@hfff]@ffffL:@T]@ffff<:@4333K]@ :@4333]@:@]@ffff :@ ]@2333:@4333]@:@]@,:@]@̌9@@]@9@̼]@P9@hfff]@Y:@]@:@|]@09@4333{]@9@a]@ܲ9@hfff]@\9@]@o9@hfff]@4333#d9@]@dfff6^9@4333]@̜h9@hfff]@u9@]@@r9@hfff]@w9@hfff]@dfff&s9@\]@j9@hfff]@[9@hfff]@N9@hfffF]@4333s;9@4333]@49@4333]@4333399@]@433359@hfff]@dfffv 9@)]@99@hfff.]@8@̜]@@8@H]@̌8@4333è]@dfff8@]@ 8@hfffF]@dfffF8@hfff]@43338@ ]@dfff8@ܣ]@43338@hfff^]@ə8@hfff]@8@4333s]@dfff68@4333]@43338@4333]@dfffV8@a]@4333c{8@{]@dffffy8@hffffy]@dfffz8@hfffu]@ly8@Iv]@dfffn8@Ax]@Ye8@̌]@0a8@<]@S8@hfff]@?8@y]@@8@u]@dfff&8@xo]@8@hfffj]@4333s7@4h]@433337@e]@4333c7@]]@07@[]@̬7@i]]@7@̔]]@y7@Z]@7@W]@7@0V]@7@4333+U]@4333s7@̜R]@7@hffffN]@43337@4333{I]@I7@HE]@)7@B]@7@H:]@̌7@7]@s7@̜0]@a7@4333-]@I\7@H(]@dfffZ7@4333+]@S7@,]@G7@4333*]@i:7@%]@77@4333s"]@.7@D!]@7@ ]@dfff&6@]@6@hfff]@96@hfff6]@dfff6@4 ]@,6@4333 ]@06@]@ 6@\@433336@`\@6@\@y6@\@ 6@8\@43336@\@dfff6@4333{\@dfff6@hfff\@dfff6@\@96@4333\@6@hfff\@|6@hfff\@4333C6@hfff^\@dfff6@̤\@dfff6@hfff\@dfffV6@4333\@6@̴\@Y6@\@̲6@4333\@p6@آ\@6@x\@dffff6@\@6@4333\@P6@̕\@ܗ6@hfff\@|6@4333\@Ѝ6@4333 \@43336@܇\@43336@4333C\@ 6@9\@6@4333+\@43336@\@ 6@{\@43336@4333u\@4333s6@Ip\@л6@Pj\@96@g\@dfff6@hffff\@ 6@hfffe\@ 7@hfffe\@43337@hfffg\@4333 7@4333Ca\@4333#7@\\@7@hfffv]\@dfff6@H\\@6@0U\@y6@hfffU\@6@V\@dfffV6@hfff[\@dfff6@\\@43336@hfff_\@@6@dc\@43336@4333Kc\@dfffvg6@e\@Y6@d\@L6@$c\@dfff96@hfffb\@`96@4333a\@dfff>6@_\@dfff=6@^\@̬76@hfff^\@26@L^\@dfff16@4333Z\@-6@4333W\@43333*6@T\@9%6@ Q\@6@I\@433336@hfffE\@<56@hfff@\@̌6@hfff>\@05@ =\@dfffF5@9\@dfff5@3\@43335@l.\@5@I*\@dfff5@̔(\@43335@hfff%\@5@\@|5@hfff\@p5@ \@dffff5@y\@dfffF5@Y\@95@\@`5@(\@5@\@5@\@5@̄\@5@` \@\5@\@dfffv5@̜\@5@i[@43335@4333K[@5@hfff[@dfff5@hfff[@43335@[@ 5@[@̼5@[@dfffƛ5@4333[@ 5@[@5@l[@4333s|5@hfff[@p~5@4333;[@4333s{5@p[@dfff|5@[@Ђ5@[@5@4333˿[@dfff&n5@1[@\e5@Y[@4333b5@̼[@4333sG5@L[@65@hfffF[@55@P[@dfff;5@Л[@S5@L[@V5@p[@i?5@[@ ,5@1[@!5@4333c[@4333 5@4333ۉ[@43334@4333[@4@4333c[@l4@ܘ[@`4@hfff[@dfff4@[@L4@ [@43334@̼[@̬4@ [@4333u4@)[@dfffFm4@Ĝ[@Z4@[@yK4@[@4333C4@|[@̌K4@4333{x[@43333]4@x[@4333i4@{[@f4@~[@6@ hfff^\@26@^\@̬76@_\@dfff=6@4333a\@dfff>6@c\@86@b\@433386@_\@36@^\@26@hfff^\@26@Tu\@dfff16@t\@43336@'\@ 6@4333+\@43336@9\@6@4333C\@ 6@܇\@43336@4333 \@43336@4333\@Ѝ6@hfff\@|6@A\@i6@\@6@hfff6\@dfff&u6@Д\@o6@t\@pe6@\@_6@l\@dfffFS6@hfff&\@K6@hfff\@43333Y6@\@9`6@{\@p]6@4333y\@dffffe6@`y\@̜m6@hfffn\@{6@\@ 6@َ\@dfff56@4333C\@dfff16@\@4333D6@4333\@J6@hfff\@K6@̏\@yC6@hfff\@;6@َ\@dfff56@4333\@433356@hfff&x\@56@v\@p86@u\@=6@4333kx\@G6@Ђ\@YU6@hfff6\@ G6@4333\@433356@?[[4333#KP̌14g4E #2IYfu3333Q[4333#;[[+;3333w[[;X[;Q[̌;3333CN[;3333Q[4333#;3333wS@3333Sy@3333SS4333@̬S4333s@ffff S@ٸShfff@(S@ffffS@̤S4333@8S@ffff6SL@̔S @3333wS@ĚQyX2(QhffffU2QLS23333ËQ@S2ȃQ4333H2I{Q42uQ2]sQ13333[sQhffff13333uQ1̈vQ,13333sQ913333kQY1eQ13333`Q̌1ffff_Q1VQ̌1ffffTQ4333s1RQ13333FQ 2EQ2ffffGQL23333OIQ$2ffffHQ433332EQLH2ffff.EQL[2CQn2BQ4333ӌ23333AQ2>Q 2>Q2=Q2;Q4333s36Qhfff3̔0Qhfff)3+Q >33333'Q4333K3#Q4333SW3|Qhfffa33333Q4333h3Qn33333+Q4333St3$Qhffff3̰,Q3ffff,Q3ffff%QhfffF3#Q3ffff#Q43333i&Q 43333.Q433343333_0Q@4̘0Q43334̸.Q&43333/Qhfff94,Q`O4ffff-QhfffV433330Qhfff`4̬0Q̌j4̰/Qhffffu4,Q43333~4Q̬43333Q41Qhfff43333 $QY4$Qhfff4i$Q̌4ffff#Qhfff4ffff*"Q4333s43333Q4ffffQ43333!5 QL5̴ Qr5ffff QY5-Qhfff5Q4333S5Q5AP6 P946yP@H63333PlU6ffffnPL~63333Pl6P̬6P6HP̬63333P43336Phfff&6DP6PhfffF63333/P6xPY6PY7ffffP>7ffffPL7lPhfffF7ffffzP̌7Phfff8P4333s8PL>8QN8QYd83333+Qu83333QL83333 Q̌8Q4333Ә83333w Q98#Q4333S8#Q4333s83333!Q433338Q8Q8dQ 93333Qhfff93333KQ9̐Q9&9Q)9̜"Q<9%Qhfffk93333k&Q4333S|9ffff"Q̦9 Q43339PQ:3333QY':!QhfffF:$QZ:ffff%Qhfffk:%Qlx:1%Q4333: Q:Q4333s:dQhfff:dQhfff&:$Qhfff&;Q4333S ;d"Q;%Q#;)Q%;ffffj-Q;D1Q̌;ffff*6QY';8Qhfff&?;Ip}Q >3333{Q>AwQ>vQ,>xQ6>ffffzQH>4}Q4333[>3333Qhffffc>ffffΉQhffff\>3333ۊQ4333b>TQ4333p>iQ43333>=Q`>ffffnQ>HQ>Q4333>Q>ȓQ?pQy?3333ۘQ?3333{Q!?3333GQ?@Q&?ܡQ 9?Q@Q?@Q̌m?tQhfffƑ?Q?3333ϜQhfff?4Q@?ffff.Q̌?Qhfff?HQ,?ffffQ@Ql@HQ @ffffQhfff@3333{Q4333#"@Q̬'@̴Q 7@3333ۊQ`<@3333SQ4333#P@3333oQYg@TQ4333n@hQ9q@ffffQY{@Ql@Q`@ffffnQ4333ә@DQ@~Q4333ã@3333[yQ @ttQ4333S@sQhfff@ffffsQhfff@ffffuQ @|xQ@BQ CBQIB@QpRBQWB33333Q|aBLQkB33333QuBQIBQ4333BffffvQB3333QpBQhfffVB̠QBlQ4333B3333QhfffBQ4333B(QyBQhfffFC)Q4333CQL(C3333Q43339CQ?C@Q4333SECQ`MC3333gQ,WC3333Qhfff^C3333Qhfff`CQgCIQhfff6lCffffQhfffqC3333QwCRhfff}H3333'BRhfffցH FRhffffH3333IRHHR|Hffff]R,H^RhfffHxcR`HdR̜HffffJ`RYH3333^R4333HaRHffff~`RI`R IffffXRhfffI3333SR4333S.IQR|J3333KR4333s>J3333gKRhfffHJOROJtXR,LJ|eRhfffWJffff~mR̬TJffffzRhfffXJRhfffQJ3333KR4333IJffffR̜AJdR43333JR)0J3333Rhfff0JLR(J3333CRhfffJRJRhfffJRl JyR4333cJRJ3333R`JhuR4333JoRhfffJfffflR4333sJkRJkR4333 JiR4333 JbRJ3333O]RJTR<J3333PR43333JffffHRJeyRII~RiI3333_Rhfff&IffffRItR4333I{RhfffIffffVyRlI |RhfffIffff‡R4333IxR0IDRhfffĪR̔ÌRhfff&I3333RIffff*R4333I$R I3333RhfffpIffffŘdI3333R43333WI3333RhfffVI3333R̼TIR)OIffffRhfffDIRhfff&Iffff6RGI,RhfffcIR4333fIR̬hII3333pREIffffyR0dI~RiI0R[ÌRhfffQI3333R NIR >Iffff|RYAIR4333#RIY}R4333SHRH̰RiH3333R4333#H3333RhfffFHfffffR,H̜R4333SHffffRhfff&H3333RhfffH3333'}RH3333yRhfffH3333uRHffffyRH<Rhfff־H3333 RHXRPHffff&R HR@H\R9HR4333HffffR̬Hffff|RhfffHffff{R̬HffffƁRYHRhfff6HffffRHffffRHffffRhfffHЋR4333óH)R4333HLR4333cHffffNRHuR4333CHRHQR HtRhfffeH3333ӕR@LHffffR,BH3333GR@?HffffFR@H̤Rhfffv@H̔RRF;RhfffFffff6R@FffffDR F|NRFffffz\R|FYRFffff2WRhfff6}FiPR4333{FERuF3333K/R]Fffff+RhfffLF|*R7Fffff4R̜2F@Rl%FIRhffffF3333PRhfffFhORiF]NRE3333gDRhfffVE?RhfffEffffvFR4333CEDRlE(/RPD33331R4333D4R4333SDffff*2R4333cD̘/RyD3333;*R D3333RlDRhfffDffff^RDRhfffD`R̬Dffff"RhffffDt&RD*RhffffD33333R̬DQ8R@D3333)Q`>3333_QhfffƠ>Q4333T>Q$>ffffFQhfff=4Q4333S=Q4333sq=Q4333Y=Q2=3333;Q,<3333Q4333<̔QYKQ@K3333QI@K3333QhfffCK Qhfff&>KQhfff/K3333Qhfff&KffffQ4333!KQ4333KK3333TQhfffvEKSQhfff&IK4PQYGKJQ=K3333/HQ4333:KDQhfff8KBQhfff6KffffBQ4KLQ\-K=Qhfff KffffzQlKQ̬JffffQlJԅQ4333cJ|QhfffJ$lQJXQJffffVQpJVQIJ0YQ̯J`QhfffƫJhQ4333êJ\pQ)JwQܬJȅQhfffJ3333QJ3333QhfffVJffffQ4333JtQhffffJpQYJ`Q4333JQ4333cJ3333{QhfffJhQhfffJ3333Q~JLQhfff&|J\Q̬xJffffQ̬uJffffjQ4333sJffffQmJQ4333hJTQ@`J3333oQ]J3333#Q\JQ`bJffffQ iJffff{QiJffffxQhfffFfJffffpQ̜]J3333sjQRJdQPFJ_Qhfff>JZQ<>J̰JQ4333sUJEQPVJ2Q4333IJ3333{0QJJ0*QhfffPJP(QSJPKPhfffK3333 P KyP4333KP4333sKP٢K3333{PhfffFKffff^PKP4333CKPhfffKAPٖKtP4333K@PKffff*P4333ӠK3333#P9K3333{QLKffff^QyKQK( Q KIQhfff}KQhfffvKPwK,Phfff|KffffP4333#}KffffP4333#KxPKPK3333qRhfffFE3333OvR4333EzR̜E3333[RhfffEffffRRЭEDRШE3333R̼EffffʘRhfffERhfffƗĒR,EhRypERhfffKER̜=E3333cR7E$Rhfff0ĒR)EffffRl"E@R4333E̠Ř ẼR43333E3333RLE4R DRPDRPDXR4333DnRIDaRDaŘD^R Effff]R<E[RE\R#EbR@(EffffaR@2E!^R;E3333'cR ?EhR AEffffiR̬CEffffmREE3333rRJEqROE3333kR)ZEffff^dR|aE`RplE[RwE@^R4333#E̜bRpE3333iRhfffFEffffoR\E9oRLE3333qRhfffFEyRHR4333H3333RHiR̼HffffRlHffff"R4333H]RhfffvH4R4333HR4333HRhfffHxRHRIRhfffvI԰RhfffvIRHȴR4333HffffR,HXRHffffvRH3333R,HRyHffffR HRHRhfffHRH3333SR@H3333R4333HffffrR9H;Rhfff6HiRhfffHR9HR H9RH3333RH4RyHŘH0RIH|R9HTR4333HffffRiH3333RRhfff&JffffBRJ̬DR JyERRhfff&JR4333IffffRĪR4333IffffRI8R43333I3333RIlQ4333uKffff9QhfffFK3333)Q̜zKPQhfffzKffffQ`K3333G&QlK@'QKy%QKffffnQhfffK QhfffK3333QKQ4333sKffffQhfffKQhfffK QKQ9K3333QLKffffQ43333KQ4333SKffffJQhfffFK QKffffQKffffQ̼KffffQ̬KffffQK3333&QK3333c,Q4333K=2Q4333÷K}7QKffffZ9Q@Kffff;QpK3333;QhfffvK8Q4333K33338QKh:QKffff@Q̼K3333BQhfffFKffffIQyKTLQK3333SQ9K3333VQKVQ|K3333#SQhfffFK3333KQhfffƼKiOQhfffK3333[ZQܸKffff*]QhfffFKffff`QyKffffgQ4333KffffViQ4333KjQ43333KffffjQPKffffkQhfffK̼tQhfffFK3333vQ4333#KhwQhffffKxQIK̴~QK3333;Q̼K|Qhfff6K3333zQ4333ӇKffffxQhfffpKlQ4333uKQ43333KQiK3333gQPKffffvQ4333KPQ4333K3333Q#K3333OQ|(KQ4333.K3333+Q/K3333Q4333#(KffffJQhfffKQpK3333QKQiK3333SQ4333c#K̴Q4333&K3333;QhfffKR43333Kx RKX R,JiRJffffQ4333CJ Q0J3333wQ`JQ43333KoR2Fffff6rR8F0wR8Fffff~RhfffV?F3333RDF!R4333KFzRSF3333'xRI]FtRkFffffrRyF3333rR4333C}FUrRLFnRFffffQRY8FaQR4333s2FPRhfff,F3333KMR*FAR)1Fffff5Rhfff:F1RAFffff0RhfffFFF6RQF3333k9R4333#[F?RcFRqFQR tFQRlsF3333RYoFRhffffhFRhfffeFffffRhfffeFRhfffviFRloFRqFTR WIffff&RbITRhfffaIR^IR\WIR̼SITR9LIR4333CIffff^R4333=IpR4333=IffffRhfff?IaRhfffVAIDRhfffFIR4333SJIRhffffLITR WIR4333kH]R@uHR4333ӈHR`HdRhfffH$RpHR4333HRhfffƑH5ŘHffffR9HRhfff~HR}HffffRhfffxHRhffffqHQRmHARIkHdRlHffffR4333gHRcH3333RbHR4333kHffff.R9GR4333GpRhfffG̴RhfffGR0GRhffffG@RG3333KRGRGHRhfffvGhRGffff.R9G̪REffff޳R EffffR9E3333RETR4333SEffffRE3333RE RERE̪REuhRhfff&iF̌jR̜jFtlR4333cjFffffbnRfFoRhfff6`F5sRWFatRySFItRhfffNF3333qR4333GFTnREF3333kREF iR0NF4hR4333#WFffffvgR``FuhRhfff&iFRhfffvIR0IRIRhfffI4R4333cI3333ǮRhfffIR4333I̜R4333IffffR4333ӶIRI\RIPRÌR I4R9I3333CR IpRIRI̔RIiRhfffƣI%R4333I$R4333I3333RiIRhfffvIRhfff%IffffR)0IR+IffffR4333+I`R IffffvRIRI3333RlIR4333I3333kRIR4333IERY IR4333I3333R@IR`IRhfff%IsR4333ErR0EffffZuR EyR E |RhfffE)}R4333EREffff&R4333ERhfffEffff}R4333EvR4333SEuREsR4333ER,I3333RhfffIffffRI̬RIR,IR43333IlR4333IٜRI,RhfffIؔRhfffI3333R4333IRyI3333cRIRIR,IffffR4333F̔R0F3333˝RFRyF`RFffff&RF3333_RF̼RhfffFF̨R4333Fffff&RF̜R`FR4333FRFDR|F0RhffffF\RF3333R@FRFffffR4333FPK!P4333#KP4333K8P4333K,PKaPKaPKPhfffvKffffPK3333PK̠P4333KPPKPK33337P4333SK3333OPKP̌KTPhfffKffffPKPhfffFKaPɘK̨PK3333{P0KPIK33337P4333SKffffvQoK|Qhfff6wK3333cQ4333xKffffQ{KQ4333yK`Q yK9QuK̸QhfffVtKQpKQKݙQ43333KpQKȢQhfffKffffzQhfffFKDQ4333SK7@d/@7@0333g/@Y7@l@/@83336@0333/@833336@hffff.@6@y.@̬6@S.@6@y1.@Y6@.@hffff6@0333S-@hfff6@-@6@0333-@83336@hfffƓ-@6@hfffq-@6@L`-@833336@0333SS-@w6@hfffFD-@̌j6@+-@̬a6@-@8333Sf6@hfff&-@l6@hfff,@yp6@,,@hfffs6@hfff,@83336@`y,@96@ h,@6@R,@̌6@@A,@`c6@l,@V6@hfff,@8333H6@0333+@C6@+@8333S,6@9+@8333 6@hfffF+@@6@+@̌6@u+@hfff&'6@@+@36@+@̬86@y*@̌;6@,*@hffff:6@*@36@hfff*@8333s(6@n*@5@`fff9*@`5@*@5@)@hfffF5@)@hfff5@{)@5@0333f)@5@03333[)@,6@X)@hfff6@c)@;6@@k)@83333Z6@`fff&R)@j6@)@hfffc6@ (@lo6@0333(@y6@,B(@8333x6@0333"(@hffff}6@`fff(@y6@(@6@0333'@l6@V'@8333S6@`fff('@6@`fff&'@hfff6@ &@hfff6@03333&@̌6@`fff&@Y6@y&@833336@0333&@Y6@̈&@ 6@0333Sb&@83336@&@,6@%@@6@%@6@y%@6@`ffff%@l~6@0333%@̬^6@,%@hffff<6@%@833316@`fff%@(6@0333%@6@%@ 6@9%@hfff6@`ffff%@5@,y%@5@ I%@ 5@`fff7%@5@L&%@5@`ffff%@hfff5@Y$@̹5@̬$@hfffƮ5@`ffff$@5@z$@hffff5@`fffo$@,5@`ffffj$@833335@0333Y$@`e5@0333$@9Z5@03333#@̌C5@#@l5@,m#@83334@`fffE#@4@`fff #@83334@0333"@ 4@"@4@`fff&"@hfff4@L"@ 4@`fffƌ"@8333W4@0333A"@4@03333D"@3@y&"@8333s3@`fffF"@3@0333 "@83333@0333 "@yf3@0333"@@%3@,"@@ 3@0333s!@2@0333!@hffff2@̌!@2@0333!@y2@y!@83332@ !@l3@Ln!@83333@0333O!@Y3@2!@ 3@9.!@83333 3@,!@hfff3@!@ 2@`ffff @Y2@0333| @̌2@9e @833332@U @8333s2@  @l2@ @t2@`ffff @hfff&=2@l @̬1@@hfff1@03333@@1@03333@ ~1@`fff@o1@L@8333f1@̉@9?1@@@833331@@l1@`fff&@0@`fff@8333s0@0333:@hfff0@033334@0@`ffff@hfffƖ0@03333@ٌ0@0333W@0@@v@83330@p@u0@`fffF@hfffg0@`fff@a0@0333@00@`ffff~@0@I@L/@@pfff/@0333@ g/@`fff&@@333-/@`ffff@.@Y@/@`fffj@@333/@0333s@/@@/@&@ .@@@@.@Lh@@333.@* @@3333.@ @;.@Y!@-@ j!@@333-@`fff!@ -@!@pfff-@`fff!@@3333w-@9!@-@ "@pfff&,@03333h"@pffff,@0333"@[,@ "@ ,@@#@̌,@l-#@Y+@0333b#@pfff,@#@̌G,@#@̌|,@#@pfff&,@Y#@pfff&2-@#@@333-@`fff&#@pfff$.@0333#@@333C.@9#@pfffb.@`fff#@٣.@#@@333/@̬#@LO/@$@Y/@L-$@.@ o$@Y.@$@pffff.@0333$@@333C.@`fffL%@pfff&#.@%@L.@03333:&@L.@`ffff&@pffff.@0333&@@333s>.@ '@@333'.@I'@pfff,.@r'@).@`fff'@pfff.@0333s'@-@y7(@-@B(@pfff-@(@@333-@0333)@-@̬O)@?-@u)@pfff-@0333)@L-@)@pffff,@`fff& *@Y},@'*@ ,@03333(*@Y+@Y*@pfff+@hfff*@@333s6+@h+@@333+@0333D,@*@hfff,@+@9,@pfffH+@0333B-@@+@hfff-@@[,@03333.@pffff,@0333/@L~-@%0@l.@dfffF0@.@̌0@̌/@4333h1@/@1@pfff0/@IV2@@333sF/@43332@̌X/@43@@333e/@dfff~3@Yx/@p3@L/@3@/@̜M4@pfff&/@X4@/@\f4@@V/@ 4@,/@4@pfff/@4@@3336/@4333S4@Y.@Yi5@n.@w5@].@5@ [.@dfff5@@3333X.@ 5@̌-.@k6@@-@dfff6@pfff.@4333#)7@A/@dfff&I7@/@q7@hfffP0@dfff&H7@L0@dfff 7@8333E1@dfff6@83331@dfffv6@9;2@dfffU6@2@dfffV6@03@dfff5@hfff&3@dfff65@%4@dfffc5@8333s4@4333'5@5@dfff4@5@43334@hffff6@4333cq4@hfff6@433344@̬7@4333C3@8333S7@43333@83337@4333#3@ 8,@)@@g;@0333%@D%8@T!@18@`fffN!@̌88@l7!@8333.8@ @Y58@ @J8@03333 @ `8@0333S @t8@z @8@0333b @8333s8@lF @9@@L39@L;@8333S?9@0333@=9@̌@l.9@:@̬09@@hffffG9@@8333sa9@`ffffU@ 9@03333@83339@B@Y :@`fff&@@:@ }@Y+:@ @H:@@\:@̌@O:@@@S:@@8333sZ:@03333a@hfffk:@@̌r:@`ffff@hfff:@`fffF@:@0333@8333:@03333@hfff:@03333@9:@0333sk@Y;@@$;@L@hffff.;@Y@6;@`fffy@hfff:;@@@hfff;;@Y@A;@(@U;@̾@@g;@o@l;@@hffff;@̌@hfffF;@̼@:@M@8333s:@`fff?@:@`fffI@8333:@@W@l,:@@@hfff9@@9@"@l9@?@8333sf9@ @yH9@03333@@8333?9@`fff&@83339@`fff@y8@̌@8@`ffff@hfffo8@03333 @Q8@@L:8@@7@ w@833337@0333C@̌7@L@ 7@@j7@ @P7@0333s@hfff87@@̬7@@,6@0333@8333S6@@@y6@03333@833336@0333]@6@@@8333s6@`fff@9v6@@ s6@ٞ@8333l6@03333@5@@5@`fff& @5@0333@hfffY5@>@8333D5@J@8333:5@0333s5@hfff& 5@`fff&T@̬4@ @4@ @4@@4@@̌|4@̌*@d4@`fff@833394@̌Q@4@`ffff@3@ @y3@0333s[@3@L|@@3@̌@R3@0333sH@̌3@̐@2@@,2@̇@2@̌b@hfffF2@@83332@`ffffw@92@`ffff@2@n @@2@ @hfffƍ2@`fff @83332@ 3333 @8333sy2@`fff @8333sQ2@ @8333<2@`ffffW @hfff12@ @83333)2@ @2@h @2@{ @2@h @̬1@j @91@w @`1@Ln @1@`ffff @hfff1@K @}1@ @ p1@z @hffffL1@ @hfff91@ @hfff1@t @̬0@LJ @`0@H @Y0@ @hfff0@`ffff @hfff0@ @ 0@ 333 @ z0@ 3333R @hfffz0@@Yw0@@hfffu0@,@8333w0@`ffff@f0@ 333@8333Q0@W@8333s@0@A@8333.0@)@"0@@8333S0@ 333@8333s0@ 3333@83330@ 333@`0@ 3333\@hfff0@`fffl@,0@/@0@@@0@D@0@ 3333@/@:@/@ 3333@L/@L@ٲ/@@̌/@ @pffffZ/@`ffff @pffff)/@`ffff @@333.@ @pffff.@ @z.@ @pfffA.@@.@`fff@.@@".@@;.@ @̌E.@%@F.@F@,.@`fff@̌ .@0333#@pfff .@`fff&o@-@03333@@333s-@;@pffffv-@h@k-@̌@R-@C@H-@Y@4-@L@pfff%-@@@ -@`fff@"-@g@@3333+-@0333@*-@03333@;-@`ffff@;-@`fffu@2-@03333@̌'-@@-@@-@`fff@,@@,@`fff'@pfff,@X@@3333,@ف@@3333-@̥@pffff-@@pfff&f-@@@z-@@@3333-@0333C@̌-@v@L-@ 9@pfff&-@03333@@333.@@#@@3333,.@@@333sP.@A@pfff&_.@`fff&@i.@@pfff}.@`fff @.@n@.@Y@@333-/@`ffff@ g/@`fff&@pfff/@0333@L/@@0@I@00@`ffff~@a0@0333@hfffg0@`fff@u0@`fffF@83330@p@0@@v@ٌ0@0333W@hfffƖ0@03333@0@`ffff@hfff0@033334@8333s0@0333:@0@`fff@l1@`fff&@833331@@9?1@@@8333f1@̉@o1@L@ ~1@`fff@@1@03333@hfff1@03333@̬1@@hfff&=2@l @t2@`ffff @l2@ @8333s2@  @833332@U @̌2@9e @Y2@0333| @ 2@`ffff @hfff3@!@83333 3@,!@ 3@9.!@Y3@2!@83333@0333O!@l3@Ln!@83332@ !@y2@y!@2@0333!@hffff2@̌!@2@0333!@@ 3@0333s!@@%3@,"@yf3@0333"@83333@0333 "@3@0333 "@8333s3@`fffF"@3@y&"@4@03333D"@8333W4@0333A"@ 4@`fffƌ"@hfff4@L"@4@`fff&"@ 4@"@83334@0333"@4@`fff #@83334@`fffE#@l5@,m#@̌C5@#@9Z5@03333#@`e5@0333$@833335@0333Y$@,5@`ffffj$@hffff5@`fffo$@5@z$@hfffƮ5@`ffff$@̹5@̬$@hfff5@Y$@5@`ffff%@5@L&%@ 5@`fff7%@5@ I%@5@,y%@hfff6@`ffff%@ 6@9%@6@%@(6@0333%@833316@`fff%@hffff<6@%@̬^6@,%@l~6@0333%@6@`ffff%@6@y%@@6@%@,6@%@hfffF6@03333%@6@%@A7@`ffff$@8333O7@$@hffft7@9Y$@hfff7@`ffff$@8333s7@0333S#@7@0333k#@̌7@0333S:#@hffff7@`ffff"@7@"@w7@:"@yv7@0333"@83333}7@0333!@,7@0333!@hfffF7@!@̌7@0333!@L7@!@hfff7@`fffw!@hfff7@`k!@8333S 8@0333a!@%8@T!@pW9-@6433311@W ".8DMy+9L0@iD9 0@N943330@iR91@pW9dfffV1@LV9L1@ 9433311@9,-1@8@1@`9 1@y+9L0@q70333.@033337 -@ 70333-@0333703333-@`fff7`'.@0333S7 U.@`fff&70333|.@`ffff7 .@0333703333.@ 7@.@\70333.@y7`R.@`fff7LG.@q70333.@`fff8p0@8P0@9dfff0@03339 0@03339dfff0@033380@̼80@0333S843330@`fff8p0@6̼<0@`fff680@y6̼90@ٿ6dfff80@P6dfffF+0@60@ɵ6 0@ 6/@0333S6hfffF/@03336̌ 0@`fff6&0@6̼<0@N8l-@b8-@`fffp8l-@~8-@`8-@033338hfff-@Yd8.@YT8 .@K8-@N8l-@0333s8\0@ 84333ӗ0@`8p0@80@9>84333s0@`ffffH8p0@`fffR8<~0@e8P0@`fffd80@p`843330@`ffffE8dfff0@0333s8\0@i60@`fff60@̜6ܮ0@ 6l0@̬60@03336L0@̜60@`ffff6l0@i60@.7hfffF.@57hfff&D.@`fffv@703333[.@0333>7hfff&{.@`fffF?70333.@033357hfff.@0333C#7̬.@̌7l.@70333SU.@.7hfffF.@a0D@2333SJffffnT@/:mHMPiz'ZB\!&'d''''(()(d(s(((((()/)G)S)\)u))))))))))** *+*4*=*Q*[*b*h*o*{*********** + +.+:+F+R+]+i+y++++++++++,,,*,4,O,],k,x,,,,,,,,,-4-G-s--------..-.:.S.m.z......../ //$/1/=/N/W/`/////`QK@ `K@`3333 K@3333` K@3333_` K@`3333K@P`DJ@`ffffJ@ffff`3333[J@3333݆`IJ@`J@3333_`3333sJ@&`J@`3333kJ@ffff܎`J@`J@ffff~`yJ@3333߄`3333KJ@`J@`_ffffH@͙_H@ffff_0H@_3333H@ffff_H@_ffffH@_0H@_H@\_ffffH@й_H@D_̤H@3333_3333H@̈_H@ffff_ffffH@P_3333H@_H@_ffff~H@H_H@ffffv_pI@3333_\ I@3333O_ I@_̌I@_I@-_ffffI@`_3333; I@_ I@\_ffffI@3333w_ I@_I@_3333I@0_I@3333O_I@ffff>_I@ffffJ_YI@3333_ffff6I@_I@̴_%I@t_((I@ffff_)I@̠_I,I@_8I@_3333c;I@8_3333K`3333mI@_ffff&nI@ffff_ffffiI@̠_QI@@`K@3333s@`3333K@@`3333L@ffffA`YL@!C` L@F` L@ffff8M`ffffL@ffffDO`8333L@4333T`!L@W`+L@ffff]`ffffv0L@3333b`3L@af`9L@̾j`(@L@o`3333CGL@4333gr`xfffLL@3333t`LLL@ffff`z`̄KL@̨z`WL@Z|`ffff^L@{`3333{eL@~`3333hL@ffffV`3333mL@4333`zL@ffff`fffffL@ffff`3333+L@Њ`3333+L@`3333L@n`iL@4333`xfff^L@(`L@`L@ `3333L@`L@V`AL@ `xL@ffffڣ`3333 M@4333Ϩ`hfffM@`$+M@֬`4M@|`q@M@̐`pLM@C`ffff>ZM@4333`aM@6`3333eM@`lM@̀`sM@ffff`HxM@`|M@`,M@ffff `33333M@`M@4333`M@`M@4333`M@`ffffM@43333`hfffM@H`M@ffff`pfff~M@ffff,`|M@`M@ffffX`xfffM@`$M@:`M@{`HM@`M@affffM@ffffL a3333kM@ffffaxfff6M@3333a3333{M@! a`M@ffffa3333úM@aԣM@3333a|M@ffffa4M@a̔M@ $affff>M@(a|~M@.asM@33330a3333+uM@ffff~/a~M@f1aIM@ffff2ahfffM@J6aM@;aѯM@4333 @aM@Eaffff^M@*Ja9M@NayM@;TahfffM@3333Vaffff^M@[affffM@daa3333#M@ea3333 N@bda3333N@4333ba#N@4333baxfff+N@3333ga|+N@naffff*N@ffffuahfff*N@̔zaffff^ N@3333%aqN@3333MafffffN@}a\&N@ffffАa3333N@ffffha@333+!N@axfffn&N@aKN@aP@apfff"QP@acP@avP@aQ@`0333?Q@dfff`@Q@4333?`hfff @Q@2333`<333@Q@j`AQ@4333`BQ@`)CQ@0`5EQ@dfff `hfff"GQ@dfff `hfffSQ@`RQ@dfff`UQ@^`SQ@(`TQ@dfffZ`dfff6[Q@ffff^`dfff\Q@`]Q@J`_Q@`dfff]Q@dfff`^Q@`pfffbQ@`hfffdQ@dfff(`hQ@dfffr`8333jQ@`hfffkQ@̾`lfffjQ@`dfffhQ@J`eQ@z`cQ@dfff̼`hfffaQ@2333'`lfff~`Q@Q`|[Q@̖`XQ@H`QQ@`hfff.PQ@dfffV`HSQ@5`WQ@:`YQ@e``ZQ@ffff8`[Q@`4333^Q@`4333`Q@ffffJ`LhQ@`̤iQ@ې`4333+iQ@y`8333giQ@`(jQ@23335`$kQ@S`XlQ@0`hffflQ@ffffB`pfff:mQ@3`nQ@``хQ@̼<`4333ˆQ@\7`8333KQ@̞5`YQ@3`lfffQ@:1`<333Q@81`4333Q@̾4`<333Q@̮N`0333qQ@ffffV`4333kQ@dfffZ`iQ@2333^`4333shQ@f`hgQ@i`<333/fQ@dfff"o`dfffeQ@{`(cQ@dfff~`8bQ@` aQ@`YQ@ffffL`<333WWQ@`SQ@f`<333{QQ@`PQ@(`8333+MQ@`}FQ@ܢ`8333AQ@M`=Q@ffff `83338Q@b`6Q@`pfffv2Q@&`E1Q@dfffL`Y/Q@j`/Q@ffff&`hfff1Q@9`lfffv4Q@ƪ`t5Q@dfff`<6Q@`4333'4Q@|`pfffB6Q@ `pfff 8Q@Z`8Q@`dfffV9Q@̦` ;Q@dfffx`<>Q@̤`8333@Q@,`BQ@`EQ@q`IQ@4333u`<333JQ@؆`LQ@L`OQ@m}`RQ@4333z`̀UQ@dfff.y`4333WQ@ffffx`8333XQ@>z`YQ@ffff:y`[Q@7t`a]Q@r`8333]Q@2333j`[Q@dfffi`̐ZQ@dj`WQ@gi`8333GWQ@fffff`̨[Q@,e`hfff]Q@dfffc`h]Q@b`\Q@n``p[Q@_`9WQ@ffffl_`5PQ@_`aMQ@B]`4333;RQ@ffff\`8333{TQ@ffff$U`^Q@̂P`udQ@PK`iQ@C`nQ@N2`tQ@y(`8333vQ@~#`qxQ@ !`4333yQ@`{Q@`}Q@4333G`}Q@ffffV`EyQ@4333 `wQ@4333m$`HuQ@ %`4sQ@[$`pQ@4333A#`mQ@4333!`lffflQ@`mQ@L`pQ@`sQ@` `8333s}Q@ffff~ `4Q@dfff`4333Q@2333`4333SQ@_<3333Q@0333_Q@hfffV_4333Q@`pfff.Q@e`hfff Q@dfffJ_=Q@2333`dfffnQ@q`ȚQ@``̴Q@`dfffQ@K`?Q@l_Q@$_$Q@hfff._Q@dfff_Q@dfffv_Q@_QQ@P_4333Q@W_a}Q@dfff_vQ@ի_qQ@-_nQ@4333_bQ@_]Q@4333z_ZQ@n_QXQ@̘a_VQ@X_YVQ@K_d[Q@J_̴^Q@P_8Q@,]\8Q@a]7Q@@]pfff26Q@hfff]5Q@,]83336Q@hfff]hfffN=Q@]<333W>Q@ ]l>Q@\Q=Q@4333\0?Q@0333\$?Q@d\pfff>>Q@dfffN\8\8333Q@̸}\hfffQ@T\Q@g\8333#Q@#\8333Q@\Q@dfff\8333KQ@hfff\8333 Q@!\0333sQ@dfffB\hfffQ@\4333cQ@\0Q@4333\pfffP@Q\<333P@dfff\P@dfffv\P@dfff\mP@4333\P@Զ\P@l\P@4333{\P@4333\4333P@0333?\lfff P@D\P@hfff*y\=P@̤k\P@dfffM\P@D\hfffP@H8\8333P@1 \̤P@\0333P@!\ P@dfff&\hfffP@{\P@0333[xP@[pP@[̬P@̜[,P@L[̤P@[hfffP@[hP@\[̜P@0333[DP@dfffΗ[P@0333׍[pfffP@hfff[̀P@4333[P@[hfffP@{[0333P@0333y[P@4u[iP@hfffp[|P@k[P@Wh[P@4333[N[̴P@43333E[|P@4333oB[]Z8333$Q@dfffn[ZTQ@'XZ|Q@dfffzLZ$Q@|FZhfffQ@dfffBZlQ@hfff?Z̬Q@m=ZQ@0333;ZdQ@]:ZQ@H8ZpfffQ@A1ZQ@)ZQ@dfff(Z̰ Q@O*Z Q@4(ZpfffQ@'Z0333 Q@hfffrZ<333Q@0333c Z4333Q@4333Y̠Q@YlQ@WY\Q@YQ@dY,P@۵Y8333P@IYP@4333YP@̀YP@lYP@Ylfff6P@xY8333P@dffflYhfffZP@̄cY\P@0333+FYpfffP@̰AYP@hfff6Ypfff"P@/YP@hfffn'YlfffP@A!Y`P@0YP@̠ Y8333P@xXhfff&P@9Xpfff.P@X8333P@dffffXPP@4333XP@X4333sP@4333X̤P@X<333P@dfffXP@_X̨P@hfffXP@XP@ЦXTP@4333XhfffP@8X<333Q@XQ@dfff&X8333;Q@4333kX̤Q@̌XQ@XhfffBP@XhfffBP@~XEP@{X}P@fX8333cP@]X|P@QXP@qLXpfffP@hfffIX}P@4333JX8333OP@4333HXP@JXhfffP@7MXP@0333UXP@bX|P@MoXlfffP@szX4333P@dfffX4333P@dfffRXhfffP@dfffX$Q@XQ@X4333wQ@XaQ@`XlfffzQ@0333X Q@pXPQ@4333X1Q@XDQ@XQ@lXQ@XtQ@XPQ@4333˅Xpfff*Q@rXdfffQ@hfffNzXQ@hfff|X0333 Q@4{X!Q@4333uX"Q@hfffhXQ@0333cXeQ@hfff^X̰Q@0333CZX0333Q@}UXdfffQ@QXQ@HX0Q@DXMQ@?XQ@hfff>XXQ@3(XQ@XQ@hfffX̐Q@XdfffQ@h.X<333Q@hfff6.X0333{Q@hfff%XQ@"Xpfff Q@̘XpQ@XQ@dfffX Q@hfffX<333#Q@WQ@hfffNX Q@0333 Xlfff:P@ XP@0333XxP@XpfffrP@XP@4333 XP@4333 X P@ Xdfff~P@ XeP@dfffXhfffVP@0333CWpfffP@4333WpfffFP@}WhfffP@W<333gP@WP@4333WhfffP@dfffW8333P@dfffW8333cP@hfffWP@WeP@ W0333P@4333WP@4333?W8333SP@$WlfffP@WAP@WqP@1Wlfff޽P@(WlfffP@4333WhfffP@?X43333P@XhfffP@ XdfffڿP@mX0333{P@4333X P@4333 XPP@XPP@hfffXlfffRP@̨WdfffrP@ W4333+P@WuP@0333gWyP@W0P@hfffjWxP@XP@0333XP@[XP@4333;WP@WP@dfffbW$P@WļP@WľP@̌WlfffP@0333WP@4333W<333P@dfffW$P@W P@dfffW P@Wlfff2P@|Wdfff^Q@KWQ@̔WhfffQ@WdfffQ@dfffWTQ@hfff"W8Q@4333WhfffQ@̤WQ@0333Wlfff* Q@̐W<333Q@dfffNW0333Q@GWQ@_{W0333SQ@iWlfff"Q@^WT&Q@4333\W'Q@fWpfff'Q@dfff6iW̄(Q@hfffFkW4333+Q@4333;jW(2Q@0333kjW̤5Q@̜kW8Q@4333mWhfff;Q@qW >Q@sW?Q@dfffvW@Q@]xW?Q@YyW>Q@ |Whfff8Q@uW̄4Q@4333'W92Q@dfffW̬0Q@̜W/Q@Wpfff1Q@mWh3Q@WX:Q@pWlfffR=Q@$W8333/CQ@hfffZWGQ@1WHQ@hfff2WpfffHQ@XWIQ@WpfffzQ@W8333oQ@hfffWQ@hfff X٨Q@0333X<333Q@X8333oQ@!#Xpfff³Q@D#XQ@qXpfff&Q@0333XhfffvQ@!X!Q@H X)Q@dfffX0Q@X8333KQ@̔XhfffZQ@hfffX0333Q@]XQ@Xpfff^Q@X|Q@̤WHQ@#W(Q@tWQ@lWQ@|W<333gQ@WQ@WqQ@W4333wQ@WXQ@hfff&WhfffBQ@4333WQ@$W8333Q@WlfffQ@WIQ@0333kWQ@0333W4333Q@WlfffQ@ĸWQ@WQ@W(Q@4333W<333Q@mWQ@̤W8333OQ@WQ@WdfffQ@̀WlfffZQ@dfffsWpfff Q@4333oWhfffQ@dfffpWQ@hfffrW(Q@hfffpWQ@0333dWeQ@ZW8333SQ@gPWlfff~Q@BW|Q@hfff>W8Q@0333W<333Q@0333=WQ@2WQ@)WQ@Q$W]Q@W̠Q@WQ@4333/WQ@ WQ@$WQ@aW8333Q@WpffffQ@WiQ@hfffVpfffFQ@0333GVݒQ@V1Q@VݕQ@VQ@Vlfff&Q@VQ@VhQ@V8333WQ@hfffnVpfffvQ@4333V}Q@Vlfff*Q@4333WQ@hfffZ WQ@̔WYQ@4333WQ@@WlfffڌQ@W̠Q@dfff WQ@4333WlfffRQ@ WhQ@WhfffQ@hfffVyQ@4333kW~Q@9WyQ@43330W̰mQ@8WjQ@̰6WiQ@dfff^3WiQ@$)W1jQ@̔WkQ@dfffWkQ@WiQ@W̘hQ@a W̜fQ@]VbQ@XV4333bQ@hfffV\gQ@4333V̐iQ@dfffVCiQ@V4333hQ@dfffV<333gQ@V4eQ@QVmbQ@(V̤aQ@pVbQ@мV`Q@IV̌`Q@hfffVlfff`Q@VI`Q@՜Vm^Q@̘V8333?]Q@٠V|\Q@V\Q@hfffƫV`[Q@VlfffYQ@dfffڲV0VQ@V8333RQ@4333V0333QQ@QVQQ@dfff&VRQ@4333V,TQ@hfffV`TQ@hfffvV]SQ@4333VUSQ@hfff.VpfffFRQ@dfffV<333FQ@hfffVTdfffδP@TP@̬TMP@T8333gP@4333oTħP@dfffTP@dfffT@P@̸TP@TP@4333Tlfff—P@dfffzTP@4333TlfffҘP@43337T|P@4333TP@0333OT83333P@TuP@TP@43333USP@dfff UӮP@P U P@dfffUP@pUP@ṲP@qUP@U43337P@U8333[P@dfff!UhfffP@dfffv"UlfffBP@4333S,UP@ 6UlfffP@BU0P@4333GGU<333 P@0333GUP@4333+AUϷP@4333>UlffffP@9ULP@43336U4P@43337/UP@hfff(UP@&UlfffP@dfff%U4333ӶP@iUhfffP@hfffFUP@ UpfffvP@hfff UlfffƥP@UP@ThfffP@hfffT8333P@4333 T4333CP@hfffT<333P@TP@0333UˎP@U̬P@UhfffP@U8333P@hffffU8333P@hfffUyP@hfff2(U0333KP@4333#:U]P@(FUpfffҔP@ALŲP@4333SUpfff.P@M\UdP@fUlfff^P@rUP@ UMP@dfffUP@hfffRUyP@,UlfffP@dfffU8333GP@4333ϬUlfffVP@AUP@dfffίUP@ثUP@lUpfffP@CUhfffFP@V|xP@dfffvVyxP@=VI{P@٠VzP@0333Vpfffz{P@شV }P@Vlfff}P@̌V4333}P@dfffVVhffff}P@XVdfff|P@@Vlfff>yP@VuP@dfffV̬xP@(VyP@VzP@hfff2V̠xP@4333'V0333tP@4333 V<333sP@${VqP@dfffnrVpfff&oP@lfVtiP@xOV\P@HVQYP@dfffV>VhfffJVP@̨ VQP@}UQP@U̬PP@U<333cNP@4333ULP@,U8333FP@4333UpfffDP@̴UP;P@U4P@U̠P@4333U[P@U̜P@dfffV4333 P@@VhfffP@0333)VP@U4VO@̸=VP@CV4P@0333LVHP@0333gMV<333P@FV̔O@4333kHVO@0333MVO@4333YV<333P@hfff]VdfffP@0333`VP@HcVpfffP@igVP@nVP@hfffpVhfff^P@rV P@sVhfff P@dfffV P@0333V,P@ViP@0333}V(P@wVIO@vVxfff~O@{VhfffO@VO@4333ÊVHO@ЃVQO@hfff&V(O@܀V@333O@4333VhfffFO@4333V)O@4333VO@0333VxfffnO@$V,O@4333+V̤O@VO@O@dfffVO@|VO@-VO@DVO@0333/V0333O@0333 VpfffO@VyO@0333sVxfffO@VDO@hWO@hfffWhO@hfff~ W0333SO@̨WO@4#Wpfff.O@>WO@[WP@̐lW<333k P@0fW̘P@dffffWIP@iW̄O@jWO@cWO@̘ZW8333CO@4333KQWO@ QW9O@4333TWpfffO@dfffVXW4O@YWyO@9XWgO@4333PW̤O@hfffJWlO@0333!WpO@WO@0333 WO@dfff WO@4333 WO@W8333O@W O@WO@0333W0333O@!O@i7W1'O@dfffIW.O@$MWxfff.O@xKWhfff,O@7?W$O@hfff:W8333[O@9WO@03337DW0333+O@0333DW\O@hfffAW O@dfff AW O@dfffDWO@JWxfffNO@dfffbVWO@dfffrWWO@RW̤N@QWN@PUWiN@0333WWN@HM@iFW@333>M@5;W̼M@03335Wxfff M@Y/W L@,WxfffL@dfffVW8333L@0333W8333CL@0333WL@%W4L@WhfffFL@dfff#W03333L@M'WpfffL@03337+W~L@0333;/WyL@hfffZ3W@333vL@3W8333vL@4333k.Wpfff~wL@)WzL@̨ W8333ۂL@3W0333L@dfffjWpfffޅL@4333WL@W|L@W<|L@Whfff&L@4333'W)L@4333VL@pV@333L@dfffV8333L@VL@τV̤L@̜rV̜}L@UV,uL@dfffMV!qL@TK@T/K@T K@4333+TxfffK@hfffT0333K@̀TxfffmK@hfff T hK@T@333=K@T8333-K@%TxfffNK@9TK@dfffސTW K@hfffZT̼K@hThfff^J@ TJ@TJ@43333T03333J@4333T̤J@0333[T@333J@0TСJ@TJ@hfffTtJ@ThfffvJ@̨TpfffJ@0333Txfff{J@TuJ@TxfffNpJ@HT8333gJ@hfffvTaSJ@hfffoT$HJ@\fT`7J@dfffdT@333/J@4333#gT0333{)J@QjTpfff%J@qThfffv J@tT@333J@!tTJ@xiTJ@0333+cT`fffNJ@dfff]T,J@hfffzYT4J@hfff>RT(333k J@$HTJ@=TqI@4333'-T0I@*TI@hfff%ThI@Txfff6I@T8333SI@0333_T̼I@hfffTxfffI@ +T8333I@hfffz6TI@2TI@X+TpfffnI@̜ThfffVI@̌T9I@Tpfff~I@̠T4I@0333wSI@̄S0I@hfffSI@1S0333pI@DSpfffaI@]SjI@SiuI@4333SxfffFI@S I@0333S8333CI@hfff2SؗI@IShfff6I@S\I@dfff&SxfffI@|SI@ S`fff6I@4333S8333I@S8333I@̬ShI@SI@SI@xSxfffI@hfffS0333[I@S8I@S\I@hfffRSqI@4333StI@hfffS(333+I@͹S8333I@pShfffƢI@S$I@S I@dfffήS̬I@!ShI@0333S8333kI@0333SI@0333ӾS$I@hfffbS@I@S,I@hfff·S8333I@S0333CI@S0J@SJ@cSLJ@0333wSD J@St!J@hfff֠S8333C%J@0333S'J@ܡS3J@4333Spfff>J@oShfff~DJ@hfffRSYPJ@S0333SJ@dfffSIaJ@0333;SgJ@/SmJ@YSsJ@S|J@|ŠJ@SdJ@}S`fffJ@dfffShfffJ@lS J@=SJ@dfff6S@333J@̔S8333J@4SJ@hfffSqJ@pŠJ@ SxfffJ@4333SXJ@̰SJ@0333SQK@dfffSK@LSxfffK@yS K@qSK@hfffS K@cSK@hfffSK@SK@0333Shfff!K@hfffShfff+K@dfffvS2K@hfffRS0333>K@DS8333MK@dfffnSxfffPK@S0333RK@SpfffSK@0333SxfffUK@ShfffFYK@0SpK@(S9tK@0333gSiK@hfffnSxfffƈK@0333?Spfff^K@yS8333CK@dfffqSHK@lSxfffK@TS8333K@̐JShfffK@̤DSpfffK@ N@4333pQY8N@`pQ03331N@eoQ*N@WmQ$N@̄hQ4N@=hQ8333kN@gQhfffN@dfffNhQN@dfffkQpfff N@rQpfffN@0333}QGN@̘QN@Q@333[N@QM@ݝQDM@0333QxfffVM@sQM@nQM@kQtM@UhQ1M@eQtM@eQiM@̌fQ̴M@0333iQTM@OlQ̄M@4333mQxfff>M@kQpfffM@YQM@Q3M@#Q0333 M@QM@hfffQ M@03333&QM@4Q@333L@M@4333P ;M@P)*M@P0333%M@TP4"M@hfffQM@4333QhfffvM@dfffP"M@Ppfff'M@̈P.M@aP3M@+PxfffV1M@$P4M@4333 P@333M@dfffP@333 M@hfffPxfffM@hPL@dfffvPhfff M@PxfffM@dfff*P8333M@tP@333SM@dfffrPxffff&M@lPh/M@hfff>Pi7M@P<;M@7P>M@P8333CFM@P|QM@hfffPAYM@P`fff]M@1PDeM@0333P0333eM@1PbM@ĊP]M@хP@333[TM@4333ۂP̄MM@P̌HM@4333P$7M@0333'P17M@{P|DM@{Pxfff6IM@0333c{P83333NM@0333|Phfff.SM@\P ^M@(PdM@P0333 iM@}P8333kkM@vPxfff^lM@uP$nM@0333zP0333rM@zP@333uM@uP}M@hfffrP}M@4333mP<|M@4nPTM@$nP0333 M@4333lPM@bP̄M@0333aP8333M@\YP@333M@XP̴M@dfff_PM@fP,M@4333hPYM@jPxfffM@lPhfffNM@DlP\M@IjPhffffM@0333fPHM@hfffdP@333[M@hfffbPM@`P٬M@YZPQM@ZPDM@Q_PPM@h^P03333M@aVPIM@QPiM@DP8333cM@dfffrBPpfffM@hDP@333M@JP(333+M@PP0333kM@VPiM@0333ZP M@i^P0333M@hfff"_PM@hfff^PYM@̼[PdM@dfffYPM@VPM@0333{RPxfffM@MPhfffM@|CP0333[M@APpfffM@@GP0333M@0JPAM@KPpfffM@JP9M@dfffFP'M@dfffDPxfffN@;PA N@dfff8P̬$N@6Phfffv'N@4333O4P`*N@,-P`fff+N@hfffPhfffV"N@P03333N@dfffPN@dfff!P N@dfff-PN@hfff.1P̌N@dfff.PM@#PhfffN@P(333KN@$P03333N@ PM@ P@333[M@{PM@̤ P̔M@hfffPIM@`fffFOyM@O@333KM@(333ǑM@hfffOpfffM@`fffO̜M@OQM@@O\M@OM@0333O̴M@OɨM@OOyM@AOM@O̴M@(333O8333M@0333#OM@0333OxfffM@OM@O M@(333OdM@hfffNO8333M@(333sOM@hfffOtM@OM@O1M@(333OqM@̟O`fffM@(333{OQM@ߦOhM@O0333cM@ģOhM@(333OvM@hO̜tM@OpfffoM@O@333mM@pOgpM@Oxfff~mM@vOaM@(333oO0333VM@O@333EM@OBM@O9M@hfffO 3M@`fffO0333;*M@O0333S*M@0333Oy8M@ߚO;M@O:M@LO83338M@Oxfff4M@O5M@0kO\=M@`^O?M@hfffMO?M@(333LO̬OM@ 'O0333sL@(333O1L@OhL@̴N̴L@N@L@N0333L@N8333L@YN|L@(3333N@333L@`fffN@333SL@ OL@\OhfffL@`fffv OhfffL@`fffV+OL@hfffF0Ohfff.L@`fffn?OxfffL@<:O!L@2Oxfff^L@&OhL@O0L@hfffF OhfffL@NܵL@NhfffΰL@`fffNiL@(333cNxfffL@,NpfffL@N̼L@`fffN@3333L@0NIL@/Npfff֗L@NL@0333sNqL@N0333[L@ANxfffuL@0333Nhfff.mL@NxfffNcL@N$WL@`fffNSL@O@333{YL@.O,bL@0O8333dL@%OjL@hfff/OkL@:O@333hL@`fff?OpffffL@2Oq]L@O(333[UL@NKL@hfffnNJL@NhfffIL@hfffnNTCL@IN`AL@ N@L@<O:L@_N86L@0333N83332L@`fffNpfff1L@oN).L@ԿNxfff)L@(333N$L@`fffFNL@NL@hfffNdL@`fffNxfffL@hfffN L@0333N L@hfffvNL@N0333sK@hfffNK@ NIK@(333#N0333K@hfffN̼K@pNK@tNaK@0333CrNK@yjN@333K@(333#_NK@I^NK@0333PNK@KNLK@0333GNxfffK@SK@(333ӽLQK@hfffƳLKK@ijL8333IK@L}MPK@`fffM`fffJ@MXJ@ǙMJ@`fffMhfffJ@0333MxffffJ@`fffMJ@YMhfffJ@MdJ@N(333{J@<NpfffJ@i N8333J@ Nxfff.J@(333NJ@̌NhfffNJ@̴!N`fffJ@̜2NJ@L/NJ@0333NhfffJ@`fff NTJ@N8333J@(%N8333J@0333#'NJ@`fff& NJ@"N`fffJ@?,NxfffJ@03333+N@333J@,*NJ@NI@\M5I@0333sM(I@(333C Nxfff I@(3338N@333I@MNhfffNI@0333SgNI@hzN8333KI@!N8333I@`fffNI@NQ I@Npfff6I@(333NxfffI@hfff&O̔I@0333K.Oxfff~#I@G@0333+Rxfff$G@hfff5Rhfff!G@>RG@0333gARdG@dfffNIR|G@KR03333G@%RRhfff.F@̀^R`fff~F@4333mRF@sRF@0333oyRhfff6F@lRF@3333RQ?F@5R>F@3333CR̔4F@S.F@ffffS%F@S!F@dS1F@%SffffF@3333,SffffF@ffff^2S3333SF@t?S| F@̤BS F@CS3333 F@CSffff F@3333WAS F@X9SF@p:SPF@ffffS|F@8Sffff F@3333;7S F@8S̴F@;SF@AS\E@BSE@BS̬E@ffff@SpE@=:S3333E@33337S3333E@3333C8SE@ffff;SE@|CSffffE@̬ISE@3333OMS E@NS(E@KSE@)LS3333KE@QSE@RSE@%TS(E@SSffffE@3333QSE@3333PS3333cE@TS\E@ZSE@3333/`S4E@tcS3333E@TdS3333F@bSF@3333#cS3333+F@3333WeSF@ffffkS̼F@3333[mS3333CF@ffff~nS0F@3333uSffff^F@ffff^xS9E@SLE@SffffE@pS3333E@S33333E@ȡSE@-S3333E@ffff֪S3333E@S)E@ffffFSE@SffffE@̔S3333E@`SHE@]S̜E@3333SE@ffffShE@STE@3333kSE@)SE@ S3333E@3333SffffE@SE@yS3333E@̔S\E@SE@SњE@SffffE@ffffSffffNE@SffffE@S3333E@\RS7q6E@ffffSE@hfff:S̔E@3333SE@ffffS$E@5SffffE@ffffSE@̬S~E@̜SyE@S@vE@ffffS tE@̤Sffff^nE@S3333mE@ffffBSoE@SffffpE@3333SpE@SffffNmE@USlE@3333SInE@SmE@SDiE@]T3333fE@TffffcE@3333KTffff^E@ffffT3333ZE@XTpWE@PT3333VE@TffffNE@TffffVME@TME@T3333{KE@T(IE@TffffFE@TEE@ffffbTIE@ffffFTffffvIE@ffffv'TDLE@4T3333SRE@BT3333TE@(PTffffSE@YT3333PE@̬_T3333KE@3333nT)9E@3333sT(/E@uT%E@ywT!E@xTffff E@xTffff#E@3333kwTffffn'E@3333wT3333S(E@ffffz{Tffff#E@ffff|T3333k"E@3333ׂT E@@T3333E@TAE@\Tffff6 E@T3333cE@YTE@ffffTffffD@̼TQD@MTffffD@3333T3333;E@ITE@)TE@]T̤D@TE@3333TlE@3333Tffff E@̀TTE@̰T3333E@T3333C#E@T&E@3333T3333'E@ffffT3333)E@ffffT*E@ffffT3333C(E@T0)E@3333Th+E@dT.E@3333wTffff4E@ȚT3333shT4F@̸kTffffF@0mT3333F@lT(F@fffffTF@YTF@RTffff֟F@@RTF@ffff6TTffff&F@TTF@ RTffffޏF@PTiF@PTF@EMTF@3333_LTffffVF@̄KT|F@HT{F@HTyF@ITvF@̌HT|uF@̼DTfffftF@ BT|zF@@T{F@A>T|F@3333=T̴zF@ffff?TwF@a@TfffftF@h@Tffff&pF@TBTkF@)HTffff&dF@THT̄bF@ffffGTffffaF@hAT̬fF@=ŤgF@:TeF@M9TffffcF@9T3333saF@̬9T3333#[F@9;TQF@8:T OF@̨6T3333CUF@̌2T3333YF@*Tffff]F@)T3333S\F@%T3333QF@tTIF@ffffvT8AF@mT3333>F@]T9BF@T,IF@ffffSSF@ffffZTZF@ Tffff_F@T3333CcF@TDgF@$T3333jF@3333SmF@ffff~SffffvnF@SamF@SiiF@ffff2S hF@3333 SgF@Sffff6fF@SffffNbF@SffffnaF@3333cSlbF@YSDeF@S3333iF@PSmF@ffffSpF@StnF@SjF@SahF@aShF@ffff6STmF@ffff2S3333CqF@SwF@SpzF@3333sS|F@ffffS(F@̌S33333F@33333SffffւF@aT3333;F@TF@UTffff.F@3333sTlF@ffffjTffffF@T3333F@(TffffF@3333T3333F@ffffT33333F@ffffTF@TffffF@ffff"Tffff.F@ffff.T3333F@T3333ӫF@3333TF@TYF@D T F@E T3333òF@3333 T3333{F@3333 T3333F@X T3333F@3333STF@\T F@`T3333F@T̬F@ffffTF@T3333kF@3333TXF@|TF@TT̄F@3333oTF@3333TF@3333 T|F@ffffF!TF@"T4F@ffff%TLF@3333?(T3333F@ffff)TffffF@()T33333F@ffff)Tffff&F@ffff,TpF@-T3333F@ffff.TIF@X2TffffF@3T3333F@ffffV4T3333F@8T3333F@3333=TF@5FTffffF@AJT9F@JTF@ffff^JT3333G@KTffffG@ffff>LTG@3333LTF@(OTF@lSTF@3333\TIF@3333'`TF@0fTF@!hT0F@fTF@9fTffffG@gT3333#G@IhT@G@hT G@ffffbTffff G@bT G@agTHG@3333[iTG@YjT3333 G@3333lTffff G@nT3333[ G@3333pT3333[G@pTiG@ffffqT$ G@G@ U3333=G@a$U3333EG@3333c$UIG@ #U3333LG@ffffUHVG@ffff Ǔ\G@ffffU3333_G@<U3333+_G@ U3333;[G@3333!U3333CYG@ffff"UAYG@#Ui]G@l#UgG@ffff!UjG@3333UlG@UkG@3333sU9mG@U3333pG@UsG@3333U3333#wG@3333;UffffxG@ffff"U yG@@%UwG@l&UffffuG@ffff'UvG@ffff)UxyG@ffff0U}G@1U3333G@3333c1U3333G@ffff-UXG@ .U0G@3333 ,UxG@'U33333G@ &UG@t'UԬG@)U3333G@*UpG@3333_,U3333G@-U̜G@]1UG@7UlG@;UG@?U!G@@U3333G@?U3333G@3333c>UXG@ffff>U3333G@̀=UffffvG@ ;U3333sG@:UG@ffff:UtG@33337UffffG@96UG@6UG@3333=UG@ KUG@3333UUG@ ^UG@UgUiG@qUffff.G@xzUH@3333oU4H@ffffU3333H@,U&H@U3333S1H@3333?U3H@3333ˍU3333#6H@1U<OH@̔U|QH@ffffUXH@Uh[H@ffffZU3333]H@̬U3333 aH@dUaH@ffff.U3333c`H@ŧŪcH@$U̴eH@ffffRUigH@UyfH@xU3333bH@3333ϸUffffbH@UdH@lU3333cH@PULcH@ffffU3333SfH@ U3333jH@UkH@3333UffffVkH@TUfffflH@ffffVŪoH@UhpH@3333UsH@3333UuH@UffffzH@pVH@xVffff.H@4V3333H@H Vffff}H@ V}H@Vffff&~H@ffffV|H@VxH@V`uH@3333[VffffnH@l VffffiH@ffffV3333ScH@V]H@VhWH@3333ViLH@3333VHLH@VJH@VGH@VTGH@3333VHH@ffffbVffffGH@tVCH@3333SV@H@Vy>H@3333 Vffff;H@3333{"V8H@#V19H@p$VTH@ffff.$VffffQH@̈&VPH@(V3333LH@(VffffEH@)VffffBH@̸+V3333KAH@ffff*-V^3333H@Z^(333H@Yu^3333H@^3333H@^3333H@3333{^3333H@^8333H@%^pfffH@̜^̌H@%^@333ˇH@dfff^`fffH@hfff&^(333H@ ^ffff&}H@ffff^x}H@^3333H@4333^pfff6H@4333^ԊH@dfff^pfff&H@0333^H@^pfff~H@^8333H@̐^H@dfff:^H@0333^XH@^̌H@dfffN^QH@hfff^H@dfffn^pfff^H@4333C^H@^(H@dfff^I@0333 i_̬;I@̤l_pfffv;I@po_A=I@0333oq_ AI@u_\AI@4333}_a>I@4333_̔?I@ _?I@$_0333BI@4333_8333CI@˜_\FI@4333_(333;KI@_MI@dfffJ_OI@M_UI@dfffry_WI@y_8333;ZI@~_pfff[I@4333_XUI@̌_VI@4333_xfffVI@_@333\I@8_xfff6bI@hfffj_hfffNgI@_hfff.kI@Ě_(333lI@hfff>_kI@d_0333nI@_zI@_xfffFI@dfff_̔{I@0333o_8333#uI@0333w_drI@dfff_(333nI@4333_@333 oI@dfff_AuI@_yI@<_̤~I@_4I@Q_YI@0333_@333cI@4333_pfffI@dfff~_I@_I@hfff._9I@hfff_I@_I@_I@@_ I@hfff._̼I@_0333I@U_I@_hfffI@0333_I@E_hfff>I@_!I@4333_xfffI@0333_̴I@4333_0333I@i_LI@4333o_@333+I@_@333;I@4333?_I@hfff_@333I@_!I@hfff_I@_ J@0333_@333sJ@_` J@hfff._&J@4333_xfff-J@̀_@3332J@0333?_L(J@dfff_4%J@g_̔ J@_8333J@dfff_J@D_OJ@_J@4333+_aJ@4333K_J@̰_xfff!J@0333 _'J@!_0333{/J@0333G_83332J@hfffj_̔:J@T_xfff?J@_0333DJ@_`fff6TJ@dfff_Q\J@0333_!`J@ٽ_pdJ@4333_kJ@<_xfffkJ@h_xfff`J@_(\J@4333;_8333CWJ@<_0333SJ@dfff_QJ@4333;_-J@_hfff+J@_(J@dfff_ %J@e_ J@_PJ@̴_@333I@E`(333I@1`I@q `xfffVJ@43333`(J@`hfff+J@`6J@dfff`pfff:J@ffff`hfff>J@,_EJ@`_hfff~FJ@23339`CJ@4333`hfff64J@`(333#/J@ffff`xfffv.J@`xfff7J@K`OJ@ffff<`$gJ@2333{`mJ@dfff`tJ@d`tJ@dfff `@333iJ@ffffv`4pJ@ffff`J@``fff6J@4333`J@̖"`@333J@4333%$`̜J@}%`LJ@#`J@ `J@ffff`@333J@X`pfff.J@6`$J@`J@ffff`8333SJ@2333Y`صJ@P`̄J@4333u `@333ۺJ@ffffP `8333J@4333?`yJ@̈`IJ@a_)J@_8J@4333`J@`ٽJ@ `ľJ@4333`pfffFJ@ffff``J@6`J@`J@dfff`hfffJ@dfff`J@p`J@`J@2333`hfffJ@ffff`0333sJ@2333`@333+J@2333`pfffJ@`̜J@`̔J@ffff|``fff6J@̰`QJ@43335`xfffJ@2333`̴J@ffffr `0333J@!`pfffJ@̨&` J@dfffj'`J@̰'`QJ@dfff@(`J@)`8333SJ@.`\J@ 2`0J@5`J@L:`ԴJ@-=`@333J@4333aB`pfffJ@lH`@333J@ffffJ`J@sG`J@B`pfffJ@dfffB`pfff K@bA`K@M9`8K@ffff4`yK@dfffp9`9K@<`K@B`8K@dfffJI`8333"K@ffffL`@333-K@M`03335K@4333L`d=K@oL` EK@4333K`\OK@23337K`SK@I`8333YK@G`y]K@D`PiK@zC`qK@dfffZ>``K@{<`0333K@8`xfffK@1`4K@*4`(333K@4333U5`K@4333q6`0333#K@ffff~7`K@~8`pfffƿK@r9`K@43339`,K@:`0333sK@:`بK@<`K@̆?`DK@2333A`TK@B`@333ˍK@dfffA`pfffK@?`̡K@dfff?`pfffK@hA`hK@4333B` K@B`K@C`xfffK@2333B`8K@ffffA`(K@dfff@`̼K@@`K@8t[S@i[S@,e[S@D`[3333GS@][LS@ffff.W[3333S@U[3333/S@U[$S@̈V[S@ffffX[S@_[@S@\m[pS@fffff[̨S@Ȓ[S@ffffƚ[S@3333S[3333S@3333õ[̠S@ffff[3333S@[̸S@[S@3333;[ffffS@[dS@ffff[̔S@3333[S@fffff\mS@3333#\3333ەS@ffff?\3333S@ffff K\)S@ffffFN\S@R\fffffS@3333R\S@̘I\3333#S@ffff6\S@3333)\S@ffff \3333S@\[ȤS@E[3333S@3333[8S@3333[ffffVS@ffff*[3333 S@ffff[S@[lS@[S@33337|[lS@8t[S@P[3333S@ffff j[ffffS@3333g[ȄS@ffffg[3333S@3333{k[S@dq[ffffF}S@Č[yS@ffff[vS@fffff[ffffbuS@Ѷ[̀tS@[3333gsS@ffff [3333rS@3333[TrS@[ffffqS@ffffƉ[pS@`[3333oS@ffff[mS@3333{[3333gS@[dS@[aS@3333Ǘ[fffff_S@[\S@33337[3333C[S@ffff[̸[S@ffffz[l[S@[3333VS@L \VS@\MWS@4)\e\S@=;\e^S@ffffB\`S@̄J\aS@L\cS@XM\!eS@ffffL\ffffbfS@3333H\gS@̸G\|hS@̼J\3333KkS@ L\mS@\Q\qS@$R\tS@R\3333{uS@S@\ffffR@9Z3333R@$ZffffzR@3333wZ3333R@ffff޹ZR@3333ǹZ3333wR@Z3333R@\ZffffR@ Z3333kR@ZR@|ZR@,ZffffR@3333ZffffR@ffffvZ`R@TZ̄S@ԡZdS@aZS@yZ3333S@ffffmZ3333R@}hZ̀R@3333fZR@ dZ\R@3333^Z̸R@^ZR@3333?aZxR@3333kkZffffR@lZfffffR@4wZffffBR@4~ZffffjR@ZR@ZR@3333Zffff*R@3333Z3333gR@ZffffVR@ZR@|ZR@3333[ffff"R@̀[R@3333[TR@ffffb[3333R@3333&[iR@0[|R@*[ffffnR@([}R@*[̔R@45[3333'R@)@[̨R@33333`[3333R@@[ffffµR@[R@3333Ǣ[R@[,R@[3333R@33337[R@3333g[3333sR@3333[ R@R@5[3333R@ffff[,R@ [ffff~R@$[3333R@3333[3333gR@̘[3333R@T[3333;R@[̼R@[ffffR@\R@̴ \R@ffffZ\ffffR@̘\R@ffff6&\R@)\R@-\ffffR@,3\R@6\R@3333<\ffffR@̼U\R@m\dR@3333r\]R@v\ffff.R@ffffv\IR@w\R@̴x\R@̜v\R@s\3333R@p\3333R@1`\3333cR@]\R@e\`R@9x\3333R@z\R@~\ffffR@ffff\3333R@3333k\ffffR@3333˄\R@ffff\3333R@Ȋ\TR@<\3333R@t\ffffR@ffff\DR@ffff\R@@\3333R@\ffffR@ffffʖ\R@\R@\R@I\yR@ffff\3333R@ffff6\3333R@ \ R@\R@\AR@q\\R@̘\R@3333c\ffff*R@\3333R@\̜R@̸\XR@\R@ ]̨R@x]ffffR@33335]ffffR@3333O@]R@ `] R@,d]3333R@hf]3333cR@0f]̸R@ffffd]R@3333`]R@X]R@yU]3333OR@|P]hR@ffffI]ER@ffff9]R@ ]R@]̌R@ffffv\ffffR@3333 \ffffR@\lR@̀\3333{R@\,R@ffff2]R@=]ffffvR@̜A]3333R@H]3333R@xJ]ER@xB]ffffR@@>]ffffR@ffffV3]aR@]R@3333\R@̄\R@ffff\|R@t\]R@3333\DR@]3333cR@ffffn]R@)]yR@*]HR@ffff&%]uR@-#]S@ffff']S@%]!S@ffff]ffff* S@ffffn ]q S@] S@3333+\ffff S@3333\ S@Ա\ S@T\x S@ffff\̈ S@ffff\YS@\)S@ffff\HS@3333;\ffffS@ffff\S@\3333WS@)\S@3333\ffffS@\] S@9\ S@ffff"\3333cS@i\S@ffff \ S@h\US@8\]S@ffff~\ffff2S@ă\3333?S@3333{\ffffS@t\< S@3333;W\ffffS@ffffJ\3333S@3333>\̨S@,\ S@ffff^\S@`[R@3333[IR@\3333sR@-\R@̴D\ffff?R@3333;0\3333?R@ffff \;R@\8R@%[1R@3333C[-R@ffff[*R@[$R@[R@9[R@ffffJ[ffffR@ffff[tR@4[5R@[uR@[R@ffff[R@ffff[`R@8[R@̼[0R@ffffb[R@([0R@([IR@[3333R@[aR@`[R@[3333+"R@͠[a&R@[̈(R@ [ffffR*R@3333O[ffff+R@ffff[0R@ܑ[̰2R@ffffn[!7R@3333[3333sR@ g[3333 8R@^[3R@3333V[ffff1R@G[}.R@B[+R@1?[ffff*R@ffff=[)R@?[(R@̤?[$&R@<[M%R@3[ffffR$R@Q0[D#R@̰,[R@,([ffff^R@3333?$[3333OR@ [R@̰[Q@3333w [3333Q@ [ffffRQ@ffffB [Q@T[\Q@8ZQ@Z3333Q@DZLQ@ffffzZ3333oQ@ZQ@4ZffffnQ@3333ZtQ@̤ZQ@3333oZffffQ@ffffZQ@ZffffBQ@ffffZ3333R@̈Zffff R@Zffff^R@3333Z<R@ZffffVR@ffffZR@ffff:ZhR@ffffZffffN!R@Z#R@Z%R@Z)R@3333?[FR@1[IR@ [3333KR@ffff[ffffLR@3333Z3333;MR@ffffZMR@,Z3333NR@[ffffRR@̸[pSR@[QVR@Z3333UR@3333ZtRR@3333CZLLR@3333ZffffLR@Z3333OR@ټZffffQR@ZQR@3333۞ZffffLR@9ZffffDR@3333tZffff@R@ffffgZ\;R@_ZU6R@ZZt2R@XZZ0R@ffff[Zffffb/R@3333OZZ\-R@̰VZ*R@3333TZ̠(R@3333 SZffff#R@OZ3333R@3333NZ̐R@ffff68ZQ@3ZQ@ffff1ZffffQ@,!ZQ@3333ZQ@ZQ@ffffZ0Q@3333_ZffffQ@ZtQ@ZffffQ@Z8Q@,ZQ@ $ZyQ@t$Z̨Q@ffff ZQ@ Z3333WQ@Y3333ϰQ@3333YffffQ@iY`Q@Y3333Q@ffffY3333Q@YQ@Y̐Q@3333[Y3333Q@TY̨Q@Y3333Q@LY3333Q@3333Y̔Q@,YQ@YfffffQ@̴YQ@YffffrQ@YYffff>Q@3333{YffffQ@nYTQ@HkY3333ϑQ@iY3333Q@hYQ@̔gYQ@ffffcYQ@ffffNOYQ@IYffffrQ@3333EY3333Q@3333BY3333Q@3333K>Y3333Q@ffff.:Y̠wQ@33339Y3333sQ@;YmQ@3333>Y3333kQ@BYjQ@ffffMY3333kQ@UYtmQ@3333YYoQ@3333;]Yffff^uQ@3333^YivQ@`YffffRuQ@ffff*dY\pQ@3333fY)nQ@3333siY̴lQ@3333nYmQ@ffffwYQ@ffffbAZ\CQ@ffff@Z3333[DQ@@AZ33333EQ@ffffPZFQ@bZHQ@̄sZIQ@ZffffrIQ@Zffff^JQ@ffffJZtLQ@ՕZ\NQ@3333ZPQ@ĖZQQ@Z̼UQ@ Z3333cXQ@Z3333{ZQ@Z3333[\Q@ffff.Zffff"\Q@3333ZffffZQ@ŶZffff:VQ@$ZKQ@3333Z3333IQ@Z3333BQ@3333'Z3333#@Q@AZ=Q@\[3333;Q@\#[3333o9Q@3333.[4Q@<[̠0Q@33337^[3333O+Q@X}[ffffV(Q@[ffff 'Q@3333G[%Q@3333C[3333&Q@ffff*[3333%Q@ffff[̰"Q@(["Q@\ !Q@3333*\ffffQ@P7\̈Q@@A\ffffQ@,H\Q@3333N\D"Q@3333U\ffffR&Q@ffffc\ 1Q@ffffzg\5Q@e\ffffn=Q@fffff\ffffAQ@k\KQ@ll\3333{LQ@3333\PQ@3333\9QQ@\tQQ@-\PQ@3333\RQ@ffff\mSQ@]UQ@ ],[Q@3333["]3333[Q@3333g$]̜]Q@']`Q@-]dQ@?]ffff nQ@F]xsQ@ffffG]3333tQ@3333I]3333xQ@3333K]mQ@L]uQ@ffffjJ]3333Q@3333H]hQ@q#]4Q@\tQ@\3333Q@\Q@z\Q@j\ffffBQ@|M\ffffQ@3333(\ffffjQ@t!\̠Q@\LQ@3333# \3333Q@([3333wQ@[IQ@|[ēQ@t[Q@ffffN\Q@PI\ffffrQ@hY\Q@3333wp\4Q@}\ffffQ@܎\3333'Q@5\33337Q@\ffffQ@ffffε\ħQ@3333\yQ@3333k\Q@ffff]ͥQ@t]3333sQ@ffff]3333Q@?]ffffQ@ffffe]ffffJQ@ffff]ffffڸQ@]3333Q@]Q@8]8Q@{]ffffQ@t]$Q@T]3333Q@-4]Q@ffff]Q@3333]Q@]%Q@\3333oQ@ffff\3333Q@ffff]Q@]3333Q@̼\Q@\ Q@33333\Q@3333\]e=R@$]CR@3333W\MR@ب\WR@ffffR\ffff*UR@5\3333SR@ffff~\DQR@!\NR@\KR@3333O\3333DR@\3333@R@p\P=R@Ȅ\ :R@\ffff7R@3333_\ffff3R@\L/R@ܟ\ffff(R@`\ffff%R@ ]5R@̠]R@ffff&]R@ffff&]33333R@ffff.]R@]ffffR@3333]ffffR@]ffff*R@p]ȁR@̌]ffffR@H]3333[R@̤]܂R@]3333KR@]R@Т]R@3333nj]ffffR@}]3333R@3333Gm]ffff&R@3333`]ԎR@L]R@3333<]}R@3333;.]̼R@3333K\ffffoR@̘\jR@3333\gR@)\3333keR@\ffffbR@$\ `R@3333W\3333]R@\ffff\R@̐\ZR@\TR@E]ffffRR@]4PR@0D]FR@]]ffffjBR@~]9R@ffff]+R@]3333(R@3333k]3333&R@]R@ffff]3333_R@ffff]3333R@ffff^ffffR@3333 ^ R@q ^R@3333^3333Q@p^Q@\^3333_Q@^Q@ffffB!^̬Q@3333'^ffff^Q@ffff;^3333Q@ffff:J^3333Q@8^^Q@3333b^Q@g^Q@l^Q@o^3333wQ@ffff^Q@3333+^3333cQ@^4Q@^_5R@3333;_ffff>7R@H%_ffffB;R@($_lGPT@>P3333T@9P3333T@ffff1PT@(PdT@A PѱT@̼PffffƱT@3333P3333T@ffffOT@ OT@ffffֿOT@̌O\T@23333O3333T@pO̬T@ffff>OT@O3333kT@TOffffҩT@O,T@$OT@2333OT@ffffOМT@2333cQ3333T@ffffnQ|T@|QT@3333/Q3333sT@ęQ`T@Q3333!T@3333Q̈"T@Q3333[ T@ffffQffffT@Q3333T@3333kQ T@QffffV T@3333KQ3333T@Q, T@ffff^QT@̔R3333T@RT@3333QT@ffffnQT@!QT@3333QT@`Q3333T@ȣQ3333T@3333{Q3333S@QffffRS@QS@ffffQS@ QffffBS@QS@ffffQS@3333QffffS@3333 RS@RpS@ffff\R3333S@ffffsR)S@3333;RffffNS@3333?RS@@R3333sS@3333Rffff2S@DRffffS@iRXS@<^RiS@ffffYRS@ffffNR33337S@3333LRffff.S@ffff^OR\S@RRaS@3333#WRAS@]R̰S@lwR3333S@RdS@3333RffffS@R3333S@R3333[S@3333RffffS@8RS@ffffRS@HSHS@S̤S@ffff9SS@6S3333?S@*S̘S@SxS@ffffrS3333S@RS@3333RTS@ffffR̜S@R S@3333RS@̞RS@R`S@RffffFS@RffffFS@R3333S@RS@3333[RS@ SlS@XSffffS@3333"SS@ffffZ1SS@yYSffffS@nS̤S@ffffR~SS@SffffBS@9SS@ffffƣSffff~S@ffffSS@4SS@3333[S̰S@3333xSPS@lS3333S@ffff`S3333S@4S$S@3333!ŠS@`SpS@3333S S@R`S@ffffRS@3333R3333gS@ffffNRffffS@Rffff~S@ RS@RXS@ffff>R1S@3333R3333S@3333;RffffޢS@aRffffvS@RS@3333SYS@S̼S@̼SxS@AR3333әS@ffff.RĖS@aRS@ffff>Rffff&S@lR̠S@ffffR3333S@ffffS0S@SlS@Q-Sffff|S@ffffV>SX{S@ffff.]Sffff|S@ffff΀S|S@SYzS@ffffbSffff&vS@0SoS@SdgS@S8aS@SQ]S@(SpZS@̐SWS@XSUS@ffffSHUS@ffffS3333/US@ffffS,SS@3333T3333KSS@̬$T%TS@7T3333VS@ffffXT3333^S@S@ S;S@3333S$9S@̬Š8S@%S:S@ffff.S3333=S@ffffS>S@|S3333>S@̐S;S@3333Sffff6S@ffff~SQ0S@̘S8)S@ffff2S3333$S@3333˻SS@]SffffS@LS̴S@̴S3333S@3333SS@ T3333_S@-,T3333K S@ffff.3T S@̠=T S@?Tffff S@!=TffffJS@9TS@m5TS@E5T3333'S@ffff^>TS@ffffDT3333S@JT S@XWTI S@]^T5S@3333eTS@mTS@3333tTU!S@0TH(S@3333GTffff*)S@ffffTffff(S@T)S@ffff.T3333',S@TffffJ.S@T̨,S@ؖT̴(S@ĐT$S@UT S@TS@TS@3333TS@ TffffS@ffffRU8+S@3333US@ffff IUffff~S@UUffffS@ffffkUffffVS@iUS@UffffzS@ffffzU#S@ؚU%S@ Uffffn%S@ffffUffff!S@̈UffffS@ffffUffffjS@3333U̬S@XUffff~%S@U̸S@VffffjS@XVS@3333V %S@Vffffv1S@M'V)S@$V#S@ffff"VS@p3V<S@WV]S@|dV|S@ffffbV8*S@_Vffff4S@ffffV1V3333?S@̘#V3333DS@3333{V3333FS@x VGS@UHS@ffffUffffHS@ffff&UHS@ UJS@ffffU)KS@UKS@ULS@tUSS@̬UAUS@UUS@UffffBVS@̴UDYS@̜U[S@ffffUffff_S@3333U3333cfS@3333V3333nS@ffffV8rS@tŪuS@3333UwS@3333U3333yS@ffff&UffffyS@3333SU3333GwS@UsS@ffffUoS@ffffzUffffJgS@nU`S@eU3333]S@3333]Uffff&S@U4S@ffffbUffffS@US@3333U)T@TUT@U3333T@̨UpT@33337JUdT@ffff:+UT@ffffUT@PT3333T@Th T@ffffFTffff~T@\TS@ T S@3333TS@vTffff>S@fffflTS@ffff]TS@pBT3333OS@*T3333wS@uTS@QT3333S@3333TS@eTtS@ffff-Tffff2S@ffff@T\S@uKTS@VT3333kS@3333;iTS@ffffwTffffBS@ET3333?T@ffffT1 T@3333TT@3333+TT@ffff:TT@PTT@ffff>T3333T@DT!T@(S(T@3333GSffffv)T@3333S333332T@t`Sl5T@3333JSffff5T@3333;7SX7T@l6S48T@ffffGS3333_9T@XSffff9T@ffff>S9T@3333CS:T@ffff֭SBT@}U3333@T@UffffVbT@lVYT@̤VYT@ffffV}[T@pV]T@vV%gT@fffftVhT@,V3333khT@ffffVhT@ViT@\VhT@3333V3333eT@ffffV3333dT@3333VeT@V3333hT@qVkT@ VoT@ VffffjrT@HVtT@3333_V$xT@3333oV8yT@̈hV@yT@ffffbXVzT@JV%}T@8V3333'T@3333G$VT@3333 V,T@UqT@UxT@ffffUT@ffff*U\}T@3333U3333T@`Uffff"T@UDT@)U3333T@ffff"UffffT@wUq~T@ffffRiUffff}T@ffffnbU}T@YU~T@ffffBUffff~T@XCUffffT@JU3333T@SUЂT@(U3333T@fffffUT@UffffޏT@zUT@rUT@ffff^UqT@QU3333T@e9U3333ÜT@/UT@ffffj#Uffff~T@3333UffffT@ffffTqT@TT@ffff>T3333T@ffffTT@̌T3333T@ffffTffffT@ȖT9T@T3333T@ T!T@ffff֯TffffT@YT3333T@3333ۨTffffT@\T3333ӏT@3333T3333T@heT3333T@1#T3333KT@ T~T@3333'S3333{T@SffffxT@SxvT@0S3333vT@IS3333{T@3333OTЁT@]TPT@T3333ϑT@S-T@S3333{T@̬ShT@3333CST@ffffST@ffffST@` S0T@S@T@3333RffffT@33333RffffT@$R3333/T@̐SPT@ ST@<Sffff6T@$:SغT@3333BST@ffffGST@̬RT@R3333T@RLT@3333R$T@zRffff޹T@mR̄T@hQRaT@(*R3333/T@̨1R\T@ORT@H\RT@4\R̈T@YRT@1URT@ffff3Rffff2T@ffffnRT@Q}T@3333QdT@3333sQ3333T@3333/QffffT@ffffQffffRT@Q T@QT@3333QffffZT@mQffffJT@3333QHT@3333~QffffnT@wQT@ffffrQT@pdQT@I_Q3333T@WrS@ffffWffff>pS@3333oWffffqS@̬WqS@WffffpS@MeWTqS@ffff&^WffffpS@3333CSWXoS@|MWtmS@Q@3333X̌Q@ffffXQ@]X|Q@ffffX3333Q@ЎXQ@XpQ@3333+X̘Q@ffffX33337Q@3333cX3333SQ@LXTQ@lXUQ@ffff*X3333Q@X̌Q@ffffXQ@ffffXQ@PXffffQ@̬Xffff&Q@X̨Q@ffff6X3333Q@XffffvQ@YffffVQ@Y3333?R@ &Y R@<-Yffff R@ffff63Y3333 R@>Yq R@AY̠R@EYR@XMYIR@3333 PYR@eTYR@_YR@TnY3333'R@qYR@|sY̤R@ffffNuY1R@ffff2zYffffR@P~YR@ffffY&R@ Y3333 .R@\Y0R@̬Y33332R@Y5R@8YffffJ:R@DY>R@ffff>Y`@R@3333YffffDR@ffffYffffDR@AYyDR@ {YCR@3333wuY3333'AR@3333sY3333G>R@ffffJpY3333WR@Y3333>R@ffffY9R@ Yffff8R@33333Y3333:R@YffffzYffffbfR@6YdR@P+Yffff_R@3333c!Y\R@ffff Yffff]R@3333S"Y3333`R@3333&Y3333dR@3333*YeR@2Yffff:gR@|9YjR@3333YffffnR@ ?Y3333pR@=YffffrR@:Y3333sR@YuR@3333 YHsR@ffffnXrR@\X5vR@ X3333vR@̐YvR@ YvR@3333cY3333wR@Y3333xR@Yffffr{R@3333Y|R@3333:UPP@8U3333OP@5U`PP@\1USP@33333'U̠\P@X$U3333{]P@ffff U3333W]P@ ÙWP@̄ Uffff>TP@3333UOP@ffffnUMP@3333TKP@ffff>TJP@hT3333oHP@ffffTffffFP@9T3333=P@T3333k=P@eT9P@ffffT1P@}T33330P@3333cT3333'.P@3333+T4,P@33333T<)P@3333s{T#P@arT3333CP@EkT P@ffffjT P@kTP P@$nTP@yTP@ffffxT P@mTfffffP@3333{UTP@̨FT`P@ffffATP@ffffR@T!P@:TffffnP@ 5TP@3333o,TP@ffff&TlO@h$TIO@%TaO@*T3333cO@ffffTtO@TffffO@TTO@ffffB Tffff>O@-TffffVO@ffff=TyO@3333@T4O@BTO@KTٽO@ffffWTO@3333}T O@XTxO@33333TxO@YTffffFO@TffffO@3333TO@T3333P@3333+T|P@yTffffP@T P@3333+T- P@T P@tT4 P@3333TYP@YTP@ffff~TP@T3333{O@XTO@TO@ffffjUffffvO@ UffffO@3333UO@U3333O@UO@e UO@ffff~#U̬O@(U̔O@ffff2U3333O@=Uffff>O@=OUԑO@ YUQO@ffff_UffffΑO@3333;dU̬O@̴mU8O@3333GoUO@ffff6qṲO@sUpO@LUO@ؤUffffO@33333U3333O@3333UO@3333cU0O@̸UffffO@ffffVU,O@hUO@3333U O@UO@3333 U3333KO@ffffUiO@̴UuP@lUxP@cU3333zP@yaUzP@ffff_U̔yP@P\UvP@ffffnOUrP@3333GKUoP@XHUXlP@ffffFUffffgP@3333WHUeP@|NUbP@OUaP@3333[OŲ`P@ffffCUffff[P@3333:UPP@lX3333S@$lX3333S@3333lX3333S@,oX=S@HoXtS@YR@ffff@YffffZR@̐PY3333'R@3333oRỲR@3333ZYffff"R@^YqR@``YR@̀`YdR@3333[Y|R@mYS@fffftYS@wYQS@ wY3333{S@ffff^qY3333 S@ffffaY S@ffffcYS@ffff:zYS@ffff2Y3333S@ЈY3333;S@3333Yffff2S@}YS@vYS@3333grYS@XkYS@ffffZY1S@ffffUYES@ffffHY3333S@EYS@3333FY3333gS@ffffCY3333S@33339Y@ S@3333Y}S@YxR@IY!R@dXffff&R@3333XffffZR@X@R@3333XlR@̜X3333S@3333CY3333CS@8ỲS@}YS@YS@ffffX|S@̠X\ S@MX S@Ẍ S@ffff Y3333 S@ffffYS@̄YmS@3333YffffZS@YS@3333X1S@3333X3333S@=YS@- YffffS@̤)Y3333WS@x4YS@7Y8S@ffff9YffffnS@ffff5Y3333!S@$Yffffj%S@YD'S@eY(S@Xffffv(S@X'S@ffffX\!S@3333XS@3333XS@$X3333W"S@3333XT'S@33337X))S@ffff~Xh,S@ġXffff*S@yXQ&S@Xffff$S@}X3333"S@̼sX4!S@tnXS@lX3333S@DY33333S@DYffffS@̄YffffS@3333YS@Y3333S@ffffΨȲS@|Y̼S@YlS@Y S@ffffYYS@3333+Y3333S@Y̨S@YHS@3333Y̤S@0YS@YS@)Y̨S@YtS@P~YS@wYS@mY S@3333#SYܾS@@IYDS@EYS@`BYS@(BYffffS@3333kGYffffS@pIYS@33333HYffffNS@:Y3333S@3333YS@YS@ XS@XPS@AX S@dXܢS@XS@3333_X$S@ffffBX S@3333Xffff&S@1XTS@ffffXffffΔS@ffffXdS@3333XS@3333kXS@fffffXS@3333KXS@XS@ffffX}S@33337X3333#xS@ffffXvS@X̼uS@3333/XtS@-XrS@Y3333KuS@%Y3333yS@+Y{S@0Yffff~S@ffff1Y3333S@3YS@4YS@I=YUS@ffffDYhS@ffffSYffffŒS@ffffuY3333S@YS@4YS@ئYffffS@3333Y`S@@YS@iYS@ffff2Y!S@ffffήY3333S@XYtS@̔YS@Z3333?S@3333 Z3333ےS@ffff0ZS@3333G8ZffffS@?ZS@3333?Z3333/S@33337:Zffff^S@|4ZffffS@.ZS@ Z3333S@3333Y@S@3333Y̌S@ffffY3333S@Y3333ߧS@UZffffS@lYtS@3333YTS@Y S@3333#YffffS@,Y9S@3333ZS@3333 ZS@t Z3333S@3333 ZS@ffff YŹS@3333YͺS@ffffvZS@33337ZS@ ZffffZS@DZ1S@3333/ZܴS@P4Z3333S@P9Z̸S@>ZS@ >ZжS@-9ZS@ffff/ZffffnS@3333/ZS@9ZES@3333SZ S@HbZS@3333dZ3333S@!eZ3333OS@dZffffS@ffff`Z̄S@ffff[ZXS@XZS@3333;6Z3333S@YHS@5YS@DY33333S@̬V̀HT@QV(CT@pVh6T@3333sV1T@̴V3333,T@V)T@ffffzV)T@3333'V3333%T@ffffbV$T@Vffff#T@(wVffffT@sV T@ kV!T@ffffaV|"T@3333UV"T@OVffff T@ffffJVffffT@HVffffFT@ffffHV,T@MV3333 T@̔LV8T@ffffIV9T@lIVT@ffffMV3333T@LVT@3333;AV T@ffff6V3333 T@3333g"VdT@ffffVffffT@3333 Vffff"T@̘ V3333T@XV T@ffff^ViT@33333'VXT@\)V3333T@u*VffffJT@1)VffffT@ffff!VT@(VeT@V|T@pUT@33333UT@PULT@ffffVUMT@3333U3333G T@U3333 T@UT@3333U@T@UT@UT@ffffUffffT@ffffUT@UffffS@ffffU3333;S@3333+US@3333;UhS@UPS@U!S@3333US@33337UffffS@3333U@S@ffffU\S@̐U3333S@܎US@̌U3333S@yU3333GS@3333sU3333S@|UffffS@ffffrsU̬S@3333pU S@ffffnkU`S@ffffviU!S@ffff`US@V͋S@ FVdS@^VS@iVffffS@3333G{V̬S@VqS@`Vffff֦S@ffffV%S@V3333S@3333wpVS@%gVّS@p`VffffS@Y_VS@̤aV33337S@ffffeVS@iVffffZS@wV4S@}V̐S@̠VS@V S@VffffS@`V-S@ȧV3333S@VS@3333V0S@ffffVɏS@VS@V3333ӋS@ĘV3333sS@ffffRV3333S@ffffºV3333#S@33337VS@V(S@3333{WffffS@h+W3333S@3ẀS@I6WffffrS@p.W%S@WTS@3333{V3333S@ffffV3333S@3333-W̸S@=>Wffff:S@GWS@QWffffS@XW!S@TcWLS@ffffhW3333S@gW3333#S@ffffcWS@UMWffff:S@3333;JWS@̈UW3333S@ffffyWffffҷS@UW3333sS@ԉWݼS@܊WffffBS@3333kW̠S@|WdS@3333RWS@aDWS@5WffffS@+WS@#WffffS@ffffVPS@ffffVS@1VffffS@TVXS@ffffWffffS@3333WS@3333C)WS@ffff4W3333S@AWxS@`XWS@ffff:cW3333S@̸{W3333S@̌WS@W`S@Wffff*S@WS@$|W3333S@t}WPS@3333W3333S@3333/W̠S@WffffS@%WqS@WS@ffffWS@3333CWS@ WS@WS@lWS@W3333/S@YW3333[S@ffffBWffffS@3333oWffffS@W S@,WpS@ffffFW3333WS@WS@\WffffS@QW@S@W3333S@ffffWS@X=S@3333%XffffS@&XffffS@(XT@|1X̰T@ W@T@4WhT@ffffVWffffT@WT@3333cWffffT@ffff6W3333T@ئW T@IW T@|W T@ffffΐWx T@ĥW T@PWT@WT@\WT@3333W T@̤X0T@ X̼T@3333XffffT@XT@8X)T@XMT@fffffXT@-XXT@ffffXT@W`T@$WffffvT@3333SW\T@3333Wffff"T@3333 Xl#T@X@,T@3333SW3333.T@Wm.T@ffffVWffff2,T@tW+T@W3333_)T@ W$T@W$T@W3333#T@3333c{W#T@ffffցW%T@W'T@)W)T@ffffvW0T@̈W33333T@W5T@W3333?7T@DW @T@W-CT@ffff>W3333AT@؍W̨CT@tWFT@fffff\WTET@ffffVWffffvET@YRW3333kFT@OW3333?HT@OWIT@LRWxKT@ZWaMT@ffff>yWffffMT@WfffffNT@qW3333kOT@ffffWPT@ЎWffffRT@W3333+TT@ffffW3333+UT@ffffzWffffUT@ffff҃W3333[VT@fffffWpVT@LUWffffRWT@8BW)VT@hW3333QT@ W3333OT@V3333KT@̬V̀HT@We:S@W33339S@̬|W:S@ffffsW:S@fW7S@ZW33333S@3333QWffff22S@̸NWL1S@3333MWL0S@LWP-S@(LW+S@ffffLWffff*S@PW(S@ETW3333$S@H[W̼!S@3333_W}S@ffff6bW3333S@[WXS@?W̴'S@3333-W3333&S@ffffWl'S@ffffV@+S@V+S@V+S@V\*S@ffffBV4%S@̴V"S@3333Vffff!S@ffffVffffS@ȧVS@LV3333S@V S@̀V S@ffffzV S@ffff^VS@̐V,S@ffff^V3333S@̴VS@5RVMS@NVffffS@3333#OVLS@RV3333 S@ZV3333 S@V S@3333V S@ffffVS@VS@ffffV< S@DV3333 S@ffffZVS@3333VS@ffffVlS@DVS@V3333#R@3333gzVR@3333rV0R@lVR@ffffiVR@`VR@QVffffR@MVR@3333MV3333/R@lPVR@ffffWVTR@3333hV\R@XiV)R@ffffUVR@ffffQVffffR@3333:V R@33337VR@̰5VR@ffffv3V(R@t4VxR@L7VR@6VffffR@,2VpR@-V3333'R@3333G)V$R@3333k$VIR@ffff VR@U3333R@1U3333R@ffffUR@̀UR@ffffVUR@qÜR@ UffffrR@ܢUR@UR@ UR@|UHR@yUHR@fffffU$R@E~UffffR@33333eU3333R@WUR@3333'?UffffFR@33330UffffR@ffff&UffffR@3333+U3333R@UffffR@TiR@3333TR@,T R@ffffTiR@lTffff^R@TUR@ՉT0R@ffffniTR@0QTffffbR@ffffIT3333R@TLTR@3333KTR@ffffGT3333R@ @T(R@ffff!TR@3333T3333CR@ffff" T1R@̠TR@ TffffR@XTffffbR@3333T3333R@`TffffR@ffff6S̈R@@SR@|SR@S3333R@̔S̠R@ffffSR@S3333R@ffffTLR@ffffrT0R@ffffT3333#R@TV R@<"V3333;R@ffff+VTR@1VŭR@x6V(R@8VffffR@:VffffR@3333+VpR@AAVR@CV3333ӯR@`GV4R@HLVR@ffffNVծR@̘LVR@LVR@LVͨR@ffffPVR@\VXR@cV̀R@ffff vVR@3333VR@$VR@hV33337R@ffff.VR@VĭR@HV̰R@3333+VDR@UVffffVR@PV3333R@ffffzVtR@̜V3333R@VPR@VR@̈V̤R@$VR@V3333R@3333VR@ffffVIJR@WffffR@% WDR@3333 WR@3333WffffvR@ffffWR@< WR@<W̴R@WffffR@ffff"WffffR@UW3333+R@dWffff~R@3333OWR@)W3333R@WR@ffff*W3333R@hW3333R@XWR@ W3333R@ W-R@3333WR@QWffff"R@ffff^-W3333SS@8W S@3333EWS@ffffNLWlS@SWS@ffffcWffffS@ffff>iW3333wS@ffffjW3333{S@̌vWffffBS@|WS@ffffvWS@ffff&WS@ȿWffff~S@3333WS@ffffW<S@WffffS@dW3333S@ffffXffff&S@ffffXffff S@|Wa"S@ffffW3333$S@W3333k%S@ffffW@$S@ffff*Wt$S@(X,S@33336X}.S@]8X@/S@x9XA0S@q9X̀1S@18X`3S@3333{+Xffff1S@3333%X0S@Xffff1S@3333X3S@Xffff3S@ffffN*X33336S@ffffZ1X8S@4Xffffv:S@D1XS@+Xffff ?S@4#Xffff:?S@%X3333K@S@3333X4CS@ffff^W0R@W.R@W3333-R@UWQ3R@eW<3R@ffffWq0R@W/R@zW-R@PqW*R@dW#R@bW"R@,bW3333R@bWR@cWR@wW3333+R@ffff>~WQR@3333gW3333R@33333W R@џWffffR@ffffWR@̀WR@YWR@̬W R@TWR@W R@ W2R@$W15R@W33338R@ffff>W3333C7Q@YX8Q@33337X3333:Q@̨Xi=Q@X3333/BQ@XyCQ@X`FQ@ffff*XeHQ@xXIQ@aXJQ@PXffffNQ@9X3333SQ@ffff.X3333kUQ@3333ӜX̨VQ@ܝXXQ@3333CXH[Q@3333X]Q@YX^Q@ffffX̰^Q@X_Q@33333XaQ@ffffXbQ@XffffdQ@tX3333eQ@3333X)dQ@ffff:Xffff_Q@X^Q@X9]Q@ffffnX`Q@|XAhQ@|XjQ@3333GXDlQ@ffff*XHpQ@ffffFXqQ@ԌXsQ@3333+XPuQ@xXvQ@3333rX$wQ@Nffff>G@@4N3333sG@ffff67NA{G@t6N3333+vG@ffffv*NHbG@̜*NffffV^G@)1NNG@=Nffff4G@@N&G@L?N"G@hDNffffvG@ffffIN G@ffffV_N G@PjN| G@2333tN̴G@ffffvNF@PF@P3333KF@P̤F@P3333F@3333SPffffF@ffffPffff~F@-PF@|Pffff>F@ffffPffffF@3333P3333F@ffff>PPF@̐P3333F@PF@3333cP`F@ffff P3333F@3333P3333F@PffffF@8P!F@PF@)PF@|PdF@̰P33333F@8P#XF@P!F@PffffnF@Pffff>F@mP3333F@LPffffF@3333_Pffff&F@̹R>P0WF@1PF@3333PF@ffffPF@3333PF@ffffPF@PF@Pffff&F@3333PF@8PF@UPdG@ffffP3333G@̸P0+G@ffffP3333?G@ PNG@8P3333cG@aPffffwG@ffffPG@PtG@1Qffff.G@ffffQHG@Q`G@QG@3333QxG@ffffQ̔G@*QqG@ 5QffffG@33338QffffG@3333;Q G@33333@Q3333CG@CQffffG@DQHG@ffff6CQ3333G@\IQffffG@3333OQ3333CG@ffffVSQtG@VQG@,^Q̌G@ffffNhQiG@mQXG@ffffwQkG@ffff~QffffZG@ffffrQ$IG@LQt8G@Q+G@Q G@ّQ33333G@|QXG@̜Q3333kF@`Qffff6F@Q3333F@3333WQF@ffffQ̤F@3333Qffff~F@ܝQyF@3333+QffffnF@Q3333F@ffffFQܿF@LQIF@%Q3333ӶF@QiF@ffff6QF@%QгF@ffffQffffޮF@ffffQħF@\QffffF@xQF@3333GQffff6F@3333sQ3333F@ffffQ3333+F@3333QF@ffffQ̤F@3333Q3333SF@ffffQ!F@Q̤F@3333QF@QF@ffffbR؀F@1RȀF@ffffKRF@HfRF@RF@3333RF@ffffrRF@hfff^Rxfff~F@ffff>R3333SF@8RF@0RffffF@pRffffF@cRiF@4aRF@^R3333F@3333]RF@3333WRF@1PŘF@ffff6JRIG@3333[?R3333C G@.RffffFG@R$-G@3333oR3G@ffff^Rffff8G@3333 RyAG@ffffRffffFG@̨Q3333PG@ffffQffffSG@QA\G@3333Q`G@ffffQhG@QmG@3333?Q)G@ffff֘QG@QG@tQ3333[G@QXG@XsQG@0eQffffnG@%^QG@3333SQH@,?Q33333#H@44Q.H@3333/Qffff.0H@T#Q:H@QffffVEH@ffff>Qffff.PH@Pffff]H@PmH@̄Pi{H@3333GP,H@3333gPHH@xP3333H@3333aPH@ffffZYP3333H@ffff5P3333H@U$PiH@PvH@ffff P3333oH@\ P1gH@ffffP3333ckH@ PkH@PfH@PffffvXH@=P3333sFH@3333SP3333+6H@(P$.H@3333+-P'H@0P1H@̜4Pffff&H@3333o=PffffvH@3333OBP H@ffffPPH@ffff WPlH@t^PH@LpP3333KH@3333O{P,H@̀PffffH@QP$ H@PH@P H@PPH@PH@3333kP3333kH@qPH@P3333H@tPG@\vP̜G@]pP G@3333jP3333G@fP3333G@^PG@3333VP3333KG@ffffNPG@3333@PdG@BPG@33337P3333 G@-PG@3333 1P4G@6PG@a:P0G@3333EPG@hTPG@3333PP܈G@3333KLPXG@ffffBPffff^G@PF@2333 O\AF@ffffOffffEF@2333;O3333KMF@ffffǑRF@P@KF@3333PEF@tPd>F@ PKF@3333OPqFF@ffffP8F@Pffff5F@̤P3333*F@iP`%F@4P3333&F@P3333F@%Pffff.F@3333C,P3333F@33334PE@07PffffE@ffffEPE@3333KPffffE@OPffffE@UP̄E@VPYE@XP3333[E@l[PE@\PE@^PPE@ dPE@\jP3333[E@=oPffffE@uuPE@3333xPE@ffff~PLE@3333#PE@hPE@ P3333+E@ffffRP33333 F@3333[PiF@3333_P /F@wPffffHF@H|P3333IF@ffff^P7F@P 5PԬF@7P3333cF@l:PF@4Pffff޼F@#PF@iPF@xP@F@3333#PF@PF@Pffff6F@3333S"PF@ffff~(P3333+F@3333)PF@ffff%Pffff&F@33331PF@3333w9P F@ffffCPF@RPffffF@bP,F@3333xPF@(}PyF@ffffPffffF@DP3333F@3333P3333sF@3333'PffffNF@ffffPF@PF@ffffކP3333F@33333P!F@P1F@ffffP F@ffff&PffffFF@3333PYF@ffffBP̬F@ffffַP̜F@ PF@̺P3333F@PffffF@aPlF@PF@K̬I@ffff&KffffI@̬K̼I@̼K3333I@KI@xKI@2333LI@L̄I@L3333 I@KI@KI@K̜I@K@I@TKxI@2333KDI@ffffK3333ӐI@qK$I@fffffK3333CI@K$tI@2333#K9kI@ LffffcI@2333 L0aI@2333L]I@\L3333SSI@ffffLJI@23330L`5I@(:L̤0I@ffff6:L,I@=L3333"I@ ELffffvI@XL3333I@̼]LI@_LH@2333_LIH@ffff`L3333H@ffffeLH@`kLH@lLffffH@2333#jLH@̔gLffffH@HgL0H@H@̬K̜5H@ffffKa2H@X Kffff1H@J33337H@ffff&J3333s9H@PJ9H@2333Jffffv?H@|JpAH@J3333=H@ffffJGH@8J3333KIH@AJ3333HH@1JIH@LJPH@TJ3333[TH@ffffvJ TH@Jffff>QH@J3333+IH@ffffƄJBH@̴J3333{=H@`Jp3H@PJ3333/H@МJ.H@̌J /H@2333˪J-H@J̬%H@ffffJffffH@ JffffH@̴J@H@2333[J H@2333JffffF H@ffff&JH@ffffJffffFH@ JlH@ffffNJ̄H@2333Jffff>H@ffffJ3333KH@JH@,JG@ffffJG@2333KJffffNG@̌J̼G@2333;JffffG@ffffJLG@Jffff6G@JG@HJffffG@2333{Jffff6G@0JG@JH@2333uJ3333H@qJH@nJffffvH@ffffoJffff H@JG@̼J\G@ffff^JffffVG@ffffNJ1G@IJ̄G@J3333G@ KffffG@ffffKffffG@KaG@KffffG@3K(G@̜7K,G@2333[:K3333G@2333{>KG@HKffffG@lEKiG@2333K;K3333G@Q@OQ؋Q@:Q3333?Q@ffff1Q3333Q@00Q3333Q@/QffffQ@ffffJ.QffffRQ@1Q3333wQ@5QQ@@Q3333~Q@h9Q|Q@ffff/Q@|Q@*Q3333}Q@3333$Q3333Q@QQffff&Q@ffff QQ@ffffQQ@3333Qffff.Q@x Q8Q@dQ3333GQ@QQ@ffffQQ@ffff QQ@̸Qffff"Q@QMQ@PQ@3333PQ@ffffFP4Q@`PffffQ@PwQ@ Pffff*sQ@ffffVPppQ@3333/PnQ@P)nQ@̌P$nQ@̘PqQ@ffffNQHqQ@3333KQffffFpQ@ QffffnQ@QlQ@QffffjQ@Q=iQ@*Q1iQ@33335QgQ@GQdQ@ffffNQcQ@ PQ3333`Q@3333DQ(aQ@A2QdQ@ QffffdQ@̸Qt^Q@ Pffffr]Q@ffffPa^Q@ffff^P^Q@P=^Q@ffff*Pffffr]Q@3333_PZQ@UPUQ@3333߭PSQ@3333۫PIRQ@HPffffPQ@yPffff:LQ@ffffFPJQ@ffffbPffffIQ@PPJQ@9PffffKQ@ffffPJQ@PKQ@ffffPLQ@POQ@3333 QLQ@QNQ@'Q3333/MQ@BQEFQ@̔?QEQ@Q3333KQ@tQffffJQ@3333Q|HQ@IP8DQ@PyBQ@P;Q@3333P@7Q@ffffP,2Q@Q2Q@Q6Q@3333Qt6Q@̼"Q5Q@3333*Q3Q@3333k.Qffff3Q@NQ7Q@3333UQ 8Q@ffffUQ7Q@lTQ6Q@7Q33330Q@"Q/Q@3333SQffff.Q@3333w Q,Q@ffff Qffff+Q@ffff~ Qffffn'Q@mQ3333?#Q@P!Q@Px!Q@ffffPffff#Q@3333P3333?#Q@HP,"Q@3333'PQ@ffffP8Q@PQ@P̈Q@3333P3333/Q@̈PLQ@̰PffffQ@3333˰P-Q@3333ӿPffffQ@PffffQ@PQ@ffff.P Q@eP3333 Q@PMQ@P4Q@ffffP Q@PAQ@3333P3333Q@ЫP3333Q@iP4Q@Pffff Q@aP3333{ Q@PQ@PffffQ@3333 PffffQ@̔PQ@|PP@3333P3333P@PyP@iP]P@Pffff>P@3333PP@iP\P@P3333cQ@P|PffffQ@ffffj|P3333Q@d~PffffFP@QwPP@ffffpP@P@lP%P@pdPffffP@̔`PP@ffffn_PffffP@TcP(P@bPP@ffffYP0P@ffffXPP@ffffvZP3333WP@M\PDP@̔ZPEP@8SP P@3333DPQ@>P3333Q@3333;PffffQ@x5P\P@47PP@5=PffffP@ffffAP3333P@ffffDPP@YAP3333gP@5P1P@(PffffP@3333!P3333P@3333_P3333[P@ P3333P@ffff>PP@2333Offff:P@PP@ffffPffff:P@hP3333P@PP@ffff&%P3333P@,P3333oP@ffff%P1P@3333PDP@PdP@ P3333wP@ PP@ O3333P@|O4P@ffffOffffP@O)P@2333O3333P@lOffffP@2333#Offff P@O(P@2333O}P@ffff&OffffbP@2333OP@DOP@OP@pOP@ffffO1P@dO(P@,{OP@2333jOP@2333SbOP@ZOP@2333+MOffffnP@23330OP@OP@N8P@|NP@NffffұP@O|sP@NOPnP@ffffVTOhP@bOffffrhP@̜hOtiP@|OgP@OjP@ffffΞOlP@OvP@pOffffvuP@2333sO3333_pP@OYmP@2333sO(kP@ffffVOMjP@ffff.O̴hP@1OxgP@ObP@2333ONP@ffffnO̔GP@0O\AP@̤Oe;P@2333[OM?P@ OICP@ffffOTEP@2333OffffFP@ffffOffffGP@ffffPGP@ PPXP@FPffff]P@ffff>KP\dP@3333?MP̼eP@ RPffffNkP@3333SPlP@UPlmP@YPpP@33333XP̜tP@QPyP@KP(|P@BPDP@33336PP@p1P3333P@ffff+PUP@$P3333kP@̀PLP@H PԔP@ffff)Pffff^P@ffff0P3333ǎP@8P3333ˈP@I@PP@3333SPffffP@̘ZP3333P@bPffff.P@tPP@3333yP3333KP@vPP@jPffffP@fffflP3333P@3333pPP@vPffffP@)|P(P@Pffff~P@YP5P@PP@ԚPIP@ffffP3333P@ffffPxP@P3333P@dPP@9PP@ P(P@ffffPffffҧP@3333P=P@PP@3333PP@3333#PP@3333PffffvP@TPMP@EPffffP@$P3333P@lP3333ۓP@3333PpP@3333PQP@3333P̠P@hP3333SP@̔Pffff^P@PffffP@eP@P3333'dP@PdP@PhP@ffffPhP@tP0iP@ffff^PhP@̔PeP@3333+P(cP@$Pffff`P@3333kP^P@̌P3333/\P@3333PZP@ffffP3333VP@Pffff.VP@PffffUP@]PqSP@AP3333OP@PffffKP@PHP@PFP@ffffP3333oEP@ffffVP4EP@̸PFP@PEP@-P3333DP@,PffffBAP@P3333 7P@ffffP,4P@ffffVP33334P@3333P3333S>P@P@P@3333#P4>P@P33337:P@QP6P@lP5P@LPffff1P@ffffP3333W0P@̼P<.P@ffff‰P/P@P33332P@ffffPffff.6P@|P8P@(qP̠6P@hPT1P@̼fPffff/P@`P33337-P@̤[P}.P@ffffQP3333k(P@3333[VPffff%P@`P!P@aPffffN P@\_P P@ffffnKP3333 P@ FP3333P@ffffDPffffP@MPhP@UPffff*P@ffffz`P3333_P@ffffePP@$ePffffP@ffffBVPffffP@ RP P@ffffVLP3333OP@3333IPP@IPffffRP@KPffffnP@3333JPP@@P̐P@3333[:P̬P@3333k2PP@l+PffffP@*P̜P@ffff+PO@3Pffff>O@)1PO@(P̌O@ffff$PO@3333P)O@LPiO@PO@#PO@8#PIO@PPO@PO@PO@ffffQ3333O@QO@̀(QO@6QP@RSP@YS1P@ffffaSP@-hS3333CP@pS P@ffffrSffff~P@SffffP@SP@,S̈'P@̤S*P@3333یSffff-P@$S0P@AS3P@ffffSP@3333SffffrAP@3333xS3333DP@3333\S3333WJP@WSLP@IWSNP@̈]SUP@3333w]S3333VP@3333_[SWP@VSffff[P@TS]P@3333PS]P@ffffFS3333[P@Y=SZP@1S|ZP@SWP@ISDRP@3333RNP@3333{R3333IP@ffffFRCP@Rffff@P@ffffRP@3333R3333@P@3333cR3333CP@RaFP@LRffffHP@xR3333sPP@Rffff SP@YR4TP@DRffffQP@̤R,RP@ffffRffff6UP@ffffR3333KWP@ԾRiXP@dRffffXP@3333R|WP@3333ˤRffffFWP@ffffRWP@RqYP@(R^P@܈R8`P@URffffaP@0xR4aP@9kR3333^P@@cRffff_P@3333cR3333bP@-iRffffiP@oRqP@fffftRsP@ffffR!xP@̬RЀP@3333R4P@śRP@ffffRP@ffffRffffRP@{RffffP@deRqP@̔[RffffRP@3333VR̸P@QRffff2P@3333LR3333P@ BRffffP@?RP@d>RffffP@Q@4Q@$S06Q@̜%S]>Q@#S3333@Q@̰SffffAQ@`S3333[CQ@S̬AQ@ RAQ@3333RCQ@3333RffffFQ@Rffff*JQ@tRffffMQ@R,SQ@`RdTQ@SffffXQ@% SMZQ@<SZQ@S3333;\Q@S3333 ^Q@M!SaQ@̘!ScQ@!SeQ@ffffSgQ@ffffSffffiQ@3333S`jQ@ SkQ@ SkQ@3333%SjQ@+S3333eQ@ffff/SffffdQ@̘:SgQ@AASffffzgQ@EShQ@ffff>HSffffiQ@FSjQ@ffff2ASlQ@33337S̰oQ@33336SqQ@=SfffftQ@AS3333uQ@NSvQ@ffff_S̄uQ@eSffffvQ@̨hS̠yQ@ffffnjSffff}Q@3333/kSQ@4nSffffQ@qSDQ@uSЏQ@SffffQ@ЎSQ@SffffQ@hSffff2Q@ɤS(Q@ŧSffffQ@3333sSQ@,S̤Q@SQ@̴S4Q@@S̠Q@9SФQ@4S8Q@3333/S3333מQ@mSQ@3333SQ@V(PR@33330VffffSR@/ViUR@U/V`WR@.VXR@!-V3333YR@ VfR@ffffJUkR@UDnR@3333;UffffpR@33333U`uR@ffffU̴vR@|UhvR@ffffGU̸sR@̘@UqR@3333>UpR@U3333wlR@3333MU̠fR@3333_UaR@kÜ]R@UTR@̈UPR@3333ϞUt=R@3333ǤUffffF:R@3333GU33337R@̼U0R@UffffV.R@ffffUP*R@3333WU!R@̤Uffff~R@̼U̼R@ffffFUR@ffffvUffff> R@ؕUffffR@UffffR@3333U3333Q@PU3333WQ@pU Q@`bUQ@TU3333Q@ EÙQ@3333AU3333Q@ffffHU3333kQ@YU3333Q@3333wpUiQ@|UhQ@|U3333#Q@IUffffQ@ṴQ@2333NH@O H@̼FOH@YfOٕH@PO3333˜H@ffffnOH@Offff޺H@ffffOdH@hOffffH@DO0H@)P3333H@ PH@ffffP̄H@PH@iPH@LOH@`OffffH@ffff^OH@mOLH@QOH@ffffO3333H@2333OH@N3333KH@0NH@2333N3333ˑH@lNH@2333NH@Offff;G@aO1:G@ffffVO=G@9OGG@fffffO33333EG@ffffnO@G@OAG@0OffffAG@ffffO:G@O3333 6G@d{O6G@2333#[O33339G@IWOffff:G@(6O8=G@O\>G@ O̜;G@2333;O 9G@ Offff5G@O|-G@(O#G@ffffVCOG@FO<G@EO G@EO3333G@T@OG@1=OffffF@2333DOF@ _O3333F@ffffgOF@ffffnpO,G@ffffsO̼G@PO3333{G@2333ӂOffffG@rOG@yO3333G@OPG@ffff6OG@ffffƆO"G@`Od%G@ffff>}Offff~(G@HOffff%G@O\ G@OLG@OG@ffffO3333G@2333SOffffvG@hOffffG@OG@ OG@2333O%G@xO/G@Oh/G@O333331G@2333O2G@ffff&Offff>4G@3333CP3G@Pt6G@P3333GG@̴P3333LG@P3333PG@PRG@PffffXG@PffffvbG@3333PjG@IP\sG@3333 P9zG@,OG@ffffO}G@OtG@PAcG@ffffOffffQG@̌O3333MG@ffffO3333CIG@O3333DG@O AG@2333O8?G@Offff;G@T3333#zO@y}TffffvO@|T(qO@̸}TiO@3333_Tffff^cO@3333T3333s]O@3333GT|SO@՘T3333sBO@lT)9O@ffff^T̜3O@3333TffffO@TffffO@LT O@3333'TO@T3333{O@ffffT3333O@̸T8O@T3333 O@3333T&O@T̄3O@dTx6O@ET!:O@TR@3333STER@3333_ T3333SJR@3333 T`NR@TOR@'TTQR@̄.ŤSR@̰1T3333cUR@33334T\XR@33334Tt[R@ffff3T-^R@1T^R@/T3333^R@4T8bR@6TeR@ffff7TffffjR@T6T(nR@4T̔oR@0T3333pR@'TqR@3333cTpR@ffffT@mR@3333SlR@3333cS3333iR@.Tffff_J@Y3T3333]J@@T\aJ@ffff.FT3333cJ@3333VTffffmJ@3333uT̜zJ@ffffRTXJ@3333T3333cJ@3333|TJ@yT1J@ffff:vTؗJ@ffffvUT̴J@HTXJ@9TJ@33330T,vJ@x-TqjJ@h-TdJ@.Tffff_J@SL@%S3333L@|SL@ S3333KL@3333׶S̴L@S%L@̔Sy+L@)S1L@ffff°S5L@ffff^S88L@̪S$8L@3333S(L@3333SX!L@3333sS@L@ffffSffffVL@SL@Sffff"L@ffff&SffffL@ffff^SL@3333;SIK@̔S3333sK@3333S3333K@3333SffffvL@S3333L@3333S!L@S(L@ffff2SffffL@3333SK@$SffffK@SK@ffffSqK@SffffK@SDK@ffffS L@̨SL@SffffnL@!S3333{L@SdK@Sffff~K@33333S1K@3333T̜K@ TffffNK@S̜L@ffff*S3333KL@ffffS3333)L@3333S3L@ffffS:L@3333SBL@ffff^SffffEL@ffffSffffDL@S3333AL@ffffSffffF9L@3333{S3333 (L@SL@xS3333L@3333SS L@TSL@ S3333c#L@S3333+0L@ffffSffffF;L@3333oS3333LL@ffffSffff>LL@ffffS̼HL@xS3333CFL@ffffSDL@SffffBL@ffffjSYS@̌YS@ffffvZQ%S@MY3333$S@̌Y=&S@AYx&S@=Y3333$S@ffffjY|"S@3333+YffffS@HYffffS@%YS@3333OYffffS@YS@Yffff>S@8Y3333S@ffffRZS@ZffffjS@3333Zffff^S@i Z3333S@3333$Zffff"S@&Z3333K%S@|%Z&S@ffff ZX(S@ Z*S@Z*S@̄Y *S@aY(S@3333YffffN'S@ffffvZQ%S@]R@I]R@L]ffffjR@]pR@ffff]ffffvR@3333]3333wR@@]ffffR@}]3333gR@]ffffR@8]@R@]R@A]3333OR@3333]R@3333x]ffffS@(p]ffff2S@ffffh]]S@ffff`]\S@_]S@ffffh]ffffR@ffffm]R@3333y]̌R@3333]R@]R@3333Gu\LpS@3333dž\ nS@a\,nS@3333\`3333۷J@'8`TJ@33338`ЛJ@';`ffff~J@3333iR`̄bK@O`ffffjK@ffffJ`yK@F`PK@ffffF`8yK@ffff.K`3333ChK@"Q`ffff_K@3333iR`̄bK@`IxJ@5`3333sOJ@3333Q`aBJ@3333u`9J@`+J@`3333%J@c`3333-J@`ffff;J@3333`,GJ@̆`LJ@`ffffaJ@̠`(`J@3333`3333VJ@3333`@VJ@3333 `3333`J@"`ffffFiJ@3333 #`(rJ@3333%`3333{J@%`ffff~J@%`3333KJ@#`3333J@̰"`J@ffff!`̞J@ffff!`ԣJ@ `ffffJ@ffffr`AJ@3333`J@>`fffffJ@`IxJ@_PH@_ffffH@_H@ffff_إH@Ў_fffffH@X_̜H@`_H@_PH@ _H@ffff_3333SH@0_IH@3333C_ffff.H@̜_pH@$!_H@a(_3333+H@3333)_H@'_ffff6H@#_H@_(H@_iH@ _H@ _3333H@_H@_ffffH@_0H@_ffffH@_3333+H@)_H@_3333H@fffff_ffff6H@@_3333;H@ffff޴_H@=_H@ffff_|H@_ffffvH@4_3333kH@ _3333;H@ _3333H@K_ffffn I@|L_̬I@̜P_̤I@V_'I@V_ffffN-I@ffffFS_5I@3333P_3333{5I@3333L_33331I@H_3333{+I@H_ffff(I@E_ffffF"I@̼D_ffff>I@3333;G_I@K_ffffn I@`HAJ@`l;J@ffffF#`̄IJ@3333$`3333{MJ@(`p\J@(`bJ@n(`fJ@'`ffffgJ@&`fJ@3333%`HeJ@`3333TJ@3333`LJ@`HAJ@-_I@=_̄I@_ffffI@l`̬I@`lI@`8I@ffff`3333I@`YI@`̬I@ffff_ffffI@(_8I@ffff_I@_I@̤_3333I@-_I@ `P3J@@`1J@o `ffffv8J@33333 `ffffG@*PG@+PffffvG@E*P3333G@3333s*PxG@%P̬G@ffff&$PG@̌ PG@xP̼G@%P G@3333"P3333G@@!PffffH@3333 P3333H@P3333H@xP̼G@Pi%F@ffffP F@ffffP3333S%F@P33330F@ffffvPffff.2F@Pi%F@̰PDWF@iPPF@PaF@ffffVPffffgF@̴PLeF@33337P3333ZF@̰PDWF@AdR3333 F@0iR|F@3333qR3333ۻF@zRF@y}RF@ffffvR3333F@3333kRF@paRF@x^R4F@|bRF@ffffNcR3333F@AdR3333 F@lRF@8tRffffNF@vR3333kF@`nRffffF@dRF@lRF@Q̼oG@3333wQ3333nG@Q$sG@ffff"Q{G@LQG@ٴQhG@ffffvQ3333uG@Q̼oG@Kffff\I@2333KffffZI@ffffKZI@ffffK3333C\I@2333#Kffff^I@`KffffcI@2333{KfffffI@KeI@2333KQcI@|Kffff^I@Kffff\I@ffffFK`H@ffffZKH@ffff6_KffffH@̬dKH@hKH@nK̼H@ffff~mK\H@2333hKH@ffffdK̬H@,dK9H@aK3333H@ffff]KH@23333OKH@2333GKH@2333DK3333[H@ffffFK`H@O@̜P|5O@"P2O@3333*P1O@ffff5P4O@9P5O@33337=P3333:O@;P>O@ffff5P@?O@33334P3333@O@d6PACO@ffffR6P3333EO@4P̄GO@ffffQffffN@ffffQN@`Q̄ N@3333QI(N@ffffQ(.N@ffffQP:N@ QGN@3333Qffff>KN@P3333IN@ffffPEN@ffff>P>N@hP9N@P!2N@3333P+N@Qffff&N@ffffQffffN@ffffQPN@y=P3333N@ffffJQffff&M@ffff"NQ{M@3333OSQ}M@,UQffff{M@̔VQzM@ffff>TQ̴M@SQ3333M@ffffUQ̄M@hSQ3333M@}LQ̴M@3333gLQM@KQffffNM@ffffIQ3333#M@ffff>JQffff&M@ P.N@HP &N@#P`)N@ffff:/P0N@ffff3P4N@\5Pfffff9N@5P!@N@2P3333;AN@\)PffffAN@"P8N@P7N@ P.N@2333KNL@}NL@N3333+L@|N L@Nffff.L@ffffN3333c L@2333+Nffff&L@ NffffL@ffff6N3333L@2333{Nffff L@IzN3333K L@2333KNL@ffff.NL@2333kN1L@NAL@2333N3333L@NiL@pO4L@O`L@N3333L@NL@PN\L@ffffN(L@ffff.NL@ffffP3333bQ@-P3333;bQ@3333 Q%eQ@3333+QxgQ@Q jQ@MPpkQ@ffff*P3333kQ@P33333kQ@3333KPihQ@3333P3333eQ@ffffP3333bQ@O3333P@_I@@_I@A_)I@̸?_lI@3333+?_I@i?_3333I@<_<I@ffff:_ffffI@:_ I@$:_ I@3333>_I@ffffgRffff*P@3333RP@R̈P@ĞR3333P@ffffRP@ffffnRP@ffffR3333P@Rffff.Q@ЮR3333Q@8R3333KQ@HR3333Q@ RQ@]xR3333gQ@`eR3333Q@_Rffff Q@d]RffffZP@3333[RP@3333YRR@3333XpR@\XXR@pX5R@X3333R@ffff:sXffffVR@lXR@3333jXąR@3333/jXR@kXdR@MpXffffZR@wX3333}R@hXffffxR@MXwR@ɌVffffZQ@ffffZVffffVQ@3333V3333wQQ@VPQ@3333#V$PQ@LVffffPQ@V UQ@}VWQ@ VXQ@$V3333ZQ@̜Vp[Q@ffff.V3333ZQ@̠V[Q@ɌVffffZQ@ffffVffff&NQ@3333äV3333gMQ@ V3333PQ@3333V3333PQ@V`RQ@aVRQ@V̀UQ@3333VffffVQ@3333kVffffWQ@aVffffWQ@̌VffffTQ@ffffVffffRQ@VOQ@ffffVffff&NQ@3333R(OO@mR NO@9R̜OO@R3333UO@R3333;[O@R\O@R]O@3333Rffff\O@DRYO@RWO@3333R3333TO@ffff>R3333kQO@3333R(OO@`RPQ@eR3333Q@RQ@R]Q@R!Q@R5#Q@3333[R3333%Q@̰R(Q@dR,Q@Ř,Q@Rffff+Q@Rffffr)Q@R3333"Q@iR̤Q@ffffR3333OQ@ffff.R4Q@R3333Q@ffffRtQ@3333cR8Q@RlQ@`RPQ@ffffSA]N@3333ϪS3333[N@ffffҪS̜]N@3333+S3333bN@ffffSpgN@xShN@ؑSffffVdN@ffff֗S`N@ffffSA]N@S3333W Q@Sffff Q@3333#S Q@3333/SQ@ffffStQ@3333SQ@̘SQ@ffffS)Q@S3333W Q@]+SlO@33332S(O@;S3333O@CSO@XWSffffNO@ffffHSLO@33330S3333kO@)StO@]+SlO@S3333krQ@ffffS3333nQ@\S3333mQ@SkQ@aS`hQ@mSfQ@ffff T̘hQ@3333'S3333cQ@ffffS̀aQ@̔Sffff`Q@T3333`Q@U TLbQ@̌TffffcQ@TffffeQ@1TffffffQ@ffff.TMeQ@TeQ@ffffvT|hQ@̬T̔iQ@ffff1TTkQ@2TlQ@33331TffffvmQ@̀.T3333coQ@3333)T pQ@T,oQ@TffffoQ@ TrQ@ffff&T sQ@TrQ@̬ T3333SsQ@ffff T3333rQ@T3333/oQ@TffffoQ@ffff"S3333KoQ@3333SffffZpQ@SrQ@S3333sQ@S3333krQ@܁SmQ@̔~SjQ@ffff~ShQ@3333SfQ@SPcQ@S)`Q@ffffZSu_Q@3333_S3333+`Q@ffffS^Q@HSffff^Q@S3333{aQ@3333SffffhQ@SiQ@3333S0kQ@SffffjQ@SffffkQ@̐SmQ@،SToQ@3333KS3333OoQ@܁SmQ@iSffffO@3333mS O@q{S3333#O@ffffN}SffffO@ffff}SO@3333{SffffP@}mSHP@gSaP@pdSffffP@ffffdSiP@iSffffO@3333TP@3333TffffRP@ffffT3333gP@3333TxP@T3333WP@TP@3333wTP@̰T3333P@ffffTdP@8T8P@9T̈P@3333TP@3333{S6Q@3333S5Q@ S6Q@S8Q@S3333;Q@S(KU<~P@3333IUP@ffffBUP@XhR@ffffRAXR@ffff>X̠R@33336XmR@3333w!XffffZR@3333_XffffR@X]R@lXeR@ffffXR@ffffN XDR@̌X}R@ffffnWffffzR@WR@3333XR@WXR@ffffWffffR@AWdR@W3333?R@fffffW3333kR@ffffrW3333GR@WPR@WlR@DW3333èR@3333WR@W|R@WR@̐Wffff:R@WXR@D^ffffR@I^fffffR@3333kO^ffffR@ffff&N^ffffR@3333A^=R@@^R@(A^̐R@̴B^ffffR@?^3333[R@ffff~:^R@8^dR@<8^3333R@fffff9^ R@:^ R@=^3333{R@l@^R@D^ffffR@ffffc\/S@̘m\y-S@\0S@3333\ffff1S@t\2S@i\3333w6S@3333ߚ\8S@y\E9S@Hm\ffff7S@3333we\ffff:6S@ffffa\4S@4_\ 2S@ffffc\/S@̬Z3333SR@Z3333R@̘(ZR@5ZR@33338ZtR@l8ZER@3333G6Z3333R@H3ZR@3333/,ZffffR@ffff)ZffffbR@XZ3333oR@(ZR@3333Z3333+R@YR@yY3333R@ffffvYR@YR@ffffY(R@Y|R@3333/YR@YmR@3333YffffR@lY\R@3333YffffR@̬Z3333SR@3333 Y̠3Q@Yffff1Q@mY33331Q@hY̤.Q@mY3333S.Q@3333SY/Q@3333YP2Q@Y2Q@X!Yffff2Q@ffff$Y33331Q@-&Y 1Q@l'Y33332Q@ffff(Y84Q@ffff'Y`7Q@d&Y3333?Q@$'Y3333_?Q@p&Yffff@Q@0$Y3333AQ@L!Yffff>BQ@ffff~YAQ@Y?Q@ffff~YffffJ=Q@= YffffF;Q@l Y9Q@3333 Y̠3Q@̨X@Q@3333'Yffff=Q@3333 Y3333>Q@ffff Yt?Q@|YBQ@Y`CQ@,Y3333DQ@3333 YLGQ@ YIHQ@̨Yffff"GQ@3333CYffffEQ@\YCQ@̨X@Q@Y3333Q@3333Yffff6Q@ffffb"YQ@̸'YQ@t)Yffff Q@3333*Y(Q@i+Y3333[Q@̨(YffffQ@m"YffffʪQ@YQ@YffffQ@̌YQ@Y3333Q@YQ@Y3333Q@WffffdQ@`Wl`Q@tW3333W^Q@WZQ@3333W8XQ@ffffWhVQ@ffffWffff~UQ@W|UQ@ffffWffff>VQ@WffffXQ@WffffYQ@̜W\Q@3333W`Q@W3333obQ@3333WcQ@̘W3333cQ@ffffVW̘bQ@W_Q@W\Q@WffffvXQ@ffff.W3333VQ@0W3333WQ@WYQ@ffffW[Q@ffffW3333^Q@W̐`Q@3333WffffJdQ@ WfQ@ffffW hQ@9WgQ@3333WfQ@WffffdQ@JYiYQ@9PYXQ@3333/QY3333XQ@̼PYZQ@ QY[Q@3333RY=\Q@MY̠]Q@DMY^Q@ffffNYffff_Q@UYaQ@VYffffbQ@|VYffffcQ@ffffTYffffdQ@OY̴dQ@3333KFYbQ@ffffAY_Q@ffff @Y]Q@%CYffff>]Q@3333EY`\Q@ HYffffZQ@JYiYQ@3333#vYffff%Q@xYp%Q@t|Y̔&Q@ Yy*Q@̸Y+Q@PYH-Q@ЉYd/Q@ffff„Y1Q@3333ۀY33334Q@uYffff"3Q@̘pY33331Q@nY80Q@3333/nYX.Q@nY̼)Q@rYffff(Q@3333#vYffff%Q@ffff"ZffffQ@$&ZQ@,ZQ@x6Z Q@ffff=ZxQ@BZ"Q@ICZ3333#Q@?Z$Q@:Z<%Q@3333,Z$Q@3333&Z#Q@33337Z9 Q@3333sZ Q@0ZQ@AZQ@ffff"ZffffQ@3333Z3333P@Z]P@ ZP@@[3333kP@[̤P@ffff [|P@ [ffffP@[\P@)[ffff:P@ffff"[P@ffffjZP@dZ(P@QZffffP@ffffZffff~P@ffffZP@Z3333P@3333Z3333P@ffffJ[3333P@3333sC[33333P@>[P@33337:[3333P@̴8[P@49[3333P@:[ffff>P@(F[3333#P@ffffVJ[P@K[fffffP@ffffJ[3333P@3333[TP@ffffZ3333ӿP@ZP@UZ3333P@ffffJZ̷P@iZffffP@ZP@ffff[P@3333[TP@ffffT[ffffjP@W[4P@ffff_[ffffQ@ffff^[EQ@ffffU[3333Q@̴T[ffffQ@ffffT[ffffjP@3333aaadQ@dabQ@33339ha3333eQ@3333Sia3333CfQ@wda3333iQ@3333Sba3333siQ@3333]a|gQ@\aeQ@3333aaadQ@V3333kH@UmH@U̬nH@3333UmH@UkH@3333KUgH@ffffUeH@UffffdH@ffff>UIbH@UaH@TffffF@ffff2TyF@TaF@ffffT9F@ffffFTF@3333T3333KF@TffffF@ffff:TF@pT0F@DŤF@T3333F@ffffʽTF@xT9F@3333T(F@TffffF@3333TF@@TF@3333TtF@ȲT3333F@TffffF@3333TF@(TF@8T3333sF@AT F@DT3333F@ffff&TffffVF@ffffT3333{F@3333WT3333#F@xTLF@ffffT3333#F@T3333F@ffffNTF@3333ףTF@TYF@ffff&TF@ffffbT3333 F@ffffT$F@ffffޟTF@T3333F@TF@lTffff6F@TDF@@TF@ْTF@ffffnT3333F@,TF@3333TF@TLF@8TF@ TIF@3333φT̤F@ffff~T.@ '@pffff.@0333&@L.@`ffff&@L.@03333:&@pfff&#.@%@@333C.@`fffL%@pffff.@0333$@Y.@$@.@ o$@Y/@L-$@LO/@$@@333/@̬#@٣.@#@pfffb.@`fff#@@333C.@9#@pfff$.@0333#@@333-@`fff&#@pfff&2-@#@pfff&,@Y#@̌|,@#@̌G,@#@pfff,@#@Y+@0333b#@̌,@l-#@ ,@@#@[,@ "@pffff,@0333"@pfff&,@03333h"@-@ "@@3333w-@9!@pfff-@`fff!@ -@!@@333-@`fff!@-@ j!@;.@Y!@@3333.@ @@333.@* @.@Lh@ .@@@@/@&@/@@@333/@0333s@/@`fffj@.@Y@.@n@pfff}.@`fff @i.@@pfff&_.@`fff&@@333sP.@A@@3333,.@@@333.@@#@pfff&-@03333@L-@ 9@̌-@v@@3333-@0333C@z-@@pfff&f-@@@pffff-@@@3333-@̥@@3333,@ف@pfff,@X@,@`fff'@,@@-@`fff@-@@̌'-@@2-@03333@;-@`fffu@;-@`ffff@*-@03333@@3333+-@0333@"-@g@@ -@`fff@pfff%-@@4-@L@H-@Y@R-@C@k-@̌@pffffv-@h@@333s-@;@-@03333@pfff .@`fff&o@̌ .@0333#@,.@`fff@F.@F@̌E.@%@;.@ @".@@.@@.@`fff@pfffA.@@z.@ @pffff.@ @@333.@ @pffff)/@`ffff @pffffZ/@`ffff @̌/@ @ٲ/@@L/@L@/@ 3333@/@:@0@ 3333@@0@D@0@@,0@/@hfff0@`fffl@`0@ 3333\@83330@ 333@8333s0@ 3333@8333S0@ 333@"0@@8333.0@)@.0@@83333-0@`ffff@0@ 333W@0@ 333@83330@`ffff,@0@@ffff?̌"0@3333?"0@@ffff?0@m? 0@@ffff?833330@?L/@)?pffff/@?@333{/@̣?Y3/@4?.@N?@333s.@?.@3333?@3333h.@2@@333Q.@`fffH@3.@@.@@L.@ 3333@ -@ 3333@-@@-@̤@-@@pffft-@ 333@@3333m-@`fff@V-@@pffff(-@̗@,@`fff<@@333,@`ffffH@,@`ffffE@pfff+@`ffffB@pfff&+@ 333F@L*@`fffJ@@3333*@ 3333@p*@ 3333 @C*@L@pfff&)@`ffff@T)@`fff @pfff3)@@@)@ 3333@@(@ 3333^@̌N(@`ffffF@Y6(@L@pfff&'@H@@3333'@`fffj@pffff&@e@pfff&@`ffff@ &@`fff@L&@`fffV@@333s1&@W@@333%@ 3333W@pfff&%@LW@@3333$@W@@333#@W@#@̴@#@`ffff@pfff&#@ 33334@#@`fffa@#@o@#@`ffffP@@3333#@ 3333@Y#@U@#@`fff@#@ @#@`ffffz @X#@M @ #@ @pfffH#@`fff @Y;#@`ffff @#@`ffffb@/#@ 333@A#@@@333z#@@pfffx#@ @pfffG#@@pffffL#@̌@@333`#@9@V#@N@pffff3#@̌@pfff#@@ #@>@pfff"@0333C@pffff#@@̌"@L@"@`fff`@"@`fffg@@3333"@`fff@@"@@̌"@@L:"@ *@ "@]@@!@0333@@3333!@03333)@!@`ffffn@@!@@pfff&!@ 7@pffff!@J@!@`fff&Q@@!@03333K@!@0333Q@@333sj!@03333@R!@@a!@0333s3@P!@@&!@@@!@I@!@`ffffl@$!@`fff&@!@Y@hfffvY@̌$@Z@i-@ 4333Y@0333&@Y@ &@̬Y@03333&@4333Y@0333&@hfffY@9&@4333{Y@@&@4333[Y@`fff&@4333Y@0333&@hfffVY@o%@Y@\%@DY@`fff%@LY@`%@hfffVY@o%@hfff>Z@i-@AZ@hfffL-@Z@l-@4333Z@hfff,@4333SZ@hfffƼ,@Z@,@hfff6Z@0333@,@Z@hfffF#,@,Z@ ,@Z@l+@hfffZ@+@Z@0333N+@4333Z@ +@Z@hfff&*@Z@ls*@lZ@̌*@Z@)@̼Z@`fff)@Z@li)@̌Z@y)@pZ@0333(@iZ@`fff(@4333Z@`ffff(@,Z@`(@ Z@Y(@hfffZ@`fff(@4333Z@`fff(@,Z@ٍ(@hfff>Z@ Z(@Z@̬'(@Z@(@hfffάZ@`ffff'@aZ@9'@Z@Y'@|Z@'@̼Z@'@IZ@ z'@hffffZ@`fffFe'@̌Z@_'@Z@]'@hfffNZ@̬j'@hfffZ@`fff'@4333cZ@'@43333}Z@l]'@L{Z@LN'@4333xZ@K'@hfff~vZ@ E'@uZ@3'@hfffvuZ@`fffF'@vZ@`&@wZ@̬&@vZ@̬&@yZ@Y}&@hfff^Z@`fffF(&@LZ@&@Z@L&@4333kZ@ %@hfff~Z@%@4333SZ@03333%@hfff^Z@ %@4333 |Z@03333%@4333xZ@̌%@̜vZ@`fff&%@4333sZ@`fff&%@4333SpZ@%@lZ@0333%@hfffdZ@0333%@\Z@ %@YZ@9%@̼XZ@0333S%@4333#TZ@%@1RZ@0333%@4JZ@̌%@BZ@%@lAZ@0333%@PBZ@`ffff%@CZ@0333w%@BZ@@g%@>Z@`fffR%@hfff9Z@03333.%@p6Z@`fff%@04Z@`fff %@4333#,Z@`fff %@$Z@,%@hfff Z@9$@4333Z@@$@IZ@̌$@4333Z@ %@Y@Y,%@hfffY@0333I%@hfffY@lO%@4333Y@@)%@\Y@0333%@4333Y@%@Y@03335%@hfffY@`V%@Y@,q%@4333Y@`ffff%@43333Y@%@Y@ &@Y@,7&@4333Y@K&@hfffY@+&@4333SY@%@Y@%@4333kY@̌%@Y@0333%@Y@`fff%&@Y@0333l&@Y@L&@Y@&@̬Y@`ffff-'@DY@0333k'@hfffY@`fff'@4333Y@{'@ĻY@0333i'@Y@0333v'@$Y@-(@43333Y@`fff(@1Y@L(@\Y@@(@4333Y@̬(@LY@#)@Y@`fffW)@hY@)@̌Y@0333*@ Y@'*@4333;Y@b*@4333+Y@0333*@hfffvY@y+@hfffY@+@lY@"+@Y@++@1Y@0333@+@ܢY@hfffQ+@̴Y@0333o+@hfffY@ +@Y@hfff+@4333Y@,@1Y@F,@Y@L,@4333Y@L,@Y@,@̬Y@,@Y@,@lY@,@4333{Y@0333,@`Y@l,@4333Y@,@hfffY@@,@yZ@,@4333Z@,@XZ@9,@$Z@0333,@43331Z@ ,@hfff>8Z@,@>Z@0333s,@>Z@03333,@8@Z@hfffF,@(BZ@lt,@hfffDZ@0333st,@HZ@ُ,@4333JZ@0333,@4333KZ@hfffF,@KZ@`,@@MZ@̄,@OZ@̬f,@4333;RZ@̬R,@iVZ@8,@!YZ@03336,@bZ@0333O,@XoZ@+,@hfffpZ@ ,@hfff6uZ@hfff+@4333yZ@Y+@hfffFZ@hfff+@0333Z@fff&,@0Z@0333A,@4333CZ@,@hfff~Z@,@Z@,@4333Z@hfff,@4Z@,@lZ@0333,@hfff&Z@0333,@Z@,@4333Z@0333-@Z@ (-@hfffZ@L-@4333Z@-@YZ@0333s,@hfffZ@@333,@hfff>Z@hfff,@$Z@0333,@yZ@,@qZ@hfff,@ Z@,@Z@`3333,@hfffZ@0333,@hfffZ@,@Z@Y,@9Z@,@Z@$-@4333Z@L/-@PZ@0333S-@4333Z@03333 -@Z@yT-@hfff>Z@i-@hfff~ W@03333#@lIY@\<@J #*3<ChfffY@Q4@4333;Y@,a4@4333X@Yj4@4333X@dfffl4@X@lb4@hfff~X@`W4@hfffX@PS4@X@ R4@hfffX@4333W4@hfff^X@\4@4333X@ Z4@43333X@B4@4333X@04@X@\&4@hfffX@I4@̌X@4@X@433334@(X@dfff4@X@y4@hfff^X@4@X@p4@4333X@4@4333SX@4333 4@1X@43333@PX@3@4333X@3@ X@43333@4333sX@I3@hfffX@dffff3@4333X@3@hfffX@dfffƱ3@4333×X@l3@4333˒X@3@LX@а3@4333X@3@4333#X@ 3@hfffX@3@pX@Y3@hfffzX@dfffƗ3@hfffFtX@u3@rX@D3@4333ssX@dffff!3@̴mX@2@0mX@2@ApX@2@̼oX@43332@4333nX@p2@4333jX@̬2@4333dX@Y2@`X@l2@ _X@dfff~2@iYX@|2@hfffWX@2@\XX@~2@\X@4333\2@hfffaX@K2@4333[fX@M2@hfffvhX@4333SJ2@hfffgX@ B2@4333iX@y,2@nX@4333 2@4333[oX@p1@̴lX@4333c1@hfff6mX@1@nX@̜1@rX@dffff1@y{X@dfff1@ X@_1@,X@i=1@4333kX@%1@hfffX@dfff0@(X@ 0@X@4333s0@4333{X@`0@$X@)0@hfffX@Ƀ0@IX@dfffT0@X@0N0@xX@dfffj0@4333X@d0@ٸX@dfffZ0@ܸX@PL0@dX@<0@YX@I.0@X@ 0@̼X@0333/@X@hfff/@|X@/@,X@.@̤X@@.@4333cX@̌.@X@.@X@.@PX@ .@܎X@0333{.@9X@h.@4333cX@yK.@X@̬-@hfffX@hfff&-@AX@d-@̜X@4-@hfffX@ ,@4333{X@hfffF,@(X@0333x,@X@hfff,@X@0333+@̄X@@+@X@0333n+@X@&+@X@l*@hfffFX@0333Sw*@hfffX@0333X*@X@5*@hfffX@*@4333X@03333)@4333X@̌)@X@z)@X@`fffFN)@hfffX@@0)@X@`fff)@4333;X@(@̤X@`fff&(@̬X@9(@X@`ffffa(@xX@`fff-(@XX@'@43333X@0333'@X@0333_'@X@`fffB'@hfffX@9'@TX@'@hfffX@`ffff&@4333+X@`fff5&@X@`fff%@hfffƸX@%@\X@j%@hfffvX@`ffffR%@hfffvX@`fffF?%@X@03333%@,X@$@̯X@$@4333X@03333$@hfffX@ya$@X@̬[$@X@`fff$@\X@`fff6$@̟X@0333s]$@yX@̴$@X@`fffZ%@X@p%@HX@9{%@4333SX@0333%@X@9@W@Q9@ܧW@dfffh9@̼W@yu9@4333KW@43339@W@P3339@dfffW@ 333C9@|W@<9@W@dfff9@0333W@9@4333W@9@yW@ :@hfffFW@ffff:@W@fffff:@iW@0:@AW@ffffX:@4333W@ffffVy:@W@ffff:@;@0X@0;@4333ۭX@ ;@X@̜:@4333CX@ffff&:@QX@:@hfff֮X@Y:@hX@n:@X@lL:@X@y0:@qX@2333#:@4333X@23333:@X@:@4333ӥX@2333:@hfffX@43339@X@43339@hfffX@43339@̼X@9@4333˝X@43339@̴X@9@\X@dfff69@4333X@9@4333 X@433339@$X@433339@`X@lj9@X@dfffVY9@X@4333J9@}X@4333cB9@zX@4333s<9@4333stX@y@9@qX@dfffv(9@mX@9@|mX@i8@9oX@8@4333SnX@̌8@jX@43338@TeX@Y8@aX@dfff8@4333bX@}8@ dX@q8@gX@dfffFl8@jX@dfffFa8@jX@P8@4333SmX@:8@43333lX@|!8@hfff^dX@ 7@!dX@97@LhX@7@kX@7@\pX@7@̜uX@|7@X@8@X@4333S8@X@y8@hfffX@̜8@4333X@L8@hfffVX@8@4333X@dfff8@YX@4333c8@qX@dfff8@`X@08@hfffX@7@PX@43337@4333X@7@4333 X@y7@iX@43337@4333CX@dfff֟7@X@97@hfffvX@dfff{7@X@p7@|X@\a7@̬X@dfffN7@HX@dfff07@hfffX@l!7@X@4333s7@X@̌7@X@7@4333X@dfff 7@4333X@,7@tX@6@X@4333c6@hfffX@96@hfffX@L6@hfffX@dfff&6@̜X@6@hfffX@^6@$X@dfffVH6@X@dfffF16@X@@'6@YX@@ 6@X@433336@hffffX@43336@X@\6@hfffX@43336@4333X@ 6@4333X@,6@X@43335@0X@5@W@dfff63@i:W@43333@:W@4333#4@i=W@4333 4@hfff@W@dfff3@=@>@T>@ffff3>@ihfff&q>@ffffl>@"83333o>@ffffE,y>@8333Ss>@p>@'̌l>@n>@t>@@3333%ك>@@3333W8333>@ffff{>@ffff>@>@hfff&>@hfff>@ffff>@̚ L>@ffff2 ̌>@y hfffF>@ffff hffff>@ffff hfff>@ hfffơ>@ffffY hfff>@ l>@ hfffff>@@3333; a>@ 83333Y>@=D>@hfff/>@ffff̬%>@pffffW=@@333:=@=@-=@bK =@@33338333=@@333v83333=@@33328333=@pfffn=@pfff o=@@]=@ffffX=@ZU=@M T=@̲ 8333T=@ hffffL=@ffff N5=@] Y6=@@ 9=@ 8333s9=@m9'=@ffff8333=@ffff@=@e=@̬=@8333S=@Q,=@ =@83332=@ffff L=@ffffb̌Y=@Uhfffc=@x8333v=@w=@W8333=@[̌=@!@=@@3333=@@3333Q8333=@c =@ffff83333=@ffffhfff>@Jhfff>@@3333Ul$>@O.>@@3333;>@`E>@ffff8333h>@8333s{>@@3333hffff>@@3333*>@ffff30333s"@@'.@?̌%@4333?0333S%@gfff?,%@?0333%@h?0333%@?`fff%@4333c?`fff#&@03333;&@ffff*ӿ0333sU&@Կ<&@ ֿ`fff-&@Qٿ+&@ffffۿ/&@ffffݿ0333&@x߿`fff&@ffffr`fff%@ `fffF%@0333%@%@r濘Y%@̰0333%@,%@3333&@`fff&&@̸0333%@ &@3333b̌&@3333%@i`fffF%@%@9%@@ffff`fff%@L0333s%@333,%@@ffffy%@3333Bt%@333Q`fffF/%@0333%@`fff$@LT`ffff$@K`fff$@@ffff0333ӹ$@L$@7,$@!0333y$@Nb$@Ď*$@#@,#@>}#@333 P#@L`#@0333s"@̼ "@"0333s"@333`fff"@Ly#@5#@̕03338#@_#@LWq#@33330333#@I `fffƲ#@ y#@LQ 0333#@ 0333#@3333 @#@3333S#@@ffff03333#@3333 #@@#@̌|#@ 3333TJ#@ 333`fffK#@`fff[#@@lr#@ـYm#@Y#@B̬#@`fff`fff#@ 333303333#@`fff$@20333A$@@f0333{$@0333ӕ$@ ̬$@ 333s`fffƠ$@Y$@ $@ 3333`fff$@0333S!%@0333I%@ 0333%@0333%@@0333&@`ffffl-&@c0333B&@ 30333si&@@`ffff&@`fff '@`fffL''@`='@)]'@@5Y'@ '`fff'@ 3330333'@L'@ 333sl`'@@0333'@10333s(@'(@Ľ=(@Y`O(@`fff&/0333s(@`ffff`fffF(@٬(@ 3330333s(@ `fff))@`fffB)@`fff&,X)@̌`)@`fffL)@`fff `)@ 333=*@P0333<*@`fff`fffe*@`fffhfff&*@`fffhfffƜ*@`ffff4*@*@@fff@*@3333 lc*@8 ̌]*@@ffff ̌d*@, hfff|*@j *@L" 03333*@L) hfff'+@3333 0333Q+@@ffff X+@3333O9G+@L03333F+@LL+@3333Vhfff[+@Yhfffy+@3333h0333Ӓ+@hfff+@;%,@hffft,@7@,@@ffffY,@@fff@V,@uhfffc,@,@hfff,@H,@Y-@ffff -@̌@-@Ghfff-@𿘙-@NhfffƮ-@0333-@U0333s.@S忘#.@3333+'.@ffffݿ̌.@ffffۿ.@ffffٿhffff.@1οl.@~?9-@hfff?̬-@hfff?hfff-@4333?̐-@?LN-@?0333,@ ?,@?y,@4333{?},@hfff?,G,@?',@x?+@4333?0333+@?hfff&h+@?^+@?YY+@4333'?0333L+@?@+@?8+@gfffJ?̌)+@I?+@3333I?̌*@? *@8? *@?*@:?y*@?̺*@A?hfff&*@4333#?9W*@?0333s*@ffff ?0333 *@ffff?0333*@ffff?`fff&)@?YZ)@ ?0333SE)@̼?Y=)@3333?:)@fffft?yA)@ffffL?03333j)@#@0333n)@@3333@̌m)@@3333@ g)@@3333G@E)@@3333@̬)@ffff@(@ffff@(@ffff@@(@@`fff(@ffff@ (@w@`fffF(@ffff@`ffff(@@3333@0333S(@@3333@E(@@3333@Y'@@L'@@ '@@3333L@a'@@ B'@?9&@̸?&@? &@?0333&@?@&@?&@3333e?&@C?`fff&@ffff?&@?,&@|?`fffF&@3333?`fff&@?`fff&@3333U?&@T?k&@3333+?`fffFY&@? P&@N?`ffff;&@ffffZ?'&@3333?&@8?"&@?0333s(&@?9&@gfff?0333S%@?̌%@8333X6@,D@ٕ<@pF@8333<@ D@8333;@ID@;@3333D@9;@pD@hfff&;@3333D@@;@ D@8333s;@iD@;@D@̌y;@33333D@hfff\;@4E@K;@ffff. E@̌>;@ E@1;@ffff E@;@E@:@pE@hfff:@D@hfff:@D@:@ffffND@hfff:@D@hffff:@ffffVD@:@D@:@`D@:@ffffD@@\:@D@hfffS:@3333D@hffffQ:@QD@hfff&R:@D@Y3:@4D@:@3333D@hfff:@!D@hfff:@,D@8333:@D@y:@D@$:@D@':@D@hfff":@`D@:@3333D@`9@D@83339@3333KD@8333S9@3333SD@9@D@9@`D@hfffa9@ffff֡D@L@9@,D@hfff&"9@3333kD@Y8@D@8@ffffvD@8@3333D@83338@̔D@̬8@D@83338@3333D@8@3333ӻD@̬8@D@hfff|8@D@c8@3333D@J8@4D@:8@D@Y8@|D@l8@3333 D@hfff8@3333D@97@D@7@\D@hfff&7@ܴD@7@D@,7@iD@8333n7@ D@@_7@D@hffff=7@ffffFD@'7@9D@̌7@ffffD@6@3333 D@6@̔D@83336@̄D@8333s7@D@7@3333D@83336@3333D@hfff6@ffff6D@6@D@96@ffff.D@6@IE@̬6@E@,6@3333k E@̌6@!E@8333X6@0(E@ l6@*E@r6@-E@hfff6@q8E@L6@=E@833336@@E@x6@3333EE@̬o6@ffffPE@v6@ZE@83333w6@`E@8333sp6@TeE@w6@ffffkE@8333Ӆ6@fffffoE@6@qpE@hfffƴ6@$qE@hfff6@,~E@Y6@ffffVE@L6@E@96@lE@6@ffff.E@83336@E@ 6@LE@6@ffff~E@6@TE@l6@ffffE@6@,E@hfff6@iE@`y6@ffffE@8333o6@ffff.E@8333e6@3333sE@ c6@̼E@^6@E@̌]6@YE@hfff&f6@E@k6@3333F@8333x6@ffffNF@83336@3333 F@y6@F@hffff6@F@6@0F@6@pF@8333s6@F@hfff6@3333KF@L7@3333 F@@7@3333 F@@6@,F@L6@\E@hfffF6@TE@@6@3333E@ 6@E@hfffF6@E@97@3333E@و7@AE@hffff7@E@ :8@E@9n8@ffffE@hfff8@̄E@(9@E@@9@E@hfff9@3333E@9@(E@83339@ffffnE@@7:@ffffF@@}:@ F@hfff:@ffffF@@;@lF@hfff;@̴F@hfffl;@F@;@F@;@E@8333;@xE@8333;@hE@`;@aE@;@̔E@ <@DE@83338<@E@ `<@TE@hffffl<@E@ٕ<@E@8333ӏ<@3333+E@hfff&w<@ԱE@8333Q<@3333E@9"<@3333E@ <@ffffVE@8333;@E@;@3333ӗE@;@ffffE@̌;@ffff_E@;@3333[E@8333;@pZE@|;@;E@;@3333S3E@L;@3333,E@hfffF;@E@8333;@E@8333<@ D@hfff\@̌@\@`fff@8hfff\@Y@\@w@hfff\@@\@03333@\@L@\@`fff@hfffn\@ v@\@ i@\@̌c@4333\@0333t@\@̏@L\@`fffT@hfff\@0333@\@H@hfff\@L@hfff\@Y@hfff\@L@hfffv\@l@T\@5@0\@0333@ɯ\@L@4333\@@\@L6@\@ @hfff^\@ @hfffƵ\@`fff@0\@k@$\@@hfff޳\@`fff@̬\@٬@hffff\@b@ܩ\@̌&@hfff\@̌@\@@2@Ƞ\@Lt@̜\@0333s@\@@4333\@ @\@7@h\@@k@̴\@03333@X\@Y@hfffΊ\@@hfff\@B@hfff\@`fff^@4333c\@`fff&]@)\@m@)\@@@ܢ\@0333@hfffV\@L1@i\@`fff&@̵\@@̴\@`fff@ \@@4333\@̌@hfff\@L@<`!R@gA`fff&@ &3=ITbm{P?ffffP?xP3333K?33337P̌?ffffNP??P@ffff&?xPH?3333 Px?YP?ffffJPT?DPx?3333P?ffffO??Ox?O?POb@ffffO@aO@\O>@lO 333@2333O 3333@2333ӱOK@O 333x@4O`fffx@2333KO@P`fff@3333P`fff@ P`ffff3@ffffP̛@P`@3333kPi@0 P @P 3333 @P @P @ffff&P @ffffP 3333M @X$P2@*P @3333,P0333s[@X4P@y2P`fff@9.P@*P@ffffF'P@3333$P@@ffff!PY@\P0333@Q P`fff@ P̌f@ffffPD@ffffP@`Pn@2333Or@̜O`fffu@2333Ŏ@ffff^OR@ffffnOL&@̜O@YO@O`@pO 3333 @̅O`fff} @{O`ffff @mO`ffff @ffffaO 3333b @ffff^O̅@ffff&[OY@)UO(@ NOL+@EOYV@|M@ffff?ffff@M?J 3333t@{J`fffw@̤sJ 3333@ioJ"@ffffFdJ@ffffYJ@2333SJ`fffg@JJ 3333;@̜GJ̕@GJ`ffff.@Y:J@ffff5J;@̼2J@ffff-Ji@ffff-J@)J 3333t @"J @ffff^J`ffff, @J`fff @JL @I, @I 333 @I @dfffI 33337@4333I`fff@4333I`fff@4333Ip@0I@4333{I`fff(@dfffI>@dffffI`ffff@dfffIY>@4333ILA@dfffީI`fff&@dfff&I_@4333ÉI_ @̴I 3333A @@I̞@iI7@4333hI@eI@T^I@VI̮@VIo@q[I@XTI 3333 @MI 3333@dfffII3333?hDI?̼:IF?4333&I3333?4333I@ffff?I?4333H̎?H?HN?dfffH?dfffH@ffff?4333 I?dfff I=?%Iffff?+Iffff?4333C;Id?pJI?dfff`I|?dfff~hIffff?tI2333?{I̬? Idfff6IеXI4333ƿ4333I!ٿdfffIM4333 IffffId4333[I`II@3333cI@3333OdfffIffffIdfffI@3333/̴I4333~ǏrIkI￘IkI@3333|uIdfffrI4333lI̞4333iIhI@3333dIVI@3333MpVI4333SXI04333QIJI@3333̜3IdfffV!Iffff4333IVIffffdfffH@3333O̔HHffffHdfff&H@3333dfffHdfffH@3333H>H(dfffH̫yHffffAdfffH@3333 HffffHffff dfff.H@33334333HГHffff4333~HFZHLHCHffffA;H9HSdfff,H̶9H@3333;H@3333Mdfff&=Hffff.L4H̪43339HT4333;'H@3333dfff(H̼4333"H̤4333Hffff~꿘qHffffr4333HHffff4333+HG̠4333G0濘aG3333;忘 G忘G4333G1dfffVGdfffVGp@GdfffGffff还iGGffff43333GG 俘aG33334333Gffffdfff>Gffffdfff&GxG4333crGdfffgG3333̌bG|RG3333SOG3333dfffBGffff43335G@3333{𿘙)Gffff ḠG̘GdfffG4333sFF@3333F̐IFffffJ4333F@33330F!FzF@3333%FffffdfffNFdfffƉFffffvLF@333374333uFljF@3333eF̘dfffN\FffffdfffcFH\F@3333\SF4333KFxEF$dfffDFldfff>JF@33334333OF7dfffNTFZF`FdfffYF@3333TFffffJF4333BF̼̅7F@3333Xdfff2F@3333(0F4333BFffff>̤BFGF1dKFffffdfff.NF@3333jQFdfffV\Fffff# ̌\Fffff 4333OFffff 8F@33330F@3333q'FH4333CF@3333dfffF4333 F F{4333kFdfffF̘4333F@3333 FzF@3333#iEdfffEffff4333CE@3333%AE@3333E@3333OdfffE@3333dffffEdfffwEffffjE<4333VEKEI4333EV4333Drdfff&DdffffDxDffffdfffnDU4333Dffff}dfffD4333pDdfff6dfffNDhfffFO6dfff~Dhfff6Dhfff69D`6pD6dffffDY6lE4333s6̬E6`JEhfff6dfff&jE,6zE433364333EL64333cE 64333E6`EL64333 E,6Ehfff6PEhffff6Ě6IE,64333E6ȘEhfffF6E64333KE643333E 7dfffFE 7 E7dfffE̬7 Ehfff 7LEhfff 7dfffEl7E`6dfffE64333F6F43337/FhfffF7QF4333370WF`7@VFhfff47OF:74333HFhfff&F7dfff>OFQ7dffffUFU7yFhfffa74333FY7dfffFhfff7dfff.F4333s7yF,7dfffnF4333s7xFhfff74333F7F7lFhfff7̼PG@84333oG<8G@~8G433384333cG4333843333GY8G8̜Ghfff& 9G9DG4333s9dfffG4333+9dfffH<94333Hj9H@g9H4333SO9#HlN9̄3HhfffE9:ȞO9̼6H@g9THhfff:VHhfffƜ:VH4333:dfffNH:KH;HH;dfffFH,2;9LȞC;dfff6IHl_;@RH4333ӎ;dfffMH@;dfffvOHY<SH 5<4333XHhffffO< fH4333Sq<4333[fHhfffF<Hٲ4333[OI>4333_Il?uIhfff&B?lIz?dfffI4333ӳ?)Iy?I4333S?J4333@2333J4333@ffffJ@?J?J4333?`Ihfff?4333SIhfff&?̬I?dfffI4333? IL?I̬?dfff֢Iz?PIV?)ILD?Il?I4333?4333s}I ?)zIY ?{Ihffff?lxIY>̔bI9>4333;XIhfffF>[I m>WIi>4333NI4333t>|JIYp>EI Q>!HI@>dfffRI<>HwI4333_>1I`^>4333+IB>4333Ihfff6>dfffI4333>4333IY>dfff&I>4333åI$>I>>!I@]>I4333si>I4333w>4333ӤIY>4333;Ihffff>Ihfff>dfffI̬>0I>ĺI̬>I@>YIy ?dfffI?4333Ihffff>?IV?yI@b?XIl}?2333sJY?ffffVJhfff?ffffJ4333?̄J4333?2333cJ4333S @ffffNJy@XJ4333C@ffff&#Jp)@2333+JI8@ffffAJ p@|SJ4333@ffffaJ@ffffuJ4333s@pJ@2333J`@ffffVJ@iJ@2333Jhfff@J@|6?J!g@2333sJ@ffffJ4333S@ɾJ@2333J@J4333@J@J4333#@LJP@@JL@ffffJ,@̬J@2333SJi@!J@0Jlz@2333ÐJffffVK@>0K>ffffFK̬>2333CK`>ffff&Khfff>\K4333S>K4333>dKhffff ?K4333?2333K4333?LhfffF?LhfffF?\L>ffffK4333S>̼L4333>̌ L>̌L> 4Ľr>`\L/>ffffjL4333s>wL>0Lhfff&>lL$>LC>2333sĽH>!LG>LB>L43330>,L4333#>ffff޳L̬>2333L=|LhfffF=L9=pLY=$xLhfffF=bLj=UĽI=2333cQL3= ILY#=;J@);23333J(;IJ;ffffJ4333s:J:2333J:lJhfff:ffffNJ:J4333sq:J4333Z:2333JhfffI:J9:2333Jl:`Jhfff9ffffJ43339J99ffff6J̥92333K43339 Khffff92333CK43339Khfff92333cK433392333 Khfff92333{*Khffff91K4333923338K91@K9DK43339NKy9ffff&NKhfffn968L 76ffff~L16YL 762333cL26LhfffF062333L4333.62333#Lhfff!6LLhffff6L43336Ll$6ffffL"62333[L433362333+L 6QL4333623333Ľ5dLhfff&52333Lhfff5L`5L5ffffFL5̌LhfffF5L5Lhfff5ffffLy~5Lk5ffffLhfffZ5PL`M5xL D5L45L43333"5DLy4Lhfff&44Lhfff42333CL4ALy4qL433334IL4LY42333#L423333L4QLhfffF4pL,4!M̌4IMhfff&w4@M4333sj42333{Mb4ffff MLU42333M K42333M<42333sMhfff&*4 M̬&4M@4̴M 4ffffLl 4̜L94,Lhfff3M,3M38 M43333`Ll3L:32333sL3ffffL4333 3LhfffF 32333CLhfff2̌L2&ffffF1Q2&ffff.2Q&3333K6Q8333&3333@Q%NQL%ffff]Q8333s%eQL%3333#kQ%3333uQhfff%ffffv}Q%ffff>Q%Qhffff&Qhfff &3333Qhfff&"&3333Q&3333ۜQ8333 & Q%-Qhfff&%Q@&3333Q%3333Q ,%3333Q$ݨQ8333\$ffffΨQ̌#3333èQ#Q8333#MQh#XQ8333=#3333Q@#}Q"Q"Qhffff"3333èQ" Q83333 #3333Q8333$#=Qhfff&@#Q̌V# Q #Q83333#`Q8333s#ffff:Q#̸Qhfff&#Q$Q$ffff& Rhfff$3333 Rhfff$ffffv R# RhfffഅR8333s#3333R`#3333Rhfff&B#3333[R#ffffBR83333#ffffR"&R8333s"4R"@R"3333gMRhfff"ER "ffff>R="ffffV>R!3333DR!GR̠!MRLp!3333[SRN!VRL"!ffffVR@!WRhffff 3333{YR [Rhfff =_R $cR $cR@ dR8333 gR@b gR8333sJ ffffFiRL% ̰kŘ 3333nRpffff3333qRpffftqR@3333nRpffffmRpfffP3333nRL!qR̜tR@333AyR|Rpfffq~RW!Rpffff9~R$X}R|RL3333}R@3333333}R|{RxffffyR~vRLf3333sRpffff]3333oRpffffW3333nR@333<3333KnR ffffpRpfffrRL3333sRQffffqRpfff̄pR3333slRUffff_R̷TRLaORA3333[KRffffHRHRHR`JRpfff 33337MR@33333333ORdfffffMRpfffflJR̻3333[DR(ffff>R>R[3333_=R:R5T9R:R8R@333}ffff>5R`,RD3333&R Rpfff̔Rpfff$3333oRpfffHR@333QpffffL\Q6QffffQ]Q QffffFQffff Q3333;QPQpffffQpffff.lQ3333+Qffff.Q@333̜Q@333ffffQQ@333ffffQLHQpfffffffNQpffff4ffffƋQL1ffff>Q%iQU@QO5~Qpffff4}Q3333|QpffffffffNzQffffbvQffffG 3333rQ@3333 3333nQ@3333"jQffffW3333fQQcQ1i`Qf^Q[Q@3333ffffZQffff󿙙YQffffTZQoffff\Q@3333w\Q p\Q@3333y\QffffB_Q33334333CdIffff*dfffeIdfffcI3333̼bI3333dfff&\I3333dfffYI[I޿4333XI4333S׿RIgfffvѿ;Ihfff&ĿdfffI̽xHhfffVͿ̌F4333S$7̌ FY+7Fhfff*79F07(FY67.F ,7dfff#F7dfffF7dfff6F97dfffF7̌F4333S$7dfffJHf:1MHi:8UHhfff&J:dfffEH+:?H8:4333CH,P:dfffHH43333a:dfffJHf:PF7dF7F,7شFY7ȹFhfffF74333F@7٢F7FY7dfff֝FL7 F`7PF7?Fffff4333LFM\HF@3333d4333{JFHFG@@Fffff=F`>FffffQ=F~?Fffffdfff6_C83331*9dC<*4333dC83333*WChfff&)̄UChfff)NC)dfffLChfff)4333LC83333)dfff6_C83331*sChffff* xČ+!}C +!C*dfffւChfff&*؀C*t}C*tCY*sChffff* qF4333;yF@33334333{F@4333F@3333pFpFD}FF4333qFn qFdfff~H)?@H̤?4333cH3333|?4333cHQI4333{I`fff?dfff$I@?4333s+I03333?,,Iffff6?dfff"I?aIffff?4333H}?dfff~H)?D&I3333?4333 3I3333I?a:I@ffff?dfff&AI<@>I`ffff@5I 333J@4333k.IL<@dfff+IL"@4333c%I@ffff?D&I3333?SI4333vI4333ԿdfffnIgfffпI̿܂Iȿ4333KIƿdfff^I4333kI8333aI줿`UI8333dfffFSISIѸHhfffƼ4333Hhffff¿@H dfffȞ,H?H ?qHl?4333CHL?HQ?HhffffѸHhfffƼ43336I2333?43338IffffOI٫?4333#NIffff6?4333[CI2333?9I?6Iffff2?X6I3333?2I̚?dfff/Iffff?,I?+Il?*I?43336I2333?4333I3333'?4333s!I? $I3333?dfff$I3333?dfff& I?pIZ? I?Ij?dfffI? I̺?4333I3333'?II>I=4333 I`񿘙I\ITI4333I3333S4333IUdfff^I@3333Y𿘙Ia𿘙I`IffffxI1>HY;FH;dffffEHhfff&;@H~;|;H4333o;43335HLf;`0H4333s;l4H;dfff?H;1>HY;833333@̬:hffff]=@1@B9@hfff&183333=9@43331Y99@L1hfff>9@43331LH9@̌ 2W9@2hffffb9@Y$2o9@hfff&<2@}9@Y29@q29@4333329@929@ 2y9@L2̌9@4333S2`9@3:@4333^3hfff+:@̉38333=:@3y:@hfff3:@̌3̬:@y3;@ 4-;@483338;@4333S%4A;@hffff;4LF;@a4G;@̌z4 x;@̌y4hfff;@{4hfff;@hfffƀ4;@ه4;@433334l;@43334L;@433334hfff&;@,4L;@4`;@4333s5hfff;@l5;@4333B5L;@[5;@5<@5̬ <@43335.<@583333<@5l<@hfff&5Y<@5<@ 5̌=@5̌ =@43335 =@5=@433335 =@43336L=@hfff& 6Y=@43336<=@Y68333P=@`(6hffff]=@hfff16@!=@668333s=@hfffFG6 <@hfff&e6<@{6 <@43336<@̬6a<@hfff65<@43336hfff&<@̬6`;@̬6l;@7;@7hfff;@hfff7;@ &7 ;@`27;@9878333Ӥ;@77;@̬@7,;@S7̬;@L^783333f;@43333b79P;@l7=;@4333s}7/;@7y%;@@7hfff;@43337̬:@`7y:@4333s7hfff:@hfff=8:@4333L8hfff&:@@e8hffff:@hffff8hfffs:@,8̬e:@43338!:@hfff8hfff&:@4333ӳ89@Y89@899@l89@%99@hffffM99@p98333s9@433339hfff9@̬98333q9@hfff9X9@l969@9̬9@`98@hfff9hfff8@@9hfff8@@9L8@y98333sf8@43339T8@,9hffff18@hfff98@hfff9833337@hfffF97@4333ә97@l983337@o97@,X9hfffc7@J9D7@@D98333&7@hfffI97@4333O9hfff7@R9hfff6@^96@9u9hfff6@Y96@٭96@y9hfff6@9:6@!:8333s6@̬-:̌x6@43338:833376@̌c:hfffF6@hfff:6@hfffƢ: 5@4333s:L5@hfff:5@hfffƵ:83335@̌:ٱ5@hfffF:8333s5@̬:Y5@:yt5@43333:,5@ :833334@43333:83334@ :hffff4@L:`4@̌:833334@:83334@4333:8333s4@q:hfff4@4333W:4@C:hfff4@9*:4@:4@:hfff4@9 4@hffff983334@433394@}9 y4@hfff89@n4@hfff%9`X4@hfff98333S4@83@83@83@hfff&83@?8hfff3@`783333@73@c73@@7l3@6Y3@6hfffF3@>6833333@ 6833344@ 6|4@ 64@ 683334@ 64@@583334@5̌4@hfffF`5hffff4@494@l483334@'4hfff4@̌34@ V34@43332l4@@2`4@Q2hfff;5@̌N25@D26@22hfffu6@283336@43333283337@4333s2hfff&87@1hffff@7@28333sL7@28333u7@hfff&;2hffff7@b27@4333s2hfff7@u2̬7@ s28333S7@l2@7@E27@̬:2̬8@4333s'2!8@28333s>8@2hfff[8@l1hfffi8@L18333y8@L28333Ӈ8@ 28@Y18@hfffF1L79@1@B9@hfff&1pfff&y/@̤GE@8333s3@fffffF@83333@AoF@hfff 3@oF@̬!3@ffff&sF@<3@ffffuF@ P3@rF@@Y3@pF@Y[3@mF@U3@cF@J3@0YF@ 93@ffffNF@&3@CF@hfff!3@=F@ 3@5F@8333S3@3333.F@ 3@ffffF*F@&3@&F@hfffF;3@#F@V3@F@ n3@ffffF@83333@h F@8333s3@F@l3@3333kF@̬3@YE@ s3@0E@`X3@E@hfff&N3@ffff&E@D3@E@>3@ffffE@A3@ffffE@83333]3@!E@|3@ffffE@~3@IE@z3@ffff.E@hfffs3@E@Lf3@ffffE@@\3@ffffE@M3@E@hfff&A3@E@13@3333CE@8333*3@E@3@̌E@3@DE@@3@)E@hffff2@3333kE@`2@iE@83332@̔E@L2@E@hffff 3@̼E@83333@ffffnE@̌2@E@hfffF2@3333sE@hfffF2@E@2@TE@̿2@3333KE@2@3333E@hfff&2@3333ӘE@hfffF2@3333E@833332@3333E@hfff2@3333E@ }2@ffffE@u2@3333E@q2@ffff{E@t2@3333 lE@Lw2@|cE@83332@3333KVE@2@ RE@83332@`OE@hfffz2@3333#JE@83333t2@AHE@8333o2@̤GE@X2@KE@8333M2@LE@2@dXE@hffff 2@^E@91@YgE@`1@3333+lE@L1@|sE@1@ffff.uE@hfff1@rE@̕1@xE@1@zE@hffff1@3333s}E@hfff1@؀E@83331@yE@f1@ffffvE@hfffK1@ffffE@yF1@3333E@F1@ffffE@?1@0E@hfff1@ffffE@0@3333E@hfff0@E@ 0@3333SE@,0@3333E@x0@TF@hfff`0@F@8333L0@F@60@F@y+0@ffff-F@Y!0@3333F@hfff&;0@hF@K0@!F@8333s]0@xF@t0@̼F@ه0@̼F@8333s0@33333F@,0@fffffF@ 1@F@51@F@9B1@ԕF@R1@F@x1@F@̬1@hF@ً1@F@L1@F@̬1@ffffFF@83331@F@1@3333F@1@QF@ 1@ffff&F@ #2@HF@72@3333F@8333H2@0F@̌[2@ffffnF@hfffl2@ffffF@}2@F@2@F@2@dF@hfff2@ffff}F@2@ffff>yF@83332@3333uF@ 2@ffffqF@2@ffffnF@83333@AoF@3333SiQhfffF6qLk#3333`Q̌1`Q@1`Qu13333gaQ4333c1dQ9U1ffffhQ`K13333SiQ?1gQ@31ffff6`Q43331 \Q13333ZQ@ 13333kXQY1ffffQQhffff0LQ03333{HQ̌0}CQ03333SAQhffff0tBQ0kgBQS~L0h@Q43330M/3333WQ8333/(WWQ#1/ffffRSQ.ffffFPQ8333s. KQhfff&y.KQe.ffff*UQ8333.3333WQ -3333WQhffff-WQ83333-ffffQQhfff}-ffff&PQW-OQ83331-LQhfff&%-iJQ-GQ,`CQ,3333@Qhfff&,I@Q8333,1>Qx,3333W8Qe,̼7QhfffV,9QL0,3333;Q,ffffZ>Q8333+yAQ+ffffDQ]+aCQ8333I+3333AQY0+>Qhfff&*9>Q*>Q)>Q)ffff;Qhfff)7Qhfff)3Q̌u)̔0Q_)33330Qhfff&7).Q)3333+Q)e4Q8333s(;Q83333"(BQY'ffffKQO'ffff~PQhffff'3333+WQ8333&]QhffffV&eQL%ffff]Q8333s%NQL%3333@Q%3333K6Q8333&ffff.2Q&ffffF1Q2&3333.Q8333>&ffffj+Q9&'Qhfff7&Q &xQ &QL%Q%3333' Q8333%ffffQh%xPLY%pPYS%HP@_%1P]%ffffPhfff2%ffffFP %3333P$3333KP@$3333P8333s$0P8333s$3333#P8333$P8333s#ffffҤP#ffffP8333#̌P#ffffސP8333#ffff.{Phfff&#3̔0Qhfff)36Qhfff3;Q4333s3=Q2>Q2>Q 23333AQ2BQ4333ӌ2CQn2ffff.EQL[2EQLH2ffffHQ4333323333OIQ$2ffffGQL2EQ23333FQ 2RQ1ffffTQ4333s1VQ̌1ffff_Q13333`Q̌1Ԗ>Qa=0BQ70HQl80̸GQ-0FQhfff!0̐FQ,0DQ43330@Q`0Qa=08H/V@:@hfffVW@O<@dqV@̌;@hfffV@;@@V@P;@4333V@ffff;@V@2333Î;@hfffV@\~;@hfffV@Iq;@4333{V@Ip;@V@2333Su;@iV@ @s;@W@\];@hfffVW@fffffJ;@hfffW@6;@)W@%;@V@2333;@V@L;@W@2333s ;@\W@`fff:@4333W@23333:@hfff.W@ffff:@V@:@hffffV@`:@4333V@,:@V@\:@<@4333;V@l7<@V@ +<@\V@<@QV@<@4333V@<@̌V@2333#<@4333SV@<@hfffέV@\<@hfffV@<@V@̜;@TV@ffffV;@V@ffffv;@V@<@tV@<<@yV@<@4333V@2333c<@hfffV@<@4333V@ffffV;@V@2333;@V@Y;@HV@ffff;@qV@̌;@m?@@`fff(@ffff?@ffff?@ffffr?0333-@?@ffff:?S@?p@=?`fff@?@t?@P? @~?@@?@@? z@ffff?L@ffff?y @ffff? @̴?Y!@3333?!@ffff?"@?`fffFF"@?"@,?,"@? "@?0333"#@?#@ffff|?`fff#@H?0333s#@?`2$@gfff?{$@Y?$@?$@m?$@43333?`fffk%@L?0333S%@gfff?%@?̌%@gfff?0333S%@?9&@?0333s(&@8?"&@3333?&@ffffZ?'&@N?`ffff;&@? P&@3333+?`fffFY&@T?k&@3333U?&@?`fff&@3333?`fff&@|?`fffF&@?,&@ffff?&@C?`fff&@3333e?&@?&@?@&@?0333&@? &@̸?&@?9&@@ B'@@3333L@a'@@ '@@L'@@3333M@`fff'@@y`(@@q(@@3333@̌(@@0333(@0@0333(@ffffs@`fff&(@@ (@@3333q@`fff(@@3333@0333S(@ffff@`fffF(@ffff2 @0333s<(@# @'@d @0333'@@3333 @'@@3333 @03333'@A @,'@ffff @d'@ffffn @`fffC'@ @&@ @0333s&@ffff @̌Z&@@ @`fff&O&@ @=&@@3333 @(&@ @%@ @l%@@%@@3333@N%@@7%@@3333E@,$@,@0333$@ffff@L$@@3333q @`fff$@@3333, @`ffff$@@3333 @̌$@ @$@̜ @`ffff$@* @R$@ @0333S$@@3333u @̌#@ffff @,#@= @`#@ @`fff&#@ @0333#@̢ @`fffU#@ @!#@@3333Q @`fffF"@ @9"@@3333/ @`fff&"@@3333@`ffff`"@\@*"@@3333/@l"@2@"@@`fff!@@`:!@@@ @@` @@3333@`fffƋ @ffff@ @}@0333~@ffff@0333sN@ffff@0333s@@3333@ w@@`fff*@H@L@E@ @ffff @`fff@@̌@@3333@`fff@ @̌E@ffff@L@ffff@@@Li@@`fff&@ffff2@@@`fff@@b@@0333@̦@z@K@0333O@3333?`fff @ffff?@$33333OV/@xUy{2@A/7UJV1@dJVdfff1@HVdfff1@ffff:CV1@T@3333I@C@fffffI@ffffH@ffffI@ffffd@ffffI@@1I@ffff@I@@333@3333 I@fff<@I@@3333K@3333I@Lf@YI@L@̴I@L>@ffff>I@@I@L@|I@ @33333I@ffff)@I@ffffo@fffffI@ffff@I@/@I@O@I@fffE@I@@~I@@ffffzI@@yI@L@PwI@@ffffnI@̎@3333kI@@3333@)gI@@3333@3333+cI@L@(cI@@9aI@0@̔`I@dFT@zS`I@@ffff`I@@]I@Lz@VI@@3333@QI@@`LI@@ffffEI@@BI@fff@3333?I@.@$>I@]@33339I@fff_@3333;3I@@3333u@x(I@L@I@@3333|@ffffI@Lw@|I@@333p@I@@3333[@I@8@I@@333@fffffI@@333w@ I@E@I@'@ H@fff@ffffH@fff@H@@H@@3333@3333H@ffff@ffffvH@fff&@3333#H@7@H@@H@m@qH@@333Y@ffffH@C@3333H@@333(@ffffH@@H@@333p@̜H@ffff+@iH@@dH@@H@j@ffffVH@@33335@3333SH@@ffffH@@3333@9H@@YH@>@ffffH@@H@fff@ffffH@ffffx@H@e@ffffnH@@333]@ffffH@)@3333H@@3333q@dI@LF@3333I@ffff@I@@l I@L@I@fff@PI@.@H@y@H@L@H@fff@\H@L@3333H@@I@fff@ffffI@L@3333I@@ I@@I@@hI@@ffffI@@333@3333cI@̲@̌I@@3333-@!)I@@+I@ffff@ffffV+I@O@i,I@ @+I@@3333 @,)I@̃ @,'I@V @3333)I@ @:I@ffff @=I@ @ffff?I@ @@I@/ @ DI@ @3333KI@@3333 @3333TI@t @]I@@3333= @_I@@cI@.@)bI@@3333`@]I@@3333@ffff[I@̷@3333@@3333@`I@ffffZ@gI@@3333@ffffpI@ffff@̴tI@@ffffFzI@@3333@~I@I@ffffVI@3@ffffnI@ffff@I@@3333 @I@ @XI@ffff @3333CI@9 @ffffI@u @tI@ @I@# @ffffI@ffff @I@fffft @II@ @ffffI@ffffA@ٝI@ffff@ffff6I@ffff7@̔I@)@I@@333@ffffNI@@3333I@@xI@ 8333,7@I@Z@@L@Al?@ J@?@ffff J@8333X?@| J@7?@ffffnJ@ +?@ffffJ@L?@ J@ >@J@>@ffffI@Y>@̔I@8333Ӫ>@4I@8333>@I@y>@0I@8333s>@TI@̌>@I@83333>@QI@>@3333I@>@ffff~I@8333>@I@hffff>@I@8333s>@I@YU>@3333I@O>@ffff&I@833338>@I@hfff&)>@3333+I@8333S>@3333I@hfff=@I@=@3333CI@=@I@9x=@DI@8333X=@I@L=@ffff޴I@;=@ffffI@,=@QI@"=@3333I@ =@3333SI@̌=@ffffI@Y=@I@L<@0I@8333s<@I@y<@$I@8333<@3333SI@83333<@yI@8333<@,I@8333ӥ<@pI@Y<@tI@83333<@ffffI@8333l<@$I@hfffJ<@yI@ /<@ffffI@$<@3333I@̌<@3333SI@<@ffffI@;@3333I@,;@I@8333;@3333I@hfffƽ;@ĽI@83333;@ffff.I@@;@ffffI@8333;@DI@8333;@I@s;@̔I@Y;@ I@K;@xI@hfff&E;@I@Y$;@3333CI@;@3333cI@:@3333I@:@ffffI@ :@̤I@8333t:@ffffI@8333d:@ffffI@`D:@qI@9@ffffI@hfff&9@@I@̌9@ffff^I@hffffD9@I@83339@3333I@L8@I@8@ffffI@hffff8@3333I@8@3333I@hfff~8@I@hfff\8@3333 I@R8@QI@8333G8@)I@y 8@3333I@8333s7@I@7@3333I@@7@ffffI@̬7@̌I@83337@ffffI@̌7@ffff~I@̛7@$I@ 7@@I@83337@3333KI@hfff&7@8I@y7@I@8333Ӕ7@ffffI@,7@I@7@̜I@̬7@3333I@hfff7@3333+J@ 7@J@83337@1 J@L7@J@Yu7@3333J@S7@ffffJ@l27@3333 J@8333,7@$J@hffff.7@3333K'J@@47@@+J@hfffM7@6J@83333i7@3333BJ@hfffz7@FJ@@7@UJ@7@ZJ@Y7@bJ@83337@hJ@7@3333sJ@7@ffffJ@83337@YJ@ 7@ffffJ@8333S7@3333J@8333|7@3333KJ@ 7@̼J@8333ӻ7@J@`7@J@hfff7@0J@,8@@J@8@ffffJ@08@J@8333<8@J@hffffQ8@LJ@z8@ffffFJ@hfff8@3333kJ@hfff8@J@ 8@ffffJ@`8@3333;K@8@̔K@ 9@K@hfff9@K@8333-9@lK@H9@) K@^9@( K@ v9@y%K@8333s9@!K@9@K@8333S9@ffffnK@hfff9@ffffnK@83339@K@99@3333K@̿9@K@hfff9@3333K@9@PK@hfff9@K@hfff;@3333K@l;@3333K@;@̄K@8333s;@ L@83333<@L@,<@L@%<@3333KL@hfffH<@(L@P<@L@`d<@ L@83333h<@d L@`<@ffff L@ <@L@ٰ<@ffffVL@hfff<@IK@8333s<@ffffK@̌<@DL@ =@L@`=@̴L@8333sH=@3333K@`=@(K@hffffe=@3333K@e=@ffffK@hfff_=@K@yZ=@fffffK@i=@K@8333s{=@K@L=@ffff&K@@=@ffffK@=@̜K@=@ffffK@8333=@K@=@1K@ >@K@;>@0K@t>@ffffK@8333y>@hK@83333>@3333K@hfff&>@HK@̌>@ffffK@>@K@>@K@ >@3333K@>@ffffVK@hfff&>@ffffK@hfff>@ffff>K@̌>@ffff޲K@>@!K@,>@ffffFK@>@3333KK@>@̬K@>@K@y>@̜K@L>@@ffffvK@hfff>@ixK@8333s>@ffffuK@8333>@33333nK@>@3333+gK@>@AdK@8333>@3333YK@ ?@SK@8333&?@3333 PK@hfff'?@33333NK@?@0BK@hfff&?@3333>K@L/?@33339K@>?@!2K@8333L?@ffffV%K@8333Sg?@K@?@3333;K@?@(K@8333s?@ffffK@y?@K@hfffF?@ffffJ@8333s?@pJ@8333?@̼J@ ?@ffff^J@?@J@hfff@@J@9@@J@9@@J@l6@@3333J@8@@$J@<@@3333J@hfffW@@\J@lZ@@J@Z@@3333J@hfff&Z@@ J@|R@@J@I@@J@4333<@@J@6@@J@hfff @@ffffnJ@,@@3333J@@@3333sJ@hfff?@J@hfff?@̒J@Y?@3333J@8333?@J@ ?@3333J@j?@J@lc?@J@8333S]?@ɑJ@̌M?@3333ˇJ@@B?@3333#J@̌K?@~J@`Z?@3333{wJ@Yq?@PnJ@?@,fJ@?@ffff.aJ@@?@]J@?@pYJ@8333?@ffffQJ@̬?@EJ@hfff?@(DJ@?@6J@̓?@'J@?@t$J@`?@!J@̰?@ffff>J@83333?@3333J@l?@ J@`ffffM*@̼Mhfff*@ $M)*@M*@@M`fffF4*@ffffFM0333L*@ffffM03333*@Mhfff*@2333sM`fffd*@̼M9N*@$M)*@ $V@Y4@l(W@P:@DJTgoy4333KCV@6@4333CV@̬/6@43333CV@LF6@,>V@̂6@:V@̡6@4333S;V@ Ы6@;V@P3336@̔9V@6@|7V@Y6@p6V@` 7@hffff;V@dfff/7@i9V@57@3V@:7@\.V@pfffFA7@hfff-V@dfffJ7@i/V@dfffo7@hfff,V@pfff6~7@(V@̌7@4333s'V@ 7@$&V@)7@P$V@dfff7@'V@̌7@,V@dfff8@hfff-V@43338@.V@̬/8@4333.V@;8@hfffN.V@`F8@4333)V@4333sS8@V@̼X8@hV@dfffc8@V@0t8@`V@z8@hffffV@u8@P V@\|8@V@dfffƌ8@V@8@V@8@4333V@8@hfff V@dfff&8@hfff V@̬8@4333V@dfff8@hfffV@8@hfffV@dfff&8@43333V@<09@$V@09@\+V@43333.9@/V@@+9@hfffN4V@-9@8V@P33319@;V@dfff99@:@4333>V@9@:@>V@@I:@V@Pffffk:@1AV@`fffi:@hfffFDV@|`:@hfffFV@N:@hfffFV@fff3:@hfffKV@ :@4333RV@ :@WV@:@]V@9@1cV@Y:@eV@:@dV@!:@|eV@/:@hfffgV@ffff67:@jV@̼6:@hfffnmV@`fff+:@4333tV@9@,sV@ 9@4333tV@dffff9@hfffrV@Pfff6`9@AsV@ V9@tV@,N9@TuV@4333J9@qwV@ K9@hfff>V@4333#B9@V@P89@dfffV@Y/9@hfffV@`(9@V@dfff*9@V@dfff_7@,V@7@V@dfff7@V@7@V@dfff7@yV@dffff!7@V@27@V@67@4333V@,37@4333+V@)$7@V@7@lV@dfff6@hfffV@6@yV@<7@V@@333 7@hfffV@)7@V@dfff57@DV@̌I7@V@l\7@4333V@dfffx7@hfffV@433337@|V@dfff&7@hfff~V@̜7@V@fff&7@W@@3337@!W@43337@ W@̸7@ W@7@W@7@̄W@4333~7@4333cW@dfffR7@\W@ >7@hfffW@7@$W@43336@)W@43336@̌W@4333c6@W@43336@4333sW@dfffv6@̜ W@43336@ "W@ i6@4333#W@L 6@0333$W@0333c5@L%W@5@d%W@5@4333%W@4333w5@(W@Y5@l(W@4333cN5@4333c&W@)E5@4333c$W@iC5@"W@Q5@43333W@\5@W@dfffh5@(W@dfffp5@hfffW@dfffvm5@4333S W@̜[5@hfff~ W@ K5@I W@dfff35@hfff W@5@W@̼5@hfff.W@433335@QW@|4@hfffW@L4@hfffW@dfff4@4333W@Y4@W@433334@t W@4@hfffW@,5@4333W@)5@4333W@L5@qV@5@hffffV@I(6@V@:6@hfffV@I@ffff:@9I@0:@hfff&VŠ9@x]S<8@3333bSy9@ffffcS9@aS43339@\S9@US@9@3333QSdfffF9@9QS9 9@ffff>VŠ9@ffffRdfff66@9R6@3333ORY6@̀R6@3333R06@fffffR43336@Rdfff6@ffffR6@,R43336@9R6@ffffRdfff66@|Rl8@ffffR7@ffffBR 7@̸Rdfff8@5Rl 8@ԜR 8@|Rl8@3333;R66@̸Rdfff/6@RL<6@RR6@YRf6@̤Rm6@Rs6@3333{RLz6@ffffzRdfff6@zRi6@|~R43336@ffffn~R6@}R,6@evRdfff&6@(xRdfffF6@uRdfff։6@`~Rdfffv\6@ffffRdffffN6@3333;R66@ffff)Sdfff|9@Sdfff_9@SU9@I S09@ffffS#9@3333[S@9@ffffS8@- S8@ S@8@! S̜8@pS8@8S8@ffffzS4333S8@ffff Š8@ S̬8@3333 Sdfff9@D Š9@ffff2S89@ffffSdfffP9@ffffSpW9@'Sn9@ffffV,SdfffVq9@ffff1SdfffFm9@ffff/Sdfff{9@ffff.Sdfff69@ffff~-S̜9@ffff)Sdfff|9@RR4333#j6@ffff~Rdfff^6@ GR^6@\JRdfffva6@3333'HRt6@BRdfffm6@:Rdfff5@(CRdfff&u5@3333DR5@ffff?RdfffƏ5@:Rdfff5@^hfffVbF@ 3C@hfff.I@3333 D@)hF@AC@hfffFdF@3333C@hfffVbF@ C@oF@ C@ F@C@ɉF@C@4333F@!C@hfffF@3333 C@F@̔C@hfffF@ C@4333SF@8C@hfffF@dC@ɬF@3333C@yF@3333KC@,F@`C@F@33333C@F@ffffC@iF@ffffC@4333F@3333{C@`F@hC@hfffF@qC@9F@3333ӬC@hffffF@ffffC@F@8C@hfffF@̖C@G@ffff>C@ G@9zC@hfffG@3333[pC@F@ffff6tC@F@̄|C@hffffF@̀C@4333ӱF@ffffFC@4333F@БC@4333àF@3333C@hffffF@C@4333F@̌C@yF@C@,F@3333sC@hfffF@ffff6C@IkF@ffffC@hF@AC@43333oH@ffff7C@kH@7C@YQH@ 3C@KH@ffff4C@l5H@ KC@0H@̄MC@'H@ffffNC@4333s!H@ffff6RC@4333H@8XC@43333H@\C@H@ffffhC@̌G@HmC@G@0qC@yH@fffftC@iH@ffffwC@̼H@̴zC@H@ffffN}C@hfff6#H@ffff.C@4333c%H@iC@@%H@ffffC@hfff#H@C@H@C@ H@ffffC@\ H@ܞC@4333sH@3333C@iH@3333C@ H@pC@<)H@C@$H@3333cC@hfffVH@C@yG@3333C@hfff6G@C@G@C@yG@̌C@4333G@ɿC@4333SG@AC@G@̤C@`G@ffff^C@4333~G@C@ mG@C@@dG@0C@4333GG@3333sC@>G@fffftC@L>G@̬C@4333>G@3333C@G@̤C@=G@C@,)G@C@G@C@4333# G@ C@PG@C@PF@fffffC@|F@xC@4333F@C@hfffF@dC@hfff6F@ C@\F@C@IF@\D@F@D@hfffF@qD@hffffF@ffff.D@hfff6F@ffffND@43333F@fffff D@F@`D@yF@D@,F@ *D@hfffF@3333[5D@)F@$DD@hfff&F@̬QD@F@8VD@`F@3333ZD@)F@fD@4333F@4jD@43333F@hlD@4333F@rD@ܸF@XyD@hfffF@3333+~D@9F@D@F@̀D@4333F@D@hfffF@̬D@4333F@HD@ F@D@YF@,D@4333#F@ffffޒD@F@3333kD@يF@D@F@3333sD@,F@ffff>D@̛F@3333+D@hfffF@3333D@ F@pD@F@8D@ F@ffffD@F@|D@yF@D@4333F@ffffD@G@iD@4333 G@D@G@3333SD@hfff#G@ēD@̼0G@ffffD@)7G@܉D@̜:G@D@hffffDG@ffffVD@,PG@pD@TG@lD@hfffVG@ffffD@9OG@D@ AG@D@hfffF1G@ܺD@'G@D@ G@3333D@ G@iD@4333cG@3333D@PG@3333D@hfffG@D@hfffG@QD@< G@9D@&G@D@4333,G@$D@hfff3G@3333sD@hfff7G@3333 D@4333DG@iD@̬FG@D@ IG@iD@NG@ID@\XG@iD@_G@3333D@̬iG@(D@hfff&wG@D@p~G@D@LG@33333D@0G@D@@G@ffffD@hfffFG@QD@lG@TD@G@ffff&D@4333G@QD@G@3333D@@G@D@9G@3333;D@YG@D@,H@ffffD@hfff6H@ D@)&H@3333D@2H@3333 D@ 7H@D@4333cBH@D@4333SIH@D@4333UH@D@hfffviH@ffffD@4333H@ffffޯD@hfffH@ffffD@hfffVH@D@\H@܎D@H@3333[D@hfffvH@afD@0H@[D@4333H@ffffMD@4333SH@JD@hfffH@ID@H@ID@@I@3333kDD@\I@̜@D@I@3333;D@hfffF'I@33334D@hfff.I@ffff#D@4333SI@`)D@̜H@(D@`H@$D@4333H@D@̌H@D@H@3333+ D@4333#H@C@hfffH@ffffC@H@(C@hfffH@ffffC@pH@ffffC@H@C@yH@C@4333H@LC@)H@C@|H@C@H@C@@H@؊C@H@ffff&C@{H@C@̌vH@3333{C@`mH@ffff^kC@lH@\hC@43333oH@ffff7C@hfffF@|D@4333CF@ffffD@ |F@|D@̼zF@̼D@{F@$D@hfffFF@D@4333F@3333D@̬F@D@hfffF@|D@4333F@3333ND@F@SD@`F@ffffTD@4333F@UD@IF@RD@IF@MD@hfffF@ffffLD@4333F@3333ND@#@)3G@%1@$H@#@G@7#@ffff&G@@333s@#@ȻG@#@lG@@333^#@G@pfffo#@G@v#@qG@K6c#@G@pfff&n#@G@@333s#@3333G@pfff#@G@@333s#@ffffG@@333s$@ffffG@pfff$@3333{G@&$@ٶG@@333!$@YG@pffff1$@ffffG@LQ$@G@̌f$@̄G@_$@G@@333]$@G@@3333{$@ffff^G@pfff&$@ffffG@$@3333ۮG@$@`G@Y$@AG@$@G@@3333$@YG@@Q%@3333 G@@333{%@ffffG@%@ffffG@%@G@@333%@8G@%@ffffG@@3333%@ffffG@&@QG@pfffE&@ffffVG@pfffa&@lG@l&@G@̌&@3333cG@̌&@G@@3333&@3333[G@&@G@%'@ffff^G@o'@G@ _(@LG@Yh(@G@d(@3333G@pfff&k(@G@pffff(@3333G@@333(@ffffG@(@3333CG@@(@3333G@ )@lG@@0)@G@pfff&_)@̬G@@333)@G@pfff)@3333G@@333)@3333G@̐)@ffff6G@pffff)@fffffG@)@3333G@pfff)@3333G@Y*@1G@pfff&*@ffffG@̌*@!G@@333*@3333G@@3333*@pG@)@ffffG@@3333)@ffff>G@)@fffffG@ )@ffffvG@̌)@dG@@3333)@G@pfff&)@ffffG@pfff&)@ H@L)@ H@pfff)@ffffH@)@3333H@ **@ffff6#H@pfffG*@%H@@3333n*@̤&H@L*@fffff*H@̿*@A.H@*@3333s2H@@333s*@3333CHH@*@1IH@pfff&*@yJH@@333Y+@3333BH@pffffb+@1DH@pfffr+@lEH@+@1KH@+@3333OH@L+@WH@+@ffff_H@pfff&+@3333+bH@@333+@3333CaH@@+@0]H@@+@XH@pfff&,@ffffMH@@3333a,@ffffJH@@3333,@IH@@333,@NH@@3333,@PH@-@NH@@333a-@3333LH@i-@VH@pffff-@_H@̤-@3333cH@Y-@̼bH@ -@3333iH@-@}H@pfff-@$H@@3333".@H@̌G.@3333|H@R.@ yH@@3333f.@\yH@pffff.@`{H@@3333.@̬|H@L.@3333zH@pfff2/@tqH@f/@3333#nH@@333/@ffffnH@/@ffffnH@hfff0@̜`H@hfff&80@̤^H@hfff^0@ffff^H@83333j0@3333bH@Yz0@ifH@hfff&0@3333eH@ٙ0@dH@8333s0@3333]H@83330@3333k\H@L0@ffffn[H@90@3333ZH@hfff0@yOH@0@ffffLH@hfff0@ffffVKH@0@̄FH@̌0@3333s@H@0@8H@̌0@ffff1H@0@3333[H@`1@ H@1@H@%1@3333H@1@XG@hfff1@PG@9 1@̼G@83331@ffff&G@ 1@3333G@̬ 1@3333G@ 1@G@833330@G@0@@G@83330@G@833330@ffffG@`0@G@0@G@hfffF0@G@ 0@G@hffff0@3333G@9x0@G@k0@TG@n0@G@hfffƣ0@G@833330@̜G@0@G@0@IG@ 0@3333[G@hfffƃ0@ȳG@`q0@3333#G@83333o0@G@lv0@ffffG@8333p0@YG@j0@G@9p0@̬G@{0@G@ ~0@3333G@|0@ffffG@z0@hG@8333v0@G@8333t0@ffffހG@hfffl0@̜G@8333T0@HG@hfff@0@h|G@83330@nG@hfff 0@3333#lG@pfff&/@3333fG@/@YZG@/@ffff>YG@L/@̼VG@pfff/@3333 [G@@/@ZG@pfffC/@fffffYG@@3333/@3333SG@pfff.@PG@o.@LRG@Y.@ PG@-@ffff~NG@Y-@ffffMG@pffff-@LJG@-@̴EG@@333s-@3333?G@@\-@Q;G@pfff1-@7G@'-@33334G@-@)3G@-@a5G@̌,@3333C5G@,@ffff6G@و,@i8G@@3332,@ ;G@ ,@=G@̌+@?G@pfff+@pAG@pfff|+@AG@pfffff+@BG@pfff*@GG@*@iGG@pffffV*@LIG@@333s)@PG@Lf)@RG@2)@SG@Y(@VG@(@YG@(@AaG@@3333(@ffffjG@pfffN(@ffffwG@@333B(@ ~G@T(@3333G@ g(@3333ˇG@@333d(@G@V(@3333G@pffff'@G@pfff&'@8~G@f'@ ~G@@@'@G@'@3333G@&@}G@pfff&}&@3333|G@̌D&@wG@ &@mG@ &@3333fG@̌%@tcG@%@ffff~bG@pffff%@3333;cG@%@3333eG@pfff`%@ffffVlG@(%@ffffFmG@@333s$@tmG@$@ffffnG@$@ sG@@333s$@q{G@pfff$@ ~G@ \$@anG@YD$@fffflG@pffff#@3333SqG@pffff#@ffffxG@@333#@|G@̰#@G@@333s}#@G@pffff=#@3333[G@)#@XG@1#@̴G@8#@ffffG@3#@G@$#@ffff6G@̌#@ffffG@pfff&#@3333+G@#@G@#@G@#@G@8 :\@hfff_K4333c@$* &-5=ERZairya@8333'a@&(Ya@V(4333+a@8333s(4333a@hffff(a@8333(!a@(Da@hffff(a@hfffG)̸a@hfffx)a@hfff&)hfffba@hffff0*a@̌*a@hfff&*̌a@hffff{+4333a@+hfffa@hffff+a@@T,4a@,Pa@Y,4333a@,4333cb@,4333b@,4333K b@ ,4333#b@8333v,b@,̼b@hfff&,Mb@@Y-"b@-hfff%b@-4)b@hfff-(b@ . (b@hfff1.hfff(b@hffffh.`)b@̌.̰(b@ .4333/+b@83333g/4333,b@/.b@4333s0u.b@hfff<04333-b@4333N0hfff-b@g0/b@90̘1b@hfff0l4b@04333'8b@hfff&0:b@ 00=b@0hfff c@9>hfff c@Y>!c@9>̰ c@,?hfffnc@4333s5?4c@4333So?%c@L?c@@4333sc@@c@4333C*@ c@433338@ c@\G@4333c@M@4333c@V@hfff^c@V@hfffNc@hfffY@c@`\@Ac@4333`@b@i@4333b@hfffVs@4333cb@@hfffrb@hfff֙@hfffb@hfff@4333{b@y@b@ܲ@4333b@4333@pb@@Xb@\@Tb@4333@hfff:b@@b@̜@b@hfff@tb@hffff@4333_b@@hfffb@̬Ahfffb@4333Ahb@Ab@A4333b@hfff&Ab@|1Ab@4333?ALb@hfff_Ahfffb@43333rAb@hfff6A4333b@hfffAb@̜A1b@APb@\Ahfffb@ЉA̔b@4333SAb@9Ahfffb@ܓA4333b@AMb@̼A(b@lAb@hfffAYb@hfffVA@b@4333Ahfffb@A.a@0Ay/a@hfffF A/a@A4a@hfff@8a@@=a@ @4333?=a@ @hfff;a@43333@hfffF;a@4333@=a@4333#@4333?a@@8=a@hfffb@hfff;a@A\`@hfffEAhfff`@LA̬`@ MAhffff`@`JAhfff`@43330A`@hfffA)`@hfff6A`@@4333`@@X`@̌@p`@,@`@@P`@hfff@hfff`@@hfffr`@hfffV@`@ @`@4333S}@hfff6`@4333_@`@]@D`@4333]@`@PT@hfff~`@hfff6F@Ľ`@43334@,`@i"@hfffJ`@hfff@̤`@i@Ѭ`@ @ɦ`@hfff@<`@?`@hfff?4333[`@@hfffކ`@@w`@@?̔l`@l?hfffi`@`?̘d`@hfff~?``@hfff&?4333W^`@ِ?hfffY`@?4333'D`@@?42`@4333?&`@4333?4333G`@?y`@@?hfff*`@4333@d_@\@x_@!@a_@&@_@'@̼_@ @4333z_@4333&@Qd_@@@̬]_@e]@4333Ahfff6I]@PA4333c7]@hffffA!]@4333s~A ]@4333nAhfff&\@4333eA4333{\@hfffVCA)\@6A\@hfff&Ax\@|'A0\@+A\@ A\\@4333AL\@̌Aq\@@4333\@hfff@T\@hfffF@\@\@hfff\@@4333\@4333@\@hfff@hfff\@@\@hfffF@hfff\@`U@\@\L@hfffN\@4333H@l\@hfffV3@<\@L?4333\@̱?\@4333sM?hfff\@9>Q\@>\@y>hfff\@Y7>\@4333 >4333K\@=4333+\@,=`\@o=hfffֶ\@$=8\@,<̥\@̌<\@̌:V\@4333S5:U\@hfffF :V\@:X\@hfff:4333[[\@43332:4333b\@o:9e\@:n\@Y:q\@43333:u\@hfff&:̔v\@hfffU:hfffq\@hfffA:hfff6m\@@9:4333e\@@:4333`\@9LY\@9hfffnY\@̬94333\\@`9hfffb\@ 9g\@L94333m\@̬9l\@4333:k\@9 :Dl\@y:Qn\@9!:4333q\@hfff(:s\@hfff:hfffv\@4333:Px\@4333:P|\@9B:|\@LR:ȅ\@hfffd:4333C\@hffffV:hfff΍\@J:4333\@Y :\@9hfff\@9\@y9hfffr\@l*9hfffj\@ 8hfffnd\@hffff89`\@984333Z\@hfffo8hfffnZ\@hfffA8hfffZ\@!8Y_\@74333cc\@74333sp\@ k7hfffq\@4333SH74333p\@43333.7r\@ 74333r\@ 6$q\@64333k\@hfffF6r\@hfffU6hfffV}\@l5hfffv\@hfff5hfff\@ 5 \@hfff5\@l.6|\@hfffR6\@̬{6!\@4333t6l\@hfffl6,\@lW6\@4333B6̔\@433335d\@54333\@hffff5Y\@l51\@}5hfff&\@̬[5`\@hfff>50\@54333]@hfff5hfff&]@44333;-]@`4hfff5]@hfff44333?]@Y4hfffH]@43334̼R]@̌4Z]@4k]@̌4Du]@43334hfff]@hfffFk4]@ `4T]@S4]@ C4]@3hfff]@hfff&4]@ 44333#]@Y3 ^@43333^@̌388^@@3hfff?^@3K^@Yz3̜U^@hfffQ3hfff_^@@3e^@hfffF2\h^@ 24n^@433324333;r^@433332\u^@ z2hffff^@hfffd2hfffƐ^@(24333^@hfff2^@4333s 2^@433311^@43331hfff>^@hffff1p^@̌1)^@̬m1A^@LP14333^@"14333K^@433331hfff^@l0q^@`0D^@l04333^@hfff0i^@̵0hfffF^@l0̬^@n0 ^@4333o04333^@ 0^@43330^@l 1hfff^@4333J1̤^@4333h1̜^@Y|1 ^@Y14333^@hfffx1^@Yj1^@L81hfff^@,1^@hfff1^@ 1^@43331hfff>^@̌14333#^@̌ 10^@1hfff^@433330hfff^@,0hfff^@`0^@hfff&0hfff^@ 0̌^@@04333^@hfff0hfff&^@l04333c^@}04333^@4333w04^@̌x0^@4333j0`^@4333W0^@Y90p^@ .0hfff^@hfffF10^@a04333^@4333]0hfff^@4333sI0_@4333C0hfffN_@`G0 _@hffffU09_@hffffc0_@a04333!_@,e0P,_@b0h1_@4333g04333s0_@4333_0*_@V0$_@4333T0hfff_@4333U0_@hfffL0_@30hfff_@,"0_@433304333 _@hfff04333$_@0q%_@hfff&04333&_@/)_@̌/hfff~)_@hffff/4333&_@83333/hfffF _@hfff/4333#_@/l_@83333/a_@8333s@/!_@8333.\ _@hffff.#_@.<)_@8333s.8,_@hfff&.+_@@.4333S,_@.0_@ .hfff6>_@. A_@.D_@8333s.D_@.4333D_@ .A_@L.0:_@.hfff~8_@@.!9_@hfff&{.43335_@LR.:_@L8.4333>_@6.hfff~A_@$.A_@ .qB_@.4333D_@̌.4333L_@@.YS_@83336.4333V_@Y=. X_@8333s,.X_@.O_@-4333SO_@̿-4333K_@̌-pK_@8333m-hfffQ_@L-hfff6R_@ +-xU_@hfff-hfff[_@-<`_@hfff&-4333e_@hffff,4333Kf_@hfff&,hfff6f_@hffff,,h_@hffff,m_@83333,k_@hfff,̔k_@,Xj_@-1l_@ -hfffVm_@-4333Co_@,4333st_@83333,4333u_@Y-hv_@1-y_@hffff<-̌|_@8333s -4333S_@83333,_@,hfffނ_@hfff,hfffn_@8333n,t_@hffff^, _@hffff:,4333_@̌!,4333s_@Y+hfff_@Y+4333ˋ_@ ,4333_@ :,4333_@S, _@E,̬_@,̙_@8333 ,_@hffff(,hfffv_@hffffR,hfffv_@-,hfff_@ +_@+4333_@8333+hfffι_@}+4333c_@8333+Y_@+_@+I_@,_@8333s0,_@hfffc,_@L,hfff_@hffff,hfff`@Yl-a`@hfff-`@-4333`@hfff&-4333`@ -.8`@.4333`@.`@s.t`@|.hfff&`@٘.I`@}.E`@Ym.̈`@Y4.`@.`@- `@8333-hfffv `@hfff-4333 `@- `@hffff-4333G`@8333s-l`@̌-hfffV`@ُ-!`@-H%`@hfff-4333%`@hfff:.&`@ R.̜'`@ ).y'`@hfff-(`@83333-43333,`@-.`@-%2`@@.hfff2`@hfff4.P4`@̌G.43334`@8333s,.hfff4`@ .43333`@ -4333c4`@8333-hfffn8`@hfff-(;`@hffff-hfff9`@8333s-8`@@-433375`@q-Y3`@LK-4333[6`@̌&-U6`@hffff-t3`@̌-|/`@,hfff,`@8333,.`@Lm,3`@hfff,43336`@+6`@+`8`@8333+A9`@p+hfff9`@L+:`@Y%+4333>`@+4333SB`@*YD`@̌*`F`@hfff*PH`@*QD`@J*hfffD`@L*aE`@83333),J`@ )L`@83333`)̈N`@83333Q)LR`@hfff&T)hfffS`@83333K)S`@̌(S`@8333(U`@Y(hfffW`@(X`@([`@)hfff\`@ )@\`@(hfff[`@(̜^`@L(``@̌(hfff``@̊(``@m(hfffva`@a( g`@[(hfff~h`@8333<(Ti`@"(hfff j`@1(hfffj`@̌k(hfffn`@̍(=w`@hffff(hfffj|`@v(~`@( `@(Յ`@83333t(hfff`@@_(`@8333sz(4333'`@(!`@LZ(hfffV`@ E(hfff`@8333s8(̤`@B(4333ϖ`@83333?(,`@(T`@'(`@8333'`@Lt'4333`@LL'4`@hfff&`@8333s&hfffF`@Y'T`@ &hfff:~`@8333s&Qz`@ٚ&hfffy`@8333&~`@\&`@̌d&hfffb`@8333&`@L&T`@hfff&&43333`@@z&h`@8333sh&`@8333sr&Ց`@ٻ&ٕ`@'`@&m`@@&`@̌&̠`@&̨`@Y>'`@Li'e`@t'hfff.`@L'`@hfff'`@hffff'4333`@'hfffv`@Y'hfff`@8333(<`@83333 (4333[`@(8`@hfff&(hfff^`@' `@(Y`@4(4333`@83333c(`@q(hfffF`@hfff&B(4333`@ (`@̌'4333;`@hffff'T`@8333'̄`@̦'hfff`@'`@'hfff`@hffff'hfffv`@L'̼`@ (4333{`@M(hfff`@8333sk(hfff`@{(hfffN`@t(p`@hffff[(hfff`@hfffM(Ea@b(a@hffff(hfffa@L(hfff*a@(4333Wa@(4333 a@8333s(4333W a@̌d(4333a@X(̤a@hffffC(0a@hfff&'Ia@L'4333a@hffffD(a@8333s(a@83333p(a@8333|(Qa@hfff&(4333/a@̌)a@hffff)hfffVa@)a@8333*a@Ls*hfff. a@hfffx*hfff a@LZ*i a@hfffF*4333oa@8333sT*Pa@8333\*̬`@̛*`@@>+hfff`@̞+4333`@hfff+D`@hffffN,`@hfffw,4333`@,hfff>`@+-$`@83333P-4333`@83333-hfff`@-`@hfff-`@83333.̤`@R.hfff`@Y.hfffa@̌.La@̌.4333S a@hfff#/a@O/̬a@i/a@c/̜a@hfffY/hfffa@Y/hfffa@^/4333ga@/a@8333/4333Wa@/a@/hfffa@hfff/ a@8333/"a@8333/h%a@/)a@00a@hfff*0̄6a@hfff;0hfff6=a@z0hfffJBa@433304333Ga@hfff0hfff.Pa@ 0Ta@ 0@Za@4333S0P`a@90ca@1da@1hfffda@4333*14333ga@ T1na@la1va@l1|a@1E~a@4333S1%a@1a@4333S14333[a@1a@4333314333a@j1hfffNa@L11a@14333a@l04333Sa@hfffv0aa@80hfff.a@0̔a@83333/4333sa@hfff5/4333a@ d.a@.Pa@-a@8333,4333a@,a@@N,hfff"a@̌ ,aa@+4333a@Y+a@̌+4333ײa@hfff*4333a@hfff*hfffa@ )a@)a@8333)hfffa@8333s)4333sa@)a@z)hfffa@\)4333a@:)Da@L()la@")a@ )a@(a@(ȹa@)(4333ۻa@'43337a@ (a@(a@'4333sa@'La@8333sC'hfffra@hfff&4333ca@hfff%hfffra@8333%a@%4333a@hfff&j%4333oa@hfff&j%\a@%a@̌%a@8333%4333#a@Y&4333a@ ;&̴a@̌m&4333a@hfff&&4333Ka@L&8a@C'a@̌'4333a@8333'a@̌' a@hfff&'a@8333'hfffz"c@433339!c@@98 c@9@c@hfff&9c@r9hfff!c@4333Z9!c@`M98!c@4333s19hfff&c@ 9H'c@y9hfff'c@,8hfff%c@hfff&8$c@8hfff%c@8$'c@4333S88(c@84333)c@8̈)c@L84333+c@L84+c@hfff&9hfff$c@hfffF9hfff"c@9hfffz"c@433339@pa@433304333ma@904333la@ 0hfffVka@4333S0hfffia@,0hfffga@04333ea@0da@04ea@90Qga@ 0`ia@w04333na@@p0ra@,e0Xsa@9g0Tva@4333Ӄ0qa@̌0@pa@43330hfffa@+Aa@ٰ+hfffa@Y+ a@+a@+a@+hfffa@hffff+a@ +a@̌+8a@@+a@83333%,4333a@;,4333/a@P,Ua@e,hfffa@hfff[,la@Y^,a@8333},hfffa@ ,la@,hfffa@,̼a@x, a@83333u, a@8333sl,̌ a@Y, a@@,( a@8333,4333 a@̺+a@hffff+hfffa@83333q+4333a@ Z+hfffva@]+Ea@s+hfffa@+hfffN`@['hfffVQ`@h'hfffR`@hffffy'IS`@hfff'hffffS`@'P`@٫'(J`@hfff&'43333D`@hfff&'4333sB`@hfff'hfffbA`@'hfffNB`@̌\'4333sD`@hfffd'hfffRF`@Q'E`@'D`@& H`@&pI`@8333s&4333J`@̌&hfffL`@&4333WL`@ 'M`@83333/'hfffN`@['S`@̌&hfffX`@&5]`@Y&̘_`@&̼``@83333&d`@8333&4333f`@83333|&h`@83333a&Aj`@hffff~&4333m`@Y&%o`@&hfffp`@&\@,9)F\@hfff94333kH\@43339pH\@43339hfff~I\@L9hfffK\@ :hfff3a@̌A:a@̌A=a@A}Aa@A4333Ca@A Ba@hfffFAa@a@,A̼:a@4333Ax5a@A3a@4333A43332a@yBY.a@4333 B4333;,a@̬B̴&a@Ahfff$a@B a@B4a@B)a@<B4333a@ALa@Aa@4333Apa@A"a@A̰*a@hfffA0a@4333sA2a@4333cAU4a@hfffA$3a@4333sAhfff3a@̌A/b@l-C4333*b@43335C(b@2C%)b@hfff+C4333s)b@4333(Chfff-b@hfff6(C/b@l-C*b@4333>C,+b@4333DC\+b@LGC4333(b@hfffBC$b@CC&b@4333:Chfff6)b@pChffffb@J44333b@4333sM4̘b@@M44333 b@H4db@L'4$b@4333844333sb@ G4hffffb@J4b@`&44333;b@'4ab@$4b@4Нb@hfff4b@Y 4b@y"4b@`&4̰b@hfff}7b@hfff&7b@Y74333b@7hfffRb@L74333b@ 74333wb@hffff7hfff^b@hfff&7b@7b@7b@74333b@hfffu7̰b@hfff}7̈b@4333R6b@ S6b@hfffN6hfffb@4333D6b@433356b@4333s:6b@4333N6̈b@4333R6̴b@l16̘b@hfff&964333ӻb@&64333b@433361b@y 6b@9&6̴b@l16=1c@o;|.c@43333;hfff-c@ٴ;hfff,c@@;,c@4333s;4333-c@hfffg;43330c@hfff&l;=1c@o;(.c@hfffP;x-c@T; ,c@@<;hfff+c@̌#;(,c@hfff ;-c@hfff;.c@ ;̤-c@43333;(.c@hfffP;4333a@h% a@hfff&%da@v%a@@V%1a@H%Ua@/%4333a@h%a@hffffb$a@hfff&$4333a@hfffx$hfff>a@ f$a@L$4333a@hfffG$a@hffffb$\a@hfffN$4333a@\$ a@Y>$4333a@$$a@hfff+$\a@hfffN$Hb@43333;2Ib@yS2Jb@lf24333wJb@r2Ib@|2hfffGb@hffffs24333Fb@hfff\2Cb@J2)Cb@4333s@2Eb@4333SA24333cGb@=2Gb@433392Hb@43333;24333'a@&a@8333&a@hfff&a@@&a@Yl&a@8333Z&̼a@Q&hfffFa@hfff5&hfffja@ &a@hffff&a@hfffc&4333'a@&hfff a@hffff4'a@Z'hfffa@hfff&''`a@hffff&hfffVa@̌&hfffa@'$ a@*'hfff a@hffff4'4333"a@hffff/̠!a@/4333a@83333/a@8333s/hfff*a@hffffl/a@T/4333a@ N/hfffN a@̌0/"a@hffffS/hfffF"a@hfffy/4333"a@hffff/4333a@hffff=/a@83333A/4333a@̌/4333a@L/|a@-/4333a@hffff=/a@hfffA/4333a@C/ta@83333A/hfffa@̌*/̸a@/a@@/a@/a@hfffA/na@4333S1hfff~ma@4333!1ma@433331na@4333 1oa@̌0qa@ 1Dra@,1na@4333S1̘a@hfff&+hfffa@+a@+a@hfff+La@+4333a@83333y+a@YT+<a@i+a@ +̘a@hfff&+`@ &4333[`@&̏`@S&`@hffff;&4333{`@&5`@̌&`@ %`@%`@6&!`@V&`@ &L_@8333(-H_@̌H-hfffE_@8333.-4333G_@hfff,Gb@yEFb@yEEb@EDb@hfff֧E5?b@yE;b@lE9b@D b@0DIb@hfff?D8b@7Dنb@:DHb@9D̤b@̼3DUb@hfff0Db@̬-D4333Wb@-Dpb@I'D̔b@ADhfffb@KDb@EDb@BDhfff.b@hffff@Db@hfff@D̔b@AD4333c@ZK c@hfff_Kc@ZKc@hfff@K4333c@hfffvD@hfffVbF@ C@]F@̌C@̼GF@̜C@hfff&3F@tC@hfff%F@3333+D@F@3333D@F@ffffD@4333E@ffffD@hfffVE@ffffD@hfffFE@,D@hfffvE@(D@E@PD@E@D@E@̤-D@4333E@X2D@E@ffff8D@E@ffff=D@|E@3333{ID@@E@RD@E@\D@hfff&E@ffffeD@E@vD@̼E@ffff{D@D@F@3333sD@يF@D@F@3333kD@4333#F@ffffޒD@YF@,D@ F@D@4333F@HD@hfffF@̬D@4333F@D@F@̀D@9F@D@hfffF@3333+~D@ܸF@XyD@4333F@rD@43333F@hlD@4333F@4jD@)F@fD@`F@3333ZD@F@8VD@hfff&F@̬QD@)F@$DD@hfffF@3333[5D@,F@ *D@yF@D@F@`D@43333F@fffff D@hfff6F@ffffND@hffffF@ffff.D@hfffF@qD@F@D@IF@\D@\F@C@hfff6F@ C@hfffF@dC@4333F@C@|F@xC@PF@fffffC@PG@C@4333# G@ C@G@C@,)G@C@=G@C@y>G@̤C@43333=G@мC@hfffV0G@C@̼.G@YC@.G@̄C@p0G@ffffC@7G@̜C@@G@ffff6C@JG@C@hffffFG@șC@4333=G@ffff^C@5G@3333C@<3G@C@4333c3G@ffffvC@G@3333C@L>G@̬C@>G@fffftC@̬(G@tC@hfffG@C@hfffF@̖C@F@8C@hffffF@ffffC@9F@3333ӬC@hfffF@qC@`F@hC@4333F@3333{C@iF@ffffC@F@ffffC@F@33333C@,F@`C@yF@3333KC@ɬF@3333C@hfffF@dC@4333SF@8C@hfffF@ C@F@̔C@hfffF@3333 C@4333F@!C@ɉF@C@ F@C@oF@ C@hfffVbF@ C@4333F@3333ND@hfffF@ffffLD@IF@MD@IF@RD@4333F@UD@`F@ffffTD@F@SD@4333F@3333ND@hfffF@|D@̬F@D@4333F@3333D@hfffFF@D@{F@$D@̼zF@̼D@ |F@|D@4333CF@ffffD@hfffF@|D@ dRK2333J4333s5L43330>L:>PLhfffK>9Llb>dLhfff~>ffffLL>ffffLhfffF>L>2333L>2333sL>2333Lhfff>ffff^L4333?(L?YL2?2333cLhfffL?ffffFMhfffj?M4333~?<M̈?ffffvL?2333L?MY?2333kM?D M4333?pMhffff?1M?M̌?2333M@M<@M@2333SM@M43333)@M`<@(M0H@2333Mz@2333M@ Mhfff@'M̜@ 0M43333@T6MhfffF@8:M@2333 FM@CM4333c@q:M@6Mhfff@2333[4MhfffA<2M4333Affff7M4333S AO4333DffffO4333sDO43333DffffPDffffP4333vDffff'P`mD33336P)hDx4PeD3333{3Phfff`D7P0^Dffff:P̜]DqDP4333gDHPpDIPhfff6yD3333IPhfffD3333/HPD3333+APD3333s@P`DCPhfff&D ?P Ey9PhfffE,P4333CEffff'Pi!Effffj"Phfff E Phfff"Ě!PL&Effff$P-E3333$P@5EPhfff7E3333P5EtP43332E3333P<-EffffP"E0P EPETPhffffEIO4333EO4333E`O4333EffffOhfff&EO0$EffffFO 4EffffOGEOYEffff~O4333s_E2333O4333gE9PpE\P4333CnE3333Phfff`EffffP4333REP@IE8PAE)PhfffDE33333P QE >PIUE̸AP4333#aED(PYtEffffBPyEXPyElPhfff|E3333 Phfff&EP4333Effff-PYE5P,E3333?P4333E$LP4333Effff&PP43333Effff&RP4333ESPEDOP<F̼SP@FffffPP#F̌RP,.F3333WP=FffffriPTFlPeFXfP4333pFfPhfffxFhPFffff~pPF3333+P|{FAPLF3333P F$P43333FqPiFffffzP4333#F@PF|P4333F3333'PhfffFFP,F3333_PGPYGffffP"GffffPhfff6,GiP̬8GffffP4333FGPGP̅GPGffffvPG8qPܠGQ4333cI,0QlHD&Qhfff6I"QIQQ4333 IQhfff6IQI%Q4333I/Q#I Rhfff}H3333c7R4333xH3333.RrHffff)RkHffffR'R|eH3333%Rhffff]H%RTH&RyBHM%RBQ5BffffQ43334BQ43334BQ@2B3333Q+B4Q@$B̧Q BffffQ̼B3333;QBQhfffBՙQ9A3333Q4333sATQAܚQA3333Q4333A3333;QٹA̴Q A3333QAQiAQA3333QAܝQɘA)Q̒AQuAQpmAffffZQ4333#cAffffQ]ALQVA|QhffffJAffff Qhfff?Affff~QL7AQ,ATQ&Affff.Q\#A̐|Q̌"AffffNxQ AffffvQhfffA3333vQA3333#wQ4333 AffffjxQ4333@Q4333>HQ>ffffnQ>=Q`>iQ43333>TQ4333p>3333ۊQ4333b>ffffΉQhffff\>3333Qhffffc>4}Q4333[>ffffzQH>xQ6>vQ,>AwQ>3333{Q>p}Q >ffff|Q43333>${Q=ffff^{Qhfff=3333~Q=3333Q4333R=Q@=3333yQ&=tQl=ffff&tQhfff =oQ̬<oQ 8P4333s8Phfff8ffffzP̌7lPhfffF7ffffPL7ffffP>7PY7xPY6\P6P6%P`6ffffnPhfff68Ph6ffffP4333W6ffff P4333D6̌P`76P433346ffffrP̌(63333_P 63333P 6ffffP̌5؏P53333P4333s5-P@53333OPhfff5Phfff&5 wP 6XqP6ffffkP964aP433336_P 63333CPL63333?P433365P$60P+6ffff,P/6&P4333:63333!P _63333P@|63333Pٕ63333P43336P6̴P6 P4333s6a Phfff}6pPhfff]6O43336O4333S6ffff6O6Ohffff6ffffFO6O 6qO623333Ohfff&62333kOL5jOhfff5ThO4333 6ffffN_O(6(UO762333SSO4333;6ffffPO4333B6 POYJ6QEOY6ffff/Olp6iOhfffƜ6ffffO43336N,7ffff6N.7ND7ffffNhfffQ72333NhfffF\7̴NYd7̴N u7̬N7؊N 7ffff6N4333s7kN̬7@N̬7!N43338ffffNY8M:i@M̌;2333FM;ffff.OM4333!;$RM433332;2333kMMyP;MF;ffffL Q;L43333n;PLYx;2333|Ľo;̔oLp;gL4333|;̜[Lhffff~;2333;MLhfffw;YALhfff|;7Lhfffƍ;l/L4333;'L4333Sp;Lhfff];LLR;ffffLhfffN;K`S;Khfff\;ffffKj;yK43333j;2333Kl[;KI;2333sKhfff&5;ffffNKhffff&;̔Khfff;ffffK;̜K`;2333CK :K:fffffK`:K4333:`K43333:ffffK:({Khffff:̜wKٳ:qK4333:iK:ffff`Kl:VK O:2333PKy:NKy9DK433391@K923338K91K433392333{*Khffff92333 Khfff92333cK43339Khfff92333CK43339 Khffff92333K43339ffff6J̥9J99ffffJ43339`Jhfff92333Jl:J9:2333JhfffI:J4333Z:J4333sq:ffffNJ:lJhfff:2333J:J:ffffJ4333s:IJ;23333J(;J@);2333#Khffff>;K4333SF;ffffK@;DKhfff&J;L!Ka;2333)Kll;\9KLr;ffff=K4333u;GK@t;ffffNKhfff&z;2333;UK̆; \K;xcK4333S; jK4333;pKhffff;ffffsKhfff;tKhffff;2333[zKhfffF;Ǩ;ԈK;,K;ffffKhfff;23333K;YK;tK̬ <2333K<2333K,L4333#>L43330>ffff)Q4333CmKp)Q\PKffff(Qy)K(QhfffK3333(QJ̤(QJffff(QhfffJm(QyJP(QSJffff$Q4333XJffffQhfff6sJffffQ4333}Jffff^QyJPQ4333JQ4333JQJT!QJP!QhffffJDQhffffJ(QJP Q9J8 Qhfff֨J3333Q43333J-P43333JP4333JfffffPJffff*P4333JP`KffffrP4333Kffff^P|KffffP4333#(KP4333s8KPIDKffffPLKoP4333SKffffWPPK PP̬QKtKPVKffff&PPdK$VP`pK3333'^P4333uK̜fPvKAnP4333vK3333uPytKffff }P̬uKPhfffvzKffffPhfff|KffffZPhfff&}KP43333KffffPK,P4333ǨP4333cvKffff"PsKP0oKtQlKffffQhfffhKffff:Q|hKlQ kK'QjKffff)Q4333CmK%#P̬[KP4333^KPi\KP`\KPl]K3333Phfff_K2333O\K`O\KOLbKQO4333gKP4333seKffffP4333eKffffPkKffff P4333kKffff(PhfffsK.PhfffvnKx0PiK,P)cK(PhfffcK4%PY`K%#P̬[KNCNCNC2333SO\C OC O C2333N\CN\CNČNdfffF0@N̶1@ Ny 1@2333NdfffF0@ Ni1@ffffN)1@̌N 1@̜N@+1@N4333s#1@ffffNdfff1@N433331@ffffN1@Ndfff 1@Ny 1@N01@Ndfffv1@N̜1@23333Ny1@ffffNL1@N̶1@2333Ndffff1@lN4333ð1@2333NL1@N01@ @333s|'@ 28333 8@@3333R*@%*@Y*@@333)@̨)@LY)@@1)@pfffpfff%)@pffff)@%pfff&(@@3333I (@\̌(@pffffs@333s )@@333 )@̲pfff)@(@pfff(@@3333@333(@pffffpffffm(@pfffpfffe(@O(@pfff@3333\(@'i(@@333Z(@L8(@pfff@333s(@$pffff (@pffff@333'(@̌U(@Yh(@Lpfff(@pfff(@(@pfff(@z)@Y̌H)@pfffYp)@@333)@pfff@)@@3333)@Y)@5*@z@%*@l7@Y%7@8333s&83338@^&̌8@& 8@̌&8333 8@̌&8@&8@ '7@hfff,'83337@̌E'7@83333s'833337@8333'Y7@'y7@L<(7@̌(hfff7@hfff&(7@hffff)7@8333E)83337@̌|)hfff7@)83337@8333)hfff7@)7@)7@*hfffƢ7@*8333V7@* 7@*̌6@*8333x6@*hfff56@*5@*5@LP*hfff5@*hfff5@8333+83335@@=,5@̌,5@م-hfff5@hfff&*.5@8333s.83335@r/83335@@/L 6@hfffFC08333&6@0hfff16@̠0N6@hfff0u6@̬0hfffƋ6@hfff08333Ӹ6@hfffF183336@hfff&I1.7@4333sy18333sa7@1y7@hfff16@1S6@hffff15@15@1j5@,2hffff^5@18333I5@hfff1 5@̬1hfff4@̌2پ4@ 2hfff4@hfff&183334@1d4@,114@1l3@1̬3@`1̌`3@4333S103@183333@4333S1̌2@433318333s2@,18333ӷ2@hfff183332@18333|2@Yq1u2@4333l1m2@g1ye2@@f12@`e11@̌d1hfffƭ1@d1K1@Yd1hfff0@43333d183330@ d1&0@hfffc1/@c1@3333.@c1L.@yc1pffff<-@4333Sc1Y,@@c1pfffs,@4333e1@333,@̬h1̌+@yg1@+@hfffc1@333+@Y\1+@4333I1c+@hfff;1+@hfff&$1@333*@@ 1@333*@1pfff&*@4333S0pfff[*@03*@0pfff&)@43331@333)@hfff1)@43331pfff&P)@)1pfff)@4333s61@333(@433341 (@61@m(@51̌:(@ *1pfff&(@hfff&+1'@:1@333s|'@?1pffff'@ 0L'@@0̣'@0 '@ /@333'@hfff/@333s'@8333/ '@hffff/'@̌p/̌'@D/@(@/%(@.(@hffffF-(@,pfff)@̂+)@hfff&*)@83333*pffff)@hfff&)LS*@hfffM)*@8333s )pfff&2+@(_+@hffff?(+@hfff&'̌+@&pfff+@&̪+@%Yz+@hfff%Yq+@hffffD%YD+@L%@3333+@hffff$pfff*@hfff$*@8333s#@3333*@L#@3333k*@ h#d*@8333#@333O*@"pfff&*@8333u"@)@"@)@hffff!@333*@83333!/*@hfff!̌'*@Y!*@L!̌*@"̷*@_!@333*@?!@333s*@ !*@@ *@L .*@pfff)@pffff)@@333pfff )@\pfff(@pfffipfff&(@̿ (@Lpfff(@^(@LVpffff)@/̔)@*@pffffpfff"*@upffff^*@l@333*@pffff*@t@3333*@rLL+@pffffr@333s+@@333k+@m@:,@pfffu@333a,@,@P-@@3333@333-@@3333-.@.@@333y@3333t/@thffff0@@333u8333P0@pffffv8333sn0@̙0@̕0@pfffhfff0@40@Lu0@@33330@@33338333s0@Lb0@833330@Lyhfff&0@`0@pffff@0@?0@̠0@8333S1@s 1@8333'1@pffff>1@L~Li1@91@& `1@83332 83331@8333s. `1@̌$ 1@hfff" @2@7 8333 2@3 hfff12@83333 U2@hfff& 8333|2@ 2@pffffhfffF2@2@hfff2@ hfff$3@ @W3@8333^3@hfff&_3@̞Yk3@@333:z3@hfff|3@{3@@333383333@pfff 3@& 3@Y3@pfffhfff04@8333s{4@̩ 4@hfffF4@8333s4@@333|,4@@333383334@L4@pffff833334@@3333 05@#hfffƂ5@/hfffF5@85@@3333BY5@P8333s5@hffff5@h83335@@3333vhfff5@L9 Y5@hfff hfff5@c!833335@!Y5@@V",5@"L5@@0#5@s#83336@#26@$hfffFF6@hfff$lM6@$H6@$H6@hffff%N6@8333a%G6@hffff%46@8333%̌-6@%y76@&hfff96@8333s>&8333A6@S&`G6@hffffc&P6@8333e&d6@hfffQ&8333s|6@hffff,&6@&6@&83336@)&hfff7@-& (7@L&&8333sf7@8333%hfffv7@L%Y7@ %hfffF7@hfff&y7@&83337@hffff%hfffF7@ %7@8333s%l7@Y%3333?̜7E@?DRE@L?l@E@3333?3333?E@b?\:E@?8E@?̜7E@ffff.?ffff7E@? ;E@ffff??E@ffff?CE@3333?1FE@ffff?ffffFLE@W?3333OE@?DRE@3333?HQE@[?ffff^ME@?IE@?3333CGE@ffffl?HCE@L?l@E@ ]!43332@̌'@3333ӋB@}@3333'!@ffffwB@2!@3333#qB@3!@ffffjB@@333s!@dB@@333s @`aB@@ @ffffPB@pfff&v @3333EB@Lj @lBB@pfffj @`?B@ @Q:B@ @ffff5B@̌ @/B@ @)B@ @ffffB@} @ffffnA@~ @A@ِ @A@٢ @A@@333s @ffffA@ @A@@ @YA@ @A@̟ @ԊA@ @`}A@pffff @3333jA@} @ffff]A@@333b @RA@@3333? @ffff.HA@Y @AA@@3333@ffff;A@ffffZ@̄4A@@3333 A@7@A@@3333@ffffN A@@ffff@@@3333@ffff@@@3333#@@@@9@@@3333@`@@fff@ffff^@@ @ffff֝@@L@@@@333& @fffff@@9 @@@l @ffffv@@ @ Y@@@333 @̔E@@!@ffff6@@pfff]!@̼'@@pfff&!@ffff&@@@333 "@| @@̌"@3333C @@pffff4"@̜?@ R"@?@@333r"@_?@pffff"@ffff ?@"@9>@pfff"@2333>@"@2333#w>@ #@:>@̌"@ffff->@ٞ"@>@@3333"@`=@pfff#@2333=@G#@=@pffffX#@ffff&=@pfff}#@2333s^=@L#@L-=@@3333#@2333c=@pffff#@̌<@#@i<@pffff#@ffff <@#@2333#;@̌#@;@~#@2333T;@L#@ffff&8;@@#@ffffv ;@#@2333s:@@333#@2333:@@3333#@|:@#@L:@@333^#@0p:@"@pU:@@3333"@>:@@"@ffff%:@"@0:@)#@9@pfff#@П9@Y$@4333U9@ $@0B9@pffff$@ 9@@3333=$@L8@@333o$@8@$@L8@̦$@̼8@@333$@P|8@$@z8@L_%@dfff&8@pffff7&@o8@pfff'@yP8@pfff'@4333sJ8@?'@4333#8@@333'@7@'@7@̌'@43337@pffff&@l67@L%@4333C6@pfff&$@6@#@dfffK6@pfff"@5@̸!@dfff5@pfff @a5@M@Y5@L@43334@@333 @ɱ4@@4333sx4@@3333@?4@@333@̬4@@333 @̜3@̅@4333c3@@333X@z3@L@)o3@Lo@ \3@ffff@4333J3@ffff@P:3@ffff@@ 333s*>@`ffff?S>@2333#w>@ 3333i>@z2333Ӛ>@2333#>@J>@Y@>@>@@ffff`>@333 >@U >@@fff <?@ ffff?@La 2333?@@ffff "?@+l)?@~ffff*?@̪23332?@3333fffffA?@@ffffO?@3333P\?@_ffffo?@@ffff)?@@fff?@?@33332333s?@3333%ffff?@ 9?@3333 Я?@333 \?@#2333?@@fff?@@ffffffff?@@ffffrq@@@@L @@@fffA @@/ffff@@L3333@@@@@@ffffi @@)ffff @@$ @@gd @@ffff󿙙 @@ffff@@1̴"@@ffffffff6+@@3@@ffff 񿙙;@@񿙙F@@3333M@@|V@@ffffZ@@33333td@@)ffffVp@@3333k@@ffffx@@ɨ@@3333@@ffff?@@m3333@@ffffo@@3333@@OA@3333/A@t7A@;A@?A@ffffNGA@3333̼MA@Q3333SA@̬\A@̺ffff>`A@3333jA@@fff D|A@333ЃA@ffffVA@@ffff$3333A@̜A@3333pA@ffff3333˦A@_A@3333ItA@3333gA@\ffffA@EۿffffFA@2333sֿ|A@dfff6ȿA@0333A@̌?DA@i?B@4333?B@gfffz?3333!B@gfffN?3333-B@?33338B@?BB@?ffffHB@@3333@ffffNB@@3333@3333LB@@3333^B@ffff@idB@* @ffffeB@ffff;@ffffrB@L@3333rB@fff@3333cnB@L@ffffngB@L@VB@.@RB@̲@tVB@fff@YfB@LB@nB@@3333xB@@333O@B@@3333@B@@333M@3333cB@̵@uB@fff@xB@@3333@{B@@3333@3333ӋB@̺@ffffB@Ln@B@*@̬pB@L@̜mB@A @fffftB@@3333'!@ffffwB@R3@ffffC@83335@RE@vhfffW3@ffff>D@8333sX3@̜D@8333s\3@ffffD@hfff&Z3@3333E@hfff\3@E@+%PW3@< E@d3@ffffF E@hfffw3@ffff E@hfff{3@ E@hffffs3@ E@hfffFd3@ E@8333]3@3333%E@[3@8'N$E@Lf3@3333+E@8333w3@3333+5E@hffff3@>E@83333@`HE@̌3@tPE@83333@RE@8333S3@8QE@3@ME@3@8CE@hfff&3@3333?E@3@3333E@hffff3@3333@E@8333 4@3333cFE@`4@ FE@4@(CE@̌/4@33336E@8333=4@3333c+E@hfff&Y4@ffff'E@hfffh4@1#E@hfffF|4@E@م4@3333E@L4@̬E@ٔ4@ffffnD@83334@D@4@aD@8333S4@ffffnD@@4@3333CD@hfff&4@D@y4@D@r4@D@ ~4@D@̬|4@D@,}4@D@`4@\D@L4@D@83334@D@83334@vD@hfff4@sD@hfff4@ffff~uD@4@sD@hffff4@ffffoD@4@lD@̬4@D@ ,>N@ffffVd=@4333 R@3333k:C@lP@3333B@P@ffffB@hP@3333۪B@4333P@3333B@hfffvP@3333ӚB@DP@ffffB@4333P@!B@P@)B@P@3333{B@P@ffffB@0P@3333B@4333P@3333 B@hfffP@B@hP@8B@PP@3333k|B@hfffVQ@3333yB@4333 Q@B@4333Q@̬B@9Q@ffffB@4333+Q@QB@4333Q@B@"Q@3333{B@(Q@3333B@4333*Q@3333B@I.Q@ffffNB@ 2Q@ffffB@4Q@ffffB@5Q@3333æB@hfff6Q@ffffB@8Q@ffffB@4333[:Q@ffffB@x=Q@3333B@43333CQ@B@KQ@3333CB@4333PQ@B@4333sSQ@B@̤VQ@4B@hfffZQ@B@[Q@3333;B@̌YQ@B@4333ZQ@LB@hfff~_Q@3333B@ hQ@ B@tQ@ffffB@43333|Q@ffffB@ Q@xB@܂Q@3333 B@4333Q@B@4333Q@ffffB@Q@3333B@QQ@B@4333ÌQ@iB@̼Q@3333SB@HQ@yB@ Q@ffffB@̼Q@ C@0Q@3333C@iQ@ffff*C@Q@ffff6C@@Q@3333k:C@hfffVQ@|5C@`Q@3333K'C@4333KQ@3333C@Q@3333C@4333Q@ffffB@yQ@pB@Q@B@8Q@HB@4333SQ@qB@4333CQ@ffff~B@$Q@B@Q@B@4333SQ@,B@4333Q@зB@4333Q@3333ˢB@̴Q@3333SB@43333Q@ffffB@Q@,lB@B@4333MR@IB@XR@3333+B@hfff^R@`B@4333fR@B@|hR@ffffB@hfffjR@B@hfffnR@B@hfffnR@B@mR@3333+B@hfffiR@ffffFB@)hR@3333{B@4333iR@3333B@oR@3333B@|R@ffff>B@R@yB@R@3333+B@hfffR@̬B@hfffR@,B@hfffVR@B@yR@3333B@̌R@B@43333R@ffff~B@R@3333B@hfff&R@B@hfffR@B@4333 R@ffffB@hfffƵR@ffffΜB@R@B@4333KR@B@R@ffff6B@ЪR@3333#B@hfffƣR@IB@їR@0B@4333R@̔B@hfffޟR@3333SB@R@B@hfffR@ffffւB@hfffR@}B@hfffvR@rB@|R@iB@hfffR@3333[iB@zR@,mB@9qR@qB@hfffnR@3333qB@PZR@3333pB@yGR@,oB@?R@mB@ 1R@jB@'R@0jB@"R@fB@R@ffffbB@R@ffff_B@R@3333 ^B@ R@ffffYB@hfffR@ffffQB@Q@`DB@Q@8>B@4333sQ@ffffF7B@Q@6B@hfffQ@ffff7B@Q@X0B@hfffQ@%B@Q@B@Q@ffffB@Q@3333cB@Q@ffffB@Q@!A@qQ@A@\Q@A@4333Q@xA@8Q@3333{A@4333Q@ffffA@Q@A@pQ@ffff6A@4333Q@iA@Q@ A@Q@A@Q@ffffA@̼Q@3333A@hfffQ@lA@Q@IA@Q@3333A@Q@3333A@ Q@{A@4333Q@ffffntA@4333Q@oA@4333sQ@cA@@Q@ffff>WA@43333Q@LA@4333 Q@ffffFA@̽Q@3333CA@hfffQ@ffff>>A@xQ@07A@ Q@I/A@Q@"A@4333Q@ffffA@Q@dA@LQ@\A@LQ@ffff@@4333۩Q@@@4333Q@@@ؔQ@ffff@@4333;Q@@@Q@A@xQ@ffffA@hfffwQ@ffff@@Q@$@@hfffQ@t@@Q@33333@@0Q@<@@hfffQ@ffff@@hfffƅQ@3333[@@4333zQ@fffff@@ mQ@ @@hfffVdQ@ffff6@@`Q@@@]Q@j@@YQ@3333a@@YQ@3333cW@@WQ@K@@hfffRQ@C@@4333sOQ@ffff~7@@4333kPQ@ffff@@QQ@2333?@hfffKQ@̌?@QEQ@ ?@L>Q@٪?@̜7Q@\?@2Q@|?@̬-Q@2333C?@hfff+Q@|?@@&Q@?@4333S!Q@L?@hfff^Q@ffff&?@xQ@ffff?@ Q@?@hfffN Q@?@TQ@fffff?@Q@?@YP@ffffV?@P@?@P@?@hfff>P@ t?@iP@2333h?@P@ffffa?@9P@ X?@hfffVP@ P?@4333+P@ffffG?@4333P@?@hfffP@L?@(P@@ԟP@>@4333kP@ffff>@43333P@2333>@\P@>@4333CP@2333À>@̌P@ffff6R>@ P@ffff1>@4333CP@>@яP@2333# >@hfffP@2333=@\P@ffff=@̎P@=@TP@=@4333}P@fffff=@4333jP@=@$^P@̦=@̌KP@=@FP@9=@:P@2333=@43334P@l=@hfff-P@0=@Y!P@2333=@43333P@Y=@P@ffffƁ=@ P@u=@̌P@ j=@QP@ffffVd=@IO@n=@hfffO@|=@=O@h=@/O@ffffl=@ O@ɇ=@N@i=@N@ٿ=@4333kN@2333=@4333SN@ >@4333sN@]>@̜N@p>@`N@>@N@>@9N@2333?@hfffN@ I?@N@ffffa?@YN@k?@,N@|s?@4333SmN@ffff{?@ iN@2333~?@4333SeN@?@4333fN@ffff?@dN@?@eN@2333?@4333iN@@@hfff&jN@@@ZN@L@@RN@ffffe@@IN@X@@GN@ffff@@GN@̤@@[N@i@@)bN@@@mN@fffff@@`uN@3333@@hffftN@@@9gN@3333@@SN@3333@@4333sIN@ffffN@@4333cAN@@@43333>N@ @@hfffvCN@ffff@@,>N@! A@HN@A@4333CRN@Q'A@qN@3333(A@hffffN@5A@̜aN@A@hfff\N@ffffVBA@hfff^N@EA@4333fN@ffffFA@43333lN@9KA@hfffuN@ffff&QA@yN@SA@zN@3333ZA@4333~N@_A@,N@QfA@@N@̄mA@N@3333uA@hfffN@$A@4333ÏN@ffff~A@hfff&N@A@0N@ A@hfffN@КA@̌N@3333ۢA@N@A@9N@A@N@IA@4333N@TA@lN@ffffA@hfffN@3333A@4333N@ffffA@N@ffffNA@ N@3333A@YN@3333A@N@A@yN@3333A@|N@ffffVA@ N@A@hfffN@3333;A@4333N@TA@N@3333˸A@y O@A@hfffFO@A@\ O@A@hfff"O@4A@hffff'O@ܕA@|1O@A@@;O@,A@4P@B@hfffS@3333A@`;S@ffff^A@hfffv8S@ffffƷA@4S@1A@1S@3333A@@8S@A@4333ES@A@hfffRS@3333 A@4333\S@A@HaS@A@̤dS@dA@hfffVnS@3333A@)sS@yA@4333lS@̼A@̔dS@3333{A@[S@@333A@RS@ffff&A@JS@A@CS@A@fhfffVf@̬BNl;8-  ^ -Il'<L\fs-<N^hp}&5AMYp}%-?KVdo|/F̬BNdfffF4333ENqFhfffJNFON43333F4333QNFhfffRN4333ۗFVN FpYN4333;F4333]N4333F)SNdfffF̜RNF4333KNFYONdfff6FyLNhFHNFhffffCNdfffFENF̬BNPVhfff3QV3QDV3Q,V3QVhfff63QVQ3Q3333Vh3QVh3QVI3Q33337V3Q3333ۨV4333s2QiVhfff1Q3333VhfffV1QyV̜0QȨVI0QV4333/QV9/QiV̴.Q33337V4333+.QDV-Q3333 V-QxV4333-QhVhfff-Q̼V-Q̄V-QffffV4333-QffffV-QDVhfff.QV4333C/QV̌/Q3333wV/Q3333[V`0Qffff:V0QV\1Q)V 2Q̨V2QVhfff3QPVhfff3Q̤LO2333vLhfffO2333dL,OjLO|L4333OAL4333O|L,OL4333O|L4333SOffffVL̾OffffL̼OffffnLhfffO2333SLOL4333O!MhfffODM,Offff\MP2333ckM PffffMy PffffMPffff}MP$vMPPfM4333PhMP2333sMPffffrM4333P(gMxPffffdM̌!P)rMd"P|M4333P\M4333cPQM4333PMhfffPMhfffP2333[M4333+Pffff^M!PM4333[%PM#PM4333P2333MPffffFM4333P N#Pffff+N<#P2333c2N'P)GNL+PyTN4333.P2333+uN :PN>PyNhfffAP@N!AP2333cN4333?Pffff6N8?PNhfff.?P2333;N$BPNKP2333NDOP̄NOP2333SNhfffNLP2333#ONPffff O|QPO4333;UPffffO<]PN`PNxaPNhfffndPffffN̴ePffffFOlPxOqP2333 'OuP%OhfffzPffffOP̤O9PfffffNhfffPNPN4333PN4333ÃPN~P\Nhfff^~P̜NhfffFPffffN|P2333{~N,|PfffftNzPhN{P$ON{Pffff^HNhfff~PONP2333;_NPmNhfff.P2333SzN4333P0N4333P̌sN9PxNP2333NP0N4333P2333+ŇPNPIN4333CPXNqP2333{NPffff&NhfffPNxPffffNhfffƙPffffN4333PO`PO̜P@?O PJO4333PLWO0Pffff`OٓPP3333gfP4333 PaP̄P3333 ^P4333QffffFcPQhP4333[QbP4333c QXP QMPhfffQ]=P4333SQ33338P4333Q33336PQQffff5P(Q3333W9Phfff Q3333_WPhffffQ\P̌Q5UPhfffNQffffEPQffff?PQ}CPQ3333HPPQffffvOP4333S%Qffff"JP̌'Q}9P+Q3333sP/QP4333[1Q Phfff+Q PH%QTOQ2333OQOhfffQO UQ|kOWQKO4333^Q23339OhffffeQ4OtQOɁQNQNČQOّQ2333OQffffn*OّQ2333[0OYQ2333O)QOџQNdQffffNyQ2333{NxQffff&N@Q2333N\Q@NQ,OIQN4333QNԶQffffNyQ2333 NhfffQffff6N$Q4NhfffQ2333+{NQdNpQNQ`N4333QDN4333Q NQNlQlN`QNQ2333N4333 Q N8QffffVNQiN4333QfffffN4333SQyyN4333Q|N4333{QN9Qffff.NQ O RpN4333R2333cN`RNhfffRffffNhfff6RN4333R2333yNhfff6RffffjNLRffff\NhfffRffff&ZN9 RtXNDRUN43333R2333{]N4333CRNRУNRN4333s&Rffff6xN,R\Nhffff)R2333#DN+R2333#DNA5R<1Nx@R2333 N4333ARNhfffR2333O4333[RO43333R|N4333RxNhfffRN8R2333OIR̬/OŘHOTRZO,ŘqOhfff6RAO\R̖OɫRffff~OhfffROhfff^RXOhfff.R2333Ohfff6RffffOhfffRO4333R\OIRffffOR O9R2333+OXR2333OR̔OR2333O1RPhfffRyORffffORȼOhfffR2333O4333RffffOR2333ORffff^PR33331Phfff>R3333BPhffffR3333TP4333+R}PR̴P4333Sffff*PhfffS3333{SQ4333sSzQh!SQ4333)S3333sQ$+S@Q-SHQQ/SQ,0Sffff:.R,S1^R4333;+SffffNxR,S,Rhfff6%SffffbŘ%S1R&S4R&S3333R%S̠Shfffv%S)LShfffN(S3333_RS,SJShfff^5S4S̔?SSQSRhUSRYS3333RY^S(R^S3333^RhfffFbSffff6RhfffeSffff8RhlSPR4333;ySffff _R!~SffffRSRaSRSS4333ӂS3333oShfff.|StSuST4333rS&T pS8T sSFTuSffff.eThfff&vS9\ThfffxSffffSS3333vShfffvSjSS3333[SћS\SܣSbShfff6SwShfffS3333S!S3333ShfffS̴TSffff>4ThfffFSy{TȣSTdSHTɏS3333_ThfffVS3333T4333~Sffff"Thfff>STyS3333TS̼TٖSffffT4333SThfffST̼S-TܙST4333ST4333cS3333T4333SŤS TDST̤SLjT4333cS0`TlS8NTSqJTSffff9ThfffS3333-TSffff:"TSThfffFSDT4333STS̬ T(S)S4333{SSSffff SSffffSSS!S3333SS#S4333S33339S4333#S9NSS3333lS̜TMS̴SDSSffffS̼TDS̬ TDJS Tt0ShffffTS4333TShfff> TRTffffR̤T`Rhfff~TR!TffffR̄'T R4333.T3333#Rhfff^3TffffR4333 7T3333R̼8TffffR5T|R84T̈XR19T3333AR̴:Th#R6T R43330TffffRQ+T3333Qd)T!Qhfff'TffffQ(TأQa)TQ/TMQ43336T̀Q̼:TlqQ=T3333hQ=T3333KQP@T%Q4333=TffffQ4333C@T33337QDT33333 QXHTP|IT3333dPy]Tffff0P4333caTffff&OhcT>OcTffffF-OdT2333+OhfffhT2333[EOikT2333yOhfffkTO4333jT2333cODkTP9jTqPjŤ,PiTaAP4333lTgP̬nT$_PqTPPHrT3P`sT, PhfffrTffffP4333wT1-PxT3333zPhfffyT̴P|zT̐P}Tffff|P$~TvPTXrPTqzPTmPhfffޑTffffdPhfff֒T)[PT3333JPhfff^Tffff:PhfffTaPhfffTOyTO4333TROhfff֐TiNYTffffmN4333T2333WNŤCN4333ˌThNhfffT OܝTFOhfff6T)^OTPOT;OhfffTffffvOT`NTffffN4333T2333 N4333TNyTffffNDTЦNTٷNTNTNhfffTpNQT}N\T2N4TIMPT MhfffVT%MTLYTPLT2333CLhfffƵT(LT2333 Lhfff~T|KhfffTKTLKT?Bi=T4333B:TdfffA9TPA43334TA/T4333۩A̤)T4333,Ahfff&T4333@hfff"T|@1!T4333S@hfff"TdZ@4333 T4333 @|T\?tThfffO?hfffT0333?Tl>hfffT =4333KT=4333 T@T=4333 T0333=8hfffT033384333T7S`fff&h7S8hfff&S0333L8TS̬8S84333S`fff6B9Shfff=hfffVS >hfffvS03336>hfffŠ->ySP>pS0>S03333>0S̬i?4333KS4333[E@8S4333C@̤S4333CAhfffSYAS4333 AhfffSdfffAS̜B̌S"BdSdfff&BS0A4333Sdfff6A4333uSxgĀtSdfffFAnS$%AhffffaS4333 A9[S4333@4333SS9@hfffRSN@4333IS3@HS@4333;JS?hfffBS<}>0S03338>4333C*S<=D&S0333<4333S0333S<S0;|Sp"; S`:S0:4333CR0333E8hfffR27hfffR)w6hfffNR`fff5lR o5R04R`fff44333R|4|R`fff6~3hfffR`fff2R̕24333RM24333R`fffFj2`R`fffV2R`fff2R̿2hfff~R`fff2aR`fffV24333SR82hfff^Ry24333;R91R0333o14333CŘL1hfff^R@0xR0333#0R`fffm04333R0333SX/R/ RY.R`fff-.4333sR`Q-IR%-|R 9-4333vR.4333xR`ffff/̄|RY804333zR)H0|wRL.04333#uR08tR /|pR03330amR0333Cc04333kR0333ӄ08iŔ0̔cRio0hfff>[R0333sG0XR`fff&&0hUR /̼IR`fff&1/1FR. CRY,GR0333ST,hfffFR , @R,V,5R0333,hfff62R0333s,.R+hffff0R`fff4+2Rj*hfff>2Rl~)@(R0(R'4333kR0333s&lR`ffff&hfffR`fff&>&Ř%Q %Q&Q0333[&Q`fff&hfffFQd' QK(hfffFQ̬(Q(Q`ffffj(4333CQ%(Q,'yQyS'43333Q&$QR&4333Q̌%Q%iQ`fffQ%TQ`fffF %Q03333$Q v$Q`fff&$\Q>$hfffQy$QL$Q̌$4333Q̌2$IQ`fff#Q2#Q"hfffQv"4333#Q̌! QK!hfffQ0333 0Q0333n iQ̩QQ QL\QQxhfffQ Q 333s~hfff.Q 333sk̜QQ`fffzhfffQ 333s\QY 4333sQLZ Q`fff0HQhfff^Q̜̾Q`ffff4333QZԶQ 333QQQ 3333RQ́QLxQQ 333QLQ@ffffQ Q Q4333QQ33334333Q@fff̼Q4333cQQ3333v0QQ̪쿚YQ4333QPhfffVQa̜QԿQǿQ̼?xQ4333;?̌Q?4333Q?4333#Q?4333;Q@3333@4333Q@3333 @4333 Qs@hfffQffff@Q@3333@Q@AQ̚@̤Q@hfffΖQ @4333Q !@4333SQ̌!@4333QH"@Q:#@8Qpffff#@əQ@333so$@Q %@4333Q@3333h&@4333Q g'@Q̪'@4333#Q"(@tQ(@hfff^QY(@Qpfff&])@Q)@Qpfff)@4333cQpffffr)@1Q@3330)@4333Qpfff@)@43333Q!*@hfffnQ̌*@Q@333+@hffffQ@3333+@hfffQ,@,Q@333 .@ܒQ@3333 /@4333+Qpfff&/@̼Q8333s0@aQ̌a0@IQ0@4333 Q̌0@lQ̬*1@4333ۜQhfff2@̔Qhffff;2@4333+Q8333Y2@Qn2@hfffQ2@hfff>Q83332@4333Qhffff3@4333QhfffF23@4333ÒQ!3@4333{Q3@4333#Qhfff&'3@QC3@Qhfffh3@Q3@4333Q3@@Q 4@Q 5@4333Q/5@hfffQYV5@Qy5@4333Q8333S5@hfffQY5@9Q@76@̴Q8333]6@hQe6@Q8333;6@!Q G6@̄Qhfffr6@XQ6@ܳQ`&7@hfffQhfff&h7@IQ833337@̤Q7@Q,8@tQY<8@hfffQb8@\Qb8@Q8@Q8@Q/9@$Q8333s9@hffffQ`9@dQ8333:@@Q :@Q:@ Q83334;@LQ83333;@ Q;@pQb<@hfffQY<@QQv=@Q>@43333Qhfff>@4333ÏQ?@aQ`?@4333sQl@@4333cQp:@@QhfffO@@ Qhfffg@@43333zQ̬t@@nQ4333~@@4333gQ|@@hfffaQs@@Q4333@@HAQhfff&@@4333[FQA@4333GQhfffFLA@ FQ_A@4333JQАA@)_QhfffƜA@hQ4333A@4333kQA@hfff>jQhfffFB@4333[jQ4333c*B@4333hQKB@4333hQ\B@hfffiQmB@pnQ4333B@hfffsQB@oQhfffB@mQB@qnQyC@tQ?C@QYqC@Q4333tC@4333CQmC@4333cQhffffC@hfff&{Q C@LrQhfffVC@fQ@C@<[Q4333C@KQ4333C@4333=QhfffVD@7QD@43333Q=D@I/QhfffhD@P.QD@hfff$Q̜D@ Q̌D@Q4333S4E@̄QhfffhE@4333Q{E@QE@4333QE@4333QF@

PH@P,)H@AP,)H@P/H@yQP@|Q4333P@QP@hfffVQhfff&P@4333{Q,P@ܔQhfff6P@Q#Q@hffffQy0Q@̬QhfffVAQ@ДQhfff^JQ@`Q4333PQ@hfffQhfffLQ@tQhfffLQ@Q43337Q@@Qhfff&1Q@hfffQ4333'Q@̜Q̤Q@QQ@hfffVQdQ@hfffQP@4333Q4333cP@hfff&QP@0RP@RP@RAP@)RP@hfffQ@QQ@QQ@Qhfff^Q@HQQ@9QhfffR@QR@PQ'R@hfff6Q0R@4333SQ4333/R@hfffNQ̜4R@4333#QhfffBR@hfffQTR@TvQDkR@tQL|R@oQ4333R@9sQ̌R@4333KxQhfffvR@vQ R@(yQ̬R@TvQhfffR@hfffnnQ R@hfffdQhfff&S@1_QhfffS@`_QI1S@̼UQILS@hfff.MQhfffbS@)KQQtS@iDQS@9QS@d0Q4333KS@ (QS@43333Q4333{S@Q@S@9 Q4333kS@4333Q<T@PhfffKT@43333PhfffT@)P|T@DP٦T@Z@PxZ@4333P4333 [@hfffP4333[@4333Phfff>:[@)Phfff][@(Pt[@4333[P[@P4333ӧ[@P[@P[@P[@}PhfffV\@4333yP#\@DvP\F\@1sP̌W\@QvP4333#`\@xPlm\@hfff~{Phfff}\@hfffރP\@ Phfff\@4333Phfff\@hfffPhfffF\@̌P\@P\@4333[PH\@PP̄\@P̄\@P\@hfffPp\@Phffffz\@P4333\@^@P4_^@hfffPhfff>g^@hfffPhfff^@hfffP4333^@P4333^@4333P0^@P^@QP ^@4333Phfff _@4333sPhfff_@hfffP4333C&_@4333SP̔4_@4333sPhfffF_@P4333SR_@4333PxY_@)Pf_@,Phffffw_@4333SP_@PPhfff_@P4333_@؟P_@P4333c_@hfffVP4333_@DP_@P4333 `@P4333`@4333P `@$Pp`@IP̔'`@P0`@0P7`@P9?`@P4333C`@PhfffI`@hfff.P4333R`@YPt^`@@Plg`@4333ˍPhfffz`@P@`@hfffPhfff`@dPhfff`@P9`@hfff6P`@ԉP`@4333P`@4333P4333k`@@P4333C`@4333P`@hfffP`@̜Phfff`@!P4333C`@4333#P`@hfffPLa@4333P4a@4333P̴a@P4333a@Pta@̼Phfff*a@,P43338a@4333P=a@hfff>PhfffzDa@ТPHa@ P La@hfffP4333ga@̼P4333sa@hfffΨP|a@ĭPٜa@ Phfff&a@e@RDe@tRLHe@4333R%Ie@R4333Fe@hfff.$R4333Ae@p&R8e@)"R4333.e@(RP"e@Re@4333Rpe@4333CR e@Re@@R=e@4333[#R(e@4333'R:e@̤.R;e@43332R6e@ 8Rp1e@9CR!e@4333LŘe@hfffER4 e@8DR4333e@hfffNHRLd@hfffGR4333d@lIR@d@@R}d@;Rd@hfff?Rd@4333[NR8d@hfffQR̴d@hfffUR̰d@4333;YRd@\R|d@)\Rd@hfffbR̸d@aRd@)bRd@dRhfffd@hfffeR4333d@hfff^hRdd@ oR9d@tRhfffzd@xwR̐d@hfff&vRhfffd@HxR4333d@4333rR4333ӧd@hfffdR$d@|XR(d@WRd@dYRd@4333cRhd@̜uR4333[d@A{Rd@0RhfffҘd@4333ӁR0d@ܐR4333kd@hfffFR4333ˬd@4333R4333d@R̰d@R d@4333RLd@4333R d@`R$d@4333#Rd@|Rhfff}d@PR4333wd@R4333qd@hfffR4333ld@tR4333hd@HR4333[ed@hfffRhfff^d@RXd@RTSd@hfffR4333Qd@R4333Md@4R8Gd@4333R4333Bd@hfffR!=d@R43335d@R$d@4333kR !d@hfffVRhfffF'd@hfffRd@Shfffr>d@4333S;d@hfffS7d@hfffSy1d@hfffS&d@4333Sd@hfff.Shfffrd@S(d@YShfffrd@S̬d@QSd@4333{S,d@4333Shfff:c@4333{S̬d@4333{ST d@̬S d@ASyd@$Shfffc@̌Sc@S̐d@hfffSd d@IS4333d@hfff~Sd@̬T43337 d@|Td@4333T4333c@hfffThfffc@TT4333[c@Tc@4333STYd@43333Tdd@4333ThfffNd@| Thfffd@hfffV%Thfff>d@̼(TXd@4333#+Td@hfff.Thfff d@433330Td@1T4333Sd@Y2T4333d@16Thfffnd@̬9Td@4333:T4333Kd@9GT4333d@hfffLTHd@xOTPd@IQTd@UT d@XT̠2d@hfffgT]7d@gT?d@4333iTMd@pTtRd@@uT4333GZd@pwT4333W[d@zT4333#`d@4333~ThfffFsd@T4333ud@ThfffMd@ TT%d@T)d@4333[TTd@ўT``d@@hfffV=@hfffV<@hfffV:@hfffVP9@hfffV7@hfffV6@hfffV5@hfffV3@hfffVG2@hfffV0@hfffV.@hfffV ,@hfffVP)@hfffV&@hfffV#@hfffV @hfffV @hfffV@hfffV@hfffV@hfffV?hfffVhfffVhfffVhfffV hfffV hfffV hfffV`fff hfffV`fff#hfffV`fff&hfffVP)hfffV ,hfffV.hfffV0hfffVH2hfffV3hfffV5hfffV6hfffV7hfffV0333P9hfffV:hfffV hfffV,@hfffV@hfffVAhfffVHBhfffVBhfffVChfffVdDhfffVEhfffVEhfffVFhfffV4GhfffVGhfffVHhfffVPIhfffVJhfffVJhfffVlKhfffV LhfffVLhfffVMhfffVUffffcd:Uɤc4333 9U3333c8U3333ߓc̼5Uc3Uc43331U33331rdhfff!U3333udhfff UIxdUffff|d4333U3333dUVd4333UTd4333;UdhffffUdhfffU3333dU|dUffff|xdUffff>xďUHzdU3333dUd9 Ud UffffJd0Ud̔U3333dlU\dU3333ďTmd4333T)dlT3333d4333TffffdT3333dTd̜TeT eTe TeT]%eTfeiTBqe Tffffe4333T3333eAŤeȲTFe̜T?e̬T3333ehfffTe(Te1THzeclT3333mGc4333gTffffOc

Vc4333S,ac!SjcIS33337cScɌS3333#c4333S&c|ScxS3333cqS>cYgS\c_S3333c̬VSchfffJS3333chfffEScESffffcNS3333uchfff~OS]cMSffffȋcHSffff†c4333FS3333m}chfffFFS{kcHSAcchfffGSZc HSffff=chfffNS6čQS3333e3cSSffffV2cbhffffDS=b4333AS9bhfff@S"4b =S33335b43338S33335b2S8b/SSEbhfff*SffffXb4333s SjbhfffSRffff\4333R8\hfff.R\hfff־R3333{\hfff־R)p\Rffffe\dR3333E\R \4333CR̐[hfffFR3333[4333R3333g[hfffR3333G[ѩRffffz[hfffR[4333CR9[hfffR3333[4333CRQ[̜R[ٌR[ RD[RffffN[hfff6R,[|R3333[xR̴[4333SRffff:[4333{R3333 [hfffR[R[Rffff[4333R3333[hfff6R\[hfffR3333kQ[R4[9RI[)R̀Z̔R3333ZhRZR3333Z4333R3333YZhfffR9Zhfff^Rffff'ZR8 ZR3333Y4333R1Y4333{R3333YR]Y|RQmYhfff&Rffff.hY1RpSYiR̄BYR4-Y4333{R̨YhfffRLY̴RXhfffRXRffff&X4333KR3333SX̼RX$R3333X4333RffffRXhfffR̸XR3333OXR YhfffRȲR3333KYԷRY4333RY`R3333YhfffR=YR!YIRp8YR3333{AYQRPYhfffRUYhŘeY4333+RmȲRffffY4333K}Rffff6Y@{R YxR33337Yhfff&rR3333+Y4333SiRHY4333sgRXY4333[hRuY4333iReY̬jR3333SYhfff~lRUHYoR?YhfffvpR-YpRXhfffnRffffXllRXIiRXhfffhR\X4333iRffffZXgRffffX4333dRX_RTY4333YRYVR LYXTRdYUR8tY4333SR4YTR)Y@RRYKRYR$Yhfff@RY̤BR3333Xhfff?RYXlAR3333ˀX BRffffbtX4333FRffffiXhfff>IRffff~^XHR3333+=Xhfff6MR@+X0QR3333;XhfffFSR̼ X4333SR3333[WhfffRR3333W4333sOR$WhfffNRW4333KOR̈WORWTRWYRRffff.mW4333MR5WJRlW4333kKR3333VhfffSRVlTRVORVGRVhfff>RV4333sU!`R$UcR̴ UdRffffTIiRffff&Thfff.mRffffT4333CmR,ThfffnRffffThfffvRfffffTrRffffST@oRqJTyhRffffOTQ^R3333PT(TRffffJKTORffffAT4333OR3333TZR3333OTSRThffffNR3333O'ThfffVER%T>RMT4333sdRBS4333mRffffHSTtR!CShfffvR8S4333tRQ0ShfffrR3333S4333sR3333R!oRR̄mRRhRRIiRRjRRhfffmRRkR̠R4333lR3333RlRx;R4333\Rffff+R4333\R3333_Rhfff\R̠QDXR̤QVRQVRQPRffffQQR}Qhfff~NRRQ4333JRffff4QFRQ;RPi5RP'R3333PhfffRPRPlQffffbP4333Q3333P4333QffffvPhfffQffffPhfff6Q3333KP4333QLPhfffQLPQPQ3333 QhfffQQ4333CQQsQQ4iQ(QaQ3333O-Q[Q3333%QiZQQ4333XQ Qhfff>VQ3333P4333cZQffffzP4333STQPOQdPhfffNJQ\PhfffAQP\>QffffPhfff7Q3333#P4333S1QffffP4333S1QyP*Q3333{P$QPQ3333/P QffffƲP4333cQ̐Pd Q3333P4333QPhfffP\Phfff6PP4333SPEPPXP4333PffffP̼PPhfffvPP4333 P)PPP8P$P0P}PP9P4333;P3333P8P0PhfffP3333#PP@PP4P|P PhfffPffffnP0PffffP̄P̼PaPP4333PxPPffff PYPLPhfffPffffPP8PPlPPPPP!P̬Pffff"P4333+PP4333P3333PhP3333;Phfff&P̼PPffffP4333PP4333Pffff }PQPEhfff>SdfffFTSdfffFFS4333FYSF4333SF4333SMhfffT M#T2333M*TMhfff.T2333Mhfff1TNhfff5TT"Nh8TJNhfffRQ3333JRQQRhfffQ̴RQR4333Q3333R4333Q3333RDQ{R4333 QffffZnRhfffQ3333bR̬Q^R QffffV[RQTXRQffffeR̬Qffff~gRaQfR4333sQU^R4333Q3333oYRhfffQ3333CARQ4ŘQ'R4333Q RqQffffRQ33339RHQffff?RQCR Qx-R4333QffffRQQIQIQ4333#QffffQQ3333kQhfffQffffnQhfffQ\QQffffQQ!QhfffQ3333zQQffffwQ4333 QffffruQQtQ(QtQLQ%uQyQ xQQ{QXQQiQQ|Q3333QpQQ4333QHQXQ3333Q4333KQ)QhfffưQ QQ)Qhfff6QQ`QQܙQ3333QhfffQɅQqQ3333k~Q QfffflQ4333Q3333;jQ4333cQ3333gQyQ3333xQQ3333QQ3333Q̌QQ8Q QQ3333GQPQ̄Q4333QffffQ4333Q̌QhfffVQQpQffffQTQQ ~QEQ,zQQ8vQ3333QhfffsQffffQiQ3333QaQQhfff[QYQyWQQ UQ)RQQQRlNQffffRLKQ3333RTGQRCQR@Qffff^Q!>QQ9X43333R8XhfffRffff3X4333R-XYRffffXI RWhfffRWRWaRffffW43333 RW4333R3333W<RWRX4333 RffffX̔!RXy#RPX$RT,X #R3333s3Xhfff#R:X4333%RAX$RPXhfffV!RdWXd!RfffffX #R3333uXhfff#RuXhfff#RX #RXXR3333kXIRffffX4RXhfffRXPRYhfffR̨Yhfff^Rffff~ Y4333sRYRfffffYhfff> R9rY` RyYhfff. RffffjYhfff RffffYRffffY0R3333sYhfffR3333#YR33333YQ̨YhQffff YhfffNQffffjYQ X Q3333SX4333R,XhfffRXR XyQ3333CX8QAXhfffQ3333X̬Q3333cXQaS@>\S>tS>hfffnS>4333S0333=SL=hfff6S0333=4333S0333=4333CSl>Sl>T,>S ?S?hfff^S @S0?Sٚ?4333CSl?S4333@SdA4333S4333=BSdfffLBSqHB\SpBhfffS$BSdfff&AStASpA4333S2ADS4333S@4333S<@4333S4333@SaQ4333S\QhfffSQ)S3333QSffffQSffffQ4333[S QxSffffQ S%QpSQSffffQ@SIQSffffQ4333SТQhfffS33333~Q̳SoQ9S|YQSP43333SpP4SffffƵPaS̘PhfffSffff^PSPSffffP4333sSP̬S Q̼S(QSffffPQhfffvSffff>YQS3333kQ`S3333hQ SnQ4333SqQSaQ4333SIL4333sPffff~L4333SPLPffffLP2333LPLOhLhfffO0LhfffPffffLhfff6P2333L4333 P2333sL4333+PL8PLPPLhfff^PL|PffffL@PffffVLlP2333sLP2333LhfffPffffLP2333SLTP̌LP2333sLhfff>P2333L8PL43333PLLP2333M̔PMhfffPfffffMP&M!PffffM|PM1 P2333MI P2333M4333;Pffff MhfffPffff-M\P2MP23338M4333CPd6MhfffVP2333+MhfffFO,#MhfffFO̤MhfffVO MyO@LhfffO|L,OiL4333OffffL4333#OL4333OLOIL4333sPffffKhfff6OffffǨOffffKlOKhfff6OKOK4333OK43333OKOffffKOLK43333O2333+LhfffO LO2333s0LOffff>;L4333O?LhfffƭOffff@LɪO%PffffO PffffO,PDO4333CP2333SOP2333O4333PpOP2333O4333P`OxP(O̬P2333O PdOhfffPffffO\PO P2333)O)P̬2O̼P2333C:O0P AOP23333JO Pffff]OhfffPdOP_O0PffffF\O4333sPffffNROP2333@O8Ph=O4333{ PffffKOP,NOqPJOhfffPEOP9O4333P*OPA"OhfffPfffff"O4333P|OhfffP2333 O4333PffffNOPO4333P&OP2333)O)P3333CP\PQyP4 QPffffQPffffQ4333P3333gQ4333P3333QPffffn QAP%%QhfffP'Qhfff>P*Q4333CP.QP3333_4Q8P9QPffff>Q̄Pffff>FQ4333PGQPHQP}HQPffffFEQPy4Q4333P3333.QP*QPffff$QhfffPQ̜PQTPffffP P3333'PP3333P4333PP`PiPPP P3333P4333۾PffffPP3333PhfffPPhfffPffffPhfff>P3333PhfffPPhfffnPffffFPhfffP4PXPQ43333P5 QhfffP QhfffPffff> QyPffffrQP PP3333CP\P9mRhfffQ8cRLQ3333slRhfffֲQ3333R$QMRLQffffRQH SyQ\SQ3333KSyQSQ̼ SiQ S@Q3333+S9QSHQffff6SQpRqQ RQR(Q3333gR4333QffffzRQRhfffƥQ̀R4333˥Q3333RaQRQ̼R4333CQffffRQ1ŘQR4333ۤQfffffRhfffVQTRQ5RQtR4333cQL}RhfffQIxRQ9mRhfffQ,R̔nQٳR(pQffff.RwQɝRhfffzQRhfff|QqR0~QRQffffRhfffnQ3333SRyQ-RQ3333Rhfff&QRqQ3333wRqQ3333R~QRzQ3333RlxQRhfffuQ3333RhfffFtQffffRoQtR oQffffRhffffoQ,R̔nQ3333RLFRffffR4333NRpR̜OR3333RhfffQRffffbRhfffSRԤRTR=RWRRhfffV[RffffnRhfff]R3333R0dR3333ǤR gR3333RIUR4ShfffnRRfffffSLPRS4333LR3333+SIRffffShfffFR!SxER3333sR4333CRRyCR`RFRRxFRRLCRR9CR3333R@R R?R3333kRY@\kP#Y@lP Y@9kPpY@kPY@hfffiPLY@̜fPhfffY@4333SaP43333Y@]P4333"Y@,ZP&Y@hfff^YP8Y@43333XP EY@4333YPhfffNY@9^P4333PY@aPAOY@!dP>Y@\kP8333s:@dQ:@hfff֚Qٛ:@dQ`x:@4333Q̌[:@4333˛Q`:@hfffޗQ9@ْQ@9@4333Qhfff9@4333ˌQ8333M:@4333Q8333l:@Q8333Ӛ:@Q̬:@4333SQhfffƼ:@Q8333:@hfffQ8333s:@dQ̌XQٟ4333#Q 3333yQhfff6QQhfffQ`fffEhfffQ 333QLQ̌XQ@fff= )Q DQ 4333Q AQ333L Qb 4333Q@ffffhfffQ@fffphfffvQLhfff~Qy4333Q3333v̔Q4333sQ@fff= )QP4333TPhfff6TffffrPhfffT3333{PyTDP4333KSffff޹P4333+S3333PSPhfffSPSffffPSTPSffffPS3333PS PSffffPdS3333gP4333CS@PSP4333+SPhfffS3333wPhfff6SffffePTSbPSH`P4333SyPTffffRPtTP4333T3333PSP4333SU QSffffQS!#QhfffSffffQ4333SSffffQhfffSQL}OL̬OLO2333{L`OLO̬L OL4333SO2333L4333OffffLiOPL̬OL4333OffffLhfff&OL4333sOL4333COtLhfffOOPNGOQ4333lQffff Rhfff^oQ R@mQffff1RHiQD=RaQ;R^Qffff6R[Qy.RpZQ3333R4333\Q1Ry_QQ4333lQ3333W*R3333 Whfff*RxWhffff)RW\&R1W!R3333;WRtW4333sR3333WxRśW̴%RDW4'R3333W*Rm"Z̤JRffff6*Z4333MRa8ZhfffLR3333cCZHRffffGZAR3333oHZt?RiEZ=R<>Z9e@4333`R4333{;e@4333[dR4333:e@fR̬d@hfffPd@hP%d@Phfffrd@PHd@P4333d@|P4333d@Phffffd@hfffP4d@hfffFPd@Ped@4333P̈d@@P̬d@hfffPid@hfffP4333id@qPgd@̌Phfff>ed@lPhfffbd@hfff֬P4333dd@P̜gd@\P̬hd@ Phfffid@Pid@hfffP̐Sd@̌PQd@4333P\Pd@IPId@̔PpJd@$Q@4333+ R*Q@R̬.Q@̴R5Q@hfff RL4Q@4333R*Q@ŘQ@4R$R@|QtQ@4333QhfffQ@hfffΧQ4333sQ@$Q43333Q@hfff֟QhfffQ@4333cQaQ@hfffQ Q@43333Q4333Q@QQ@4333QyQ@QQQ@QR@N4333cQ^NyQFN4333cQySNQffffeNQ2333tNyQffff&yNQqN̻Q23333dNQ2333{NN4333Q2333CDNQffffBNQDNhfffQFN4333cQ2333˱M8O2333;M9OIM2OMY-O@M4333-O2333M4333/O2333;M4O2333˱M8O@N4333{OGN }O2333SON |OONI~Offff&HNhfff&O2333ONLOXN4333sOffff^NlyOYZNsOffffQNhfffrO@N4333{OSNO2333cNyOmN Op|N̬OgNhfffOeN̼O[N̜O2333GN4333OSNhfff&O,XNiOffffSNOSNONPffffO$POPNO,NOpNPN|PNPyO7PO:PxO43339PɺOhfff2PffffO2PO̴.POH/P2333O̜2PyO7P2333NOOSO4333sOffffQOhfffOffffvCO@vO(O4333oO ,OyuO23334O\|O2333NOOvP4333uP3333P`xP8PtwP̜P4333tPffff҉P̄qP,PoPHPjP3333PhP}P4333dPYuPhfffaP3333hPhfffcPjP4333hPjPiP(rP(kPfffftPkPuP4333CoP|uPtPvP4333uPP،PdP4333PfffffP̌PPhfffΒP|PhfffPP4333P3333۱PPhPhfffFPФPhfffFPܧPPPhfffnPP،P1P@P0PPTPlPP PPhfffnPPhffffP3333CP)Pffff:P9P33333P,PffffrPѵP1P@PTP PPAP`PP$P4333P3333P|PPQPPP3333PPffffPQP1PPP̜PffffPPffff.Phfff.PTP P3333{QQtQQ3333Q4333QffffQQ3333QQQQhfffQ3333GQhfffQQhfffNQ QhQQtQ3333{QQ8xRhfffVR3333c~RXR3333sRdWRffffbR0TRffffR̴QRhRORffffRNRAuR@GRffff&kRlFR3333bRGRffffkRhffffNR3333+nRhfffRR8xRhfffVR3333rW:R3333}W:RW8Rffff>W4333 7RW̬4REWhfffv4R,sW4333s8R3333_pWhfff:R3333rW:RE/]RN]hfffVR3333;W]LR}Y]hfffևRX]LR3333g]dwR ]QyR3333 ]DzR]!Ri%]hfffR&]4333cR0"]TR3333 ]R$]4333 RE/]R3333`HR3333{`hfffRn`̌R3333`4333R`hfffR`S-b4333?S3333bp@Sb-Sb.S4b.S3333Kb̤/SDb4333c1Sދb2SlbT3S3333bhfff5S|b6SbhfffV4Sbt0Sb-SbhfffUS3333bXS bWS2b4333CSS̘b̔QSb4333QSb)TSbhfffUSpb1S3333bhfff~2S3333b̼0Sbhfff&/Sb̴-S3333bhfff>,SffffPb.Sffffb /Spb1SVbS\b4333Sffffdb4333 S kb4333c Sffff mbSxmbhfffS`mb4333SffffkbSffff^^bHSVbSHYb̄(S ]b4333-S3333gb*S^kb4333'Sffffhb\#SffffTdb"SQ^b̄#S\b $SHYb̄(S̴bWS2b4333WSbhfffRS3333_bhfff~QSbhfff~NSffffbNSbqUSfffffbhfffVVS̴bWSffff=c!TffffCchfffNT)Kc4333T3333PcT"^cSnachfffSpc,S xcSuchfffS0ecqSQcS@chfff6Sffff=c!TabhfffGSdbhfffHSPb9HS$bhfffNGS3333gb\FS3333bDSbhfffF@S;b4333>Sffffb4333^W"_ zkfszyhXpR hhh@hXp|P l@̰P  "b&N'70 @lI:KMjR`R [p_bdxh Ht >&2\XJ%""Zh ` uHF/@0ߔ4 HH D`\>$b608;l`=Fd``aPapb^hjlp`r ^  Nl2h.2 6h>F8Vr ~x  % 1| J:@?`Tr 0^4_stSp`LTȤ?  0  8      ˌ H L  <` B !F % 48 7 <$ >8 C N ` N $ Z [0 c^ l* t8 t4 @ ,@ p պ ֈ 6  j 4P hXastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.README.html0000664000175000017500000005431015151324131024047 0ustar hibbyhibby Coastline | Natural Earth

« 1:50m Physical Vectors  « Downloads 

Coastline

coast_thumb
Includes major islands.

About

The 50 million coastline is a generalized version of the 10 million coastline achieved by automated and manual techniques. Ocean coastline, including major islands. Coastline is matched to land and water polygons. The Caspian Sea, which is technically a lake, is included. The ocean coastline, the foundation for building all of NEV, primarily derives from World Data Bank 2 with modest generalization applied via line simplification in Adobe Illustrator. The Antarctica coast derives from NASA Mosaic of Antarctica.

(below) Yucatan peninsula, Cuba, and Hispaniola.

coast_banner

Issues

World Data Bank 2 coastlines have suspect accuracy for certain parts of the world, including northern Russia, southern Chile, and most egregiously, the west coast if the United States extending to the Baja Peninsula, Mexico, where the coast was approximately 7 km east of where it should be. The west coast of the US was corrected on NEV; other areas were not.

Does not include rank 6, 7, or 8 coastlines from the minor islands. Some rank 5 coastline should be reclassified as rank 6.

Version History

The master changelog is available on Github »


Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.VERSION.txt0000664000175000017500000000000615151324131024103 0ustar hibbyhibby4.1.0 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.cpg0000664000175000017500000000000515151324131022710 0ustar hibbyhibbyUTF-8Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.dbf0000664000175000017500000021072515151324131022706 0ustar hibbyhibbyu 1scalerankN featureclaC min_zoomN 0Coastline 1.5 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 0.0 0Coastline 0.5 0Coastline 1.0 0Coastline 1.0 0Coastline 0.5 0Coastline 1.5 0Coastline 2.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.0 0Coastline 1.5 0Coastline 1.0 0Coastline 1.5 0Coastline 0.5 0Coastline 1.0 0Coastline 1.5 0Coastline 1.0 0Coastline 1.5 0Coastline 1.0 0Coastline 2.0 0Coastline 0.5 0Coastline 2.0 0Coastline 2.0 0Coastline 1.0 0Coastline 1.5 0Coastline 1.0 0Coastline 1.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 1.0 0Coastline 0.0 0Coastline 1.0 0Coastline 2.0 0Coastline 1.0 0Coastline 2.0 0Coastline 2.0 0Coastline 1.0 0Coastline 1.0 0Coastline 2.0 0Coastline 0.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 1.0 0Coastline 2.0 0Coastline 2.0 0Coastline 0.0 0Coastline 0.5 0Coastline 2.0 0Coastline 0.0 0Coastline 0.5 0Coastline 0.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.5 0Coastline 1.5 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 2.0 0Coastline 0.0 0Coastline 1.0 0Coastline 2.0 0Coastline 1.0 0Coastline 2.0 0Coastline 1.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.5 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 1.5 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 1.0 0Coastline 1.5 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 1.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 0.0 0Coastline 3.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.5 0Coastline 1.0 0Coastline 1.0 0Coastline 1.5 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 3.0 0Coastline 2.0 0Coastline 0.0 0Coastline 0.0 0Coastline 3.0 0Coastline 0.0 0Coastline 3.0 0Coastline 0.0 0Coastline 0.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 1.5 0Coastline 1.5 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 0.5 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 1.5 0Coastline 1.5 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 0.5 0Coastline 0.5 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 1.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.5 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.5 0Coastline 2.0 0Coastline 2.0 0Coastline 0.5 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 0.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 0.5 0Coastline 1.5 0Coastline 1.5 0Coastline 3.0 0Coastline 1.0 0Coastline 1.5 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 0.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 1.0 0Coastline 1.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.5 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 1.5 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 4.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 0.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 1.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 1.5 0Coastline 1.5 0Coastline 2.0 0Coastline 1.5 0Coastline 2.0 0Coastline 2.0 0Coastline 1.5 0Coastline 1.5 0Coastline 1.5 0Coastline 2.0 0Coastline 1.5 0Coastline 0.0 0Coastline 0.5 0Coastline 1.0 0Coastline 1.0 0Coastline 0.0 0Coastline 0.5 0Coastline 0.0 0Coastline 0.0 0Coastline 1.0 0Coastline 1.0 0Coastline 1.0 0Coastline 0.5 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 0.5 0Coastline 1.5 0Coastline 0.0 0Coastline 0.0 0Coastline 0.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 4.0 0Coastline 2.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 4.0 0Coastline 3.0 0Coastline 2.0 0Coastline 0.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 0.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 3.0 0Coastline 2.0 0Coastline 3.0 0Coastline 0.0 0Coastline 4.0 0Coastline 1.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 0.0 0Coastline 0.5 0Coastline 0.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 3.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0 0Coastline 4.0Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.dbfawk0000664000175000017500000000151615151324131023405 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This file is used to set rendering rules for the Natural Earth Vector # file ne_50m_coastlines.shp from natural-earth-vector # (https://github.com/nvkelso/natural-earth-vector) # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="scalerank:featurecla:min_zoom"; dbffields="featurecla"; } #Default: black lines, visible all the way out to max zoom. There is # nothing to fill or be labeled here, so everything else is irrelevant BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=26; name=""; filled=1; pattern=0; display_level=2147483647; label_level=10000; label_color=9; font_size=0; symbol=""; fill_style=0;} # All the features in this file are coastlines, but set to thin, solid lines # for all of them /^featurecla=Coastline/ {lanes=1; pattern=0; next} Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.prj0000664000175000017500000000021715151324131022737 0ustar hibbyhibbyGEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.shp0000664000175000017500000377431015151324131022755 0ustar hibbyhibby' dfLLUf@`T@4333Of@hfff0f@hfff&'08f@hfff&'0${f@60hfff>yf@433380vf@hfff&50Ttf@hfff&90qf@?04of@LK0hfff~kf@@a0dif@ f00gf@g0bf@p0̼^f@{0[f@@04333Yf@hfff04333Wf@Y0hfffUf@hffff0LTf@hfff0̬Rf@4333304333+Rf@43330XQf@4333S0pPf@04333Of@43330QSf@433304333kTf@0HUf@hfff0̜Vf@hfff0Yf@04333G\f@43330i^f@l08`f@4333s0hfffaf@hfffF0yff@4333s0if@ٵ0Xjf@4333ӷ0hfffkf@ 0lf@04333kmf@y0nf@Y0rf@y04333vf@Y0Dzf@hfff0}f@433304333{|f@0|f@hffff0hfff}f@90}f@0Q|f@0zf@0hfffNvf@hfffơ0hfff.rf@Y0 rf@ 0sf@0wf@@r04333gyf@^0${f@9M0f@hfff&+0X%f@4333)1hfff2)f@4333s 1=(f@ 1hfff2)f@4333s 14333(f@1hfff~'f@hfff%1%f@4333)1&f@43331'f@433331=(f@ 1XT_@3333E?_@?_@ffffR?̤_@ffff?x_@?̼_@?T_@3333?hfff_@3333?_@3333E?_@ffffR?`ZT4333C8@xTT8@ ̠TT`8@ffffZT8@ZŤ8@ffffBXT8@ffffBXT43338@XWT4333C8@mUTdfff8@xTT8@̠TT`8@P3333K6T̼8@@2Tdfff8@)3Tdfff8@5T`8@3333K6T̼8@5T̼8@ffffZ2T08@@2T43338@)3Tdfff8@@*T8@U'T8@3333 (T8@*T8@(Tdfff68@U'T8@3333 (T8@$(4333K\@C3c@hfff&j%42`@4333?&`@4333?4333G`@?y`@@?hfff*`@4333@d_@\@x_@!@a_@&@_@'@̼_@ @4333z_@4333&@Qd_@@@̬]_@e]@4333Ahfff6I]@PA4333c7]@hffffA!]@4333s~A ]@4333nAhfff&\@4333eA4333{\@hfffVCA)\@6A\@hfff&Ax\@|'A0\@+A\@ A\\@4333AL\@̌Aq\@@4333\@hfff@T\@hfffF@\@\@hfff\@@4333\@4333@\@hfff@hfff\@@\@hfffF@hfff\@`U@\@\L@hfffN\@4333H@l\@hfffV3@<\@L?4333\@̱?\@4333sM?hfff\@9>Q\@>\@y>hfff\@Y7>\@4333 >4333K\@=4333+\@,=`\@o=hfffֶ\@$=8\@,<̥\@̌<\@̌:V\@4333S5:U\@hfffF :V\@:X\@hfff:4333[[\@43332:4333b\@o:9e\@:n\@Y:q\@43333:u\@hfff&:̔v\@hfffU:hfffq\@hfffA:hfff6m\@@9:4333e\@@:4333`\@9LY\@9hfffnY\@̬94333\\@`9hfffb\@ 9g\@L94333m\@̬9l\@4333:k\@9 :Dl\@y:Qn\@9!:4333q\@hfff(:s\@hfff:hfffv\@4333:Px\@4333:P|\@9B:|\@LR:ȅ\@hfffd:4333C\@hffffV:hfff΍\@J:4333\@Y :\@9hfff\@9\@y9hfffr\@l*9hfffj\@ 8hfffnd\@hffff89`\@984333Z\@hfffo8hfffnZ\@hfffA8hfffZ\@!8Y_\@74333cc\@74333sp\@ k7hfffq\@4333SH74333p\@43333.7r\@ 74333r\@ 6$q\@64333k\@hfffF6r\@hfffU6hfffV}\@l5hfffv\@hfff5hfff\@ 5 \@hfff5\@l.6|\@hfffR6\@̬{6!\@4333t6l\@hfffl6,\@lW6\@4333B6̔\@433335d\@54333\@hffff5Y\@l51\@}5hfff&\@̬[5`\@hfff>50\@54333]@hfff5hfff&]@44333;-]@`4hfff5]@hfff44333?]@Y4hfffH]@43334̼R]@̌4Z]@4k]@̌4Du]@43334hfff]@hfffFk4]@ `4T]@S4]@ C4]@3hfff]@hfff&4]@ 44333#]@Y3 ^@43333^@̌388^@@3hfff?^@3K^@Yz3̜U^@hfffQ3hfff_^@@3e^@hfffF2\h^@ 24n^@433324333;r^@433332\u^@ z2hffff^@hfffd2hfffƐ^@(24333^@hfff2^@4333s 2^@433311^@43331hfff>^@hffff1p^@̌1)^@̬m1A^@LP14333^@"14333K^@433331hfff^@l0q^@`0D^@l04333^@hfff0i^@̵0hfffF^@l0̬^@n0 ^@4333o04333^@ 0^@43330^@l 1hfff^@4333J1̤^@4333h1̜^@Y|1 ^@Y14333^@hfffx1^@Yj1^@L81hfff^@,1^@hfff1^@ 1^@43331hfff>^@̌14333#^@̌ 10^@1hfff^@433330hfff^@,0hfff^@`0^@hfff&0hfff^@ 0̌^@@04333^@hfff0hfff&^@l04333c^@}04333^@4333w04^@̌x0^@4333j0`^@4333W0^@Y90p^@ .0hfff^@hfffF10^@a04333^@4333]0hfff^@4333sI0_@4333C0hfffN_@`G0 _@hffffU09_@hffffc0_@a04333!_@,e0P,_@b0h1_@4333g04333s0_@4333_0*_@V0$_@4333T0hfff_@4333U0_@hfffL0_@30hfff_@,"0_@433304333 _@hfff04333$_@0q%_@hfff&04333&_@/)_@̌/hfff~)_@hffff/4333&_@83333/hfffF _@hfff/4333#_@/l_@83333/a_@8333s@/!_@8333.\ _@hffff.#_@.<)_@8333s.8,_@hfff&.+_@@.4333S,_@.0_@ .hfff6>_@. A_@.D_@8333s.D_@.4333D_@ .A_@L.0:_@.hfff~8_@@.!9_@hfff&{.43335_@LR.:_@L8.4333>_@6.hfff~A_@$.A_@ .qB_@.4333D_@̌.4333L_@@.YS_@83336.4333V_@Y=. X_@8333s,.X_@.O_@-4333SO_@̿-4333K_@̌-pK_@8333m-hfffQ_@L-hfff6R_@ +-xU_@hfff-hfff[_@-<`_@hfff&-4333e_@hffff,4333Kf_@hfff&,hfff6f_@hffff,,h_@hffff,m_@83333,k_@hfff,̔k_@,Xj_@-1l_@ -hfffVm_@-4333Co_@,4333st_@83333,4333u_@Y-hv_@1-y_@hffff<-̌|_@8333s -4333S_@83333,_@,hfffނ_@hfff,hfffn_@8333n,t_@hffff^, _@hffff:,4333_@̌!,4333s_@Y+hfff_@Y+4333ˋ_@ ,4333_@ :,4333_@S, _@E,̬_@,̙_@8333 ,_@hffff(,hfffv_@hffffR,hfffv_@-,hfff_@ +_@+4333_@8333+hfffι_@}+4333c_@8333+Y_@+_@+I_@,_@8333s0,_@hfffc,_@L,hfff_@hffff,hfff`@Yl-a`@hfff-`@-4333`@hfff&-4333`@ -.8`@.4333`@.`@s.t`@|.hfff&`@٘.I`@}.E`@Ym.̈`@Y4.`@.`@- `@8333-hfffv `@hfff-4333 `@- `@hffff-4333G`@8333s-l`@̌-hfffV`@ُ-!`@-H%`@hfff-4333%`@hfff:.&`@ R.̜'`@ ).y'`@hfff-(`@83333-43333,`@-.`@-%2`@@.hfff2`@hfff4.P4`@̌G.43334`@8333s,.hfff4`@ .43333`@ -4333c4`@8333-hfffn8`@hfff-(;`@hffff-hfff9`@8333s-8`@@-433375`@q-Y3`@LK-4333[6`@̌&-U6`@hffff-t3`@̌-|/`@,hfff,`@8333,.`@Lm,3`@hfff,43336`@+6`@+`8`@8333+A9`@p+hfff9`@L+:`@Y%+4333>`@+4333SB`@*YD`@̌*`F`@hfff*PH`@*QD`@J*hfffD`@L*aE`@83333),J`@ )L`@83333`)̈N`@83333Q)LR`@hfff&T)hfffS`@83333K)S`@̌(S`@8333(U`@Y(hfffW`@(X`@([`@)hfff\`@ )@\`@(hfff[`@(̜^`@L(``@̌(hfff``@̊(``@m(hfffva`@a( g`@[(hfff~h`@8333<(Ti`@"(hfff j`@1(hfffj`@̌k(hfffn`@̍(=w`@hffff(hfffj|`@v(~`@( `@(Յ`@83333t(hfff`@@_(`@8333sz(4333'`@(!`@LZ(hfffV`@ E(hfff`@8333s8(̤`@B(4333ϖ`@83333?(,`@(T`@'(`@8333'`@Lt'4333`@LL'4`@hfff&`@8333s&hfffF`@Y'T`@ &hfff:~`@8333s&Qz`@ٚ&hfffy`@8333&~`@\&`@̌d&hfffb`@8333&`@L&T`@hfff&&43333`@@z&h`@8333sh&`@8333sr&Ց`@ٻ&ٕ`@'`@&m`@@&`@̌&̠`@&̨`@Y>'`@Li'e`@t'hfff.`@L'`@hfff'`@hffff'4333`@'hfffv`@Y'hfff`@8333(<`@83333 (4333[`@(8`@hfff&(hfff^`@' `@(Y`@4(4333`@83333c(`@q(hfffF`@hfff&B(4333`@ (`@̌'4333;`@hffff'T`@8333'̄`@̦'hfff`@'`@'hfff`@hffff'hfffv`@L'̼`@ (4333{`@M(hfff`@8333sk(hfff`@{(hfffN`@t(p`@hffff[(hfff`@hfffM(Ea@b(a@hffff(hfffa@L(hfff*a@(4333Wa@(4333 a@8333s(4333W a@̌d(4333a@X(̤a@hffffC(0a@hfff&'Ia@L'4333a@hffffD(a@8333s(a@83333p(a@8333|(Qa@hfff&(4333/a@̌)a@hffff)hfffVa@)a@8333*a@Ls*hfff. a@hfffx*hfff a@LZ*i a@hfffF*4333oa@8333sT*Pa@8333\*̬`@̛*`@@>+hfff`@̞+4333`@hfff+D`@hffffN,`@hfffw,4333`@,hfff>`@+-$`@83333P-4333`@83333-hfff`@-`@hfff-`@83333.̤`@R.hfff`@Y.hfffa@̌.La@̌.4333S a@hfff#/a@O/̬a@i/a@c/̜a@hfffY/hfffa@Y/hfffa@^/4333ga@/a@8333/4333Wa@/a@/hfffa@hfff/ a@8333/"a@8333/h%a@/)a@00a@hfff*0̄6a@hfff;0hfff6=a@z0hfffJBa@433304333Ga@hfff0hfff.Pa@ 0Ta@ 0@Za@4333S0P`a@90ca@1da@1hfffda@4333*14333ga@ T1na@la1va@l1|a@1E~a@4333S1%a@1a@4333S14333[a@1a@4333314333a@j1hfffNa@L11a@14333a@l04333Sa@hfffv0aa@80hfff.a@0̔a@83333/4333sa@hfff5/4333a@ d.a@.Pa@-a@8333,4333a@,a@@N,hfff"a@̌ ,aa@+4333a@Y+a@̌+4333ײa@hfff*4333a@hfff*hfffa@ )a@)a@8333)hfffa@8333s)4333sa@)a@z)hfffa@\)4333a@:)Da@L()la@")a@ )a@(a@(ȹa@)(4333ۻa@'43337a@ (a@(a@'4333sa@'La@8333sC'hfffra@hfff&4333ca@hfff%hfffra@8333%a@%4333a@hfff&j%4333oa@hfff&j%\a@%a@̌%a@8333%4333#a@Y&4333a@ ;&̴a@̌m&4333a@hfff&&4333Ka@L&8a@C'a@̌'4333a@8333'a@̌' a@hfff&'a@8333'a@&(Ya@V(4333+a@8333s(4333a@hffff(a@8333(!a@(Da@hffff(a@hfffG)̸a@hfffx)a@hfff&)hfffba@hffff0*a@̌*a@hfff&*̌a@hffff{+4333a@+hfffa@hffff+a@@T,4a@,Pa@Y,4333a@,4333cb@,4333b@,4333K b@ ,4333#b@8333v,b@,̼b@hfff&,Mb@@Y-"b@-hfff%b@-4)b@hfff-(b@ . (b@hfff1.hfff(b@hffffh.`)b@̌.̰(b@ .4333/+b@83333g/4333,b@/.b@4333s0u.b@hfff<04333-b@4333N0hfff-b@g0/b@90̘1b@hfff0l4b@04333'8b@hfff&0:b@ 00=b@0hfff c@9>hfff c@Y>!c@9>̰ c@,?hfffnc@4333s5?4c@4333So?%c@L?c@@4333sc@@c@4333C*@ c@433338@ c@\G@4333c@M@4333c@V@hfff^c@V@hfffNc@hfffY@c@`\@Ac@4333`@b@i@4333b@hfffVs@4333cb@@hfffrb@hfff֙@hfffb@hfff@4333{b@y@b@ܲ@4333b@4333@pb@@Xb@\@Tb@4333@hfff:b@@b@̜@b@hfff@tb@hffff@4333_b@@hfffb@̬Ahfffb@4333Ahb@Ab@A4333b@hfff&Ab@|1Ab@4333?ALb@hfff_Ahfffb@43333rAb@hfff6A4333b@hfffAb@̜A1b@APb@\Ahfffb@ЉA̔b@4333SAb@9Ahfffb@ܓA4333b@AMb@̼A(b@lAb@hfffAYb@hfffVA@b@4333Ahfffb@A.a@0Ay/a@hfffF A/a@A4a@hfff@8a@@=a@ @4333?=a@ @hfff;a@43333@hfffF;a@4333@=a@4333#@4333?a@@8=a@hfffb@hfff;a@A\`@hfffEAhfff`@LA̬`@ MAhffff`@`JAhfff`@43330A`@hfffA)`@hfff6A`@@4333`@@X`@̌@p`@,@`@@P`@hfff@hfff`@@hfffr`@hfffV@`@ @`@4333S}@hfff6`@4333_@`@]@D`@4333]@`@PT@hfff~`@hfff6F@Ľ`@43334@,`@i"@hfffJ`@hfff@̤`@i@Ѭ`@ @ɦ`@hfff@<`@?`@hfff?4333[`@@hfffކ`@@w`@@?̔l`@l?hfffi`@`?̘d`@hfff~?``@hfff&?4333W^`@ِ?hfffY`@?4333'D`@@?42`@4333?((f@C2]Uf@ P1.eRf@4333ӿ1Sf@43331hfffRf@hfffƦ1hfffPf@hfff1hfff&Mf@hfff1Jf@@p14333If@4333so14333Hf@̌j14333Hf@9_1Gf@@T1Ff@ P1Df@V1hfff>f@hfff&e1,:f@4333sc1hfff3f@hfffv1$0f@ 1hfff,f@43331hfff,f@14333-f@1hfff&-f@43331X,f@hfff&1+f@91hfff+f@14333*f@1hfffr(f@ 1((f@91hfffn(f@1H*f@24333C,f@hfff2hfff.f@4333%2]4f@Y.2hfff8f@43333824333;f@@A24333>f@C2 Bf@@2 Ef@ @2Gf@/2Jf@"2̌Mf@2Nf@4333#24333Of@2Sf@hfff2]Uf@43332Sf@1hfffRSf@1eRf@4333ӿ1  1d@L`64333#d@9$4A(d@43336hfff>d@Y6d@5d@4333s5hfffd@hffff5̴d@ 5d@{5hfffbd@@q5Td@c5Td@ ]5ɸd@O55d@hffffD54333d@4333.54333Od@5td@4333 543333d@94-d@43334Щd@433344333d@hffff44333#d@43334̔d@48d@Y4ђd@4333a44333d@@H4d@4333O4yd@?4d@9$4Ld@@,41d@;4d@4333SG4d@ N44333d@4333Y4hfffބd@9j4hfffnd@z44333d@4d@@4̌d@@44333d@hfff44333d@4hfff^d@35d@43333J54333Sd@̬S5hfffd@hfff5d@54333d@4333s5سd@hffff5ͷd@5Yd@433354333۽d@4333s54333d@hfff5d@ 5̔d@` 64333d@43336hfffZd@4333'64333Sd@926d@hfffF;6d@̌A6d@?6hfffBd@C6d@L`6d@[6d@4333sZ6 d@hfffR64333#d@4333B6(d@43336 @hfff_@̐쿚`@@ehfff_@hfffv4333_@١?hfff_@2333?4333[_@p?4333_@?p_@?4333_@ffffV?`_@ffff?̬_@?I_@?q_@3333y?_@$?hfffN_@?l_@@ffff=?hfff_@?`_@z?8_@3333'?̴_@%?hfff_@3?hfffn_@?_@3333u?_@L@hfff_@e@hfff*`@@hfff^`@ 333A@`@@_@@ffff!?_@3333?_@S?4333_@@ffff?Y`@33338?hfff`@V?`@@ffffT?``@N?hfff6_@3333?_@̚?_@8?4333_@3333E?_@?4333[_@^?_@$?4333_@n?4333c_@̠?4333_@?hfffv_@3333?_@@ffff?`@?hfff`@@ffff?$`@@ffff?hfff`@@ffff? `@?hfff`@i?hfff `@G?A`@?4333`@3333)?̐`@q?`@@ffffk?`@@ffff?|`@̳?hffff`@@ffff?4333w`@V?hfff `@3333? `@?4333;`@ffff?4333W`@3333{? `@3333q?4333`@3333?`@C?`@?!`@?`@?`@3333?`@,?`@ffff?4333K`@?I`@3333?hfff `@x?4333`@3333?d`@3333?4333_@33333?)_@ ?_@3333?4333_@?_@h?a_@D?_@Y?̔_@Ͽ`@gfff߿`@i̴ `@3333꿚 `@̐hfff`@3333x`@4|`@X`@_@4333ۿ̜_@Pؿi_@9ӿ4333C_@hfffο0_@Ŀhfff_@hfffv 0@1Q@ȞQ@hfffTHchfff~Q@HT@O@3333>T@ P@?T@hfff P@IBT@x P@ffffFT@`P@ffff>IT@P@ffff6KT@4333$P@LT@T3P@LT@hfffAP@JT@KP@8IT@4333SP@,FT@4333sXP@CT@4333 WP@ffff@T@WP@=T@hfff[P@̐;T@hfff?P@h4T@#P@X0T@ٯO@ffff,T@4333O@,T@hfffFO@3333-T@hfffVaO@0T@BO@4T@KO@6T@hO@49T@4333ӎO@=T@ lL@̨T@4333M@̜T@hfff6L@T@L@ffff T@hfffL@h T@hffffL@ffffT@L@̔T@hfff֗L@\T@̬L@ffff~T@lL@T@L@̜T@L@lT@=M@ffffT@`|M@T@hfff֎M@T@4333M@3333T@2M@fffffT@hfffV$M@3333T@4333$M@T@4333 M@ffff T@4333M@ T@hffffL@3333T@iL@̨T@hfff6L@T@`l %@i^@@b%@^@0333%@hfffF^@̥%@^@l%@hfff^@`fff%@4333c^@`fff%@0^@ &@^@`fff&@hfff^@`fff;&@^@d&@hfff^@ْ&@9^@`fff&&@4333^@0333&@!^@03333'@4333^@9'@^@0333S"@4333S^@`fff%@3hfff^@%@l^@`fff%@1^@03333%@^@%@hfff^@0333%@^@ %@^@ %@hfffV^@̌e%@^@4%@^@Y%@I^@0333%@̌^@`$@t^@l$@i^@@$@^@,$@^@0333#@|^@̌#@|^@Y#@,^@L#@<^@#@^@`ffff#@L^@`fffFc#@^@03333"@^@"@^@"@p^@ "@hfffv^@"@^@`fffF7"@^@ "@4333#^@0333S"@`^@0333 "@Q^@-"@4333^@`fff&>"@hfff^@@o"@4333^@"@^@̌"@̼^@`fffƶ"@hfff^@Y6#@^@0333Q#@i^@`fffm#@hfff^^@#@^@#@ ^@9$@4333^@?$@^@$@4333 ^@$@4333^@`fff&*%@hfff^@0333R%@4333S^@%@^@0333ӡ%@hfff^@%@_@0333$@hfff.Q_@`fff'@4hfffL_@$@4333L_@0333s+%@J_@`F%@)H_@0333^%@hfff^E_@0333sq%@)B_@%@@_@`fffF%@4333B_@`%@hfffB_@@E&@4333A_@`ffffl&@̜?_@`fff&@̄;_@`fff&@̌4_@`fff&@4333[._@`fff&@<)_@&@hfff$_@`fff&@hfff#_@@&@4333 _@`fff&@hfff_@&@_@̬'@)_@`fff'@_@&@hfff._@̬&@l_@̽&@Y_@L&@4333_@%@hfff. _@0333%@hfffn'_@`fff%@i*_@`fff%@hfffF/_@l%@Y2_@0333%@3_@̬v%@3_@L]%@hfff6/_@`fff&$@2_@0333$@43332_@0333$@1_@ V$@4_@D$@hfffv;_@1$@4333A_@0333$@A_@`fff;$@P@_@`fffd$@43333?_@03333$@B_@$@hfffF_@`fffo$@ I_@a$@hfffH_@x$@I_@y$@hfff6P_@0333$@hfff.Q_@̌$@̤P_@$@hfffL_@$@_@`ffff&@o_@`fff&%)@5hfff&h_@w&@̴d_@y&@De_@&@f_@`ffff&@4333e_@`fff&@hfff^`_@`fff'@y__@L0'@`_@0333O'@__@0333sm'@hfff]_@ '@8]_@0333'@4333`_@0333(@hfff6`_@`fffE(@Hb_@b(@^_@(@)Z_@ّ(@4333V_@`fff(@hfff~T_@`fffƤ(@hfffT_@@(@S_@(@TO_@`fffF)@̜I_@`fff&%)@5_@0333)@hfff6$_@l )@_@#)@_@(@_@|(@hfff_@9N(@!_@̌((@$_@9(@P+_@0333 (@/_@'@hfff2_@'@̌4_@`fffF'@8_@ '@;_@`'@hfff?_@`fff'@4333?_@g'@hfff>_@`fffF'@:_@`fff'@<_@0333S&@1B_@&@E_@ &@I_@&@N_@`fffFJ&@S_@H&@4333[_@`fff9&@43333h_@C&@)k_@=&@o_@`ffff&@o_@̬%&@hfffm_@`T&@hfff&h_@w&@^@`fffp(@b^@y +@74333^^@)@4333c^^@)@X_^@`fff *@yb^@-*@ta^@,C*@L\^@y`*@hfffV^@*@43333R^@̌*@L^@Y*@hfffG^@03333*@4333E^@L*@̔A^@*@>^@0333*@̔:^@̌+@X0^@hfff&*@-^@*@)^@hfff*@^@y +@hfff^@+@4333^@hfff&*@^@ *@^@hfff*@ ^@0333*@hfff&^@y*@4333^@@*@ ^@hfff&*@hfff$^@0333j*@)^@V*@+^@B*@0^@̌)@433331^@̌)@1^@`fffƔ)@2^@~)@̴6^@`fffFh)@9^@̬J)@:^@`fff))@;^@0333)@=^@(@4333C^@L(@hfffVE^@̌(@4333F^@0333s(@|G^@(@4333I^@y(@hfff&O^@`fffp(@|R^@̬(@T^@0333s(@hfffV^@L(@hfff^c@@333l4333S`c@mac@Lxfc@;̀gc@̬fc@hfffVhc@hfffkc@̬mc@!4333pc@@3333Rsc@lwc@shfffnxc@pffffVhfffyc@@333.hfff|c@ 4333G}c@/}c@@3333̤~c@L4333}c@B4333;|c@pfffhfffRzc@b@pffffT=$c@ffff2 c@@3333l, c@̧ 4333 c@+ c@ffffH c@@3333= c@ b@b 4333b@@3333hfffb@@3333hfff6b@@3333hfffb@4333?b@ffffhfffb@Pb@ib@ffffb@&hfffrb@b@@3333!b@=hfffb@@3333=4333#b@̡hfffb@Kb@4333b@ffff: ab@ 4333'b@ffff3 hfff"b@ hfffc@ \c@ hfff&c@ c@̨ hfffb c@ffffX hfff&c@ffffac@Lc@ 0c@lc@c@pffffc@4333+c@@33334333c@ ̈c@pffffTc@hfff c@Lu!c@@3333N4333k!c@#c@=$c@pfffh#c@pffff c@@3333l4a@ hfff_a@@333hfffXa@̏4333gQa@@333tIa@hfffEa@@3333hfffBa@C=@a@:a@5a@@ 4a@8333 6a@ hfff;a@hffff 4333s?a@̌ 4333{Ia@8333s !Qa@ 4333Sa@̌e hfff&Ya@@ 4333\a@Lhfff_a@^a@Z\a@pfff Ya@hfffXa@̏p0_@̄[`@@3333IKX`@Y hfffV`@ffffJ yU`@! ̈T`@~ T`@ `@" e?`@̂ @`@@3333 H`@ffff hfffK`@ffff hfffR`@ 4333Y`@̄[`@ 4333[`@@3333D X`@Y _@̖_@hfffv_@ffff 4333_@| _@ffff8 hfff_@ffff _@T _@4333_@hfff_@_@ffffhfff_@ffff/ hfff_@4_@ffff _@@3333] ,_@ hfff_@@3333^ 4333c_@. i_@ 4333_@ffff P_@ffff _@ffff,_@̖a_@ffff4333Ӳ_@@3333P̬_@ffffC8_@q_@^ hfff_@- _@ffff _@ ̌_@ hfffv_@ffff hfff]@8333!a^@/ V̜^@M ^@ 6 ^@/ hfff^@@ ̌^@83333_ 4333Ӻ^@q hfffn^@ٛ ^@̴ ^@ 4333^@8333 ^@8333s 4333^@8333!ܝ^@"!hfff^@3!^@8333A!hfff֐^@8333?!4333K^@L I^@ 4333}^@ Yz^@ 9w^@hfff o^@hffff!̼k^@!g^@hffff !c^@̌&!hfff_^@+!4333s\^@'!hfffW^@ !̴Q^@8333 G^@ hfff@^@hfff& hfff8^@@ hfff0^@ i-^@ hfff'^@{ #^@ 4333^@@ 1^@8333s ^@ 4333^@hffff Y^@L hfff]@ ]@hfff ]@8333 hfffn]@@ @]@8333 !\]@$!hfff]@8333>!̴]@83333e!]@8333!4333C]@!43333]@!hfff^@̞!̼^@̍!4333s^@!4333;#^@̌!43331^@!hfff>^@L!AB^@8333!4333E^@!H^@!hfff6L^@!4333U^@8333s!Z^@83333!_^@ٟ!ie^@hfff&!4333g^@hfff&!i^@hfff&!@o^@hfff!̬u^@!hfff^@L}!4333^@hfffu!4333^@z!̴^@hfff&x!^@8333ss!q^@hfff\!hfff^@hffffK!4333^@833339!4333{^@1!1^@!^@Y ̼^@hfff& ^@ hfff&^@L a^@ ̜^@M \]@̌$I5^@Y".4333,^@hffff#|(^@hfff#hfff#^@hfff&p#< ^@Y#d^@̌J#X^@83333O#^@8333K#^@4#^@8333#hfff&^@@#^@hfff"^@ٿ"4333S]@hfff"4333K]@Y"4333s]@"4333]@"X]@8333s"!]@Y"]@"]@"4333]@hffff"]@8333"\]@hfff #̌]@L%#]@8333=#hfff]@̌V#x]@8333i#4]@hfff&#]@̊#]@hffff#x]@ #]@#]@#hfff]@Y$4333S^@hfff>$D ^@8333sf$Y^@ |$@^@hfff$4333^@̌$4333#^@hfffx$(^@8333t$̬,^@i$x3^@̌7$I5^@83333$42^@#4333,^@hffff#hfff&1]@83332"L]@- `hfff]@ 8]@hfff hfffF]@hffff ]@ Բ]@ ]@̌ ]@8333s hfffF]@8333s 4333]@ )]@8333 hfffV]@8333s hffff]@ ]@hfff& ]@ hfff]@hfff 4333]@8333 4333]@و ̤]@L ̄]@> z]@- w]@hfff3 hfffVp]@̌L Ao]@h q]@َ hfff&t]@hfff& ~]@8333 $]@L ]@8333 hfffn]@L 4333#]@!]@ /!hfff.]@hfffM!]@8333L! ~]@t!)y]@hfffh!hfffs]@l!4333m]@L*!k]@hffff !,i]@83333!4333g]@L 4333Kd]@L []@8333 4333V]@hffff PN]@ ̌J]@ 4333D]@̌ =]@!8]@@!q5]@!H3]@hfff&2!hfff2]@LT!̤3]@83333!i1]@hfff!hfff&1]@83333!hfffv2]@@"7]@hfff"4333S=]@'"C]@83332"QJ]@8333s#"tM]@8333s"hfffP]@hffff "4333T]@@"4333X]@Y"`]@"4333n]@!r]@!hfffw]@hfff!hfff]@!4333k]@@!(]@Y!]@!@]@hffffY!]@Lh!hfffv]@8333s!4333S]@!]@!]@8333!hfff]@L!4333]@83333!I]@8333!̌]@hfff&!4333[]@hfff!hffff]@!̼]@̌x!hfff]@l!й]@g!hfff]@m!,]@{!hffff]@! ]@v!4333]@k!L]@V!x]@hfffA!]@3!]@83333!hfff]@ hfff\@hfff!4333.]@̌h 4333]@̌h y]@y ]@hfff& ]@8333 ]@9!]@hffff}!hfff]@̇!hfff\@!4333\@L|!hfff\@hffff!\@8333!hfff]@ !Q]@!̌]@8333!$]@hfff!%]@8333!#]@8333s! ]@Y!4333)]@L:!4333.]@ 4333.]@ ,]@8333 h)]@ 4333]@̌h 8\@8333!4333\@hfff! $)\@hfffj \@8333sO hfff\@; 9\@̌" 4333\@hfff! \@LY \@_ P\@] hfff\@hffffA hfffF\@8333; 4333k\@hfff&= \@hfff&U hfff\@8333m \@̌ \@ٰ hfff>\@8333 hfffή\@8333 \@hffff hfff\@hfff& hfff\@hffff%!4333\@LB!\@d!\@8333!4333\@hfff!hfffF\@8333!hfffn\@!\@!\@Y!\@ك!\@S!\\@@;!hfff\@@!T\@ 4333\@8333s 8\@hfff& )\@hfffj HZ@aZ@ffff94333kZ@\Z@ffffYZ@@33334333#Z@ Z@Z@Z@}~Z@ffffhfff>zZ@ffff4333;tZ@4333nZ@̊IpZ@4333lZ@ffffjZ@hZ@ffffxeZ@mi]Z@2iZZ@WZ@ffffPWZ@H̼XZ@@3333WZ@S@B=8@yS@ 7@XwS@7@3333xS@T7@M}S@7@tS@hfff&7@3333S@Y]7@ffffS@8333s7@̐S@hfffZ7@S@hfff7@ES@hfff&6@ S@ 6@3333[S@hfffs6@ffffƍS@̬L6@ffffS@833356@3333S@ 6@S@5@S@̬5@ S@lt5@ffff>S@ 5@S@\4@ffffS@Y:4@̔S@l_4@ffff^S@l4@3333ךS@@4@ffff֔S@8333S4@3333#S@L4@S@8333 5@ɃS@55@ffff^S@833335@3333{S@5@̠zS@Ln5@sS@̌U5@dqS@`@5@mS@y35@gS@hfff4@ffff.dS@4@3333k]S@hfff 5@8\S@,5@_S@̌6@3333`S@,A6@aS@8333e6@|dS@r6@dS@̞6@,cS@8333s6@lcS@̌6@̄bS@̭6@ffff`S@hfffFq6@ffffz[S@8333|6@ WS@hfffx6@0US@Lm6@8TS@6@QS@@6@ffffQS@hfffF6@SS@hfff&6@3333WS@83337@̤XS@a7@3333WXS@8333S7@̰YS@8333s7@3333]S@Y7@3333_S@y7@cS@8@\hS@9!8@ jS@8@lpS@L8@3333guS@=8@yS@# 4333M@ffffT@hfff&O@%9T@!, O@ffffv7T@N@33338T@yN@%9T@hfffN@57T@hN@ffff4T@4333=N@x3T@hfff#N@3333K3T@4333N@5T@ N@3333O6T@M@33335T@M@A4T@4333SM@ffff&2T@`M@ffff1T@yM@ffff-T@43333M@'T@4333M@ffff$T@hfffM@`!T@hfffVM@ffffR T@,M@T@9M@̌T@#N@̤T@4333s\N@T@N@ffffT@N@M T@yN@<"T@43333N@ffff%T@4333sN@3333w&T@4333 O@|'T@O@+T@̌O@.T@hfff&O@33332T@yO@l5T@, O@ffffv7T@$@hfffsF@3333T@WH@ffff6T@%iG@#T@̌G@ffff&T@`G@3333['T@hfffG@&T@4333G@3333++T@4333G@3333,T@G@|/T@hfffFG@0T@G@fffff0T@̬H@3333*T@PH@ffffF(T@WH@3333(T@WH@-T@FH@1T@ 9H@3T@0,H@ffffj4T@4333#H@4T@4333#G@33334T@4333G@ffff6T@G@ffff6T@4333G@33334T@IfG@U0T@)G@ /T@F@ffff)T@hfffsF@3333'T@F@Q&T@4333ӱF@#T@hfffF@]"T@ F@ffffr$T@hfffG@"T@G@ffffT@G@3333T@hffff0G@<T@AG@3333oT@OG@ffff"T@VG@#T@iG@#T@%|RG@ffff:T@I@X;T@?hfff6I@̨/T@hfffvuI@8T@fI@:T@97I@L:T@#I@X;T@I@ ;T@H@a7T@hfffFH@4T@H@3333-T@H@)T@hfffH@#T@Q@p(H@PQ@H@hCQ@hfff I@HQ@ I@HFQ@ I@3333gBQ@<I@3333CQ@9$I@EQ@4333!I@KQ@iI@tPQ@hfffH@SQ@4333ӜH@`Q@'X̌\@̘R@,L\@PR@P\@tR@hfff&S\@LR@V\@3333R@X\@̠R@QR\@9R@<\@R@h\@ffff"R@+@a@3333zR@hfffa@R@:@A@lA:@ffff.A@hfffG:@aA@8333sL:@aA@Q:@ffffVA@I:@ffffA@*:@A@-6@ffff&B@8@xC@5hfffv8@3333C@8333\8@C@F8@)C@Y88@X+C@08@Q;C@hfff68@3333@C@ 38@@EC@'8@LKC@hfff 8@SC@Y8@3333UC@83337@WC@@7@aC@7@ffffbC@hffff7@ hC@8333x7@lC@Yj7@̴zC@ P7@xC@B7@3333C@8333S%7@XC@6@K@@333s(@K@)@|K@pfff&)@K@@333s$)@̬K@@3333#)@|K@@333 )@K@)@K@7)@9L@L()@33333L@@3333 )@̬ L@@(@̌ L@(@L@p(@0L@L(@̬L@'@K@Y'@K@'@̬K@'@ffffK@L'@3333kK@@333s'@K@@333'@LK@@3333'@K@a'@PK@L]'@,K@Ld'@ffff6K@pffffA'@3333{K@ &@3333K@L&@ K@pffff&@̌K@&@3333SK@ &@DK@pfffr&@K@pffff&@K@@3333%@3333[K@&@|K@$&@̌K@@333=&@K@@3333=&@tK@̌A&@3333sK@pfff&a&@K@pffffW&@K@&@3333+K@ٞ&@3333SK@L&@|K@pfff&@3333K@N'@K@d'@IK@@h'@3333K@z'@y|K@Y{'@)uK@'@bK@(@\hK@@#(@3333[tK@pffff%(@ffff}K@1̷#@ffff>K@@333s%@qK@ %@3333K@pfff%@K@%@K@@333s%@33333K@pfffy%@!K@pfff_%@`K@LJ%@ffffK@>%@qK@%@ffffnK@$@K@ $@3333K@$@0K@ #@̄K@pfff#@3333K@̷#@K@@3333#@LK@L#@LK@@#@3333K@Y$@@K@@333$@ffff>K@pffff?%@ffffK@ %@3333K@2(@C@̱ @9C@" @3333C@) @!C@E @C@ @AC@̖ @ffffC@V @0C@P @LC@ @C@E @9C@=@3333CC@G@3333kC@ffff@yC@@9C@'@3333+C@@ffffC@@3333+C@ffff@C@@1C@̚@dC@@PC@(@3333C@f@IC@ffff3@ffff&C@@3333@C@< @C@@3333 @|C@X @C@@3333 @ C@@3333Q @ffffFC@̱ @PC@ffff @pC@* @ffff~C@̼ @3333C@ @3333C@3@(^̙Rp^kR%8.^ pR_^hfffnRffff}^hfffmRffff^kRD^kR^kR-^kR^hfffFoR̬^dsR(^uRffff6^4333[vR8^4333uRu^hfffvR^hfffvwR3333^4333}Rp^Rffff^^hfffVR^ RԲ^0R^hfffR^R0^aR3333^TR3333^hfffRX^̙RffffC^hfffR(@^4333RL@^hfffRTB^RffffvC^4333R8A^RT?^ Rp^hfffNR^{R33333^hfffvR#^4333cpR8.^ pR4Hu_dRffff:^QRF_yeR3333_mR3333_\nR_nRh_4333snR̴_PkR_jR_iRffffJ_jRt_kR_lR̝_4333oR0_sR3333_yRffffx_}Rk_DR(c_4333RffffZ_yR3333E_̬R33337_TR3333 _pR^4333cRffff^dŘ^qRffff^ĊR^4333Rffff:^Ry^hfffR3333^4333R3333G_hfff&~R3333 _hfffn|R3333o_ zR̰_XxR9_`uR3333"_XoR̄'_hfffoRp,_oR?_4333uRffffF_tR\N_@sR3333T_rRffffZc_|tR)k_hffftRs_4333SsRv_hfffqRw_oRu_mRHn_lR1g_|mR3333Q_1lRP_hfffjRT_4333gR@`_dRc_TbRh_]R3333o_hfffYR3333v_XRt~_hfffVR-_hfff&TR_QRR33333_QRffff_̜RR̔_hfffSR_hfffRR _tSR<_hfffvXRu_\R̄_4333 aR@_QdR_yeR5ffffPhfff6TH`PS@PS3333gP4333CSffffPdS PS3333PSffffPSTPSffffPSPSPhfffS3333PSffff޹P4333+SDP4333KS3333{PyTffffrPhfffTPhfff6TP4333TffffRPtTyPTH`P4333SbPSffffePTS3333wPhfff6SPhfffSP4333+S@PS623338Mhfff>P2333sL4333O2L|PPLhfff^PLPL8P2333sL4333+P2333L4333 PffffLhfff6P0LhfffPhLhfffOLO2333LPffffLPLPffff~L4333SPIL4333sPLOL4333OffffL4333#OiL4333O|L,O@LhfffO MyO̤MhfffVO,#MhfffFO2333+MhfffFOd6MhfffVP23338M4333CP2MPffff-M\Pffff MhfffP2333M4333;P2333MI PM1 PffffM|P&M!PfffffMPMhfffP2333M̔PLLPL43333P2333L8P2333sLhfff>P̌LP2333SLTPffffLP2333LhfffP2333sLPffffVLlPffffL@PL|P70iPd5P2333kO̬P#̴O$P2333sO$PO PffffO\PdOhfffP2333O P(O̬P`OxP2333O4333PpOP2333O4333P2333SOPDO4333CPffffO,PffffO P3333 Phfff>%PffffzP(PiP̤,Pffff Pi-PXP.PtP01PffffO2P̌O̼3POd5POd3P2333{O.PǑ.PlO.PAO-PffffO+PffffFO'P2333kO$PvO RYRffff~ Y4333sR̨Yhfff^RYhfffRXPRXhfffRffffX4R3333kXIRXXRX #RuXhfff#R3333uXhfff#RfffffX #RdWXd!RPXhfffV!RAX$R:X4333%R3333s3Xhfff#RT,X #RPX$RXy#RffffX̔!RX4333 RWR3333W<RW4333RffffW43333 RWaRWRWhfffRffffXI R-XYRffff3X4333R8XhfffRffff>X43333R-XlRX4333RXPQ̈XhfffQ̤7XhfffvQEX4333kQIXR3333LX4333R|OXpRVX Rt]X RaX̌ R3333?eXhfffRM^XRleX|Q9tXhfffQ{XhfffvRXRffffBXhfff.RԅXhffffQ3333X4333{QP%%QhfffPffffn QAP3333QP3333gQ4333PffffQ4333PffffQP4 QPQyP3333CP\P PPffffrQPffff> QyP QhfffP5 QhfffPQ43333P4PXPffffFPhfffPPhfffnP3333PhfffPffffPhfff>PPhfffP3333PhfffPffffPP3333P4333۾PP PiPPP`P3333P4333P3333'PPffffP PQTPQ̜Pffff$QhfffP*QP3333.QPy4Q4333PffffFEQP}HQPHQPGQPffff>FQ4333Pffff>Q̄P9QP=fкQ@/f(Q@fffffjQ@3333 {f3333CQ@vfQ@|qfffffFQ@lfDQ@33335hfffffQ@cf(Q@3333_f3333Q@ \fffffQ@ NfffffQ@ffffPKfffffQ@Ff3333Q@HDfffffQ@AfQ@1?fffffQ@$:fffffQ@33332f3333Q@1fffffQ@/fffffQ@33330fffffQ@L:f3333SQ@Bf3333Q@3333PfffffQ@3333efffff&Q@3333MmfкQ@6pfQ@3333}wf0Q@fQ@>Ml'JYĽI9YLlIL4333cILhfffI,L4333SI|LLILhfffIffffL43333IlM̳Iffff.!M4333cI%MI2333[#MhfffIMIMI2333"MI2333-NJffff$Np JN4333CINIffffNhfff6IMhfffIMIM4333cIffff^Mhfff&IB |RhfffvI]R@ZHAR HR9HiRhfffH;Rhfff6HffffrR9H3333R4333H3333SR@HRHRhfffHRHffffR HRyH3333R,HffffvRHXRHffffR,HȴR4333HRH԰RhfffvIRhfffvIRIxRHRhfffHR4333H4R4333H]RhfffvHffff"R4333HffffRlHiR̼H3333RHR4333HyRHffffR4333hH3333R)bH3333CR̜`H3333R_HɯR̼ZHȲR@ZH\R]H RIeHľRhHffff~RqHRhfffzH`R4333ӂHffffR4333H3333sR4333H3333RHRhfffHRyHARhfffHR4333cH̸R9H3333RHffffrRhfffFH3333OR43333H3333RF(TR4333DFYRLLF|\R RFffffZRhfff\FiYRcFD P H@2333NH@DO0H@hOffffH@ffffOdH@Offff޺H@ffffnOH@PO3333˜H@YfOٕH@̼FOH@O H@2333NH@lNH@2333N3333ˑH@0NH@N3333KH@2333OH@ffffO3333H@QOH@mOLH@ffff^OH@`OffffH@LOH@iPH@PH@ffffP̄H@ PH@)P3333H@DO0H@EfffffNHF@Mffff>G@PM̄F@MF@ffffM|G@M3333G@̤MtG@MG@M3333kG@MqG@ffff Nffff^G@NG@ffff6N3333"G@2333#&Nffff'G@10Nl$G@ffff&7N G@@NG@JNffffG@ffff^ING@]NqF@9ZNiF@:NffffF@ffffvNffff>G@ING@ffffNNffff|G@hP4333a2@3333[pPf2@=xPq2@Px2@ffffPx2@`P4333m2@MPl2@HPdfffq2@̉P|x2@Py2@ffffPdfff~2@P̬2@2@ffff>hP4333a2@KffffVccL@ciL@}* c3333L@qcffffL@ffffcL@i c3333#L@ffff. c(L@ffff cL@^cL@ffffcL@GcL@ffff4cIL@cffffnL@̼cffffvL@ffff6cL@3333/cL@ffff"%ciL@:'c3333L@3333g%cL@3333%cffff~L@n&cL@h&cffffL@&c3333L@(cffff.L@m+cL@ffff~,c1L@̆-c3333L@.cffffL@3333/cL@ffff0cL@12c3333kL@ffff45cL@ffffB6c̄L@8cL@33339c3333L@:cqL@3333cL@@@c0L@@cL@3333?c,L@ffff@c3333L@Cc3333[L@3333Ec3333L@Ic̬L@bLc̔L@3333!Qc3333L@̊UcL@ffffVcL@3333VcL@8Rc3333[L@OcffffL@JcuL@YHc̴tL@Fcffff^{L@EcffffL@3333FcL@3333Fc3333L@GcffffL@Hc3333L@2Lc3333[L@Lc3333L@aJcffffސL@GcffffNL@PDcL@3333BcL@3333AcL@ffff@c3333L@3333BcЇL@KCcL@ffffBcL@?cdL@&`3333k+L@g3333`ffffxK@؋`3333 vK@` tK@`3333fK@ffff`^K@ffffL`4[K@ffff`H[K@`\K@3333c`gK@ffffr`ffffjK@3333`ffff.oK@`asK@3333K`YxK@ffffH`|K@3333`TK@>`3333K@)`̄K@O`K@3333`K@ffff`ffffNK@`3333K@``K@ `XK@`K@ffff`ffffK@3333_`нK@ffff`pK@3`K@`ffffVK@`K@ffff`̔K@ffff\`ffffK@x`K@ffffH`TK@̆`̄K@3333߆`iK@ffff>`pK@č`K@3333`(K@`ffffK@`K@>`\K@`ffff L@3333=`ffff L@ffff`yL@j`3333L@`3333L@X`L@3333`#L@~`(L@3333 `̬(L@`3333k+L@(`3333{(L@`L@3333i`L@`̤L@,` L@ffff*`ffffK@·`K@3333`̬K@ffff<`K@3333`L@3333A`dL@`K@ffff`K@3333ߩ`xK@N`K@,`0K@M`K@ffff0`|K@̰`3333K@B`3333K@ĵ`K@~`K@ffff`xK@ffff`3333K@Ϋ`0K@ffff`ffffNK@3333`ffffK@̧`ffff6K@ffffޢ`iK@`3333{K@ffff`xK@`ffffK@3333`K@`ffff&K@`3333SK@L`K@3333ˣ`K@ffff`̄K@4` K@`4K@ffff`كK@ڕ`ffffvK@t`̴K@ffffJ`ɒK@`fffffK@`ffffK@Ԓ`3333K@`tK@ffff`ffffyK@3333`ffffyK@3333`ffffxK@OxW`33339L@3333k`3333ˈL@,W`9L@ffffZ`{L@ffffV`QvL@=`ffff6pL@ffffʵ`fL@`ZL@`3333SLL@ƴ`ffff&BL@4`=L@J`h;L@ffff~`33339L@?``LL@̮`ffffnM@̢`M@`M@ffffv`M@ffff`3333(M@3333`d-M@`3333*M@ `3333!M@`ffffM@ffff>`M@`ffff M@!`\L@ffff>`ffff6L@`̬L@`ffffL@`3333L@`ȵL@m`L@3333`ffffL@ffff`L@`ffffƋL@`ffff^L@3333`3333sL@`3333KL@3333S`ɒL@3`iL@R2aL@ffff`ffff^"M@5ffff$`L@3333`|L@ffff`iL@3333y`3333KL@`LL@ffff`L@ `lL@3333`iL@`ffffL@ffff`3333kL@3333`L@R`L@ffff`L@`3333cL@f`lL@E`ffffL@ffffH`ffffL@`3333L@`L@̌`ffffM@3333`M@6`D M@`3333M@`M@ffffz`3333 M@N`M@`L@z`ffffM@.`ffffM@3333`3333[M@`M@`M@3333_`3333CM@/`ffff^"M@33337`3333M@3333Q`XM@`(M@3333a\M@a3333M@a3333 M@a(M@M aM@3333 aPM@ffffa3333 M@daI M@ayM@2apL@aL@ffff āL@saXL@`ffffvL@3333%`)L@ffff$`L@S%`3333%J@5`ԣJ@̆`LJ@3333`,GJ@`ffff;J@c`3333-J@`3333%J@`+J@3333u`9J@3333Q`aBJ@5`3333sOJ@`IxJ@>`fffffJ@3333`J@ffffr`AJ@ `ffffJ@ffff!`ԣJ@ffff!`̞J@̰"`J@#`3333J@%`3333KJ@%`ffff~J@3333%`3333{J@3333 #`(rJ@"`ffffFiJ@3333 `3333`J@3333`@VJ@3333`3333VJ@̠`(`J@`ffffaJ@̆`LJ@Tffff"`8J@3333]u`XK@:`8J@\`J@3333~`3333J@̲}`J@}`@J@t|`3333cJ@Fz`ffffJ@3333{v`AJ@u`3333K@3333]u`K@3333Ev`3333SK@ffff:z`ffff K@3333~``K@3333M`3333cK@3333Y`xJ@`G@(6O8=G@IWOffff:G@2333#[O33339G@d{O6G@O3333 6G@ffffO:G@0OffffAG@OAG@ffffnO@G@fffffO33333EG@9OGG@ffffVO=G@aO1:G@Offff;G@2333O8?G@O AG@O3333DG@ffffO3333CIG@̌O3333MG@ffffOffffQG@PAcG@OtG@ffffO}G@,OG@3333 P9zG@IP\sG@3333PjG@PffffvbG@PffffXG@PRG@P3333PG@̴P3333LG@P3333GG@Pt6G@3333CP3G@ffff&Offff>4G@2333O2G@O333331G@Oh/G@xO/G@2333O%G@ OG@OG@hOffffG@2333SOffffvG@ffffO3333G@OG@OLG@O\ G@HOffff%G@ffff>}Offff~(G@`Od%G@ffffƆO"G@ffff6OG@OPG@yO3333G@rOG@2333ӂOffffG@PO3333{G@ffffsO̼G@ffffnpO,G@ffffgOF@ _O3333F@2333DOF@1=OffffF@T@OG@EO3333G@EO G@FO<G@ffffVCOG@(O#G@O|-G@ Offff5G@2333;O 9G@ O̜;G@O\>G@W RffffID@ffffQffffD@5RD@ffff RffffD@ RD@eRD@,Rp|D@ffffRffffwD@!RuD@,%RffffuD@ Rffff6~D@ffffZRffffD@3333RffffD@RD@3333"RtD@(R~D@3333 5Rl|D@)BR̤{D@3333GR3333{zD@KRwD@QRLvD@ffffWRffffxD@ZRffffvxD@33337\RvD@1_RuD@dRffffuD@ffffgRffffsD@$iRpD@ffffiRDkD@ffff~lR\oD@ffffvpRffffjD@ExRTeD@3333}R\D@33337RqWD@ RQD@RdJD@t{RffffLD@3333xRhSD@fffftRffffSD@%sR3333 RD@HsRffffOD@ffffyRffffID@ffffqRffffKD@̼gRLD@ffffPRTD@NRdSD@3333oLR̼SD@ffff0RcD@D+R33333eD@ffff#R3333iD@eR pD@R3333srD@ffffQćD@@R3333D@RD@Xxhfffʊb@44333 c@lPc@$c@Lhfffb@DLb@pfff/b@ 8b@@3333̄b@hfffb@b@Lhfffjb@pffff2b@aDb@Lb@L hfffzb@hfffRb@4333b@L0b@pfff4333sb@pffffhb@s4b@pffffhfffb@pffffHhfff~b@pfff4333b@pfffhfffb@b@@3333̀b@@333 hfffb@pffff4333b@Lb@4333b@$b@@3333hffffb@LQb@=b@pfffhfffzb@L4333sb@LHb@b@ 4333sb@#ab@pfff4333Ͼb@4333b@@3334333˵b@43337b@pffffhfff6b@K|b@V٧b@Jb@@3333b@@3333hfffb@pfff -b@hfffNb@L̴b@b@4333Ӎb@b@.hfffʊb@hfff֌b@pffffPb@@3338hfffb@@333R4333b@@3333x4333יb@pffff4333+b@w b@@333b@pffffQc@< c@pfffI c@ c@pffff c@@333=hfff c@4333 c@pfff\̔ c@pffffHPc@$Y hfff^@$4333_@hfff Ahfff _@hfff&"^@8333"^@"hffff^@:#̜^@i#^@#hfff^@#\^@$^@@($4333+^@8333A$|^@hfffU$L^@n$̴^@L$9^@83333$4333^@$4333^@hfff$hfff&^@8333$4333C _@]$_@8333V$\_@L$hfff _@,$̄&_@hffff#hfffV-_@ #5_@#4333=_@T#hfff?_@8333s!#tM_@"Z_@83333" o_@hffffR"u_@hfffB"4333Cy_@hfffC"̌|_@8333s?"̬_@L"4333_@L!_@ !4333{_@L!)_@L!4333c_@8333s!hfff_@hffff!_@!4333_@83333n!T_@*!4333_@Y 4333s_@ _@8333 hfff_@L ٽ_@hfff hfff_@hfff _@83333 4333_@8333s _@@ _@ _@Y y_@ ys_@ pX_@&!hfffT_@.!dK_@8333K!hG_@j!A_@ٷ!8_@!4333S-_@hfff"hfffV)_@;"$_@̌O"hfff _@hfff&"Z(̬b@hfffFEhfffb@ VD%yb@)E]vb@Etb@4333Ehfffub@l}Exb@pE̜yb@y}Ehfffyb@ zEyb@vE0vb@̜oE\rb@@lE%qb@4333cpEqb@̼|E,qb@̌Eynb@hfffFEhfffmb@irËib@Gb@yEFb@yEEb@EDb@hfff֧E5?b@yE;b@lE9b@W@3333QT@hfff6W@XQT@hfffW@ LT@W@HT@$W@ffffVGT@W@3333FT@W@ET@4333xW@̼CT@hW@pBT@_W@ffffBT@VW@3333BT@4333+DW@3333C?T@4333W@,T@4W@ffff'T@$W@ "T@W@T@4333cV@T@V@T@hfffV@ffffT@4333V@ffffFT@V@T@hfffW@3333KT@hfff W@y T@hfff&@W@̈T@hfffiW@T@wW@T@W@T@)W@T@QW@T@hfffW@ T@W@3333S T@hfff6KX@lT@SX@tT@ZX@ffffT@4333[RX@T@4333PX@3333;T@\GX@T@̤DX@E!T@AX@ffffF"T@S@hfffFX@3333S@X@ S@X@ T@4333kX@T@,X@3333WT@ X@ffffT@43333X@T@X@S@X@̘S@|X@S@!X@3333S@wX@S@hfff^nX@ffffS@̴iX@ffffS@eX@̘S@ hX@mS@4333pX@US@̴sX@4S@zX@=T@4333#X@ffffvT@yX@T@4333+kX@ T@hfffeX@ T@hfffGX@3333 T@X@T@X@3333 T@hffff X@ffff2T@hfffW@ffff T@W@ffffT@W@̨T@W@ffffT@W@T@0W@ffff2T@W@ffffT@)W@ffff:T@4333 W@T@9W@HS@tW@ffffS@qW@ffffbS@9vW@S@hfffYW@lS@DW@3333S@lQW@ffffVS@4333^W@S@̌pW@S@W@S@W@ffffS@4333۞W@S@W@PS@lW@S@W@(S@W@3333S@hfffNW@3333_S@hfffW@,S@hfffW@3333[S@W@3333GS@4333W@S@W@3333S@4333;X@S@̄X@1S@43333X@ S@7X@3333S@̴;X@ŻS@OX@S@̌cX@ffffS@lX@3333S@hfffyX@ffffڳS@xX@3333S@X@S@PX@3333kS@4333sX@ffff^S@!X@dS@̜X@3333S@yX@S@4333X@hS@4333#X@ffff"S@ X@S@4333X@TS@](`X@<}S@hfffUZ@S@bXIZ@hS@@Z@S@4333c8Z@ffffS@hfff(Z@3333sS@hfffZ@ffffRS@hfffZ@S@Z@̰S@hfffZ@̈S@Z@S@AZ@S@hfff>Y@3333S@@Y@S@Y@S@̼Y@ffffS@hfffY@S@Y@S@4333ӼY@S@Y@3333S@ٯY@żS@hfffY@3333÷S@4333cY@xS@Y@3333S@4333Y@S@4333cY@ffffJS@Y@@S@4333#Y@3333[S@4333[Y@S@DY@$S@Y@8S@̌Y@S@Y@S@4333Y@ffffS@hY@mS@Y@S@XY@S@Y@3333cS@9Y@(S@hfffVY@S@`zY@S@tY@S@pY@ffffS@,iY@ S@eY@mS@cY@ffffS@bY@HS@hfffSY@3333S@̌LY@S@hfffIY@ffff S@XCY@3333S@\DY@(S@AY@}S@=Y@3333kS@9Y@S@T7Y@@S@6Y@tS@x9Y@3333S@4333+=Y@ffffvS@ 8Y@ffff&S@'Y@S@!Y@3333kS@hfffY@4S@,Y@xS@Y@ffffjS@hfffvY@S@4333 Y@ffffJS@hfffn Y@@S@Y@S@hfffY@XS@hfff6Y@̰S@4333cX@S@4333X@mS@4333X@3333_S@`X@pS@X@3333 S@X@x~S@X@<}S@4333CY@fffff~S@4333"Y@ffff S@hfffBY@ffff&S@MY@HS@PlY@pS@̌Y@$S@Y@`S@Y@S@Y@3333'S@Y@ffffS@43333Y@`S@ Y@3333S@ Z@qS@hfff>!Z@YS@y/Z@ffffS@I5Z@3333S@TZ@ffffS@hfffUZ@3333S@SZ@ffffS@4333cPZ@S@MZ@ffffS@XIZ@hS@^4333Sa@R@̄+b@ S@zhfffa@ffffFR@4333a@R@a@̠R@a@ffffR@a@R@la@ffffBR@4333a@R@ a@S@a@ffffS@̈a@3333S@a@S@4333 a@3333KR@a@ffffR@ha@YR@a@ffffzR@hfffa@!R@a@R@hfff6a@R@ta@ffffR@a@]R@a@R@Da@ffff6R@hfff~a@qR@a@%R@4333sa@3333R@Ȉa@ffffR@hfffބa@R@4333a@ R@wa@3333R@pa@S@4333fa@ffff*S@hfff~ca@3333S@`a@3333? S@l]a@3333 S@ Za@ S@Ma@3333SS@̤Fa@3333[S@hfffCa@3333'S@R@1a@ffff"R@ 0a@8R@hfff2a@ffffR@6a@̜R@x+a@ffffR@hfff(a@ffffR@4333&a@3333{R@E)a@PR@P%a@ffff.R@pa@aR@4333Sa@R@4333a@MR@43333 a@ffff R@&a@3333R@M.a@xR@-2a@̘R@43335a@R@H=a@R@4333 @a@R@Ba@ R@4333[a@ܬR@hfffj_a@R@,ca@R@fa@8R@4333kja@R@4333ma@3333R@dpa@ffffR@qa@ܹR@4333csa@̄R@ua@3333R@4333Cxa@ffffR@hfffZa@DR@hfffa@4R@؎a@ɶR@$a@pR@4333a@R@a@ffffR@4333a@ffffR@a@pR@43333a@ܼR@a@3333R@hfff2a@dR@a@3333R@ a@R@a@R@4333a@R@a@R@a@ffffR@Ma@̘R@̼a@3333R@xa@3333'R@\a@!R@a@HR@hfffa@HR@hfffa@DR@hfffa@3333#R@4333#a@ffffR@a@3333;R@a@3333R@4333a@R@̀a@ffffR@4333ca@ffffR@Xa@R@hfff>a@$R@a@ffffR@4333sa@3333{R@̬a@MR@4333a@`R@b@R@b@R@ b@R@Eb@ffff6R@hfffb@R@Ab@eR@4333b@̠R@ b@XR@̄+b@3333R@)b@R@4333+(b@ffffzR@hfffa@ffffFR@_0ua@ NR@̸a@ffffzR@#a@fffffdR@ta@esR@a@vR@hfffa@ffffVyR@ѽa@ffffzR@hfffҵa@ffffyR@4333a@wR@a@xR@hfffa@ffffjwR@ya@8uR@Ha@3333qR@Qa@DhR@hfffa@!dR@hfff.a@^R@4333a@H]R@q}a@\R@ua@3333?[R@4333#ya@VR@hfff}a@VR@܀a@!WR@4333a@[R@5a@\R@ a@\R@إa@XR@a@SR@4333 a@3333RR@4333a@3333/PR@a@ffff6PR@hfffa@3333OR@4333/a@ NR@hfffra@NR@̸a@OR@a@ffff^]R@$a@UaR@a@fffffdR@`Db@pR@Pb@Hb@33333R@Eb@ffffR@Db@̰R@Vb@3333OR@̘]b@R@db@ffffR@9hb@ffffR@4333tb@3333_R@wb@R@b@ffff޶R@b@شR@b@ffff:R@4333b@pR@b@ffffrR@Ѻb@ffffR@b@yR@b@кR@hfffb@tR@Pb@R@8b@dR@4333b@R@a P4333e@)D(Qf@6A'4333e@fB4333e@4333pB e@hfffzBye@0B4333e@Bhffff@hfffB f@B̴f@hfffBf@4333Bhfff6f@4333Bxf@4333Bf@`Bf@BU f@ Bf@\Bf@B-%f@,B(f@)B*f@4333B.f@̌B1f@B4f@hffffBhfffF7f@PB:f@hfffBhfff=f@hfffB>f@4333SB4333K@f@hfffBHf@B4333Kf@)B4333;Of@4333sB(Qf@hfffB4333Pf@BhfffNNf@\B4333Lf@BKf@hfffCJf@hfff8C̐Hf@̌FCEf@QC4333Bf@4333XCf@Chfff>f@Be@ MBe@4333CHBe@`ABLe@hfff9B4333e@3BTe@ 0BLe@4333S)B4333e@hfff#Be@Bhfffe@4333Bhfffe@Be@ Be@43333Bhfffe@4333Bhfff*e@̬Be@4333B4333Ce@PAe@4333#AhfffZe@4333SBe@Bhfffe@ %B4333Se@)Bhfffe@@0Bhfffe@ 2Be@ .Bhfffe@\Bhfff>e@4333B0e@4333sAhfff^e@A4333e@̼Ae@A e@٨A̜e@4333AUe@9Ae@`Ae@Ahfffڬe@hfffA4333 e@4333A e@AIe@4333CAQe@4333AȨe@yALe@hffffA e@hfffAe@hfffFAhfff e@hfff֏Ae@4333Ae@sAhfffe@4333cfA4333e@PA4333e@4333C:Ae@i7Ahe@6A4333מe@DAhfffe@YLAe@RAye@IgḀe@hfff&mAhfffe@4333sA4333e@hfffwA4333e@4333}Ae@hfffVyA43333e@rATe@4333lA e@vA e@hfff6yA43333e@Ae@A(e@hfffƈAhfffe@hfffFAe@\Ae@PATe@IAhfffe@A4333e@4333Ae@hfffA̔e@hffffÀe@A e@4333sA@e@4333Ahfffe@A̔e@,AQe@Aie@4333A4333e@ Ade@Ae@@AhfffFe@lA̔e@̌Ahfffe@A4333e@ Ahfffe@AQe@)A4333e@B4333[e@P B4333e@̜'Be@ 2Be@8Bhfffe@4333>B43337e@YNBhfffe@,SBe@4333cB4333e@eBhfffe@̬kBe@hfff6mBhfff2e@oBhfffe@hfffftBYe@nB4333we@,mBe@4333tBe@4333S|Be@4333#Bhfffre@DDqe@hfffEPe@hfffE4333äe@Ee@}E4333e@kEqe@LBE4333۲e@De@4333?De@hfffVBD4333e@4333ODhfffe@aDhfffve@@yDe@̙DXe@DhfffV~e@4333D̔ze@Diwe@Dhfffue@4333SD)qe@hfffD4333oe@Dume@̌D4333ke@< E4333Sje@43333E|ie@&Ehfffhe@4333s3Eyie@7E4333je@hfff:E9he@;Ege@4333C=Efe@@E4333`e@YEae@4333fEhfff:ae@YnE``e@IqE`e@hE]`e@aE _e@4333[EZe@lE4333We@4333vE5We@|E4333We@ЃE4333KUe@ {EhfffSe@y|EPe@hfff&E%Qe@hfff6ESe@E%Qe@|ENe@4333ӄE$Le@yḚIe@hfffƍEhfffKe@Gl e@EGhfffn e@PKGhfff: e@|MGe@@KGPe@hfff6NG4e@hfff6KGe@|HG4333e@4333JGe@hfffvNG(#e@PG*e@lOG5e@̜FGT7e@̼BGX8e@i=Ghfffb=e@*GEe@hfffGHe@4333 GJe@4333FiMe@4333sF4333Ue@hfffFWe@4333cF4333Xe@yFQYe@4333F4333;Ye@pF̬We@hfffFdVe@4333cF4333kVe@hfffFhfffZe@4333sFhfffz\e@ܯF^e@4333F_e@4333cFce@hfffF4333Kde@hfff&}F4333`e@wF_e@tFhfffde@hffftFTfe@IbFfe@\NFdge@hfffBFje@4333&F!ie@̬#Fge@!Fhfffke@4333 F\me@hfffF)ne@4333cFpe@hfff&Fhfffue@Fve@y Fhfffye@iF|e@4333FHe@Ee@ Ee@Ede@Ee@E4333#e@4333Ehfffe@̼Ee@E}e@hfffEhfff6e@ETe@0Ęe@Ee@̌E4333_e@4333E4333ߐe@hfffEhfffe@4333E4333;e@̬Ehfffe@Ee@iEhfffe@4333Ehfff*e@`Eue@E4333e@hfffVEe@4333Ee@ Ee@ E4333#e@ EXe@̌EPe@LE4333әe@|Ee@Ee@hfff6Ee@4333E0e@Ehfffڐe@|Ee@зE4333;e@hfffƶEde@)E4333e@iEe@hfffFEe@hfffVEe@Ehfffe@ E4333ۙe@PEqe@hfffEchfffy^@Ye@_@̬#@_@`fff/@|_@@آ_@03333@̤_@`fff&@ܛ_@T@8_@0333@9_@,L @4333[_@g @hfffN_@L @a_@ @_@ !@4333_@!@hfff_@0!@_@,A!@_@d!@Ԑ_@`fff|!@4333s_@!@hfff~_@0333s!@a_@@)"@I_@0333?"@`_@̬"@4333_@"@a_@0333S"@}_@0333s"@4333x_@#@hfffi_@O#@hfffVa_@̬#@)^_@y#@hfff~Z_@V#@hfff`_@@"@4333#b_@`fff&H"@4333__@̌"@ X_@!@O_@ "@4333kM_@`fff "@hfffFK_@!@hfffI_@̼!@B_@0333!@h<_@0333!@̜7_@!@3_@!@4333[2_@̌!@0_@,a!@4333._@@ !@4333'_@ !@_@0333s6!@_@ 3!@_@l!@_@0333S!@ _@ @4333s_@0333 @hfff _@`fffu @43333 _@`fff&g @^@`ffffQ @^@A @)^@`fff& @43333^@0333 @hfff^@LJ @(^@̬` @4333^@̌ @Y^@̌ @4333#^@l!@hfff^@=!@4333^@K!@hfff^@0333\!@^@h!@T^@03333;!@hfff^@ $!@hfff^@9!@4333k^@03333!@4333#^@, @<^@, @ ^@0333 @^@L @,^@`fff @4333ÿ^@`fffp @P^@P @4333{^@0333sD @^@`fff&D @^@`fff/ @^@ @4333^@̌ @4333^@@p^@0333=@̬^@@Y^@@^@Lt@hfffn^@0333s@,{^@L@hfffy^@M@hfff}^@0333s@ā^@`fff@H^@`fff@hfff^@0333s@hfffF^@L@^@@hfffv^@`ffff\@hfff^@>@\^@L@hfffޟ^@`fff@p^@0333s @^@0333@̬^@@hffff^@`fff;@4333^@@hfff^@@@T^@`ffff/@!^@u@0^@@@^@`fff@^@ @̤^@M@h^@`fff&@ ^@@@^@L@|^@Y@4333^@L@hfff^@@hfff^@L;@h^@T@^@S@̜^@`ffffE@^@@$@^@0333s@4333^@@Y_@O@̬ _@03333@9 _@0333@ _@T@4 _@@ _@ @hfff_@L@4333_@t@hfff^@̌@hfff^@@9^@0333s@_@̌@hfff._@Y!@_@`fff&@hfff _@@hfff_@z@(_@`fff&@Y;_@Y@i>_@v@4333CB_@̌{@D_@@4333#K_@0@9L_@@@N_@03333G@hfff.Q_@0333!@P_@̳@N_@0333;@lO_@@lR_@0333s@,V_@Ye@,]_@03333@hffff_@ {@j_@`fff&@j_@`ffff@e_@0333@!d_@@$__@K@̴[_@0333m@\X_@@Y_@.@hfff]_@@4333b_@@i_@k@Aj_@0333s@j_@`fff@l_@Y @4333q_@`fffI@4333t_@LU@̬y_@w@4333}_@"@ _@03333@_@`ffff_@ _@0333@hfff_@`ffff@hfff_@@hfff_@=@(_@@`_@@4333K_@i@_@`ffff@ђ_@@_@`fff @_@ @8_@0333@hfff_@0333L@_@`fff/@dx]@Y")@4333# _@43332@hfffΒ^@;2@4333C^@9(2@|^@4333s2@^@1@^@dfff1@hfff6^@`1@(^@4333So1@8^@0e1@0^@IX1@̘^@N1@$^@dfff=1@^@-1@^@dfff'1@9^@dfff1@^@1@4333^@4333s0@@^@0@t^@io0@̴^@Y0@hfff^@P/0@a~^@l(0@yr^@43330@k^@dfff0@f^@0333/@hfffc^@L/@e^@Y/@f^@s/@f^@0333V/@e^@0333?/@Y_^@/@hfff\^@0333S.@\Z^@hfff.@4333Y^@.@Y^@.@hfff[^@n.@b^@0333-@hfffFj^@9-@k^@hfff-@l^@y-@h^@ ]-@0h^@̌)-@i^@hfff,@hfffp^@hfffw,@q^@ V,@4333;s^@L:,@̜v^@L ,@Yz^@0333s ,@^@+@<^@̌+@̌^@@+@hfff^@+@hffff^@ +@^@hfff,@hfff^@,9,@Ȍ^@K,@43333^@Y,@hfff^@0333a,@hfff^@,@i^@ ,@4333#^@0333,@̴^@ّ,@ɶ^@hffff,@ɻ^@L`,@hfff^@(,@4333^@+@hfff^@03333+@̤^@+@hfff^@ٓ+@hfff^@ +@^@hfff~+@^@@+@4333^@hfff+@^@l+@4333^@0333 ,@^@0333,@(^@̬,@4333^@+@^@hfff+@^@hfffF+@hfffv^@hfff+@4^@+@4333^@hffff+@^@hfffq+@4333^@̬h+@,^@J+@4333^@`+@^@*@4333^@*@hfffn^@*@4333C^@b*@@^@8*@4333^@`fff;*@!^@ 3*@l_@Y*@_@ *@4333# _@0333S*@_@0333)@4333_@Y")@̌^@0)@hfff.^@ a)@hfffF^@`fff&)@̴^@03333)@^@@)@I^@)@Y^@`fff)@4333^@9)@^@0333)@^@0333*@hfff^@0333*@hfff^@03332*@^@`n*@hfff.^@*@4333C^@hfffF*@4333s^@,*@4333[^@0333/+@4333C^@hfff<+@^@`y+@^@0333+@^@+@ ^@hfff&+@4333^@+@^@0333+@D^@0333+@4333^@hfffh+@4333^@LP+@(^@+@^@hfff+@hfff^@l*@4^@*@d^@`ffffc*@^@ *@̠^@0333*@hfffޟ^@ *@4333 ^@L*@^@̌ +@4333#^@hfffK+@^@hfff+@q^@0333+@4333o^@hfffF+@Dl^@+@hfff.i^@+@`^@03333+@\^@+@\^@yl+@hfffV^@YL+@hfffM^@0333G+@F^@hfff[+@d@^@hfff&+@4333;^@0333+@hfff5^@+@.^@0333+@hfff(^@hfff+@4333'^@+@y'^@hfffF`,@!)^@},@ ,^@,@4333;^@y,@hfff<^@̬-@hfff><^@hfffFJ-@hfff8^@yn-@|3^@-@hfffN-^@-@(^@-@4333[%^@03333-@hfff"^@@-@4333K%^@0333s0-@̬%^@Y,@#^@,@^@`,@^@ ,@Y^@0333,@`^@0333s7-@4333+^@hffff^-@ ^@,-@ ^@-@^@̙-@A^@-@^@-@X^@hfff:.@Q^@`u.@hffff]@03333.@4333]@.@]@hfff/@i]@/@]@/@]@hffff/@hfff6]@)0@]@43330@q]@PA0@4333]@dfffM0@4333+]@S0@hfff]@4333I0@4333]@ =0@ ]@dfff&70@4333#^@@/0@^@43330@9 ^@43333 0@\^@) 0@^@43330@^@ 0@^@43333)0@^@̼80@^@|f0@^@|0@4333{^@<0@hfff^@ 0@4333+^@43330@4333^@1@Y^@E1@hfffV^@|`1@4333+^@dfff6p1@^@1@^@`1@4333S ^@4333)2@4333C#^@C2@h%^@dffff^2@a&^@43332@hffff-^@4333Ë2@4^@y2@7^@4333S2@43333;^@ɕ2@IC^@2@F^@43332@IP^@<2@4333e^@``2@m^@T2@hfffv^@K2@̤|^@I2@hfffv^@4333S2@^@dfff&_2@4333c^@|2@(^@)2@hfff^@dfffvu2@0^@g2@)^@R2@hfffΒ^@;2@eXhfff_`@LO%4333/b@<ֿH4333+a@̌!a@hffft!a@hfff=!@a@hfff a@d 4333wa@@U 4333a@YG hfff2a@+ hfffa@pfffa@hfff }a@3 hfffNya@8333s6 ta@83333@ pa@8333sX 4333Wla@` hfff6ja@hfffT hfffha@6 Dha@ hfffga@,fa@, ba@hfff&I 4333]a@Y \a@y [a@8333sb e[a@LJ hfffR\a@0 \a@ 4333]a@`a@@333Yhfffvaa@4333[ba@ba@LY̐aa@t_a@pffff4333^a@hfffV\a@@3333~L[a@[eYa@24333Wa@̌Ya@pfff̬[a@@33334333k]a@4333`a@Lba@̨ea@hfffca@aa@pffff[a@hfff Wa@Ghfff>Sa@4Sa@Ua@̋hfff[a@o4333Ya@pffff)@Wa@@3334333WVa@@333̌Ta@pfff=̰Pa@@333 Na@_Ka@pffffy4333{Ia@4333 Ja@̌Ka@pfff_ Ia@@333Z4333cFa@pffff:4333Ga@hfffJa@pfffHa@@333TEa@Da@@333Ba@@3333Ba@@3333Ba@4333kBa@pfff.hfffAa@pffff̄?a@pfff4333=a@{`b@i$Xb@hfff$4333/b@x$4333b@$`b@ $hfffFb@Y$ b@8333$̤b@$`b@$b@83333 %hfffb@%pb@F%b@ L%?hfffVM^@33333?R^@3333?V^@?Y^@?)\^@3333n?A^^@}?`^@?hfff>c^@@ffffF?e^@@ffff?4333w^@j?^@?^@J?(^@̀?4333^@3333?̌^@̜?hfff^@?hfff^@33333?q^@3333?^@ ?A^@3333#?^@̲?0^@ffff?^@6?4333_@3333[?4333K_@3333?("_@?4333$_@@ffff?i&_@@ffffG?43333)_@?/_@?i2_@3333{?7_@@ffff7?̜<_@3333?P?_@@ffff7?G_@?̌J_@@ffffL?hfffN_@@ffff ?0N_@̨?I_@̈?̄G_@?4333A_@3333?=_@@ffffR?43338_@?hfff,_@3333k?4333(_@3333?4333%_@?hfff _@?\_@ffff?_@ffffz?4333_@? _@X?|_@?hfff>^@?^@ ?^@8?hfff^@3333S?^@3333?|^@?H^@?̿^@?hfff6^@ffff?^@?hfff^@?4333u^@?An^@3333?f^@?a^@ffff?@[^@3333?@^@D?0:^@?4333,^@ffffx?hfff%^@?p^@ffffT?hfffV^@?hfff^@ ?hfffN ^@3333/?hfff&^@Q?4333^@Y?hfffN^@hfff^@ɿhfff^@ӿ^@gfffۿhfff^@3333<^@hffff^@D^@ffff쿜9^@ !^@𿜙&^@"hfff*^@.^@3^@̜:^@ (B^@@3333I^@ffffn4333M^@fffffQ^@4333[^@Z@Z@ffff̜Z@0!Z@.!Z@ffffhffff$Z@I+Z@2Z@S6Z@ffff 6Z@_hfff4Z@4333c2Z@C*Z@l)Z@ffffp4333[(Z@Xhfff)Z@,Z@hfff/Z@@333388Z@Y:Z@@3333#!>Z@AZ@@3333hfffVRZ@hYZ@ 4333_Z@p@eZ@4333yZ@@3333hfffւZ@Z@I ̼Z@̼ (Z@ffff yZ@G ̤xZ@@3333 vZ@ vZ@@3333 PyZ@<̌{Z@`{Z@ uZ@@333|hfff6uZ@̦̼xZ@@33337hfffxZ@hfffFxZ@@333,xZ@ 4333;tZ@̴`sZ@oZ@pfffELkZ@@3333EhfffgZ@2dZ@pfff hfffcZ@pffff4333saZ@pfff\VZ@@3332tSZ@@333G43333HZ@@33334EZ@pffff4333sAZ@L;Z@hfff(Z@pfff'Z@I'Z@pfff4333C+Z@Chfff+Z@4333c(Z@@333&Z@LhfffZ@pffff6hfffZ@ĽZ@' Z@hfffFZ@@3333hfff6Y@QLY@!hfffY@DAY@IY@pfffY@bкY@iY@̛hfffΗY@4333Y@ffffe )Y@@3333 XtY@@3333 iY@ eY@V 4333ZY@0pWY@wSY@ffff43333MY@OhfffGY@̳qX@`fff @hfff69X@: @4333C3X@ @!X@"@hfffvX@̇@X@@X@J@4333;W@ @W@٥@W@`fff @̤W@u@hffffW@@9W@"@ W@̌b@W@`fff@̌W@0333s@4333SW@@̔W@YB@W@_@YW@`fff@hfffW@@@W@0333o@0W@03333Q@W@@X@g@X@Y-@hfffX@`ffff@hfffX@@`'X@@hfff5X@ @=X@@|EX@0333s@0LX@L@\X@0333@4333`X@@cX@@eX@0333s@4333;mX@)@4333#zX@@}X@`fff&@X@`fff&@4333SX@0333s@hfffX@@hfff~X@ J@pX@03333@4333X@_@СX@@(X@l@X@@4333+X@@ɱX@L@X@̮ @̬X@`ffff @`X@L} @hfffX@`fffv @hfffX@@4333 X@(@\Y@Z@$Y@L.@Y@@4333Y@ 333J@̬Y@ 3333@@Y@ 3333@hfff!Y@`ffff@&Y@@4333+Y@`fff@hfffF4Y@?43338Y@,?43338Y@g@H4Y@@i 9[@̭4333 ]@@4333\@LQ@4333[@@4333[@ 3333@[@ 333@hfff^[@@0[@@[@d@h[@`ffff @hfff[@`ffff@|[@`ffff@[@ 3330@[@`ffff|@Y[@ @4333[@`@hfff^[@̔@)[@ 3333@hfff[@̂@̬[@?[@o?hfff[@? [@?4333[@@ffff#?hfff[@?hfff[@@ffff?hfff[@3333/?I[@@ffffU?4333K[@1?L[@j?([@G?hfffF[@? [@@ffffU?hfff6[@?[@2?Y[@?[@8?̼[@?L[@@ffff-?4333[@@ffff{?Yw[@3333;?hfffn[@?pl[@@ffff8?@h[@`ffff8@9X[@@ffff?\T[@3333#?4333{Q[@I?4333J[@?4333D[@3333?̌C[@?@[@?0D[@@ffff?hfff&F[@@ffff!?4333kH[@?E[@3333?A[@E?Y=[@@ffff'?̬:[@ffff4?9[@h?hfff;[@ ?4333s<[@3333?D[@ffff.?I[@ffffv?K[@0333?N[@dfff?4333O[@̌?4333{P[@`fff?tL[@L4333J[@<¿4333I[@ǿ4333G[@gfffпG[@ٿhfffVH[@ܿhfffFJ[@̬߿4333sP[@ffffz4333W[@l俜qW[@3333[4333S[@XQ[@lP[@ffff|R[@XU[@33334333 ][@뿜k[@33337dr[@ffff.hfffw[@񿜙 |[@hfff~[@e4333;[@aP[@@3333i[@Hhfff}[@hfffn}[@̄[@ffff$hfff.[@hfff[@4333[[@ffff4333[@f4333c[@\[@hfffv[@)[@ffffx̼[@!4333ê[@ [@*[@[@hfff[@D[@̑[@[@chfff[@hfff[@@3333rhfff[@̦hfff[@@3333x̬[@ffff[@![@hhfffv[@hfff[@ffff[@ffff̬[@@3333u[@@3333v hffff[@ffff\ ̜[@B 4333[@@3333j 4333[@k [@< 4333\@@3333 <\@ffff i\@ 4333k&\@@33334 43330\@̓ ,>\@@3333 ,B\@whfffU\@ W\@ ,Z\@ a\@y hfff>d\@l 4333 g\@̐ 4333Sh\@ h\@ ̌h\@\ m\@ffff hfffr\@ffff \}\@' 4333C\@@3333; \@H 4333+\@@3333 4333c\@ \@ 4333\@@3333s \@ hfffN\@ hfff~\@G \@@3333 4333k\@ 4333\@ 4333\@ffff P\@ Ȧ\@ffff \@pffffr4333é\@4333c\@̭hfff\@@3333A1\@ hfff\@/ ]@ffffv hfff]@@3333 ]@ ]@v ]@@33330 hfffv]@ hfff ]@3 ]@̤ ]@z4333s]@|]@)]@74333]@ffff]@]@̟]@hfffF]@@3333j]@@3333,hfff]@(4333]@ffffN!]@hfff&#]@ffffI0$]@e!]@̩4333]@ffff~]@D]@ffff4333]@k]@@3333hfff~]@(]@̎4333]@@3333u]@̎,]@A]@fffffhfff]@ !]@4333"]@|#]@@3333$']@hfff-]@@333380]@<X1]@D0]@ffffP4333.]@i򿜙y.]@񿜙Y/]@@3333̬0]@43333]@\6]@~hfff~:]@4@]@hfff~D]@`I]@$hO]@33334333V]@da]@ffff~d]@3333远d]@H4333c]@応!c]@]]@Կhfff]]@ɿ4333ka]@1?ic]@3333?o]@3333Y?q]@ ?v]@?$]@:?4333k{]@@ffff?hfffVw]@~?43333u]@@4333r]@7@4333cx]@ 3333|@x]@ 3333@@}]@G@]@ 3333@hfff>]@@4333C]@`fff@0]@`ffff@x]@U@4333s]@Z@Lr]@`ffff@4333o]@`ffff4@̬j]@t@4333h]@ 3333@j]@@hfffl]@ 3333@h]@Q@ld]@ 3333o@4333h]@L@1g]@ @g]@̃@Ld]@ 333@p`]@ 3333@4333[]@LR @hfffV]@̌ @T]@ @hfffX]@L @)V]@ 333i @hfffJ]@`ffff @IG]@ 333 @̔C]@ 3333 @4333J]@ @lR]@L @4333\]@ 3333 @̬_]@S @hfff`]@ @Pd]@m @Ph]@ 3333 @m]@( @hfffq]@ @p]@ @n]@)@4333n]@ 333_@hfffh]@@9d]@p@c]@@]]@`fffM@hfff_]@@]@6@Ty]@@Tt]@@4333`]@`fff@g]@L@@i]@`fff@hfffi]@YK@4333kg]@@@̄l]@@hffffl]@`fffff@4333j]@@4333Si]@ @g]@0333 @4333_]@03333I@XX]@0333r@R]@`fff&@QP]@@"@4333O]@`ffffU@(P]@L@hfffN]@̌@9H]@`fff&@D]@٪@0A]@0@4333s:]@@hfff3]@n@p2]@`fffl@3]@`fff@43335]@@4333c6]@̌N@P5]@`fff@̬1]@@/]@̌@4333s"]@0333T@]@03333@4333]@`fff@4333 ]@Y@4333]@̌@\@Y@4333#\@@t@\@%@i\@!@\@0333#@\@ 2@hfff\@`fffi@̜\@LD@\@@\@0333sR@\@03333@@\@@|\@_@D\@2@hfff^\@0333s@hfff\@`fff&@hfff\@Y@hfff\@L@4333\@̌@ \@@̴\@`fff@̵\@@i\@`fff&@hfffV\@L1@ܢ\@0333@)\@@@)\@m@4333c\@`fff&]@hfffn\@_@̀\@ M@hfff~\@`fff.@4333c\@`ffff@8\@̮@hfff|\@`fff'@!{\@ @4333m\@0333s@̌\\@ 333 @|T\@`fff} @H\@ @B\@L @9?\@K @:\@ 333 @0/\@L@4333\@LQ@jhfffJ@SR@DR@ٟN@R@N@ffff&R@hfffFN@R@N@tR@hfffvO@`R@4333O@R@O@̘R@iO@R@O@ R@hfffP@3333R@hfff/P@ffffrR@hfffLP@R@gP@R@4333P@R@4333P@ffffS@)P@S@ P@S@`P@ffffR S@4333P@4S@hfff Q@3333;S@4333;Q@S@#Q@3333S@hfff9Q@3333$S@6Q@ffff'S@hfff8Q@8*S@DL@ffff&R@1L@R@4333$L@R@4333L@R@̌L@ffffnR@K@ffffR@K@ffffR@K@R@|K@ffffR@K@33337R@hfff+L@R@6L@DR@hfff?L@@R@4333L@pR@4333K@3333R@pK@R@hfffK@,R@ K@3333˥R@̬K@3333R@9K@3333R@hfffFK@3333R@̌L@R@hfff L@͞R@LK@R@4333K@3333ۚR@K@R@uK@3333CR@hffffjK@ R@]K@,R@4333CRK@i}R@hfffMK@ffff|R@4333s1K@{R@hfffFK@xR@4333SJ@̠tR@J@R@YJ@3333@R@0J@FR@hfffVJ@qIR@hfff&J@KR@hfffƭJ@3333_NR@J@AOR@J@PR@iJ@RR@J@ffff"SR@hfff K@QR@hfffK@RR@)K@ffff*SR@VK@ffffWR@hffffK@3333XR@hffffxK@3333XR@K@ffffVR@K@3333SR@hfffK@0QR@L@dPR@,L@3333oNR@6L@LR@2L@HR@hfff*L@ffffFGR@0L@BR@`L@>R@L@33339R@4333L@3333G6R@4333L@33333R@ L@2R@K@33332R@K@ 1R@hfffK@-.R@K@*R@hfffK@3333W&R@|K@3333$R@K@$#R@\K@ R@K@R@hfffK@(R@K@ffff.R@hfffK@ffffR@PK@3333R@YK@3333 R@K@3333R@K@R@ K@Q@LK@Q@K@ffff"Q@̌K@3333'Q@K@|Q@hfffL@ffffQ@):L@3333Q@rL@TQ@hffffL@Q@hfffL@̴Q@9L@3333Q@ L@̤Q@b@ F@,b@ffffF@hfffba@3333SF@`a@F@hfffJa@F@hfffa@TF@aa@ffff#F@E@`a@GE@hfffa@ffffHE@̼a@!IE@hfffa@ffffGE@4a@@E@Ya@ffff.E@hfffa@3333+E@4333a@FE@hfff>a@ffffJE@a@aB@4333w!a@ B@hfffna@3333B@a@3333B@a@B@hfffa@lB@ a@zB@h a@3333rB@̈ a@)kB@#a@cB@'a@h`B@hfff)a@3333{`B@hfff*a@3333bB@q/a@ffff^vB@4333s0a@yB@8=a@DB@Ca@ffffVB@hfffFa@1B@A@`@3333{;A@hfff.`@ffff7A@@`@q7A@`@3333S1A@hfff`@,A@hfff`@ffff&A@ox4333 `@A`@@̤`@-A@L@`@@@`@ffff@@T`@A@hffff`@A@`@|A@p`@ A@`@ffff(A@m`@-A@X`@̌,A@4333k`@ffffF'A@`@aA@hfff`@ffffA@H`@ffff6A@4333`@<A@hfff`@A@`@1A@4333`@̄@@1`@@@`@@@-`@3333s@@4333G`@@@`@@@4333`@H A@`@33333 A@ܚ`@A@`@@@4333`@@@4333`@ffff@@]`@<@@`@P@@4333'`@3333@@`@@@hfff6`@@@`@@@4333 `@̄@@4333`@@@hfff`@Y@@4333`@@@5`@@@4333`@fffff@@@`@@@]`@3333@@4333{`@@@4333+`@3333 @@D`@0@@9`@0@@̰`@@@4333Ï`@3333@@؏`@3333Su@@4333C`@3333u@@`@̄s@@`@a@@hfff&`@Qc@@̼`@A`@@hfff֛`@ffff`@@E`@ffffk@@4333`@}@@4333`@@@hfff:`@̜@@̨`@̤@@`@3333@@hfff&`@3333@@9`@h@@`@ffff@@T`@@@`@3333c@@`@̴@@`@̤@@̔`@i@@`@@@@4333`@ffffn@@`@@@4333`@Y@@̤`@ffff@@`@̄@@@`@@@p2`@?@hfffF`@@@@`@ffffl@@`@p@@hfffF`@3333u@@hfff"}`@|@@}`@L@@`~`@ffff@@4333|`@<@@!{`@@@Y{`@@@@̰|`@ffff@@hfffv`@D@@hfff2q`@@@hfffs`@(@@v`@L@@,w`@3333@@Hv`@)@@t`@3333@@r`@@@hfffo`@@@hffffm`@ffff@@hfffk`@3333@@i`@P@@hfffe`@!@@a`@ @@hfffJ``@ffffN@@^`@ffff@@hfffZ`@y@@hfffV`@@@lU`@ffff.@@4333{O`@@@N`@@@N`@3333@@hfffK`@ffff6@@H`@@@`E`@̔@@-D`@@@4333OC`@@@hfffNB`@@@i=`@3333@@l:`@@@:`@@@p;`@@@4333;`@0@@x6`@ffff@@hfff5`@@@hfff3`@@@2`@ffff>@@H5`@3333@@43339`@3333@@hfff<`@܂@@=`@ffffv~@@?`@m@@4333<`@3333 m@@:`@3333Cr@@43338`@ffff&~@@43335`@̬@@15`@Y@@hfff^5`@ffffv@@6`@p@@hfff&9`@ d@@t:`@\@@9`@R@@8`@ffffI@@H;`@̔O@@l>`@a\@@4333A`@b@@D`@_@@,F`@hZ@@4333G`@̬V@@hfffI`@fffffV@@J`@ffffY@@K`@`@@PK`@g@@hfffrJ`@3333#m@@hfffH`@n@@G`@dl@@E`@l@@hfff^E`@Dw@@hfffE`@@@4333D`@3333k@@̨E`@@@G`@̼@@1I`@Г@@43337L`@ً@@N`@ffffy@@4333Q`@qj@@8R`@]@@hfffO`@ffffT@@hfffR`@,P@@4333T`@3333CO@@hfffQ`@`:@@N`@'@@4333L`@@@hfff6J`@ffff^@@F`@@@8F`@ffff @@DF`@)?@F`@ffffV?@4333F`@2333?@,G`@ffff?@4333H`@2333C?@MJ`@?@I`@|?@iI`@`s?@hfffVH`@2333o?@hfffD`@2333h?@lF`@J?@H`@E?@I`@2333SD?@4333R`@2333-?@4333S`@7?@T`@yD?@R`@ffff6Z?@4333KQ`@0g?@hfffP`@̬u?@4333Q`@ffff&?@S`@Y?@hfffT`@?@V`@?@4333X`@д?@Y`@٫?@4333{Y`@2333ß?@X`@ffff?@4333W`@2333#?@̈V`@2333ӓ?@V`@̬?@hfffX`@b?@EY`@2333D?@DX`@2333'?@4333W`@@?@4333V`@ffff?@U`@,?@U`@?@4333\`@?@hfff&c`@2333A?@ a`@`?@Db`@ffffo?@xd`@q?@g`@h?@hfffj`@g?@n`@?@5o`@ffffF?@hfffn`@,?@hfff.p`@@@@4333p`@@@r`@̌@@s`@)@@!u`@;@@mw`@K@@@`@ffffl@@q4333^@5@t{^@4333F9@=hfffy^@4333s9@̔v^@̼9@hfffn^@4333s'9@k^@|.9@(i^@;9@hfffe^@|F9@a^@4333F9@hfff\^@?9@4333cW^@(9@4333F^@9@B^@dffff9@4333=^@8@43339^@433338@5^@8@y0^@l8@L(^@z8@, ^@43337@t^@dfff&7@hfff^@І7@hfff& ^@)f7@^@ N7@y^@I67@4333^@dfffV&7@hfffV^@7@^@y 7@4333 ^@43336@hfff^@ɷ6@hfffv^@6@hfff^@܊6@<^@06@hfff^@ |6@̴^@ q6@43333%^@<[6@4333&^@4333P6@d+^@(6@4333+,^@y6@/^@̼5@5^@5@P7^@\6@88^@<$6@hfff&8^@ C6@hfffn9^@a6@<^@ɀ6@@^@О6@QJ^@6@R^@4333s6@4333V^@97@pY^@),7@^^@l7@4333a^@43337@hfffVe^@4333c7@T@0333!@hfff;T@`ffff!@hfff>:T@̌ "@hfff.9T@+"@4333-T@0333"@T@H#@hfff.T@#@̔ T@#@T@l#@hfffS@#@4333S@0333ӕ#@hfffS@0333|#@S@0333f#@hfffT@L#@|T@8#@T@#@iT@@"@̌T@"@YT@L"@iT@0333S"@̌ T@`fff#@hfffT@'#@T@0333"@4333T@Y"@`T@k"@hfff&T@0"@4333sS@`ffff!@4333cS@`!@dS@y{!@hfffFS@ b!@tS@ @hfff>S@̬ @S@ @$S@0333s @4333S@`fff @S@`fff @S@Y] @LS@! @4333S@/@S@@W@S@03333Q@4333S@̌V@hfffvT@`fff&u@T@ٜ@T@ @4333T@`fff&@X.T@̌@hfff&>T@Z@ST@@QXT@0333@4333hT@Y@̜mT@`fff& @4333#qT@ u@4333ctT@Y@!wT@`fff@ xT@0333@wT@@'@@uT@0333@tE@ 9=I@((3F@ 34333S7F@39F@hfff34333s9F@m3y1F@M3F@@34333F@Y34333sF@2hfffF@2F@Y2 F@hfff2 F@I2F@1F@43331,E@1hfffE@ٔ1\E@@d15F@0hfff7F@05F@Li06F@J043338F@hffff>04333+4333H@i+̬ H@Lp+9+H@G+3H@8333s+4333@H@*OH@*4333eH@8333*hffftH@hfff&)uH@)hfffvrH@q)ImH@hffff8)hfffdH@(hffffH@L(hfff&sH@(4333CwH@(4333H@8333(H@((H@ )(4333H@8333s?(4333CH@`(hfffH@y(iH@hffff(hfffH@@(hfffH@)4333H@83333F) H@hffff)0H@83333)H@%*H@Y*hffff I@hfff'+@I@,0I@hffff- I@v- (I@hfff-|8I@8333sL.=I@8333s.3I@B/P%I@̌/4333!I@/I@/̬I@hffff/hfff I@/̜I@/H@hfff%/@H@Y.9H@.43333H@hfff&. H@ /0H@L"/`H@83333d/9H@8333s/H@/YQSffffPQhfffvS(QS Q̼SP̬SffffP4333sSPSffff^PS̘PhfffSzX/K7T4333xEArShdfff>Ehfff>SESdfffES4333kE̤SlEhfffSEhfffVS`E4333S F̴S+FSLF@S mFASFixS F4333tS!G4333sSiGArSԃGrS4333SG4333ktSdfffGuSdffffH S4333cHSTHEhfff>S{ffffZPhfffQR@QRCQ3333RTGQffffRLKQQRlNQ)RQQQ UQYQyWQQhfff[Q3333QaQffffQiQ3333QhfffsQQ8vQEQ,zQQ ~QffffQTQQpQ̌QhfffVQffffQ4333Q̄Q4333Q3333GQPQ QQQ8Q3333Q̌Q3333QQ3333xQQ3333gQyQ3333;jQ4333cQfffflQ4333Q3333k~Q QɅQqQ3333QhfffQQܙQQ`Q)Qhfff6Q QQ)QhfffưQ3333Q4333KQHQXQQ4333Q3333QpQQ|QQiQ{QXQ xQQ%uQyQtQLQtQ(QffffruQQffffwQ4333 Q3333zQQ!QhfffQffffQQ\QQffffnQhfffQ3333kQhfffQffffQQIQ4333#QQIQffffRQx-R4333QCR Qffff?RQ33339RHQffffRQ RqQ'R4333Q4ŘQ3333CARQ3333oYRhfffQU^R4333QfR4333sQffff~gRaQffffeR̬QTXRQffffV[RQ^R Q3333bR̬QffffZnRhfffQ{R4333 Q3333RDQ3333R4333QR4333Q̴RQRhfffQ9Rhfff>QffffRhfffvQ3333SRQŘQ3333RQ3333˚R4333+Qffff2RhfffQffffR̄Q=RhfffQ`R4333QR4333[QxR4333KQRQ3333RpQ,Rhfff&Q3333RQffff~RQ̘R8QRhfff~QMRQ3333R4333CQ R!R3333KRRffffrRyRyRhfffRRhfffR3333_R4333 RffffʉR) RRhfff RyR R`bRhfffnR̠dRQffff2lR4333{QuRQqRTQhRpQRQffff^;RQaR4333cQ3333RhfffvQ̔R QRhfffVQJoP4333SKffffPLKPIDKP4333s8KffffP4333#(Kffff^P|KffffrP4333KP`Kffff*P4333JfffffPJP4333J-P43333J3333Q43333J8 Qhfff֨JP Q9J(QJDQhffffJP!QhffffJT!QJQJQ4333JPQ4333Jffff^QyJffffQ4333}JffffQhfff6sJffff$Q4333XJP(QSJ0*QhfffPJ3333{0QJJ2Q4333IJEQPVJ̰JQ4333sUJZQ<>J_Qhfff>JdQPFJ3333sjQRJffffpQ̜]JffffxQhfffFfJffff{QiJffffQ iJQ`bJ3333#Q\J3333oQ]JTQ@`JQ4333hJffffQmJffffjQ4333sJffffQ̬uJ\Q̬xJLQhfff&|J3333Q~JhQhfffJ3333{QhfffJQ4333cJ`Q4333JpQYJtQhffffJffffQ4333J3333QhfffVJ3333QJȅQhfffJwQܬJ\pQ)JhQ4333êJ`QhfffƫJ0YQ̯JVQIJffffVQpJXQJ$lQJ|QhfffJԅQ4333cJffffQlJQ̬JffffzQlK=Qhfff KLQ\-KffffBQ4KBQhfff6KDQhfff8K3333/HQ4333:KJQ=K4PQYGKSQhfff&IK3333TQhfffvEKffffTQ|>KXWQ43338KZQ4KgQ.KffffzoQhfff&'KsQ)K|wQ /Kffff^Q0KЊQ̌0K3333Q,KQ4333#KQQ KffffBQlK3333OQhfffKyQKMQLJ\Q\JQLJQJ̄QJ3333?Q4333SJ̈Q,JԶQhfffvJK3333QhfffCK3333QI@KQ@K3333߬Q4333#>KQhfff5KQhfff,KffffQ4333)K|Q@+K3333gQhfff.KffffQ43332KffffڽQ43335KQ8Kffff*Q̬9KQ̜2K-Q93KffffQ43338KQhffff?KQ4333?KQ8K5Q̌7K3333QVS 4@NS̤4@ffff&MS`4@LSY4@FS}4@ES4333s4@̤FS4333Sh4@ISdfffX4@MSdfffL4@pcSdfff4@mS3@̤]S43333@̐MS3@3333?S3@8S3@33331S3@!S3@ffff.Sdfff3@$ S`3@R3@Rdfff3@3333SR 3@3333R43333@3333 R4333s3@XR3@R4333#4@ffffR433333@Rdfff3@3333sR43333@4Rdfff3@ R93@3333gRdfff4@R43334@`RI4@ffff.Rdffff4@ffffR4@ffff։Rdfff&+4@R`;4@RJ4@R̼O4@RS4@uR@Q4@RT4@3333נR4333sb4@1@3333oS@2;@̔T@}`:@= T@o:@3333; T@9@5 T@L9@ T@9@l T@hfffx9@3333T@833338@̴T@833338@ffff>T@8@HT@8@3333KT@83338@T@8333g8@3333T@,L8@T@G8@3333T@;8@fffffT@$8@T@83337@ffff~T@7@T@ 7@8 T@8333sZ7@ffffr T@8333S7@3333 T@97@TT@hfff@7@`T@P7@33337T@Y@7@ffffT@ 7@UT@6@T@hfff6@ffffT@ 6@hT@6@3333T@hffffs6@ffffT@j6@dT@9r6@T@8333Sq6@- T@Y`6@̼T@,J6@ffff&T@833306@ffffT@83335@ffffzT@5@T@Y5@0 T@hfff5@3333 T@5@T@4@HT@4@3333T@hfff4@T@8333y4@T@\4@̨T@83334@̄T@hfff3@(T@3@̔T@hfffF3@ffffT@3@T@83333@T@8333s3@ffffT@`3@T@hfffF3@ffffT@hfff3@T@8333S3@T@hfffC3@̀T@hfff-3@8T@,(3@QT@13@T@Z3@ T@3@ffffr T@hfffW3@3333sT@$3@T@@2@0 T@2@ffffb T@hfff2@ T@1@( T@hfff&!2@ffffT@hfffX2@T@ 2@XT@2@ffffS@92@ffffS@`A2@xS@hfffH2@ffffS@ S2@S@8333m2@S@2@S@,2@ S@hfffff3@S@Y3@S@ 3@̠S@4@S@8333u4@S@4@S@8333ӯ4@ffffBS@4@1S@8333S~4@3333S@hfff/4@3333wS@4@S@833333@S@hfff&3@̌S@83333@S@8333s3@)S@8333 4@US@hfffFf4@S@hfff4@AS@94@5S@8333s4@ffffvS@8333S5@3333cS@83336@\S@6@3333S@hfff6@3333S@Y6@3333S@@7@(S@7@3333oS@hfff"8@ffffS@A8@S@hfff&b8@MS@hfff&8@US@hfff8@̀S@hfff&%9@S@83333=9@S@hfff&9@3333S@83339@$S@9@S@:@}S@8:@3333[S@8333s;@ffffbS@2;@S@%;@ffffT@hffff;@T@`:@= T@ @]%@3333%S@hfffc5@]T@5̌4@3333S@hfff5@HS@8333s>5@3333ìS@hfffc5@3333cS@@Z5@hS@O5@3333S@83335@S@hffff4@3333S@,4@3333ϾS@hffff4@S@l4@3333S@Lu4@ES@hfff)4@ffffRS@L4@S@ 4@S@3@̘S@93@eS@}3@ffff>S@hfff3@ S@2@3333wS@L2@ffffS@83332@S@hfff2@S@8333S2@S@83332@3333gS@̬2@S@2@S@83332@ffffNS@hfff2@ffffzS@2@ffff>S@ٔ2@̔S@e2@3333S@8333SU2@S@hfffE2@pS@l1@S@833331@3333S@ 1@S@hfff1@ffffS@1@ffff"S@̌1@3333sS@1@S@hfff1@ffffS@hfff1@4S@L1@S@hfff1@ffffS@,81@5S@hffff0@3333_S@83330@aS@83330@ffffS@hfff0@S@hffff0@S@hfff&0@PT@b0@]T@hfff>0@ffff*T@hfff0@xT@0@ S@hfff0@ffffS@Y/@ffffrS@@333/@3333S@̦/@`S@١/@3333S@@333s/@3333S@ /@3333;S@ 0@S@hfff@0@,S@X0@xS@hffffK0@ɾS@̌/@S@01@ffff@S@ '1@!CS@@Y1@ffff JS@hfffFq1@ffffjNS@83331@3333YS@1@3333_S@,#2@3333s`S@Y:2@ffffraS@yL2@3333eS@hfff\2@ffffkS@lg2@rS@Lp2@ffffJ|S@@n2@eS@8333sp2@ffffS@2@ffffS@Y2@̐S@8333s2@3333S@2@33337S@93@3333wS@hfff&2@S@2@S@@3@iS@hfff&3@HS@8333sa3@̴S@Y3@ffffS@̬3@3333CS@@3@3333S@3@ffffڧS@8333c4@3333+S@̌4@3333S@\ @ptC@L#@D@R@3333]#@hD@C#@ffffpD@pfff%#@ffffuD@#@PwD@@333-#@ D@ >#@D@ ;#@ffff6D@&#@D@#@ffffކD@#@̜D@ "@8D@"@3333D@pfff"@ЙD@@333t"@D@@]"@D@S"@3333D@pfff6"@3333KD@ !@ D@@333s!@ffffyD@e!@rD@$!@3333lD@ @3333jD@ @TlD@̞ @3333mD@̌} @tD@r @tD@Yh @3333soD@\ @bD@@a @hSD@pfffu @MD@L @GD@ٴ @@D@L @8D@ @-D@L @ffffv%D@ @3333D@ @ffff D@@3333 @D@@333s @4C@ @hC@pfff @C@@333s!@3333kC@!@̄C@!@̤C@!@`C@@3333 @C@ @`C@ @C@pfff @ C@Y @3333C@Y @̤C@L @YC@ @TC@@333 @$C@L!@C@0!@ffffn{C@ L!@vC@pfffo!@ffffvC@@3333!@ptC@@!@tC@pfff!@3333[{C@ "@C@"@̜C@4"@3333 C@@333sL"@ffff6C@@333i"@ffff^C@@"@C@@333"@qC@"@ܑC@ #@@C@*#@tC@pfff;#@\C@@_#@QC@i#@ffff.D@f#@ D@pfffQ#@aD@@3333I#@3333["D@pfff&#@<3D@̐#@33338D@L#@?D@@333#@1GD@@3333]#@hD@!!@DD@pfff#@E@=H!@!E@pffff!@< E@@333g!@̄E@̌N!@ffffnD@@333:!@D@pffff>!@!D@pfffX!@D@{!@3333kD@@333s!@iD@@333o!@D@o!@ffffvD@!@YD@ !@D@ !@3333D@٨!@XD@@333s!@PD@pfff&!@D@@!@D@̌"@D@L_"@DD@"@3333D@pffff"@ffffFD@"@3333D@pfff&"@D@@"@ffffD@Y"@xD@@333#@3333E@pfff#@E@pffff #@̼FE@#@JE@L"@3333NE@̌"@LTE@@333"@gE@ "@$nE@@333"@xE@@3333"@}E@"@E@@333"@9E@@333s"@ffffxE@pffff"@33333hE@@"@)bE@@333s"@I[E@L"@XE@́"@1[E@pffffe"@ffffV]E@F"@]E@@-"@K`[Q@2333cK3333YQ@ffff~KffffRWQ@̌KUQ@ffffvJTSQ@ffffJPQ@ffffJffffPQ@ JlPQ@fffffJUQ@ffffbJffffJWQ@iJM_Q@Hffff2 `Q)H@)^ffff&nI@3333^ffff^YH@3333[^aXH@3333O^3333SVH@3333C^MH@3333^JH@^yiH@%^yH@3333{^H@^AH@ffff^ܕH@3333^̬H@ _yH@_̬H@$)_ffff޶H@(5_H@;_3333SH@̬;_H@9_H@;_ffffH@@D_H@N_I@T_ I@Z_ I@ffff^_̌(I@ffff2b_ffff+I@`g_-I@̴u_ffff0I@ _:I@ܬ_AI@̠_QI@ffff_ffffiI@_ffff&nI@>`3333mI@̺`jI@ffff `ffffeI@ `3333C_I@ffff2 `)YI@̎`MI@3333W`BI@`ffff?I@̬_ffff?I@3333W_3333?I@3333_3333DI@3333_3333II@_ffffMI@_`LI@_3333JI@3333_̴DI@_t?I@Q_33336I@3333#_33333I@_3333;I@ _3333S=I@8_3333K_I@3333O_I@0_I@_3333I@_I@3333w_ I@\_ffffI@_ I@`_3333; I@-_ffffI@_I@_̌I@3333O_ I@3333_\ I@ffffv_pI@H_H@_ffff~H@_H@P_3333H@ffff_ffffH@̈_H@3333_3333H@D_̤H@й_H@\_ffffH@_H@_0H@_ffffH@ffff_H@_3333H@ffff_0H@͙_H@ffff>_ffffH@̔_ffffH@_8H@ffffV_DH@ffff_̔H@_H@_H@3333_H@9_ɲH@_1H@3333s_ffffH@ffffʚ_yH@|_ffffH@_33333H@3333C_HH@3333_H@ffffΊ_$H@d_H@3333˄_3333SH@_3333H@L_3333H@{_3333cH@3333|_̜H@3333~_٤H@|_H@ffffz_H@xu_iH@r_ffffNH@n_̔H@el_ffff^H@i_3333H@3333;i_ȗH@ffffl_ёH@3333s_H@ffffu_H@Ej_3333H@ffffb_ffffyH@3333S__ffffwH@u]_txH@33337W_ffffH@J_~H@Y;_сH@ffff9_H@ffff7_ H@5_̑H@33334_3333H@ffff4_8H@333373_ffffH@ffffJ4_H@`6_ffffH@3333;_izH@3333H_DiH@ffffH_̼fH@G_aaH@ffffA_[H@7_SH@3333,_tLH@_3333AH@`_7H@3333^3333{1H@ffff^*H@ffff^Q)H@U^(,H@3333^ffff63H@^6H@h^4H@^̜4H@)^3333C:H@q^MH@^UH@3333^ffff^YH@Rdfff1@̴Qdfff3@3333+Q2@9Q 2@BQ`3@3333oJQI3@3333QQI 3@LYQ 3@̈`Q̌3@gQ)3@3333gQdfff)3@fQ43@3333CaQdfffF63@TQy33@PQdfff93@NQdfffE3@TQdfffS3@ffffRoQL3@3333tQ]3@ffff6xQ)y3@ yQ3@<}Q3@ffffQdfffF3@HQ٢3@hQdfffV3@̀Q43333@ffffQp3@Qdfff3@3333Q3@ffffQ43333@AQ43333@ffff^Q4333#3@Q3@ffff>Qdfff3@Q 3@Q3@DQ3@ffffQdfff63@lQ3@ffffQ@3@0Q3@ Q03@3333Qٷ3@lQ\3@3333Q3@R3@R433333@(R3@8Rdfff3@GR`3@MR93@ffff.TRdfff3@ffffYR43333@ffff\Rܸ3@]YR3@1TRdfff&3@`CRY3@ffffB7R̬3@-Rp3@y/R4333W3@ffff&1R=3@p/R!3@3R4333S3@3333)Rdfff2@ffffRY2@@Rɬ2@0R̬2@R2@ffffRdfff2@ffff'R2@9*R2@3333,Rw2@3333S/R0q2@̄2RPo2@̴:Rt2@eR2@kR2@33333wRP2@ffffv~Rdfff2@lR 2@3333Rdfff2@4R2@̘R2@R43333s2@pRd2@њRX2@tRD2@3333wR433372@3333SRdfff$2@3333xR 2@̴uRdfff2@tR,2@oR433302@8iR4333:2@3333`R>2@ffffXRL@2@lQR;2@ffff>JR433342@33338R&2@ffffV0R'2@(R-2@%R/2@h#RY52@ffff: RL82@R4333:2@!RdfffF62@̌Q4333/2@ffffQ2@,Qdfff 2@̘Qdffff2@ffffQ@1@Q1@!Qdfff61@ffffnQ 1@3333kQ43331@,Q1@Qdfff1@3333SQdffff1@ffffQ43331@3333Q1@Q2@IQ 2@3333CQp92@ffffzQdfff@2@QE2@(QJ2@̐QyX2@ffffBQ4333V2@0QD2@3333Q72@Q4333s@2@QF2@ Q|X2@,Qdfff_2@ffff^yQj2@ffffRqQ̌q2@3333CiQdfffo2@ffff>aQij2@hYQ̌k2@QQp2@DQ43333f2@ffff;Q4333sh2@3333s4QV2@ffff1Q D2@$.Q72@ffff+Qdfff72@ffff**Qdfff82@ffff.'QdffffN2@$Q[2@̐Qdfffa2@xQj2@ffffQ2@̴Q̌2@hQЫ2@Qdfff2@3333+Q2@pdfffeI0H̽K0Hֿ̔4333C2Hӿ8HgffffѿAHhfffϿDKHhfffͿdfffdHhfff˿HĿHPĿ9H|ſHy˿HhfffͿxHhfffVͿdfffI̽;Ihfff&ĿRIgfffvѿ4333XI4333S׿[I޿dfffYIdfff&\I3333̼bI3333dfffcI3333dfffeI4333CdIffff*ZIffff>KI*񿘙IIffffdfffNJI@3333;dfffFLI\4333UI`]I@3333@aIdfff\I1VIAOI4MI*@I43338IQ+Iffff I@3333iIBdfffFIVdfffH@33335dfffH̤HdfffFH@3333@HfIHffffH/4333 H4333#H4333Hdfff6HAHffff4333HdfffHH943333~H@3333dfffvH4333jH=4333fH@3333;jHl4333{kH󿘙eH@]H0ZH̴񿘙OH̔IHffffdfffVFH3333EHHH3333BH ̬?H3333G4333c;HῘ6HAܿ0Hֿ̔`fff̼I@?33333SM@@fffffffffL@L@ L@@fff8 L@3333[ ffffL@@fff4L@IffffL@̒9L@333̜L@ffff&L@333L@ffffb̜L@aL@ffffr33333L@}̬L@[L@L@)3333#L@3333]L@333̤L@@ffff L@nL@i]L@3333{QL@̽GL@rAL@3=L@ā9L@p6L@3333 $1L@z ffff.L@ 3333.L@33331L@2L@8̼(L@@fffdp L@$L@L@m A L@@ffff$ L@@fff L@@fff 33333L@ 3333L@P0 L@ ffffL@ L@cK@@fff3333K@@fff\L@@ffffffff~L@3333-̔K@"3333kK@H3333K@,K@ffff|K@3333K@ffff\8K@3333aK@ffffcK@3333ZK@ffffxffffSK@ffffLLEK@|@K@ffff33332K@׿̼#K@dfffͿffffVK@K@ĿQ K@PʿK@ſJ@`fffffffJ@?J@hfff?J@8333?J@y?J@`fff擿J@ಿ3333cJ@@ƿ̼J@HѿffffNJ@2333ݿ3333J@ffff*⿙J@̬J@2333 ߿J@ҿffffJ@l?J@X?J@?yJ@4333?aJ@hfff?؃J@ٿ?\|J@?3333sJ@?3333gJ@!?3333gJ@q?iJ@?mJ@4333?xJ@?{J@4333?ffff}J@t?L|J@gfffZ?zJ@?zJ@3333W?XvJ@3333?ffff^rJ@?y`J@3333u?VJ@? JJ@?I@?I@gfff?$I@4333?I@gfffR?3333I@?ffff~I@4333;?3333#I@4333+?I@?3333I@5?ffffI@?̳I@?3333{I@u?I@3333=?3333 I@3333?3333I@?ffffI@?I@ffff?ɧI@ffff\?LI@3333?ffffI@? I@P?`|I@?3333vI@4333?̌wI@gfff?YqI@?I@VџI@ I@SffffƼI@@ffffI@@fffffffI@@fffvI@PI@@ffffWffffI@@fffaI@I@ffffvI@ I@LX I@333 I@I@L 3333I@3333{I@3333I@ vI@ 3333I@ٱLI@ 3333]xI@\I@OI@̌3333I@@ I@ 3333g3333kI@3333I@ 333)I@YI@`ffffI@@ffffnI@`ffffAI@ I@ffffI@ 3333ZyI@3333[J@>PJ@YAJ@ 3333333#J@ 3333333)J@`fff&fQ2J@3M@DffffBM@`fff&̄HM@ HJM@ٲPKM@ =TIM@`fff&FM@HAM@̼AM@#GM@ 3333333HM@`fff̤AM@`fff&3333SGM@LffffIM@@ffffK 3333MM@@fff ffffNM@333 33333SM@333lAQM@^NM@333t\KM@3333AM@33337M@3333ffffV4M@ l0M@@fff ffff)M@333I ̬M@333333333M@L@ffffL@ 333s$ffffL@3333AyL@@ffffffffL@L@LPL@3333L@@fffffffffL@ @$3333I@ 3333333ӮK@%0333# I@ #ffff.I@(#9I@L#3333I@0333$9I@0333=$3333I@̌#$I@0333S#I@ #I@0333#3333I@#I@2#I@ +$I@`ffffl$LI@`fff{$ffffI@$3333CI@`fff$33333I@0333v$̼I@̬J$J@̌$̴J@`#8 J@#̼J@`#ffff~J@$J@$DJ@`fff$̤J@$|J@l$ffff"J@C$3333$J@$Q#J@y#1!J@`fff#3333kJ@0333S#3333 J@#ffffN%J@ٴ#0J@`fff#̬3J@L#8J@0333#;J@0333C#FJ@03333,#3333GJ@"JJ@"OJ@ !ffffVJ@!,[J@`fff!`J@ 2"UJ@Y"DQJ@"NJ@L"ffff>PJ@@#̴SJ@`fff.#3333cRJ@03333=#ffffOJ@Y#K@0333u ffff@K@b AJK@0333SD ffffRK@ MK@ !1WK@,n!3333]K@0333L!daK@!8dK@,!̜gK@`fff& pjK@, qK@ {K@Y ̜K@̦ 9K@ ٍK@ K@F xK@  K@K@ 333s63333K@̌ȗK@ ɟK@ԠK@`fff3333;K@tffffK@ 333GK@:̤K@WȊK@ K@\4K@̌H|K@`ffffV3333;K@`fff3333K@̌ffffK@ffffK@ 3333 ИK@L̼K@LK@5ffff>K@v3333K@ 3333<3333ӮK@0K@ K@ 333=AK@3333sK@93333ӖK@K@`fffffffƋK@`fffHK@ gffff.K@QK@`fff\K@Lffff.K@`fffL K@3333ØK@ 333sٞK@L3333K@K@@3333ӛK@`fff$K@`ffff̃K@ zffffFuK@ 3333hK@`K@̌\K@ 3333WK@ 333ffffRK@6ffffTK@Yffff&VK@T3333TK@POK@ 3333333FK@ 333ffff@K@8K@:K@ 3333F̜AK@v3333DK@ 3333ffff^FK@3333+=K@ 3330K@ 3333/K@ 3333;|/K@Ym3333"K@ xK@N0K@`fff&kK@K@@fffff K@K@`ffffzK@@3333[ K@ 333K@ 3334K@ 3333ffffvK@;iK@ 333sa\J@ 333c|J@LI3333J@̌J@3333sJ@̌J@@J@ܿJ@3333J@ 3333J@LffffJ@ 333ffffJ@JIJ@.3333J@ 3333vJ@ 3333InJ@̅TgJ@`ffff3333{^J@TJ@ 333s̄EJ@ 333at3J@̌.J@L4,J@L3333J@ 333sJ@̌>3333+J@ TJ@!J@Yp3333J@aJ@3333J@ 333J@Y<J@SJ@`ffffffffJ@ 333s̴J@ 333 J@ 333@3333J@\`J@`fffffffI@hI@ZXI@}I@YI@ ̬I@@J !I@`fffq PI@03333 lI@ I@ 3333I@`fffF )I@ٱ I@0333ӫ I@ I@ $I@`fff I@03333-!`I@ x!ffffnI@y!ffffI@̗"ffffƿI@0333ӥ"̤I@"xI@"I@#ffffI@y#3333I@0333#ffff޽I@0333k#ffffFI@0333# I@ (f3333P@3333U7e>Q@Bf>Q@yf0eP@3333@e$P@EeP@3333Lel{P@3333MQe3333cwP@ffffRetP@3333SQetmP@QejP@ffffRUe3333gP@3333\e iP@ `ejP@ce3333{lP@lge(oP@3333letsP@3333}mesP@pnerP@lepP@ielP@3333Mdeffff2hP@ffffaeffff2cP@3333cce̴`P@ffffpeeffff"`P@fe-`P@keaP@neffffbP@Jye3333`P@3333}e_P@3333O~effff`P@3333~ebP@33335eHdP@|effffdP@ffffeDeP@PegP@3333e3333jP@ffffre)lP@ePlP@effffkP@3333ϑe3333+gP@Seffff_P@3333e3333_^P@ffff^e\P@ffffȉę\P@3333seffff*]P@3333ņeffff6[P@̢e`SP@eQP@ffff.eOP@3333We3333NP@3333me33333NP@ffffeffffNP@3333'effff*MP@ffff(e\P@`fffU+̈YP@j+lXP@`fff+WP@ +̴VP@0333+TP@r+3333RP@0333N+3333RP@@H+QP@0333sG+ffffzPP@@L+ffff*OP@W+3333CNP@03333j+MP@+ffffRLP@`)+3333'IP@+ffffGP@+@FP@̬#+\DP@2+LBP@M+AP@0333+@P@@+3333?P@٧+P=P@+3333:P@0333+-7P@@+3333'2P@,3333{/P@03333E,3333-P@ ,\.P@,,/P@`fff&,3333[+P@`fffF,3333(P@̌,t&P@,Q%P@y,t"P@`ffff,P@-ffffP@`fffA-3333P@@-3333OP@0333-uP@ .P@.P@l.ffffP@0333s/ffffN P@y0ffffP@l<0aP@0333w03333KO@0O@\0ffffO@03333O@Y1pO@)1O@033313333CO@1XO@033331tO@i13333SO@1ffffO@Y13333O@i13333O@|2O@`fff$2̜O@0333823333O@@2O@`fffC23333#O@D2ffffO@`fff82O@`fffM2$O@0333S2ffffO@ @33333O@|3@O@<3ffffO@03333O@24$O@0333f4̌O@y~43333O@`ffff4ffffO@0333}4O@Px4O@@p4O@)_4O@\4O@i4O@0333sv4dO@̗4 O@033343333cO@ 4O@ܺ4̌O@`fff4ffffO@03335PO@`fff"5O@'53333O@033353333O@ 5LO@0333'5ffffO@ ?5̼O@9c5O@r5O@`_6O@\63333+O@`fff63333O@i63333+O@6O@033336=P@л6P@63333SP@03336ffffP@0333c6,P@P6P@03336O@`fff06ffffP@6̐P@@6̄P@y53333 P@̬5ffff P@05% P@53333;P@5P@,5ffffVP@0333#5ffffvP@̜v5DP@03335ffffvP@̌5ffffvP@033353333P@ 63333P@ 6P@6qP@5P@0333#5ffffBP@,6qP@6P@I5 P@г5ffffB&P@ܝ5ffff 'P@033335ffff(P@`fff5(P@ɬ5t)P@`fff5$P@0333#6"P@0333(6|"P@A6$P@H6ffff%P@ S6ffff'P@0333Q6l)P@;6-P@`?6.P@N6.P@w62P@`ffff6|2P@0333X7ffff4P@y733333P@73333k0P@7ffffN/P@7ffff 0P@733331P@0333c73333;4P@03338ffffB7P@83333_9P@`fff73333:P@0333#7%;P@`fffv7ffffj:P@<|7̈P@0333L23333P@ .2ffffFP@01,P@1MP@0333c1ffffP@ 13333+~P@1̸}P@1̜~P@w1ffffP@j1ffffP@0333U1P@,'13333P@1ffff2P@13333P@033330ffffP@0ffff.P@0P@0lP@03333P@)|0ffffP@`fffo0)P@`fffm0БP@i03333P@L~03333˞P@0333?03333wP@0 03333P@`fff/P@̬/P@/P@0333sm/3333P@0333g/IP@0333sK/P@0333/P@`.3333cP@Y{.P@`fff&S.3333P@-P@0333S-iP@\-ffffP@03331-3333kP@03330-3333P@@g-P@0333-ffff6P@H3333AP@R2@6P̜b2@6PT2@33338P_2@ffffJX̌<@5?Xffff&;@ffffNBX0;@3333@X;@3333:X<@ffff5X̼<@Hd@#VffffC>@3333C.VffffC>@3333-V2333>>@0*V9>@$Vl4>@#VffffF7>@$V:>@3333C.VffffC>@P=V;>@̐V2333F>@V2333F>@Vffff6A>@=V̌=>@3333V;>@ffff2 V;>@̐V@>@V2333F>@`ffffO2@4Odfff2@ O92@ffffOdfffv2@2333O 2@2333O2@2333O 2@4O43332@,O43332@2333Odfff2@O92@`3333dPy2@3333RP@*2@ 3333dPdfff@ffffcP2@A`Py2@<[P 2@3333RP4333#"2@3333_SPdfff$2@pWP<)2@^P@*2@3333dPdfff@POO1@ DOdfffv31@OO,!1@̌JO1@ DO433331@`DǑ+1@IOdfffv31@NO21@OO,!1@PfffffPu2@3333Py2@DPY2@fffffP0y2@Pu2@Pu2@3333KPv2@3333Py2@DPY2@Hi2PS2@ffff:*P9_2@i2P4333SW2@Q1P4333T2@ffffv.PS2@ffff:*PdfffZ2@(0P9_2@i2P4333SW2@P|,P,f2@"P@r2@)PIq2@|,P4333ci2@3333*P,f2@ffff%P g2@"P)p2@l$P@r2@)PIq2@P33338P43331@ffff&%PY1@33338P43331@+P4333ô1@ffff&%P 1@3333+P 1@1PY1@33338P43331@33338P43331@hffffcS<8@9QS@9@ \S9@aS43339@ffffcS9@3333bSy9@x]S<8@ffff>VŠ9@9QS9 9@3333QSdfffF9@US@9@\S9@PffffHTp8@̌;Tl8@tET43338@ffffHT43338@ffffETp8@BT8@ffffJ?TdfffV8@̌;Tl8@tET43338@X4333\@dfff16@̏\@K6@4333\@J6@\@4333D6@4333C\@dfff16@َ\@dfff56@hfff\@;6@̏\@yC6@hfff\@K6@4333\@J6@P!+SffffSA@"SffffYA@3333'SffffXA@"S3333SA@ffffb$SffffSA@ffff&STA@]*S3333WA@!+SffffYA@3333'SffffXA@ffffeC5ffffey5ffffehfff!5̰ehfff&)5eC5ye4333395e`(5ffffeY5-ey5Rel53333ehfff5ffff6ehffff5ffffe%5ffffde'5ffff.eY+5e`+58ehfff#5ffffehfff!5X4333FJ@ffff^F@4333XJ@ffffF@lTJ@PF@MJ@ffffF@4333FJ@3333F@hfffLJ@ffffζF@UJ@ffff^F@YWJ@ffffF@4333XJ@F@lTJ@PF@P4333sG@(F@YG@3333F@YG@3333F@^@D4333s^@ @^@fffft^@ffff4333^@!PY_@%A@hfffF_@̬2A@̬_@̬2A@_@ffff1A@Y_@,A@_@'A@hfffF_@%A@1_@,A@̬_@̬2A@Xc@}S@Yc@x S@̔c@x S@c@0 S@c@0 S@)c@}S@Yc@ffffS@c@u S@̸c@ S@̔c@x S@XP@ffffR\Q@4333P@3333dQ@P@3333dQ@P@^Q@hfffP@]Q@4333CP@ffff\Q@P@ffffR\Q@4333P@aQ@ P@dQ@P@3333dQ@pDP@Q@4333cP@3333sQ@ 4333KP@̸Q@P@ed@lPgd@̌P4333id@qPid@hfffPhfffid@P̬hd@ Pd@hfffvvSI+e@YJSle@hfffXSd@e@TR hfff^e@4333`Rhfff^Y@\kPAOY@!dP4333PY@aPhfffNY@9^P EY@4333YP8Y@43333XP&Y@hfff^YP4333"Y@,ZP43333Y@]Pp TU@4333P4333|U@4333KP UU@4333KP TU@PhfffVU@̬P4333gU@4333ۼP4333gU@ȽP4333iU@4333PtU@4333P4333|U@9PsU@4333PacU@PUU@4333KPpW@hffftP4333*W@lP 4333KW@4333;mPW@4333[oPW@̤pPPW@sPW@hffftP|&W@4333sP4333*W@hfffqP*W@4333pP(W@4333nPW@lP4333KW@4333;mPh܎U@PU@0P U@0PhfffƑU@hfffP܎U@PU@hPhfffNU@P̬U@hfffPU@hfffPU@4333+PQU@hfffPU@0P`hffffDU@hfff.PhfffUU@0P 4333JU@aPGU@0PhffffDU@\PEU@̬PhfffHU@hfffƨP$Q@4333+ RQ@4333R4333+Q@hfff6ŘQ@4R*Q@RL4Q@4333R5Q@hfff R̬.Q@̴R*Q@RxhfffX@hffffP4AX@4333KP ̌.X@Phfff6'X@4333KPX@PhfffX@!PhfffX@P@X@hffffPhfff;X@ٌPAX@hfff~P4AX@P4333[@X@1P;X@̼P̌.X@PhfffQ@4333Q4333;R@Q4333R@QR@QR@S3333Ib=Sb;Sffffb̜9Sxb6SDb-S ދb2SDb4333c1S3333Kb̤/S4b.Sb.Sb-Sbt0SbhfffV4S|b6S3333bhfff5SlbT3Sދb2Sffff4`̴R^`R|g`xRffffq`Rs`Rhx`Rffff~`XRffff4`@R`R̀`hfffFRz~`4333Rffffz`Rffff"s`pRe`̴Rffff"b`\R^`hfffR^`43333R3333e_`R|g`xR]ЇRffff&]qR!]hfffR̴]R]RX]4333}Rffff&]1xRffff:]duRd]hfffsRffff]qR ]qR]4333sR]]4333#tR3333W]QRfffff]dR]hfffށR]8R]9R3333]R̈]ЇR!]hfffR}Y]hfffVR3333 ]dwR3333g]dwRX]LR}Y]hfffևR3333;W]LRN]hfffVRE/]R$]4333 R3333 ]R0"]TR&]4333cRi%]hfffR]!R3333 ]DzR ]QyR3333g]dwR3333E`hfffRffffJ_4333R!_R3333_,S ffffb /SffffPb.S3333bhfff>,Sb̴-Sbhfff&/S3333b̼0S3333bhfff~2Spb1Sffffb /Shxmb4333SVbS ffffdb4333 S\b4333SVbSffff^^bHSffffkbS`mb4333SxmbhfffSffff mbS kb4333c Sffffdb4333 S`^kb4333-SHYb"S Q^b̄#SffffTdb"Sffffhb\#S^kb4333'S3333gb*S ]b4333-SHYb̄(S\b $SQ^b̄#Sffffp~d4333CfTd4333RTdeT̈dIdTdiaT3333d]T1d4333cYTNd TTkfd4333RT{d̼TT}dVTffffp~dYTffff~dYT||d[Txdx\T3333hd^TEd4333CfTdeT`3333_b4333WSfffffbNS ffffbNSbhfff~NS3333_bhfff~QSbhfffRS2b4333WS̴bWSfffffbhfffVVSbqUSffffbNS xchfffNTffff=chfffS ffff=c!T@chfff6SQcS0ecqSuchfffS xcSpc,SnachfffS"^cS3333PcT)Kc4333TffffCchfffNTffff=c!T;bhfffHSab8SdbhfffHSabhfffGS:bhfffES3333Sb ES"bhfff&CS3333/b4333@S3333÷bT;SffffFb8Sܻb8Sb̄9S9bD;Sffffb4333SbhfffF@S3333bDS3333gb\FS$bhfffNGSPb9HSdbhfffHSxc4333+T̴cqT Xc|TffffcyT3333=cqTcqTffffcdtTcxT3333sc|TffffchfffTffffpc4333+TcT̴cTXc|Th4333#Q̌hfffQ `fffEhfffQhfffQQhfff6Q 3333yQٟ4333#Q̌XQLQ 333Q`fffEhfffQxffff@Q@3333 @lQ ̓@lQ@3333 @hfffQffff@hfff6Qffff@Q@QK@4333;Qffff^ @4333sQ@3333 @9Q@3333 @Q@3333 @ęQ̊ @!Q̓@lQx; $Q̣PQ 1 Q3333" 1Q; 4333Q hfff&Qy 4333Q ̼Q|$Q̣hfffQ@fff Q̳ Q333 PQ1 Qx4333c?hQ`?tQ ?tQm?0Q4333c?Q4333{?ЊQ̰?4333[Qffff?xQffff?43333Qffffb?hQ?TQ`?hfffQffff?4333Q ?tQ@fff Q)Q3333C4333#QlQR)Q@fffK 4333Q@fff Q@ffff QLhfff~QQhfff.QgܾQqQ3333Q@fffhfff6QDQQQ@ffffXhfff޿Q4333QhfffQQ@ffff 4333Q3333c9Q3333C4333#QffffG@4333+Qffffx@iQ @333@Q@Qv@4333+Q@4333Q\@hfffQffffx@QLX@ԒQfff@hfffQ@3333@iQffffr@4333QffffG@4333QN@єQ@333@Q%H@4333P̌dH@ܬP 4333QH@ܬP-H@4333 P&H@YP%H@P4333%H@hfffP&H@P`0H@4333P4333EH@0P)cH@бP̌dH@ Phfff&dH@4333ˮP4333#`H@hfffP4333QH@ܬP /@4333Q 0@hfffmQ@333/@hfffnQpfffe/@|qQ1/@hffftQ /@8wQY$/@xQL:/@|Q@333S/@ }Q/@~Qhfff(0@4333Q90@|QP0@4333 vQ 0@pQ̒0@InQ83333?0@hfffmQ@333/@hfffnQ@9@4333Q8333:@Q̬:@4333SQ8333Ӛ:@Q8333l:@Q8333M:@4333Qhfff9@4333ˌQ@9@4333Q9@ْQ`:@hfffޗQ̌[:@4333˛Q`x:@4333Qٛ:@dQ:@hfff֚Q8333s:@dQ8333:@hfffQhfffƼ:@Q̬:@4333SQ @TL=S,>aSl?Sٚ?4333CS0?S @S?hfff^S ?S,>Sl>Tl>S0333=4333CS0333=4333SL=hfff6S0333=S>4333S>hfffnS>tS@>\S,>aSdfffLB4333S4333@4333S4333S@4333S2ADSpA4333StASdfff&AS$BSpBhfffSqHB\SdfffLBS4333=BSdA4333S4333@S<@4333S4333S@4333S DQ3333vhfffQ 4333sQ3333v̔Qy4333QLhfff~Q@fffphfffvQ@ffffhfffQb 4333Q333L Q AQ 4333Q DQ@fff= )Q4333sQ 6R0333Si4gR4R)44333R|4R4hfffxRL4sRL4hfffmR4gR̬44333hR`fff4hfffNkR̬4hfffrR`fffF54333SxRY 5hfff&|RI5QR,5R 6цR 5R0333*5|R 5DR 4hR|4R0333S44333R̬4ȞR0}4Rj4`R0333Si4$R`l4PR4Rp<04333,R0YR M0R[0YR0333t0hfffNR<0!R04333C%Rs0)RLQ0,R,04333,R0hfffv+R),0hffff&RM0Rx03333)̌ Ř)4333 R `fff)4333kR@)4333 R`)R03333) R,)TR)hfffRp)4333 R`fffF-)̌ Ř) R)hfffR0333E)R`fff)4333kRhJ@4333Shfff?S ?̤Shfff?XS43333@S40@8S4333@@SJ@!SA@4333S+@Sdfff&@S?̤ShF4333]N F̬BNF4333KNdfffF̜RN4333F)SN4333;F4333]N FpYN4333ۗFVNFhfffRN43333F4333QNFONqFhfffJNdfffF4333ENF̬BNdfffFENFhffffCNhFHNdfff6FyLNFYONF4333KN`2333K|NKPN ̜K4333әN2333KNKhfffNffffK|N KINIKNKPN2333cK0N̜K4333әN!#Q4333SdP4333SffffQ4333SS!#QhfffSffffQSU QSP4333S3333PS3333P8STPSPSdPhfff.Sffff^PDS̴P4333SQSQ;L4333O2333s0LO LO2333+LhfffOLK43333OffffKOKOK43333OK4333OKOKhfff6OffffKlOffffǨO `2333LL}O̜NLhfffƅOffffLL4333OffffELhfffO2333S-L̜ONi_OffffM4333OffffNfN4333N4333cQx9N̜Q23339NԢQffffFNQxffff&yNQffffBNQ ffffBNQ2333CDNQ2333{NN4333Q23333dNQqN̻Qffff&yNQ2333tNyQffffeNQySNQFN4333cQDNhfffQffffBNQpffff^NLO@NhfffrO ffffQNhfffrOYZNsOffff^NlyOXN4333sO2333ONLOffff&HNhfff&OONI~O2333SON |OGN }O@N4333{OffffQNhfffrOxp|NyO2333GN̜O 2333GN4333O[N̜OeN̼OgNhfffOp|N̬OmN O2333cNyOSNOffffSNO,XNiOSNhfff&O2333GN4333O`ffff>W:R3333_pWhfffv4R EWhfffv4RW̬4Rffff>W4333 7RW8R3333}W:R3333rW:R3333_pWhfff:R,sW4333s8REWhfffv4RVAMRV#RffffV.RffffڰVhfff+RV'RffffV4333#RlV#R1V&RV4333'R3333KV4333;0RtV43337R3333V4:R3333V=RV4333LR3333VAMRHVKRffffV̼HR(V`ER3333V̌?RV:RV6RMVhfff4RffffV.R `3333oHZ4333MRm"Z9Z9Z9T@LmJ@T@4333×J@hT@4333#J@T@hfffFJ@qT@9J@ffffT@4333J@,T@4333J@̜T@4333J@ffff>T@̼J@ffff T@̜mJ@ffff T@hffffQJ@ffffr T@4333MJ@< T@hfffvFJ@3333 T@+J@ T@2̬K@3333T@4333L@3333oT@̜K@3333s T@L@ T@4333K@|T@ L@T@SL@$T@hfffZL@@T@hfffxL@3333oT@4333L@uT@4333L@IT@9L@i T@PL@T@4333CL@3333T@4333S~L@3333T@̬L@T@4333K@T@̬K@T@̜K@3333s T@3xuM@3333S@̜M@3333T@ yM@T@0M@3333sT@4333M@3333T@̜M@ffffJT@̜M@ffffS@,M@,S@4333SM@3333S@M@S@M@̰S@ٌM@̴S@uM@S@yM@T@4pffffPKP0K ̨PKaPɘKPhfffFKffffPKTPhfffKP̌K3333OPK33337P4333SKPIK3333{P0K̨PK5hR tFRhfffeF 3333RYoFQRlsFQR tFRqFRloFRhfffviFffffRhfffeFRhfffeFRhffffhF3333RYoF6̨RaHRhfffHhRUHffffRP\HRaHRaH̨R KHffff.Rhfff*HRhfffHlRH3333RhfffF HffffR4333 H RhfffHRy HRhfffHRl6H$R4333OHhRUH7RbIaR4333=IpR4333=Iffff^R4333=IR4333CITR9LIR̼SIR\WIR^ITRhfffaIffff&RbITR WIRhffffLIR4333SJIDRhfffFIaRhfffVAIffffRhfff?IpR4333=I8HRJ3333HR]J&SR4333Jffff\RyJffffJ`RJ3333'cRhfffJ3333iRJrR,JDxRJ8R{J3333RhfffyJffffR4333vJ3333R9wJRvJffffRhfffnJ3333_RhfffjJRbJR]JRhfff_JR4333SbJ̬RjJ3333RvJRYJ3333KRpJ RɉJffffވRhfffJR4333J|wRhffffJrR4333sJffff~gRhffffJ$fR`JLeRlJffffNdRhfffFJ`R4333èJ33333ZRhfffJffffrNRJ3333HRLJ,IR4333J\SRhfff6JSR4333J93333;QhfffFKffffQhfffpK?QhfffKffffQhfffKQ4333sK3333QK QhfffKffffnQhfffKy%QK@'QK3333G&QlKffffQ`KPQhfffzK3333)Q̜zKffff9QhfffFKlQ4333uKffffxQhfffpK3333zQ4333ӇK|Qhfff6K3333;Q̼K̴~QKxQIKhwQhffffK3333vQ4333#K̼tQhfffFKffffkQhfffKffffjQPKjQ43333KffffViQ4333KffffgQ4333Kffff`QyKffff*]QhfffFK3333[ZQܸKiOQhfffK3333KQhfffƼK3333#SQhfffFKVQ|K3333VQK3333SQ9KTLQKffffIQyK3333BQhfffFKffff@Q̼Kh:QK33338QK8Q4333K3333;QhfffvKffff;QpKffffZ9Q@K}7QK=2Q4333÷K3333c,Q4333K3333&QKffffQKffffQ̬KffffQ̼KffffQK QKffffJQhfffFKQ4333SKffffQ43333K3333QLKQ9K QKQhfffK:RhfffHRbH]R@uHR4333kH3333RbHRcHffffR4333gHdRlHARIkHQRmHRhffffqHffffRhfffxHR}HRhfff~HffffR9H5ŘHRhfffƑHR4333H$RpHdRhfffHR`HR4333ӈH]R@uH;XP#NININIP#N|Iffff>#NININiI N٫ILN̬INI<Xhfffvs:4333?M`fffB:0MM:0Mhffff: 1Mhfffvs:)5M0333Sj:L8M`fffB:4333?M̜C:43337M`fffG:l3MM:0M=lJ@0333S(@lAK@yn)@K@S)@4333J@Q)@4333J@`fff?)@J@ F)@J@,j)@yJ@yn)@)J@S)@4333J@`fffFD)@J@`fff&4)@lJ@)@J@`fff(@hfffJ@@(@4333J@0333S(@4333K@`fff(@"K@̬(@hfff4K@0333s(@9K@ )@lAK@`fff)@K@S)@>hpJ@@8@J@9i8@ J@dfff_8@ɴJ@9i8@yJ@L]8@J@4333sW8@pJ@yJ8@J@@8@hfffJ@43333B8@J@dfffG8@YJ@4333N8@J@dfff_8@?h RM@ 44@4333yM@94@ dM@ 4@4333RM@\V4@ RM@54@\TM@ 44@l\M@84@bM@PD4@hfffjM@dfffl4@4333yM@4333#4@43333qM@94@dM@ 4@@PhfffJJ@4333H8@,TJ@4333s`8@LJ@4333H8@hfffNJ@I8@,TJ@dfff&U8@PJ@4333s`8@4333JJ@43333Z8@hfffJJ@4333U8@LJ@4333H8@A4333åK@ffffF:@4333#L@ffff;@| L@̼:@K@:@K@:@̬K@2333S:@lK@p:@̜K@:@K@2333õ:@iK@:@4333K@ffffV:@4333åK@2333:@K@ffff:@4333K@2333:@I@ffff:@4333;I@,9@4333EI@`9@hfffII@9@MI@43339@ OI@:@ NI@:@hffffGI@23332:@KI@=:@43333HI@ffff?:@hfff&e@hfff0hfffe@hffff.0d@L20hfffd@̌:0d@4333E0e@P0hfffe@hfffX0hfff~ e@hfff&V0Ne@hfff1e@̊1De@̊1 e@4333S19 e@@1̄ e@1e@`1e@43331e@hfff14333e@̌1hfffve@43331e@1 e@hfff1 e@1 e@hfff1e@L1e@hfff&1te@hfffF1De@̊1OP4333d@8333.e@.e@.pd@.4333d@83333. d@8333s.d@8333.)d@83333.e@.Pd@ E/ld@hfffE-4333d@̌.hfff6d@LE.hd@L@.1d@$.̼d@hfff-4333kd@ -d@hffff-d@L-hfffd@.̌d@@G.4333Sd@@P.d@P.d@Y-4d@Yx-4333sd@hfffE-(d@H-d@-4333d@@-4333d@Ll.1d@hfff.]d@/Id@83333"/Dd@hfff&C/ld@ E/d@8333'/d@hffff)/4333cd@8333.ld@.4333d@̌.Q`hfffe@/e@8333s. hfffe@8333s.hfffe@\/̼e@8333/4333Ge@/e@/4e@ /e@/4333e@83333/hfffe@8333s.RXUe@. e@ -,e@L.e@. e@L.4333e@d.]e@ -e@hfff&-Ue@.,e@L.Sd@hfff0d@hfff/\d@hfffe0d@,W0d@LP0d@4333B04333d@hffffC0d@̌*0hfffzd@0̬d@043333d@̌0hfffd@Y/hfffd@hfff/hfffbd@hfff&/4333d@hffff/d@0hfffd@'0d@L&0d@43330,d@̌'04333+d@hfff>0d@̌f0Ld@0d@hfff0`d@43330d@hfff0̐d@hfff0Pd@433330d@ s0\d@hfffe0THd@ /d@>/d@@J/4333d@>/d@^/ld@ /d@r/d@@J/U4333c@hffff!0c@-hc@hfff hfffc@hffff hfffc@ c@-c@hfffVc@pffffc@@3333hfffVc@Yhfffc@(c@@333c@j4333c@-hfffRc@Oc@hfffc@L c@@333Ec@@333hfffc@pfffXc@5c@ 4333c@hfff4 c@d Uc@hfff&h Tc@Y c@L 4333c@ 0c@hffff!!c@̌!(c@L hc@hfff V4333{c@pfff̘c@o,c@<c@@33330c@@3333c@tHc@@3333c@pffffhfff~c@pffffUc@pffff4333Wc@o4333{c@4333c@pffffhfff֏c@pfff Dc@̤c@̸@c@pffffKhfffʧc@ic@@333]4333'c@p4333۪c@4333c@pfff̘c@pffffv4333c@LR4333sc@@3333A,c@<WH2c@~433375c@@3333*2c@Lb4c@~5c@@333e433375c@@3333*x4c@-2c@LbXhfff8^@z@Z^@Lb@R^@@M^@@43333J^@0333sM@iB^@Lb@|9^@@hfff8^@@;^@0333@0A^@@PE^@0333s@hfffM^@Y@R^@z@hfffNZ^@`ffff@Z^@`fff@hfffY^@`fff&@R^@@YX \@Lh\@@3333K \@pfffc43333\@@33334333s\@Lh\@@333̌\@RT\@@3333Khfff\@LR \@pfffcZh`@ffff&6A@`@fffffDA@ `@ffffvBA@hfff`@?A@hfff`@;A@4333`@ffff&6A@4333`@ffffRhfff&JiARJffffnCR|JDRɲJGRlJaGRYJ\FRhfffJffffjWR0J̜\R|JkR4333JvRJffffiRJ9eRhfffJ$^R9J WR̬JTRJffffTRhfffVJRR4333cJffffRRJffffSRhfffJ̀SR4333J3333{MR0JGR43333K3333+ERJ̈DR0JyERRhfff&J;R0Jffff7R̜J0R4333J33332Rhfff6Jffffn8R4333SKY=RpǨR4333IRJR|JRhfff"JffffrR̼#J3333R|J RI3333[RIjffff&R4333ErR4333SE |RhfffEyR EffffZuR ErR0EsR4333EuREvR4333SEffff}R4333ERhfffEffff&R4333ERE)}R4333E |RhfffEkx R/KPQ4333CJ3333QKQpKffffJQhfffK3333Q4333#(K3333+Q/KQ4333.K3333OQ|(K3333Q#KPQ4333KffffvQ4333K3333gQPKQiKQ43333K3333wQ`J Q0JffffQ4333CJiRJX R,Jx RKR43333K3333;QhfffK̴Q4333&K3333SQ4333c#KQiK3333QKllRhfffI3333cRIffffRI3333RhfffIR,IRI3333cRIRyI3333R4333IؔRhfffI,RhfffIٜRIlR4333IR43333IR,I̬RIffffRImRhfff&FmR4333CF-nRG@3333+"P)G@̌ PG@ffff&$PG@tP%P G@xP3333H@%P G@xP̼G@P3333H@3333 P3333H@@!PffffH@3333"P3333G@%P G@uX3333wQ3333nG@ٴQG@Q$sG@3333wQ3333nG@Q̼oG@ffffvQ3333uG@ٴQhG@LQG@ffff"Q{G@Q$sG@vHffffP F@ffffvPffff.2F@ffffP F@Pi%F@ffffvPffff.2F@P33330F@ffffP3333S%F@ffffP F@wXffff,QF@ffff'Q3333 F@5,QffffF@ffff,QF@,QaF@P*QF@ffff'QF@3333)QF@P+Q3333 F@5,QffffF@xPiPPF@̴PffffgF@iPPF@̰PDWF@33337P3333ZF@̴PLeF@ffffVPffffgF@PaF@iPPF@yYQffffF@ Qffffn:F@ )Qffffn:F@5Qffff7F@4Q.F@YQ̬%F@̰Qp#F@ffff*QffffF@Qd"F@3333Qffff&)F@Q(F@ Qffff*F@8 Q3333.F@<Q8F@)Qffffn:F@zt.\@P\@~PD\@hfff7\@433331\@Lt.\@J0\@hfffB\@pfff H\@I\@J\@L4333L\@ ^\@@333b\@i\@pffffrhffft\@z v\@pfffkx\@@33332P\@hfff\@@3333a~\@~PD\@{Pc@hfff_K4333c@hfffvb03333b0~̆c3333?c<@c@ffff?Lc3333?$cL3@c<@c3333#?3333c?ffffc@ffff?3333Cc+?c@ffff?̆cn?qc̙?ffffc3333?c@ffff?c@ffff?`Sea#yZa8333c# 3333`a8333c#SeaY#ffffJda8333#[ba#`a83333#[a8333#yZa8333{#[ǎ~#3333`a8333c#HKdahfff$3333aa8333#Kda@#Idahfff$3333aa#3333ba8333#ffffpca8333#Kda@#PVa%Sahfff$Va%Ta%ffffeL#3c9eL2ffff=e2X>ehfff3+@ hfffJb@ +@4333b@*@b@*@5b@hfff*@hfffbb@ك*@̼b@*@b@*@4333b@$+@b@03332+@4333b@0333:+@hfffb@hfff>+@hfffJb@ +@Phfff2b@-@15b@.@hfff2b@hfff.@hfff2b@hffff-@43333b@-@15b@hfff-@43334b@0333s.@hfff3b@.@hfff2b@hfff.@h4333Aa@̌"@Fa@`fff/#@ ̸Ba@9"@4333Aa@9"@%Ba@̌"@̐Da@Y#@4333Ea@`fff#@Fa@,#@hfffEa@`fff/#@Da@*#@Ca@0333#@̸Ba@9"@>f@4333&3̜Of@92hfffJf@92If@24333Ff@924333Ef@hfff&3TCf@43333Af@hffff3hfff@f@3>f@ 3hfff@f@4333&30Ef@3Ef@3 Ff@34333Ff@hfff343337If@43333Jf@3|Kf@̬ 34333Of@`3̜Of@`24333sMf@hffff2hfffJf@92`d@̌,hfff*d@H, d@@V,$d@e,d@hfff&,d@,hfffbd@̌,4333d@,hfff*d@^,4d@H, d@@V,xd@̌+hfffd@@k+ d@hfff+4333_d@ +hfffd@+hfffd@+4333d@hfff+dd@@k+d@+d@hfff+4333od@+,d@̌+̤d@+d@hfff+X7e@hfff=4hfffc@8333 hfff"c@@ 4333۱c@83333 c@8333 вc@ c@ c@ !8c@Y9!c@83333%!Uc@hffff#!Pc@̦!c@83333[!c@83333[!c@hffff!̸c@̦!lc@٤!c@@!c@!c@83333[!4333#c@8333!4333;c@83333!c@!!c@hfff,!4333#c@hffffV!c@ y!Mc@8333!tc@L^!Pc@K!hfffc@>!0c@6!4333;c@!`c@!4333c@83333!c@hfff!hfffc@83333!c@!!x4333˦c@t!hfff&c@  hfff&c@@ $c@ 4333 c@hffff 4333{c@83333 !4333˦c@L!!4333c@hfffff!4333sc@t!hfffrc@Lm!c@hfff&M!4333c@hfff&!Ec@83333!hfff&c@@ c@Lc@K4333c@pffffxc@Ls4333c@Kc@Yc@4333c@9c@@333vTc@hffffc@L4333c@@3333c@Ic@c@@33334333c@pffffXDc@d ̘c@@c@c@LhfffZc@̌ Dc@Y% 4333c@d 4333Sc@W ̘c@@1 @c@xhfffc@? 4333kc@l c@hfff) 4333kc@hfff& c@hfffc@̇Ic@lŠc@@333xc@hfffc@Y Qc@hfff&< ̤c@? c@Y7 c@hfff) Phfffuc@|4333{c@Lwc@L4333vc@ hfffuc@[̨wc@|zc@c4333{c@L,wc@LHy]d@`fff@hfff_d@ W@y]d@̌E@]d@4@hfff_d@`fff@hfffv_d@̌M@^d@ W@y]d@̌E@pc@*@c@03333@ c@03333@Pc@@c@Y@%c@@hfffc@4@5c@*@4333c@03333A@hfffc@`fff&k@c@@mc@`fff@c@03333@e@̼*B4333e@4333 B 4333ge@hfffB8e@̬Be@4333 B4333we@4333 Bhfff6e@4333# Be@@Be@B4333{e@hfffBhfff:e@"B0e@@(B4333e@̼*Bae@#B4333ge@hfffB`e@uDܾe@4333C[D hfffe@_D4333e@hfffeD(e@4333pDe@uDDe@̌nDe@hfffdDܾe@4333C[De@hfff_Dhfffe@_Dxhfffd@lFd@F %d@|Fhfffd@4333Fd@hfffF4333d@4333F4333d@F9d@lFUd@hffffFhfffd@J "e@?Jhfff e@i?JhfffF!e@hfffCJhfffn"e@4333FJ$e@IJx'e@,FJ%e@hfff?J$e@>J"e@?Jtd@LlI4333d@hfffCI̴d@hfffVNILd@4333II4333d@GI4333#d@EI4d@hfffCIhfff>d@DILd@YII\d@VILd@̬aItd@4333cgIhfffd@hfff&iId@hfffhIld@4333cI4d@4333dIXd@LiI4333d@LlId@@lI4333d@yaIld@`Ihfffd@y[I d@XI̤d@4333SI̴d@hfffVNId@G4333We@4333XGe@~Ge@4333czGae@`wGPe@4333qGhfffe@ysG4333e@\nGd@4333XGhfffd@4333YG|d@fGd@ tGhfffd@yzGd@̼Ghfffd@G0d@a@hfff&$a@hfffG$a@L$hfff>a@ f$4333a@hfffx$a@hfff&$a@hffffb$4333a@hfffG$a@L$H a@\$$a@$4333a@$ a@Y>$4333a@\$\a@hfffN$$a@hfff+$4333a@$da@0Tva@,e0ra@,e04333na@@p0`ia@w0Qga@ 04ea@90da@04333ea@0hfffga@0hfffia@,0hfffVka@4333S04333la@ 04333ma@90@pa@43330qa@̌0Tva@4333Ӄ0Xsa@9g0ra@,e0Xma@4333!1Dra@̌0oa@̌0na@4333 1ma@433331hfff~ma@4333!1na@4333S1Dra@,1qa@ 1oa@̌0  a@ ,la@ Z+!Ua@e,4333/a@P,4333a@;,a@83333%,8a@@+a@̌+a@ +hfffa@hffff+a@+a@+ a@+hfffa@Y+Aa@ٰ+hfffa@+Ea@s+hfffva@]+4333a@ Z+hfffa@83333q+a@hffff+4333 a@̺+( a@8333, a@@,̌ a@Y, a@8333sl, a@83333u,̼a@x,hfffa@,la@,hfffa@ ,a@8333},la@Y^,hfffa@hfff[,Ua@e,ha@+a@YT+ 4333a@83333y+La@+a@hfff+a@+hfffa@+̘a@hfff&+a@ +<a@i+a@YT+4333a@83333y+xa@8333&a@hffff& a@8333Z&a@Yl&a@@&a@hfff&a@8333&4333'a@&a@hfffc&a@hffff&hfffja@ &hfffFa@hfff5&̼a@Q&a@8333Z&Xa@Z'hfffVa@̌&hfff a@hffff4'$ a@*'hfffa@'hfffVa@̌&`a@hffff&hfffa@hfff&''a@Z'hfff a@hffff4'hfffbA`@٫'hffffS`@8333s&hfffN`@['M`@83333/'4333WL`@ 'hfffL`@&4333J`@̌&pI`@8333s& H`@&D`@&E`@'hfffRF`@Q'4333sD`@hfffd'hfffNB`@̌\'hfffbA`@'4333sB`@hfff'43333D`@hfff&'(J`@hfff&'P`@٫'hffffS`@'IS`@hfff'hfffR`@hffffy'hfffVQ`@h'hfffN`@['4333K`@Y'\@,9̜<\@43339 :\@9hfff=\@y94333J\@43333:hfffK\@ :hfff~I\@L9pH\@433394333kH\@43339Ycb@Edkb@4333Ejb@Eib@4333E|gb@LEgb@EYfb@Eeb@43333E8eb@4333EYcb@ٴE\cb@0Edb@hfffEhgb@hfffֽEhfffib@Edkb@вEjb@4333SEjb@Ehhfffb@\Elb@KE hfffb@QEb@TE4333b@[Ehfffb@\EhfffVb@ZE8b@WElb@lSEb@hfffNEhfffRb@KEhfffb@QEhyib@4333ӞEmb@hfffFE Hkb@hfffFEyjb@̬Ehfff6jb@Eyib@4333Ejb@hfffvE)kb@Ehfffkb@4333ӞEmb@ОEhffflb@4333#EHkb@hfffFEPb@4333sKDhfffNb@7D b@0Db@4333sKDb@@DhfffNb@\8Db@7D b@0D,b@Y7Dhfffvb@/Dpb@I'Ďxb@̌!DXb@Cab@̌!D4333b@D̔b@4333Db@hfff6DXb@|Dhfffb@̼ DhfffFb@`Db@,Cb@̼Cb@ C4333b@C4333}b@Chfffzb@pČxb@hffffChfffyb@Chfff |b@hfffC|b@hfffVC4333|b@D4333ˀb@4333Db@<D4333[b@4333Dab@̌!DPb@KD̔b@hffff@Dhfffb@KD̔b@ADb@hfff@Dhfff.b@hffff@Db@BDb@EDhfffb@KDLa@4333 B4333Ca@hfffA}Aa@A=a@A:a@̌Ahfff3a@̌A$3a@4333sAU4a@hfffA2a@4333cA0a@4333sA̰*a@hfffA"a@Apa@Aa@4333ALa@A4333a@A)a@<B4a@B a@Bhfff$a@B̴&a@A4333;,a@̬BY.a@4333 B43332a@yB3a@4333Ax5a@A̼:a@4333Aa@a@,A Ba@hfffFA4333Ca@A}Aa@AP(b@43335C/b@hfff6(C4333s)b@4333(C%)b@hfff+C(b@2C4333*b@43335C/b@l-Chfff-b@hfff6(C4333s)b@4333(CX$b@LGC\+b@4333:C&b@4333:C$b@CC4333(b@hfffBC\+b@LGC,+b@4333DC*b@4333>Chfff6)b@p]@`fff:@E]@`ffff# @hfff?]@ @4333s>]@`fff @ >]@`ffff@A]@`fff:@E]@@hfffD]@`ffff# @hfff?]@ @X]@$@^@G%@]@G%@]@l%@4333]@$@4333]@0333$@4333]@0333%@^@`fff#%@]@`fff5%@]@G%@hp]@Y&@]@ '@ 4333]@&@p]@`fff&@]@`fff&&@]@`fffF&@)]@Y&@hfff]@@&@]@&@!]@ '@]@`fff'@4333]@&@4333k]@'@^@`(@4333^@̌p(@hffff ^@`fffU(@hfff ^@`fffN(@hffff^@U(@hfff^@@e(@]@0333s(@hfff]@`(@4333c]@y(@]@`fff(@4333S]@L(@4333]@`fff(@]@|(@4333k]@`fffe(@Y]@`fff[(@@]@0333s#(@̬^@9(@h^@'@ ^@ (@̔^@0333s(@!^@Y(@^@`fff'(@̬^@0333H(@4333^@̌p(@]@V'@hfff^@0333s'@8]@`fff'@]@0333s'@]@l'@4333]@`fff'@]@ {'@y]@`fffa'@]@V'@4333{^@h'@hfff^@`fff&'@hfff^@`fff'@hfff^@'@L^@'@]@@'@8]@`fff'@^@0333$@hfff.^@03333{%@ ^@c%@hffff^@03337%@^@,$@t^@0333$@8^@ $@̧^@`fff$@^@`fff$@^@$@hfff.^@`fff&O%@4333^@̬i%@^@03333{%@4333 ^@`fffFz%@^@q%@ ^@c%@ 9^@̌"@̴_@ &@!\_@&@̌_@0333s&@hfffV_@6&@̴_@9o&@|_@ &@hfff^@0333_&@4333^@`F&@hfff^@`fff(&@,^@0333&@4333^@y%@8^@`fffFv%@hfff~^@%@^@`fff$@^@$@4333^@G$@^@`fff&#@hfff^@L#@hfff^@'#@9^@Y"@4333;^@̌"@4333^@03333"@hfff^@-#@4333^@#@,^@Y $@^@0333A$@y^@ q$@hfff^@0333$@^@$@Q_@$@H_@0333+%@4333_@`fff&%@i_@%@\_@&@HI^@,M&@43333^@ &@4333s^@ &@4333s^@&@I^@~&@hfff&^@̌M&@43333^@,M&@4333s^@ &@L^@2#@&_@Q$@ _@`fff!$@_@@$@4333_@YB$@_@`H$@|_@Q$@ _@9E$@_@`ffff$@4333_@$@4333+^@#@I^@0333#@L^@#@hfff^@0333#@^@Y#@^@y?#@hfff_@2#@_@̬B#@_@`fffN#@_@~#@\ _@́#@d%_@@#@&_@ #@4333C%_@#@hfff#_@`fff&#@$_@̬ $@ _@`fff!$@`hfff(_@̌*"@3_@|"@ (/_@|"@Q-_@l|"@)_@s"@hfff(_@`fffY"@̜*_@C"@1_@̌*"@3_@`fffI"@43332_@0333Sa"@(/_@|"@h̔^@`fff4"@43333^@"@ hfff^@y"@^@"@^@Y"@@^@Ym"@hfff^@Yn"@̔^@Yb"@4333^@lB"@4333S^@`fff4"@43333^@`D"@hfff^@y"@4333]@`fff=@hfff^@@\@P ^@@\@4333 ^@`ffffT@^@0333 @]@`fff@4333]@Y@4333]@03333G@)]@`fff=@Q]@0333sQ@^@@p^@ @4333^@̌@ ^@@4333C ^@Y@I^@0333@hfff^@@hfff^@`fff"@P ^@@\@s^@@̴^@@4333^@@hfffz^@0333s@@u^@@s^@0333st@hfffw^@@@@Px^@@4333c}^@̩@4333s^@@^@@܌^@@^@0333Q@̴^@0333h@p^@@@4333^@@pp_@`fff#@4333 _@0333S$@ I_@#@_@0333S$@_@`fff#@p_@0333S#@hfff_@`fff#@̃_@L#@4333È_@#@4333 _@0333#@4333_@#@@_@@#@I_@#@4333__@#@4333m_@Y$@4333m_@$$@4333ci_@`fff}$@k_@$@̬j_@Y$@xi_@`fff$@hffff_@Y$@!e_@03333$@4333a_@0333$@ha_@ b$@4333__@`fff<$@4b_@ .$@4333e_@0333#@4333i_@`#@4333 k_@#@,l_@03333#@Ql_@`fff#@k_@`fff&#@4333m_@$$@X\^@̬]+@hfffv^@0333S+@ ^@,+@^@0333S+@hfff^@`+@\^@hfffF+@4333^@0333+@hfffv^@̬]+@\^@Y+@ ^@,+@)t^@0333h*@ԇ^@!+@^@0333+@~^@hfff&+@̌z^@hfff+@pw^@!+@)t^@0333S*@u^@@*@hfffx^@@*@P^@0333h*@hfff^@x*@^@̌*@ԇ^@0333*@hfffކ^@y*@T^@hfff&*@^@0333+@hfff{^@03336(@H^@`fff&N)@^@0333s2)@4333S^@(@9|^@0333S(@hfff{^@(@{^@̬(@~^@}(@4333s}^@b(@^@03336(@^@0333(@l^@9)@hfffV^@`fff9)@H^@`fff&N)@̤^@ M)@^@0333s2)@P܏^@ (@^@0333/)@܏^@`fff&)@4333^@0333)@^@ (@^@)@hffff^@0333-)@4333ˑ^@0333/)@܏^@`fff&)@h^@9(@4333^@(@ ^@0333(@43333^@(@^@(@hfff^@`fff(@^@0333s(@̜^@9(@4333^@9(@4333^@(@^@9(@^@0333(@x̼^@0333f)@^@y;*@ ^@ :*@^@y;*@H^@6*@̼^@ *@L^@`fff*@x^@`fff)@hfff^@0333s)@̌^@03333)@^@0333f)@ ^@0333)@43333^@0333)@^@ :*@X̔^@`fff(@^@̌Y)@^@`ffff(@4333[^@8)@hfff^@̌Y)@̔^@@D)@^@$)@t^@ (@^@`fff(@^@`ffff(@^@@'@_@*)@y^@03336(@^@'@^@'@4333^@(@hfff^@0333sc(@Q^@n(@^@̬d(@4333+^@03333.(@^@#(@0^@(@4333^@Y(@i^@03333'@A^@0333s'@A^@'@^@`fffF'@_@@'@_@`fff'@̔_@'@!^@0333V(@^@ (@^@Y(@hfff^@(@^@)@^@0333)@!^@*)@Y^@`fffF(@^@y(@4333^@0333(@y^@03336(@|_@hfff&+@4333_@',@̌_@+@4333_@+@d_@',@4333 _@y,@hfff _@hffff ,@_@+@4333_@+@|_@hfffS+@hfff_@ 6+@9 _@hfff&+@4333_@`,+@_@@.+@hfff_@"+@_@0333C+@4333_@[+@\_@ +@4333_@+@̌_@+@P4333|^@,@9^@ u,@4333c}^@ u,@4333|^@hfffi,@|^@\,@43333}^@hfffO,@hfff^@,@9^@,@4333c}^@ u,@t^@hfffO-@L^@.@u^@hfff.@t^@Y-@0w^@-@x^@-@4333{^@-@{^@hfff&y-@{^@m-@Hz^@@U-@hfff{^@hfffO-@hfffV^@hfffS-@4333c^@0333ӄ-@~^@03333-@4333^@9-@^@y-@L^@0333-@$^@0333.@0~^@.@u^@hfff.@`t^@2@9^@̬3@ 4333x^@dfff2@hfffw^@2@hfffw^@̜2@t^@̼2@v^@2@z^@ 2@9^@dfff2@`|^@̬3@4333x^@dfff2@XK^@43333@$P^@/3@̌L^@ 3@O^@43333@$P^@3@O^@̜$3@̤M^@/3@(L^@#3@K^@dfff3@̌L^@ 3@XW^@dfffvE3@b^@|^@̌Z4@q}^@]4@hfff^@)x4@p^@dfffz4@<|^@dfff&t4@z^@4333\4@Pr^@dfffF4@43333x^@\4@r^@4333#4@r^@4@u^@dfffF4@43333x^@)4@|w^@dfff4@4333Cv^@\4@r^@4333#4@xhfffxb@V4333ob@ hfff{b@myb@@3333hfff yb@hfffxb@L{b@@3333~b@'̈b@V4333Ӏb@@3333N4333b@4333ob@̙b@@3333rhfff{b@`0`b@pfffgb@pffff 1db@pffffx`b@0`b@pffff:`b@^cb@pfffeb@Lgb@@333hffffb@1db@pffffhhfffFb@pfffhfff@b@Ab@hfff2Ab@pfffJ?b@@3333(hfff>b@7hfffTc@@3333`Sc@#HQc@qhfffRc@pRc@@33334333Rc@B4333Tc@@3333hfffTc@YVc@DWc@L Vc@4333Uc@L7Phfffbc@ uc@Wpc@W<c@hfffbc@̸c@[ c@ uc@@3333 pc@WXb@,c@0b@b@4333b@@3333+c@c@,c@@33334333cc@Y0b@Pb@\c@@3333c@Hb@@3333b@@3333hfffb@b@@3333\c@@3333yc@ hxb@@3333mhfff~b@̦ Ab@4333b@̦b@xb@yb@ffff8b@ffff"lb@@3333mhfff~b@@33335b@Ab@ žb@ffffg4333sb@hfffb@ffffDb@Hb@ffff=žb@ffffhfffb@db@@b@Mb@@3333Hb@ffffgb@ffffKhfffFb@4333sb@@3333Thffffb@@3333hfffb@ffff b@8333c$|b@ k#4333b@Y $4333b@L $ib@Y#b@#b@ٚ#hfff"b@x#b@ k#Db@8333s#b@#̬b@hfff#hfffzb@83333#b@hffff/$b@YQ$4333cb@8333c$|b@#hfff.b@hffff#8b@#4333b@Y $ h4333b@ #b@hfffi" hfff>b@@"hfffb@hfffi"Qb@hfff"4333b@L"4333b@83333#hfffb@ # b@"b@"lb@8333"hfff>b@@" hfffb@g#b@8333"$b@@S#hfffb@g#b@U#b@hffffH#hfffJb@8333)#!b@# H`@L|`@hfff~`@$hfff `@@333`@@3334333`@ԣ`@M`@dhfffn`@E4333`@>H`@L|+xhfff*`@ԙ`@m `@`@pfffT`@ohfff*`@m͕`@hfffZ`@lhfffΕ`@hfff`@`@ԙ`@@3333g̼`@'`@,h`@ hfff`@ffff  T`@@3333" `@ffff `@ 4333`@ffff `@̳ 4333`@ 4333 `@ hfff`@` 1`@@33332 T`@@3333" -H `@ffff `@@3333 4333s`@@3333 ̴ `@R `@ffff `@ )`@T 4333s`@@3333 .43333_@+ `@@3333 u`@@3333 `@@3333 ̄`@ \_@ffffo 43333_@@3333 _@ _@+`@ffff `@} 4333`@j hfff`@̔ ̔`@ 4333#`@ 4333`@ffff `@e `@ P `@ `@ffff `@ u`@@3333 /p^@pffffhfff^@@333304333K^@@33334333^@Lɾ^@@33330^@̍4333#^@@3333^@hfff&^@@333S^@@3333hfff^^@̤^@@333^@^@@333hfff^@pffffJhfff^@^@pffff4i^@hfff^@@33334333s^@@3333^@L̜^@@3333y\^@@3333S4333^@q^@4333˲^@@3335 ^@hfff^@@3333Ю^@@3333 4333^@R ^@L^@^@p^@@333-H^@L̫^@@33334333^@@3333^@pffffi^@L4333^@)^@pfffѻ^@@3333^@hfff^@hfff^@pffff^@^@U^@pfff^@pffff4333K^@@33330hfff^@^@yX^@@3333^@y<^@^@̜^@h^@pfffbhfff^@\^@Ghfff^@hfff^@@3333Ghfff^@4333×^@Lhfff^@WP^@̅4333C^@hfff^@̌4333^@pfffWI^@pfffL^@^@LX^@@33331hfffs^@pfff^@J^@hfff^@@3333hfff}^@pffffMyz^@Jqw^@Lb4333w^@4333v^@hffft^@hfffs^@Lw^@@333f~^@pfff^@^@^@2h^@pfffhfff^@ ^@@3334333#^@>^@^@@^@pfff4333^@@333shfff^@pfff)^@^@^@@33339w_@ffff4_@̘ hfffv~_@@3333X_@@3333hfff}_@̜hfff{_@̘4333w_@I9w_@hfffy_@|_@@3333hfff~_@Rl_@ffffhfff_@@33334_@@3333hfffv~_@@3333X4X_@ffff 4333;_@̢ ̌_@̢n_@@3333hfffVa_@ffffhfffv\_@X_@@3333}4333C[_@[_@ffff4333^_@ffff u_@hfff6}_@ffffp_@4333;_@ffff*̌_@̢5_@@3333hfff~T_@,hfffL_@hTI_@H_@ffff04333#F_@ffffD_@@3333 >_@Ihfff~*_@,_@@3333O_@ffff`_@_@̼_@ Q!_@@3333(_@̦h5_@Ohfffn@_@H_@@33339T_@hfff~T_@4333S_@hfffP_@UhfffL_@|hfffL_@h6Hhfff^@ffffl^@ $^@ hfff^@̲l^@l^@ffffI^@I$^@ 7^@@3333hfff^@@33334333^@4333^@ffff8^@:̬^@ffffhfff^@@3333hfff^@򿜙!^@@3333<^@^@ffff4333C^@@3333^@^@^@@3333e^@+4333^@p^@@3333̴^@ffffhfff^@X^@@3333=^@@3333^@̒1^@@3333;^@^@|^@@3333^@@33334333^@ffff(hfff^@f^@Q^@&4333^@8P^@b4333^@\^@4333 ^@b4333^@ffff^@\^@ffffhfff~^@ ^@9xi^@ffff࿜ z^@ ڿ s^@4333ڿo^@ ڿk^@̤޿i^@ffff̔k^@࿜1n^@߿4333cp^@i߿43333v^@Y߿hffffx^@࿜ z^@ܿQw^@ ڿs^@4333ڿ:hfff_@`fff @4333_@ 1@hfff^_@Y@_@&@x_@ 1@_@̩@hfff6_@0333s`@4333_@Y!@_@0333@I_@@hfff_@0333H@̄_@@hfff_@`fff @4333C_@L"@@_@L@4333_@*@_@0333s}@hfff^_@Y@;P̨_@@hfffV_@0333*@̨_@0333*@Q_@`ffffm@1_@@ _@L@hfffV_@W@_@0333s@̨_@0333*@<`4333ñ_@ 3333@hfff_@@ ,_@`ffffE@y_@ 3333@̄_@%@hfff_@ 3333L@ٶ_@@|_@@ٱ_@̾@4333ñ_@`fff@,_@`ffffE@=x4333#]_@L> @hfffj_@ 333 @ 4333{e_@ @b_@] @^_@ 333 @4333#]_@ 3333y @]_@`fff @4333`_@`fff @ a_@e @̼`_@`ffff @hfffh_@L> @hfffj_@} @0i_@`fff @4333{e_@ @>X4333 W_@L @4333\_@`ffffq@4333Y_@`ffffq@4333 W_@@lY_@L @4333Z_@6@Y_@@4333\_@@4333[_@`ffffE@4333Y_@`ffffq@?p^@hfff&#^@pfff ̌^@pfff4333^@Lhfff^@@3333a^@|^@4333^@pfff0^@!^@1hfff&#^@0"^@̌^@pfff@`hfffx`@pffffl`@k 4333}`@khfffx`@wx`@pffffTz`@M|`@̨}`@pffffhfff`@pffffl`@pfff4333}`@kA`hfffX`@hfff& ̤e`@.  ̤``@. 4333Z`@hfff hfffX`@hfff& 4333[`@83333 4333]`@} hffffa`@̌l ̤e`@8333B b`@? ̤``@. B4333b`@̌ hfffw`@s lv`@4333t`@sq`@p`@ q`@pfffqo`@@3334333Gn`@pfffB4333'm`@L\,k`@i`@hfffRh`@Pf`@wf`@hd`@L`d`@ 4333b`@u4333c`@c`@L4333e`@i`@̌ 4333kj`@j`@ k`@l`@z4333'o`@L4333o`@@3333r`@4333s`@@3333v`@pffffhffft`@Lhfffw`@lv`@Ch2`@ hfff:`@pfff- 4`@pfff-|3`@@3336(3`@LS2`@pffff6`@ 8`@ :`@hfff:`@@333:`@pffffG4`@pfff-Dh`@4333`@pffffF hfff`@pffffFy`@@3333U`@̉4333`@`@q`@@3334333W`@L4333`@t`@L]hfff`@pffffFEXQ_@ `@2 hfff_@83333G 4333_@2 Q_@= _@hffffa `@ `@hffffW )`@ E hfff_@83333G FX̼_@i_@ _@ _@@3333J̼_@_@~_@@3333chfffV_@pffffPi_@_@ Ghfffs_@@3333 _@I|_@4333_@I_@pffffn_@̬_@@333hfffv_@4333k~_@Lhfffu_@LD̼s_@̅hfffs_@@3333t_@hfff|_@̤_@_@@33334333_@@3333hfff_@@333hfff6_@@3333)_@z4333_@;X_@4333_@ _@@3334333C_@pfff|_@HHt`_@hfff Yi_@hfffG t`_@ٌ hfffe_@hfff Yi_@hfffG g_@L ae_@8333s[ t`_@ٌ I`hfff^@̬$4333^@hfffG$ L^@W$hfff^@@$^@̬$4333^@8333$^@Lt$4333^@Lc$̜^@Z$\^@hfffG$L^@W$Ja^@%4333^@hfff$̼^@8333$^@L %T^@hfffG%hfff^@e% ^@ %a^@@%^@Y%hfffƶ^@%4333^@̌%hfffV^@8333%^@%4333^@e%4333^@8333sM%l^@>%̄^@"%^@hfff&$^@hfff$̼^@8333$Khm^@L4%^@8333$ hfffr^@%m^@%yn^@8333s%%Qu^@L4%4333x^@@.%hfff~^@̌%^@$|^@8333$|w^@8333$hfffr^@%L_@hfff hfffnH_@YE $0_@8333Q Q+_@ V `&_@Lg hfff$_@H ̌ _@YE _@] 0_@̌ 4333C_@8333s _@ \_@̌ hfffn_@hfff 1F_@hfff hfffnH_@hfff& G_@h 8C_@8333[ $;_@U $0_@8333Q M`^@8333s!|_@Lg T_@hfff&h 4333_@ !_@Y hffff_@8333 _@hfff& ,^@L `^@ 4333_@@ 4_@8333s!4333c _@! _@Y 4333s_@Y X_@8333 |_@hfff&u `_@j _@Lg T_@hfff&h N^@Y,!0^@a ^@a p^@hfff& hfff^@@ 4333^@̇ I^@ ^@ hfffF^@hfff hfff6^@8333s t^@ ^@ ^@ ^@8333!hfff6^@!hfff^@@!I^@Y,!4333^@8333&!hfffF^@̌!d^@83333"!!^@!^@83333 !I^@!^@8333 D^@L ^@L 4333+^@hffff 0^@ Y^@z ^@@m ^@a O`^@ ^@̌x  ^@̌x 4333^@8333 hfff^@8333 hfff^@8333 ^@ hfff^@ Q^@hfff ^@ ^@̌x P@]@@!]@ ]@L 4333]@ ]@8333 ]@!@]@L,!̴]@LK!̬]@x!1]@@!4333]@hffff{!4333k]@8333W!hfff]@hfffA!4333S]@-!̌]@Y!]@hfff !]@ 4333#]@L ]@hfff& ]@L QhhfffV]@hfffz ]@@G  X]@P hfffV]@Yf 4333]@hfffz ]@Lz ]@hffffr ]@hfffd hfff6]@8333Z A]@@G ]@G X]@P RX\@!@\@W!\@Ln!hfff\@Y|!hfff>\@! \@hfff&!@\@hfff&m!hfff\@W!\@Y!\@Ln!Sx\@4333\@Z hfff\@pfff[4333\@Zd\@pfffq8\@pfff\@pffffhfff\@!\@$\@@33334333\@@3333̌\@4333\@{hfff\@pfff[TX%\@b̌.\@%\@pfff6&\@pfff_4333,\@b4333 .\@>̌.\@),\@)\@pffff%\@pfff6Uhh]@@{]@0333 @ Pm]@0333 @`j]@03333@̬j]@`fff@h]@`ffff|@(o]@@{]@7@hfffz]@0333\@x]@@4333p]@`ffff@Pm]@0333 @VXhffffb]@`ffff @4333k]@} @c]@ 333t @hffffb]@L @c]@ 3333 @Ti]@`ffff @4333#j]@> @4333k]@B @h]@} @c]@ 333t @WHhfff]@ 4333S]@3 hfff]@P ]@ $]@@3333 4333S]@3 L]@c hfff]@P X,]@pffff7d]@@3333  ]@@3333G 4333]@ hfffV]@@3333 hfff]@( 4333C]@@3333 Q]@@3333 4333]@ffff ]@̩ p]@@3333 ,]@ffff ]@@33334333]@]@pffff7i]@4333]@@3333d]@]@ ]@@3333G YHp3[@<=[@@3333$8[@@3333p3[@5[@=[@<=[@ffff$8[@@3333Zxhffff[[@ffff̬p[@T l[@hfffVg[@Thfffv^[@ᅵ\[@̴hffff[[@̬][@p`[@fffftm[@ p[@R̬p[@̮4333o[@@3333l[@[HhfffV2[@@8[@`fff@hfffV2[@@5[@@8[@L>@8[@`fff@hfff~7[@`ffff@hfffV2[@@\hfff&[@9 @hfff[@Y@$[@ 333@4333[[@`ffff@[@Y@ [@L@9[@+@hfff&[@`fff@[@@[@@[@{@[@F@ [@`ffff-@ [@$@l[@`fff @hfff~ [@9 @9[@`ffff @0[@@hfff[@@$[@ 333@]P܌Z@ 333@AZ@ 3333 @4333Z@L @(Z@ 333@AZ@A @4333[Z@ @QZ@ 3333 @܌Z@ @4333Z@L @^LlZ@@̌uZ@@4333nZ@ 333K@LlZ@@LlZ@ 3333@mZ@`fff@hfffNmZ@L@1mZ@`ffff@mZ@@pZ@@sZ@L;@̌uZ@`fff@hffftZ@@rZ@ 333@pZ@ 333@4333nZ@ 333K@_YY@s?qY@@iY@@bY@`ffff|@\Y@`fff@8ZY@`ffff,@YY@k?]Y@@ffff&? `Y@3333?4333fY@s?4333 nY@@ffff?4333nY@?qY@@ffff?pY@?QmY@@iY@@`Y@ffff?Y@@ffffZ?Y@S?hY@@ffffZ?Y@̐?Y@33339?YY@Z?Y@6?єY@?`Y@ffff?hfffVY@3333?4333sY@?Y@?XY@@ffff?lY@3333,?4333Y@̇?Y@S?a,Y@@ffffK?hfffY@? 4333{Y@X? Y@3333)?4333Y@?Y@3333?,Y@^?hfffVY@@ffff? Y@3333?4333SY@@ffffr?̌Y@@?4333{Y@̥?hfff6Y@?hfffY@@ffffK?4333{Y@X?b Y@̨?4333Y@@ffff?Y@3333?yY@?hfffY@?hfff&Y@@ffff?lY@k?4333sY@ffff?ٝY@3333i? Y@v?4333cY@i?Y@ffff?yY@?hfffY@ffff?,Y@?Y@̨?4333Y@ffff?(Y@3333?lY@3333?Y@3333?c4333Y@?hfffY@̥?4333SY@@ffffY@3333[?hfffY@ffffd?Y@ffff?hfffY@?Y@ffff(?4Y@W?4333Y@?hfff>Y@3333[?eX0Y@?Y@@ffff#?QY@@ffff#?Y@3333?0Y@$?@Y@?Y@?!Y@?Y@3333)?QY@@ffff#?f`4333 Y@?hfffY@? hfffY@?hY@ffffZ@3333|Z@Z@̜4333k Z@"Z@%Z@ݿhfffV$Z@4333ۿYZ@4333kտDZ@ٿn`hfffY@ؿY@ Ϳ Y@4333Ϳ!Y@ ͿY@ ӿhfffY@4333ֿhfffY@ؿ4333#Y@DֿY@gfffVԿTY@̴ѿY@4333ͿoZ@ [@> [@ffff4333[@4333Z@@3333zhfffZ@>̤Z@̇Z@@3333HZ@ehfffZ@Z@ffff\hfff^Z@Z@4333Z@wZ@4333SZ@̬ hfff6Z@ Z@@3333I 4333Z@Z@̰4333;Z@ Z@@3333U Z@@3333 [@ Y[@@3333 ̴ [@ffff$ hfffF [@4333C [@@3333[@̣ [@ffffpXZ@g4333Z@ffff4333Z@g4333KZ@@333324333Z@\Z@ffffhfffZ@ffffZ@1Z@ffff44333Z@gq`4333Z@3HZ@1 Z@14333Z@ffffv4333Z@hfffZ@Z@Z@34333Z@ HZ@xZ@1r`GZ@pffffQZ@ GZ@@333u4333#IZ@0LZ@pffffhfff.PZ@̏QZ@pfff>̬PZ@qNZ@hfffNLZ@@333.GZ@@333usEX@?̤{X@̢?TrX@U?lX@?^X@q?VX@̢?UX@@ffffr?4333TX@̴?OX@3333?EX@?SX@@ffff?4333WX@3333?YX@M?̄]X@ ?hffffX@3333?hfffkX@?hfffkX@3333?tX@?xX@3333?4333yX@K?̤{X@ffff*?hfffyX@J?TrX@U?t`hfffY@4333Y@% 4333˗Y@@3333w4333Y@'4333ӉY@%hfffY@LJ̬Y@@3333qLY@Y@@33334333Y@4333˗Y@@3333wuy Y@̠ Y@DhfffY@ffffY@OY@Y@D̴ Y@Hy Y@̏4333 Y@4333Y@t@Y@LY@@3333E hfff&Y@ffff Y@̠ 4Y@v Y@ffff! hfffY@ffffvphfffX@@3333 Y@ 4333Y@9X@4 X@hfffX@X@14333{X@(Y@̎hfff~Y@@3333 Y@ Y@p4333Y@wdX@@33334333CX@" hfffX@lhfffX@́X@"hfffX@4X@hX@ffffdX@JX@ffffX@A4333CX@@3333X@4X@ffffFhfffX@lx4333X@@3333`X@L\X@X@@X@%hfff~X@@3333q)X@4333X@ffffX@3333hfffX@LDX@ffff4333X@ffff* X@ffff.hfff>X@̜X@ffffX@ffffX@@3333|X@ffffr`X@4333X@@3333 hfffvX@\X@yѓX@u4333ӢX@}?hfffX@@333X@}?4333X@IhfffVX@̿)X@gfffӿ̴X@gfffFؿX@ݿѓX@̔X@udX@࿜IX@Lؿ4333ӢX@|пX@hfffvſhfffX@@333z`hfffFX@m@4333cUX@@ hfffRX@L@hfff.PX@`ffff@hfffJX@@hfffFX@ 3333@hNX@D@4333UX@m@4333cUX@`fff@ UX@ 33330@hfffRX@L@{hfffW@ 3333@̬X@T@̴X@@̄ X@`ffffJ@hfffNX@`ffff@X@@W@L@@TW@@W@T@4333kW@@hfffW@@W@!@W@ 333>@hfffNW@ @W@@hX@@hfffX@o@X@@X@ 3333@̬X@L@hffffX@S@4333[X@@̴X@@|`hfffW@0333"@lW@̠@ |W@̠@hfffW@َ@ W@03331@W@0333"@,W@`fff?@lW@`fff^@W@́@W@L@|W@̠@}h9[@ 3337@[@%@ [@L@hfff6[@ 333@[@@X[@%@9[@`fff@[@ 3333@[@ 3337@[@R@Y[@`fff@[@L@~hC]@ v@Q]@h@ D]@0333 @C]@`fff&@)E]@ v@I]@@@QO]@03333@4333Q]@@Q]@)@hfffP]@h@hffffI]@Y@D]@0333 @h@?@G@hfff6@@3333/G@ ?@ffff&G@@?@3333/G@Y?@ffff>'G@Y?@ffff G@@?@fffffG@43333@@3333{G@hfff6@@G@@@G@8333s?@3333"G@?@ffff&G@hffff6@QXM@97@ffff&M@9i6@3333nM@z6@|`M@y6@$[M@̊6@QXM@8333S6@ffffZM@l6@3333iM@6@3333 fM@y6@3333cM@y6@iM@97@ffffjM@L6@̼uM@6@~M@6@ffffM@8333S6@M@hfffƳ6@ffffM@@6@ffff&M@8333S6@dM@,6@3333cM@lv6@ffff|M@hffff6@xM@8333s)6@sM@8333N6@ffffrM@9i6@3333nM@X@7@ffffEM@@[7@VM@Y*7@VM@7@aTM@@7@8NM@hfffB7@ffffEM@8333W7@qFM@@[7@3333IM@83333U7@SM@Y*7@VM@4333A@>P@A@̤LP@A@DP@A@!IP@hfffvA@3333KP@4333SA@̤LP@A@ffffJP@A@JP@4333A@3333IP@A@EP@A@3333CP@ A@CP@̬A@>P@A@@P@hfffA@UBP@A@DP@`4333:E@ P@Y[E@P@ 4333PE@P@4333FE@P@;E@ffffFP@4333:E@MP@=E@3333 P@yVE@ P@Y[E@P@iXE@3333P@4333PE@P@``h:@`S@8333;@3333S@ :@US@:@3333S@̬t:@3333߳S@`h:@ffff2S@hfffu:@S@:@`S@@:@S@8333;@S@:@US@;@ S@Y=@ffff"S@ =@3333_S@`<@ffff"S@ق<@S@,j<@S@_<@TS@<@$S@;@S@8333 <@ S@~<@ȸS@8333<@3333SS@O=@̈S@Y=@3333S@hfff&=@S@lX=@S@ =@3333_S@h,H@3333T@(I@T@ (I@ T@̬'I@ T@ I@ T@H@T@,H@, T@LH@ffffT@hfffFH@3333T@I@T@@ I@T@(I@ T@4333 I@S@4333I@T@4333I@pS@4333sI@T@I@T@wI@T@VI@3333T@GT@Y5K@3333#?T@4333/K@9T@K@9T@K@ffff7T@hfffK@ffff4T@4333#0K@]2T@43333DK@2T@OK@0T@hfffUK@ffffF/T@K@33330T@43333K@3333-T@43333K@(T@4333K@8(T@4333c(L@̀(T@IhL@x*T@IL@Y0T@L@̴2T@̬L@ffffv4T@ptL@l:T@4333sGT@)/I@BT@yI@JT@y`I@CT@hfffdI@̘DT@yI@FT@hfffvpI@IT@4333[I@JT@KI@JT@4333BI@ JT@4333@I@3333;IT@4333;I@HT@)/I@3333GT@P0I@3333FT@4I@fffffET@4333SBI@ffffBT@NI@BT@y`I@CT@L@0T@wM@̔GT@hfffVM@̔GT@L@BT@4333L@ffffBT@L@AT@ܳL@:T@L@ffff8T@ L@ffff2T@$M@0T@)RM@ffff&1T@4333nM@1T@wM@ffff:5T@hfffsM@3333s9T@\hM@;T@yaM@l?T@OM@ffffBT@@M@CT@PM@ FT@ M@PGT@hfffVM@̔GT@ O@ffff.fT@hfff&O@3333nT@ hfffFqO@fT@hfffO@ffff.fT@4333SO@3333fT@hfff&O@ffffiT@9O@jT@4333O@kT@eO@3333nT@Y$O@8mT@ O@ffffzkT@4333AO@3333/jT@DO@hiT@YIO@hT@hfffFqO@fT@x4333cL@lT@IM@3333vT@ M@3333pT@̬M@3333qT@IM@tT@4333M@3333vT@9M@tT@4333L@ffffsT@L@oT@4333cL@4nT@hfffL@xmT@L@lT@%M@mT@M@3333pT@Phfff)2@T@ٽ2@3333T@hffff2@T@ٽ2@ffffBT@83332@3333KT@̬J2@3333T@42@<T@hfff)2@qT@hffff2@T@%@dS@;(@ɹS@'@ffffS@ '@ffff2S@'@S@̌;'@hS@@3333&@S@&@3333S@pfff&&@S@YO&@3333S@ (&@S@LN&@]S@@333s?&@33337S@@333%@3333+S@@333%@̸S@%@ɹS@%@S@A%@3333?S@pfff%@S@pffff%@3333CS@>&@ffffS@f&@=S@@333&@S@L,'@ؘS@Y'@ffffS@'@dS@;(@ffffS@(@3333S@'@ffffS@`hfff&2@R@8333SF3@%R@ y2@R@hfff&2@R@hfff2@HR@93@R@hfff&83@ffffR@8333SF3@3333;R@8333B3@3333R@8333.3@%R@y2@R@4333J@3333Q@4333CJ@ffffQ@J@3333{Q@yJ@ffff:Q@@J@Q@sJ@\Q@lcJ@ffffQ@]J@ffffQ@43333\J@ffffQ@hffff]J@ffffQ@hfffOJ@̈Q@̜AJ@̤Q@hfff%J@ffffQ@4333J@Q@4333J@R@4333ӛR@3333:R@4333R@d8R@4333ۨR@H7R@hfffFR@ffff7R@hfffR@:R@@R@y;R@lR@>R@hfffR@BR@R@DR@4333kR@FR@dR@3333GR@)R@YHR@h R@ffff[R@LS@ffffdR@ LS@3333'cR@hfffS@cR@R@ffffdR@hfffvR@bR@R@^R@ R@ffff[R@R@S@xBR@4333S@ FR@ S@33339R@hfffS@ffffr6R@,S@3333k3R@4333[S@ffff0R@S@|-R@S@4.R@lS@<1R@̤S@3333:R@hffffS@3333>R@hT@̜R@pT@TR@ yT@R@T@dR@4333kT@YR@T@لR@8T@̜R@pT@ЅR@T@ffffR@4333T@R@4333T@TR@yT@R@phfffVT@R@4333T@R@ hfffT@R@ɹT@@R@hfffVT@܅R@,T@ffff҄R@HT@R@T@ffffNR@4333T@R@4333#T@R@4333T@R@T@ԇR@hfffT@R@XU@ffffR@7U@ffffR@̔"U@3333cR@U@R@4333sU@ffffR@x-U@ffffR@43330U@3333gR@7U@ffffR@4333+U@ffffʠR@̔"U@3333cR@̌U@3333+R@U@ffffR@̩U@;R@U@ffffR@IU@ffffҽR@)U@R@̌U@3333/R@hfffU@tR@IU@ffffJR@hfffVU@3333+R@U@)R@U@3333'R@hfffVU@ffffR@ U@|R@,U@R@̩U@;R@ `T@R@hfff.T@R@hffffT@R@4333kzT@ffffR@9zT@pR@L{T@S@hfff#X@3333'MS@W@ffff>FS@W@CS@LW@4AS@LW@̼@S@4333W@]AS@4333W@fffff?S@4333W@e>S@X@)@S@hfffn X@3333?S@9X@3333w@S@DX@̴AS@(X@ffffDS@#X@3333KHS@hfff#X@IS@!X@3333'MS@W@ffff>FS@hIV@ffffKS@hfff~kV@SS@ pgV@SS@RV@3333KSS@LV@hQS@IV@NS@yKV@3333oMS@4333+SV@ffffKS@`V@LS@̜jV@IPS@hfff~kV@QS@pgV@SS@LS@TS@eS@ffffS@S@)S@S@`S@hfffS@3333S@ S@ffffS@LS@3333CS@S@ffff S@hfff S@ffff S@IS@S@̼(S@S@)S@S@3S@TS@eS@3333S@(cS@S@ WS@3333S@S@)S@xS@3T@4333cT@l>T@ S@ffffv=T@S@;T@S@I6T@pS@m5T@hfffNS@3T@̴T@H6T@T@7T@T@|8T@4333cT@3333_;T@T@T@S@ffffv=T@`̬yV@DT@LV@MT@ ̔V@KT@V@ffffLT@yV@MT@̬yV@JT@zV@̄IT@4333s~V@=GT@4333CV@DT@LV@ IT@̔V@KT@hZ@ffffS@4333Z@3333S@ TZ@S@Z@3333S@4333Z@3333S@Z@3333OS@4333Z@ffffS@Z@HS@4333Z@`S@Z@S@Z@3333S@TZ@S@4333Z@ffffS@hfffZ@3333ÕS@hfffvZ@S@4333Z@S@hfffZ@ԒS@a@Q@)a@Q@a%a@Q@$$a@Q@hfff"a@Q@ "a@Q@̄"a@$Q@4333(a@-Q@+a@yQ@4333,a@Q@hfff.a@Q@`0a@`Q@̜3a@Q@43336a@ffffQ@4333>a@}Q@=a@̼Q@q;a@PQ@4333#:a@Q@)a@Q@`4333 d@3333Q@d@3333ǻQ@ 4333d@3333Q@hfffZd@3333ǻQ@d@ Q@4333 d@3333wQ@4333'd@ffffvQ@d@3333Q@d@3333Q@4333d@Q@4333d@3333Q@hfff>d@ffffdQ@-e@Q@t e@Q@He@Q@e@d~Q@d@3333yQ@ d@wQ@hfff>d@3333uQ@Hd@ttQ@d@3333qQ@hfffe@3333mQ@4333# e@̄jQ@Me@ffffdQ@l&e@ffff&eQ@'e@xfQ@m(e@d@aXK@d@̔bK@d@XK@4333d@K@yd@0tK@Xd@ffffyK@d@K@d@,K@\d@K@4333d@ffffK@d@xK@̽d@K@4333d@IK@d@3333K@d@aK@4333d@ffff^K@hfffd@̉K@d@3333K@4333[d@wK@dd@nK@43337d@ffffFkK@hfffd@ffffiK@hfffd@AbK@̤d@XK@4333d@fffffkK@yd@0tK@p`c@ QI@c@YnI@ c@YnI@цc@qdI@`c@ffff]I@Hc@YI@lc@QI@c@ QI@hfffc@,TI@uc@(`I@c@ffffkI@hfffc@ffffnI@ c@YnI@hfff>fc@HI@hfffc@bI@c@bI@ c@3333`I@P|c@WI@hfffxc@=I@uc@3333K3I@hfffmc@9/I@tjc@%I@fc@ &I@hfff>fc@!I@4333gc@<I@4333gc@ I@ c@3333[G@ ̨b@3333;oG@b@$mG@hfff&b@ffffjG@!b@dG@b@dG@c@ffffrG@hfff> c@33333G@hfffc@3333[G@hfffNc@3333#G@hfffFc@3333G@̨b@3333;oG@hfffNb@F@4333b@QG@4333˾b@ffffG@4333{b@3333#F@4333Ob@ffff~F@hfffNb@3333F@hfff>b@F@b@ffff.F@Db@ffff>F@b@ffffFF@b@F@=b@3333sF@b@3333G@4333b@G@(b@QG@b@̤G@4333˾b@ffffG@X\b@3F@ɚb@3333cF@(b@HF@b@3333cF@̜b@̤F@b@ F@`b@ffff&F@)b@ F@4333ˁb@̌F@~b@YF@}b@F@{b@pF@hfffV|b@F@4333xb@iF@ ub@F@qb@ffffF@hfffmb@xF@gb@3333mF@db@3333bF@hfffdb@TF@,_b@iHF@4333]b@̬AF@\b@3F@hfff&cb@DF@4333fb@3333FF@ib@̼VF@rb@3333jF@sb@3333{qF@hfffsb@xF@ ub@3333}F@4333yb@3333zF@=}b@~F@4333+b@3333F@db@F@Db@3333F@4333/b@F@Mb@xF@ɚb@lF@hfffb@ffffF@ib@3333[F@pb@8F@b@HF@` b@3333M@Ib@M@ Qb@M@b@qM@ b@3333M@b@3333sM@4333[b@3333M@b@fffffM@Ib@0M@hfffb@̬M@Qb@M@t'a@ffffSK@̘Fa@8K@>a@3333ۋK@hfff"=a@ffffK@y2a@8K@e1a@K@-a@ K@L,a@ffffK@hfff(a@ rK@t'a@1eK@(a@leK@hfff.a@3333oK@0a@̴iK@(5a@ffffSK@hfff7a@TK@I9a@4YK@;a@_K@>a@ffffdK@?a@ iK@@a@PsK@hfffCa@ffff~K@̘Fa@3333KK@Ea@K@Aa@3333ӆK@>a@3333ۋK@phfffa@DvK@4333%a@̍K@ 4333{"a@ffffK@a@ffffދK@4333sa@33333K@hfffa@3333czK@|a@yK@4333a@ffffzK@a@DvK@!a@vK@4333%a@3333یK@hfff$a@̍K@4333{"a@ffffK@`ySb@E@\b@$E@ 4333Sb@E@Sb@E@ySb@E@4333Ub@E@Vb@4E@\b@ffffE@hfffJ\b@!E@4333cZb@$E@4333Sb@E@4333-b@E@4333+Rb@@F@dKb@Y6F@̤Fb@3333?F@hfffCb@@F@>b@ffff"F@|@4333U`@,w>@O`@,w>@4333kL`@`c>@hfffBN`@2333C>@4333CP`@=>@S`@2333SC>@4333U`@]>@T`@2333c>@O`@,w>@x[`@ffffb>@̤b`@ffff>@ P^`@2333ӫ>@^`@9>@[`@q>@[`@ffffb>@hfff^`@̜e>@4333_`@̬>@hfffa`@y>@̤b`@ffffv>@hfffa`@ffff>@hfffFa`@2333>@d``@2333>@P^`@2333ӫ>@`@ffffK@@`@ffffVd@@`@ffffa@@4333`@3333Sc@@hfffZ`@b@@`@`@@hfffJ`@ffffVd@@`@̼T@@`@pP@@,`@hM@@`@ffffK@@4333K`@Q@@H`@3333R@@`@yS@@$`@ffffX@@`@ffffa@@>`@@@hfffbF`@ffffFE@@ P@`@B@@hfff@`@3333<@@hfffV?`@P,@@}@`@ffff&(@@@`@3333[%@@>`@33333@@?`@4@@@`@@@B`@fffff@@hfffbF`@+@@4333KF`@>@@hfff^E`@ffffFE@@P@`@B@@XG`@̬5@@N`@3333{C@@G`@<;@@1H`@3333+7@@\I`@̬5@@1L`@<6@@dM`@ffff:@@N`@3333B@@K`@3333{C@@G`@<;@@X`@PB@43333`@+B@̘`@ffff%B@`@ffffB@`@B@d`@PB@4333۫`@B@43333`@B@hfffv`@+B@̘`@ffff%B@4Ga@B@hRa@p(C@hfffRPa@ffff&!C@Pa@p(C@4333Na@ffffN%C@Ia@C@Ha@3333 C@Ga@ffffNB@4333KJa@3333B@PJa@B@hfff6Ia@B@ Ia@ffffVB@4Ga@)B@Ga@B@hfffKa@3333;B@4333Oa@3333B@hRa@3333cC@Na@ C@4333Na@C@hfffRPa@ffff&!C@`4333+ma@ffff E@hfffqa@3333E@ ma@3333E@4333+ma@pE@ma@3333 E@4333na@ffff E@hffffoa@ffff^ E@)pa@ffffV E@hfffqa@3333E@oa@E@ma@3333E@Xa@yF@Ta@̔F@a@̔F@ma@F@hfffa@yF@Ta@3333F@A@d`@A@`@A@`@̜A@`@3333+ A@̔`@̜ A@hfff`@ffffA@p4333k`@3333k@@<`@Q@@ ̄`@3333k@@4333'`@@@<`@3333@@hfffƍ`@ffff6@@`@L@@4333`@3333@@`@Q@@4333k`@@@hfff`@@@`@̌@@̄`@3333k@@P4333c]@4333j8@]@8@]@x8@4333c]@4333z8@4333]@4333o8@]@4333j8@]@t8@4333]@8@]@x8@`]@dfffo8@hfff]@dffff8@ ]@\8@hfff]@dfff&}8@4333˅]@dfff6r8@]@dfffo8@hfff]@ 8@]@̼8@̤]@dffff8@4333]@̌8@]@\8@X`@Q^A@hfff`@̼A@`@̼A@``@ A@`@TwA@`@nA@`@hA@`@Q^A@hfff`@ffff6fA@`@̼A@x4333C_@3333ZA@4333`@3333uA@ 4333C_@oA@hfff_@3333hA@hfff_@3333^A@hffff_@$^A@hfffF_@bA@_@3333ZA@`@ZA@4333`@ffff&gA@43337`@ffffvpA@_@ffffNrA@hfff_@3333uA@4333C_@oA@@0_@3333JA@4333#_@PWA@0_@PA@4333k_@3333JA@4333#_@NA@`_@PWA@0_@PA@_@3333˙@@_@@@_@@@4333_@P@@̜_@ffff@@4333Ì_@@@_@@@p_@3333+@@_@Ԝ@@`_@@@ _@3333˙@@_@@@4333;_@@@4333c_@ffffƢ@@ܷ_@3333@@_@@@_@и@@̬_@@@_@@@p4333_@ffffv-A@P_@3333HA@ _@EA@hfff֏_@3333HA@_@0DA@܇_@33338A@4333_@ 3A@_@ffff1A@܊_@ffffv-A@_@l/A@x_@̔6A@P_@̼?A@_@EA@`4333_@fffffB@4333S_@LB@ 4333S_@PB@hfff_@3333+B@X_@LB@4333_@B@_@ B@_@3333B@hfff~_@ B@hfff_@fffffB@4333S_@PB@4333M^@v?@hfff6w^@,?@hfffd^@ffff&?@̴b^@ffff?@y_^@2333?@̴]^@ffff?@U^@ ?@4333M^@,?@̄N^@2333?@U^@̤?@hfffFa^@2333?@4333q^@v?@hfff6w^@ffff~?@hfffu^@?@4333s^@Y?@hfffd^@ffff&?@h4333 ~^@=@^@2333$>@ 4^@i>@4333^@ffff#>@4333 ~^@2333$>@̔~^@ffffV>@^@i>@^@2333S>@^@=@^@2333=@^@ >@4^@i>@X4333^@ffff=@4333 ^@@=@^@@=@^@2333=@4333^@fffff=@\^@=@ъ^@ffff=@4333 ^@2333ӭ=@^@fffff=@^@@=@P<^@=@ٙ^@=@4333^@2333C=@hfffv^@=@<^@Y=@hfff^@I=@8^@=@ٙ^@2333s=@4333^@2333C=@4333]@4333#i9@̬]@dfff69@ ]@̌9@]@dfff69@hfff>]@9@4333]@4333C9@hfffF]@43339@4333]@dfff~9@]@dfffn9@]@4333#i9@]@t9@hfffF]@dfffz9@]@9@̬]@dfffF9@]@P9@ ]@|9@ ]@̌9@x[@̼4@[@5@ a[@dfffF5@[@5@hfff[@5@ԓ[@4333#5@[@4333s5@4333[@L5@[@l4@[@43335@@[@̼4@|[@5@[@ 5@a[@dfffF5@P4333Z@dfffv5@4333Z@D5@4333{Z@D5@hfffZ@<<5@4333Z@5@4333[Z@dfffv5@4333Z@75@4333Z@l85@4333{Z@D5@X̌Z@4@HZ@dfff5@Z@4@̌Z@I4@4333Z@4@\Z@dfff64@DZ@04@HZ@dfff5@hfff6Z@I5@Z@4@`HZ@94@ Z@dfff4@ Z@94@Z@dfff4@HZ@4@\Z@94@Z@<4@̴Z@43334@Z@̼4@ Z@94@Z@94@Phfff>Z@4@hffffZ@̌4@hfffZ@̌4@hfff>Z@<4@hffffZ@4@Z@4@hffffZ@43334@Z@dfff4@hfffZ@̌4@PYZ@l\!@hfff&Z@`!@YZ@f!@hfffZ@l\!@̄Z@]!@4333éZ@f!@Z@,r!@hfff&Z@`!@YZ@f!@hfff^Y@0333$@PZ@0333S$@ hfffZ@0333S$@Y@$@Y@̬$@hfff^Y@$@̌Y@$@Y@`|$@hfff.Z@0333$@Z@@$@4333[Z@03338$@Z@ s$@PZ@`fff$@Z@$@hfffZ@0333S$@X4333Y@ &@4333Y@`fff&@4333Y@0333&@̬Y@03333&@Y@ &@4333Y@0333&@4333[Y@`fff&@4333{Y@@&@hfffY@9&@4333Y@0333&@HY@0333$'@ЦY@`fff&b'@Y@:'@Y@0333$'@ЦY@`Z'@iY@`fff&b'@Y@`fffU'@Y@:'@phfff~Y@0333'@̄Y@M(@ hY@`fffH(@Y@M(@hfff~Y@=(@4333SY@,'@ Y@`fff'@43333Y@`fffF'@̄Y@0333'@PY@9'@4333#Y@ (@43333Y@L%(@hY@`fffH(@`̜Y@??Y@3333'? YY@3333'?4333#Y@@ffff?̜Y@@ffff5?yY@??Y@M?Y@?hfff~Y@F?,Y@̧?YY@3333'?X4333CZ@L@IZ@L@4333 Z@L@hfff Z@@4333CZ@L#@hffff Z@`ffff@ Z@L@hfff.Z@@IZ@1@4333 Z@L@X9 Y@`ffff@Y@@hfffY@@ Y@@9 Y@`fff!@Y@`ffff@hfff~Y@-@Y@`fff@Y@0333s@hfffY@@\X@ @4333X@`fff@hfffFX@`fff@hfffX@0333@4333X@0333s@yX@@\X@`ffff@hfffX@0333w@X@`fffY@X@ @hfffX@@X@@@@iX@033330@X@L>@4333X@03333o@hfffFX@`fff@H4333X@@4333X@@@4333X@@@4333X@`fff&c@8X@@pX@0333s@4333X@@H@4333X@@@XX@`fff&\#@hfffY@L#@X@L#@X@`fff~#@̤Y@`ffffl#@ Y@`fff&\#@hfffY@0333d#@̬Y@̌#@Y@0333S#@X@L#@`X@"@Y@ ,#@ X@y)#@!X@0333#@X@"@X@"@pY@@"@Y@0333#@hfffY@ ,#@Y@Y'#@X@y)#@@X@ @̬X@03337 @hfffX@ @4333X@Y@̬X@Y @X@03337 @hfffX@ @xɐX@0333@hfff֛X@`fff&U @ hfffX@0333@hfff֛X@+ @hfffvX@`fff8 @̜X@`fff&U @IX@E @ɐX@L@hfffX@0333@43333X@!@X@YQ@X@LP@hfff.X@0333@hfffX@0333@P X@`fff"@X@9G"@ X@`fff"@hfffX@Y"@X@`fff&)"@hfffFX@9G"@4333X@B"@X@0"@ X@`fff"@hjW@`fff@hfff~{W@L@ vW@@4333tW@L@kW@@jW@@jW@0333s@dmW@0333@4333 uW@`fff@hfffxW@S@hfff~{W@@vW@@P9fW@`fff& @4333nW@0333s@hfffiW@ @PgW@0333n@9fW@`ffffF@hW@`fff& @4333nW@ m@QlW@0333s@hfffiW@ @PDW@0333l @4333JW@ @4FW@ @hfffDW@ @DW@`fffƌ @`GW@o @4333JW@0333l @IW@ @4FW@ @`SW@@\W@, @ XW@, @hUW@̌ @SW@`fff&@4333UW@`ffff@\WW@@4333S\W@`fff@\W@0333@[W@`fff&@XW@, @phfff6]W@0333 @\bW@`fffs @ hfff`W@Q @hfffbW@0333sm @hfff_W@`fffs @hfff6]W@X @̄]W@7 @^W@03333% @1^W@ @4333^W@`fff @\_W@0333 @\bW@ @hfff`W@Q @`hfff-W@ C"@43333W@|"@ hfff-W@`fffh"@-W@`fffT"@hfff/W@ C"@hffff2W@E"@43333W@`fffX"@I2W@`fff&{"@hfff0W@|"@D/W@v"@hfff-W@`fffh"@p̔W@ %@$W@%@ W@%@W@`fff&%@W@`fffF%@̔W@0333%@4333#W@M%@hfffW@`fffF%@@W@ %@hfff. W@%@$W@0333h%@t#W@%@ W@%@X &W@&@\,W@̬'@),W@`fffF&@(W@̬'@(W@&@ &W@&@@)W@&@\,W@`fff&&@4333+W@̌&@),W@`fffF&@H$=W@'@CW@(@AW@(@4333?W@`fffF(@$=W@@(@>W@@'@CW@'@AW@(@P+W@0333)@hfff.W@0333S)@+W@`fff)@4333+W@0333)@-W@0333Ӻ)@hfff.W@`fff)@4333{-W@0333S)@q,W@)@+W@`fff)@4333+"W@l'@DW@hfffF+@7hfffAW@ *@DW@hfff&*@DDW@y*@CW@hfffF+@AW@0333s+@,;W@*@hfff6W@Y*@ 7W@ v*@hfff3W@`fffF*@,5W@Y*@hfff3W@)@433330W@L)@\/W@,)@hfff0W@0333V)@.W@03333;)@ .W@ )@4333.W@0333(@4333.W@(@1W@`fff(@4333s2W@s(@4333;1W@`n(@hfffv,W@m(@4333K+W@b(@)W@0333s9(@p(W@(@&W@`fff&'@A$W@l'@4333+"W@,'@#W@'@hfff$W@o'@hfff*W@0333'@,W@l'@A.W@y'@0W@@G'@hfff1W@'@4333 3W@0333ӿ'@hfff2W@`fff'@0W@'@/W@L'@Q2W@(@ 3W@0333((@7W@`fff\(@I8W@0333t(@hfffF7W@@(@;W@(@`?W@)@4333=W@0333s)@8W@0333s)@<:W@L)@4333W@dfff63@|AW@03@hfff@W@dfff3@i=W@4333 4@:W@4333#4@8iW@dfffvL3@4333|W@3@4333wW@dfff&{3@hfffuW@̬y3@mW@3@hffflW@`3@8iW@̼~3@ajW@|u3@hfffnW@4333j3@`pW@`S3@,tW@dfffvL3@yW@U3@hfff{W@̌]3@4333|W@|h3@hfff|W@m3@4333wW@dfff&{3@XhfffvV@5@4333{V@4333S5@qV@4333S5@4333sV@dfff5@hfffvV@P5@4333V@5@V@dfff5@4333{V@dfff65@ V@95@qV@4333S5@hV@ـ5@V@43335@ V@43335@V@4333s5@4333V@ 5@V@p5@4333V@ـ5@V@5@V@5@hfffV@̼5@hfffV@5@V@43335@HV@6@hV@ 6@hfffV@ 6@V@6@hfffV@,6@hV@4333sH6@!V@̌]6@hfffV@ 6@h4333SV@PZ6@V@4333ӝ6@ 4333SV@dfffy6@V@`6@4333V@PZ6@V@a6@V@dfffl6@yV@}6@V@6@0V@4333ӝ6@hfffV@L6@4333SV@dfffy6@P4333SV@dfff6@hfff6V@4333 7@V@4333 7@4333SV@7@V@dfff6@hfffV@6@hfff6V@dfff6@4333V@dfff6@V@4333 7@0V@ 6@V@6@hfffV@ 6@hfffV@,6@,V@6@0V@6@qV@\6@ܣV@,6@(V@6@̌V@i6@1V@q6@̌V@dfffS6@hfffV@̬6@V@ 6@ıV@6@V@4333(6@iV@c6@V@ |6@)V@43336@V@6@hfffV@ 6@ ` S@Y=#@ S@}#@ S@`fffB#@\S@[#@S@y{#@4333S@}#@4333S@x#@ S@`fffm#@S@l_#@ S@Y=#@ S@`fffB#@!PS@03333!@hfffS@̌5"@hfffS@03333!@S@"@ S@`fff!"@S@̌5"@4333S@#"@̌S@ "@hfffS@03333!@"x2"ffffJQ@L3333_Q@ Q@`fff !ffffQ@`fff!ffffQ@2"ffffQ@0333s"ffffJQ@9!̴Q@LE!0Q@̚ 3333˾Q@0333 Q@L3333{Q@0333 3333_Q@ Q@#̎c43332@Yc̜F4@{^cdfff3@_c4333c3@bc3@3333bc)3@ffff\fc3@scdfff)4@̜zc̜F4@{c4333B4@|c*4@@zc4@}c 3@3333c43333@̎c3@~c@3@̀|ca3@|cdfff6 3@3|c 3@uc2@3333tc43332@ffffrc43333@ qc3@fffficB3@acdfffQ3@5[c@t3@Yc4333C3@ffffZc4333s3@{^cdfff3@$ffffJcl5@ʖc4333:5@Yc4333c-5@yc 35@c05@֦c4333#75@c4333:5@3333c9.5@c'5@ffffJc43335@3333c 5@cl5@c43335@ʖc4333'5@c)5@Yc4333c-5@%TcI4@̬c5@Pc 4@3333c4@cdfff4@3333Wc43334@3333c,4@c̼4@c 4@c5@3333cdfffF5@Tcdfff4@c43334@c4333c4@3333gc<4@\c4@3333]c̴4@c,4@c4@3333cI4@3333c4@mc4@3333oc4@̬c43334@̘cdfff4@Pc 4@&xffffd5@3333ddfff6@ d43335@ffffd43335@̂d̼5@ffffhd5@dP5@ddfff5@dL5@fffftddfffF5@3333d06@ffff8ddfff6@ffff>d̬5@d43335@'c4333D5@3333Uč5@cx5@Vc 5@?c5@̾č5@̦c5@ffffc5@c4333ӕ5@3333cdfffv5@̦cdfffF}5@3333ič`5@cQ5@ffffcO5@dcP5@c4333#^5@3333Ocdfff`5@ffffc]5@cS5@3333ۼc0W5@-c4333sJ5@c4333D5@c̜G5@3333UcN5@c|U5@c`5@c,u5@zcps5@ffffcdffft5@cx5@(@cI5@3333c 96@̈c 96@ffff@c4333#6@@c4333 6@cdffff5@3333cdfff5@{cdfff5@3333ac5@cI5@c5@c@5@̐c 6@3333c43336@cp'6@Dcdfff686@̈c 96@)hffffcdfff4@ffffcdfff4@ 3333#cdfff4@ffffcdfff4@3333c`4@&c4@cdfff4@0c4@ffffcdfff4@3333%cdfff4@-c43334@3333#cdfff4@*xTf@̤I@4333snf@ffffI@ ef@ffff&I@hfffbf@3333I@hfff]f@3333I@hfff&Vf@ffffI@Tf@3333kI@Wf@I@̠]f@|I@hfffhf@̤I@4333snf@I@Lmf@PI@4333kif@ffff޵I@ef@ffff&I@+Xof@3333I@xf@J@tf@J@ pf@3333cI@of@fffffI@hfffqf@pI@tf@3333I@Iwf@I@xf@I@tf@J@,hfff(f@I@m5f@J@hfff 2f@$J@0f@TJ@4333O/f@I@hfff.,f@ffffI@hfff(f@3333I@4333W(f@I@4333*f@I@4333K-f@I@43333f@II@hfff3f@ffff6I@4f@ffffJ@m5f@0 J@hfff^4f@J@hfff 2f@$J@-he@ffff-J@ոe@ffff@J@ 4333 e@ffff@J@4333e@9J@e@8J@e@3J@e@2J@ e@ffff-J@ e@ffff.J@Էe@3333+9J@ոe@`?J@4333 e@ffff@J@.Տe@D`J@e@J@e@mJ@ e@xJ@De@pJ@|e@y}J@hfffe@J@e@J@Տe@ xJ@4333 e@ffff&tJ@e@YqJ@јe@fJ@e@D`J@e@@hJ@e@gJ@hfffe@iJ@$e@̔iJ@e@jJ@e@mJ@/ffff^eI&N@3333me̬MN@ fffffe3N@Րe$2N@ffffe3333:N@̆e@N@ffffe̬MN@ffffeffffHN@ffff^e!?N@3333e<;N@Xe*N@ea*N@3333meI&N@e+N@fffffe3N@0P3333_LeL@Ce3333L@3333_LeL@3333YLe3333#L@tKe̼L@rHeL@3333#Ee3333L@Ce3333L@3333_LeL@1P3333d K@ dK@dK@3333d3333K@ffffbďK@ffff d K@ d9K@ dK@dK@2dffffK@rd3333˳K@3333d`K@d3333K@ffffd̼K@^d3333kK@3333qd4K@ffffnd9K@d3333KK@RdK@ffffdK@BdK@ffff*d3333˳K@3333Ad K@ffffdffffK@d٧K@ffffjdDK@3333qdffffK@3333dK@3333ud̼K@}d3333[K@dK@rdDK@dٝK@3333d`K@3pffffMd3333kK@zGd3333}K@ ffffMdK@icPK@=d̤K@3333Ed3333#K@GdaK@dK@ffffdHK@ffffdK@<dffffVK@Dd3333vK@3333mdxK@:dK@3333cK@c3333K@c̬K@c3333{K@Tc̄K@ffffcXK@ffffc3333SK@7ffffcffffVK@|cK@|cpK@3333qcK@ffffdcffffޛK@ffff cLK@3333c)K@ffff"cffffK@xcffffޏK@3333UcK@ffffc3333K@ffffcffffVK@c3333[K@ffffcK@3333cJ@̰dQJ@dqJ@d3333K@3333}dHK@ffff(d3333+J@ffffLdAJ@8dJ@3333dJ@dJ@ffffd3333J@3333adJ@IdffffFJ@3333d3333sJ@ffff"dJ@wdJ@3333dJ@ffffdAJ@d3333J@3333d̴J@33333dJ@d3333J@̜d3333;J@̀ddJ@[dJ@ffffdfffffJ@Zd3333cJ@d3333[J@dJ@3333ddJ@ffffpd3333{J@3333dyJ@dqJ@dffffnJ@ldffffFJ@d4J@3333dJ@d3333[J@Zd`J@̸dJ@3dffffƫJ@d̤J@3333dܬJ@ffffdpJ@d4J@ffffd3333CJ@3333;dJ@3333dffffJ@ffffxdJ@ffffd J@>xdffff6J@3333IdJ@ d`J@dffffFJ@3333daJ@)dffff6J@ffffd̔J@3333dJ@odJ@3333IdJ@dJ@dffffJ@dffffFJ@d`J@?`Փe J@3333 e33331J@ e33331J@eeI-J@3333effff)J@Փe"J@ffff@e J@ߎe"J@3333 e0*J@ffffBe̼/J@ e33331J@@ffff¿eQJ@efffffJ@ffffneffff> J@̴eqJ@efffffJ@effff&J@3333ieY J@ effffJ@ffff¿eJ@̪e3333C J@ffffĽe< J@ffff effffJ@̾e3333+J@eJ@ffffeQJ@ʫeffffJ@ffffne3333J@3333eJ@e! J@3333Ǡeffff J@e J@ffffneffff> J@A3333ue8I@ffffe5J@ge5J@e`0J@e+J@e3333(J@e3333%J@ffffHep"J@e3333J@3333-effffJ@ffff^effffFJ@3333Oeffff J@eJ@ffffeJ@3333ueffffJ@e8I@3333e3333{J@ffffe J@ffffeffffNJ@e̤J@33339eJ@e|J@ffffe%J@ffffex*J@ue/J@ge5J@BH̊fffff.I@IfqI@ffff2fqI@̊f3333I@fffff.I@If3333I@JfI@ffff2fqI@CP3333= fI@f9I@, f`I@f3333I@3333 f9I@3333= fI@̬ f3333CI@ffff0 fI@, f`I@DfDI@ fffff6I@fffffffffI@fffffI@̦f̴I@̘fffffI@3333f3333I@Xfffff6I@f̄I@̐f3333I@fI@3333fffff.I@fDI@f3333I@fI@3333f$I@ZfpI@fffffffffI@yf3333+I@ f̌I@ fI@&f0I@fffffffffI@Epf3333I@5e3333 J@ 3333qf3333I@fffffPJ@5e̴J@ffffeTJ@f J@zf3333 J@3333f J@f,J@fffffJ@fffff̌J@3333qf3333I@Fffffr5fI@ffff"f3333I@ffff&fffffI@;(fI@*f3333[I@3333]5fPI@ffffr5f̼I@4fI@{2f3333I@ffff0/f3333I@ffff<,f8I@3333['fffffI@%f3333I@$fffffI@R$fII@ffff#f3333I@"f3333I@ffff"fqI@#fI@33335$f3333I@3333S%fhI@ffff&fffffI@G9FfffffI@4fI@4f3333I@ffff9fffffI@3333;f!I@>fI@3333Cf3333;I@ffffbEfffffI@9FfI@3333Df3333I@qAfI@ffff?f3333I@E?fpI@ffff@fffffI@̂Bf3333{I@ffffAfI@ffff=fffffI@3333ZB@hfff&8@3333aB@u8@̬_B@@s8@ffffN]B@l8@A[B@\P833338@B@`8@3333#B@`8@3333+B@83338@3333#B@833338@!B@l8@3333 B@Y8@ffffB@8@B@`8@3333+B@]@8@B@8@̼B@8@B@83338@B@hfff8@3333B@Y8@̼B@l8@fffffB@@8@B@8@ffffB@98@3333sB@l8@yB@8333S8@B@8333S8@B@8@3333;B@8@B@8@B@^h8@ffff~B@A9@ B@ hfff(9@B@89@ffff~B@A9@B@833399@B@9@B@8333 9@ B@8@̤B@,9@ffffB@L 9@ffffB@hfff(9@B@_Xhfffƫ8@3333cuB@`8@ B@,8@zB@8@3333cuB@̌8@uB@`8@yB@8333S8@ B@8333s8@ĂB@hfffƫ8@B@,8@zB@`9@̬C@ ):@MC@83333:@MC@9@yIC@9@3333AC@9@@5C@9@@-C@9@̼&C@83339@3333"C@8333S9@$C@9@̬C@8333:@C@hffff:@C@Y:@3333#C@83333(:@ffff&C@L&:@ffff;C@hfff&$:@3333;>C@ ):@ffff6EC@hfffF:@ffffEC@83333:@MC@a9@̄|C@y:@ffffC@8333:@C@̌d:@3333C@i:@3333+C@hfffY:@ffffC@Y*:@ЯC@83333*:@ffff~C@:@3333C@hfff:@ffffnC@9@ffffΤC@9@3333C@9@ffffޖC@9@ɑC@hfff:@:@C@:@`C@,):@PC@c:@|C@x:@̄|C@8333:@@C@̀:@ffffC@}:@3333C@8333:@D@̌9@BD@fhffff 9@ffff.C@r9@tD@hfff_9@D@Y9@ C@hfff&I9@hC@8333;9@D@9@C@hffff 9@C@83339@ffffvC@9@3333C@` 9@̴C@hffff/9@3333;C@hfff49@C@L99@@C@?9@3333sC@8333s@9@\C@lC9@ffffVC@yL9@ffff.C@hffff[9@pC@@_9@ffffC@`f9@3333C@ p9@C@r9@tD@hfff_9@D@gp8@3333+JD@L8@ffff~eD@ 83338@ffff~eD@hfff8@fffffbD@hfffF8@ffffWD@8@RD@Y8@3333+JD@833338@ffffND@hfff8@ffffVTD@L8@ZD@ 8@y]D@8@̤dD@83338@ffff~eD@hX@9@ D@ 9@ffffvD@̬9@ D@@9@dD@9@ D@8333S9@3333sD@ 9@3333D@9@ffffvD@83339@D@̬9@ D@i`fff<00333&@0333 0`fffe&@ <0d&@0333c0`fffe&@03330a&@$0lU&@`fff-0B&@033310B&@`fff<00333:&@0333#;0@0&@100333&@P0l&@|0 +&@0333 0,<&@<0d&@jXz03@W03@k0L3@z0ٵ3@Iw0y3@0333p03@0333_0ٴ3@W03@̬d0i3@k0L3@kx0333=13333R@@y0ffff.o@@ y0ffffa@@0333#03333c@@03333k@@0333 1ffffnh@@01ffff.o@@0333=1Xg@@91(b@@0333+1fffff\@@̬1ffffT@@`03333R@@0Z@@y0ffffa@@lȟ/`fff&@0333/0333b&@ L/0&@/,&@̌/03333&@0333s/`fff&@0333/9*&@/0333K&@y/R&@/0333b&@/`fff\&@L/0&@m03330ffff<@02333s<@U02333Ca<@0<<@`fff02333s<@Q0ffff<@`fffv0ffffi<@̌0fffff<@`fff0̬^<@03330I`<@03330V<@033302333K<@0333s00&<@0333s0ffff<@03330ffff6<@ 0<@k02333&<@U02333Ca<@n`fffF+p<@̌*<=@0333+$=@L+ffffv=@̌+\=@0333+i=@`fffF+|<@`ffff+p<@0333n+ffffF<@+<@0333*=@0333S*&=@̌*2=@Y*<=@+23336=@0333+$=@o,ffffV<@+2333<@`fff,<@ N,h<@`fffv,@7<@ ,23333!<@,ffff<@,ffff<@L,ffffV<@d,ffffV+<@`fff&+2333@<@ٹ+h<@+̕<@+2333<@`fff+<@`fff+2333<@`fff+н<@,<@`fff,<@ph9)@0333S)@ ;)@0333s)0333|@9)̌H@6)`fff@)@Y )̾@0333S)0333#@`ffff)`ffffT@)0333m@;)@q0333s/9;@,.(<@.%<@.(<@̌.|'<@0333. #<@0333]/p'<@ q/l<@0333s/ffff;@Y/ffff6;@̬k/;@O/ffff&;@`ffff/9;@.;@@.;@,.);@9. <@.%<@rp@/YY&@0333Q/&@ Yo/&@`ffff/0333&@@/c&@0333/0333S]&@`fffFs/YY&@`fffFs/0333Sn&@_/w&@U/`fff&@0333Q/̬&@`fffX/̗&@Yo/&@sX@=/ '@`fff.C'@/9<'@@=/`fff&'@`fff& / '@Y/0333'@l /0333'@`fff.0333"'@`fff.C'@/9<'@tppW9 0@8433311@ 8@1@9,-1@ 9433311@LV9L1@pW9dfffV1@iR91@N943330@iD9 0@y+9L0@`9 1@8@1@u`03339P0@`fff80@ 033380@03339dfff0@03339 0@9dfff0@8P0@`fff8p0@0333S843330@̼80@033380@vp,S1ffffv<@123334<@ ,S1 <@ F1 <@033391ffffv<@`fffF/1<@1\<@12333s<@0!1'<@6123333<@03333B123334<@0333SJ12333#-<@,S1 <@wX0l&@/0333S2'@/l&@/&@`fff/-'@/0333S2'@03330 '@0L&@0333/&@/l&@xP`fff'0'@ /'@90'@ 0'@ /'@0'@`fff'0'@%0`fff&'@90'@yX)2y;@P12333;@ 22333;@)2;@"2Y;@I2;@1y;@P1@;@̬12333;@ 22333;@zx03336/@6̼<0@ P6dfffF+0@ٿ6dfff80@y6̼90@`fff680@6̼<0@`fff6&0@03336̌ 0@0333S6hfffF/@ 6/@ɵ6 0@60@P6dfffF+0@{h`8-@K8.@ YT8 .@Yd8.@033338hfff-@`8-@~8-@`fffp8l-@b8-@N8l-@K8-@YT8 .@|x033332ffffV|<@1ffff<@ `fff1ffff6<@033332<@03331<@1ffffV|<@033312333C~<@ 1<@12333<@i1ffffF<@1ffffv<@1\<@,1ffff<@`fff1ffff6<@}xe8<~0@`843330@ `ffffE8dfff0@p`843330@`fffd80@e8P0@`fffR8<~0@`ffffH8p0@9>84333s0@80@`8p0@ 84333ӗ0@0333s8\0@`ffffE8dfff0@~`̬60@i60@ `ffff6l0@̜60@03336L0@̬60@ 6l0@̜6ܮ0@`fff60@i60@`ffff6l0@h`fffv@7hfff&D.@7hfff.@ 033357hfff.@`fffF?70333.@0333>7hfff&{.@`fffv@703333[.@57hfff&D.@.7hfffF.@70333SU.@̌7l.@0333C#7̬.@033357hfff.@`fff7 -@q703333.@`fff7LG.@y7`R.@\70333.@ 7@.@0333703333.@`ffff7 .@`fff&70333|.@0333S7 U.@`fff7`'.@0333703333-@ 70333-@033337 -@q70333.@`fff7LG.@,F@̌(lCF@̌$(!@̣ @̌'!@`fff @!@ 333 @pfff @̚ @L @b @Y @̨ @ @Y @pfff& @ @N!@ @@333sh!@ @pfff!@`fffo @!@4 @pffff!@ 3333 @!@ @@333!@@Y!@`fff@xffff@@?@? fff@?fff@3333?@?ffff@?fff@ ?@3333@?@3333:@@?̣@0333?@)?@3333?ffff@?fff@?hR@3333?@3333@/? ffff@/?fff@?R@@ffff?^@@ffff?fff@3333?@@ffff?@3333@?@3333@@ffff?@?ffff@/?P̏@0333@O@@@@̏@@@0333@4@03333@O@`fff@fff@`fff@@@p.FY67̌ F7 dfff6F97dfffF7dfff#F7.F ,7(FY679F07Fhfff*7̌ FY+7̌F4333S$7dfffF7dfff6F97X8UHi:?H+:?H8:dfffEH+:8UHhfff&J:1MHi:dfffJHf:dfffHH43333a:4333CH,P:?H8:hFH;`0HLf; dffffEHhfff&;FH;1>HY;dfff?H;l4H;`0H4333s;43335HLf;|;H4333o;@H~;dffffEHhfff&;pȹF7dfff֝F@7 dfff֝FL7FY7٢F74333F@7ȹFhfffF7شFY7F,7dF7PF7 F`7dfff֝FL7HL?&@AWA@pfff&@iA@&@iA@YN&@ffffN_A@L?&@AWA@Y&@|`A@pfff&@fffffA@&@iA@@333q%@@@@&@Q@@ %@Q@@̌}%@@@w%@̄@@@333q%@̔@@%@ffff@@̑%@@@%@@@%@X@@%@@@L%@l@@@333s%@3333{@@@&@|@@@3333&@3333 @@pfff& &@3333c@@ %@Q@@ 3333$3333K@Zffff4K@ 333K@ 333K@Zq"K@@@2K@ 33333K@`fffffff4K@80K@u3333+"K@K@ 333s4K@ 3333$Y K@`fff&3333K@l K@u3333K@ 333K@X3333+JL@LVL@G3333TL@3333KL@`ffff3333+JL@ 3333nJL@4PL@L8UL@ 3333VL@G3333TL@3333[K@aK@kxK@@YK@`fffqK@`fffK@EffffK@biK@ 333{ffff^K@ffff&K@ 333sS3333K@ 333ffffvK@ 3333[K@ 333k3333sK@affffFK@kxK@`fffM$L@ ffff.SL@X3333BL@`ffff3333kDL@LffffNL@ 3333i̤RL@ffff.SL@ 333sLRL@ 3333%QNL@9̤LL@YG3333HL@>̬FL@ 3333>L@Lffff-L@`fff1i+L@`fffM)L@ 333@ffff%L@`ffff$L@̌3333,L@ ffff>L@X3333BL@̌K@`fff8K@K@K@>K@`ffff`ffffK@ 333K@dK@ 3333333K@ 333tK@`fffffffnK@̌K@`fff&AK@$K@`fffUffffK@53333K@L%K@L53333;K@K@:@K@`ffff8K@@K@Z)K@`fff8K@;3333{K@ _̬K@K@ 333I3333K@̌fffffL@3333L@L@K@`fffK@L*3333{K@ 333IQK@`ffffHK@=TK@̌*DK@ 3333333K@Y3333CK@Y0L@̌,L@̌ fffffL@2 L@3333L@x3333K@N@0\N@ 3333~0\N@LMN@3333K@N@3333ffffAN@3333CN@̏KN@ffffRN@ffffSN@ffff𿚙9TN@WN@ffff[N@3333~0\N@`̞xM@ffffNN@)ffff>N@3333;N@DN@MN@ffffNN@3333LN@ffffCN@3333;BN@&I?N@3333=N@ffff1;N@ffff̜*N@3333p%N@:1&N@̞)$N@!N@CffffNN@3333SN@DN@ffff3333cN@3333N@33331N@ffffAN@3333*N@̤N@3333k̬N@N@M@xM@ffffffffM@󿚙QM@ffff0N@3333̔N@̦N@q3333N@#ffff~N@ 0N@8N@3333t5N@3333x5N@ffff>N@3333WN@3333{jN@ffffj3333WN@p3333[N@3333ffffvfN@ffffgN@fffffffffjN@Y3333{jN@$gN@ffffphN@ffffN̼gN@ffff fN@q_N@3333@YN@WN@ffffj3333WN@@fff4 ffffcM@333D uM@ @fff, sM@ uM@@ffff( ffffntM@@fff4 ffffpM@ |kM@; ffffdM@@fff ffffcM@Q eM@333D fffffM@@ffff 3333#hM@@fff ffffiM@3333 mM@@fff, sM@E,J@̌23333J@`fffBhJ@3333J@ExJ@6ffffVJ@L3333J@`fffɖJ@~,J@LJ@ 3333J@LVԡJ@̌23333#J@3333æJ@$J@`fffBhJ@P@fffKffffvM@AffffM@IffffM@3333M@@fffKffffvM@d̜M@LpM@AffffM@IffffM@XH3333^M@@fff+jM@HLiM@3333`M@3333^M@@ffffo^M@NYfM@@fff+ffffiM@jM@HLiM@@ffff qM@lM@ffff}M@~M@ffffM@̐3333M@u3333˃M@)aM@@ffff'3333M@333h̬M@@ 3333sM@ lM@{ ffffM@L QM@@ffff fffffM@ L~M@3333 Q|M@Lo {M@@fff ffffM@ ̬~M@@ffff ffffNzM@@ffff )xM@3333 pvM@3333U ̤uM@@ffffM@`fff&\@M@L0I>M@@-3333 1M@3333+)M@&M@`fff&ffffV$M@IM@`fffffff>M@?M@ffff^M@YM@Y ffffFM@tM@.M@LWQM@`fffa3333M@Z4 M@N M@`fff&'A M@L3333M@ 333ffffvM@`fff&5LM@ 333s:hM@L@`fffthL@`ffffmffff6L@3333cL@`fff̴L@ 333sU)L@ L@ 333L@`fffL@ 3333ffffL@@j3333L@hyL@ xL@ 3333KL@ffffF|L@̌bffff&zL@`fff&<yL@3333{{L@ ~L@̌ 8L@`fffL@JxL@3333KL@X`ffff L@ 3333333L@(sfffffL@ 333sJ3333L@L@`fffPL@ 3333#L@ffffL@L@ȅL@ 333L@.L@`ffffffffL@ 3333333 L@XL@ 333lL@`ffffL@@E3333KL@`fff_ffffL@̊9L@ 3333DL@ 333TL@`fff3333L@ 33333333L@ 3333L@3333[L@L93333L@@nYL@9L@wffffL@ vL@ṲL@UL@`fffflffffξL@`fffffffƽL@tL@ffffL@`ffff L@3333˴L@`fff3333sL@ 3333L@sfffffL@3333CL@_3333kL@ 3333kL@ 333(L@`fffLL@LffffL@L@ffffL@`ffff3333sL@L@ L@@HQL@3333CL@_ffff6L@3333kL@x L@L@ /L@`ffffȰL@̠4L@3333[L@`fffL@`fffL@c̼L@ + L@3333ÎL@,L@̌ffffL@/L@h$3333;J@0333s#,K@ G$̬K@\$,K@$ffff&J@`fff$J@0333 $J@0333#3333;J@0333s#J@̌#aJ@ #ffffnK@G$̬K@`,yL@lL@ ffffހL@,ffffv|L@L&zL@`fffyL@`fff3333{L@ffff}L@ 333s L@`fffflL@ffffހL@x@5@*N@hfff5@ffff&K@pffffW+@DK@@333P+@GK@pfffE+@3333IK@*@NK@@333s*@ffff&SK@@333s*@3333YK@@333s*@3333;YK@z*@QK@v*@JK@@333sZ*@EK@\*@ffff&AK@ P*@ffff2K@S*@.K@La*@ffff)K@̌*@xK@@*@K@*@0+K@0+@I+K@pfff&j+@#K@pfffw+@`(K@k+@0K@pfff&4+@3333k6K@<(@%@ffff^_K@@333%@4K@ z%@3333#{K@̌b%@ffffsK@L>%@3333lK@LB%@̼iK@pfff&a%@ffff^_K@w%@`K@̇%@3333[fK@@333s%@3333K@@333%@ffffK@%@4K@pfff%@ffffK@z%@3333#{K@p@%@ffffK@R%@K@ %@3333SK@@.%@ffffK@@3336%@3333;K@@3333A%@̼K@R%@TK@E%@3333K@pfff&%@K@@%@K@@333%@3333 K@pffff %@3333K@ %@3333SK@`&@@5K@̐&@ffffFDK@ +&@ffffFDK@@&@3333AK@&@3333;K@@3333$&@ffff^:K@@3333B&@@5K@̐&@5K@&@8K@w&@)@K@+&@ffffFDK@Xpffff%@3333SL@YY&@3333;L@%@L@pffff%@L@&@3333SL@@333&@3333SL@Y'&@qL@YY&@TL@pfff+&@3333;L@%@L@ @0bK@YB!@̄K@ pfff& @ffffK@@333s @̄K@pffff @3333CtK@ @0bK@̌ @3333dK@ٱ @ffff~lK@3!@nK@YB!@$rK@ @ffff.sK@ @ffffvK@pfff @ffff>~K@pfff @3333K@pfff& @ffffK@X8ffffF@ffff3333sG@83333sG@88G@3333F@|F@jffffF@ffffF@XG@83333sG@TKI@ 񿙙cI@ 3333cI@ffff,]I@3333@ffffZI@3333CUI@>3333UI@TKI@ffff^KI@3333#3333LI@3333NI@cffffSI@ 񿙙YXI@N3333 ^I@3333cI@P@3333@J@@333@ffffvJ@@J@@3333@̜J@@3333@3333J@&@J@ffff@ J@@333@ffffvJ@@J@@33338$@I[E@L$@mE@̷$@AiE@L$@ffffiE@$@3333khE@LA$@gE@@33338$@|dE@@3333C$@3333^E@k$@3333S^E@٫$@laE@@333$@I[E@pfff$@bE@L$@ffffeE@L$@3333hE@L$@mE@̷$@AiE@P @{C@@3333 @ffff֎C@̻ @ffff֎C@ @̤C@̸ @3333C@ @{C@@3333 @̤C@ @C@̻ @ffff֎C@`Li @@D@ @D@ @D@@333 @D@pfff @D@@333r @D@Li @̬D@pffff @@D@@333s @D@L @D@ @D@x̽@ffffFC@I@̜ D@ <@̜ D@@D@ffff@3333D@̽@C@@C@̽@C@fff@ffffFC@@333,@C@I@C@@333B@hC@@3333@$D@<@̜ D@hffffn?TTC@̀?TbC@ ̬?̬^C@ffffn?[C@~?3333UC@ffff?3333UC@#?TTC@̀?ffffVC@{?YC@3333? [C@3333?TbC@̬?̬^C@̒?3333mC@ffff?ffff~C@ ?XC@3333?C@?}C@?|C@̒?sC@ffff?3333pC@3333?3333mC@?uC@?\wC@ffff?C@?0C@?ffff~C@?XC@XpH?C@#?3333C@hfffB?ffffC@pH?qC@0333A? C@l.?C@#?ffffC@|#?ffff^C@)3?3333C@hfffB?ffffC@pb;(QC@̼ ;fffffC@ 0333 ;eC@yB;fffffC@Y;dC@b;ffffbC@hfff\;3333SYC@hfffM;̜TC@hffff;(QC@0333C;\RC@ ;ffffVC@̼ ;^C@0333 ;eC@PhfffO<3333EC@I;8_C@hfffO<8_C@/<3333SC@0333.@ F@L~.@ffffvF@Lv.@F@@3333,@QzF@ٞ-@ĜF@ @333sz-@aF@g-@ffffF@̌B-@ɖF@pffff$-@ĜF@ -@3333˒F@@3333,@F@,@3333#F@-@F@9-@AF@@333A-@9F@_-@QzF@ٞ-@}F@@333sz-@aF@hR-@[F@-@lF@ -@[F@@333-@$aF@ -@3333#iF@pfff&-@3333#lF@̌a-@lF@LX-@̄iF@R-@`fF@@[-@3333bF@pffff-@`F@-@[F@{-@3333'F@z.@3333CYF@Y-@0>F@-@7F@.@ffffN2F@pfff&2.@-F@@S.@3333'F@`.@*F@Ym.@|,F@z.@3333,F@9.@ffff7F@L.@aDF@-@0NF@@333-@3333#OF@̌-@SF@{-@3333CYF@Y-@ffffUF@@333-@EF@Y-@0>F@`pfff-@E@@333g.@F@ @333-@F@pfff-@F@Y-@F@̌E.@!E@@333L.@ffffE@@g.@E@@333g.@0E@pfff`.@E@@333-@F@H@.@3333#E@.@`F@.@E@.@3333#E@pfff&.@ffffE@@.@`F@.@3333E@.@E@Y,@̄OF@pfff,@ffffnF@pffff,@\F@@333,@AoF@L,@0|F@,@F@,@\F@pffff,@ffffnF@,@ffffF@Y,@3333F@,@ffffF@@3333,@ffffn}F@pfff,@`xF@@333,@@sF@,@aF@,@UF@@333,@̄OF@pfff,@|TF@ ,@XF@pffff,@\F@HX1@̤YE@hfff1@3333sfE@c1@9fE@X1@3333+eE@hfff1@̤YE@1@pbE@8333n1@3333sfE@c1@9fE@,Z4@ C@83334@3333H@^|:H@ffff^33337H@ffff^5H@^ffff67H@ffff"^ffff9H@)^<@H@^9FH@hffff^;H@3333'^NH@ ffffN^NH@`^ffffMH@ffff^KH@^ffff^CH@^AH@3333 ^>H@3333'^;H@3333^@H@^DH@ffffN^NH@3333^xG@ffffv^ffff.1H@ffff.^@ H@ffff^AH@^ H@3333?^H@ffff^\H@^DH@L^3333H@3333^%H@ffffF^)H@3333^ffff.H@^0H@3333;^ffff.1H@Ъ^ffff,H@ffff^^#H@3333^H@t^ffffH@3333/^AH@^H@٧^aH@ͦ^tH@ffff^3333 H@إ^3333H@ffff^ G@^3333G@3333^dG@^ffff6G@T^xG@^3333+G@ffffv^3333+G@x^3333#G@ffff.^@ H@3333)_3333SH@ffff_ffff6H@ ̜_pH@3333C_ffff.H@0_IH@ffff_3333SH@ _H@_iH@_(H@#_H@'_ffff6H@3333)_H@a(_3333+H@$!_H@̜_pH@X^ffffpH@^,H@̠^ffffpH@^lqH@0^AtH@ffff^33333zH@^,H@Q^H@^yH@̠^ffffpH@pD^H]H@^vH@ ^ffffoH@^ffffvH@D^vH@3333^`H@^]H@3333^H]H@^`H@^ffff`H@ffff^̌eH@4^@lH@^ffffoH@pA_I@:_3333I@ 3333>_I@$:_ I@:_ I@ffff:_ffffI@<_<I@i?_3333I@3333+?_I@̸?_lI@A_)I@@_I@3333>_I@_H@ _H@=_H@ffff޴_H@@_3333;H@fffff_ffff6H@_3333H@)_H@_3333+H@_ffffH@_0H@_ffffH@_H@ _3333H@ _3333;H@4_3333kH@_ffffvH@ffff_|H@=_H@V_̬I@̼D_3333{5I@H_ffff(I@H_3333{+I@3333L_33331I@3333P_3333{5I@ffffFS_5I@V_ffffN-I@V_'I@̜P_̤I@|L_̬I@K_ffffn I@3333;G_I@̼D_ffff>I@E_ffffF"I@H_ffff(I@`ť]h@@l]ffff.@@ ffffz]ffffz@@3333]ffff.@@ť]ffffn@@١]w@@H]ak@@ffff&]h@@l]ffffi@@ffff]3333l@@ffffz]ffffz@@h]\<@]ffff0=@ ]i!=@].=@ffff]ffff0=@])=@3333]=@E]\<@]2333#<@ԏ] =@ffff] =@]i!=@X3333^3333@@]dA@3333^ffffA@ffff ^3333@@ffffJ^3333@@^̜@@]ffff@@]@@̘^dA@3333^ffffA@h]@@3333']33333 A@ ffffr]̤A@x]33333 A@]ffffA@]ffffA@]Y@@]@@3333]A@3333']3333A@l]A@ffffr]̤A@q]3333@@ ]@@ ]ffff@@]ffff@@]ffff@@ ]3333@@D]`@@]!@@ffff]@@q]i@@ ]@@ͣ]3333K@@x]@@}]ffffִ@@ ]ffff@@PQffffD@Q1D@(QffffD@aQD@QiD@PQ1D@3333QD@QD@(QffffD@@4R3333C@ԆR3333C@R3333C@ffffR3333#C@ԆR3333C@4R|C@R3333C@`RdBD@PRHTD@ 3333 R3333ND@RdBD@ffff RBD@݈R3333[ED@RKD@PRffffND@fffffRSD@ffffnRHTD@3333 R3333ND@X87P3333;!@@*Pffff1@@3333[1P3333c'@@87Pffff#@@6P3333!@@|4P3333;!@@̼.P%@@*P33330@@t,Pffff1@@3333[1P3333c'@@XQD@ffffQffffD@ffffQiD@QѯD@Q3333D@ffffBQD@ffffQ3333+D@3333QD@lQffffD@ffffQiD@`(QxD@QD@ (QD@ffffQxD@3333sQD@QD@QD@ffffQ\D@QffffD@\QffffD@(QD@`ffffQffffD@ffff~QD@ 3333Q3333 D@3333QffffD@ffffQffffD@ffffQffffD@ffff~QffffD@Q9D@3333QD@ffffʂQD@3333Q3333 D@@Rffff6A@3333 RXA@3333 RXA@3333[RIA@RA@̬Rffff6A@3333 RXA@HffffRA@3333R3333A@ffffRA@3333RffffA@3333RA@3333RA@ffffR3333A@ffffRA@h9RB@DR(&C@ ffffvRA C@(R3333C@9RB@PR3333B@tR(C@RD C@R3333C@DR(&C@3333R3333C@ffffvRA C@ffff*Rffff>A@ffff6R3333sA@ 9R3333sA@ffffFR!A@R3333;A@9R`A@TRA@ffff*R\A@hRffff>A@3333R3333A@̘RA@ffffRlA@ffff6Rffff6A@RffffA@9R3333sA@ P!SPA@E Sffff.xA@S`A@!SPA@< SLRA@SfffffA@E Sffff.xA@eSuA@S`A@ pE3X&<@Xa<@ ;@CXp;@RX;@XX T;@̠XXffff>;@VXL;@ffffPX̌;@CXp;@ffffRHXffffv;@RX;@ P̼Wffff"=@ W`W=@̼Wffff"=@ffffWY%=@3333[W̼@=@ WV=@ܴW`W=@ɷWffffFJ=@̼Wffff"=@ `3333ZX:@JXL2;@ XXL2;@3333ZXffff;@YX :@QXlT:@3333KX:@JX(:@LXL:@ffffzVX,:@XXL2;@`xGUL=@-/U=@ (CUffffF=@xGU=@3333@UL=@3333:U2333=@-/U=@33333Uffff=@ 8U̼=@@U=@(CUffffF=@H_TP>@ZT>@]TP>@ZT>@\T>@_T>@^Tfffff>@]TP>@h3333UV >@KV,+>@ KV,+>@QV`>@hRV>@SVffff&>@3333UVffff>@ffff>QV̌>@NV >@UNVffff>@|MVP >@KV,+>@plW|=@ffffFV٤=@ V2333Ә=@Vffff=@4V٤=@lW<=@ffffVffff=@,V|=@V0=@3333V=@ffffFV =@!V=@V2333Ә=@P3333{7V=@4Vffff>@4V=@33336V=@4Vffff=@4V=@33334V>@3333{7Vffff>@4V=@ffffS97@33333aS̜I8@ffff bS|7@3333[bS07@ bSdfff7@cSdfff#8@ffffbgS4333c78@ffffkS4333S8@ffffVpS)8@ffffiS:8@jS?8@lS̜I8@ypSE8@3333_vSA8@̌xS4333=8@|S@8@ffffSdfffF88@zSdfffF8@3333vSdfffV 8@ffffsS07@ffffqS43337@\qSdfff7@dS97@33333aS43337@]aS,7@ffff bS|7@xzS5@ffffhS6@ qS<6@vS6@zŠ6@yS4333 6@3333tS5@3333'rSl5@ffffRpS05@qmS5@jS43335@XiS5@ffffhS4333 6@qS<6@xS̼D6@S p6@ SI6@ffffSPN6@ffffS c6@3333Sdfffvn6@܌S p6@Spl6@HSf6@xSdfffFa6@SlR6@SdfffFN6@ffff S̼D6@SI6@3333S4333q6@3333+S`6@3333+St6@ffffzS43336@ffffSdfff&6@S433336@3333S43336@TS`6@3333S43336@S4333C6@AS|6@ Sv6@,Su6@S4333q6@S4333q6@3333+St6@fffff|S<9@3333sBS:@`S2333:@USL:@EOSffff:@0MS,}:@ffffNSl:@ffff&NS̜\:@3333OSJ:@3333OSffff(:@RS2333s:@YS2333S:@TUS9@OS<9@pNSy9@9LS9@̴JSffff=:@3333sBS\U:@3333?DS:@`JSffff:@uPS:@U̬E4@ffffRU<4@ aU04@3333U4333c}4@ffff>Ua4@3333sU̬E4@3333#UdfffM4@3333óUw4@ffffRU@4@ٰU<4@3333U 4@aU04@0̔kO4333s91@POg1@ 2333[[OpZ1@ffffeOg1@iOb1@qkOdfff]1@̔kOX1@akOV1@DcOdfffM1@2333YO9I1@TO4333s91@POp=1@QOdfff&C1@VOyJ1@2333[[OpZ1@1h\Nhffffo+@qN/,@ -@2333sN,4-@N03333-@`Nhfff-@(Nhfff&,@ sN0333,@YnN@,@ffffkN0333,@2333iN,,@2333[oN9:-@qNJ-@2333wN0333S_-@32333N!$@tuN03333%@tuN03333%@ N0333%@hffffN`t.@2333#Nhfff&D/@ 2333#N .@|N̬ /@ffffŇ+/@2333Nhfff&D/@ffff&N4/@ffffN /@ffff6N.@ N`t.@ffffN.@2333#N .@?ffffN4333#80@N43330@ NA0@N\0@̴Ndfffi0@ffffN4333w0@PN43330@\NIz0@2333N o0@2333Ndfff6\0@ffffN4333L0@ffffN`:0@N4333#80@N:0@NA0@@̤N0333/@2333N4333Z0@ N4333sS0@N4333Z0@1N)W0@̤N M0@4N43330@N̬/@N0333/@ffffvNdfff0@,N9 0@2333Ndfff&:0@2333NYE0@2333kNJ0@N4333sS0@Ahffff~NH*@N̬*@ 8Ng*@Ň*@ɑN̬*@PN@*@ffffNL*@\NL*@ffff~NLk*@NH*@ffffVN0333P*@8Ng*@B\JRdffffJ6@3333/Rt6@ >Rdfff^6@8R9\6@3333+2RdffffJ6@3333/RS6@ffff0R)X6@3333+5Rdfffb6@ffff~R4333#j6@BRdfffm6@3333'HRt6@\JRdfffva6@ GR^6@>Rdfff^6@Ch3333+JQ`fffF(@0Q0333(@ 4Q,Q(@3333@Q0333sv(@DQ (@̔GQ(@3333+JQ0333(@IQ̘(@?QH(@i3Q`fffF(@0Q(@4Q,Q(@D`@Qp5@3333Q4333#5@ 1QL5@Qp5@TQdfff5@3333Q̜5@ffffQ\5@Q4333#5@@Q5@%Qdffff5@1QL5@E@3333DRdfff&u5@:RdfffƏ5@:Rdfff5@ffff?RdfffƏ5@3333DR5@(CRdfff&u5@:Rdfff5@Fh8R4333s5@PQ5@ ffff&QI5@pQ4333s5@PQdfff&5@3333Q5@ffffQ5@ffffRP5@8R43335@ffffQdfff5@ffffQ\5@ffff&QI5@GhRdfffV5@< R43335@ 4 R5@ffff R5@< R5@ffff R43335@ffff R5@LR43335@R5@xR 5@ARdfffV5@4 R5@H`33335$dGM@ffffdeM@ ̴"dUM@33335$dUM@?"dHM@dGM@ffffhdffffIM@ffffdeM@ffffdeM@3333d3333C^M@̴"dUM@I+cffffL@ffff cL@ %cffffL@K$cًL@: c3333L@c3333L@ffff c3333L@c3333L@3333c3333kL@ffff )cL@V+c3333L@+c̤L@t)cffffL@ffff'cL@%cffffL@JX5c-N@db3333{@N@b3333{@N@$cffff&4N@5c-N@cL.N@̔bffff/N@dbN@b3333{@N@Kx3333_c3333C=M@3333k cHOM@ 3333c3333C=M@c>M@ c3333;EM@ cIM@3333k c(LM@ c8NM@ cHOM@ffffc3333+OM@3333[cHM@3333_cffffVEM@cffff.AM@3333c3333C=M@Lpffff0c3333CL@3333'c3333KL@ 3333'cL@H)cffffL@ffff+cfffffL@d/c3333KL@ffff0cffffVL@0cL@.cfffffL@:+cTL@ffffp)c,L@(c3333CL@3333'cL@MhffffwcK@ rcPK@ ffffwcffff6K@ffff$wcffffK@uc3333[K@3333[scK@rcK@ rcffff~K@XrcffffK@scPK@scK@ffffwcffff6K@NxffffXc4L@ffff2N@ECb4N@Cb3333C6N@̾Eb6N@Kb 6N@QP)b(N@3333G#bX3N@)b+N@̚'b!)N@$b(N@#bffff&+N@3333G#b1N@$bX3N@)b+N@R`ffffbM@3333bN@ ffffTbiM@ffffbM@bM@3333 bffffM@bffffM@3333bN@S b3333M@<bM@ffffTbiM@S3333{b@M@̦^by.N@̢`bffff*N@3333cby.N@eb3333-N@3333fb'N@jbN@nb3333k N@jsbN@zwbM@xbM@3333zb3333sM@3333{bM@3333{b@M@ffffwbM@fffffubpM@3333tb3333CM@Dsb3333M@Iqb3333 M@ffffobM@3333Wob3333M@ffffRnbM@lb(M@ffff lbffffM@3333kbffffN@0jb3333 N@3333_bffff N@̦^b$N@̢`bffff*N@TP3333bqN@3333A}biN@3333A}b N@biN@abN@3333bN@_bqN@ffffb\N@3333A}b N@Ŭ|bffffN@ffffubffff>N@3333zbffff,N@3333[{b$)N@̆|b3333S&N@{biN@ybffffN@3333Kzb3333N@3333zb3333N@6ybffffN@3333QxbYN@mwblN@vb"N@ffffubffff-N@vbffff3N@ubI6N@ffffub9N@vbffff>N@~vbP>N@wbD9N@Sxb)8N@xb8N@xb;N@lyb:N@zbffff/N@3333zbffff,N@VhbhN@ffff}bIvN@ ffff}biN@.~b pN@ffff~b8sN@33335bIvN@@b3333CuN@0brN@b3333lN@bQjN@ffffցbhN@ffff}biN@W`3333WK@ffff`K@3333`\K@``K@J`̔kK@ffff`3333;rK@Ô`3333tK@k`3333uK@̶`vK@3333`qK@Κ`3333pK@`|rK@E`TK@n`9K@3333ݟ`(K@%`ffffFK@`3333[K@}`K@̺`3333K@`3333SK@``K@3333e`ffffK@ `3333kK@ffff`ЊK@3333`3333#|K@`ffffyK@i`ffffuK@3333I`3333kmK@w`ffffaK@3333ՙ`ZK@`3333WK@3333`\K@X ` L@̠`ffffVwL@!ffff^`̄JL@`@NL@`LL@̠`ASL@ffff`L]L@ffff`dL@`IcL@̪`(lL@`AoL@ffff`3333rL@`ffffVwL@`ffffuL@3333`YkL@`ffff_L@3333M`̬\L@ffff`NL@I`ffff>JL@`AL@3333`i:L@3333A`ffff4L@`L@3333` L@` L@(`ffffL@`3333;L@ο` L@` L@d`YL@ffff`L@N`d%L@ڻ`1L@ffffF`$>L@ffff^`̄JL@Yffff`xK@`K@K`ffffK@ffff`3333K@R`K@ffffδ`xK@`3333K@ffffʯ`3333KK@Ѯ`ffff6K@3333`xK@`9K@`K@`K@3333é`K@`K@`3333K@ffff"`3333{K@K`ffffK@Z3333 s`qK@lg`ffffΡK@m`̌K@ffffn`wK@3333Cn`dtK@l`xrK@j`qK@lg`ffffsK@3333g`yK@3333j`8K@l`ffffNK@gp`K@r`ffffΡK@̂r`؟K@}r`̴K@q`ffffK@3333 s`̜K@r`IK@Hq`4K@ffffjo`3333K@m`̌K@[ffffV`iAL@,`3333eL@ffff`ffffQL@`̬ML@ffffV`3333HL@3333ɝ`!CL@O`AL@ffff>`iAL@ffff`ICL@ܖ`qEL@K`FL@,`̴IL@ffff(``QL@`̤WL@`3333eL@ffffܛ`3333#YL@ffff`ffffQL@\ffff^`ffffK@$`?L@'`?L@0`*L@?`ffff~)L@(`ffffL@3333`L@ffff^`ffff^L@`ffffL@` L@K`L@p`ffff6L@ffff`L@u`aK@`ffffK@ˋ`IK@1`ffffK@̺`3333K@`K@3333A`̼K@ffff`L@$`3333CL@ffff`1L@ `fffff>L@'`?L@]ffff4`@L@!`:L@`̌8L@`,2L@ffff4`3333.L@`3333+L@̆`4!L@3333`@L@`ffffL@k`ffff$L@̰`ffff(L@ `ffffn+L@`3333.L@;`33331L@!`4L@ffff`33337L@`h9L@ݜ`:L@`̌8L@^`+` M@`*M@ `LM@`3333$M@`*M@ffff`'M@+`<%M@`ffffM@`pM@ffff<` M@`LM@_(`l;J@`ffffgJ@ &`fJ@'`ffffgJ@n(`fJ@(`bJ@(`p\J@3333$`3333{MJ@ffffF#`̄IJ@`l;J@`HAJ@3333`LJ@`3333TJ@3333%`HeJ@&`fJ@`xffff^`(=K@X`ffffPK@ 3333]`̴NK@̂^`3333[EK@ffff^`?K@h^`(=K@3333]`Q=K@Y`3333EK@mX`IK@X`3333LK@AX`NK@X`8OK@]`ffffPK@3333]`̴NK@a`3333c`I@3333W``HJ@ mc`3333{J@3333c`ffff J@3333Oc`ffffJ@b`ffff~I@3333a`I@``ffffI@3333W``1 J@#c`HJ@mc`3333{J@bV`ffffJ@G`d K@J`K@̶L` K@VN`d K@O`ffff~ K@T`J@3333CV`3333J@V`3333J@ffffV`4J@U`ffffJ@`3333۷J@"A`̔J@d`̄I@̤_̬I@ffff_I@(_8I@ffff_ffffI@`̬I@`YI@ffff`3333I@`8I@`lI@l`̬I@_ffffI@=_̄I@-_I@̤_3333I@_I@ffff_I@e@`1J@`fffffdJ@ffff `,FJ@3333`^J@`fffffdJ@3333 `dJ@`3333#YJ@3333 `GJ@ `Y@J@33333 `ffff4333I3333S4333I3333STII俘I\4333 I`񿘙I=I>IIffffxI`󿘙Iadfff^I@3333Y4333IU4333I3333SlH)Slk @0S0333s @)S0333 @Slk @0S`fff& @uS0333s @)S@ @)S0333 @mHxS?ffffS?xS?̽S?0S@ffff ?ffffS?ffffS3333?xS?nXffffrSL(@3333GS 333+@3333kS 333+@ffffrS@QS`ffffy@3333SL(@3333GSU@S 3333@3333ψS@3333kS 333+@opxN 6"@0^No"@ 2333+eNZ"@0^Nh"@2333#aN0333n"@2333 dNo"@2333#iN0333Sj"@$lN03333b"@!tN["@@xNC"@xN 6"@iNF"@2333+eNZ"@ph4333LFM=F =F@@FffffHFG4333{JF\HF@3333d4333LFM?Fffff=F~`>FffffQ=Fq`4333dC<*dfffLChfff) ̄UChfff)WChfff&)4333dC83333*9dC<*dfff6_C83331*4333LC83333)dfffLChfff)NC)̄UChfff)r`dfffւČ+sC* ؀C*dfffւChfff&*!C*!}C + xČ+sChffff*tCY*t}C*؀C*s`4333F@ qFF D}FFpFpF4333F@33334333{F@4333;yF@3333 qF4333qFnD}FFt,,I@H}? aIffff?dfff"I?,,Iffff6?4333s+I03333?dfff$I@?4333{I`fff?QI4333cH4333cH3333|?@H̤?dfff~H)?4333H}?aIffff?uhdfff&AI3333I?4333c%I 333J@ >I`ffff@dfff&AI<@a:I@ffff?4333 3I3333I?D&I3333?4333c%I@ffff?dfff+IL"@4333k.IL<@5I 333J@>I`ffff@vxI4333ԿdfffFSI줿 SIdfffFSI`UI8333aI줿kI8333dfff^I43334333KIƿ܂IȿI̿dfffnIgfffп4333vI4333ԿSIwp@Hhffff¿Hl? 4333Hhffff¿ѸHhfffƼHhffffHQ?4333CHL?qHl?H ?,H?dfffȞ@H 4333Hhffff¿xOIffff*Iffff?+Il?,I?dfff/Iffff?2I̚?X6I3333?6Iffff2?9I?4333[CI2333?4333#NIffff6?OI٫?43338Iffff43336I2333?*I?+Il?ypdfff$I?dfffIj? 4333s!I?4333I3333'? I̺?dfffI?Ij? I?pIZ?dfff& I?dfff$I3333? $I3333?4333s!I?zpffffV3333܋V߿ =V߿Vffff3333V3333ffffVffffƘV3333ffffnV̰0V3333;这Vffff翙UV܋V3333oῙ=V߿{3333fVyPV3333[V3333^V3333cbVu3333fV3333o쿙fV3333;ffffdVXbVy3333ZV3333'3333VV3333o3333RVffff&鿙PV3333O翙QVlRV3333`TV3333[V|3333vT`ffffO@fŤ|@xmT03333@jT@nT|@%pŤ|@ffffsT^@vT@3333vT0333@vT03333@IqT@{@ffffjT`ffffO@fTT@ffffBgTL@ffffvlT03333@xmT03333@}hV4333޿3333V\п 3333V4333Կ3333sV\п3333cV4ҿVgfffӿaV4333ٿffffViܿV4333޿3333CVgfff~ݿ̘Vڿ3333V4333Կ~X@VxDV@3333ffffV@3333@V@3333̸Vx!VffffpDV@3333̄Vffff2VffffffffV@3333ffff2VffffP𿙙-V2333? 3333_V 3333V3333k3333׼Vffff3333oVgfffڿ3333GV̌̿qV 3333kV?Vdffff? V2333?lV?ffffV?ffff2V3333a?VL33333Vhfff槿3333VffffrV@333̠VaҿV׿Vgfff߿VffffBVffff㿙aVTV̴V̌ffffVffffV3333VE3333cVffffPV-V4V33333333_V `VP׿iVĿ ̸VLȿVĿ̀VȿVgfff^ѿ3333dzVտVP׿3333V`տiVѿ̸VLȿP[[+;3333CN[;X[;3333w[[;[[+;3333Q[4333#;3333CN[;Q[̌;X[;`3333ZL5@$ZP5@ ffffZ5@TZdfff&5@3333;ZP5@3333Zdfff5@ffffZdfff5@٦Z̼5@ZL5@$Z`5@ffffZ5@P3333[i2@ffff[dfff2@ffffR[dfff2@ffff[43332@3333[2@3333c[i2@ffff[н2@3333K[<2@ffffR[dfff2@`[<8@|[|9@ [ 9@3333[dfff8@ť[dfffv8@|[<8@P[43339@[ 9@,[|9@[9@[ 9@Xy[dfff%8@r[dfffFX8@3333x[dfffFX8@y[dfffT8@0x[\38@t[dfff%8@ffffs[̬&8@3333r[)8@r[4333.8@3333x[dfffFX8@ffff f\ffff=@I\2333=@L\ffffFM=@W\2333V=@ X\j=@ffffZ\fffff|=@ffff`\ffffV=@̔e\2333=@ffff f\2333sv=@(e\i=@_\N=@P\2333=@3333kJ\ffff=@I\` =@3333cK\ffff!=@L\ffffFM=@Xffff\̌?@3333\I?@ffff\ffffV?@3333\̌?@l\2333?@3333\fffff?@a\2333?@Y\I?@ffff6\0?@ffff\ffffV?@`ffff\ <@\L^<@ ffff\L^<@̈\W<@ffff\ffffv8<@ffff\̜<@3333\ <@3333\2333<@\,<@3333\S<@ffff\L^<@H\̬X8@ffff[dfff8@ffff[8@33337[dfff8@\̌8@ffff[̬X8@ffff[4333d8@ffff[8@h`[9@[`:@ [`:@[:@̴[fffff :@`[9@ffff[dfff9@[9@3333 [\9@[ 9@3333k[ffffF:@[`:@p!\2333<@3333 \̌==@ 3333 \\=@3333\@ =@\4=@ffff>\̌==@3333\2333#4=@\*=@!\<@ffff \<@̼\<@\2333<@3333 \\=@ffff\و8@ffff\ I9@3333{ \dfff8@3333{ \P8@ffff \̬8@m\p99@4 \ I9@ffff:\|8@ffff\dfff&8@x \\8@3333; \dfffƺ8@l \y8@3333\و8@ffff\43338@Q\i8@\l8@U\dfffƺ8@3333{ \dfff8@H̐d@`Fd@F̐d@ɞFd@pFd@`FXd@Fhfffd@hfffF̐d@ɞFPhfffv_@03333%@x_@0333i%@4333k_@0333i%@hfffv_@03333%@<_@`fffF6%@h_@C%@x_@0333\%@_@a%@4333k_@0333i%@P4333H_@̌#@iR_@`O$@N_@9;$@AK_@YM$@4333H_@`O$@,J_@9 $@iR_@̌#@Q_@#@N_@9;$@h4333^@`fff&B@̬^@̻@ ̌^@̻@^@ٖ@hfff^@@4333^@̒@^@̌C@4333^@`fff&B@d^@0333q@̬^@@^@0333@̌^@̻@Phfffk_@@hfff6r_@@4333#r_@̅@m_@@hfffk_@0333J@Hm_@0333(@hfff6q_@@hfff6r_@@4333#r_@̅@P4333{_@"#@̌_@`fff#@}_@`fff#@̴|_@yz#@4333{_@03333>#@|_@"#@~_@`fff/#@̌_@^#@}_@`fff#@`_@&@4333'_@c'@ ($_@`fffG'@4333 _@_'@hfff_@c'@_@0333T'@q_@@'@_@&@&_@&@4333'_@`'@($_@`fffG'@`hfff._@,'@hfff6_@@n'@ t2_@]'@hfff._@@n'@/_@,Q'@1_@Y)'@3_@y'@5_@,'@hfff6_@`fff0'@43334_@0333@'@t2_@]'@Pq`@X`@LK4333s`@q`@9`@X`@LKhfffB`@pffffLU`@f4333s`@`!`@@3334333`@L~ !`@pfff4`@ `@@333̔`@<`@@3334333`@L~4333S`@@3334333;`@!`@pfffHd_@)9_@~d_@ `_@ffff!4333_@)9_@~hfff_@ffffd_@ Phfff6_@ hfffF_@ |_@ 4333_@ hfff6_@@3333N _@ hfffF_@ _@ffff |_@ P9^@H_@Lx_@̛4333s^@L9^@pfff\_@pfff_@H_@x_@̛Xhfff^@~^@4^@SI^@@3333x4333^@~^@^@̼^@hfff^@14^@SP(^@@3332^@@333(^@@3334333)^@v+^@@3331^@y2^@@hfff/^@=(^@@333pѸ^@@5!^@83333  ̬^@̌ 4333^@ 4333ӹ^@8333!Ѹ^@8333,!4333^@@5!̌^@hfff&!^@Y ^@ 4333^@8333 ^@83333 ̬^@̌ h4333^]@hffff j]@hfffK  4333b]@M d_]@hfff] 4333^]@z a`]@83333 4333c_]@̌ hfff&b]@hffff 4333c]@ j]@hfff` j]@hfffK 4333b]@M  ^Q@XP@4333 Q@P@Q@]P@Q@$P@Q@P@zQ@P@9sQ@ffff"P@4333sgQ@LP@,`Q@P@ ^Q@ffffҭP@iQ@ffff.P@vQ@XP@4333SQ@$P@ɃQ@ P@4333 Q@lP@Q@]P@Q/X@3333 S@dCX@S@ hfff6X@3333 S@Y>X@3333#S@dCX@]S@hfffBX@3333/S@`?X@ffffS@08X@S@t5X@S@hfffN5X@3333S@`/X@̀S@Q/X@ffff> S@I0X@3333 S@3X@3333 S@hfff6X@3333 S@XhfffX@̀S@8Y@S@`Y@S@4333+X@ffff.S@hfffNX@S@hfffX@̀S@4333Y@3333OS@8Y@S@hfff Y@S@`Y@S@hfff"d@9Q@3d@hQ@0d@hQ@hfff*0d@hQ@-d@ fQ@X*d@ffffbQ@4333#d@^Q@hfff"d@ffffYQ@D%d@YUQ@$d@LQ@hfff^$d@ffffGQ@4333%d@8EQ@hfff+d@BQ@.d@?Q@.d@3333=Q@̄-d@9Q@hfff.d@9Q@433370d@];Q@43330d@ >Q@/d@ffffAQ@,d@FQ@,d@qLQ@+d@RQ@hfff:+d@3333WQ@4333+d@yZQ@hfffJ1d@[Q@43333d@3333`Q@3d@ffffeQ@0d@hQ@Hhfff5`@?@e9`@?@hfff6`@?@hfff5`@?@6`@9?@e9`@2333?@19`@?@hfff6`@?@H4333c_@6B@_@hNB@hfff_@3333IB@4333c_@hNB@_@3333;3\@43335@4\@P5@47\@̬5@43335\@dfff5@ 2\@43335@H!\@dfffV5@4333s)\@4333ӵ5@hfff#\@̼5@!\@5@4333"\@dfffV5@43333)\@5@4333s)\@4333ӵ5@hfff#\@̼5@Xu\@56@Ђ\@YU6@4333\@433356@hfff6\@ G6@Ђ\@YU6@4333kx\@G6@u\@=6@v\@p86@hfff&x\@56@4333\@433356@PZ@0333S$@yZ@0333s$@Z@`ffff$@\Z@0333S$@4333Z@Y$@yZ@03333$@LZ@0333s$@Z@03333$@Z@`ffff$@@DY@\%@hfffVY@`%@LY@`%@DY@`fff%@Y@\%@hfffVY@o%@LY@`%@` @ffffXK@-!@QaK@ !@QaK@@333 @3333`K@ @̌^K@ @h[K@Y @tXK@ !@ffffXK@-!@9[K@%!@ffff_K@!@QaK@H@3333#J@4@J@@333@J@@ffffJ@@3333#J@ffff@J@4@J@@333@J@-̜V3333#N@\N̴vR@2333OOffff P@?OffffV~P@d9O3333|P@̄4OyP@1OffffwP@0OTuP@)>O|sP@NOPnP@ffffVTOhP@bOffffrhP@̜hOtiP@|OgP@OjP@ffffΞOlP@OvP@pOffffvuP@2333sO3333_pP@OYmP@2333sO(kP@ffffVOMjP@ffff.O̴hP@1OxgP@ObP@2333ONP@ffffnO̔GP@0O\AP@̤Oe;P@2333[OM?P@ OICP@ffffOTEP@2333OffffFP@ffffOffffGP@ffffPGP@ PPXP@FPffff]P@ffff>KP\dP@3333?MP̼eP@ RPffffNkP@3333SPlP@UPlmP@YPpP@33333XP̜tP@QPyP@KP(|P@BPDP@33336PP@p1P3333P@ffff+PUP@$P3333kP@̀PLP@H PԔP@ffff)Pffff^P@ffff0P3333ǎP@8P3333ˈP@I@PP@3333SPffffP@̘ZP3333P@bPffff.P@tPP@3333yP3333KP@vPP@jPffffP@fffflP3333P@3333pPP@vPffffP@)|P(P@Pffff~P@YP5P@PP@ԚPIP@ffffP3333P@ffffPxP@P3333P@dPP@9PP@ P(P@ffffPffffҧP@3333P=P@PP@3333PP@3333#PP@3333PffffvP@TPMP@EPffffP@$P3333P@lP3333ۓP@3333PpP@3333PQP@3333P̠P@hP3333SP@̔Pffff^P@PffffP@eP@P3333'dP@PdP@PhP@ffffPhP@tP0iP@ffff^PhP@̔PeP@3333+P(cP@$Pffff`P@3333kP^P@̌P3333/\P@3333PZP@ffffP3333VP@Pffff.VP@PffffUP@]PqSP@AP3333OP@PffffKP@PHP@PFP@ffffP3333oEP@ffffVP4EP@̸PFP@PEP@-P3333DP@,PffffBAP@P3333 7P@ffffP,4P@ffffVP33334P@3333P3333S>P@P@P@3333#P4>P@P33337:P@QP6P@lP5P@LPffff1P@ffffP3333W0P@̼P<.P@ffff‰P/P@P33332P@ffffPffff.6P@|P8P@(qP̠6P@hPT1P@̼fPffff/P@`P33337-P@̤[P}.P@ffffQP3333k(P@3333[VPffff%P@`P!P@aPffffN P@\_P P@ffffnKP3333 P@ FP3333P@ffffDPffffP@MPhP@UPffff*P@ffffz`P3333_P@ffffePP@$ePffffP@ffffBVPffffP@ RP P@ffffVLP3333OP@3333IPP@IPffffRP@KPffffnP@3333JPP@@P̐P@3333[:P̬P@3333k2PP@l+PffffP@*P̜P@ffff+PO@3Pffff>O@)1PO@(P̌O@ffff$PO@3333P)O@LPiO@PO@#PO@8#PIO@PPO@PO@PO@ffffQ3333O@QO@̀(QO@6QP@RSP@YS1P@ffffaSP@-hS3333CP@pS P@ffffrSffff~P@SffffP@SP@,S̈'P@̤S*P@3333یSffff-P@$S0P@AS3P@ffffSP@3333SffffrAP@3333xS3333DP@3333\S3333WJP@WSLP@IWSNP@̈]SUP@3333w]S3333VP@3333_[SWP@VSffff[P@TS]P@3333PS]P@ffffFS3333[P@Y=SZP@1S|ZP@SWP@ISDRP@3333RNP@3333{R3333IP@ffffFRCP@Rffff@P@ffffRP@3333R3333@P@3333cR3333CP@RaFP@LRffffHP@xR3333sPP@Rffff SP@YR4TP@DRffffQP@̤R,RP@ffffRffff6UP@ffffR3333KWP@ԾRiXP@dRffffXP@3333R|WP@3333ˤRffffFWP@ffffRWP@RqYP@(R^P@܈R8`P@URffffaP@0xR4aP@9kR3333^P@@cRffff_P@3333cR3333bP@-iRffffiP@oRqP@fffftRsP@ffffR!xP@̬RЀP@3333R4P@śRP@ffffRP@ffffRffffRP@{RffffP@deRqP@̔[RffffRP@3333VR̸P@QRffff2P@3333LR3333P@ BRffffP@?RP@d>RffffP@Q@4Q@$S06Q@̜%S]>Q@#S3333@Q@̰SffffAQ@`S3333[CQ@S̬AQ@ RAQ@3333RCQ@3333RffffFQ@Rffff*JQ@tRffffMQ@R,SQ@`RdTQ@SffffXQ@% SMZQ@<SZQ@S3333;\Q@S3333 ^Q@M!SaQ@̘!ScQ@!SeQ@ffffSgQ@ffffSffffiQ@3333S`jQ@ SkQ@ SkQ@3333%SjQ@+S3333eQ@ffff/SffffdQ@̘:SgQ@AASffffzgQ@EShQ@ffff>HSffffiQ@FSjQ@ffff2ASlQ@33337S̰oQ@33336SqQ@=SfffftQ@AS3333uQ@NSvQ@ffff_S̄uQ@eSffffvQ@̨hS̠yQ@ffffnjSffff}Q@3333/kSQ@4nSffffQ@qSDQ@uSЏQ@SffffQ@ЎSQ@SffffQ@hSffff2Q@ɤS(Q@ŧSffffQ@3333sSQ@,S̤Q@SQ@̴S4Q@@S̠Q@9SФQ@4S8Q@3333/S3333מQ@mSQ@3333SQ@V(PR@33330VffffSR@/ViUR@U/V`WR@.VXR@!-V3333YR@ VfR@ffffJUkR@UDnR@3333;UffffpR@33333U`uR@ffffU̴vR@|UhvR@ffffGU̸sR@̘@UqR@3333>UpR@U3333wlR@3333MU̠fR@3333_UaR@kÜ]R@UTR@̈UPR@3333ϞUt=R@3333ǤUffffF:R@3333GU33337R@̼U0R@UffffV.R@ffffUP*R@3333WU!R@̤Uffff~R@̼U̼R@ffffFUR@ffffvUffff> R@ؕUffffR@UffffR@3333U3333Q@PU3333WQ@pU Q@`bUQ@TU3333Q@ EÙQ@3333AU3333Q@ffffHU3333kQ@YU3333Q@3333wpUiQ@|UhQ@|U3333#Q@IUffffQ@ṴQ@-UHQ@U3333Q@3333#Uffff"Q@tU Q@4iUQ@ffffFUQ@@UQ@̼BUQ@5DUQ@ CUQ@3333C?UQ@33337UQ@4UQ@̈2UQ@Y-UQ@(+UQ@ffff*U3333Q@<*U3333Q@3333,UiQ@5U3333'Q@BUQ@`HUQQ@PU8Q@3333UUQ@3333cYUQ@̼`UffffBQ@(fU3333sQ@ tUffff6Q@XzU3333#Q@,wUhR@jUR@ffffbUR@ffffYU R@TUR@33333AUffff R@&UIR@Uffff^R@(UR@UR@<U3333 R@ffff&)U! R@33331UR@33335U̸R@3U3333R@ffffB)U}R@'UR@\6UR@̴=UR@3333CUR@ffffJUR@UUffffR@3333 YUffffjR@3333_U R@pcUd$R@egUffff&R@3333hUffff(R@iU8.R@@iU̐1R@̤gUm4R@ffffdU33336R@3333]U5;R@ffffXU3333{Q@OQ؋Q@:Q3333?Q@ffff1Q3333Q@00Q3333Q@/QffffQ@ffffJ.QffffRQ@1Q3333wQ@5QQ@@Q3333~Q@h9Q|Q@ffff/Q@|Q@*Q3333}Q@3333$Q3333Q@QQffff&Q@ffff QQ@ffffQQ@3333Qffff.Q@x Q8Q@dQ3333GQ@QQ@ffffQQ@ffff QQ@̸Qffff"Q@QMQ@PQ@3333PQ@ffffFP4Q@`PffffQ@PwQ@ Pffff*sQ@ffffVPppQ@3333/PnQ@P)nQ@̌P$nQ@̘PqQ@ffffNQHqQ@3333KQffffFpQ@ QffffnQ@QlQ@QffffjQ@Q=iQ@*Q1iQ@33335QgQ@GQdQ@ffffNQcQ@ PQ3333`Q@3333DQ(aQ@A2QdQ@ QffffdQ@̸Qt^Q@ Pffffr]Q@ffffPa^Q@ffff^P^Q@P=^Q@ffff*Pffffr]Q@3333_PZQ@UPUQ@3333߭PSQ@3333۫PIRQ@HPffffPQ@yPffff:LQ@ffffFPJQ@ffffbPffffIQ@PPJQ@9PffffKQ@ffffPJQ@PKQ@ffffPLQ@POQ@3333 QLQ@QNQ@'Q3333/MQ@BQEFQ@̔?QEQ@Q3333KQ@tQffffJQ@3333Q|HQ@IP8DQ@PyBQ@P;Q@3333P@7Q@ffffP,2Q@Q2Q@Q6Q@3333Qt6Q@̼"Q5Q@3333*Q3Q@3333k.Qffff3Q@NQ7Q@3333UQ 8Q@ffffUQ7Q@lTQ6Q@7Q33330Q@"Q/Q@3333SQffff.Q@3333w Q,Q@ffff Qffff+Q@ffff~ Qffffn'Q@mQ3333?#Q@P!Q@Px!Q@ffffPffff#Q@3333P3333?#Q@HP,"Q@3333'PQ@ffffP8Q@PQ@P̈Q@3333P3333/Q@̈PLQ@̰PffffQ@3333˰P-Q@3333ӿPffffQ@PffffQ@PQ@ffff.P Q@eP3333 Q@PMQ@P4Q@ffffP Q@PAQ@3333P3333Q@ЫP3333Q@iP4Q@Pffff Q@aP3333{ Q@PQ@PffffQ@3333 PffffQ@̔PQ@|PP@3333P3333P@PyP@iP]P@Pffff>P@3333PP@iP\P@P3333cQ@P|PffffQ@ffffj|P3333Q@d~PffffFP@QwPP@ffffpP@P@lP%P@pdPffffP@̔`PP@ffffn_PffffP@TcP(P@bPP@ffffYP0P@ffffXPP@ffffvZP3333WP@M\PDP@̔ZPEP@8SP P@3333DPQ@>P3333Q@3333;PffffQ@x5P\P@47PP@5=PffffP@ffffAP3333P@ffffDPP@YAP3333gP@5P1P@(PffffP@3333!P3333P@3333_P3333[P@ P3333P@ffff>PP@2333Offff:P@PP@ffffPffff:P@hP3333P@PP@ffff&%P3333P@,P3333oP@ffff%P1P@3333PDP@PdP@ P3333wP@ PP@ O3333P@|O4P@ffffOffffP@O)P@2333O3333P@lOffffP@2333#Offff P@O(P@2333O}P@ffff&OffffbP@2333OP@DOP@OP@pOP@ffffO1P@dO(P@,{OP@2333jOP@2333SbOP@ZOP@2333+MOffffnP@23330OP@OP@N8P@|NP@NffffұP@OT@pO̬T@23333O3333T@̌O\T@ffffֿOT@ OT@ffffOT@3333P3333T@̼PffffƱT@A PѱT@(PdT@ffff1PT@9P3333T@>P3333T@ffff>GPT@dJPT@OPffffbT@3333#SP,T@YPffffZT@,cPT@ffffnPffffT@PT@(Pffff~T@hPT@ffffڿPԭT@iPffffªT@PT@ Q3333WT@ QЩT@ffffQPT@ffffPXT@lPffffT@0PffffT@3333 PQT@ݥP3333kT@ffffP T@3333P̸T@,P3333/T@3333QT@-QffffVT@ffff+QT@I_Q3333T@pdQT@ffffrQT@wQT@3333~QffffnT@3333QHT@mQffffJT@3333QffffZT@QT@Q T@ffffQffffRT@3333/QffffT@3333sQ3333T@3333QdT@Q}T@ffffnRT@ffff3Rffff2T@1URT@YRT@4\R̈T@H\RT@ORT@̨1R\T@(*R3333/T@hQRaT@mR̄T@zRffff޹T@3333R$T@RLT@R3333T@̬RT@ffffGST@3333BST@$:SغT@<Sffff6T@ ST@̐SPT@$R3333/T@33333RffffT@3333RffffT@S@T@` S0T@ffffST@ySffff>T@ST@tNS̔T@^ST@ffffgSUT@ffff}ST@̘ST@ffffST@ST@ffff TPT@ T3333;T@3333[ST@\SAT@ffffSS-T@Tffff2T@ffff*T8T@ffff@TܱT@4HTT@eKT̨T@ffffbIṰT@3T3333T@333337TT@ffffLT T@eT3333'T@3333CrŤT@ffffzTT3333T@TT@ffffTqT@3333UffffT@ffffj#Uffff~T@/UT@e9U3333ÜT@QU3333T@ffff^UqT@rUT@zUT@UffffޏT@fffffUT@(U3333T@SUЂT@JU3333T@XCUffffT@ffffBUffff~T@YU~T@ffffnbU}T@ffffRiUffff}T@wUq~T@ffff"UffffT@)U3333T@UDT@`Uffff"T@3333U3333T@ffff*U\}T@ffffUT@UxT@UqT@3333 V,T@3333G$VT@8V3333'T@JV%}T@ffffbXVzT@̈hV@yT@3333oV8yT@3333_V$xT@HVtT@ VffffjrT@ VoT@qVkT@V3333hT@3333VeT@ffffV3333dT@3333V3333eT@\VhT@ViT@ffffVhT@,V3333khT@fffftVhT@vV%gT@pV]T@ffffV}[T@̤VYT@lVYT@>VbT@̨V3333#dT@|VcT@5U3333aT@xU̘`T@V4aT@'V3333`T@33339VX^T@T[VXT@kVUT@3333hVTST@3333[MVPT@PVLOT@ffffdVffff~NT@̠|V KT@~V3333GT@̴rVffff&DT@gVBT@3333YV3333AT@8VffffCT@3333U,ET@3333ۧUGT@xUpOT@ffffYUffffBRT@4MU3333RT@<BT@3333(U3333GFT@|TxIT@YT̜FT@+UffffBT@3333OU9?T@ffffhU,;T@ffff"U2T@0U.T@̘U3333*T@3333cUffffR(T@U&T@U5$T@8U#T@ffffznU1%T@̬SU!T@UIUffffZ!T@Uffff!T@U3333k"T@U#T@T3333&T@ffffjT$+T@̰T-T@3333T3333/T@ffffT0T@3333;Tm1T@Tffff.T@,T\(T@̘Tffff$T@S9T@XSffff9T@ffffGS3333_9T@l6S48T@3333;7SX7T@3333JSffff5T@t`Sl5T@3333S333332T@3333GSffffv)T@(S(T@DT!T@ffff>T3333T@PTT@ffff:TT@3333+TT@3333TT@ffffT1 T@ET3333?T@ffffwTffffBS@3333;iTS@VT3333kS@uKTS@ffff@T\S@ffff-Tffff2S@eTtS@3333TS@QT3333S@uTS@*T3333wS@pBT3333OS@ffff]TS@fffflTS@vTffff>S@3333TS@ T S@\TS@ffffFTffff~T@Th T@PT3333T@ffffUT@ffff:+UT@33337JUdT@̨UpT@U3333T@TUT@3333U)T@US@ffffbUffffS@U4S@ffff>]Uffff&S@3333/QÙS@3333EU-S@5US@3333o!UffffS@3333cUHS@ UhS@TpS@ffff^T3333S@3333T3333oS@ffffTS@dUPS@lUS@̌UffffS@!U3333{S@ffffV$US@US@ffff^UȿS@3333;U3333kS@T UmS@T3333S@3333T S@8TS@TչS@1T$S@ЁT3333S@3333xTdS@pT3333sS@qTffffҼS@ffff~T̀S@3333TMS@ffffTffff6S@ffffFTɵS@XTffffS@3333oTS@3333_TLS@TS@ffffT|S@3333T̴S@ffffb2U̜S@=@UffffbS@3333NUffffS@9lU3333S@3333{UffffS@̴U3333S@U}S@US@3333U3333S@qU3333S@ffffnU4S@PUMS@U}S@ffffrUS@dUffffS@TUS@ffffU33337S@ffffzUS@U3333S@Uffff2S@eU3333S@ZUS@ffffJQUČS@ffffAUffffS@ 2UġS@3333C:U3333WS@33333#UffffS@3333U4S@@UDS@!U̜S@3333c'UffffS@BUS@3333PUS@3333 cU3333_{S@̰RU3333pS@̄RU3333cS@EU`S@33337U_S@U3333cS@ UtaS@3333gT,aS@TffffbS@hT3333gS@pTffffkS@3333T}S@T3333S@T{S@ffffTffffxS@ffffvTffff^vS@ffffƹTnS@TmeS@̌T3333`S@0Tffff^S@ffffTM\S@)TffffZS@3333OTffffXS@3333+ǓWS@ffffF/U3333WS@3333TS@E5T3333'S@m5TS@9TS@!=TffffJS@?Tffff S@̠=T S@ffff.3T S@-,T3333K S@ T3333_S@3333SS@̴S3333S@LS̴S@]SffffS@3333˻SS@ffff2S3333$S@̘S8)S@ffff~SQ0S@3333Sffff6S@̐S;S@|S3333>S@ffffS>S@ffff.S3333=S@%S:S@̬Š8S@3333S$9S@ S;S@iSffff>S@ffffSffffAS@S3333sES@S3333#JS@3333ŠLS@ffffSdLS@3333 TaIS@̌T̨IS@3333 +TffffOS@3T3333PS@GTAQS@QTtPS@4bTMS@hpTffffMS@ffffuTMS@}TOS@9T3333'RS@ffffTffffRS@qTRS@xaTSS@ISTVS@ffffQT3333_WS@4XT3333XS@ffff:`T[S@iT_S@ffff.jT̠aS@SX{S@Q-Sffff|S@SlS@ffffS0S@ffffR3333S@lR̠S@ffff>Rffff&S@aRS@ffff.RĖS@AR3333әS@̼SxS@S̼S@3333SYS@RS@aRffffvS@3333;RffffޢS@3333R3333S@ffff>R1S@RXS@ RS@Rffff~S@ffffNRffffS@3333R3333gS@ffffRS@R`S@3333S S@`SpS@3333!ŠS@4S$S@ffff`S3333S@lS3333S@3333xSPS@3333[S̰S@4SS@ffffSS@ffffƣSffff~S@9SS@SffffBS@ffffR~SS@nS̤S@yYSffffS@ffffZ1SS@3333"SS@XSffffS@ SlS@3333[RS@RS@R3333S@RffffFS@RffffFS@R`S@̞RS@3333RS@R S@ffffR̜S@3333RTS@RS@ffffrS3333S@SxS@*S̘S@6S3333?S@ffff9SS@S̤S@HSHS@ffffRS@8RS@3333RffffS@R3333[S@R3333S@3333RffffS@RdS@lwR3333S@]R̰S@3333#WRAS@RRaS@ffff^OR\S@3333LRffff.S@ffffNR33337S@ffffYRS@<^RiS@iRXS@DRffffS@3333Rffff2S@@R3333sS@3333?RS@3333;RffffNS@ffffsR)S@ffff\R3333S@RpS@3333 RS@3333QffffS@ffffQS@QS@ QffffBS@ffffQS@QS@QffffRS@3333{Q3333S@ȣQ3333T@`Q3333T@3333QT@!QT@ffffnQT@3333QT@RT@̔R3333T@ffff^QT@Q, T@3333KQ3333T@QffffV T@3333kQ T@Q3333T@ffffQffffT@Q3333[ T@3333Q̈"T@Q3333!T@ęQ`T@3333/Q3333sT@|QT@ffffnQ|T@ffff>cQ3333T@3333YQT@fffff=Q3333%T@Y(Qp+T@3333P7T@̄PffffBT@PffffZIT@^P9RT@L5Pffff\T@1P3333_T@\OPffff`T@oP_T@TQPT@"Q3333OT@(.QPT@33333a+Q@3333+^Q@3333+^HdQ@3333#4^ffffzgQ@̘=^DjQ@̄U^uoQ@a^ffffqQ@ffffzo^ffff sQ@|^z`YQ@ffffx`3333XQ@ffff.y`3333WQ@3333z`̀UQ@m}`RQ@L`OQ@؆`LQ@3333u`3333JQ@r`IQ@`EQ@,`BQ@̤`3333@Q@ffffx`<>Q@̦` ;Q@`ffffV9Q@Z`8Q@ `ffff 8Q@|`ffffB6Q@`3333'4Q@ffff`<6Q@ƪ`t5Q@9`ffffv4Q@ffff&`ffff1Q@j`/Q@ffffL`Y/Q@&`E1Q@`ffffv2Q@b`6Q@ffff `33338Q@M`=Q@ܢ`3333AQ@`}FQ@(`3333+MQ@`PQ@f`3333{QQ@`SQ@ffffL`3333WWQ@`YQ@` aQ@ffff~`8bQ@{`(cQ@ffff"o`ffffeQ@i`3333/fQ@f`hgQ@3333^`3333shQ@ffffZ`iQ@ffffV`3333kQ@̮N`3333qQ@̾4`3333Q@81`3333Q@:1`3333Q@3`ffffQ@̞5`YQ@\7`3333KQ@̼<`3333ˆQ@3333=>`хQ@bA`Q@3333E`3333Q@ffffH`EQ@3333L`EQ@3333O`)Q@KU`!Q@3333]`MQ@3333_`(Q@a`~Q@3333]d`ffff zQ@fffff`ffffyQ@4j`%{Q@n`3333zQ@ffffr`txQ@ffff}`8pQ@:`ffffmQ@p`ffffRmQ@`pQ@`Q@`3333O;Q@ `:Q@ffffj`ffff9Q@`33335Q@` 5Q@f`3333o,Q@ffffH`+Q@̖`ffff,Q@`I5Q@ffffaffffv8Q@33333aI9Q@e4333JgA(Q@#33333aI9Q@3333am9Q@ffffa8Q@@"a3333Q@ffffAbQ@IbQ@WbEQ@bbQ@ffffvb3333Q@ffffLybffff^Q@3333{bhQ@@b0Q@3333bQ@bԖQ@ffffb(Q@UbXQ@3333b̤Q@ffffbffff6Q@3333b Q@#b3333sQ@hb3333ӠQ@ػbffffQ@3333beQ@b̛Q@3333bhQ@ffffdbffff^Q@ffff4bffffQ@ffffTbQ@b3333Q@1b̚Q@:b3333Q@ffff:bQ@̘b3333oQ@b٣Q@̈cQ@cffff^Q@3333cXQ@ffff cQ@3333cԩQ@ cQ@tcܳQ@̜ c1Q@caQ@wcQ@cQ@t'c3333Q@3333/c3333Q@q6c0Q@b=cffff&Q@3333?FcEQ@̌Lc3333Q@(ScEQ@ffff YcWc`Q@̎Uc,Q@3333)ZcffffQ@3^cPQ@VecYQ@Zgc3333CQ@3333jcQ@ffffrcQ@"cQ@ffffjcQ@ffffc9Q@cffffZQ@ffffdQ@3333c̔Q@c3333Q@ffff`cQ@cQ@ffffcПQ@cffffQ@pcQ@^c3333Q@cؑQ@ cffff6Q@ dTQ@-d̤Q@gdffff>Q@c\Q@udffffzQ@dffff֥Q@JdQ@dffffQ@dffff~Q@r4dffffQ@̔8dQ@?d3333Q@3333]Bd]Q@3333[AdffffNQ@.=dffff&Q@ffff0:dffffQ@Z8d}Q@33338dQ@:ďQ@0d,P@ 7dPP@33333dP@f7d3333P@P@HdpP@dQP@3333d3333c}P@3333dffffyP@`d!xP@ffffd3333vP@dpP@ffffBd̘kP@dmP@3333doP@3333OeffffnP@ejP@efffffP@dffffVdP@d[P@JdffffUP@d3333VP@3333QdffffSP@ffffd3333KRP@3333dPP@3333dQP@tdOP@d3333IP@fdffffHP@jdlIP@3333d|JP@d JP@ffffvdffff&FP@̠dO@ Id̼O@KdffffO@3333SdffffO@3333YdqO@S^dO@ad4O@6idO@{kd3333ۅO@̊mdъO@#pďO@tdDO@ffffwdO@wdO@33339wdffffO@iN@3333apd)fN@ffffxmd3333`N@3333pdUN@\wd̄KN@HzdUN@3333|da_N@}daN@ffffdffffbN@8d3333XN@dMN@ffffdKN@HdRN@ffffd\N@33331dbN@׋deN@jdffffhN@֕dffffoN@ędffff.rN@3333˜d3333oN@3333d^N@ffffRdffffFEN@3333/dCN@dffffVCN@3333٠d@N@3333dl;N@dffff4N@ffffnd,N@3333d3333S'N@33331d3333&N@ffffdN@5d3333CM@dtM@dM@3333}dDM@udM@3333gddYN@ffffJ>dWN@qDd3333NN@5Id3333{:N@{MdY$N@ffffGd3333N@kDdqM@=dhM@̄:dXM@3333:d3333M@3333;dѶM@q=dȮM@̾@dYM@d?d̴M@3333dK@, dffffK@D d3333K@ffffd|K@3333d9K@d0K@3333dK@3333$dK@3333)&dffff&K@3333'dK@3333%dL@ffff&dffffL@ffffP6d K@=dffff~K@3333EdffffK@.Kd K@mPdK@ffffUdffffK@(YdffffK@m[d3333cK@[d3333K@]dK@ffff^dK@C`d3333K@sad4K@cd3333ӘK@hdK@idDK@ffffidffff~K@ffff$idffffFK@{idyK@jd,pK@̺jdikK@ffffKM@I:c3333SMM@Z6c,PM@33333cffffSM@.cffff`M@3333+cffff>iM@*cffffmM@3333w*c1qM@*c3333KtM@ffffb-czM@33335c3333M@69cM@3333bN@"bpM@bM@3333bPM@ffffbyM@^b3333+M@3333[b3333cM@1bffffM@b3333M@ffffȍb3333M@̨bffffN@RbffffN@3333ׇb3333N@3333׆bffffN@RbyN@3333b3333C"N@ffffb\)N@bffff.N@ffffЅbP2N@ffff"b5N@xb33336N@bffff9N@~b>N@3333}bBN@3333bHN@ffffЃbffffIN@bFN@|b3333DN@3333bffffCN@ffffbAN@b3333C>N@|bffff>N@b3333 CN@ffffNbYHN@b9IN@ffffԊbHN@ffff‰b3333JN@ffffbffffMN@33337bpVN@ffffbYN@bffff\N@Œb]N@֑bfffffN@̑b3333iN@bjN@b3333{jN@bAmN@abHxN@bԃN@ffff:b3333N@ffff2b3333N@̪bN@$bxN@pb3333N@b3333N@bxN@bLN@ b33333N@̔b̔N@ffffbN@{b3333ۗN@xbN@3333xbffffN@bpN@*b{N@ffffbayN@|bqN@ybTqN@3333tb3333ktN@sblwN@ffffrbffff^}N@3333'rbYN@̾pb33333|N@ffffmb3333yN@lbuN@ffffkbffffuN@ffffFjbffffvvN@#ib0yN@(hb8}N@=fbN@dcb3333SN@3333ab3333N@]_b(}N@[bN@VbN@Rb\N@LLb3333cN@Ib3333kN@,SbنN@ffffZTb3333 N@nTb3333rN@ffffPSb3333{oN@Qb`kN@3333LbgN@3333Obffff`N@|Qb`_N@3333ARbT]N@ffffPb3333YN@Kb3333{^N@ffffHb_N@Eb ^N@XEbffff[N@3333SEb̜XN@DbTN@̘5bXSN@ffff6b̜ON@ffffP8bGN@9b(CN@a rM@3333=affffflM@;ǎdM@8aZM@'5axTM@33333affffvRM@33332aPM@ffff1a3333KM@ffffh1adJM@3333M"affff2M@ǎ*M@]a3333"M@pa3333;M@̤a3333cM@a3333)M@&a,M@affff.M@ffffa,1M@a33339M@Jaffff@M@0affffMM@ffff< affffOM@zaOM@3333 a3333WM@ affffYM@ffffa^M@affffN`M@.affffdM@3333affffgM@3333a3333lM@!affffpM@3333aqM@ffff:!affffnM@!affffoM@̜a3333kvM@ffffVa3333wM@}a{M@ a̴M@aiM@3333affff}M@ffffapxM@[a3333tM@ffffHafffffnM@paTlM@3333+ aiM@ adM@:a3333aM@ffffa̔bM@̲adM@3333ahM@ainM@a\rM@ffffa0yM@3333a(M@3333GaM@ffff8a3333M@ffffaTrM@affffoM@ffff`ffffsM@q`rM@3333aa3333+iM@taeM@3333w`̴OM@3333`IM@̮`ffff^;M@̸`93M@3333`ffffv2M@L`ffff4M@f`$0M@̞`ffff.&M@ffff` M@`M@3333`xM@`3333#M@3333`D'M@`+M@ffff`AM@`|KM@ffff`UM@9`̌cM@̰`ffffntM@3333[`4M@3333`M@3333`M@`̜M@W`M@}`3333M@33335`3333èM@`1M@3333`M@ffff*`|M@ffffx`ffffM@`M@`ffffΉM@8`3333kM@ffffr`eM@ffff`bM@`_M@3333)`RM@`:M@ffff<`ffff>1M@̈`/M@3333`Y&M@ffff>`AM@̮`M@2`#M@(`)5M@4`?M@(`3333AM@ffff`3333SBM@n`ffff?M@ffff`3333;M@r`ffff%M@`M@`ffffnM@`< M@`3333#L@H`3333L@з`3333cL@3333`L@ffff`ffffL@`L@ffff`TL@`3333[L@8`XL@3333ɦ`ffffL@3333[`L@ffff*`3333L@ffff `ffffL@~`8L@`L@̾`yL@`ffffL@ffff`L@`L@N`3333L@`L@ffff´`ffff6L@3333?`ffffL@3333`ffffL@ffff` L@:`3333L@3333c`$L@ffff`ffff6L@ך`zL@ffff`ffffwL@`̔rL@ffffv`@iL@v`eL@ffff`bL@:`(SL@`3333+QL@r`PL@Ɗ`33333ML@`iGL@ffff‰`3333BL@-`3333>L@3333Ӆ`5L@C`ffff.3L@`ffff0L@3333~`ffffn)L@ffff}`"L@i|`ffffL@{`dL@̤q`xL@w`3333L@{`ffff~L@.` K@`ffffvK@`K@`pK@ffff&`3333KK@3333`ffffK@΃`ffffK@x`3333{K@=~`ffffK@ffff{`ffffK@̬z`K@ffffy`3333 K@y`33333K@pz`K@ffffz`ffffVK@y`33333K@Tt`3333SK@4i`̌L@ffff a`ffffF L@ffff^b`ffffL@~d`ffffK@d`ffffK@C_`ffffK@d]`4K@&\`PK@[`3333K@3333'\`ѺK@d[`tK@̸Z`K@3333W`̴K@3333X`3333K@ffff|_`9K@xa`K@a`ffff.K@Y_`ԇK@ffff]`ffffyK@0[``gK@̴S```K@zC`qK@D`PiK@G`y]K@I`3333YK@33337K`SK@3333K`\OK@oL` EK@3333L`d=K@M`33335K@ffffL`3333-K@ffffJI`3333"K@B`8K@<`K@ffffp9`9K@ffff4`yK@N9`8K@bA`K@ffffB`ffff K@B`ffffJ@sG`J@ffffJ`J@lH`3333J@3333aB`ffffJ@.=`3333J@L:`ԴJ@5`J@ 2`0J@.`\J@)`3333SJ@ffff@(`J@̰'`QJ@ffffj'`J@̨&` J@!`ffffJ@ffffr `3333J@3333`̴J@33335`ffffJ@̰`QJ@ffff|`ffff6J@`̔J@`̜J@3333`ffffJ@3333`3333+J@ffff`3333sJ@3333`ffffJ@`J@p`J@ffff`J@ffff`ffffJ@`J@6`J@ffff``J@3333`ffffFJ@ `ľJ@`ٽJ@3333`J@_8J@a_)J@̈`IJ@3333?`yJ@ffffP `3333J@3333u `3333ۺJ@P`̄J@3333Y`صJ@ffff`3333SJ@`J@6`$J@X`ffff.J@ffff`3333J@ `J@#`J@}%`LJ@3333%$`̜J@̖"`3333J@3333`J@`ffff6J@ffff`J@ffffv`4pJ@ffff `3333iJ@d`tJ@ffff`tJ@3333{`mJ@ffff<`$gJ@L`OJ@`ffff7J@ffff`ffffv.J@`3333#/J@3333`ffff64J@33339`CJ@`_ffff~FJ@,_EJ@ffff`ffff>J@ffff`ffff:J@`6J@`ffff+J@33333`(J@q `ffffVJ@1`I@E`3333I@̴_3333I@_PJ@e_ J@ffff_ %J@_(J@_ffff+J@3333;_-J@ffff_QJ@<_3333SJ@3333;_3333CWJ@_(\J@h_ffff`J@<_ffffkJ@3333_kJ@ٽ_pdJ@3333_!`J@ffff_Q\J@_ffff6TJ@_3333DJ@T_ffff?J@ffffj_̔:J@3333G_33332J@!_3333{/J@3333 _'J@̰_ffff!J@3333K_J@3333+_aJ@_J@D_PJ@ffff_J@_3333J@h_̔ J@ffff_4%J@3333?_L(J@̀_33332J@3333_ffff-J@ffff._&J@_` J@3333_3333sJ@_ J@ffff_I@_!I@ffff_3333I@3333?_I@_3333;I@3333o_3333+I@i_LI@3333_3333I@3333_̴I@3333_ffffI@_!I@E_ffff>I@3333_I@_ffffI@U_I@_3333I@ffff._̼I@@_ I@_I@_I@ffff_I@ffff._9I@_I@ffff~_I@3333_ffffI@3333_3333cI@Q_YI@_4I@<_̤~I@_yI@ffff_AuI@3333_3333 oI@ffff_3333nI@3333w_drI@3333o_3333#uI@ffff_̔{I@_ffffFI@_zI@d_3333nI@ffff>_kI@Ě_3333lI@_ffff.kI@ffffj_ffffNgI@8_ffff6bI@_3333\I@3333_ffffVI@̌_VI@3333_XUI@~_ffff[I@y_3333;ZI@ffffry_WI@M_UI@ffffJ_OI@_MI@3333_3333;KI@̜_\FI@3333_3333CI@$_3333BI@ _?I@3333_̔?I@3333}_a>I@u_\AI@3333oq_ AI@po_A=I@̤l_ffffv;I@3333 i_̬;I@ g_ffff6>I@ffff~e_lII@ffffc_3333CQI@̄b_3333SI@a_ffff^DI@u`_ffff@I@|^_3333?I@ffffnM_H@0^3333?H@^>H@Ъ^̌;H@fffff^3333#9H@Ѩ^ffffv7H@H^ffff6H@ffff^4H@ffffB^/H@%^ffff%H@Й^t"H@^ffff!H@L^3333SH@ݡ^3333H@ffff^pH@ffff^3333H@D^ H@ffff^3333 H@ffff.^̄H@̜^3333H@^3333KH@3333^H@Q^3333C H@̸^aH@|^`H@a^ffffnG@$^ffffG@$^G@3333^3333cG@ffffr^LG@^̴G@^G@E^G@ffff^^\G@3333^LG@^G@x^ffffG@̤^G@3333^3333G@^ܥG@^3333åG@3333^ffffFG@ffff^`G@!^ffffvG@^1G@ffff^PG@3333^G@^ԐG@^ȑG@5^ffffG@ffff2^ffffNG@ٺ^3333G@^G@^3333G@!^G@3333#^3333G@3333#^ffffG@3333K^G@3333^ffffG@ffff^ffff&G@^ffffG@m^ԳG@̬^IG@ffff~^3333G@3333;^aG@^G@5^G@E^G@T^ffffG@^G@3333_3333/G@_#G@l^ffff~&G@3333S^ffffF"G@ffff^a&G@3333^D"G@^3333"G@3333^IG@^ffffG@^iG@ffff^G@̔^ffffnG@3333^ffffG@^ffffG@ffffb^G@^`G@X^QG@̠^3333G@P^G@ffffj^3333G@^ffffG@̄^ffffF@ffffz^F@3333^F@^ffffNF@_̌cF@_RF@0_BF@ _ffffv6F@X_*F@\_ F@̄ _3333E@ _fffffE@3333O_ E@ffffn_qE@_3333۷E@ffff _0E@_ffffE@̄_!E@ffff._3333E@_̔E@_3333wE@"_ hE@3333g_UE@ffff_ffffJE@_0E@=_&E@̼_3333E@ffff_E@ _D@\ _̼D@_3333D@ffffr _D@_̔D@ffff_ѺD@ffffb_,D@ffff_D@̄_!|D@3333 _9iD@3333_ffff6eD@=_4cD@, _bD@3333W __D@_ffff&YD@ _ZD@ffff_3333+]D@@_^D@(_3333ZD@_ffffLD@_>D@_/D@̼_@ D@_ D@3333^ffff.C@ffffN^3333CC@$^1C@3333^C@^(C@ ^4C@3333^!tC@0^3333{VC@3333^ffffDC@^9C@^ 'C@3333#^x#C@3333^)C@^C@̐^C@ffff^3333k C@^xC@^3333B@^C@ffff޷^ffffVC@ffff^3333 B@̐^B@3333c^B@]^B@^IB@̬^ffffB@^ffff C@,^C@3333^dC@T^I C@3333׉^3333cC@^C@3333^`C@{^ C@ffff^x^ C@o^L C@k^3333 C@ h^ffff C@3333a^(C@d^̴C@ffffh^C@m^\C@̌^YC@^33333C@^C@3333^B@d^B@3333W^3333B@^)B@8^3333B@^0B@^3333B@-^TB@3333^8B@ffff^̽B@^ffff6B@ffff^ffff.B@ ^B@^3333B@ffff^3333B@̔^ffffB@̄^$B@^B@3333^ffffB@3333^tB@$^3333ïB@ffffF^B@ffff^~B@\x^ffff.xB@̬s^lB@r^fffffB@3333r^3333]B@3333su^(TB@3333z^3333CIB@@z^i7B@3333'x^`*B@̄j^B@ffff]^̴A@ffff[^3333A@V^hA@ffff*R^A@H^ffffA@ffffvA^A@33339^iA@33337^ffffƮA@8^1A@33336^ffff֚A@@-^ffff.A@ffff.*^3333A@̌(^ɉA@3333o*^yA@ffff'^ffffgA@ffff(^3333_A@(^UA@ffffB)^@ffff]>@3333C]>@]ffffF>@3333\j>@\\>@33333\M>@\̌>@3333\=@ffff\̌=@ \2333=@-\ffff=@ffff\,=@\`m=@\ib=@\2333Z=@3333\)H=@3333\ffff6=@ffffʓ\ܺ<@P\<@ffff\m<@3333\8<@3333ۋ\fffff<@\9;@3333+\2333s;@3333#\p;@\23333;@9\;@̤\2333;@p\;@Ȉ\2333;@\ffffַ;@X\ffff;@\̬;@<\|;@ffffڗ\Y;@\;@3333{\;@̴\ffffv;@U\2333;@ \2333;@\l;@\;@̭\ ;@\\n;@\P`;@3333\H;@3333\7;@ffffV\2333s(;@3333\̼$;@3333 \ ;@ffff\:@ffff{\9:@ffffu\l:@lp\:@l\ffff:@ffffNf\ffff:@A[\:@lQ\|:@3333+M\2333c:@I\<:@ffff*I\:@G\l:@TA\P:@3333#*\ffffQ:@3333!\2333F:@$\23336:@ \9@ffff\9@U\`9@\9@x\dfff9@\|9@\R9@9\ 9@ffff\8@̤\ 8@I[8@[̼8@[ɒ8@\[43338@ffff[܍8@̴[I8@[iq8@ffff[9T8@P[43338@P[4333c7@[43337@Q[7@ffff6[ܚ7@3333{[dfff7@3333[i7@3333[lW7@[dffff7@fffff[6@{[6@̬t[43336@ffffn[Y6@Yh[4333#7@_[(7@P][67@3333Z[4333g7@3333Z[z7@`[7@Lk[\7@ym[dfff7@q[i7@s[4333c7@)y[4333s8@~[8@u[4333,8@3333Ӑ[43333X8@p[dfffV8@ffffΔ[4333SN8@[YB8@3333[433318@ffffz[4333#8@[8@33337[dfff!8@[dfffF*8@[4333.8@[433368@ffff2[iW8@ffff[8@[8@X[8@[ 8@\[̜8@ffff6[$9@3333[k9@4[dfff9@ffff[dfff9@[09@$[l9@A[ :@[C:@[ffffY:@ffff[h:@3333[2333:@[ffffF:@u[ffff&:@[23333:@[ffffv:@3333G[:@3333[:@3333[:@L[|:@A[̜:@5[2333:@[ffff:@̔\2333:@3333\|;@@\@;@H\\%;@@ \/;@ffff\2333X;@\;@ffff^#\P;@ffff.\2333s;@ffff0\;@/\;@33333\<@2\ffff5<@̔7\J<@`7\2333Y<@7\l<@9=\2333t<@ffff&B\x<@ffffE\2333<@(M\|<@P\<@ffffT\)<@pU\<@ U\<@pX\Y<@3333_\<<@ffffvb\=@ffffb\,=@Yp\2333^=@ u\p=@ffff\ =@x\=@ؗ\=@љ\=@3333;\2333>@P\2333(>@\ffff<>@\2333Á>@ffffޫ\ffff>@\2333>@̴\p>@3333\?@p\ (?@H\ffff?@\?@ffff\l?@H\2333?@\ffff?@q\ffffv?@\ffff?@ffff\2333#?@\ɻ?@ffff\?@ffff\2333?@-\ffff?@,\p?@3333~\̼?@|\?@ffffp\Ɏ?@l\?@3333h\ffffw?@3333g\̌X?@^\)K?@N\ffffA?@ffffK\l@G\ffff>@̰C\>@<\>@4\ffffL>@33330\, >@A/\ffffF=@ffff,\ffff=@)\̼=@ffff$\23333=@\2333S=@\u=@ffff*\2333sk=@4\2333Y=@ffffJ\R=@M\D=@ffffJ \23333=@ffffZ \ffff=@3333\Y<@ffff6[̼<@ffff[2333C<@ [2333<@ffffF[<@ffff[`<@ffff[ffffvx<@0[Lb<@3333[<@[̌;@[ ;@ffff[̌;@P[ffff;@[I;@[<;@ffff[;@d[fffff;@ffff[Y;@[:@ffffV[2333s#:@=[[ffffV:@3333X[dfff&9@yS[dfff9@@P[ٛ9@3333L[9@aE[4333s9@̈@[Y9@;[dfff9@8[4333û9@8[09@A>[dfff9@aD[433339@D[dfffF9@A[{9@)9[dfff9@5[dfff9@ffffb2[̼9@0[l9@,[dfffb9@3333[C9@ffff[19@[9@3333K[)9@H[ 9@[9@3333[dfff9@ffffJ [9@ffff[9@[9@ffffJ [̌8@3333[̌8@[̌8@Zi8@DZ8@hZi8@Z8@3333Zy}8@ Z98@3333Z9}8@ffffJZl8@̘Z^8@ffffZ,\8@̀Zx8@Zx8@ffffnZ 8@3333߻Z7@ZdfffV7@AZs7@ffffZ433327@3333Z7@dZ<6@`|Z6@̬rZ43336@PiZS6@3333iZ43335@aZdfff5@ffffF]Zdfff&5@̜[ZdfffF5@3333[MZdfff}5@NZ4333ca5@fffffNZ?5@,OZ43335@3333SSZ5@33337YZdfff4@4]Z43334@`Z 4@3333_Z4@3333ZZ4@ffffTZ43334@%PZ4333#4@̨OZY4@ffffPZ<4@!XZ 4@bZy4@iZ̜o4@jZdfffb4@3333kgZP4@dZ4333S:4@3333bZL4@ffff^Z3@TRZܴ3@FZ3@BZyq3@kT`fff& @D`T@3333WT@-QT@NT{@ffffLT0333s@3333{KT`fff:@JT`fffj@3333FTY@ffffDTY@3333?BT03333@:T@9T@6TY@3333*T@ffffŤ@ffffT0333sL@IT0333@3333cTٳ@Tٻ@ffffNT@T @T03333f@T @3333Th@eT0333@3333/T @QT0333s' @T`fffG @`Tm @T` @̘Tٓ @ffff T @ T`fff @3333S`fff0!@8S`fffFG!@S0333Sl!@S!@3333S0333!@Sy!@ffffNS0333S!@tS̬!@AS0333"@S`fffF "@3333Š!@!S0333s!@IS03333!@ffffBS`fffF!@tS!@ffffުS|!@̼Slm!@ffffSA!@3333 S0333 @S @3333;S @ffffFS @S0333S @3333ӘS`fff @̌S`fff!@S @hS`fff @dSL @ffffS`fff @ffffFS0333 @5S̬ @3333[SL @]S0333s @̨S0333S @̀S @ffffvS0333n @̬pS9D @ffffZuS`ffffM @|S`fffu @ffffS̑ @ISY @S̬ @S @3333S~ @PSF @dS/ @0S`fffF" @3333S $ @3333S9 @4S@3333S,@{S@̬yS@psŠ@̔kS0333s@UiSz@fS`ffffY@aS@ffff\S`fff@ffffWS`ffffM@WS@|YS@ffff*\S@@ffffF^S$@3333 ^S@3333VS@@OS`fff@ffffTSٳ@4bS&@ffffYS`fff&@WSK@VSY@xWS`ffffN@US`fffZ@ffffSS#@3333SRS @3333TS`@3333US`ffff@VSٗ@3333ZS0333c@̈\S@4@ffff`S0333s@3333SaS`fff@(ZS0333@3333YS@3333[S@X[S`fff=@VS̎@3333QS`fff;@OS0333)@PSL%@MS@JS`fff@ffffHS?@ffffDS`ffffN@OS̮ @3333TSL @VS`fff @ffffZS @8^S @LaS 3333H @cS@3333shSh@dlSQ@lS@3333jSZ@jS`fff@̴qS`ffffL@sS@tS@wS@ffffyS 3333@ffff{S 333@ffff.SL@ffffS 3333X@DS 333@ffffS@S@S 3333@ffffS 3333@xS 333@8S 333c@ffffޥS`ffff@}SLt@3333;S 3333s@ffff:S3333?S@ffffa?S@ffff?ffffJS ?̠S?ܸSb?S3333I?ffffS3333?SL?̨S@ffff?S?ffff>S?pSffffZ?3333S3333?3333S̆?LT̴?ffffT?T?T@?T2333?Tx3333+T4333T9ſT׿TۿTffffT3333Tffff&T3333S T3333s#Tffff"ffff'Tffff쿙5T09T@3333C3333{4T̒ffffJ3Tffff"p5Tffff33330T*0TM1T33337T@3333!ffff=T3333Q4333T>3333_QhfffƠ>)Q`>Q4333>]Qhffff+?ffffQ4333?QL?Q̜@ffffQ43331@QD@QlT@Q|@̬Q4333@̌Q,@̔Q@3333Q@̸Qhfffv@̄Q@ffff.Qhfff@3333Q@QQAffff.R)AtQ$AR43335A̔R4333NA̬ RuAffffRRPARhfffƞAffffRAT Rhfff6A#RAffff'RA3333%R/RPD3333'RYEffffŘDffffrR4333sEdR1ER7E#R̼ E3333c(R4333EE-R9E|1R E@2R&E-R4Ep(RR@Fffff6RF3333LRIF QRPFffff:XRF1cRFnRpFqR`FlpRhfffF]jRF fRpFeRhfffFHhRhfffFF̴iR4333cGjRhfff&G3333_jR4333&GffffmRhfff&5GLqR?GffffvR4333sHGfffff|R)IGffff|RRI\RH̛RYI3333KRhfffI R"I4R4333,IRhfffv.IffffR43332IR4333#I3333R NÌRhfffQI0R[I~RiIffffyR0dI3333pREIkR>IffffiR?Iffff^lRhfffHI3333KgR`PIgRYSI-jRISIeoR,YIfffftRjIffffsRxIIffffRhfff0I3333?R43333.I0RI4IRhfff&yRIffffvRIsŘI3333+pR4333IffffiRIDeRI)aR@J3333XRhfffJ3333LRIffffj;RI3333g&RIIT%R`Iffff)RhfffI-RhfffĪ2RI\GR4333ItJRpILR0IJRIHRPI0R`I̸"R4333cIffffVRIR|Iffffv!R I'Rhfff&I'R4333JD'R̼J3333!RJJffffGRhfffv>J3333DR|DJDIR MJiOR4333ZJ$VŘ`J3333KiR4333#kJ3333{`RhfffsJffffn]R{J̤URJffffGRhfffvJ̌CRhfffօJxAR4333ӂJAR}JLARhfff&rJ;R dJffffR3R0[Jffff1R@RJ33331RIJ3333-ŘDJD)RCJH RGJRPMJ3333RPJ3333/RDJqRBJffffQ̼DJ3333QGJ̸Q|MJ3333wQlRJffffQ4333TJ3333QhffffWJ̬Q4333RJffffR43333SJR@hJffff(RhfffhJt(R cJ3333C+R_Jffff.R4333aJ=5RhfffhJ8RoJ<:RwJ:R̜J3333?RJ`CR)J?Rhfff6J.R4333õJ!#RJ!R4333JffffR43333JTR4333J3333RJ3333CRQ4333cIffffn:QHX*QhfffH(QhfffvH +QH*Q4333SH3333o$QH9Q,HQhfffvIffffvQ4333c IffffR Q4333 Iffff~P4333HPhfffH$PH]P̫HePHP4333HP4333yHffffP9hHaP XHffffPYPHPBH)P43335H,P4333+HP H`|PyH`zPhfffGsPhfffvGffffFwPhfff6Gffff{P4333G3333;Phfff6GPhfffGffffjP4333GP4333CGxPGtPGqPGPIUE33333P QE)PhfffDE8PAEP@IEffffP4333RE3333Phfff`E\P4333CnE9PpE2333O4333gEffff~O4333s_EOYEffffOGEffffFO 4EO0$EffffOhfff&E`O4333EO4333EIO4333ETPhffffEPE0P EffffP"E3333P<-EtP43332E3333P5EPhfff7E3333$P@5Effff$P-Ě!PL&E Phfff"Effffj"Phfff Effff'Pi!E,P4333CEy9PhfffE ?P ECPhfff&D3333s@P`D3333+APD3333/HPD3333IPhfffDIPhfff6yDHPpDqDP4333gDffff:P̜]D7P0^D3333{3Phfff`Dx4PeD33336P)hDffff'P`mDffffP4333vDffffPDO43333DffffO4333sDffff>O4333DzO D$fO D2OhfffrD2333&OhfffFhDOYVDa2O:D6O-Dp3O)Dx)OC$OC O4333CffffOhfffC OC O4333CffffO?dfffI?YIy ?I@>ĺI̬>0I>dfffI̬>Ihfff>4333;Ihffff>4333ӤIY>I4333w>I4333si>!I@]>I>>4333åI$>dfff&I>4333IY>dfffI4333>4333Ihfff6>4333+IB>1I`^>HwI4333_>dfffRI<>!HI@>EI Q>|JIYp>4333NI4333t>WIi>[I m>4333;XIhfffF>̔bI9>lxIY>{Ihffff?)zIY ?4333s}I ?I4333?Il?)ILD?PIV?dfff֢Iz?I̬? IL?dfffI4333?̬I?4333SIhfff&?`Ihfff?J4333?J?ffffJ@?2333J4333@J4333@I4333S?)Iy?dfffI4333ӳ?lIz?uIhfff&B?4333_Il?4333[OI>dfffV&Im>DI =|H\=HL=Hhfff<Hٲ<4333[fHhfffF< fH4333Sq<4333XHhffffO<SH 5THhfff:hSH h:YH,Y:_HhfffD:\[H::VH9:IOH-:IHy9qNH9VH 98UHhfff&9EH9Y3H9dfff7Hٌ9dfff@H4333s9XH4333}9]Hhffff^9dfffnRHo9dfff6HȞr9OFQ74333HFhfff&F7OF:7@VFhfff470WF`7QF433337/FhfffF7F433374333F6dfffE6E`6dfffEl7LEhfff 7 Ehfff 7dfffE̬7 E7dfffFE 743333E 74333KE6E6ȘEhfffF64333E6IE,6Ě6PEhffff6Ehfff64333 E,6`EL64333E64333cE 64333EL6zE43336dfff&jE,6`JEhfff6̬E6lE4333s6dffffDY6pD69D`6Dhfff6dfff~Dhfff6dfffNDhfffFO6̜D`>6dfffD6 D5q~D54333ÂD`5dfffD̘5 D4333s5dfff.zDhfff<5jDhfff5dfffeD43334]D4\LDhfff4dfff2DhfffƑ4dfff(Dm4A&DJ44333D444333#D3,D43333 C,34333CC`3C43333t3̔C G3C43332C̣2LC@2dfffNCy1дChfff1C4333s1dfffC433331dfff֕C`1̌CP1C-1Chfff& 1Cy0C 04333zC/0pC/PqC/4333xC8333 /4333C8333.dfffC -C@O-dfffxC8333,dfff{C,dfffC3,)C,xChffff+4333CChfff&+(C@T+4333~Chfff:+)C8333)+xC+pChfff&-+C*C8333*dfffzC̋*4333jCYK*̤jC*aC)LdCY)dfffmČ)dC)8_C@)qXC8333s?)dfffSC J)0CCL)?C)A9Chfff&)l3C8333)C@)dfffvC.)B8333s((B833333(4333BhfffN'dfffB& B&4333BL&0Bhfff&n&B&4333sBhfff&lB8333s&B&dfffVB&1B`&dffffB #&B+&4333B & xB %XbBhfffW%`QB .%4B$2B$̜B@s$ B&$dfffVA#4333A#dfffA_#AAhfff&p#A8333g#lA#Av"1A8333s!4333{A8333 qA83333/ dfffjA kA@333|dfffvpApffffdfffoA@333imA0nALa4333mA"dfffhALgAL'̼jA pApAvApfff#|~A@33338A̽$A@33334333#ALD@ApfffA4333SAlA@3337̴B`1BLV̜KBpfffc_Bpfff39nB9zB@33334333[BLdfffB@33334333+BL^B@C"C4333S.Cdfff0Fdfff2F@3333(̼7F@3333X4333BF̅JFTFffffdfffYF@3333`FZFdfffNTF4333OF7dfff>JF@3333dfffDFlEF$4333KFx\SFH\F@3333dfffcFdfffN\FffffeF̘jF@33334333uFlLF@33337dfffƉFffffvdfffNFFffffF@3333%!Fz0F4333F@3333IFffffJF̐F@33334333sFdfffGḠG̘ G𿘙)Gffff43335G@3333{dfffBGffff￘OG3333|RG3333ŠbGdfffgG33334333crGxGdfff&Gdfff>Gffff4333Gffff忘aG3333G 43333GGffff忘iGdfffGffff@GdfffVGpdfffVG4333G1翘G濘 G忘aG3333;4333G0G̠4333+HHffff4333H翘qHffffr4333Hffff~4333"H̤dfff(H̼4333;'H@333343339HTL4H̪dfff&=Hffff.;H@3333M9H@3333dfff,H̶9HSA;HCHffffLHZH4333~HFГHffff4333Hdfff.H@3333Hffff HffffdfffH@3333 yHffffAdfffH̫H(H>dfffH@3333dfffHdfff&H@3333HHffff̔HdfffH@3333OIffff4333IVdfffV!Iffff̜3IJI@33334333QI4333SXI0pVIVI@3333MdIhI@33334333iI4333lI̞dfffrI|uI񿘙IkI@3333kǏrI4333~I̴IdfffI@3333/IdfffIffffI@3333OII@3333c,J>'J2333UJffffFJ9XJffffJffffb4333I@3333̜I I򿘙Iffff@dffffI`ffff@dfffI>@N@!@pN`fff;!@̌+NA!@ffff3N0333s8!@=N03333!@fffffN,/!@nNY(!@2333Ny @̘N`fff @N @ffffN0333s!@qN!@1N`fff1!@ffffN`3!@2333N`ffffs!@N̯!@ffffN0333!@ffffNy!@2333ۆN "@2333ˆN03330"@ffffN`fff&O"@2333K|N,n"@̤kN"@peN0333"@oN"@ffffN`fff#@N1#@N D#@2333N#@`N#@ N`fff#@ N̬#@,N`fffF#@N̬g#@23333N,C#@ffffN`Z#@ffffN9i#@2333cN0333Sw#@2333+Nl#@LN`ffff#@O#@ffff O9#@PO@#@O`#@O`fff&#@OL#@O#@2333O`fffF#@`O03333#@ffffNO#@ O`fffF#@#O#@`&Ǒ#@2333)O#@Q3O9#@AO,Z$@qFOf$@LO@o$@MO̬S$@LO;$@YSO,$$@2333^O$@2333XO@3$@TO̬e$@WO`$@hZO`fff$@dO`ffff$@ffffhO$@kO$@ffffkO0333%@tO %@ffffXO@ %@23330O%@OD%@,OlJ%@N`fff\%@2333N`ffff{%@2333O,f%@ffffYO`fff%@ffff.yO`fffj%@2333O0333p%@ffffNOk%@ffffOYI%@OS%@ PC%@P03333E%@3333P%@3333 P0333(%@lO`fff%@ffffO%@O$@ffffO`fff$@ P`ffff$@ffffn6P92$@3333k$@Q_PQ$@iPt$@3333vP$@ffffʅP`fff&$@P%@ffffƆP03333&%@ffffҏP0333C%@LP`fff8%@P $%@4P`fff& %@P0333$@Q`fffF$@3333Q`ffff#%@ffffQ0333`%@Q0333%@iQ0333%@Q %@ffffQ &@3333QlR&@p'Q`ffff&@4Q &@ffff~CQ &@ffffNQ0333s '@aQ&@xdQ̌&@lhQ&@mQ '@3333pQ Z'@sQy'@(uQ'@ wQ(@̄zQ̬:(@@Q0333[(@3333χQ0333E(@ffffQ`2(@Q(@ffffVQ`fff'@Qu'@ffffQ\'@3333SQ?'@LzQ X'@3333OtQX'@3333wqQ`fff&'@sQ&@xQ&@3333Q`fff'@33337Q '@%@Q%@ffffQ@$@ffffQ $@Q`fffI$@3333CQy$@3333;Q#@3333_Q`i#@Q`fff#@ffff~QL"@$Q`fffq"@3333sQ`fff&R"@Q0333S@"@XQ"@ffffQ̌"@3333Q %"@ffff^Q̌D"@Q"@Q`fff"@Q"@Q0333"@3333{Q@#@Q0333sH#@8R0333#@ffff*Q0333S7$@QU$@Q`fffơ$@̌Q03333$@ Q0333P%@LQ0333s%@0Q`fffƫ%@3333Q`fffF%@ffff>Q0333S%@Q&@3333Q`fff&E&@ffffrQ0333sa&@3333Q03333&@3333CQ03333&@ffff>Q#'@Q`fffF7'@Q03333A'@AQp'@Q`fff'@\Q@'@ffffvQL'@0Q,'@Q(@Q T(@ffffQ̬(@Q0333S(@Ť"@3333Tl"@T`fff #@T@'#@ T`ffff;#@ѱTV#@ܳTx#@qT#@3333T`fff#@TL$@ffff2Ty$@Ť$@T,x%@̤T`fffF%@T`fffF%@ffffT%@3333T %@%T@&@U0333/@ffffCU̬/@yJU/@^Ǔ/@,rU0@U00@ }U43330@{Uhfff&/@3333cU0333/@̘U03333/@3333ӖU/@ŞUhfff&/@3333sUhfff/@U0333S/@LU9/@(Uhfff&/@)U0333/@U,/@U/@3333U@/@3333U9/@ Uhfff/@ffffVhfff/@ffff~V/@dVf/@̜V@u/@3333&V̌/@E&V/@̔$VY/@Q"V/@&V@/@ffffZ-V0333/@3V/@ffff5V/@89V/@Y:Vy/@3333C8V4333C0@},Vdffff?0@#VYJ0@3333V o0@Vdfff}0@3333V0@V0@V011@|V P1@Vd1@ V@1@dV 1@,VY1@3333G V1@8V4333#2@tV433392@ffffVVY2@3333VZ2@VdfffX2@ffffZV[2@Vx2@V2@ V43332@ V<2@Vdfff2@̸V2@V43332@ffffV43332@̜V4333C2@V{2@3333kUp2@ffffrUF2@3333UD2@ffffvUi[2@Udfff6r2@ffffU2@3333Ul2@U 3@U̬I3@3333UdfffFQ3@@U)R3@U @3@U4333B3@(U43333Z3@)Ua3@IUlj3@3333U4333l3@Uq3@ffffUp3@3333/UdfffV3@ffff U4333#3@3333U 3@ffffU3@LU̍3@ffff*U3@3333U3@}Ǔ3@pUdfff3@ffffU3@EǓ3@̤U43333@U3@ffffUdfff&4@U<;4@(U܁4@U4@3333GUdfffV4@3333WU43334@1UdfffV5@dU&5@ffffrUdfff635@3333KUdfff;5@U4333k5@YU|v5@9U̜5@8U5@ffffU5@UdfffV5@U5@3333U,5@U4333c5@3333UІ5@ffffzU@5@ U43335@U43335@U0z5@ffffU@u5@ffffUlr5@U4333x5@U,5@̄U̬5@pV43335@lV5@ V5@ Vi5@3333 Vdfff65@V 5@ffffV4333Ñ5@3333o%Vdfff5@/Vr5@<8V4333j5@3333wtVLF5@3333xV̬@5@̴V43335@Vi5@ٛV4@3333WVdfff4@Vl4@̜VdfffFa4@ VY94@Vdfff4@xV`3@tVp3@3333V43333@\Vٺ3@PV,Z3@3333V4333&3@V4333#3@3333V 3@ffffV2@MVY2@3333V@2@V433332@V̌2@dVdfffv2@V\2@V2@3333Vdfff2@3333V|2@Vܟ2@0Vdfff2@,Vt2@aVyr2@dVyx2@xVL2@TV<2@YV43332@XVdfffF2@ffffRV4333C2@3333W4333S2@̤ W4333S2@9W2@3333W02@ffffr-Wdfff2@3333.W43332@81W,2@8Ww2@ffff&HWdffffl2@ffffNW̜q2@YcW43333n2@pW[2@wWM2@W12@3333W|*2@lW*2@W4333,2@Wdfff6Y2@W̼2@W43332@3333W4333c2@ffffW2@W`2@W43332@ffffW4333C2@3333W2@Wɰ2@̌W02@3333W2@hW2@W2@Wdfff62@3333oW̬2@W4333 3@ffffX 3@3333Xdfff23@XX3@ffff.X y3@3333Xdfff63@0X3@3333[-X4333304@GXp4@KX4@ffffzLX43334@3333VX5@ `Xdfffe5@`Xn5@ffff`X\z5@ffffBdX5@3333?fX05@hX5@ffff>pX43336@eX43335@8]XdfffƜ5@ffffXX43335@̠XX5@)[X w5@[X4333C[5@0ZXdfffE5@XX_5@3333UXp5@ TXp5@ WXl5@ffff_Xp5@leX5@pX6@ffffrXG6@3333uX43336@uX̜6@ffffvX6@DtX̼6@̈pX43336@oX@6@qX`N7@nX4333s7@oX7@nXdfff7@mX 7@3333jXdfffc8@t`X9@$[X̬;9@dNX9@ffffJX4333C9@\IX4333#9@HX̜:@IX:@̰MX`:@YX2333e:@[X`|:@]Xffff:@ffff_Xffffv:@ffffaX2333S:@cX2333:@ffffaX ;@q^X,;@ffff^^XffffF,;@ _Xffff<;@PlX2333I;@ffff.qX u;@kXe;@3333aX`P;@̴^X Q;@ffff\X T;@YXXYk;@ffffzRX̬;@[X2333S;@YX;@WX;@PX̼;@JX,;@DXp;@ffff2BXffff<@ffff IX̌<@IXffffF<@JX2333$<@%FX2333(<@@X)<@=Xffff0<@3333;Xi9<@3333:X2333s/<@9XffffV(<@ffff5X23331<@3X`8<@ffff2X2333#R<@1Xk<@I+X`W<@3333#X]<@HX2333g<@3333X2333u<@ffffnX̬z<@!X}<@ffff(X2333s<@&X)<@$X9<@ffff#X9<@ffff!Xffff<@X0<@X<@ffffX23333<@3333Xffff<@\XI<@̴Xffffơ<@3333wXffff<@ffffX,}<@ Xy<@ffffNX9<@ffffW<@3333W23333<@W<@3333W<@̀W<@̼WI=@ffffWffff*=@,WlB=@ٸW^=@Wu=@ffffW=@ffffvW̳=@ݾWl=@3333W =@WL=@DW=@|W=@\W=@3333ϱW@=@3333W =@W\=@ffffWffffF=@ffffW2333k=@W`b=@ĤW |=@`W=@xWy=@ffffxW=@|W2333=@ffffuW=@rW,=@8qW=@ffffzqW=@3333sW=@3333KvW=@xW\=@hwWp=@tW2333=@qW=@xlW=@XW=@ RWffff=@ffff>KWi=@@YV >@̤_V2333>@ffffdV>@ffffeV@=@mhV`=@ffffoV =@,tV>@ffffqV2333 >@mV >@jVffff>@̸jV%>@ffff2oVffff,>@3333{qV #>@sV>@8yV9 >@̠V,>@8V2333s>@@3333oV#>@3333?VG>@3333kVa>@V|^>@VffffY>@ffff}VD>@eV|*>@UaVP1>@ffffb\V 9>@TVfffffX>@ffffPVW>@PNVffffU>@uCVffffF^>@33339VffffFj>@ffff7V2333j>@y4Vh>@3333K,VZ>@3333V^>@dV̜_>@3333V\>@3333V]>@uV2333Sj>@V2333>@3333Vfffff>@Vffff>@ffffU|>@ffffU>@(Us>@ffffrUffffj>@3333ULh>@ UX>@U2333J>@3333U2333SB>@ffff U A>@aV;>@3333UffffC>@U<^>@TU`>@̰Uffffd>@fffffU2333#]>@ U,O>@3333sUffffVK>@UV>@Ǔe>@Uffff&t>@3333U>@ffffU>@U>@3333+U̍>@ؿU>@ĽU|>@3333ULn>@Ǔe>@ffffzU_>@UV>@U2333S_>@3333U2333#g>@ɦUl>@3333U2333w>@3333U~>@ffffUi{>@xUffff6~>@ffffUv>@ЈU q>@U2333g>@]Um>@U,f>@5U U>@3333vU23336>@rUffff,>@3333_pU*>@̌oUffff3>@ioU>>@AkUG>@fUiI>@iUffff<>@ujU0>@ffffgU%>@3333gU>@@kUffff6>@ffffF`U=@VU0=@3333SU@=@3333'TU2333=@UUy=@ffffXU=@|ZU̬=@|ZU=@ffffXU=@iTU2333#=@KU9=@AU=@3333>U̾=@8U2333=@<3Uffff=@33333#U=@3333U=@UI=@U=@Uffffv=@ffffUl>@U2333>@U2333>@pT =@3333Ts=@TO9@0@XTE>@ffffB]T >@@`T@>@ aT2333C>@ffffNaT>@ `T>@3333+^TP?@]T?@ffffv]Tffff ?@E\T 3?@hZT-?@ffffZWT,?@ffffvRTC?@UT2333SP?@,XT2333U?@aXTpZ?@RTffff_?@PTo?@ffffNTx?@ffff:KT2333?@ffffLTffff?@LNTI?@PTffff?@3333OTffff?@JTS9A@3333DS3333˓A@33337S3333A@1S3333~A@1(S3333cA@A'STA@&S̔A@8$S3333A@ S̜A@`#SffffA@&S33333A@]>S̬A@3333BSA@8SffffFA@3333s/S3333;A@(S3333A@3333'SA@$S3333#A@"SA@!Sffff޷A@TSѲA@S1A@S\A@SEC@ffffvOSffffV?C@NS04C@ffffIS2C@DS33338C@3333@Sffff8C@A?S3333k2C@C@3333WR3333C@̴RffffC@3333R3333sC@ RffffvC@RfffffC@\R٫C@qRC@3333KRffff.C@3333RPC@ Rffff>C@(RC@3333kR3333C@ERC@3333RC@$RC@ffff"RffffC@`R C@RC@!Rffff&C@ЁRX D@ARffffD@4~R D@I}R*D@9~Rffff>3D@ffffR9D@0R7D@tRfffff:D@RCD@ffffR3333MD@ffffRRD@̉R,VD@pRWD@3333OR\D@R`D@3333W{RffffuD@ffff>zRD@0zRD@3333zRaD@3333~RffffD@8{RD@ffffvxRffff֕D@ffffwRD@zR3333tD@|R\kD@,R,`D@3333|R3333scD@HzRffffvhD@3333{vR3333kjD@3333qRppD@jR{D@YhR~D@PeR̂D@ffffKRD@̄AR̴D@ffff.;RD@86RD@ffffRLD@3333RD@ffffRTD@ffffRffffD@QD@QD@D@3333σQ3333D@3333'Q̌D@ffff|Q̬D@{QD@3333C|QhD@~Q3333 D@Qffff E@3333;Qffffn E@ffffQffff E@mQ̬ E@3333#Q E@3333Qffff~E@3333 Q E@ffffQ3333E@3333ÅQfffffD@dQD@3333QD@Q3333D@QffffND@ffffNQffffD@Q3333D@!Q$D@ffffQXD@3333KQ3333E@Q,E@@Q3333KE@YQ!E@ffffʿQfffff&E@Qa*E@̌Q3333K7E@̼Q?E@1Q3333FE@ffffQIE@TQffffNE@ffff:QffffOE@ffffQ)SE@3333QUE@QDVE@QUE@Q3333UE@QQ\E@8Q3333cE@3333Q̤iE@3333Q9pE@ıQdxE@3333QffffE@E@iQ8E@hQ3333sE@ffffgQE@ffffeQ3333{E@̠cQ3333E@̨bQffff6E@TaQE@ffff^QE@ffff[QhE@ VQffffF@xNQDE@HQF@`DQ| F@DQF@1=Qffff,F@̈=Q7F@3333;6Qffff>F@ffff63Q3333SFF@0QffffIF@ffff0Q@AF@2Q,:F@ffff1Q9F@/Q,:F@ffffr-Qffff8F@33332Q0F@ffff3Qp+F@ffffJ.Q+F@3333+'Q'F@$Q3333"F@"Q3333!F@ Qffff&F@3333_!Q33330F@3333Q3333 9F@ffffQ@F@Q3333 F@3333Q3333+8F@Q11F@QP3F@P5F@̜Pffffn;F@ P:F@3333P3333IF@3333PJF@P3333HF@ffffPGF@3333WPIF@PRF@LP TF@LP33333YF@=PyVF@3333+PiF@tPlF@P3333oF@PIqF@ffffJPxF@ffff&P̜~F@3333P3333;F@XP3333ˑF@PF@aPlF@PffffF@̺P3333F@ PF@ffffַP̜F@ffffBP̬F@3333PYF@ffff&PffffFF@ffffP F@P1F@33333P!F@ffffކP3333F@PF@ffffPF@3333'PffffNF@3333P3333sF@DP3333F@ffffPffffF@(}PyF@3333xPF@bP,F@RPffffF@ffffCPF@3333w9P F@33331PF@ffff%Pffff&F@3333)PF@ffff~(P3333+F@3333S"PF@Pffff6F@PF@3333#PF@xP@F@iPF@#PF@4Pffff޼F@l:PF@7P3333cF@ffff>5PԬF@/P̄F@3333+PF@i&P|F@PܱF@PF@ffffOhF@ffffO3333sF@2333OF@OF@O3333˧F@ffffPɛF@ PђF@P3333F@ffff PF@PF@hPF@3333Pffff~F@PTF@3333+PF@ffffP1F@ffff P!F@PffffƠF@0PF@9PffffvF@jPQaF@ffffJlP^F@3333nP3333;YF@eP@]F@$`PTaF@HaP]F@hgPWF@3333kPQSF@qPffffRF@̰zP3333NF@3333cPffffGF@̅P@F@P F@3333PEF@P@KF@ffffǑRF@2333;O3333KMF@ffffOffffEF@2333 O\AF@lO3333C>F@ Op=F@OAF@̼OEF@tO(NF@PO3333sWF@̬OSF@yOQF@ffffOqSF@4O@RF@ffffO [F@2333kOZF@2333Offff~[F@PbOffff~dF@2333AOkF@2333!OffffwF@ffffnO3333KF@ffffNffffΊF@NF@ffffN̴F@NF@2333NF@NF@2333SN$F@)NȠF@NF@N\F@ NXF@N3333CF@NF@NF@$NffffF@NtF@ffffvNffffF@ܬNffffnF@̼N3333F@2333NF@N33333F@dN3333F@IN3333kF@NIF@8N3333F@ffffNN F@ffffǑF@6O3333F@@9OF@=OF@ffffJOF@2333`OF@2333[OffffF@YO3333F@̔tO`F@ЍOffff&F@2333ÛOF@yO@F@pO3333F@2333ӭOF@ffff.OffffF@O`F@O3333F@ffffOF@3333PG@P3333G@|O G@2333OffffG@Qffff.PH@QffffVEH@T#Q:H@3333/Qffff.0H@44Q.H@,?Q33333#H@3333SQH@%^QG@0eQffffnG@XsQG@QXG@tQ3333[G@QG@ffff֘QG@3333?Q)G@QmG@ffffQhG@3333Q`G@QA\G@ffffQffffSG@̨Q3333PG@ffffRffffFG@3333 RyAG@ffff^Rffff8G@3333oR3G@R$-G@.RffffFG@3333[?R3333C G@ffff6JRIG@1PŘF@3333WRF@3333]RF@^R3333F@4aRF@cRiF@pRffffF@0RffffF@8RF@ffff>R3333SF@ffff^Rffff~F@ffffR3333kF@ɕR3333sF@3333GRyF@3333S~R,F@RxF@ُRffffF@ffff*RF@lRRG@ffff5Rffff!G@3333+Rffff$G@lRffff>G@ RGG@ffffRMG@3333KQWG@3333wQ8VG@QdYG@3333#QeG@fffffQdvG@@Q3333ۀG@,QG@̬Q33333G@4Q3333cG@̤Q̴G@yQffffG@uQffffG@qQffff H@dwQ H@(~QffffVH@LQ,H@ffff Q3333[-H@3333Qffff6-H@ffffQffff/H@ Qffff6H@3333+QQ:H@ffffQ.H@Q̔#H@Qffff"H@ffffvQ3333H@3333pQxH@ kQffff~H@4cQ H@3333WQffffv1H@NQlIH@u;Q3333jH@*QAxH@3333/(Q3333H@ffff"Q0H@Q̼H@Q3333H@ffffQ(H@3333 QI@2333cMtVI@2333+M3333cI@MffffpI@̜QMI@NMXI@KMI@2333SAMĥI@̜8M(I@ffff"MɥI@q MffffΧI@ffffM9I@HL3333#I@L̄I@L3333 I@LL8I@ЌLI@}MPK@uM<K@kMK@ffff\M3333 K@ QMXK@yGMffff. K@̴7M33333K@-Ml K@ M3333$K@M(K@`M3333,K@ffffL)1K@L3333{1K@L`8K@ LSK@LOM@ffffFKO<M@̤hO3333M@ffff}O M@)OffffFM@yOM@iOffff M@ ODM@gOffffM@PVO3333(M@2333LO̬M@P<;M@ffff>Pi7M@lPh/M@ffffrPfffff&M@tP3333SM@ffff*P3333M@PffffM@ffffvPffff M@hPL@ffffPffffM@ffffP3333 M@3333 P3333M@$P4M@,PffffV1M@aP3M@̈P.M@Pffff'M@ffffP"M@3333QffffvM@ffffQM@TP4"M@P3333%M@P)*M@3333P ;M@XQffff>M@3333QffffM@ Q3333CM@0Q@GM@Qffff6LM@dQ3333+_M@Q0dM@dQhiM@ffff$QffffnM@(QIrM@3333,QsM@AM@PlQ̄M@3333iQTM@̌fQ̴M@eQiM@eQtM@UhQ1M@kQtM@nQM@sQM@3333QffffVM@ݝQDM@QM@Q3333[N@̘QN@3333}QHN@rQffffN@ffffkQffff N@ffffNhQN@gQffffN@=hQ3333kN@̄hQ4N@XmQ$N@eoQ*N@`pQ33331N@3333pQY8N@pQd>N@3333+nQHN@hQ3333KXN@dQ_N@3333[_QcN@[Q9hN@3333YQ3333clN@ffff~YQqN@̄ZQ3333vN@4^QfffffN@ffff6`Q,N@cQ3333N@gQffffVN@̠iQЁN@]kQ3333yN@ffffVmQ3333uN@ffff:sQfffftN@0zQnN@QmN@Q̬pN@ffffVQffffuN@9Q̔}N@Q̤N@3333Q0N@QɈN@Q0N@QpN@IQN@K@ffffvS2K@ffffSffff+K@3333Sffff!K@SK@ffffSK@dSK@ffffS K@qSK@yS K@LSffffK@ffffSK@3333SQK@̰SJ@3333SXJ@ SffffJ@pŠJ@ffffSqJ@4SJ@̔S3333J@ffff6S3333J@=SJ@lS J@ffffSffffJ@}SffffJ@SdJ@|ŠJ@S|J@YSsJ@0SmJ@3333;SgJ@ffffSIaJ@S3333SJ@ffffRSYPJ@pSffff~DJ@3333Sffff>J@ܡS3J@3333S'J@ffff֠S3333C%J@St!J@3333wSD J@dSLJ@SJ@S0J@S3333CI@ffff·S3333I@S,I@ffffbS@I@3333ӾS$I@3333SI@3333S3333kI@!ShI@ffffήS̬I@S I@S$I@pSffffƢI@͹S3333I@ffffS3333+I@3333StI@ffffRSqI@S\I@S8I@ffffS3333[I@xSffffI@SI@SI@̬ShI@S3333I@]SI@3333S3333I@ Sffff6I@|SI@ffff&SffffI@S\I@ISffff6I@ffff2SؗI@3333S3333CI@S I@3333SffffFI@3333OS̤{I@SiuI@]SjI@DSffffaI@1S3333pI@@SuI@ffffSI@̄S0I@3333wSI@̠T4I@Tffff~I@̌T9I@̜TffffVI@X+TffffnI@2TI@ffffz6TI@ +T3333I@ffffTffffI@3333_T̼I@T3333SI@Tffff6I@ffff%ThI@*TI@3333'-T0I@=TqI@$HTJ@ffff>RT3333k J@ffffzYT4J@ffff]T,J@3333+cTffffNJ@xiTJ@!tTJ@tT3333J@qTffffv J@QjTffff%J@3333#gT3333{)J@ffffdT3333/J@\fT`7J@ffffoT$HJ@ffffvTaSJ@HT3333gJ@TffffNpJ@TuJ@3333Tffff{J@̨TffffJ@TffffvJ@ffffTtJ@TJ@0TСJ@3333[T3333J@3333T̤J@33333T33333J@TJ@ TJ@hTffff^J@ffffZT̼K@ffffސTX K@9TK@%TffffNK@T3333-K@T3333=K@ffff T hK@̀TffffmK@ffffT3333K@3333+TffffK@T K@T0K@ffff>TK@TK@TqK@3333TffffK@TxK@ffffrT3333K@3333T3333ۡK@3333GTffffFK@1Tffff6K@xUffffK@ffffU9K@3333ŪK@U)K@ffff&!U3333#K@3333+-Uffff.K@:UDK@ffffCUK@3333?HU3333K@3333MUK@`WUffff&K@3333+WU8K@MU3333K@MU3333K@RUK@ZU0K@3333^U̴K@cU$K@ffffNkUK@3333'uUffffK@U3333K@U3333K@ UK@3333׺UK@\UK@UL@Uffff6L@33333U+L@ffffV;L@]VDL@̜VML@3333+Vffff\L@4V9hL@M@HWffff>HM@IWXM@pKW\M@QW`M@XW^M@_W3333K_M@qW3333bM@WHaM@ffffWL^M@3333_W,PM@3333kW3333c0M@3333CW&M@IWh+M@WXTM@3333_Wffff[M@ԚWl_M@ffffWlM@W)oM@3333WpM@W`oM@WsM@W3333|M@̬W3333M@ffff.WqM@DWЈM@ffffW3333CM@3333sWffff^M@3333sWIM@̴W33333M@ffffJWffffM@fffffW9N@ffffvWffff N@W&N@dWL5N@Wffff:N@3333#W =N@Wffff?N@pW3333DN@hW`EN@WaMN@3333WW]N@W|oN@܉WAN@ffffVWffffƑN@ffff2W3333 N@̈WN@3333WWffffަN@3333WffffN@I|WlN@ffffxW N@xWN@33337|WɸN@ffffjzWN@3333kmW N@3333ZWXN@̌VWN@SWffff6N@3333TWN@[W3333N@_WhN@aWN@!O@ffffz)WO@%W3333O@ffff!WffffO@"WO@((W#O@,W3333*O@1W3333,O@ffff&1W33330O@ffffF-W5O@&W3333+WO@4#Wffff.O@̨WO@ffff~ W3333SO@ffffWhO@hWO@VDO@3333sVffffO@VyO@3333 VffffO@3333/V3333O@DVO@-VO@|VO@ffffVO@Vffff>O@ffffV3333[O@VffffJVP@HVQYP@xOV\P@lfVtiP@ffffnrVffff&oP@${VqP@3333 V3333sP@3333'V3333tP@ffff2V̠xP@VzP@(VyP@ffffV̬xP@VuP@@Vffff>yP@XVffff|P@ffffVVfffff}P@̌V3333}P@Vffff}P@شV }P@3333Vffffz{P@٠VzP@=VI{P@ffffvVyxP@ffff>V|xP@xVffffwP@AvV3333wP@ffffj|V{P@xVffff6|P@ffffoV{P@ffffeVffff2zP@3333ZV3333wP@EV3333KoP@UfffffP@3333+AUзP@3333GUP@3333GGU3333 P@BU0P@ 6UffffP@3333S,UP@ffffv"UffffBP@ffff!UffffP@U3333[P@U33337P@qUP@ṲP@pUP@ffffUP@P U P@ffff UԮP@33333UTP@TP@TuP@3333OT33333P@3333TP@33337T|P@3333TffffҘP@ffffzTP@3333Tffff—P@TP@̸TP@ffffT@P@ffffTP@3333oTħP@T3333gP@̬TMP@TP@ffff>TffffδP@3333STP@<{TaP@3333wTffff:P@3333;nTP@3333ShT P@]TxP@U\TP@XTP@DSTP@IQT3333oP@ffffRTP@3333cZTffffP@_T3333P@YmT3333;P@3333wT\P@ffff~~T3333+P@T3333gP@ffffnTYP@T5Q@T3333KQ@3333ۀT Q@̀Th Q@3333+Tffff Q@T Q@3333TQ@TffffQ@W3333Q@;WffffƸQ@ffff9W̠Q@ffff~8WpQ@8WQ@3333W8Q@BW|Q@hPWffff~Q@ZW3333SQ@3333dWeQ@ffffpWQ@ffffrW(Q@ffffpWQ@3333oWffffQ@ffffsWffff Q@̀WffffZQ@WffffQ@WQ@̤W3333OQ@mWQ@3333W3333Q@W(Q@WQ@ĸWQ@WffffQ@3333W3333Q@3333kWQ@WIQ@WffffQ@$W3333Q@3333WQ@ffff&WffffBQ@WXQ@W3333wQ@WqQ@WQ@|W3333gQ@lWQ@tWQ@$W(Q@̤WHQ@X|Q@Xffff^Q@]XQ@ffffX3333Q@̔XffffZQ@X3333KQ@ffffX0Q@H X)Q@!X!Q@3333XffffvQ@qXffff&Q@D#XQ@!#Xffff³Q@X3333oQ@3333X3333Q@ffff X٨Q@ffffWQ@W3333oQ@ffff>WffffzQ@3333W3333Q@3333;Wffff"Q@X3333KQ@3333X3333Q@}X3333Q@ XffffQ@ffffX3333Q@3333"XQ@#XQ@I#XuQ@3333XffffQ@=XyQ@ffff Xffff2{Q@3333XwQ@5X1uQ@W`sQ@qW3333?rQ@ffffFWffffqQ@3333W]pQ@pWmQ@WffffjQ@WffffdQ@3333WxeQ@̜WiQ@HWffff jQ@̐WiQ@W3333WeQ@ԚW3333aQ@WffffZ^Q@TW ]Q@qWffff\Q@ffffW3333\Q@̐zWffffJ]Q@3333rW_Q@ffffiW8aQ@bW3333^Q@3333oaW\Q@ffffbW3333ZQ@3333_bWxXQ@̔[WXQ@ffff\W3333VQ@QdWSQ@oWxNQ@fffftW3333+PQ@3333CsWffffQQ@5gWYQ@gWZQ@ffffvWffffXQ@W3333UQ@MWTQ@ffffWQQ@Q@]xW?Q@ffffvW@Q@sW?Q@qW >Q@3333mWffff;Q@̜kW8Q@3333kjW̤5Q@3333;jW(2Q@ffffFkW3333+Q@ffff6iW̄(Q@fWffff'Q@3333\W'Q@^WT&Q@iWffff"Q@`{W3333SQ@HWQ@ffffNW3333Q@̐W3333Q@3333Wffff* Q@̤WQ@3333WffffQ@ffff"W8Q@ffffWTQ@WffffQ@̔WffffQ@LWQ@|Wffff^Q@Wffff2P@ffffW P@W P@ffffW$P@3333W3333P@3333WP@̌WffffP@WľP@WļP@ffffbW$P@WP@3333;WP@\XP@3333XP@XP@ffffjWxP@W0P@3333gWyP@WuP@ W3333+P@̨WffffrP@ffffXffffRP@XPP@3333 XPP@3333X P@mX3333{P@ XffffڿP@XffffP@@X33333P@3333WffffP@(WffffP@1Wffff޽P@WqP@WAP@$WffffP@3333?W3333SP@3333WP@ W3333P@WeP@ffffWP@ffffW3333cP@ffffW3333P@3333WffffP@WP@W3333gP@}WffffP@3333WffffFP@3333CWffffP@ffffXffffVP@ XeP@ Xffff~P@3333 X P@3333 XP@XP@XffffrP@3333XxP@ XP@3333 Xffff:P@ffffNX Q@WQ@ffffX3333#Q@ffffX Q@XQ@̘XpQ@"Xffff Q@ffff%XQ@ffff6.X3333{Q@h.X3333Q@XffffQ@ffffX̐Q@XQ@4(XQ@ffff>XXQ@?XQ@DXMQ@HX0Q@QXQ@}UXffffQ@3333CZX3333Q@ffff^X̰Q@3333cXeQ@ffffhXQ@3333uX"Q@4{X!Q@ffff|X3333 Q@ffffNzXQ@rXffffQ@3333˅Xffff*Q@XPQ@XtQ@lXQ@XQ@XDQ@3333X1Q@pXPQ@3333X Q@`XffffzQ@XaQ@X3333wQ@XQ@ffffX$Q@ffffRXffffP@ffffX3333P@tzX3333P@MoXffffP@bX|P@3333UXP@8MXP@JXffffP@3333HXP@3333JX3333OP@ffffIX}P@qLXffffP@QXP@]X|P@fX3333cP@{X}P@~XEP@XffffBP@XffffBP@̌XQ@3333kX̤Q@ffff&X3333;Q@XQ@8X3333Q@3333XffffP@ЦXTP@XP@ffffXP@`X̨P@ffffXP@X3333P@3333X̤P@X3333sP@3333XP@fffffXPP@X3333P@9Xffff.P@xXffff&P@̠ Y3333P@0YP@A!Y`P@ffffn'YffffP@/YP@ffff6Yffff"P@̰AYP@3333+FYffffP@̄cY\P@fffflYffffZP@xY3333P@Yffff6P@lYP@̀YP@3333YP@IYP@ܵY3333P@dY,P@YQ@XY\Q@YlQ@3333Y̠Q@3333c Z3333Q@ffffrZ3333Q@(Z3333 Q@4(ZffffQ@P*Z Q@ffff(Z̰ Q@)ZQ@A1ZQ@H8ZffffQ@]:ZQ@3333;ZdQ@m=ZQ@ffff?Z̬Q@ffffBZlQ@|FZffffQ@ffffzLZ$Q@(XZ|Q@ffffn[ZTQ@ffff>]Z3333$Q@̌bZffff-Q@fZ33332Q@kZ5Q@sZX7Q@Z9Q@ffffZ3333:Q@Z̐9Q@Zffffr4Q@)Zffff3Q@ffffZffff,Q@ Z)Q@[3333'Q@ [ffffB&Q@)[9Q@-[ Q@+[Q@[\ Q@̨[ Q@̴[ Q@[ Q@[m Q@Zffff Q@ffff^Z Q@Z!Q@tZIQ@3333Z0Q@Z̴Q@ZQ@3333[ZxQ@Zffff2Q@ZQ@3333ZQ@ffffZQ@Z3333Q@DZQ@ŢZffffzQ@PZ !Q@0Zffff$Q@̼Z'Q@{Z̼(Q@ffffqZ'Q@3333pZ%Q@3333qZ3333!Q@vZhQ@3333{Z\Q@ZQ@tZQ@\ZffffQ@ZpQ@|ZffffvQ@3333'Zffff Q@hZ Q@3333;Zd Q@3333ǪZ3333 Q@̀Z< Q@3333ZD Q@3333{Z3333;Q@3333 ZffffNQ@ZQ@ZQ@XZQ@xZffffQ@ffffZ-Q@ZQ@̴Z3333Q@3333Z\Q@eZQ@Z]P@ffffZ P@ZffffP@ffffVZdP@33337ZP@3333ZP@]ZP@1Z3333P@Z̸P@3333ZYP@̨ZhP@8ZP@QZyP@3333ZffffP@aZ-P@3333ZP@3333CZP@ZqP@=Z|P@ZffffnP@Z|P@ZP@ZP@ffffZ̐P@ZPP@3333ZffffP@3333Z33333P@hZP@ffffZ̈P@`ZP@ffffZffff:P@ffffvZ\P@ ZP@Z1P@3333ZP@Z3333P@ffffZћP@ZyP@ZffffƨP@3333ZP@3333OZP@[ffffZP@,[ P@ffff~[P@3333 [ P@ffff [=P@3333#[P@3333[P@a[P@ [ffffP@![\3333Q@E\Q@\Q@\̌Q@ffff\T#Q@|\ffff6*Q@̰\/Q@\3333g6Q@Y\9Q@ffffN\8>Q@3333\$?Q@3333\0?Q@\Q=Q@ ]l>Q@]3333W>Q@ffff]ffffN=Q@,]33336Q@ffff]5Q@@]ffff26Q@a]7Q@,]\8Q@ffff2#]ffff>8Q@A]3333:Q@ffffnH]ffff:Q@ffffN]u:Q@S];Q@$u]ffff?Q@]3333BQ@]3333EQ@]EIQ@]ffffNQ@̘]uPQ@̔]UQ@^3333[XQ@̸^ffffZQ@3333+^HdQ@3333T3333]J@h-T̴J@HTXJ@ffffvUT̴J@ffff:vTؗJ@yT1J@3333|TJ@3333T3333cJ@ffffRTXJ@3333uT̜zJ@3333VTffffmJ@ffff.FT3333cJ@@T\aJ@Y3T3333]J@.Tffff_J@h-TdJ@x-TqjJ@33330T,vJ@9TJ@HTXJ@RP@|YR3333Q@`eR3333Q@]xR3333gQ@ RQ@HR3333Q@8R3333KQ@ЮR3333Q@Rffff.Q@ffffR3333P@ffffnRP@ffffRP@ĞR3333P@R̈P@3333RP@ffffgRffff*P@3333ZRP@|YRP@3333YRpS@WrS@WrS@ffff& XmS@t XlS@ffffNX3333 kS@X3333[hS@3333X fS@3333X8`S@,W^S@,WY^S@uW\S@3333_oW3333]S@bW]S@@aW\^S@̴UWLhS@YffffnR@3333YffffbfR@3333[GYffff"fR@ffffTY3333dR@ffff]Yffff*bR@ffff.aYffffR`R@|aY _R@ffff^Ÿ\R@3333\Y̔[R@33338Y3333QR@3333W0YffffQR@%Y,SR@3333Yffff6TR@ffffnYffffVR@ffffYffffUR@`YTOR@3333XMR@XLR@IYffffMR@tYLPR@ffffYPR@Y3333KPR@PYNR@T"YLR@ffff6#YffffzJR@ffff"YHR@ffffY3333GR@fffffY8HR@3333Y3333GR@Y3333FR@ffff YffffCR@0Y=R@YffffzR@3333SY3333>R@3333SY33333R@Y1R@ffffYx1R@X9Yu.R@3333EYffff-R@|QY0.R@pVY3333/R@[Y4R@ffffbY8R@gY8:R@ffffJpY3333WR@3333wuY3333'AR@ {YCR@AYyDR@ffffYffffDR@3333YffffDR@ffff>Y`@R@DY>R@8YffffJ:R@Y5R@̬Y33332R@\Y0R@ Y3333 .R@ffffY&R@P~YR@ffff2zYffffR@ffffNuY1R@|sY̤R@qYR@TnY3333'R@_YR@eTYR@3333 PYR@XMYIR@EYR@AY̠R@>Yq R@ffff63Y3333 R@<-Yffff R@ &Y R@Y3333?R@YffffVQ@XffffvQ@ffff6X3333Q@X̨Q@̬Xffff&Q@PXffffQ@ffffXQ@ffffXQ@X̌Q@ffff*X3333Q@lXUQ@LXTQ@3333cX3333SQ@ffffX33337Q@3333+X̘Q@XpQ@ЎXQ@ffffX3333Q@]X|Q@ffffXQ@3333X̌Q@ffffXffff>Q@3333_X0Q@ffffXeQ@3333XQ@3333+X3333Q@|XQ@3333XeQ@DeXLQ@̄]X3333Q@8NXffffQ@xGXffff~Q@AXQ@3333TJP@3333TKP@ffffnUMP@3333UOP@̄ Uffff>TP@ ÙWP@ffff U3333W]P@X$U3333{]P@33333'U̠\P@\1USP@5U`PP@8U3333OP@3333:UPP@ffffCUffff[P@3333[OŲ`P@OUaP@|NUbP@3333WHUeP@ffffFUffffgP@XHUXlP@3333GKUoP@ffffnOUrP@P\UvP@ffff_U̔yP@yaUzP@cU3333zP@lUxP@tUffff>uP@}UffffmP@UffffhP@ffffƄUffff*bP@3333OU̴ZP@ Ų@P@U]9P@Ud*P@Uffff6$P@ffffU0 P@UP@U<P@$U P@ffff"UffffP@UffffP@ULP@̴UO@ffff2U3333O@(U̔O@ffff~#U̬O@e UO@UO@U3333O@3333UO@ UffffO@ffffjUffffvO@TO@XTO@T3333{O@ffff~TP@YTP@3333TYP@tT4 P@T P@3333+T- P@T P@yTffffP@3333+T|P@T3333P@3333TO@TffffO@YTffffFO@33333TxO@XTxO@3333}T O@ffffWTO@KTٽO@BTO@3333@T4O@ffff=TyO@-TffffVO@ffffB Tffff>O@TTO@TffffO@ffffTtO@*T3333cO@PSSP@RffffQ@'ARQ@tRffffQ@RDQ@ffffSQ@3333 S3333Q@3333SSeQ@!&SffffQ@ ,SHQ@`/SQ@ffffvR@3333kSffff9R@SE7R@ffffSffff4R@Sa0R@pSffff~0R@ffffSffffb1R@uS6R@Sp8R@uSe9R@ffff@S6R@ffffS4R@̼ S5R@ffffSe8R@̤Sd:R@ffffVSd=R@S?R@S3333/ER@1SffffnFR@3333WSGR@3333w$S1JR@'SlNR@*SDPR@ffff0S3333SR@3333W@SVR@BSWR@ffffGS\R@8MS_R@tXSXbR@3333S3333siR@ffffVS̜jR@yS iR@3333cS3333iR@3333SlR@ffffT@mR@3333cTpR@'TqR@0T3333pR@4T̔oR@T6T(nR@ffff7TffffjR@6TeR@4T8bR@/T3333^R@`ffff YR@UXh,S@8wXYR@GY3333R@3333PYffffR@ZY3333 R@`fYffffJR@3333W|Y̐R@3333CYR@ffffRYR@!YffffR@HY3333R@̔YR@ffff Y`R@3333ӬYffffR@YR@ffffY3333R@ffff]YR@ZжS@>ZS@P9Z̸S@P4Z3333S@3333/ZܴS@DZ1S@ ZffffZS@33337ZS@ffffvZS@3333YͺS@ffff YŹS@3333 ZS@t Z3333S@3333 ZS@3333ZS@,Y9S@3333#YffffS@Y S@3333YTS@lYtS@UZffffS@Y3333ߧS@ffffY3333S@3333Y̌S@3333Y@S@ Z3333S@.ZS@|4ZffffS@33337:Zffff^S@3333?Z3333/S@?ZS@3333G8ZffffS@ffff0ZS@3333 Z3333ےS@Z3333?S@̔YS@XYtS@ffffήY3333S@ffff2Y!S@iYS@@YS@3333Y`S@ئYffffS@4YS@YS@ffffuY3333S@ffffSYffffŒS@ffffDYhS@I=YUS@4YS@3YS@ffff1Y3333S@0Yffff~S@+Y{S@%Y3333yS@Y3333KuS@-XrS@3333/XtS@X̼uS@ffffXvS@33337X3333#xS@ffffX}S@XS@3333KXS@fffffXS@3333kXS@3333XS@ffffXdS@ffffXffffΔS@1XTS@3333Xffff&S@ffffBX S@3333_X$S@XS@dXܢS@AX S@XPS@ XS@YS@3333YS@:Y3333S@33333HYffffNS@pIYS@3333kGYffffS@(BYffffS@`BYS@EYS@@IYDS@3333#SYܾS@mY S@wYS@P~YS@YtS@)Y̨S@YS@0YS@3333Y̤S@YHS@Y̨S@3333+Y3333S@ffffYYS@Y S@YlS@|Y̼S@ffffΨȲS@Y3333S@3333YS@̄YffffS@DYffffS@DY33333S@5YS@YHS@3333;6Z3333S@XZS@ffff[ZXS@ffff`Z̄S@dZffffS@!eZ3333OS@3333dZ3333S@HbZS@3333SZ S@9ZES@ |1X3333S@ffffBUffffRWT@3QV(CT@̬V̀HT@V3333KT@ W3333OT@hW3333QT@8BW)VT@LUWffffRWT@fffffWpVT@ffff҃W3333[VT@ffffzWffffUT@ffffW3333+UT@W3333+TT@ЎWffffRT@ffffWPT@qW3333kOT@WfffffNT@ffff>yWffffMT@ZWaMT@LRWxKT@OWIT@OW3333?HT@YRW3333kFT@ffffVWffffvET@fffff\WTET@tWFT@؍W̨CT@ffff>W3333AT@W-CT@DW @T@W3333?7T@W5T@̈W33333T@ffffvW0T@)W)T@W'T@ffffցW%T@3333c{W#T@W3333#T@W$T@ W$T@W3333_)T@tW+T@ffffVWffff2,T@Wm.T@3333SW3333.T@X@,T@3333 Xl#T@3333Wffff"T@3333SW\T@$WffffvT@W`T@ffffXT@-XXT@fffffXT@XMT@8X)T@XT@3333XffffT@ X̼T@̤X0T@3333W T@\WT@WT@PWT@ĥW T@ffffΐWx T@|W T@IW T@ئW T@ffff6W3333T@3333cWffffT@WT@ffffVWffffT@4WhT@ W@T@|1X̰T@(XT@&XffffS@3333%XffffS@X=S@ffffWS@W3333S@QW@S@\WffffS@WS@ffffFW3333WS@,WpS@W S@3333oWffffS@ffffBWffffS@YW3333[S@W3333/S@lWS@WS@ WS@3333CWS@ffffWS@WS@%WqS@WffffS@3333/W̠S@3333W3333S@t}WPS@$|W3333S@WS@Wffff*S@W`S@̌WS@̸{W3333S@ffff:cW3333S@`XWS@AWxS@ffff4W3333S@3333C)WS@3333WS@ffffWffffS@TVXS@1VffffS@ffffVS@ffffVPS@#WffffS@+WS@5WffffS@aDWS@3333RWS@|WdS@3333kW̠S@܊WffffBS@ԉWݼS@UW3333sS@ffffyWffffҷS@̈UW3333S@3333;JWS@UMWffff:S@ffffcWS@gW3333#S@ffffhW3333S@TcWLS@XW!S@QWffffS@GWS@=>Wffff:S@3333-W̸S@ffffV3333S@3333{V3333S@WTS@p.W%S@I6WffffrS@3ẀS@h+W3333S@3333{WffffS@V(S@33337VS@ffffºV3333#S@ffffRV3333S@ĘV3333sS@V3333ӋS@VS@ffffVɏS@3333V0S@VS@ȧV3333S@`V-S@VffffS@V S@̠VS@}V̐S@wV4S@iVffffZS@ffffeVS@̤aV33337S@Y_VS@p`VffffS@%gVّS@3333wpVS@V3333S@ffffV%S@`Vffff֦S@VqS@3333G{V̬S@iVffffS@^VS@ FVdS@ffff>V͋S@ffff4VS@2VPS@.VxS@3333)V\S@&VffffS@'V3333S@-VS@ffffv/V`S@d-Vffff&S@)%VS@ffff6V3333ǟS@q V̈S@3333V̤S@3333U3333_S@PU$S@US@33333VdS@ffff^V S@V3333˩S@=VS@$ VS@ VffffS@, VS@| VffffS@̨VffffBS@ffffV3333S@33337UqS@UffffS@EU3333SS@ UffffּS@US@|U(S@33333ÙS@3333UffffS@ffff"US@D1XiW3333wS@ffffcWffffS@SWS@ffffNLWlS@3333EWS@8W S@ffff^-W3333SS@QWffff"R@3333WR@ W-R@ W3333R@XWR@hW3333R@ffff*W3333R@WR@)W3333R@3333OWR@dWffff~R@UW3333+R@ffff"WffffR@WffffR@<W̴R@< WR@ffffWR@3333WffffvR@3333 WR@% WDR@WffffR@ffffVIJR@3333VR@V3333R@$VR@̈V̤R@VR@VPR@̜V3333R@ffffzVtR@PV3333R@UVffffVR@3333+VDR@HV̰R@VĭR@ffff.VR@hV33337R@$VR@3333VR@ffff vVR@cV̀R@\VXR@ffffPVR@LVͨR@LVR@̘LVR@ffffNVծR@HLVR@`GV4R@CV3333ӯR@AAVR@ffff>VpR@3333+V R@̜VpR@3333V3333;R@3333VR@̀VffffR@h"VffffR@#VffffvR@#V3333R@ V3333R@3333VR@`VQR@UffffR@0ЕXsS@3333ǸẄS@C&X3333[vS@̄XwS@X3333xS@ffffWffff*{S@ffffW}S@ffffW!~S@ffffWffff}S@W3333S@3333˻W3333ׄS@W3333φS@8W̸S@3333WeS@ffffW3333gS@$W3333ϐS@3333WS@3333ǸWS@иWffffS@WffffS@3333WS@mW؟S@WS@3333WTS@ffff XS@ffffjXES@3333X3333S@ffffXffffS@lXffffS@ffff%XS@;XS@ffffJX}S@xXX3333S@3333#fXffffS@ffffẌS@3333X}S@IXS@ЕXS@XPS@$XS@܃XS@33333XffffS@XS@3333OX̄S@̤XffffS@PXxS@PX3333˙S@3333oXS@3333+XܔS@3333uXffffʐS@3333ktXffffŽS@̬TXS@AX3333S@uS@]3333AS@I]FS@]HS@ ]hKS@ffff\QS@l\ffffRS@\SS@p\TS@H\@WS@3333]3333{]S@ffff^ ]ffffaS@4]bS@ ] cS@u5]aS@ffff<]3333?`S@3333B]]S@B]\S@A][S@ffff 1]|YS@-]PXS@ffff2]ffff.VS@5]3333US@C]MVS@̈I]WS@}M]ffff6US@Q]ffffTS@ffffZ]PTS@T]eXS@3333{]3333KUS@]ffffSS@]3333gOS@3333]ffffRKS@1]ffffDS@ffff ^3333;S@ffff^9S@^33338S@^@4S@^2S@?^@,S@3333F^I*S@ M^'S@c^S@Hg^@S@ffffb^S@3333^3333S@=^ffffS@^ffffS@5^ S@3333ǹ^3333S@ѫ^d S@ffff^ S@3333^3333_ S@^ffff S@^ffffS@^S@^ffff:S@^3333'S@3333ߦ^yS@3333W^S@^̔S@ԥ^ER@^R@^ffffnR@`^mR@̬^ffff*S@ z^9S@3333sl^LS@d[^ffffR@}T^3333R@M^R@\̨S@ffffJ\3333S@3333;W\ffffS@t\< S@3333{\ffffS@ă\3333?S@ffff~\ffff2S@8\]S@h\US@ffff \ S@i\S@ffff"\3333cS@9\ S@\] S@3333\ffffS@)\S@\3333WS@ffff\S@3333;\ffffS@ffff\HS@\)S@ffff\YS@ffff\̈ S@T\x S@Ա\ S@3333\ S@3333+\ffff S@] S@ffffn ]q S@ffff]ffff* S@%]!S@ffff']S@-#]S@ffff&%]uR@*]HR@)]yR@ffffn]R@]3333cR@3333\DR@t\]R@ffff\|R@̄\R@3333\R@]R@ffffV3]aR@@>]ffffR@xB]ffffR@xJ]ER@H]3333R@̜A]3333R@=]ffffvR@ffff2]R@\,R@̀\3333{R@\lR@3333 \ffffR@ffffv\ffffR@]̌R@ ]R@ffff9]R@ffffI]ER@|P]hR@yU]3333OR@X]R@3333`]R@ffffd]R@0f]̸R@hf]3333cR@,d]3333R@ `] R@3333O@]R@33335]ffffR@x]ffffR@ ]̨R@\R@̸\XR@\̜R@\3333R@3333c\ffff*R@̘\R@q\\R@\AR@\R@ \ R@ffff6\3333R@ffff\3333R@I\yR@\R@\R@ffffʖ\R@\ffffR@@\3333R@ffff\R@ffff\DR@t\ffffR@<\3333R@Ȋ\TR@ffff\3333R@3333˄\R@3333k\ffffR@ffff\3333R@~\ffffR@z\R@9x\3333R@e\`R@]\R@1`\3333cR@p\3333R@s\3333R@̜v\R@̴x\R@w\R@ffffv\IR@v\ffff.R@3333r\]R@m\dR@̼U\R@3333<\ffffR@6\R@,3\R@-\ffffR@)\R@ffff6&\R@̘\R@ffffZ\ffffR@̴ \R@\R@[ffffR@[̼R@T[3333;R@̘[3333R@3333[3333gR@$[3333R@ [ffff~R@ffff[,R@5[3333R@3333[ffff>R@0[\R@3333+[ffffR@3333W \R@3333o*\̤R@̀5\pR@T\R@9w\R@ffffz\R@3333\ĭR@ \3333R@3333+\R@3333/\R@ffffu\3333KR@3333j\ffffR@ffff`\ffffR@A\̸R@R@3333Zffff:R@ffffZ3333R@ZR@ffffZ̬R@3333Zffff*R@̸ZffffVR@ffffZffffR@3333S[R@3333ZR@TZ-R@ffffZ(R@)ZffffVR@MZ̴R@ZffffBS@ZS@33333[,S@̤ [yS@ffff[S@[ffffBS@ffff[qS@p[hS@ffff[ S@3333c [ S@ffff[S@3333c [ S@[S@ [3333S@![ffffS@x"[33333 S@3333#[3333S"S@3333+([̌%S@ffff([ffff&S@('[M(S@ [+S@[T-S@3333[4/S@3333[D0S@3333s#[0S@95[4S@IF[3S@ N[2S@ffffU[33330S@ffffR`[D,S@Yw[ffffn!S@ffff~[ffffS@8[3333S@xW R@VpR@ZVR@XV3333ǁR@ffffVрR@@W3333;~R@ffffW3333R@ffffWR@ffff%W3333KR@33331W3333GR@3333JWMR@ffffBZWpR@ffff&cWffffR@33337rW3333R@|WlR@ffffW=R@3333ẀR@ffffNWffffR@̌W3333R@W3333 R@DWu}R@Wffff{R@WffffzR@WfffffxR@ffffWffffsR@3333gW3333mR@WkR@9WjR@WxjR@3333GW3333gjR@W3333kR@WTpR@ffffW3333pR@qWffffnR@WfffflR@LWffffjR@xWhR@3333;WcR@WTR@ffffW%KR@W`GR@ffff.W?R@ffff>W3333C~WQR@wW3333+R@cWR@bWR@,bW3333R@bW"R@dW#R@PqW*R@zW-R@W/R@ffffWq0R@eW<3R@UWQ3R@W3333-R@W.R@Wffff>0R@V3333[6R@tV:R@ffffVAR@ffffjVMIR@ffffBVxLR@3333VMR@pVOR@3333V7Q@X@7Q@ffffX8Q@X33339Q@X3333:Q@ffffX;Q@3333X̬;Q@3333?X3333:Q@3333GX49Q@XQ7Q@X5Q@XE4Q@3333 X`3Q@Xffff3Q@3333X`4Q@ Xffff5Q@X33335Q@ffffX3333+5Q@ffffX̨3Q@yXfffff1Q@ffffX/Q@3333 XQ/Q@xX +Q@3333mX3333(Q@5^X"Q@PXffff!Q@@Xy"Q@3333S&Xffff~Q@3333X Q@ X Q@X&Q@AW$(Q@ffffVW3333+Q@W/Q@3333OWffff/Q@W3333/Q@W1Q@W3Q@3333#Wffff4Q@3333sWffff7Q@ffffW9Q@W\8Q@xWffffr5Q@H]iQ@ffff[WR@ffff[ffff>R@ffff[>R@ffff[3333?R@[ffff?R@3333K[ffff@R@3333[3333sR@ffffR\]e=R@iP]:R@3333Oc]05R@̄](R@]3333+"R@8]=R@͞]3333_R@ffff]̌R@]ffffR@̼]R@3333G]\R@]3333R@]ffff& R@] R@t]3333Q@m]8Q@]pQ@]dQ@ffff6]Q@3333]Q@]Q@P]Q@3333Ǘ]Q@ffffx]ffffNQ@ffffo]ffff2Q@8x]Q@ffff~]Q@ffff~]Q@33333]Q@3333 ]ffffQ@{]Q@3333Kn]Q@3333U]Q@1]mQ@\Q@\ffffQ@3333k\̘Q@3333\Q@JZ$=Q@ffffFZ:Q@ffff$Z7Q@3333sZd:Q@ffffZ3333g;Q@3333OZe7Q@̀YE6Q@3333Y33333Q@ffffbY 5Q@HYffff4Q@ffffnYT5Q@@Y\7Q@ffffBY8Q@ffffY;Q@~YD?Q@3333vŸAQ@3333krY3333wHQ@3333rYKQ@tYMQ@wY3333[OQ@3333yYffffOQ@̌Y3333OQ@3333Y}PQ@YffffQQ@YSQ@HY3333UQ@ffffbYWQ@3333o~Y ZQ@3333~Y4[Q@Y]Q@̰Yffff6_Q@Y|^Q@Yffff[Q@Yffff*XQ@̔YUQ@YMQ@YMQ@ffff6YffffOQ@YffffWQ@ Yffff[Q@!Y1^Q@Y_Q@̄Y3333^Q@Y3333_Q@YadQ@Y!gQ@Y3333?iQ@3333Y3333jQ@ffffYkQ@hY(kQ@Y3333fQ@ݺY3333#dQ@3333YffffcQ@YLcQ@ffff YdQ@ffffYeQ@3333;Y3333gQ@Yffff:jQ@,YLlQ@3333#YffffmQ@̀YffffpQ@3333GYtQ@3333Y3333uQ@Y$vQ@DYfffftQ@ffffwYY3333kQ@;YmQ@33339Y3333sQ@ffff.:Y̠wQ@3333K>Y3333Q@3333BY3333Q@3333EY3333Q@IYffffrQ@ffffNOYQ@ffffcYQ@̔gYQ@hYQ@iY3333Q@HkY3333ϑQ@nYTQ@3333{YffffQ@YYffff>Q@YffffrQ@̴YQ@YfffffQ@,YQ@3333Y̔Q@LY3333Q@Y3333Q@TY̨Q@3333[Y3333Q@Y̐Q@YQ@ffffY3333Q@Y3333Q@iY`Q@3333YffffQ@Y3333ϰQ@ Z3333WQ@ffff ZQ@t$Z̨Q@ $ZyQ@,ZQ@Z8Q@ZffffQ@ZtQ@3333_ZffffQ@ffffZ0Q@ZQ@3333ZQ@,!ZQ@ffff1ZffffQ@3ZQ@ffff68ZQ@3333NZ̐R@OZ3333R@3333 SZffff#R@3333TZ̠(R@̰VZ*R@3333OZZ\-R@ffff[Zffffb/R@XZZ0R@ZZt2R@_ZU6R@ffffgZ\;R@3333tZffff@R@9ZffffDR@3333۞ZffffLR@ZQR@ټZffffQR@Z3333OR@3333ZffffLR@3333CZLLR@3333ZtRR@Z3333UR@[QVR@̸[pSR@[ffffRR@,Z3333NR@ffffZMR@3333Z3333;MR@ffff[ffffLR@ [3333KR@1[IR@3333?[FR@Z)R@Z%R@Z#R@ffffZffffN!R@ffff:ZhR@ffffZR@ZffffVR@3333Z<R@Zffff^R@̈Zffff R@ffffZ3333R@ZffffBQ@ffffZQ@3333oZffffQ@̤ZQ@3333ZtQ@4ZffffnQ@ZQ@ffffzZ3333oQ@DZLQ@Z3333Q@8ZQ@T[\Q@ffffB [Q@ [ffffRQ@3333w [3333Q@̰[Q@ [R@3333?$[3333OR@,([ffff^R@̰,[R@Q0[D#R@3[ffffR$R@<[M%R@̤?[$&R@?[(R@ffff=[)R@1?[ffff*R@B[+R@G[}.R@3333V[ffff1R@^[3R@ g[3333 8R@ffff[ffff>R@v_Q@$\3333R@^̴R@^R@3333,_HR@e-_R@H)_ffffzR@3333C(_HR@ffff$_R@_ffff}R@A _ffffyR@ffff_3333vR@^3333tR@3333^ffffBrR@ffff^)qR@ffff_3333;iR@ffffN_aR@ffff&_ZR@&_ffffOR@3333g)_MR@u3_3333 HR@5_DR@3333K4_3333CR@!/_tAR@,)_ffff6AR@ffff%_3333W@R@ffff~$_3333G?R@#_3333=R@($_l7R@3333>_5R@ffff@_ 4R@@_33331R@@_.R@3333A_D)R@0A_|'R@?_ffff&R@,?_%R@ffff~D_M#R@J_ffffr!R@S_R@3333X_ R@ \_tR@3333`_R@d_ffffR@%h_3333OR@di_3333#R@h_u R@8g_ffffR R@\e_3333 R@ffffp_R@0q_DR@p_ffffNR@ffff"q_xR@r_R@v_ffffQ@u_Q@q_ffff~Q@R_ffffFQ@̼M_3333Q@ffffH_Q@33330_3333sQ@3333_3333[Q@ffff^ffffQ@3333[^3333Q@3333^3333Q@3333^Q@,^Q@$^Q@ffffz^ffffQ@3333^Q@^Q@^LL@3333oS3333LL@ffffSffffF;L@S3333+0L@ S3333c#L@TSL@3333SS L@xS3333L@SL@3333{S3333 (L@ffffSffffF9L@S3333AL@ffffSffffDL@ffff^SffffEL@3333SBL@ffffS:L@3333S3L@ffffS3333)L@ffff*S3333KL@S̜L@ TffffNK@3333T̜K@33333S1K@Sffff~K@SdK@!S3333{L@SffffnL@̨SL@ffffS L@SDK@`ffffS`L@SnL@ ffffSiL@dSlcL@3333?S`L@|S$cL@pS3333shL@S3333kL@3333SnL@3333{SnL@ffffSiL@SL@SL@̜SL@SffffL@3333SL@S3333 L@ffffS3333cL@ffffSL@$S3333L@SffffL@lS3333SL@8SDL@S3333ӽL@SL@̰S3333kL@̜SL@TffffL@ffffS;L@3333S)L@|Sy1L@ffffS;L@ffffS3333:L@S̴3L@ffffS10L@S10L@S/L@3333S,L@3333ST(L@T$L@T`L@TffffL@̐SL@3333S)L@h3333Tffff~M@ TM@ ffff"T3333KM@3333T M@MTffff~M@AT3333M@dŤM@3333 T|M@ T̼M@p TM@lTffffM@ffff"T3333KM@`̼T3333J@ SffffJ@ ffff.TffffJ@̼TJ@XT3333{J@̄T J@3333CT٣J@S3333J@ SffffJ@3333_SffffJ@ffff.TffffJ@` TffffM@3333S@M@ ffffS3333M@3333S33333M@,S@M@ffffTaM@ffffZT M@ffffTffff^M@ TffffM@TM@ffffS3333M@XSiRL@SR@LX}R@33333X̰|R@ffffX3333?{R@XLzR@XffffNyR@ffffXffffFxR@3333Xffff*wR@TXsR@}V$PQ@ffffZV[Q@ffffZVffffVQ@ɌVffffZQ@̠V[Q@ffff.V3333ZQ@̜Vp[Q@$V3333ZQ@ VXQ@}VWQ@V UQ@LVffffPQ@3333#V$PQ@VPQ@3333V3333wQQ@ffffZVffffVQ@aV3333gMQ@VffffWQ@aVffffWQ@3333kVffffWQ@3333VffffVQ@V̀UQ@aVRQ@V`RQ@3333V3333PQ@ V3333PQ@3333äV3333gMQ@ffffVffff&NQ@VOQ@ffffVffffRQ@̌VffffTQ@aVffffWQ@R NO@ffff>R]O@ DRYO@3333Rffff\O@R]O@R\O@R3333;[O@R3333UO@9R̜OO@mR NO@3333R(OO@ffff>R3333kQO@3333R3333TO@RWO@DRYO@R3333Q@ffffŘ,Q@ffffR3333OQ@iR̤Q@R3333"Q@Rffffr)Q@Rffff+Q@Ř,Q@dR,Q@̰R(Q@3333[R3333%Q@R5#Q@R!Q@R]Q@RQ@eR3333Q@`RPQ@RlQ@3333cR8Q@ffffRtQ@R3333Q@ffff.R4Q@ffffR3333OQ@`ffffҪS3333[N@xShN@ 3333+S3333bN@ffffҪS̜]N@3333ϪS3333[N@ffffSA]N@ffff֗S`N@ؑSffffVdN@xShN@ffffSpgN@3333+S3333bN@`3333/Sffff Q@ffffSQ@ ffffStQ@3333/SQ@3333#S Q@Sffff Q@S3333W Q@ffffS)Q@̘SQ@3333SQ@ffffStQ@`XWS(O@)SLO@ )StO@33330S3333kO@ffffHSLO@XWSffffNO@CSO@;S3333O@33332S(O@]+SlO@)StO@33337=P1O@P̄GO@3333PDO@3333 PFO@p(P$FO@4P̄GO@ffffR6P3333EO@d6PACO@33334P3333@O@ffff5P@?O@;P>O@33337=P3333:O@9P5O@ffff5P4O@3333*P1O@"P2O@̜P|5O@P3333c>O@3333PDO@xoOP@23332O)P@ PO3333SP@2333 UO|P@`O4P@̜iOP@oOP@gOP@O3333P@23332OiP@Y5OP@ KN@3333Qffff>KN@ QGN@ffffQP:N@ffffQ(.N@3333QI(N@`Q̄ N@ffffQN@ffffQffffN@Qffff&N@3333P+N@P!2N@hP9N@ffff>P>N@ffffPEN@P3333IN@3333Qffff>KN@ffffQ̼EO@4QapO@yQ9UO@TQ]O@(QLgO@ffffjQkO@Q3333nO@QapO@ffffQoO@3333QphO@QffffdO@3333{Q(ZO@ffffQRO@3333QfffffLO@Qffff^IO@Q3333FO@Q̼EO@ffffQPN@@PdN@AP̄N@`DPN@ffff HP3333N@!KP3333N@yMPN@OPN@̼NPN@ffffJPN@U|~Q@U3333cQ@UffffQ@3333UffffQ@3333U|~Q@̰U3333Q@U3333Q@ffffU Q@ffffUQ@33337UĆQ@KUdP@3333&UP@3333IUP@ffff>KU<~P@%KUfffff|P@8IUxP@̸HÜtP@ffff*FUepP@3333DU0oP@;U3333lP@̜7UffffiP@3333#5UUfP@33332U|dP@3333.UdP@3333/+UdP@(ŲfP@3333&UffffjhP@&UffffjP@E,U3333rP@x0UvP@ffff7UA|P@8Uffff6~P@ffff:U3333P@YS@\YS@PYffff S@aYffffS@YffffS@IY3333S@ffffYffffS@ZES@pZ3333 S@ZS@̄ZS@ffffYffffS@@Yffff^S@ffffYR@DYR@ffffYXR@YffffR@Y3333R@$YR@3333cYR@Y3333R@S@YS@3333OYffffS@%YS@HYffffS@3333+YffffS@ffffjY|"S@=Y3333$S@AYx&S@̌Y=&S@MY3333$S@ffffvZQ%S@3333YffffN'S@aY(S@̄Y *S@Z*S@ Z*S@ffff ZX(S@|%Z&S@&Z3333K%S@3333$Zffff"S@i Z3333S@3333Zffff^S@ZffffjS@ffffRZS@8Y3333S@xffffYffffS@3333sY\S@ YS@̤YffffS@ffffYS@XYS@$Y3333׈S@̐YffffS@33337Y3333_S@3333sYffffS@մYS@3333Y\S@ffffJYffffS@YS@3333gYkS@!@Y3333yS@YLlS@0uYkS@3333clY̔lS@ieYmS@3333sYY̨nS@!@Y oS@@AYpS@BYqS@ffff*HYtS@]LY3333uS@TYffffvS@hYyS@ffffzY3333yS@ؐY3333xS@3333Y\xS@-Y3333wS@3333gYuS@3333SYffffJqS@ffff.YnS@YLlS@V4S@qlV̐5S@̸|V̄5S@V̐5S@5V3S@ffffVl2S@VffffF0S@V3333/S@8V3333k*S@ȒVffff%S@Vffff!S@yVS@X~V4S@${Vffff S@}qV3333S@ffff~nVy S@|nVT!S@xqV,"S@sV#S@fffftVffff&S@tV\(S@3333grV33337*S@ffffZmV,S@qlV.S@lV3333o/S@3333knV0S@ffffqV 2S@̸|V̄5S@ffffRAXR@ffffnWR@3333_XffffR@3333w!XffffZR@33336XmR@ffff>X̠R@ffffRAXR@ffff>XhR@:XLR@33336XR@3333C.Xffff^R@t+Xffff:R@ffff'XffffR@3333XR@ XaR@$X3333cR@ffff X3333R@3333XR@WR@ffffnWffffzR@̌X}R@ffffN XDR@ffffXR@lXeR@X]R@3333_XffffR@ffffrWffffR@̐W3333èR@3333WR@DW3333èR@WlR@WPR@ffffrW3333GR@fffffW3333kR@W3333?R@AWdR@ffffWffffR@WXR@̐Wffff:R@WR@W|R@3333WR@\ nS@g\ffffS@ty\̘zS@̔\ffff~S@̔\3333S@\ffffFS@ffffb\S@\3333 S@$\ffffS@3333צ\̔S@ffff~\ffffS@3333\S@\~S@\}S@3333\ffffzS@3333\H@ffffNJ̄H@ JlH@ffffJffffFH@ffff&JH@2333JffffF H@2333[J H@̴J@H@ JffffH@ffffJffffH@J̬%H@2333˪J-H@̌J /H@МJ.H@PJ3333/H@`Jp3H@̴J3333{=H@ffffƄJBH@J3333+IH@Jffff>QH@ffffvJ TH@TJ3333[TH@LJPH@1JIH@AJ3333HH@8J3333KIH@ffffJGH@J3333=H@|JpAH@2333Jffffv?H@PJ9H@ffff&J3333s9H@J33337H@X Kffff1H@ffffKa2H@̬K̜5H@YJffff>H@ffffJ`CH@ffff&JIH@iJSH@YJWH@\J3333YH@lJ3333WH@ffffJtZH@2333J\H@2333J3333^H@2333JHbH@2333JeH@2333+JgH@JDgH@̼ K3333sdH@̤K3333dH@̜JqH@0JtvH@ffffJffffyH@J(H@JH@JH@fffffJ3333H@JH@JСH@IJ3333+H@2333JQH@dJH@ffffJffffH@"K3333H@2333(KIH@ffff-K H@1K1H@`9K3333+H@2333S;KffffH@2333;KDH@̄=K3333H@ffffKG@2333[:K3333G@̜7K,G@3K(G@KffffG@KaG@ffffKffffG@ KffffG@J3333G@IJ̄G@ffffNJ1G@ffff^JffffVG@̼J\G@ffff>JG@9JG@ K G@ffffKffff{G@ffff.KfffffuG@<KpG@KffffVkG@2333 KffffiG@2333 KhG@9KxkG@J@xG@J3333G@JG@tJG@ffffvJG@2333 JffffG@1JG@2333[J3333SG@iJzG@ffff.JqG@J3333WG@ffff~JffffQG@̬J3333kPG@JffffPG@ܰJ[G@YJ3333[G@IJ[G@JffffNYG@YJ3333TG@`JRG@2333JSG@ffffJ33333WG@ffffJ3333\G@{J3333hG@qJ|G@pJ3333kG@ffffqJffffޅG@tJffff6G@WJG@UJ3333#G@2333SJ3333SG@ VJffffG@ p2333#KffffZI@KfffffI@ `KffffcI@2333#Kffff^I@ffffK3333C\I@ffffKZI@2333KffffZI@Kffff\I@|Kffff^I@2333KQcI@KeI@2333{KfffffI@`KffffcI@ nKH@2333DKH@hKH@̬dKH@ffff6_KffffH@ffffZKH@ffffFK`H@2333DK3333[H@2333GKH@23333OKH@ffff]KH@aK3333H@,dK9H@ffffdK̬H@2333hKH@ffff~mK\H@nK̼H@hKH@ XffffKI@KaI@KaI@YKffffI@,K I@ffffK4I@ffffVKI@uG@I0LlG@@1L3333hG@ffffV-LeG@0"L3333SkG@2333 L4nG@%L0sG@ffffN(LzG@x)K G@hK3333G@ ̌K̴G@2333KG@ffffK3333cG@2333KffffG@!K3333G@(K!G@)KBQ@ffff~YffffJ=Q@Y?Q@ffff~YAQ@L!Yffff>BQ@0$Y3333AQ@p&Yffff@Q@$'Y3333_?Q@3333K&Y>Q@d&Y3333?Q@3333'Yffff=Q@̨X@Q@\YCQ@3333CYffffEQ@̨Yffff"GQ@ YIHQ@i+Yffff6Q@YffffQ@̌YQ@YffffQ@YQ@m"YffffʪQ@̨(YffffQ@i+Y3333[Q@3333*Y(Q@t)Yffff Q@̸'YQ@ffffb"YQ@3333Yffff6Q@Y3333Q@YQ@Y3333Q@̌YQ@ffffW|UQ@`W hQ@ WYQ@0W3333WQ@ffff.W3333VQ@WffffvXQ@W\Q@W_Q@ffffVW̘bQ@̘W3333cQ@3333WcQ@W3333obQ@3333W`Q@̜W\Q@WffffYQ@WffffXQ@ffffWffff>VQ@W|UQ@ffffWffff~UQ@ffffWhVQ@3333W8XQ@WZQ@tW3333W^Q@`Wl`Q@WffffdQ@3333WfQ@9WgQ@ffffW hQ@ WfQ@3333WffffJdQ@W̐`Q@ffffW3333^Q@ffffW[Q@WYQ@VYXQ@ffff @YffffdQ@3333KFYbQ@OY̴dQ@ffffTYffffdQ@|VYffffcQ@VYffffbQ@UYaQ@ffffNYffff_Q@DMY^Q@MY̠]Q@3333RY=\Q@ QY[Q@̼PYZQ@3333/QY3333XQ@9PYXQ@JYiYQ@ HYffffZQ@3333EY`\Q@%CYffff>]Q@ffff @Y]Q@ffffAY_Q@3333KFYbQ@̸Yp%Q@3333/nY33334Q@3333ۀY33334Q@ffff„Y1Q@ЉYd/Q@PYH-Q@̸Y+Q@ Yy*Q@t|Y̔&Q@xYp%Q@3333#vYffff%Q@rYffff(Q@nY̼)Q@3333/nYX.Q@nY80Q@̘pY33331Q@uYffff"3Q@3333ۀY33334Q@ICZQ@0Z<%Q@3333&Z#Q@3333,Z$Q@:Z<%Q@?Z$Q@ICZ3333#Q@BZ"Q@ffff=ZxQ@x6Z Q@,ZQ@$&ZQ@ffff"ZffffQ@AZQ@0ZQ@3333sZ Q@33337Z9 Q@3333&Z#Q@ffff []P@ZP@ ZP@Z]P@3333Z3333P@Z3333P@ffffZP@ffffZffff~P@QZffffP@dZ(P@ffffjZP@ffff"[P@)[ffff:P@[\P@ [ffffP@ffff [|P@[̤P@@[3333kP@ ZP@pK[ffff>P@̴8[3333P@ >[P@3333sC[33333P@ffffJ[3333P@K[fffffP@ffffVJ[P@(F[3333#P@:[ffff>P@49[3333P@̴8[P@33337:[3333P@>[P@`3333[ffffP@ZTP@ iZffffP@ffffJZ̷P@UZ3333P@ZP@ffffZ3333ӿP@3333[TP@ffff[P@ZP@iZffffP@Pffff_[4P@ffffT[EQ@ffff^[EQ@ffff_[ffffQ@W[4P@ffffT[ffffjP@̴T[ffffQ@ffffU[3333Q@ffff^[EQ@xNL@IzNffffL@ ffff6N3333L@ NffffL@2333+Nffff&L@ffffN3333c L@Nffff.L@|N L@N3333+L@}NL@2333KNL@IzN3333K L@2333{Nffff L@ffff6N3333L@xpOAL@N(L@ NL@N3333L@O`L@pO4L@NiL@2333N3333L@NAL@2333kN1L@ffff.NL@ffffN(L@PN\L@NL@̔VQzM@ffffIQ̴M@}LQ̴M@hSQ3333M@ffffUQ̄M@SQ3333M@ffff>TQ̴M@̔VQzM@,UQffff{M@3333OSQ}M@ffff"NQ{M@ffff>JQffff&M@ffffIQ3333#M@KQffffNM@3333gLQM@}LQ̴M@6@1N@`j6@t/N@hfffFN6@AN@P6@ffff"N@`j6@&N@Z6@̌-N@@M6@|,N@8333,6@t/N@9 6@̌-N@83336@ffffN(N@6@ffff$N@#6@!N@hfff&06@ffffNN@56@ffff6N@ B6@33333N@L\6@1N@hfffX6@ffffN@hfffFN6@AN@h65@i=N@ls5@3333QN@ 65@3333KMN@̌>5@3333SCN@L5@i=N@y^5@ffff~>N@o5@=N@ls5@CN@ M5@3333;LN@D5@3333QN@hfff95@pON@65@3333KMN@ P5@ffff N@hfffF5@N@hfff5@3333sN@l5@ffffN@5@3333N@̬5@ffff N@L5@N@hfffF5@N@hfff5@3333sN@!x5P &N@ PffffAN@ P7N@"P8N@\)PffffAN@2P3333;AN@5P!@N@\5Pfffff9N@ffff3P4N@ffff:/P0N@#P`)N@HP &N@ P.N@P7N@"`4333{_@ffff~ZA@_@uA@ Ɋ_@33333jA@_@uA@4333{_@ oA@T_@4kA@̄_@3333;dA@`_@3333k[A@)_@ffff~ZA@_@ffff]A@Ɋ_@33333jA@#aR@̽R@@333hfffR@ ̄R@@3334333R@R@pfffQR@=̔R@pfffYhfffR@pffffxR@@33334333[R@3R@@333 aR@@333 hfffR@VhfffvR@̽R@@3333|R@R@pfff-hfffR@ $`7taY!ffffDpaY! 3333qa83333!raY!sahfff!7ta !3333saY!ffffqahffff!3333Qpa!ffffDpaL!3333qa83333!%`4333c@̌!4333c@hfffd! c@x!c@Lh!ذc@hfffd!4333c@8333si!4333c@u!4333c@8333!̔c@̌!4333c@̌!c@x!&he4@ffff~N@4@ffff N@ 83334@N@y}4@ffff N@m4@ffffN@e4@4N@hfffFi4@3333N@|4@1N@83334@ffff~N@y4@3333+N@4@4N@83334@N@'Xl|5@ N@5@ffffN@8333S5@N@hffff5@ffffN@5@N@l|5@3333;N@hffff5@ N@٠5@ N@5@N@8333S5@N@(h8@L=P@`8@EP@ 98@EP@83338@DP@8@ffffBP@ 8@̠>P@8@L=P@hfff&8@l?P@L8@ffffAP@`8@ffffzBP@y8@ffffCP@98@EP@)`hfff=@3333qQ@ >@yQ@ =@yQ@83333=@3333uQ@hfff=@rQ@hfff&=@3333qQ@hfff=@ffffrQ@ >@uQ@83333=@3333wQ@=@yQ@=@yQ@*X@33332@4N@@̄N@Lr@ИN@@3333L@ЖN@@33332@ffffN@{@4N@@333@3333ӊN@@N@ffff@̄N@Lr@ИN@+hL7@ O@pfff&H @3333CO@ 4 @ffff6O@pfff&H @ffffO@@333E @ffff6O@pfff% @3333CO@fff@3333O@L7@3333O@fffB@IO@@O@pffff @ O@4 @ffff6O@,p @O@@3333!@ffffO@ @dO@@333!@3333 O@@3333!@O@L!@ffffO@!@ffffO@w!@O@@333j!@O@ @̬O@ @O@Y @O@ @dO@-hpfff(@ffffyP@)@ffffP@ (@̈~P@@(@(|P@pfff(@ffffyP@pfff)@yP@@333o)@}P@)@xP@~)@ffffP@pfffH)@P@)@3333P@(@̈~P@.p(@XP@>)@yP@ >)@ffffևP@=)@3333cP@ )@yP@@3333(@3333׋P@̌(@3333P@(@هP@(@3333+P@(@XP@(@ĂP@')@ffffP@>)@ffffևP@/Y3@aQ@hfff4@ffffQ@`3@Q@3@ffffQ@y3@ffffލQ@ 3@ffffQ@Y3@Q@ 3@Q@3@̔Q@hfff&3@ffffQ@hfff3@Q@83333@aQ@hfff4@Q@hfff4@Q@83334@ffff:Q@3@Q@83333@Q@`3@Q@05@ffffQ@hfffp7@Q@6@3333Q@83336@3333ǣQ@@6@̨Q@6@lQ@6@̴Q@8333s7@Q@ N7@0Q@c7@@Q@k7@4Q@hfffp7@5Q@hfffFe7@Q@G7@Q@hffff47@0Q@̬6@̀Q@̬6@ffffQ@6@ffffQ@hfffk6@3333Q@̬Y6@3333Q@̌;6@ffffQ@hfff+6@Q@5@ffffQ@hfffF6@@Q@83333+6@Q@8333[6@ffffQ@hfffn6@ffffQ@6@Q@6@3333Q@18333g4@ffffQ@hfff4@ffffƎQ@ hfff4@ffff&Q@94@ Q@hfff4@ffffƎQ@hfff&~4@3333Q@hffffi4@Q@8333g4@Q@v4@ffffQ@4@-Q@4@ffffQ@4@ffffQ@̬4@AQ@y4@ffffQ@hfff4@ffff&Q@2P9@3333 Q@%:@Q@9@hQ@@":@3333Q@%:@3333Q@:@3333Q@9@ffffQ@9@Q@9@Q@hffffl9@*@̐Q@ Y)@Q@)@̼P@pfff)@3333P@̌)@P@@3333&*@P@L2*@ffff6P@ 2*@,Q@pfff>*@)Q@"*@̐Q@Y)@Q@7Xy0@@Q@hfff2@(fQ@( 2@Q`Q@l1@l`Q@1@bQ@1@dQ@hffff1@ffffcQ@̌1@bQ@hfffƀ1@(fQ@|1@3333eQ@̬{1@udQ@ t1@ffffaQ@hfff[1@̼aQ@@1@ffff>`Q@:1@ffff^Q@_1@ffff\Q@e1@3333ZQ@`\1@ffffjXQ@@1@ffffYQ@8333s1@)WQ@833330@$UQ@`0@8RQ@`0@33333LQ@hfff0@3333HQ@83330@0GQ@0@ffffFQ@y0@ffffDQ@0@pDQ@1@BQ@ 1@@Q@83333)1@̨AQ@R1@ffffRHQ@hfff|1@̘LQ@8333s1@DJQ@hfff1@ffffKQ@`1@ffffLQ@83331@ffffQQ@,1@ UQ@hffff2@`VQ@hfff2@TYQ@` 2@H]Q@ 2@Q`Q@82@EbQ@3@ffff֏Q@-3@Q@hfff&r3@ffffjQ@l3@Q@X3@ĀQ@LA3@@Q@?3@mQ@8333s63@ffff֏Q@!3@Q@`3@Q@ 3@ffffQ@,3@|Q@ 3@lQ@2@Q@2@̬Q@hfff2@ffffr}Q@2@yQ@̌2@PwQ@̬2@fffftQ@̌2@ffffrQ@8333ӟ2@tQ@2@3333sQ@,2@1qQ@h2@rQ@lY2@$qQ@hfffP2@ffffmQ@D2@fffflQ@hffff;2@PkQ@9:2@hQ@`2@ffffhQ@2@̈fQ@@!2@cQ@,F2@EbQ@hfffi2@acQ@hfff2@ffffeQ@2@fffffQ@83332@3333hQ@2@ffff:mQ@3@̜pQ@!3@ffffsQ@8333s23@0sQ@8333U3@3333tQ@@q3@3333#zQ@3@3333~Q@3@9Q@3@Q@9@333,@h Q@ 0@TSQ@=0.@@Q@@333+-@3333Q@pfff&,@Q@@333,@qQ@ك,@5 Q@@333,@h Q@B-@ Q@̌-@3333Q@L.@Q@@33332.@ffffQ@@3333`.@Q@@3333.@Q@̌.@4Q@̮.@Q@.@Q@@333s]/@Q@/@ffff.Q@/@-Q@پ/@3333;Q@@3333/@Q@Y/@ffffQ@hffff 0@̬Q@hfff10@ffffv"Q@hfffV0@X$Q@0@3333(Q@ 0@-Q@z0@3333c3Q@l0@5Q@83333T0@8Q@̌F0@ffff7Q@@:0@6Q@̌&0@5Q@0@(3Q@ 0@/Q@hfff0@ffff-Q@@0@+Q@@3333/@)Q@@333s/@x#Q@L/@3333#Q@ٔ/@}'Q@/@.Q@/@m4Q@/@$:Q@pfff/@|=Q@/@̌AQ@@/@5GQ@hffff0@MQ@hfff&!0@QQ@L 0@TSQ@@/@TSQ@ /@QQ@pfff{/@JQ@̌L/@|HQ@L.@BQ@.@̠>Q@pfff&.@:Q@/@d:Q@pfff /@33337Q@.@ffff3Q@@.@i'Q@0.@@Q@:@3333,@ffff&Q@ .@3333@Q@pfff&4.@3333@Q@Y.@@Q@@3333.@<9Q@pfff-@|:Q@ -@33338Q@-@ffff>6Q@̌-@33332Q@s-@43Q@a-@$4Q@-@h4Q@L,@fffff1Q@@3333,@-Q@@3333,@ffffr*Q@pfff -@(Q@pffff9-@ffff(Q@pfff|-@3333W+Q@pfff&-@*Q@pfff-@(Q@-@ffff'Q@ .@ffff&Q@@333q.@q'Q@pffff.@+Q@ .@ffff&2Q@pfff.@ffff5Q@ j.@\Q@A.@@@Q@pfff&4.@3333@Q@;hz%@ffff5P@ ~&@3333>P@ pfffC&@y>P@ &@3333>P@%@ffff;P@z%@33337P@@%@5P@ &@7P@pfff[&@ffff5P@v&@ffffj7P@ ~&@3333:P@pfffC&@y>P@<pffff@)N@@3333[@9N@ @$N@fff@PN@@3333[@)N@fffW@ffff^'N@ffff3@1N@ffff@9N@@3333@@9N@ffff@ffff4N@@3333+N@@3333@ffff"N@@$N@=`'@ fP@pfff(@-mP@ '@fffflP@@3333'@-mP@̙'@kP@'@ahP@'@̰fP@'@ fP@'@hP@pfff(@|kP@'@fffflP@>S3333R@3333SffffV S@iSS@3333oSS@HSUR@S3333R@SffffR@S3333R@3333S1R@ffffS̨R@PS|R@ SAR@S R@ffffS̠S@3333SS@ASffffS@̘SffffV S@iSS@?̬R@TS@Q]S@3333R]S@3333Rffff]S@ffffR̤\S@TR[S@̬R̬XS@ffffR3333VS@R@TS@QTS@QffffVS@Q=YS@ffffVQ3333YS@Q[S@Qp]S@3333R]S@@G9T@_FLT@3GLT@4333dG3333T@٢G3333 T@GYT@\G3333#T@dfff>`GHT@̜GőT@ѾF3333T@F9T@nFffffZT@`cF3333T@_FT@puFT@FffffT@3GLT@ApL3tT@,2ffffT@ `fffP3ffffT@`fff~3xT@L3T@03pT@^3̴zT@ 3tT@`fff2tT@,2,vT@ 2|T@ 3%T@`fffP3ffffT@Bp`ffff#3̄S@̜f1T@ , 2̄S@̜13333S@̜f10S@̬x1ffffT@1T@ 2T@`fffF20S@`ffff#3̌S@L3xS@y2S@, 2̄S@CxP3|S@2MM̨R@ffff#Mffff6R@MmR@ffff0M3333+R@2333BMR@TMR@2333pMR@qMR@ffffMhR@M3333R@M\R@NffffR@2333oN8S@Nffff S@N̄ S@xN S@` OffffS@2333?O3333S@ffff_O3333#S@fffffiO̼S@ffffOlS@IOS@,OS@̜OS@O S@O3333_ S@3333PS@HPiS@ffffPAS@PtS@3333"Pffff2S@3333K,P3333 S@]:Pffff S@EPffff S@ TPffff^ S@̬WP3333[S@<]P3333OS@dP3333; S@3333kP S@DrP S@ xP@S@3333}PxS@PffffS@3333'P S@3333ϝPS@hP3333W S@S@ffffnlQ3333S?S@]Q6S@ffff>Q3S@=Q̘4S@Q33336S@Q33337S@Q`9S@\Q:S@Qt;S@ffffQ?S@ QAS@QffffDS@̌QffffGS@QQIS@8Qffff:KS@3333QhLS@jQNS@̜>QLS@ffff/Q̤SS@%QUS@̬Q3333KXS@3333PffffXS@P3333OWS@3333+PffffUS@PQS@3333×P SS@ffffP3333cVS@3333P(YS@єP3333]S@ P`S@̜P dS@̀P3333ggS@Q3333_S@EQ4^S@3333LQ̠]S@|VQ]S@3333~Q cS@QXeS@ffffQhS@3333_Q3333/lS@DQlS@ffffQffffmS@XQffffsS@33337Q5uS@3333SQuS@dQuS@DQ33333sS@3333QrS@3333Q̨rS@ffffbQffff tS@3333Q@uS@3333QffffxS@QffffyS@(R{S@% Rffff>}S@3333R3333cS@ffff%RtS@2RS@3333[4RpS@4%RܑS@ffff$RffffS@ +RuS@3333-R0S@̀+RffffS@=RٞS@QR3333GS@R`S@3333QS@QS@DQ S@QܨS@3333CQS@ffffQ3333+S@ffffQdS@ffffN~QűS@̔?QS@3333;QyS@!;QqS@@Q3333S@AQXS@5QS@!QlS@ffffRQffff6S@3333PXS@LP$S@P3333{S@̰PS@\PS@PffffS@ffff҄P̐S@}PxS@tPffffS@3333cPS@3333ZPffffS@3333kRPS@|GPffffS@P?Pffff*S@9PfffffS@5P3333S@̴2Pffff T@y(P̘T@ffffPffffT@3333w PffffZT@3333# P,T@ffffP̌T@(P T@3333"P3333T@ffff/P3333T@>P3333GT@33337NPT@ffffFYPT@3333kcPffffT@ffffsPffffT@~P3333T@PT@3333P3333#T@ffffPT@hPT@PT@3333 P3333 T@P8T@\PT@=PT@̼PffffnT@3333 P!T@ԗP3333c%T@3333P(T@ffff}P̈)T@3333CsP8*T@3333KiP+T@VPffff1T@ffffCPffff5T@3333g,P3333=T@ffff P@T@ffffO̜CT@iO3333CT@OBT@O3333@T@O8T@2333Offff8T@8O TLffffT@=ffff&T@03333333T@0333?̰T@ ?ffffvT@0@T@hfff6?T@?3333wT@0333b>3333T@̬=ffffT@,=3333T@hfff&<T@;T@hfff;LT@ $:,T@`fff933337T@\80T@`ffffx83333'T@0333s,83333'T@`ffff7T@0333c7ffffT@0333ӱ7lT@,h7T@`6T@p5٭T@5ffffT@ 5ffffT@I53333T@03335 T@0333s5ffffT@x63333T@97ȔT@73333_T@0333S=PT@0333=fffffT@,=ffffT@̜=ffff&}T@9=(|T@`<̼T@; T@0333 ;3333T@&9ffffT@0333Ӗ8xT@`fffK8lT@03337ffffzoT@03337yqT@d7tT@O7̨xT@?7|T@ .73333ST@̌7T@6T@96dT@`fffV5̄T@`fffV5eT@*53333~T@\!5ffff{T@033335wT@5ffffrT@`fff%5}lT@0333;5|fT@5\T@@5IVT@03335,RT@Pj6ffffHT@6DFT@̌73333O;T@`fffF273333;6T@0333#4733332T@0333#71T@ 6L5T@@67T@`6h:T@033363333KAT@l5ffff6CT@0333#s53333gKT@`fffv$5yNT@`fff4QT@4ST@`fff4ffffdT@0333C3hT@93ffffhT@)'3`T@٪2_T@t2ffff_T@,2]T@)1<\T@`fffv13333g[T@t1tYT@91[T@`fff(1\T@033303333bT@0hT@`fff[0̨nT@LD0@pT@`fff0qT@0333/ErT@l/YuT@.̐uT@yt.tT@`fff{,fffftT@0333h+rT@y)nT@l(ffffkT@b(3333iT@`fff'ffffdT@l'3333+`T@&ffff^T@&<]T@'3333#[T@0333sv(ffffST@`fff&(NT@@*ffffET@*pBT@̛+0AT@ e,@T@,3333?T@0333,ffffJ>T@0333,ffffr:T@`fffu,7T@z,ffffF5T@,33331T@0333-0T@0333sc.,.T@/)T@/)T@`fffQ0ffff)T@`fff0ffff$T@y0 T@m0T@/ffff^T@/IT@0333*0T@ }0 T@P0 T@1, T@01 T@0333s[1 T@ 1D T@)23333 T@L2@ T@l3T@̼43ffffT@m3ffff~T@ك33333sT@`fff33333C T@ 4 T@p&4T@24ffffS@l.4S@0333s#4ffffjS@4S@0333C3`S@3ffffS@03333XS@9d3S@`Z3S@H3̸S@`fffK3S@̬Z33333OS@9f3AS@0333cn33333{S@i33333SS@0333H3ffffS@033393S@`fff&33333S@`3ffffS@`fff3S@`fff23333S@03332ffffjS@03S@ C33333S@3)S@03333S@Y3ffffS@03333ffffbS@ 3LS@33333S@ 4S@,34$S@Le43333 S@`fff43333sS@<"53333'S@`fff6$53333S@̌43333#S@`fff4S@153333OS@̜B5S@O5ffff"S@0333e5S@`fff5ffffzS@`fff5pyS@`5rS@`fffƺ5XmS@033335iS@03333a5̤lS@0333!58vS@03334\zS@0333c43333yS@Q4ffff*wS@33333ksS@l3qS@̌}3ffffnS@d3ffffjkS@L33333gS@K3teS@w3ffff6dS@,33333dS@`fff3jS@|)4ffff&lS@pp4XjS@I4gS@v4̠\S@`;4WS@03333EUS@l3RS@)m3ffffOS@L33333;NS@!3NS@`fffF23333QS@2RS@Pq2PS@V23333MS@J2̀HS@M2ffff@S@`fffVV2:S@0333ce23333 7S@033321S@033320S@03332ffff"1S@`fff252S@0333#24S@`fff(3ffff5S@@37S@l3:S@y4];S@|4ffff:S@,48S@̼4ffff5S@\5ffff,S@5(,S@I5/S@l/6ffff2S@`fffU62S@`fff6.S@63333-S@L6+S@`fffq6(S@`6ffff.'S@|K6ffff~&S@033363333%S@5$S@03335ffffS@5S@|5fffffS@`fffj5S@y/5ffff&S@,4tS@`fff4S@`fffV4YS@`fffvo4S@G4S@`fff4S@`fff3̸S@,3R@3ffffnR@`fff3R@L33333{R@`fffV|3ffff"R@0333z3DR@Pv3R@0333sn3HR@`fffFf3̤R@]33333R@0333`3R@ m3R@3̈R@ 33333R@i3R@`fff33333R@4LR@24R@`fff&|4R@`fff43333 R@`fff5ffffR@?5R@h5%R@95R@l5̌R@̜;6R@`fff63333?R@03335@R@5,R@03335R@54R@0333u5ؿR@#53333cR@03335R@\4ffffR@033343333kR@p4ffffR@0333#4ffffR@4̔R@`fff4 R@03334ffff&R@ 53333ߪR@ 5ݩR@43333R@0333s43333R@ 4ffffR@`fffj4iR@643333;R@0333#3iR@3ffffR@̬3R@`ffffm3uR@yI3R@93R@=3̜R@`fffE3R@P3ffffR@^3-R@|w33333?R@p3ffffR@, 4R@`fffA4R@`fff;4R@033334ffffʈR@0333#!5R@5ffffvR@`fffv5ffffR@5ݖR@5R@0333c54R@̌5QR@5R@03335ffffR@\-6!R@0333SR6\R@`fffU6TR@`fffvC63333oR@033376ffffR@`fff26ffff*R@0333S86R@0333cJ6R@`fff6T6ffff҅R@0333U63333R@0333CE6R@0333"6dR@5$~R@\L5̘}R@5=|R@`fff^4IvR@`fffV4utR@r43333iR@y43333_R@43333]R@lS59]R@I5̠[R@0333s53333VR@`/6EQR@X63333;QR@6(VR@0333;7tYR@`fff7ffffbR@`(8pR@0333W8kR@`fffs89hR@8fR@`8fffffR@8gR@83333iR@9nR@Y9fffftR@0333s9̀vR@9uR@lm9rR@G9UoR@̬8!eR@@8bR@8̸`R@93333_R@̌O9[R@9s9YR@Y9RR@|9QR@0333:1PR@`fff&+:PR@ h:3333TR@hfff:HVR@ :ffffJXR@9E;[R@\+;ffffWR@hfff:3333QR@hfff:3333OR@Y:LLR@hfff:JR@0333:JR@hfff;3333sKR@C;3333KKR@x;ffff:JR@hfffƏ;HR@hfffV;4GR@{;̰ER@i;TDR@Y;3333WDR@̜0;yHR@;HR@0333:GR@n:JR@`fff3:]LR@\:̸LR@`fff&f9ffffQR@D9ffff*WR@9`YR@0333S8[R@`fff!833333ZR@0333#7}YR@7ffffFTR@̬t7̔PR@|>7ffff^LR@63333JR@06`ER@@s6?R@163333=R@L 6:R@03336!.R@63333(R@`fff&6̌R@̼G6R@@=6R@K6ffffR@\6 R@03336TR@@57ffffR@03337 R@`fff7R@̬83333R@[8+R@`fff8:R@`fffF8hBR@83333BR@03338ffff@R@+9̼>R@A9$;R@`9333336R@:2R@̬4:ffff2R@Y:-R@z:ffff^+R@`d:3333+R@5:p,R@̌:4.R@ 93R@[933333R@<95R@88R@`fff68ffff9R@88R@0333c87R@`ffff8H%R@`8h R@@83333KR@`fff 9R@`fff&49ffff&R@,94R@83333R@`fff8R@`fff8R@j8IR@`fff>8R@`fff67 R@L7ffffR@yJ73333/R@̬6ffffQ@`fffV63333Q@6hQ@033336|Q@`fff^6DQ@`fffC6ffff>Q@̬5̨Q@i6Q@O6!Q@ w6Q@0333Ӏ63333Q@0333}6ffff:Q@z6ffffQ@`fffj6ffffQ@`fffY63333Q@̌L63333Q@;6Q@i+6ffffQ@ 5ffffQ@03335̜Q@̬5̘Q@0333ӫ5ffff.Q@̌5Q@`fff5Q@̬5ͶQ@ 53333Q@5ffffʥQ@̅5Q@0333#5Q@5aQ@̼633333Q@`fffVb6Q@pb63333נQ@\f6Q@f6)Q@l6Q@o6ffff Q@̬63333Q@`fff6Q@`fff6,Q@03336ffffQ@а6Q@L6ٜQ@07QQ@S7ܜQ@03337Q@̬7̐Q@`!8̠Q@:8Q@`fffD83333Q@0333`8ffff^Q@8ffffNQ@83333OQ@̌93333_Q@`fffFA93333SQ@ r9(Q@`fff9Q@9ffffQ@ 6:Q@0333C:UQ@;3333[Q@0333S;Q@̌);ffffQ@hffff;3333Q@: Q@hfffs:Q@`fff:Q@̼93333Q@9(Q@ 9ffffQ@`fff93333Q@03339Q@̜:Q@0333S(:8Q@0333s:3333Q@ɷ:ԼQ@<;yQ@U;ffffQ@0333S;̔Q@;Q@MQ@?=3333Q@m=Q@̬=Q@hfffV=Q@=3333Q@hfff >3333gQ@ 2> Q@pQ>3333_ Q@0333S>3333Q@<>eQ@ >d Q@Y>Q@>Q@0333>Q@ +?Q@0333ck?8Q@0333?Q@@ffffQ@)@Q@dfff&(@ffffQ@4333"@ffffQ@@ffffQ@dfff@3333wQ@4333@ffffQ@$$@ffffjQ@4333c-@hQ@.@ffff Q@@3333Q@dfff@3333 Q@@ffffnP@,#@P@L/@3333P@p9@P@u@P@<@xP@؍@ P@@P@̔@ffffP@@UP@@P@@ P@@@3333P@dfff@\P@̔@P@@ffff&P@@ffffNP@4333 AuP@`AP@4333k"AP@$(A̰P@ 6ATP@~P@C3333yP@dfff2C3333~P@4333BCffffP@8CzP@C3333uP@dfffCsP@ČmP@QCgP@4333cCgP@CeP@C̘cP@dfff6DcP@̄DpaP@dfffCWP@C3333UP@dfffClRP@CPPP@CIP@dfffDFP@dffff D CP@4333sUDFP@dfffpD3333?EP@dfffΊDtFP@YD3333CBP@̌D4?P@dfff{D33337P@dfff&jDffff28P@dfffSD̔:P@4333BD4P@4333c7D+P@4333#D$&P@DffffR"P@4333SD3333P@̤#D P@4333#=D3333 P@iYDffffP@WDP@dD1P@dfff~Dffff P@)DffffP@D3333P@dfff^DP@dffffDffffZ P@D3333P@{Dffff P@iD3333g P@4333ODffffnP@SDO@GD̔O@4333sFDO@bDffff&O@9cDffffNO@4333tDO@E3333CN@E3333CM@tEffffM@dfff6EM@dEffffM@EHM@ EaM@F|M@dfff~ FYM@aF`M@4333FYM@l"F3333KM@dffff*F3333kM@1FM@43334FM@4333 :FN@3FN@̜F3333N@4333FHN@F3333#N@dfff,Fffff6N@DFffffN@NF!N@dfffgF3333cN@4333FN@aF%N@4333F̼/N@4333F0N@FffffF5N@4333|Fffff:N@@mFffffDN@_FSN@`FUN@dfffF3333@N@4333CFffff.:N@̴F33338N@F;N@dfffFiBN@F3333[EN@F3333+JN@dfffF3333LN@GNN@4333+GdcN@4333cG3333c|N@̄F3333N@F N@F0N@4333cFN@̜FPN@4333FN@dfff6FN@GdN@%G܂N@̌JG${N@[GsN@ gGffffnN@dfffoGhN@dffff}GiN@4333GgN@G4dN@4333SGqfN@yG3333kN@dfffGylN@dfffGffffiN@4333GjN@G3333kfN@dfffnG`]N@G\N@Hi\N@4333 H_N@$HffffvbN@HffffFgN@4333CHffffmN@dfffGffffyN@GffffN@GN@̴HffffN@4333HN@dfffv1H3333N@dffff0HN@d6HN@dfff6HN@dfffV?H3333ÜN@iGH3333N@pLH3333N@dfffvH3333N@t{HffffN@\~HN@LHffffN@4H3333;N@H3333N@4333sHN@H3333N@4333H3333N@dfff֧HN@H3333N@4333sHTN@̬HN@ H$N@̜H(N@H3333O@4333H O@4333jH33333 O@4333 H O@4333kHiO@Hffff O@4333H3333O@̜HffffNO@HN@dfffH3333+O@yH O@xHPO@HO@dfffH"O@,H̬$O@H)O@I.O@dfffI4O@$I̬;O@(IIffff^ P@4333?IP@:I3333P@7IP@=IffffzP@4333K\I3333KP@AI- P@`IP@IP@YIP@iI5P@dfffIffffP@LI3333 P@4333I P@4333SIP@dfffI̤P@4333I#P@Į$P@ tI3333S$P@dfffjIffff#P@mIy'P@4333lIffffB)P@WI3333g+P@>I\,P@t-I3333+P@l"IX'P@@ITP@dfff&IP@Iy P@dfff I3333o%P@Iffff -P@dfff&I3333?0P@A&I1P@,BIffff1P@dfffRI̜6P@VI33338P@4WI\;P@gIQCP@XmI3333KGP@JyP@ J٠P@2333J]P@ȷJѧP@JP@J,P@̬Jffff>P@ffffJffffP@23333MJ3333P@2333>JhP@97JP@̄1JdP@7JqP@GJffff.P@fffftJffff P@ J3333׺P@J̤P@ȸJ-P@ffffJffffP@Jffff"P@4J̬P@JP@8J3333P@!JffffP@J̔P@ffffJpP@|JP@ffffNUJ3333P@AJ̸P@1Jffff&P@\IffffzP@ Iffff^P@̬IP@9I̼P@IZIP@dfffNIP@QIP@IdP@I3333P@4333IP@qI%P@4333|IP@dfff&I3333WP@,IIP@4333I8P@IP@ffffV JffffP@2333#,JP@EJXP@,VJP@rJ|P@2333c}J3333P@2333JP@2333CJUP@2333J3333#P@HJP@JP@JP@2333JffffP@,JP@ffffJ|Q@fffffJL Q@ffff>Jffff Q@ffffqJ3333 Q@7JffffR Q@|JQ@dfffIQ@dffffIQ@YIQ@dfffnImQ@aI3333' Q@I3333 Q@dI Q@IffffzQ@IQ@dfffI3333Q@dfffIQ@H8hffff@̌0f@,}0f@@04333f@̌0hffff@̬0f@,}0I@f4333+0:~fhfffF 0fhfff&'03333fhfffF 0:~fhfffF 0̘~f43333&0f4333+0JX̀}U4333Sg0@\uU43330@̀}Un0@3333|U4333Sg0@wUdfff&v0@3333 vU|0@\uUɂ0@4xU43330@ffff&{U{0@̀}Un0@KPN9@ܴB@hfffv9@,B@g9@ffffB@u9@9B@hfffv9@LB@ Y9@,B@ P9@B@N9@ܴB@g9@ffffB@LXhfffd@4333d@Q߿ d@Q߿7e@@7e@@i6e@@4e@@4e@Yl@43333e@03333L@2e@`fff&5@NH4333ce@`ffff@4333e@ 3330 @̞e@ 3330 @4333ce@`ffff@e@`ffff@4333e@ @hfffʞe@ 333$ @̞e@ 3330 @OXe@ 333@4333ce@@e@ 333C@hfffe@ 333@e@`fffh@4333+e@m@4333ce@@hfffve@@e@`ffffE@e@ 333C@P`؝e@3333)?e@@ffff? he@Z?4333e@@ffff?4333ge@?e@@ffff?؝e@?hfffe@*?e@3333)?e@?he@Z?Q`ȟe@h?hfffre@? 4e@?e@?e@?4333e@̣?ȟe@h?e@@ffffz?hfffre@@ffff?]e@u?4e@?R e@?Ģe@f? e@5?hfffe@f?hfffe@f?hfffe@?Qe@?Ѡe@ffff?e@ffff?e@3333꿚e@鿚Ye@|e@̴T`e@6e@# e@ffffe@[e@#hfffe@4333e@ffff0e@ffffe@6hfffe@de@ffffUPhfffe@,@e@LX@̼e@LX@hfffe@`fffI@e@6@e@,@e@`ffff<@,e@03333J@̼e@LX@Vhyre@@8xe@`ffff1@ 8xe@@`we@ @0ve@`fff&@ue@L @4333se@Y@re@`fff@yre@`ffff1@se@@@4333ve@0333@8xe@@Wx$ae@`ffffF@le@`fff@ le@q@hfffke@a@ie@S@lhe@`ffffF@ge@`ffffF@yfe@LK@hfffce@`fffo@$ae@ٟ@̜ae@`fff@4333Cce@̌@4333Cge@ Y@le@q@X`ffff8FfY,eAfv, 3333Df83333|,ffffEfv,ffff8Ff̂,3333Ef8333,ffffNCfY,ffff~Af,eAf@,ffff\Cf,3333Df83333|,Y@a,1ffffla4333s1ffffaL13333ahffff1ahfff1a1טa 1ݔa1ffffla433313333˔a4333s13333a 1]a13333al1ffff`a133339a1@a1ahfff1a,1ffffaL1ZPa2g a4333v2 a2g aY2| a43332, a,2̢ aly2a4333v2Pahfffx23333a,|23333 a43333}2@ a2ffff a2 a43332 a2[@)"ahffff\23333aC23333ahffff\2ffffǎW2 aE2)"aC23333ahffff\2\X0Ra940Pal4Qa940Pa4333s4ffffzPa94|Qal40Ra4|Qǎ4Pa4Qa94]Hahfffj2ǎU2ahfffj2ffffa@a2ǎU2ffffa ]2Fa,f2ahfffj2^`3333'ahfff72Sahfff&2 Sahfff72ffffay02a2̚a4333s23333'ahfff&23333ahfff2a%2a22Sahfff72_@ffffal0fǎ0ffffal08a0fǎ0`ahfff0ffffal0`P3333a90[a0[a903333ahfff0a43330a03333a0ffffa̬0[a90aH3333a43330Fa43330Fa0ffffa90ffffra433303333a43330ffffa43330Fa0bP$%bY/̤!b/ffff!bY/̤!bL/F$bhfff&/$%b/j$b/r"b/ffff!bY/cffff3bhfffX0ffffn/bhfffF0 ffffn/bhfffX0̒/blT033330b G0Z1b90w2b(0ffff3bhfffF03b!0~3bL*0fffft2b43333033331bL@0ffffF1b̌K0ffff0bhfffX0ffffn/bhfffX0dp\e@j?e@@ffff3? hfff:e@3333y?\e@j?hfffe@@ffff?hfffe@?e@@ffff3?e@?|e@@ffff?8e@@ffff?4333ge@?e@?hfff:e@3333y?e`ffff8effffnEL@-/eIQL@ 33333e̼NL@*8eIQL@ffff8eML@ffff>4eEL@2effffnEL@-/e LL@̊/eOL@1efffffPL@33333e̼NL@fxffffv=R`3@3333'R4@ ffff~6R4@:R4@ffffv=R4@ffff9R 4@88Rdfff4@6R4333 4@X/R4@3333(R`3@3333'R4@*R 4@2Rdfff4@ffff~6R4@gXl8@ffffB@833338@B@{8@B@8333p8@3333B@l8@B@̌|8@ffffB@hfff8@3333B@833338@ffffvB@8333s8@ffffB@{8@B@hPma@̜:@xa@:@,a@:@hfffa@:@ma@ffff:@pa@̜:@a@2333ӝ:@xa@ffff:@,a@:@iXY`@pB@]`@B@Z`@3333B@Y`@DB@4333#Z`@ffff>B@[`@pB@P]`@ffff>B@]`@ffffB@4333\`@B@Z`@3333B@jOpfLLUf@hfffO fUvLfU5Bf̌U_7f4333KUfhfffU? fhfffUof4333kUe U33331e̴U3333eU8e̜Uffffvehfff"Uffff^e+Ue.Ud4333[5U'dhfffn4Und9Uffff]d̬9UDd$?UffffcKUcLLU3333cKUcEUc>Uffffcd:Uɤc4333 9U3333c8U3333ߓc̼5Uc3Uc43331U33331rdhfff!U3333udhfff UIxdUffff|d4333U3333dUVd4333UTd4333;UdhffffUdhfffU3333dU|dUffff|xdUffff>xďUHzdU3333dUd9 Ud UffffJd0Ud̔U3333dlU\dU3333ďTmd4333T)dlT3333d4333TffffdT3333dTd̜TeT eTe TeT]%eTfeiTBqe Tffffe4333T3333eAŤeȲTFe̜T?e̬T3333ehfffTe(Te1THzeclT3333mGc4333gTffffOc
Vc4333S,ac!SjcIS33337cScɌS3333#c4333S&c|ScxS3333cqS>cYgS\c_S3333c̬VSchfffJS3333chfffEScESffffcNS3333uchfff~OS]cMSffffȋcHSffff†c4333FS3333m}chfffFFS{kcHSAcchfffGSZc HSffff=chfffNS6čQS3333e3cSSffffV2cbhffffDS=b4333AS9bhfff@S"4b =S33335b43338S33335b2S8b/SSEbhfff*SffffXb4333s SjbhfffSRffff\4333R8\hfff.R\hfff־R3333{\hfff־R)p\Rffffe\dR3333E\R \4333CR̐[hfffFR3333[4333R3333g[hfffR3333G[ѩRffffz[hfffR[4333CR9[hfffR3333[4333CRQ[̜R[ٌR[ RD[RffffN[hfff6R,[|R3333[xR̴[4333SRffff:[4333{R3333 [hfffR[R[Rffff[4333R3333[hfff6R\[hfffR3333kQ[R4[9RI[)R̀Z̔R3333ZhRZR3333Z4333R3333YZhfffR9Zhfff^Rffff'ZR8 ZR3333Y4333R1Y4333{R3333YR]Y|RQmYhfff&Rffff.hY1RpSYiR̄BYR4-Y4333{R̨YhfffRLY̴RXhfffRXRffff&X4333KR3333SX̼RX$R3333X4333RffffRXhfffR̸XR3333OXR YhfffRȲR3333KYԷRY4333RY`R3333YhfffR=YR!YIRp8YR3333{AYQRPYhfffRUYhŘeY4333+RmȲRffffY4333K}Rffff6Y@{R YxR33337Yhfff&rR3333+Y4333SiRHY4333sgRXY4333[hRuY4333iReY̬jR3333SYhfff~lRUHYoR?YhfffvpR-YpRXhfffnRffffXllRXIiRXhfffhR\X4333iRffffZXgRffffX4333dRX_RTY4333YRYVR LYXTRdYUR8tY4333SR4YTR)Y@RRYKRYR$Yhfff@RY̤BR3333Xhfff?RYXlAR3333ˀX BRffffbtX4333FRffffiXhfff>IRffff~^XHR3333+=Xhfff6MR@+X0QR3333;XhfffFSR̼ X4333SR3333[WhfffRR3333W4333sOR$WhfffNRW4333KOR̈WORWTRWYRRffff.mW4333MR5WJRlW4333kKR3333VhfffSRVlTRVORVGRVhfff>RV4333sU!`R$UcR̴ UdRffffTIiRffff&Thfff.mRffffT4333CmR,ThfffnRffffThfffvRfffffTrRffffST@oRqJTyhRffffOTQ^R3333PT(TRffffJKTORffffAT4333OR3333TZR3333OTSRThffffNR3333O'ThfffVER%T>RMT4333sdRBS4333mRffffHSTtR!CShfffvR8S4333tRQ0ShfffrR3333S4333sR3333R!oRR̄mRRhRRIiRRjRRhfffmRRkR̠R4333lR3333RlRx;R4333\Rffff+R4333\R3333_Rhfff\R̠QDXR̤QVRQVRQPRffffQQR}Qhfff~NRRQ4333JRffff4QFRQ;RPi5RP'R3333PhfffRPRPlQffffbP4333Q3333P4333QffffvPhfffQffffPhfff6Q3333KP4333QLPhfffQLPQPQ3333 QhfffQQ4333CQQsQQ4iQ(QaQ3333O-Q[Q3333%QiZQQ4333XQ Qhfff>VQ3333P4333cZQffffzP4333STQPOQdPhfffNJQ\PhfffAQP\>QffffPhfff7Q3333#P4333S1QffffP4333S1QyP*Q3333{P$QPQ3333/P QffffƲP4333cQ̐Pd Q3333P4333QPhfffP\Phfff6PP4333SPEPPXP4333PffffP̼PPhfffvPP4333 P)PPP8P$P0P}PP9P4333;P3333P8P0PhfffP3333#PP@PP4P|P PhfffPffffnP0PffffP̄P̼PaPP4333PxPPffff PYPLPhfffPffffPP8PPlPPPPP!P̬Pffff"P4333+PP4333P3333PhP3333;Phfff&P̼PPffffP4333PP4333Pffff }PQPPyNhfffAP@N!AP2333cN4333?Pffff6N8?PNhfff.?P2333;N$BPNKP2333NDOP̄NOP2333SNhfffNLP2333#ONPffff O|QPO4333;UPffffO<]PN`PNxaPNhfffndPffffN̴ePffffFOlPxOqP2333 'OuP%OhfffzPffffOP̤O9PfffffNhfffPNPN4333PN4333ÃPN~P\Nhfff^~P̜NhfffFPffffN|P2333{~N,|PfffftNzPhN{P$ON{Pffff^HNhfff~PONP2333;_NPmNhfff.P2333SzN4333P0N4333P̌sN9PxNP2333NP0N4333P2333+ŇPNPIN4333CPXNqP2333{NPffff&NhfffPNxPffffNhfffƙPffffN4333PO`PO̜P@?O PJO4333PLWO0Pffff`OٓPP3333gfP4333 PaP̄P3333 ^P4333QffffFcPQhP4333[QbP4333c QXP QMPhfffQ]=P4333SQ33338P4333Q33336PQQffff5P(Q3333W9Phfff Q3333_WPhffffQ\P̌Q5UPhfffNQffffEPQffff?PQ}CPQ3333HPPQffffvOP4333S%Qffff"JP̌'Q}9P+Q3333sP/QP4333[1Q Phfff+Q PH%QTOQ2333OQOhfffQO UQ|kOWQKO4333^Q23339OhffffeQ4OtQOɁQNQNČQOّQ2333OQffffn*OّQ2333[0OYQ2333O)QOџQNdQffffNyQ2333{NxQffff&N@Q2333N\Q@NQ,OIQN4333QNԶQffffNyQ2333 NhfffQffff6N$Q4NhfffQ2333+{NQdNpQNQ`N4333QDN4333Q NQNlQlN`QNQ2333N4333 Q N8QffffVNQiN4333QfffffN4333SQyyN4333Q|N4333{QN9Qffff.NQ O RpN4333R2333cN`RNhfffRffffNhfff6RN4333R2333yNhfff6RffffjNLRffff\NhfffRffff&ZN9 RtXNDRUN43333R2333{]N4333CRNRУNRN4333s&Rffff6xN,R\Nhffff)R2333#DN+R2333#DNA5R<1Nx@R2333 N4333ARNhfffR2333O4333[RO43333R|N4333RxNhfffRN8R2333OIR̬/OŘHOTRZO,ŘqOhfff6RAO\R̖OɫRffff~OhfffROhfff^RXOhfff.R2333Ohfff6RffffOhfffRO4333R\OIRffffOR O9R2333+OXR2333OR̔OR2333O1RPhfffRyORffffORȼOhfffR2333O4333RffffOR2333ORffff^PR33331Phfff>R3333BPhffffR3333TP4333+R}PR̴P4333Sffff*PhfffS3333{SQ4333sSzQh!SQ4333)S3333sQ$+S@Q-SHQQ/SQ,0Sffff:.R,S1^R4333;+SffffNxR,S,Rhfff6%SffffbŘ%S1R&S4R&S3333R%S̠Shfffv%S)LShfffN(S3333_RS,SJShfff^5S4S̔?SSQSRhUSRYS3333RY^S(R^S3333^RhfffFbSffff6RhfffeSffff8RhlSPR4333;ySffff _R!~SffffRSRaSRSS4333ӂS3333oShfff.|StSuST4333rS&T pS8T sSFTuSffff.eThfff&vS9\ThfffxSffffSS3333vShfffvSjSS3333[SћS\SܣSbShfff6SwShfffS3333S!S3333ShfffS̴TSffff>4ThfffFSy{TȣSTdSHTɏS3333_ThfffVS3333T4333~Sffff"Thfff>STyS3333TS̼TٖSffffT4333SThfffST̼S-TܙST4333ST4333cS3333T4333SŤS TDST̤SLjT4333cS0`TlS8NTSqJTSffff9ThfffS3333-TSffff:"TSThfffFSDT4333STS̬ T(S)S4333{SSSffff SSffffSSS!S3333SS#S4333S33339S4333#S9NSS3333lS̜TMS̴SDSSffffS̼TDS̬ TDJS Tt0ShffffTS4333TShfff> TRTffffR̤T`Rhfff~TR!TffffR̄'T R4333.T3333#Rhfff^3TffffR4333 7T3333R̼8TffffR5T|R84T̈XR19T3333AR̴:Th#R6T R43330TffffRQ+T3333Qd)T!Qhfff'TffffQ(TأQa)TQ/TMQ43336T̀Q̼:TlqQ=T3333hQ=T3333KQP@T%Q4333=TffffQ4333C@T33337QDT33333 QXHTP|IT3333dPy]Tffff0P4333caTffff&OhcT>OcTffffF-OdT2333+OhfffhT2333[EOikT2333yOhfffkTO4333jT2333cODkTP9jTqPjŤ,PiTaAP4333lTgP̬nT$_PqTPPHrT3P`sT, PhfffrTffffP4333wT1-PxT3333zPhfffyT̴P|zT̐P}Tffff|P$~TvPTXrPTqzPTmPhfffޑTffffdPhfff֒T)[PT3333JPhfff^Tffff:PhfffTaPhfffTOyTO4333TROhfff֐TiNYTffffmN4333T2333WNŤCN4333ˌThNhfffT OܝTFOhfff6T)^OTPOT;OhfffTffffvOT`NTffffN4333T2333 N4333TNyTffffNDTЦNTٷNTNTNhfffTpNQT}N\T2N4TIMPT MhfffVT%MTLYTPLT2333CLhfffƵT(LT2333 Lhfff~T|KhfffTKTLKT?Bi=T4333B:TdfffA9TPA43334TA/T4333۩A̤)T4333,Ahfff&T4333@hfff"T|@1!T4333S@hfff"TdZ@4333 T4333 @|T\?tThfffO?hfffT0333?Tl>hfffT =4333KT=4333 T@T=4333 T0333=8hfffT033384333T7S`fff&h7S8hfff&S0333L8TS̬8S84333S`fff6B9Shfff=hfffVS >hfffvS03336>hfffŠ->ySP>pS0>S03333>0S̬i?4333KS4333[E@8S4333C@̤S4333CAhfffSYAS4333 AhfffSdfffAS̜B̌S"BdSdfff&BS0A4333Sdfff6A4333uSxgĀtSdfffFAnS$%AhffffaS4333 A9[S4333@4333SS9@hfffRSN@4333IS3@HS@4333;JS?hfffBS<}>0S03338>4333C*S<=D&S0333<4333S0333S<S0;|Sp"; S`:S0:4333CR0333E8hfffR27hfffR)w6hfffNR`fff5lR o5R04R`fff44333R|4|R`fff6~3hfffR`fff2R̕24333RM24333R`fffFj2`R`fffV2R`fff2R̿2hfff~R`fff2aR`fffV24333SR82hfff^Ry24333;R91R0333o14333CŘL1hfff^R@0xR0333#0R`fffm04333R0333SX/R/ RY.R`fff-.4333sR`Q-IR%-|R 9-4333vR.4333xR`ffff/̄|RY804333zR)H0|wRL.04333#uR08tR /|pR03330amR0333Cc04333kR0333ӄ08iŔ0̔cRio0hfff>[R0333sG0XR`fff&&0hUR /̼IR`fff&1/1FR. CRY,GR0333ST,hfffFR , @R,V,5R0333,hfff62R0333s,.R+hffff0R`fff4+2Rj*hfff>2Rl~)@(R0(R'4333kR0333s&lR`ffff&hfffR`fff&>&Ř%Q %Q&Q0333[&Q`fff&hfffFQd' QK(hfffFQ̬(Q(Q`ffffj(4333CQ%(Q,'yQyS'43333Q&$QR&4333Q̌%Q%iQ`fffQ%TQ`fffF %Q03333$Q v$Q`fff&$\Q>$hfffQy$QL$Q̌$4333Q̌2$IQ`fff#Q2#Q"hfffQv"4333#Q̌! QK!hfffQ0333 0Q0333n iQ̩QQ QL\QQxhfffQ Q 333s~hfff.Q 333sk̜QQ`fffzhfffQ 333s\QY 4333sQLZ Q`fff0HQhfff^Q̜̾Q`ffff4333QZԶQ 333QQQ 3333RQ́QLxQQ 333QLQ@ffffQ Q Q4333QQ33334333Q@fff̼Q4333cQQ3333v0QQ̪쿚YQ4333QPhfffVQa̜QԿQǿQ̼?xQ4333;?̌Q?4333Q?4333#Q?4333;Q@3333@4333Q@3333 @4333 Qs@hfffQffff@Q@3333@Q@AQ̚@̤Q@hfffΖQ @4333Q !@4333SQ̌!@4333QH"@Q:#@8Qpffff#@əQ@333so$@Q %@4333Q@3333h&@4333Q g'@Q̪'@4333#Q"(@tQ(@hfff^QY(@Qpfff&])@Q)@Qpfff)@4333cQpffffr)@1Q@3330)@4333Qpfff@)@43333Q!*@hfffnQ̌*@Q@333+@hffffQ@3333+@hfffQ,@,Q@333 .@ܒQ@3333 /@4333+Qpfff&/@̼Q8333s0@aQ̌a0@IQ0@4333 Q̌0@lQ̬*1@4333ۜQhfff2@̔Qhffff;2@4333+Q8333Y2@Qn2@hfffQ2@hfff>Q83332@4333Qhffff3@4333QhfffF23@4333ÒQ!3@4333{Q3@4333#Qhfff&'3@QC3@Qhfffh3@Q3@4333Q3@@Q 4@Q 5@4333Q/5@hfffQYV5@Qy5@4333Q8333S5@hfffQY5@9Q@76@̴Q8333]6@hQe6@Q8333;6@!Q G6@̄Qhfffr6@XQ6@ܳQ`&7@hfffQhfff&h7@IQ833337@̤Q7@Q,8@tQY<8@hfffQb8@\Qb8@Q8@Q8@Q/9@$Q8333s9@hffffQ`9@dQ8333:@@Q :@Q:@ Q83334;@LQ83333;@ Q;@pQb<@hfffQY<@QQv=@Q>@43333Qhfff>@4333ÏQ?@aQ`?@4333sQl@@4333cQp:@@QhfffO@@ Qhfffg@@43333zQ̬t@@nQ4333~@@4333gQ|@@hfffaQs@@Q4333@@HAQhfff&@@4333[FQA@4333GQhfffFLA@ FQ_A@4333JQАA@)_QhfffƜA@hQ4333A@4333kQA@hfff>jQhfffFB@4333[jQ4333c*B@4333hQKB@4333hQ\B@hfffiQmB@pnQ4333B@hfffsQB@oQhfffB@mQB@qnQyC@tQ?C@QYqC@Q4333tC@4333CQmC@4333cQhffffC@hfff&{Q C@LrQhfffVC@fQ@C@<[Q4333C@KQ4333C@4333=QhfffVD@7QD@43333Q=D@I/QhfffhD@P.QD@hfff$Q̜D@ Q̌D@Q4333S4E@̄QhfffhE@4333Q{E@QE@4333QE@4333QF@

PH@P,)H@AP,)H@P/H@yQP@|Q4333P@QP@hfffVQhfff&P@4333{Q,P@ܔQhfff6P@Q#Q@hffffQy0Q@̬QhfffVAQ@ДQhfff^JQ@`Q4333PQ@hfffQhfffLQ@tQhfffLQ@Q43337Q@@Qhfff&1Q@hfffQ4333'Q@̜Q̤Q@QQ@hfffVQdQ@hfffQP@4333Q4333cP@hfff&QP@0RP@RP@RAP@)RP@hfffQ@QQ@QQ@Qhfff^Q@HQQ@9QhfffR@QR@PQ'R@hfff6Q0R@4333SQ4333/R@hfffNQ̜4R@4333#QhfffBR@hfffQTR@TvQDkR@tQL|R@oQ4333R@9sQ̌R@4333KxQhfffvR@vQ R@(yQ̬R@TvQhfffR@hfffnnQ R@hfffdQhfff&S@1_QhfffS@`_QI1S@̼UQILS@hfff.MQhfffbS@)KQQtS@iDQS@9QS@d0Q4333KS@ (QS@43333Q4333{S@Q@S@9 Q4333kS@4333Q<T@PhfffKT@43333PhfffT@)P|T@DP٦T@Z@PxZ@4333P4333 [@hfffP4333[@4333Phfff>:[@)Phfff][@(Pt[@4333[P[@P4333ӧ[@P[@P[@P[@}PhfffV\@4333yP#\@DvP\F\@1sP̌W\@QvP4333#`\@xPlm\@hfff~{Phfff}\@hfffރP\@ Phfff\@4333Phfff\@hfffPhfffF\@̌P\@P\@4333[PH\@PP̄\@P̄\@P\@hfffPp\@Phffffz\@P4333\@^@P4_^@hfffPhfff>g^@hfffPhfff^@hfffP4333^@P4333^@4333P0^@P^@QP ^@4333Phfff _@4333sPhfff_@hfffP4333C&_@4333SP̔4_@4333sPhfffF_@P4333SR_@4333PxY_@)Pf_@,Phffffw_@4333SP_@PPhfff_@P4333_@؟P_@P4333c_@hfffVP4333_@DP_@P4333 `@P4333`@4333P `@$Pp`@IP̔'`@P0`@0P7`@P9?`@P4333C`@PhfffI`@hfff.P4333R`@YPt^`@@Plg`@4333ˍPhfffz`@P@`@hfffPhfff`@dPhfff`@P9`@hfff6P`@ԉP`@4333P`@4333P4333k`@@P4333C`@4333P`@hfffP`@̜Phfff`@!P4333C`@4333#P`@hfffPLa@4333P4a@4333P̴a@P4333a@Pta@̼Phfff*a@,P43338a@4333P=a@hfff>PhfffzDa@ТPHa@ P La@hfffP4333ga@̼P4333sa@hfffΨP|a@ĭPٜa@ Phfff&a@e@RDe@tRLHe@4333R%Ie@R4333Fe@hfff.$R4333Ae@p&R8e@)"R4333.e@(RP"e@Re@4333Rpe@4333CR e@Re@@R=e@4333[#R(e@4333'R:e@̤.R;e@43332R6e@ 8Rp1e@9CR!e@4333LŘe@hfffER4 e@8DR4333e@hfffNHRLd@hfffGR4333d@lIR@d@@R}d@;Rd@hfff?Rd@4333[NR8d@hfffQR̴d@hfffUR̰d@4333;YRd@\R|d@)\Rd@hfffbR̸d@aRd@)bRd@dRhfffd@hfffeR4333d@hfff^hRdd@ oR9d@tRhfffzd@xwR̐d@hfff&vRhfffd@HxR4333d@4333rR4333ӧd@hfffdR$d@|XR(d@WRd@dYRd@4333cRhd@̜uR4333[d@A{Rd@0RhfffҘd@4333ӁR0d@ܐR4333kd@hfffFR4333ˬd@4333R4333d@R̰d@R d@4333RLd@4333R d@`R$d@4333#Rd@|Rhfff}d@PR4333wd@R4333qd@hfffR4333ld@tR4333hd@HR4333[ed@hfffRhfff^d@RXd@RTSd@hfffR4333Qd@R4333Md@4R8Gd@4333R4333Bd@hfffR!=d@R43335d@R$d@4333kR !d@hfffVRhfffF'd@hfffRd@Shfffr>d@4333S;d@hfffS7d@hfffSy1d@hfffS&d@4333Sd@hfff.Shfffrd@S(d@YShfffrd@S̬d@QSd@4333{S,d@4333Shfff:c@4333{S̬d@4333{ST d@̬S d@ASyd@$Shfffc@̌Sc@S̐d@hfffSd d@IS4333d@hfff~Sd@̬T43337 d@|Td@4333T4333c@hfffThfffc@TT4333[c@Tc@4333STYd@43333Tdd@4333ThfffNd@| Thfffd@hfffV%Thfff>d@̼(TXd@4333#+Td@hfff.Thfff d@433330Td@1T4333Sd@Y2T4333d@16Thfffnd@̬9Td@4333:T4333Kd@9GT4333d@hfffLTHd@xOTPd@IQTd@UT d@XT̠2d@hfffgT]7d@gT?d@4333iTMd@pTtRd@@uT4333GZd@pwT4333W[d@zT4333#`d@4333~ThfffFsd@T4333ud@ThfffMd@ TT%d@T)d@4333[TTd@ўT``d@2C@43333oH@ffff7C@lH@\hC@`mH@ffff^kC@̌vH@3333{C@{H@C@H@ffff&C@@H@؊C@H@C@|H@C@)H@C@4333H@LC@yH@C@H@C@pH@ffffC@hfffH@ffffC@H@(C@hfffH@ffffC@4333#H@C@H@3333+ D@̌H@D@4333H@D@`H@$D@̜H@(D@4333SI@`)D@hfff.I@ffff#D@hfffF'I@33334D@I@3333;D@\I@̜@D@@I@3333kDD@H@ID@hfffH@ID@4333SH@JD@4333H@ffffMD@0H@[D@hfffvH@afD@H@3333[D@\H@܎D@hfffVH@D@hfffH@ffffD@4333H@ffffޯD@hfffviH@ffffD@4333UH@D@4333SIH@D@hfff=H@3333D@43336H@DD@ 1H@ D@&H@D E@4333CH@)E@4333C H@ffffF-E@4333CG@ffffNE@hfffG@RE@hfff&G@!WE@4333G@gE@4333CG@̤sE@hfffG@3333{E@4333G@E@IG@|E@hfffG@E@|G@E@4333G@3333۰E@hfff&G@ffff>E@4333G@̬E@\G@)E@G@3333;E@4333G@ffffE@F@4333CG@ffffF@4333H@IF@`H@ffffVF@ H@ffffF@hfffV>H@F@hfffDH@F@hffffKH@F@hfffQH@F@hfffFXH@ffffF@4333c]H@3333F@4333_H@F@ ZH@F@WH@ffffG@4333WH@ G@ _H@ G@̬gH@ G@0H@8G@)H@ffff>G@H@$G@yH@3333S%G@H@(+G@4333SH@ffff^1G@hfffH@7G@YH@4G@H@ffff&>G@yH@3333sBG@hfffH@DG@H@EG@hfffH@ffffHG@YH@ffff&IG@4333sH@ffff>LG@H@0QG@ I@$YG@43333'I@eG@̬5I@3333pG@4333sD@l$K@ffffD@KK@ffffƘD@4333UK@3333D@4333ZK@3333D@hfff[K@D@4333\K@3333yD@4333ZK@rD@f@>Q@{f@@Q@hf@ffffPQ@l^f@ffffRQ@]f@TQ@]f@,WQ@%[f@XQ@4333+Nf@\Q@=f@_Q@,f@$gQ@̔f@XiQ@hfff" f@3333/qQ@pf@3333wQ@|e@LyQ@ e@yQ@ue@3333 wQ@4333#e@3333vQ@8e@lxQ@hfffVe@wQ@xe@yQ@ e@̘|Q@hfffNe@3333#{Q@e@tQ@͡e@3333[wQ@Лe@zQ@e@}Q@hfffe@Q@ge@3333߄Q@hfff[e@%Q@Oe@ffffQ@Pe@ffff|Q@Pe@vQ@Ke@pQ@pFe@kQ@hfff&Ee@hQ@Re@UeQ@hfffVe@XQ@H\e@3333PQ@_e@3333HQ@hfff_e@ffffBQ@4Qe@33334Q@Be@3Q@3e@ffffN2Q@D-e@3333:Q@)e@3333EQ@4333Ge@tJQ@e@NQ@ e@TOQ@hfff e@`QQ@\e@\Q@e@dQ@hfffe@ffff hQ@4333gd@3333lQ@4333kd@3333nQ@d@aoQ@4333Wd@|cQ@Ld@ffff_Q@@d@_Q@`d@bQ@Xd@3333geQ@ld@fQ@4333d@nQ@E~d@ oQ@vd@fffflQ@od@ffff^lQ@qfd@ffffmQ@hfff:^d@ffffkQ@Ld@ffffiQ@PEd@$gQ@hfff>>d@3333bQ@hfff.1d@ffffJXQ@\/d@4SQ@\/d@LQ@2d@DQ@2d@ffff9Q@/d@d6Q@4333+d@4Q@]'d@)Q@X#d@$Q@dd@t"Q@d@&Q@ $d@)Q@hfff*d@ffff9Q@hfff)d@>Q@$d@|BQ@4333#!d@HFQ@ld@hUQ@d@X]Q@$d@fffffQ@d@ffffiQ@d@̴nQ@c@Q@433378b@ffffRR@@5b@IR@6b@] R@6b@4 R@hfffF8b@tR@̔9b@33333R@Ab@3333 R@dDb@` R@hfff^Gb@R@0@b@ffffQ@Cb@ffffzQ@hfffLb@ER@,Sb@R@4333Yb@$R@hfffZb@R@4333Sb@3333[R@@!b@R@b@3333/ R@p b@T R@hfffjb@R@̌ b@3333R@b@R@b@3333wR@b@\R@&b@!R@hfff.b@,R@4333Gb@aR@Hb@MR@hfffBb@3333+R@hfff6b@R@4333/b@"R@`&b@ffff~$R@hfff2b@'R@ b@3333')R@hfffa@+R@a@,R@4333a@!.R@hfffa@y2R@a@6R@ܙa@9R@̨a@ffff8R@a@7R@a@5R@!a@3333-R@hfffva@ffffR(R@a@%R@a@ffff6!R@4333ka@3333R@ R@4333sa@` R@4333{a@ffff R@|ta@Q@4333ka@3333Q@̬qa@3333OQ@hfff"wa@3333Q@hfff>va@Q@hfff ~a@̰Q@hfff~a@tQ@hfff:ta@PQ@4333?ja@ffffvQ@4333fa@3333wQ@(`a@ffffQ@4333Xa@AQ@pUa@̠Q@hfffPa@Q@-Ja@̔Q@hfff~Ga@ffff*Q@hfffCa@a@Q@9a@}Q@4a@ffffRQ@\-a@3333#Q@*a@Q@̴#a@ffffQ@4333 a@3333Q@a@3333Q@P`@3333[Q@`@Q@`@Q@4333`@ffffQ@4333 `@ffffzQ@|`@Q@hfffJ`@@Q@4333 `@ffffQ@4333`@lQ@0`@Q@4333ۚ`@TQ@4333`@ Q@`@ffffQ@`@ffffQ@`@3333CQ@hfff`@LQ@l`@ffffzQ@H`@3333#Q@)`@Q@hfff`@iQ@̴`@Q@!`@ffffQ@}`@Q@x`@}Q@q`@ffffQ@m`@ffffQ@h`@ffffQ@ e`@Q@̰``@Q@̼\`@mQ@4333Z`@Q@hfff:X`@3333Q@dU`@ffffڸQ@0Q`@3333Q@I`@̠Q@@`@3333/Q@a8`@ffffQ@y,`@Q@4333/'`@̐Q@L$`@Q@hfff`@3333Q@`@ffffvQ@hfff^`@HQ@hfff~'`@3333Q@4333.`@PQ@hfffV)`@iQ@hfff&`@3333Q@#`@Q@4333$`@R@!`@BR@8#`@0GR@!`@FR@hfff:`@GR@`@3333HR@p`@,LR@``@NR@`@3333PR@@`@ffffQR@t`@3333?SR@ `@(UR@̈`@VR@hfff`@ffffYR@_@=[R@ _@\R@a_@^R@_@ cR@!_@ffffaR@_@[R@\_@3333oUR@x_@XR@_@ffff:YR@y_@ZR@ē_@̬]R@4333_@3333g`R@_@XbR@I_@cR@_@ffffaR@4333x_@_R@r_@3333]R@hfffNf_@ffff\R@hfff~g_@QaR@hfff2_@mR@4333"_@pR@hfff_@3333OpR@8_@ffffmR@^@lR@^@hR@hfffn^@jR@4333^@ffffhR@hfff^@3333bR@hfff^@ffff[R@̼^@ffffYR@^@ffff:VR@^@ffffPR@4333^@ffff^LR@4333^@YKR@hffff^@KR@4333^@ffff:IR@^@3333{ER@hfffF^@@R@4333C^@=R@^@̼=R@`^@AR@hfff^@AR@ ^@3333>R@hfffƮ^@ffff;R@ ^@:R@4333K^@33339R@hffff^@-8R@hfff^@3333[8R@^@l9R@̴x^@3333=R@o^@3333>R@̬V^@ffff">R@?^@3333;R@D&^@ffff>R@]@ffff*>R@hfff]@>R@8]@DR@hfffv]@GR@]@3333OR@]@̀WR@@]@̸]R@I]@ffff]R@hfff]@^R@Q]@,aR@̼]@lbR@М]@3333eR@S]@XfR@hfff]@DkR@̜\@3333lR@9\@fR@\@3333keR@v\@3333#bR@`\@Q`R@hfffb\@[R@hfffm\@ffff:XR@4333r\@WR@x\@!VR@4333u\@ffffTR@p\@YTR@h\@ffffQR@c\@3333NR@hfff6e\@ffffIR@̼b\@ffffzCR@Z\@̨;R@S\@ffff68R@4333M\@33333R@S\@I/R@ Y\@-R@4333Sh\@U+R@m\@)R@j\@(R@4333S\@ffff*R@K\@3333.R@ J\@3333?1R@hfff.H\@)5R@O\@l9R@4333W\@HnR@hfffօ[@XmR@٘[@3333wnR@4333;[@ffffqR@hfff&[@pR@[@nR@hfff~[@3333lR@p[@@hR@̼v[@<^R@hfffh[@ffff]R@0U[@ffff2_R@J[@3333YR@E[@8XR@4333$[@3333kTR@hfff~[@ffffSR@4333C[@QR@ [@PR@[@OR@hfffZ@KR@Z@pJR@hfffZ@XKR@hfffZ@HR@)Z@3333FR@\Z@CR@hfff6Z@ @R@DZ@ffffW@ffffS@43336W@R@8W@U@xR@hfffάU@pR@4333;U@ȜR@4333U@ԙR@4333U@IR@xU@ffffҔR@4333U@3333R@hfffvU@ffffnR@TU@ffffΜR@̴U@3333R@hfffU@9R@aU@R@̌U@R@̜U@R@4333kU@zU@XR@!~U@ffff6VR@ɇU@SR@4333íU@ HR@TU@FR@4333U@HR@̴U@3333LR@HU@ffffrQR@\tU@TR@4333[sU@WR@rU@ \R@4333;sU@3333_]R@hffftU@_R@hfffU@3333eR@4333kU@ffffgR@hfffU@mR@4333U@3333tR@hfffU@ffffwR@hfff&U@ffffxR@٥U@Q@eR@dsQ@cR@3333CmQ@4333sjR@ffff~gQ@4333KuR@@`Q@yR@ZQ@̤qR@LQ@uR@ffff*IQ@hfff~R@ffffVGQ@4R@@IQ@hfff&R@EQ@lR@qGQ@R@EOQ@R@PQ@S@3333 OQ@hfffF)S@3333GQ@4333US@ffffZ=Q@]S@9Q@̤iS@33339Q@ArS@Y(Q@ zS@Q@4333[}S@!Q@S@3333Q@wS@Q@ppS@3333;Q@̌jS@3333/ Q@LbS@}Q@IaS@33337P@hfffeS@3333P@QS@ffffjP@ȣS@3333P@4333S@eP@hfffθS@=P@ S@P@4333S@P@4333S@P@aqS@3333P@4kS@P@eS@ffff6P@QYS@3333P@hfffTS@P@)KS@3333P@hfffOS@9P@̴PS@ffff2Q@4333COS@ Q@hfff&GS@(&Q@4333 /S@̸1Q@&S@ffffr9Q@4333cS@>Q@9S@t?Q@S@ffffr>Q@4333R@̬9Q@R@ffff&7Q@R@0Q@ȞR@3333+*Q@ R@3333Q@R@eQ@yR@ Q@R@̴Q@hfffαR@P@4333cR@pP@@R@ P@DR@tP@ĄR@̀P@hfffR@P@xR@pP@rR@3333P@hfff`R@P@UR@3333P@hfffR@P@4333R@3333kP@̔R@AP@4333SR@ffff6P@Q@ffffʏP@43333Q@\P@Q@P@PQ@3333wP@Q@P@~Q@̰P@lQ@3333P@hfff^ZQ@P@pLQ@P@hfff6IQ@P@EQ@3333OP@hfffFCQ@ P@@Q@tP@ EQ@8P@MQ@P@4333coQ@ffff"P@4333#xQ@P@hfff|Q@ffffP@Q@3333GP@4333#Q@P@iQ@̠P@Q@=P@hfff^Q@DP@4Q@3333P@YQ@3333۬P@4333SQ@ĪP@4333+Q@ffffrP@Q@3333P@hfffQ@P@dQ@ffff>P@ Q@P@43333Q@P@4333Q@3333P@Q@P@hfffFQ@3333P@4333Q@@P@`Q@P@4333Q@$P@R@(gQ@>R@ YQ@3333'=R@BQ@*R@5Q@3333R@&Q@R@4333 Q@Q@4333;Q@3333Q@hffffP@Q@̬P@ffff^Q@̌P@3333CQ@P@ffffQ@(P@Q@P@5Q@4333SP@3333Q@hfff6P@Q@P@3333Q@P@3333Q@hfff6P@3333WQ@P@ffffbQ@4333P@Q@,P@ffffQ@P@Q@9P@3333GQ@P@Q@ P@3333Q@`P@3333Q@4333P@Q@PP@ffffQ@hfff>P@Q@4333kP@\Q@IP@Q@4333CP@ffffuQ@4333cP@ffff^oQ@tP@0jQ@hfffƵP@fQ@4333cP@qcQ@ɻP@0fQ@4333P@iQ@ P@elQ@P@3333geQ@hfffP@3333aQ@`Q@̸^Q@̬Q@ffffZQ@4333Q@ffffOQ@Q@3333SDQ@̼"Q@=Q@hfff6*Q@ffffZ;Q@43330Q@ffff:Q@);Q@ffff2=Q@hfffHQ@3333N@3333.Q@4333N@,Q@M@4-Q@̼M@3333&Q@M@ Q@ M@ffff*Q@M@Q@M@XQ@M@3333WQ@4333M@̀Q@YM@xQ@hfffƧM@ffffQ@̬M@pQ@`M@q'Q@|M@ffff>,Q@0M@3333W-Q@lM@A/Q@hfff6M@`6Q@M@\9Q@M@ffff>>Q@hfffVM@3333c@Q@uM@ffff>@Q@L-M@3333:Q@hfffVM@3333_5Q@hfff&M@8Q@L@ffff)Q@K@ffff?Q@K@ffff6@Q@hfffJ@̼?Q@ٴJ@3333g:Q@WJ@.Q@ ,J@&Q@7J@ 'Q@iFJ@ffff%Q@hfffRJ@d Q@\J@ffffQ@UJ@PQ@F@ffffP@(F@ԞP@@F@ P@p F@3333 P@F@33337P@4333F@!P@\ F@̌P@4333#F@3333/P@E@PP@E@P@hfffVE@3333#P@E@dP@\E@P@4333sE@P@E@P@9E@3333P@4333E@P@ٝE@P@4333ÀE@P@P@hfff=A@8P@NA@УP@̌iA@P@hfffA@3333oP@A@TP@/B@XP@̌bB@ɒP@}B@qP@̼B@3333gP@iB@3333KP@IB@ffffP@43332C@ P@4333SC@3333kP@C@3333sP@9 D@ffff2P@4333BD@P@0D@P@hfffFD@P@YD@P@D@3333kP@D@3333P@4333#D@P@4333#D@̴P@̇D@mP@4333{D@P@hfffbD@P@ TD@ffffP@LCD@ffffP@0D@=P@4333sD@HP@4333D@Q@4333C@TQ@hfffC@3333 Q@hfffC@a Q@hfffC@-Q@4333cC@Q@4333C@3333Q@pjC@3333Q@PZC@Q@4333TC@Q@7C@ffffQ@hfff-C@Q@4333B@L,Q@4333#OB@8@Q@A@ELQ@A@̠QQ@ٝA@3333PQ@4333A@NQ@9A@(NQ@hfffnA@̘NQ@hfff&-A@3333cSQ@\A@ffff TQ@@@3333SQ@4333C@@RQ@4333÷@@XHQ@̬@@HFQ@4333@@eDQ@4333#@@ffffzGQ@4333@@IQ@ܴ@@QQ@@@-TQ@Y@@4XQ@hfff&@@3333g[Q@4333C@@3333o\Q@@@`[Q@L}@@ffffWQ@hfffx@@̈XQ@@@̄\Q@@@ffff^Q@ q@@ffff~]Q@4333Q@@3333S_Q@Y0@@^Q@P*@@xcQ@hfff@@3333/fQ@hfff @@|hQ@@@3333#kQ@̌`@@fQ@ u@@fffffQ@P@@3333hQ@̜@@jQ@@@33337nQ@x@@ffffpQ@`H@@sQ@ 2@@̘wQ@ ?@}Q@hfff&?@}zQ@@@uuQ@y?@sQ@ ?@3333?uQ@?@5tQ@̌?@$nQ@hfff?@fffflQ@hfffs?@ffff"lQ@̬ ?@3333;qQ@hfff>@$rQ@hfff>@rQ@83333>@rQ@|>@3333rQ@hfffm>@9nQ@8333e>@ffffnQ@LY>@iuQ@8333<>@ffff.wQ@.>@uQ@'>@oQ@>@mQ@hfff=@%oQ@hfff=@nQ@8333ӱ=@3333oQ@̢=@qQ@=@]tQ@8333=@wQ@=@e|Q@8333=@3333~Q@hfff<@Q@<@ffffNQ@hfff=@,Q@8333SC>@3333Q@ x>@Q@8333>@Q@>@Q@hfff&>@Q@̌>@Q@ l>@Q@83336>@ŢQ@3>@Q@<>@ѧQ@̬>@Q@=@pQ@hfff=@3333Q@̼=@eQ@8333Ӹ=@ɪQ@=@3333Q@e=@Q@83333R=@Q@83337=@Q@83333=@ffffQ@<@3333KQ@8333<@3333۵Q@<@ffffQ@|<@ffffQ@8333o<@ffffQ@8333SO<@3333[Q@8333G<@љQ@hffff1<@Q@*<@hQ@*<@Q@hfff0<@,Q@hfff3<@Q@8333E<@Q@833337<@Q@8333;@3333Q@hfff;@3333cQ@8333s;@Q@E<@Q@̬S<@дQ@a<@̤Q@ld<@3333kQ@hfffF$<@Q@hfff;@Q@hfffƻ;@,Q@٘;@Q@hfffT;@ffffʿQ@9<;@3333Q@D;@=Q@@;@Q@hfff;@tQ@83333O;@mQ@hfff/;@ffffQ@8333%;@̘Q@@;@Q@hfffF:@ffffQ@hfff:@Q@hfffƕ:@=Q@:@3333 Q@hfff:@8Q@̠:@AQ@hfff:@Q@hfff:@3333ӪQ@:@lQ@hfff:@̠Q@L:@$Q@hfffƁ:@3333kQ@;:@ffffQ@83339@ffffQ@8333sx9@̕Q@9k9@ffffQ@969@Q@9 9@ffffQ@83338@33337Q@hfff8@3333Q@y%9@̼Q@833359@ffffRQ@hfffF9@ffffZQ@w9@Q@hffff9@̼Q@ 9@ffffFQ@hfff9@ffffQ@@9@Q@8333S9@Q@9@̤Q@o9@\Q@hfff&`9@Q@LS9@\Q@C9@Q@8333+9@3333ϷQ@ 9@ffffnQ@hfff8@Q@hfff8@ffffQ@8333s8@Q@q8@3333Q@8333sC8@ffffQ@hfffD8@tQ@Lg8@3333Q@hfffk8@Q@hfff[8@tQ@I8@dQ@ 8@Q@̬7@Q@hfffF7@Q@ a7@ffff֏Q@@T7@3333CQ@9I7@Q@lO7@Q@8333sf7@DQ@Z7@~Q@hfffB7@ffffQ@L-7@܁Q@hfff 7@̄Q@6@3333'Q@83336@̄Q@hfff6@ffffʕQ@@6@Q@8333k6@3333Q@b6@ffffƑQ@lR6@Q@,86@ɓQ@ 6@Q@5@ffffƒQ@5@ffffQ@5@}Q@8333[5@Q@hfffX5@TQ@f5@ffff*Q@5@HQ@5@ffff:Q@5@EQ@hfff5@iuQ@hfff5@$tQ@83335@xQ@5@|Q@8333n5@؀Q@8333@5@4Q@)5@xQ@95@xQ@4@zQ@ 4@zQ@@4@}zQ@hfffƋ4@xvQ@`4@3333OlQ@4@hQ@Y4@leQ@4@5bQ@L4@PaQ@|4@bQ@24@WQ@8333s4@ffffUQ@8333 4@ffffJUQ@83333 4@3333VQ@8333F4@3333KbQ@8333V4@3333wgQ@,U4@3333SkQ@ c4@3333wQ@Z4@{Q@S4@|Q@94@3333W{Q@y%4@dyQ@hfff4@ffffxQ@hfff3@fffftQ@Y3@33337nQ@3@ffff>`Q@93@3333#[Q@hfffƣ3@ffff>`Q@,3@ffff:gQ@83333@ffffrQ@3@̀sQ@23@oQ@8333 3@DjQ@hfff3@3333gQ@3@̜eQ@2@cQ@2@ffff~aQ@@2@3333aQ@̌2@MaQ@L2@e_Q@ٟ2@[Q@2@8XQ@y2@ffffzUQ@hfff2@ TQ@@2@TQ@̌{2@YWQ@8333`2@ffff&\Q@ K2@h^Q@B2@ffff^Q@02@[Q@hfff&2@TQ@L2@3333NQ@83332@̘KQ@2@JQ@`1@3333gFQ@ً1@ffff@Q@8333s}1@=8Q@ d1@(3Q@8333!1@a,Q@y0@+Q@0@ (Q@8333s0@ffff%Q@̬0@"Q@y0@3333gQ@0@ffffQ@31@dQ@m1@Q@z1@3333[Q@1@ffffQ@91@3333Q@hfff1@HQ@z1@HQ@ V1@3333CQ@83331@Q@̌0@3333Q@l0@̼Q@l0@Q@Lc0@ffffQ@,40@EQ@,0@Q@B0@@ Q@Q0@3333Q@Yd0@Q@hfffF_0@Q@hfffO0@HQ@83333B0@Q@8333O0@iP@B0@P@0@Q@hfff0@3333 Q@ 0@ffff Q@hfff0@3333Q@ٳ/@̨ Q@@3333P/@̄ Q@@.@̔Q@̡.@fffffQ@@333.@UQ@.@3333;Q@pfff&6/@9P@pfff&>/@̰P@pffff/@3333GP@@.@3333P@.@P@D.@@P@.@3333+P@ -@P@pffff-@P@ -@1P@-@tP@pfff.@3333P@.@ffffP@ .@P@@333s.@3333OP@@333o.@P@Y.@P@@.@P@.@ffffP@R/@P@ b/@ffff^P@&/@hP@Y0/@ffffNP@/@3333P@@.@P@.@XP@ .@P@@333=.@P@-@P@̌-@P@@3333(-@̴P@-@ffffP@̌,@P@pfff&,@ffff^P@pffff,@aP@)-@P@-@,P@pfff.@qP@.@P@.@P@-@ffffrP@̌3-@ P@,@!P@@,@,P@@i,@ffffP@@3337,@P@@333s ,@P@pfff+@P@pfff+@}P@ t+@P@M+@ P@h+@P@+@pP@@+@ffffֲP@@333s+@P@>+@ffff޲P@Y +@3333wP@*@3333˭P@pfff*@3333P@@l*@3333P@b*@`P@5*@P@pfff"*@ffffP@<*@3333ÎP@@*@ffff&P@@3333*@ffff*P@@333s*@3333P@\+@ffffP@@+@ffffvP@,@3333 P@pfff+@ԏP@@333+@%P@LY+@̄P@@3333*@ffffP@L)@mP@)@lP@)@ffff:P@@333*@33333}P@L)@3333C|P@@3333)@|P@@333`)@yP@pffffA)@sP@̌(@ThP@@333(@\dP@i(@ffff_P@̌>(@0WP@̌D(@QP@@3333f(@OP@ن(@dPP@(@hOP@L(@3333_LP@(@KP@)@LP@@n)@ QP@)@QTP@)@ffffUP@ z)@̸MP@L)@\FP@@333(@̀EP@t(@MIP@Q(@tKP@̌&@t>P@pfff&&@ffff9P@pffff&@5P@@333&@ffffN0P@@333&@x1P@'@ffff^4P@ D'@33334P@@3333 '@/P@pfff&@ffff+P@pffffs&@|+P@L.&@T'P@Y%@$P@%@P@!%@P@@333x$@3333 P@$@ffffRP@#@O@#@3333{O@j#@̴O@:#@̼O@@333s"#@3333cO@@333s0#@O@P#@AO@@333#@O@pfff&#@O@#@O@#@O@@3333$@O@pfff$@O@pfff%@ffffO@@3333&@0O@@333%@fffffO@%@ffffO@&&@3333{O@Ym&@P@&@ P@&@P@L&@0P@ٖ&@ffff^O@pfffY&@ffffO@m&@fffffO@&@O@pfff&&@9O@̽&@O@s&@O@Y<&@ffffO@@333%@ffff^O@@333%@YO@Ys%@O@pfffX%@lO@i%@ffffO@@3333%@3333 O@@333h%@ffffVO@̌.%@ffff>O@$@3333O@̌`$@ffff6O@@)$@3333cO@ $@ffffO@Y#@O@@#@3333KO@@333s#@3333O@#@O@d#@O@Y4#@ffffO@ #@O@@333"@O@pfffO"@3333˺O@+"@QO@&"@ O@@333P"@3333{O@̌E"@O@L!@̬O@pfffX!@O@'!@3333O@ @ffff~O@@333 @3333ۿO@pfff @ffffO@ @3333KO@0!@3333O@@3333H!@0O@pffffE!@ѫO@ )!@O@ @ffffO@@333s^ @ffffFO@pfffP @̬O@pffffx @̄O@Y @fffffO@pfff7!@ffffpO@ ?!@QlO@ @ffff{O@l @lO@3 @̤O@q@pO@@333@3333KO@@O@I@̼O@ffff@3333O@@333@̔zO@@wO@@̌sO@L @3333eO@@@\O@@333@YO@@I]O@q@A`O@fff@L`O@@3333@3333@L @bO@pfff0 @̬]O@8@I\O@L'@ffffVO@@RO@@ffffNO@L@JO@̜@1HO@G@3333+FO@@3333{EO@"@MO@@3333@9PO@@ffffQO@@3333y@ffffOO@@ NO@ffffi@9NO@ffff@3333JO@@3333@̌BO@@333@=O@Ly@<9O@ffff@(4O@ @I5O@@3333[9O@@;O@fffz@ffff.6O@R@!4O@@(-O@U@,O@@3333@ffff0O@L@4O@@@5O@ffff/@<1O@ffff@0O@"@3333'O@fff@3333O@@3333O@Ln@3333kO@fff,@3333O@@333@ffff&O@@xO@b@iO@ffff@ffff~N@L@N@ffff@ N@ffff@!N@L@N@ffff@N@@333@N@L@TN@fff@YN@@3333@N@L,@ffffN@@ffffN@w@TN@@333@AN@ffff@lN@@3333@N@@N@@ffffN@e@aN@@̌N@@̤N@Z@$N@@LN@@3333N@@N@@333@XN@@3333@3333N@Lm@N@ffffL@3333ۍN@@N@L@N@T@iN@@333@3333#N@ffff@ɓN@,@LN@Lf@3333N@fff@N@fffp@3333SN@̠@qN@ffff-@ffff^N@@3333@̌N@@333@ffff>N@@)N@@33331@XN@fff@XN@S@ffffN@@3333@N@ffff@N@fffb@yN@@pN@k@3333N@.@̬N@)@3333N@/@N@O@{N@'@yN@@@N@ffff@)N@@3333N@@3333;N@p@N@@ɊN@+@\N@@N@ffff@ffff.N@'@ N@@N@@333a@!N@@3333N@@3333@3333wN@ @mN@L2@ZN@v@hQN@fff@HN@@ON@[@ffffXN@fff@XN@/@ON@@3333@ffff>N@ffff@ 9N@@y'N@@333$@TN@ffff@N@K@IN@ffff@N@@N@ffff@ N@@3333N@@ N@@A N@@N@@HM@@3333M@z@ffffM@ffffk@M@ffffq@3333{M@L@M@@ffff6M@@̌M@@3333@M@fffi@3333KM@ffff@̬M@ffff:@1M@@HN@4@3333[N@@ffffN@@HN@@PN@@3333h@3333#%N@@Q,N@Lc@̤5N@@3339@@N@@AN@@ffff6=N@&@ :N@@3333@ffff5N@̤@/N@@3333N@@XN@ffffK@(.N@@3333+4N@e@ffff.-N@fff@3333N@@333k@3333#N@r@N@G@ N@ffff@N@ffff"@ffffM@@yM@ @iM@V@M@fff@ffffM@@333<@dM@@xM@@M@@QM@x@3333M@@333@M@ffffQ@3333M@ffff@ffffFM@@ffffFM@@3333@M@@33338@@M@@3333;M@@M@̆@M@ffff@ffffΔM@s@3333KM@@ffffM@A@ffffFM@@ffffM@@3333@8M@a@ffff>M@@ M@ffff@̬M@@3333@3333kM@@ffffM@L@M@9@ffffM@@333@3333M@fff3@ M@@333@HM@̿@3333M@@3333ӗM@@ffffVM@@M@@ffffM@ffff@l~M@e@yM@H@3333M@t@ffffM@L@3333xM@@oM@ffffe@doM@j@zM@fffr@ffffM@fff8@3333|M@@LiM@@333@ffff\M@X@iOM@@ffffCM@@ffffV7M@8@0M@ffff@L"M@L@4!M@ffffx@"M@@333@!M@@M@@̬M@Ll@3333M@ffff8@M@@333\@t M@@ffffM@@3333@p M@@M@6@M@@3333KM@@3333@IM@̔@tM@@ M@@ffff M@@M@@M@@ffffM@@< M@pfff& @M@ U @M@ٟ @3333M@@333 !@y&M@Y!@HM@@3333["@fffffVM@@3333c"@ffff[M@@3333z"@^M@Y"@_M@pfff"@ gM@@333"@̬mM@pfff&#@lwM@pfff<#@yM@YP#@P|M@pffffd#@ffff>M@A#@M@L#@lM@@3333E#@3333M@@333#@ffffvM@pffff#@zM@L#@ffff{M@̌*$@M@[$@0M@ i$@3333M@|$@M@$@3333ˣM@$@QM@̌$@ȸM@@333s$@3333SM@$@yM@$@PM@#%@ffff&M@Y%@M@0%@M@5%@3333 M@D%@ffffM@C%@ffffζM@@3333J%@ѱM@@3333|%@3333M@@%@3333M@%@ffffޕM@@333s%@ M@.&@ffff&M@pfffC&@TM@Y&@aM@&@iM@&@̬M@@3333&@ffffM@@d&@M@@333sU&@ԅM@YK&@3333~M@V&@3333vM@@333sj&@ffffnM@r&@WM@ &@L@̌m-@3333+L@pffff-@L@@3333.@3333 L@@3333.@ffffNL@@333/@lL@@/@L@q/@L@@/@ffffL@@3333/@lL@L/@ffff~L@8333&0@3333@L@l70@̄KL@hfffFY0@ZL@hffffh0@3333gL@ u0@vL@hfff&0@L@0@3333#L@z0@ffffL@y0@L@0@L@0@ffffL@̬0@ffffL@8333s0@$L@83330@fffffL@,0@L@8333Ә0@L@hfff0@qL@90@̔M@0@lM@8333s0@&M@hfff0@7M@hfff0@:M@0@ ?M@0@JM@ٮ0@LM@`z0@3333sNM@ d0@ MM@lQ0@lPM@60@ffff~QM@P0@TM@̬0@YSM@hffff0@3333SM@8333S1@ZM@Y1@cM@t1@mM@l1@ffffFuM@83331@ffff{M@91@0zM@1@ffffVM@ 2@M@ I2@M@lR2@M@_2@M@ j2@)M@hfff2@ffff^M@2@ܩM@l2@ffff~M@hfffF2@8M@̌u2@ȲM@8333Se2@ffff.M@hfffV2@3333 M@@E2@ffffM@hfff52@lM@8333!2@yM@83331@ffffM@1@M@)2@ffffM@hfff72@3333ӵM@hfffF2@M@̌V2@ M@hfffg2@ľM@2@3333kM@8333ӣ2@3333M@2@$M@hfffF2@M@8333s2@M@̌2@M@hfff2@̜M@`2@ffffvM@L2@PN@y2@, N@hfff2@3333CN@83332@N@2@t N@hfffff2@ffff&+N@ @2@ffffF.N@)2@ffff64N@hfff2@ffffvAN@̬1@ffff~KN@ 1@@JN@1@EN@@1@DN@y1@JN@8333ӗ1@XPN@833331@DRN@u1@ffff&RN@ \1@ffffRN@@@1@3333YN@B1@aN@hffffG1@gN@833331@ffffyN@61@0~N@̌/1@N@hfff.1@N@8333)1@ffffN@31@ffffN@̌-1@ffffƭN@8333S#1@3333۰N@ *1@N@hfff%1@N@y!1@N@8333371@3333N@hfffF21@ffffN@hfffU1@N@hfff&w1@̜N@8333j1@ffffN@8333e1@3333N@_1@3333N@yi1@N@8333Sr1@ffffO@1@IO@1@,O@91@3333O@hfff1@!O@8333m1@*O@8333_1@6O@`1@<;O@hfffi1@3333AO@L1@3333=O@83331@33339O@y1@ffff9O@1@@O@1@Y@O@8333s1@3333 JO@̌ 2@ffffLO@̬2@)PO@833331@RO@,1@iTO@83331@ffffWO@8333s1@3333K\O@83331@dO@hfffF1@ffffNjO@,1@oO@1@qO@y1@̼jO@83332@3333kO@83332@ffffgO@ 2@4eO@hfff+2@ eO@hfff72@ffffgO@?2@fffflO@̌v2@3333rO@̌{2@3333vO@hfff|2@3333zO@hfff2@3333~O@P2@O@ X2@O@`h2@̄O@ه2@!O@2@ffff.O@@2@іO@̪2@O@8333s2@`O@hfff2@@O@hfff2@qO@hfff2@O@83332@3333{O@83332@O@3@ffffnO@<3@ffffvO@I3@O@8333Z3@ffffO@~3@QO@̬}3@O@3@(O@ 3@ffff^O@3@O@ٸ3@ffffNO@3@3333O@hfff3@ffff&O@hffff44@3333O@8333_4@O@hfff&t4@ O@y4@3333O@@4@O@5@d P@yA5@%P@ w5@3333KP@̌~5@P@hfff5@3333P@8333d5@ffff"P@T5@3333G(P@G5@a.P@y45@ffff1P@`#5@3P@hfff&25@33338P@83333K5@=fP@@D6@3333gP@hffffF6@fffffnP@I6@ffff pP@V6@ffffrP@hfff]6@ffffuP@hffff6@,wP@8333w6@vP@6@ffffrP@̞6@ffffsP@ 6@wP@Y6@UrP@833337@oP@8333'7@ffffoP@87@PrP@k7@ffffzsP@83337@ffffsP@7@ffffuP@7@rP@'8@sP@<8@sP@g8@3333qP@Y8@tP@8333s8@3333vP@hfffƠ8@vP@̌8@ffff:uP@8@tpP@hfffƬ8@jP@hfff8@ffffjP@8@3333CjP@hfff=9@ffffbP@ Y9@^P@8333N9@3333VP@@L9@̐OP@A9@3333+IP@W9@PFP@\9@3333+DP@hffff_9@3333@P@hffffE9@ffff>P@`:9@6@ffffO@I6@HO@8333P6@ffff>O@Q6@̼O@6@@O@L5@O@hfff5@lO@̌5@ffff&O@5@O@83335@ffffO@hfff5@O@9y5@AO@ u5@yO@25@0eO@8333$5@^O@@5@9XO@hfff5@̼OO@hffff$5@AO@hffff*5@5O@R5@+O@hfffW5@#O@̌Z5@ffffO@9M5@3333kO@hfffA5@̬N@hfffb5@N@8333sx5@N@̬5@3333N@hfffF5@3333[N@ 5@N@5@N@hfff5@3333N@5@N@̌5@ffffN@8333ӆ5@3333N@hffff5@8N@hfff5@ffffN@83335@ffffN@8333s5@"N@hfff9@D(N@hfff&9@3333c,N@, :@ffff+N@L :@/N@:@p6N@9@3333N@Y;@ffff?N@;@4DN@83333;@DN@hfff-<@ffffIN@hfffF<@VN@<@ffffSN@̌<@4NN@<@|EN@Y<@>N@}<@3333#EN@8333<@=N@hfff<@ 0N@ <@p*N@8333=@N@8333^=@̄N@=@ffffN@=@N@L=@xN@ =@`N@Y>@TN@83333,>@3333M@hfff&(>@M@`>@M@8333s=@3333SM@8333%=@M@@=@M@l=@fffffM@hfffF<@iM@<@M@<@M@hffff<@AM@<@ffffM@hfff<@ffffM@83333t<@9M@yl<@ffffM@hfffU<@̤M@hffff6<@M@8333!<@̬M@<@ M@8333<@M@ <@ffffM@`<@M@83333<@M@y<@3333#M@;@M@U;@M@hfff:@ffffM@ :@3333cM@:@ffffM@u:@ffffM@833339@K@y35@K@<5@ffffK@ 95@3333ˍK@Y05@̴wK@83334@3333sK@833334@itK@hfff&4@8yK@4@3333SzK@hfffF4@ffff}K@4@K@ 5@ܬK@5@ffffnK@5@K@hffff5@K@5@3333K@5@K@5@3333sK@Y4@K@4@3333K@̭4@3333#K@833334@XK@̌e4@3333yK@̌4@ffffnzK@y3@uK@hfff3@LjK@83333@`K@3@!QK@,3@̼EK@3@ffff:K@hffff3@7K@9h3@3333k1K@2@,K@ 2@ffffN/K@l2@(7K@L2@ffffAK@̬o2@3333S_K@hffff2@^K@hfff2@(UK@83332@QK@`2@WK@2@|bK@R2@IkK@2@jK@1@hK@ C1@a]K@1@pSK@̬0@ffffVLK@L0@3333FK@hfff&`0@33337K@8333J0@I.K@hfffF=0@*K@8333/0@3333+%K@8333 0@"K@/@ K@pfff.@K@@333sn-@XK@@333,@\J@pfff,@IJ@@l,@̤J@pfff,@lK@̧+@IK@ +@ K@+@K@@333+@̤K@pfff+@J@pfff+@0J@+@̄J@,@yJ@pfff&X,@3333J@pfff,@3333J@pfff-@ffff^J@@!-@3333sJ@@333-@J@pfff$-@3333J@*-@ffffJ@pfff,@J@,@ffffJ@ ,@3333;J@+@3333J@pfff&+@3333;J@+@pK@r+@̜K@pffff*@K@K*@0$K@pfff*@̜4K@)@6K@pfff)@ 9K@&)@3333;K@(@3333k,K@@333(@3333S$K@YV(@K@9(@3333K@@333'@ffffK@@333f'@K@&@|J@&@J@pffff5&@,K@pfff%@fffffJ@̌%@AK@%@ffff K@pffff&@0K@@333 &@#K@&@0K@@333s%@ffff0K@̌v%@3333{(K@̌$@33338K@l$@X4K@@333sW$@9K@@333sI$@̄>K@#@y%@ffffL@%@L@%@3333%L@@333%@-L@@3333%@̼8L@%@ffff?L@%@BL@$@BL@pffff$@GL@$@lOL@pfff$@cL@@333$@ffffViL@$@3333L@L$@3333L@@333$@ L@Y %@!L@ %@ffffL@%@iL@pfff$@ffffL@pfff$@L@@$@L@L8%@3333SL@ %@!L@pfff$@3333L@@333#@\L@Y#@L@pfff @~L@@333s @mL@Y @\hL@Y @3333`L@ @ffff&[L@ @UL@4!@ffffZL@@!@ffff\L@̌!@qL@L!@L@̌8"@ffffL@"@L@Yk"@ygL@̌d"@YL@G"@ffff`L@Y""@̜eL@@3333!@,cL@@333!@ffff^L@pfffx!@PPL@pfffo!@3333EL@pfffW!@q?L@7!@3333AL@!@GL@@ @`HL@ @NL@pfffv @OL@@333S @ffffML@B @)L@@3333> @L@g @ffffK@\ @YK@pfffC @ffffK@̰ @QK@Y;!@K@YM!@ffffK@@333V!@K@Y%!@0K@F!@ԅK@pfffR!@33333~K@Y]!@3333[eK@L!@YK@ !@ffffLK@!@DK@Y!@;K@̌!@6K@K!@ffff2K@pffff@!@ffffN-K@@3333J!@%K@x!@%K@̌!@(K@!@X&K@@3333!@a!K@!@ K@@!@J@!@ffffJ@pfff#"@QJ@n"@3333J@"@J@@3333C#@3333J@pffff#@ffffJ@pfffX#@fffffJ@@333+#@J@٤"@ J@@i"@J@pfff!@J@pfff@ffffzJ@L@DtJ@@3333[@vJ@@3333@|xJ@@oJ@@ffffgJ@?@ffff8J@ffff@3333'J@L@1J@@̌J@fff@ffffJ@fffV@ffff>I@@333@I@@̄I@@3333@I@̉@!I@̡@I@@ffffI@fff@DI@ffffR@3333I@@333@xI@@I@@333@ffff^I@@333@tI@@333@ffffVI@@I@ @3333KI@c @hI@@3333 @I@ffff @8I@* @3333;I@ @I@ffff @ffffI@@3333@fffffI@@333@3333I@@3333@dI@@xI@@3333r@)I@L @ffffI@@3333@`I@ffff @@I@@3333 @ I@h @ffff^I@ @XI@@3333 @I@ffff@I@3@ffffnI@̐@3333I@?~I@ffffH?wI@?HqI@?hI@E?^I@3333?%I@|?H I@ffff?I@9?@I@?T I@?ffffH@gfff?H@?tH@hfff?H@43333?H@?\H@?H@?LH@?H@hfff?dH@l?dH@@fff憿DH@ĿH@3333࿙aH@33333333 H@33333333SH@ffff7ffffH@H@ffffXH@3333=3333H@ffff#H@H@ffffiffffvH@3333H)H@ffffH@H@,H@̼H@ ffffH@ffffTH@3333 3333gH@3333KYH@SH@RH@2̴PH@̜UH@}3333;YH@3333KQH@JH@333RH@̑3333RH@@fffffffDH@WLH@4eH@ kH@ ffffhH@3333^ bH@@fff ZH@@ffffXH@L<ZH@ 3333333[OH@ 3333EH@ 9H@3333{4H@`fff3333{.H@V3333-H@`ffff/H@ffff/H@`fff&u-H@5l,H@ 3333ffff&H@3333%H@ffffN&H@`ffff̤'H@O %H@`ffff-̜H@ hH@ ffffH@YQH@`fff|H@ 333 a H@L3333 H@ffffH@@ffffG@PG@?TG@G@`ffffHffffG@54G@ fffffG@3333 3333G@* ffff6G@ ffffNG@ G@ G@LE 3333G@G@@ffffG@ffffG@3333LG@@ffffG@_G@)ffffG@SYG@333nffffvG@|G@@fffkffffFG@3333۴G@=ذG@@ffffG@333yffff>G@ffffG@3333ħG@ffff̤G@$؜G@ffff\G@8G@G@L0G@3333۔G@&3333+G@̧IG@333&фG@@fff3333uG@@ffffnG@ygG@3333WG@ffffAG@G,G@3333)G@3333󿙙)G@3333W3333'G@X G@.8G@񿙙qF@ffff F@ffffF@3333F@ffffffff^F@\̬F@"3333sF@3333F@ffff.3333F@NF@u3333;F@3333F@3333F@33333333F@IF@ffffF@ffffE@@ E@`fffE@ 333ffffE@`E@`fffE@ 3333iffff~E@`ffff E@9F ̄E@0333s 9E@`fff E@, 3333E@0333s ffff>E@ 3333˲E@ 3333cE@!$E@T!ffffE@0333S!ffffΪE@̌ "ffffE@0"3333kE@,["ffffFE@`fffx"̔E@lx"3333 }E@["3333tE@ A"nE@L"1hE@!8fE@!3333#bE@0333"TE@0333"3333LE@!ffffJE@!ffffQE@̌!LE@̬!3333GE@̟!3333+fC@"̌]C@`fff"ZC@`fff"TYC@,"<[C@`fffE"3333_C@."ffffjC@!ffffC@`fff&!qC@L!C@L!C@@"ffffsC@@!fffffC@ "_C@`fff/",YC@ [" XC@03333"TC@ h"DC@03333m"3333[9C@_"ffff8C@`fff&1"D:C@`!̌AC@`fff&!ffffFAC@`fff!3333SBC@w!=C@,V!P6C@ !,9C@03333!ffff^&C@!C@`fff!ffffB@03333!B@l!B@!B@٠!$B@@!AB@!!B@`fff! B@`ffff!B@lz!̌B@2!B@ ffffΌB@`fffF ܉B@@B@`fff&V3333B@ 333s3333B@`fffB@`fff&B@ fffffB@̷3333B@t3333B@pB@ىܘB@@1zB@ 3333333sjB@`fffHItB@tB@`fff sB@ 3333PlB@`fff&3333K]B@YQB@`ffffaLB@`fffLHB@LdCB@ 333ffff6B@̌*B@`fff)ffffB@3333CB@;ffffN B@QB@4B@q B@@ffffFB@ffffVB@)B@qDB@Q,B@ 3333/B@ffff>6B@3333C@B@L3333@B@LPB@LYB@`fffw3333[B@Lffff`B@@ffff 3333^B@3333s ̜ZB@333 ̼`B@1 ffffaB@7 _B@@fffL|[B@@ffff]_B@3333;gB@@ffff3333cjB@qhB@@ffff3333k_B@@fffficB@ffffyB@ffffΝB@ffffAB@=3333B@!B@3333OffffVB@3333这QB@3333ffffB@VffffB@̌B@ffffB@̺lB@3333B@ffffpC@3333C@ffff̜(C@fffffؿ33337C@JC@4333s?0YC@?,aC@4333?ffffiC@y3333rC@ |C@0333;ʿ3333C@ տ3333cC@Կ3333C@E@̃@̌E@@3333@ȯE@(@E@&@aE@L;@ffff޳E@_@lE@@333~@E@̥@ffffE@ffff@ffffE@@3333=@ffffE@L>@E@fffJ@E@L{@3333E@L@ffffE@fffG@ffff&E@L@@E@@333@3333ÖE@fff<@E@L@E@@333v@3333CE@@3338@E@fff@3333E@fffG@3333{E@@ffff~E@fff@3333ӪE@@ѯE@u@3333E@̹@ffff^E@ @E@̂@E@@3333@ffffE@@1E@fff@3333E@̌ @9E@) @E@@333 @yF@!@ffffN,F@!@ffff6F@Y!@14F@Yd"@X)F@pfff&"@(F@@3333v#@3333 F@pffff$@ffffF@L`$@HE@}$@E@$@̬E@pfff&$@3333E@pfff %@ffffE@̌%@E@%@ffffVE@%@{E@@3333.%@zE@ J%@̄zE@@333j%@wE@pffffy%@1sE@%@fffflE@@3333%@3333fE@pfff&%@ffff^E@pfffU&@DE@^&@q:E@H&@8E@4&@3333S5E@LH&@1E@@333`&@Q2E@&@ffff65E@@333&@ffff.6E@@3333&@t.E@LF'@ffff$E@@3333'@ E@̌&(@ffffnD@Li(@D@C)@ffffD@̲)@QD@pffff *@̄D@*@3333D@pffff-*@ffff6D@pfff]*@3333D@pffff~*@D@L*@ffffD@ +@D@pfffV+@3333D@w+@)D@@3333+@3333D@pffff,@fffffoD@@333,@gD@&,@eD@pffff4,@iD@YK,@ iD@pfff&,@hD@@3333,@1aD@,@ffffF]D@ ,@ffffLD@@333,@LD@@3333,@PD@pfff&-@ffff.PD@@3338-@RD@ -@ffffUD@٭-@3333PD@Y-@,GD@@3333-@3333D@?1@ 8D@A1@3D@8333Se1@̌+D@hfffy1@P(D@8333s1@#D@83332@ffffC@hfff&82@ C@X2@3333#C@d2@C@,l2@QC@`|2@3333k D@u2@3333KD@hfffT2@x/D@@ 2@PHD@y1@SD@hffffy1@kD@8333sF1@3333|D@y1@D@hfffF0@3333D@90@3333D@ /@3333D@/@xD@0@3333D@&0@ffffD@l00@1D@hfff&*0@ffffD@0@D@/@@D@Y.@D@pffffV.@ffffD@@333s-@E@-@DE@̌],@3333@E@Y,@3333CXE@̌+@mE@+@ffffE@@333b+@E@ +@ E@@3333+@3333KE@@3333*@E@pffff)@E@a)@3333SE@@(@ffff.F@pfff(@F@pfff&(@6F@pfff&(@3333{\F@̎(@ffffjF@Y(@3333jF@(@0fF@Y(@0lF@@333(@ sF@ )@ffff{F@@333(@F@(@ffffF@̌s(@F@pffff(@ffff6F@@333s(@F@pfff&(@F@(@F@)@F@@(@F@(@F@@33339)@̤F@)@3333F@Y)@ffff.F@*@F@=*@TF@@P*@F@pfffi*@̼F@pfff&*@F@+@ffffF@@333A+@ffffF@ +@IF@̌p+@ffff6F@LF+@F@pfff'+@)F@+@3333F@pfff4+@ffffF@:+@3333F@@3333B+@ٍF@pfff&|+@~F@@333+@0kF@@333+@(jF@+@ffffjF@,@ffffvF@pffff.,@F@y,@pF@,@)F@,@.@ffff F@pfff&_.@F@@333.@3333SE@@333O/@E@pfff&/@33333E@ /@ E@@333/@E@/@3333E@/@E@hfff 0@̴E@̌!0@ffffE@D0@E@d0@̌E@̬0@fffffE@833330@3333;E@ !1@ffffE@8333sT1@̴E@̌1@3333+{E@̕1@xE@hfff1@rE@@1@3333lE@hfffF81@PE@` 1@ffffFE@ 1@E@B1@ffff{E@1@(kE@hfff1@fE@ )2@(QE@@U2@CE@y2@i7E@83332@6E@8333s2@33338E@Y2@33338E@hfff&2@)6E@y2@ffff2E@hfff2@d0E@2@ffffE@L3@ffffE@/3@lD@hfffW3@ffff>D@w3@ffffD@ٓ3@D@`3@D@3@dD@8333S3@ffffD@p3@ffff^D@8333t3@ffffD@hfffz3@AD@t3@3333D@8333v3@ffffvwD@hfffFb3@ffff6eD@hffffV3@TD@9X3@OD@8333sp3@1C@[5@ffff6@(C@ 5@)C@ 5@*C@5@#C@̌5@iC@y5@C@s5@4C@Yg5@,C@N5@3333C@ %5@3333B@5@ B@8333S#5@TB@̌45@B@I5@3333#B@LT5@̬B@̌j5@B@@5@@B@̭5@B@hfffF5@ffffB@,5@ffffB@95@\B@83335@ffff~nB@8333s5@`^B@,5@fffffB@hfff5@ffff&rB@5@3333~B@6@B@6@̴B@@"6@a{B@,*6@sB@,;6@pB@@`6@YB@a6@ffffRB@8333_6@̼AB@m6@ffffB@Y7@ffff9B@)7@3333[9B@7@FB@ 7@RB@83337@1cB@8333s7@@mB@6@B@6@9B@6@XB@83336@dB@hffff6@B@6@ B@hfff6@0B@7@3333B@83337@dB@7@B@Y)7@3333B@37@̜B@hfff@7@3333KB@@}7@XB@}7@`B@hfffFu7@3333B@hfffh7@QB@le7@ffff6B@X7@|B@@C7@ffff6B@833327@3333cB@̬%7@ffffB@̬%7@B@ 7@33333B@L 7@ffffnB@hfff& 7@B@`7@B@833317@B@8333k7@B@8333s7@ffffvC@hfff7@1C@7@YC@7@)B@7@ffffB@7@B@ 8@B@,8@B@83338@3333#B@83338@B@8333s8@HB@hfffF8@C@`8@C@̌7@33333#C@hfff7@)C@7@-C@8333ӑ7@̤>C@8333s^7@DCC@@7@3333TC@@#7@UC@833337@ffff^C@hfff&6@3333sfC@6@lC@`6@3333lC@83336@ oC@hfffƘ6@ffffqC@hfffF6@sC@y6@hsC@833336@ffffNyC@83337@3333ۄC@,6@C@`6@ffffFC@83336@C@hfff6@C@6@ffff6C@,6@`C@hffff)7@ffffC@83333+7@C@83337@ffffC@'7@C@hfff77@\C@hfffS7@3333cC@I7@C@;7@C@y7@3333C@83336@3333+C@hfffF6@C@83336@yC@6@D@6@ffffFD@6@a#D@hfff6@.D@6@6D@hfff&6@ffffn?D@6@3333DD@6@JD@6@KD@83336@3333CD@83336@>D@6@03D@ 7@3333&D@O7@̴D@hfffT7@3333 D@hfffFe7@3333C@7@HC@8333S7@̜C@83337@̼C@8333w7@ffffv D@hfffn7@ffffD@b7@iD@ m7@!D@ 7@ffffD@7@D@8333s7@C@Y7@@3333#F@hfff&/>@3333F@83338>@F@83333~>@ G@8333>@| G@ >@"G@>@&G@>@.G@>@̌@FG@hfff#?@ffffOG@R?@fffffNG@hfff&g?@|PG@83333?@3333^G@9?@ffff~cG@9?@ffffUG@83333?@3333;RG@8333?@PG@8333s?@3333+SG@8333?@ffff^\G@hfff?@3333vG@̬?@3333kG@@?@3333#G@Y?@ffff>G@8333?@ G@`?@,G@hfff?@}G@?@3333kmG@hfff?@fffffdG@l?@ZG@̬@@(G@ܣA@ffff#G@A@G@܁A@ G@4333A@P G@A@G@)A@G@٠A@G@9A@0G@A@OG@0B@YUG@B@RG@hfff#B@LTG@L7B@]G@hfffGB@aG@hfff&XB@ffffaG@̼eB@q[G@LwB@ffffiG@hfffB@(pG@B@3333kuG@B@\uG@̌B@3333G@4333B@DG@4333C@DG@pC@̴G@ >C@xG@4333IC@3333G@hfffaC@|G@hfff6^C@0G@yRC@)G@hfffFC@ffff>G@hfffUC@lG@4333vC@|G@ C@آG@ C@iG@LC@G@C@G@C@3333G@hfffC@ffffG@9C@G@fC@sG@̼PC@oG@hfff&8C@3333hG@hfffv>C@]G@ @C@3333TG@hfff+C@3333VG@pC@3333YG@iC@hXG@hfffB@3333OG@hfffB@ QG@B@lQG@B@3333DG@B@4G@ B@1G@4333 C@y2G@Y(C@G@4333?C@ffff G@@3C@ffff> G@'C@4 G@C@3333# G@C@\G@0 C@F@C@$F@4333s C@0G@4333C@G@pB@8G@4333B@XF@B@F@4333cB@HF@4333B@F@43333B@@F@B@3333F@4333#B@F@hfffB@HF@4333ӡB@̧F@hfffVB@3333ۢF@@B@ĦF@)}B@F@hfffnB@F@eB@qF@hfff6\B@F@|aB@ffffF@gB@ffffF@yxB@F@oB@9F@@OB@ffffF@hfffVPB@ffff^F@LSB@0F@4333xB@F@hfff6B@i|F@\B@sF@B@dF@hfffB@ ^F@`B@ffffXF@hfffFB@ffffUF@9B@TF@B@3333sYF@43333C@5F@'C@ffff/F@4333cQC@̴(F@[C@$F@)C@E@4333#C@3333+E@4333C@̄E@9C@̼E@hffffD@E@hfff&;D@ffffE@4333CD@ffff~E@hfffkD@ E@4333D@ffff&wE@yD@jE@D@3333k^E@D@dTE@4333D@2E@hfffD@E@D@)D@`D@3333CD@ D@D@4333D@3333KD@ID@D@B@D@)B@3333D@yB@3333D@~B@@D@̌cB@ffffD@4333RB@ D@hfff&KB@ЩD@@܊D@LX>@4D@Y=@ffffND@R=@ffff&D@%=@3333KD@hfff&=@D@@=@3333D@hfff =@D@ =@Q{D@hfff&=@3333 xD@B=@tlD@`]=@ffffgD@8333=@LaD@hffff=@3333KaD@L=@y^D@8333=@̬ZD@ =@ffffSD@@<@ffffPD@8333<@3333[DD@Y<@q@D@hfff<@=D@Y<@3333;D@ =@3333K6D@8333=@33331D@hfff&<@2D@Y<@00D@J<@ffff3D@l;@X/D@;@0D@;@7D@̬;@;D@8333S;@ffff>D@;@AD@hfff;@3333;AD@Y;@=D@9;@0D@8333;@,D@`;@ffff*D@y;@3333(D@hfff&U;@ffff0D@lP;@33335D@H;@Q:D@hfff&;@ffff9D@;@33332D@8333:@3333;3D@8333y:@@D@9P:@33333D@l.:@3333C@Y&:@C@':@ C@8333:@3333C@8333:@C@8333:@3333ӻC@Y:@ffffC@{:@ffffC@:@ C@83333:@3333[C@83333:@8C@83333:@3333C@8333:@yC@̌:@hC@hfff&:@\C@hfff:@̎C@l:@3333CC@:@ȁC@:@{C@:@3333#vC@:@̔wC@Y:@3333uC@;@̄qC@:@LcC@hfffF:@8^C@:@ZC@hfff:@TC@:@ffff.PC@y:@ffff^GC@hfff&:@=C@l:@3333S9C@$;@9C@@;@ffff65C@hfff:@̼/C@:@1C@83333:@̔5C@hfffF:@33333C@:@*C@,:@-C@8333S:@̔5C@@:@3333S>C@hfff&:@LGC@y:@3333PC@p:@3333RC@`:@OC@L_:@GC@n:@fffff8C@j:@ffff/C@W:@ffff^/C@lJ:@3333{#C@9U:@ C@̌m:@pC@8333S:@C@:@3333C@:@3333C@̮:@3333cC@8333:@̴C@:@3333C@:@ C@(;@QB@;;@DB@9A;@B@8333s9;@3333B@;@ffffB@hffff;@ffff6B@%;@3333CB@833334;@ffffB@ 8;@бB@ J;@B@8333S`;@̜B@̌f;@3333CB@hfff&;@3333B@;@B@@^;@3333B@L;@<@B@8333s9<@B@@<@3333uB@`<@ffff~jB@9;@ffffgB@;@dB@;@3333#aB@hfffw;@_B@83333t;@([B@Y;@̔WB@hfff;@YVB@hfff;@D^B@<@0`B@<@UB@<@ffff6QB@̌<@̼RB@83332<@WB@M<@ffffgB@{<@3333fB@<@ffffYB@ <@pVB@Y<@8VB@9<@[B@ =@3333XB@=@ffffQB@hfff=@KB@=@3333BB@̬$=@2B@@9=@)B@,Y=@!!B@hffff=@ffffB@ =@3333B@L>@3333B@L;>@ffffV'B@K>@3333$B@hfff&c>@3333#B@83333r>@3333"B@{>@3333'B@̌>@ffff9B@>@ffffNCB@>@ fB@>@ffffnB@hfffF>@lB@=?@ffff.iB@@Z?@fB@hfff&?@pNB@@@̄DB@hfff@@|9B@4333S$@@I"B@Y0@@B@4333SD@@ B@̼e@@B@v@@@ B@̼@@ffff. B@̌@@B@@@ffffnB@@@3333KB@9@@%B@A@ffff+B@Y&A@ffffVMB@LA@idB@ZA@̌hB@hfffgA@ffffNfB@xA@3333\B@̌A@3333CQB@4333SA@IB@A@3333kLB@4333A@ffffSB@A@ffff\B@A@aB@A@cB@A@ffff~lB@4333CB@fffftB@LB@mB@ B@3333SgB@hfffB@_B@ B@YTB@B@BB@A@33334B@A@'B@̌A@\B@|A@3333A@4333CA@QA@yA@3333A@A@)A@4333A@ٵA@@A@ffffެA@4333A@ffffVA@hfffA@ffffA@A@A@hfffA@lyA@A@mA@hfffA@PA@,A@FA@A@$?A@4333A@7A@A@ffffA@PA@ffffA@4333cA@3333@@A@q@@,A@A@@ A@ffff&@@ٓA@3333{@@hfffA@ffff@@܉A@{@@A@ffffi@@vA@N@@4333fA@!@@hfffVA@L?@4333=A@?@=A@?@43331A@{?@\A@ffffR?@A@M?@hfff@@2333S.?@P@@2333c!?@`@@ffff!?@@@2333?@@@P ?@@@ +?@hffffs@@fffff?@`m@@2333#?@W@@2333?@9M@@?@43333D@@?@i)@@̌A?@4333 @@K?@̬@@23333K?@4333@@??@4333$@@l3?@p@@y?@hfff @@2333?@hffff@@)'?@hfff@@2333s8?@?@|=?@hffff?@ffffJ?@9?@i?@hffff?@2333{?@̼ @@0X?@i@@PW?@?@?@8333?@?@?@̼?@hfffF?@̬t?@@?@Pu?@hfff1?@l?@9?@2333s?@L ?@p?@hfff?@?@8333s?@yv?@hffff>@̜p?@8333S>@2333cg?@ >@j?@Y>@?@l>@?@,>@ffffy?@hfff&e>@ffff&u?@X>@g?@8333O>@fffff[?@hfff&C>@Q?@9>@ffff&B?@hfff >@2333sA?@hfff >@2333C?@hfff=@<:?@8333s=@2333?@8333m=@l>@hffffG=@>@8333(=@ffff>@8333s=@̌>@hfff<@2333S>@8333<@2333S>@̃<@ ?@8333;@?@y;@1?@;@ffff1?@@;@2333s6?@?;@̼`?@hfff:@ix?@8333u:@?@̬9@2333?@a9@ffffF?@99@ffff?@hfff&9@̬?@8333s9@Y?@hffff9@2333#?@`8@ffff&?@hfff8@?@83338@3333 @@8333z8@?@83333!8@ffff.@@ 8@̼@@7@H@@833337@P@@LI7@ffff^@@833337@l*@@hfffF7@ffff2@@83333!7@\9@@833337@33333O@@6@W@@ 6@^@@6@e@@83333W6@p@@/6@u@@hfff5@ffffNt@@̬5@3333x@@̢5@w@@l5@3333Kf@@Q5@3333c@@83335@Dc@@4@3333CJ@@^4@3333#7@@4@@@4@ffff @@833333@2333?@hfff&3@I?@83333@ffffV?@ 4@ i?@83334@L?@ $4@ 2?@hfff&4@ ?@̌4@ffff>@`4@>@3@ffff}>@3@i>@̬J3@I>@̬3@ D>@2@YJ>@y2@ij>@02@>@hfff1@ffff>@1@ffffv>@hffffY1@?@83330@6?@8333ss0@0:?@0@2333C?@/@i\?@@333si/@)m?@ 1/@ffff?@pfff&.@2333#?@.@?@pfff.@?@ٷ.@p@@pfff.@'@@pffffZ.@2@@-@3333kA@@,@pF@@pffffy,@33333W@@@333O,@Z@@@333+@Ye@@pfffK+@@f@@+@i@@pfff&*@3333u@@@333F*@r@@́)@f@@pfff(@ j@@L(@m@@'@ffff@@@333sP'@8@@Y'@I@@&@ɜ@@&@К@@@333w&@ffff@@g&@ffff@@v&@3333â@@@3333&@ffff@@̃&@@@@333L&@3333C@@L+&@ @@%@3333+@@%@P@@%@3333k@@ r%@@@h%@ @@pfff&m%@1@@$@@@L$@8@@pffffQ$@ffff@@$@4A@$@ffffA@@3333!$@ffffA@<$@#A@f$@3333K,A@%@EA@a%@VA@%@1qA@pffff%@ffffNA@=&@A@pfff&&@A@pfff&&@A@Y&@3333A@@3333&@!A@@%@3333A@`%@ffffVA@.%@A@@333%@ffff&B@$@3333kB@$@ B@pfff& %@3333c)B@pfffH%@ffff5B@pfff%@ffff?B@@3333%@3333_B@@333&@̴kB@@&@oB@@333s'&@̼{B@&@HB@%@ffffB@L%@3333wB@$%@pB@L %@3333KeB@$@̬]B@pfff&$@dB@ $@nB@pfff`$@ffffVB@̌d$@YB@,$@)B@pfff#@ffffB@L#@B@@#@ffff>B@@333#@@B@#@3333SB@pffff#@B@̌#@B@L#@̌B@̌#@ffffFB@@`#@B@@333H"@B@pfff&"@3333B@pfff!@B@@3333'!@ffffwB@A @fffftB@L@̜mB@*@̬pB@Ln@B@̺@ffffB@@3333@3333ӋB@@3333@{B@fff@xB@̵@uB@@333M@3333cB@@3333@B@@333O@B@@3333xB@LB@nB@fff@YfB@̲@tVB@.@RB@L@VB@L@ffffngB@fff@3333cnB@L@3333rB@ffff;@ffffrB@* @ffffeB@ffff@idB@@3333^B@@3333@3333LB@@3333@ffffNB@?ffffHB@?BB@?33338B@gfffN?3333-B@gfffz?3333!B@4333?B@i?B@̌?DA@0333A@dfff6ȿA@2333sֿ|A@EۿffffFA@\ffffA@3333gA@3333ItA@_A@ffff3333˦A@3333pA@̜A@@ffff$3333A@ffffVA@cffffΏA@3333lA@@fffffffNA@3333\A@A@@ffffhA@ffffVA@@fffyA@!A@33333333A@@fff 3333A@@ffff( A@ 9A@̋ ffff֣A@MYA@(A@`fffQ3333A@`ffff3333kA@LYA@`fffkA@A@Y3333cA@Y3333A@̌A@`fffffffA@ffffVA@}A@`fffqA@̔A@̌0A@iffffVcA@`fff3333A@ @@`fff&H@@?@@03333 3333@@0333!P@@L1!@@`fff&!u@@}"ffffFI@@̌"0>@@"3333@@`fff"ffff @@0333Y#2333?@ #2333l?@̬#2333?@03333#ffff>@@#ɷ>@03333#2333>@ً#fffff>@LN#2333r>@`ffff?#ffffFZ>@̌U#>@`fff|#L=@̌#)=@`$23333=@0333f$`a=@0333$=@Y%p<@0333s)&<@ &̬<@@&a<@'2333cO<@'!<@0333(i<@Y)y;@)ffff;@*2333;@Z*ܧ;@`fff&*2333Co;@0333*%;@0333*fffff:@&+0:@Ld+ffff:@y+ }:@03333V,Yj:@,ffffK:@`fff,2333@:@,̼):@`fff -9@`4-9@j-dfff69@-dfffvg9@0333-Y89@L- 8@-4333C8@`fff.8@0333`.4333z8@03333,/8@9/43337@0333s/,7@/dfff7@ /7@9/4333C7@ٵ/43337@0333s/̜7@/7@`fff/7@/y7@0333S/l7@0@:7@0333507@0333s+0,7@̬3043336@`fffM0dfff6@`fff[0433336@0`U6@0)@I0^)@09n)@0S)@|t0`fff?)@`q0 8)@0s00333S))@0333|0`fff))@003335)@y0)@0333003333 )@0(@0`fff(@90̬(@0333o0`fffh(@0333O0l|(@̜>0`ffffy(@`fff6A0i(@Q0I(@S0l(@9F0'@p#0`fff'@`fff/0333S'@`fff&/`fff&'@03333/'@,/'@`fff/`fff'@`fff&M/'@`fff/'@.'@L`.`fff'@9.`fff'@0333(. '@$.'@03334.0333'@`fff&D.̌'@0333k.'@.Y'@03333.`fff'@ /`fff'@/0333r'@0333s.;'@`fff&.>'@`fff&.V'@0333u._'@̬>.R'@03333%.03332'@S.0333s)'@0333S.`fff%'@0333.l&@.0333&@.̌&@`.̌&@.&@`ffff.0333&@.@&@.L&@`fffF.9o&@̌.0333M&@ن.`R&@0333n.P&@q.0333&@0333\.`fff&@̌1.0333G&@0333.̬H&@0.`fff&@`fff.Y%@9.L%@Y.0333ӛ%@03333-Y%@-%@-`fff%@`fffƬ-0333%@`fffF-%@`fffƃ-`%@c-`ffff{%@Z-`%@/-̌%@,-`fffFx%@,:-0333S<%@8-`fff%@0333,`fff&$@@W,A$@,,,`fff&A$@ ,0333SH$@0333S,0333:$@03333 ,$@`fff+#@`fff+@#@`fff+0333#@l+̌#@,a+`fff#@`ffff+ٳ#@@Q+#@0333sP+9G#@a+0333S#@0333"+9#@`*03333"@`fff*`fff"@*"@*o"@*0333SW"@0333* ("@ٕ*03333"@0333*̌!@0333N*!@0333s*`fff&!@`$*0333s!@0333i*̬!@s*,!@0333t*Ld!@]*`'!@`fffF>*0333s-!@,-*`@!@ )0333:!@)P!@`fff)0333sB!@l))!@ )̌ !@`fff+*y @P*0333s @h*0333 @*`fff @`fff*`fff @Lg*0333 @`fffFL*m @`fff *f @0333)`ffffJ @̬)@ @ )03333m@`fff)YF@Y)*@,e) @0333#)`ffff@Y)0333s@`fff(Y@Y)0333@̌(.@(@`fff(̌@y(^@'0333@`fffw'0333Z@0333S'0333@'L@L&@0333S&:@0333%@@9%=@Lj%0333@03331%@$Y@$O@ O#`fff&@"@̬C"03337@ `fff&\@ 3333`fff@٣w@ .g@L @ 333`fff@Y;-@ `fff@ 333sa@1 @ 3333?0333@ 33303333 @LB[@L?̅@`ffffk @`fff&̌@Yx`ffff@W@`fff&!L@@@`ffffL@L`fff@`ffff0333@&`fff@̌?@ 333u`fff @ǒ@6@m`fff4@ {`fff&=@03333,@@ ̅@ `fff@ 0333sW@ k@6 `fffd@Y `fff@@5`fff&@3333'0333@`ffff@ @ t@Z@3330333sT@L`ffff/@ @1`fff@! @333`ffff@ @n@33337`ffff@`fff&@ffff @̆`fff&@l03333F@߿0333@Qֿ@1E@hfff?@?0333 @gfff?Y @d?0333=@ ?`fff&@?@ffff?4@?̌[@ffff?`ffff@ffff?@3333?`fff @K@0333O@̦@z@.@@@3333 @0333s@q @@ @ @ffff @Ld@ffff@U@ffff^ @`fff@ffff @@@@3333 @L@ @@fff@@@@333@0333d@̈@`ffff@@333q@0333@+@`fff0@L_@@l@@s@0333@@03333i@fff@0333@@3338@@@3333O@@M@@@333f@@~@@0333@@`ffffr@L@LL@(@YO@@`ffffI@@Y"@@`ffff@@`ffff@fff2@@ @@fff@0333@@v@x@Y@ffft@ @fffz@0333@@0333@ffff@̌@@@fff@0333@@@fff@̌@@`fffZ@fff6@@fffY@@1@`fff@@3333@ @@0333Z@ffffN@)@@ @@L+@@@@@fff@|@@V@@<@3@`fff&7@@3333@`fff&U@@`fffS@fff7@]@fffQ@`ffff@h@@x@̀@@3333@`ffff\@L@`fff^@@3333@_@q@L~@,@`ffff@@3333+@^@fff$@`fff@@@&@@L@@L[@ @@333x@0333@ffff@ @@333 @ٖ@ffff@@@Yv@Y@L@ffffN@Y@L@@@333@r@@3333#@0@fff@̌8@@333 @03333a@@0333@@`fff@@3333C@`ffff>@@333@0333@4@@ @03338@ @;@@333 @ٟ@@333w @@@pffff @`fff&@pfff& @̌L@̌ @LA@ @`fff&@!@@pffff!@@!@Y@$!@`fff&@!@`ffffl@@!@I@&!@@P!@@a!@0333s3@R!@@@333sj!@03333@!@0333Q@@!@03333K@!@`fff&Q@pffff!@J@pfff&!@ 7@@!@@!@`ffffn@@3333!@03333)@@!@0333@ "@]@L:"@ *@̌"@@@"@@@3333"@`fff@"@`fffg@"@`fff`@̌"@L@pffff#@@pfff"@0333C@ #@>@pfff#@@pffff3#@̌@V#@N@@333`#@9@pffffL#@̌@pfffG#@@pfffx#@ @@333z#@@A#@@/#@ 333@#@`ffffb@Y;#@`ffff @pfffH#@`fff @ #@ @X#@M @#@`ffffz @#@ @#@`fff@Y#@U@@3333#@ 3333@#@`ffffP@#@o@@3333#@ 333@@3333#@? p#@@ffff?K#@?pfffC#@@ffff ?pfff&+#@̤? "@?@"@?"@@ffff:?"@3333? #@3333?pfff2#@?.#@?&#@̸?@333s@#@3333?pfff&@#@ffff6?pffff<#@r?3#@*?#@?@333#@?"@ffffF?@333"@?L"@̪?@3333"@ffff&?@333"@)?#@?pfff#@2333?̌#@$?$@?#@2333?@333#@`fff? z#@? &#@?@333"@2333s?"@?@333"@y?pffff"@?@333"@?̌"@3333w?̌"@dfff?"@8333ӭpfff"@4333{ֿpfffE"@X)"@ffffpffff"@`̌!@3333Ǒ!@ffff ̌!@3333@333!@h!@@!@L"@Y"@{̌"@ffff$̌#@@333 #@̒ "@@3333'"@3@"@"@@3333 "@pfffP"@qL"@̞@333~"@x"@3@3333"@@3333Epffff"@ffffP"@@3333"@eY"@ffffL "@r@333"@@333"@8#@Opfff%#@.#@ffffX?#@LZ#@@3333Š#@N#@ffff #@@3333$@@3333fpfff$@̚$@#@ffff@333q#@ل#@&pfff&$@$@+%@ffff9 H%@@3333/ @333s%@} %@L pffff&@pfffB&@T&@@333pfff&@ V'@@333'@pffffC̏'@̴@'@@3333'@Y'@v'@Lpffff(@pffff (@pffff@333s(@$8(@pfff@333Z(@Li(@@3333\(@'O(@pfffpfffe(@pffffm(@pfff{(@@333:L(@̔(@pfff(@@333s)@L\)@pfffL)@̂)@j@333*@@3333Xpfff"*@u*@pffff̔)@pffff)@/(@LVpfff(@^ (@Lpfff&(@̿pfff(@pfffipfff )@\)@@333)@pffff.*@pfff*@L *@@ @333s*@ !@333*@?!̷*@_!̌*@"*@L!̌'*@Y!/*@hfff!@333*@83333!@)@hffff!@)@"pfff&*@8333u"@333O*@"d*@8333#@3333k*@ h#@3333*@L#*@8333s#pfff*@hfff$@3333+@hffff$YD+@L%Yq+@hffffD%Yz+@hfff%̪+@%pfff+@&̌+@&+@hfff&'_+@hffff?(pfff&2+@(*@8333s )LS*@hfffM)pffff)@hfff&))@83333*)@hfff&*pfff)@̂+(@,(@hffffF-%(@.@(@/̌'@D/'@̌p/ '@hffff/@333s'@8333/@333'@hfff/ '@ /̣'@0L'@@0pffff'@ 0@333s|'@?1q'@w1̌w'@@1@'@4333s2'@@E2(@x21(@y2L(@hfffF2(@@2̌*@94@3333V*@hfffF/4*@ 4@333*@̬4+@hfff&y5@333+@L5L+@5̤,@06@333,@r6L -@ٳ6@3333 -@ 6,@6pfff&,@6,@l6,@43336,@ 7,@G7pfff,@hfffz7pffff,@43337,@hfff 8-@433338A-@L8@3333-@8-@9-@4333?9pfff&-@[9@3333-@9-@hfffƹ9-@L9-@lQ:@333s1.@m:@3333G.@ :S.@hfff:Y?.@:D.@:@333sn.@:@.@hffffF;ٮ.@4333b;pfff&p/@@;pfff&/@ '<83330@4333S;X1@q>l1@?hfffF1@b?hfff)2@?52@4333?̌O2@̬@8333sT2@"@hfffFS2@4333@@9@2@yS@ 2@4333_@Y 2@hfff6c@1@4333Z@833331@`@1@i@83331@4333{@Y1@@1@@hfff&2@@hfff(2@@B2@@9O2@@n2@@t2@4333@ w2@4333@Z2@43333@YU2@ A Z2@ A i2@hfff%A,v2@hffff,ALv2@4333A2@ A̬2@ A2@hfff Al2@43333 Ǎ2@4333 A 2@ Ǎ2@ Ahfff2@ A92@4333%A83332@.A2@).A2@,A,3@,A,&3@\5A>3@hfff4AhfffG3@7A̬T3@hfff?AR3@IAYL3@NA9d3@hfffMǍ3@l`A3@`A 3@)cAhfffF4@4333dAhfffFo4@AAhfff4@hfffF;AY4@P8Ahfff4@y1Ahffff4@ /Ahffff5@̬.A?5@4ǍY5@@4A5@/A5@4333/A>6@Aj6@4333Ahfffƍ6@IAL6@PA83336@hfffAhfffD7@4333c A8333Y7@4333Ahfff7@@hfff7@4333@.8@A8333s8@hfffVA8@A83338@hfffA9@@8333s+9@@,z9@A9@hfffA`9@lAhfff9@@L9@Y@8333S9@ @8333m:@9@:@̌@8333;@hfff@ ];@hfff&@;@I@8333S;@hfff@6<@hfffvb@ s<@4333O@ <@%@ =@hffff@{=@?83333=@lx?̌=@l?=@4333sR?hfffI>@Y>hfffx>@>>@hfff&o>̬>@43333>?@=+?@@=U?@`=9?@hfff<9?@<8333?@@<|@@<4333$@@1̼0C@̌+1QC@ 1UC@ 1L[C@4333 1`C@ 1@qC@hfff 1`zC@,1̊C@ 04333CC@̌04333C@hfff0 C@4333S0C@w0C@hfffo0,hfffKD@hfff+GD@=+4333sGD@+hfffED@*̜JD@*hfffFD@hffff*hfffHD@hffffr*@HD@;*`ID@̌*HD@hfff&)7D@Y)43337D@83333)L9D@@)4333FD@83333)9ID@L)YJD@hffffE)0FD@ )Y>D@(hfffBD@(,AD@83333(0@D@hfff&=( DD@Y(hfffVAD@',?D@Y'p7D@̌P';D@&3D@&43335D@&hfff>D@[&4333ED@!&pCD@ &@D@83333%BD@8333%pLD@L%I>D@% GD@8333n%LND@8333R%4333#BD@"%hfffV;D@$9D@$7D@ $43331D@$hfffD@83333{$hfffD@g$hfff D@83333P$hfffC@8333Q$C@@/$C@@ $4333C@@$4333SC@@#,C@#,C@s#,C@hfff&(#C@hfff"hfffC@̌b"4333ùC@!4333sC@!4333C@@!LC@ q!C@@ ̌C@8333 hfffC@Y| 4333sC@hfff hfffֶC@L@LC@̼C@&C@L43333C@]yC@hfffvC@hfffC@hfffvC@@333hfffƤC@B@@=@̌<@@=@iH@@ffffV=@hfffR@@fffff=@Y\@@2333=@4333#b@@23333s=@hfffg@@ffffff=@po@@ffffFI=@4333@@2333=@@@p<@4333@@<@ٙ@@<@hfff@@ffffV<@4333C@@c<@ @@lA<@P@@23333 <@hfffA@0;@,A@;@hfff(A@2333;@)3A@<@̬6A@2333C<@hfff&9A@y[<@OA@ffff<@4333C^A@ffffFE=@̜lA@n=@sA@23333z=@|A@ffff=@}A@ffff|=@4333yA@Z=@IfA@2333s<@4333cA@<@hfffvWA@̜C<@NA@%<@PA@2333<@l\A@2333s!<@iA@<@hfffA@ffffF<@A@<@@A@ٻ;@iA@ffffn;@A@@B;@4333A@ ;@B@:@ B@ :@4333B@2333C:@hffffBB@:@lVB@2333 :@YB@4333#9@aB@dfffV9@nB@dfffF9@uB@4333#9@ B@dfffJ9@4333B@4333&9@)B@9@hfffB@dfff8@hfff6B@43338@hfff&B@8@4333SB@dfff8@)B@4333u8@4333B@J8@B@G8@PB@@F8@hfffB@08@B@dfffv/8@)B@43338@ C@8@$C@dfff67@i;C@<7@iEC@4333ӎ7@`ZC@dfff6N7@hfff`C@̼17@fC@p 7@4333jC@433336@hfffvxC@6@4333qC@6@)xC@dfff6@4333C@4333#6@,C@6@C@6@hfffFC@̌d6@4333C@,K6@YC@46@hfffC@6@4333s~C@5@ЃC@dfff5@hfffC@5@4333ӒC@܄5@IC@n5@C@4333sO5@hfffVC@dfffV4@C@̬4@̌C@dfff4@9C@c4@)C@K4@4333S D@4333D4@=D@4333S3@hfffND@dfff3@,aD@dffff3@hfffvcD@dfff3@4333SeD@y3@hffflD@dfff&3@hffftD@y}3@َD@ 3@4333sD@433332@lD@dfff2@4333CD@dfff2@`D@̬2@4333CD@4333s2@D@A2@9D@dfff2@D@1@E@Y1@%E@Yo1@̌*E@4333A1@1E@Y1@4@L@4333c8@1L@̬8@/L@9@hfff.L@4333Ñ9@ &L@43339@4333S'L@dfff9@hfff&*L@9@4333/L@9@L5L@ffff:@y5L@I5:@43337L@2333S:@4L@ffffY:@y0L@9[:@Y,L@IP:@'L@ffff6<:@<L@2333C8:@@L@̬::@ L@5:@L L@ :@̌ L@2333 :@9L@9@yK@4333C9@K@dfff9@yK@d9@,K@L9@٦K@<9@K@dfff 9@hfff_K@y8@YTK@,8@4333OK@ 8@LJK@4333C8@pDK@8@?K@4333sv8@̬:K@dfff[8@43332K@dfff6G8@4333&K@A8@K@4333+8@YJ@8@J@8@0J@433338@`J@dfff%8@RJ@dfff'8@hfffvAJ@8@ J@dfff7@,J@7@I@@7@I@8@hfffVI@4333#8@@I@ A8@ I@dfffFC8@I@@8@4333I@4333M8@I@4333V8@I@4333CI8@4333sI@LI8@hfffI@dfffN8@hfffI@Q8@I@4333#W8@YI@dfffz8@̌I@8@4333I@ 8@4333SI@y8@LI@4333s8@I@dfff&8@hfffƶI@43338@hfffFI@8@ I@8@I@ 9@ I@%9@I@4333H9@I@dfffc9@PI@s9@ I@4333S9@4333sI@9@@I@9@4333I@43339@̱I@:@4333I@<':@hfff֍I@:@hffffI@@9@sI@\9@0oI@ٜ9@̼fI@@9@hfffaI@q9@hfff`I@dfff6f9@cI@l-9@4333clI@y8@kI@43338@hffffI@ 8@\I@8@\UI@̼8@iGI@09@hfffAI@4333N9@4333C:I@l9@$I@9@hfffI@4333s9@hfffFI@|9@̬I@̼9@` I@9@ I@i:@hfffI@2333s:@I I@2333c:@PI@ffff:@hfffI@̼:@`I@N:@̬I@g:@,I@t:@I@:@4333sI@ٛ:@ I@2333:@`I@:@hfff I@):@<I@ffff֨:@,I@2333:@9H@23333:@hfffH@2333:@4333H@&;@H@2333S.;@ H@|O;@iH@ p;@hffffH@2333#~;@)H@9;@ H@p;@hffftH@ ;@ fH@l;@4333SgH@;@jH@;@̌gH@Y;@ cH@ffff;@,PH@!<@4333BH@2333Z<@?H@r<@43338H@<@1H@<@hfff/H@<@l+H@fffff<@` H@<@hfffH@<@ H@23335=@ H@ffffF=@hfffH@Z=@4333G@2333b=@G@]=@43333G@]=@G@̜d=@hfffG@̼j=@4333G@ffff|=@G@=@0H@ffff=@4333s H@@=@\H@̌=@lH@<=@hfff H@0=@H@ffff=@G@ffff&=@hfffFG@=@4333G@ffff>@P H@ >@4333#H@y >@4333c-H@=@4333#:H@@=@4333EH@\=@9LH@̜=@UH@@>@̌jH@ffff >@`oH@>@hfffuH@2333>@PtH@=>@4333rH@S>@YuH@2333e>@H@2333Ss>@@H@̬>@H@i>@̼H@x>@hfffH@i>@\H@`>@PH@2333#h>@hfffFH@2333e>@@H@_>@H@\U>@4333H@2333N>@ H@fffff!>@hfffH@i>@hfffH@5>@) I@23332>@I@P >@I@ffff=@hfffvI@ffffv=@hfff1I@ffff֭=@4333EI@I=@hfff&SI@k=@UI@W=@4333RI@2333S6=@lVI@ffff%=@4333eI@=@pI@ =@pI@ =@hfffkI@ffff<@nI@2333<@hfffI@ffff6<@I@2333<@4333I@<@pI@fffffo<@hfffVI@ffff8<@4333I@!<@`I@ffff;@hffffI@<;@II@P;@hfffI@ffff&;@J@ ;@J@;@Q@b6@4333>Q@PJ6@@Q@`26@DLQ@43335@4333XQ@5@bQ@dfff5@hfffoQ@dfffv5@43333Q@dfff-5@hfff&Q@<5@4333 Q@dfff4@ Q@̌4@LQ@4@4333Q@dfff&4@`Q@4@̌Q@dfffv4@R@'5@hfffR@\95@AR@5@lR@dfffF5@hfffv R@l5@ R@95@hfffR@i5@aR@43335@hfffR@5@4333 R@43335@Y R@5@4333R@43336@R@6@̜R@p06@hfffR@4333>6@4333 R@ E6@IR@,E6@hfff.R@4333?6@%R@43333G6@,R@|C6@3R@;6@\-R@ 56@0(R@36@d#R@4333(6@l!R@5@̄'R@433335@,R@5@8)R@ 5@4333%R@5@"R@4333S5@hfff5R@5@>R@dffff5@43333GR@5@pAR@5@3R@43335@-R@ 5@@'R@9v5@hfff*R@dffft5@hfff/R@dfffx5@+R@̌o5@'R@9_5@P,R@y-5@0R@!5@hfff4R@5@4R@dffff5@43335R@dfff4@@8R@4@433339R@94@d8R@,4@`-R@4@̼*R@3@4333C+R@dfffF3@4333,R@43333@.R@ 3@)3R@43333@i0R@dfffVs3@0R@dfffi3@l2R@\3@hfff.?R@dfffG3@3R@dfffL3@2R@@3@`3R@83@d3R@L3@4333k5R@2@̤9R@dfff3@hfff6>R@@'3@4333[@R@dffff3@̄>R@\2@̄9R@i2@̼7R@ܮ2@8R@2@4333:R@|2@\R@`B2@̜?R@43332@CR@ 1@IR@dfff61@IR@dfff1@hfffNOR@433321@4333UR@u0@ ]R@&0@x^R@4333 0@fR@/@4333kR@0333j/@hfffnR@YP/@LuR@Q/@dqR@hffff%/@hffftR@/@hfffvR@hfff.@̤{R@@.@@sR@@.@xR@hfff.@|R@hfffF&.@R@0333-@hfffR@-@hfffFR@0333j-@R@̌L-@qR@&-@hfffvR@L,@4333kR@,@4333R@n,@hfffޝR@0333sV,@R@,@R@hfff+@R@0333U+@R@*+@4333R@̌+@PR@'*@4333cR@`fff&)@R@l)@4333R@ !)@hfffR@0333s(@̴R@0333 (@4333#R@'@ R@ٟ'@R@h'@YR@0333&@4333SR@9&@hfffR@y&@4333 R@0333s%@hfff&S@0333$@S@l$@ S@f$@T S@S$@̄ S@,$@AS@l $@4333S@03333 $@,S@ #@\S@̌#@S@y #@ S@l#@4333S@,j#@S@#@8S@#@4333S@̬#@hfffS@YZ#@hfffS@y"@S@@y"@S@`ffffj"@4333S@`fff`"@1S@YR"@S@y."@4333k#S@9!@'S@0333!@=S@`fff @8DS@ @4333KSS@`ffffJ @ aS@( @̔eS@B @LqS@03333a @كS@`fff @hfffS@!@̴S@`fffS!@QS@ !@S@!@S@`fff5"@S@"@S@0333"@TS@b"@hfffS@"@S@"@S@,"@hfffFS@̬"@S@"@4333ӺS@"@(S@̬!#@4333ÿS@]#@S@`fff$@4333;S@Y$@!S@l$@hfffS@`fff$@hfffS@`fffƨ$@4333S@$@hfffS@0333s$@qS@0333ӛ$@̤S@`fff&$@iS@`fff%@PS@d&@tS@`fff&@4333#S@`ffff&@\S@`fff&@hfffS@&@hfffS@0333&@4333CS@̌&'@hfff^S@`ffffa'@S@@'@S@̌x(@hffffT@0333s(@( T@l(@T@0333sa)@T@*@̔T@*@PT@0333+@T@hffff6+@ T@0333sm+@T@hfff&6+@T@hfff +@hfffT@Y*@4333T@hfff&_+@T@hfff+@\T@hffff+@1 T@,,@hfff&T@hfffl,@T@,@4333 T@hfff,@p T@hfff,@hfff T@'-@PT@0333-@4333kT@hfff%.@xT@0333.@T@hfffk/@T@hfff/@a)T@@/@L-T@0333/@ 2T@0333/@4T@hfff&/@X7T@/@̼:T@0333/@4333>T@hfffF/@̔?T@0333/@AT@L/@tHT@l/@DOT@4333C0@PRT@IV0@YT@]0@̌mT@U0@4333pT@YT0@hfffT@@|0@T@4333S0@T@43330@̬T@0@hfffT@dffff0@hffffT@@0@T@0@4333 T@43330@hfffVT@4333c0@4333T@1@hfffT@ F1@̄T@9v1@T@dfff1@T@4333c1@T@2@T@43332@U@J2@ U@̌f2@hfffU@43332@'U@4333c2@hfff6,U@dfff2@/U@4333 3@X1U@ 3@pNU@4333#3@4333C\U@dffff3@hfff[U@)3@̼WU@̭3@NU@3@KU@I3@4333kJU@43333@OU@dfff3@p]U@Y3@4333C`U@@3@hfffcU@3@4333cU@43333@hfff`U@dfff3@_U@i3@dU@4333c3@hfffvU@3@hfff֍U@4333S3@4333U@`3@4333cU@dfff3@hfffU@3@U@4333 4@4333˒U@4333 4@U@4@U@43334@4333U@+4@hfffU@0P4@4333;U@[4@̰U@Lk4@U@Ɉ4@4333+U@4@hfffnU@<4@hfffU@̼4@TU@04@U@95@4333U@<5@U@dfff]5@qU@433335@U@|5@hU@L5@U@433335@4333U@P5@@V@dfffF6@V@ 6@1 V@)6@PV@dfff.6@V@p66@4333U@IA6@@U@4333_6@̤U@4333D6@4333V@̼76@ V@#6@hfff V@l6@\V@dfff&5@4333V@43335@V@4333â5@<V@P5@hfffV@dffff5@hffffV@5@̌V@,5@4333V@@5@4333k%V@43335@4333c&V@5@hfffF$V@dfff5@)V@96@hfff6*V@4333#6@T-V@`6@̼.V@< 6@`/V@4333c6@<,V@dfffƻ5@hfffv,V@43335@-V@95@hfff/V@5@hffff5V@P5@6V@43335@4333:V@05@=V@05@hfffNCV@4333s5@BV@95@AAV@i5@X@X@ @̌X@0333s @hfffX@_ @X@@[ @hfffVX@l~ @X@ @X@`fffF @X@, @hfffX@0333s @yX@ @hfffַX@@ @TX@`fff@DX@`fff&@4333X@@X@L@̼X@L@X@`fffy@9X@>@4333X@`fff&}@X@`ffffV@X@`ffffQ@4X@`fff&l@dX@ @hfffX@ @̼X@@X@l@4333X@0333@X@`fff@Y@@4333# Y@L@Y@`fff@Y@@Y@`fff@Y@Y@LY@Y-@T'Y@`fff@T'Y@`ffff~@hfffN*Y@`fff&@0Y@̌c@2Y@0333@4333s0Y@@-Y@̺@ 2Y@`ffff@4333{6Y@ 3336@hfffAY@`ffff @4333cGY@ 333 @1SY@ 333 @!UY@# @̬VY@@RY@`fff@|VY@ 3333@ ZY@@4333CaY@x@rY@ 333@xY@`ffff@QY@`fff@hfffY@V@Y@@ffff?hffffY@@ffff?hfffY@?Y@3333?YY@?̼Y@E?0Y@3333S?4333sY@1?hfffFY@?Y@%?tY@F?pY@?Y@@ffff?hfffZ@D?Z@z?pZ@3333?Z@#?4333[Z@?I Z@?Z@7?Z@3333?hfffvZ@̰? Z@̐?Y@@DY@`ffff@4333Y@̤@4333cY@ 3332@ Y@L@ Y@w@4333{Y@ 333 @|Y@L @hfffY@ 3333* @Y@`ffff^ @4333+Y@ 3333'@Y@@Y@0333@ Y@̌@̜Y@0333f@4333Y@0333s @hfff6Y@@@Y@̌@Y@LA@4333Y@`ffff@43333Y@@s@ĕY@`fff&@Y@L@xY@ @hfff&sY@@PgY@ @hfff_Y@ v@YY@`fff&@4333SSY@@IY@`fff&@$AY@q@2Y@̌@,Y@0333S@̄%Y@03333@XY@@@4333Y@Y@Y@@ Y@̌@I Y@`fffe@ Y@@lY@@PY@`fff&@Y@`fff@4333Y@YV@)Y@4@4333Y@`fff&6@XY@*@IY@0333s@hfffY@@"Y@Y@< Y@`ffffY@hfffY@`fff@Y@y @4333Y@0333s @hfffv Y@L!@4333+ Y@0333 @ Y@ @hfffFY@, @Y@0333!@TX@̬-!@4333{X@̬W!@hfffX@9"@)X@`fffc"@yX@`fff"@4333SX@"@4X@lm"@xX@ls"@@X@̇"@hfffX@"@4333sX@`fffF"@hfff>X@A#@IX@0333w#@hfffX@L#@tX@0333Y$@hfff.X@ $@X@$@0X@$@9X@`ffff#%@)X@0333s%@4333X@3&@X@,n&@hfff&X@&@hfffnX@0333R'@hfffX@`'@4333X@̌'@X@L(@LX@0333sW(@\Y@(@X@La)@X@)@Y@`*@DY@̬W*@dX@hfff|*@hfffY@0333Ӵ*@Y@ *@Y@ *@T"Y@hffff+@hfff&Y@hfff"+@)Y@hfff +@:Y@*@̜=Y@,*@4333)@hfffEY@`fffX)@y\Y@`fff<)@PnY@0333`)@|uY@G)@hfffxY@/)@4333s|Y@ )@43333Y@0333S)@hfffY@0333(@Y@̩(@hfffY@ (@̔Y@`fff(@hfffY@0333S(@țY@`fff[(@4333Y@7(@ɤY@P(@hfffY@0333g(@Y@03333L(@԰Y@`(@Y@'@hfffY@`fff'@4333cY@`h'@ĻY@0333i'@4333Y@{'@hfffY@`fff'@DY@0333k'@̬Y@`ffff-'@Y@&@Y@L&@Y@0333l&@Y@`fff%&@Y@0333%@4333kY@̌%@Y@%@4333SY@%@hfffY@+&@4333Y@K&@Y@,7&@Y@ &@43333Y@%@4333Y@`ffff%@Y@,q%@hfffY@`V%@Y@03335%@4333Y@%@\Y@0333%@4333Y@@)%@hfffY@lO%@hfffY@0333I%@Y@Y,%@4333Z@ %@IZ@̌$@!Z@0333$@&Z@`fff$@hfff6'Z@0333Sj$@hfffv*Z@W$@/Z@0333e$@4333S3Z@g$@43337Z@`fff:$@=Z@3$@AZ@`fff"$@hEZ@#@4333FZ@#@EZ@L#@,?Z@#@hfff9Z@#@6Z@Y6#@4333#4Z@^"@4333c4Z@̌!@\9Z@`fffF~!@hfffN1Z@2!@9Z@*!@QGZ@`fff&B!@{Z@`ffff#@hfffZ@0333Y#@1Z@#@4333Z@l#@Z@`fff5#@4333Z@@H#@hfffZ@`ffffn#@yZ@y#@Z@H$@4333Z@q$@hfffZ@#@4333Z@0333s#@hfffZ@@#@ Z@Y#@hfffZ@#@0Z@#@̴Z@0333$@AZ@;$@AZ@`ffffM$@Z@b$@hfffZ@`fffv$@4333Z@$@xZ@0333$@0Z@$@yZ@0333s$@hfffZ@̌$@4333ñZ@0333$@pZ@`fff$@4333Z@0333$@(Z@$@hfffƦZ@ $@̌Z@@%@4333Z@$@4333Z@$@4333Z@$@ԽZ@`fff$@Z@0333<%@lZ@03333R%@4333SZ@ C%@IZ@0333%@hfffZ@`fff&$@lZ@0333s$@4333 Z@$@̼Z@$@4333Z@0333$@Z@$@ Z@`ffff%@hfffZ@0333sf%@hfff[@0333p%@4333[@`ffff%@hfffF [@ %@4333c[@Y%@[@&@H#[@O&@,[@`ffff&@4[@&@hfff&?[@9&@hfff.A[@&@B[@0333s/'@4333{H[@3'@hfffK[@YT'@hfffL[@ s'@TL[@'@J[@'@̴J[@0333'@4333L[@`fff'@hfffL[@'@4333M[@Y(@N[@'@4333O[@@'@hfffP[@'@hffffP[@Y'@hfffM[@0333S%(@0@[@4333T0@hZ@LV0@Z@4333ST0@4333sZ@4333CO0@\Z@̌R0@hffffZ@0g0@XZ@4333|0@4333Z@l0@̜Z@Л0@(Z@0@Z@433330@4333Z@0@̬Z@dfff61@hfffFZ@̬81@hfffZ@^1@4333Z@̬1@hfffZ@433331@hfffƖZ@1@hfffZ@dfff61@hffffZ@1@Z@I1@\Z@̜ 2@TZ@82@@Z@iB2@43333Z@P2@xZ@43332@hfffuZ@2@sZ@dfffV2@oZ@ 2@nZ@2@4333gZ@`2@hfffhZ@43333@mZ@dfff 3@rZ@PK3@4333CrZ@`3@sZ@̌w3@tZ@4333c3@4333~Z@dffff3@4333Z@43333@4333Z@dfff3@PZ@dfff44@hfff&Z@4333I4@Z@dffffd4@@Z@̆4@8Z@,4@0Z@`4@4333;Z@43334@̼Z@43335@iZ@4@Z@4@̄Z@ 4@Z@433334@hfffZ@\4@оZ@̬4@4333;Z@4@Z@4@hfff&Z@dfff4@4333Z@4@̬Z@ 5@Z@4333 5@4333Z@433315@\@05@hfff@\@̌6@hfffE\@<56@I\@433336@ Q\@6@T\@9%6@4333W\@43333*6@4333Z\@-6@_\@36@c\@86@d\@L6@e\@Y6@4333Kc\@dfffvg6@dc\@43336@hfff_\@@6@\\@43336@hfff[\@dfff6@V\@dfffV6@hfffU\@6@0U\@y6@H\\@6@hfffv]\@dfff6@\\@7@4333Ca\@4333#7@hfffg\@4333 7@hfffe\@43337@hfffe\@ 7@hffff\@ 6@g\@dfff6@Pj\@96@Ip\@л6@4333u\@4333s6@{\@43336@\@ 6@hfffn\@{6@`y\@̜m6@4333y\@dffffe6@{\@p]6@\@9`6@hfff\@43333Y6@hfff&\@K6@l\@dfffFS6@\@_6@t\@pe6@Д\@o6@hfff6\@dfff&u6@\@6@hfff\@|6@̕\@ܗ6@4333\@P6@\@6@x\@dffff6@آ\@6@4333\@p6@\@̲6@̴\@Y6@4333\@6@hfff\@dfffV6@̤\@dfff6@hfff^\@dfff6@hfff\@4333C6@hfff\@|6@4333\@6@\@96@hfff\@dfff6@4333{\@dfff6@\@dfff6@8\@43336@\@ 6@\@y6@`\@6@\@433336@]@ 6@4333 ]@06@4 ]@,6@hfff6]@dfff6@hfff]@96@]@6@ ]@dfff&6@D!]@7@4333s"]@.7@%]@77@4333*]@i:7@,]@G7@4333+]@S7@H(]@dfffZ7@4333-]@I\7@̜0]@a7@7]@s7@H:]@̌7@B]@7@HE]@)7@4333{I]@I7@hffffN]@43337@̜R]@7@4333+U]@4333s7@0V]@7@W]@7@Z]@7@̔]]@y7@i]]@7@[]@̬7@]]@07@e]@4333c7@4h]@433337@hfffj]@4333s7@xo]@8@u]@dfff&8@y]@@8@hfff]@?8@<]@S8@̌]@0a8@Ax]@Ye8@Iv]@dfffn8@hfffu]@ly8@hffffy]@dfffz8@{]@dffffy8@a]@4333c{8@4333]@dfffV8@4333]@43338@4333s]@dfff68@hfff]@8@hfff^]@ə8@ܣ]@43338@ ]@dfff8@hfff]@43338@hfffF]@dfffF8@]@ 8@4333è]@dfff8@H]@̌8@̜]@@8@hfff.]@8@)]@99@hfff]@dfffv 9@]@433359@4333]@4333399@4333]@49@hfffF]@4333s;9@hfff]@N9@hfff]@[9@\]@j9@hfff]@dfff&s9@hfff]@w9@]@@r9@hfff]@u9@4333]@̜h9@]@dfff6^9@hfff]@4333#d9@]@o9@hfff]@\9@a]@ܲ9@4333{]@9@|]@09@]@:@hfff]@Y:@̼]@P9@@]@9@]@̌9@]@,:@4333]@:@ ]@2333:@]@ffff :@4333]@:@4333K]@ :@T]@ffff<:@hfff]@ffffL:@4333c]@̌U:@]@ffff^:@]@ffffj:@1]@@s:@9]@:@hfffv]@2333:@]@ffff:@]@ffff:@]@:@̤]@2333:@4333]@L:@x]@:@]@2333S:@y]@:@]@̬:@4333+]@0:@]@ffff:@]@ffffv:@I]@ٮ:@hfffv]@ffffF:@]@:@^@2333C:@̌^@:@<^@:@hfff^@:@hfff^@;@̜^@';@hfff^@A;@̌"^@Q;@&^@2333i;@4333C(^@l{;@%^@̬;@̌*^@2333;@4333S*^@;@+^@̜;@P5^@ffff6;@P5^@2333;@0^@9;@/^@̌<@4^@l<@hfff9^@<@Y=^@y <@DB^@2333C(<@LF^@`J<@4333SI^@S<@M^@X<@lQ^@8<@V^@:<@4333`^@2333S<@ g^@J<@f^@]<@pb^@fffff<@i^^@23333<@9a^@2333<@e^@<@4333Sh^@ffff<@hffffj^@ffff<@b^@<@hfffi^@y<@k^@<@hfffj^@ffff=@hfffVa^@2333S=@hfff\^@!=@,_^@2333s1=@(b^@<=@4333i^@2333s<=@4333m^@A=@̜r^@ffff9=@v^@!=@̼z^@"=@}^@}=@<|^@=@x^@ffff=@t^@ɚ=@0l^@Ђ=@hffff`^@ |=@hfffd^@y=@Lk^@2333s=@y^@=@hfffN^@=@4333^@@=@p|^@2333=@s^@=@4333ck^@ffff=@[^@ffff:>@U^@IH>@4333P^@M>@43333J^@@M>@43339^@ )>@(^@ffff">@hfff^@ffffM>@^@ffffV?>@̬^@ffffVC>@^@2333?>@t ^@ffff=>@hfff^@ffffH>@^@Ic>@Q(^@d>@43334^@Z>@p9^@2333d>@ <^@@x>@?^@>@hfffS^@ >@Z^@0>@4333a^@I>@hfff6k^@ >@hfff>q^@>@0x^@>@hu^@ffff?@Lr^@2333)?@Hj^@Q?@hfffvV^@@|?@M^@ɠ?@4333C^@,?@<^@ ?@4333k2^@?@$0^@@?@4333-^@ffff?@^@@@<^@̼?@4333C ^@ffff?@L^@?@4333^@2333?@Q^@?@ ^@ffffV?@I!^@̌ @@hfffF*^@` @@43332^@@@hfffN>^@?@TI^@2333?@ Q^@?@hfffV^@?@4333k^@P?@hfffp^@2333?@qw^@?@hfffv^@2333?@hfffFu^@ffffV?@p^@,?@hfff&k^@@@d_^@@@\^@@@Y^@fffff@@Y^@3333/@@hfffU^@h6@@hfffR^@:@@4333[?^@̔H@@43336^@T@@6^@ffffa@@hfffn9^@ffffk@@7^@@@/^@I@@hffff'^@ɾ@@hfffN ^@@@^@̴@@hfff>^@3333@@hfff^@A@^@3333#A@ ^@)A@̬]@Q9A@4333C]@3333?A@hfffN]@ffffJA@P]@i[A@|]@_A@]@_A@̔]@fffflA@]@A@̔]@A@]@̔A@]@ffffA@]@$A@]@3333[A@]@A@p]@3333cA@Y]@3333A@4333]@A@^@QA@^@9A@^@3333A@9^@A@^@B@̜ ^@<B@hfff^@8B@|^@<B@4333 ^@B@I^@3333B@^@4B@4333^@@B@4333#^@B@I^@3333# B@(^@B@B@|8^@3333DB@2^@MB@3^@QB@98^@LQB@4333[?^@LB@qC^@ANB@8I^@TB@pZ^@3333^B@4333j^@ffffkB@{^@zB@4333+^@A|B@d^@̴zB@^@ffffvB@^@̔pB@^@lB@̌^@3333jB@ѕ^@ffffjB@@^@3333#uB@4333C^@1yB@^@ffffVB@1^@قB@hfff^@B@hfff^@̤B@hfff^@ffff.B@^@B@^@B@̌^@̔B@^@8B@̜^@B@4333ӊ^@3333cB@4333^@3333B@^@3333B@hfff^@tB@}^@B@@t^@3333sB@h^@B@hfffV`^@B@hfffX^@3333B@ N^@B@4333#C^@3333B@0^@ffffB@^@3333B@8^@ffffB@hfffv^@B@`^@B@^@̴B@ ^@\B@]@B@Q]@ܥB@]@ffffnB@̬]@ٓB@4333]@B@d]@3333B@(]@B@]@xB@]@3333cB@]@ffff>B@i]@B@$]@̜B@̴]@B@]@B@hfffv]@dB@H]@3333B@4333]@ffffB@)]@yC@43333]@ffff6C@]@,C@Ģ]@ffff& C@]@yC@q]@'C@i]@L6C@4333c]@PC@qc]@XC@xg]@3333+mC@8r]@ffff6C@hw]@3333{C@hfff]@ffffC@hfffv]@C@]@ffffC@4]@3333C@hfff]@3333C@(]@3333C@]@C@4333c]@LC@hfff]@ffff^C@]@ffffvC@`]@3333;C@]@3333C@]@C@]@QC@]@C@l]@dC@̜^@D@^@D@4333S1^@fffffKD@5^@SD@hfff;^@pWD@0@^@3333_D@E^@kD@4333+K^@\sD@`b^@ppD@Tf^@kD@̬n^@ffffNlD@q^@pD@s^@{D@hfffnu^@̴|D@hfffv^@kD@^@ffffXD@p^@ffff&MD@^@3333[ED@4333^@ffff@D@4333^@2D@8^@3333-D@hfff~^@3333cD@̜w^@D@4333Cs^@3333C@a^@3333#C@Y^^@C@`^@ffffC@ a^@C@ ^^@C@4333Z^@̄C@hfffQ^@C@4333SR^@|C@0S^@C@Q^@@C@4333V^@3333;C@`^@3333C@Dr^@ffffNC@at^@yC@p^@|C@j^@fffffC@4333+h^@ffff.C@4333k^@C@P^@zC@ L^@,yC@F^@uC@G^@hC@xJ^@ffff]C@hfffFM^@3333+_C@ O^@3333+bC@|T^@3333sgC@a^@ffffVjC@i^@3333nC@j^@ffff&rC@h^@8zC@Xk^@pC@4333o^@_@t=C@4333[8_@3333+C@hfff~8_@%C@7_@C@8,_@C@43331_@ffff C@ :_@3333kC@hfff?_@ffff C@hJ_@ C@4333;M_@p C@O_@ffffFC@\L_@ffffC@H?_@9B@hfffA_@B@hfffF_@B@4333S_@B@YW_@ffffB@hfffV_@ffffB@hfffZ_@ B@\_@xB@8e_@3333SB@hfffFk_@xB@4333{l_@9B@9q_@ B@D|_@B@8_@ffffVB@x_@B@hfffN_@B@_@ B@̬_@ffffnB@_@ffffB@4333_@$B@_@3333B@_@3333B@_@3333SB@hfff_@ffffB@!_@ffffB@4333_@B@ _@̌B@hfff_@3333;B@hfff_@B@_@B@į_@ffffƘB@4333_@@B@d_@ffff&B@̜_@|B@l_@3333zB@̄_@ffff>xB@P_@sB@4333C_@XnB@з_@iB@hfff_@LlB@4_@fffffyB@4333_@zB@_@B@4333+_@B@p_@ |B@_@ffffzB@hfff_@3333{oB@hfffF_@ffffbB@4333_@ffffXB@4333Î_@9XB@_@YSB@hfff_@VB@hfff6_@ffffXB@l_@ffffJB@hfff_@3333#=B@4333S_@7B@Ԣ_@̬+B@_@0B@hfff_@DB@hfff6_@q B@4333_@3333B@a_@B@y_@̼A@p_@A@hfff_@ffffA@1_@̜A@_@iA@_@3333kA@hfff_@̬A@4333C_@3333A@4333#_@̜A@(_@|A@L_@ffffA@4333C_@iA@_@)A@x_@QA@hfffV_@ffff>A@4333_@3333ÛA@_@3333A@_@ffffƅA@hfffv_@fffffwA@_@diA@_@gA@_@3333kA@_@̄iA@x_@3333cA@4333C_@`A@Q_@h^A@_@TYA@<_@XA@D_@(\A@_@,VA@I_@yKA@Ԟ_@9?A@i_@6A@_@,A@4333_@9(A@hffff_@̤(A@_@ffff3A@hfffN_@̄AA@_@D?A@_@̼9A@p_@,8A@_@ffffMA@_@`A@1_@4\A@̬_@TA@y_@qMA@_@EA@hfff_@L;A@4333[_@@A@̬_@FA@_@PA@_@ XA@_@3333_A@_@3333[iA@hfff_@lA@4333_@kA@0_@ bA@y_@YXA@_@3333K\A@_@3333+dA@hffff_@kA@4333_@qA@hfff._@3333vA@_@33333zA@4333_@{A@4333_@dA@(`@ЂA@hfff`@wA@`@3333;uA@`@3333tA@h `@3333pA@4`@hoA@4333S`@ffffNwA@4333g `@A@̨`@3333A@Y`@A@`@ffffNA@hfffv`@A@\`@ffffA@t"`@̴A@hfff&`@ffffFA@4333*`@A@i-`@A@̈/`@A@1`@LA@T2`@xB@P0`@B@hfff.`@3333B@-`@hB@,`@̬B@,`@ffffB@,`@B@,`@ffffN)B@4333-`@X1B@=.`@@D@'`@̜TD@hfff*`@\D@6`@̼mD@hfff7`@TwD@6`@ԏD@8`@D@I8`@D@hfff5`@ffffFD@hfff5`@(D@48`@3333+D@4333 <`@3333D@=`@D@<@`@ffffD@4333/B`@3333E@E`@i E@4333G`@3333sE@hfffJ`@hE@N`@ffff&E@43337R`@ffffV%E@hfff^T`@ffff.#E@hfffU`@&E@4333[W`@3333)E@Z`@BE@4333V`@TE@hfff2X`@ffff.VE@4333C^`@$QE@4333``@̔RE@e`@!PE@g`@DYE@\i`@bE@l`@AiE@hfffp`@3333E@4333w`@E@hfffny`@̬E@ ~`@ffffE@=`@E@4333k`@أE@4333|`@3333ەE@4333{`@ffff.E@P~`@ffff6E@4333`@9E@hfffv`@ffff^E@`@!E@4333`@̌E@̸`@qE@4333g`@3333stE@hfffr`@oE@`@3333pE@hfff`@eE@̐`@3333gE@`@lgE@hfff`@̄\E@hfff`@ffff6YE@4333`@ffffaE@hfffƲ`@3333jE@4333`@3333;jE@U`@ffffFyE@`@dE@4333#`@1E@X`@E@1`@3333KE@4333S`@E@x`@E@hfff`@ E@`@YE@`@/F@`@L8F@a@3333>F@a@GF@ a@YUF@a@3333;iF@Ta@4}F@4333a@ffff>F@hfffa@F@$a@ffff^F@4333-a@3333F@43335a@F@̜8a@F@4333gCa@ G@Fa@A;G@Ja@ffffEG@La@ffff^_G@Pa@ffffqG@4333Pa@|G@4333Ra@3333SG@4333 `a@G@Xea@3333CG@ka@̔G@pa@ffffG@ua@ H@Xxa@H@4333a@q)H@a@6H@ua@CH@,a@bH@4333a@h{H@a@ffffVH@4333a@ffffH@4333ka@\H@(a@`H@̨a@DH@Ōa@H@4333ˍa@ffffnH@̌a@ffffNH@\a@ffff~H@ݎa@̬H@hfffΎa@3333H@̴a@DI@a@I@a@̌ I@ a@ I@hfff"a@̼I@hfff>a@3333EI@4333a@lfI@̨a@ffffN~I@hfffva@I@a@3333I@՚a@3333I@؝a@YI@$a@(I@Da@3333+I@a@I@hfffVa@3333SJ@4333a@J@4333a@ffffJ@̌a@̴"J@4333oa@(/J@a@AJ@43337a@J@*a@J@hfff(a@J@hfff'a@3333#J@ *a@J@43330a@J@hfff4a@3333J@(9a@J@hfff:a@ffff.J@3a@8J@4333?/a@K@4333*a@ffff K@,a@K@p.a@3333K@l0a@K@P5a@3333C$K@0a@ffffF%K@hfff,a@3333#$K@$a@3333SK@#a@tK@̄%a@HK@A(a@3333;K@$a@,J@ a@J@]a@pJ@4333a@J@a@J@4333a@4J@4333Wa@3333K@4333a@9-K@@a@ffff9K@\a@ffffGK@4333a@|OK@a@OK@a@3333NK@a@NK@@`@ffffJK@hfff`@3333XK@i`@̌ZK@4333?`@]K@`@kK@4333`@̜sK@hffff`@ffffxK@L`@K@hfff`@K@4333a@ffffK@< a@HK@hfffa@K@da@3333K@4333c a@3333K@4333&a@ffff6K@hfffJ,a@K@U2a@YL@ 6a@ffffL@\Ba@p7L@Da@?L@4333Ea@TKL@Fa@3333PL@0Ua@ffff{L@4333^a@HL@ea@yL@4na@33333L@hfff6pa@ܭL@sa@TL@̴ya@L@{a@PL@4333a@L@La@ffff&L@؏a@ffffL@4333a@(M@Ia@&M@4333a@3333[5M@4333a@CM@4333Ka@3333SM@hfff&a@d_M@a@M@hfffa@M@a@̼M@hfff&a@`M@4333a@M@a@M@4333b@3333CM@xb@)M@43331b@ffffM@48b@ffff֯M@:b@HM@=b@dM@Ab@ԕM@Hb@YM@8Nb@M@0Qb@ffff~M@Yb@̼M@Hab@ЮM@hfffvpb@`M@4333vb@4M@{b@3333M@M@b@hM@b@̜M@4333{b@\M@4333kb@ffffM@b@̜M@hfffZb@ffff6M@hfffFb@1M@yb@HM@b@ffffM@Xb@ M@Yb@M@b@3333ۼM@hfff.b@3333M@pb@!M@4333b@ffffM@4333sb@M@$b@3333M@4333b@ffffM@b@`M@(b@\M@Xc@1M@lc@3333M@4333Wc@ffffM@hfffb@|M@xb@ffffƒM@(b@ffffM@b@M@tb@3333pM@b@nM@c@tM@Ic@ffffM@hfff: c@M@hfff c@aM@4333kc@ zM@,c@vM@4333;c@33333xM@|"c@3333{M@hfffF&c@ffffM@(c@M@hfff+c@ffff~M@4333?6c@ĜM@̈c@ffffvN@c@ffffN@c@N@hfffc@3333N@`c@N@tc@ N@hfffc@ffffN@pc@3333N@c@ffffnN@c@ffffN@̬c@N@c@3333N@4333d@N@d@N@hfff d@3333{N@I d@ffffVN@( d@̌N@hfffd@N@4d@N@c@ffffvN@hfffBc@YN@4333?c@3333N@`c@ffffvN@̴c@ɁN@4333Kc@3333szN@hfffBc@xN@ d@3333N@d@N@ d@3333N@ d@3333CN@9d@pjN@4333od@d]N@̬d@iXN@hfffd@QN@1 d@aUN@ d@ZN@ld@3333^N@d@l`N@Hd@3333CrN@0!d@@{N@4333Fd@4N@Ld@N@4Pd@ffffN@qSd@4N@hfff^Vd@N@Vd@N@4333Xd@3333 N@d[d@ffff>N@hfff~]d@N@hfff_d@N@4333ad@3333N@hfffbd@N@qdd@3333CN@Tfd@N@@hd@N@̤fd@HN@L`d@PN@̐`d@ffffN@1dd@3333cO@hfffcd@3333O@4333;ed@9!O@4333fd@ffff(O@Ahd@ +O@4333id@ffff/O@gd@I:O@0id@ffffvAO@jd@̄FO@hfff.d@)YO@4333cd@1ZO@$d@ffffvVO@4333[d@IO@hd@,BO@̰d@8?O@4333[d@99O@d@3333C;O@ئd@ffff^9O@8d@3O@̨d@ffff/O@d@̬4O@hd@H7O@hfffvd@̤ L@4333tc@3333K@qc@3333K@4333 rc@|K@sc@nK@4333vc@BK@|c@J@h~c@DJ@)c@ԀJ@c@ffffnJ@c@ffff_J@Pc@)PJ@c@33333AJ@4333c@3333.J@̬c@ffffI@4333c@мI@c@̬I@dc@3333I@4333wc@ I@Ԗc@3333I@-c@ffffI@c@|I@hfffc@؀I@xc@3333;I@̬c@XI@c@lI@ c@lI@Xc@3333{I@Pc@I@̜c@ J@c@ 'J@c@3333 1J@4333c@3333:J@hfffbc@ffff6PJ@c@ffffXJ@4333{c@3333oJ@c@ vJ@c@̌zJ@4333c@$J@c@fffffJ@4333wc@J@c@3333wJ@hfffc@XtJ@4333wc@ffffJ@4333[c@ffffJ@c@lJ@̰c@fffffJ@Qc@3333J@d@ffffJ@d@0J@c@̼J@c@ffffNJ@hfffc@ffffJ@Ac@xJ@hfffc@J@c@ffffNJ@4333c@3333K@4333Sd@K@ad@ffff6K@hfff> d@$K@̌d@ffff&7K@d@3333KEK@d@JK@($d@3333LK@h)d@BK@hfff3d@BK@87d@8DK@>d@ffff&XK@`Cd@ffffF`K@Bd@lqK@?d@ffffK@`:d@ȑK@hfff9d@HK@4333W7d@3333ӭK@hfff*7d@K@8d@K@=d@K@Bd@y L@̬Dd@3333kL@̰Jd@L@Nd@$L@4333Pd@ffff^!L@4333Od@ffff3L@Rd@3333;:L@|Ud@3333>L@\d@d@ M@4333Ad@"M@Dd@D9M@4333Nd@3333ZM@hfffTd@3333cfM@[d@9xM@]d@3333c{M@_d@D~M@4333#`d@̔M@^d@M@hfff2_d@3333M@4333S`d@3333M@4333bd@ѐM@4333hd@3333M@hd@M@4333Gjd@3333KM@̬kd@ffffM@hfffmd@M@od@M@`rd@M@vd@N@d@ffff5N@\d@L,N@hfffZd@3333N@4333cd@ffff^ N@hfffZd@3333[M@d@ffffM@d@3333M@̼d@M@hfffd@3333M@4333{d@8M@d@L'N@Ad@4N@d@ffffN@@e@ħN@ěe@3333N@hfffe@3333N@Кe@3333N@љe@3333ӷN@he@ffffN@4333e@ffffN@8e@ N@̀e@3333CN@4333e@N@Pe@ffffN@qe@N@hfffe@̤N@ue@lN@e@ffffN@e@TN@e@,N@(e@hO@hfffe@3333 O@̴e@O@$e@`O@̤e@O@hfff f@3333K,O@ f@ffff4O@4333{f@̼@O@ f@ffffDO@hfff%f@ffffGO@&f@KO@A f@33333PO@4333f@ffffNTO@f@̼XO@hffff@q\O@ f@|cO@4333"f@eO@hfff%f@3333 `O@4333G(f@ffff`O@)f@adO@*f@3333dO@hfff+f@T^O@4333*f@ffffWO@x)f@ffff~RO@\)f@̬LO@=+f@1KO@85f@JO@@f@3333FO@^f@y-O@maf@ffffn)O@cf@)O@Hdf@ffff2O@ef@fffff@9P@6f@̀P@hfff-f@ffffrP@-f@̨$P@4333.f@(/P@-f@33330P@hffff,f@1P@!f@.P@f@(P@df@'P@hfff>f@̬+P@hffff@ffff~%P@f@)P@ f@|*P@4333; f@ -P@̠ f@ffff*2P@4333f@5P@hfffjf@8P@4333f@33339P@De@3333_7P@ye@4P@e@2P@̔e@/P@4333e@/P@4333[e@̜+P@e@+P@ e@1P@e@(2P@4333e@6P@f@3333=P@hfff f@33336P@f@ffff5P@f@Y6P@43333"f@X2P@hfff$f@ffff3P@!'f@%7P@4333#f@EP@%f@3333@P@4333(f@=P@*f@3333;P@̜2f@1P@7f@-P@!If@ffff+P@Pf@3333&P@YVf@d(P@df@2P@Xnf@4P@tf@:P@yzf@0BP@f@MDP@m;b@̼E@1>b@ѺE@1>b@ffffE@>b@E@=b@E@hfff>=b@IE@̨b@ffffE@n`4333Hb@YE@4333{Kb@pE@ hfffJb@E@Ib@pE@Ib@ffffE@4333Hb@ffffE@8Ib@ E@hfffJb@YE@4333{Kb@ E@1Kb@3333sE@hfffJb@E@o`@b@E@9Cb@yE@ Bb@yE@̐Ab@E@@b@ffffεE@Ab@E@uAb@dE@B@<0_@3333CB@Y0_@3333#B@hfff/_@̄B@-_@B@P*_@B@4333(_@̄B@hfff(_@B@)_@ffff^B@hfff,_@B@-_@hB@Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_coastline.shx0000664000175000017500000002640415151324131022754 0ustar hibbyhibby' fLLUf@`T@2XjX`*P~@$(')z +@.023 3`5:6&P8z:;=?JAxBDFEpGHKfLPP8R&T xU(W X@Z\.]"X^~_Z``a~@ceg*0h^jzkF(lr@mHppr0s0uuxb0y{2|.~ fZXV@6`JNPx"Vx >(j 8(0Ś P 8*>xX x f( F%b*f05 A:xCHJhLxOnWbXWxX:PX8Y(ZX^R`fgl(tx vzfBHzp @. (Z@ɞHXFXʢXXZH˦X@FP̚XPJP͞X`^PβXϒhXZ`о`"ѦppҎP`FPӚXXR`Զ`HfPպP`r`P*P~HPPrhP2XَP~XP.PۂXP2ܾXPnHݺh&PzXX2pߦ` XfhX.`XhZhXp p~h`NXhx>hXXb`rxpbPh"xBXz&`h`Z`ZxhzxxrxF^:p&xh`h&`f`NJXR`XXZxp ` r` x Rx p Bx ` " ` Jp p2p*xRpRPH@6phhpz6xVph6nHXXJhjhP* h r!^"BH"#P#f$P$V`$P%%&.&P'&(*`(X()H*2+>,H,f,X-Vh-x.>h./>020`1Z`1h2*45H6^678j99:v; <=Bx=H> `>n?*h?P?X@FH@X@PABABPBhCBXCD*`DHDPE.EhF6PFGGH&HXIXIjPIHJ xJHJhK>xKPLhLzM6`MxNXNrhNOjOPQ>XQHQXRBRSTUxVxVW`WrXVPXY>xYZFXZx[P[rH[p\2\`]x]^P^`_b`6a2paHaXbNpbXcXczcPdRPdHdeXe ghgxgXhZi&j*XjpjXkVpkl^hlhm6Pmn6noPopPq2XqXq`rNs"sXtPtVPtPtXuZhuvw&w xHy"z`zjhz{z|p|z}&X}~~P~hZxX26P6`FXXPRPx"`hXNBPXvPh6nh"P2p:X`hXZpP"zhhPBxX`~hXF:H*pbxhJHR>h.HP:xRP` xXpV``:hhXnXH`Vhn`h6XxXjhX2H~*HvxH>P>VnXX^`Pf``.~`X:```*þp2Ķr`b&`NJhhbhɢXʊ``RhR`BV:ЂxтP`.2hBPՖ:xֶh"pזX~BPBhJxZ`ܾh*ݶh"޾`"hߎBXx`*hpNh`P>pFX`pN`ppvX8`r>PXxjzXX2`BX`X^Px.xhPjPJXpPn`X.x@p`jhbXPx"PvX`6PPbXH p~`X>X&HrX`2@vxPFhPPZ`p2`p X fH P  H &p ` x zX P*``vx`VpPPr``:HPfXh.HzhP:`RPx"~xhxrXZhjPBP jp X!:X!"b"p#b#$%H&Z((x)`)f*"*H+JP+,bp,-.V.x/fX/h0.01^`1`2&p2`2`3bh3P4"4h5p5h5P6N`6h7P7r7h8jX89r:n@:H:p;rP;<p=X=b=X>Bx>h?*?@R@hAbApBrXBpCB`CpDXDvPDXE&xEhFxFxG`GjhGHbHPIBIJbJ`KJLLMN`MHMPNRNXO:OxPrhPPQ2pQXRhRnpRHS.STVXTU>UVWrxW`YRYZbZP[BX[\x]]p^^_F`_aNhaXccxdhd`dxebhefgXgh`iij`jkzhkhlRxlpmB`mXnnXnofPopFPp`pxqzhqrjXrps:PsXspt^tXu>Huvhvzw`wHwxzHxypzxzp{{p|6h|p}}X~&~pxXxnhfphFZX:pp"R`h"X~hnP@`jXX"``@.HzhjPp2XP`F`HhbpP*xxpPfh.xXvPX:HJXrpXBhX HVhFh6hzXP*`JH`hf`xFh6h&h`z@h*h`~XxVph6xp&P&`~Ph& J.` x `nRzx`jxzHRHXpnh`>`â`ĊhxrprppZzhXB^`P`zP`2X̎Xv`H&hΒpϢHPBPЖhPVPѪ``rP`*HvPPXzPpBhծ:־XHZHئHXN`ٲx.HzXP*@n`H- :0!n*GH:HI0J LMMNOQn RS&S U\H`fPac`hm v p.0bPRnBXJ^JXHXN`V"x:.`h``rh~ `B`` x*>pHp.x@ºn"xŞƚvXZNxˆrNζZPpߊ&Xxx~.*pB`Pxvx~hPxV`^``&hXhZ`XhphfpvjFxhXvhfp`>fpnpx^`^h=(?8@2@@vX@PA&XApAHBBXB`C`CfCxDn`DPE&hExF`FrGG@GXH:HH`H@I.PIHIPJ"JpK`K~xKXLVPLXMOpzN4`$`p```P,P`pp`Hh@p@p8` ``l`TP` P`hX(HtP`,PPX0X`pXastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.README.html0000664000175000017500000011061515151324131023166 0ustar hibbyhibby Natural Earth » Blog Archive » Lakes + Reservoirs - Free vector and raster map data at 1:10m, 1:50m, and 1:110m scales


Lakes + Reservoirs

lakes_thumb
Natural and artificial lakes.

lakes_wide_half_2About

Generalized from 10 million lakes theme. The 10 million lakes primarily derive from World Data Bank 2 with numerous reservoir additions from imagery sources. Diminishing areal extent of Aral Sea and Lake Chad was digitized from recent satellite imagery.

Ranked by relative importance, coordinating with river ranking. Includes name attributes.

(right) Lakes and reservoirs in Argentina and Brazil.

Issues

Areal Sea is probably lower now than what is shown.

Version History

The master changelog is available on Github »

Comments are closed.


Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.VERSION.txt0000664000175000017500000000000615151324131023221 0ustar hibbyhibby5.0.0 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.cpg0000664000175000017500000000000515151324131022026 0ustar hibbyhibbyUTF-8Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.dbf0000664000175000017500001333043615151324131022032 0ustar hibbyhibbyy ascalerankN featureclaC nameCname_altCnoteCdadminC2nameparCmin_zoomNmin_labelNname_abbClabelCwikidataidCname_arCname_bnCname_deCname_enCname_esCname_frCname_elCname_hiCname_huCname_idCname_itCname_jaCname_koCname_nlCname_plCname_ptCname_ruCname_svCname_trCname_viCname_zhCne_idN name_faCaname_heCUname_ukCPname_urCQname_zhtCP 0Lake Mälaren Lake Malar 2.0 3.7Mälaren Mälaren Q184492 بحيرة مالارين মালারেন Mälaren Mälaren Mälar Mälar Μέλαρεν मालारेन Mälaren-tó Mälaren Mälaren メーラレン湖 멜라렌호 Mälarmeer Melar Mälaren Меларен Mälaren Mälaren Mälaren 梅拉伦湖 1159122891دریاچه مئلارن מלארן Меларен مالارین 梅拉倫湖 0Lake Lake Ladoga 1.0 3.0L. Ladoga Lake Ladoga Q15288 بحيرة لادوغا লাডোগা হ্রদ Ladogasee Ladoga Ládoga Ladoga Λάντογκα लादोगा झील Ladoga-tó Ladoga Ladoga ラドガ湖 라도가호 Ladogameer Ładoga Ladoga Ладожское озеро Ladoga Ladoga Ladoga 拉多加湖 1159113095دریاچه لادوگا ימת לדוגה Ладозьке озеро جھیل لاڈوگا 拉多加湖 0Lake Lake Albert admin-0 1.0 3.0L. Albert Lake Albert Q125888 بحيرة ألبرت লেক আলবার্ট Albertsee Albert Alberto Albert Λίμνη Αλβέρτου ऐल्बर्ट झील Albert-tó Albert Alberto アルバート湖 앨버트호 Albertmeer Jezioro Alberta Alberto Альберт Albertsjön Albert Albert 艾伯特湖 1159113145دریاچه آلبرت אגם אלברט Альберт جھیل البرٹ 艾伯特湖 0Lake Lake Erie Lakes admin-0 1.0 3.0L. Erie Lake Erie Q5492 بحيرة إري ইরি হ্রদ Eriesee Erie Erie Érié Λίμνη Ήρι ईरी झील Erie-tó Erie Erie エリー湖 이리호 Eriemeer Erie Erie Эри Eriesjön Erie Erie 伊利湖 1159106757دریاچه ایری ימת אירי Ері جھیل ایری 伊利湖 0Lake Lake Chad 1.0 3.0L. Chad Lake Chad Q125309 بحيرة تشاد চাদ হ্রদ Tschadsee Chad Chad Tchad λίμνη Τσαντ चाड झील Csád-tó Chad Ciad チャド湖 차드호 Tsjaadmeer Czad Chade Чад Tchadsjön Çad Tchad 乍得湖 1159113219دریاچه چاد ימת צ'אד Чад جھیل چاڈ 乍得湖 0Lake Lake Malawi Lake Nyasa admin-0 1.0 3.0L. Malawi Lake Malawi Q5532 بحيرة ملاوي মালাউই হ্রদ Malawisee Malawi Malaui Malawi Λίμνη Νιάσα मलावी झील Nyasza-tó Malawi Malawi マラウイ湖 말라위호 Malawimeer Niasa Niassa Малави Malawisjön Malavi Malawi 马拉维湖 1159113163دریاچه مالاوی אגם מלאווי Ньяса جھیل ملاوی 马拉维湖 0Lake Lake Victoria admin-0 1.0 3.0L. Victoria Lake Victoria Q5505 بحيرة فيكتوريا ভিক্টোরিয়া হ্রদ Victoriasee Nyanza Victoria Victoria Βικτόρια विक्टोरिया झील Viktória-tó Victoria Vittoria ヴィクトリア湖 빅토리아호 Victoriameer Jezioro Wiktorii Vitória Виктория Victoriasjön Victoria Victoria 維多利亞湖 1159113191دریاچه ویکتوریا אגם ויקטוריה Вікторія جھیل وکٹوریہ 維多利亞湖 0Lake Lake Baikal 1.0 3.0L. Baikal Lake Baikal Q5513 بحيرة بايكال বৈকাল হ্রদ Baikalsee Baikal Baikal Baïkal Βαϊκάλη बयकाल झील Bajkál-tó Baikal Bajkal バイカル湖 바이칼호 Baikalmeer Bajkał Baikal Байкал Bajkalsjön Baykal Baikal 贝加尔湖 1159113127دریاچه بایکال ימת באיקל Байкал جھیل بیکال 贝加尔湖 0Lake Lake Winnipeg 1.0 3.0L. Winnipeg Lake Winnipeg Q3272 بحيرة وينيبيغ লেক উইন্নিপেগ Winnipegsee Winnipeg Winnipeg Winnipeg Λίμνη Γουίνιπεγκ विनिपेग झील Winnipeg-tó Winnipeg Winnipeg ウィニペグ湖 위니펙호 Winnipegmeer Winnipeg Winnipeg Виннипег Winnipegsjön Winnipeg Winnipeg 溫尼伯湖 1159106747دریاچه وینیپگ אגם ויניפג Вінніпег جھیل ونیپیگ 溫尼伯湖 0Lake Great Slave Lake 1.0 3.0Great Slave L. Great Slave Lake Q5539 بحيرة جريت سليف গ্রেট স্লেভ লেক Großer Sklavensee Great Slave Gran Esclavo Grand Esclaves Μεγάλη Λίμνη των Σκλάβων ग्रेट स्लाव झील Nagy-Rabszolga-tó Great Slave Grande Schiavi グレートスレーブ湖 그레이트슬레이브호 Great Slave Wielkie Jezioro Niewolnicze Grande Escravo Большое Невольничье озеро Stora Slavsjön Büyük Esir Slave Lớn 大奴湖 1159106729دریاچه گریت اسلیو ימת העבדים הגדולה Велике Невільниче озеро گریٹ سلیو جھیل 大奴湖 0Lake Lake Ontario admin-0 1.0 3.0L. Ontario Lake Ontario Q1062 بحيرة أونتاريو লেক অন্টারিও Ontariosee Ontario Ontario Ontario Λίμνη Οντάριο ओण्टारियो झील Ontario-tó Ontario Ontario オンタリオ湖 온타리오호 Ontariomeer Ontario Ontário Онтарио Ontariosjön Ontario Ontario 安大略湖 1159106765دریاچه انتاریو ימת אונטריו Онтаріо جھیل انٹاریو 安大略湖 0Lake Great Bear Lake 1.0 3.0Great Bear L. Great Bear Lake Q5525 بحيرة الدب العظيم গ্রেট বেয়ার লেক Großer Bärensee Great Bear Gran Oso grand l'Ours Μεγάλη Λίμνη των Άρκτων ग्रेट बियर झील Nagy-Medve-tó Beruang Besar Grande Orsi グレートベア湖 그레이트베어호 Groot Berenmeer Wielkie Jezioro Niedźwiedzie Grande Urso Большое Медвежье озеро Stora Björnsjön Büyük Ayı Gấu lớn 大熊湖 1159106721دریاچه گریت بر ימת הדובים הגדולה Велике Ведмеже озеро گریٹ بیئر لیک 大熊湖 0Lake Lake Saint Clair admin-0 1.0 3.0L. St. Clair Lake St. Clair Q736707 بحيرة سانت كلير লেক সেন্ট ক্লেয়ার St. Clair Saint Clair Sainte-Claire Sainte-Claire Λίμνη Σεν Κλερ सेंट क्लेयर झील Saint Clair-tó Danau Saint Clair St. Clair セントクレア湖 세인트클레어호 Saint Clairmeer St. Clair Saint Clair Сент-Клэр St. Clair St. Clair Hồ Saint Clair 圣克莱尔湖 1159106775دریاچه سنت کلیر סיינט קלייר Сент-Клер جھیل سینٹ کلیئر 聖克萊爾湖 0Lake Vänern 1.7 3.6Vänern Vänern Q173596 بحيرة فنرن ভেনার্ন Vänern Vänern Vänern Vänern Βένερν वेनर्न Vänern-tó Vänern Vänern ヴェーネルン湖 베네른호 Vänermeer Wener Vänern Венерн Vänern Vänern Vänern 维纳恩湖 1159113235دریاچه ونرن ונן Венерн وینرن 維納恩湖 0Lake Lake Okeechobee 1.7 3.6L. Okeechobee Lake Okeechobee Q202905 بحيرة أوكي تشوبي লেক ওকীচোবী Okeechobeesee Okeechobee Okeechobee Okeechobee Λίμνη Οκιτσόμπι ओकेचोबी झील Okeechobbee-tó Danau Okeechobee Okeechobee オキーチョビー湖 오키초비호 Okeechobeemeer Okeechobee Okeechobee Окичоби Okeechobee Okeechobee Hồ Okeechobee 奧基喬比湖 1159106781دریاچه اوکیچوبی אגם אוקיצ'ובי Окічобі جھیل اوکیجوبی 奧基喬比湖 0Lake Lago de Nicaragua 1.7 3.6L. de Nicaragua Lago de Nicaragua Q173862 بحيرة نيكاراغوا নিকারাগুয়া হ্রদ Nicaraguasee Nicaragua Cocibolca Nicaragua Λίμνη Νικαράγουα निकारागुआ झील Nicaragua-tó Nikaragua Nicaragua ニカラグア湖 니카라과호 Meer van Nicaragua Nikaragua Nicarágua Никарагуа Nicaraguasjön Nikaragua Nicaragua 尼加拉瓜湖 1159106791دریاچه نیکاراگوئه אגם ניקרגואה Нікарагуа جھیل نکاراگوا 尼加拉瓜湖 0Lake Lake Tana 1.7 3.6L. Tana Lake Tana Q116685 بحيرة تانا তানা হ্রদ Tanasee Tana Tana Tana Τάνα ताना झील Tana-tó Tana Tana タナ湖 타나호 Tanameer Jezioro Tana Tana Тана Tanasjön Tana Gölü Tana 塔纳湖 1159113265دریاچه تانا אגם טאנה Тана جھیل ٹانا 塔納湖 0Lake Lago Titicaca admin-0 1.7 3.6L. Titicaca Lago Titicaca Q35342 بحيرة تيتيكاكا তিতিকাকা হ্রদ Titicacasee Titicaca Titicaca Titicaca Τιτικάκα टीटीकाका झील Titicaca-tó Titicaca Titicaca チチカカ湖 티티카카호 Titicacameer Titicaca Titicaca Титикака Titicacasjön Titikaka Titicaca 的的喀喀湖 1159113279دریاچه تیتیکاکا אגם טיטיקקה Тітікака جھیل ٹیٹیکاکا 的的喀喀湖 0Lake Cedar Lake _untitled_0 1.7 3.6Cedar L. Cedar Lake Q1052532 سيدار ليك সেডার লেক Cedar Cedar Cedar Cèdres Λίμνη Σένταρ सिडर लेक Cedar-tó Danau Cedar Cedar シーダー湖 시더 레이크 Cedar Cedar Cedar Сидар Cedar Cedar Gölü Hồ Cedar 錫達湖 1159123681دریاچه سدار סידר לייק Сідар کیدار جھیل 錫達湖 0Lake Lake Onega 1.7 3.6L. Onega Lake Onega Q166162 بحيرة أونيغا লেক ওনেগা Onegasee Onega Onega Onega Λίμνη Ονέγκα ओनेगा झील Onyega-tó Onega Onega オネガ湖 오네가호 Onegameer Onega Onega Онежское озеро Onega Onega Onega 奥涅加湖 1159113251دریاچه اونگا ימת אונגה Онезьке озеро جھیل اونیگا 奧涅加湖 0Alkaline Lake Great Salt Lake 1.7 3.6Great Salt L. Great Salt Lake Q178741 البحيرة المالحة الكبرى গ্রেট সল্ট লেক Großer Salzsee Great Salt Gran Salado Grand Salé Μεγάλη Αλμυρή Λίμνη महान नमक झील Nagy-sóstó Garam Besar Gran Salato グレートソルト湖 그레이트솔트호 Great Salt Wielkie Jezioro Słone Grande Salgado Большое Солёное озеро Stora Saltsjön Büyük Tuz Muối Lớn 大盐湖 1159126421دریاچه نمک یوتا ימת המלח הגדולה Велике Солоне озеро گریٹ سالٹ لیک 大鹽湖 0Lake Lake Michigan admin-0 1.0 3.0L. Michigan Lake Michigan Q1169 بحيرة ميشيغين মিশিগান হ্রদ Michigansee Michigan Míchigan Michigan Λίμνη Μίσιγκαν मिशिगन झील Michigan-tó Michigan Michigan ミシガン湖 미시간호 Michiganmeer Michigan Michigan Мичиган Michigansjön Michigan Michigan 密歇根湖 1159113005دریاچه میشیگان ימת מישיגן Мічиган جھیل مشی گن 密歇根湖 0Lake Lake Superior admin-0 1.0 3.0L. Superior Lake Superior Q1066 بحيرة سوبيريور সুপিরিয়র হ্রদ Oberer Superior Superior Supérieur λίμνη Σουπίριορ सुपीरियर झील Felső-tó Superior Superiore スペリオル湖 슈피리어호 Bovenmeer Jezioro Górne Superior Верхнее озеро Övre sjön Superior Thượng 苏必利尔湖 1159112991دریاچه سوپریور ימת סופיריור Озеро Верхнє جھیل سپیریئر 苏必利尔湖 0Lake Lake Huron admin-0 1.0 3.0L.Huron Lake Huron Q1383 بحيرة هرون লেক হুরন Huronsee Huron Hurón Huron Λίμνη Χιούρον ह्यूरॉन झील Huron-tó Huron Huron ヒューロン湖 휴런호 Huronmeer Huron Huron Гурон Huronsjön Huron Huron 休伦湖 1159113021دریاچه هیوران ימת יורון Гурон جھیل ہیورون 休伦湖 0Alkaline Lake Lago Madre _untitled_0 2.0 3.7Lag. Madre بحيرة مادر লাগুনা মাদ্রে Laguna Madre Laguna Madre Laguna Madre Laguna Madre Λαγκούνα Μάντρε लगुना माद्रे Laguna Madre Laguna Madre Laguna Madre マドレ湖 라구나 마드레 Laguna Madre Laguna Madre Lago Madre озеро Лагуна-Мадре Laguna Madre Laguna Madre Phá Laguna Madre 马德雷湖 1159126435لاگونا مادر אגם לגונה מאדרה Лагуна Мадре لاگونا مادرے 馬德雷湖 0Lake Wollaston Lake 2.0 3.7Wollaston L. Wollaston Lake Q1640500 بحيرة وولاستون ওয়ালাসটন লেক Wollaston Wollaston Wollaston Wollaston Λίμνη Γουόλαστον वोलास्टन झील Wollaston-tó Danau Wollaston Wollaston ウォラストン湖 월라스턴 레이크 Wollastonmeer Wollaston Lago Wollaston Вулластон Wollaston Wollaston Gölü Hồ Wollaston 伍拉斯顿湖 1159106809دریاچه وولاستون אגם וולסטון Вулластон والیسٹن جھیل 伍拉斯頓湖 0Lake Lake Athabasca 2.0 3.7L. Athabasca Lake Athabasca Q272463 بحيرة أثاباسكا আথাবাস্কা হ্রদ Athabascasee Athabasca Athabasca Athabasca Λίμνη Αθαμπάσκα अथाबास्का झील Atapaszka-tó Athabasca Athabasca アサバスカ湖 레이크 애서배스카 Athabascameer Athabaska Athabasca Атабаска Athabascasjön Athabasca Hồ Athabasca 阿萨巴斯卡湖 1159106863دریاچه آتاباسکا אגם אתבסקה Атабаска جھیل اتھابسکا 阿薩巴斯卡湖 0Lake Lake Mistassini 2.0 3.7L. Mistassini Lake Mistassini Q1458051 بحيرة ميستاسيني লেক মিস্তাসসিনি Mistassinisee Mistassini Mistassini Mistassini Λίμνη Μιστασίνι मिस्टासिनी झील Mistassini-tó Danau Mistassini Mistassini ミスタシニ湖 레이크 미스타시니 Mistassini Mistassini Mistassini Мистассини Mistassini Mistassini Gölü Hồ Mistassini 米斯塔西尼湖 1159106873دریاچه میتاسینی אגם מיסטסיני озеро Містассіні جھیل مسٹاسینی 米斯塔西尼湖 0Alkaline Lake IJsselmeer admin-0 2.0 3.7IJsselmeer IJsselmeer Q4121 بحيرة آيسل ইজসেলমীর IJsselmeer IJsselmeer IJsselmeer IJsselmeer Άισελμιρ आईजेसेल्मीर IJsselmeer IJsselmeer IJsselmeer アイセル湖 에이설호 IJsselmeer IJsselmeer IJsselmeer Эйсселмер IJsselmeer IJsselmeer Hồ IJsselmeer 艾瑟爾湖 1159126631دریاچه آیسل אייסלמיר Ейсселмер اسیلمیر 艾瑟爾湖 0Reservoir Rybinsk Reservoir 2.0 3.7Rybinsk Res. Rybinsk Reservoir Q375029 خزان ريبنسك রাইবিনস্ক জলাধার Rybinsker Stausee Rybinsk Rybinsk Rybinsk Τεχνητή Λίμνη Ρύμπινσκ रायबिंस्क जलाशय Ribinszk-víztározó Reservoir Rybinsk Rybinsk ルイビンスク人造湖 리빈스크 레저보어 Stuwmeer van Rybinsk Zbiornik Rybiński Represa de Rybinsk Рыбинское водохранилище Rybinskreservoaren Rıbinsk Baraj Hồ Rybinsk 雷賓斯克水庫 1159124965مخزن سد ریبینسک מאגר ריבינסק Рибінське водосховище رائےبنسک ریزروائر 雷賓斯克水庫 0Alkaline Lake Issyk-Kul Ysyk Köl Ysyk Köl 2.0 3.7Issyk-Kul Issyk-Kul Q42191 بحيرة إيسيك كول ইসস্যক-কুল Yssykköl Issyk-Kul Issyk-Kul Yssyk Koul Ισσύκ-Κουλ इसिक कुल Iszik-köl Issyk Kul Ysykköl イシク・クル 이식쿨호 Issyk Koelmeer Issyk-kul Issyk-Kul Иссык-Куль Issyk-Kul Issık Göl Issyk Kul 伊塞克湖 1159126655دریاچه ایسیک کول איסיק קול Іссик-Куль اسیک کول 伊塞克湖 0Lake Lake of the Woods 2.0 5.0L. of the Woods Lake of the Woods Q845876 بحيرة الغابات লেক অফ দ্য উডস Woods Woods los Bosques Bois Λίμνη του Δάσους लेक ऑफ द वुड्स Lake of the Woods-tó Lake of the Woods dei Boschi ウッズ湖 우즈호 Woods Jezioro Leśne dos Bosques Лесное Woods Lake of the Woods Hồ Lake of the Woods 伍兹湖 1159106825دریاچه وودز אגם היערות Лісове озеро لیک آف دا ووڈز 伍茲湖 0Lake Lake Nipigon 2.0 3.7L. Nipigon Lake Nipigon Q122184 بحيرة نيبيغون লেক নিপিগন Nipigonsee Nipigon Nipigon Nipigon Λίμνη Νιπιγκόν निपिगन झील Nipigon-tó Nipigon Nipigon ニピゴン湖 니피곤호 Nipigonmeer Nipigon Nipigon Нипигон Nipigon Nipigon Hồ Nipigon 尼皮贡湖 1159106833دریاچه نیپیگون אגם ניפיגון Ніпіґон جھیل نیپیگون 尼皮贡湖 0Lake Reindeer Lake 2.0 3.7Reindeer L. Reindeer Lake Q1134446 Reindeer Reindeer Reindeer Reindeer Reindeer delle Renne 레인디어호 Reindeer Jezioro Reniferowe Reindeer Оленье озеро Reindeer 驯鹿湖 1159107185 Оленяче 馴鹿湖 0Lake Oneida Lake 3.0 5.0Oneida L. Oneida Lake Q1247231 بحيرة أونيدا ওনিয়েদা লেক Oneida Oneida Lago Oneida Oneida Λίμνη Ονέιδα ओनिडा झील Oneida-tó Danau Oneida Oneida オナイダ湖 오네이다 레이크 Oneida Oneida Lago Oneida Онейда Oneida Oneida Gölü Hồ Oneida 奧奈達湖 1159106881دریاچه اونیدا אגם אונידה Онейда اونیڈا لیک 奧奈達湖 0Lake Iliamna Lake 3.0 4.0Iliamna L. Iliamna Lake Q965436 بحيرة إليامنا ইলিয়ামনা লেক Iliamna Iliamna Iliamna Iliamna Λίμνη Ιλιάμνα इलियाम्ना झील Iliamna-tó Danau Iliamna Iliamna イリアムナ湖 일리암나 레이크 아울렛 Iliamna Iliamna Lago Iliamna Илиамна Iliamna Lake Iliamna Gölü Hồ Iliamna 伊利亞姆納湖 1159106893دریاچه ایلیامنا אגם איליאמנה Іліамна آئیامنا جھیل 伊利亞姆納湖 0Lake _untitled_1 3.0 4.0 1159106899 0Lake Lake Tahoe 3.0 4.0L. Tahoe Lake Tahoe Q169962 بحيرة تاهو টাহো হ্রদ Tahoe Tahoe Tahoe Tahoe Λίμνη Τάχο टाहो झील Tahoe-tó Tahoe Tahoe タホ湖 타호호 Tahoe Tahoe Tahoe Тахо Tahoesjön Tahoe Tahoe 太浩湖 1159106907دریاچه تاهو אגם טאהו Тахо جھیل ٹاہوئی 太浩湖 0Lake _untitled_0 3.0 4.0 1159113307 0Lake Lake Zaysan 3.0 5.0L. Zaysan Lake Zaysan Q216621 بحيرة زيسان লেক জেসান Saissansee Zaysan Zaysan Zaïssan Λίμνη Ζαϊσάν ज़ायसान झील Zaysan-tó Zaysan Zajsan ザイサン湖 자이산호 Zaysanmeer Zajsan Zaysan Зайсан Zajsan Zaysan Zaysan 斋桑泊 1159123091دریاچه زایسان אגם זייסאן Зайсан جھیل زیسان 齋桑泊 0Lake Lake Winnebago 3.0 6.0L. Winnebago Lake Winnebago Q1801110 بحيرة ويني باجو লেক উইন্নেবাগো Winnebago Winnebago Winnebago Winnebago Λίμνη Γουινεμπάγκο विनेबागो झील Winnebago-tó Danau Winnebago Winnebago ウィネベーゴ湖 레이크 위네바고 Winnebago Winnebago Winnebago озеро Виннебаго Lake Winnebago Winnebago Gölü Hồ Winnebago 溫納貝戈湖 1159106917دریاچه وینه باگو אגם ווינבגו озеро Віннебаго جھیل وینےباگو 溫納貝戈湖 0Lake Nettilling Lake 3.0 4.0Nettilling L. Nettilling Lake Q1132211 بحيرة نيتلينغ নেত্তিলিং লেক Nettilling Nettilling Nettilling Nettilling Λίμνη Νετίλινγκ नेचिलिंग झील Nettilling-tó Danau Nettilling Nettilling ネチリング湖 네틸링호 Nettilling Nettilling Nettilling Неттиллинг Nettilling Nettilling Gölü Hồ Nettilling 纳蒂灵湖 1159106925دریاچه نتیلینگ אגם נטילינג Неттіллінг نیٹیلنگ جھیل 納蒂靈湖 0Alkaline Lake Lake Turkana Lake Rudolf 3.0 4.0L. Turkana Lake Turkana Q182719 بحيرة توركانا লেক তুরকানা Turkana Turkana Turkana Turkana Τουρκάνα तुर्काना झील Turkana-tó Turkana Turkana トゥルカナ湖 투르카나호 Turkanameer Jezioro Rudolfa Turkana Рудольф Turkanasjön Turkana Turkana 图尔卡纳湖 1159126669دریاچه تورکانا אגם טורקאנה Туркана جھیل ٹرکانا 圖爾卡納湖 0Lake Dubawnt Lake 3.0 4.0Dubawnt L. Dubawnt Lake Q1262967 بحيرة دوباونت দুবোয়ান্ত লেক Dubawntsee Dubawnt Dubawnt Dubawnt Λίμνη Ντουμπαβντ डुबॉंवन्त झील Dubawnt-folyó Danau Dubawnt Dubawnt ドゥボーント湖 두번트 레이크 Dubawnt Dubawnt Lago Dubawnt Дубонт Dubawnt Dubawnt Gölü Hồ Dubawnt 杜邦特湖 1159106935دریاچه دوبانت דובוואנט Дубонт ڈبوانٹ جھیل 杜邦特湖 0Lake Baker Lake 3.0 4.0Baker L. Baker Lake Q1391737 بحيرة بيكر বেকার রিভার Baker Baker Baker Baker Λίμνη Μπέικερ बेकर झील Baker-tó Danau Baker Baker Lake ベイカー湖 베이커 레이크 Baker Jezioro Baker Baker Бейкер Baker Baker Gölü Hồ Baker 貝克湖 1159106943دریاچه بیکر אגם בייקר Бейкер بیکر جھیل 貝克湖 0Alkaline Lake Kaliningradskiy Zaliv 3.0 4.0Kaliningradskiy Zaliv Kaliningradskiy Zaliv Q5605 فيستولا لاجون কালিনিনগ্র্যাদস্কি জালিভ Frisches Haff Vistula Lagoon del Vístula Lagune de la Vistule Λιμνοθάλασσα του Βιστούλα कलिनिन्ग्राद्स्की ज़ालिव Kalinyingradszkij Zaliv Kaliningradskiy Zaliv della Vistola ヴィスワ潟 비스툴라 석호 Wislahaf Zalew Wiślany Lagoa do Vístula Калининградский залив Frisches Haff Vistül Lagünü Phá Vistula 维斯图拉潟湖 1159126681کالینینگرادسکی زالیو לגונת ויסטולה Віслинська затока کالینینگراڈسکی زالیو 维斯图拉潟湖 0Alkaline Lake Zalev Wislany Zalew Wislany 3.0 4.0Zalew Wislany Zalev Wislany Q5605 زاليو ويسلاني জালেউ উইসলানি Frisches Haff Vistula Lagoon del Vístula Lagune de la Vistule Λιμνοθάλασσα του Βιστούλα ज़ालेव विस्लानी Zalew Wislany Zalew Wislany della Vistola ヴィスワ潟 비스툴라 석호 Wislahaf Zalew Wiślany Lagoa do Vístula Калининградский залив Frisches Haff Vistül Lagünü Phá Vistula 维斯图拉潟湖 1159126693زاله ویسلانی לגונת ויסטולה Віслинська затока زیلیو وسلانی 维斯图拉潟湖 0Lake Lake Champlain 3.0 4.0L. Champlain Lake Champlain Q68467 بحيرة شامبلين লেক চ্যামপ্লেন Champlain Champlain Champlain Champlain Λίμνη Τσάμπλεϊν चम्पलेन झील Champlain-tó Champlain Champlain シャンプレーン湖 챔플레인 호 Champlainmeer Champlain Champlain Шамплейн Champlainsjön Champlain Hồ Champlain 尚普蘭湖 1159106953دریاچه چمپلین אגם שמפליין Озеро Шамплейн جھیل چامپلین 尚普蘭湖 0Alkaline Lake Salton Sea 3.0 4.0Salton Sea Salton Sea Q503301 بحر سالتون সালটন সাগর Saltonsee Salton Sea Saltón Salton Sea Θάλασσα Σάλτον साल्टन सागर Salton-tó Salton Sea Salton ソルトン湖 솔턴호 Salton Sea Salton Sea Salton Солтон-Си Salton Sea Salton Denizi Biển Salton 索尔顿湖 1159126453دریای سالتون ימת סלטון море Салтон بحیرہ سالتون 索爾頓湖 0Lake Lac la Martre 3.0 4.0L. la Martre Lac la Martre Q1516443 بحيرة لا مارتر ল্যাক লা মার্ত্রে Martre Martre Martre Martre Λακ λα Μάρτρ लैक ला मार्ट्रे Lac la Martre Lac la Martre Lac la Martre マルトル湖 라마르트르 Lac la Martre Lac la Martre Lago la Martre Ла-Мартр Martre Lac la Martre Hồ Lac la Martre 馬特爾湖 1159106971دریاچه لا مارتره אגם לה מרטר Ла-Мартре لاک لا مارٹرے 馬特爾湖 0Lake Lago Llanquihue 3.0 4.0L. Llanquihue Lago Llanquihue Q826464 بحيرة يانكيوي লাগো ল্যাঙ্কুইহুয়ে Llanquihue Llanquihue Llanquihue Llanquihue Λίμνη Γιανκίουε लागो लैनक्यू Llanquihue-tó Llanquihue Llanquihue ジャンキウェ湖 라고 랑키후에 Llanquihue Llanquihue Lago Llanquihue Льянкиуэ Llanquihue Lago Llanquihue Hồ Llanquihue 延基韦湖 1159113343لاگو لیانکیهو אגם יאנקיווה Янкіуе لاگو لانقوئیہوئی 延基韋湖 0Lake Hongze Hu 3.0 4.0Hongze Hu Hongze Hu Q31845950 بحيرة هونغز হংজে হু Hongze Hu Hongze Lake Hongze Hu Lac Hongze Χονγκζέ Χου होंग्ज़े हु Hongze Hu Danau Hongze Lago Hongze 洪沢湖 홍제 후 Hongze Lake Hongze Hu Lago Hongze озеро Хунцзэху Hongze Hu Hongze Hu Hồ Hồng Trạch 洪泽湖 1159113359هونگز هو הונגזה Хонжху ہونگزی ہو 宏澤湖 0Lake Khövsgöl Nuur Hövsgöl Nuur 3.0 5.0Khövsgöl Nuur Khövsgöl Nuur Q192215 بحيرة خوفسغول খোভসগোল নূর Chöwsgöl Nuur Khövsgöl Nuur Ubsugul Khövsgöl Λίμνη Χουβσγκούλ ख़ोव्स्गोल झील Hövszgöl-tó Khövsgöl Hôvsgôl Nuur フブスグル湖 후브스굴호 Hövsgöl Nuur Chubsuguł Khuvsgul Хубсугул Chövsgöl Hövsgöl Khovsgol 库苏古尔湖 1159113373دریاچه خووسگول אגם חבסגל Хубсуґул کھوسگول نور 庫蘇古爾湖 0Alkaline Lake Uvs Nuur 3.0 4.0Uvs Nuur Uvs Nuur Q81150 بحيرة يوفس উভস হ্রদ Uws Nuur Uvs Uvs Uvs nuur Ουβς Νουρ यूवीएस नूर Uvsz-tó Uvs Uvs Nuur ウヴス・ヌール 우브스 누르 Uvs Nuur Uws-nur Uvs Убсу-Нур Uvs Nuur Ubsa Uvs 烏布蘇湖 1159126709دریاچه یواس אובס נור Убсу-Нур اوس نور 烏布蘇湖 0Lake Lac Moeru Lake Mweru 3.0 4.0L. Moeru Lac Moeru Q504433 بحيرة مويرو মুয়েরু হ্রদ Mwerusee Mweru Moero Moero Λακ Μοερού लैक ओनैन्गु Mweru-tó Mweru Mweru ムウェル湖 므웨루호 Mwerumeer Mweru Mweru Мверу Mwerusjön Mweru Mweru 姆韦鲁湖 1159113405دریاچه مورو אגם מורו Мверу لاک موئیرو 姆韋魯湖 0Lake Lake Khanka Xingkai Hu, Ozero Khanka admin-0 3.0 4.0L. Khanka Lake Khanka Q201843 بحيرة خانكا লেক খাংকা Chankasee Khanka Janka Khanka Λίμνη Χάνκα खानका झील Hanka-tó Khanka Chanka ハンカ湖 한카호 Chankameer Chanka Khanka Ханка Chanka Khanka Khanka 兴凯湖 1159113423دریاچه خانکا אגם חאנקה Ханка جھیل کھانکا 興凱湖 0Lake Tonlé Sap 3.0 4.0Tonle Sap Tonlé Sap Q199938 تونلي ساب টনলে স্যাপ Tonle Sap Tonlé Sap Tonlé Sap Tonlé Sap Τόνλε Σαπ टोनले साप Szap-tó Tonle Sap Tonle Sap トンレサップ 톤레사프호 Tonlé Sapmeer Tonle Sap Tonle Sap Тонлесап Tonlé Sap Tonlé Sap Tonlé Sap 洞里萨湖 1159113439تونله ساپ טונלה סאפ Тонлесап تونلے ساپ 洞里薩湖 0Alkaline Lake Qinghai Hu Koko Nor 3.0 4.0Qinghai Hu Qinghai Hu Q201294 بحيرة تشينغهاي কোইংহাই হু Qinghai Qinghai Qinghai Qinghai Λίμνη Τσινγκχάι चिंगहई झील Csinghaj-tó Qinghai Qinghai 青海湖 칭하이호 Qinghaimeer Kuku-nor Chingai Кукунор Qinghaisjön Koko Nor Thanh Hải 青海湖 1159126725دریاچه چینگهای ימת צ'ינגהאי Кукунор جھیل چنگھائی 青海湖 0Lake Ozero Yarroto Vtoroye L. Yarroto Vtoroye 3.0 4.0O. Yarroto Vtoroye Yarroto Q4539001 بحيرة ياروتو فتوري ওজেরো ইয়াররোতো ভতোররোয়ে Ozero Yarroto Vtoroye Yarroto Vtoroe Lago Yarroto Vtoroye Ozero Yarroto Vtoroye Οζέρο Γιαρότο Περβόιε ओज़ेरो यारोतो वोतोरोये Jarroto Vitoroje-tó Danau Yarroto Vtoroye Ozero Yarroto Vtoroye ヤロトヴトロウェ湖 오제로 야로토 브토로예 Ozero Yarroto Vtoroye Jezioro Yarroto Vtoroye Lago Yarroto Vtoroye Яррото 2-е Ozero Jarroto Vtoroje Ozero Yarroto Vtoroye Hồ Yarroto Vtoroye 亚罗托夫托罗耶湖 1159113467اوزرو یاروتو وتورویه אגם יארוטו וטורויה озеро Яррото Друге اوزیرو یاروتو ویٹوروئے 雅羅托維托耶湖 0Lake Lake Tharthar 3.0 4.0Buhayrat ath Tharthar Buhayrat ath Tharthar Q1640519 منخفض الثرثار বুহায়রত আথ থর্থর Tharthar Tharthar Tharthar du Thartar Μπουχαϊράτ ατ Ταρτάρ बुहारत अथ थारथार Buhayrat ath Tharthar Tharthar Buhayrat ath Thartar サルサール湖 부하이라트 타르타르 Tharthar Jezioro Tharthar Tharthar Тартар Tharthar Buhayrat ath Tharthar Tharthar 塞尔萨尔湖 1159123125دریاچه ثرثار בוהאיראט אט טארטאר Озеро Тартар بوحیرت اتھ تھرتھار 塞尔萨尔湖 0Alkaline Lake Razzaza Lake Lake Razazah Lake Milh 3.0 4.0L. Razazah Lake Razazah Q2007652 بحيرة الرزازة লেক রাজাজাহ Razzaza Milh Razzaza Lake Milh Λίμνη Ραζαζά रज़ाज़ाह झील Razazah-tó Danau Razazah Milh ミル湖 레이크라자자 Lake Milh Jezioro Razazah Lago Razzaza Эль-Мильх Razzaza Razazah Gölü Hồ Razazah 赖扎宰湖 1159126735دریاچه رزازه אגם רזאזה озеро Разаза جھیل رازازا 赖扎宰湖 0Alkaline Lake Dead Sea 3.0 4.0Dead Sea Dead Sea Q23883 البحر الميت মৃত সাগর Totes Meer Dead Sea mar Muerto mer Morte Νεκρά θάλασσα मृत सागर Holt-tenger Laut Mati Mar Morto 死海 사해 Dode Zee Morze Martwe Mar Morto Мёртвое море Döda havet Lut Biển Chết 死海 1159126747دریای مرده ים המלח Мертве море بحیرہ مردار 死海 0Lake Lake Pskov Pihkva järv|Pskovskoe Ozero admin-0 3.0 4.0L. Pskov Pskov Q1144905 بحيرة بسكوف লেক পস্কভ Pleskauer Pihkva Pskos Pihkva Λίμνη Πσκοβ पस्कोव झील Pszkovi-tó Danau Pskov Lago di Pskov プスコフ湖 프스콥스코예호 Pskovskoe ozero Jezioro Pskowskie Lago Peipus Псковское озеро Pskovsjön Pskov Gölü Hồ Pskov 普斯科夫湖 1159113451دریاچه پسکوف אגם פסקוב Псковське озеро جھیل سکوو 普斯科夫湖 0Lake Lac Saint-Jean 4.0 5.0L. St.-Jean Lac St.-Jean Q979922 بحيرة سان جان ল্যাক সেন্ট-জ্যাঁ Saint-Jean Saint-Jean Saint-Jean Saint-Jean Λακ Σαιν-Ζαν लैक सेंट-जीन Lac Saint-Jean Lac Saint-Jean Saint-Jean サンジャン湖 락 생 쟝 Saint-Jean Saint-Jean Lago Saint-Jean Сен-Жан Saint-Jean Lac Saint-Jean Hồ Saint-Jean 圣让湖 1159123839دریاچه سنت جین מאגר סן ז'אן Сен-Жан لاک سینٹ جین 聖讓湖 1Lake Keuka L. 4.0 5.0 Keuka L. Q1335725 بحيرة كيوكا কেউকা লেক Keuka Keuka Lago Keuka Keuka Λίμνη Κέουκα केउका झील Keuka-tó Danau Keuka Keuka キューカ湖 크카 레이크 Keuka Keuka Lago Keuka озеро Кеюка Keuka Lake Keuka Gölü Hồ Keuka 奎爾加湖 1159106979دریاچه کیوکا אגם קאוקה озеро Кеука کیوکا جھیل 奎爾加湖 4Lake Seneca Lake 4.0 5.0 Seneca Lake Q1552706 بحيرة سينيكا সেনেকা লেক Seneca Seneca Lago Seneca Seneca Λίμνη Σενέκα सेनेका झील Seneca-tó Danau Seneca Seneca セネカ湖 세네카 레이크 Seneca Seneca Seneca Сенека Seneca Lake Seneca Gölü Hồ Seneca 塞內卡湖 1159106989دریاچه سنکا אגם סנקה Сенека سینیکا جھیل 塞內卡湖 0Lake Cayuga Lake 4.0 5.0Cayuga L. Cayuga Lake Q731175 بحيرة كايوغا কেউগা লেক Cayuga Cayuga Lago Cayuga Cayuga Λίμνη Καγιούγκα केयुगा झील Cayuga-tó Danau Cayuga Cayuga ケイユーガ湖 카유가 레이크 Cayuga Cayuga Cayuga озеро Каюга Cayuga Lake Cayuga Gölü Hồ Cayuga 卡尤加湖 1159106997دریاچه کایوگا אגם קייוגה озеро Каюга کےیوگا جھیل 卡尤加湖 0Reservoir Kainji Reservoir 4.0 5.0Kainji Res. Kainji Reservoir Q770141 بحيرة كاينجي কাইনজি রিজার্ভার Kainji-Stausee Kainji Kainji Kainji Τεχνητή Λίμνη Κάιντζι केंजी जलाशय Kainji-víztározó Kainji Kainji カインジ湖 카인지 레저보어 Kainji Kainji Kainji Каинджи Kainji Kainji Rezervuarı Hồ Kainji 卡因吉大坝 1159124975مخزن سد کینجی מאגר קיינג'י Каїнджі کینجی ریزروائر 卡因吉大壩 0Alkaline Lake Lake Urmia 4.0 5.0L. Urmia Lake Urmia Q199551 بحيرة أرومية উর্মিয়া হ্রদ Urmiasee Urmia Urmía Ourmia Λίμνη Ούρμια उर्मिया झील Urmia-tó Urmia Urmia オルーミーイェ湖 우르미아호 Urmiameer Urmia Urmia Урмия Urmiasjön Urmiye Urmia 尔米亚湖 1159126761دریاچه ارومیه ימת אורמיה Урмія بحیرہ ارومیہ 爾米亞湖 0Lake Cree Lake 4.0 5.0Cree L. Cree Lake Q945023 بحيرة كري ক্রী লেক Cree Cree Cree Cree Λίμνη Κρι क्री झील Cree-tó Danau Cree Cree Lake クリー湖 크리 레이크 Cree Cree Cree Кри Cree Cree Gölü Hồ Cree 克里湖 1159107007دریاچه کِری אגם קְרִי озеро Крі کری جھیل 克里湖 0Lake _untitled_29 4.0 5.0 1159107015 0Lake Kasba Lake 4.0 5.0Kasba L. Kasba Lake Q719538 بحيرة كاسبا কাসাবা লেক Kasba Kasba Kasba Kasba Λίμνη Κάσμπα कस्बा झील Kasba-tó Danau Kasba Kasba Lake カスバ湖 카스바 레이크 Kasba Jezioro Kasba Lago Kasba Касба Kasba Kasba Hồ Kasba 卡斯巴湖 1159107025دریاچه کاسبا אגם קסבה озеро Касба کاسبہ جھیل 卡斯巴湖 0Alkaline Lake Sarygamysh Köli admin-0 4.0 5.0Sarygamysh Köli Sarygamysh Köli Q257416 ساريغاميش كولي সরিগামিশ কলি Sarykamyschsee Sarygamysh Sariqamish Sary Kamysh Σαριγκαμίς सरयगमिश कोलि Sarygamysh Köli Sarygamysh Sarygamysh サリカミシュ湖 사리가미시 콜리 Sarygamysh Jezioro Sarykamyskie Sariqamish Сарыкамышское озеро Sarygamysh Köli Sarıkamış Hồ Sarygamysh Köli 薩雷卡梅什湖 1159126775دریاچه ساریقامیش אגם סריקמיש Сарикамиське озеро سارگامیش کولی 薩雷卡梅什湖 0Lake L. Chany 4.0 5.0 L. Chany Q1520895 Tschanysee Chany Chany Tchany Csani-tó Čany Tsjani Czany Чаны 钱尼湖 1159121323 Чани 錢尼湖 0Alkaline Lake Alaköl Alakol 4.0 5.0Alakol Alakol Q310547 بحيرة الأكول আলাকোল Alakölsee Alakol Alakol Alakol Λίμνη Αλακόλ अलाकोल Alakol-tó Alakol Alakol アラコル湖 알라콜 Alakol Ała-kol Alakol Алаколь Alakol Alagöl Hồ Alakol 阿拉湖 1159126789آلاکول אגם אלאקול Алаколь ایلاکول 阿拉湖 0Lake _untitled_28 4.0 5.0 1159107033 0Lake Lac-à-l'Eau-Claire 4.0 5.0Lac-à-l'Eau-Claire Lac-à-l'Eau-Claire Q1699973 بحيرة ألو كلاير ল্যাক-আ-এউ-ক্লেয়ার Eau Claire Wiyâshâkimî Lagos Clearwater Wiyâshâkimî Λακ-α-λΩ-Κλερ लैक-अ-इऔ-क्लेयर Lac-à-l'Eau-Claire Lac-à-l'Eau-Claire Lac-à-l'Eau-Claire オークレア湖 락-에-로-끌레르 Clearwater Lakes à l'Eau Claire Lac-à-l'Eau-Claire Клируотер Wiyâshâkimî Lac-à-l'Eau-Claire Hồ Lac-à-l'Eau-Claire 歐克萊爾湖 1159107045دریاچههای کلیرواتر לאק-א-ל'אאו-קלייר Клірвотер لاک ایل ایو کلیئر 歐克萊爾湖 0Lake Lake Nipissing 4.0 5.0L. Nipissing Lake Nipissing Q1356838 بحيرة نيبيسينغ লেক নিপিসিং Nipissing Nipissing Nipissing Nipissing Λίμνη Νιπίσινγκ निपिसिंग झील Nipissing-tó Nipissing Nipissing ニピシング湖 레이크 니피싱 Nipissingmeer Nipissing Lago Nipissing Ниписсинг Nipissingsjön Nipissing Gölü Hồ Nipissing 尼皮辛湖 1159107053دریاچه نیپیسینگ אגם ניפיסינג Ніпіссінґ جھیل نپیسنگ 尼皮辛湖 0Lake Hulun Nuur Hulun Nur 4.0 5.0Hulun Nuur Hulun Nuur Q537374 بحيرة دالاي হুলুন নূর Hulun Hulun Hulun Hulun Χουλούν Νουρ हुलुन नुउर Hulun Nuur Hulun Hulun フルン湖 후룬호 Hulun Hulun Nur Hulun Далайнор Hulunsjön Hulun Hô Luân 呼倫湖 1159113513دریاچه هولون אגם חולון Гулунь-Нур ہولون جھیل 呼倫湖 0Lake Lake Bangweulu 4.0 5.0L. Bangweulu Lake Bangweulu Q673169 بحيرة بانغويلو লেক বাংগোয়েউলু Bangweulusee Bangweulu Bangweulu Bangwelo Λίμνη Μπανγκουέλου बंगवेलु झील Bangweulu-tó Bangweulu Bangweulu バングウェウル湖 레이크 방웨울루 Bangweulumeer Bangweulu Bangweulu Бангвеулу Bangweulusjön Bangweulu Gölü Hồ Bangweulu 班韋烏盧湖 1159113531دریاچه بانگوولو אגם בנגוואולו Бангвеулу جھیل بینگوئیلو 班韋烏盧湖 0Lake Inarijärvi 4.0 5.0Inarijrvi Inarijrvi Q203137 بحيرة إناري ইনারিজভি Inarijärvi Inari Inari Inari Ίναρη इनारिज्र्विक Inarijrvi Inari Inari イナリ湖 이나리호 Inarimeer Inari Inari Инари Enare träsk İnari Hồ Inarijrvi 伊纳里湖 1159113545دریاچه ایناری אגם אינארי Інарі ایناریجروی 伊納里湖 0Lake Oulujärvi 4.0 5.0Oulujärvi Oulujärvi Q580019 أولو جيرفي Oulujärvi Oulujärvi Oulu Oulu Οουλουγιάρβι Oulujärvi Oulujärvi オウル湖 Oulujärvi Oulujärvi Оулуярви Ule träsk Oulujärvi 奧盧湖 1159117309 奧盧湖 0Lake Lake Peipus Lake Peipsi-Pihkva admin-0 4.0 5.0L. Peipus Lake Peipus Q19253 بحيرة بيبوس লেক পেইপুস Peipussee Peipus Peipus Peïpous Πέιπους पीपुस झील Peipus-Pszkovi-tó Peipsi dei Ciudi ペイプシ湖 페이푸스호 Peipusmeer Pejpus Peipus Псковско-Чудское озеро Peipus Peipus Peipus 楚德湖 1159113563دریاچه پیپوس אגם פייפסי Чудсько-Псковське озеро جھیل پائیپس 楚德湖 0Lake Lake Kivu admin-0 4.0 5.0L. Kivu Lake Kivu Q125912 بحيرة كيفو কিভু হ্রদ Kiwusee Kivu Kivu Kivu Λίμνη Κίβου कीवू झील Kivu-tó Kivu Kivu キブ湖 키부호 Kivumeer Kiwu Kivu Киву Kivusjön Kivu Kivu 基伍湖 1159113577دریاچه کیوو אגם קיוו Ківу جھیل کیوو 基伏湖 0Lake Lake Edward admin-0 4.0 5.0L. Edward Lake Edward Q125211 بحيرة إدوارد এডওয়ার্ড হ্রদ Eduardsee Edward Eduardo Édouard Λίμνη Εδουάρδου ऍड्वर्ड झील Edward-tó Edward Eduardo エドワード湖 에드워드호 Edwardmeer Jezioro Edwarda Eduardo Эдвард Edwardsjön Edward Edward 爱德华湖 1159113595دریاچه ادوارد אגם אדוארד Едвард جھیل ایڈورڈ 愛德華湖 0Lake Tai Hu 4.0 5.0Tai Hu Tai Hu Q140712 بحيرة تاي তাই হু Tai Hu Tai Taihu Tai Τάι Χου ताइहू झील Taj-tó Taihu Tai Hu 太湖 타이 호 Taihu Tai Hu Taihu Тайху Tai Hu Tai Thái 太湖 1159113611رود تای טאיהו Тайху تائی ہو 太湖 0Lake _untitled_27 4.0 5.0 1159107065 0Alkaline Lake Laguna Mar Chiquita Mar Chiquita 4.0 5.0Mar Chiquita Mar Chiquita Q21837060 مار تشيكيتا মার চিকুইতা Mar Chiquita Mar Chiquita Mar Chiquita Mar Chiquita Μαρ Τσικίτα मार् चिक्विटा Mar Chiquita Mar Chiquita Mar Chiquita マール・チキータ 마르 치키타 Mar Chiquita Mar Chiquita Mar Chiquita озеро Мар-Чикита Mar Chiquita Mar Chiquita Hồ Mar Chiquita 马契基塔湖 1159126805مار چیکیتا מאראצ'ה Мер-Чікіта مار چیکیٹا 馬奇基塔 0Reservoir Kremenchuk Reservoir 4.0 5.0Kremenchuk Res. Kremenchuk Reservoir Q1431500 خزان كريمنشوك ক্রেমেনচুক রিজার্ভার Krementschuker Stausee Kremenchuk Kremenchuk Krementchouk Τεχνητή Λίμνη Κρεμεντσουκ क्रेमेनचुक जलाशय Kremencsuk-víztározó Reservoir Kremenchuk Serbatoio Kremenchuk クレメンチュク貯水池 크레멘추크 레저보어 Kremenchuk Zbiornik Kremieńczucki Represa de Kremenchuk Кременчугское водохранилище Krementjukdammen Kremenchuk Rezervuarı Hồ Kremenchuk 克列缅丘格水库 1159125001مخزن سد کرمنچوک מאגר קרמנצ'וק Кременчуцьке водосховище کریمینچک ریزروائر 克列緬丘格水庫 0Reservoir Rés. de La Grande 3 4.0 5.0Rs. de La Grande 3 Réservoir de La Grande 3 Q2179011 خزان دي لا جراندي ۳ রিজার্ভার ডি লা গ্র্যান্ডি 3 La Grande 3 La Grande 3 Presa de La Grande 3 La Grande 3 Ρεζερβουάρ ντε Λα Γκράντε 3 रिज़र्वोयर डे ला ग्रांडे 3 La Grande 3-víztározó Reservoir La Grande 3 Réservoir de La Grande 3 レゼルヴォワール・ド・ラグランデ3 레저보어 드 라 그란데 3 La Grande-3 Reservoir Zbiornik La Grande 3 Represa de La Grande 3 водохранилище Резервуар-ла-Гран-Ривьер 3 La Grande 3 Réservoir de La Grande 3 Hồ La Grande 3 格朗德三级水库 1159123951مخزن سد گراند 3 מאגר לה גרנדה 3 водосховище Де-ла-Гранде 3 ریزروائر ڈی لا گرانڈے 3 格蘭德水庫 3 0Reservoir Rés. de La Grande 2 4.0 5.0Rs. de La Grande 2 Réservoir de La Grande 2 Q1337872 خزان دي لا جراندي ۲ রিজার্ভার ডি লা গ্র্যান্ডি 2 Robert-Bourassa Robert-Bourassa Robert-Bourassa Robert-Bourassa Ρεζερβουάρ ντε Λα Γκράντε 2 रिज़र्वोयर डे ला ग्रांडे 2 La Grande 2-víztározó Reservoir La Grande 2 Réservoir de La Grande 2 ロバート=ブラッサ貯水池 레저보어 드 라 그란데 2 La Grande-2 Reservoir Zbiornik La Grande 2 Represa de La Grande 2 Робер-Бурасса Robert-Bourassa Réservoir de La Grande 2 Hồ La Grande 2 格朗德二级水库 1159123871مخزن سد گراند 2 מאגר לה גרנדה 2 Робер-Бурасса ریزروائر ڈی لا گرانڈے 2 格蘭德水庫 2 0Lake _untitled_26 4.0 5.0 1159107077 0Alkaline Lake Lago Enriquillo 4.0 5.0L. Enriquillo Lago Enriquillo Q1464758 بحيرة إنريكيو লাগো এনরিকুইল্লো Enriquillo Enriquillo Enriquillo Enriquillo Λάγκο Ενρίκιλο लागो एनरिकेलो Enriquillo-tó Enriquillo Enriquillo エンリキージョ湖 라고 엔리퀼로 Enriquillomeer Enriquillo Enriquillo Энрикильо Enriquillo Lago Enriquillo Enriquillo 恩里基湖 1159126465لاگو انریکیلو אגם אנריקיו Енрикільйо لاگو اینریکوئیلو 恩里基湖 0Lake _untitled_25 4.0 5.0 1159107087 0Lake _untitled_24 4.0 5.0 1159107099 0Lake Lake Sakami 4.0 5.0L. Sakami Lake Sakami Q1799611 بحيرة ساكامي লেক সাকামি Sakami Sakami Lago Sakami Sakami Λίμνη Σακάμι सकामी झील Sakami-tó Danau Sakami Lake Sakami サカミ湖 레이크 사카미코 Lake Sakami Jezioro Sakami Lago Sakami озеро Саками Sakami Sakami Gölü Hồ Sakami 薩卡米湖 1159107115دریاچه ساکامی אגם סאקאמי озеро Сакамі جھیل ساکامی 薩卡米湖 0Lake Lago Argentino 4.0 5.0L. Argentino Lago Argentino Q753898 بحيرة أرخنتينو লাগো আরজেন্টিনো Argentino Argentino Argentino Argentino Λίμνη Αρχεντίνο अर्जेंटीनो झील Argentino-tó Argentino Argentino アルヘンティーノ湖 아르헨티노호 Argentinomeer Argentino Argentino Архентино Argentino Argentino Hồ Argentino 阿根廷湖 1159113621دریاچه آرخنتینو אגם ארחנטינו Архентіно لاگو ارجینٹینو 阿根廷湖 0Lake Nam Co 4.0 5.0Nam Co Nam Co Q651294 نامتسو নাম কো Nam Co Namtso Nam Namtso Ναμ Κο नम त्सो Nam Co Nam Co Namtso ナムツォ 남초호 Namtso Nam Co Lago Nam Намцо Namtso Namtso Namtso 纳木错 1159113637نامتسو נאם דין Намцо نامتسو 納木錯 0Alkaline Lake Lake Tuz 4.0 5.0L. Tuz Lake Tuz Q211823 بحيرة طوز লেক তুজ Tuz Tuz Tuz Tuz Λίμνη Τουζ तुज़ झील Tuz-tó Danau Tuz Salato トゥズ湖 레이크 투즈 Tuz Tuz Tuz Туз Tuz Tuz Tuz 图兹湖 1159126815دریاچه توز ימת טוז Туз جھیل ٹز 圖茲湖 0Lake Scott Lake 4.0 5.0Scott L. Scott Lake Q7359166 بحيرة سكوت স্কট লেক Lake Scott Scott Lago Scott Scott Λίμνη Σκοτ स्कॉट झील Scott-tó Danau Scott Scott Lake スコット湖 스콧 레이크 Scott Lake Scott Lake Lago Scott озеро Скотт-Лейк Scott Lake Scott Gölü Hồ Scott 斯科特湖 1159107139دریاچه اسکات אגם סקוט озеро Скотт اسکاٹ جھیل 斯科特湖 0Lake _untitled_22 4.0 5.0 1159113653 0Lake Rikkavesi _untitled_21 4.0 5.0Rikkavesi Rikkavesi Q7334058 ريكافيسي রিকভেসি Rikkavesi Rikkavesi Rikkavesi Rikkavesi Ρικκαβέσι रिक्कावेसि Rikkavesi Rikkavesi Rikkavesi リッカヴェシ 리카베시 Rikkavesi Rikkavesi Rikkavesi озеро Риккавеси Rikkavesi Rikkavesi Hồ Rikkavesi 里卡韦西水库 1159123265ریکاوسی ריקאבססי Ріккавесі رکاویسی 里卡韋西水庫 0Lake _untitled_20 4.0 5.0 1159113669 0Lake Ozero Nerpich'ye L. Nerpich'ye 4.0 5.0O. Nerpich'ye Ozero Nerpich'ye Q1774501 بحيرة نيربيتشي ওজেরো নেরপিচ্যে Ozero Nerpich'ye Nerpichye Lago Nerpich'ye Ozero Nerpich'ye Οζέρο Νερπίχγιε ओज़ेरो नेरपिच'ये Nerpicsje-tó Danau Nerpich'ye Nerpič'e ネルピチエ湖 오제로 네르피치예 Nerpitsje Jezioro Nerpich'ye Lago Nerpich'ye Нерпичье Ozero Nerpitje Ozero Nerpich'ye Hồ Nerpich'ye 涅尔皮奇耶湖 1159113701اوزرو نرپیچیه אגם נרפיצ'יה Нерпине اوزیرو نرپیچے 涅爾皮奇耶湖 0Lake Ozero Yarroto Pervoye L. Yarroto Pervoye 4.0 5.0O. Yarroto Pervoye Ozero Yarroto Q4538999 بحيرة ياروتو بيرفوي ওজেরো ইয়াররোতো পেরভোয়ে Ozero Yarroto Pervoye Yarroto Pervoe Lago Yarroto Pervoye Ozero Yarroto Pervoye Οζέρο Γιαρότο Περβόιε ओज़ेरो यारोटो परवॉय Jarroto Pervoje-tó Danau Yarroto Pervoye Ozero Yarroto Pervoye ヤロトペルヴォウェ湖 오제로 야로토 퍼보이 Ozero Yarroto Pervoye Jezioro Yarroto Pervoye Lago Yarroto Pervoye Яррото 1-е Ozero Jarroto Pervoje Ozero Yarroto Pervoye Hồ Yarroto Pervoye 亚罗托佩尔沃耶湖 1159113749اوزرو یاروتو پروویه אגם יארוטו פרבויה озеро Яррото Перше اوزیرو یاروتو پیروئے 雅羅托皮維耶湖 0Lake Ozero Neyto L. Neyto 4.0 5.0O. Neyto Ozero Neyto -1 بحيرة نيتو ওজেরো নেয়তো Ozero Neyto Ozero Neyto Lago Neyto Ozero Neyto Οζέρο Νέιτο ओज़ेरो नेटो Nejto-tó Danau Neyto Ozero Neyto ネイト湖 오제로 네이토 Ozero Neyto Jezioro Neyto Lago Neyto озеро Неято Ozero Neyto Ozero Neyto Hồ Neyto 涅托湖 1159113765اوزرو نیوتو אגם נייטו озеро Нейто اوزیرو نیٹو 涅托湖 0Lake Ozero Yambuto L. Yambuto 4.0 5.0O. Yambuto Ozero Yambuto -1 بحيرة يامبوتو ওজেরো ইয়ানবুতো Ozero Yambuto Ozero Yambuto Lago Yambuto Ozero Yambuto Οζέρο Γιαμπούτο ओज़ेरो यंबुतो Jambuto-tó Danau Yambuto Ozero Yambuto ヤムブト湖 오제로 얌부토 Ozero Yambuto Jezioro Yambuto Lago Yambuto озеро Ямбуто Ozero Jambuto Ozero Yambuto Hồ Yambuto 亚姆布托湖 1159113781اوزرو یامبوتو אגם ימבוטו озеро Ямбуто اوزیرو یامبوتو 延布托湖 0Lake _untitled_15 4.0 5.0 1159113799 0Lake Lake Vygozero 4.0 5.0L. Vygozero Lake Vygozero Q1315765 بحيرة فيجوزيرو লেক ভ্যগোজেরো Wygosero Vygozero Vygózero Vygozero Λίμνη Βιγκοζέρο वायगोज़ेरो झील Vygozero-tó Danau Vygozero Vygozero ヴィゴゼロ湖 레이크 비고제로 Vygozeromeer Wygoziero Vyg Выгозеро Vygozero Vıgozero Hồ Vygozero 维戈泽罗湖 1159113819دریاچه ویگوزرو אגם ויגוזרו озеро Вигозеро جھیل وائےگوزیرو 维戈泽罗湖 0Lake Lake Segozerskoye 4.0 5.0L. Segozerskoye Lake Segozerskoye Q1416209 بحيرة سيجوزيرو লেক সেগোজেরস্কোয়া Segosero Segozero Segozero Segozero Λίμνη Σεγκοζερκόιε सेगोज़एर्स्कोये झील Segozerskoye-tó Danau Segozerskoye Segozero セゴゼロ湖 레이크 세고제르스코예 Segozero Segoziero Lago Segozero Сегозеро Segozero Segozero Hồ Segozerskoye 谢戈泽罗湖 1159113851دریاچه سگوزرسکویی אגם סגוזרסקויה озеро Сегозеро جھیل سیگوزرسکوئی 謝戈澤羅湖 0Lake Koitere _untitled_13 4.0 5.0Koitere Koitere Q1345130 كويتير কোইতেরে Koitere Koitere Koitere Koitere Κόιτερε कोइतेरे Koitere Koitere Koitere コイテレ湖 코이테레 Koitere Koitere Koitere Койтере Koitere Koitere Hồ Koitere 科伊泰雷湖 1159123247کویتره קויטרה Коїтере کوائیٹیرے 科伊特雷水庫 0Lake Pielinen 4.0 5.0Pielinen Pielinen Q845891 بيلينين পিয়েলিনেন Pielinen Pielinen Pielinen Pielinen Πιελίνεν पाइलिनेन Pielinen Pielinen Pielinen ピエリネン湖 필리넨 Pielinen Pielinen Pielinen Пиелинен Pielisjärvi Pielinen Hồ Pielinen 皮耶利宁湖 1159113873پیلینن אגם פילינן Пієлінен پائیلینن 皮耶利寧湖 4Lake Pääjärvi 4.0 5.0Pääjärvi Pääjärvi Q1458409 باجارفي পাজার্ভি Pjaosero Pyaozero Piaozero Piaozero Πααγάρβι पजार्विक Pääjärvi Paajarvi Pjaozero ペーヤルヴィ湖 파야르비 Pjaozero Piaoziero Pääjärvi Пяозеро Pääjärvi Pääjärvi Hồ Pääjärvi 皮亚奥泽罗湖 1159106703پاجاروی אגם פאאיארווי Пяозеро پاجاروی 皮亞奧澤羅湖 0Lake Lake Topozero 4.0 5.0L. Topozero Lake Topozero Q709323 بحيرة توبوزيرو লেক তোপোজেরো Toposero Topozero Topozero Topozero Λίμνη Τοποζέρο टोपोज़ेरो झील Topozero-tó Danau Topozero Topozero トポゼロ湖 레이크 토포제로 Topozero Topoziero Lago Topozero Топозеро Topozero Topozero Gölü Hồ Topozero 托波泽罗湖 1159113889دریاچه توپوزرو אגם טופוזרו озеро Топозеро جھیل ٹوپوزیرو 托波澤羅湖 0Lake _untitled_9 4.0 5.0 1159107149 0Lake _untitled_8 4.0 5.0 1159107159 0Lake Bosten Hu 4.0 5.0Bosten Hu Bosten Hu Q611206 بحيرة بوستن বোস্টেন হু Bosten Bosten Bosten Bosten Μπόστεν Χου बोस्तेन झील Boszten-tó Bosten Bosten ボステン湖 보스텅 호수 Bosten Bosten Hu Lago Bosten Баграшкёль Bosten Bosten Bosten 博斯腾湖 1159113927بوستن هو בוסטן Баграшкьоль بوسٹن ہو 博斯騰湖 0Lake _untitled_2 4.0 5.0 1159113979 0Lake Lake Il'Men' 4.0 5.0L. Il'Men' Lake Il'Men' Q203462 بحيرة إيلمين লেক ইল'মেন Ilmensee Ilmen Ilmen Ilmen Λίμνη Ιλλ-Μεν इल'मेन' झील Ilmeny-tó Ilmen Il'men' イリメニ湖 일멘호 Ilmenmeer Ilmień Ilmen Ильмень Ilmen İlmen Hồ Il'Men' 伊尔门湖 1159123281دریاچه ایلمن אגם אילמן Ільмень جھیل آئیمین 伊爾門湖 0Lake Poyang Hu 4.0 5.0Poyang Hu Poyang Hu Q207690 بحيرة بويانغ পোয়াং হু Poyang Poyang Poyang Poyang Πουανγκ Χου पोयांग झील Poyang Hu Poyang Poyang 鄱陽湖 포양호 Poyangmeer Poyang Hu Poyang Поянху Poyangsjön Poyang Bà Dương 鄱阳湖 1159114015دریاچه پویانگ אגם פויאנג Поянху پویانگ ہو 鄱陽湖 0Lake Daguan Hu 4.0 5.0Daguan Hu Daguan Hu Q10934898 بحيرة داغوان দাগুয়ান হু Daguan Hu Daguan Lake Daguan Hu Daguan Lake Νταγκουάν Χου डगुआन हु Daguan Hu Danau Daguan Daguan Hu 大官湖 다관 후 Daguan Lake Jezioro Daguan Lago Daguan озеро Дагуан Daguan Hu Daguan Hu Hồ Đại Quan 大官湖 1159114031داگوآن هو דגואן Дагуан Ху ڈیگوان ہو 大官湖 0Lake Long Hu 4.0 5.0Long Hu Long Hu Q6673852 بحيرة لونج লং হু Longhu Longgan Longgan Longhu Λονγκ Χου लॉन्ग हू Long Hu Long Hu Long Hu 龍湖 롱 후 Longhu Lake Jezioro Long Lago Long озеро Лунху Longgan Hu Long Hu Long Hồ 龙感湖 1159114049لونگ هو אגם לונג Лонгху لانگ ہو 龙感湖 0Lake Liangzi Hu 4.0 5.0Liangzi Hu Liangzi Hu Q7374197 بحيرة ليانغزي লিয়াংজি হু Liangzi-See Liangzi Liangzi Hu Lac Liangzi Λιανγκζί Χου लिआंगज़ी हु Liangzi Hu Liangzi Liangzi Hu 梁子湖 량지 후 Liangzi Lake Jezioro Liangzi Lago Liangzi озеро Лянцзыху Liangzi Hu Liangzi Hu Hồ Lương Tử 梁子湖 1159114069لیانگزی هو אגם ליאנגזי Ліангці لیانگزی ہو 梁子湖 0Lake Siling Co 4.0 5.0Siling Co Siling Co Q1404973 بحيرة سيلنج সাইলিং কো Serling Tsho Siling Siling Siling Σίλινγκ Κο सिलिंग को Siling Co Siling Co Siling Co 色林錯 실링 코 Serling Tso Jezioro Siling Siling Силинг-Цо Siling Co Siling Co Siling 色林错 1159114083سیلینگ کو אגם סילינג Сілінгко سائلنگ کو 色林错 0Lake Har Us Nuur 4.0 5.0Har Us Nuur Har Us Nuur Q1323267 بحيرة خار-أس হার উস নুর Khar-Us-Nuur Khar-Us Khar-Us Khar-Us Χαρ Ους Νουρ हर उस नूर Har-Usz-tó Har Us Nuur Har-Us nuur ハル・ウス・ヌール 하 우스 누르 Khar-Us Char Us nuur Khar-Us Хар-Ус-Нуур Har Us Nuur Khar-Us Khar-Us 哈尔乌苏湖 1159114107هار آس نور האר אוס Хара-Ус-Нур ہار اس نور 哈爾烏蘇湖 0Lake Lake Taupo 4.0 5.0L. Taupo Lake Taupo Q199903 بحيرة تابو লেক তাউপো Taupo Taupo Taupo Taupo Λίμνη Τάουπο ताऊपो झील Taupói-tó Taupo Taupo タウポ湖 타우포호 Taupomeer Taupo Taupo Таупо Tauposjön Taupo Taupo 陶波湖 1159127099دریاچه تاپو אגם טאופו Таупо جھیل ٹاپو 陶波湖 0Lake Lake Geneva Lac Léman 4.0 5.0L. Geneva Lake Geneva Q6403 بحيرة ليمان লেক জেনেভা Genfersee Geneva Lemán Léman Λίμνη της Γενεύης जेनेवा झील Genfi-tó Jenewa Lemano レマン湖 레만호 Meer van Genève Jezioro Genewskie Léman Женевское озеро Genèvesjön Cenevre Genève 萊芒湖 1159114143دریاچه لمان אגם ז'נבה Женевське озеро جھیل جینیوا 萊芒湖 0Lake Lough Neagh 4.0 5.0Lough Neagh Lough Neagh Q206942 بحيرة لوك ناي লাফ নেইহ Neagh Neagh Neagh Neagh Λοχ Νέι लफ नेघ Lough Neagh Neagh Neagh ネイ湖 러프 네이그 Neagh Neagh Neagh Лох-Ней Neagh Neagh Hồ Lough Neagh 内湖 1159114155لخ نی לוך ניי Лох-Ней لف نیاگھ 內湖 0Lake Vättern 4.0 5.0Vättern Vättern Q188195 بحيرة فترن ভ্যাটার্ন Vättern Vättern Vättern Vättern Βέτερν वैटर्न Vättern-tó Vättern Vättern ヴェッテルン湖 베테른호 Vättermeer Wetter Vättern Веттерн Vättern Vättern Hồ Vättern 韦特恩湖 1159114173دریاچه وترن אגם וטרן Веттерн ویٹرن 韋特恩湖 0Alkaline Lake Lake Van 4.0 5.0L. Van Lake Van Q126307 بحيرة وان লেক ভ্যান Vansee Van Van Van Βαν वान झील Van-tó Van Van ヴァン湖 반호 Vanmeer Wan Van Ван Vansjön Van Van 凡湖 1159126829دریاچه وان ימת ואן Ван جھیل وان 凡湖 0Lake Yellowstone Lake 4.0 5.0Yellowstone L. Yellowstone Lake Q923693 بحيرة يلوستون ইয়েলোস্টোন লেক Yellowstone Yellowstone Yellowstone Yellowstone Λίμνη Γιέλοουστόουν येलोस्टोन झील Yellowstone-tó Danau Yellowstone Yellowstone イエローストーン湖 옐로스톤호 Yellowstonemeer Yellowstone Yellowstone Йеллоустон Yellowstonesjön Yellowstone Gölü Hồ Yellowstone 黃石湖 1159107195دریاچه یلو استون אגם ילוסטון озеро Єллоустоун ییلو اسٹون جھیل 黃石湖 0Lake Teshekpuk Lake 4.0 5.0Teshekpuk L. Teshekpuk Lake Q3518981 بحيرة تيشيكبوك টেশেকপুক লেক Teshekpuk Lake Teshekpuk Lago Teshekpuk Teshekpuk Λίμνη Τεσεκπουκ तेशेकपुक झील Teshekpuk-tó Danau Teshekpuk Teshekpuk Lake テシェクプク湖 테섹퍽 레이크 Teshekpuk Lake Teshekpuk Lake Lago Teshekpuk Тешекпук Teshekpuk Lake Teshekpuk Gölü Hồ Teshekpuk 特什普克湖 1159107207دریاچه تشک پوک אגם טשקפוק Тешекпук تیشیکپک جھیل 特榭普克湖 0Lake Flathead Lake 4.0 5.0Flathead L. Flathead Lake Q1427364 بحيرة فلاتهيد ফ্ল্যাটহেড লেক Flathead Flathead Flathead Flathead Λίμνη Φλάτχεντ फ़्लैटहेड लेक Flathead-tó Flathead Flathead フラットヘッド湖 플랫헤드호 Flathead Flathead Lago Flathead Флатхед Flathead Flathead Flathead 弗拉特黑德湖 1159107217دریاچه فلت هد אגם פלאטהד озеро Флетхед فلیٹ ہیڈ جھیل 弗拉特黑德湖 0Reservoir Lake Mead 4.0 5.0L. Mead Lake Mead Q654515 بحيرة ميد লেক মীড Mead Mead Mead Mead Λίμνη Μιντ मीड झील Mead-tó Mead Mead ミード湖 미드호 Mead Mead Mead Мид Mead Mead Gölü Hồ Mead 米德湖 1159123963دریاچه مید אגם מיד Мід جھیل میڈ 米德湖 0Lake Lake Claire 4.0 5.0L. Clare Lake Claire Q1534419 بحيرة كلير লেক ক্লেয়ার Claire Claire Claire Claire Λίμνη Κλερ क्लेयर झील Claire-tó Danau Claire Claire クレア湖 레이크 클레어 Clairemeer Jezioro Claire Claire Клэр Claire Claire Gölü Hồ Claire 克萊爾湖 1159107229دریاچه کلر אגם קלייר озеро Клер جھیل کلیئر 克萊爾湖 0Reservoir Smallwood Reservoir 4.0 5.0Smallwood Res. Smallwood Reservoir Q1539726 خزان سمول وود স্মলউড জলাধার Smallwood Smallwood Smallwood Smallwood Τεχνητή Λίμνη Σμολγουντ स्मॉलवुड जलाशय Smallwood-víztározó Reservoir Smallwood Smallwood スモールウッド貯水池 스몰우드 레저보어 Smallwood Zbiornik Smallwood Albufeira de Smallwood Смолвуд Smallwoodreservoaren Smallwood Rezervuarı Hồ Smallwood 斯莫尔伍德水库 1159123999مخزن سد اسمالوود מאגר סמולווד Смолвуд سمال ووڈ ریزروائر 斯莫爾伍德水庫 0Lake Lake Taymyr 4.0 5.0L. Taymyr Lake Taymyr Q845868 بحيرة تايمير লেক তেমির Taimyrsee Taymyr Taimir Taïmyr Λίμνη Ταϊμίρ तैमिर झील Taymyr-tó Danau Taymyr Tajmyr タイミル湖 레이크 타이미르 Tajmyrmeer Tajmyr Taimir Таймыр Tajmyrsjön Taymyr Gölü Taymyr 泰梅尔湖 1159114189دریاچه تایمیر ימת טיימיר Таймир جھیل ٹانیمیر 泰梅爾湖 0Lake Lago de Izabal 4.7 6.0L. de Izabal Lago de Izabal Q138637 بحيرة إيزابال লাগো দে ইজাবেল Izabal Izabal Izabal Izabal Λάγκο ντε Ιζαμπάλ लागो द इज़ाबेल Izabal-tó Izabal Lago de Izabal イサバル湖 이사발호 Izabalmeer Izabal Izabal Исабаль Departamento de Izabal Lago de Izabal Izabal 伊薩瓦爾湖 1159107241لاگو د ایزابل אגם איסבל Ісабаль لاگو ڈی آئزابال 伊薩瓦爾湖 0Lake Ozero Mogotoyevo L. Mogotoyevo 4.7 6.0O. Mogotoyevo Ozero Mogotoyevo Q2639916 بحيرة موجوتوييفو ওজেরো মোগোতোয়েভো Ozero Mogotoyevo Mogotoyevo Lago Mogotoyevo Ozero Mogotoyevo Οζέρο Μόγκοτογιεβο ओज़ेरो मोगोटोयेवो Mogotojevo-tó Danau Mogotoyevo Mogotoevo モゴトエヴォ湖 오제로 모고토예보 Mogotoyevo Jezioro Mogotoyevo Lago Mogotoyevo Моготоево Ozero Mogotojevo Ozero Mogotoyevo Hồ Mogotoyevo 莫戈托耶沃湖 1159114197اوزرو موگوتویوو אגם מוגוטויבו Моготоєво اوزیرو موگوٹوییو 莫戈托耶沃湖 0Lake Ayakkum Hu 4.7 6.0Ayakkum Hu Ayakkum Hu Q631714 بحيرة أياكوم আয়াক্কুম হু Ayakkum Hu Ayakum Ayakum Lake Ayakum Αιακούμ Χου अयाक्कुम हु Ayakkum-tó Danau Ayakkum Ayakum アヤクム湖 아야쿰 후 Lake Ayakum Jezioro Ayakkum Lago Ayakum Аяккумкёль Ayakkum Hu Ayakum Gölü Ayakum 阿雅克库木湖 1159114215آیاکوم هو אגם איאקום Аякум آیاکم ہو 阿雅克庫木湖 0Lake Storsjön 4.7 6.0Storsjön Storsjön Q629354 ستورسهون স্টর্জন Storsjön Storsjön Storsjön Storsjön Στορσγιόν स्टोर्सजोन Storsjön Storsjön Storsjön ストゥール湖 스토르스욘 Storsjön Stor Storsjön Стуршён Storsjön Storsjön Hồ Storsjön 斯圖爾湖 1159114237استورسیون אגם סטורסיון Стуршен اسٹورسجون 斯圖爾湖 0Lake Lake St. Joseph 4.7 6.0L. St. Joseph Lake St. Joseph Q659225 بحيرة سان جوزيف লেক সেন্ট জোসেফ St. Joseph St. Joseph Lago St. Joseph Saint-Joseph Λίμνη του Αγίου Ιωσήφ सेंट जोज़फ झील Szent József-tó Danau St. Joseph Lake St. Joseph セントジョセフ湖 레이크 세인트 조셉 St. Joseph Lake Saint Joseph Lago St. Joseph Сент-Джозеф St. Joseph St. Joseph Gölü Hồ St. Joseph 聖約瑟夫湖 1159107297دریاچه سنت جوزف אגם סנט ג'וזף Св. Джозеф جھیل سینٹ جوزف 聖約瑟夫湖 0Lake Lake Rukwa 4.7 6.0L. Rukwa Lake Rukwa Q1143935 بحيرة روكوا লেক রুকোয়া Rukwasee Rukwa Rukwa Rukwa Λίμνη Ρούκουα रुक्वा झील Rukwa-tó Rukwa Rukwa ルクワ湖 레이크 루크와 Rukwa Rukwa Rukwa Руква Rukwa Rukwa Gölü Hồ Rukwa 鲁夸湖 1159114299دریاچه روکوا אגם רוקאה Руква جھیل رکوا 魯誇湖 0Reservoir Nam Ngum Reservoir 4.7 6.0Nam Ngum Res. Nam Ngum Reservoir Q6132621 خزان نام نجوم নাম এঙ্গুম রিজার্ভার Nam-Ngum-Talsperre Nam Ngum Dam Presa Nam Ngum Barrage Nam Ngum Τεχνητή Λίμνη Ναμ Νγκουμ नम नगम जलाशय Nam Ngum-víztározó Bendungan Nam Ngum diga di Nam Ngum ナムグムダム 남응음 댐 dam von Ang Nam Ngum Zbiornik Nam Ngum Represa de Nam Ngum водохранилище Нэм-Нгам Nam Ngum Dam Nam Ngum Rezervuarı Thủy điện Nam Ngum 塔什幹日本滯留者墓地 1159125069سد نام ناگم נאמאקזאר-אה שאדאד ГЕС Нам-Нгум 1 نام نگم ریزروائر 塔什幹日本滯留者墓地 0Reservoir Réservoir Gouin 4.7 6.0Rs. Gouin Réservoir Gouin Q1540136 خزان جوان গুইন জলাধার Gouin-Stausee Gouin Gouin Gouin Ρεζερβουάρ Γκουίν रिज़र्वोयर गौउइन Gouin-víztározó Reservoir Gouin Gouin レゼヴォワール・グアン 레저보어 구앵 Gouin Zbiornik Gouin Represa de Gouin водохранилище Резервуар-Гуен Gouin Réservoir Gouin Hồ Gouin 古安水庫 1159124077مخزن سد گوئین מאגר גואין водосховище Гуїна ریزروائر گوئین 古安水庫 0Lake Gaoyou Hu 4.7 6.0Gaoyou Hu Gaoyou Hu Q630331 بحيرة جاويو গাওইউ হু Gaoyou Hu Gaoyou Gaoyou Gaoyou Lake Γκαογού Χου गाओउ हु Gaoyou Hu Danau Gaoyou Gaoyou Hu 高郵湖 가오유 후 Gaoyou Lake Gaoyou Hu Lago Gaoyou Гаоюху Gaoyou Hu Gaoyou Hu Hồ Cao Bưu 高邮湖 1159114321گائویو هو גאיו озеро Гаою گاؤیو ہو 高郵湖 0Lake Ozero Pyasino L. Pyasino 4.7 6.0O. Pyasino Ozero Pyasino Q1535541 بحيرة بياسينو ওজেরো পিয়াসিনো Pjassinosee Pyasino Piasino Piassino Οζέρο Πιασίνο ओज़ेरो पायसिनो Pjaszino-tó Danau Pyasino Pjasino ピャシノ湖 오제로 피아시노 Pjasinomeer Piasino Lago Pyasino Пясино Ozero Piasino Ozero Pyasino Hồ Pyasino 皮亚西诺湖 1159114343اوزرو پیاسینو אגם פיאסינו озеро Пясино اوزیرو پیاسینو 皮亞西諾湖 0Lake _untitled_25 4.7 6.0 1159114377 0Lake Hjälmaren 4.7 6.0Hjälmaren Hjälmaren Q211425 هجالمارين হজল্মারেন Hjälmaren Hjälmaren Hjälmaren Hjälmaren Χγιελμαρέν हल्मारेने Hjälmaren Hjälmaren Hjälmaren イェルマレン湖 옐마렌호 Hjälmarmeer Hjälmar Hjälmaren Ельмарен Hjälmaren Hjälmaren Hồ Hjälmaren 耶尔马伦湖 1159114391هیلمارن ילמארן Єльмарен جالمارین 耶爾馬倫湖 0Lake _untitled_22 4.7 6.0 1159114495 0Lake Lake Bienville 4.7 6.0L. Bienville Lake Bienville Q1496993 بحيرة بينفيل লেক বিয়েনভিল Bienville Bienville Bienville Bienville Λίμνη Μπιενβιγ बीनविल झील Bienville-tó Danau Bienville Lake Bienville ビエンビル湖 레이크 비엔빌 Bienville Lake Bienville Lago Bienville Бьенвиль Bienville Bienville Gölü Hồ Bienville 比安維爾湖 1159107323دریاچه بینویل אגם בינוויל озеро Б'єнвіль جھیل بائینولے 比安維爾湖 0Lake Lake Beloye 4.7 6.0L. Beloye Lake Beloye Q953140 بحيرة بيلوي লেক বেলোয়ে Weißer Beloe Béloye Beloïe Λίμνη Μπελόε बेलोये झील Beloye-tó Danau Beloye Bianco ベロエ湖 레이크 벨로예 Belojemeer Jezioro Białe Lago Beloye Белое озеро Beloje ozero Beyaz Göl Hồ Beloye 白湖 1159114573دریاچه بلویه אגם בלויה Біле озеро جھیل بیل اوئے 白湖 0Reservoir Van Blommestein Meer Professor Doctor Ingenieur W. J. Van Blommestein Meer 4.7 6.0Van Blommestein Meer Brokopondo Res. Q926100 خزان بروكوبوندو প্রফেসর ডক্টর ইঙ্গেনিউর ডব্লু. জে. ব্লমমেস্টিন মীর Brokopondo-Stausee Brokopondo Brokopondo Brokopondo Λίμνη του Καθηγητής Διδάκτορα Μηχανικού Β. Γ. βαν Μπλόμεσταϊν प्रोफेसर डॉक्टर इनजीनियर डब्ल्यू जे वैन ब्लोमस्टीन मीर Professor Doctor Ingenieur W. J. Van Blommestein Meer Professor Doctor Ingenieur W. J. Van Blommestein Meer Brokopondo ブロコポンド貯水池 프로페서 닥터 인제니어 W. J. 반 블로메스테인 미어 Brokopondostuwmeer Zbiornik Brokopondo Albufeira de Brokopondo Брокопондо Professor Doctor Ingenieur W. J. Van Blommestein Meer Professor Doctor Ingenieur W. J. Van Blommestein Meer Hồ Professor Doctor Ingenieur W. J. Van Blommestein Meer 布羅科蓬多水庫 1159125121مخزن سد پرفسور دکتر اینگنیر دابلیو جی ون بلومستین میرפרופסור דוקטור מהנדס דאבליו ג'יי בלומסטיין מירБрокопондо پروفیسر ڈاکٹر انجینیئر W. J. وین بلومسٹائن میر布羅科蓬多水庫 0Lake Lake Manyara 4.7 6.0L. Manyara Lake Manyara Q577148 بحيرة مانيارا লেক মান্যারা Manyara Manyara Manyara Manyara Λίμνη Μανιάρα मान्यारा झील Manyara-tó Danau Manyara Manyara マニャラ湖 레이크 만야라 Manyara Jezioro Manyara Lago Manyara Маньяра Manyarasjön Manyara Gölü Hồ Manyara 马尼亚拉湖 1159114585دریاچه مانیارا אגם מניארה Маньяра جھیل مانیارا 馬尼亞拉湖 0Alkaline Lake Lake Äbaya Lake Abaya 4.7 6.0L. Abaya Lake Abaya Q304933 بحيرة أبايا লেক আবায়া Abajasee Abaya Abaya Abaya Αμπάγια अबाया झील Abaya-tó Abaya Margherita アバヤ湖 레이크 아바야 Abayameer Jezioro Małgorzaty Abaya Абая Ābaya Hāyk' Abaya Gölü Hồ Abaya 阿拜亞湖 1159126845دریاچه آبایا אגם אבאיה Абая جھیل ابایا 阿拜亞湖 0Lake Akkajaure 4.7 6.0Akkajaure Akkajaure Q419614 أكاجور আক্কাজাউরে Akkajaure Akkajaure Akkajaure Akkajaure Ακαγάουρε अक्काजाउरे Akkajaure Akkajaure Akkajaure アッカ湖 아카자우레 Akkajaure Akkajaure Akkajaure Аккаяуре Akkajaure Akkajaure Hồ Akkajaure 阿卡湖 1159123397آکاجائوره אקאג'אור Аккаяуре اکاجورے 阿卡湖 0Lake Lake Balaton 4.7 6.0L. Balaton Lake Balaton Q6383 بالاتون লেক বালাতোন Balaton Balaton Balaton Balaton Μπάλατον बालाटोन झील Balaton Balaton Balaton バラトン湖 벌러톤호 Balatonmeer Balaton Balaton Балатон Balaton Balaton Balaton 巴拉顿湖 1159114609دریاچه بالاتون אגם בלטון Балатон جھیل بالاٹون 巴拉顿湖 5Lake Canandaigua Lake Finger Lakes 4.7 6.0 Canandaigua Lake Q1032768 بحيرة كانانديغوا ক্যানাডাইগুয়া লেক Canandaigua Canandaigua Lago Canandaigua Canandaigua Λίμνη Κανανταϊγκουα कैननडाईगुआ झील Canandaigua-tó Danau Canandaigua Canandaigua カナデーグア湖 캐난다이과 레이크 Canandaigua Canandaigua Lago Canandaigua озеро Канандейгуа Canandaigua Lake Canandaigua Gölü Hồ Canandaigua 加拿戴奎湖 1159107347دریاچه کاناندیگوآ אגם קננדאיגואה Канандайгуа کیننڈیگا جھیل 加拿戴奎湖 5Lake Owasco Lake Finger Lakes 4.7 6.0 Owasco Lake Q1339170 بحيرة أواسكو ওয়াস্কো লেক Owasco Owasco Lago Owasco Owasco Λίμνη Οβάσκο ओवास्को झील Owasco-tó Danau Owasco Owasco オワスコ湖 오와스코 레이크 Owasco Owasco Lago Owasco озеро Оваско Owasco Lake Owasco Gölü Hồ Owasco 奥瓦斯科湖 1159107357دریاچه اواسکو אגם אוסקו озеро Оваско اواسکو جھیل 奧瓦斯科湖 5Lake Skaneateles Lake Finger Lakes 4.7 6.0 Skaneateles Lake Q1333432 بحيرة سكانيتيليس স্কানেটেলেস লেক Skaneateles Skaneateles Lago Skaneateles Skaneateles Λίμνη Σκανεάτελες स्केनेटेल्स झील Skaneateles-part Danau Skaneateles Skaneateles スカネアトレス湖 스캐니텔레스 레이크 Skaneateles Skaneateles Lago Skaneateles озеро Сканителс Skaneateles Lake Skaneateles Gölü Hồ Skaneateles 斯卡尼阿特勒斯湖 1159107371دریاچه اسکانیتلس אגם סקאניטלס озеро Сканетелес ایکانیٹایلیس جھیل 斯卡尼阿特勒斯湖 0Lake _untitled_19 4.7 6.0 1159107379 0Lake Bear Lake 4.7 6.0Bear L. Bear Lake Q812997 بحيرة بير বেয়ার লেক Bear Bear Oso Bear Λίμνη Μπερ बेयर झील Bear-tó Danau Bear Lago dell'Orso ベアー湖 베어호 Bear Jezioro Niedźwiedzie Lago Bear Бэр Bear Lake Bear Lake Hồ Bear 熊湖 1159107393دریاچه بیر אגם בר Медвеже озеро بیئر جھیل 熊湖 0Lake Utah Lake 4.7 6.0Utah L. Utah Lake Q729974 بحيرة يوتا উটাহ লেক Utahsee Utah Utah Utah Λίμνη Γιούτα यूटा झील Utah Lake Utah Utah ユタ湖 유타 레이크 Utah Utah Utah Юта Utahsjön Utah Gölü Hồ Utah 犹他湖 1159107397دریاچه اوتاه אגם יוטה Юта اوتاہ لیک 犹他湖 0Lake _untitled_18 4.7 6.0 1159107413 0Lake Leech Lake 4.7 6.0Leech L. Leech Lake Q1812063 بحيرة ليتش، والكر লীচ লেক Leech Leech Leech Leech Λίμνη Λιτς लीच झील Leech-tó Danau Leech Leech リーチ湖 리치 레이크 Leechmeer Leech Lake Lago Leech Лич-Лейк Leech Leech Gölü Hồ Leech 利奇湖 1159107427دریاچه لیچ אגם כרישה озеро Ліч لیچ جھیل 利赤湖 0Lake Lac des Mille Lacs 4.7 6.0L. des Mille Lacs Lac des Mille Lacs Q3215670 بحيرة ميل لاك ল্যাক দেস মিলে ল্যাক্স Mille Lacs Mille Lacs Lago des Mille Lagos Mille Lacs Λακ ντε Μίλ Λακ लैक देस मील लैक Lac des Mille Lacs Lac des Mille Lacs Lac des Mille Lacs デミルラック湖 락 데 밀 락스 Mille Lacs Jeziora Lac des Mille Lac des Mille Lacs озеро Лак-де-Мил-Лакс Mille Lacs Lac des Mille Lacs Hồ Lac des Mille Lacs 米尔湖 1159107441دریاچه د مایل لکس אגם דה מיל Міл-Лакс لاک ڈیس ملے لاکس 密爾湖 0Reservoir Réservoir Baskatong 4.7 6.0Rs. Baskatong Réservoir Baskatong Q1329423 خزان باسكاتونج বাস্কাতং জলাধার Baskatong Baskatong Presa Baskatong Baskatong Ρεζερβουάρ Μπασκατόνγκ रिज़र्वोयर बास्काटोंग Baskatong-víztározó Reservoir Baskatong Réservoir Baskatong レゼルヴォワール・バスカトング 레저보어 바스카통 Baskatong Reservoir Zbiornik Baskatong Represa de Baskatong Баскатонг Baskatong Réservoir Baskatong Hồ Baskatong 巴斯卡通水库 1159124119مخزن سد باسکاتونگ מאגר בסקטונג водосховище Баскатонг ریزروائر باسکاٹونگ 巴斯卡通水庫 0Lake Lago Ranco 4.7 6.0L. Ranco Lago Ranco Q1800398 بحيرة رانكو লাগো র‍্যাঙ্কো Ranco Ranco Ranco Ranco Λάγκο Ράνκο लागो रैंको Ranco-tó Danau Ranco Ranco ランコ湖 라고 랑코 Ranco Ranco Ranco Ранко Ranco Lago Ranco Hồ Ranco 蘭科湖 1159114631لاگو رانکو אגם ראנקו Ранко لاگو رینکو 蘭科湖 0Lake Trout Lake 4.7 6.0Trout L. Trout Lake Q1638242 بحيرة تراوت ট্রাউট লেক Trout Trout Lago Trout Lac Trout Λίμνη Τράουτ ट्राउट झील Trout-tó Danau Trout Trout Lake トラウト湖 트라우트 레이크 Trout Lake Trout Lake Lago Trout озеро Траут Trout Lake Trout Gölü Hồ Trout 特勞特湖 1159107451دریاچه تروت אגם פורל Троут ٹراؤٹ جھیل 特勞特湖 0Lake Lago Viedma 4.7 6.0L. Viedma Lago Viedma Q918713 بحيرة فيدما লাগো ভিয়েদমা Viedma Viedma Viedma Viedma Βιέδμα लागो विदमा Viedma-tó Danau Viedma Viedma ビエドマ湖 비에드마호 Viedmameer Viedma Lago Viedma Вьедма Viedma Viedma Hồ Viedma 别德马湖 1159114641دریاچه ویدما אגם ויידמה В'єдма لاگو ویڈما 別德馬湖 0Lake Lac Tumba 4.7 6.0L. Tumba Lac Tumba Q1324212 بحيرة تومبا ল্যাক তুম্বা Tumbasee Tumba Tumba Tumba Λακ Τούμπα लैक तुम्बा Lac Tumba Tumba Tumba トゥンバ湖 툼바호 Tumbameer Tumba Lago Tumba Тумба Mantumba Lac Tumba Hồ Tumba 通巴湖 1159114657دریاچه تومبا אגם טומבה Тумба لاک ٹومبا 通巴湖 0Lake _untitled_17 4.7 6.0 1159114683 0Lake Po Hu 4.7 6.0Po Hu Po Hu Q11143308 بحيرة بو পো হু Pohu Lake Po Po Hu Pohu Πο Χου पो हु Po Hu Po Hu Po Hu 泊湖 포 후 Pohu Lake Jezioro Po Lago Po озеро Боху Po Hu Po Hu Bạc Hồ 泊湖 1159114699پو هو אגם פה По ху پو ہو 泊湖 0Lake Buyr Nuur Buir Nur 4.7 6.0Buyr Nuur Buyr Nuur Q715788 بحيرة بوار বুয়ার নূর Buir Nur Buir Buir Buir Μπουρ Νουρ बुय्र नूर Bujr-tó Buir Bujr nuur ブイル湖 부이르호 Buir Bujr nuur Lago Buir Буйр-Нуур Buyr Nuur Buyr Buir 贝尔湖 1159114715بویر نور בויר Буйр-Нуур بائر نور 貝爾湖 0Lake Ngangla Ringeo 4.7 6.0Ngangla Ringeo Ngangla Ringeo Q4761833 نغانجلا رينجيو এঙ্গাংলা রিনেগিও Ngangla Ringeo Ang Laren Ngangla Ringeo Ngangla Ringeo Νγκάνγκλα Κάνγκρι एनगांग्ला रिंगियो Ngangla Ringeo Ngangla Ringeo Ngangla Ringeo ンガンラ・リンゲオ 응강라 링게오 Ngangla Ringeo Ngangla Ringeo Ngangla Ringeo озеро Нгангле-Ринцо Ngangla Ringco Ngangla Ringeo Hồ Ngangla Ringeo 昂拉仁错 1159114735نگانگلا رینگئو אגם ננגלה רינגו Нгангла Рінгео انگانگلا رنگیو 昂拉仁错 0Lake Tangra Yumco 4.7 6.0Tangra Yumco Tangra Yumco Q659377 تانجرا يومكو ট্যাংরা ইয়ামকো Tangra Yumco Tangra Yumco Tangra Yumco Tangra Yumco Τάνγκρα Γιούμκο तंगरा युमको Tangra Yumco Tangra Yumco Tangra Yumco タンラ・ユムツォ 탕그라 윰코 Tangra Yumco Tangra Yumco Tangra Yumco Данграюм Tangra Yumco Tangra Yumco Hồ Tangra Yumco 当惹雍错 1159114759تانگرا یومکو אגם טאנגרה יומקו Тангра Юмко تانگرا یمکو 当惹雍错 0Lake Ozero Kulundinskoye L. Kulundinskoye 4.7 6.0O. Kulundinskoye Ozero Kulundinskoye Q731761 بحيرة كولوندينسكوي ওজেরো কুলুন্দিনস্কোয়ে Kulundasee Kulundinskoe Kulunda Koulounda Οζέρο Κουλουντίνσκογιε ओज़ेरो कुलुंडिनस्कॉय Kulunda-tó Danau Kulundinskoye Kulunda クルンジスコエ湖 오제로 쿨룬딘스코예 Koeloendameer Jezioro Kułundyńskie Lago Kulundinskoye Кулундинское озеро Ozero Kulundinskoje Kulundin Hồ Kulundinskoye 庫倫達湖 1159114777اوزرو کولوندینسکویه אגם קולונדינסקויה Кулундинське озеро اوزیرو کولونڈنسکوئے 庫倫達湖 0Lake Siletitengiz Köli 4.7 6.0Siletitengiz Kli Siletitengiz Kli Q4244492 سايلتينتيتنغز كلي সাইলেটিটেনিজ ক্লি Siletitengiz Köli Siletiteniz Lago Seletyteniz Siletitengiz Koli Σιλετιτενγκίζ Κλι सिलेटिटेंगिज़ क्ली Siletitengiz Kli Siletitengiz Kli Siletitengiz Kli セレティテニス湖 실레티텐기즈 클리 Seletyteniz Siletitengiz Kli Lago Seletyteniz Селетытениз Siletitengiz Köli Siletiteniz Hồ Siletitengiz Kli 谢列特田吉兹湖 1159114787سیلتیتنگیز کلی אגם סילטיטנגיז Сілетітеніз سیلےٹیٹینگز کلی 谢列特田吉兹湖 0Lake Ubinskoye Lake 4.7 6.0Ubinskoye L. Ubinskoye Lake Q1115650 بحيرة أوبينسكوي উবিনস্কয় লেক Lake Ubinskoye Ubinskoye Ubinskoe Lac Ubinskoye Λίμνη Ουμπίνσκογιε उबिंस्कॉय झील Ubinszkoje-tó Danau Ubinskoye Ubinskoye Lake ウビンスコエ湖 우빈스코예 레이크 Oebinskoe Jezioro Ubinskoje Lago Ubinskoye Убинское Ubinskoje Ubinskoye Gölü Hồ Ubinskoye 乌宾斯科耶湖 1159114805دریاچه اوبینسکویه אגם אובינסקויה Убінське اوبنسکوئی جھیل 烏賓斯科耶湖 0Lake _untitled_16 4.7 6.0 1159114823 0Lake _untitled_15 4.7 6.0 1159114841 0Lake Umbozero Lake _untitled_14 4.7 6.0Umbozero L. Umbozero Lake Q1460079 بحيرة أمبوزيرو উম্বোজেরো লেক Umbosero Umbozero Umbozero Oumbozero Λίμνη Ουμποζέρο अम्बोजेरो झील Umbozero-tó Danau Umbozero Lago Umbozero ウムボゼロ湖 움보제로 레이크 Oembozero Umboziero Lago Umbozero Умбозеро Umbozero Umbozero Gölü Hồ Umbozero 温博泽罗湖 1159123333دریاچه اومبوزیرو אגם אומבוצרו озеро Умбозеро امبوزیرو جھیل 溫博澤羅湖 0Lake Lake Kovdozero 4.7 6.0L. Kovdozero Lake Kovdozero Q240398 بحيرة كوفدوزيرو লেক কোভদোজেরো Kowdosero Kovdozero Kovdozero Kovdozero Λίμνη Κοβντοζέρο कोवडोज़ेरो झील Kovdozero-tó Danau Kovdozero Kovdozero コフトゼロ湖 레이크 코브도제로 Kovdozero Jezioro Kovdozero Lago Kovdozero Ковдозеро Kovdozero Kovdozero Gölü Hồ Kovdozero 科夫多澤羅湖 1159123191دریاچه کوودوزرو אגם קובדוזרו озеро Ковдозеро جھیل کوڈوریزو 科夫多澤羅湖 0Lake Lake Tekapo 4.7 6.0L. Tekapo Lake Tekapo Q1194022 بحيرة تيكابو লেক তেকাপো Tekapo Tekapo Tékapo Tekapo Λίμνη Τεκάπο टेकापो झील Tekapo-tó Tekapo Tekapo テカポ湖 테카포 호수 Tekapo Tekapo Lago Tekapo Текапо Tekapo Tekapo Gölü Tekapo 特卡波湖 1159127119دریاچه تکاپو אגם טקאפו Текапо جھیل ٹیکاپو 特卡波湖 0Lake Ozero Bustakh L. Bustakh 4.7 6.0O. Bustakh Ozero Bustakh Q2996806 بحيرة بوستاخ ওজেরো বুস্তাখ Ozero Bustakh Bustakh Lago Bustakh Ozero Bustakh Οζέρο Μπουστάχ ओज़ेरो बुस्टाख Bustak-tó Danau Bustakh Bustach ブスタフ湖 오제로 부스타크 Ozero Bustakh Jezioro Bustakh Lago Bustakh Бустах Ozero Bustach Ozero Bustakh Hồ Bustakh 布斯塔赫湖 1159114859اوزرو بوستاک אגם בוסטח Бустах اوزیرو بستاخ 布斯塔赫湖 0Lake Yamzho Yumco 4.7 6.0Yamzho Yumco Yamzho Yumco Q939604 بحيرة يامدروك ইয়ামড্রক হ্রদ Yamzhog Yumco Yamdrok Yamdrok Yamdrok-Tso Γιάμζο Γιο΄ύμκο यमद्रोक झील Jamdok-tó Yamdrok Yamzho Yumco ヤムドク湖 암드록쵸 호수 Yamdrok Yamzho Yumco Lago Yamdrok Ямджо-Юмцо Yamzho Yumco Yamdrok Yamdrok 羊卓雍错 1159114885یامژو یومکو אגם יאמזו יומקו Ямжжо-Юмцо یامزو یمکو 羊卓雍錯 0Lake Ozero Tenis L. Tenis 4.7 6.0O. Tenis Ozero Tenis -1 بحيرة تينيس ওজেরো তেনিস Ozero Tenis Ozero Tenis Lago Tenis Ozero Tenis Οζέρο Τένις ओज़ेरो टेनिस Tenis-tó Danau Tenis Ozero Tenis テニス湖 오제로 테니스 Ozero Tenis Jezioro Tenis Lago Tenis озеро Тенис Ozero Tenis Ozero Tenis Hồ Tenis 捷尼斯湖 1159114903اوزرو تنیس אגם טניס озеро Теніс اوزیرو ٹینس 帝尼斯湖 0Lake Ozero Chërnoye L. Chërnoye 4.7 6.0O. Chërnoye Ozero Chërnoye -1 بحيرة تشيرنوي ওজেরো চেরনোয়ে Ozero Chërnoye Ozero Chernoye Lago Chërnoye Ozero Chërnoye Οζέρο Τσερνόιε ओज़ेरो चेर्नॉय Csërnoje-tó Danau Chërnoye Ozero Chërnoye チェルノエ湖 오제로 체르노예 Ozero Chërnoye Jezioro Chërnoye Lago Chërnoye озеро Черное Ozero Tjernoje Ozero Chërnoye Hồ Chërnoye 切尔诺耶湖 1159114929اوزرو چرنویه אגם צ'רנויה озеро Чорне اوزیرو چرنوئے 車諾耶湖 0Lake _untitled_12 4.7 6.0 1159114951 0Lake Ozero Bol'šoe Morskoe L. Bol’shoye Morskoye 4.7 6.0O. Bolshoye Morskoye Ozero Bol'šoe Morskoe Q1774474 بحيرة بولزو مورسكو ওজেরো বলশয় মোরস্কেয়ে Ozero Bol'šoe Morskoe Bolshoe Morskoe Lago Bol'šoe Morskoe Ozero Bol'šoe Morskoe Οζέρο Μποσλόε Μόρσκοε ओज़ेरो बोल'सो मोर्सकोए Bol'šoe Morszkoje-tó Danau Bolshoe Morskoe Bol'šoe Morskoe ボリショエ・モルスコエ湖 오제로 볼쇼에 모르스코에 Bolsjoe Morskoe ozero Jezioro Bolszoje Morskie Lago Bol'šoe Morskoe Большое Морское озеро Ozero Bolsjoje Morskoje Ozero Bol'šoe Morskoe Hồ Bol'šoe Morskoe 大莫尔斯科湖 1159114973اوزرو بولچوئه مورسکوئه אגם בולשו מורסקו Велике Морське озеро اوزیرو بولسوئے مورسکوئے 布索莫斯科伊湖 0Lake Ozero Chukochye L. Chukoch’ye 4.7 6.0O. Chukochye Ozero Chukochye Q1108335 بحيرة تشوكوتشى ওজেরো চুকোচে Ozero Chukochye Chukochye Lago Chukochye Ozero Chukochye Οζέρο Τσουκότσιε ओज़ेरो चुकोचे Csukocsje-tó Danau Chukochye Čukoč'e チュコチエ湖 오제로 추코체 Tsjoekotsje ozero Jezioro Chukochye Lago Chukochye Чукочье озеро Ozero Tjukotje Ozero Chukochye Hồ Chukochye 丘科奇耶湖 1159114993اوزرو چوکوچیه אגם צ'וקוצ'יה озеро Чукоче اوزیرو چوکوچائی 丘科奇耶湖 0Lake Shijiu Hu 4.7 6.0Shijiu Hu Shijiu Hu Q7374652 بحيرة شيجيو শিজিউ হু Shijiu Hu Shijiu Shijiu Hu Lac Shijiu Σιτζιού Χου शिजिउ हू Shijiu Hu Danau Shijiu Shijiu Hu 石臼湖 시주 후 Shijiu Lake Jezioro Shijiu Lago Shijiu озеро Шицзю Shijiu Hu Shijiu Hu Hồ Thạch Cữu 石臼湖 1159115009شیو هو אגם שיג'יו Шиджуху شیجو ہو 石臼湖 0Lake Hong Hu 4.7 6.0Hong Hu Hong Hu Q5895614 بحيرة هونغ হং হু Hong Hu Hong Hong Hu Hong Χονγκ Χου हांग हु Hong Hu Danau Hong Hong Hu 洪湖 홍 후 Hong Lake Hong Hu Lago Hong озеро Хонгху Hong Hu Hong Hu Hồng Hồ 洪湖 1159115027هونگ هو אגם הונג Хонгху ہونگ ہو 洪湖 0Lake Võrtsjärv 4.7 6.0Võrtsjärv Võrtsjärv Q211516 فورجاف ভর্টসজার্ভ Võrtsjärv Võrtsjärv Võrtsjärv Võrtsjärv Βίρτσγιαρβ वोर्त्स्जार्व Võrts-tó Võrtsjärv Võrtsjärv ヴォルツ湖 페르트스야르프 Võrtsjärv Võrtsjärv Võrtsjärv Выртсъярв Võrtsjärv Võrtsjärv Hồ Võrtsjärv 沃尔茨湖 1159115043دریاچه وورتسیارو אגם וורטסיארב Виртс'ярв وورٹسجارو 沃爾茨湖 0Lake Chao Hu 4.7 6.0Chao Hu Chao Hu Q1062495 بحيرة تشاو শাও হু Chao Hu Chao Chao Chao Τσάο Χου चाओ हु Chao Hu Danau Chao Lago di Chao Hu 巣湖 차오호 Chao Chaohu Lago Chao Чаоху Chao Hu Chao Hu Sào 巢湖 1159115069چائو هو צ'או Чаоху چاؤ ہو 巢湖 0Lake _untitled_11 4.7 6.0 1159115089 0Lake Lake Rossignol 4.7 6.0L. Rossignol Lake Rossignol Q3215164 بحيرة روسيجنول লেক রসসিগনোল Lake Rossignol Rossignol Lago Rossignol Rossignol Λίμνη Ροσιγκνόλ रॉसिग्नोल झील Rossignol-tó Danau Rossignol Lake Rossignol ロシニョール湖 레이크 로시뇰 Lake Rossignol Lake Rossignol Lago Rossignol озеро Россиньоль Rossignol Rossignol Gölü Hồ Rossignol 罗西诺湖 1159107465دریاچه روسیگنول אגם רוסיניול озеро Россінгол جھیل روسگنول 荷夕紐湖 0Lake Grand Lake 4.7 6.0Grand L. Grand Lake Q1275436 غراند ليك গ্র্যান্ড লেক Grand Lake Foshay Lake Lago Grand Grand Lake Λίμνη Γκραντ ग्रैंड झील Grand Lake Danau Grand Grand Lake グランド湖 그랜드 레이크 Grand Lake Grand Lake Grand Гранд-Лейк Grand Lake Grand Lake Hồ Grand 格蘭德湖 1159107475دریاچه گرند גרנד לייק Гранд-Лейк گرینڈ لیک 格蘭德湖 0Alkaline Lake Goose Lake 4.7 6.0Goose L. Goose Lake Q1309664 بحيرة جوس গুজ লেক Goose Goose Goose Goose Λίμνη Γκουζ गूज़ झील Goose-tó Danau Goose Goose Lake グース湖 구스 레이크 Goose Goose Lake Lago Goose Гус Goose Lake Goose Gölü Hồ Goose 鹅湖 1159126483دریاچه گوس אגם האווזים озеро Гуз گوس جھیل 鵝湖 0Alkaline Lake Pyramid Lake 4.7 6.0Pyramid L. Pyramid Lake Q761535 بحيرة بيراميد পিরামিড লেক Pyramid Pyramid Pirámide Pyramid Λίμνη Πύραμιντ पिरामिड झील Pyramid Danau Pyramid Pyramid ピラミッド湖 피라미드호 Pyramid Pyramid Lago Pyramid Пирамид Pyramid Lake Piramit Gölü Hồ Pyramid 金字塔湖 1159126491دریاچه پیرامید אגם פירמיד Пірамід پائرامڈ جھیل 金字塔湖 0Lake Lake Sevan Lake Sevana 4.7 6.0L. Sevan Lake Sevan Q181932 بحيرة سيفان লেক সেভেন Sewansee Sevan Sevan Sevan λίμνη Σεβάν सेवन झील Szeván-tó Sevan Sevan セヴァン湖 세반호 Sevanmeer Sewan Sevan Севан Sevansjön Sevan Sevan 塞凡湖 1159115109دریاچه سوان ימת סוואן Севан جھیل سیوان 塞凡湖 0Lake _untitled_10 4.7 6.0 1159115135 0Lake _untitled_9 4.7 6.0 1159115153 0Lake Weishan Hu 4.7 6.0Weishan Hu Weishan Hu Q839287 بحيرة وايشان উইশান হু Weishan Lake Nansi Nansi Lac de Weishan Γουεϊσάν Χου वीशान हु Weishan Hu Danau Weishan Weishan Hu 囲山湖 웨이산 후 Nansi Jezioro Weishan Lago Weishan Наньсыху Weishan Hu Weishan Hu Hồ Vi Sơn 微山湖 1159115165ویشان هو אגם ווישאן Вейшанху ویشان ہو 微山湖 0Lake _untitled_8 4.7 6.0 1159115185 0Lake Huangtang Hu 4.7 6.0Huangtang Hu Huangtang Hu -1 بحيرة هوانغتانغ হুয়াংতাং হু Huangtang Hu Futou Lake Huangtang Hu Huangtanghu Χουανγκτάνγκ Χου हुआंगतांग हु Huangtang Hu Danau Huangtang Huangtang Hu 黄塘湖 황탕 후 Huangtang Lake Jezioro Huangtang Lago Huangtang озеро Чуантан Huangtang Hu Huangtang Hu Hồ Phủ Đầu 黄塘湖 1159115205هوآنگتانگ هو הואנגטנג Хуангтангху ہوانگٹانگ ہو 黃塘湖 0Lake _untitled_7 4.7 6.0 1159115225 0Reservoir Millerton Lake 4.7 6.0Millerton L. Millerton Lake Q6859416 بحيرة ميلرتون মিলার্টন লেক Millerton Lake Millerton Lago Millerton Millerton Λίμνη Μίλερτον मिलर्टन झील Millerton-tó Danau Millerton Millerton Lake ミラートン湖 밀러턴 레이크 Millerton Millerton Lake Reservatório Millerton озеро Миллертон Millerton Lake Millerton Gölü Hồ Millerton 米勒顿湖 1159124147رودخانه میلرتون מפרץ מילן озеро Міллертон ملرٹن جھیل 米勒頓湖 0Lake Bluenose Lake 4.7 6.0Bluenose L. Bluenose Lake Q886010 بحيرة بلو نوس ব্লুনোজ লেক Bluenose Bluenose Lago Bluenose Bluenose Λίμνη Μπλουνόουζ ब्लूनोज झील Bluenose-tó Danau Bluenose Bluenose Lake ブルーノーズ湖 블루노즈 레이크 Bluenose Jezioro Bluenose Lake Lago Bluenose Блуноз Bluenose Bluenose Gölü Hồ Bluenose 布盧諾斯湖 1159107513دریاچه بلونوز אגם בלונוז озеро Блуноз بلونوس جھیل 布盧諾斯湖 0Reservoir Réservoir Pipmuacan 4.7 6.0Rs. Pipmuacan Rés. Pipmuacan Q1471254 خزان بيبميوكان পিপমুয়াকান জলাধার Pipmuacan Pipmuacan Presa de Pipmuacan Pipmuacan Ρεζερβουάρ Πιπμουακάν रिज़र्वोयर पिपमुआकाना Pipmuacan-víztározó Reservoir Pipmuacan Réservoir Pipmuacan レゼルヴォワール・ピミャカン 레저보어 삐무아칸 Pipmuacan Reservoir Zbiornik Pipmuacan Represa de Pipmuacan водохранилище Резервуар-Пипмюакан Pipmuacan Réservoir Pipmuacan Hồ Pipmuacan 皮普馬康水庫 1159124167مخزن سد پیپمواکان מאגר פיפמואקאן водосховище Піпмуакан ریزروائر پپمواکان 皮普馬康水庫 0Lake Grand Lake 4.7 6.0Grand L. Grand Lake Q1275436 غراند ليك গ্র্যান্ড লেক Grand Lake Grand Lake Lago Grand Grand Lake Λίμνη Γκραντ ग्रैंड झील Grand Lake Danau Grand Grand Lake グランド湖 그랜드 레이크 Grand Lake Grand Lake Grand Гранд-Лейк Grand Lake Grand Lake Hồ Grand 格蘭德湖 1159107521دریاچه گرند גרנד לייק Гранд-Лейк گرینڈ لیک 格蘭德湖 0Lake _untitled_6 4.7 6.0 1159107535 0Lake Colville Lake 4.7 6.0Colville L. Colville Lake Q1112986 بحيرة كولفيل কোলভিল লেক Colville Colville Colville Colville Λίμνη Κόλβιλ कोल्विल झील Colville-tó Danau Colville Colville Lake コルビル湖 콜빌 레이크 Colville Colville Lake Lago Colville Колвилл Colville Colville Gölü Hồ Colville 科爾維爾湖 1159107549دریاچه کولویل אגם קולוויל озеро Колвілл کول ولے جھیل 科爾維爾湖 0Lake Hottah Lake 4.7 6.0Hottah L. Hottah Lake Q1631233 بحيرة هوتا হোটাহ লেক Hottah Hottah Hottah Hottah Λίμνη Χότα होट्टा झील Hottah-tó Danau Hottah Hottah Lake ホッター湖 호타 레이크 Hottah Jezioro Hottah Lake Lago Hottah Хотта Hottah Hottah Gölü Hồ Hottah 霍塔湖 1159107563دریاچه هنا אגם הוטה озеро Хотта ہوتاہ جھیل 霍塔湖 0Lake Big Trout Lake 4.7 6.0Big Trout L. Big Trout Lake Q859461 بحيرة تروت الكبيرة বিগ ট্রাউট লেক Big Trout Big Trout Lago Big Trout Big Trout Μεγάλη Μπιγκ Τράουτ बिग ट्राउट झील Big Trout-tó Danau Big Trout Big Trout Lake ビッグ・トラウト湖 빅 트라우트 레이크 Big Trout Lake Big Trout Lago Big Trout Биг-Траут Big Trout Big Trout Gölü Hồ Big Trout 大特勞特湖 1159107573دریاچه بیگ تروت אגם הפורל הגדול Біг-Траут بگ ٹراؤٹ جھیل 大特勞特湖 0Lake Trout Lake 4.7 6.0Trout L. Trout Lake Q1638242 بحيرة تراوت ট্রাউট লেক Trout Trout Lago Trout Lac Trout Λίμνη Τράουτ ट्राउट झील Trout-tó Danau Trout Trout Lake トラウト湖 트라우트 레이크 Trout Lake Trout Lake Lago Trout озеро Траут Trout Lake Trout Gölü Hồ Trout 特勞特湖 1159107587دریاچه تروت אגם פורל Троут ٹراؤٹ جھیل 特勞特湖 0Lake Island Lake 4.7 6.0Island L. Island Lake Q179505 جزيرة آيلاند আইল্যান্ড লেক Island Island Island Island Νήσος Λέικ द्वीप झील Island-tó Danau Island Island アイランド湖 아일랜드 레이크 Island Island Lake Island Айленд Island Island Gölü Hồ Island 湖心岛 1159107599جزیره لیک אגם האי озеро Айленд جزیرہ لیک 雷克島 0Lake Lake Naococane 4.7 6.0L. Naococane Lake Naococane Q3215083 بحيرة ناوكوكان লেক নাওকোকেন Naococane Naococane Lago Naococane Naococane Λίμνη Ναοκοκάν नाओकोकेन झील Naococane-tó Danau Naococane Lake Naococane ナオコケーン湖 레이크 나오코케인 Lake Naococane Jezioro Naococane Lago Naococane озеро Наококан Naococane Naococane Gölü Hồ Naococane 纳科坎湖 1159107609دریاچه نوکوکین אגם נאוקוקאן озеро Наококейн جھیل ناؤکوکین 瑙科坎湖 0Lake Lac la Ronge 4.7 6.0L. la Ronge Lac la Ronge Q250257 بحيرة لا رونج ল্যাক লা রঙ্গে Ronge Ronge Ronge Ronge Λακ λα Ρόνζ लैक ला रोन्गे Lac la Ronge Lac la Ronge Lac la Ronge ラ・ロンジュ湖 라크 라 롱주 Ronge Lac la Ronge Lago la Ronge Ла-Ронж Ronge Lac la Ronge Hồ Lac la Ronge 拉龍日湖 1159107627دریاچه لا رانژ אגם לה רונג Ла-Рондж لاک لا رونج 拉龍日湖 0Lake Mille Lacs Lake 4.7 6.0Mille Lacs L. Mille Lacs Lake Q1600016 بحيرة ميل لاكس، غاريسون মাইল ল্যাক্স লেক Mille Lacs Mille Lacs Mille Lacs Mille Lacs Λίμνη Μιγ Λακ मिल लैक झील Mille Lacs-tó Danau Mille Lacs Mille Lacs Lake ミラックス湖 밀레 락스 레이크 Mille Lacs Mille Lacs Lake Lago Mille Lacs озеро Милле-Лакс Mille Lacs Mille Lacs Gölü Hồ Mille Lacs 米拉湖 1159107635رودخانه میل لاکس אגם מילרטון озеро Мілле-Лакс ملے لاکس جھیل 米拉湖 0Lake Lake Winnipesaukee 4.7 6.0L. Winnipesaukee Lake Winnipesaukee Q224872 بحيرة وينيبساوكي লেক উইন্নিপেসাউকী Winnipesaukee Winnipesaukee Winnipesaukee Winnipesaukee Λίμνη Γουινιπεσόκι विनीपेसौकी झील Winnipesaukee-tó Danau Winnipesaukee Winnipesaukee ウィニペソーキ湖 레이크 위니피소키 Winnipesaukee Winnipesaukee Winnipesaukee Уиннипесоки Winnipesaukee Winnipesaukee Hồ Winnipesaukee 温尼珀索基湖 1159107675دریاچه وینیپسائوکه אגם וויניפסאוקי озеро Вінніпесокі جھیل ونیپیسوکی 温尼珀索基湖 0Lake Lake Simcoe 4.7 6.0L. Simcoe Lake Simcoe Q366985 بحيرة سيمكو লেক সিমকো Simcoe Simcoe Simcoe Simcoe Λίμνη Σίμκο सिमको झील Simcoe-tó Simcoe Simcoe シムコー湖 레이크 심코 Simcoemeer Simcoe Simcoe Симко Simcoe Simcoe Gölü Hồ Simcoe 錫姆科湖 1159107689دریاچه سیمکو אגם סימקו Сімко جھیل سمکوئی 錫姆科湖 0Lake Gods Lake 4.7 6.0Gods L. Gods Lake Q1533897 بحيرة جودس গড'স লেক Gods Gods Gods Gods Λίμνη Γκοντς गॉड्स लेक Gods Lake-tó Danau Gods Gods Lake ゴッズ湖 갓즈 레이크 Gods Meer Jezioro God’s Lake Gods Годс Gods Gods Gölü Hồ Gods 戈茲湖 1159107699دریاچه گادز אגם האלים озеро Годс گاڈز لیک 戈茲湖 0Lake Hoh Xil Hu 4.7 6.0Hoh Xil Hu Hoh Xil Hu Q10913764 بحيرة هو زيل হো জিল হু Hoh Xil Hu Hoh Xil Hu Hoh Xil Hu Hoh Xil Lake Χο Ξιλ Χου होह ज़िल हु Hoh Xil Hu Danau Hoh Xil Hoh Xil Hu 可可西里湖 호 실 후 Hoh Xil Lake Jezioro Hoh Xil Lago Hoh Xil озеро Кукушили Hoh Xil Hu Hoh Xil Hu Hồ Hy Nhĩ 可可西里湖 1159115243هو ایکسیل هو הו סיל Кукушилі ہو زل ہو 可可西里湖 0Alkaline Lake Lake Hammar 4.7 6.0L. Hammar Lake Hammar Q2668029 هور الحمّار লেক হ্যামার Hammar-See Hammar Hammar Al-hammar Λίμνη Χαμάρ हमार झील Hammar-tó Danau Hammar Lake Hammar ハンマール湖 레이크 함마르 Lake Hammar Jezioro Hammar Lago Hammar Эль-Хаммар Hammar Hamar Hồ Hammar 哈马尔湖 1159126873هور حمار אגם האמר озеро Гаммар جھیل حمار 哈马尔湖 0Alkaline Lake Malheur Lake 4.7 6.0Malheur L. Malheur Lake Q3215037 بحيرة مالهور মালহেউর লেক Malheur Malheur Lago Malheur Malheur Λίμνη Μαλέρ मल्हेउर झील Malheur-tó Danau Malheur Malheur Lake マルヒュア湖 말허어 레이크 Malheur Lake Malheur Lake Lago Malheur Малур Malheur Lake Malheur Gölü Hồ Malheur 马豪尔湖 1159126509دریاچه مالهور מאלי озеро Мальхейр مالہیور جھیل 馬勒爾湖 0Lake _untitled_5 4.7 6.0 1159107735 0Lake _untitled_4 4.7 6.0 1159107747 0Lake _untitled_3 4.7 6.0 1159107757 0Lake _untitled_2 4.7 6.0 1159107859 0Lake _untitled_1 4.7 6.0 1159107873 0Lake Tikchik Lakes 4.7 6.0Tikchik Lks. Tikchik Lakes Q2433031 Tikchik Tikchik 1159107889 0Lake Tikchik Lakes 4.7 6.0Tikchik Lks. Tikchik Lakes Q2433031 Tikchik Tikchik 1159107899 0Lake Tikchik Lakes 4.7 6.0Tikchik Lks. Tikchik Lakes Q2433031 Tikchik Tikchik 1159107913 0Lake Tikchik Lakes 4.7 6.0Tikchik Lks. Tikchik Lakes Q2433031 Tikchik Tikchik 1159107927 0Alkaline Lake Khyargas Nuur Hyargas Nuur 4.7 6.0Khyargas Nuur Khyargas Nuur Q1125601 بحيرة خيارجاس খ্যারগাস নূর Chjargas Nuur Khyargas Nuur Khyargas Khyargas Χουάγκας Νουρ ख्यारगस नूउर Hjargasz-tó Khyargas Nuur Hjargas nuur キヤールガス・ヌール 캬르가스 누르 Khyargas Nuur Chjargas nuur Khyargas Хяргас-Нуур Khyargas Nuur Khyargas Nuur Khyargas 吉爾吉斯湖 1159126887خیارگاس نور אגם חיארגאס Хярґас-Нур کھائراگاس نور 吉爾吉斯湖 0Lake _untitled_0 4.7 6.0 1159115267 0Alkaline Lake Lake Assal 4.7 6.0L. Assal Lake Assal Q81239 بحيرة عسل আসাল হ্রদ Assalsee Assal Assal Assal Λίμνη Ασσάλ असल झील Assal--tó Assal Assal アッサル湖 아살호 Assalmeer Asal Assal Ассаль Assalsjön Asal Assal 阿萨勒湖 1159126901دریاچه عسل אגם עסל Ассаль جھیل اسال 阿薩勒湖 0Lake Rainy Lake 4.7 6.0Rainy L. Rainy Lake Q202019 بحيرة ريني، انترناشيونال فولس রেইনি লেক Rainy Rainy Rainy Pluie Λίμνη Ρέινι रेनी झील Rainy Lake Danau Rainy Rainy レイニー湖 레이니 레이크 Rainy Meer Rainy Rainy Рейни-Лейк Rainy Rainy Lake Hồ Rainy 雷尼湖 1159107275دریاچه رینی אגם רייני Дощове озеро رینی جھیل 雷尼湖 0Reservoir Williston Lake 4.7 6.0Williston L. Williston Lake Q967775 بحيرة ويليستون উইলিস্টন লেক Williston Williston Williston Williston Λίμνη Γουίλιστον विलिस्टन झील Williston-tó Danau Williston Williston ウィリストン湖 윌리스턴 레이크 Williston Meer Williston Lake Williston Уиллистон Williston Williston Gölü Hồ Williston 威利斯顿湖 1159124009دریاچه ویلیستون אגם ויליסטון озеро Уілстон ولیسٹن جھیل 威利斯頓湖 0Lake Split Lake 4.7 6.0Split L. Split Lake Q7375301 سبليت ليك স্প্লিট লেক Split Lake Split Lago Split Split Λίμνη Σπλιτ स्प्लिट झील Split-tó Danau Split Split Lake スプリット・レイク 스플리트 레이크 Split Lake Jezioro Split Split Lake озеро Сплит-Лейк Split Split Gölü Hồ Split 斯普利特湖 1159107285دریاچه اسپلیت אגם ספליט озеро Спліт سپلٹ جھیل 斯普利湖 0Reservoir Ft. Peck Lake 4.7 6.0Ft. Peck L. Fort Peck Lake Q4492006 بحيرة فورت بيك ফোর্ট পেক লেক Fort Peck Fort Peck Lago Fort Peck Fort Peck Λίμνη Φορτ Πεκ फ़ोर्ट पेक झील Fort Peck-tó Danau Fort Peck Fort Peck Lake フォート・ペック湖 포트 펙 레이크 Fort Peck Lake Jezioro Fort Peck Lago Fort Peck Форт-Пек Fort Peck Lake Fort Peck Gölü Hồ Fort Peck 佩克堡湖 1159124029دریاچه فورت پک אגם פורט פק озеро Форт-Пек فورٹ پیک جھیل 派克堡湖 0Reservoir Lake Sakakawea 4.7 6.0L. Sakakawea Lake Sakakawea Q1801077 بحيرة سكاكاويا লেক সাকাকাউই Sakakawea Sakakawea Sakakawea Sakakawea Λίμνη Σακακαβέα सकाकावी झील Sakakawea-tó Danau Sakakawea Sakakawea サカカウェア湖 레이크사카카웨아 Sakakawea Lake Sakakawea Lago Sakakawea Сакакавиа Lake Sakakawea Sakakawea Gölü Hồ Sakakawea 沙卡卡威亞湖 1159124039دریاچه ساکاکاوی אגם סאקאווה озеро Сакакавеа جھیل ساکاکاویا 沙卡卡威亞湖 0Lake Teslin Lake 4.7 6.0Teslin L. Teslin Lake Q283793 بحيرة تسلين টেসলিন লেক Teslin Teslin Lago Teslin Teslin Λίμνη Τέσλιν टेस्लिन झील Teslin-tó Danau Teslin Teslin テスリン湖 테슬린 레이크 Teslin Lake Teslin Lake Teslin Теслин Teslin Teslin Gölü Hồ Teslin 特斯林湖 1159107319دریاچه تسلین אגם טסלין озеро Теслін تیسلن جھیل 特斯林湖 0Reservoir Lower Arrow Lake 4.7 6.0Lower Arrow L. Lower Arrow Lake Q280135 بحيرة السهم السفلي লোয়ার অ্যারো লেক Arrow Arrow Lakes Lagos Arrow lacs Arrow Λίμνη Λόουερ Άρροου लोअर एरो झील Lower Arrow-tó Danau Arrow Bawah Laghi Arrow アロー湖 로어 애로우 레이크 Arrow Lakes Arrow Lake Arrow озеро Лоуэр-Эрроу Lower Arrow Lake Lower Arrow Gölü Hồ Lower Arrow 下阿罗湖 1159124087دریاچه اروی پایینی אגם לואר רד озеро Лоуер-Ерроу ایرو جھیلیں 下箭湖 0Lake Lake Pend Oreille 4.7 6.0L. Pend Oreille Lake Pend Oreille Q1632195 بحيرة بيند أوريلي লেক পেন্দ ওরেল্লি Pend Oreille Pend Oreille Pend Oreille Pend Oreille Λίμνη Πεντ Ορέιγ पेंड ओरीले झील Pend Oreille-tó Pend Oreille Pend Oreille ペンドオレイル湖 레이크 펜드 오헤 Pend Oreille Pend Oreille Lago Pend Oreille Панд-Орей Lake Pend Oreille Pend Oreille Gölü Hồ Pend Oreille 庞多雷湖 1159107335دریاچه پند اوریل אגם פנד אוריי озеро Панд-Орей جھیل پینڈ اورئیلے 龐多雷湖 0Reservoir Lake Chelan 4.7 6.0L. Chelan Lake Chelan Q1115201 بحيرة شيلان লেক চেলান Chelan Chelan Chelan Chelan Λίμνη Τσελάν चेलान झील Chelan-tó Chelan Chelan シュラン湖 레이크 첼란 Chelan Chelan Lago Chelan Челан Lake Chelan Chelan Gölü Hồ Chelan 奇蘭湖 1159124141دریاچه چلان אגם צ'לאן озеро Челан جھیل چیلان 奇蘭湖 0Lake Black Lake 4.7 6.0BL.k L. Black Lake Q880358 بحيرة بجزيرة ব্ল্যাক লেক Black Black Lago Black Black Λίμνη Μπλακ ब्लैक लेक Black-tó Danau Black Black Lake ブラック湖 블랙 레이크 Black Lake Crno jezero Lago Black Блэк-Лейк Black Black Gölü Hồ Black 布萊克湖 1159107491دریاچه بلک אגם בלאק озеро Блек بلیک جھیل 布萊克湖 0Lake Lake Louise 4.7 6.0L. Louise Lake Louise Q1343275 بحيرة لويز লেক লুইজি Louise Louise Louise Louise Λίμνη Λουίζ लुईस झील Louise-tó Danau Louise Louise レイク・ルイーズ 레이크 루이스 Louise Louise Louise Лейк-Луис Louise Louise Gölü Hồ Louise 路易斯湖 1159107499لیک لوئیس، آلاسکا אגם לואיז Лейк-Луїз لیک لوئس، الاسکا 路易斯湖 0Lake Lower Red Lake 4.7 6.0Lower Red L. Lower Red Lake Q1320568 بحيرة ريد লোয়ার রেড লেক Red Red Red Red Λίμνη Λόουερ Ρεντ लोअर लाल झील Lower Red-tó Danau Red Bawah Lower Red Lake レッド湖 로어 레드 레이크 Red Red Lake Lower Red Lake озеро Лоуэр-Ред Lower Red Lake Lower Red Gölü Hồ Lower Red 聆雷德湖 1159107655رد لیک پایینی נהר תחתון озеро Лоуер-Ред لوئر ریڈ جھیل 下紅湖 0Lake Upper Red Lake 4.7 6.0Upper Red L. Upper Red Lake Q1320568 بحيرة ريد আপাপ্র রেড লেক Red Red Red Red Λίμνη Άπερ Ρεντ अपर रेड झील Upper Red-tó Danau Red Atas Upper Red Lake レッド湖 어퍼 레드 레이크 Red Upper Red Lake Upper Red Lake озеро Аппер-Ред Upper Red Lake Upper Red Gölü Hồ Upper Red 厄珀雷德湖 1159107661رد لیک بالایی אגם רד העליון Аппер-Ред-Лейк اپر ریڈ لیک 上紅湖 0Lake Yathkyed Lake 4.7 6.0Yathkyed L. Yathkyed Lake Q1888261 بحيرة ياثكيد ইয়াথকয়েড লেক Yathkyed Yathkyed Yathkyed Yathkyed Λίμνη Γιατχιέντ यथकीड झील Yathkyed-tó Danau Yathkyed Yathkyed Lake ヤスカイエド湖 야트키드 레이크 Yathkyed Yathkyed Lago Yathkyed Яткайед Yathkyed Yathkyed Gölü Hồ Yathkyed 亚斯凯德湖 1159107715دریاچه یاتکید אגם יתקייד Яткієд یاتھکائیڈ جھیل 亞斯凱德湖 0Lake Amadjuak Lake 4.7 6.0Amadjuak L. Amadjuak Lake Q452088 بحيرة أماجيواك আমাদঝুয়াক লেক Amadjuak Amadjuak Amadjuak Amadjuak Λίμνη Αμαντγιουάκ अमदजुआक झील Amadjuak-tó Danau Amadjuak Amadjuak アマジュアク湖 아마주악 레이크 Amadjuak Amadjuak Lago Amadjuak Амаджуак Amadjuak Amadjuak Gölü Hồ Amadjuak 阿馬朱瓦克湖 1159107307دریاچه آمادجوئاک אגם אמדג'ואק Амаджуак آمدجواک جھیل 阿馬朱瓦克湖 0Reservoir Amistad Reservoir 4.7 6.0Amistad Res. Amistad Reservoir Q1634424 خزان أميستاد আমিস্তাদ রিজার্ভার Amistad-Stausee Amistad Presa de la Amistad Amistad Reservoir Τεχνητή Λίμνη Άμισταντ अमिस्ताद जलाशय Amistad víztározó Reservoir Amistad Amistad Reservoir アミスタード貯水池 아미스타드 레저보어 Amistad Zbiornik Amistad Represa de Amistad водохранилище Амистад Amistad Reservoir Amistad Rezervuarı Hồ Amistad 阿米斯塔德水庫 1159124109دریاچه آمیستاد מאגר אמיסטד вдосховище Амістад ایمستاد ریزروائر 阿米斯德水庫 0Lake Cabonga Reservoir _untitled_20 4.7 6.0Cabonga Res. Cabonga Reservoir Q1328792 خزان كابونجا কাবোংগা রিজার্ভার Cabonga Cabonga Presa de Cabonga Cabonga Τεχνητή Λίμνη Καμπόνγκα कबोंगा जलाशय Cabonga-víztározó Reservoir Cabonga Cabonga カボンガ貯水池 카봉가 레저보어 Cabonga Reservoir Zbiornik Cabonga Represa de Cabonga Водохранилище Кабонга Cabonga Cabonga Rezervuarı Hồ Cabonga 卡邦加水库 1159123781مخزن سد کابونگا מאגר קאבונגה водосховище Кабонга کابونگا ریزروائر 卡邦加水庫 0Lake Lago de Chapala 4.7 6.0L. de Chapala Lago de Chapala Q318350 بحيرة تشابالا লাগো দে চাপালা Chapalasee Chapala Chapala Chapala Λάγκο ντε Τσαπάλα लागो द चप्ला Chapalai-tó Danau Chapala Chapala チャパラ湖 라고 데 차팔라 Chapalameer Chapala Chapala Чапала Lago de Chapala Lago de Chapala Hồ Chapala 查帕拉湖 1159107251لاگو د چاپالا אגם צ'פלה Чапала لاگو ڈی چاپالا 查帕拉湖 0Lake Lago de Managua Lake Xolotlán 4.7 6.0L. de Managua Lago de Managua Q272380 بحيرة ماناغوا মানাগুয়া হ্রদ Managuasee Managua Xolotlán Managua Λίμνη Μανάγκουα लागो द मानागुआ Managua-tó Managua Managua マナグア湖 마나과호 Managuameer Managua Manágua Манагуа Managuasjön Lago de Managua Managua 马那瓜湖 1159107259دریاچه ماناگوا אגם מנגואה Манагуа لاگو ڈی ماناگوا 馬那瓜湖 0Reservoir Itaipú Reservoir Represa Itaipu 4.7 6.0Rs. Itaipu Represa Itaipu Q10315670 ريبريسا إيتايبو রেপ্রেসা ইটাইপো Itaipu-Stausee Itaipu Presa de Itapú Barrage d'Itaipu τεχνητή λίμνη Ιταϊπού रेप्रेसा इताइपु Represa Itaipu Reservoir Itaipu Diga di Itaipú レプレーザ・イタイプ 레프레사 이타이푸 Itaipudam Zbiornik Itaipu Itaipu водохранилище Лагоа-ди-Итайпу Itaipu Represa Itaipu Hồ Itaipu 伊泰普水库 1159125135رپرسا ایتائیپو סכר איטאיפו Репреса-Ітайпу ریپریسا لیپے 伊泰普水庫 0Lake Lago Gatun 4.7 6.0L. Gatun Lago Gatun Q313637 بحيرة غاتون লাগো গাতুন Gatúnsee Gatun Gatún Gatún Λάγκο Γκατούν गाटुन झील Gatún-tó Gatun Gatún ガトゥン湖 라고 가툰 Gatúnmeer Gatún Gatún Гатун Gatúnsjön Gatun Gatun 加通湖 1159123579لاگو گاتون אגם גאטון Гатун لاگو گاتن 加通湖 0Reservoir Lake Kariba admin-0 4.7 6.0L. Kariba Lake Kariba Q1047206 بحيرة كاريبا কারিবা হ্রদ Lake Kariba Kariba Kariba Kariba Λίμνη Καρίμπα कैरीबा झील Kariba-tó Kariba Kariba カリバ湖 레이크 카리바 Karibameer Kariba Kariba Кариба Karibasjön Kariba Kariba 卡里巴水库 1159125055دریاچه کاریبا אגם קאריבה Каріба جھیل کاریبا 卡里巴水庫 0Lake Lake Kyoga 4.7 6.0L. Kyoga Lake Kyoga Q124978 بحيرة كيوغا লেক কিয়োগা Kyogasee Kyoga Kyoga Kyoga Λίμνη Κιόγκα क्योगा झील Kyoga-tó Kyoga Kyoga キオガ湖 키오가호 Kyogameer Kioga Kyoga Кьога Kyogasjön Kyoga Kyoga 基奥加湖 1159114279دریاچه کیوگا קיוגה Кйога جھیل کائیوگا 基奧加湖 0Reservoir Ozero Kubenskoye _untitled_26 4.7 6.0Oz. Kubenskoye Ozero Kubenskoye Q1463552 بحيرة كوبنسكوي ওজেরো কুবেন্সকোয়ে Kubenasee Kubenskoe Kubenskoye Koubenskoïe Οζέρο Κουμπενσκόγιε ओज़ेरो कुबेन्सकोये Kubenszkoje-tó Danau Kubenskoye Kubenskoe クベンスコエ湖 오제로 쿠벤스코예 Koebenskoe ozero Jezioro Kubieńskie Lago Kubenskoye Кубенское озеро Ozero Kubenskoje Kubena Hồ Ozero Kubenskoye 库边斯科耶湖 1159125041اوزرو کوبنسکویه אגם קובנסקויה Кубенське озеро اوزیرو کوبینسکوئے 庫邊斯科耶湖 0Lake Bodensee Lake Constance admin-0 4.7 6.0Bodensee Bodensee Q4127 بحيرة كونستانس বোদেন্সি Bodensee Constance Constanza Constance Λίμνη Κωνσταντίας बोडेनसी Boden-tó Konstanz Costanza ボーデン湖 보덴호 Bodenmeer Jezioro Bodeńskie Constança Боденское озеро Bodensjön Konstanz Bodensee 博登湖 1159114259دریاچه کنستانس ימת קונסטנץ Боденське озеро جھیل کونسٹانس 博登湖 0Lake _untitled_23 4.7 6.0 1159114461 0Alkaline Lake Dead Sea _untitled_13 4.7 6.0Dead Sea Dead Sea Q23883 البحر الميت মৃত সাগর Totes Meer Dead Sea mar Muerto mer Morte Νεκρά θάλασσα मृत सागर Holt-tenger Laut Mati Mar Morto 死海 사해 Dode Zee Morze Martwe Mar Morto Мёртвое море Döda havet Lut Biển Chết 死海 1159126865دریای مرده ים המלח Мертве море بحیرہ مردار 死海 0Lake Sea of Galilee 4.7 6.0Sea of Galilee Sea of Galilee Q126982 بحيرة طبريا গালীল সাগর Genezareth Sea of Galilee mar de Galilea Tibériade Θάλασσα της Γαλιλαίας गलील सागर Galileai-tenger Galilea Tiberiade ガリラヤ湖 갈릴리 호 Meer van Tiberias Jezioro Tyberiadzkie Mar da Galileia Тивериадское озеро Galileiska sjön Taberiye Biển Galilee 加利利海 1159114879دریاچه طبریه הכנרת Тиверіадське озеро بحیرہ طبريہ 加利利海 0Reservoir Lake Argyle 4.7 6.0L. Argyle Lake Argyle Q1757739 بحيرة أرجيل লেক আরগািল Argyle Argyle Lago Argyle Argyle Λίμνη Αργκίλε अरगेले झील Argyle-tó Danau Argyle Lake Argyle アーガイル湖 레이크 아가일 Argyle Lake Argyle Lago Argyle озеро Аргайл Argyle Argyle Gölü Hồ Argyle 阿盖尔湖 1159125081دریاچه آرجیل אגם ארגייל Аргайл جھیل آرگائل 亞蓋爾湖 0Lake Ngoring Hu 4.7 6.0Ngoring Hu Ngoring Hu Q847864 بحيرة إنجورينغ এনগোরিং হু Ngoring Hu Ngoring Eling Lac Ngoring Νγκόρινγκ Χου एनगोरिंग हू Ngoring Hu Danau Ngoring Ngoring Hu ゴレン湖 응고링 후 Ngoring Lake Ngoring Hu Lago Ngoring Орин-Нур Ngoring Hu Ngoring Hu Hồ Ngạc Lăng 鄂陵湖 1159114305انگورینگ هو אגם נגורינג Нгорінгху اینگورنگ ہو 鄂陵湖 0Lake Gyaring Hu 4.7 6.0Gyaring Hu Gyaring Hu Q4128895 بحيرة جيرنج গ্যারিং হু Gyaring Hu Gyaring Zaling Gyaring Γκιάρινγκ Χου ग्यारिंग हु Gyaring Hu Danau Gyaring Gyaring Hu ギャリン湖 갸링 후 Gyaring Lake Gyaring Co Lago Gyaring Джарин-Нур Zhalinghu Gyaring Hu Hồ Trát Lăng 扎陵湖 1159114475جیارینگ هو גיירינג Джарін-Ху گیرانگ ہو 扎陵湖 0Reservoir Toktogul Res. Toktogul Suu Saktagychy 4.7 6.0Toktogul Suu Saktagychy Toktogul Suu Saktagychy Q16508570 توجتوجول سو ساكاتجيتشي টকটোগুল সু সাক্তাগাইচি Toktogul Reservoir Toktogul Toktogul Toktogoul Τοκτογκούλ Σου Σακταγκούτσι टोकतोगुल सू सक्ताग्यच्य Toktogul Suu Saktagychy Toktogul Suu Saktagychy Toktogoul トクトグル貯水ダム 톡토굴 수 삭타기치 Toktogul Reservoir Zbiornik Toktogul Represa de Toktogul Токтогульское водохранилище Toktogul Suu Saktagychy Toktogul Suu Saktagychy Hồ Toktogul Suu Saktagychy 托克托古尔水库 1159125107توکتوگول سو ساکتاگیچی טוקטוגול סואו סאקטאגיצ'י Токтогул Суу Сактагичи ٹوکٹوگل سو ساکتاگیچی 托克托古水庫 0Lake Langa Co 4.7 6.0Langa Co Langa Co Q628327 لانجت كو রাক্ষসতাল Rakshastal Rakshastal 'nga Co Rakshastal Λίμνη Ρακσαστάλ राक्षस झील Raksasztal-tó Langa Co Rakshastal ラークシャスタール湖 랑가 코 Rakshastal La'nga Co Langa Ланга-Цо Lannga Co Rakshastal Hồ Lạp Ngang Thác 拉昂错 1159114537لانگا کو אגם לנגה Ракшастал لانگا کو 拉昂錯 0Lake Mapam Yumco 4.7 6.0Mapam Yumco Mapam Yumco Q233627 بحيرة ماناساروفار মানস সরোবর Manasarovar Manasarovar Mana Sarovar Manasarovar Μάπαμ Γιουμκό मानसरोवर Manaszarovar-tó Mansarovar Manasarovar マナサロワール湖 마나사로바 호수 Manasarovar Mapam Yumco Manasarovar Мапам-Юмцо Manasarovar Manasarovar Manasarovar 玛旁雍错 1159114553دریاچه ماناساروار מפוטו Манасаровар جھیل ماناساروار 瑪旁雍錯 0Reservoir Lake Volta 4.7 6.0L. Volta Lake Volta Q201679 بحيرة فولتا ভোল্টা হ্রদ Volta-Stausee Volta Volta Volta Λίμνη Βόλτα वोल्टा झील Volta-tó Volta Volta ヴォルタ湖 볼타호 Voltameer Wolta Volta Вольта Voltasjön Volta Volta 沃尔特水库 1159125149دریاچه ولتا אגם וולטה Вольта جھیل وولٹا 沃爾特水庫 0Lake South Aral Sea Southern Aral Sea|Large Aral Sea|Big Aral Sea admin-0 1.0 3.0S. Aral Sea South Aral Sea Q276776 بحر آرال الجنوبي দক্ষিণ আরাল সাগর Westlicher Aralsee South Aral Sea Mar de Aral Sur Grande Aral Θάλασσα Νότια Αράλ दक्षिण अरल सागर Dél-Aral-tenger Laut Aral Selatan Grande Aral 南アラル海 사우스 아랄 씨 South Aral Sea Południowa część Jeziora Aralskiego Mar de Aral do Sul Большое Аральское море Södra Aralsjön Güney Aral Biển Nam Aral 南咸海 1159126555دریای آرال جنوبی ים אראל הדרומי Південне Аральське море ساؤتھ ایرل سی 南鹹海 0Lake North Aral Sea Northern Aral Sea|Small Aral Sea admin-0 1.0 3.0N.Aral Sea North Aral Sea Q3358037 بحر آرال الشمالي নর্থ আরাল সি Nördlicher Aralsee North Aral Sea Mar de Aral Norte Petite mer d'Aral Βόρεια Λίμνη Αράλη उत्तरी अरल सागर Észak-Aral-tenger Laut Aral Utara Piccolo Aral 北アラル海 노스 아랄 씨 North Aral Sea Jezioro Północnoaralskie Mar de Aral do Norte Малое Аральское море Norra Aralsjön Kuzey Aral Biển Bắc Aral 北咸海 1729982865دریای آرال شمالی אגם ים ארל הצפוני Мале Аральське море نارتھ ایرال سی 北咸海 0Lake Barsakelmes Lake Tushchybas|Tsche-Bass Bay|Shche-bas Bay admin-0 5.0 6.5Barsakelmes L. Barsakelmes Lake Q28750379 بحيرة بارساكيلميس বারসাকেল্মেস লেক Barsakelmes-See Barsakelmes Barsakelmes Barsakelmes Lake Λίμνη Μπαρσακέλμες बार्सकेल्मेस झील Barsakelmes-tó Danau Barsakelmes Barsakelmes バルサケルムス湖 바르사켈메스 레이크 Barsakelmes Lake Jezioro Barsakelmes Lago Barsakelmes озеро Барсакелмс Barsakelmes-sjön Barsakelmes Hồ Barsakelmes 巴尔萨克梅斯湖 1729983019دریاچه بارساکلمس אגם ברסקלמס Барсакельмес بارساکیلمیس جھیل 巴薩克美斯湖 0Lake Lake Balkhash Balqash Köli 1.0 3.0L. Balkhash Lake Balkhash Q134485 بحيرة بالكاش লেক বালখাশ Balchaschsee Balkhash Baljash Balkhach Λίμνη Μπαλκάς बलख़श झील Balkas-tó Balkhash Balqaš バルハシ湖 발하시호 Balkasjmeer Bałchasz Balkhash Балхаш Balchasjsjön Balkaş Balkhash 巴尔喀什湖 1159113111دریاچه بالخاش ימת בלחש Балхаш جھیل بالخاش 巴爾喀什湖 0Lake Lake Tanganyika admin-0 1.0 3.0L. Tanganyika Lake Tanganyika Q5511 بحيرة تنجانيقا টাংগানিকা হ্রদ Tanganjikasee Tanganyika Tanganica Tanganyika Τανγκανίκα तांगान्यीका झील Tanganyika-tó Tanganyika Tanganica タンガニーカ湖 탕가니카호 Tanganyikameer Tanganika Tanganica Танганьика Tanganyikasjön Tanganika Tanganyika 坦干依喀湖 1159113185دریاچه تانگانیکا אגם טנגניקה Танганьїка جھیل ٹانگانیکا 坦干依喀湖 1Alkaline Lake Lagoa Mirim admin-0 1.7 3.6Lagoa Minim Lagoa Minim Q876280 بحيرة ميريم লাগোয়া মিরিম Merín Lagoa Mirim Merín Lagoa Mirim Λαγκόα Μιρίμ मिरिम लैगून Lagoa Mirim Laguna Mirim Lagoa Mirim メリン湖 미링호 Merínlagune Lagoa Mirim Lagoa Mirim Лагоа-Мирин Lagoa Mirim Lagoa Mirim Phá Mirim 密林湖 1159126619لاگوآ میریم לגונת מירים Мірим لاگوا میریم 密林湖 2Lake Lake Manitoba 2.0 3.7L. Manitoba Lake Manitoba Q645901 بحيرة مانيتوبا লেক মানিতোবা Manitobasee Manitoba Manitoba Manitoba Λίμνη Μανιτόμπα मैनिटोबा झील Manitoba-tó Manitoba Manitoba マニトバ湖 매니토바호 Manitobameer Manitoba Manitoba Манитоба Manitobasjön Manitoba Gölü Hồ Manitoba 缅尼托巴湖 1159106843دریاچه مانیتوبا אגם מניטובה Манітоба جھیل مانیٹوبا 曼尼托巴湖 1Lake Lake Winnipegosis 2.0 3.7L. Winnipegosis Lake Winnipegosis Q934638 بحيرة وينيبيغوسيس লেক উইন্নিপেগোসিস Winnipegosissee Winnipegosis Winnipegosis Winnipegosis Λίμνη Γουινιπεγκόσις विनीपेगोसिस झील Winnipegosis-tó Winnipegosis Winnipegosis ウィニペゴシス湖 레이크 위니페고시스 Winnipegosis Winnipegosis Winnipegosis Виннипегосис Winnipegosis Winnipegosis Gölü Hồ Winnipegosis 温尼伯戈西斯湖 1159106851دریاچه وینیپگوسیس אגם וויניפגוסיס Вінніпеґосіс جھیل ونیپیگوسس 溫尼伯戈西斯湖 2Reservoir Réservoir Manicouagan 2.0 3.7Rés. Manicouagan Rés. Manicouagan Q756106 خزان مانيكوجان ম্যানিকিউগান জলাধার Manicouagan-Stausee Manicouagan Manicouagan Manicouagan Ρεζερβουάρ Μανικουαγκάν रिज़र्वोयर मानिकोउआगान Manicouagan-víztározó Reservoir Manicouagan Manicouagan マニクアガン湖 레저보어 매니쿠아간 Manicouagan Manicouagan Manicouagan Маникуаган Manicouaganreservoaren Réservoir Manicouagan Hồ Manicouagan 曼尼古根陨石坑 1159123939آبگیر مانیکواگان מכתש מניקאגן Манікуаган ریززروائر مانیکوگان 曼尼古根隕石坑 2Alkaline Lake Syvash 2.0 3.7Syvash Syvash Q1130771 سيفاش সিভ্যাশ Sywasch Syvash Mar de Syvach Syvach Σιβάς सिवाशो Syvash Syvash Sivaš 腐海 시바시 Sivash Siwasz Sivash Сиваш Syvasj Sivaş Hồ Syvash 锡瓦什湖 1159126643سیواش אגם סיואש Сиваш سیواش 錫瓦什湖 2Lake Lake Saimaa 2.0 3.7L. Saimaa Lake Saimaa Q192770 سايما লেক সাইমা Saimaa Saimaa Saimaa Saimaa Σάιμαα साइमा झील Saimaa Saimaa Saimaa サイマー湖 사이마호 Saimaameer Saimaa Saimaa Сайма Saimen Saimaa Saimaa 塞马湖 1159113295دریاچه سایما סאימה Саїмаа سائی ما 塞馬湖 3Lake Lake Zaysan 3.0 4.0L. Zaysan Lake Zaysan Q216621 بحيرة زيسان লেক জেসান Saissansee Zaysan Zaysan Zaïssan Λίμνη Ζαϊσάν ज़ायसान झील Zaysan-tó Zaysan Zajsan ザイサン湖 자이산호 Zaysanmeer Zajsan Zaysan Зайсан Zajsan Zaysan Zaysan 斋桑泊 1159123091دریاچه زایسان אגם זייסאן Зайсан جھیل زیسان 齋桑泊 3Lake Churchill Lake 3.0 4.0Churchill L. Churchill Lake Q1089891 بحيرة تشرشل চার্চিল লেক Churchill Churchill Lago Churchill Churchill Λίμνη Τσόρτσιλ चर्चिल झील Churchill-tó Danau Churchill Churchill Lake チャーチル湖 처칠 레이크 Churchill Lake Jezioro Churchill Lago Churchill Черчилл Churchill Churchill Gölü Hồ Churchill 丘吉爾湖 1159106961دریاچه چرچیل אגם צ'רצ'יל озеро Черчилль چرچل جھیل 丘吉爾湖 3Lake Lago Buenos Aires 3.0 4.0Lago Buenos Aires Lago Buenos Aires Q503842 بحيرة كاريرا العامة লাগো Buenos Aires / General Carrera General Carrera/Buenos Aires Buenos Aires/General Carrera Buenos Aires/General Carrera Λάγκο Μπουένος Άιρες लागो ब्यूनस आयर्स General Carrera-tó Danau Buenos Aires Buenos Aires ヘネラル・カレーラ湖 헤네랄카레라호 General Carrera/Buenos Aires Buenos Aires/General Carrera Buenos Aires/General Carrera Буэнос-Айрес Buenos Aires Lago Buenos Aires Hồ Buenos Aires 布宜诺斯艾利斯湖 1159113323لاگو بوئنوس ایرز אגם חנרל קאררה Буенос-Айрес لاگو بیونوس ایئرس 布宜諾斯艾利斯湖 3Lake Päijänne 3.0 4.0Päijänne Päijänne Q213769 باياني পাইজান্নে Päijänne Päijänne Päijänne Päijänne Λίμνη Πάγιαννε पेजेन्ने Päijänne Päijänne Päijänne パイエンネ湖 파이옌느 Päijänne Päijänne Päijänne Пяййянне Päijänne Päijänne Hồ Päijänne 派延奈湖 1159113395دریاچه پایجانی אגם פאאיאנה Пяйянне پائیجانے 派延奈湖 3Lake Lake Srednye Kuyto 3.0 4.0L. Srednye Kuyto Lake Srednye Kuyto Q1894057 بحيرة سريدني كويتو লেক স্রেদন্যে কুইটো Sredneje Kuito Srednee Kuyto Lago Srednye Kuyto Lake Srednye Kuyto Λίμνη Σρέντνιγε Κουγτο श्रेडनी कुयतो झील Srednye Kuyto-tó Danau Srednye Kuyto Lake Srednye Kuyto スレドニ・カイト湖 레이크 스레드니예 쿠이토 Srednee Koeyto Sriednieje Kujto Lago Sredneye Kuyto Среднее Куйто Srednye Kuyto Srednye Kuyto Gölü Hồ Srednye Kuyto 中库伊托湖 1159113481دریاچه سردنی کویتو אגם סרדניה קויטו озеро Середнє Куіто جھیل سریڈائن کوئٹو 中庫伊托湖 4Reservoir Kakhovka Reservoir 4.0 5.0Kakhovka Res. Kakhovka Reservoir Q1540436 خزان كاخوفكا কাখোভকা রিজার্ভার Kachowkaer Stausee Kakhovka Kajovka Kakhovka Τεχνητή Λίμνη Κάκοβα कखोवका जलाशय Kakhovka-víztározó Reservoir Kakhovka Serbatoio di Kachovka カホフカ貯水池 카호브카 저수지 Kakhovka Zbiornik Kachowski Represa de Kakhovka Каховское водохранилище Kachovka-reservoaren Kakhovka Rezervuarı chứa nước Kakhovka 卡霍夫卡水库 1159124989مخزن سد کاخووکا מאגר קאחובקה Каховське водосховище کاکھوا ریزروائر 卡霍夫卡水庫 1Lake _untitled_23 4.0 5.0 1159107123 4Reservoir Samara Reservoir Kuybyshev Reservoir 4.0 5.0Samara Res. Samara Reservoir Q745937 خزان سمارة সামারা জলাধার Kuibyschewer Stausee Kuybyshev Kúibyshev Kouïbychev Τεχνητή Λίμνη Σαμαρά समारा जलाशय Kujbisevi-víztározó Reservoir Samara Samara クイビシェフ湖 사마라 레저보어 Koeybisjevskoe vodochranilisjtsje Zbiornik Kujbyszewski Represa de Samara Куйбышевское водохранилище Kujbysjevreservoaren Kuybışev Baraj Hồ Samara 古比雪夫水库 1159125013مخزن سد سامارا מאגר סמארה Куйбишевське водосховище سامارا ریزروائر 古比雪夫水庫 4Reservoir Lake Mead 4.0 5.0L. Mead Lake Mead Q654515 بحيرة ميد লেক মীড Mead Mead Mead Mead Λίμνη Μιντ मीड झील Mead-tó Mead Mead ミード湖 미드호 Mead Mead Mead Мид Mead Mead Gölü Hồ Mead 米德湖 1159123963دریاچه مید אגם מיד Мід جھیل میڈ 米德湖 4Reservoir Lake Powell 4.0 5.0L. Powell Lake Powell Q667507 بحيرة باول লেক পোয়েল Powell Powell Powell Powell Λίμνη Πάουελ पॉवेल झील Powell-tó Danau Powell Powell パウエル湖 파월호 Powellmeer Powell Lago Powell Пауэлл Lake Powell Powell Hồ Powell 鲍威尔湖 1159123979دریاچه پاول אגם פאוול озеро Поуел جھیل پاول 鲍威尔湖 1Lake Southern Indian Lake 4.0 5.0Southern Indian L. Southern Indian Lake Q1888211 البحيرة الهندية الجنوبية দক্ষিণ ভারতীয় হ্রদ Southern Indian Southern Indian Southern Indian Southern Indian Νότια Ινδική λίμνη दक्षिणी भारतीय झील Dél-Indiai-víztározó Southern Indian Lake Southern Indian Lake サザンインディアン湖 사우던 인디언 레이크 Southern Indian Lake Jezioro Indiańskie Południowe Lago Southern Indian Саутерн-Индиан-Лейк Southern Indian Güney Hint Gölü Hồ Southern Indian 南印第安湖 1159123651دریاچه ایندین جنوبی אגם הודו הדרומי Озеро Південної Індії ساؤدرن انڈین جھیل 南印第安湖 4Reservoir Represa de Sobradinho 4.0 5.0Represa de Sobradinho Represa de Sobradinho Q3234165 ريبريسا دي سوبرادينيو রিপ্রেসা ডি সোব্রাদিনহো Sobradinho-Stausee Sobradinho Sobradinho Sobradinho Ρεπρέσα ντε Σομπραντίνιο रेप्रेसा डी सोब्राडिन्हो Represa de Sobradinho Reservoir Sobradinho Sobradinho ソブラジーニョ湖 레프레사 데 소브라지뉴 Sobradinho Reservoir Zbiornik Sobradinho Sobradinho Собрадинью Sobradinho Represa de Sobradinho Hồ Sobradinho 索布拉迪紐水庫 1159125027رپرسا د سوبرادینهو סכר סובראדיניו Репреса-де-Собрадінго ریپریسا ڈی سوبراڈینو 索布拉迪紐水庫 5Lake Danau Toba 4.7 6.0Danau Toba Danau Toba Q183360 بحيرة توبا টোবা হ্রদ Tobasee Toba Toba Toba Λίμνη Τόμπα तोबा झील Toba-tó Toba Toba トバ湖 토바호 Tobameer Toba Toba Тоба Tobasjön Toba Siêu núi lửa Toba 多巴湖 1159114361دریاچه توبا אגם טובה Тоба ڈانو ٹوبا 多巴湖 1Lake _untitled_21 4.7 6.0 1159114511 5Lake Lake Pukaki 4.7 6.0L. Pukaki Lake Pukaki Q1347588 بحيرة بوكاكي লেক পুকাকি Pukaki Pukaki Lago Pukaki Pukaki Λίμνη Πουκάκι पुकाकि झील Pukaki-tó Pukaki Lake Pukaki プカキ湖 푸카키 호수 Pukaki Pukaki Lago Pukaki Пукаки Pukaki Pukaki Gölü Hồ Pukaki 普卡基湖 1159127169دریاچه پوکاکی אגם פוקאקי озеро Пукакі جھیل پوکاکی 普卡基湖 1Lake Lake Ohau 4.7 6.0L. Ohau Lake Ohau Q1349516 بحيرة أوهاو লেক ওহাউ Ohau Ōhau Ohau Lake Ohau Λίμνη Οχάου ओहाऊ झील Ohau-tó Danau Ohau Lake Ohau オハウ湖 오하우 호수 Ohaumeer Ohau Lago Ōhau Охау Ohau Ohau Gölü Hồ Ohau 奥豪湖 1159127131دریاچه اوهائو אגם אואו озеро Охау جھیل اوہاو 奧豪湖 5Lake Lake Abitibi 4.7 6.0L. Abitibi Lake Abitibi Q321534 بحيرة ابيتيبي লেক আবিতিবি Abitibisee Abitibi Abitibi Abitibi Λίμνη Αμπίτι एबिटिबि झील Abitibi-tó Danau Abitibi Abitibi アビティビ湖 레이크 아비티비 Abitibi Abitibi Abitibi Абитиби Abitibisjön Abitibi Gölü Hồ Abitibi 阿伯蒂比湖 1159123795دریاچه آبیتیبی אגם אביטיבי Абітібі جھیل آبیٹیبی 阿伯蒂比湖 1Reservoir Fort Peck Lake 4.7 6.0Ft. Peck L. Fort Peck Lake Q4492006 بحيرة فورت بيك ফোর্ট পেক লেক Fort Peck Fort Peck Lago Fort Peck Fort Peck Λίμνη Φορτ Πεκ फ़ोर्ट पेक झील Fort Peck-tó Danau Fort Peck Fort Peck Lake フォート・ペック湖 포트 펙 레이크 Fort Peck Lake Jezioro Fort Peck Lago Fort Peck Форт-Пек Fort Peck Lake Fort Peck Gölü Hồ Fort Peck 佩克堡湖 1159124029دریاچه فورت پک אגם פורט פק озеро Форт-Пек فورٹ پیک جھیل 派克堡湖 5Reservoir Lake Oahe 4.7 6.0L. Oahe Lake Oahe Q474408 بحيرة أوهي লেক ওহায়ে Oahe Oahe Lago Oahe Oahe Λίμνη Οάχε ओहे झील Oahe-tó Danau Oahe Oahe オアへ湖 레이크 오아헤 Oahe Lake Oahe Lago Oahe Оахе Oahe OaheGölü Hồ Oahe 欧河湖 1159124053دریاچه اواهه אגם אוהאה озеро Оахе جھیل اواہی 歐瓦賀湖 1Lake Teslin Lake 4.7 6.0Teslin L. Teslin Lake Q283793 بحيرة تسلين টেসলিন লেক Teslin Teslin Lago Teslin Teslin Λίμνη Τέσλιν टेस्लिन झील Teslin-tó Danau Teslin Teslin テスリン湖 테슬린 레이크 Teslin Lake Teslin Lake Teslin Теслин Teslin Teslin Gölü Hồ Teslin 特斯林湖 1159107319دریاچه تسلین אגם טסלין озеро Теслін تیسلن جھیل 特斯林湖 5Reservoir Lower Arrow Lake 4.7 6.0Lower Arrow L. Lower Arrow Lake Q280135 بحيرة السهم السفلي লোয়ার অ্যারো লেক Arrow Arrow Lakes Lagos Arrow lacs Arrow Λίμνη Λόουερ Άρροου लोअर एरो झील Lower Arrow-tó Danau Arrow Bawah Laghi Arrow アロー湖 로어 애로우 레이크 Arrow Lakes Arrow Lake Arrow озеро Лоуэр-Эрроу Lower Arrow Lake Lower Arrow Gölü Hồ Lower Arrow 下阿罗湖 1159124087دریاچه اروی پایینی אגם לואר רד озеро Лоуер-Ерроу ایرو جھیلیں 下箭湖 5Reservoir Lake Nasser 4.7 6.0L. Nasser Lake Nasser Q182796 بحيرة ناصر নাসের হ্রদ Nassersee Nasser Nasser Nasser Λίμνη Νάσερ नासेर झील Nasszer-tó Nasser Nasser ナセル湖 나세르호 Nassermeer Jezioro Nasera Nasser Насер Nassersjön Nasır Hồ Nasser 纳赛尔湖 1159125095دریاچه ناصر אגם נאצר Озеро Насера جھیل ناصر 納賽爾湖 1Lake _untitled_24 4.7 6.0 1159114413 5Lake Pyhäjärvi 4.7 6.0Pyhäjärvi Pyhäjärvi Q545559 بياهافي প্যহাজার্ভি Pyhäjärvi Pyhäjärvi Pyhä Pyhä Πουχαγάρβι पाइहाजर्विक Pyhäjärvi Pyhäjärvi Pyhäjärvi ピュハ湖 피하야르비 Pyhäjärvi Pyhäjärvi Pyhäjärvi озеро Нясиярви Pyhäjärvi Pyhäjärvi Hồ Pyhäjärvi 皮海湖 1159114429پیهاجاروی אגם פיהאיארוי Пюгяярві پیہاجاروی 皮海湖 5Reservoir Lake Volta 4.7 6.0L. Volta Lake Volta Q201679 بحيرة فولتا ভোল্টা হ্রদ Volta-Stausee Volta Volta Volta Λίμνη Βόλτα वोल्टा झील Volta-tó Volta Volta ヴォルタ湖 볼타호 Voltameer Wolta Volta Вольта Voltasjön Volta Volta 沃尔特水库 1159125149دریاچه ولتا אגם וולטה Вольта جھیل وولٹا 沃爾特水庫 1Reservoir Bratsk Reservoir Bratskoye Vdkhr. 5.0 6.5Bratsk Res. Bratsk Reservoir Q899803 خزان براتسك ব্র্যাতস্ক রিজার্ভার Bratsker Stausee Bratsk Bratsk Bratsk Τεχνητή λίμνη Μπρατσκ ब्राटस्क जलाशय Bratszki-víztározó Reservoir Bratsk Bratsk ブラーツクダム 브라츠크 레저보어 Stuwmeer van Bratsk Zbiornik Bracki Albufeira de Bratsk Братское водохранилище Bratsk-reservoaren Bratsk Rezervuarı Hồ Bratsk 布拉茨克水庫 1159125163مخزن سد براتسک מאגר בראטסק Братське водосховище براسک ریزروائر 布拉茨克水庫 6Lake Ozero Khantayskoye L. Khantayskoye 5.0 6.5O. Khantayskoye O. Khantayskoye Q233071 بحيرة خانتايسكوي ওজেরো খান্তায়স্কোয়ে Chantaisee Khantayskoye Khantai Khantaï Οζέρο Χανταϊσκόγιε ओज़ेरो खांटायस्कॉय Kantajszkoje-tó Danau Khantayskoye Chantajskoe ハンタイスコエ湖 오제로 칸타이스코예 Hantayskoe ozero Jezioro Chantajskie Lago Khantayskoye Хантайское озеро Ozero Chantajskoje Ozero Khantayskoye Hồ Khantayskoye 汉泰湖 1159115275اوزرو کهانتایسکویه אגם חנטייסקויה Хантайське озеро اوزیرو کھانٹےسکوئے 漢泰湖 6Lake Ozero Keta L. Keta 5.0 6.5O. Keta O. Keta Q1739872 بحيرة كيتا ওজেরো কেতা Ketasee Keta Lago Keta Keta Οζέρο Κέτα ओज़ेरो केटा Keta-tó Danau Keta Keta ケタ湖 오제로 케타 Keta Keta Lago Keta Кета Ozero Keta Ozero Keta Hồ Keta 克塔湖 1159115303اوزرو کتا אגם קטה озеро Кета اوزیرو کیٹا 克塔湖 6Lake Ozero Lama L. Lama 5.0 6.5O. Lama O. Lama Q1460034 بحيرة لاما ওজেরো লামা Lamasee Lama Lama Lama Οζέρο Λάμα ओज़ेरो लामा Lama-tó Danau Lama Lama ラマ湖 오제로 라마 Lama Łama Lago Lama Лама Ozero Lama Ozero Lama Hồ Lama 拉马湖 1159115317اوزرو لاما אגם לאמה Лама اوزیرو لاما 拉馬湖 6Lake Uddjaure 5.0 6.5Uddjaure Uddjaure Q953206 أودجايور উদ্দৌরে Uddjaure Uddjaure Uddjaure Uddjaure Ουντγιάουρε उद्जौरे Uddjaure Uddjaure Uddjaure ウッド湖 웃자우레 Uddjaure Uddjaure Uddjaur озеро Уддьяуре Uddjaure Uddjaure Hồ Uddjaure 乌德湖 1159115361اوداجوره אגם אודיאור Удд'яур اودا جورے 烏德湖 6Lake Storavan 5.0 6.5Stornavan Stornavan Q204987 ستورافان স্টোরাভান Storavan Storavan Lago Storavan Storavan Στόραβαν स्टोरवन Storavan Storavan Storavan ストゥーラバ湖 스토라반 Storavan Jezioro Storavan Storavan озеро Стораван Storavan Storavan Hồ Storavan 斯托拉文湖 1159115335استوراوان אגם סטורובאן Стураван اسٹوراوین 大亞萬湖 1Lake _untitled_52 5.0 6.5 1159115381 1Lake _untitled_51 5.0 6.5 1159115407 6Lake Lake Habbaniyah 5.0 6.5L. Habbaniyah Lake Habbaniyah Q2539972 بحيرة الحبانية লেক হাববানিয়াহ Al-Habbaniyya Habbaniyah Habbaniyah Habbaniya Λίμνη Χαμπανίγια हब्बानियाह झील Habbaniyah-tó Danau Habbaniyah Habbaniyya ハバニヤー湖 레이크 하바니야 Habbaniyah Jezioro al-Habbaniyya Lago Habbaniyah Эль-Хаббания Habbaniyyasjön Habbaniye Hồ Habbaniyah 哈巴尼亚湖 1159123107دریاچه حبانیه אגם חבאנייה озеро Хаббанія جھیل ہیبانیاہ 哈巴尼亞湖 6Lake Lake Skadar Lake Scutari admin-0 5.0 6.5L. Skadar Lake Skadar Q203811 بحيرة سكيوتاري লেক স্কাদার Skutarisee Skadar Skadar Skadar Λίμνη Σκόδρας स्काडार झील Shkodrai-tó Skadar Scutari シュコダル湖 슈코더르호 Meer van Shkodër Jezioro Szkoderskie Escútare Шкодер Shkodrasjön İşkodra Hồ Skadar 斯库台湖 1159115429دریاچه اشکودرا אגם שקודרה Скадарське озеро جھیل اسکادار 斯庫台湖 6Lake Aylmer Lake 5.0 6.5Aylmer L. Aylmer Lake Q793085 بحيرة آيلمر আইলমার লেক Aylmer Aylmer Lago Aylmer Aylmer Λίμνη Αϊλμέρ आयल्मर झील Aylmer-tó Danau Aylmer Lago Aylmer エールマー湖 아일머 레이크 Aylmer Jezioro Aylmer Aylmer Эйлмер Aylmer Aylmer Gölü Hồ Aylmer 艾爾默湖 1159107937دریاچه آیلمر אגם איילמר озеро Ейльмер ایلمیر جھیل 艾爾默湖 6Lake Clinton-Colden Lake 5.0 6.5Clinton-Colden L. Clinton-Colden Lake Q1101640 بحيرة كلينتون-كولدين ক্লিন্টন-কোল্ডেন লেক Clinton-Colden Clinton-Colden Lago Clinton-Colden Clinton-Colden Λίμνη Κλίντον - Κόλντεν क्लिंटन-कोल्डन झील Clinton-Colden-tó Danau Clinton-Colden Clinton-Colden Lake クリントン=コールデン湖 클린턴-콜든 레이크 Clinton-Colden Jezioro Clinton-Colden Lago Clinton-Colden Клинтон-Колден Clinton-Colden Clinton-Colden Gölü Hồ Clinton-Colden 克林頓科爾登湖 1159107951دریاچه کلینتون- کلدن אגם קלינטון-קולדן Клінтон-Колден کلنٹن کولڈن جھیل 克林頓科爾登湖 6Reservoir Lake Francis Case 5.0 6.5L. Francis Case Lake Francis Case Q6475894 بحيرة فرانسيس كيز লেক ফ্রান্সিস কাসা Lake Francis Case Francis Case Lago Francis Case Francis Case Λίμνη Φράνσις Κέις फ्रांसिस केस झील Francis Case-tó Danau Francis Case Lake Francis Case フランシス・ケース湖 레이크 프랜시스 케이스 Lake Francis Case Lake Francis Case Lago Francis Case озеро Франсис-Кейс Lake Francis Case Francis Case Gölü Hồ Francis Case 弗朗西斯卡塞湖 1159124183دریاچه فرانسیس کیس אגם פרנסיס קייס озеро Френсіс-Кейс جھیل فرانسس کیس 法蘭西斯凱斯湖 1Reservoir Falcon Lake 5.0 6.5Falcon Lake Falcon Lake Q4967120 بحيرة فالكون ফ্যালকন লেক Falcon Lake Falcon International Falcón Falcon International Λίμνη Φάλκον फ़ाल्कन झील Falcon-tó Danau Falcon Lago Falcon ファルコン湖 팔콘 레이크 Falcon Lake Jezioro Falcon Lago Falcon водохранилище Фалкон-Лейк Falcon Lake Falcon Gölü Hồ Falcon 猎鹰湖 1159124201دریاچه فالکون אגם פלקון озеро Фалькон فیلکن جھیل 法爾康湖 6Lake Lac Île-à-la-Crosse 5.0 6.5L. Île-á-la-Crosse Lac Île-á-la-Crosse Q6468085 بحيرة إيل-آ-لا-كروس ল্যাক ইলে-আ-লা-ক্রসে Île-à-la-Crosse Île-à-la-Crosse Lago Île-à-la-Crosse Île-à-la-Crosse Λακ Ιλ-α-λα-Κρος लैक इले-ए-ला-क्रोस Lac Île-à-la-Crosse Lac Île-à-la-Crosse Lac Île-à-la-Crosse イルアラクロス湖 라크 일라크로스 Lac Île-à-la-Crosse Lac Île-à-la-Crosse Lago Île-à-la-Crosse озеро Лак-Иль-а-ля-Кросс Île-à-la-Crosse Lac Île-à-la-Crosse Hồ Lac Île-à-la-Crosse 勒拉克罗斯湖 1159107967دریاچه ایله لا کروسه אי-א-לה-קרוס Іль-а-ля-Кросс لاک آئی ا لا کراسے 伊克羅斯湖 6Lake Wholdaia Lake 5.0 6.5Wholdaia L. Wholdaia Lake Q1606564 بحيرة ولدايا হোল্ডাইয়া লেক Wholdaia Wholdaia Wholdaia Lake Wholdaia Λίμνη Γουολντάια वोल्डिया झील Wholdaia-tó Danau Wholdaia Wholdaia Lake ウォルダイア湖 월다이아 레이크 Wholdaia Wholdaia Lake Lago Wholdaia Уолдайа Wholdaia Wholdaia Gölü Hồ Wholdaia 霍爾達亞湖 1159107971دریاچه وولدائیا אגם וולדאיה озеро Волдайа ہولدایا جھیل 霍爾達亞湖 6Lake Tehek Lake 5.0 6.5Tehek L. Tehek Lake Q1328351 بحيرة تيهيك তেহেক লেক Tehek Tehek Lago Tehek Lac Tehek Λίμνη Τεχέκ तहक झील Tehek-tó Danau Tehek Tehek Lake テヘク湖 테헥 레이크 Tehek Lake Jezioro Tehek Lago Tehek Техек Tehek Tehek Gölü Hồ Tehek 蒂希克湖 1159107987دریاچه تِهِک אגם טהק Техек تیہیک جھیل 蒂希克湖 6Reservoir Réservoir de Caniapiscau 5.0 6.5Rés. de Caniapiscau Rés. de Caniapiscau Q1033302 خزان كانيابيسكو রিজার্ভার ডি ক্যানিয়াপিসকাউ Caniapiscau-Stausee Caniapiscau Caniapiscau Caniapiscau Ρεζερβουάρ ντε Κανιαπισκάου रिज़र्वोयर डे कैनीपिस्कौ Caniapiscau-víztározó Reservoir Caniapiscau Caniapiscau レゼルヴォワール・ド・カニアピスコー 레저보어 드 카니아피스카우 Caniapiscau Zbiornik Caniapiscau Caniapiscau Каниаписко Kaniapiskausjön Réservoir de Caniapiscau Hồ Caniapiscau 卡尼亞皮斯科水庫 1159124219مخزن سد کانیاپیسکائو מאגר קניאפיסקאו Каніапіско ریزروائر ڈی کینیاپسکاؤ 卡尼亞皮斯科水庫 1Reservoir _untitled_50 5.0 6.5 Q6474964 بحيرة بيرمين ল্যাক বারমেন Bermen Bermen Lago Bermen Bermen Λακ Μπερμπέν लैक बर्मन Lac Bermen Reservoir Bermen Lac Bermen ベルメン湖 락 베르멘 Lac Bermen Jezioro Bermen Lago Bermen водохранилище Лак-Бермен Bermen Lac Bermen Hồ Bermen 伯曼湖 1159124231دریاچه برمن מאגר בֶּרְמֶן Бермен لاک برمین 貝門湖 1Reservoir _untitled_49 5.0 6.5 Q1033302 خزان كانيابيسكو রিজার্ভার ডি ক্যানিয়াপিসকাউ Caniapiscau-Stausee Caniapiscau Caniapiscau Caniapiscau Ρεζερβουάρ ντε Κανιαπισκάου रिज़र्वोयर डे कैनीपिस्कौ Caniapiscau-víztározó Reservoir Caniapiscau Caniapiscau レゼルヴォワール・ド・カニアピスコー 레저보어 드 카니아피스카우 Caniapiscau Zbiornik Caniapiscau Caniapiscau Каниаписко Kaniapiskausjön Réservoir de Caniapiscau Hồ Caniapiscau 卡尼亞皮斯科水庫 1159124249مخزن سد کانیاپیسکائو מאגר קניאפיסקאו Каніапіско ریزروائر ڈی کینیاپسکاؤ 卡尼亞皮斯科水庫 6Reservoir Kentucky Lake 5.0 6.5Kentucky L. Kentucky Lake Q2781219 بحيرة كنتاكي কেন্টাকি লেক Kentucky Lake Kentucky Lago Kentucky Kentucky Λίμνη Κεντάκι केंटकी झील Kentucky-tó Danau Kentucky Kentucky Lake ケンタッキー湖 켄터키 레이크 Kentucky Jezioro Kentucky Lago Kentucky озеро Кентукки Kentucky Lake Kentucky Gölü Hồ Kentucky 肯塔基湖 1159124267دریاچه کنتاکی אגם קנטקי озеро Кентукі کینٹکی جھیل 肯塔基湖 6Reservoir J. Strom Thurmond Lake Clarks Hill Lake 5.0 6.5J. Strom Thurmond L. J. Strom Thurmond Lake Q6477865 بحيرة ستروم ثورموند জে. স্টর্ম থুরমাউন্ড লেক J. Strom Thurmond Lake Strom Thurmond Lago J. Strom Thurmond Clarks Hill Lake Λίμνη Τζ. Στρομ Θέρμοντ जे. स्ट्रॉम थरमंड झील J. Strom Thurmond-tó Danau J. Strom Thurmond J. Strom Thurmond Lake クラークスヒル湖 J. 스트롬 서먼드 레이크 J. Strom Thurmond Lake J. Strom Thurmond Lago J. Strom Thurmond озеро Хилл-Лейк J. Strom Thurmond Lake J. Strom Thurmond Gölü Hồ J. Strom Thurmond 杰斯特罗姆瑟蒙德湖 1159124279دریاچه استورم ترموند אגם ג'ורם ת'רמונד озеро Стром-Турмонд J. اسٹروم تھرمونڈ جھیل 史錯瑟蒙德湖 6Reservoir Kinbasket Lake 5.0 6.5Kinbasket L. Kinbasket Lake Q317407 بحيرة كينباسكيت কিনবাস্কেট লেক Kinbasket-See Kinbasket Lago Kinbasket Kinbasket Λίμνη Κινμπάσκετ किनबास्केट झील Kinbasket-tó Danau Kinbasket Kinbasket キンバスケット湖 킨바스켓 레이크 Kinbasketmeer Kinbasket Lake Kinbasket Кинбаскет Kinbasket Kinbasket Gölü Hồ Kinbasket 金篮湖 1159124293دریاچه کینبسکت אגם קינבאסקט озеро Кінбаскет کنباسکٹ جھیل 金巴期奇湖 6Lake Lake George 5.0 6.5L. George Lake George Q1800933 بحيرة جورج লেক জর্জ George George Lago George George Λίμνη Τζόρτζ जॉर्ज झील George-tó Danau George Lake George ジョージ湖 레이크 조지 Lake George Lake George Lago George озеро Джорж Lake George George Gölü Hồ George 乔治湖 1159108003دریاچه جورج אגם ג'ורג' озеро Жорж جھیل جارج 喬治湖 6Lake Lake Havasu 5.0 6.5L. Havasu Lake Havasu Q451522 بحيرة هافاسو লেক হাভাসু Havasu Havasu Lago Havasu Havasu Λίμνη Χαβασού हवासु झील Havasu-tó Danau Havasu Havasu ハヴァス湖 하바수 호 Havasu Jezioro Havasu Havasu озеро Хавасу Lake Havasu Havasu Gölü Hồ Havasu 哈瓦苏湖 1159108013دریاچه هاواسو אגם האוואסו озеро Хавасу جھیل ہواسو 哈瓦蘇湖 1Reservoir Shasta Lake 5.0 6.5Shasta L. Shasta Lake Q14683954 شاستا لاكي শাষ্টা লেক Shasta-Talsperre Shasta Shasta Shasta Λίμνη Σάστα शास्ता झील Shasta-tó Danau Shasta Shasta シャスタ湖 샤스타 레이크 Shasta Jezioro Shasta Lago Shasta Шаста Shasta Lake Shasta Gölü Hồ Shasta 沙斯塔湖 1159124305دریاچه شاستا אגם שאסטה озеро Шаста شاستہ جھیل 沙斯塔湖 6Lake Point Lake 5.0 6.5Point L. Point Lake Q1233362 بحيرة بوينت পয়েন্ট লেক Point Point Point Lake Point Πόιντ Λέικ पॉइंट लेक Point-tó Danau Point Point Lake ポイント湖 포인트 레이크 Point Lake Point Lake Lago Point Пойнт Point Point Gölü Hồ Point 波因特湖 1159108035پوینت لیک אגם פוינט Поінт-Лейк پوائنٹ جھیل 波因特湖 6Lake Upper Klamath Lake 5.0 6.5Upper Klamath L. Upper Klamath Lake Q1972978 بحيرة كلاماث العليا আপার ক্লামাথ লেক Upper Klamath Upper Klamath Upper Klamath Klamath supérieur Λίμνη Άπερ Κλαμάθ अपर कलामथ झील Upper Klamath-tó Danau Klamath Atas Upper Klamath アッパークラマス湖 어퍼 클래머스 레이크 Upper Klamath Upper Klamath Lake Lago Upper Klamath Аппер-Кламат Upper Klamath Lake Upper Klamath Gölü Hồ Upper Klamath 上克拉瑪斯湖 1159108051دریاچه کلامات بالایی אגם קלמת העליון Аппер-Кламат-Лейк اپر کلاماتھ جھیل 上克拉瑪斯湖 6Alkaline Lake Harney Lake 5.0 6.5Harney L. Harney Lake Q5659764 بحيرة هارني হার্নি লেক Harney Lake Harney Lago Harney Harney Λίμνη Χάρνεϊ हर्नी झील Harney-tó Danau Harney Harney Lake ハーニー湖 하니 레이크 Harney Lake Jezioro Harney Lago Harney озеро Харни Harney Lake Harney Gölü Hồ Harney 哈尼湖 1159126529دریاچه هارنی אגם הארני озеро Харні ہارنے جھیل 哈尼湖 6Lake Chiputneticook Lakes admin-0 5.0 6.5Chiputneticook Lks. Chiputneticook Lakes Q3215856 بحيرات شيبوتنيتيكوك চিপুতনেতিকুক লেকস Chiputneticook Lakes Chiputneticook Lakes Lagos Chiputneticook lacs Chiputneticook Λίμνες Τσιπουτνέτικουκ चिपुटनेटिकूक झीलें Chiputneticook-tavak Chiputneticook Lakes Laghi Chiputneticook チプトネティクック湖 치푸트네티쿡 레이크스 Chiputneticook Lakes Jeziora Chiputneticook Lagos Chiputneticook озера Чипутнетикук Chiputneticook Lakes Chiputneticook Gölleri Quần thể hồ Chiputneticook 希珀特内蒂库克湖群 1159108063دریاچه های چیپوتنتیکوک אגמי צ'יפוטנטיקוק озера Чипутнетікук چیپوٹنیٹیکوک جھیل 奇普特尼庫克湖 6Reservoir Represa de Tucuruí 5.0 6.5Represa de Tucurí Represa de Tucurí Q3215567 ريبريسا دي توكوروي রেপ্রেসা ডি টুকুরুই Tucuruí-Stausee Tucuruí Dam Presa de Tucuruí Tucuruí Ρεπρέσα ντε Τουκουρουί रेप्रेसा डी तुकुरुइ Represa de Tucuruí Reservoir Tucurui Diga di Tucuruí レプレーザ・デ・トゥクルイー 레프레사 데 투쿠루이 Tucuruí Dam Zbiornik Tucuruí Represa de Tucuruí водохранилище Репреза-ди-Тукуруи Represa de Tucuruí Represa de Tucuruí Hồ Tucuruí 图库里水库 1159125177رپرسا دو توکوروئی סכר טוקורו Репреса-де-Тукуруй ریپریسا ڈی ٹوکوروئی 圖庫魯伊水庫 6Reservoir Represa Três Marias 5.0 6.5Três Marias Res. Três Marias Reservoir Q1457581 ريبريسا تريس مارياس রেপ্রেসা ট্রাস মারিয়াস Três-Marias-Talsperre Três Marias Dam Presa de Três Marias Barrage de Três Marias Ρεπρέσα Τρες Μαρίας रेप्रेसा ट्रस मारियास Represa Três Marias Reservoir Três Marias Represa Três Marias レプレーザ・トレッス・マリアス 레프레사 트레스 마리아스 Três Marias Dam Zbiornik Três Marias Três Marias Трес-Мариас Represa Três Marias Represa Três Marias Hồ Três Marias 三瑪麗亞鎮壩 1159125193رپرسا ترس ماریاس סכר טרס מאריאס ГЕС Трес-Мар'яс ریپریسا ٹریس ماریاس 三瑪麗亞鎮壩 1Reservoir _untitled_48 5.0 6.5 ريبريسا دي جوبيا রেপ্রেসা ডি জুপিয়া Jupiá-Stausee Engineer Souza Dias Dam Presa de Jupiá Barrage de Jupiá Ρεπρέσα ντε Χούπια रेप्रेसा डी जुपिया Repressa de Jupia Reservoir Jupia Repressa de Jupia レプレーザ・デ・ジュピア 레프레사 데 주피아 Jupiádam Zbiornik Jupia Represa de Jupiá водохранилище Репреза-ди-Жупия Repressa de Jupia Repressa de Jupia Hồ Jupia 朱皮亚水库 1159125243رپرسا د جوپیا סכר יופיה Репреса-де-Джупіа ریپریسا ڈی جوپیا 朱皮亞水庫 1Lake _untitled_47 5.0 6.5 1159115447 6Lake Lago Colhué Huapí 5.0 6.5Lago Colhué Huapi Lago Colhué Huapi Q21842912 جزيرة كولهوابي লাগো কোহুয়ে হুপাই Lago Colhué Huapí Colhué Huapí Lago Colhué Huapí Lac Colhué Huapi Λάγκο Κολχού Χουαπί लागो कोल्हुए हुआपी Lago Colhué Huapí Danau Colhue Huapi Lago Colhué Huapí コルウエ・ウアピ湖 라고 콜후에 우아피 Lago Colhué Huapí Lago Colhué Huapí Lago Colhué Huapí озеро Колуэ-Уапи Colhué Huapí Lago Colhué Huapí Hồ Colhué Huapí 科尔胡瓦普湖 1159115469لاگو کولهویی هوآپی קולהו הואפי Кольує-Уапі لاگو کولہوئی ہواپی 科維瓦皮湖 1Lake _untitled_46 5.0 6.5 1159115487 1Lake _untitled_45 5.0 6.5 1159115515 1Lake _untitled_44 5.0 6.5 1159115537 1Lake _untitled_43 5.0 6.5 1159115563 1Lake _untitled_42 5.0 6.5 بحيرة إيماندرا লেক ইমান্দ্রা Imandra Imandra Imandra Imandra Λίμνη Ιμάντρα इमंद्रा झील Imandra-tó Danau Imandra Imandra イマンドラ湖 이만트라호 Imandrameer Imandra Lago Imandra Имандра Imandra İmandra Hồ Imandra 伊曼德拉湖 1159123217دریاچه ایماندرا אגם אימנדרה Імандра جھیل اماندرا 伊曼德拉湖 1Lake _untitled_41 5.0 6.5 1159115575 6Reservoir Shardara Bögeni Shardara Res. 5.0 6.5Shardara Bögeni Shardara Bögeni Q2474777 شاردارا بجيني শারদারা বেগেনি Schardara-Talsperre Chardara Reservoir Embalse de Shardara Shardara Bgeni Σαρντάρα Μπγκενί शारदरा बगेनिक Shardara Bgeni Shardara Bgeni Shardara シャルダラ貯水池 샤다라 브게니 Shardara Reservoir Zbiornik Szardarski Reserva de Shardara Чардаринское водохранилище Shardara Bgeni Shardara Bgeni Hồ Shardara Bgeni 沙达拉布格尼水库 1159125247شاردارا بگنی שרדארה בְגֶני Шардаринське водосховище شاردارا بگینی 沙達拉水庫 6Reservoir Vilyuy Reservoir Vilyuyskoye Res. 5.0 6.5Vilyuy Res. Vilyuy Res. Q2065167 خزان فيليوي ভিলিউ জলাধার Wiljui-Stausee Vilyuy Viliui Barrage de Viliouï Τεχνητή Λίμνη Βιλγιι विलुय जलाशय Vilyuy-víztározó Reservoir Vilyuy del Viljuj ヴィリュイ貯水池 빌류이 레저보어 Viljoej-stuwmeer Wilujski Zbiornik Wodny Represa de Vilyuy Вилюйское водохранилище Viljujreservoaren Vilyuy Rezervuarı Hồ Vilyuy 维尔尤伊水库 1159125251مخزن سد ویلیوی מאגר וילְיוּי Вілюйське водосховище ولیوئے ریزروائر 維留伊水庫 1Lake _untitled_40 5.0 6.5 1159115599 6Lake Ozero Krasnoye L. Krasnoye 5.0 6.5O. Krasnoye O. Krasnoye Q1786723 بحيرة كراسنوي ওজেরো ক্রাসনোয়ে Krasnoje Krasnoye Lago Krasnoye Ozero Krasnoye Οζέρο Κρασνόγιε ओज़ेरो क्रास्नोय Krasznoje-tó Danau Krasnoye Krasnoe クラスノエ湖 오제로 크라스노예 Krasnoe Jezioro Czerwone Lago Krasnoye Красное Ozero Krasnoje Ozero Krasnoye Hồ Krasnoye 克拉斯諾耶湖 1159115617اوزرو کراسنویه אגם קראסנויה Червоне اوزیرو کراسنوئے 克拉斯諾耶湖 6Lake Biwa Ko 5.0 6.5Biwa Ko Biwa Ko Q200239 بحيرة بيوا বিওয়া কো Biwa Biwa Biwa Biwa Λίμνη Μπίβα बिवा झील Biva-tó Biwa Biwa 琵琶湖 비와호 Biwameer Biwa Biwa Бива Biwasjön Biwa Biwa 琵琶湖 1159115641دریاچه بیوا אגם ביווה Озеро Біва بیوا کو 琵琶湖 6Lake Aishihik Lake 5.0 6.5Aishik Lake Aishik Lake Q3214697 بحيرة أيشيهيك আইশিহিক লেক Aishihik Aishihik Lago Aishihik Aishihik Λίμνη Αίσιχικ ऐशिहिक झील Aishihik-tó Danau Aishihik Aishihik アイシヒンク湖 아이시히크 레이크 Aishihik Lake Jezioro Aishihik Lago Aishihik Эйшихик Aishihik Aishihik Gölü Hồ Aishihik 艾希克湖 1159108077دریاچه آیشیهیک אגם איישיחיק озеро Айшихік ایشیہک جھیل 艾西希克湖 1Lake _untitled_39 5.0 6.5 1159108091 1Lake _untitled_38 5.0 6.5 1159108105 6Lake Lake Clark 5.0 6.5L. Clark Lake Clark Q1476428 بحيرة كلارك লেক ক্লার্ক Clark Clark Lago Clark Clark Λίμνη Κλαρκ क्लार्क झील Clark-tó Danau Clark Lake Clark クラーク湖 레이크 클락 Clark Lake Clark Lago Clark Кларк Lake Clark Clark Hồ Clark 克拉克湖 1159108117دریاچه کلارک אגם קלארק озеро Кларк جھیل کلارک 克拉克湖 1Lake _untitled_37 5.0 6.5 1159108131 1Lake _untitled_36 5.0 6.5 1159108145 1Lake _untitled_35 5.0 6.5 1159108157 1Lake _untitled_34 5.0 6.5 1159108171 1Lake _untitled_33 5.0 6.5 1159108183 1Reservoir Wheeler Lake 5.0 6.5Wheeler L. Wheeler Lake Q3561541 بحيرة ويلر হুইলার লেক Wheeler Lake Wheeler Wheeler Wheeler Λίμνη Γουίλερ व्हीलर झील Wheeler-tó Danau Wheeler Wheeler ウィーラー湖 휠러 레이크 Wheeler Lake Wheeler Lake Lago Wheeler озеро Уилер Wheeler Lake Wheeler Gölü Hồ Wheeler 韋勒湖 1159124317دریاچه ویلر אגם ווילר озеро Уіллер وہیلر لیک 韋勒湖 6Lake Üüreg Nuur 5.0 6.5Üüreg Nuur Üüreg Nuur Q978800 بحيرة ريج রেগ নুর Reg Nuur Üüreg Üüreg Üüreg Ρεγκ Νουρ रेग नुउर Reg Nuur Reg Nuur Ùùrėg nuur ウウレグ・ヌール 레그 누르 Üüreg Üüreg nuur Lago Reg Уурэг-Нуур Reg Nuur Üüreg Uureg 烏雷格湖 1159115657رگ نور אגם רג Урег-нур ریگ نور 烏雷格湖 1Lake _untitled_32 5.0 6.5 1159115681 1Lake _untitled_31 5.0 6.5 1159115701 1Lake _untitled_30 5.0 6.5 1159115721 1Lake _untitled_29 5.0 6.5 1159115741 1Lake _untitled_28 5.0 6.5 1159115757 6Lake Banggong Co 5.0 6.5Banggong Co Banggong Co Q1032254 بحيرة بانغونق প্যাঙ্গং হ্রদ Pangong Tso Pangong Tso Pangong Tso Pangong Μπανγκόγκ Κο पांगोंग त्सो Banggong-tó Pangong Tso Pangong Tso パンゴン湖 방공 코 Pangong Banggong Co Pangong Tso Пангонг-Цо Pangongsjön Pangong Pangong Tso 班公错 1159115773بنگونگ کو אגם באנגונג Пангонг-Цо بینگونگ کو 班公錯 6Alkaline Lake Tengiz Köli 5.0 6.5Tengiz Köli Tengiz Köli Q931708 حيرة تنجيز টেঙ্গিজ কেলি Tengizsee Tengiz Tengiz Tengiz Τενγκίζ Κάλι तेंगिज़ कोलि Tengiz-tó Tengiz Tengiz テンギス湖 텡기즈 콜리 Tengizmeer Tengyz Lago Tengiz Тенгиз Tengiz Köli Tengiz Hồ Tengiz Köli 田吉茲湖 1159126917دریاچه تنگیز אגם טנגיז Тенгіз تینگیز کولی 田吉茲湖 6Alkaline Lake Qusmuryn Köli 5.0 6.5Qusmuryn Köli Qusmuryn Köli Q2454806 كوسمورين كولي ক্যুসমুর‍্যান কোলি Qusmuryn Köli Kushmurun Qusmuryn Koli Qusmuryn Koli Κουσμουρίνκ Κόλι कुस्मुरिन कोलि Kušmurun Qusmuryn Koli Qusmuryn Köli クスムリュン・コリ 쿠스무린 콜리 Lake Ubogan Kusmuryn Lago Qusmuryn Кушмурун Ozero Kushmurun Qusmuryn Köli Hồ Ubogan 库斯马林湖 1159126933کوسمورین کولی אגם קוסמורין Кусмирін Колі قسمورین کولی 庫斯穆林湖 6Lake Femunden 5.0 6.5Femunden Femunden Q1324437 فيموندين ফেমুন্ডেন Femundsee Femund Femund Femunden Φεμούντεν फ़ेमुंडेन Femunden Femunden Femund フェームンデン湖 페문호 Femund Femunden Femund Фемунн Femunden Femund Hồ Femunden 费蒙登湖 1159115801فموندن פמונד Фемунн فیمنڈن 費蒙登湖 6Lake Femunden 5.0 6.5Femunden Femunden Q1324437 فيموندين ফেমুন্ডেন Femundsee Femund Femund Femunden Φεμούντεν फ़ेमुंडेन Femunden Femunden Femund フェームンデン湖 페문호 Femund Femunden Femund Фемунн Femunden Femund Hồ Femunden 费蒙登湖 1159115821فموندن פמונד Фемунн فیمنڈن 費蒙登湖 1Lake _untitled_27 5.0 6.5 1159108199 1Lake _untitled_26 5.0 6.5 1159108211 1Lake _untitled_25 5.0 6.5 1159108225 1Lake _untitled_24 5.0 6.5 1159108237 1Lake _untitled_23 5.0 6.5 1159108251 1Lake _untitled_22 5.0 6.5 Q1330203 خزان دوزوا দোজোইস রিজার্ভার Dozois Dozois Dozois Dozois Τεχνητή λίμνη Ντοζουά डोज़ोइस जलाशय Dozois-víztározó Reservoir Dozois Dozois ドゾア湖 도조아 레저보어 Dozois Zbiornik Dozois Represa Dozois водохранилище Дозуа Dozois Dozois Rezervuarı Hồ Dozois 多祖瓦水库 1159123805مخزن سد دوزویس מאגר דוזואה водосховище Дозуа ڈوزوئس ریزروائر 多祖瓦水庫 1Lake _untitled_21 5.0 6.5 1159108267 1Lake _untitled_20 5.0 6.5 1159108279 1Lake _untitled_19 5.0 6.5 1159108291 1Lake _untitled_18 5.0 6.5 1159108305 1Lake _untitled_17 5.0 6.5 1159108319 1Lake _untitled_16 5.0 6.5 1159108339 1Lake _untitled_15 5.0 6.5 1159108347 1Lake _untitled_14 5.0 6.5 1159108359 1Lake _untitled_13 5.0 6.5 1159108369 1Lake _untitled_12 5.0 6.5 1159108391 1Lake _untitled_11 5.0 6.5 1159108399 1Lake _untitled_10 5.0 6.5 1159108417 1Lake _untitled_9 5.0 6.5 1159108429 1Lake _untitled_8 5.0 6.5 1159108445 1Lake _untitled_7 5.0 6.5 1159108453 1Lake _untitled_6 5.0 6.5 1159108469 1Lake _untitled_5 5.0 6.5 1159108483 1Lake _untitled_4 5.0 6.5 1159108493 1Lake _untitled_3 5.0 6.5 1159108505 1Lake _untitled_2 5.0 6.5 1159108519 1Lake _untitled_1 5.0 6.5 1159108539 1Lake _untitled_0 5.0 6.5 1159108549 3Alkaline Lake Lake Disappointment 5.7 6.7L. Disappointment Lake Disappointment Q1638191 بحيرة ديسابوينتمينت লেক ডিসঅ্যাপয়েন্টমেন্ট Kumpupintil Kumpupintil Disappointment Disappointment Λίμνη Ντισαπόιντμεντ डिसअपोइन्टमेंट झील Kumpupintil-tó Kekecewaan Lake Disappointment ディサポイントメント湖 디서포인트먼트호 Disappointment Jezioro Disappointment Lago Kumpupintil Дисаппойнтмент Disappointment Disappointment Gölü Hồ Disappointment 失望湖 1159126103دریاچه نامیدی אגם דיסאפוינטמנט Дісаппойнтмент جھیل ڈس اپوائنٹمنٹ 失望湖 3Alkaline Lake Lake Mackay 5.7 6.7L. Mackay Lake Mackay Q1074063 بحيرة ماكاي লেক ম্যাকে Mackay Mackay Mackay Mackay Λίμνη Μακέι मैके झील Mackay-tó Danau Mackay Lake Mackay マッカイ湖 레이크 맥케이 Mackaymeer Lake Mackay Mackay Маккай Mackay Mackay Gölü Mackay 麦凯湖 1159126115دریاچه مکی אגם מאקאי Маккай جھیل مک کے 馬開湖 3Alkaline Lake Lake Gairdner 5.7 6.7L. Gairdner Lake Gairdner Q965973 بحيرة جيردنر লেক গেয়ার্ডনার Gairdner Gairdner Gairdner Gairdner Λίμνη Γκάιρντερ गेर्डनर झील Gairdner-tó Danau Gairdner Lake Gairdner ゲアドナー湖 레이크 가어드너 Gairdner Gairdner Lago Gairdner Гэрднер Gairdner Gairdner Gölü Hồ Gairdner 盖尔德纳湖 1159126129دریاچه گایردنر אגם גיירדנר Герднер جھیل گیرڈنر 盖尔德纳湖 3Alkaline Lake Lake Torrens 5.7 6.7L. Torrens Lake Torrens Q163855 بحيرة تورينس লেক তোররেন্স Torrens Torrens Torrens Torrens Λίμνη Τόρες टोरेन्स झील Torrens-tó Danau Torrens Lake Torrens トレンズ湖 레이크 토렌스 Torrens Torrens Torrens Торренс Torrens Torrens Gölü Torrens 托伦斯湖 1159126147دریاچه تورنس אגם טורנס Торренс جھیل ٹورینز 托伦斯湖 5Alkaline Lake Lake Barlee 6.0 7.0L. Barlee Lake Barlee Q1465138 بحيرة بارلي লেক বার্লি Barlee Barlee Barlee Barlee Λίμνη Μπάρλεϊ बर्ली झील Barlee-tó Danau Barlee Lake Barlee バーリー湖 레이크 발리 Barlee Barlee Lago Barlee озеро Барли Barlee Barlee Gölü Hồ Barlee 巴利湖 1159126175دریاچه بارلی אגם בארליי озеро Барлі جھیل بارلی 巴利湖 3Alkaline Lake Lake Frome 5.7 6.7L. Frome Lake Frome Q626907 بحيرة فروم লেক ফ্রোমে Frome Frome Frome Frome Λίμνη Φρόμε फ्रोम झील Frome-tó Danau Frome Lake Frome フローム湖 레이크 프롬 Frome Frome Lago Frome Фром Frome Frome Gölü Hồ Frome 弗罗姆湖 1159126159دریاچه فروم אגם פרום Фром جھیل فروم 夫倫湖 5Alkaline Lake Lake Eyre South 6.0 7.0L. Eyre South Lake Eyre South Q21890578 بحيرة إيري الجنوبية লেক আইরে সাউথ Lake Eyre South Eyre South Lago Eyre del sur Eyre South Λίμνη Νότιο Έιρε आइर साउथ झील Déli Eyre-tó Danau Eyre Selatan Lake Eyre South エア湖南 레이크 에어 사우스 Eyremeer (zuid) Jezioro Eyre Południowe Lago Eyre (Sul) озеро Эйр-Саут Eyre South Güney Eyre Gölü Hồ Eyre South 南艾尔湖 1159126189دریاچه ایر شمالی אגם אייר הדרומי озеро Ейр (південь) جھیل آئر ساؤتھ 南艾爾湖 1Alkaline Lake Lake Eyre North 5.6 6.6L. Eyre North Lake Eyre North Q21890573 بحيرة إيري الشمالية লেক আইরে নর্থ Lake Eyre North Eyre North Lago Eyre del norte Eyre North Λίμνη Βόρειο Έιρε आइरी नॉर्थ झील Északi Eyre-tó Danau Eyre Utara Lake Eyre North エア湖北 레이크 에어 노스 Eyremeer (noord) Jezioro Eyre Północne Lago Eyre (Norte) озеро Эйр-Норт Eyre North Kuzey Eyre Gölü Hồ Eyre North 北艾尔湖 1159126091دریاچه ایر شمالی אגם אייר הצפוני озеро Ейр (північ) جھیل آئر نارتھ 北艾爾湖 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.dbfawk0000664000175000017500000000322115151324131022516 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This file is meant to be used with the ne_50m_lakes shapefile # from natural-earth-vector (https://github.com/nvkelso/natural-earth-vector) BEGIN { dbfinfo="scalerank:featurecla:name:name_alt:note:admin:namepar:min_zoom:min_label:name_abb:label:wikidataid:name_ar:name_bn:name_de:name_en:name_es:name_fr:name_el:name_hi:name_hu:name_id:name_it:name_ja:name_ko:name_nl:name_pl:name_pt:name_ru:name_sv:name_tr:name_vi:name_zh:ne_id:name_fa:name_he:name_uk:name_ur:name_zht"; dbffields="name:featurecla:min_zoom:min_label";} # defaults: color 117 (same as Tiger/Line water color), fill color 117, # stippled 50%, display all the way out to max zoom, stop labeling at # 50k zoom, label in black. BEGIN_RECORD {key=""; lanes=1; color=117; name=""; filled=1; fill_color=117; fill_style=2; fill_stipple=2; pattern=0; display_level=2147483647; label_level=50000; label_color=8; symbol=""; font_size=3; label_method=0;} # Feature name from DBF record /^name=(.*)$/ {name="$1";} # color reservoirs and alkaline lakes in a different shaed of blue /^featurecla=Alkaline Lake$/ {fill_color=128;} /^featurecla=Reservoir$/ {fill_color=23;} # set display level and label level based on attributes # higher numbers are smaller features /^min_zoom=6./ {display_level=1024;} /^min_zoom=5./ {display_level=2048;} /^min_zoom=4./ {display_level=4096;} /^min_zoom=3./ {display_level=8192;} /^min_zoom=2./ {display_level=16384;} /^min_zoom=1./ {display_level=32768;} /^min_label=7./ {label_level=1024;} /^min_label=6./ {label_level=2048;} /^min_label=5./ {label_level=4096;} /^min_label=4./ {label_level=8192;} /^min_label=3./ {label_level=16384;} Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.prj0000664000175000017500000000022115151324131022050 0ustar hibbyhibbyGEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_lakes.shp0000664000175000017500000122757015151324131022072 0ustar hibbyhibby' ffffd\OIf@ffff.|T@ 8333S 0@AM@83331@lM@!83331@ffffM@L1@M@ 1@AM@yy1@PM@hfff^1@M@M1@ffff֢M@,1@3333M@1@ffffƯM@83330@M@hfff0@ffffM@hfffF0@ M@8333$0@PM@8333S 0@ffff>M@8333s@0@!M@y0@3333{M@hfff0@3333KM@0@ffffM@0@3333M@L0@33333M@@0@|M@ 1@M@@_1@tM@c1@M@8333ӈ1@3333 M@83331@3333SM@1@!M@83331@lM@833331@3333M@1@M@1@M@L1@3333M@1@M@83331@ffffM@ 83333=@ffffM@x@@4N@83333=@N@83333=@N@83333=@N@83333=@N@83333=@N@8333S=@ N@hfff=@N@,=@N@ =@3333 N@8333s>@3333N@L>@ffffN@>@N@hfff>@N@ >@ffffNN@hfffF!>@3333N@hfff,>@33333N@hffff1>@3333N@,2>@̄N@.>@8N@hfff->@3333N@l3>@ɱN@5>@N@hfff7>@ffff6N@<>@!N@hfff@>@̴N@hffff@>@N@ <>@ffffN@ =>@ffffN@I>@ N@Yw>@3333[N@ {>@N@|>@N@@>@9N@>@N@>@IN@>@N@hfff>@,N@hfff&>@3333N@>@N@>@4N@`>@N@Y>@N@>@N@?@pN@hfff?@8N@83333?@3333N@83333?@hN@ )?@1N@,?@̜N@N@l\@@̴BN@4333#R@@DN@L@@IDN@YL@@3333kAN@hfffO@@@ffff!N@`>@8N@hfff>@:N@ >@3333:N@hfff>@3333+9N@hfff>@3333[9N@83333>@>N@83333>@3333#CN@hfffF>@GN@̩>@KN@̬>@ffffPN@ >@SN@hfff>@ffffZN@hfff&>@ffff]N@>@3333^N@>@aN@hfff&>@ffffgN@hfff>@ffffkN@8333t>@nN@8333p>@3333oN@8333o>@3333sN@h>@vN@J>@N@>@ffff.N@8333s=@N@83333=@N@83333=@N@,c>@X?̌y?@ 3334@6x?@`ffff@@e?@L>@Lb?@ 333@,c?@@Yf?@T?,c?@?Y^?@3333b?W?@3333X?8333sR?@@ffff?M?@?8333D?@3333?8333s*?@?!?@g?83333 ?@??@3333?>@3333o?hfff>@@ffff+?>@?8333>@?8333>@?>@?>@3333u? >@X?>@?83333>@3333?>@@ffff?}>@3333?}>@@ffff@?>@c?~>@?8333Sz>@3333?hfffw>@?8333s>@%?j>@@ffff?Lf>@?,c>@@ffff?p>@?z>@v?>@̄?83333>@3333E?̌>@3333?ٶ>@@3333?>@3333?8333S>@?-?@`ffff@LB?@:@M?@ 333@ X?@S@Yn?@`ffff@̌y?@ 3334@x?@`ffff@x?@`ffff@x?@`ffff@|ffff2TD@3333ӷS̔E@T$E@T3333C#E@̰T3333E@̀TTE@3333Tffff E@3333TlE@TE@]T̤D@)TE@ITE@3333T3333;E@MTffffD@̼TQD@ffffTffffD@YTE@T3333cE@\Tffff6 E@TAE@@T3333E@3333ׂT E@ffff|T3333k"E@ffffz{Tffff#E@3333wT3333S(E@3333kwTffffn'E@xTffff#E@xTffff E@ywT!E@uT%E@3333sT(/E@3333nT)9E@̬_T3333KE@YT3333PE@(PTffffSE@BT3333TE@4T3333SRE@ffffv'TDLE@ffffFTffffvIE@ffffbTIE@TEE@TffffFE@T(IE@T3333{KE@TME@TffffVME@TffffNE@PT3333VE@XTpWE@ffffT3333ZE@3333KTffff^E@TffffcE@]T3333fE@SDiE@SmE@3333SInE@USlE@SffffNmE@3333SpE@SffffpE@ffffBSoE@S3333mE@̤Sffff^nE@ffffS tE@S@vE@̜SyE@̬S~E@ffffSE@5SffffE@ffffS$E@3333SE@ffff:S̔E@3333SE@3333CSdE@3333SIE@3333SIE@3333SIE@3333SIE@3333SIE@3333SIE@(SffffE@ܺSffff^yE@S\qE@3333ӷSkE@ffff.SIfE@ĺSaE@3333S]E@S3333WE@3333SSE@SXE@`S3333~E@بTD@بTD@بTD@بTD@$T̴D@$T`D@TD@)T,D@ffffޫTD@3333ϫT0D@بTD@0̌,@`fff)@L|-@9z*@# |-@0333'*@L|-@*@n-@*@c-@ *@_-@0333s)@@R-@)@@=-@̬)@@3333/-@)@L-@)@,@L)@@3333,@`)@@333s,@`fff)@pfff,@)@̌,@L)@̌,@)@,@03333*@,@`ffff*@pfff,@*@@,@!*@,@**@pfff,@0333,*@pfff&,@;*@pfff&,@E*@L,@S*@@,@^*@L,@j*@@333,@9z*@-@z*@.-@lm*@pffffN-@j*@pfff&V-@c*@i-@ F*@ |-@0333'*@ |-@0333'*@ |-@0333'*@@@83333,PA@hfff"LA@ ,LA@ ,LA@ ,LA@ ,PA@8333,A@ ,A@83333,.[A@y[A@y[A@yhA@̤ѿ)fA@ҿhfffZA@4333ԿIA@տ)=A@ֿ̜:A@̜׿4333c@@},@@@3333)@@@@ffff8@@40@@ffffy@@ffff@@@3333|@@̬@@ffff"`@@l@@@33337@@ @@-@@@3333̌@@'i@@hfff֮@@G4333c@@ @@hfff@@̤ @@ffff4333Ӿ@@>4333@@̬4333@@@3333hfffƴ@@hfff@@ffffBl@@/hfffƝ@@@@ffff4333S@@43333@@K4333@@@3333WY@@̬@@@@Ǎ@@hfff6@@ffff4333@@@33334333S@@ffffphfffV@@@3333̜@@@@-43333@@@hfff@@@3333@@ffffH@@64333x@@@3333]hfff6t@@ffffhfff6r@@,q@@PhfffFy@@̋9{@@43333r@@4333c@@ffffLa@@c@@ffffHa@@|l@@a4333Sn@@43333h@@,i@@@3333Yhfffg@@,`@@4333Y@@ffffW@@ffffU@@@3333`R@@)F@@hfffD@@hfffD@@B@@̠L8@@ 2@@@3333a-@@&hfff(@@ffffn<$@@ffffB@@Chfff@@z9@@hfff@@@33334333S @@'@@@@@@33333̬@@K@@@3333!8333s?@_?@?@@3333jp@@ 8333s?@ffff?@@3333dhfff?@qhfff?@ffffhfff&?@@3333hfff?@@3333b,?@ffffS8333?@?@?@ ?@hfff&?@@3333@?@<83333?@@3333?@@3333hfffF?@0hfff&?@ffffhfff?@ffff̬?@7?@@3333?@@3333! ?@@3333hffff?@̌?@ffffl?@ffffy?@x񿠙Y?@̲𿠙Y?@C83333?@4?@X`?@(?@8333s?@hhffff?@ffff ?@H8333s?@0?@gfff޿?@̌Կhfff@@Pпhfff?@hfff˿8333?@hfffǿ?@hfffFĿ@?@4333)@@)4333@@8333hffff@@Yhfff@@́?hfff!@@fffft$@@ ?,@@̍?4333#1@@?4@@?hfff8@@?y9@@̬?9>@@?hfff6D@@ٱ?9H@@0333S?9K@@̼?N@@ffff?4333R@@ffff.? W@@@?[@@ffff?4333V@@2333?U@@0333?X@@dfff? ^@@̼?4333c@@l? m@@̬?hfffvp@@̜?r@@dfffƼ? u@@0333s?z@@?@@2333?4333@@?ɉ@@?@@3333#?̼@@ffff?@@3333g?`@@?hfff@@ffff?4333@@?@@5?4333@@?@@̘?hfffF@@ffffZ? @@`?@@(?@@?|@@T?L@@D?ٽ@@2333?,@@2333s?hfffF@@p?hfff@@3333;?hfff@@[@XJ@hfff;[@J@!1[@J@4333.[@̔J@,[@IJ@hfffF+[@ffffJ@Q*[@̜J@hfff[@ffffJ@X[@J@hfff[@J@[@0J@l[@̄J@4333k[@~J@[@ yJ@4333s[@3333#kJ@hfffZ@cJ@hfffZ@`[J@)Z@ffffYJ@hfffZ@YJ@hfffZ@RJ@4333SZ@TEJ@4333 Z@ffff.[@ffffLK@I2[@ffffVK@4[@̌^K@433336[@YfK@4333s8[@3333#mK@hfff;[@rK@l<[@wK@hfff:[@3333yK@=[@ffff}K@`C[@K@ G[@K@4333J[@3333˘K@hfffL[@ffffvK@hfffM[@3333K@43333L[@3333[K@aL[@ffffK@hfffFO[@ffffK@T[@K@4333s`[@ffffK@hfffd[@K@4333j[@K@p[@3333K@4v[@K@$}[@3333 K@hfffw[@3333K@Iw[@K@4333Z@ffff.J@4333Z@ffff.J@4333Z@ffff.J@hfffZ@LJ@̤Z@J@aZ@3333CJ@Z@J@4333Z@ffffJ@hfffZ@̤J@xZ@J@Z@J@hfffZ@3333J@Z@ J@4333Z@4J@4333Z@ffff.J@ \X2I@pXffff4K@XX]I@XX]I@ffffXyXI@3333X3333OI@ffffX3333sPI@ffffXSI@̬"X,]I@=$XffffXI@ffff%XTI@&X3333LI@ffff&XffffFI@3333$X;I@!&Xffff8I@̸+X2I@33330X2I@e7X5I@̐;X ;I@=X3333HI@}>XaRI@>XlWI@ffff.=XfI@ffff=XlI@=XffffvI@ X!I@>XI@3333{:X3333kI@3333/XI@ffff"/X3333I@ffff 0Xffff^I@82Xffff>I@2XI@D4XI@4XffffI@6XlI@ffffZ8X3333I@$DX3333#I@FX,I@!HX3333I@3333GX̤I@ffffIX3333CI@NXffffI@-PXȸI@QXI@ffffRXffffI@QXI@\OXI@OX̼I@3333SXffffI@VXffffJ@̈\XJ@ffff_XJ@5cXYI@dXAI@3333gfXiI@ffffaX3333J@̬_X3333 J@_XJ@ffffaXyJ@kX3333J@ffffoX3333SJ@qX3333 J@̤nX3333K J@ffffoXffffJ@3333rX I@fffftXI@3333}X̬I@3333SX̜I@قX̜J@̈X3333 J@XJ@ffff&X3333J@Xffff#J@pXffff0J@ X45J@ffffX9>J@eX9GJ@ffffƳX3333\J@ffffX bJ@3333{X9dJ@TX̜mJ@ٹXHsJ@HX9uJ@qX|{J@ffffXIJ@mX3333J@̔XTJ@X̌J@ffffXɉJ@3333ϹXJ@3333_XffffJ@4XTJ@ffffXhJ@ffffXJ@\XٚJ@ffffXffff&J@ffffrX3333sJ@ffffXHJ@X3333J@XJ@XtJ@yXJ@XJ@ɮXffff>J@3333CXJ@,X3333J@)X3333J@̐XJ@̨}X3333J@5zXJ@̔yX3333J@3333ׄXLJ@3333 XJ@X3333J@%X̔J@XDK@@XK@ffff"XK@XXx4K@3333+Xffff4K@{X0K@{X!-K@YX))K@~Xffffn(K@uX3333(K@̀tXt&K@3333OwX3333!K@XX3333K@ffffX( K@Xffff>K@3333OX0J@Xffff&J@XAJ@3333X3333J@ X9K@-|X̬K@3333sXPK@3333nXY K@nXK@3333pXK@0~X3333cJ@ffff~XJ@|X3333J@ffff>uXffff&J@ttXffffJ@3333uXJ@3333rX3333kJ@3333?mXffffJ@iX3333CJ@3333;eXAJ@fffff^XJ@[X1J@VXffff^J@8VXĀJ@3333XXffff~}J@3333#[X{J@xYXffff~pJ@LUX3333[dJ@LX!VJ@,GX =J@DX4J@(@X3333{"J@p@Xffff J@0AX3333+J@?XffffJ@ffffJ=X J@6X3333I@l5XffffI@ffff6X1I@33336XI@ffff>1XhI@3333;-XHI@3333,X0I@33333-XI@x0X3333I@3333;.XffffI@ffff~&X3333SI@<#X3333I@"X3333I@XI@XI@̔X(I@pX̜I@XI@QX̌I@8Xffff6I@3333X̌I@̄XffffmI@XXaI@XX]I@3333|X̼(J@3333|X̼(J@xX-J@d|XffffCJ@3333XaEJ@3333X:J@X33332J@̐~X`(J@3333|X̼(J@u(XI@u(XI@H&X3333I@ffffZ-XffffI@ffff*/X̌I@2XI@5X|I@ 6XiI@0XN@ \N@3333O \N@ \N@ffffB+\HN@ffff&9\N@3333 >\N@ffff@\ѳN@a?\3333N@x@\xN@ffffE\N@|I\ffffN@V\3333N@Y\LN@3333`\ffffVN@f\N@Mk\ffffN@ffffl\ffffVN@m\3333sN@k\`N@@l\3333+N@3333n\3333N@`n\N@xi\3333N@3333h\ffffN@ffffVh\ffffN@3333j\9N@ffffn\̌N@3333Cu\N@A~\L}N@3333\3333}N@ffff \ĀN@3333\̄~N@ffff6\3333vN@3333\ffff&tN@3333w\vN@ffffj\ttN@P\lN@I\ffffFkN@3333\̴mN@ffff\lN@ffff]3333#oN@0]ffffyN@ffff" ]8N@!]N@$']]N@2]fffffN@3333?/]N@p.]N@33332]3333N@ffff.2]$N@33330])N@ffff&]xN@ffff ]3333N@]3333{N@u]ffffN@̴ ]N@3333]ffff>N@\pN@\ffffN@ffff\N@ffffB\N@3333\XN@̨\QN@ffff\̜N@ffff\ffff֩N@]N@3333{]ffffΰN@4\ffffN@ffff\ffffN@`\fffffN@\̔N@ffff\3333KN@̀\N@̠\3333N@\̜N@̴\3333sN@P\̬N@t\̼N@\N@̄\3333N@4\̄N@̤\ffffN@3333\N@3333\̤N@ffff\N@̠\ffffN@3333+\ N@3333c\9N@q\ffff.N@ffff\PN@\N@q\N@\9N@ffff\3333#N@ffff\3333N@3333W\N@\dN@\O@d\DO@\ffffNHO@3333\LO@ffffv\QO@3333w\\tN@̰@\ffff~N@:\N@H0\ffffN@3333o/\ffffFN@.\)N@ffff&,\3333sN@&\3333N@ffff\3333sN@-\)N@ffff\N@ffff\N@X[AN@X[DO@3333[ffffn O@ HSffffNE@̤RQ?F@3333WRffff=F@3333WRffff=F@3333WRffff=F@̤R̼:F@ffffRffff7F@ffffBR2F@8S3333sF@ffffS3333 F@SF@ffffSF@S3333F@ S F@3333 S3333+ F@Q SF@ SF@ffffN SffffnF@ffff: S4E@ShF@SffffE@PSffffE@S3333+E@! S3333E@ SffffE@ASE@!S3333{E@SE@33337S3333CE@qS3333E@ffffS E@Sffff>E@ SE@l SE@ SE@3333{ SE@ffff Sffff>E@ SE@d S3333CE@3333 SE@StE@̈SffffE@S|E@@SffffE@%SffffE@)SسE@X,S33333E@ffff:.S3333۫E@3333s/SffffάE@̨8S1E@ffff;SffffE@SE@ffffES3333ӤE@TQS3333E@ffffZSԤE@aS9E@gSE@EmS3333SE@uS̴E@ffff2S̄E@3333GS3333E@ SDE@3333gSffff~E@S3333E@SffffE@ffffSffffNE@SffffE@SњE@SE@̔S\E@yS3333E@SE@3333SffffE@ S3333E@)SE@3333kSE@STE@ffffShE@3333SE@]S̜E@`SHE@̔S3333E@SffffE@ffffFSE@S)E@ffff֪S3333E@-S3333E@ȡSE@S33333E@pS3333E@SffffE@SLE@ffff^xS9E@3333uSffff^F@ffff~nS0F@3333[mS3333CF@ffffkS̼F@3333WeSF@3333#cS3333+F@bSF@TdS3333F@tcS3333E@3333/`S4E@ZSE@TS\E@3333PS3333cE@3333QSE@SSffffE@%TS(E@RSE@QSE@)LS3333KE@KSE@NS(E@3333OMS E@̬ISE@|CSffffE@ffff;SE@3333C8SE@33337S3333E@=:S3333E@ffff@SpE@BS̬E@BSE@AS\E@;SF@8S̴F@3333;7S F@8Sffff F@ >S|F@3333BS9F@3333FSffffF@|GS, F@3333SESF@`GS3333#F@`QSF@̌RS<F@̔RS3333 F@xQS3333+F@3333QSffffV F@RS F@9USffffV F@4US<F@TS3333CF@3333KUS3333F@]XSF@̈\S̼F@|eS3333 F@fffffeS3333 F@cSffffF@ffffzYSF@TS3333F@QSyF@ PS3333+F@lNS)F@3333MS3333sF@tIS$F@CS@F@3333OAS4F@ffffBSffffF@@SF@ffffF@3333RQ?F@3333WRffff=F@,SF@,SF@,SF@ffff(S8F@ )SF@33330S F@(3S3333F@ffff3SF@Y2SF@.S8F@,SF@SF@SF@SF@̴SXE@S̼E@SffffFF@SffffF@̠SffffF@SF@ffff*SffffF@ffff*SffffF@ffff*SffffF@Sffff F@SF@ffff SffffF@̌SF@SF@3333SF@yS3333F@ffffSF@3333[S3333F@ffffS3333[F@ SF@ SffffF@ffffZS3333F@3333SxF@SF@ffff*SffffF@(S%F@(S%F@(S%F@S3333#'F@Sffff&'F@3333K S3333c%F@ffff S#F@ffff" Sffffv"F@ffffSffff~#F@(S%F@ 8ffffE_4P@`]ffffP@3333u]P@3333u]P@3333u]P@3333u]P@KP@^ffffDP@!7^-=P@<^;P@ffffD^ffff9P@3333{H^!7P@ffffN^4P@yW^Y5P@,^^I8P@̸^^;P@3333oY^=P@3333sT^U>P@ffffM^ffff?P@̰E^A@P@ffff.@^3333sBP@ffffn?^@EP@ffff:#^̄RP@^TZP@̈^̐`P@̈^̨cP@^meP@ffffv*^3333fP@̔>^acP@ffffK^_P@W^ffff[P@c^HWP@b^UP@3333kd^SP@3333f^3333NP@ffff&g^3333;KP@dg^ffff2HP@3333_g^3333EP@pj^̴DP@n^CP@3333Gq^dBP@m{^ffff?P@ffff^ffff=P@̰^|AP@ffff ^]DP@^LGP@^mGP@4^ffffIP@i^KP@ffff ^LP@^MP@̐^QP@3333^3333UP@3333;^%ZP@ɸ^3333+_P@H^ffffbP@^eP@^jP@,^ffff*pP@x^QtP@^d|P@ ^P@̘^3333sP@ffffN^~P@hq^ffff|P@e^^ffff>}P@3333R^ffffP@ffffO^xP@ffffQ^P@3333b^ԇP@3333l^hP@^ffffP@ffff^P@ffff^P@^UP@D^ P@3333^P@^P@ffff^hP@H^̨P@ffffn^pP@^P@̨^ffffP@3333[^P@d^P@@^P@3333?_UP@_P@_̉P@%_P@̸$_P@%_P@)_mP@3333K+_ffffP@3333._P@@2_P@E4_=|P@x9_}P@̠=_ffffP@MA_̨P@ffffE_P@D_3333ۏP@3_P@3333%_3333P@̜!_̬P@ffff_3333ǓP@^\P@P^P@ffff^^3333P@,^ffffP@̤^LP@,^ffffP@ffff ^3333P@3333ס^أP@ffffr^\P@T^PP@^XP@3333~^3333P@f^]P@a^ffffP@3333]^XP@N^3333GP@L,^ffff P@%^P@L^P@ffff^P@)]ffffP@ffff>]ffffFP@ffffV]ffffbP@3333]̀P@3333_]ffffҽP@]̸P@4]3333/P@(]3333P@X]ffffP@]3333P@̈]\P@h^ܩP@ffff^3333P@ffffJ^mP@ffff^ ^XP@3333#^3333cP@3333^ffffP@^3333P@ffff^3333P@3333O^,P@^3333P@̀^IP@^ffffP@ ^TP@̐]P@3333]P@3333;]P@3333]P@3333[]@P@3333S]3333P@̴]P@ffff^]4P@]ffffBP@]ffffP@̏]uP@D]P@3333C]|P@u]3333P@yn]4P@3333l]$P@k]P@l]ħP@8l]!P@ffffn]DP@ffffu]3333+P@3333Sw]}P@,w] P@3333u]P@ 8T3333C#E@3333wT4YE@$T3333C#E@T$E@ffffTL)E@ffffTffffn,E@3333CT0E@ffffTffffn2E@Tffff8E@TffffnBE@ffffҵTHE@ThKE@)TffffnNE@|TQE@dTUE@3333T3333CXE@T4YE@TWE@T̜TE@QTLE@3333T̄IE@ITffffnGE@ffffTlEE@M@t)@ffff9M@[)@33335M@pfffL)@2M@pfff?)@0M@@33334)@ 0M@()@/M@@333)@/M@pfff)@ffff~0M@)@3333{2M@@3333%)@5M@pffff$)@Q7M@)@7M@)@ffff2M@(@1M@Y(@/M@pffff(@2M@(@33337M@@333(@AM@6)@NM@9)@ffffRM@pfff& )@9SM@pfff )@3333TM@pfff)@XM@@333s)@ ]M@(@aM@L(@1dM@pfff&(@1dM@(@fffffM@@(@hM@(@hM@(@3333{kM@̌(@ffff>pM@̌(@uM@pfff(@wM@(@ffffwM@(@3333uM@@)@3333[sM@@3333 )@ffffoM@ )@*@ffffuM@Q*@sM@pfffc*@sM@@333x*@sM@@333|*@wM@@3333q*@M@Z*@hM@ ?*@HM@pfff4*@ffffM@4*@M@Y7*@TM@<*@3333ӥM@B*@ffff֨M@ I*@ЫM@LO*@,M@pfffX*@3333{M@b*@̌M@̌o*@M@}*@M@ـ*@3333SM@*@M@@333s*@M@*@(M@@333*@ffffM@*@̼M@pfff*@T2333:@3333AT9:@3333DT:@,ETffff:@ffffCT2333:@ffff?T;@DyU(@wU 2(@quU7(@ sU6(@pU/(@@kU0333 (@eU0333S(@3333`U'@@\U0333'@(WU0333'@̘PUِ'@3333sHUS'@@U0333 '@ffff:U`fff&@6U0333&@4U0333S&@4U0333S&@4U0333S&@4U0333S&@@B@̌C'@B@`fffF(@6̌B@`fffƖ'@YB@̬'@hfffB@'@B@'@B@'@hfffvB@̵'@hfffFB@9'@B@0333'@4333sB@ '@hfff&B@`fff&'@B@'@@B@03333'@hfffƀB@`fff'@hfffB@(@B@`ffff,(@B@9T(@)B@`fffk(@0B@`fff|(@hfffFB@`fff(@4333#B@L(@ B@(@B@ v(@ B@̌u(@4333sB@r(@hfffB@0333s(@9B@y(@hfffB@ٔ(@B@`fffF(@B@03333(@4333B@(@B@,r(@pB@03333T(@B@0333;(@B@*(@B@ (@B@`fff& (@̬B@'@lB@`fffF'@hfffB@'@ B@0333S'@yB@l'@PB@'@B@C'@/@QQLA/QNQR/ LQhffff[/3333JQd/3333cIQ8333r/FQ̌/yBQY/@Qhffff/@Q/ffff?Q8333/9Q /45Q83333/33332Qhfff/3Q8333/4Qhffff0ffff6Q̌ 08Q07Q4333"05Q4333000Q303333k,Q 80ffff(Q80%Q =0%QE03333%QI03333%Q@M03333#'QO0ffff)QyQ03333_,QhfffS0$-QV0̘-Q[0L/Qb0fffff2Q,h03333 7QhfffFj0:Qhfffl03333k;Qr0l9Qv07Qhfff033336Qhfff&06Qhfff&0333337Q4333033337Q09Q0M0qWQ433390qWQ433390qWQ433390qWQ433390p 9YJ@3333#XffffN K@TXffffvJ@3333#XhJ@̘X@J@ffffXffffJ@TXԌJ@IX؊J@XffffvJ@ffffXffffFJ@XdJ@3333[XJ@$XJ@3333+Xffff>J@|XJ@XffffJ@ffffrXhJ@LXqJ@qXffffVJ@XffffΏJ@XJ@ffffXffff֔J@XffffJ@XJ@3333?XqJ@DXffffƕJ@3333cX3333ӓJ@ XJ@ffffX3333J@̼XffffJ@3333 XJ@X3333J@0XJ@Y3333J@ffffYĐJ@3333 YffffnJ@ffffY̼J@(Y3333J@aY̌J@ YJ@"Y3333[J@Y)YqJ@3333[-YJ@ffff^1YffffnJ@A2YffffNJ@5YJ@ffff8YffffvJ@ 9Yffff>J@3333c8YJ@ffff6Y(J@1ȲJ@<-YJ@3333)YiJ@̠&YJ@%YJ@%YiJ@&YffffvJ@3333k(YffffJ@̌(YJ@%Yffff.J@ Y3333J@ffffY3333J@YJ@ YJ@ffffYJ@ffffYffff&J@̄YffffJ@̠Y J@3333sY@J@ffffYJ@8YJ@)Y$J@TY3333J@ffffYJ@fffff Y3333[J@3333Y̌J@ffffYffff&J@3333/Y̤J@`Y̔J@ffff2YffffJ@dYK@YK@PYK@Y̔ K@YK@3333{Y̬K@Y3333K@dY|K@ffffnYffffvK@3333YffffVK@YPK@̜Y3333K@ YqK@4 Y̼K@p YffffN K@Y3333{K@YK@3333XffffK@ffffNXK@ffffvX3333K@XffffK@3333_XffffK@Yffffv K@ffff Y3333cK@ffff~YK@` YK@ffffb Y|K@Y!J@3333YYJ@3333YJ@ffff6YJ@Y J@̤ Y,J@ YPJ@̔Yffff.J@Yffff^J@XJ@XJ@3333/XJ@3333?X3333[K@xX̌K@X|K@X`K@̄XJ@XffffJ@$XffffvJ@3333XPJ@3333X3333J@XXJ@X`J@$XJ@XffffJ@3333XlJ@ffffFXXJ@XJ@XJ@ffffYffff^J@3333YJ@ffffYJ@ YJ@3333 YJ@3333 YJ@3333 YJ@ Y9J@Y3333J@ffff2Y1J@}X3333۾J@xXffffnJ@ffff"XJ@tX3333#J@XİJ@ffffXhJ@0XJ@,XħJ@̄X3333ӤJ@ffffXPJ@0X̜J@XȟJ@̴X3333[J@ffff&XYJ@XJ@TX3333;J@ffffXJ@iXJ@XffffJ@X3333J@ffffJXffff֧J@3333 X3333J@X3333۠J@XJ@TXffffvJ@TXffffvJ@TXffffvJ@hffff@@nN@hfff6B@ffff6uO@ 5B@9N@5B@9N@5B@9N@hfff6B@3333ïN@4333c6B@N@hfffF4B@٨N@43332B@3333N@0B@3333{N@hfff0B@ffffN@4333/B@̴N@4333/B@N@hffff0B@ffffN@1B@ffffΜN@43332B@3333cN@hfff1B@N@4333.B@qN@)B@XN@#B@N@B@YN@hfffB@N@4333 B@N@hfffB@̃N@hfffA@8N@A@{N@̬A@PyN@,A@ffff.wN@hfffA@QuN@hfffvA@̄sN@4333A@qN@̬A@lpN@4333sA@loN@4333A@nN@A@oN@4333A@ffffvqN@ A@sN@9A@uN@yA@xN@A@3333#|N@hfffA@ffffFN@4333A@N@̌A@ffff>N@hfff&A@3333N@A@N@hfffvA@N@A@ffffށN@̜A@N@4333A@N@4333A@؂N@4333A@N@܂A@@N@4333xA@3333N@rA@N@O@4333YA@8O@hfffaA@0O@gA@*O@hfffkA@'O@ mA@%O@mA@T!O@hfffvoA@O@A@sO@)DA@ffff6uO@|MA@ffffoO@hfffZA@lO@dA@ajO@lmA@ffffiO@tA@`hO@4333zA@fO@̼A@bO@A@ffff^O@ٙA@ffffFZO@A@DUO@hfff6A@8PO@`A@ffffVMO@iA@ffffMO@\A@AOO@yA@ffffOO@|A@3333OO@4333A@LO@4333A@3333IO@4333A@GO@YA@DO@4333A@ffffBO@hfffA@y?O@hfffA@ffff;O@43333A@̴4O@LA@-O@4333sA@ffff$O@4333A@3333CO@hfffvA@O@4333SA@) O@D@ \ffffƲD@\Uffff.F@ffff&=U(F@3333>UpF@CUF@ffffEUyF@QFUF@̜EUF@CU3333F@h@UaF@XD@3333U3333 D@UD@UE@tU E@UffffFE@3333U3333E@ UE@U+E@3333UEE@ffffNUffffWE@ffffUp`E@3333_U3333gE@eUlE@̤ṲrE@UffffyE@,U~E@UE@-U3333CE@AUffffE@3333?U33333E@3333#UffffE@YUffffE@ffffUE@̴UYE@3333U3333E@]U3333kE@3333U̴E@ffffU3333E@AUE@UE@U3333E@3333UPE@LUE@ffffU3333E@3333SU!E@3333UE@$UffffF@ffffUffffF@UF@ffffΧUffffF@ԧUtF@yU@F@3333+U)F@ffff¡UhF@ffffU|F@|U\F@3333UF@dUF@3333_U3333F@ffffއUffffF@3333U9F@e}UhF@ffffzzUxF@yU3333kF@duUfffffF@LmUiF@XgUffffG@ffffcU G@̤^U G@3333XU G@PUI G@pFUG@ffff2>UffffF@Q3U3333F@q0UpF@ffff0UlF@ffff_UffffNF@3333wbU@F@dU3333sF@fUF@,gUF@eU3333{F@ffffNcU!F@̔`UffffF@ffff_UF@`UF@ffff_UffffNF@ffff_UffffNF@ffff_UffffNF@3333[UF@ЃU3333˒F@mU)F@ffffUiF@ffff>U3333CF@ffffz~U3333F@~UِF@3333U8F@3333[UF@3333[UF@3333[UF@HUF@UyF@ffff޽U$F@U@F@UЫF@(UffffF@ffffҶU3333{F@(ULF@8U3333F@HUF@HUF@HUF@$UĦF@U3333F@3333U̼F@ffffUAF@3333'UDF@UF@UffffnF@1U3333F@`U!zF@3333UhwF@|U3333sF@3333sUnF@Uffff^kF@ffff6UiF@UjF@ U3333vF@|UtxF@ffff>UyF@mU}F@ U4F@ffffJU3333ÈF@ffff*U3333F@ffffUF@UF@UF@|U̜F@3333cU̴F@UDF@UF@mUF@U3333KF@U4F@3333{UٞF@U9F@ffffRUܥF@$UĦF@$UĦF@$UĦF@W7G@3333Uffff.H@ 5=IQZk̬U3333BG@3333UCG@U@G@UI@G@%Uffff>G@ffffU3333k;G@!U7G@3333%U8G@(U3333=G@̠,U>G@1U3333;G@y6UG@U3333>G@ffff~U0{G@3333V3333G@H VG@U!V3333G@ V9G@"VG@ffff&VG@ffff~(V\G@4(VlG@(V33333G@)VG@-V̄G@5V3333G@ffff:VG@QVffffuG@VV3333pG@_Vffff~mG@|lVffffVkG@wVyeG@V[G@ԉVffffSG@ؕVffffMG@VJG@PVLG@tVPG@(V,XG@3333GVffff~WG@ffffVUG@دVTG@3333GV̜RG@ffffV1MG@ffffbV3333;OG@3333VVG@ffffJV3333C\G@aVffff^aG@V̬gG@iV(oG@,V9tG@3333 VvG@V1{G@3333Vffff~{G@VzG@$VoG@ffffNVoG@V3333qG@V\qG@VffffgG@VbG@3333{VffffYG@ffffV3333XG@0VxYG@̨W3333;^G@W̄aG@W3333 eG@!WhG@ffffJVhG@̸V|G@AV G@0VG@TH@3333S#V̄WH@3333"Vi`H@@"VdH@3333+ VjH@IVfffflH@LV$lH@ffffViH@VIcH@Vffff^H@YV3333ZH@4VSH@A$VffffCH@h%V?H@p$VH@3333SV@H@tVCH@ffffbVffffGH@3333VHH@VTGH@VGH@VJH@3333VHLH@3333ViLH@VhWH@V]H@ffffV3333ScH@l VffffiH@3333[VffffnH@V`uH@VxH@ffffV|H@Vffff&~H@ V}H@H Vffff}H@4V3333H@xVffff.H@pVH@UffffzH@3333UuH@3333UsH@UhpH@ffffVŪoH@TUfffflH@3333UffffVkH@UkH@ U3333jH@ffffU3333SfH@PULcH@lU3333cH@UdH@3333ϸUffffbH@xU3333bH@UyfH@ffffRUigH@$U̴eH@ŧŪcH@ffff.U3333c`H@dUaH@̬U3333 aH@ffffZU3333]H@Uh[H@ffffUXH@̔U|QH@Uffff>OH@ULH@ffffrU33333FH@1U<U3333G@3333c>UXG@?U3333G@@U3333G@?U!G@;UG@7UlG@]1UG@-U̜G@3333_,U3333G@*UpG@)U3333G@t'UԬG@ &UG@'U33333G@3333 ,UxG@ .U0G@ffff-UXG@3333c1U3333G@1U3333G@ffff0U}G@ffff)UxyG@ffff'UvG@l&UffffuG@@%UwG@ffff"U yG@3333;UffffxG@3333U3333#wG@UsG@U3333pG@3333sU9mG@UkG@3333UlG@ffff!UjG@l#UgG@#Ui]G@ffff"UAYG@3333!U3333CYG@ U3333;[G@<U3333+_G@ffffU3333_G@ffff Ǔ\G@ffffUHVG@ #U3333LG@3333c$UIG@a$U3333EG@ U3333=G@mU>G@ffff^Uffff~@G@̬U3333BG@]Vffff~{G@V̴yG@VwG@AVffffuG@3333OV3333vG@3333VxxG@G@eV3333KG@ffffNVPG@@VG@V3333kH@ffffVlgH@V^H@̠V̼[H@ffffV[H@ffffU!_H@UIbH@UffffdH@ffffUeH@3333KUgH@UkH@3333UmH@U̬nH@UmH@V3333kH@ffffN:VffffG@'VaH@%Vffff6 H@ffff2&V1 H@4%V,H@VffffnH@3333V̄H@ffff%VIH@ffffZ0V@ H@ffffbIVG@TLVG@ffffLV3333cG@ffffJV3333cG@JVyG@3333LVffffG@ffff~LVG@JVffffG@9EVG@ffff>VG@3333;VG@ffff;VG@ffffr=ViG@!=VG@ffffN:VffffG@3333UG@lUG@UлG@0UG@ffffU3333G@ V3333{G@VffffG@<VG@3333#Vffff֢G@&V̛G@h'V3333KG@$VXG@VG@TV3333{G@̸VYG@3333 VpG@VG@ffffVffffvG@ffff.V3333ӐG@3333VffffG@3333V3333G@ffffVG@V`G@ffffVxG@VdG@3333'VXG@ffffbV3333ӖG@33333VG@ffffVG@dUffffnG@ffffUG@V3333sG@ffffRV9G@3333UG@-U`H@U`H@UcH@U$iH@3333U3333kH@ffffU̔kH@ffffUffffjH@,U3333{iH@U̜eH@3333U3333cH@̘UaH@U`H@-U`H@fffffUffffG@ffff&fUG@iUG@pU3333CG@tUG@ffff~xU@G@{U3333G@|UG@L|U3333G@3333vU3333 G@jUffffG@fffffUffffG@bffff0U9E@3333cS3333HG@ Ghv1<3333UCG@UDGG@ U3333HG@U EG@3333U@G@]U3333{LTG@KTffffG@ffff^JT3333G@JTF@AJT9F@5FTffffF@3333=TF@8T3333F@ffffV4T3333F@3T3333F@X2TffffF@ffff.TIF@-T3333F@ffff,TpF@ffff)Tffff&F@()T33333F@ffff)TffffF@3333?(T3333F@ffff%TLF@"T4F@ffffF!TF@3333 T|F@3333TF@3333oTF@TT̄F@|TF@3333TXF@T3333kF@ffffTF@T̬F@`T3333F@\T F@3333STF@X T3333F@3333 T3333F@3333 T3333{F@E T3333òF@D T F@TYF@3333TF@T3333ӫF@ffff.T3333F@ffff"Tffff.F@TffffF@ffffTF@ffffT33333F@3333T3333F@(TffffF@T3333F@ffffjTffffF@3333sTlF@UTffff.F@TF@aT3333;F@33333SffffւF@̌S33333F@ffffS(F@3333sS|F@SpzF@SwF@ffff2S3333CqF@ffff6STmF@aShF@SahF@SjF@StnF@ffffSpF@PSmF@S3333iF@YSDeF@3333cSlbF@SffffnaF@SffffNbF@Sffff6fF@3333 SgF@ffff2S hF@SiiF@SamF@ffff~SffffvnF@3333SmF@$T3333jF@TDgF@T3333CcF@ Tffff_F@ffffZTZF@ffffSSF@T,IF@]T9BF@mT3333>F@ffffvT8AF@tTIF@%T3333QF@)T3333S\F@*Tffff]F@̌2T3333YF@̨6T3333CUF@8:T OF@9;TQF@̬9T3333#[F@9T3333saF@M9TffffcF@:TeF@=ŤgF@hAT̬fF@ffffGTffffaF@THT̄bF@)HTffff&dF@TBTkF@h@Tffff&pF@a@TfffftF@ffff?TwF@3333=T̴zF@A>T|F@@T{F@ BT|zF@̼DTfffftF@̌HT|uF@ITvF@HTyF@HT{F@̄KT|F@3333_LTffffVF@EMTF@PTF@PTiF@ RTffffޏF@TTF@ffff6TTffff&F@@RTF@RTffff֟F@YTF@fffffTF@lT(F@0mT3333F@̸kTffffF@ffff>hT4F@eT3333;F@dT̜F@3333bTF@_TlF@\T3333F@3333ZTa~F@ XT}F@VT }F@3333VT̜tF@UTYoF@4STffff~jF@QTeF@3333QTffff[F@ffffQTdRF@ffff ST`LF@VTiEF@XT3333?F@YT:F@3333[Tffff7F@3333[^TX6F@4aT3F@(dT .F@fT'F@fT3333S F@ffffbiT3333F@QmT3333F@nT3333F@mT̤E@3333mT1E@!mT`E@ffffmTffffE@ffffRoTffffE@5rTffff֩E@HvT3333ۣE@TzTpE@X~TE@TȗE@3333T3333E@ffffTE@TE@T9E@̤TE@Tffff^E@ T3333ˣE@0T4E@tTffffVE@ԭT1E@ffffjT3333sF@4TF@3333T3333F@TF@ffffrT4F@dTffff.E@TffffE@ffff*TE@TffffE@|THE@T3333SE@̘T3333E@3333TffffE@TE@TE@TE@TE@TE@TE@ffffTffffE@ffffTffffFE@T3333;E@TxE@ffffT|E@ Tffff6E@ETE@ffffT̬E@ ThE@ffff"TffffE@T̼E@3333TE@ffff>T4E@ffffT)E@ffff6TF@ATF@3333T3333{F@ TXF@3333KTtF@T̄F@ffff TffffF@T"F@1T#F@T|#F@ffffT!F@pTffff>*F@(T33330F@T5F@3333oT3333;GF@̴ThRF@TxWF@,TdF@ffffT3333CoF@ffffT{F@ffffT~F@ffffT$F@ffffBT3333F@ffff.TF@T3333+F@ffffTF@XTF@3333;TF@}TɑF@0TF@UTF@3333[TffffVF@TɟF@lTF@TffffFF@Tffff^F@ffffTF@TffffnF@Tffff>F@ T|F@̨U3333+F@,U(F@ U3333sF@ U9F@U|F@ffffUDF@@UF@3333$U(F@8,U3333 F@ffff0UlF@q0UpF@.UDF@3333-UlF@̜-UF@l.U3333F@-UF@d.UF@-+U3333CG@3333k(U̼G@33337%UG@1#UffffG@\"UyG@\!UffffNF@aU33333F@3333GUF@̠UF@̠UG@UF@̤T3333F@xTF@ŤF@9T3333+G@3333TffffG@UG@UI G@UG@8UffffG@3333UXG@3333UffffG@UG@ffffUG@3333CUyG@ U̜G@ Uffff>$G@3333 U3333&G@̨U3333.G@ffffNU3333+4G@U G@U@G@3333UCG@T3333F@3333Tffff~F@ffffT3333KF@TF@TF@3333T0F@T,F@3333?TF@ffff:T)F@XT F@T3333F@T3333F@T3333F@T3333F@3333TG@ T@ G@T\ G@T G@3333T< G@̈T3333 G@ffffT3333SG@3333TG@T3333kG@3333T3333G@pT3333sG@T9G@ffffTF@hT3333SF@T3333SF@T3333F@ffffTffffvF@3333'T3333F@T3333F@8TffffG@3333TG@3333TG@3333TG@ TffffG@3333T3333SG@ffffTffffnG@Tq G@3333T`$G@ T&G@Uffff'G@5U$G@U3333CG@3333{UG@TG@T̼ G@ Tq G@T8G@3333TffffG@T(G@ TffffG@ TffffG@ TffffG@ U)G@ffff Uh)G@3333 Uffff&G@ U#G@UffffG@̸UyG@eUa!G@3333U3333{$G@U33333'G@ U)G@ U)G@ U)G@ffff~U3333+G@U\.G@x U3333{4G@̐ Ux:G@ffffUT@G@ UCG@ UYEG@3333 UffffDG@Ufffff>G@3333 Uffff8G@h U01G@ Uffff.G@u U3333;,G@ffff~U3333+G@ffff~U3333+G@ffff~U3333+G@tUF@UF@UF@ffffVU3333F@U3333;F@tUTffffF@TffffF@TffffF@TffffF@3333mTffff^F@3333 oTF@3333 uT3333F@uT3333F@MuT3333{F@(tT3333KF@prTF@nTF@3333mTffff^F@3333mTffff^F@3333mTffff^F@3333 T3333eF@( TgF@3333 TlF@ T3333nF@ T3333oF@3333TnF@ffffTkF@ffff TLiF@3333 T3333eF@3333 T3333eF@3333 T3333eF@ffffRuX433337@P[Xdfffr9@.P[X4333Z9@5]XE9@3333cbX9@ffff.gX,8@kX4333y8@nX0A8@pX433337@pX̬7@qXdfff8@pX4333(8@pX|C8@loX4333d8@3333+qXdfffo8@sX̬q8@3333uXz8@ffffRuX`8@3333tX`8@8sXdfffƋ8@xoXp8@inX4333S8@lX٩8@3333lXdfffv8@lX433338@3333'iX\8@ffffiXdfff8@3333CmX<8@3333nX4333c8@̸lX̼(9@lXdffff39@,mX99@IpXA9@%nXI9@̈kXdfffX9@3333iX4333c]9@)iX]9@gXiS9@dXdfffO9@bXO9@aXdfffS9@,aXyo9@}`Xdfffr9@3333?^Xp9@\Xg9@P[X4333Z9@P[X4333Z9@P[X4333Z9@HDYL@YffffFM@FY9*M@ffff&Yffff(M@LYffffN)M@3333Y3333'M@ffff޾Yffff&#M@ffffY3333M@3333Y3333+M@ffffY3333[M@1Y33333M@YM@Y M@ffffYffffV M@Y3333M@3333YffffL@Y3333L@33333YffffNL@3333YL@YL@̄YffffL@8YqL@ffffYffff>L@YL@33333Y\L@ffffY̤L@3333YL@YAL@YL@Yffff6L@Y1L@Y3333L@YffffnL@3333YL@DYffffL@YdL@Y̬L@3333Y3333#L@̴YYL@fffffY33333L@YffffVL@3333YyM@YM@ffffYM@̤Y M@`Y M@,YPM@3333Yffff&M@̤YM@4Y3333;"M@3333Yffff.$M@\YffffN$M@3333#Y,M@Y3333K4M@0Y3333;7M@1YA:M@Y3333+;M@Yffff>7M@MY\M@,Y$CM@!YEM@YffffFM@3333Yffff6DM@Y)DM@Yp@M@Y=M@ffffjYffff4M@Yffff0M@Y9*M@Y9*M@Y9*M@3333K[̜@M@ffff*Z3333M@\ffffN[33333M@Q[ffffFM@\[3333M@ffffx[ffff΀M@̸[pyM@3333[nM@̄[ffffiM@͙[TbM@3333+[ffff[M@؛[YM@ffff[ffff~VM@[ffff~RM@U[PM@ [PM@ѯ[ffffNM@[JM@`[EM@3333[AM@̰[dAM@[tPM@й[PM@3333c[OM@`[3333LM@ffffN[ffffBM@[̜@M@ffff[dCM@ffff[ffffEM@ffff[4IM@ffff>[NM@[YM@[ffff^]M@3333K[ffff`M@[dM@q[dM@[0cM@I[̔^M@[^M@0[ffffaM@̷[,kM@ffff*[ffffFM@3333[M@̌[3333M@8[ M@x[ffffM@hu[ٱM@ffffq[M@3333#s[3333{M@3333?s[ffffM@m[M@3333g[qM@c[M@yY[qM@̤P[3333M@ K[M@LB[M@4[ffffVM@33332[xM@ffff67[ffffM@6[M@ffff/[M@l"[3333M@[ffffM@Z3333M@ZM@ffffJZM@3333;ZԩM@ZM@]Z!M@ffff*Z3333M@̴ZPRtI@ffffWRlI@e]ReI@3333O]R)hI@I@zR̴I@M.RffffI@3333+,R̞I@-RћI@9R3333I@9R3333I@9R3333I@ffff@ffff> J@fffz@HJ@<(x@ffffHJ@x@ffffHJ@x@ffffHJ@x@ffffHJ@fffz@ >J@@3333.@ffff6J@@3333@ffff> J@C@P%J@fff(@ ,J@ffff@.J@%@3J@?@!7J@@333F@ffff9J@G@̜BJ@ffff=@dHJ@C@ffffOJ@L@4PJ@@̼UJ@ffff@|]J@̨@3333dJ@ffffx@kJ@L`@ffffnqJ@@333E@33333vJ@@̼{J@ffff@|J@L@HJ@̗@ffff^J@@sJ@@ffffoJ@fff@mJ@ffff0@ffff>lJ@@3333lJ@@ffffhJ@L@3333dJ@x@3333`J@s@WJ@z@ITJ@@PJ@W@MJ@x@ffffHJ@4@ffff;J@4@ffff;J@4@ffff;J@4@ffff;J@@3333V@I@J@ffffQ@DJ@0@DHJ@@3333@ffffJJ@fff@ffff6KJ@@3333(@3333cGJ@@3333>J@@3333{0J@L@ffff-J@@3333@*J@@&J@@3333&J@@33331@ffff)J@{@ffff0J@@6J@4@ffff;J@LB@ffffM@̬C@ٚM@u)WC@ M@LNC@3333{M@ 1C@M@4333-C@ M@7C@M@43337C@ffff>M@)5C@ffffM@4333C/C@3333 M@4333'C@1M@#C@M@,!C@3333 M@4333C@$ M@ C@pM@9C@`M@ C@3333M@hfffB@3333&M@hfffB@Y%M@B@ffffDM@\B@yNM@̌B@ffff&TM@B@XM@ɓB@pZM@B@\M@LB@3333lM@iB@HaM@hfffB@]M@ B@]M@hfffB@33333XM@hfffB@UM@hfffƺB@$QM@4333B@lNM@hfffFB@3333FM@B@EM@B@3333[GM@4333SB@ffffFIM@yB@(PM@B@pQM@B@3333 OM@hfffFB@ffffOM@YB@tFM@hfffv C@ffff^EM@4333s C@KM@43333 C@3333KOM@9 C@ffff6QM@lB@3333 VM@B@XM@B@33333\M@B@$^M@ B@ffff._M@C@y_M@yB@3333KnM@4333sB@3333mM@IB@3333rM@hfffB@uM@|B@ffffvM@YB@vM@9B@ffffuM@hffffB@ sM@,B@!lM@4333SB@̴mM@B@oM@B@ffffvM@4333B@3333xM@B@ffff~M@,B@9M@ B@0M@B@M@B@M@̌B@M@4333B@M@4333SB@HM@`B@M@43333C@3333sM@4333C@fffffM@|C@dM@C@!M@hffffC@M@C@M@C@M@4333C@M@C@M@hfffVC@ٚM@iC@ffffM@4333%C@ffffM@43335C@33333M@4333#4C@ffff~M@p*C@ًM@hfffC@ffffM@4333C@3333SM@B@ffff&M@hfffB@3333 M@B@ffffM@B@3333cM@4333C@AM@IC@0zM@43336C@ffff_M@4333NC@3333{QM@\`C@FM@~C@p?M@yC@E@wS@6E@4333vS@3333{3E@hfffvS@ffff.E@hfffmS@E@fS@ffffE@hfff`S@ffffFE@̼HS@ffffE@xAS@ffff&E@:S@`E@$S@3333K%E@S@ffff(E@ S@<*E@hfffS@ffff)E@4333S@1E@ S@̴7E@hfff~S@:E@4333S@>E@/S@\HE@4333=S@ffff^NE@,LS@RE@US@UE@4333;bS@ffff^SE@kS@YE@S@3333]E@S@3333]E@S@UE@̜S@RE@S@ME@hfff^S@PKE@hfff^S@PKE@hfff^S@PKE@ 0W̄nH@WH@|lTW3333ïH@TW3333ïH@TW3333ïH@WffffޭH@ffffWffffNH@,W3333H@WH@WiH@H@3333W#VH@ffff#VH@3333$V)H@'VĶH@*V3333{H@ffff*-V3333H@x1V3333H@L2VH@ffff0V3333sH@ffffv-V!H@'VH@%VH@ffff%V`H@&VH@ffff ,V H@̠/VffffH@3333G2VffffH@33334VH@̜7VH@-:VTH@q=V)H@@VH@0AVffffH@ AVH@q=VH@:V3333H@3333:V3333+H@:VffffH@u;VH@ffff;VH@ffff*=VH@3333{@VlH@BV3333H@EVDH@EV3333H@ffffnDVyH@H@V̬H@3333H@%VH@V̼H@LVH@aVLH@̐VH@VH@"`Yfffff#L@3333#bYffff M@iffffZnYtL@ffffZnYtL@ffffZnYtL@ffffZnYtL@hkYqL@bYL@3333#bY3333L@3333bYqL@ThYL@oYL@uYffffL@ffff}YffffL@ffffYL@3333ˆYffffL@Y L@xYL@ffffzuY̔L@ffffNwYL@ffffF}YL@3333YyL@YL@YL@ffff}Y)L@̜Y3333{L@(YffffuL@PYffffnL@ffffYQkL@ffff•YgL@ffff–YffffbL@|Y33333YL@Y9TL@Y8PL@ȝYffffML@3333ˢY3333;KL@tY(HL@Y3333QP@8QP@3333Q3333P@Q P@PQpP@ffffvQ P@ffffrQP@3333QiP@3333sQffff}P@Q~P@Q1P@ffff&Q̌P@ffffzQ3333KP@3333cQffffP@AQP@QffffjP@dQP@Q(P@ffffvQ3333ǗP@QP@Q3333P@Q3333+P@Q3333+P@Q3333+P@Q3333+P@+h4333sA@=@,YB@@*WB@`ffffM@hfffQB@e@hfffIB@=@yDB@ 3333@hfffF6B@@i*B@@4333B@@̜B@`fff@B@M@pB@ 3333U @B@ @4333A@ 333 @hfffA@ @A@& @hfffA@ @4333sA@3@A@L@4333A@Y'@A@`fff@yA@`ffff@A@033336@4333SA@03333C@B@0333'@p B@Y8@ B@@~@4333B@`fff@B@@IB@@hfff6B@@@|B@`ffff@hfffFB@6@B@`fff @PB@ @hfff'B@ 3333 @6B@`ffff@DB@c@hfffvSB@@,YB@@WB@`ffffM@WB@`ffffM@WB@`ffffM@WB@`ffffM@,YffffTO@=)Y3333O@O{YLO@3333sY0O@oY(O@fffflY\O@3333hYO@3333gYO@XeY3333۲O@3333[eYO@ffff cY3333[O@<]YO@TYY̌O@aWYffffƲO@pTYhO@RYO@DUYO@ffffQY3333˾O@HYffffO@33333EY0O@CYԺO@3333@YDO@9YO@6Y3333O@$3Y)O@3333+-Y3333O@=)YffffO@3333+Y̼O@L1Yffff֨O@ffff4Y3333 O@E7YO@:Y|O@>YffffΦO@BYYO@CYffff>O@DY3333 O@3333CGYO@3333FY O@CY̴O@m@Y̴O@̔8YO@ffff8YfffffzO@ffff>YtO@ffffAYrO@3333CYmO@3333sAYfO@AYlaO@HY3333K[O@RYAUO@3333kXYaWO@ffffYYI\O@3333VY bO@3333TYjO@3333UYrO@ffffZXYvO@̄ZYtO@[Y!lO@ffff>^Y33333eO@3333_Y^O@ffff`Y3333cVO@aYffffTO@ycY̌WO@dcȲ\O@̼eYTcO@ffffkYeO@LpYxfO@tYffffpO@ffffzYffff6pO@3333OY3333{qO@8YXvO@YO@ffff҅YfffffO@ffff6YffffƉO@3333'Y`O@Y̜O@@YO@3333Y̘O@{YLO@{YLO@{YLO@{YLO@-3333XO@ffff^WffffP@ffff Wffff* P@ffffWffff P@4WffffP@(WP@3333ϏWffffP@ffff^WffffP@WP@WO@WP@W1P@(WP@W3333P@W̜P@0WP@ffffWaP@WP@ffffXY P@3333XffffJP@3333 XffffP@WPP@ W3333P@`WHP@3333W3333gP@W P@W P@ffff Wffff* P@ffff Wffff* P@ffff Wffff* P@ffff Wffff* P@.83333@7K@hfffg4@ZK@3@7K@83333@3333=K@83333@hKK@hfff3@ffffRK@Y3@LWK@3@ZK@83334@YK@83334@)VK@8333S54@̌WK@8333S54@̌WK@8333S54@̌WK@8333S54@̌WK@8333S54@̌WK@8333S54@̌WK@hfffg4@@WK@,4@JK@3@1BK@3@8K@3@7K@/x@@3@L"K@3@3333=K@ 83333@3333=K@3@7K@ 3@ffff4K@hfff3@/K@3@3333,K@{3@t&K@hfffX3@L"K@@@3@3333'K@8333SG3@P+K@83333@33330K@̝3@̔6K@83333@3333=K@0\RE@3333ER3333F@03333WRF@ffffYRF@3333WRE@VRffffE@3333WRE@XRffffE@ffffYRE@[R3333F@3333\R3333F@\R̬ F@i\R3333F@̨VR#F@ffffXRffffF2F@3333YRffff&7F@3333g\R3333QF@3333YR0cF@̀XRwF@1VRffffNF@3333TRffffF@SR\zF@RRfffftF@ffff>RRtF@XPR3333xF@ffffMRffffƂF@eIRXF@FR3333F@3333ERF@GR1F@ffffjJR3333#~F@TLRqzF@ffff KR̤uF@3333GKRffffoF@qLR3333ZF@MRKF@NRHF@PRYEF@\PR@F@NR3333#?F@NR8F@ORfffff7F@OR7F@PQR2F@3333kRR(F@TRffffF@3333WRF@3333WRF@3333WRF@3333WRF@13333]3333@@$\ffff@@$\!@@m\ffff~@@ffff\3333@@|\3333Ò@@3333S\@@3333]`@@l]D@@3333]ffff@@3333\|@@ffff\й@@<\@@$\!@@$\!@@$\!@@$\!@@25]3333{O@̘S]O@fffffT]O@̘S]O@3333W]O@3333wc]ffffO@3333Co]3333{O@Ar]O@ffffކ]O@Ȉ]3333O@̀]iO@܌]ffff.O@%]4O@ܝ]O@(]!O@5]3333O@]ĶO@]O@i]O@]ffffO@3333z]3333O@p]̼O@Lh]O@d]O@ffffvd]حO@3333^]ffffO@3333[]O@3333U]O@fffffT]O@fffffT]O@fffffT]O@fffffT]O@3ffff?R̜DffffV&R|D=RDM?R4333#Dffff?Rhfff6D3333S>R43333D3333_:R4333DQ6R|Dffff1R4333~D-RLD(RDffffV&RDH(R4333sDffff.ŘD8R̜D=RD=RD=RD=RD4`hfffs]@@q@@4333]@3333@@I4333]@ffff@@̴]@ffff@@1]@ffff@@x]@@@]@3333|@@]@`v@@]@r@@]@@q@@]@s@@H]@3333{x@@4333]@3333S|@@]@9~@@̤]@3333z@@<]@w@@1]@ffff^{@@4333c]@3333@@T]@ffff@@4333s]@3333~@@a]@@@hfff]@@@4333]@ffff֑@@]@h@@~]@8@@z]@ @@y]@3333C@@̤u]@@@hfffs]@(@@|v]@@@hfffw]@ffff@@x]@ffff@@Xz]@3333+@@t]@ffff@@P]@3333{@@1]@@@]@I@@]@3333@@hfffƕ]@3333C@@]@3333C@@]@3333@@4333#]@@@hfffn]@@@hfff]@3333[@@hfff]@@@hfff]@3333[@@4333]@ffffN@@]@@@y]@ffff6@@`]@Y@@]@D@@4333]@3333@@\]@3333c@@4333{]@@@4333ۦ]@!@@]@@@hfff6]@@@hfff]@3333@@Ԣ]@3333@@hfff]@ffffV@@]@@@x]@ffffF@@hfff]@̬@@4333]@3333@@4333]@Y@@\]@@@hfffα]@3333@@4333˭]@ffffn@@4333]@3333ˉ@@4333k]@@@ɩ]@@@@4333]@ffff@@4333]@ffff@@4333]@ffff@@4333]@ffff@@5| Y@4?I@4333[2Y@I@ 4333[2Y@вI@hfffN1Y@I@/Y@3333sI@̼.Y@I@+Y@yI@4333 ,Y@3333}I@hfffv Y@3333gI@hfff.Y@^I@hfff~Y@XTI@LY@3333PI@hfff>Y@ffff6MI@pY@HI@hfffY@DI@` Y@4?I@| Y@DI@h Y@ LI@Y@SI@4333Y@3333_I@Y@ffffI@,Y@ I@Y@I@̼Y@0I@4333Y@dI@LY@I@pY@3333#I@!Y@fffffI@4333#Y@I@!0Y@0I@4333[2Y@вI@4333[2Y@вI@4333[2Y@вI@4333[2Y@вI@6W@3333I@(WW@ATI@@W@̜&I@W@4I@IW@ffffW@EI@4333DW@ffff6I@hfffNW@.I@hfffPW@-I@DPW@ffff)I@4333TW@x'I@(WW@3333 $I@*@hfffY@j*@Y@0333*@Y@hfff&x*@4333Y@[*@`Z@03333*@̼ Z@̌)@hfffZ@,)@4333#Z@,z)@Z@0333s~)@hfff&Z@r)@4333Z@yG)@Z@Y$)@$Z@ )@hfffZ@)@#Z@Y)@4333#Z@`fff(@,$Z@(@4333%Z@0333(@hfff~$Z@L(@hfff~$Z@L(@hfff~$Z@L(@hfff~$Z@L(@:X@ffffFGB@,0Y@B@,0Y@3333gB@/Y@3333cB@@.Y@\_B@hfff>.Y@ffffVB@4333-Y@pKB@)(Y@ffffFGB@x!Y@3333CJB@hfffY@ffffRB@4333Y@̄RB@XX@VB@X@̤^B@4333X@33333mB@X@̤tB@4333X@DyB@hfffX@`yB@@X@IzB@hX@x~B@yX@ffffB@aX@3333B@hfffX@3333[B@43333X@B@̬Y@̙B@Y@3333;B@Y@9B@y%Y@sB@,0Y@3333gB@,0Y@3333gB@,0Y@3333gB@,0Y@3333gB@;Q@33333P@\Q@ffffQ@DQ@UP@|Q@3333Q@(Q@P@hfffQ@ffffQ@Q@3333#Q@Q@3333KQ@4333Q@ffffQ@Q@Q@\Q@3333Q@\Q@P@hfffQ@33333P@DQ@UP@DQ@UP@DQ@UP@DQ@UP@<4333sE@fffff@@4333E@!*A@pE@ffff&@@ E@3333c@@hfffE@$@@lE@ffffvA@4333sE@!A@4333E@I(A@4333ӎE@!*A@E@A@`E@ffffvA@hfffֻE@@@4333E@3333@@E@I@@9E@3333S@@hfffE@fffff@@yE@@@pE@ffff&@@pE@ffff&@@pE@ffff&@@pE@ffff&@@=hfff&E@C@@pE@3333+@@pE@ffffX@@iE@ffffFN@@4333sE@D@@hfffE@C@@4333E@F@@hfffvE@3333;J@@4333E@9L@@hfffE@9R@@4333E@3333[@@hfff&E@g@@YE@9o@@ɹE@3333p@@мE@u@@E@d@@E@@@lE@3333+@@hfffE@ @@hfff&E@3333{g@@ E@ffff]@@pE@ffffX@@pE@ffffX@@pE@ffffX@@pE@ffffX@@>yA@LS?@A@?@A@2333c?@̌A@?@hfffA@[?@A@ffffS?@ A@LS?@A@ffff&Y?@yA@~?@A@Y?@hfff6A@ٵ?@A@?@̌A@?@A@2333c?@A@2333c?@A@2333c?@A@2333c?@?@;@3333L@8333S+<@ffff~M@@;@M@̌;@ffff~M@;@YM@;@ffffM@y;@4M@y;@4M@y;@4M@y;@4M@y;@4M@;@M@8333<@M@83333&<@L@8333S+<@ffffL@ <@3333L@;@ffffL@83333;@L@;@L@8333;@L@;@L@hfff;@ffff^M@8333;@3333M@@;@M@@3333'R8H@̄Q̬`H@3333R:H@̈RSI5E@8STpE@ D8SI5E@@:S:E@:SKE@ffff=Sffffv]E@3333>STpE@ffff=SPoE@3333s8SdWE@ffff~8S3333DE@8S33338E@D8SI5E@D8SI5E@D8SI5E@Ct1S̜>E@3333C!SffffxE@ 3333C!S3333#@E@!S̜>E@ffff%SFE@ffff*S$ME@t1S̔cE@ 0S3333svE@/SffffxE@,SaE@*SffffUE@&SLE@3333C!S3333#@E@3333C!S3333#@E@3333C!S3333#@E@D8@#@@333@I%@$@333@ $@̶@L$@d@`ffffd$@@3333f@03339$@fffw@l$@ffff@#@@333@#@L`@̻#@LC@0333s#@@333%@y$@ffff@!$@@#$@@l2$@@0333@$@L @̌K$@fff@X$@@@_$@@Ld$@@`fff&u$@@l$@@3333@`fff&$@@`fff$@ffff@ $@@03333$@@̌$@@@%@L@I%@D@4%@@333l@̬;%@fff@`fff6%@@333@`ffff+%@@3333@`fff%@@3333@0333$@@333@ $@@333@ $@@333@ $@E8F@3333CB@F@3333!C@$IF@ffffB@IF@ffffB@IF@ffffB@IF@ffffB@4333F@B@hfffF@ffffB@4333F@3333B@F@ffffB@4333cF@ffffB@F@ȦB@hfffF@B@hffffF@B@̌F@3333CB@iF@!B@F@B@pF@B@F@ffffB@iF@̬B@F@B@4333#F@TB@hfffFF@iB@hfffF@3333C@hfffF@ffff C@F@iC@F@C@F@3333{C@4333SF@3333C@4333F@3333!C@F@3333!C@̬F@33333C@`F@ffffV C@hfffFF@YB@̷F@1B@ٽF@tB@hfffF@ffffB@IF@ffffB@F`Z3333L@̐Z3333CL@)Z!L@Z!L@Z!L@Z!L@Z)L@Z3333L@QZ8L@ІZ̬L@̐ZL@-Z3333L@3333ZxL@Z3333L@ffff^ZL@HZffffL@Z8L@3333Z3333éL@3333Z3333#L@ZL@3333׮ZffffƫL@3333߰Z3333L@mZ3333L@̐ZffffL@ffffZ̬L@ZtL@EZffffNL@ffffZ3333L@Z3333+L@̬Z̬L@PZ3333+L@ZhL@ZffffL@ZL@lZ3333L@(Z L@3333Z(L@4ZL@ffffZyL@Z L@ffff>ZDL@Z3333CL@Z!L@GffffX3333[gO@ffffXO@X3333zO@ffffXtO@DXO@ XO@aXffff֓O@3333?X̼O@mXffffO@ffffXffff&O@4X~O@ffffXvO@3333cX̴oO@ffffXhO@X3333[gO@̰XhO@3333X3333lO@ffffXoO@X3333zO@X3333zO@X3333zO@HlY3333M@QvY3333SN@$Y@)N@ffffY@(N@ffffBYffff/N@ffff.YD6N@3333Y8N@Yffff@N@̛YffffJN@3333YffffQN@ffffY3333SN@ōYNN@ffffVY3333GN@YffffAN@Yx:N@Y33330N@ffffxYN@QvYHN@4xYffffN@ffffxY3333M@ffff~Y3333CN@8YffffM@ffff~Y3333M@3333wYdN@3333YN@ffffnY N@Y9N@ffffYqN@lYffff'N@$Y@)N@$Y@)N@$Y@)N@IhfffֆL@`D@L@ffff*E@L@ffffD@̬L@̔D@L@ffffnD@lL@D@L@ffffD@D@L@ffffD@L@ffffD@L@ffffD@Jx.S@NK@$S@DK@,hfff/S@jK@hfff7S@pK@hfffNDS@ffffuK@HS@,vK@hfffJS@qK@4333OS@mK@RS@ffffqK@4333SS@3333kvK@hfffTS@{K@4333[S@̜K@dS@цK@hS@DK@hfffjS@K@lS@3333 K@hfffNnS@0K@0xS@3333K@S@|K@$S@ffffvK@hfff|S@ rK@sS@xnK@̼qS@ffffmK@qlS@ffff~jK@hfff.iS@fK@4333hS@3333sbK@YlS@ffff^K@hfffnS@ffffXK@hffffoS@ffffTK@llS@ffffQK@dfS@NK@4333#dS@ffffOK@̴dS@RK@iaS@ffffUK@[S@̌WK@4333VS@ffffXK@OS@\K@XCS@3333]K@hfffAS@t]K@hfff^@4Vffff&Y>@ 4Vffff&F>@ܝV̬2>@eV->@̼Vfffff2>@3333V<>@V2333H>@3333Vffff&Y>@V|S>@4Vffff&F>@4Vffff&F>@4Vffff&F>@MɴR̼K@R+L@XRffffFL@RK@ċR3333K@ffffRK@ffff*R̼K@RK@̰RK@ffffŽR K@RL@RffffL@R L@9R3333L@ɴRffff^L@lR#L@XRl'L@|R+L@ffffR(L@3333R!L@ffffR3333L@IR3333cL@3333wR3333L@R3333[ L@XRffffFL@XRffffFL@XRffffFL@N3333T̔G@S3333-G@3333Tffff$G@3333/Tffff%G@$Ť$G@T!G@-TG@3333c Tffff G@T̄#G@ffff" Tffff&G@Tl)G@iT3333C,G@3333Sffffv+G@ffffS,G@S3333-G@S3333'G@S3333#G@3333#S̔G@S<G@eSAG@ffffS3333G@ffff"S̔G@`T8G@pS3333sG@TffffG@T<G@ffffTG@3333Tffff$G@3333Tffff$G@3333Tffff$G@O04333C?]@GH@8]@ffffH@#hfffN]@JH@PG]@GH@4333E]@ JH@F]@PH@F]@8ZH@hfff@]@dH@4333C?]@ffffkH@4333C]@ tH@iN]@3333SH@X]@ffffΑH@4333a]@ffffH@h]@3333˫H@4333+l]@ffffH@hfff>m]@33333H@ l]@3333H@k]@4H@hfffm]@ H@o]@QH@q]@3333H@s]@ffffH@hfffy]@H@hfffv]@yH@8]@ffff&H@hfff}]@3333{H@hfffx]@HH@t]@3333H@lq]@ffffH@hfffn]@̃H@m]@ffff6~H@hfff`]@YlH@T]@XH@4333S]@iQH@hfffN]@JH@hfffN]@JH@hfffN]@JH@P~=@ &hfff>@hfff%8333=@Y.&hfff=@n&=@8333&8333S=@&=@ &Y=@L&̌=@&hfffƏ=@hffff&8333ӌ=@&̂=@v&~=@8333c&=@@X&=@YP&=@8333s%8333=@%=@hfff%hffff=@hfff%=@ %hfff>@L&8333=@Y.&8333=@Y.&8333=@Y.&QPhffff);@-Q@hfff<@3333ZQ@G8333sr<@TQ@8333sr<@TQ@8333sr<@TQ@8333sr<@TQ@<@3333UQ@̬<@QWQ@8333S<@EYQ@hfff<@3333ZQ@hfff<@5YQ@hfff&<@ffff>WQ@<@SQ@hfffF<@ffffrPQ@<@3333/NQ@@<@PLQ@r<@IQ@hfff&q<@lGQ@f<@EEQ@hfff&@<@DQ@L<@y@Q@hfff<@>Q@C<@3333;Q@@T<@(9Q@,[<@ffff7Q@U<@ffff6Q@K<@ffff6Q@<@8Q@L;@ffffN8Q@ ;@33337Q@,;@5Q@hffff;@@4Q@ ;@ffffn2Q@̬;@/Q@ ;@ffff/Q@hfff;@ 2Q@8333s;@̰2Q@8333;@ffff0Q@;@.Q@hfff;@/Q@8333v;@ffff0Q@o;@0Q@];@33330Q@hfffFH;@-Q@B;@3333#/Q@[;@`1Q@̌m;@3333W3Q@hfffj;@5Q@S;@ffff8Q@LE;@ffff9Q@ ,;@33339Q@hffff);@ffff;Q@ >;@3333M@8333S;@19M@8333s;@7M@,;@8'M@8333;@3333 M@̌;@ffff~M@T̬<@@3333̌[=@2=@ffffL2=@ffffL2=@ffffL2=@ffffL?=@8333I=@̌[=@ hfffV=@ffffwH=@@3333̌A=@ y==@K &=@@33338̬=@l=@ffffhfff& =@<@ffffhfff<@ffffv̬<@@3333L<@̬<@@3333MhfffF<@@3333,<@ffffhfffF<@~ <@@33339hfff<@<@ffff8333<@fhffff=@\9=@2=@ffffLU8333S=@ffffz俠=@hfff@k=@ffff&]=@ffffz̬U=@ffffz8333S=@3333 \=@ܿj=@gfffտ8333=@ǿ=@,̤=@hfff8333s=@=@4333ƿ83333=@`ӿy=@3333;hfff=@3333s=@l@k=@ffff&@k=@ffff&@k=@ffff&Vhfff]@̜>@&^@ffff&?@&^@2333c?@hfff>^@y>@4333^@̜>@4333^@)>@]@P?@hfff]@2333@?@1]@Ld?@^@ffff}?@ ^@ffff&?@H^@̌?@a^@2333~?@^@y?@hfffV^@2333q?@^@2333q?@X^@ffffm?@4333^@̼b?@4^@yY?@^@Q?@4333^@2333E?@ ^@ :?@^@@3?@,^@@'?@4333C^@2333?@4333^@2333C?@|^@?@hfff"^@ ?@&^@2333c?@&^@2333c?@&^@2333c?@Wffff"S3333;L@RlFL@ffff"S3333L@3333!Sffff~L@H Sffff6L@3333S0'L@lS1,L@S3333.L@4S1L@ S?L@iSlFL@SCL@3333S3333s@L@S;L@S!6L@S2L@̠Sx0L@ S8)L@ffffrSd#L@SIL@RlL@Rffff>L@R̜L@d S3333;L@̌SL@ffff"S3333L@ffff"S3333L@ffff"S3333L@XY}O>iOhfffF>iO4333>84O43333>2333IO > ]O>2333gOhfff>!nOhfff&>9wO43333>Y}O4333>)wO >ffffiO>2333c\Ol>XOY>iROhfffF>23336Ohfff>4O4333>ffff/O4333S>$O>2333Ohfff>iO4333>iO4333>iO4333>Y(8333S?@ffff.H@@@3333H@"4333c@@xH@̔@@ffff.H@4333É@@ffffH@hfffv@@̼H@@@H@̌}@@H@4333n@@3333+H@b@@ffff֎H@[@@H@lO@@lH@@4@@ffffH@4333%@@PH@hfff@@3333óH@hfff?@3333H@8333S?@H@8333?@3333H@hfff@@IH@@@ffffH@,@@3333 H@;@@H@P@@H@YW@@3333SH@iT@@qH@4333U@@̼H@4333#[@@H@`@@ H@)n@@33333H@@@H@4333S@@ffffH@@@33333H@4333Ә@@H@4333c@@xH@4333c@@xH@4333c@@xH@Z3333SffffJ@RJ@:SffffFJ@hSTJ@TSffffVJ@RffffJ@ffffRAJ@aRJ@eR3333sJ@UR3333+J@̴RJ@)R`J@iR3333J@3333RJ@3333'R3333[J@ffffR̤J@aRJ@xRffffNJ@3333RffffJ@RTJ@3333kR3333SJ@ffffFRJ@RffffJ@3333WRJ@XRJ@TRJ@ffffRffffnJ@ffffRffffnJ@ffffRffffnJ@ffffRffffnJ@ffffRffffnJ@ffffRffffnJ@3333/RffffJ@RffffJ@RJ@3333oRJ@̨RffffnJ@ܻRJ@ffffR3333J@RffffJ@,R3333J@R3333J@4R0J@3333R3333J@RJ@3333Rffff^J@ffffFRffffJ@xRJ@yRJ@R3333J@ffffRffffJ@SؼJ@3333SJ@3333SJ@SJ@3333{R3333J@RJ@3333{RffffJ@ffff&SffffJ@SffffFJ@[3333kSJ@SK@>hSTJ@SffffFJ@ SJ@SAJ@ S3333[J@ffff5SffffJ@X:S,J@KSJ@ffffFNSJ@̌RSJ@ffffbYSJ@ffff6_SffffJ@ffff_S̴J@]SffffJ@`SQJ@ffffgSYJ@3333kSJ@%gS\J@ZSffffJ@ffffUS3333J@lRS3333CJ@ASJ@9SpJ@1SqJ@.SffffJ@3333#6SK@8S@K@7S3333C K@5SD K@33337*Sffff^K@3333'S9K@̌&S3333K@#S!K@ S K@)SffffK@4Š K@!"S3333K@ffff$SK@̬#SffffK@ SffffK@3333SK@ SK@S3333cK@ SK@33337 SK@ffff S@K@SK@S K@̼ S9 K@XSh K@tS3333;J@ffffVS3333J@SffffJ@S3333J@0SJ@&SffffJ@,SJ@ffff/SJ@,SffffJ@p#S(J@ffff" S3333SJ@hSTJ@\fcL@c|L@cffffL@WcffffL@3333cqL@ffff cffff6L@cL@3333yc\L@ffffcL@čL@ffffcffffL@fc L@4chL@ffffcL@c1L@cffff&L@ƚcL@cL@ޕc3333L@c|L@cffffL@cffffL@cffffL@]hQdfffk2@Q43332@ QPx2@ffffVQo2@ffffQdfffk2@Q4333~2@Q2@Q43332@3333_Q2@QPx2@QPx2@QPx2@^xLd̈P@ffff4cffffʢP@ KcffffNP@ffff4c̴P@ffffc̈P@3333AcEP@ffffcP@Ld@P@̮dffffʢP@̄cffff>P@ffffRcŠP@KcffffNP@KcffffNP@KcffffNP@_Y\ N@ffff\,N@ffff\)*N@q\YN@\3333N@\3333cN@Q\3333sN@ffff\N@ffff\ N@\3333N@\!N@ffff\3333N@ffffF\N@Y\ffffN@y\ N@3333\3333 N@3333\̌!N@3333W\%N@,\3333#+N@\,N@ffff\)*N@ffff\)*N@ffff\)*N@`HRhfff-II@R5Iffff=R9NR*IQR9,IffffBRRl*I̸MR"IffffARhfff%I1>R4333s!I>RIBRlIuJR4333INR,IffffRRhfffIffff:SRhfffI3333QRhfffITRRIPR43333IMR)ILRHffffHRhfffI3333CR I3333@V@>@ V@23333>@V@̼>@4333V@>@|V@>@hfffV@2333S>@hfffvV@2333>@hfffV@23333>@V@ffff>@@V@ffff>@V@>@hffffV@>@hffffV@>@hffffV@23333>@V@I>@V@2333>@V@>@V@ɷ>@V@,>@,V@>@ V@23333>@ V@23333>@ V@23333>@c<@@BC@hfff6@@8C@@@3333CmC@4333#@@ffffgC@y@@3333CfC@hfff6@@,[C@@@IC@<@@BC@hfff@@GC@̬@@)NC@,@@ffffVUC@<@@bC@@@)pC@y@@ffff{C@hfff@@XC@hfff@@8C@٬@@hC@<@@$C@,@@ffff~C@hfffV@@ffffxC@@@3333CmC@@@3333CmC@@@3333CmC@dp3333 ZM@mZ8N@+ffffb}ZM@33333Zffff.M@ffffZM@33333Z33333M@Zffff&M@Z̜M@3333ZtM@tZM@ffff.ZM@%Z`M@ZM@БZ3333M@ZM@Z3333SM@ٔZffffM@EZ3333N@yZN@3333 Z3333#N@ffffZ0 N@3333Zffff N@ffffZ N@3333ېZN@3333Z|N@tZ̼N@̈ZxN@3333ˉZ3333c N@ԇZdN@ffff6ZN@wZ8N@tZaN@@sZ3333N@mZ3333N@HqZffffN@|zZ3333N@ȁZ9N@3333kZ N@Z3333cN@|ZN@3333SxZ3333N@3333xZN@ffffb}ZM@ffffb}ZM@ffffb}ZM@eV;@xN@hfffF;@N@ ;@xN@m;@|N@W;@ffff&N@V;@ffffN@8333];@@N@r;@8N@L;@}N@;@3333{N@;@3333+N@l;@N@8333;@3333N@L;@N@hfffF;@3333}N@8333s;@yN@ ;@xN@ ;@xN@ ;@xN@fk=@LWO@̌=@3333O@hfffx=@HoO@l=@jO@8333=@̴jO@@=@qO@hffff=@|O@`~=@O@=@3333O@hfffF=@}O@8333S=@ffffpO@̌=@eO@=@]O@8333ӽ=@9YO@=@LWO@=@̼^O@`=@ cO@@u=@jO@k=@3333 qO@̬p=@`rO@hfffx=@HoO@hfffx=@HoO@hfffx=@HoO@g0=@3333 RO@hfff=@gO@:=@HZO@hfff&8=@bO@K=@gO@8333SX=@i_O@c=@P\O@w=@^O@hfff=@3333[ZO@@t=@3333 RO@̬V=@DTO@83337=@ffff6SO@0=@WO@:=@HZO@:=@HZO@:=@HZO@hxc@NQ@]d@4XQ@ ]d@OQ@ d@NQ@4333/d@4OQ@c@ RQ@c@Q@XQ@ffffbQ@PQ@P@̬Q@P@Q@MP@Q@ffffP@Q@ffffP@Q@ffffP@jh)Q@̬Q@Q@̴Q@ HQ@3333ۅQ@Q@̌Q@4333×Q@Q@̎Q@̬Q@)Q@ffffքQ@!Q@̴Q@̌Q@tQ@HQ@3333ۅQ@HQ@3333ۅQ@HQ@3333ۅQ@khfffQ@}Q@4333Q@3333Q@ hfffvQ@3333}Q@hfffQ@ffff"Q@hfffFQ@LQ@hfffQ@ Q@4333Q@̴Q@hfff6Q@3333Q@hfffQ@hQ@4333[Q@ffffvQ@4333Q@9Q@4333Q@}Q@hfffvQ@3333}Q@hfffvQ@3333}Q@hfffvQ@3333}Q@lh Q@3333߇Q@Q@܍Q@ Q@3333߇Q@4333ӗQ@3333ˉQ@ Q@ŌQ@hfffNQ@܍Q@Q@ffff6Q@hfffƲQ@Q@4333Q@̸Q@ Q@3333߇Q@ Q@3333߇Q@ Q@3333߇Q@mpA@3333uO@4333A@3333O@64333A@ffffO@4333A@ffffO@4333A@ffffO@4333A@ffffO@4333A@̼O@hfffA@O@4333ӯA@3333O@4333A@ffffVO@ܰA@O@̬A@̴O@A@̴O@A@ O@4333SA@ffffO@ }A@O@oA@\O@hfffjA@3333O@IqA@ffffO@yA@,O@zA@3333;O@4333yA@AO@tA@̴yO@ynA@3333uO@hfff6nA@xxO@ oA@|O@hfffnA@TO@oA@)O@hfffsA@O@4333rA@3333O@4333mA@ffffO@,mA@ԜO@jA@`O@fA@ffffO@YA@ O@̬FA@O@hfff&BA@O@@CA@PO@hfff:A@3333O@hfff-A@,O@hffff'A@O@"A@ffffO@4333A@xO@pA@O@hffff$A@tO@4333s,A@3333O@hfff6A@3333O@4333HA@ffff~O@pRA@3333O@4333NA@3333O@mA@DO@4333CnA@ffffO@~A@O@hfff}A@4O@yA@ffff&O@4333A@ffffO@n4333@@3333#O@4333sA@3333cO@@@̸O@ @@3333cO@̌@@ffffO@ @@3333sO@43333@@3333cO@l@@ O@hffff@@̄O@@@ffffO@4333sA@HO@0A@O@@@3333#O@hfff@@XO@<@@O@hfff@@ffffO@hfffF@@PO@ @@ffff~O@ @@O@hfff6@@3333۰O@4333@@33333O@y@@DO@@@̸O@@@̸O@@@̸O@o8333{>@)bO@hfff>@ffff^O@>@)pO@@>@3333wO@Y>@3333{O@,>@|O@>@ffffO@@>@ffff^O@8333>@iO@hfff>@3333+zO@8333>@3333nO@>@ffffvlO@8333>@lgO@>@TdO@8333>@)bO@l>@(cO@>@cO@8333{>@dO@8333>@hO@>@)pO@>@)pO@>@)pO@pP =@a\O@lT>@dO@'`=@xO@8333>@ffffO@@=@ffffޡO@8333s=@3333O@8333=@O@8333s#>@3333|O@lT>@!jO@8333Q>@̌gO@hfff:>@fffffO@$>@a\O@>@T]O@'>@3333eO@L7>@)oO@hfff#>@3333vO@̌>@ffffxO@y>@ffffzO@̬=@,O@hffff=@ffffO@=@)O@,=@ffffO@d=@ffff^O@lL=@3333O@<=@dO@hfff=@3333O@ =@ffffO@L=@ffffO@=@ffff.O@̌=@dO@/=@O@,O=@ffffO@83333_=@TO@=@8O@8333Ӹ=@`O@hfff=@̬O@̬=@ffffFO@hfffF=@TO@`=@xO@`=@xO@`=@xO@qhfffƦ>@yP@U?@@P@8333s+?@ffff҆P@8333s+?@ffff҆P@8333s+?@ffff҆P@8333s+?@ffff҆P@ 6?@ffff΃P@`=?@HP@F?@3333#}P@U?@zP@lK?@yP@8333'?@ffffzP@hfffF>@}P@hfffƦ>@PP@ >@P@>@P@hfff>@3333P@ >@3333ӐP@?@@P@8333s?@P@hfff,?@ffff҈P@8333s+?@ffff҆P@r hfff?@3333XP@,[@@3333xP@!9B@@bP@9B@@bP@9B@@bP@9B@@bP@4333U@@^P@X@@\P@,[@@3333ZP@iZ@@3333XP@hfffU@@XP@@Q@@3333ZP@=@@^P@4333#@@]`P@4333 @@bP@ ?@ddP@?@PfP@8333S?@3333gP@8333?@hP@Y?@ffff2iP@?@ffffjP@ْ?@oP@hfff?@rP@hffff?@ffffvP@?@3333xP@hfff@@ffffxP@)@@XuP@@@3333+rP@,@@3333pP@ *@@lP@4333.@@̰jP@hfff.@@ffff:hP@4333C0@@dP@l6@@bP@9B@@bP@sffff5RjT@=Qffff.|T@ffff5RkT@3333'R3333mT@ffff.RnT@EeQzT@@RQ{T@=Qffff.|T@t^QxT@QffffuT@3333R3333lT@-RjT@3333/RTkT@ffff5RkT@ffff5RkT@ffff5RkT@tmaV3333KmJ@V3333SxJ@BV3333coJ@IV3333KmJ@0WVnJ@̔^Vffff&oJ@maV3333pJ@maV3333pJ@maV3333pJ@uU@D@4333U@ffff E@4333U@ffffD@hfffU@3333cD@U@PD@hfff6U@XD@8U@D@U@D@4333 U@ffffD@U@D@U@H E@U@ffff E@hfff~U@ E@hfff.U@$E@4333U@0D@4333U@ffffD@4333U@ffffD@4333U@ffffD@v>@N@y ?@̜ O@ @>@3333N@8333S>@ffff6O@L>@ffff>O@>@3333 O@8333>@̜ O@>@QO@y ?@,N@8333?@N@Y>@N@>@hN@@>@3333N@@>@3333N@@>@3333N@whffff>@,M@83333?@=M@?@ffffvM@Lr?@3333[M@d?@,M@(?@ffffM@L>@hM@hffff>@3333M@8333s>@fffff$M@?@(M@y?@q*M@8333+?@3333.M@l@?@t6M@`L?@=M@8333_?@6M@ n?@Q5M@?@ffff1M@hfff?@/M@?@1M@hfffF?@33333/M@L?@3333,M@?@y'M@83333?@M@l?@M@?@ffffvM@?@ffffvM@?@ffffvM@x 4333\@ffff<@Y-]@Y=@A4333+-]@"=@Y-]@ffff6=@+]@=@hfff(]@ffff=@']@=@0%]@ffff =@Y!]@̬$=@hfff]@ffffV=@4333]@2333 =@4 ]@<@!]@<@X"]@p<@̼ ]@ffff<@4333]@ <@@]@ <@]@23333<@0]@<@A]@<@]@<@9]@=@hfff]@&=@hfff]@23330=@hfff\@yG=@4333\@ffffO=@ ]@2333d=@]@2333s=@]@ffff&=@̄]@23333=@`]@ =@D]@ٳ=@<]@2333ӹ=@̌ ]@P=@̤ ]@Y=@4333]@ɲ=@hfff]@ffffv=@hfffF ]@ =@4333 ]@=@ ]@=@, ]@2333ӄ=@@ ]@t=@hfff]@ffff6m=@hfff^]@f=@4333# ]@b=@hfff ]@a=@̌ ]@\=@ ]@̌U=@hfff]@0O=@ ]@@=@hfff]@ffffF;=@]@ffff;=@̔]@ffff8=@]@ffff/=@)]@\'=@ ]@-=@(]@2333s<=@hfff]@ffff@=@̔"]@==@hfff&]@ffff<=@(]@ffff<=@y*]@23339=@4333K*]@23330=@4333+]@(=@4333+-]@"=@4333+-]@"=@4333+-]@"=@yq]@2333=@hfffF!]@>@hfff~]@ffff >@]@)>@hfffF!]@=@hfff]@2333=@hfff]@I=@hfff]@\=@]@P >@q]@>@]@I>@ ]@ >@hfff]@9>@̴]@̼>@D]@ffff>@hfff~]@ffff >@hfff~]@ffff >@hfff~]@ffff >@zhfff\@=@]@>@| ]@ >@| ]@ >@| ]@ >@| ]@ >@x]@9>@)]@>@]@2333=@4333;]@`=@4333 ]@Y=@a]@ffff=@4333]@=@hfff\@=@\@>@]@>@]@>@@]@2333>@ ]@>@| ]@ >@{hfffn\@̬>@\@]>@hfffn\@,2>@\@5>@hfffF\@y<>@\@D>@4333c\@I>@4333\@ffffJ>@4333\@O>@\\@PU>@P\@I]>@4333\@]>@hfff\@2333SX>@̔\@̬L>@\@ffffA>@\@ffff">@hfff\@̌>@1\@ #>@\@,0>@hfff\@23331>@4333S\@2333(>@hfff~\@̬>@4333#\@@>@`\@ffffF*>@hfffn\@,2>@hfffn\@,2>@hfffn\@,2>@|hfff>$V@y?@TV@2333?@4333STV@P?@hfffVRV@̜?@4PV@ffffƿ?@hfffMV@?@hfffHV@?@hfffCV@y?@L?V@2333ӛ?@4333$V@?@hfff&V@L?@hfff-V@?@̔0V@ffffv?@43332V@?@43334V@P?@P7V@,?@4333=V@2333?@GV@?@4333 QV@P?@TV@?@4333STV@P?@4333STV@P?@4333STV@P?@}yV@3333cG@4333S3W@ffff..H@X2W@ffffH@4333'W@̄ H@LW@ffffH@W@3333kG@4333W@G@ W@3333cG@4333cW@iG@iV@lG@yV@<H@W@ffffH@W@ffffH@W@ffff!H@hfff^W@-H@9W@ffff..H@1W@.H@W@a+H@W@3333cH@hfffW@H@4333W@ffffH@4333"W@ffffH@,)W@H@hfffN)W@̬"H@(W@<*H@hfff.W@̼'H@4333S3W@` H@X2W@ffffH@X2W@ffffH@X2W@ffffH@~e@4333SyCf@hfffVCf@gCf@nCe@psChfff:e@9wChfffre@4333SyC,e@xChfffe@hfff6lCe@hfffeCe@4333bChe@]Ce@hfffVC1e@hfffVChffff@4333S\Cf@hfffaCf@gCf@gCf@gC@0G@~@CG@~@3333S7G@@3333w@3G@La@A1G@L@33333G@@̼1G@X@33333.G@̠@@G@@0G@@3333@ffff&G@@3333`@3333:G@LZ@CG@F@;G@~@3333S7G@~@3333S7G@~@3333S7G@V?K@`ffff̄\K@̄\K@[K@̌E3333ZK@`ffff3333{TK@!HMK@ 3333e)CK@jH@K@`fff?K@`fff?AK@VffffGK@@*OK@ 333 dYK@̄\K@̄\K@̄\K@>,@L@pfff-@3333SmM@@333-@ffffVdM@-@`M@pfff-@ffffYM@pfff-@ffffFQM@pffff-@3333KM@-@ffffEM@@333s-@dAM@-@3333;M@@333s_-@̄2M@@333>-@A&M@@3333*-@M@@-@ffffM@@333,@ M@@333,@ffffvL@@333s},@̜L@̌Q,@L@>,@ffffVL@pfff&m,@9M@@333,@4M@pffff-@ffffGM@pffffC-@WM@̌s-@̜]M@@-@3333CeM@@-@3333SmM@pfff-@fffflM@-@jM@@333-@ffffVdM@@333-@ffffVdM@@333-@ffffVdM@h43333-E@̼)C@,E@q~C@*̌~E@<,C@vE@1C@tE@33336C@pE@=C@mE@3333=C@hfffcE@3333:C@hfffvWE@p:C@hfffKE@̤=C@DE@ffff>C@43333-E@?C@.E@ffff6FC@̌7E@$NC@̬:E@ffffFRC@:E@XC@4333SCE@a_C@hfff\E@3333dC@)lE@eC@hfffwE@eC@)E@gC@hfff֔E@PlC@4333SE@3333;oC@0E@pC@hfff6E@pC@E@3333CuC@yE@IyC@yE@ffffV{C@̷E@q~C@4333E@3333#}C@,E@8yC@E@rC@E@kC@\E@ hC@E@3333[C@ܗE@33333MC@E@$FC@E@ffff>C@hfffE@ 4C@hfffE@ffff+C@9E@̼)C@̌~E@<,C@̌~E@<,C@̌~E@<,C@ffff[(F@̼[HF@̼[ffff*F@[<)F@ffffv[(F@[+F@[̜-F@ffff֕[1F@ffff>[2F@[\6F@D[ffff.9F@D[7F@[33334F@ffff[ffff.9F@ԡ[IcffffQ@9cffffbQ@̐3c3333'Q@ffffv c3333Q@3333cdQ@3333cdQ@3333cdQ@A\3333G@3333K\ H@\`G@\H@\H@\\H@̌\ H@\ffffH@3333\̔G@3333K\xG@ffffZ\G@\3333G@3333\G@3333\pG@3333s\3333G@ \3333SG@3333w\ffffG@\\G@\ffffG@A\ffffG@m\3333G@\`G@\`G@\`G@<\YA@̀h\ffffvBB@.3333h\YA@3333j\A@ffffvn\ffffA@r\8B@@y\ffff& B@3333|\̜B@D\ffffB@3333\B@\B@3333W\B@ђ\3333B@\ B@ffffڗ\ B@\3333 B@3333ۜ\ffff& B@3333?\ffff B@\ B@\ B@ffffr\3333B@0\3333B@ffff\3333 B@<\̌B@Щ\ffffB@Ġ\B@ffff\3333[B@3333o\ffff,B@\=B@ffffF\3333AB@\ffffvBB@i\8B@\*B@3333\B@3333\!B@t\\B@ffff2\ B@8\fffffB@\QB@\0B@ {\3333B@v\3333B@ffffq\)B@l\A@̀h\3333A@3333h\YA@3333h\YA@3333h\YA@0\3333&M@ffff[̌iM@#D[GM@3333[33333BM@-[ffff=M@ffff[:M@ffff[3333k6M@ffff6[d2M@}[h*M@[3333&M@}[('M@%\h,M@ \4M@(\:M@M \?M@ffff \aFM@3333S\IM@3333'\ffffHM@ffff*\IM@\3333OM@ffff\`WM@ffff\cM@3333 \̌iM@ffff\hM@3333_\̬dM@=\cM@ffff\ffff>^M@[3333S[M@[3333\M@[L\M@T[)YM@[ffffWM@ffff[WM@ffff[iTM@D[GM@D[GM@D[GM@XPffffJ@2333COK@yO3333K@yO3333K@yO3333K@yO3333K@2333OK@ffffO3333s K@2333COffffvK@ffffOJ@O3333SJ@O3333J@OJ@POK@̤ǑK@OK@OJ@̬ODJ@̼OJ@lOYJ@OtJ@2333OfffffJ@OffffvJ@O3333J@3333PHJ@ffffPJ@ffffPffffJ@D PK@̬P( K@!PffffK@3333$PK@3333)P3333K@,P3333[ K@)P3333K@3333#*PtJ@3333k,P3333J@0P̔J@̈5PffffJ@;PffffFJ@@PJ@GPyJ@ffffRKPJ@3333PPffffJ@3333 SP3333;J@3333RPJ@9LP3333KJ@!LPJ@qIP8J@3333wJP!J@-HPffffJ@3333G>PAJ@LAPffffJ@NPDJ@aPffffJ@HePpJ@ffff^Pffff6J@3333XP̔J@ffffjUP3333J@ffffFTPlJ@TPfffffJ@ffffRWPffff^J@3333cXPffffJ@3333;WPJ@TPffffJ@ffffUPJ@ZPJ@]PJ@t`PJ@aPffffJ@HePK@nP K@tPQK@0Pa,K@DPx6K@P9=K@HPffffFEK@ffff*PffffGK@pPAK@3333[Pffff66K@$P 0K@3333PffffN+K@ɘP!K@4PK@̴PffffK@pPK@tP"K@P3333.K@Pffff66K@Pffffn>K@tPBK@TPpJK@POK@ffff>PiPK@̀PffffSK@PbK@̐P̴fK@̌PffffqK@lP3333vK@PffffyK@QPffffzK@ffffP3333~K@DPK@aPffffNK@ffff^PffffK@3333P3333[K@ffffPK@3333PЌK@3333P3333K@ffffPI}K@XPffffyK@3333PwK@ffff~PfffftK@ffffNP3333sK@ffffPffff^sK@ffffPLrK@\PffffpK@ffffP$mK@`P8kK@ffffP3333jK@3333wP hK@P[K@PffffWK@3333όPIK@9Pffff6CK@9P4P K@3333;Pffff$K@>P4K@:P3333K@8PffffK@<8P|K@6P3333kK@ffff0PpK@3333+P@K@'P3333kK@3333W%PK@ Pffff.K@PK@ffffRP@K@PK@PffffK@PK@4P3333 K@3333Pffff"K@ P K@3333Pffff^ K@ffffP3333"K@ffff.Pffffv*K@P3333cAK@qP3333NK@ffff*PVK@̤Pa^K@lP(_K@ffff~PYK@P3333KTK@P3333sHK@ffff~P3333;BK@ffff P3K@3333P3333,K@3333Pt$K@)OffffK@hO̜K@OT K@2333O3333 K@O K@O3333K@2333ӨODK@4OK@yO3333K@hfffvX@3333uR@QUZ@3333?R@r4333sAY@wR@̼Z@pR@̄ Z@YR@Y@3333R@Y@}R@Y@ER@tY@|R@4333cY@R@ Y@YR@hfffVY@ffffR@̴Y@ffffR@hfffY@ R@4333Y@ffffrR@Y@̠R@4333#Y@]R@QY@3333R@ăY@ȎR@̤~Y@R@hfff>vY@R@@lY@3333R@4333K[Y@3333ǖR@hfffTY@3333ۙR@4UY@R@hffffWY@R@4333MY@lR@hfff&CY@ffffR@hfff6Y@R@x8Y@33333R@hfff>Y@dR@̔FY@ĘR@aFY@ R@JY@3333R@4333QY@ffff&R@\Y@ffffR@aY@}R@\cY@1xR@hfffbY@uR@4333[Y@3333uR@XY@uR@4333HY@ffffVvR@4333sAY@wR@4333sAY@wR@4333sAY@wR@ffffXVl.@5Vه/@,8Vyl/@,;Vhfff[/@3333>V0333E/@?VhfffF%/@ffffnAVhfff.@EV .@̬KVhfff.@V `/@3333'7V`/@5Vه/@6V{/@,8Vyl/@,8Vyl/@,8Vyl/@,8Vyl/@hfffNb@Q@-b@fffff R@-b@XR@b@3333R@ b@Q@4333b@Q@hfffb@Q@Pb@0Q@4333#b@3333Q@hfffNb@ffff&R@b@,R@b@DR@b@ R@b@fffff R@4333b@ffff^ R@b@ R@(b@R@ b@DR@-b@XR@-b@XR@-b@XR@-b@XR@@EV@ B@4333KiV@ffffB@gV@aB@4333`V@ B@hfff^WV@B@hfffNV@ffffB@4333CIV@B@O@W-@ёO@pffff#-@ɔO@@-@O@pfff,@O@,@33333O@pfff&,@|O@pfff&,@ffffO@,@yO@̌,@̌qO@,@kO@̌,@iO@,@iO@,@ffffoO@̰,@ivO@,@yO@,@izO@,@3333 zO@@333s,@ffffzO@ ,@l}O@,@ffffO@pfff,@ffff&O@@j,@xO@@:,@ؖO@@3333,@٘O@Y+@3333{O@+@O@pffff,@ffff.O@pffff,@3333+O@@*,@3333O@@+,@O@@+,@O@@+,@O@ffff~VuI@ffffRVtI@V3333|I@ffffVV3333I@3333VԈI@V|I@VфI@ffffzVlI@3333SV3333˄I@ VHI@3333۲VI@3333ViI@iVffffI@VtI@ffffJV3333I@V̄wI@YVuI@ffff~VwI@V3333|I@V3333|I@V3333|I@L?@L. hfffC@@WhfffA@@8333 hfffC@@# B@@L. 4333s.@@hfff 4333@@@@?@hfff?@?@?@L"L?@̬?@pfffhfff?@pfffy8333?@W4333c@@@333 @@pfffM\9@@hfffA@@8333 hfffA@@8333 hfffA@@8333 hfffA@@8333 `Y@,s2@9Y@92@9Y@4333ӆ2@4333۴Y@І2@4333 Y@L2@4333;Y@4333#w2@`Y@,s2@TY@y2@Y@P2@Y@2@̴Y@dfffF2@`Y@dfff2@Y@92@Y@433332@H@ffffzR:H@3333R33330H@uR.H@3333R.H@Rffff-H@Rffff^,H@3333;R̜+H@ffffNR$H@R$H@QR8*H@TR4H@YR4=H@Rh?H@RAH@3333Rffff6HH@)R\NH@ffffzRYLH@ R3333IH@=R3333GH@̌RTCH@RQ=H@R 8H@ R3333 5H@R33333H@33333R@4H@ffff:RffffN6H@Rffff7H@4R6H@ffffR33338H@ffffR3333 8H@3333R=H@ffffbR3333 DH@LRffff6JH@ R3333sLH@3333RLH@ffffRKH@RMH@3333_RxQH@3333RdVH@3333RhZH@3333R[H@ RffffXH@RZH@R3333`H@̰RffffbH@@R3333sdH@3333SRfH@R̴fH@RffffcH@ffffnR`H@̢RZH@ffffRffffQH@RMH@ffffvRLH@ Rffff>JH@3333+RdJH@YRTKH@aRffff&JH@ffffR FH@̨R,>H@Rffff~9H@3333ӐR3333#8H@ARffff6H@3333R2H@3333R2H@ffffR1H@iR̤/H@3333R.H@33333Rd,H@R<0H@ffffNRY8H@ffffRffff> N@hfffƲB@3333 N@4333ӣB@3333N@4333B@ N@4333B@ N@4333B@ N@4333B@ N@ܪK0333s@eK@1`rKY!@2333cvK0333s@2333sxK@ xKL@IvK`fff@rK`fff&@nK̞@ffffnK@oKg@2333CsK`ffff`@ffffFwKLS@2333yK`ffffb@}Ko@ffffK`ffffe@K`fffG@(K!@,K@ffffK0333s@ffffK`fff@2333[K@2333#K@2333sK03333@P@hfffV1@P@hfff>1@ffffP@`81@P@'1@ffffP@y!1@P@8333sM1@33333P@lo1@ffffP@83332@ffffP@42@3333P@8333Se2@̐P@̌m2@ffffP@/2@P@/2@P@/2@P@8333D1@3333S\G@hfff)2@G@1@bG@8333y1@̜\G@F1@3333S\G@8333D1@_G@hfffFE1@ffffFaG@O1@aG@,b1@ffffcG@̌z1@hfG@Y1@mG@1@tG@̌1@3333xG@`1@ffff^~G@ 2@G@2@G@hffff!2@ffffG@hfff)2@YG@hfff$2@ffffF{G@1@nG@83331@0eG@1@bG@1@bG@1@bG@1@bG@xffffJWSffff.XE@OSrE@ PSDhE@SSXbE@VSffff.XE@ffffJWSffffZE@WS]E@3333cUStdE@RSkE@PQSrE@OSpE@PSDhE@PSDhE@PSDhE@`#S3333sbE@3333SffffvE@ 3333SffffbE@!SkE@#SrE@ffffR"SffffvE@ SffffcE@3333S3333sbE@3333SffffbE@3333SffffbE@3333SffffbE@`dS3333dE@3333kSzE@ 3333kS3333dE@(SlE@dS3333tE@3333;SzE@ffffS3333qE@3333SjE@3333kS3333dE@3333kS3333dE@3333kS3333dE@ ̶dYN@nd3333;8N@!nd4N@pdD2N@qdX.N@3333srd+N@qd"N@ffff"tdfffffN@3333xdYN@xdN@ffffryd3333N@yd!N@xdffff$N@ffff`yd,&N@ffffzd%N@3333}d3333$N@ffffVdffff6#N@̶d̴%N@̐dffff&N@3333|d3333*N@/{d,N@1|d3333;/N@ffff~d1N@3333|dffff.4N@{d33337N@E{dx7N@ydI5N@|wd07N@wd3333;8N@ffff ud`7N@oda6N@nd4N@nd4N@nd4N@nd4N@ffff[3333D@[E@ffffr[33333E@[|D@ffff[D@Q[3333D@[3333 D@9[D@ffff[iD@ffff[3333E@-[ffffE@3333 [E@[E@3333C[ E@[̄E@ffffr[33333E@ffffr[33333E@ffffr[33333E@̄[ffff&D@ffff[D0D@ffffz[3333[D@[9D@I[ffff. D@̀[ D@[ffff&D@ffff>[3333k D@[3333D@̐[̼D@̄[ffffD@̌[3333K D@ [3333K)D@3333g[D0D@[ffff6/D@[ffff.+D@[3333k$D@ffff[ffffnD@ffff[D@ [\D@ffffz[3333[D@ffffz[3333[D@ffffz[3333[D@ffffz[3333[D@_ffffFP@<_PP@_ P@̌_P@3333˖_3333P@_PP@_̜P@3333#_P@<_ffff6P@ffff_(P@ffff_|P@ffff2_ffffP@X_HP@ffff_3333P@_̠P@_ffffFP@_ffffP@_1P@!_ܶP@_ P@_ P@_ P@_ P@3333WG@3333WffffnG@3333WG@W4G@LW`G@)WG@AW3333G@ffffW3333ۉG@W3333G@=W3333KG@4W3333SG@ffffvWG@3333WG@ffff~W)G@ffffW̼G@3333W4G@W\G@3333WԙG@$WffffVG@3333WG@ffffFWܞG@WffffnG@W̔G@WffffFG@WfffffG@ɑWԗG@3333WG@3333WG@3333WG@3333WG@3333 VpdH@ffffjVffff|H@̬V̬wH@ffffjV33333uH@VlpH@̼Vffff&iH@ffffVdH@3333/VpdH@ffffRV3333#fH@Vffff.gH@uV3333gH@̘VjH@mVnH@VTuH@3333˫VffffuH@3333 VxH@̜V3333{H@Vffff|H@ԥVzH@V̌vH@V̔rH@V9qH@3333V3333cqH@3333Vffff>rH@ĔV8uH@̬V̬wH@̬V̬wH@̬V̬wH@̬V̬wH@$S3333[G@RG@3333oRrG@RoG@ffffR̔iG@3333RQbG@3333R3333[G@3333R3333[G@QR`G@ffff^R3333aG@ffffS̔_G@$Sffff6aG@ŠcG@,RhG@ffffRR3333mG@ffffR3333oG@RqG@(RhsG@R3333[{G@3333#RG@Rffff|G@3333oRrG@3333oRrG@3333oRrG@3333oRrG@ffff#R̬&D3333RhfffVDRP!D3333Rhffff%DffffvR̬&Dffff.RP&DDR|%D#R4333"Dffff#RhfffDX#RD!RD9R4333SD RhfffVD3333#R)D}RIDRhfffD@RYDRP!DRP!DRP!D̀e^(3N@E^3333bN@3333_P^I9N@V^3333C4N@Z^(3N@q[^33335N@1]^̬8N@3333_^3333:N@̀e^ 8N@@d^T;N@_^3333;BN@ffffX^3333GN@1T^ffffNKN@=S^ffffON@T^YN@ffffU^3333bN@Q^̄aN@HK^ffffv\N@F^UN@E^KN@I^AN@3333_P^I9N@3333_P^I9N@3333_P^I9N@3333_P^I9N@AR\H}RIHR`HYRH3333'R Hl-RH10RHffff4RhffffH3333_RH3333>RhfffFHfffff?RH(AR4333Hffff?R4333H;RIH3333+8RPHffff4R9HH!RHR)H R HyR4333H}R4333H}R0HHR,HR0H R\HR`HR`HR`HR`H83331@!2@ffff 2@ffff2@8333s1@33331@D83331@hfff1@33331@1@833331@3333;83331@ffffhfff&1@h1@H忠1@ffff8333s 2@忠2@3333833332@33332@ffffb`2@33332@̔鿠2@3333뿠Y 2@!2@3333c,2@hfff2@3333hfff2@̔ 2@ffff 2@ffff 2@ffff 2@ffff8hfff&>@xO@ 3?@ O@$>@3333O@hfff>@3333O@ >@ O@ >@3333sO@l>@O@8333>@yO@L>@ffffO@8333?@3333O@8333*?@3333KO@ 3?@O@hfff0?@33333O@hffff+?@O@8333#?@,O@̌?@ffff&O@̌?@O@8333s?@O@?@O@L#?@O@`"?@PO@hfff&?@3333+O@9?@O@8333$?@O@ ?@xO@8333S?@O@>@ffffvO@>@dO@>@3333O@L>@tO@8333>@8O@>@O@8333>@ffffO@hfff&>@3333O@>@3333O@>@3333O@>@3333O@>@3333O@ ]@2333>@hfff"]@>>@ ]@ffff>@hfff]@>@hfff]@$>@hfff]@ )>@t]@,>@I]@ffff4>@ ]@2333:>@q]@ffff<>@]@>>@hfff]@>>@]@2333C9>@`]@4>@4]@ffffF4>@ ]@Y5>@"]@4>@hfff"]@ffff.>@!]@,&>@hfff!]@2333>@4333!]@>@hffff ]@2333>@]@>@]@>@ ]@ffff>@ ]@ffff>@ ]@ffff>@ ]@ffff>@4333a]@@G@hfffw]@G@0e]@3333G@̼c]@G@4333a]@̌G@a]@aG@4333sd]@G@h]@\G@4333cm]@HG@p]@G@Ds]@3333G@u]@3333G@hfffw]@3333G@hfffv]@G@hfffs]@ffffG@4333n]@G@i]@ G@4333f]@@G@hfff~e]@G@0e]@3333G@0e]@3333G@0e]@3333G@0e]@3333G@hfffT@2333q?@T@2333Ӧ?@̼T@v?@hfffT@v?@ T@2333}?@iT@܃?@hT@`?@4333۶T@|?@hfffT@y?@hfff>T@2333#?@aT@?@ĻT@ɜ?@4333ST@?@T@ ?@hT@2333Ӧ?@hfffT@?@\T@2333?@T@ ?@T@,v?@4333ST@2333q?@4333T@@U@]?@U@*?@U@ffff"?@U@2333s?@1U@?@hfffަU@?@)U@ffffv>@4333sU@ffff>@̜U@>@9U@2333>@ؚU@>@4333kU@>@\U@ffff>@aU@ffff>@|U@>@hfffU@?@٦U@̜8?@٩U@]?@4333{U@ffffW?@U@A?@U@*?@U@*?@U@*?@U@*?@̼S@8jJ@S@\J@4333CS@3333{J@̤S@3333[wJ@S@3333#sJ@S@̼oJ@4333S@ffffnJ@4333S@3333kJ@@S@8jJ@S@)kJ@S@mJ@hfffS@ffffsJ@S@xJ@S@|J@̼S@ـJ@hfffS@3333KJ@4333SS@̬J@9S@ J@ S@\J@S@3333J@S@)J@8S@ȋJ@S@0J@S@J@S@J@4333CS@3333{J@4333CS@3333{J@4333CS@3333{J@ ;R@J@![R@J@̼XR@J@hfffTR@3333J@LR@ffffFJ@hfffER@lJ@4333@R@ffffJ@X=R@J@̴;R@3333CJ@ ;R@J@D=R@J@>R@3333J@)?R@3333#J@AR@,J@hfffFR@ffffJ@MR@J@̌TR@3333J@4333YR@4J@![R@3333#J@hfffZR@3333J@ZR@3333J@ZR@3333ۍJ@YR@33333J@ZR@,J@̼XR@J@̼XR@J@̼XR@J@̼XR@J@4333S@IK@T@(K@T@K@T@33333K@4333S T@3333۹K@`T@ԴK@4333#S@3333K@yS@IK@9S@3333˲K@S@ffffK@4333S@3333۹K@hffffS@3333SK@S@K@yT@dK@ T@(K@0T@K@T@K@T@K@T@K@T@K@RC@N@hfffVuC@ĻN@hfffFSC@ffffN@\VC@ffffޱN@hfffZC@N@ fC@N@4333srC@ĻN@hfffVuC@N@,qC@ɰN@hfffmC@\N@oC@ffffN@̌rC@ffffN@\qC@HN@4333kC@3333sN@4333saC@N@9YC@iN@4333TC@ffffN@RC@ffffN@hfffFSC@ffffN@hfffFSC@ffffN@hfffFSC@ffffN@hfffFSC@ffffN@;@(P@=@ffffP@-`<@P@`<@P@`<@P@`<@P@ <@ffffP@=@ݓP@=@3333P@̌ =@ffff&P@=@MP@8333=@3333P@8333<@P@̌<@ffffVP@l<@3333džP@83333<@P@<@3333#P@hfffF]<@(P@<@33333P@8333 <@ffffP@̌ <@33337P@8333 <@P@hfff<@P@L<@ffffP@;@1P@;@ffffŠP@hfff;@3333P@8333<@3333_P@hfff<@3333GP@8333S<@P@ <@9P@@#<@P@83333-<@̘P@Q<@`P@n<@3333P@hfff<@P@@<@3333P@hfff<@P@ٳ<@P@hfffF<@ffffP@<@ffffP@<@3333ːP@hfff<@8P@hfff&<@,P@83333<@ffffP@8333<@3333sP@`<@P@hfffA@P@JA@P@hfffA@P@̬A@tP@#A@P@*A@3333P@.A@}P@y9A@P@4333FA@@P@JA@P@`DA@XP@L4A@P@(A@3333P@4333(A@̔P@ (A@hP@4333C(A@P@(A@P@&A@XP@4333 A@P@LA@3333_P@̼A@3333P@hfffA@P@hfffA@P@hfffA@P@hfffA@P@hfffA@P@?@8P@2@@`P@7\(@@ffffP@\(@@ffffP@\(@@ffffP@\(@@ffffP@\(@@ffffP@hffff&@@P@&@@3333ǞP@̌)@@ѝP@4333.@@PP@0@@P@2@@}P@1@@P@l-@@8P@@@P@`@@ffffP@?@,P@8333s?@aP@8333?@P@ @@3333?P@9@@tP@I@@3333P@hfff@@̔P@8333?@ѬP@hfff?@hP@L?@3333P@hfff?@ffffP@8333?@4P@?@ffffP@Y?@3333#P@̛?@ P@?@ffffP@83333?@P@?@̜P@8333?@P@y?@3333׷P@hfff&?@̠P@hfff?@`P@L?@P@?@3333˵P@4333# @@ffffP@@@tP@̌@@ffff2P@@@P@@@P@hfff&@@ffffP@@@ŮP@4333'@@5P@ *@@3333'P@4333c+@@$P@'@@3333P@hfff @@ffffP@0@@}P@@@33337P@)'@@3333P@\(@@ffffP@Pe@hfffVF4333Te@hffffE4333Te@V@ffffV<@)V@2333<@V@l<@)V@l<@4333V@\<@4333V@\<@4333V@\<@4333V@\<@Q@3333kL@hfffR@ L@4333+R@3333L@hfffR@L@hfffFQ@ffffFL@4333Q@ L@hfffQ@ L@hfffNQ@) L@hfffQ@3333 L@Q@1L@Q@3333kL@AQ@L@aQ@̴L@Q@̼L@hfffQ@L@,Q@8L@hfffvQ@@L@0Q@̔L@4333SQ@3333[L@[\@ffffF=@ Y\@l=@W\@2333=@U\@ffff=@4333S\@̿=@4333Q\@=@0O\@ =@̼N\@̌=@O\@p=@XS\@fffff=@43333U\@ffff=@)W\@ffff=@hfffY\@=@\\@2333=@\\@2333=@\\@2333=@\\@2333=@̌9@\M@̌$:@2M@̌$:@ffff)M@$:@h"M@9:@3333M@8333:@\M@ :@3333M@8333:@M@̌9@ffff'M@9@(,M@8333S9@0M@:@2M@8333:@2M@:@/M@̌$:@ffff)M@̌$:@ffff)M@̌$:@ffff)M@̌$:@ffff)M@S]@2333q?@<|]@2333s?@<|]@@?@Yz]@ffff?@u]@?@4r]@2333C?@43333m]@2333C?@hfffg]@\t?@ d]@2333q?@]]@2333sw?@qX]@9?@LT]@ffffv?@S]@Y?@0T]@̌?@qW]@2333s?@4333kZ]@2333?@4333[]@2333æ?@̬\]@,?@)_]@ٗ?@b]@ffffF?@4333f]@2333?@4333i]@?@hfffn]@?@4333s]@?@4333z]@2333?@<|]@@?@<|]@@?@<|]@@?@<|]@@?@@333s)@O@pffff*@O@@333s)@3333O@)@O@Y*@!O@pfff;*@O@k*@O@*@3333O@Y*@3333O@*@O@@333Q*@DO@@33338*@3333O@@333+*@D@̼F@T=D@F@33337D@4333F@ffff.D@ F@̼(D@pF@̬#D@F@D@`F@3333D@`F@D@hfffF@ D@hfffF@D@hfffF@ffffD@4333ñF@aD@hfffF@ D@PF@D@̟F@ffffFD@F@%D@|F@P1D@F@3D@4333F@ffff6D@43333F@;D@F@>D@̬~F@3333AD@̬~F@3333AD@̬~F@3333AD@̬~F@3333AD@hfff\@23336>@hfff&\@lX>@\@2333cI>@\@2333SH>@\@G>@)\@2333sH>@P\@G>@\@lC>@4333\@<>@\@|8>@4333˱\@7>@ɰ\@23336>@4333\@ffffF6>@4333\@`6>@4333s\@2333c:>@t\@@>@hfff\@F>@hfff\@L>@\@2333cT>@\@ffffVX>@0\@X>@\@lX>@\\@S>@hfff&\@iM>@\@2333cI>@\@2333cI>@\@2333cI>@\@2333cI>@\\@̼>@4333S\@ffffF>@4333s\@Y>@̧\@>@\@ffff֨>@\@2333>@X\@>@!\@@>@4333\@2333C>@4333 \@ffffF>@̼\@2333Ӽ>@\@\>@4333S\@>@4333c\@l>@4333\@ܜ>@̧\@̼>@\\@ffff>@|\@ffffƩ>@4333s\@Y>@4333s\@Y>@4333s\@Y>@hfff6H]@?A@T]@\A@T]@ffff.KA@R]@8FA@4333O]@4@A@hfffnM]@?A@ K]@̌EA@ I]@ffffVNA@hfff6H]@TA@H]@\A@4333sK]@3333\A@ Q]@,UA@hfffVT]@3333OA@T]@ffff.KA@T]@ffff.KA@T]@ffff.KA@T]@ffff.KA@ܞ\@V>@i\@>@4333s\@W>@4333c\@`b>@\@j>@ܞ\@2333Sn>@̬\@Pp>@ \@Yo>@Ԥ\@g>@hfffv\@fffff>@4333[\@k>@\@̜p>@D\@t>@٦\@{>@4333\@~>@hfff\@|>@\@2333s}>@`\@@>@hfffެ\@>@hfffF\@2333~>@i\@,z>@(\@2333v>@د\@pq>@)\@2333m>@\@yk>@hfff\@ffffe>@\@yX>@ܧ\@V>@4333s\@W>@4333s\@W>@4333s\@W>@,\@̼=@@\@ $>@@\@`>@4333\@2333>@4333#\@=@\@=@\@L=@4333S\@=@hfff\@̼=@\@2333=@,\@=@4333c\@ >@4333S\@ffff&>@hfff\@ $>@\@#>@hfff\@>@0\@fffff>@,\@| >@\@ffff6 >@4333Ӓ\@ >@@\@`>@@\@`>@@\@`>@@\@`>@43333|\@ffff=@hfff\@>@hfff\@0=@\@ffff=@I\@=@̔\@ =@\@p=@4333\@ffff=@`\@=@hfff}\@2333S=@}\@2333s=@hfff~\@̌=@4\@@=@\@̌=@hfff~\@y=@d|\@i=@43333|\@2333#=@0\@ffffF>@hfff\@>@t\@>@hfffV\@2333s=@̼\@=@hfff\@0=@hfff\@0=@hfff\@0=@h\]B@ffffF]YB@ ]YB@ffffF]B@]ffffB@ffff]B@\]B@]B@]ffffޅB@]YB@]YB@]YB@Hffff]̸Q@]M0Q@&ffff]ffff#Q@L]ffffV%Q@ffff]ffff'Q@]3333)Q@]M*Q@U]+Q@].Q@3333]/Q@1]M0Q@]A0Q@m]/Q@]3333-Q@9],Q@3333]ffff+Q@]ffff"*Q@]|(Q@]&Q@$]&Q@3333S]3333&Q@ ]$Q@̼]3333"Q@ffff]$Q@]ffff"Q@]]Q@ffff]ffff"Q@]3333;Q@3333W]3333Q@3333]XQ@ffffB]̸Q@A]<Q@]3333Q@Q]Q@x]ffffQ@]!Q@ffff]ffff#Q@ffff]ffff#Q@ffff]ffff#Q@ffff]ffff#Q@3333Q̤H@ffffrQH@Uffff&QffffNH@̈QѾH@QH@ffffʈQYH@3333Q̼H@|QH@yQDH@Q H@QH@uQH@ffffvQ3333H@QH@ffffQffff~H@QqH@ffffQH@ffffƜQH@3333Q H@$QH@3333KQ3333H@Q̜H@ffffQffffH@ffffzQ3333+H@̐QH@Q3333H@PQhH@٬Q̴H@QH@ffffjQfffffH@3333wQH@33337QH@hQXH@3333Q3333;H@3333Q3333sH@0Qffff>H@3333QffffH@ffffQ3333H@3333Q3333H@dQffffH@شQffffH@3333QHH@QH@̭Q,H@ffffQH@tQ@H@ffffQffffH@ffff&QffffH@MQffff~H@LQ3333CH@ffffƕQH@ffff~Q3333H@̬Q3333H@3333Q|H@3333QH@3333QH@LQH@3333QH@QffffH@ffffQiH@(QIH@ffffQ̌H@QH@ffffbQ3333KH@3333QDH@3333QaH@|QffffH@yQffffH@vQqH@ffffZrQhH@ffffrQXH@3333tQ̤H@vQffff֫H@lwQ̮H@3333xQffffH@yQH@ffffyQffffH@ffffzQffffH@̐|QAH@~Q)H@QffffH@3333QffffƼH@qQH@ffff&QffffNH@ffff&QffffNH@ffff&QffffNH@ffff&QffffNH@ 2333MTRH@vLH@!ffffvLH@ffffvLH@ffffvLH@ffffvLH@ffffvLH@YLH@ffff~LtH@A{LH@xL3333H@vL̼H@2333|LH@P@ffff]3333?P@ffff]3333?P@ffff]3333?P@ffff]3333?P@ܖVJ@3333fV3333sJ@ܖVffffJ@ffffVffffJ@̌VffffJ@VJ@Vffff^J@ffffVJ@ffffڌVJ@ffffV@J@ffffFVLJ@qVffffvJ@V3333J@ffffV3333sJ@ffff^{Vffff~J@(wVJ@0vVffffNJ@nVIJ@3333fVJ@3333ckVJ@3333tVPJ@3333|VJ@)V̴J@V3333J@ffffVJ@ffffVffffJ@ܖVffffJ@ܖVffffJ@ܖVffffJ@ܖVffffJ@^WII@DWI@3333JWI@ffffKWI@ffffLWI@OWII@tTW̌I@y[WI@^W̤I@3333^WHI@3333#]W3333ˡI@YWaI@ffffWWI@UWI@!RWffffƣI@MW3333CI@,KWI@3333IWI@3333GWўI@ffff~FWI@DW0I@ffffDW3333[I@HWI@3333JWI@3333JWI@3333JWI@0ffffWJ@3333#WJ@#3333WJ@tWtJ@ffffW3333J@ WJ@ffff^WIJ@̤WJ@3333WJ@WJ@ffffWJ@3333WJ@WpJ@3333WffffJ@ffff~W\J@ffffWJ@=WJ@̔WQffff\J@aQqaJ@ffff^QffffdJ@3333oQ3333[fJ@QfJ@Q3333 eJ@Q)aJ@Qffff.^J@Q`J@3333Qffff&cJ@3333˰QdJ@QgJ@̸QhnJ@QsJ@HQLtJ@0QqpJ@QlJ@)QffffhJ@̼QffffhJ@ɾQkJ@QoJ@QtJ@QffffxJ@QaxJ@ffffQffffxJ@ffff.Q3333[zJ@3333Q9{J@qQ}J@3333QxJ@`Q3333J@Q3333ہJ@33333QJ@TQ̄J@QffffJ@Q܄J@@QJ@Q3333~J@QQq~J@QـJ@ffffQـJ@̘QxJ@xffff~PZdvK@̜ZffffFK@,YZ3333{K@ffffZ̴K@u ZK@ffff%Z̬K@ffff(ZK@ffff&,ZffffK@ffff/ZK@2ZffffNK@33334Z9K@9Z3333}K@ffffAZ0yK@1HZdvK@hLZ3333wK@3333'OZ3333szK@̬OZF@iS9F@ffffSffff5F@ffffS333331F@ffffSffff+F@S'F@S'F@S'F@P(W4K@3333OiWlK@' {WjK@ffffqWigK@ffff.lWleK@3333OiWdK@ffffniWcK@lWaK@puWaK@ffff^zW33333_K@{W3333ZK@3333KWUK@3333WYQK@WOK@̼WMK@̄W3333JK@͜W`EK@ȝW3333BK@W4@K@IW3333c=K@3333/WffffN8K@3333۰W4K@W33336K@(W:K@W@4333G@>@*4333G@>@\G@2333>@4333G@2333é>@hfffG@>@hffffG@>@hfffFG@|>@hfffG@ >@yG@>@|pG@23333>@mG@2333ø>@@4333SgG@̼>@fG@>@fG@ffff6>@4333SeG@2333s>@hfffaG@ >@`G@>@[G@9>@[G@>@_G@ >@4333fG@ffff>@̼hG@2333#>@,nG@>@hfffrG@L>@hfffvG@@>@4333}G@2333S>@ G@>@9G@fffff>@̬G@2333C>@4333G@>@hfffG@2333>@G@ffffF>@G@ffff>@iG@`>@G@ffff>@G@>@G@̌>@hfffG@i>@4333G@>@4333G@>@4333G@>@4333G@>@]ffffE@ffff2]ffffvE@]ffff&E@ffff]4E@3333]ffffE@ffff]ffffE@M]3333E@й]ЦE@ݻ]DE@]lE@p]E@]ffffvE@ffff~]ٳE@̈]E@ffff2])E@]3333E@(]E@3333ө]TE@]ffff&E@]ffff&E@]ffff&E@]ffff&E@23333[LIH@̬;Lffff~.H@2333=L\&H@ffffJLffffH@23333[LIH@2333#XL H@QL"H@2333CMLd&H@,KL)H@GL-H@ CLffff~.H@ffff6?LL,H@̬;L *H@2333=L\&H@2333=L\&H@2333=L\&H@2333=L\&H@3333W3333K@ffff^WK@ffff^WK@ffffWffffK@WK@WffffK@8WffffK@Wffff޵K@3333W3333K@pWȷK@W3333K@QWffffFK@ffffNWYK@WffffK@̴WffffNK@ffff^WK@ffff^WK@ffff^WK@ffff^WK@ffffd$EP@ffffdffff"MP@ffff8dffff"MP@ffffdffff^LP@dffffJP@ffffjdHP@dffff6FP@d$EP@ffffZd3333EP@hdHP@ffffdJP@ffffBd̨KP@cYM@ffffcffffM@̦c4M@ec3333{M@cDM@̶cپM@ffff4cM@ZcM@ffffcYM@?c3333M@ffff8cM@cM@ffffcM@ffffcM@3333{cM@ffffcM@ffff>cffffVM@cffffM@:cM@cM@hc0M@3333c3333;M@̦c4M@̦c4M@̦c4M@̦c4M@D5W@~H@)sW@3333CH@)sW@3333H@qW@3333;H@`kW@ffffH@TbW@QH@4333\W@3333H@pYW@~H@hfffTW@̬H@iOW@3333kH@yKW@PH@hfffFW@ȑH@d>W@H@4333[7W@3333ۜH@D5W@hH@i5W@!H@I7W@1H@,@xU@2333 ?@hfffxU@ffff>@yvU@ffff>@4333vU@>@hffftU@2333>@LsU@P>@rU@`>@PrU@>@4333spU@2333>@hfffNlU@2333>@hU@Y>@lfU@>@TdU@l>@hfff`U@2333>@\U@ >@$XU@>@̌VU@>@WU@2333>@hfffYU@ffff?@4333{^U@2333 ?@4333cU@ffffF?@4333ciU@i?@inU@ffff&?@sU@)?@hfffxU@l>@xU@ffff>@hfffxU@ffff>@hfffxU@ffff>@hfffxU@ffff>@hfffxU@ffff>@p̬2E@03333B'@433339E@̌l'@ 433339E@Z'@4333s8E@0333G'@4333c5E@03333B'@3E@@J'@̬2E@W'@hfff3E@c'@hfff4E@̌l'@43337E@d'@433339E@Z'@433339E@Z'@433339E@Z'@8gW3333,H@W3333wH@`:W3333k7H@ffff?W̬9H@3333;CWa=H@DW@H@CW̤AH@>Wffff>H@\7W!;H@h2W3333;:H@ffff/W =H@ -W̔@H@,Wffff.BH@4Wffff.EH@;W3333CHH@W3333XH@H@Q$W;H@fffffWfffff:H@3333WI8H@3333WI6H@W2H@<W-H@,W3333,H@3333W3333.H@D!Wffff3H@l&W3333K6H@0W7H@:W3333k7H@:W3333k7H@:W3333k7H@:W3333k7H@(3333{5_ffffK@0^3333`L@b^ L@ffff^ffffv L@Ь^ L@3333c^L@,^aL@^(L@3333^K@3333s^3333K@^L@3333^3333cK@3333^ffffK@ffff^3333K@3333^lK@|^XK@ffff^ffffK@^ffffK@3333^ffff6K@L^ffff&K@T^K@3333^̼K@^ffff>K@l^K@^qK@X^|K@3333^AK@^K@ ^ffff6K@^0K@33333^K@m^qK@8^ffffK@^pK@-^ffffVK@^̌K@3333^3333[K@a^3333{K@^ffffK@ffff^ffffK@̈^ffffK@^ K@^3333SK@ffff_3333K@ffff_3333K@ _ffffK@_K@_`K@3333_L@3333g_L@l _L@3333_3333#L@| _ffffL@_3333L@3333_` L@3333 _3333L@ _ffffL@ _$ L@<_ffffL@3333_3333L@3333_D.L@3333g5_8[L@3333{5_3333`L@̔0_^L@ffffF*_3333+TL@#_ffff~HL@`_XZM@ffff@Z3333+M@3333MZ3333M@ffff^SZM@3333;YZTM@3333;YZTM@3333;YZTM@3333;YZTM@ffffVb3333$O@3333#ObAO@3333#Ob*O@3333KOb'O@3333}Pb3333$O@ffffRb%O@TbffffF.O@ffffVbffff4O@̀Vb8O@Vb=O@Ub3333@O@3333%UbAO@3333Tb3333=O@GTb:O@̄Sb4O@3333IQby.O@3333#Ob*O@3333#Ob*O@3333#Ob*O@3333#Ob*O@ffffVW3333G@̼WffffVH@WH@ffffW3333H@ WG@̼WG@WpG@3333gW0G@W3333G@ffffW3333#G@ffffVWG@W3333G@WffffFH@WffffVH@̰W̤H@WH@WH@WH@WH@3333W3333;H@WffffH@ffffNWH@ffffbWfffffH@WH@,WffffH@,W3333{H@WffffH@WffffH@ffffjW H@lW H@3333Wffff~H@5W3333;H@WffffF H@3333W H@ffffNWH@ffffNWH@ffffNWH@ffffNWH@@TX5O@SXY}O@E3333}X4FO@XfffffHO@ffffFX3333MO@lXTO@3333+XHXO@3333XUO@$X!OO@`XNO@3333?X3333+UO@3333ϖX3333ZO@ɘXffff~]O@̚XffffaO@3333X3333fO@TX jO@̬XjO@(XihO@ŖXgO@ѐXgO@3333GXgO@XffffjO@3333cXlO@ffffJXimO@PX3333kO@3333XlO@3333~X̤nO@3333wXnO@pXnO@ffffmXqO@̄kXO@ WX>O@ffffVXq?O@ffffWX@O@QVXffffAO@3333TXffff&@O@SX>O@ffff^TX ;O@3333#XXffffV7O@y\X5O@aX3333 :O@ hX>O@lX@O@qXAO@ffffuX@O@ffff xXy>O@xXffff&Yffffz=@xBYffffu=@ffffbFYffffVu=@IYw=@%LY2333}=@NYffff=@hQYffffv=@XRYffff=@QY̬=@PY=@0QY=@QY̬=@3333SSY=@SYffffF=@SY<=@SYl=@QYffffƥ=@3333MY`=@ffffKYffffV=@3333IY=@FY2333C=@DY2333=@ffff:BY=@H@YL=@ffff?Y=@3333>Yffff=@G@ffff'S|G@(SffffNG@̜#S̴G@`Sffff޼G@SG@ S9G@eS3333kG@HSLG@SG@ SfffffG@3333!S̴G@̼ S3333ӕG@3333SG@Ydfff4@ѬYT4@ffffzYdfff14@ѬY.4@Yl)4@Ydfff#4@IYdfff4@ffffY4333#4@ɻYdfff+4@Y.4@ffffY<.4@Y-4@YYdfff34@Y9;4@YB4@dYdfffG4@3333YN4@!YT4@4Y̌Q4@AY24@ffffYdfff24@ffffzYdfff14@ffffzYdfff14@ffffzYdfff14@ffffzYdfff14@U X(@ffffU(@U`fff(@ffffU`fff(@ULj(@1U`fff^(@̴U X(@ffff"UZ(@U0333i(@U`fff{(@qU0333(@ffffU@(@U0333S(@ffffU`fff&(@3333סU0333S(@U(@U(@U`fff(@U(@3333U,(@ffffU0333S(@U(@ԒU(@3333U(@QUy(@U@(@U`fff(@U`fff(@U`fff(@U`fff(@eKp9fffffK8XfffffKY8K8fffff%KY8ffff'Kl8p'Khfff82333 K89Ǩ82333 Khfff82333#(KL8̼-KhfffF8ffff0Ky8ffffV2K 81KL8ffff.+Kl92333(Khfff&9̌*Ky9,Khfff#9233330K4333&9L0K.9$KY79̬Kl=9ffffV"KB9+K`J91KM9ffff^7K43333O9@7KhfffU9d3K _92333C6Kyc9>K c9lCKe9FK4333Sk9JKp9ffff&NKhfffn9 QK4333j923333QKLM9MKYD92333 FK <9pBK09CK'9̜GK`#9ffff.JK 9IK92333OK9Y\K4333s9|`Khfff&9![K4333 9NǨ 9CK4333s 9LAK433339@K 8`CK@8ffffUK̬8eK982333bK 8YK8INKhffff8ffffCK8ffffK98(3K8ffffv1K81K823335K98̼5K̊8̬1KY82333#3Kt823330Kj8*K`g8ffff'K ^8(KyR8̄,KC82333/K 68-K43333*8,K4333S82333S)Ky8)"K8H$K$8ffff"K982333; K@I8!K4333w8(!Kl8̜K43338fffffKY8fffffKY8fffffKY8fffffKY8TL"@3333S0333"@/3333SI"@3333S`fffF?"@1S`fff5"@ffff.Sl%"@S`ffff"@<@@08333H<@0LL<@4333S0@J<@08333sP<@08333Y<@4333S0hffff_<@hfffƒ0d<@hfff0q<@09<@hfffF0̬<@hfff083333<@4333S0hfffF<@0 <@l0̌<@4333~08333s<@hfff&08333<@90hfff<@4333S0 <@0Y<@y0<@433308333<@hffff08333<@hffff08333<@hffff08333<@hffff0XhfffD@@?P@@@ffff?HP@@3333I?@@@?@@?@@[?@@? @@3333 ?4333@@@ffff?Y@@? @@? @@@ffffC?hfff@@?43333@@c?hfff@@,?hfff@@@ffffo?ɦ@@?@@̶?hfff&@@_?hfffƩ@@@ffff?@@3333?4333@@ ?P@@?l@@?`@@̞?hfffƏ@@?hfffv@@3333? s@@?,o@@?̌n@@3333?4333o@@y?)r@@3333?4333Sr@@?hfffn@@P?li@@4?̜d@@o?a@@O?@`@@?_@@n?T@@?LJ@@̓?F@@@ffff?hfffD@@3333?E@@@ffffY?,N@@@ffff8?hfff&^@@@ffff?hffff@@J?hffff@@&?4333f@@3333?g@@?Yn@@3333? x@@?hfff}@@?@@?@@?hfff@@3333?@@#?4333s@@?hfffv@@?ܔ@@7?4333S@@?4333S@@?hfffv@@̟?̼@@}?@@?@@@ffff?hfff@@?y@@?I@@3333?4333ý@@s?P@@3333I?P@@3333I?P@@3333I?P@@3333I?C@3333kM@)C@ffffFM@,C@)M@C@M@C@M@4333C@M@hffffC@̄M@hfffvC@$M@4333C@ M@C@3333M@4333CC@3333 M@YC@M@C@M@)C@9M@C@3333kM@C@M@yC@M@4333ӘC@M@C@3333[M@نC@)M@4333C@ffffFM@hfffƑC@3333M@4333C@M@4333cC@M@,C@)M@,C@)M@,C@)M@@3339"@G@v#@ffffG@v#@qG@pfffo#@G@@333^#@G@#@lG@"@G@pfff&"@G@]"@G@@3339"@G@C"@ffffG@pfff&v"@G@pfff"@̜G@pfff&#@G@I#@ffff~G@v#@qG@v#@qG@v#@qG@v#@qG@@6@ЙN@hfffJ7@N@=7@dN@8333s/7@ N@̌7@ffff.N@8333 7@`N@̌6@ffffFN@6@3333{N@83336@N@6@ N@hfff6@ЙN@@6@N@̬6@3333N@6@PN@hfffƷ6@3333sN@833336@̜N@̌6@̔N@̬ 7@3333N@#7@ffffN@hfffB7@N@hfffJ7@ܹN@̬?7@pN@l>7@3333KN@=7@dN@=7@dN@=7@dN@=7@dN@ 9A@?@A@2333S;?@A@2333S-?@)A@'?@4333A@ ?@̼A@?@ɺA@?@PA@?@A@"?@9A@̌-?@A@233337?@IA@2333;?@ A@2333S;?@,A@|4?@A@2333S-?@A@2333S-?@A@2333S-?@A@2333S-?@ hfffVA@33333\@@4333cA@)s@@A@ d@@hfffA@_@@hfffA@33333\@@A@3333_@@hfffVA@fffff@@4333A@̄m@@4333SA@ r@@A@)s@@A@ffffnp@@4333cA@3333j@@A@ d@@A@ d@@A@ d@@A@ d@@ 4333`@04333!`@hffff0=4333!`@hfff$0} `@@)0 `@hfff004333 `@L:04`@E0`@@M0p`@̬Q0`@LY04333`@^0`@d0̠`@l0`@o0`@ym08`@ l0hfffv`@hfffl0̬`@Ls0X`@ 0`@hfff0hffff`@hfffƗ08`@0hfff`@04333;`@ 0}`@0hfff `@@0hfffF`@̬0hfff6`@hfffF0 `@hfff0`@,0`@,0`@hffff04333`@43330`@̌0`@04333/`@04333`@0,`@hfffq0hfff`@4333SP0T`@4333@0`@`<0`@,90hfffv`@hfff204333`@4333(0hfff`@4333$05`@"0`@43333"04333`@hfffF0`@hffff0`@@0`@, 0`@9&0P`@+04333`@+0`@hfff(0`@hfff#0A`@43330`@hfff04333 `@ 04333!`@hfff$04333!`@hfff$04333!`@hfff$04333!`@hfff$0 4333cX@3333dA@xX@ffffFA@xX@IkA@ wX@ffffViA@IsX@3333iA@pX@jA@mX@ffffiA@hfffvlX@\jA@lX@gA@kX@QeA@4333siX@3333dA@fX@fA@dX@ffffiA@4333cX@ pA@hfff~cX@qsA@IeX@ffffvA@hfffgX@zA@hfff6iX@ffff>}A@hfffhX@\A@4333iX@ffffA@4333kX@ffffƆA@oX@LA@4333pX@ffffFA@rX@9A@4333sX@̬}A@4333KsX@3333SwA@0vX@3333pA@xX@IkA@xX@IkA@xX@IkA@xX@IkA@ hfffCX@̴iA@hfff]X@A@hfff]X@|A@4333s]X@ {A@hffffZX@ffff>uA@ WX@nA@4333sRX@jA@NX@̴iA@4333cEX@3333tA@̜DX@ffffwA@hfffCX@3333C}A@ADX@ffffA@4333kEX@A@hfffGX@A@NX@A@hfffvVX@̄A@ZX@̬A@hfff]X@|A@hfff]X@|A@hfff]X@|A@hfff]X@|A@(R@D@8SR@$D@RR@3333+D@ QR@D@LR@iD@FR@D@<>R@D@5R@3333D@hfffv+R@D@hfff)R@ffffnD@(R@D@*R@D@,R@4D@Y-R@3333;D@hfff,R@3333CD@4333#*R@ffffD@hfff+R@$D@L4R@3333D@)@ST@>@ST@2333>@4333RT@>@hfffNPT@ffff>@̌MT@\>@JT@23333>@ HT@2333>@hfffIT@2333>@4333KT@2333s>@KT@ffff>@LT@2333#>@NT@>@QT@̼>@RT@9>@RT@ >@$PT@ffff>@4333QT@>@ST@l>@ST@2333>@ST@2333>@ST@2333>@ST@2333>@WT@2333C>@aeT@ >@aeT@23333>@4333[cT@>@hfff_T@ >@[T@2333C>@hfffYT@ffff>@WT@>@ XT@ffff>@0ZT@ >@4333k]T@>@aT@ffff>@hfffdT@̌>@aeT@23333>@aeT@23333>@aeT@23333>@aeT@23333>@ *pLZ@|?0333;"@hffff?0333@hffff?0333@hffff?0333@hfff?@I? @?@?`fff@hffff?`fffv@4333? n@?`ffffu@y?`fffx@hfffv?Lq@̬?Yc@L?`fffG@hfff?03333'@?0333s@4333?Y@̬?v@8333s?LZ@?i@8333ò?@ ?`fff@@ @̬@l0333@`ƿ!@ffffVп̌W@̸Կ|@ffff^ۿ0333@@F`ffff@33334@33330333sV@`fffW@0333:@̌#@ffffL>@࿐,@e߿`ffff@ݿ@Lܿ@2333ڿ̌@1ڿ@2333ٿ D@,ٿP@׿@@uտ`ffff@ӿ`ffff@Tѿ@dfff>Ϳ@dfffȿ @iƿ@Ŀ@0333c¿@03330333@`fff&@`fff&@`fff&@`fff摿L@`ffff@`fffFL@0`fff'@0333C<@ M@yc@`ffffi@@3333?a@fff&? f@8333?̌z@?`fff&@̌?0333s@@3333?0333@@333S?03333@,?L@̾?̌@̌?@P?@@8333?Y@̷?`fff%@ٹ?033336@?`fffQ@hfff?`fff&|@hfff?@?ٚ@?٧@L?̌@fff?L@~?`ffff@?@̡? @0? @P?Y@8333C?0333s@@? @?@hfff?@?@4333C?0333s@?̌@?̌%@4333?`fff&7@?L<@п`ffff@dfffʿ03333@0333Ŀ0333@@Y@@dfff&@!Ŀ@@dffffĿ-@yÿ@@0333ÿ ]@̼ſ`fff@0333ǿ03333@ȿ`fff&@̤̿@8ҿ @,Կy @ֿ`fff @2333oֿ @2333ؿY@̬ڿ@ffff>ٿ`fff@Hؿ`fff @ffffڿY( @ܿ. @2333߿  @0333 @ffff࿘yA @3333_N @3333̬D @ffff⿘Y3 @㿘y+ @0333s, @ffff俘Y6 @ffff,濘8 @.033334 @ffffV< @D @D @H @ffffR03333Q @33333̌X @ffff0333a @ffff03333z @3333- @ @q`fff @̤03333 @@ @ @ffff09!@ 5!@3333`fffB!@3333̌J!@ffffbG!@C!@3333A0333s0!@q`fffF!@ 5!@`fffQ!@ffff0333U!@`fffd!@̞̌r!@3333yYz!@33330333sv!@ffff`fffd!@S!@3333I!@A!@p`fffB!@33330333X!@uc!@3333M0333sv!@u!@`fffƏ!@0333!@̬!@03333!@3333O`fffs!@h!@0333q!@ffff03333!@`fffF!@#@!@RL!@ffff!@`fffF!@0333 "@3333򿘙%"@ffffm0333;"@0333&"@3333̌"@3333`fff&!@񿘙!@ffff`fffF!@ffff4!@ffff`fff!@h!@0333!@`ffffN!@+!@ffff0333s(!@"03332!@) M!@Yi!@ffff鿘y|!@ffffN0333Ӆ!@鿘!@s,q!@3333鿘`!@3333`fffO!@F!@̒@I!@ffff0333?!@90333'!@03333 !@3333 @`fff @3333`fff @ffff忘 @ 0333 @`fff @ffff0333 @l @࿘v @߿@k @̴ܿ@k @0ٿ`ffffq @ffffֿ`fffF| @XԿ0333| @ffffFҿ @hϿ} @ɿm @̤ȿ0333S_ @lп̬^ @̈ԿZ @$տP @̼ӿ0333H @п7 @Xȿ @dfff^ @l`fff&@0333`ffff@̪0333>@+@4333[? ,@@333s?'@?03333+@hfff?H@pfff?@s@?`fff@L?@̲?`fff@hfff&?̬ @pfff?`fff @?0333s) @Y?/ @̌?@, @?0333' @?03333, @4333#?; @l?0333sR @8333?k @8333?`fff{ @?ف @?`fff @Y?`fff& @4333? @4333? @̌?`ffff @?0333 @? @83333? @8333?0333!@ ?*!@4333S?1!@4333#?D!@|?f!@?{!@L?y!@4333?03333a!@̌?@!@|?0333S/!@4333S? &!@?`ffff !@hfff?, @hfffF? @Y?0333 @?l @? @̬?ٵ @?0333s @?9 @hfff.?Y @hfff?٤ @l? @?̌ @4333S?`fff @?`fffFi @?T @4333?9@ @4333#?Y6 @4333?L0 @?0333- @4333S?( @̜? @?0333 @hfff?Y@hfffƻ?@@?@?`fff@y?t@P?0333@4333{?0333@4333?@4333#?0333ss@hfff?`fffe@hfffV?̌U@?033336@4333?`fff @hfff?@4333?Lw@?03333M@4333?`ffffS@hfff?O@9?9@L?@%@?0333 @?̌@A?@|?+@?@Q?@?@hfff?0333@a?ن@?̌i@hfff?0333s[@?0333Q@?`ffff6@?@̤?@a?0333@?@hfff?`ffff@?̌@hfff?0333s@hfff^?ٌ@x?`fffl@?Ye@0?I@?0@hfffv?03333@?@?ٕ@Y?@@? @hffff?0333@?`ffff@?`ffff@?`ffff@4333#?Y@`?`fff&@`?0333.@@333?;@fff?0333s@?@@333?Y@?0333s@?`ffff@H"JM@t<]6F@XŦM@/hNG@&si'M@ȔF@/M@.F@ox`5M@?"5F@=WԨQFM@>/F@xyIM@F@RQM@_F@14"SM@_RiF@=&[M@z^_F@,DžNkM@F@"Z&hM@FF@ÛclM@S'F@хM@yE+F@>;M@/sF@S)M@ OvF@v~žM@G8F@XŦM@/hNG@%;M@):7F@_kM@`rF@maXuM@<vMF@(IoM@4LF@9RbM@wF@N,cVM@SŬԺF@ڏ*PM@ EáF@I$Z!TWM@I ڜF@H9EM@o0F@82DKM@ϓ3~F@k3HM@Fܐ$uF@[OM@P"hF@b|HM@EjbF@t@mCM@ HF@t=M@Gp@F@5,.M@t<]6F@`BH!M@P:7F@_^M@8:F@NM@?)F!CF@ &)M@9j/MF@"JM@`lF@si'M@ȔF@p5M@ G@jN@e㶎VdG@+ @G@lP 5N@D2AG@E:N@wOG@T:N@yPOG@30=8G@hfffqS@ 6G@4333snS@4G@̼iS@,5G@dS@̼7G@y[S@?G@̼VS@I@G@ RS@G@hfffFS@$:G@4333;@S@Y;G@6S@3333?G@y/S@DG@S@\EG@4333CS@ffffGG@H S@DG@!S@ffff~AG@43333R@3333DG@|R@DG@4333R@3333BG@ R@3333@G@4333R@CG@4333R@HG@hfffvR@YLG@`R@PG@hfffR@ffffnQG@4333R@ffff6QG@hfffR@RG@4333R@̔SG@aR@ffffVG@hfffR@VG@hfffR@ffffUG@4333R@RG@4333R@3333 NG@R@\EG@̬R@?G@hfffR@3333C@(!8333s>@!! >@@!8333s>@83333!8333>@hffff!>@!̞>@Y! >@(!>@hffff(!L>@!8333>@ !8333S>@!8333>@!~>@!hfffv>@ r>@8333 hfffu>@ hffffz>@ >@٩ 8333>@ ̒>@L >@hfff\ >@hfff: @>@8333 >@hfff w>@ hfff&q>@hffffe>@@3338333^>@`K>@}G>@@333dC>@L83338>@L4>@X83336>@pfff:hfff&5>@Lhfff%>@pffff28333>@L8333S>@@333hfff=@@3333a=@@8333s=@@3333̬=@JY=@L=@@3333z=@@3333{=@&hfffy=@hfff&t=@L8333o=@L ̌l=@8333O=@@333J=@̳ E=@hfff?=@o7=@Z8333s1=@pfff&hfff/=@hfff0=@6=@@333`T=@@3331 W=@9W=@L@U=@̥8333sW=@pfff^=@pffff9_=@@3333w9=@L|,(=@@333=@ =@L7=@83333=@@3333=@Xhfff%=@8333S+=@@33333=@L 3=@Lhfff&A=@g>=@BhfffF:=@pfffH7=@@333x9%=@pfffVhfff"=@@333_ =@D=@@3333%=@l=@=@ =@^8333s=@*=@ffff=@8333s=@M83333=@@#=@ 8333%=@ffff #=@ffff hffff$=@ffffC 8333S(=@ ,=@ ,2=@@3333 hffffL=@ffff 8333T=@ T=@̲ U=@M X=@Z@]=@ffff o=@n=@pfff8333=@pfff83333=@@33328333=@@333v =@@333383333=@@3333l=@@333',=@̅=@pfff=@ =@pffff83333=@hfffƿ=@@333=@pfff) =@p=@@333y=@pfffhfff=@8333=@@333 hfff=@pfffj=@@3333hfff&=@=@pffff=@8333s=@=@qhfff=@pffff̌=@pfff@=@83333=@hffff=@L=@@333=@̌=@@333ahfff=@pfffٸ=@y=@&hfff=@pfffzhfff=@hfff&=@8333=@pffffhfff>@L>@8333#>@*>@@3333hfff.>@@3333 L>@v@[>@pfff8333e>@yt>@l,>@pfff@>@>@C >@pffffjL>@pfffm83333>@pffffvhfff>@>@Y>@̀8333>@hfff>@pfff*9>@p>@L>@pffff>@@ >@hffff& hfff>@@2 >@8333= 8333S>@hfff&G >@8333R hfff&>@La hfff>@hfffy ?@hfff& hfff?@ ̌$?@ hfffF#?@L!&?@hfff&! /?@hffff4!2?@M!hffff0?@8333u!8333-?@hfff{!hffff*?@hfff&z!hfff&?@hffffp!8333"?@s! ?@!̌?@hffff! ?@hfff&!hfff?@8333!8333>@}!Y>@(!Y>@(!Y>@(!XffffJ4333S@2333KJi@HffffLJJ@NJQ@dTJLY@ffffXJ4333`@]Jhfffg@bJp@igJhffft@qlJ4333cu@̌rJ4333st@2333#xJ9n@|J@i@2333JI@XffffHI@ffffҭX3333c^I@$XnI@3333XffffyI@33337XI@3333kX3333ÉI@ffffjX̔I@ffffX3333ۑI@@Xffff~I@8XffffƎI@eXI@̀X3333I@8XI@X4I@ffffXČI@3333϶XI@fffffXI@XܙI@̤XI@ffffX33333I@XqI@XdI@3333gXI@|X3333I@3333sXI@ffffX3333SI@I@PX3333I@3333?XI@X3333[I@ffffbX3333wI@XtI@3333X3333nI@3333?X3333ciI@3333X\I@3333XTI@ffffXFI@(~X3333+I@YI@̠YI@%Y̴I@ffffBY3333I@0 YffffJ@ Y3333 J@3333 Y!'J@̸Yffff,J@ffffY`;J@ffffX3333HJ@Y3333SJ@ffffY3333aJ@3333Y3333eJ@pY3333nJ@,Y̔oJ@3333Y3333mJ@Y̤jJ@YLgJ@YffffeJ@YdJ@YffffQJ@̰Y3333OJ@YOJ@3333?YffffNSJ@YUJ@Y3333C[J@̸YbJ@ YQvJ@YyJ@ffffr!Yffff{J@3333$ȲJ@ffff^&YJ@ffff*Yffffv}J@̬*YzJ@'YhqJ@d+Y3333cJ@ffff/Yffff6`J@33334Ya`J@5Yffff&bJ@33334Yffff6fJ@Q5YhJ@̈:Yffff>hJ@9Y3333#wJ@̜?YL~J@3333o@YJ@3333FYXJ@ffffEYьJ@QI@;QffffI@6QG@̌A@ffffNG@4333C A@ffffG@@@@ G@hfff&@@G@hfff@@ G@P@@G@I@@3333G@i@@3333[G@Y@@8G@@@G@4333@@DG@@@3333G@@@G@0@@33333G@@@3333G@4333@@G@ @@ffffNG@A@3333#G@ A@G@̬ A@yG@9 A@QG@LA@̬G@hfffA@XG@hfffA@ffff~G@hfffA@G@9A@ffffG@LA@ "G@YA@ "G@4333CA@`G@"A@ffff~G@&A@8G@'A@ G@*A@3333KG@EA@G@hfffGA@3333G@,FA@̴G@ ?A@G@ <@N@hffff=<@ffffN@YA<@3333N@8333><@N@9<@N@y=<@ffffvN@N<@,N@̌j<@ffffNN@~<@ffffָN@~<@4N@z=@N@z=@N@z=@N@83333q=@3333O@\=@d O@R=@ffffO@hffff;=@3333#O@/=@O@9=@O@hfff=@O@Y<@d O@ <@| O@ <@| O@8333<@O@̶<@YN@hfff<@L@I,[ffff>L@ffff-[3333BL@,.[ffff&NL@/[xUL@3333W2[TXL@6[ZL@33337[3333_L@33335[3333[dL@0[3333hL@ffff,[PeL@3333([[L@$[ YL@![ZL@ffff[XL@ffff.[̄PL@ffffV[q;L@̼[d8L@ [7L@3333[̌6L@ffff[ffff0L@[h'L@3333 ["L@1 [q L@ffff& [3333L@ffffz [LL@[ L@3333[L@h [L@[ffffK@[K@-[K@ [3333K@̜$[HK@̴&[K@=&[K@([̬K@3333*[K@+[qK@`+[ffffK@ffff ,[ffffK@-[K@0[̜K@:[pK@ffff&B[ K@iF[3333K@ffffJ[̴L@ffffH[ffff L@E[L@7[ffff. L@*[HK@'[K@ffff^&[3333K@A![ffff~K@3333[K@[ffff6L@ L@ffff[ffffL@u[fffffL@ffff.[HL@![)%L@ [3333K$L@ffff[3333{$L@3333G[*L@̄"[ffff.L@4"[33336L@![H=L@ffff#[Q43337GQ43330GffffVQhfff+GQ4333s)G33333Qhffff(GffffVQ9*GQ&GQhfff(GQhfff&.GPQ)4Gffff Q7GffffQ4333=GQpCGQpCGQpCGQpCG 09@{N@;@ffffO@7,:@3333mO@:@mO@;@ffffkO@8333;@jO@;@|jO@8333;@ifO@hfff:@eO@L:@eO@8333s:@H_O@̌:@3333WO@:@SO@̬:@̄NO@8333:@4MO@L:@ffffOO@hfffF:@̄MO@8333:@3333+HO@hfffF:@aCO@:@3333?O@hfff:@h?O@:@ffff=O@8333:@i:O@@:@3333K=O@L:@I?O@hffff:@ffffFO@8333:@9LO@̌:@JO@L:@̄FO@ :@Q=O@:@ffff4O@hfff:@33332O@ m:@ffff.O@n:@3333#*O@k:@(O@ a:@H,O@`b:@0O@83333h:@5O@hfff&w:@6O@8333:@T6O@:@9O@hfffƎ:@>O@hfffƆ:@3333DO@b:@3333HO@F:@FO@ =:@BO@8333<:@3333=O@A:@ffff7O@I:@3333 4O@8333O:@ffff/O@hfffF:@3333+O@83333,:@ffff-O@8333 :@3333*O@8333 :@#O@hfff:@3333%O@8333 :@|,O@9@ffff/O@9@-O@9@3333'O@:@p#O@hffff9@t O@hfff&9@3333O@9@3333O@833339@ffffO@83339@O@8333S9@PO@83339@O@,9@9 O@9@O@9@ffff.O@,9@3333N@833339@N@ 9@iN@ 9@N@hfff9@DN@hfffƦ9@̜N@8333s9@LN@9@9N@y9@N@9@N@hfff&9@3333N@8333Ӯ9@N@83339@N@9@̤N@,9@ N@9@N@hfff9@N@hfffF9@N@83339@N@hfff&9@1N@9@IN@83339@N@L9@ffffN@ 9@3333#N@9@ffff>N@9@N@̌9@fffffN@`9@̤N@99@̤N@83333:@N@8333:@ffffN@:@ffffN@@:@3333N@ :@pN@):@3333N@lF:@3333N@hfffFG:@ffffN@hfff<:@N@hfffFA:@iN@hfffA:@ffffN@8333;:@3333N@@6:@ffffN@,,:@3333N@%:@ɠN@hfff,:@3333N@l2:@iN@,/:@3333N@=:@3333N@Y7:@ffffVN@̬-:@̔N@,:@O@`9@aDO@hfff9@yEO@̤9@fffffKO@١9@PPO@83339@dSO@9@4ZO@9@ffff\O@hfff9@3333\O@@9@ffff`O@hfff9@9dO@9@ffffeO@L9@3333iO@hfff9@oO@ 9@tO@9@P~O@83339@3333O@hfffƼ9@ԅO@83339@ O@9@3333ۃO@hfff9@{O@8333~9@zO@8333o9@̼|O@,^9@O@hfffFb9@O@q9@O@8333r9@O@p9@3333kO@`9@3333O@9@ffffO@8333s9@ffffO@9@LO@hffff9@O@9@ffffO@Y9@ffff>O@99@ffffO@hfffF9@,O@83339@̄O@̬9@3333sO@hffff:@)O@9:@ffff}O@hfff:@~O@:@h|O@:@wO@@8:@QmO@83333]:@@bO@hfff^:@\O@8333SM:@L]O@hfff4:@cO@l:@iO@ :@hO@ :@eO@L:@33333`O@:@ffffZO@9@3333cZO@9:@ffff.UO@:@ffffPO@83339@RO@ 9@NO@y9@yDO@hfff&9@3333+;O@@:@ffff=O@hffff:@BO@hfff:@iBO@Y:@|>O@8333:@:O@8333s:@5O@(:@33331O@Y/:@:O@-:@pFO@7:@ffff>IO@W:@MO@hfff[:@QO@8333ss:@ QO@8333x:@ffffZO@c:@ffffeO@̌[:@3333iO@hfff\:@AmO@8333Sr:@fO@:@ffff_O@:@iZO@:@yQO@8333:@MO@,:@OO@hfff:@ffffNTO@hffff:@@YO@:@ffff_O@hffff:@3333dO@8333:@hO@L:@ffffoO@:@33333sO@:@PsO@ :@3333KlO@:@ffffjO@L:@nO@:@vO@hfff:@3333zO@8333:@zO@:@3333c}O@̬:@؀O@:@O@8333;@|O@Y:@3333O@hffff:@3333kxO@:@33333uO@ :@tO@hfff:@3333[uO@:@rO@`:@3333mO@,:@3333mO@,:@3333mO@,:@3333mO@,:@3333mO@!phfff\>@3333G7P@`?@3333KP@+hfff\>@3333IP@e>@(JP@hfffw>@GP@Y>@DP@8333>@ffffFP@hfff&>@3333GP@ >@3333JP@l>@3333KP@yX?@KP@8333?@3333HP@?@%GP@̠?@%DP@hfff&?@ffffBP@@?@m=P@,?@3333g9P@`?@3333G7P@?@ffffN8P@̌?@;P@8333?@u?@uGP@1?@ffffFP@L.?@3333DP@hfff&!?@DP@8333?@ffffEP@L>@EEP@8333>@DP@hfff>@ffffBP@Y>@ffff>P@ >@d@3333#@;P@@>@@ffff>P@̌>@?P@hfff>@ffffVAP@y>@DP@Yg>@ffff2GP@hfff\>@3333IP@"@@ffff>iG@A@G@4A@3333G@|A@G@IA@ffffG@hfffFA@ffffζG@4333zA@G@4333cgA@HG@4333KA@3333G@5A@TG@LA@G@A@ԱG@yA@ffff>G@ A@3333G@p A@tG@@@QG@@@dxG@@@ sG@@@)nG@@@ffff>iG@@@fffffjG@hfff@@pG@̜@@YG@4333@@pG@Y@@`G@43333@@ɇG@4333s@@A@ffffG@hfff]A@G@A@ffff6G@K@hfff&fH@ffffK@gH@ K@lH@K@H@K@9H@ K@H@TK@H@K@H@K@H@iK@LH@fffffK@hfffH@ffff6K@yH@3333K@hfffH@̌J@4333H@3333J@ H@3333cJ@hfffH@̴J@H@IJ@4333H@̔J@hfffH@J@9H@J@H@`J@H@tJ@H@33333J@LH@YJ@9H@J@H@J@43333H@LJ@H@̤J@H@3333[J@4333H@DJ@H@ؿJ@H@(J@H@ffffvJ@ H@J@4333SH@ffffηJ@hfffvH@|J@H@J@lH@aJ@ H@J@fH@J@43333aH@qJ@`vH@ffffJ@yH@3333J@YH@4J@#Dhffff7#4333D8333.#ȡD 0#4333Dhfff#dfffDhffff"4333ˡD@"TD83333"4333×Dhffff"dffffD "xD"D"dfffސDhfff"9Ď"pD8333{"DLc"Dhfff&L"43333Dhfff&@"dfff΄D8333"dfff~D@"|D "̴zD8333s"4333wD"yDhfffX"dfffuD8333"fE%fE%fE%lE8333%pkEY%dffffEL%dfffbEhffff%DdEhfff%dfffvlE %qE%~E %4333E%4333sE%pEhffff%yuEY&wEhfff(&4333stE 9&pEhfffK&lEhffffI&XgEL*&fE%)@̬X@`ffff@hfff.X@@%hfff&X@ 333K@hfff.X@L,@X@L@X@`ffff@X@`ffff@)X@@YX@ @@X@`ffff@hfffX@`fffp@X@@1X@@hfffX@`ffff@PX@ 3333@X@ @ѺX@ 3333w@X@^@4333X@@AX@ 3333@4333#X@L@`X@&@hfffX@3@43333X@`fff@̬X@̗@4333X@`ffff@X@@X@L@hfffFX@@̬X@ 333d@X@`ffff@hfffƺX@ 3333Q@X@ 3333@X@ 3333@X@`fff~@hfff&X@ 333K@hfff&X@ 333K@hfff&X@ 333K@hfff&X@ 333K@*833339@TN@:@̬N@5:@3333N@83333:@N@:@N@hfff&y:@HN@hfffX:@N@̌=:@N@hfff.:@hN@ :@̬N@:@3333N@̌:@N@8333:@3333#N@8333s:@N@:@ffffN@$:@3333N@8333*:@3333N@hfff.:@ffffN@hfff&,:@N@y(:@PN@8333%:@3333N@:@TN@hfff&:@N@8333:@ffffvN@Y9@1N@hffff9@N@833339@3333sN@L9@N@hffff9@N@L9@3333#N@hfff9@(N@9@3333N@hfff9@3333N@hfffF:@ffffN@` :@e@%Fe@FX?e@E4333o?e@F=e@4333 Fhfff:=e@ F|=e@4333CF4333K>e@ Fhfff>e@l"F?e@4333$F?e@4333$F?e@4333$F-̈ Tx9H@3333{S̤wH@;̈ T3333gH@ffff TffffjH@TApH@TtH@̈T3333uH@ffffS̤wH@ffffSLvH@XSqH@ffffSffffoH@|S3333+mH@SAgH@SffffaH@ffffFSi]H@AS3333[H@Š\H@S^H@̀SbH@S fH@ffffSdaH@hSy[H@S4ZH@ffffS3333CXH@Sffff.UH@3333kSffffLH@3333SEH@Sh@H@3333{SqY3333+fF@h=YhF@3333#:Y3333hF@!7YQjF@̌3Y3333jF@1YlF@1Y3333pF@ffff./YqF@ffff*YoF@&YiF@3333#YgF@"Y3333[kF@ YfffffoF@@Y̔oF@@YrF@`Y)xF@YF@ffffYffffF@33333YffffF@iYF@ffffYffffF@EYffff>F@YF@ Y3333F@"Y33333F@ffff.'YlF@!Y@F@̔YffffF@YF@YF@,Yffff>F@ffffY|F@ffff"YF@ (YF@(YffffF@3333&Y F@3333!YxF@ffffYffff~F@̜Y3333F@YF@qYffffF@̀Y3333cF@YF@%YffffG@4*YffffNG@3333*YG@)Y3333G@ffff&'Y G@%Y((G@&Y!2G@&Y>G@3333'Y3333DG@(Y3333;JG@̤-YffffRG@1YffffVG@P2Y YG@̼1Y\[G@ffff-YHZG@*Y̬UG@ffffr%YOG@3333$Y3333GG@"Y>G@!Yx1G@L#Y3333#G@ffff$Y3333G@#YffffG@3333#YQ G@ffff:"YffffG@3333YtF@Y$F@3333Y3333F@mYPF@Y33333F@ Y3333F@YF@qYffff&F@!Y)F@YF@̤Y F@Y3333F@Y33333F@XYF@ffffVY3333F@3333wYF@ffffNY3333;F@ffffYffffF@3333Y̬F@3333{Yffff.F@3333{Yffff.F@3333{Yffff.F@3333{Yffff.F@0է`IM@؂`i9N@ `ffffM@`IM@`M@Ԇ`M@`ffffM@ƌ`M@`fffffN@`ffffFN@̦`N@b`ffff N@`ffff0N@է`i9N@3333i`̴6N@Z`&N@`̜N@3333u`3333N@ے`N@`3333 N@ffff`3333N@̢`1M@W`̴M@و`dM@\`3333M@5`DM@܆`dM@y`3333M@`M@؂`fffffM@ `ffffM@ `ffffM@ `ffffM@1ffff]H@ffffz]H@ffffz]H@<}]H@ffff]ffffH@$]H@]H@ffff]H@ffffΈ]ffffH@0]ffff6H@3333]H@ffffb]H@]̤H@]ffffH@3333]tH@t~]H@3333Sz]3333H@ffffz]H@ffffz]H@ffffz]H@283333?@43335@4333@@7@@@43336@i@@,6@L@@96@9 @@ٮ6@@@dfff&6@hfff@@dfffV6@?@43336@@?@̬6@hfff?@43336@̌?@){6@?@q6@?@,j6@?@a6@`?@Y6@̌?@[6@?@\6@̬?@Y6@?@U6@8333?@̬S6@hfff?@4333sR6@,?@O6@hfff?@dfffL6@̥?@4333E6@?@dfff>6@hffff?@433356@̌|?@dfff(6@hfffp?@43336@i?@dfff6@d?@dfff5@hfffZ?@i5@Q?@5@hffffK?@5@̬A?@dfffv5@hfff4?@dfffv5@'?@433335@?@̌5@83333?@43335@hfff?@̫5@@+?@43335@8333s8@N@@)8@ffffN@8@8N@hfff&8@ffffN@83338@̄N@l 8@̄N@8@N@hfff&-8@\N@=8@N@hfffK8@ffffN@Z8@N@@_8@ffffN@hfffZ8@ffff&N@8333sT8@3333ˑN@@V8@ffffNN@Le8@N@8333sp8@ffffN@i8@ffffN@hfff&Z8@\N@F8@܋N@8@N@83337@tN@hfff7@hN@hfff7@)N@8333s7@DN@hfffF7@ffff6N@97@3333N@7@̬N@83337@̼N@`8@N@ 8@N@y8@ffff>N@8333 8@(N@8333+8@ffffN@ A8@ffffN@9N8@N@hfff[8@1N@LU8@̤N@9O8@̄N@LR8@N@ ^8@|N@hfffl8@xN@9t8@$N@hfff&{8@ffffN@98@yN@hfff}8@N@,8@N@hfff8@N@8@ffffVN@8@N@8333s8@3333{N@hfffƨ8@3333N@8@N@8@ffffN@8@ffffN@8@ffffN@8@ffffN@4YY7@|N@y8@"O@8333ӂ7@3333N@7@ffffN@ 7@ffff6N@L7@N@7@3333kN@83337@ffffN@97@N@̬7@N@y7@N@̬7@|N@̬7@ffffNN@7@N@9|7@hN@̌p7@̌N@`a7@N@YY7@ܱN@`]7@N@`j7@ffffvN@97@N@hfff7@оN@hffff7@dN@97@N@l7@ffff.N@8333s7@lN@l7@3333N@7@N@Y7@N@hfffơ7@iN@8333s7@ffff&N@8333S7@ N@7@3333N@7@1N@7@YN@hfff7@pN@@7@N@ 7@N@y7@N@L7@N@97@HN@y7@ffffVN@7@̄N@7@3333sN@y7@N@83337@ffffN@8@3333N@L8@LN@83338@ O@8@O@8@ O@L7@3333 O@hffff7@$ O@83337@3333+ O@hffff7@3333O@,7@O@hffff7@|O@,7@33333O@8333S7@ffffFO@7@̔O@٬7@O@83337@O@83337@3333SO@7@ffffvO@7@O@7@PO@y7@O@7@O@̌7@0O@hfff7@O@hfffF7@ O@7@ffffVO@hfff7@O@hfff7@O@7@O@83337@3333O@L7@tO@7@pO@hfff8@O@,8@PO@8333S.8@3333O@@%8@@O@hffff8@ffffO@8@ O@8333S 8@YO@`.8@̴O@Y88@O@hfffA8@ffffF O@ I8@3333O@M8@fffffO@hfff&R8@O@U8@$ O@hfffQ8@3333S O@M8@lO@hfffS8@O@ `8@ffffO@`8@|O@̬8@O@,8@3333[ O@hffffu8@ O@Lb8@<O@W8@O@8333\8@O@p8@O@`8@̜ O@@8@̌ O@8@ O@l8@̤O@8@O@8333ӕ8@1O@̙8@̼O@y8@ffff6O@8@O@`8@3333# O@@8@3333!O@Y8@"O@l8@YO@y8@O@hfff8@YO@y8@!O@y8@ffffO@8@33333 O@hffff8@xO@L8@1N@83338@ffffN@8@3333N@y8@ffffN@`8@|N@83338@N@{8@)O@8333j8@fffffN@j8@aN@hfff`8@N@@K8@N@hfffF.8@QO@hfff&8@ffffO@̌8@|N@8@̼N@hfff 8@N@8@ffffN@hfffF7@hN@7@N@ 7@ffffN@hfff&7@N@7@ffffN@hfff&7@IN@Y7@3333N@,7@N@L7@TN@hfff7@ffffN@l7@xN@83337@ffffN@7@`N@L7@3333N@8333s7@ffffN@hfff7@N@7@hN@Y7@N@8333ӂ7@3333N@8333ӂ7@3333N@8333ӂ7@3333N@8333ӂ7@3333N@5 *pLZ@|?0333;"@hffff?0333@hffff?0333@hffff?0333@hfff?@I? @?@?`fff@hffff?`fffv@4333? n@?`ffffu@y?`fffx@hfffv?Lq@̬?Yc@L?`fffG@hfff?03333'@?0333s@4333?Y@̬?v@8333s?LZ@?i@8333ò?@ ?`fff@@ @̬@l0333@`ƿ!@ffffVп̌W@̸Կ|@ffff^ۿ0333@@F`ffff@33334@33330333sV@`fffW@0333:@̌#@ffffL>@࿐,@e߿`ffff@ݿ@Lܿ@2333ڿ̌@1ڿ@2333ٿ D@,ٿP@׿@@uտ`ffff@ӿ`ffff@Tѿ@dfff>Ϳ@dfffȿ @iƿ@Ŀ@0333c¿@03330333@`fff&@`fff&@`fff&@`fff摿L@`ffff@`fffFL@0`fff'@0333C<@ M@yc@`ffffi@@3333?a@fff&? f@8333?̌z@?`fff&@̌?0333s@@3333?0333@@333S?03333@,?L@̾?̌@̌?@P?@@8333?Y@̷?`fff%@ٹ?033336@?`fffQ@hfff?`fff&|@hfff?@?ٚ@?٧@L?̌@fff?L@~?`ffff@?@̡? @0? @P?Y@8333C?0333s@@? @?@hfff?@?@4333C?0333s@?̌@?̌%@4333?`fff&7@?L<@п`ffff@dfffʿ03333@0333Ŀ0333@@Y@@dfff&@!Ŀ@@dffffĿ-@yÿ@@0333ÿ ]@̼ſ`fff@0333ǿ03333@ȿ`fff&@̤̿@8ҿ @,Կy @ֿ`fff @2333oֿ @2333ؿY@̬ڿ@ffff>ٿ`fff@Hؿ`fff @ffffڿY( @ܿ. @2333߿  @0333 @ffff࿘yA @3333_N @3333̬D @ffff⿘Y3 @㿘y+ @0333s, @ffff俘Y6 @ffff,濘8 @.033334 @ffffV< @D @D @H @ffffR03333Q @33333̌X @ffff0333a @ffff03333z @3333- @ @q`fff @̤03333 @@ @ @ffff09!@ 5!@3333`fffB!@3333̌J!@ffffbG!@C!@3333A0333s0!@q`fffF!@ 5!@`fffQ!@ffff0333U!@`fffd!@̞̌r!@3333yYz!@33330333sv!@ffff`fffd!@S!@3333I!@A!@p`fffB!@33330333X!@uc!@3333M0333sv!@u!@`fffƏ!@0333!@̬!@03333!@3333O`fffs!@h!@0333q!@ffff03333!@`fffF!@#@!@RL!@ffff!@`fffF!@0333 "@3333򿘙%"@ffffm0333;"@0333&"@3333̌"@3333`fff&!@񿘙!@ffff`fffF!@ffff4!@ffff`fff!@h!@0333!@`ffffN!@+!@ffff0333s(!@"03332!@) M!@Yi!@ffff鿘y|!@ffffN0333Ӆ!@鿘!@s,q!@3333鿘`!@3333`fffO!@F!@̒@I!@ffff0333?!@90333'!@03333 !@3333 @`fff @3333`fff @ffff忘 @ 0333 @`fff @ffff0333 @l @࿘v @߿@k @̴ܿ@k @0ٿ`ffffq @ffffֿ`fffF| @XԿ0333| @ffffFҿ @hϿ} @ɿm @̤ȿ0333S_ @lп̬^ @̈ԿZ @$տP @̼ӿ0333H @п7 @Xȿ @dfff^ @l`fff&@0333`ffff@̪0333>@+@4333[? ,@@333s?'@?03333+@hfff?H@pfff?@s@?`fff@L?@̲?`fff@hfff&?̬ @pfff?`fff @?0333s) @Y?/ @̌?@, @?0333' @?03333, @4333#?; @l?0333sR @8333?k @8333?`fff{ @?ف @?`fff @Y?`fff& @4333? @4333? @̌?`ffff @?0333 @? @83333? @8333?0333!@ ?*!@4333S?1!@4333#?D!@|?f!@?{!@L?y!@4333?03333a!@̌?@!@|?0333S/!@4333S? &!@?`ffff !@hfff?, @hfffF? @Y?0333 @?l @? @̬?ٵ @?0333s @?9 @hfff.?Y @hfff?٤ @l? @?̌ @4333S?`fff @?`fffFi @?T @4333?9@ @4333#?Y6 @4333?L0 @?0333- @4333S?( @̜? @?0333 @hfff?Y@hfffƻ?@@?@?`fff@y?t@P?0333@4333{?0333@4333?@4333#?0333ss@hfff?`fffe@hfffV?̌U@?033336@4333?`fff @hfff?@4333?Lw@?03333M@4333?`ffffS@hfff?O@9?9@L?@%@?0333 @?̌@A?@|?+@?@Q?@?@hfff?0333@a?ن@?̌i@hfff?0333s[@?0333Q@?`ffff6@?@̤?@a?0333@?@hfff?`ffff@?̌@hfff?0333s@hfff^?ٌ@x?`fffl@?Ye@0?I@?0@hfffv?03333@?@?ٕ@Y?@@? @hffff?0333@?`ffff@?`ffff@?`ffff@4333#?Y@`?`fff&@`?0333.@@333?;@fff?0333s@?@@333?Y@?0333s@?`ffff@6QY@3333J@hfffY@3333,L@4333Y@aJ@4333Y@aJ@4333Y@aJ@4333Y@aJ@hY@J@)Y@3333J@hfffY@tJ@yY@J@Y@ffffJ@Y@̤J@4333[Y@ J@0Y@lJ@hfff6Y@3333J@0Y@J@4333Y@3333J@Y@)J@Y@1J@4333Y@̴J@)Y@3333J@̌Y@3333J@YY@J@yY@ffffJ@XY@ffff6J@Y@ J@hfff6Y@K@hfff&Y@K@Y@,$K@Y@ 5K@ Y@D6K@hfffY@ffffF>K@Y@33333PK@Y@ffff6[K@hfffY@dK@4333sY@uK@hfffvY@ffffK@hfffY@QK@hffffY@K@hfffnY@DK@hfffY@K@hfffY@3333K@4333Y@K@hfff^Y@3333CK@4333Y@ffffK@Y@L@hfffY@ffffV L@Y@ L@Y@3333[L@4333Y@ffffL@Y@,L@4333cY@L@̜Y@4L@hfffY@3333 L@hfffY@̴ L@,Y@Q L@Y@!L@Y@ffff> L@Y@ffffL@Y@ffffFL@Y@ffffK@4333~Y@K@yY@K@pzY@9K@aY@ffffK@4333kY@K@Y@K@hfff>Y@ffffK@Y@pK@4333CY@yK@Y@K@pY@ K@hfff.Y@ffff޷K@Y@ffffFK@hfffY@8K@Y@K@hfffY@3333K@Y@̄K@Y@|K@hfffY@K@hfff~Y@ffffK@9Y@TK@Y@K@4333Y@K@̔Y@ȆK@4333Y@HK@̋Y@$K@HY@K@4333Y@3333{K@Y@ffffnK@ Y@ffffK@4333ۓY@̄K@,Y@,K@̤Y@fffffK@!Y@ffffK@̤Y@iK@hfff6Y@3333K@Y@K@Y@ffffvK@4333{rY@K@4333pY@ܷK@ypY@ K@4333~Y@K@~Y@K@Q@hfffFW@ffffQ@V@ffffzQ@V@dQ@hfffV@Q@4333ۺV@Q@V@`Q@{V@ffffbQ@hfffsV@Q@iqV@3333Q@hfffjV@0Q@cV@ffffQ@43333^V@Q@4333YV@ Q@TV@qQ@4333UV@}Q@hfff&TV@Q@yaV@Q@؎V@̠Q@V@Q@V@Q@V@3333Q@V@UQ@hfffV@ffff"Q@4333V@3333GQ@84333bV@,Q@V@3333/7Q@̔V@2Q@̔V@2Q@̔V@2Q@̔V@2Q@4333V@T0Q@ТV@p-Q@hfffƖV@,Q@4333;V@3333,Q@4333cV@3333;-Q@LV@̀.Q@4333bV@i4Q@8eV@ffffF6Q@4333+oV@ffff6Q@V@ffff5Q@@V@a2Q@|V@33330Q@hfffƫV@1Q@hfff^V@ffff3Q@4333V@333334Q@hfffFV@<5Q@4333sV@05Q@hfffV@̀5Q@V@3333/7Q@4333V@ffffb2Q@̔V@2Q@9hfff4V@TQ@V@ffffhQ@4333^V@4XQ@4333^V@4XQ@4333^V@4XQ@4333^V@4XQ@hfffnNV@ffffZVQ@I=V@TQ@hfff4V@UQ@6V@WQ@GV@8[Q@hfff&VV@a]Q@hfffbV@̬_Q@yV@̘fQ@4333#V@ffffhQ@tV@3333dQ@$V@<_Q@V@`Q@V@ffffZQ@9V@`]Q@hfff6V@]Q@ V@4333E@ffff^@@43333E@@@43333E@0@@43333E@0@@43333E@0@@43333E@0@@E@@@̽E@ffff^@@E@@@4333E@ܠ@@4333E@3333@@E@3333@@hfffE@@@ɶE@3333۱@@4333E@P@@hfffE@̔@@43333E@0@@?L3@ffff E@hfff{3@3333%E@8333K3@!E@8333K3@!E@8333K3@!E@8333K3@!E@8333]3@3333%E@hfffFd3@ E@hffffs3@ E@hfff{3@ E@hfffw3@ffff E@d3@ffffF E@hffff73@IE@L3@#E@,3@|#E@8333K3@!E@@Ph[3333O@3333ZffffvP@'3333ZTP@][P@H [3333kP@3333'[hP@[3333O@fffff[3333O@P*[ffffO@/[LP@6[3333+P@ffffNG[P@3333;Y[MP@̄d[)P@h[3333GP@4W[ffff6P@I[ffffP@A[P@̌([3333 P@ffffJ&[t P@q&[P@'[P@3333&[4P@ffff"[P@[ffffvP@3333P@ [ffffP@[P@[3333P@D[ffffFP@3333[4P@[̴P@h[h P@[3333 P@ffff[ P@[3333 P@q[@ P@ffff [3333S P@[3333P@xZP@3333ZTP@A(xZ3333KO@̠Z\P@"xZP@3333ZP@ffffZ3333P@8Z,P@Z0P@3333Z4P@̤Z\P@9Z3333cP@ZDP@UZXP@XZffffnP@ffff2ZO@P@3333W:P@W6P@4W4P@fffffW}2P@,W1P@3333+W33330P@W33332P@ffffW3P@ffffW33334P@W!6P@̌W7P@3333W3333;P@W:P@W7P@`Wt6P@W9P@ X;P@4X\>P@3333W33333@P@Wffff@P@tWeAP@tWBP@3333/WffffBP@W0BP@W8@P@W8@P@W8@P@GQ3333J@ffff6QQ̌0K@5yVQ K@ffff6QQffffK@3333wTQ(K@dZQ3333K@3333#`Qffff^K@fQJ@8nQJ@ rQ4J@huQ3333J@wQffffFJ@vQJ@3333tQ3333J@ffffjoQ K@mQK@QXJ@CQffffJ@pEQܸJ@BQffffJ@ffff>QffffJ@3333QffffvK@ffffK@{QBK@\zQFK@\zQNK@3333zQSK@l}Q̜WK@ffffށQffffVK@3333Qd\K@~Q3333^K@{Q]K@̜yQffff&ZK@ffff wQ̔OK@uQ1GK@uQffff&CK@̌qQffff>K@qQ;K@3333sxQfffff:K@3333|Qp6K@ffff>Qq6K@ffffQ 8K@3333Q7K@Q8K@Q8K@Q8K@J!VffffA@AUB@̤V̬UB@̤V̬UB@̤V̬UB@̤V̬UB@pVffffCB@pV33336B@4U&B@AUB@U3333s B@lUffffA@̤ViA@U B@pUB@|VD'B@3333?V3333;(B@V3333S!B@ffffnVy%B@3333Vd-B@V333339B@ffff^V3333GB@VffffSB@dV̬yB@!VB@9 V<|B@̤V̬UB@KffffT3333@@ffffT9A@HT @@HT @@HT @@HT @@ffffbT3333@@T3333k@@ԏT@@ffffTffff@@UT@@@T @@T3333@@ȤT3333C@@̤T@@3333T@@T3333@@3333TP@@ԚT@@@hTffff@@ffffRTT@@ffffT@@Tffff@@iT@@T3333k@@ffffT9A@TA@Tffff@@FJ@3333+]^J@3333]]J@3333]3333#OJ@3333[]̤4J@ffff*]&J@]J@MxkT̬2=@ffffaTffffV=@ kT ^=@kT ^=@kT ^=@kT ^=@kTffffV=@ffffhTj=@bTI=@ffffaT\9=@fT̬2=@ffffhTA=@pjTlP=@kT ^=@N\ffffA@ffff:\EA@\33338A@\33338A@\33338A@\33338A@\>A@3333\EA@ffff\ffff&=A@3333+\5A@ffff:\̴(A@̔\ffffA@3333w\ffffn A@ffff\̴(A@3333\3333#/A@\33338A@OffffF^X\D@3333^|oD@Ԏ^|oD@Ԏ^|oD@Ԏ^|oD@Ԏ^|oD@^ffff&gD@^ffffeD@e^`fD@3333^IdD@^bD@^ffffv_D@h^ffff`D@P^\D@3333G^X\D@ffffF^33333_D@^YbD@3333K^ jD@-^hD@ffffv^\dD@H^fD@^3333+nD@Ԏ^|oD@PD\F@PffffnF@P!F@3333P̴F@3333PpF@PffffF@ffffPffffF@3333;P3333F@3333_Pffff&F@LPffffF@TH@3333dfffwH3HLHLHLHLH@33334333H@333HIdfffH14333KH dffffHHpffflHpfffuH;HHffff4333HHdfffH4333H@3333dfffH4333H@333dfffH4333ۿH!PH@333pHpffff4333HpffffHhH̶qH,Hpffff3HXpHpffff8HH̨Hpfff){HLdfffwH@33336L|HUɕH@3333Hpffff4H Hpfff,4333HpffffbLHHpfffHLx4333SH^dfffvH.HdffffHpfffHLUFhfff 3sF32M4333k|F4333324333k|F4333324333k|F4333324333k|F433332xFY2XwFhfff2sF92uF4333s24333{F̌2dfffFhfff2F`24333{FL2tF2dfffF@34333[Fhfff 3PFy3dfffF̬2F 2dfffFhffff2F@2dfffƲF3FL2hFhffff2Fhfff2КF2F2dfffVF2@F43332F43332dfffF`24333F4333324333{Fhfff2F̬24333F2F21F 2F43332dfffFhfffƢ2Fhfff2dffffFhfffF2dfffF4333s2F433332dfffF4333|2$F 2ܶF4333s2Fhffff2Fhfff2F2HFhfffFy2Fn2pF e2dfff>F4333[24333FhfffM24333#FE24333sF̌D2 FL=2̼F32FL42qF4333;2iFK2dfffvF j2 F9y20F@}2dfffF2F2dfff&FY2F 2dfffF2hF2dfffF24333sFhfff&2pFhffff24333FL2)F2F2~F24333k|F433332V4333Il4JIhfff34AIm4AIm4AIm4AIm4,Ie4Ihfff_4I4333Z44333IH4IhfffA4ɰIF49IhfffG4IhffffA49IA44333IY=4IhfffF/44333+I%4YI-4I,4dffffI43334PIl4I34333ۃI3̬Ihfff30|I 34333CzI3qyIhfff&34333[gI34333sUI433333JI433334333UIhfff3dfff^eI34333lIL4wI4~I+443333}I`;4̜wIhfffC44333tIQ44333}IhfffN4I@T4tIlV44333cIYV4IY4̄I@^4\I4333Sd4ILu44333KI4333S44333cIl4dfff.I44333Ip4lI̬s4ɲIq4AIm4Wpffff&Rhfff&ZDXROD ffff&RhfffFTDffff&RhfffFTDffff&RhfffFTDffff&RhfffFTD"ROD RODXRQDR4333TDRhfff&ZD̀$RIXDffff&RhfffFTDXq>QF33333$Q4333ӡFH+Q4333FH+Q4333FH+Q4333FH+Q4333F3333*Q4333Fffff)Q|Fx&QhffffFffff$Q̬F33333$Q̬FY&QFM-QFH6QlF3333 ;QF3333=Q43333Fq>QlF>QFffff;Q4333ӡF33338QF6Q4333F3333{5QFU3QF 1QF,QIFH+Q4333FYhpfff&!@G@LA"@O@[@ܶO@hfffFv[@O@hfffp[@O@xi[@DO@hfffe[@LO@hfffo[@ffffO@y[@YO@|[@3333sO@t[@aO@[@O@ [@O@̬[@O@P[@O@8[@ffffVO@$[@ffffO@4333ˏ[@O@[@кO@ў[@3333ӺO@[@3333O@[@ffffO@4333[[@O@4333[[@ffffO@[@؝O@[@ffffVO@hfffƪ[@qO@8[@ffffΛO@hfff[@̤O@[@ O@[@LO@hfffƺ[@ffffƖO@hfff[@aO@hfff~[@ffffO@4333[@ffffO@[@3333O@[@ O@d[@O@Y[@yO@l[@O@[@܅O@[@3333 O@[@dO@4333+[@3333{O@[@ȧO@4333[@3333O@hfff[@ O@)[@[@̔O@|[@3333O@[@33333O@h[@ffff֎O@4333K[@O@hfff[@)O@Y[@O@4333K[@3333O@([@3333+O@̼[@HO@0[@3333O@ [@O@[@ffffO@[@t[@ffffO@hfff{[@! O@4333K[@)O@̼[@3333O@̦[@ffffO@)[@ffffnO@t[@ O@4333۳[@3333+O@̼[@ O@4333[@ffff O@hfff[@ffff O@4333C[@O@4333[@yO@4333[@ffffO@hfff[@ffffO@hfff[@3333CO@\[@ O@4333[@3333'O@ [@/O@hfff^[@ffff67O@hfff[@=O@4333[@ffff@O@hfff[@t>O@[@;O@hfff[@ffff.=O@̌[@?O@0[@CO@4333{[@EO@[@ EO@hfffF[@ffffEO@̼[@HO@[@POO@ahfffua@J@̀}a@ J@1|a@ J@1|a@ J@1|a@ J@1|a@ J@̀}a@3333kJ@\{a@J@ya@3333#J@4333Sza@3333;J@za@J@hfffwa@J@hfff~ua@3333J@hfffua@dJ@wa@ J@1|a@ J@b4333e@P@4333e@,P@̼e@ffffr$P@̼e@ffffr$P@̼e@ffffr$P@̼e@ffffr$P@he@(%P@]e@3333W'P@le@ffff)P@e@ffff*P@4333e@)P@e@3333W$P@xe@P@Me@P@e@P@4333e@ P@e@&P@De@D+P@hfffe@,P@e@=*P@Ae@&P@̼e@ffffr$P@ct`@A@a@A@a@A@a@A@a@A@a@A@hfffa@3333A@aa@A@a@ffffA@4333/a@ffff&A@a@pA@4333a@3333ˡA@``@ffffA@̀`@TA@t`@A@`@3333A@4333`@ffffA@a@A@a@A@d̲0aN@̢a3333sN@3333$apN@3333$apN@3333$apN@3333$apN@ffff#a|N@j"a3333kN@ffffX!aN@affffN@̢a!N@ aN@ffff` affffN@ !a3333N@̦"aiN@ffff`%affffN@*a`N@̲0aaN@ffff".a3333sN@*aHN@h(aN@3333$apN@ec3333AM@mcY]M@ffffnc̄QM@ffffnc̄QM@ffffnc̄QM@ffffnc̄QM@3333krc3333NM@fffftcMM@tcIM@ocFM@"ocffffCM@3333pc3333AM@tcBM@wcffffFM@zcffffvLM@3333c3333LM@3333-c3333cMM@ffffVčPM@3333)cUM@chXM@cZM@3333Wc[M@ffffJc3333\M@cY]M@ffffcL[M@33331cYM@4cXM@ffffzcxWM@ffffqcTM@mc3333TM@ffffnc̄QM@f`ffff`d33333N@Vd3333N@ ffffZd33333N@ffffZd33333N@ffffZd33333N@ffffZd33333N@ffff`d̤N@`d3333N@Yd3333[N@Vd܉N@ffffZd33333N@gXc!N@ 4c7N@"OcxN@"OcxN@"OcxN@"OcxN@ffffIc3333#N@Bc3333+N@ 6cffff7N@ 4c7N@5c3N@Ač&N@3333QHcaN@3333Qc3333N@ Wc!N@XcN@TcffffVN@TRcffff^N@SQc,N@"OcxN@hffffNbffffN@b3333'N@ffffNbN@ffffNbN@ffffNbN@ffffNbN@3333bfffff N@3333b3333'N@ffffb3333"N@bffff^N@b3333N@ffffbffffN@bN@3333b3333 N@3333b3333[N@b3333sN@bQN@bN@ffffNbN@ip/dffffN@c3333N@ dܬN@dܬN@dܬN@dܬN@ffffdffffN@/dN@3333IdN@33337d3333N@ffffcffffvN@cffffN@dܬN@jLdiN@Fd~N@ffffIdyN@ffffIdyN@ffffIdyN@ffffIdyN@IduN@3333yHdqN@Fd)mN@GdiN@HdiN@KdS@?@4333cR@2333?@ R@@@4333R@@@hfffR@3333@@hfffS@fffff @@ S@@?@4333 S@2333s?@rx!V@i?@4333V@ @@ 4333V@̌?@4333V@̌?@4333V@̌?@4333V@̌?@V@2333?@!V@@@V@3333[@@4333V@ @@4333V@4 @@4333V@2333C?@,V@i?@4333V@̌?@sp̌U@?@!U@?@ ̌U@ffff?@̌U@ffff?@̌U@ffff?@̌U@ffff?@4333#U@fffff?@TU@P?@4333U@?@U@?@!U@0?@U@?@̌U@ffff?@tYS@@@pS@̜@@ YS@ffff>@@YS@ffff>@@YS@ffff>@@YS@ffff>@@4333cS@̜@@S@@@4333S@ffff@@yS@@@pS@3333@@S@3333+@@hfffS@@@hfff^S@3333@@YS@ffff>@@u ,,Q@I@xgQ@\I@!hffffRQ@XI@hffffRQ@XI@hffffRQ@XI@hffffRQ@XI@hfffWQ@\I@4333 aQ@XI@xgQ@̌VI@43333gQ@NI@`Q@KI@hfffXQ@̬LI@iUQ@`MI@QQ@3333;KI@FQ@:I@CQ@|6I@4333KBQ@2I@CQ@3333.I@$OQ@@-I@̔PQ@'I@hfff^PQ@ffff I@LQ@x I@4333{IQ@ffffI@̼DQ@3333I@P@P@qJ@=P@ffff]J@43338P@VJ@2P@ffffOJ@43330P@pNJ@4.P@ffffLJ@̄)P@FJ@hfff P@3333BJ@hfff P@|DJ@hfff$P@lMJ@wX |'@3333N@@333'@ffffO@@333'@3333;N@@333'@3333;N@@333'@3333;N@@333'@3333;N@pffff'@3333N@ |'@O@L'@ffffO@@333'@3333;N@xLq'@(N@'@5O@pfff'@ffffO@pfff'@ffffO@pfff'@ffffO@pfff'@ffffO@Y'@a&O@'@$3O@L'@5O@'@ 4O@pffff'@̤'O@'@AO@'@aO@pfff&'@X O@pfff'@XO@@333s'@(N@@333'@(N@̌'@O@Lq'@ffff& O@x'@ffffO@@'@ffffO@pfff'@ffffO@y̨ASI@l#S8I@3333W+S̯I@3333W+S̯I@3333W+S̯I@3333W+S̯I@l#SI@ $SI@0SI@̨AS3333I@ffff>SI@ffff9SdI@$7SI@ffff5SI@ffffr4S8I@0SffffI@3333W+S̯I@zdVI@Vffff>I@ ̼VLI@̼VLI@̼VLI@̼VLI@VI@̨VI@VffffI@dVI@3333Vffff>I@ffffFVI@@VٔI@3333VffffVI@̼VLI@{ppVffffvI@MV̴I@ 3333VffffI@3333VffffI@3333VffffI@3333VffffI@V̴I@MVI@DVffffI@VffffvI@V3333SI@pVI@3333VffffI@|hSQI@0Sffff~I@ qSI@qSI@qSI@qSI@0SQI@SffffvI@Sffff~I@ffffֲS̬I@3333SI@qSI@}SffffG@3333SqG@0ShG@0ShG@0ShG@0ShG@SG@ffffҰSffffG@]Sffff&G@ffffSG@SG@3333SqG@3333WS3333G@(SffffG@3333SG@\S3333G@SG@0ShG@~3333TSaG@;SffffG@|QSffffG@|QSffffG@|QSffffG@|QSffffG@OSffffVG@3333SKS3333G@ffff>HSG@3333FSffffG@ffff.DSffffG@̠=SLG@;ShG@=SffffG@GSG@KSdG@ffffnKS̬G@3333JSffffֱG@3333KS3333;G@ffffPSaG@3333wRShG@LQS@G@|SSG@3333TShG@3333oSSG@tRSffffG@|QSffffG@p̼[,P@ffffZ3333/P@ ̼[-P@̼[-P@̼[-P@̼[-P@ffffj[0/P@[3333/P@3333[̰/P@ffffZffff.P@33333Zffffr-P@ [,P@̼[-P@!"[#P@ [+P@ 3333 [])P@3333 [])P@3333 [])P@3333 [])P@ffff^ [ffff(P@\[3333'P@[#P@!"[#P@3333[=&P@3333[)P@`[ffff+P@ [+P@3333 [])P@mF[P#P@ffff4[3333.P@ffffv;[3333k&P@ffffv;[3333k&P@ffffv;[3333k&P@ffffv;[3333k&P@D?[3333C'P@C[ffff%P@E[̐%P@mF[3333&P@3333CF[)P@C[3333+P@D[-P@C[3333.P@;[,-P@$9[̄*P@ffff6[ffff&P@ffff4[P#P@6[#P@ffffv;[3333k&P@0W[3333S"P@̐I[̄0P@ffffP[ffff%P@ffffP[ffff%P@ffffP[ffff%P@ffffP[ffff%P@ R[ffff&P@3333U[3333)P@0W[3333,P@ W[ffff.P@ffff6V[3333{0P@3333R[̄0P@aO[`/P@ffffjP[3333.P@,R[,P@hQ[]*P@̐I[%%P@EJ[#P@\N[3333S"P@xQ[3333S"P@O[($P@ffffP[ffff%P@xSffffQ@SfffffQ@ffffrSffffBQ@ffffrSffffBQ@ffffrSffffBQ@ffffrSffffBQ@SXQ@S3333Q@S(Q@SlQ@YSffffQ@Sffff2Q@SQ@xS3333Q@S3333Q@̼S,Q@3333SfffffQ@LSffffQ@ffffrSffffBQ@x,7ZmQ@ffffZvQ@ ffff ZmQ@ffff ZmQ@ffff ZmQ@ffff ZmQ@ffffR)ZnQ@,7ZvQ@̼0ZvQ@ZuQ@ffffZ$uQ@ffffZ0tQ@Z]pQ@ffff ZmQ@LXffffJP@3333XP@3333wXffffP@3333wXffffP@3333wXffffP@3333wXffffP@\X3333kP@3333XAP@dXffff~P@3333XffffJP@3333gX33333P@XP@LXdP@}XyP@XP@ԛX}P@3333wXffffP@33337X1K@ffff>W`K@33337XlK@33337XlK@33337XlK@33337XlK@! X̼K@̀XffffK@ffffW(K@|W9K@W`K@ffff>WK@W\K@3333W3333ۣK@XffffΛK@X1K@33337XlK@5Yp9K@ņYffffv^K@@YIK@@YIK@@YIK@@YIK@̄YSK@`Y3333[K@ffffYffffv^K@mY3333ZK@ņYLK@-Y0?K@ЊYH:K@ffffbYp9K@ffffƕYK@TdZ:K@ecZ1K@udZ)K@hZX"K@3333 kZtK@3333;mZ,K@3333mZ3333 K@XpZffffK@ffffsZffff K@sZK@tZffffK@ffffQ3333J@Qffff>J@QiJ@QiJ@QiJ@QiJ@3333߻Q3333ӽJ@ܹQJ@Q̹J@QJ@3333WQ3333J@Q(J@QffffJ@ffffQ\J@yQffffJ@4Qffff>J@ɼQQJ@QiJ@Nffff^(J@2333LN3333COJ@2333sNYFJ@2333sNYFJ@2333sNYFJ@2333sNYFJ@ffff\N33338J@ZN`4J@TN-J@IMN *J@2333LN(J@RNffff^(J@^Nffffn0J@ffffeNL6J@auN=J@{N3333BJ@ffff6NpKJ@NIT$`@ћ6n|Sg&`@|XZ 6akrn&`@Ǯ6-8I"`@&o,6X|Sg!`@ⰋUE6Z$`@UU6-8'`@rp]6 &`@j6R %`@nD빚r6(#`@X)i6 `@26L`@ԭm6V;`@dy6#<`@VXZƥ6#<`@VXZƥ6#<`@VXZƥ6 b`@[)@2^1 a@$V9?0`@[)@xL}`@_@St`@C9Dx7@<-hra@n H?" ya@?|ը`@ ?AE`@뜞,?&ј`@ ?SZ6`@% ??`@Q ŗ?4u`@GI͘?W`@vE2?|0d`@VQ?D8r,`@d?G`@loq?h`@lSf?` 'n`@( a?]1 `@xV]?`@Z? ?ٵ`@P?^18`@HkG?`@*ikg;? b`@\wߟ?ZnO`@$V9?P`@d?b]^`@:]wo0?18`@H ya@-@*4a@/it@4"a@|s@aa@("r @;#a@e=>@tėa@j@HuI/`@+3g@4S`@Ͷ(@`@[)@`@[)@`@[)@x<&a@ ?;>Da@(->,`:a@@?8a@-DF?$d7a@ ?v|6a@H?8z3a@fL?+=3a@T$?TZ!}5a@b1l?S6a@z?q7a@E,atS?V~6a@4E?]4a@ "=?n1a@N'?0a@-?dL2a@~3?84a@Tj<?0?95a@w_?ܰc.5a@֙>ek4a@s]>Pŗ3a@d>[4a@+>r 3a@ M>2(a-a@B֨|,a@$.~>plD,a@ʴx>DL*a@0Pu]>2s2(a@VI><&a@9>XB'a@(->WV*a@P9բ7>@Y{-a@N>u n/a@. \*b> ?3a@3=m>p9rl7a@Ep~>tb;:a@ \>[=a@ԢXZ>du @a@L6>2 @a@ >w|@a@d?T-@a@Nʹt?;>Da@AB?> FCa@xP{d?`:a@@?`:a@@?`:a@@?x^@hF]@ǒ=Dw/Wf^@j]<,1 ]@7Y=}iH]@ǒ=]@ǒ=Z(o]@g=F@_b]@=b[]@s=eF]@NUwc=Z(o]@i%'}V=]@%F=ӻ]@`5=@E]@b1/=B%]@©4#0=0 ]@.(~c7= ໰]@4Df&a=<¶]@zc`=FZE]@Df̍=hj]@\pȊ=;]@Q <=UQ]@F6=6[G%]@:<=o]@j#Y=8+%]@6G=^@hF]@?ɗL==K}]@PڨG=F]@TXZ= Qps]@ō]@NM=r=Z(]@zL=]@(g_=|^]@i=1 ]@7Y=1 ]@7Y=1 ]@7Y=oa@Y ?]ha@m:R>)a~a@nsB>hјt}a@b1?R |a@~?DSgza@Y ?ya@:U?/wa@#d?(Wua@S?:0sa@m?qB֝pa@@*>oa@tyw>gUqa@ ̴>4Sva@Q א> |a@|_>q~a@m:R>m[a@m0W>]ha@&D.l>(Հa@g>>~ka@>)a~a@nsB>)a~a@nsB>)a~a@nsB>؉#a@jK;w=CI 7a@I;m!=4b#5a@"Uw%Y=L(aZ3a@ z|_=v0a@\(e=Ԙ -a@$Rڨq=+a@N=r)t=V(a@\ s=&֨ &a@jK;w=؉#a@BXZs=h#a@b빲X=d&a@v >=X[*a@n8=2a@*2U(=U6a@I;m!=CI 7a@(9*\2=4b#5a@"Uw%Y=4b#5a@"Uw%Y=4b#5a@"Uw%Y=u a@\ d=@t@a@Z ;0ގA@=a@\ d=8a@S =<3a@*P = G/a@TXZ=-a@4u=^ʞ+a@LPڨi=q)a@:XZ<7'a@yw<$a@z|<.$a@nsB<ؑdx#a@Z=<>28e"a@.?ɗ=* a@J'~=*[a@p<ʞa@p<~Za@Q }a@ʇGI%s<^a@\m<.a@d<55a@JgP<‘d8a@lB2<PJ8a@쓻#d<^Rqa@RL<a@n&P# 8Dz8EJKMjO68SrpXa:e n}bzHRNb`$0XV<`xvZ6^hhfx.^j`rŽÒnR(~ǂɞ2˲p&x̢&8b8Ϟ`ѶӦx"pR620f2P܆"R(~jv:hx"H2^pv:xBxh*hvP 6v J.2.fh j F   b0XF `nZ ("6#h%fp'(*r,,.f/ 0&01x2*`2`2 445~6B7>8299:;<8=>?@VA*BCCDjEFHIjJ LBMM NOPQ:QRS~TbUUVW: X^YJYZ[\b]6h]H^a bcd`efg0hjxlvm2mnPp6phrVsstJtuvNvwxby>zB{Fp{~(@B(n.B^@ HZF"X~bn *0H|pPDH`̬X$Px"؞X:8X0X `pHX8XP@V*@bHn$*`&+ *8>t?@lAH`BCExEF,FPH (I8 J\KXLD NhOlQ0R0T UVVxWPWXZ[h[\^4`btpbchd0deftxfghP`op@pqr\s``stpupuvvxwwpx$xydxyxz\pz{T |x}$X}~<~Tph4p(Xx4\@p $\h0$x<x| Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.README.html0000664000175000017500000011515015151324131026767 0ustar hibbyhibby Natural Earth » Blog Archive » Rivers, Lake Centerlines - Free vector and raster map data at 1:10m, 1:50m, and 1:110m scales

Rivers, Lake Centerlines

rivers_lake_centerlines_thumb
Single-line drainages including optional lake centerlines.

About

Generalized from the 10 million rivers. The 50 million rivers primarily derive from World Data Bank 2. Double line rivers in WDB2 were digitized to created single line drainages. All rivers received manual smoothing and position adjustments to fit shaded relief generated from SRTM Plus elevation data, which is more recent and (presumably) more accurate.

Lake centerlines obtained by manually drawing connecting segments in reservoirs. When available, Admin 0 and 1 political boundaries in reservoirs serve as the lake centerlines.

Ranked by relative importance. Includes name and line width attributes for creating tapered drainages.

(below) Congo River basin, Africa.

rivers_tapered_drains_wide

Includes scale ranks (large rivers, small rivers):

(below) Southern United States.

river_ranks_wide

Avoid data dump overload:

(below) Quebec, Canada in Natural Earth compared to Digital Chart of the World.

rivers_scale_ranks_compare_with_dcw_wide

Issues

Does not include intermittent rivers (eg: large seasonal rivers in Australia draining to Lake Eyre playas). Rivers in northeastern Russia and parts of the Amazon basin have suspect alignments.

Version History

The master changelog is available on Github »

Comments are closed.


Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.VERSION.txt0000664000175000017500000000000615151324131027023 0ustar hibbyhibby5.0.0 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.cpg0000664000175000017500000000000515151324131025630 0ustar hibbyhibbyUTF-8Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.dbf0000664000175000017500001453356415151324131025644 0ustar hibbyhibbyy 'scalerankNfeatureclaCnameCnoteCmin_zoomNname_altCmin_labelNname_enClabelCwikidataidCname_arCname_bnCname_deCname_esCname_frCname_elCname_hiCname_huCname_idCname_itCname_jaCname_koCname_nlCname_plCname_ptCname_ruCname_svCname_trCname_viCname_zhCne_idN name_faCPname_heCPname_ukCPname_urCPname_zhtCP 6Lake Centerline Kama 4.7 6.0Kama Kama Q79082 نهر كاما কামা Kama Kama Kama Ποταμός Κάμα कामा नदी Káma Kama Kama カマ川 카마강 Kama Kama Kama Кама Kama Kama Kama 卡馬河 1159125905رود کاما קאמה Кама دریائے کاما 卡馬河 6River Kama 4.7 6.0Kama Kama Q79082 نهر كاما কামা Kama Kama Kama Ποταμός Κάμα कामा नदी Káma Kama Kama カマ川 카마강 Kama Kama Kama Кама Kama Kama Kama 卡馬河 1159125917رود کاما קאמה Кама دریائے کاما 卡馬河 3Lake Centerline Abay 3.0 4.0Lesser Abay Q3501984 أباي অ্যাবে Abajasee Abay Abbey Lake Άμπαι एबे Abay Abay Abay 小アバイ川 아바이 Abay Abaj Lesser Abay Абая Lesser Abay Abay Abay 阿拜河 1159125319ابی אבאי Абая ابے 阿拜 3Lake Centerline Al Furat 3.0 4.0Euphrates Al Furat Q34589 الفرات ফোরাত Euphrat Éufrates Euphrate Ευφράτης फ़रात नदी Eufrátesz Efrat Eufrate ユーフラテス川 유프라테스강 Eufraat Eufrat Eufrates Евфрат Eufrat Fırat Euphrates 幼发拉底河 1159125935فرات פרת Євфрат دریائے فرات 幼发拉底河 6Lake Centerline Alabama 5.0 6.0Alabama Alabama Q558643 ألاباما আলাবামা Alabama Alabama Alabama Αλαμπάμα अल्बामा Alabama Alabama Alabama アラバマ川 앨라배마강 Alabama Alabama Alabama Алабама Alabama Alabama Alabama 阿拉巴馬河 1159114961آلاباما נהר אלבמה Алабама البامہ 阿拉巴馬河 6Lake Centerline Albany 5.0 6.0Albany Albany Q1241991 ألبانيا আলবেনি Albany Albany Albany Ώλμπανι अल्बेनी Albany Albany Albany オールバニー川 알바니 Albany Albany Albany Олбани Albany Albany Albany 奥尔巴尼河 1159114709رود آلبانی אלבני Олбані دریائے البانی 奧巴尼 1Lake Centerline Albert Nile 2.0 3.0White Nile Albert Nile Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159129205نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 3Lake Centerline Amur 3.0 4.0Amur Amur Q6862 نهر آمور আমুর নদী Amur Amur Amour Αμούρ अमूर नदी Amur Amur Amur アムール川 아무르강 Amoer Amur Amur Амур Amur Amur Amur 黑龙江 1159126525آمور אמור Амур دریائے آمور 黑龍江 2Lake Centerline Angara 2.1 3.1Angara Angara Q162737 نهر أنغارا আঙ্গারা নদী Angara Angará Angara Αγγαράς अंगारा नदी Angara Angara Angara アンガラ川 안가라강 Angara Angara Angara Ангара Angara Angara Angara 安加拉河 1159117253رود آنگارا אנגרה Ангара انگارا 安加拉河 6Lake Centerline Atbara 5.0 6.0Atbarah Atbara Q753897 نهر عطبرة আতাবারা Atbara Atbara Atbara Ατμπάρα अतबरा Atbara Atbara Atbara アトバラ川 아트바라 Atbarah Atbara Atbara Атбара Atbara Atbara Atbara 阿特巴拉河 1159115327آتبارا עטברה Атбара دریائے عطبرہ 阿特巴拉河 5Lake Centerline Athabasca 4.7 5.7Athabasca Athabasca Q2216 نهر أتاباسكا আথাবাস্কা নদী Athabasca Athabasca Athabasca Ατάμπασκα अथाबास्का Athabasca Athabasca Athabasca アサバスカ川 아사바스카 Athabasca Athabaska Athabasca Атабаска Athabascafloden Athabasca Athabasca 阿萨巴斯卡河 1159113183رود اتبسکا אתבסקה Атабаска ایتھاباسکا 阿萨巴斯卡河 6Lake Centerline Back 5.0 6.0Back Back Q798339 باك ব্যাক Back Back Back Μπακ बैक Back Back Back バック川 백 Back Back Back Бак Back Back Back 巴克河 1159115519بک באק Бек بیک 北克湖 6Lake Centerline Biya 5.0 6.0Biya Biya Q859934 بيا বিয়া নদী Bija Biya Biia Μπίγια बिया नदी Bija Biya Bija ビヤ川 비야강 Bieja Bija Biya Бия Bija Biy Biya 比亞河 1159115367رود بیا ביה Бія بیا 比亞河 6Lake Centerline Chattahoochee 5.0 6.0Chattahoochee Chattahoochee Q1068297 تشاتاهوتشي চাত্তাহূছি Chattahoochee Chattahoochee Chattahoochee Τσαταχούτσι चत्ताहूची Chattahoochee Chattahoochee Chattahoochee チャタフーチー川 채터후치 Chattahoochee Chattahoochee Chattahoochee Чаттахучи Chattahoocheefloden Chattahoochee Chattahoochee 查特胡奇河 1159114925رودخانه چاتاهوچی צ'אטאוצ'י Чаттахучі چاٹاہوچی 查特胡奇河 6Lake Centerline Churchill 5.0 6.0Churchill Churchill Q291233 تشرشل চার্চিল Churchill Churchill fleuve Churchill Τσόρτσιλ चर्चिल Churchill Churchill Fiume Churchill チャーチル川 처칠 Churchill Churchill Churchill Черчилл Churchillfloden Churchill Churchill 丘吉尔河 1159114731چرچیل צ'רצ'יל Черчилл چرچل 丘吉爾河 5Lake Centerline Colorado 4.7 5.7Colorado Colorado Q1265 نهر كولورادو কলোরাডো নদী Colorado Colorado Colorado Κολοράντο कोलोरेडो नदी Colorado Colorado Colorado コロラド川 콜로라도강 Colorado Kolorado Colorado Колорадо Coloradofloden Kolorado Colorado 科羅拉多河 1159112837رودخانه کلرادو קולורדו Колорадо دریائے کولوراڈو 科羅拉多河 3Lake Centerline Columbia 3.0 4.0Columbia Columbia Q2251 نهر كولومبيا কলাম্বিয়া নদী Columbia Columbia fleuve Columbia Κολούμπια कोलम्बिया नदी Columbia Columbia Columbia コロンビア川 컬럼비아강 Columbia Kolumbia Columbia Колумбия Columbiafloden Kolumbiya Columbia 哥倫比亞河 1159124363رودخانه کلمبیا קולומביה Колумбія کولمبیا دریا 哥倫比亞河 6Lake Centerline Coppermine 5.0 6.0Coppermine Coppermine Q1131514 كوبرمين কপারমাইন Coppermine Coppermine Coppermine Κόπερμαϊν कापरमाइन नदी Coppermine Coppermine Coppermine コッパーマイン川 쿠퍼마인 Coppermine Coppermine Coppermine Коппермайн Copperminefloden Coppermine Coppermine 科珀曼河 1159115263کوپرمین קופרמיין Коппермайн کاپر مائن 銅礦湖 6Lake Centerline Dalälven 5.0 6.0Dalälven Dalälven Q216627 دالالڤين দালালভেন Dalälven Dal Dalälven Ντάλελβεν डलालवेन Dalälven Dalälven Dalälven ダール湖 달라벤강 Dalälven Dalälven Dalälven Далэльвен Dalälven Dalälven Dalälven 達爾河 1159114315داللون דאלאוון Далельвен ڈالالوین 達爾河 6Lake Centerline Dniester 5.0 6.0Dniester Dniester Q131210 دنيستر দনিএস্তের Dnister Dniéster Dniestr Δνείστερος डेनिस्टर Dnyeszter Dniester Dnestr ドニエストル川 드네스트르강 Dnjestr Dniestr Dniestre Днестр Dnestr Dinyester Dnister 德涅斯特河 1159114439نیستر דניסטר Дністер نائیسٹر 德涅斯特河 4Lake Centerline Dnipro 4.0Dnieper 5.0Dnieper Dnipro Q40855 دنيبر নিপার নদী Dnepr Dniéper Dniepr Δνείπερος नीपर Dnyeper Dnieper Dnepr ドニエプル川 드네프르강 Dnjepr Dniepr Dniepre Днепр Dnepr Dinyeper Dnepr 第聂伯河 1159111985دنیپر דנייפר Дніпро دریائے دنیپر 第聂伯河 6Lake Centerline Don 4.7 6.0Don Don Q1229 نهر الدون দোন নদী Don Don Don Ντον दोन नदी Don Don Don ドン川 돈강 Don Don Don Дон Don Don Đông 頓河 1159115979رودخانه دان דון Дон ڈان 頓河 3Lake Centerline El Bahr el Azraq 3.0Blue Nile 4.0Blue Nile El Bahr el Azraq Q882739 النيل الأزرق নীলাভ নীল নদ Blauer Nil Nilo Azul Nil Bleu Γαλάζιος Νείλος नीली नील Kék-Nílus Nil Biru Nilo Azzurro 青ナイル川 청나일강 Blauwe Nijl Nil Błękitny Nilo Azul Голубой Нил Blå Nilen Mavi Nil Nin Xanh 青尼罗河 1159126685نیل آبی הנילוס הכחול Блакитний Ніл نیل ازرق 青尼罗河 2Lake Centerline Ertis 2.1 3.1Irtysh Ertis Q128102 إيرتيش ইর্তিশ নদী Irtysch Irtish Irtych Ποταμός Ιρτίς इरतिश नदी Irtis Irtysh Irtyš エルティシ川 이르티시강 Irtysj Irtysz Irtich Иртыш Irtysj İrtiş Irtysh 额尔齐斯河 1159116591ایرتیش אירטיש Іртиш دریائے ارتش 額爾齊斯河 3Lake Centerline Firat 3.0 4.0Euphrates Firat Q34589 الفرات ফোরাত Euphrat Éufrates Euphrate Ευφράτης फ़रात नदी Eufrátesz Efrat Eufrate ユーフラテス川 유프라테스강 Eufraat Eufrat Eufrates Евфрат Eufrat Fırat Euphrates 幼发拉底河 1159124657فرات פרת Євфрат دریائے فرات 幼发拉底河 6Lake Centerline Gan 5.0 6.0Gan Gan Q1046685 نهر جان গান Gan Gan Gan Γκαν गन Gan Gan Gan 贛江 간장 강 Gan Gan Gan Гань Ganfloden Gan Cám 赣江 1159116025گان גאן Ґань گین 贛江 5Lake Centerline Grande 4.7 5.7Grande Grande Q386331 ريو غراندي গ্র্যান্ডে Grande Grande Grande Ρίο Γκράντε ग्रैंडे Grande Grande Grande ブラジル 그란데 Grande Grande Grande Риу-Гранди Grande Grande Grande 格兰德河 1159112877گراند גראנדה Ріо-Гранде گرانڈے 格蘭德河 6Lake Centerline Han 5.0 6.0Han Han Q875573 هان হান Han Han Han Χαν हान नदी Han Han Fiume Han 漢江 한강 Han Han Shui Han Ханьшуй Han Shui Han Hán Thủy 汉水 1159115735هان נהר האן Ханьшуй ہان 漢江 3Lake Centerline Huang 3.0 4.0Huang هوانغ হুয়াং Ngoring Lake Huang Huang Χουάνγκ हुआंग Huang Huang Huang 黄河 황 Huang Huang Huang озеро Орин-Нур Huang Huang Huang 黄河 1159124945هوآنگ הואנג Хуанг ہوانگ 黃湖 3Lake Centerline Indus 3.0 4.0Indus Q7348 نهر السند সিন্ধু নদ Indus Indo Indus Ινδός ποταμός सिन्धु नदी Indus Indus Indo インダス川 인더스강 Indus Indus Indo Инд Indus İndus Ấn 印度河 1159122813سند אינדוס Інд دریائے سندھ 印度河 6Lake Centerline Jordan 5.0 6.0Jordan Jordan Q40059 نهر الأردن জর্দান নদী Jordan Jordán Jourdain Ιορδάνης ποταμός जॉर्डन नदी Jordán Yordan Giordano ヨルダン川 요르단강 Jordaan Jordan Jordão Иордан Jordan Şeria Jordan 约旦河 1159114351اردن נהר הירדן Йордан دریائے اردن 約旦河 6Lake Centerline Kemijoki 5.0 6.0Kemijoki Kemijoki Q214779 كيميوكي কেমিজোকি Kemijoki Kemi Kemijoki Κέμιγιοκι केमिजोकि Kemijoki Kemijoki Kemijoki ケミ川 케미강 Kemijoki Kemijoki Kemijoki Кемийоки Kemi älv Kemijoki Kemijoki 凱米河 1159115645کمیجوکی קמיוקי Кемійокі کیمیجوکی 凱米河 5Lake Centerline Klamath 4.7 5.7Klamath Klamath Q968640 كلاماث ক্লামাথ Klamath Klamath Klamath Κλάμαθ क्लामथ Klamath Klamath Klamath クラマス川 클라마스 Klamath Klamath Klamath Кламат Klamath Klamath Klamath 克拉玛斯河 1159113143رود کلمث נהר קלאמת Кламат دریائے کلیمیتھ 克拉瑪斯河 6Lake Centerline Krishna 5.0 6.0Krishna Krishna Q193499 نهر كريشنا কৃষ্ণা নদী Krishna Krishná Krishnâ Κρίσνα कृष्णा नदी Krisna Krishna Krishna クリシュナ川 크리슈나강 Krishna Kryszna Krishna Кришна Krishnafloden Krişna Krishna 奎师那河 1159116071رود کریشنا קרישנה Крішна دریائے کرشنا 奎師那河 4Lake Centerline La Grande 4.0 5.0La Grande La Grande Q31379 لا غراندي লা গ্র্যান্ডে La Grande Grande la Grande Λα Γκράντε ला ग्रैंड La Grande La Grande La Grande ラグランデ川 라 그란데 La Grande La Grande La Grande Ла-Гранд La Grande La Grande La Grande 拉格朗德河 1159111059لا گراند לה גראנדה Ла-Гранде لا گرانڈے 拉格朗德河 2Lake Centerline Mackenzie 2.1 3.1Mackenzie Mackenzie Q3411 نهر ماكينزي ম্যাকেঞ্জি নদী Mackenzie Mackenzie fleuve Mackenzie Ποταμός Μακένζι मैकेन्ज़ी नदी Mackenzie Mackenzie Mackenzie マッケンジー川 매켄지강 Mackenzie Mackenzie Mackenzie Маккензи Mackenziefloden Mackenzie Mackenzie 馬更些河 1159117649رود مکنزی מקנזי Макензі میکینزی 馬更些河 1Lake Centerline Madison 2.0 3.0Madison Madison Q947477 ماديسون মাদিয়েরা Madison Madison Madison Μάντισον मैडिसन Madison Madison Madison マディソン川 매디슨강 Madison Madison Madison Мадисон Madison Madison Madison 麦迪逊河 1159127599مادیسون מדיסון Медісон میڈیسن 麥迪遜河 6Lake Centerline Mahäna Nadï 5.0 6.0Mahäna Nadï مهانا نادي মাহানা নাদি Mahäna Nadï Mahäna Nadï Mahäna Nadï Μαχάντα Νάντι महाना नदी Mahäna Nadï Mahanadi Mahäna Nadï マハナ湖 마하나 나디 Mahanadi Mahäna Nadï Mahäna Nadï Mahäna Nadï Mahäna Nadï Mahäna Nadï 默哈讷迪河 1159115781ماهانا نادی מהאנה נאדי Махана-Наді ماہانا ندی 馬哈納河 5Lake Centerline Mississippi 4.7 5.7Mississippi Mississippi Q1497 نهر المسيسيبي মিসিসিপি নদী Mississippi Misisipi Mississippi Ποταμός Μισσισσιππής मिसिसिप्पी नदी Mississippi Mississippi Mississippi ミシシッピ川 미시시피강 Mississippi Missisipi Mississípi Миссисипи Mississippifloden Mississippi Mississippi 密西西比河 1159112609رودخانه میسیسیپی מיסיסיפי Міссісіпі دریائے مسیسپی 密西西比河 1Lake Centerline Missouri 2.0 3.0Missouri Missouri Q5419 نهر ميزوري মিসৌরি নদী Missouri Misuri Missouri Μιζούρι मिसोरी नदी Missouri Missouri Missouri ミズーリ川 미주리강 Missouri Missouri Missouri Миссури Missourifloden Missouri Missouri 密蘇里河 1159128475رودخانه میزوری מיזורי Міссурі دریائے مسوری 密蘇里河 5Lake Centerline Mouhoun 4.7Black Volta 5.7Black Volta Mouhoun Q1256528 الفولتا الأسود মৌহোউন Schwarzer Volta Volta Negro Volta Noire Μουχούν मौहौन Mouhoun Mouhoun Volta Nero 黒ヴォルタ 무운 Zwarte Volta Wolta Czarna Volta Negro Чёрная Вольта Mouhoun Siyah Volta Mouhoun 黑沃尔特河 1159113239ولتای سیاه מוהון Чорна Вольта موہون 黑沃爾特河 4Lake Centerline Murray 4.0 5.0Murray Murray Q183078 نهر موراي মারি নদী Murray Murray Murray Ποταμός Μάρρεϋ मर्रे नदी Murray Murray Murray マレー川 머리강 Murray Murray Murray Муррей Murray Murray Murray 墨累河 1159128979مورای מארי Муррей دریائے مرے 美利河 6Lake Centerline Nakanbé 5.0White Volta 6.0White Volta Nakanbé Q1259188 ناكانبي নাকানবে Weißer Volta Volta Blanco Volta Blanche Νακανμπέ नाकनबे Nakanbé Nakanbe Volta Bianco 白ヴォルタ 나칸베 Witte Volta Wolta Biała Volta Branco Белая Вольта Nakambe Beyaz Volta Nakanbé 白沃尔特河 1159115595ناکانبه נאקנבה Наканбе ناکانمبی 白沃爾特河 5Lake Centerline Naryn 4.7 5.7Naryn Naryn Q651195 نارين নারিন Naryn Naryn Naryn Νάριν नारीन नदी Narin Naryn Naryn ナルイン川 나린강 Naryn Naryn Naryn Нарын Naryn Narın Naryn 纳伦河 1159113113رود نارین נרין Нарин نارائن 納倫河 6Lake Centerline Nelson 5.0 6.0Nelson Nelson Q3292 نيلسون নেলসন নদী Nelson Nelson fleuve Nelson Ποταμός Νέλσον नेल्सन Nelson Nelson Nelson ネルソン川 넬슨강 Nelson Nelson Nelson Нельсон Nelsonfloden Nelson Nelson 納爾遜河 1159115901رود نلسون נהר נלסון Нельсон نیلسن 納爾遜河 5Lake Centerline Neva 4.7 5.7Neva Neva Q645 نهر نيفا নেভা নদী Newa Nevá Neva Νέβας नेवा नदी Néva Neva Neva ネヴァ川 네바강 Neva Newa Neva Нева Neva Neva Neva 涅瓦河 1159113003رود نوا נייבה Нева نیوا 涅瓦河 3Lake Centerline Niger 3.0 4.0Niger Niger Q3542 نهر النيجر নাইজার নদী Niger Níger Niger Νίγηρας ποταμός नाइजर नदी Niger Niger Niger ニジェール川 나이저강 Niger Niger Níger Нигер Niger Nijer Niger 尼日尔河 1159123295رودخانه نیجر ניז'ר Нігер دریائے نائجر 尼日河 1Lake Centerline Nile 2.0 3.0Nile Nile Q3392 نهر النيل নীলনদ Nil Nilo Nil Νείλος नील नदी Nílus Nil Nilo ナイル川 나일강 Nijl Nil Nilo Нил Nilen Nil Nin 尼罗河 1159121573نیل נילוס Ніл دریائے نیل 尼羅河 4Lake Centerline Ob 4.0 5.0Ob Ob Q973 أوبي ওব নদী Ob Obi Ob Ομπ ओब नदी Ob Ob Ob' オビ川 오비강 Ob Ob Ob Обь Ob Obi Obi 鄂畢河 1159111921رود اب אוב Об اوب 鄂畢河 6Lake Centerline Orange 5.0 6.0Orange Orange Q181475 نهر أورانج অরেঞ্জ নদী Oranje Orange Orange Οράγγης आरेंज नदी Oranje Orange Orange オレンジ川 오렌지강 Oranjerivier Oranje Orange Оранжевая Oranjefloden Turuncu Nehir Orange 奥兰治河 1159114127رودخانه نارنجی אורנג' Оранжева اورنج 奧蘭治河 6Lake Centerline Ord 5.0 6.0Ord Ord Q2028742 نهر الأورد ওর্দ Ord Ord Ord Ορντ ऑर्ड Ord Ord Ord オード川 오드 Ord Ord Ord Орд Ord Ord Ord 奥德河 1159115167اورد אורד Орд اورد 奧德湖 6Lake Centerline Ottawa 5.0 6.0Ottawa Ottawa Q60974 نهر أوتاوا অটোয়া Ottawa Fluss Ottawa Outaouais Οτάβα ओटावा नदी Ottawa Ottawa Ottawa オタワ川 오타와강 Ottawa Ottawa Ottawa Оттава Ottawafloden Ottawa Ottawa 渥太華河 1159113849رود اتاوا אוטווה Оттава اوٹاوا 渥太華河 6Lake Centerline Panama Canal 5.0 6.0Panama Canal Panama Canal Q7350 قناة بنما পানামা খাল Panamakanal Canal de Panamá canal de Panama Διώρυγα Παναμά पनामा नहर Panama-csatorna Terusan Panama Panama パナマ運河 파나마 운하 Panamakanaal Kanał Panamski Canal do Panamá Панамский канал Panamakanalen Panama Kanalı Kênh đào Panama 巴拿馬運河 1159114277آبراه پاناما תעלת פנמה Панамський канал نہر پاناما 巴拿馬運河 4Lake Centerline Paranaíba 4.0 5.0Paranaíba Paranaíba Q776155 نهر بارانَيبا পারানাইবা Paranaíba Paranaíba Paranaíba Παραναΐμπα परानाइबा Paranaíba Paranaíba Paranaíba パラナイバ川 파라나이바 Paranaíba Paranaiba Paranaíba Паранаиба Paranaíba Paranaíba Paranaíba 巴拉那伊巴河 1159110887پارانائیبا פארנאיבה Паранайба پارانیبا 巴拉那伊巴河 4Lake Centerline Paraná 4.0 5.0Paraná Paraná Q127892 نهر بارانا পারানা Paraná Paraná Paraná Παρανά पराना नदी Paraná Paraná Paraná パラナ川 파라나강 Paraná Parana Paraná Парана Paranáfloden Paraná Paraná 巴拉那河 1159129191رودخانه پارانا פרנה Парана دریائے پارانا 巴拉那河 2Lake Centerline Peace 2.1 3.1Peace Peace Q2220 بيس পীস Peace de la Paz Paix Πις पीस Peace Peace Peace ピース川 피스강 Peace Peace Peace Пис Peace Peace Peace 皮斯河 1159117447رود پیس נהר פיס Піс دریائے پیس 皮斯河 6Lake Centerline Pit 5.0 6.0Pit Pit Q1760800 بيت পিট Pit Pit Pit Πιτ पिट Pit Pit Pit ピット川 피트 Pit Pit Pit Пит Pit River Pit Pit 皮特河 1159115813پیت פיט Піт دریائے پٹ 皮特河 6Lake Centerline R. des Outaouais 5.0 6.0R. des Outaouais نهر أوتاوا এর. দেস আউতাওউয়াইস Ottawa Río Outaouais Rivière des Outaouais Ρ. ντε Ουαταουέ आर. डेस आउटौइस R. des Outaouais Sungai Ottawa Fiume Ottawa ウタウエ湖 데스 아우타우아이스 Ottawa Rzeka Ottawa Rio Otava водохранилище Резервуар-Дозуа Rivière des Outaouais R. des Outaouais Sông Ottawa 奥托埃斯河 1159113801رودخانه اوتاوایس דס אוטאווה Утауа آر دیس آؤٹوایس 庫陶烏艾斯湖 6Lake Centerline Rainy 5.0 6.0Rainy Rainy Q2128582 رايني রেইনি Rainy Rainy Pluie Ρέινι रेनी Rainy Rainy Rainy レイニー川 레이니 Rainy Rainy Rainy Рейни Rainy Rainy Rainy 雷尼河 1159115437رینی הנהר הגשום Рейні رینی 雷尼河 4Lake Centerline Rhein 4.0 5.0Rhine Rhein Q584 راين রাইন নদী Rhein Rin Rhin Ρήνος राइन नदी Rajna Rhein Reno ライン川 라인강 Rijn Ren Reno Рейн Rhen Ren Rhine 莱茵河 1159110393راین ריין Рейн دریائے رائن 莱茵河 6Lake Centerline Rhône 5.0 6.0Rhône رون রোন Rhône Ródano Rhône Ρον रौन Rhône Rhone Ròdano ローヌ湖 론 Rhône Rhône Ródano река Рона Rhône Rhône Rhône 罗纳河 1159115093رهون רונה Роне رہونے 隆河 4Lake Centerline Rio Grande 4.0 5.0Grande Rio Grande Q160636 ريو غراندي রিও গ্রান্দে Grande Bravo Grande Ρίο Γκράντε रियो ग्रांडे Grande Grande Grande リオ・グランデ川 리오그란데강 Grande Grande Grande Рио-Гранде Grande Grande Grande 格兰德河 1159111297رودخانه ریوگرانده ריו גראנדה Ріо-Ґранде ریو گرانڈے 格蘭德河 6Lake Centerline Rupert 5.0 6.0Rupert Rupert Q427437 روبرت রুপার্ট Rupert Rupert Rupert Ρούπερτ रूपर्ट Rupert Rupert Rupert ルパート湖 루퍼트 Rupert Rupert Rupert Руперт Rupert Rupert Rupert 鲁珀特河 1159114827روپرت רופרט Руперт روپرٹ 魯伯特湖 6Lake Centerline Río Grande de Santiago 5.0 6.0Grande de Santiago Río Grande de Santiago Q2302661 ريو غراندي دي سانتياغو রিও গ্রান্দে দে সান্তিয়াগো Grande de Santiago Grande de Santiago Santiago Ρίο Γκράντε ντε Σαντιάγκο रियो ग्रांडे डी सैंटियागो Río Grande de Santiago Sungai Grande de Santiago Río Grande de Santiago グランデ・デ・サンティアゴ川 리오 그란데 데 산티아고 Grande de Santiago Grande de Santiago Grande de Santiago Рио-Гранде-де-Сантьяго Río Grande de Santiago Río Grande de Santiago Sông Santiago 大聖地亞哥河 1159114479ریو گرانده د سانتیاگو ריו גרנדה דה סנטיאגו Ріо-Гранде-де-Сантьяго ریو گرانڈے ڈی سانتیاگو 大聖地亞哥河 5Lake Centerline Sacramento 4.7 5.7Sacramento Sacramento Q335575 ساكرمينتو স্যাক্রামেন্টো Sacramento Sacramento Sacramento Σακραμέντο सैक्रामेंटो Sacramento Sacramento Sacramento サクラメント川 새크라멘토강 Sacramento Sacramento Sacramento Сакраменто Sacramento Sacramento Sacramento 萨克拉门托河 1159112977رودخانه ساکرامنتو סקרמנטו Сакраменто دریائے سکرامنٹو 沙加缅度河 6Lake Centerline San Joaquin 5.0 6.0San Joaquin San Joaquin Q751347 سان هواكوين সান জোয়াকুইন San Joaquin San Joaquín San Joaquin Σαν Χοακίν सैन जोकिन San Joaquin San Joaquin San Joaquin サン・ワーキン川 샌와킨강 San Joaquin San Joaquin San Joaquin Сан-Хоакин San Joaquin River San Joaquin San Joaquin 圣华金河 1159114865رودخانه سن ژاکویین סן חואקין Сан-Хоакін دریائے سان جوکن 圣华金河 5Lake Centerline San Juan 4.7 5.7San Juan San Juan Q1161204 نهر سان خوان সান জুয়ান San Juan San Juan San Juan Σαν Χουάν सैन जुआन San Juan San Juan San Juan サン・フアン川 산 후안 San Juan San Juan San Juan Сан-Хуан San Juan San Juan San Juan 圣胡安河 1159112699سان جوئان סן חואן Сан-Хуан دریائے سان خوآن 聖胡安河 4Lake Centerline Saskatchewan 4.0 5.0Saskatchewan Saskatchewan Q3047 ساسكاتشوان সাসকাচেয়ান Saskatchewan Saskatchewan Saskatchewan Σασκατσεγουάν सस्केचेवान Saskatchewan Saskatchewan Saskatchewan サスカチュワン川 서스캐처원강 Saskatchewan Saskatchewan Saskatchewan Саскачеван Saskatchewan Saskatchewan Saskatchewan 萨斯喀彻温河 1159111543ساسکاچوان נהר ססקצ'ואן Саскачеван ساسکاچیوان 萨斯喀彻温河 6Lake Centerline Sassandra 5.0 6.0Sassandra Sassandra Q1535828 ساساندرا সাসান্দ্রা Sassandra Sassandra Sassandra Σασσάνδρα सासान्द्रा Sassandra Sassandra Sassandra ササンドラ川 사산드라 Sassandra Sassandra Sassandra Сасандра Sassandra Sassandra Sassandra 萨桑德拉河 1159115853ساساندرا ססאנדרה Сассандра ساسینڈرا 薩桑德拉河 6Lake Centerline Savannah 5.0 6.0Savannah Savannah Q370750 نهر سافانا সাভানা Savannah Savannah Savannah Σαβάνα सवाना Savannah Savannah Savannah サバンナ川 서배너강 Savannah Savannah Savannah Саванна Savannah River Savannah Savannah 沙瓦纳河 1159115051رود ساواناه סוואנה Саванна دریائے ساواناہ 薩凡納河 6Lake Centerline Semliki 5.0 6.0Semliki Semliki Q205428 نهر سمليكي সেমলিকি Semliki Semliki Semliki Σεμλίκι सेमलिकी Semliki Semliki Semliki セムリキ川 셈리키 Semliki Semliki Semliki Семлики Semliki Semliki Semliki 塞姆利基河 1159114169رود سملیکی נהר סמליקי Семлікі سیملیکی 塞姆利基河 3Lake Centerline Shire 3.0 4.0Shire Shire Q2279579 نهر شيري শায়ার Shire Shire Shire Σάιρ शायर Shire Shire Shire シーレ川 샤이어 Shire Shire Chire Шире Shire Shire Shire 希雷河 1159126365رود شایر שייר Шире شائر 希雷河 4Lake Centerline Shishhid Gol 4.0 5.0Shishged Q15277375 شيشيد جول শিশিদ গোল Shishhid Gol Shishhid Gol Shishged Σισχίντ Γκολ शीशिद गोल Shishhid Gol Shishhid Gol Shishhid Gol シシド・ゴル湖 쉬쉬드 골 Shishhid Gol Shishhid Gol Shishhid Gol озеро Шишгид-Гол Shishhid Gol Shishhid Gol Shishhid Gol 希希黑德河 1159110715شیشهید گل שישיד גול Шишшид Гол شیشید گول 希希黑德河 4Lake Centerline Snake 4.0 5.0Snake Snake Q272074 نهر الثعبان স্নেক Snake Snake Snake Σνέικ स्नेक Snake Snake Snake スネーク川 스네이크강 Snake Snake Snake Снейк Snake Snake Snake 斯内克河 1159110075رود اسنیک סנייק Снейк دریائے سنیک 斯內克河 6Lake Centerline South Saskatchewan 5.0 6.0South Saskatchewan South Saskatchewan Q2242 نهر ساسكاتشوان الجنوبي দক্ষিণ সাসকাচোয়ান South Saskatchewan Saskatchewan Sur Saskatchewan Sud Νότιο Σασκατσουάν दक्षिण सस्केचेवान नदी Dél-Saskatchewan South Saskatchewan South Saskatchewan サウスサスカチュワン川 사우스서스캐처원강 South Saskatchewan Saskatchewan Południowy South Saskatchewan Саут-Саскачеван South Saskatchewan Güney Saskatchewan South Saskatchewan 南萨斯喀彻温河 1159115555رود ساسکاچوان جنوبی נהר ססקאצ'ואן הצפוני Південний Саскачеван ساؤتھ ساسکاچیوان 南萨斯喀彻温河 6Lake Centerline Suez Canal 5.0 6.0Suez Canal Suez Canal Q899 قناة السويس সুয়েজ খাল Suezkanal canal de Suez canal de Suez Διώρυγα Σουέζ स्वेज़ नहर Szuezi-csatorna Terusan Suez Suez スエズ運河 수에즈 운하 Suezkanaal Kanał Sueski Canal de Suez Суэцкий канал Suezkanalen Süveyş Kanalı Kênh đào Suez 苏伊士运河 1159113913کانال سوئز תעלת סואץ Суецький канал نہر سوئز 蘇伊士運河 4Lake Centerline Sukhona 4.0 5.0Sukhona Sukhona Q82812 نهر سوخونا সুখোনা Suchona Sújona Soukhona Σουχόνα सुखोना Szuhona Sukhona Suchona スホナ川 수코나 Soechona Suchona Sukhona Сухона Suchona Suhona Sukhona 蘇霍納河 1159110557سوخونا סוקהונה Сухона سوکھونا 蘇霍納河 6Lake Centerline Sutlej 5.0 6.0Sutlej Sutlej Q171675 نهر ستلج শতদ্রু Satluj Sutlej Sutlej Ζάραδρος सतलुज नदी Szatledzs Sutlej Sutlej サトレジ川 수틀레지강 Sutlej Satledź Sutlej Сатледж Sutlej Satlec Sutlej 象泉河 1159115213رود ستلج סוטלג' Сатледж دریائے ستلج 象泉河 5Lake Centerline Svir 4.7 5.7Svir Svir Q213067 سفير এসভির Swir Svir Svir Σβιρ स्वीर Szvir Svir Svir' スヴィリ川 스비리강 Svir Świr Svir Свирь Svir Svir Svir 斯维里河 1159113209رودخانه سیویر סביר Свір سوئر 斯維里河 5Lake Centerline Syr Darya 4.7 5.7Syr Dar Syr Darya Q483159 نهر سيحون সির দরিয়া Syrdarja Sir Daria Syr-Daria Συρ Ντάρια सिर दरिया Szir-darja Syr Darya Syr Darya シルダリヤ川 시르다리야강 Syr Darja Syr-daria Sir Dária Сырдарья Syr-Darja Seyhun Syr Darya 锡尔河 1159113079سیردریا סיר דריה Сирдар'я دریائے سیحوں 錫爾河 4Lake Centerline São Francisco 4.0 5.0São Francisco São Francisco Q142148 نهر ساو فرانسيسكو সাঁও ফ্রাঁসিশকু নদী São Francisco São Francisco São Francisco Σάο Φραγκίσκο साओ फ़्रांसिस्को São Francisco São Francisco São Francisco サン・フランシスコ川 상프란시스쿠강 São Francisco São Francisco São Francisco Сан-Франсиску São Francisco São Francisco São Francisco 圣弗朗西斯科河 1159110233رود سائو فرانسیسکو סאו פרנסיסקו Сан-Франсіску ساؤ فرانسسکو 聖法蘭西斯科河 5Lake Centerline Tajo 4.7 5.7Tagus Tajo Q14294 نهر تاجة তাজো Tajo Tajo Tage Τάγος तैजो Tajo Tagus Tago タホ川 타구스강 Taag Tag Tejo Тахо Tajo Tejo Tagus 塔霍河 1159112911تاقوس טחו Тахо تاجو 塔霍河 5Lake Centerline Tennessee 4.7 5.7Tennessee Tennessee Q193737 نهر تينيسي টেনেসি নদী Tennessee Tennessee Tennessee Ποταμός Τενεσί टेनेसी Tennessee Tennessee Tennessee テネシー川 테네시강 Tennessee Tennessee Tennessee Теннесси Tennesseefloden Tennessee Tennessee 田纳西河 1159113035رودخانه تنسی טנסי Теннессі دریائے ٹینیسی 田納西河 3Lake Centerline Teslin 3.0 4.0Teslin Teslin Q284495 تسلين টেসলিন Teslin Telsin Teslin Τέσλιν टेस्लिन Teslin Teslin Teslin テスリン 테슬린 Teslin Teslin Teslin Теслин Teslin Teslin Teslin 特斯林河 1159123737تسلین טסלין Теслін تیسلن 特斯林河 5Lake Centerline Thelon 4.7 5.7Thelon Thelon Q2416760 ثيلون থেলন Thelon Thelon Thelon Θέλον थेलोन Thelon Thelon Thelon セロン川 테론 Thelon Thelon Thelon Телон Thelon Thelon Thelon 塞隆河 1159112767تلون תלון Телон تھیلون 塞隆湖 4Lake Centerline Tocantins 4.0 5.0Tocantins Tocantins Q156054 نهر توكانتين টোক্যান্টিনস Tocantins Tocantins Tocantins Τοκαντίνες टोकैन्तिंस Tocantins Tocantins Tocantins トカンチンス川 토칸칭스강 Tocantins Tocantins Tocantins Токантинс Tocantins Tocantins Tocantins 托坎廷斯河 1159111951توکانتینس טוקנטינס Токантінс ٹوکانٹینز 托坎廷斯河 6Lake Centerline Tugaloo 5.0 6.0Tugaloo Tugaloo Q2459279 توجالو তুগালু Tugaloo Tugaloo Tugaloo Τούγκαλου तुगलू Tugaloo Tugaloo Tugaloo トガルー湖 투갈루 Tugaloo Tugaloo Tugaloo озеро Тагалу Tugaloo River Tugaloo Tugaloo 图加卢河 1159114997توگالو טוגאלו Тугалу ٹوگالو 圖加盧湖 4Lake Centerline Ural 4.0 5.0Ural Ural Q80240 نهر الأورال ইউরাল নদী Ural Ural Oural Ποταμός Ουράλης यूराल नदी Urál Ural Ural ウラル川 우랄강 Oeral Ural Ural Урал Uralfloden Ural Ural 乌拉尔河 1159111455رود اورال אורל Урал دریائے اورال 烏拉爾河 4Lake Centerline Vaal 4.0 5.0Vaal Vaal Q209530 فال ভ্যাল Vaal Vaal Vaal Βάαλ वाल नदी Vaal Vaal Vaal バール川 바알 Vaalrivier Vaal Vaal Вааль Vaal Vaal Vaal 瓦尔河 1159109769رودخانه واله ואל Вааль وال 瓦爾河 4Lake Centerline Verkhniy Yenisey 4.0 5.0Verkhniy Yenisey فيركني يانيساي ভার্কনি ইয়েনিসেই Verkhniy Yenisey Verkhniy Yenisey Ienisseï supérieur Βερκνίι Γιενισέι वेर्खनी येनिसे Verkhniy Yenisey Verkhniy Yenisey Enisej ヴェルフニ・エニセイ湖 베르크니 예니세이 Jenisej Verkhniy Yenisey Ienissei Superior Верхний Енисей Verchnij Jenisej Verkhniy Yenisey Verkhniy Yenisey 上叶尼塞河 1159112425ورکهنی ینسی ורחני יניסיי Верхній Єнісей ورکھنائی یینیسے 上葉尼塞湖 1Lake Centerline Victoria Nile 2.0 3.0White Nile Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159123321نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 6Lake Centerline Vilyuy 5.0 6.0Vilyuy Vilyuy Q26433 نهر فيليوي ভিলিউ Wiljui Viliui Viliouï Βιλιούι विलुयू Viljuj Vilyuy Viljuj ヴィリュイ川 빌류이강 Viljoej Wiluj Vilyuy Вилюй Viljuj Vilyuy Vilyuy 維柳伊河 1159115677رود ویلیوی וילוי Вілюй ولیوئے 維柳伊河 5Lake Centerline Vistula 4.7 5.7Vistula Vistula Q548 فيستولا ভিস্তুলা নদী Weichsel Vístula Vistule Βιστούλας विस्चुला नदी Visztula Vistula Vistola ヴィスワ川 비스와강 Wisła Wisła Vístula Висла Wisła Vistül Wisla 维斯瓦河 1159112937ویستولا ויסלה Вісла وسٹولا 维斯瓦河 3Lake Centerline Volga 3.0 4.0Volga Volga Q626 فولغا ভোলগা নদী Wolga Volga Volga Βόλγας वोल्गा नदी Volga Volga Volga ヴォルガ川 볼가강 Wolga Wołga Volga Волга Volga Volga Volga 伏尔加河 1159125617رودخانه ولگا וולגה Волга دریائے وولگا 伏尔加河 5Lake Centerline Volta 4.7 5.7Volta Volta Q192415 نهر فولتا ভোল্টা নদী Volta Volta Volta Βόλτα वोल्टा नदी Volta Volta Volta ヴォルタ川 볼타강 Volta Wolta Volta Вольта Volta Volta Volta 沃尔特河 1159113273رود ولتا וולטה Вольта وولٹا 沃爾特河 6Lake Centerline Vorma 5.0 6.0Vorma Vorma Q576337 فورما ভোরমা Vorma Vorma Vorma Βόρμα वोर्मा Vorma Vorma Vorma ヴォルマ湖 보르마 Vorma Vorma Vorma Ворма Vorma Vorma Vorma 沃马河 1159115943وورما וורמה Ворма وورما 沃馬湖 6Lake Centerline Vuoksi 5.0 6.0Vuoksa Vuoksi Q819448 فووكسي ভুক্সি Vuoksi Vuoksi Vuoksi Βουόκσι वुओक्सी Vuoksi Vuoksi Vuoksi ヴオクサ川 복시 Vuoksi Vuoksi Vuoksi Вуокса Vuoksen Vuoksi Vuoksi 武克希河 1159115129رودخانه ویوکسی וווקסי Вуоксі ووکسی 武克希河 6Lake Centerline Waikato 5.0 6.0Waikato Waikato Q1048219 نهر وايكاتو ওয়াইকাটো Waikato Waikato Waikato Ποταμός Γουαϊκάτο वायकाटो नदी Waikato Waikato Waikato ワイカト川 와이카토강 Waikato Waikato Waikato Уаикато Waikatofloden Waikato Waikato 怀卡托河 1159129609رود وایکاتو וואיקאטו Ваїкато وائیکاٹو 怀卡托河 6Lake Centerline Winnipeg 5.0 6.0Winnipeg Winnipeg Q1400022 وينيبيغ উইনিপেগ Winnipeg Winnipeg Winnipeg Γουίνιπεγκ विनीपेग Winnipeg Winnipeg Winnipeg ウィニペグ川 위니펙 Winnipeg Winnipeg Winnipeg Виннипег Winnipeg Winnipeg Winnipeg 溫尼伯河 1159115475وینیپگ נהר ויניפג Вінніпег ونیپیگ 溫尼伯河 6Lake Centerline Yuan 5.0 6.0Yuan Yuan Q1063190 يوان ইউয়ান Yuan Yuan Yuan Ποταμός Γιουάν युआन Yuan Yuan Yuan 沅江 위안 강 Yuan Yuan Yuan Yuanfloden Yuan Nguyên 沅水 1159114803رود یوان יואן Юань یوان 沅水 3Lake Centerline Zambezi 3.0 4.0Zambezi Zambezi Q43106 نهر زمبيزي জাম্বেজি নদী Sambesi Zambeze Zambèze Ζαμβέζης जेम्बेजी नदी Zambézi Zambezi Zambesi ザンベジ川 잠베지강 Zambezi Zambezi Zambeze Замбези Zambezi Zambezi Zambezi 赞比西河 1159126201زامبزی זמבזי Замбезі زیمبیزی 赞比西河 6Lake Centerline _untitled_72 5.0 6.0 1159115397 5Lake Centerline _untitled_78 4.7 5.7 1159112807 3River Abay 3.0 4.0Blue Nile Abay Q882739 النيل الأزرق নীলাভ নীল নদ Blauer Nil Nilo Azul Nil Bleu Γαλάζιος Νείλος नीली नील Kék-Nílus Nil Biru Nilo Azzurro 青ナイル川 청나일강 Blauwe Nijl Nil Błękitny Nilo Azul Голубой Нил Blå Nilen Mavi Nil Nin Xanh 青尼罗河 1159128181نیل آبی הנילוס הכחול Блакитний Ніл نیل ازرق 青尼罗河 3River Abay 3.0Blue Nile 4.0Blue Nile Abay Q882739 النيل الأزرق নীলাভ নীল নদ Blauer Nil Nilo Azul Nil Bleu Γαλάζιος Νείλος नीली नील Kék-Nílus Nil Biru Nilo Azzurro 青ナイル川 청나일강 Blauwe Nijl Nil Błękitny Nilo Azul Голубой Нил Blå Nilen Mavi Nil Nin Xanh 青尼罗河 1159128181نیل آبی הנילוס הכחול Блакитний Ніл نیل ازرق 青尼罗河 3River Al Furat 3.0 4.0Euphrates Al Furat Q34589 الفرات ফোরাত Euphrat Éufrates Euphrate Ευφράτης फ़रात नदी Eufrátesz Efrat Eufrate ユーフラテス川 유프라테스강 Eufraat Eufrat Eufrates Евфрат Eufrat Fırat Euphrates 幼发拉底河 1159125949فرات פרת Євфрат دریائے فرات 幼发拉底河 6River Alabama 5.0 6.0Alabama Alabama Q558643 ألاباما আলাবামা Alabama Alabama Alabama Αλαμπάμα अल्बामा Alabama Alabama Alabama アラバマ川 앨라배마강 Alabama Alabama Alabama Алабама Alabama Alabama Alabama 阿拉巴馬河 1159114979آلاباما נהר אלבמה Алабама البامہ 阿拉巴馬河 6River Albany 5.0 6.0Albany Albany Q1241991 ألبانيا আলবেনি Albany Albany Albany Ώλμπανι अल्बेनी Albany Albany Albany オールバニー川 알바니 Albany Albany Albany Олбани Albany Albany Sông Albany 奥尔巴尼河 1159114727رود آلبانی אלבני Олбані دریائے البانی 奧巴尼 1River Albert Nile 2.0 3.0White Nile Albert Nile Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159129211نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 4River Aldan 4.0 5.0Aldan Aldan Q191832 نهر ألدان আল্ডান Aldan Aldán Aldan Αλντάν एल्डन Aldan Aldan Aldan アルダン川 알단강 Aldan Ałdan Aldan Алдан Aldan Aldan Aldan 阿尔丹河 1159109925رود آلدان אלדאן Алдан الدان 阿爾丹河 3River Allegheny 3.0 4.0Allegheny Allegheny Q686021 أليني আল্লেঘেনি Allegheny Allegheny Allegheny Αλεγκέινι एलेघेनी Allegheny Allegheny Allegheny アレゲニー川 앨러게니강 Allegheny Allegheny Allegheny Аллегейни Alleghenyfloden Allegheny Allegheny 阿勒格尼河 1159127733رود الیگنی אלגיני Аллегейні دریائے الیگھینی 阿利根尼河 1River Amazonas 2.0 3.0Amazon Amazonas Q3783 نهر الأمازون আমাজন নদী Amazonas Amazonas Amazone Αμαζόνιος अमेज़न नदी Amazonas Amazon delle Amazzoni アマゾン川 아마존강 Amazone Amazonka Amazonas Амазонка Amazonfloden Amazon Amazon 亚马逊河 1159116655آمازون אמזונאס Амазонка دریائے ایمیزون 亚马逊河 5River Amu Darya 4.7 5.7Amu Darya Amu Darya Q8493 جيحون আমু দরিয়া Amudarja Amu Daria Amou-Daria Αμού Ντάρια आमू दरिया Amu-darja Amu Darya Amu Darya アムダリヤ川 아무다리야강 Amu Darja Amu-daria Amu Dária Амударья Amu-Darja Ceyhun Amu Darya 阿姆河 1159113673آمودریا אמו דריה Амудар'я دریائے جیحوں 阿姆河 3River Amur 3.0 4.0Amur Amur Q6862 نهر آمور আমুর নদী Amur Amur Amour Αμούρ अमूर नदी Amur Amur Amur アムール川 아무르강 Amoer Amur Amur Амур Amur Amur Amur 黑龙江 1159126543آمور אמור Амур دریائے آمور 黑龍江 6River Anadyr’ 5.0 6.0Anadyr Anadyr’ Q26390 نهر أنادير আনাদিয়ার Anadyr Anádir Anadyr Αναντίρ अनादिर नदी Anadir Anadyr Anadyr' アナディリ川 아나디르 Anadyr Anadyr Anadyr Анадырь Anadyrfloden Anadyr Anadyr 阿纳德尔河 1159116983رود آنادیر אנאדיר Анадир آنادیر 阿纳德尔河 2River Angara 2.1 3.1Angara Angara Q162737 نهر أنغارا আঙ্গারা নদী Angara Angará Angara Αγγαράς अंगारा नदी Angara Angara Angara アンガラ川 안가라강 Angara Angara Angara Ангара Angara Angara Angara 安加拉河 1159117269رود آنگارا אנגרה Ангара انگارا 安加拉河 4River Araguaia 4.0 5.0Araguaia Araguaia Q171847 نهر اراغوايا আরাগুয়াইয়া নদী Araguaia Araguaia Araguaia Αραγκουάια अरागुआइया Araguaia Araguaia Araguaia アラグアイア川 아라과이아강 Araguaia Araguaia Araguaia Арагуая Araguaia Araguaia Araguaia 阿拉瓜亚河 1159109637رود ارگوایا ארגואייה Арагуая آراگایا 阿拉瓜亞河 3River Argun’ 3.0Ergun 4.0Argun Argun’ Q26439 نهر أرغون আরগুন' Argun Argún Argoun Αργκούν' अर्गुन नदी Arguny Argun Argun' アルグン川 아르군강 Argoen Argun Argun Аргунь Argun Argun Argun 额尔古纳河 1159128109رود آرگون נהר ארגון Аргунь آرگن' 额尔古纳河 4River Arkansas 4.0 5.0Arkansas Arkansas Q8319 نهر أركنساس আরকানস’ নদী Arkansas Arkansas Arkansas Άρκανσο अरकंसास नदी Arkansas Arkansas Arkansas アーカンザス川 아칸소강 Arkansas Arkansas Arkansas Арканзас Arkansas Arkansas Arkansas 阿肯色河 1159112219رود آرکانزاس ארקנסו Арканзас دریائے آرکنساس 阿肯色河 6River Atbara 5.0 6.0Atbarah Atbara Q753897 نهر عطبرة আতাবারা Atbara Atbara Atbara Ατμπάρα अतबरा Atbara Atbara Atbara アトバラ川 아트바라 Atbarah Atbara Atbara Атбара Atbara Atbara Sông Atbara 阿特巴拉河 1159115347آتبارا עטברה Атбара دریائے عطبرہ 阿特巴拉河 5River Athabasca 4.7 5.7Athabasca Athabasca Q2216 نهر أتاباسكا আথাবাস্কা নদী Athabasca Athabasca Athabasca Ατάμπασκα अथाबास्का Athabasca Athabasca Athabasca アサバスカ川 아사바스카 Athabasca Athabaska Athabasca Атабаска Athabascafloden Athabasca Sông Athabasca 阿萨巴斯卡河 1159113197رود اتبسکا אתבסקה Атабаска ایتھاباسکا 阿萨巴斯卡河 2River Ayeyarwady 3.0 4.0Irrawaddy Ayeyarwady Q26076 نهر إيراوادي ইরাবতী নদী Irrawaddy Irawadi Irrawaddy Ιραουάντι इरावती नदी Iravádi Irrawaddy Irrawaddy エーヤワディー川 이라와디강 Irrawaddy Irawadi Irauádi Иравади Irrawaddy İravadi Ayeyarwaddy 伊洛瓦底江 1159112315رود ایراوادی נהר איראוואדי Іраваді ایراوادی دریا 伊洛瓦底江 6River Back 5.0 6.0Back Back Q798339 باك ব্যাক Back Back Back Μπακ बैक Back Back Back バック川 백 Back Back Back Бак Back Back Sông Back 巴克河 1159115531بک באקוי Бек بیک 後退 4River Bafing 4.0 5.0Bafing Bafing Q180558 بافينج বাফিং Bafing Bafing Bafing Μπάφινγκ बाफिंग Bafing Bafing Bafing バフィン川 베이핑 Bafing Bafing Bafing Бафинг Bafing Bafing Sông Bafing 巴芬河 1159112029بفینگ באפינג Бафінг بیفنگ 巴芬河 6River Bahr el Zeraf 5.0 6.0Bahr el Zeraf Bahr el Zeraf Q1112393 بحر الزراف বার এল জেরাফ Bahr el Zeraf Bahr el Zeraf Bahr el-Zeraf Μπαχρ ελ Ζεράφ बहर अल ज़ेरफ़ Bahr el Zeraf Bahr el Zeraf Bahr el Zeraf バール・エル・ゼラフ川 바르 엘 제라프 Bahr el Zeraf Bahr el Zeraf Bahr el Zeraf Бахр-эль-Зераф Bahr el Zeraf Zürafa Sông Zeraf 宰拉夫河 1159117915بحرالزراف בהר אל זראף Бахр-ель-Зераф بحر ال زیرف 宰拉夫河 1River Bahr el Jebel 2.0Mountain Nile 3.0White Nile Bahr el Jebel Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159113063نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 1River Bahr el Jebel 2.0White Nile 3.0White Nile Bahr el Jebel Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159113063نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 6River Bamingui 5.0 6.0Chari Bamingui Q135477 نهر شاري বামিংগুই Schari Chari Chari Ποταμός Τσάρι चारी नदी Chari Chari Chari シャリ川 샤리강 Chari Szari Chari Шари Chari Chari Chari 沙里河 1159114263رود شاری צ'ארי Шарі بامنگی 沙里河 6River Barito 5.0 6.0Barito Barito Q979518 نهر باريتو বারিতো Barito Barito Barito Μπαρίτο बरितो नदी Barito Barito Barito バリト川 바리토 Barito Barito Barito Барито Barito Barito Sông Barito 巴里托河 1159114011باریتو באריטו Баріто باریٹو 巴里托河 3River Barwon 3.0 4.0Barwon Barwon Q809666 بارون বারোন Barwon Barwon Barwon Μπάργουον बारवॉन Barwon Barwon Barwon バーロン川 바르원 Barwon Barwon Barwon Баруон Barwon Barwon Sông Barwon 巴旺河 1159127961باروون בארוון Барвон بارون 巴旺河 4River Benue 4.0 5.0Benue Benue Q204806 نهر بنوي বেনুই Benue Benue Bénoué Μπενί बेनिउ Benue Benue Benue ベヌエ川 베누에강 Benue Benue Benue Бенуэ Benue Benue Benue 贝努埃河 1159112301بنوئه נהר בנו Бенуе بینیو 貝努埃河 6River Biya 5.0 6.0Biya Biya Q859934 بيا বিয়া নদী Bija Biya Biia Μπίγια बिया नदी Bija Biya Bija ビヤ川 비야강 Bieja Bija Biya Бия Bija Biy Sông Biya 比亞河 1159115375رود بیا ביה Бія بیا 比亞河 2River Borcea 2.1 3.1Borcea بورسيا বোরসেয়া Borcea Borcea Borcea Μπορκέα बोर्सिया Borcea Borcea Borcea ボルチャ川 보르시아 Borcea Borcea Borcea Борсеа Borcea Borcea Sông Borcea 博尔恰河 1159122121بورسی בורצ'ה Борча بورسیا 博爾恰河 4River Braco Menor 4.0 5.0Javaés Q639478 نهر جافاس ব্র্যাকো মেনর Javaés Braco Menor Braço Menor do Araguaia Μπράκο Μενόρ ब्राको मेनोर Braco Menor Braco Menor Braco Menor ブラソ・メノール川 브라코 메노르 Braço Menor Braco Menor Javaés Брасу-Менор Javaés Braco Menor Sông Braco Menor 布拉科梅诺河 1159112543بارکو منور בראקו מֶנור Брако-Менор بریکو مینور 布拉科梅諾河 2River Brahmaputra 2.1 3.1Brahmaputra Brahmaputra Q45403 نهر براهمابوترا ব্রহ্মপুত্র নদ Brahmaputra Brahmaputra Brahmapoutre Βραχμαπούτρας ब्रह्मपुत्र नदी Brahmaputra Brahmaputra Brahmaputra ブラマプトラ川 브라마푸트라강 Brahmaputra Brahmaputra Bramaputra Брахмапутра Brahmaputra Brahmaputra Brahmaputra 布拉马普特拉河 1159121927رود براهماپوترا בראהמאפוטרה Брахмапутра دریائے برہم پتر 布拉马普特拉河 6River Branco 5.0 6.0Branco Branco Q1165761 برانكو ব্র্যাঙ্কো Branco Branco Branco Μπράνκο ब्रैंको Branco Branco Branco ブランコ川 브랑코 Branco Branco Branco Риу-Бранку Branco Branco Branco 布朗库河 1159116319برانکو ריו ברנקו Ріу-Бранку برانکو 布朗庫河 2River Bratul Chillia 2.1 3.1Chilia branch Bratul Chillia Q1344617 نهر تشيليا ব্র্যাতুল চিল্লিয়া Kilijaarm Bratul Chillia Bras de Chilia Μπρατούλ Τσίλια ब्रातुल चिलिया Bratul Chillia Bratul Chillia Braccio di Chilia チリア支流 브라툴 칠리아 Chilia-arm Kilia Braço de Chilia Килийское гирло Bratul Chillia Kili kolu Sông Chillia 基利亚分流 1159121381براتول چیلیا תעלת קיליה Кілійське гирло براٹل چیلیا 基利亞分流 2River Bratul Sfântu Gheorghe 2.1 3.1Sfântu Gheorghe branch Bratul Sfântu Gheorghe Q1668781 فرع سفانتو جورج ব্র্যাতুল স্ফান্তু ঘেওর্ঘে St. Georg Bratul Sfântu Gheorghe Bras de Saint Georges Μπρατούλ Σφάντου Γκεόργκε ब्रातुल सफ़ंतु घोरघे Bratul Sfântu Gheorghe Bratul Sfantu Gheorghe Braccio di Sfântu Gheor スフントゥ・ゲオルゲ支流 브라툴 스판투 게오르게 Saint George Branch Dopływ Świętego Grzegorza Braço Sfântu Gheorghe Георгиевское гирло Bratul Sfântu Gheorghe Sfântu Gheorghe Kolu Sông Sfântu Gheorghe 聖格奧爾基分支 1159121559براتول سفانتو قورقه תעלת גאורגה הקדוש Георгіївське гирло براٹل سفانٹو غیورغے 聖格奧爾基分支 2River Bratul Sulina 2.1 3.1Sulina branch Bratul Sulina Q1369180 فرع سولينا ব্র্যাতুল সুলিনা Sulinaarm Bratul Sulina Bras de Sulina Μπρατούλ Σουλίνα ब्रातुल सुलीना Bratul Sulina Bratul Sulina Braccio di Sulina スリナ支流 브라툴 술리나 Sulina-arm Brațul Sulina Braço Sulina Сулинское гирло Bratul Sulina Sulina Kolu Sông Sulina 蘇利納分支 1159121753براتول سولینا תעלת סולינה Сулинське гирло براٹل سولینا 蘇利納分支 6River Brazos 5.0 6.0Brazos Brazos Q903306 برازوس ব্রাজোস Brazos Brazos Brazos Μπράζος ब्राज़ोस Brazos Brazos Brazos ブラゾス川 브래저스강 Brazos Brazos Brazos Бразос Brazos Brazos Brazos 布拉索斯河 1159117559رود برازوس בראזוס Бразос بریزوس 布拉索斯河 6River Busira 5.0 6.0Tshuapa Busira Q2635327 بصيرا বুসিরা Tshuapa Busira Tshwapa Μπουσίρα बुसीरा Busira Busira Tshuapa ツアパ川 부시라 Tshuapa Tshuapa Busira Чуапа Tshuapa Busira Tshuapa 楚阿帕河 1159117951بوسیرا בוסירה Бусіра بوسیرا 楚阿帕河 1River Bykovskaya Protoka 2.0 3.0Bykovskaya Protoka بيكوفسكايا بروتوكا বাইকোভস্কায়া প্রোটোকা Bykovskaya Protoka Bykovskaya Protoka Léna Μπουκόβσκαγια Πρότοκα ब्यकोवस्काया प्रोटोका Bikovszkaja-csatorna Bykovskaya Protoka Bykovskaya Protoka ビコフスカヤ・プロトカ川 비콥스카야 프로토카 Bykovskaya Protoka Odnoga Bykovskaya Bykovskaya Protoka Быковская протока Bykovskaja Protoka Bykovskaya Protoka Sông Bykovskaya Protok 贝科夫河 1159114071بیکووسکایا پروتوکا ביקובסקאיה פרוטוקה Биковська протока بائکووسکایا پروٹوکا 比科夫斯卡亞·普托卡 4River Bénoué 4.0 5.0Benue Bénoué Q204806 نهر بنوي বেনোউই Benue Benue Bénoué Μπενούε बेनौउ Benue Bénoué Benue ベヌエ川 베누에강 Benue Benue Benue Бенуэ Benue Benue Benue 贝努埃河 1159112033بنوئه נהר בנו Бенуе بینوئی 貝努埃河 5River Bío-Bío 4.7 5.7Bío Bío Bío-Bío Q93360 نهر بيو بيو বিও-বিও Bío Bío Biobío Biobío Μπίο-Μπίο बिओबिओ नदी Bío-Bío Biobío Bío Bío ビオビオ川 비오비오 Biobío Biobío Biobío Био-Био Bio-Bío Bío-Bío Biobío 比奥比奥河 1159113593رود بیو بیو ביוביו Біобіо بائو بائو 比奥比奥河 5River Caquetá 4.7 5.7Japurá Caquetá Q171840 نهر جابورا কাকুয়েতা Japurá Caquetá Caquetá Κακετά जापरा नदी Caquetá Caqueta Caquetá ジャプラー川 자푸라강 Japurá Japurá Japurá Жапура Japura Caquetá Japurá 雅普拉河 1159113415رود جاپورا ז'פורה Жапура کیقوئیٹہ 雅普拉河 1River Chang Jiang 2.0Yangtze 3.0Yangtze Chang Jiang Q5413 يانغتسي ছাং চিয়াং নদী Jangtsekiang Yangtsé Yangzi Γιανγκτσέ यांग्त्सीक्यांग Jangce Panjang Fiume Azzurro 長江 창 강 Jangtsekiang Jangcy Yangtzé Янцзы Yangtze Yangtze Trường Giang 长江 1159113509رود یانگتسه יאנגצה Янцзи دریائے یانگزے 長江 6River Chari 5.0 6.0Chari Chari Q135477 نهر شاري চারি Schari Chari Chari Ποταμός Τσάρι चारी नदी Chari Chari Chari シャリ川 샤리강 Chari Szari Chari Шари Chari Chari Chari 沙里河 1159114243رود شاری צ'ארי Шарі چاری 沙里河 6River Chattahoochee 5.0 6.0Chattahoochee Chattahoochee Q1068297 تشاتاهوتشي চাত্তাহূছি Chattahoochee Chattahoochee Chattahoochee Τσαταχούτσι चत्ताहूची Chattahoochee Chattahoochee Chattahoochee チャタフーチー川 채터후치 Chattahoochee Chattahoochee Chattahoochee Чаттахучи Chattahoocheefloden Chattahoochee Sông Chattahoochee 查特胡奇河 1159114943رودخانه چاتاهوچی צ'אטאוצ'י Чаттахучі چاٹاہوچی 查特胡奇河 6River Chattooga 5.0 6.0Chattooga Chattooga Q834880 تشاتوغا চাত্তাউগা Chattooga Chattooga Chattooga Τσατούγκα चट्टूगा Chattooga Chattooga Chattooga チャトゥーガ川 채투가 Chattooga Chattooga Chattooga река Чаттуга Chattooga River Chattooga Sông Chattooga 查图加河 1159115035چاتوگا צ'אטוגה Чаттуга چاٹوگا 查圖加河 6River Chenab 5.0 6.0Chenab Chenab Q216875 نهر تشيناب চিনাব নদী Chanab Chenab Chenab Ακεσίνης चनाब नदी Chenab Chenab Chenab シェナブ川 첸나브강 Chenab Ćenab Chenab Чинаб Chenab Çenab Chenab 奇纳布河 1159116961چناب צ'נאב Чинаб دریائے چناب 奇納布河 5River Chixoy 4.7 5.7Chixoy Chixoy Q1726738 تشيكسوي চিক্সয় Chixoy Chixoy Chixoy Τσιξόι चिक्सॉय Chixoy Chixoy Chixoy チクソイ川 칙소이 Chixoy Chixoy Chixoy река Чиксой Chixoy Chixoy Sông Chixoy 奇霍伊河 1159113579چیکسوی צ'יקוי Чіксой چکسوئے 奇霍伊河 6River Chubut 5.0 6.0Chubut Chubut Q955354 تشوبوت চুবুত Chubut Chubut Chubut Ποταμός Τσουμπούτ चुबुत Chubut Chubut Chubut チュブ川 추붓 Chubut Chubut Chubut Чубут Chubutfloden Chubut Sông Chubut 丘布特河 1159116247رود چوبوت צ'ובוט Чубут چوبوٹ 丘布特河 6River Chulyshman 5.0 6.0Chulyshman Chulyshman Q1808438 تشوليشمان চুল্যাশমান Tschulyschman Chulyshman Tchoulychman Τσουλισμάν चुलिशमैन Chulyshman Chulyshman Čulyšman チュリシュマン川 출리쉬만 Tsjoelysjman Czułyszman Chulyshman Чулышман Tjulysjman Chulyshman Sông Chulyshman 丘雷什曼河 1159117541رودخانه چولیشمن צ'ולישמן Чулишман چولشمان 丘雷什曼河 6River Churchill 5.0 6.0Churchill Churchill Q291233 تشرشل চার্চিল Churchill Churchill fleuve Churchill Τσόρτσιλ चर्चिल Churchill Churchill Fiume Churchill チャーチル川 처칠 Churchill Churchill Churchill Черчилл Churchillfloden Churchill Sông Churchill 丘吉尔河 1159114751چرچیل צ'רצ'יל Черчилл چرچل 丘吉爾河 6River Coco 5.0 6.0Coco Coco Q1468689 نهر كوكو কোকো Coco Coco Coco Ποταμός Κόκο कोको Coco Coco Coco ココ川 코코스 Coco Coco Coco Коко Coco Coco Sông Coco 科科河 1159117081کوکو קוקו Коко کوکو 科科河 5River Colorado 4.7 5.7Colorado Colorado Q270627 كولورادو কলোরাডো Colorado Colorado Colorado Κολοράδο कोलोराडो Colorado Colorado Colorado コロラド川 콜로라도 Colorado Colorado Colorado Рио-Колорадо Colorado River Colorado Sông Colorado 科罗拉多河 1159113559کلرادو קולורדו Ріо-Колорадо کولوراڈو 科罗拉多河 3River Columbia 3.0 4.0Columbia Columbia Q2251 نهر كولومبيا কলাম্বিয়া নদী Columbia Columbia fleuve Columbia Κολούμπια कोलम्बिया नदी Columbia Columbia Columbia コロンビア川 컬럼비아강 Columbia Kolumbia Columbia Колумбия Columbiafloden Kolumbiya Columbia 哥倫比亞河 1159124377رودخانه کلمبیا קולומביה Колумбія کولمبیا دریا 哥倫比亞河 2River Congo 2.1 3.1Congo Congo Q3503 نهر الكونغو কঙ্গো নদী Kongo Congo Congo Κονγκό कांगो नदी Kongó Kongo Congo コンゴ川 콩고강 Kongo Kongo Congo Конго Kongofloden Kongo Congo 刚果河 1159120849کنگو קונגו Конго دریائے کانگو 刚果河 6River Copper 5.0 6.0Copper Copper Q1131444 كوبر কপার Copper Copper Copper Κόπερ कॉपर Copper Copper Copper カッパー川 쿠퍼 Copper Rzeka Miedziana Copper Коппер Cooper River Copper Sông Copper 銅河流域 1159114561کوپر קופר Мідна річка کاپر 銅河流域 6River Coppermine 5.0 6.0Coppermine Coppermine Q1131514 كوبرمين কপারমাইন Coppermine Coppermine Coppermine Κόπερμαϊν कापरमाइन नदी Coppermine Coppermine Coppermine コッパーマイン川 쿠퍼마인 Coppermine Coppermine Coppermine Коппермайн Copperminefloden Coppermine Sông Coppermine 科珀曼河 1159115279کوپرمین קופרמיין Коппермайн کاپر مائن 銅礦河 6River Cubango 5.0 6.0Okavango Cubango Q188773 نهر أوكافانغو কুবাঙ্গো Okavango Okavango Okavango Οκαβάνγκο ओकावंगो नदी Okavango Okavango Okavango オカヴァンゴ川 오카방고강 Okavango Okawango Cubango Окаванго Okavango Okavango Okavango 奥卡万戈河 1159114105رود اوکاوانگو נהר האוקוונגו Окаванґо کیوبانگو 奧卡萬戈河 5River Culuene 4.7 5.7Culuene Culuene Q1644776 كولوين কুলুয়েনে Culuene Culuene Culuene Κουλουένε कुलुएने Culuene Culuene Culuene クルエン川 쿨루엔 Culuene Culuene Culuene река Кулуене Culuene Culuene Sông Culuene 库鲁埃尼河 1159113305کولوئن קולואן Кулуене کیولین 庫盧希河 6River Dadu 5.0 6.0Dadu Dadu Q1075393 دادو ডাদু Dadu He Dadu Dadu Μπατού दादू Dadu Dadu Dadu 大渡河 다두허 Dadu Dadu Dadu Даду Dadu He Dadu Đại Độ 大渡河 1159116839دادو ریور דאדו Дадухе دادو 大渡河 6River Daly 5.0 6.0Daly Daly Q13359982 دالي দালে Daly Daly Daly Ντάλι डैली Daly Daly Daly デーリー川 데일리 Daly Daly Daly река Дейли Daly Daly Sông Daly 达利河 1159117493دالی דאלי Дейлі ڈالی 戴利 6River Dalälven 5.0 6.0Dalälven Dalälven Q216627 دالالڤين দালালভেন Dalälven Dal Dalälven Ντάλελβεν डलालवेन Dalälven Dalälven Dalälven ダール川 달라벤강 Dalälven Dalälven Dalälven Далэльвен Dalälven Dalälven Sông Dalälven 達爾河 1159114331داللون דלאלוון Далельвен ڈالالوین 達爾河 1River Damietta Branch 2.0 3.0Damietta Branch فرع دمياط দামিয়েত্তা ব্রাঞ্চ Damietta Branch Ramal Damietta Damiette Νταμιέτα Μπραντς डेमीएटा ब्रांच Damietta Branch Anak Sungai Damietta Ramo Damietta ダミエッタ支流 다미에타 브랜치 Damietta Branch Damietta Braço Damietta река Думьят Damietta Dimyat Kolu Nhánh sông Damietta 达米埃塔支流 1159113949شاخه دامیتا סניף בראנץ' Дамієтта ڈیمیٹا برانچ 達米埃塔河 2River Danube 2.1 3.1Danube Danube Q1653 دانوب দানিউব নদী Donau Danubio Danube Δούναβης डैन्यूब नदी Duna Donau Danubio ドナウ川 도나우강 Donau Dunaj Danúbio Дунай Donau Tuna Đa Nuýp 多瑙河 1159115307دانوب דנובה Дунай دریائے ڈینیوب 多瑙河 3River Darling 3.0 4.0Darling Darling Q181482 نهر دارلينج ডার্লিং নদী Darling Darling Darling Ντάρλινγκ डार्लिंग नदी Darling Darling Darling ダーリング川 달링강 Darling Darling Darling Дарлинг Darling Darling Darling 达令河 1159128253دارلینگ דרלינג Дарлінг ڈارلنگ 達令河 5River Daugava 4.7Zapadnaya Dvina 5.7Daugava Daugava Q8197 نهر دفينا দাউগাভা Düna Daugava Daugava Νταουγκάβα डुगावा नदी Daugava Daugava Daugava ダウガヴァ川 다우가바강 Westelijke Dvina Dźwina Duína Ocidental Западная Двина Daugava Daugava Tây Dvina 道加瓦河 1159113381دائوگاوا דווינה Західна Двіна ڈوگاوا 道加瓦河 6River Desaguadero 5.0 6.0Desaguadero Desaguadero Q385342 ديساجواديرو দেসাগুয়াদেরো Salado del Oeste Desaguadero Desaguadero Ποταμός Ντεσαγουαδέρο देसागुआदेरो Desaguadero Desaguadero Desaguadero デサグアデーロ川 데사구아데로 Desaguadero Salado Desaguadero Десагуадеро Desaguadero Desaguadero Sông Desaguadero 德薩瓜德羅河 1159117897دساگوادرو דסאגואדרו Десаґуадеро ڈیساگواڈیرو 德薩瓜德羅河 4River Dicle 4.0 5.0Tigris Dicle Q35591 دجلة দজলা Tigris Tigris Tigre Τίγρης ποταμός दजला नदी Tigris Tigris Tigri チグリス川 티그리스강 Tigris Tygrys Tigre Тигр Tigris Dicle Tigris 底格里斯河 1159112059دجله חידקל Тигр دریائے دجلہ 底格里斯河 6River Digul 5.0 6.0Digul Digul Q575695 نهر ديجول দিগুল নদী Digul Digul Digul Ντιγκούλ डिगुल Digul Digul Digul ディグル川 디굴 Digoel Digul Digul Дигул Digul Digul Sông Digul 迪古尔河 1159117311دیگول דיגול Дігул ڈائےگول 迪古尔河 2River Dihang 2.1 3.1Brahmaputra Dihang Q45403 نهر براهمابوترا ব্রহ্মপুত্র নদ Brahmaputra Brahmaputra Brahmapoutre Βραχμαπούτρας ब्रह्मपुत्र नदी Brahmaputra Brahmaputra Brahmaputra ブラマプトラ川 브라마푸트라강 Brahmaputra Brahmaputra Bramaputra Брахмапутра Brahmaputra Brahmaputra Brahmaputra 布拉马普特拉河 1159121213رود براهماپوترا בראהמאפוטרה Брахмапутра دریائے برہم پتر 布拉马普特拉河 4River Dnepre 4.0 5.0Dnieper Dnepre Q40855 دنيبر নিপার নদী Dnepr Dniéper Dniepr Δνείπερος नीपर Dnyeper Dnieper Dnepr ドニエプル川 드네프르강 Dnjepr Dniepr Dniepre Днепр Dnepr Dinyeper Dnepr 第聂伯河 1159112073دنیپر דנייפר Дніпро دریائے دنیپر 第聂伯河 6River Dniester 5.0 6.0Dniester Dniester Q131210 دنيستر দনিএস্তের Dnister Dniéster Dniestr Δνείστερος डेनिस्टर Dnyeszter Dniester Dnestr ドニエストル川 드네스트르강 Dnjestr Dniestr Dniestre Днестр Dnestr Dinyester Dnister 德涅斯特河 1159114451نیستر דניסטר Дністер نائیسٹر 德涅斯特河 4River Dnipro 4.0Dnieper 5.0Dnieper Dnipro Q40855 دنيبر নিপার নদী Dnepr Dniéper Dniepr Δνείπερος नीपर Dnyeper Dnieper Dnepr ドニエプル川 드네프르강 Dnjepr Dniepr Dniepre Днепр Dnepr Dinyeper Dnepr 第聂伯河 1159112001دنیپر דנייפר Дніпро دریائے دنیپر 第聂伯河 6River Don 4.7 6.0Don Don Q1229 نهر الدون দোন নদী Don Don Don Ντον दोन नदी Don Don Don ドン川 돈강 Don Don Don Дон Don Don Đông 頓河 1159115995رودخانه دان דון Дон ڈان 頓河 2River Donau 2.1Danube 3.1Danube Donau Q1653 دانوب দানিউব নদী Donau Danubio Danube Δούναβης डैन्यूब नदी Duna Donau Danubio ドナウ川 도나우강 Donau Dunaj Danúbio Дунай Donau Tuna Đa Nuýp 多瑙河 1159118769دانوب דנובה Дунай دریائے ڈینیوب 多瑙河 6River Double Mountain Fork Brazos 5.0 6.0Double Mountain Fork Brazos Double Mountain Fork Brazos Q5299851 نهر دبل ماونتن فورك برازوس ডাবল মাউন্টেন ফর্ক ব্র্যাজোস Double Mountain Fork B Double Mountain Fork Braz Double Mountain Fork Br Νταμπλ Μάουντεν Φορκ Μπράζος डबल माउंटेन फोर्क ब्रेज़ोस Double Mountain Fork Brazos-fo Double Mountain Fork Brazos Double Mountain Fork Br ダブル・マウンテン・フォーク・ブラゾス川 더블 마운틴 포크 브라조스 Double Mountain For Double Mountain Fork Brazos Double Mountain Fork Brazos река Дабл-Маунтин-Форк-Бразос Double Mountain Fork Bra Double Mountain Fork Brazo Sông Double Mountain F 双山叉布拉索斯河 1159117103دبل مونتن فورک بریزوس דאבל מאונטיין פורק בראזוס Дабл-Маунтін-Форк-Бразос ڈبل ماؤنٹین فورک بریزوس 布拉索斯河雙山支流 6River Mur 5.0Drava 6.0Mur Mur Q204040 مور মুর Mur Mura Mur Μουρ मुर Mura Mur Mura ムール川 무어강 Mur Mura Mur Мура Mura Mora Sông Mur 穆尔河 1159113895رودخانه مور מורה Мура مر 穆爾河 6River Duero 5.0 6.0Douro Duero Q14299 دورو দোরু নদী Douro Duero Douro Δούρος दयोरो Duero Duero Duero ドウロ川 도루강 Douro Duero Douro Дуэро Duero Douro Douro 杜罗河 1159116751دورو דורו Дору ڈویرو 杜罗河 5River Ebro 4.7 5.7Ebro Ebro Q10965 أبرة এব্রো Ebro Ebro Èbre Έβρος एब्रो Ebro Ebro Ebro エブロ川 에브로강 Ebro Ebro Ebro Эбро Ebro Ebro Ebro 埃布羅河 1159112595ایبرو אברו Ебро ایبرو 埃布羅河 1River El Bahr el Abyad 2.0White Nile 3.0White Nile El Bahr el Abyad Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159113335نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 3River El Bahr el Azraq 3.0Blue Nile 4.0Blue Nile El Bahr el Azraq Q882739 النيل الأزرق নীলাভ নীল নদ Blauer Nil Nilo Azul Nil Bleu Γαλάζιος Νείλος नीली नील Kék-Nílus Nil Biru Nilo Azzurro 青ナイル川 청나일강 Blauwe Nijl Nil Błękitny Nilo Azul Голубой Нил Blå Nilen Mavi Nil Nin Xanh 青尼罗河 1159126701نیل آبی הנילוס הכחול Блакитний Ніл نیل ازرق 青尼罗河 5River Elbe 4.7 5.7Elbe Elbe Q1644 إلبه লাবে নদী Elbe Elba Elbe Έλβας एल्वे नदी Elba Elbe Elba エルベ川 엘베강 Elbe Łaba Elba Эльба Elbe Elbe Elbe 易北河 1159112751البه אלבה Ельба ایلب 易北河 2River Ertis 2.1 3.1Irtysh Ertis Q128102 إيرتيش ইর্তিশ নদী Irtysch Irtish Irtych Ποταμός Ιρτίς इरतिश नदी Irtis Irtysh Irtyš エルティシ川 이르티시강 Irtysj Irtysz Irtich Иртыш Irtysj İrtiş Irtysh 额尔齐斯河 1159116609ایرتیش אירטיש Іртиш دریائے ارتش 額爾齊斯河 2River Ertix 2.1Irtysh 3.1Irtysh Ertix Q128102 إيرتيش ইর্তিশ নদী Irtysch Irtish Irtych Ποταμός Ιρτίς इरतिश नदी Irtis Irtysh Irtyš エルティシ川 이르티시강 Irtysj Irtysz Irtich Иртыш Irtysj İrtiş Irtysh 额尔齐斯河 1159116855ایرتیش אירטיש Іртиш دریائے ارتش 額爾齊斯河 3River Euphrates 3.0 4.0Euphrates Euphrates Q34589 الفرات ফোরাত Euphrat Éufrates Euphrate Ευφράτης फ़रात नदी Eufrátesz Efrat Eufrate ユーフラテス川 유프라테스강 Eufraat Eufrat Eufrates Евфрат Eufrat Fırat Euphrates 幼发拉底河 1159123947فرات פרת Євфрат دریائے فرات 幼发拉底河 6River Ferenc Csatorna 5.0 6.0Ferenc Csatorna فيرينك كساتورنا ফেরেংক ক্সাতোরনা Donau-Theiß-Donau-Kana Ferenc Csatorna Canal Danube-Tisa-Danub Φέρεντς Τσατόρνα फेरेक सेसटोरना Ferenc Csatorna Ferenc Csatorna Ferenc Csatorna グレートバイカ運河 페렌츠 차토르나 Ferenc-tápcsatorna Ferenc Csatorna Canal Danúbio – Tisa – Danú канал Дунай — Тиса — Дунай Ferenc Csatorna Ferenc Csatorna Sông Ferenc Csatorna 弗朗西斯运河 1159117717فرنک سیساتورنا פֶרֶנץ צאטורנה Ференц Чаторна فیرینک ساٹورنا 費倫茨河 6River Finlay 5.0 6.0Finlay Finlay Q280696 فينلي ফিনলে Finlay Finlay Finlay Φίνλεϊ फ़िनले Finlay Finlay Finlay フィンレイ川 핀레이 Finlay Finlay Finlay Финлей Finlay Finlay Finlay 芬利河 1159117141رود فینلی פינליי Фінлей فنلنے دریا 芬利河 3River Firat 3.0 4.0Euphrates Firat Q34589 الفرات ফোরাত Euphrat Éufrates Euphrate Ευφράτης फ़रात नदी Eufrátesz Efrat Eufrate ユーフラテス川 유프라테스강 Eufraat Eufrat Eufrates Евфрат Eufrat Fırat Euphrates 幼发拉底河 1159124669فرات פרת Євфрат دریائے فرات 幼发拉底河 6River Fitzroy 5.0 6.0Fitzroy Fitzroy Q1421418 فيتزروي ফিটজরয় Fitzroy Fitzroy Fitzroy Φιτζρόι फ़िट्ज़रॉय Fitzroy Fitzroy Fitzroy フィッツロイ川 피츠로이 Fitzroy Fitzroy Fitzroy Фицрой Fitzroy Fitzroy Sông Fitzroy 费希尔斯峰 1159117293فیتزوری פיצרוי Фіцрой فٹزرائے 菲茲羅伊河 5River Fraser 4.7 5.7Fraser Fraser Q269710 نهر فريزر ফ্রেজার Fraser Fraser fleuve Fraser Φρέιζερ फ़्रेज़र Fraser Fraser Fraser フレーザー川 프레이저강 Fraser Fraser Fraser Фрейзер Fraserfloden Fraser Sông Fraser 弗雷泽河 1159113463رود فریزر נהר פרייזר Фрейзер فریزر دریا 弗雷澤河 6River Gan 5.0 6.0Gan Gan Q1046685 نهر جان গান Gan Gan Gan Γκαν गन Gan Gan Gan 贛江 간장 강 Gan Gan Gan Гань Ganfloden Gan Cám 赣江 1159116043گان גאן Ґань گین 贛江 3River Ganges 3.0 4.0Ganges Ganges Q5089 نهر الغانج গঙ্গা নদী Ganges Ganges Gange Γάγγης गंगा नदी Gangesz Gangga Gange ガンジス川 갠지스강 Ganges Ganges Ganges Ганг Ganges Ganj Hằng 恒河 1159122643گنگ גנגס Ганг دریائے گنگا 恆河 6River Ariège 5.0 6.0Ariège Ariège Q18451 أرياج আরিয়েজ Ariège Ariège Ariège Αριέζ एरीगे Ariège Ariège Ariège アリエージュ川 아리에주 Ariège Ariège Ariège Арьеж Ariège Ariège Ariège 阿列日河 1159129235آریژی ארייז' Ар'єж آریگے 阿列日河 6River Genale 5.0 6.0Genale جانالي গেনেল Ganale Genale Janale Γκενάλε जेनाले Genale Genale Genale ジェネール川 제날레 Genale Genale Ganale Dorya река Дженейл Genale Genale Sông Genale 加纳勒多里亚河 1159114673گنال גֶ'נייל Дженейл گینالے 加納里河 4River Gharraf Canal 4.0 5.0Shatt al-Hayy Q2076850 نهر الغراف ঘারাফ ক্যানেল Shatt Al Gharraf Gharraf Canal Shatt Al Gharraf Κανάλι Γκαράφ गर्राफ कैनल Gharraf-csatorna Kanal Gharraf Canale di Gharraf ガラフ川 가라프 캐널 Gharraf Canal Kanał Gharraf Canal Gharraf Шатт аль-Хай Gharrafkanalen Gharraf Kanalı Kênh Gharraf 加拉夫运河 1159112397کانال قراف תעלת גארף канал Гарраф غراف کنال 加拉夫運河 6River Gila 5.0 6.0Gila Gila Q838143 جيلا জিলা Gila Gila Gila Γκίλα गिला Gila Gila Gila ヒラ川 길라 Gila Gila Gila Хила Gilafloden Gila Gila 希拉河 1159117349رود هیلا חילה Гіла دریائے ہیلا 希拉河 6River Glomma 5.0Glåma 6.0Glomma Glomma Q214535 جلوما গ্লোম্মা Glomma Glomma Glomma Γκλόμμα ग्लोम्मा Glomma Glomma Glomma グロンマ川 글로마 강 Glomma Glomma Glomma Гломма Glomma Glomma Sông Glomma 格羅馬河 1159117401گلوما גלומה Гломма گلوما 格羅馬河 5River Godävari 4.7 5.7Godavari Godävari Q191314 نهر جودافاري গোদাবরী নদী Godavari Godavari Godâvarî Γκοντάβαρι ποταμός गोदावरी नदी Godávári Godavari Godavari ゴーダーヴァリ川 고다바리강 Godavari Godawari Godavari Годавари Godavari Godavari Godavari 哥达瓦里河 1159113319گوداواری נהר גודאבארי Ґодаварі دریائے گوداوری 哥達瓦里河 3River Grande 3.0 4.0Grande Grande Q1519602 غراندي গ্র্যান্ডে Grande Grande Grande Γκράντε ग्रैंडे Grande Grande Grande グランデ川 그란데 Grande Rio Grande Grande Рио-Гранде Grande Grande Grande 格蘭德河 1159127321ریو گرانده גראנד Ріо-Гранде گرانڈے 格蘭德河 6River Great Pee Dee 5.0 6.0Pee Dee Great Pee Dee Q2061230 غريت بي دب গ্রেট পী ডী Pee Dee Pee Dee Pee Dee Γκρέιτ Πι Ντι ग्रेट पी डी Great Pee Dee Great Pee Dee Great Pee Dee グレート・ピー・ディー川 그레이트 피 디 Pee Dee Pee Dee Great Pee Dee река Грейт-Пи-Ди Great Pee Dee Great Pee Dee Sông Great Pee Dee 格雷特皮迪河 1159118047گریت پی دی גרייט פי די Пі-Ді گریٹ پی ڈی 大皮迪河 3River Guaporé 3.0 4.0Guaporé Guaporé Q916349 نهر غوابوري গুয়াপোরে Guaporé Iténez Guaporé Γκουαπορέ गुआपोरे Guaporé Guapore Guaporé グアポレ川 구아포레 Guaporé Guaporé Guaporé Гуапоре Guaporéfloden Guaporé Guaporé 瓜波雷河 1159128533رود گوآپوره גואפור Гуапоре گواپورے 瓜波雷河 6River Göta älv 5.0 6.0Göta älv Göta älv Q214748 جوتا গোটা আল্ভ Göta älv Göta Göta älv Γκέτα Έλβ गोटा अल्व Göta Göta älv Göta älv イェータ川 예타강 Göta älv Göta älv Göta älv Гёта-Эльв Göta älv Göta älv Göta 约塔河 1159117981گوته الو יטה אלב Гета-Ельв گوٹا آلو 約塔河 3River Hailar 3.0 4.0Argun Hailar Q26439 نهر أرغون হাইলার Argun Argún Argoun Χαϊλάρ अर्गुन नदी Arguny Hailar Argun' アルグン川 아르군강 Argoen Argun Argun Аргунь Argun Argun Argun 额尔古纳河 1159126861رود آرگون נהר ארגון Аргунь ہیلار 额尔古纳河 6River Han 5.0 6.0Han Han Q875573 هان হান Han Han Han Χαν हान नदी Han Han Fiume Han 漢江 한강 Han Han Shui Han Ханьшуй Han Shui Han Hán Thủy 汉水 1159115755هان נהר האן Ханьшуй ہان 漢江 3River Heilong Jiang 3.0Amur 4.0Amur Heilong Jiang Q6862 نهر آمور আমুর নদী Amur Amur Amour Αμούρ अमूर नदी Amur Amur Amur アムール川 아무르강 Amoer Amur Amur Амур Amur Amur Amur 黑龙江 1159128755آمور אמור Амур دریائے آمور 黑龍江 6River Helmand 5.0 6.0Helmand Helmand Q8510 نهر هلمند হেলমান্দ নদী Hilmend Helmand Helmand Χέλμαντ ποταμός हेलमंद नदी Hilmend Helmand Helmand ヘルマンド川 헬만드강 Helmand Helmand Helmand Гильменд Helmandfloden Helmend Helmand 赫爾曼德河 1159116765هیرمند נהר הלמנד Гільменд دریائے ہلمند 赫爾曼德河 5River Holston 4.7 5.7Holston Holston Q1333747 هولستون হোলস্টন Holston Holston Holston Χόλστον होल्सटन Holston Holston Holston ホールストン川 홀스턴 Holston Holston Holston Холстон Holston River Holston Sông Holston 霍尔斯顿河 1159113431هولستون הולסטון Холстон ہولسٹن 霍斯頓河 6River Hong 5.0Red 6.0Red Hong Q206850 النهر الأحمر লাল নদী Roter Fluss Rojo fleuve Rouge Ερυθρός Ποταμός हांग Vörös Merah Fiume Rosso 紅河 홍강 Rode Rzeka Czerwona Vermelho Хонгха Röda floden Kızıl Nehir Hồng 红河 1159116785رود سرخ הנהר האדום Хонгха دریائے سرخ 紅河 4River Hongshui 4.0 5.0Hongshui Hongshui Q615328 هونغشوي হংশ্যুই Hongshui Hongshui Hongshui Χονγκσούι होंगशुई Hongshui Hongshui Hongshui 紅水河 홍수이 Hongshui Hongshui He Hongshui Хуншуйхэ Hongshui He Hongshui Hồng Thủy 红水河 1159112463هونگشوی הונגשוי Хуншуйхе ہانگشوئی 紅水河 3River Huang 3.0 4.0Yellow Huang Q7355 النهر الأصفر হুয়াংহো নদী Gelber Fluss Amarillo fleuve Jaune Κίτρινος Ποταμός ह्वांगहो Sárga Kuning Fiume Giallo 黄河 황하 Gele Huang He Amarelo Хуанхэ Huanghe Sarı Irmak Hoàng Hà 黄河 1159128895هوانگ هو הנהר הצהוב Хуанхе دریائے زرد 黃河 3River Huang 3.0Yellow 4.0Yellow Huang Q7355 النهر الأصفر হুয়াংহো নদী Gelber Fluss Amarillo fleuve Jaune Κίτρινος Ποταμός ह्वांगहो Sárga Kuning Fiume Giallo 黄河 황하 Gele Huang He Amarelo Хуанхэ Huanghe Sarı Irmak Hoàng Hà 黄河 1159128895هوانگ هو הנהר הצהוב Хуанхе دریائے زرد 黃河 6River Hudson 5.0 6.0Hudson Hudson Q3140 نهر هدسون হাডসন নদী Hudson Hudson Hudson Χάντσον हडसन नदी Hudson Hudson Hudson ハドソン川 허드슨강 Hudson Hudson Hudson Гудзон Hudsonfloden Hudson Hudson 哈德遜河 1159117183رودخانه هادسون הדסון Гудзон ہڈسن 哈德遜河 2River Ideriyn 2.1 3.1Ider Ideriyn Q26301 إداريين ইদেরিয়ান Ider Ider Ider Ιντεριίν इडेरिएन Ider Ideriyn Ideriin gol イデル川 이데린 Ider Ider gol Ider Идэр Ider Ider Ideriin gol 伊德尔河 1159115719ایدریان אידריין Ідер آئیڈیرن 伊德尔河 4River Indaiá 4.0 5.0Indaiá Q10362010 إنديا ইন্ডালা Rio Indaiá Indaiá Indaiá Ινταϊά इंदाई Indaiá Indaiá Indaiá インダイア川 인다이아 Indaiá Indaiá Indaiá река Индайа Indaiá Indaiá Sông Indaiá 因达亚河 1159112101ایندایا אינדאיה Індайа انڈایا 因達亞河 5River Indigirka 4.7 5.7Indigirka Indigirka Q82207 نهر إنديغيركا ইন্ডিগিরকা Indigirka Indigirka Indiguirka Ιντιγκίρκα इंडिगिरका Ingyigirka Indigirka Indigirka インディギルカ川 인디기르카강 Indigirka Indygirka Indigirka Индигирка Indigirkafloden İndigirka Indigirka 因迪吉爾卡河 1159113479رود اندگریکا אינדיג'ירקה Індигірка انڈیگیرکا 因迪吉爾卡河 6River Indragi 5.0 6.0Batang Indragiri Indragi Q3511574 نهر إندراجيري ইন্দ্রাগি Indragiri River Indragi Indaragi Ιντράγκι इंद्रगी Indragi Batang Kuantan Indragiri インドラギリ川 인드라기 Indragiri Inderagiri Indragiri Индерагири Batang Indragiri Indragi Sông Indragi 英德拉吉河 1159114045ایندراگی אינדראגי Індрагі اندراگی 英德拉吉河 3River Indus 3.0 4.0Indus Indus Q7348 نهر السند সিন্ধু নদ Indus Indo Indus Ινδός ποταμός सिन्धु नदी Indus Indus Indo インダス川 인더스강 Indus Indus Indo Инд Indus İndus Ấn 印度河 1159122839سند אינדוס Інд دریائے سندھ 印度河 2River Irrawaddy Delta 2.1 3.1Irrawaddy Irrawaddy Delta Q26076 نهر إيراوادي ইরাবতী নদী Irrawaddy Irawadi Irrawaddy Ιραουάντι इरावती नदी Iravádi Irrawaddy Irrawaddy エーヤワディー川 이라와디강 Irrawaddy Irawadi Irauádi Иравади Irrawaddy İravadi Ayeyarwaddy 伊洛瓦底江 1159109417رود ایراوادی נהר איראוואדי Іраваді ایراوادی دریا 伊洛瓦底江 2River Irtysh 2.1 3.1Irtysh Irtysh Q128102 إيرتيش ইর্তিশ নদী Irtysch Irtish Irtych Ποταμός Ιρτίς इरतिश नदी Irtis Irtysh Irtyš エルティシ川 이르티시강 Irtysj Irtysz Irtich Иртыш Irtysj İrtiş Irtysh 额尔齐斯河 1159120669ایرتیش אירטיש Іртиш دریائے ارتش 額爾齊斯河 6River Ishikari 5.0 6.0Ishikari Ishikari Q1061515 نهر إشيكاري ইশিকারি Ishikari Ishikari Ishikari-gawa Ισικάρι इशिकारी Isikari Ishikari Ishikari 石狩川 이시카리강 Ishikari Ishikari Ishikari Исикари Ishikari Ishikari Sông Ishikari 石狩川 1159113981رود ایشیکاری אישיקארי Ісікарі ایشیکاری 石狩川 6River Ismailiya Canal 5.0 6.0Ismailiya Canal قناة الإسماعيلية ইস্মাইলিয়া ক্যানেল Ismailiakanal Canal Ismailiya Lac Timsah Κανάλι Ισμαιλίγια इस्माइलिया कैनल Ismailiya-csatorna Kanal Ismailiya Canale di Ismailia イスマイリヤ運河 이스마일리야 캐널 Ismailia Canal Kanał Ismailijski Canal de Ismaília канал Исмаилия Ismailiakanalen İsmailiye Kanalı Kênh Ismailiya 伊斯梅利亚运河 1159113967کانال اسماعیلیه תעלת איסמעיליה канал Ісмаїлія ایسمیلیا کنال 伊斯梅利亞運河 5River Japurá 4.7 5.7Japurá Japurá Q171840 نهر جابورا জাপুরা Japurá Caquetá Caquetá Τζαπουρά जापरा नदी Caquetá Japurá Caquetá ジャプラー川 자푸라강 Japurá Japurá Japurá Жапура Japura Japurá Japurá 雅普拉河 1159113783رود جاپورا ז'פורה Жапура جاپورا 雅普拉河 6River Jequitinhonha 5.0 6.0Jequitinhonha Jequitinhonha Q2742774 نهر جيكوتينهونا জেকুইত্নহোনহা Rio Jequitinhonha Jequitinhonha Jequitinhonha Ζεκίντινιονια जेक्विटिनहोन्हा Jequitinhonha Jequitinhonha Jequitinhonha ジェキティニョニャ川 제퀴티논하 Jequitinhonha Jequitinhonha Jequitinhonha Жекитиньонья Jequitinhonha Jequitinhonha Sông Jequitinhonha 热基蒂尼奥尼亚河 1159116227جکیتینهونها ג'קיטינהונה Жекичіньонья جیکوئٹیہونہا 熱基蒂尼奧尼亞河 1River Jinsha 2.0Yangtze 3.0Jinsha Jinsha Q1038418 جينشا চিনশা নদী Jinsha-Fluss Jinsha Fleuve Jinsha Γίνσα जिंशा Jinsha Jinsha Jinsha 金沙江 진사강 Jinsha Jinsha Jinsha Цзиньша Jinshafloden Jinsha Kim Sa 金沙江 1159112733جینشا ג'ינשה Цзиньша جنشا 金沙江 6River Jordan 5.0 6.0Jordan Jordan Q40059 نهر الأردن জর্দান নদী Jordan Jordán Jourdain Ιορδάνης ποταμός जॉर्डन नदी Jordán Yordan Giordano ヨルダン川 요르단강 Jordaan Jordan Jordão Иордан Jordan Şeria Jordan 约旦河 1159114369اردن נהר הירדן Йордан دریائے اردن 約旦河 6River Jubba 5.0 6.0Jubba Jubba Q138491 نهر جوبا জুব্বা Juba Juba Jubba Τζούμπα जुब्बा नदी Jubba Jubba Giuba ジュバ川 주바 Jubba Dżuba Juba Джуба Juba Cubba Sông Jubba 朱巴河 1159117963رودخانه جبا ג'ובה Джуба جوبا 朱巴河 5River Juruena 4.7 5.7Juruena Juruena Q472816 نهر جورينا জুরুয়েনা Juruena Juruena Juruena Ζουρουένα जुरुएना Juruena Juruena Juruena ジュルエナ川 주루에나 Juruena Juruena Juruena Журуэна Juruena Juruena Juruena 茹魯埃納河 1159113527جوروئنا ז'ורוונה Журуєна جورینا 茹魯埃納河 6River Kadéï 5.0 6.0Kadeï Kadéï Q2591927 كاديو কাদেই Kadéï Kadéï Kadéï Καντέι कडी Kadéï Kadei Kadéï カダイ川 카데이 Kadéï Kadéï Kadéï Кадеи Kadeï Kadéï Sông Kadéï 卡代伊河 1159116671کادی קאדיי Кадей کادے 卡代伊河 6River Kafue 5.0 6.0Kafue Kafue Q846063 كافو কাফুয়ে Kafue Kafue Kafue Καφουέ काफुए नदी Kafue Kafue Kafue カフエ川 카푸에 Kafue Kafue Kafue Кафуэ Kafue Kafue Kafue 卡福埃河 1159116211کافو קאפוּ Кафуе کافوئی 卡福埃河 1River Kagera 2.0 3.0Kagera Kagera Q2750140 كاجيرا কাজিরা নদী Kagera-Nil Kagera Kagera Καγκέρα कगेरा नदी Kagera Kagera Kagera カゲラ川 카게라 Kagera Kagera Kagera Кагера Kagerafloden Kagera Kagera 卡蓋拉河 1159125959رود کاگرا קאגרה Кагера کاگیرا 卡蓋拉河 6River Kamchatka 5.0 6.0Kamchatka Kamchatka Q133476 كامشاتكا কামচাটকা Kamtschatka Kamchatka Kamtchatka Καμτσάτκα कमचटका नदी Kamcsatka Kamchatka Kamčatka カムチャツカ川 캄차카강 Kamtsjatka Kamczatka Kamtchatka Камчатка Kamtjatka Kamçatka Kamchatka 堪察加河 1159117039کامچاتکا קמצ'טקה Камчатка کامچاٹکا 堪察加河 6River Kapuas 5.0 6.0Kapuas Kapuas Q841359 نهر كابواس কাপুয়াস নদী Kapuas Kapuas Kapuas Ποταμός Κάπουας कापुआस Kapuas Kapuas Kapuas カプアス川 카푸아스강 Kapuas Kapuas Kapuas Капуас Kapuas Kapuas Kapuas 卡普阿斯河 1159116891رودخانه کاپواس קפואס Капуас کاپواس 卡普阿斯河 3River Kasai 3.0 4.0Kasai Kasai Q186541 نهر كاساي কাসাই Kasai Kasai Kasaï Κασάι कसाई नदी Kasai Kasai Kasai カサイ川 카사이강 Kasaï Kasai Cassai Касаи Kasai Kasai Kasai 开赛河 1159127863رود کاسای קסאי Касаї کاسائی 開賽河 6River Katherine 5.0 6.0Katherine Katherine Q532543 كاثرين ক্যাথারিন Katherine Katherine Katherine Κάθριν कैथरीन Katherine Katherine Katherine キャサリン川 캐서린강 Katherine Katherine Katherine река Кэтрин Katherine Katherine Sông Katherine 凯瑟琳河 1159116905کترین קתרין Кетрін کیتھرین 卡瑟林河 6River Kayan 5.0 6.0Kayan كيان কায়ান Kayan Kayan Kayan River Καγιάν क्यान Kayan Kayan Kayan カヤン川 카얀 Kayan Kayan Kayan река Каян Kayanfloden Kayan Sông Kayan 卡扬河 1159114001کایان קייאן Каян کایان 卡延河 6River Kem 5.0 6.0Kem Kem Q1130713 كيم কেম Kem Kem Kem Κεμ केम Kem Kem Kem' ケミ川 켐 Kem Kiem Kem Кемь Kem Kem Sông Kem 科恩河 1159113877رودخانه کم קֶם Кем کیم 科恩河 6River Kemijoki 5.0 6.0Kemijoki Kemijoki Q214779 كيميوكي কেমিজোকি Kemijoki Kemi Kemijoki Κέμιγιοκι केमिजोकि Kemijoki Kemijoki Kemijoki ケミ川 케미강 Kemijoki Kemijoki Kemijoki Кемийоки Kemi älv Kemijoki Sông Kemijoki 凱米河 1159115659کمیجوکی קמיוקי Кемійокі کیمیجوکی 凱米河 6River Khatanga 5.0 6.0Khatanga Khatanga Q82175 خاتنجا খাতাংগা Chatanga Játanga Khatanga Κατάνγκα खटंगा Hatanga Khatanga Chatanga ハタンガ川 카탕가 Chatanga Chatanga Khatanga Хатанга Khatanga Khatanga Sông Khatanga 哈坦加河 1159118135رود خاتانگا חטנגה Хатанга کھاٹانگا 哈坦加河 6River Kheta 5.0 6.0Kheta Kheta Q920267 خيتا খেতা Cheta Jeta Cheta Κέτα खेटा Heta Kheta Cheta ヘタ川 케타 Cheta Cheta Kheta Хета Kheta Kheta Sông Kheta 赫塔河 1159117523ختا חטה Хета کھیٹا 赫塔河 3River Kibali 3.0 4.0Kibali Kibali Q1120933 كيبالي কিবালি Kibali Kibali Kibali Κιμπαλί किबाली Kibali Kibali Kibali キバリ川 키발리 Kibali Kibali Kibali Кибали Kibali Kibali Sông Kibali 基巴利河 1159127587کیبالی קיבאלי Кібалі کیبالی 基巴利 5River Klamath 4.7 5.7Klamath Klamath Q968640 كلاماث ক্লামাথ Klamath Klamath Klamath Κλαμάθ क्लामथ Klamath Klamath Klamath クラマス川 클라마스 Klamath Klamath Klamath Кламат Klamath River Klamath Sông Klamath 克拉玛斯河 1159113167رود کلمث נהר קלאמת Кламат دریائے کلیمیتھ 克拉瑪斯河 6River Kokemäenjoki 5.0 6.0Kokemäenjoki Kokemäenjoki Q1329599 كوكيماينيوكي কোকেমায়েনজোকি Kokemäenjoki Kokemäenjoki Kokemäenjoki Κοκενμαεντζόκι कोकेमेनजोकी Kokemäenjoki Kokemäenjoki Kokemäenjoki コケマエンヨキ 코케마엔조키 Kokemäenjoki Kokemäenjoki Kokemäenjoki Кокемяэнйоки Kumo älv Kokemäenjoki Sông Kokemäenjoki 科凱邁基河 1159118035کوکماینجوکی קוקמאקניוקי Кокемяеньйокі کوکیمینجوکی 科凱邁基河 4River Kolyma 4.0 5.0Kolyma Kolyma Q78879 نهر كوليما কোলিমা নদী Kolyma Kolymá Kolyma Κολιμά कोलिमा Kolima Kolyma Kolyma コリマ川 콜리마강 Kolyma Kołyma Kolyma Колыма Kolymafloden Kolima Kolyma 科雷馬河 1159112111رود کلیما קולימה Колима کولیما 科雷馬河 6River Konqi 5.0 6.0Konqi He Konqi Q625404 كونكي কোনকি Konqi Konqi Konqi He Κόνκι कोन्कि Koncse-darja Konqi Konqi 孔雀河 콘치 Konqi Koncze-daria Konqi Кончедарья Konqi He Konqi Sông Khổng Tước 孔雀河 1159117613کونکی קונקי Кончедар'я کونقی 孔雀河 6River Koukourou 5.0 6.0Koukourou Koukourou Q22555212 كوكورو কৌকৌরৌ Koukourou Koukourou Koukourou Κούκουρου कौकौरौ Koukourou Koukourou Koukourou コウクロウ 코우코로 Koukourou Koukourou Koukourou Koukourou Koukourou Sông Koukourou 库库鲁河 1159114205کوکورو קוקורו Коукоуроу کوکورو 庫庫魯河 6River Koyukuk 5.0 6.0Koyukuk Koyukuk Q1546553 كويوكوك কোয়ুকুক Koyukuk Koyukuk Koyukuk Κογιούκουκ कोयुकुक Koyukuk Koyukuk Koyukuk コユクク 코유쿡 Koyukuk Koyukuk Koyukuk Коюкук Koyukuk Koyukuk Sông Koyukuk 科玉库克河 1159114655کویوکوک נהר קויוקוק Коюкук کویوکک 科玉庫克河 6River Krishna 5.0 6.0Krishna Krishna Q193499 نهر كريشنا কৃষ্ণা নদী Krishna Krishná Krishnâ Κρίσνα कृष्णा नदी Krisna Krishna Krishna クリシュナ川 크리슈나강 Krishna Kryszna Krishna Кришна Krishnafloden Krişna Krishna 奎师那河 1159116095رود کریشنا קרישנה Крішна دریائے کرشنا 奎師那河 6River Kuskokwim 5.0 6.0Kuskokwim Kuskokwim Q60067 كوسكوكويم কুস্কোকুইম Kuskokwim Kuskokwim Kuskokwim Κουσκόκβιμ कुस्कोकविम Kuskokwim Kuskokwim Kuskokwim カスコクウィム川 쿠스코쿰 Kuskokwim Kuskokwim Kuskokwim Кускоквим Kuskokwim Kuskokwim Sông Kuskokwim 卡斯科奎姆河 1159114525رود کاسکوکویم קוסקוקווים Кускоквім کوسکوکوم 卡斯科奎姆河 6River Kwango 5.0 6.0Kwango Kwango Q732790 كوانجو কোওয়াঙ্গো Kwango Kwango Kwango Ποταμός Κουάνγκο क्वांगो नदी Kwango Kwango Kwango クワンゴ川 쾅고 Kwango Kuango Cuango Кванго Kwango Kwango Kwango 宽果河 1159116191کوانگو קוואנגו Кванго کوانگا 寬果河 4River Kyzyl-Khem 4.0 5.0Little Yenisei Q1511505 نهر ينيسي الصغير কাইজিল-খেম Kleiner Jenissei Mali Yeniséi Petit Ienisseï Κοζούλ-Χεμ काज़िल-खेम Kis-Jenyiszej Kyzyl-Khem Malyj Enisej カー=ヘム川 키질-켐 Little Yenisei Mały Jenisej Kyzyl-Khem Малый Енисей Kyzyl-Khem Küçük Yenisey Enisei Nhỏ 小葉尼塞伊河 1159112249کیزیل-خم קיזיל-חֶם Малий Єнісей کیزل خیم 小葉尼塞伊河 4River La Grande 4.0 5.0La Grande La Grande Q31379 لا غراندي লা গ্র্যান্ডে La Grande Grande la Grande Λα Γκράντε ला ग्रैंड La Grande La Grande La Grande ラグランデ川 라 그란데 La Grande La Grande La Grande Ла-Гранд La Grande La Grande Sông La Grande 拉格朗德河 1159111069لا گراند לה גרנדה Ла-Гранде لا گرانڈے 拉格朗德河 2River Lancang 2.1Mekong 3.1Mekong Lancang Q41179 نهر ميكونغ মেকং নদী Mekong Mekong Mékong Μεκόνγκ मीकांग नदी Mekong Mekong Mekong メコン川 메콩강 Mekong Mekong Mekong Меконг Mekong Mekong Mê Kông 湄公河 1159119517مکونگ מקונג Меконг دریائے میکانگ 湄公河 4River Lek 4.0 5.0Lek Lek Q1143852 ليك লেক Lek Lek Lek Λεκ लेक Lek Lek Lek レック川 렉강 Lek Lek Lek Лек Lek Lek Sông Lek 莱克河 1159112387لک לק Лек لیک 萊克河 1River Lena 2.0 3.0Lena Lena Q46841 نهر لينا লেনা নদী Lena Lena Léna Λένας ποταμός लेना नदी Léna Lena Lena レナ川 레나강 Lena Lena Lena Лена Lena Lena Lena 勒拿河 1159112191رود لنا לנה Лена لینا 勒拿河 6River Liao 5.0 6.0Liao Liao Q559661 نهر لياو লিয়াও নদী Liao He Liao Liao Λιάο लियाओ नदी Liao Liao Liao 遼河 랴오허 Liao Liao He Liao Ляохэ Liaohe Liao Liêu Hà 辽河 1159114785رود لیائو ליאו Ляохе لیاؤ 遼河 6River Liard 5.0 6.0Liard Liard Q2249 ليارد লিয়ার্ড Liard Liard Liard Λιαρντ लिअर्ड नदी Liard Liard Liard リアード川 리아드 Liard Liard Liard Лиард Liard Liard Sông Liard 利亚德河 1159116161رود لیارد ליארד Лаярд لیارڈ دریا 利亚德河 6River Limpopo 5.0 6.0Limpopo Limpopo Q173017 نهر ليمبوبو লিম্পোপো নদী Limpopo Limpopo Limpopo Λιμπόπο लिम्पोपो नदी Limpopo Limpopo Limpopo リンポポ川 림포포강 Limpopo Limpopo Limpopo Лимпопо Limpopo Limpopo Limpopo 林波波河 1159117383رود لیمپوپو לימפופו Лімпопо دریائے لیمپوپو 林波波河 6River Lom 5.0 6.0Lom Lom Q23672111 لوم লোম Lom Lom Lom Λομ लोम Lom Lom Lom ロム川 롬 Lom Lom Lom река Лом Lom Lom Sông Lom 洛姆河 1159116499لوم לום Лом لوم 洛姆河 5River Lower Tunguska 4.7Nizhnyaya Tunguska 5.7Nizhnyaya Tunguska Lower Tunguska Q26428 تونجوسكا লোয়ার তুঙ্গুস্কা Untere Tunguska Tunguska Inferior Toungouska Inférieure Κάτω Τουνγκούσκα लोअर तुंगुस्का Alsó-Tunguszka Tunguska Bawah Tunguska Inferiore ニジニャヤ・ツングースカ川 니즈냐야퉁구스카강 Beneden-Toengoeska Dolna Tunguzka Tunguska Inferior Нижняя Тунгуска Nedre Tunguska Aşağı Tunguska Nizhnyaya Tunguska 下通古斯河 1159113367رود نیژنیایا تونگوسکا טונגוסקה תחתונה Нижня Тунгуска لوئر ٹنگوسکا 下通古斯河 2River Lualaba 2.1 3.1Lualaba Lualaba Q836812 لوالابا লুয়ালাবা নদী Lualaba Lualaba Lualaba Λουαλάμπα लुअलाबा नदी Lualaba Lualaba Lualaba ルアラバ川 루알라바 Lualaba Lualaba Lualaba Луалаба Lualaba Lualaba Lualaba 卢阿拉巴河 1159120477لوالابا לואלבה Луалаба لوالابا 盧阿拉巴河 2River Lualaba 2.1Congo 3.1Lualaba Lualaba Q836812 لوالابا লুয়ালাবা নদী Lualaba Lualaba Lualaba Λουαλάμπα लुअलाबा नदी Lualaba Lualaba Lualaba ルアラバ川 루알라바 Lualaba Lualaba Lualaba Луалаба Lualaba Lualaba Lualaba 卢阿拉巴河 1159120477لوالابا לואלבה Луалаба لوالابا 盧阿拉巴河 2River Mackenzie 2.1 3.1Mackenzie Mackenzie Q3411 نهر ماكينزي ম্যাকেঞ্জি নদী Mackenzie Mackenzie fleuve Mackenzie Ποταμός Μακένζι मैकेन्ज़ी नदी Mackenzie Mackenzie Mackenzie マッケンジー川 매켄지강 Mackenzie Mackenzie Mackenzie Маккензи Mackenziefloden Mackenzie Mackenzie 馬更些河 1159117661رود مکنزی מקנזי Макензі میکینزی 馬更些河 3River Madeira 3.0 4.0Madeira Madeira Q118251 نهر ماديرا মাদেইরা নদী Madeira Madeira Madeira Μαδέιρα मादेइरा Madeira Madeira Madeira マデイラ川 마데이라강 Madeira Madeira Madeira Мадейра Madeira Madeira Madeira 玛代拉河 1159128601رود مادیرا מדיירה Мадейра ماڈیرہ 瑪代拉河 1River Madison 2.0 3.0Madison Madison Q947477 ماديسون ম্যাডিসন Madison Madison Madison Μάντισον मैडिसन Madison Madison Madison マディソン川 매디슨강 Madison Madison Madison Мадисон Madison Madison Sông Madison 麦迪逊河 1159127611مادیسون מדונה Медісон میڈیسن 麥迪遜河 6River Madre de Dios 5.0 6.0Madre de Dios Madre de Dios Q849693 مادر دي ديوس মাদ্রে দে দিওস Madre de Dios Madre de Dios Madre de Dios Ποταμός Μάδρε δε Δίος माद्रे द डायओस Madre de Dios Madre de Dios Madre de Dios マドレ・デ・ディオス川 마드레 드 디오스 Madre de Dios Madre de Dios Madre de Deus Мадре-де-Дьос Madre de Dios Madre de Dios Madre de Dios 馬德雷德迪奧斯河 1159116415رود مادره د دیوس מדרה דה דיוס Мадре-де-Дьйос مادرے ڈی ڈائوس 馬德雷德迪奧斯河 4River Magdalena 4.0 5.0Magdalena Magdalena Q191829 نهر ماجدالينا মাগদালেনা নদী Magdalena Magdalena Magdalena Μαγδαλένα मग्देलेना नदी Magdalena Magdalena Magdalena マグダレナ川 마그달레나강 Magdalena Magdalena Magdalena Магдалена Magdalenafloden Magdalena Magdalena 马格达莱纳河 1159112139رود ماگدالنا נהר מגדלנה Магдалена دریائے مگدالینا 馬格達萊納河 6River Mahäna Nadï 5.0 6.0Mahäna Nadï مهانا نادي মাহানা নাদি Mahäna Nadï Mahäna Nadï Mahana River Μαχάντα Νάντι महाना नदी Mahäna Nadï Mahanadi Mahäna Nadï マハナ川 마하나 나디 Mahanadi Mahäna Nadï Mahäna Nadï Маханади Mahäna Nadï Mahäna Nadï Sông Mahäna Nadï 默哈讷迪河 1159115803ماهانا نادی מאהאנווארה Махана-Наді ماہانا ندی 馬哈納河 4River Malyy Yenisey 4.0 5.0Little Yenisei Q1511505 نهر ينيسي الصغير মাল্য ইয়েন্সেই Kleiner Jenissei Mali Yeniséi Petit Ienisseï Μαλίι Γένισει माली येनिसे Kis-Jenyiszej Malyy Yenisey Malyj Enisej カー=ヘム川 말리 예니시 Little Yenisei Mały Jenisej Pequeno Ienissei Малый Енисей Malyy Jenisej Küçük Yenisey Enisei Nhỏ 小葉尼塞伊河 1159112411مالی ینیسی ממבראמו Малий Єнісей مالی یینیسی 小葉尼塞伊河 6River Mamberamo 5.0 6.0Mamberamo Mamberamo Q726986 نهر مامبيرامو মাম্বেরামো Mamberamo Mamberamo Mamberamo Μαμπεράμο मम्बरमो Mamberamo Mamberamo Mamberamo マンベラモ川 맘베라모 Mamberamo Mamberamo Mamberamo Мамберамо Mamberamo Mamberamo Sông Mamberamo 曼伯拉莫河 1159117517مامبرامو מאמברה-קאדיי Мамберамо میمبرامو 曼伯拉莫河 3River Mamoré 3.0 4.0Mamoré Mamoré Q117615 نهر ماموري মামোরে নদী Mamoré Mamoré Mamoré Μαμόρε ममोर Mamoré Mamore Mamoré マモレ川 마모레 Mamore Mamoré Mamoré Маморе Mamoréfloden Mamoré Mamoré 马莫雷河 1159128327رود ماموره ממורה Маморе مامورے 馬莫雷河 6River Mananantanana 5.0 6.0Mananantanana مانانانتانا মানানানতানানা Mananantanana Mananantanana Mananantanana Μαναναντανάνα मननंतनाना Mananantanana Mananantanana Mananantanana マナナンタナナ川 마나난타나나 Mananantanana Mananantanana Mananantanana гора Мананантанана Mananantanana Mananantanana Sông Mananantanana 曼南塔纳河 1159116551مانانانتانانا מאנאוואטו Мананантанана مانانانتانانا 馬納納塔納納河 6River Mangoky 5.0 6.0Mangoky Mangoky Q1288223 مانجوكي ম্যাংগোকি Mangoky Mangoky Mangoky Μανγκόκι मंगोक्य नदी Mangoky Mangoky Mangoky マンゴキ川 망고키 Mangoky Mangoky Mangoky Мангоки Mangoky Mangoky Sông Mangoky 曼戈基河 1159117429مانگوکی מאניה Мангоку مانگوکی 曼戈基河 2River Maquan 2.1Damqogkanbab 3.1Damqogkanbab ماكان মাকুয়ান Maquan Río Maquan Maquan Μακουάν माक्वान Maquan Maquan Maquan マクアン川 마쿠안 Maquan Maquan Maquan река Макуан Maquan Maquan Sông Mã Tuyền 马泉河 1159117059ماکوان אגם צ'יקיטה Макван میکوان 馬匡河 5River Marañón 4.7 5.7Marañón Marañón Q200174 نهر مارانيون মারানিয়োন নদী Marañón Marañón Marañón Μαρανιόν मारानोन Marañón Marañón Marañón マラニョン川 마라논 Marañón Marañón Marañón Мараньон Marañón Marañón Marañón 马拉尼翁河 1159113397رود مارانیون מרניון Мараньйон میرانون 馬拉尼翁河 2River Mekong 2.1 3.1Mekong Mekong Q41179 نهر ميكونغ মেকং নদী Mekong Mekong Mékong Μεκόνγκ मीकांग नदी Mekong Mekong Mekong メコン川 메콩강 Mekong Mekong Mekong Меконг Mekong Mekong Mê Kông 湄公河 1159121023مکونگ מקונג Меконг دریائے میکانگ 湄公河 6River Mendoza 5.0 6.0Mendoza Mendoza Q2363673 ميندوزا মেন্ডোসা Mendoza Mendoza Mendoza Μεντόζα मेंडोज़ा Mendoza Mendoza Mendoza メンドーサ川 멘도자 Mendoza Mendoza Mendoza Мендоса Mendoza Mendoza Sông Mendoza 门多萨河 1159116265رود مندوزا מנגש Мендоса مینڈوزا 門多薩河 6River Meta 5.0 6.0Meta Meta Q655251 ميتا মেতা Meta Meta Meta Μετα मेता नदी Meta Meta Meta メタ川 메타강 Meta Meta Meta Мета Meta Meta Irmağı Sông Meta 梅塔河 1159116389مِتا מטה אינקוגניטה Мета میٹا 梅塔河 6River Min 5.0 6.0Min Min Q729269 نهر مين মিন নদী Min Min Min Ελάχ मिन Min Min Min 岷江 민강 Min Min Min Миньцзян Min Min Irmağı Dân 岷江 1159118115مین מין Міньцзян من 岷江 1River Mississippi 2.0 3.0Mississippi Mississippi Q1497 نهر المسيسيبي মিসিসিপি নদী Mississippi Misisipi Mississippi Ποταμός Μισσισσιππής मिसिसिप्पी नदी Mississippi Mississippi Mississippi ミシシッピ川 미시시피강 Mississippi Missisipi Mississípi Миссисипи Mississippifloden Mississippi Mississippi 密西西比河 1159119147رودخانه میسیسیپی מיסיסיפי Міссісіпі دریائے مسیسپی 密西西比河 1River Missouri 2.0 3.0Missouri Missouri Q5419 نهر ميزوري মিসৌরি নদী Missouri Misuri Missouri Μιζούρι मिसोरी नदी Missouri Missouri Missouri ミズーリ川 미주리강 Missouri Missouri Missouri Миссури Missourifloden Missouri Missouri 密蘇里河 1159128481رودخانه میزوری מיזורי Міссурі دریائے مسوری 密蘇里河 6River Mitchell 5.0 6.0Mitchell Mitchell Q1939518 Mitchell Mitchell Mitchell ミッチェル川 Mitchell Mitchell 1159116943 5River Mouhoun 4.7Black Volta 5.7Black Volta Mouhoun Q1256528 الفولتا الأسود মৌহোউন Schwarzer Volta Volta Negro Volta Noire Μουχούν मौहौन Mouhoun Mouhoun Volta Nero 黒ヴォルタ 무운 Zwarte Volta Wolta Czarna Volta Negro Чёрная Вольта Mouhoun Siyah Volta Sông Mouhoun 黑沃尔特河 1159113257ولتای سیاه מולויה Чорна Вольта موہون 黑沃爾特河 3River Murray 3.0 4.0Murray Murray Q183078 نهر موراي মারি নদী Murray Murray Murray Ποταμός Μάρρεϋ मर्रे नदी Murray Murray Murray マレー川 머리강 Murray Murray Murray Муррей Murray Murray Murray 墨累河 1159122485مورای מארי Муррей دریائے مرے 美利河 6River North Fork Kuskokwim 5.0 6.0North Fork Kuskokwim River N. Fork Kuskokwim Q3344120 نورث فورك كوسكوكويم নর্থ ফর্ক কুস্ককুইম North Fork Kuskokwim R Rama norte del río Kuskok North Fork Kuskokwim Νορθ Φορκ Κουσκόκβιμ उत्तर कांटा कुस्कोकविम Kuskokwim északi ág North Fork Kuskokwim North Fork Kuskokwim ノース・フォーク・カスコクウィム川 노스 포크 커스코큄 North Fork Kuskokwi North Fork Kuskokwim Confluência norte do Kuskok река Северный Кускокуим North Fork Kuskokwim Kuzey Fork Kuskokwim Sông North Fork Kuskok 北福克库斯科维姆河 1159114543نورت فورک کوسکوکویم נורת' פורק קוסקוֹ-ווים Норт-Форк-Кускоквім ناتھ فورک کسکوویم 北福卡斯科奎母河 6River Nakanbé 5.0White Volta 6.0White Volta Nakanbé Q1259188 ناكانبي নাকানবে Weißer Volta Volta Blanco Volta Blanche Νακανμπέ नाकनबे Nakanbé Nakanbe Volta Bianco 白ヴォルタ 나칸베 Witte Volta Wolta Biała Volta Branco Белая Вольта Nakambe Beyaz Volta Sông Nakanbé 白沃尔特河 1159115619ناکانبه נקאסֶקֶה Наканбе ناکانمبی 白沃爾特河 4River Nanpan 4.0 5.0Nanpan Nanpan Q1569231 نانبان নানপান Nanpan Nanpan Nanpan Νανπάν नानपन Nanpan Nanpan Nanpan 南盤江 난판 Nanpan Nanpan Nanpan Наньпаньцзян Nanpan Nanpan Nam Bàn 南盘江 1159112165نانپان נאנפאן Нанпан نانپان 南盤江 6River Narmada 5.0 6.0Narmada Narmada Q234004 نارمادا নর্মদা নদী Narmada Narmada Narmadâ Ναμαδής नर्मदा नदी Narmada Narmada Narmada ナルマダー川 나르마다강 Narmada Narmada Narmada Нармада Narmada Narmada Narmada 讷尔默达河 1159116821نرمدا נרמאדה Нармада دریائے نرمدا 訥爾默達河 5River Naryn 4.7 5.7Naryn Naryn Q651195 نارين নারিন Naryn Naryn Naryn Νάριν नारीन नदी Narin Naryn Naryn ナルイン川 나린강 Naryn Naryn Naryn Нарын Naryn Narın Naryn 纳伦河 1159113129رود نارین נרין Нарин نارائن 納倫河 4River Nederrijn 4.0 5.0Nederrijn Nederrijn Q1152951 نيديرراين নেদেরিজিন Nederrijn Nederrijn Rhin inférieur Νέντερραϊν नेदेर्र्जिन Nederrijn Nederrijn Nederrijn ネーデルライン川 네데린 Nederrijn Dolny Ren Reno Baixo Недеррейн Nederrijn Nederrijn Sông Nederrijn 荷兰莱茵河 1159112369ندرجین נֶדֶריאין Недеррейн نیدرجن 荷蘭萊茵河 3River Negro 3.0 4.0Negro Negro Q118771 نهر نجرو রিউ নেগ্রু Negro Negro Negro Ρίο Νέγκρο रियो नीग्रो Negro Negro Negro ネグロ川 네그루강 Negro Negro Negro Риу-Негру Negro Negro Negro 内格罗河 1159127465ریو نگرو ריו נגרו Ріу-Неґру ریو نیگرو 內格羅河 6River Nelson 5.0 6.0Nelson Nelson Q3292 نيلسون নেলসন নদী Nelson Nelson fleuve Nelson Ποταμός Νέλσον नेल्सन Nelson Nelson Nelson ネルソン川 넬슨강 Nelson Nelson Nelson Нельсон Nelsonfloden Nelson Nelson 納爾遜河 1159115909رود نلسون נהר נלסון Нельсон نیلسن 納爾遜河 4River Neuquén 4.0 5.0Neuquén Neuquén Q1472009 نيوكوين নেউকুয়েন Neuquén Neuquén Neuquén Νεουκουέν न्यूक्वेनो Neuquén Neuquén Neuquén ネウケン川 네우켄 Neuquén Neuquén Neuquén Неукен Neuquén Neuquén Sông Neuquén 內烏肯河 1159112149نئوکوئن נאוקן Неукен نیقوئین 內烏肯河 5River Neva 4.7 5.7Neva Neva Q645 نهر نيفا নেভা নদী Newa Nevá Neva Νέβας नेवा नदी Néva Neva Neva ネヴァ川 네바강 Neva Newa Neva Нева Neva Neva Neva 涅瓦河 1159113025رود نوا נייבה Нева نیوا 涅瓦河 3River Niagara 3.0 4.0Niagara Niagara Q182343 نياجارا নায়াগ্রা নদী Niagara Niágara Niagara Νιαγάρας नियागरा Niagara Niagara Niagara ナイアガラ川 나이아가라강 Niagara Niagara Niágara Ниагара Niagarafloden Niagara Niagara 尼亚加拉河 1159128401رود نیاگارا נהר ניאגרה Ніагара نیاگرا 尼亞加拉河 3River Niger 3.0 4.0Niger Niger Q3542 نهر النيجر নাইজার নদী Niger Níger Niger Νίγηρας ποταμός नाइजर नदी Niger Niger Niger ニジェール川 나이저강 Niger Niger Níger Нигер Niger Nijer Niger 尼日尔河 1159123305رودخانه نیجر ניז'ר Нігер دریائے نائجر 尼日河 1River Nile 2.0 3.0Nile Nile Q3392 نهر النيل নীলনদ Nil Nilo Nil Νείλος नील नदी Nílus Nil Nilo ナイル川 나일강 Nijl Nil Nilo Нил Nilen Nil Nin 尼罗河 1159121589نیل נילוס Ніл دریائے نیل 尼羅河 2River N'Mai 3.0 4.0Derung-Nmai N'Mai Q3334104 نماي এনমেই N'Mai Hka N'Mai N'Mai N'Mάι एन'माय N'Mai N'Mai N'Mai ンマイ川 은마이 N'Mai N'Mai N'Mai река Ньмаи Nmai Hka N'Mai Sông N'Mai 独龙江-恩梅江 1159112125مِی شمالی נ'מאי Нмаї اینمائی 独龙江-恩梅江 4River North Saskatchewan 4.0 5.0North Saskatchewan North Saskatchewan Q2237 شمال ساسكاتشوان নর্থ সাস্কাচেওয়ান North Saskatchewan Saskatchewan Norte Saskatchewan Nord Βόρειο Σασκατσουάν उत्तर सस्केचेवान North Saskatchewan North Saskatchewan North Saskatchewan ノースサスカチュワン川 노스서스캐처원강 North Saskatchewan Saskatchewan Północny North Saskatchewan Норт-Саскачеван North Saskatchewan Kuzey Saskatchewan Sông North Saskatchewa 北萨斯喀彻温河 1159112013رود ساسکاچوان شمالی נהר ססקצ'ואן הצפוני Північний Саскачеван نارتھ ساسکاچیوان 北沙斯克寸旺河 4River Nu 4.0 5.0Salween Nu Q26422 نهر سالوين সালউইন নদী Saluen Salween Salouen Νου सालवीन नदी Nu Salween Saluen サルウィン川 살윈강 Salween Saluin Salween Салуин Salween Saluen Thanlwin 怒江 1159112449سالوین נהר הסלווין Салуїн نو 怒江 4River Nu 4.0Salween 5.0Salween Nu Q26422 نهر سالوين সালউইন নদী Saluen Salween Salouen Νου सालवीन नदी Nu Salween Saluen サルウィン川 살윈강 Salween Saluin Salween Салуин Salween Saluen Thanlwin 怒江 1159112449سالوین נהר הסלווין Салуїн نو 怒江 4River Ob 4.0 5.0Ob Ob Q973 أوبي ওব নদী Ob Obi Ob Ομπ ओब नदी Ob Ob Ob' オビ川 오비강 Ob Ob Ob Обь Ob Obi Obi 鄂畢河 1159111937رود اب אוב Об اوب 鄂畢河 4River Ob 4.0 5.0Ob Ob Q973 أوبي ওব নদী Ob Obi Ob Ομπ ओब नदी Ob Ob Ob' オビ川 오비강 Ob Ob Ob Обь Ob Obi Obi 鄂畢河 1159111937رود اب אוב Об اوب 鄂畢河 2River Ob 2.1 3.1Ob Ob Q973 أوبي ওব নদী Ob Obi Ob Ομπ ओब नदी Ob Ob Ob' オビ川 오비강 Ob Ob Ob Обь Ob Obi Obi 鄂畢河 1159114911رود اب אוב Об اوب 鄂畢河 4River Oder 4.0 5.0Oder Oder Q552 أودر ওডার নদী Oder Óder Oder Όντερ ओडर नदी Odera Oder Oder オーデル川 오데르강 Oder Odra Oder Одра Oder Oder Oder 奧得河 1159112201اودر אודר Одра اوڈر 奧得河 3River Ohio 3.0 4.0Ohio Ohio Q4915 نهر أوهايو ওহাইও নদী Ohio Ohio Ohio Ποταμός Οχάιο ओहायो Ohio Ohio Ohio オハイオ川 오하이오강 Ohio Ohio Ohio Огайо Ohiofloden Ohio Ohio 俄亥俄河 1159128673رودخانه اوهایو אוהיו Огайо دریائے اوہائیو 俄亥俄河 6River Okavango 5.0 6.0Okavango Okavango Q188773 نهر أوكافانغو ওকাভাঙ্গো Okavango Okavango Okavango Οκαβάνγκο ओकावंगो नदी Okavango Okavango Okavango オカヴァンゴ川 오카방고강 Okavango Okawango Cubango Окаванго Okavango Okavango Okavango 奥卡万戈河 1159114093رود اوکاوانگو נהר האוקוונגו Окаванґо اوکاوانگو 奧卡萬戈河 1River Olenekskaya Protoka 2.0 3.0Olenekskaya Protoka أولينيسكايا بروتوكا ওলেনেকস্কায়া প্রোতোকা Protoka Olenëkskaya Olenekskaya Protoka Olenekskaya Protoka Ολένσκαγια Πρότοκα ओलेनेक्सकाया प्रोटोका Olenekskaya Protoka Olenekskaya Protoka Olenekskaya Protoka オレネクスカヤ・プロトカ川 올레넥스카야 프로토카 Olenekskaya Ujście Olenekskaja Canal Olenëkskay река Оленекская протока Olenekskaja Protoka Olenekskaya Protoka Sông Olenekskaya Proto 奥列尼克斯卡亚河 1159114387اولنکسکایا پروتوکا אולנקסקאיה פרוטוקה Оленекська протока اولینیکسکایا پروٹوکا 奧列尼斯卡亞·普托卡河 6River Olenëk 5.0 6.0Olenyok Olenëk Q26799 أولينيك ওলেংক Olenjok Oleniok Oleniok Ολένκ ओलेनेक Olenyok Olenëk Olenëk オレニョーク川 올레넥 Olenjok Oleniok Olenyok Оленёк Olenek Olenëk Olenyok 奧列尼奧克河 1159117003رود اولنیوک אולנק Оленьок اولینیک 奧列尼奧克河 6River Omo 5.0 6.0Omo Omo Q273456 نهر أومو ওমো Omo Valle bajo del Omo Omo Όμο ओमो की निचली घाटी Omo Omo Omo オモ川 오모강 Omo Omo Omo Омо Omo Omo Thung lũng thấp Omo 奥莫河 1159116533رودخانه اومو אומו Омо اومو 奧莫河 4River Orange 4.0 5.0Orange Orange Q181475 نهر أورانج অরেঞ্জ নদী Oranje Orange Orange Οράγγης आरेंज नदी Oranje Orange Orange オレンジ川 오렌지강 Oranjerivier Oranje Orange Оранжевая Oranjefloden Turuncu Nehir Orange 奥兰治河 1159129067رودخانه نارنجی אורנג' Оранжева اورنج 奧蘭治河 6River Ord 5.0 6.0Ord Ord Q2028742 نهر الأورد ওর্দ Ord Ord Ord Ορντ ऑर्ड Ord Ord Ord オード川 오드 Ord Ord Ord Орд Ord Ord Sông Ord 奥德河 1159115199اورد אורד Орд اورد 奧德河 3River Orinoco 3.0 4.0Orinoco Orinoco Q131792 نهر أورينوكو অরিনোকো নদী Orinoco Orinoco Orénoque Ορινόκο ओरिनोको नदी Orinoco Orinoko Orinoco オリノコ川 오리노코강 Orinoco Orinoko Orinoco Ориноко Orinoco Orinoco Orinoco 奥里诺科河 1159127013رود اورینوکو אורינוקו Оріноко اورینوکو 奧里諾科河 6River Ottawa 5.0 6.0Ottawa Ottawa Q60974 نهر أوتاوا অটোয়া Ottawa Fluss Ottawa Outaouais Οτάβα ओटावा नदी Ottawa Ottawa Ottawa オタワ川 오타와강 Ottawa Ottawa Ottawa Оттава Ottawafloden Ottawa Ottawa 渥太華河 1159113867رود اتاوا אוטווה Оттава اوٹاوا 渥太華河 6River Ouham 5.0 6.0Ouham Ouham Q2001150 أوهام ওউহ্যাম Ouham Sara Bahr Sara Ουχάμ ऑउहम Ouham Ouham Ouham ウハム川 오함 Ouham Ouham Ouham река Уам Sara Ouham Sông Ouham 瓦姆河 1159116569اوهام אוהאם Оухам اوہام 瓦姆河 5River Pamir 4.7 5.7Pamir Pamir Q8550 بامير পামির Pamir Pamir Pamir Παμίρ पामीर नदी Pamir Pamir Pamir パミール川 파미르 Pamir Pamir Pamir Памир Pomir Pamir Sông Pamir 帕米尔河 1159113449رود پامیر פמיר Памір پامیر 帕米爾河 6River Panama Canal 5.0 6.0Panama Canal Panama Canal Q7350 قناة بنما পানামা খাল Panamakanal Canal de Panamá canal de Panama Διώρυγα Παναμά पनामा नहर Panama-csatorna Terusan Panama Panama パナマ運河 파나마 운하 Panamakanaal Kanał Panamski Canal do Panamá Панамский канал Panamakanalen Panama Kanalı Kênh đào Panama 巴拿馬運河 1159114297آبراه پاناما תעלת פנמה Панамський канал نہر پاناما 巴拿馬運河 5River Panj 4.7 5.7Panj Panj Q8542 بنج পঞ্জ নদী Pandsch Panj Piandj Παντζ पंज नदी Panj Panj Panj パンジ川 판지강 Pandj Pandż Panj Пяндж Pjandsj Panj Panj 噴赤河 1159113607رود پنج פאנג' Пяндж دریائے پنج 噴赤河 6River Paraiba 5.0 6.0Paraiba بارايبا পারাইবা Paraíba do Sul Paraiba Paraíba Παραϊμπα पारैबा Paraiba Paraiba Paraiba パライバ川 파라이바 Paraíba Paraiba Paraíba река Параиба Paraiba Paraiba Sông Paraiba 帕拉伊巴河 1159116437پارائیبا פאראיבה Парайба پاریبا 帕萊巴河 4River Paranaíba 4.0 5.0Paranaíba Paranaíba Q776155 نهر بارانَيبا পারানাইবা Paranaíba Paranaíba Paranaíba Παραναΐμπα परानाइबा Paranaíba Paranaíba Paranaíba パラナイバ川 파라나이바 Paranaíba Paranaiba Paranaíba Паранаиба Paranaíba Paranaíba Sông Paranaíba 巴拉那伊巴河 1159110899پارانائیبا פארנאיבה Паранайба پارانیبا 巴拉那伊巴河 2River Paraná 2.1 3.1Paraná River Paraná Q21847787 بارانا পারানা Río Paraná Paraná Paraná Παρανά पराना Paraná Parana Paraná パラナ川 파라나 Parana Paraná Paraná река Парана Parana Paraná Sông Paraná 巴拉那河 1159118169پارانا פאראנה Парана پارانا 巴拉那河 2River Peace 2.1 3.1Peace Peace Q2220 بيس পীস Peace de la Paz Paix Πις पीस Peace Peace Peace ピース川 피스강 Peace Peace Peace Пис Peace Peace Peace 皮斯河 1159117465رود پیس נהר פיס Піс دریائے پیس 皮斯河 4River Pechora 4.0 5.0Pechora Pechora Q8168 نهر بيشورا পেচোরা নদী Petschora Pechora Petchora Πετσόρα पिकोरा Pecsora Pechora Pečora ペチョラ川 페초라강 Petsjora Peczora Pechora Печора Petjora Peçora Pechora 伯朝拉河 1159112087رود پیچورا פצ'ורה Печора پیچورا 伯朝拉河 6River Pend Oreille 5.0 6.0Pend Oreille Pend Orielle Q270499 بند أوريل পেন্দ ওরিয়েলে Pend Oreille Pend Oreille Pend Oreille Πεντ Οριέλ पेंड ओरिएल Pend Orielle Pend Orielle Pend d'Oreille ペンド・オレイル川 펜드 오리엘 Pend Oreille Pend Oreille Pend Oreille Панд-Орей Pend-d'Oreille Pend Orielle Sông Pend Orielle 庞多雷河 1159118153پند اوریل פנד אוריאל Пенд-Оріелле پینڈ اوایئل دریا 庞多雷河 6River Pilcomayo 5.0 6.0Pilcomayo River Pilcomayo Q21806688 بيلكومايو পিলকোমেয়ো Río Pilcomayo Pilcomayo Pilcomayo Πιλκογάγιο पिलकोमायो Pilcomayo Pilcomayo Pilcomayo ピルコマジョ川 필코마요 Pilcomayo Pilcomayo Pilcomayo река Пилькома́йо Pilcomayo Pilcomayo Sông Pilcomayo 皮科马约河 1159116483پیلکومایو פילקומאיו Пілкомайо پلکومایو 皮可馬約河 6River Pit 5.0 6.0Pit Pit Q1760800 بيت পিট Pit Pit Pit Πιτ पिट Pit Pit Pit ピット川 피트 Pit Pit Pit Пит Pit River Pit Sông Pit 皮特河 1159115835پیت פיט Піт دریائے پٹ 皮特湖 6River Po 5.0 6.0Po Po Q643 نهر بو পো নদী Po Po Pô Πάδος पो Pó Po Po ポー川 포강 Po Pad Pó По Po Po Po 波河 1159129663پو פו По دریائے پو 波河 6River Porcupine 5.0 6.0Porcupine Porcupine Q284603 بوركوبين পর্কুপাইন Porcupine Porcupine Porcupine Πόρκιουπάιν साही Porcupine Porcupine Porcupine ポーキュパイン川 포큐파인강 Porcupine Porcupine Porcupine Поркьюпайн Porcupine River Porcupine Sông Porcupine 豪猪河 1159114619پورکوپین פורקיופיין Поркупайн پورکیوپائن 豪豬河 6River Potomac 5.0 6.0Potomac Potomac Q179444 نهر بوتوماك পোটোম্যাক নদী Potomac Potomac Potomac Ποταμός Ποτόμακ पोटोमैक Potomac Potomac Potomac ポトマック川 포토맥강 Potomac Potomak Potomac Потомак Potomac Potomac Irmağı Potomac 波托马克河 1159118189رودخانه پوتوماک פוטומק Потомак دریائے پوٹومیک 波多馬克河 6River Purari 5.0 6.0Purari Purari Q1724008 بوراري পুরারি Purari Purari Purari Πουράρι पुरारी Purari Purari Purari プラリ川 푸라리 Purari Purari Purari Пурари Purari Purari Sông Purari 普拉里河 1159114027پوراری פורארי Пурарі پوراری 普拉里河 6River Purús 5.0 6.0Purus Purús Q26271 نهر بوروس পুরুস নদী Purus Purús Purus Πουρούς प्युरस Purus Purus Purus プルス川 푸루스강 Purus Purus Purus Пурус Purus Purús Purus 普魯斯河 1159116331رود پوروس פורוס Пурус پورس 普魯斯河 6River Pánuco 5.0 6.0Pánuco Pánuco Q1893265 بانوكو পানুকো Pánuco Pánuco1 Pánuco Πάνουκο पैन्यूको Pánuco Panuco Panuco パヌコ川 파누코 Pánuco Pánuco Pánuco река Пануко Pánuco Pánuco Sông Pánuco 帕努科河 1159117595پانوکو פאנוקו Пануко پانوکو 帕努科河 4River Quan 4.0 5.0Qianjiang Quan Q2509519 كوان কোউয়ান Quan River Quan Qian Κουάν क्वानो Quan Quan Quan 泉川 콴 Quan Quan Quan Цяньцзян Qianjiang Qu Quan Kiềm 黔江 1159112477کوان קוואן Кван قوان 黔江 6River R. des Outaouais 5.0 6.0R. des Outaouais نهر أوتاوا এর. দেস আউতাওউয়াইস Ottawa (Fluss) Río Outaouais Rivière des Outaouais Ρ. ντε Ουαταουέ आर. डेस आउटौइस R. des Outaouais Sungai Ottawa Fiume Ottawa ウタウエ川 데스 아우타우아이스 Ottawa (rivier) Rzeka Ottawa Rio Otava река Резервуар-Десель Rivière des Outaouais R. des Outaouais Sông Ottawa 奥托埃斯河 1159113823رودخانه اوتاوایس דס אוּטָאוֶוה Утауа آر دیس آؤٹوایس 庫陶烏艾斯河 6River Rainy 5.0 6.0Rainy Rainy Q2128582 رايني রেইনি Rainy Rainy Pluie Ρέινι रेनी Rainy Rainy Rainy レイニー川 레이니 Rainy Rainy Rainy Рейни Rainy Rainy Sông Rainy 雷尼河 1159115457رینی הנהר הגשום Рейні رینی 雷尼河 4River Rhein 4.0 5.0Rhine Rhein Q584 راين রাইন নদী Rhein Rin Rhin Ρήνος राइन नदी Rajna Rhein Reno ライン川 라인강 Rijn Ren Reno Рейн Rhen Ren Rhine 莱茵河 1159110403راین ריין Рейн دریائے رائن 莱茵河 4River Rhin 4.0Rhein 5.0Rhine Rhin Q584 راين রাইন নদী Rhein Rin Rhin Ρήνος राइन नदी Rajna Rhein Reno ライン川 라인강 Rijn Ren Reno Рейн Rhen Ren Rhine 莱茵河 1159112359راین ריין Рейн دریائے رائن 莱茵河 4River Rhine 4.0 5.0Rhine Rhine Q584 راين রাইন নদী Rhein Rin Rhin Ρήνος राइन नदी Rajna Rhein Reno ライン川 라인강 Rijn Ren Reno Рейн Rhen Ren Rhine 莱茵河 1159112519راین ריין Рейн دریائے رائن 莱茵河 6River Rhône 5.0 6.0Rhône Rhône Q602 نهر الرون রোন Rhone Ródano Rhône Ροδανός रोन नदी Rhône Rhone Rodano ローヌ川 론강 Rhône Rodan Ródano Рона Rhône Rhône Rhone 罗讷河 1159115107رون רון Рона دریائے رون 罗讷河 4River Rio Grande 4.0 5.0Grande Rio Grande Q160636 ريو غراندي রিও গ্রান্দে Grande Bravo Grande Ρίο Γκράντε रियो ग्रांडे Grande Grande Grande リオ・グランデ川 리오그란데강 Grande Grande Grande Рио-Гранде Grande Grande Grande 格兰德河 1159111317رودخانه ریوگرانده ריו גראנדה Ріо-Ґранде ریو گرانڈے 格蘭德河 1River Rosetta Branch 2.0 3.0Rosetta Branch فرع رشيد রোজেটা ব্রাঞ্চ Rosetta Branch Ramal Rosetta Rosetta Branch Παρακλάδι Ροζέτα रोज़ेटा ब्रांच Rosetta Ág Anak Sungai Rosetta Ramo di Rosetta ロゼッタ・ブランチ川 로제타 브랜치 Rosetta-tak Ramię Rosetta Canal de Roseta Rosetta Rosetta Kolu Nhánh Rosetta 罗塞塔支流 1159113693شاخه روزتا סניף רוזטה Розетта-Бранч روزیٹہ برانچ 羅塞塔支流 6River Ruki 5.0 6.0Tshuapa Ruki Q2635327 روكي রুকি Ruki (Fluss) Ruki Tshwapa Ρούκι रुकी Ruki Ruki Tshuapa ツアパ川 루키 Tshuapa Tshuapa Ruki Чуапа Tshuapa Ruki Tshuapa 楚阿帕河 1159118079روکی רוקי Рукі روکیل 楚阿帕河 6River Rupert 5.0 6.0Rupert Rupert Q427437 روبرت রুপার্ট Rupert Rupert Rupert Ρούπερτ रूपर्ट Rupert Rupert Rupert ルパート川 루퍼트 Rupert Rupert Rupert Руперт Rupert Rupert Sông Rupert 鲁珀特河 1159114845روپرت רופרט Руперт روپرٹ 魯伯特 6River Ruvuma 5.0 6.0Ruvuma Ruvuma Q746779 نهر روفوما রুভুমা Rovuma Rovuma Ruvuma Ποταμός Ρουβούμα रुवुमा नदी Ruvuma Ruvuma Ruvuma ルブマ川 루부마 Ruvuma Rovuma Rovuma Рувума Ruvuma Ruvuma Sông Ruvuma 鲁伏马河 1159116689رود روووما רובומה Рувума رووما 魯伏馬河 6River Río Grande de Santiago 5.0 6.0Grande de Santiago Río Grande de Santiago Q2302661 ريو غراندي دي سانتياغو রিও গ্রান্দে দে সান্তিয়াগো Grande de Santiago Grande de Santiago Santiago Ρίο Γκράντε ντε Σαντιάγκο रियो ग्रांडे डी सैंटियागो Río Grande de Santiago Sungai Grande de Santiago Río Grande de Santiago グランデ・デ・サンティアゴ川 리오 그란데 데 산티아고 Grande de Santiago Grande de Santiago Grande de Santiago Рио-Гранде-де-Сантьяго Río Grande de Santiago Río Grande de Santiago Sông Santiago 大聖地亞哥河 1159114499ریو گرانده د سانتیاگو ריו גרנדה דה סנטיאגו Ріо-Гранде-де-Сантьяго ریو گرانڈے ڈی سانتیاگو 大聖地亞哥河 6River S. Branch Potomac 5.0 6.0Potomac Q179444 نهر بوتوماك পোটোম্যাক নদী Potomac Potomac Potomac Ποταμός Ποτόμακ एस. ब्रांच पोटोमैक Potomac Potomac Potomac ポトマック川 포토맥강 Potomac Potomak Potomac Потомак Potomac Potomac Irmağı Potomac 波托马克河 1159117169رودخانه پوتوماک פוטומק Потомак دریائے پوٹومیک 波多馬克河 5River Sacramento 4.7 5.7Sacramento Sacramento Q335575 ساكرمينتو স্যাক্রামেন্টো Sacramento Sacramento Sacramento Σακραμέντο सैक्रामेंटो Sacramento Sacramento Sacramento サクラメント川 새크라멘토강 Sacramento Sacramento Sacramento Сакраменто Sacramento Sacramento Sacramento 萨克拉门托河 1159112993رودخانه ساکرامنتو סקרמנטו Сакраменто دریائے سکرامنٹو 沙加缅度河 6River Saint John 5.0 6.0Saint John Saint John Q607546 سان جون সেন্ট জন Saint John San Juan fleuve Saint-Jean Σέιντ Τζον सेंट जॉन Saint John Saint John Saint John セントジョン川 세인트 존 Saint John Saint John Saint John Сент-Джон Saint John-floden Saint John Sông Saint John 圣约翰河 1159117217سنت جان סנט ג'ון Сент-Джон سینٹ جان 聖約翰河 6River Salado 5.0 6.0Salado Salado Q1162365 سالادو সালাদো Salado Salado Salado del Norte Σαλάδο सलादो Salado Salado Salado del Norte サラド川 살라도 Salado Salado Salado Рио-Саладо Salado Salado Salado 萨拉多河 1159116289سالادو סאלאדו Ріо-Саладо سالادو 薩拉多河 4River Salween 4.0 5.0Salween Salween Q26422 نهر سالوين সালউইন নদী Saluen Salween Salouen Σάλγουιν सालवीन नदी Salween Salween Saluen サルウィン川 살윈강 Salween Saluin Salween Салуин Salween Saluen Thanlwin 怒江 1159112557سالوین נהר הסלווין Салуїн سالوین 怒江 6River San Joaquin 5.0 6.0San Joaquin San Joaquin Q751347 سان هواكوين সান জোয়াকুইন San Joaquin San Joaquín San Joaquin Σαν Χοακίν सैन जोकिन San Joaquin San Joaquin San Joaquin サン・ワーキン川 샌와킨강 San Joaquin San Joaquin San Joaquin Сан-Хоакин San Joaquin River San Joaquin San Joaquin 圣华金河 1159114891رودخانه سن ژاکویین סן חואקין Сан-Хоакін دریائے سان جوکن 圣华金河 5River San Juan 4.7 5.7San Juan San Juan Q1161204 نهر سان خوان সান জুয়ান San Juan San Juan San Juan Σαν Χουάν सैन जुआन San Juan San Juan San Juan サン・フアン川 산 후안 San Juan San Juan San Juan Сан-Хуан San Juan San Juan San Juan 圣胡安河 1159112711سان جوئان סן חואן Сан-Хуан دریائے سان خوآن 聖胡安河 6River Sanaga 5.0 6.0Sanaga Sanaga Q1250532 ساناجا সানাগা Sanaga Sanaga Sanaga Σανάγκα सनागा Sanaga Sanaga Sanaga サナガ川 사나가 Sanaga Sanaga Sanagá Санага Sanaga Sanaga Sông Sanaga 薩納加河 1159117935ساناگا סאנגה Санага ساناگا 薩納加河 6River Sangha 5.0 6.0Sangha Sangha Q239883 سانغا সংঘ Sangha Sangha Sangha Σάνγκα संघा Sangha Sangha Sangha サンガ川 상하 Sangha Sangha Sangha Санга Sangha Sangha Sông Sangha 桑加河 1159118069سانگها סנגהה Сангха سانگھا 桑加河 5River Santa Cruz 4.7 5.7Santa Cruz Santa Cruz Q1478566 نهر سانتا كروز সান্তা ক্রুজ Santa Cruz Santa Cruz Santa Cruz Σάντα Κρουζ सांता क्रूज़ नदी Santa Cruz Santa Cruz Santa Cruz サンタクルス川 산타 크루즈 Santa Cruz Santa Cruz Santa Cruz Рио-Санта-Крус Santa Cruz Santa Cruz Sông Santa Cruz 聖克魯斯河 1159113631رود سانتاکروز נהר סנטה קרוז Санта-Крус سانتا کروز 聖克魯斯河 4River Saskatchewan 4.0 5.0Saskatchewan Saskatchewan Q3047 ساسكاتشوان সাসকাচেয়ান Saskatchewan Saskatchewan Saskatchewan Σασκατσεγουάν सस्केचेवान Saskatchewan Saskatchewan Saskatchewan サスカチュワン川 서스캐처원강 Saskatchewan Saskatchewan Saskatchewan Саскачеван Saskatchewan Saskatchewan Saskatchewan 萨斯喀彻温河 1159111555ساسکاچوان נהר ססקצ'ואן Саскачеван ساسکاچیوان 萨斯喀彻温河 6River Sassandra 5.0 6.0Sassandra Sassandra Q1535828 ساساندرا সাসান্দ্রা Sassandra Sassandra Sassandra Σασσάνδρα सासान्द्रा Sassandra Sassandra Sassandra ササンドラ川 사산드라 Sassandra Sassandra Sassandra Сасандра Sassandra Sassandra Sông Sassandra 萨桑德拉河 1159115867ساساندرا ססנדרה Сассандра ساسینڈرا 薩桑德拉河 6River Savannah 5.0 6.0Savannah Savannah Q370750 نهر سافانا সাভানা Savannah Savannah Savannah Σαβάνα सवाना Savannah Savannah Savannah サバンナ川 서배너강 Savannah Savannah Savannah Саванна Savannah River Savannah Sông Savannah 沙瓦纳河 1159115071رود ساواناه סוואנה Саванна دریائے ساواناہ 薩凡納河 4River Seine 4.0 5.0Seine Seine Q1471 السين সেন নদী Seine Sena Seine Σηκουάνας सेन Szajna Seine Senna セーヌ川 센강 Seine Sekwana Sena Сена Seine Sen Seine 塞纳河 1159112177سن סן Сена دریائے سین 塞纳河 2River Selenga Selenge 2.1 3.1Selenga Selenga Q75745 نهر سيلينجا সেলেংগা নদী Selenga Selengá Selenga Σελένγκα सेलेन्गा नदी Szelenge Selenga Selenga セレンガ川 셀렝가강 Selenga Selenga Selenga Селенга Selenga Selenge Irmağı Selenge 色楞格河 1159116113رود سلنگا סלנגה Селенга سیلینگا 色楞格河 6River Semliki 5.0 6.0Semliki Semliki Q205428 نهر سمليكي সেমলিকি Semliki Semliki Semliki Σεμλίκι सेमलिकी Semliki Semliki Semliki セムリキ川 셈리키 Semliki Semliki Semliki Семлики Semliki Semliki Semliki 塞姆利基河 1159114175رود سملیکی נהר סמליקי Семлікі سیملیکی 塞姆利基河 6River Setit 5.0 6.0Tekezé Setit Q843308 نهر سيتيت সেটিট Tekeze-Setit Tekezé Tekezé Σετίτ सेतित Tekeze Setit Tacazzè テケゼ川 세트 Tekezé Takaze Tekezé Тэкэзе Tekezē Wenz Setit Sông Setit 特克泽河 1159117483ستیت תכזה Сетіт سیٹیٹ 特克澤河 3River Shatt al-Arab 3.0 4.0Shatt al-Arab Shatt al-Arab Q166966 شط العرب শাতিল আরব Schatt al-Arab Shatt al-Arab Chatt-el-Arab Στα αλ-Αράμπ शत अल-अरब Satt-el-Arab Shatt al-Arab Shatt al-'Arab シャットゥルアラブ川 샤트알아랍강 Sjatt al-Arab Szatt al-Arab Chatt al-Arab Шатт-эль-Араб Shatt al-Arab Şattülarap Shatt al-Arab 阿拉伯河 1159128827اروندرود שט אל-ערב Шатт-ель-Араб شط العرب 阿拉伯河 3River Shiquan 3.0 4.0Shiquan He Shiquan Q7666170 شيكوان শিকান Sênggê Zangbo Shiquan Shiquan Σικουάν सेंगे खबब Shiquan Shiquan Shiquan センゲ川 스촨 Sênggê Zangbo Shiquan Shiquan река Шицюань Shiquan He Shiquan Sông Shiquan 狮泉河 1159124095شیکوان שיקאן Шікван شیقوان 狮泉河 3River Shire 3.0 4.0Shire Shire Q2279579 نهر شيري শায়ার Shire Shire Shire Σάιρ शायर Shire Shire Shire シーレ川 샤이어 Shire Shire Chire Шире Shire Shire Sông Shire 希雷河 1159126379رود شایر שירה Шире شائر 希雷河 4River Shishhid Gol 4.0 5.0Shishged Q15277375 شيشيد جول শিশিদ গোল Shishhid Gol Shishhid Gol Shishged Σισχίντ Γκολ शीशिद गोल Shishhid Gol Shishhid Gol Shishhid Gol シシド・ゴル川 쉬쉬드 골 Shishhid Gol Shishhid Gol Shishhid Gol река Шишгид-Гол Shishhid Gol Shishhid Gol Sông Shishhid Gol 希希黑德河 1159110725شیشهید گل שישיד גול Шишшид Гол شیشید گول 希希黑德河 6River Skeena 5.0 6.0Skeena Skeena Q2291822 سكينا স্কীনা Skeena Skeena Skeena Σκίνα स्कीना Skeena Skeena Skeena スキーナ川 스키나 Skeena Skeena Skeena Скина Skeena Skeena Sông Skeena 斯基納河 1159116139اسکینا סקניה Скеена سکینہ دریا 斯基納河 2River Slave 2.1 3.1Slave Slave Q2226 سلايف স্লেভ Slave Esclavos Esclaves Σλέιβ स्लेव Slave Slave Fiume degli Schiavi スレイブ川 슬레이브 Slave Rzeka Niewolnicza Slave Невольничья Slave Slave Sông Slave 奴河 1159119121رود اسلیو נהר סלייב Невільнича دریائے سلیو 奴河 4River Snake 4.0 5.0Snake Snake Q272074 نهر الثعبان স্নেক Snake Snake Snake Σνέικ स्नेक Snake Snake Snake スネーク川 스네이크강 Snake Snake Snake Снейк Snake Snake Snake 斯内克河 1159110085رود اسنیک סנייק Снейк دریائے سنیک 斯內克河 6River Songhua 5.0Sungari 6.0Songhwa Songhua Q210326 نهر سونغوا সংহুয়া নদী Songhua Songhua Songhua Σονγκούα सोंगहुआ Songhua Songhua Songhua 松花江 송화강 Songhua Sungari Songhua Сунгари Songhua Songhua Tùng Hoa 松花江 1159118095سونگ هوا סונגואה Сунгарі سانگ ہوا 松花江 6River Soroksari Duna 5.0 6.0Ráckeve-Soroksár Danube Soroksari Duna Q1252126 سوروكساري دونا সোরোকসারি ডুনা Ráckevei (Soroksári)-D Soroksari-Duna Ráckevei-Duna Σοροκσάρι Ντούνα सोरोक्सारी दुना Ráckevei-Duna Soroksari Duna Soroksari Duna ソロクサリ・ドゥナ 소록사리 두나 Ráckevei-Duna Soroksari Duna Soroksári-Duna река Шорокшар Soroksari Duna Soroksari Duna Sông Soroksari Duna 索罗克萨里多瑙河 1159117707سوروکساری دونا סורוקסרי דונה Сороксарі Дуна سوروکساری دونا 索羅克薩里多瑙河 6River South Saskatchewan 5.0 6.0South Saskatchewan South Saskatchewan Q2242 نهر ساسكاتشوان الجنوبي দক্ষিণ সাসকাচোয়ান South Saskatchewan Saskatchewan Sur Saskatchewan Sud Νότιο Σασκατσουάν दक्षिण सस्केचेवान नदी Dél-Saskatchewan South Saskatchewan South Saskatchewan サウスサスカチュワン川 사우스서스캐처원강 South Saskatchewan Saskatchewan Południowy South Saskatchewan Саут-Саскачеван South Saskatchewan Güney Saskatchewan Sông South Saskatchewa 南萨斯喀彻温河 1159115577رود ساسکاچوان جنوبی נהר ססקאצ'ואן הצפוני Південний Саскачеван ساؤتھ ساسکاچیوان 南萨斯喀彻温河 5River Sprague 4.7 5.7Sprague Sprague Q2313261 سبراج স্প্রেগ Sprague Río Sprague Sprague Σπράγκ स्प्रागुए Sprague Sprague Sprague スプレイグ川 스프라그 Sprague Sprague Sprague река Спраг Sprague River Sprague Sông Sprague 斯普拉格河 1159113493اسپراگوئه ספראג Спрак سپریگ 斯普拉格河 3River St. Clair 3.0 4.0St. Clair St. Clair Q1054325 سان كلير সেন্ট ক্লেয়ার St. Clair St. Clair Sainte-Claire Σεντ Κλερ सेंट क्लेयर St. Clair St. Clair Fiume Saint Clair セントクレア川 세인트클레어강 St. Clair St. Clair St. Clair Сент-Клэр St. Clair St. Clair Saint Clair 圣克莱尔河 1159128471سنت کلیر סנט קלייר Сент Клер سینٹ کلیئر 聖克萊爾河 2River Saint Lawrence 2.1 3.1Saint Lawrence St. Lawrence Q134750 نهر سانت لورانس সেন্ট লরেন্স নদী Sankt-Lorenz-Strom San Lorenzo fleuve Saint-Laurent Άγιος Λαυρέντιος सैंट लारेन्स् नदी Szent Lőrinc Saint Lawrence San Lorenzo セイント・ローレンス川 세인트로렌스강 Saint Lawrence Rzeka Świętego Wawrzyńca São Lourenço Река Святого Лаврентия Saint Lawrencefloden Saint Lawrence Saint Lawrence 圣劳伦斯河 1159114637سن لوران סנט לורנס Річка Святого Лаврентія دریائے سینٹ لارنس 聖勞倫斯河 5River Stikine 4.7 5.7Stikine Stikine Q2092571 ستيكيني স্টিকাইন Stikine Stikine Stikine Στίγινε स्टिकिन Stikine Stikine Stikine スティキーン川 스티킨 Stikine Stikine Stikine Стикин Stikinefloden Stikine Sông Stikine 史堤金河 1159112685استیکین סטיקין Стікіне اسٹیکائن 史堤金河 6River Suez Canal 5.0 6.0Suez Canal Suez Canal Q899 قناة السويس সুয়েজ খাল Suezkanal canal de Suez canal de Suez Διώρυγα Σουέζ स्वेज़ नहर Szuezi-csatorna Terusan Suez Suez スエズ運河 수에즈 운하 Suezkanaal Kanał Sueski Canal de Suez Суэцкий канал Suezkanalen Süveyş Kanalı Kênh đào Suez 苏伊士运河 1159113931کانال سوئز תעלת סואץ Суецький канал نہر سوئز 蘇伊士運河 4River Sukhona 4.0 5.0Sukhona Sukhona Q82812 نهر سوخونا সুখোনা Suchona Sújona Soukhona Σουχόνα सुखोना Szuhona Sukhona Suchona スホナ川 수코나 Soechona Suchona Sukhona Сухона Suchona Suhona Sông Sukhona 蘇霍納河 1159110571سوخونا סוקהונה Сухона سوکھونا 蘇霍納河 6River Susitna 5.0 6.0Susitna Susitna Q60065 سوسيتنا সুসিতনা Susitna Susitna Susitna Σουσίτνα सुसीत्ना Susitna Susitna Susitna スシトナ川 수싯나 Susitna Susitna Susitna Суситна Susitna Susitna Sông Susitna 蘇西特納河 1159114579سوسیتنا סוזיטנה Сусітна سوستنا 蘇西特納河 6River Sutlej 5.0 6.0Sutlej Sutlej Q171675 نهر ستلج শতদ্রু Satluj Sutlej Sutlej Ζάραδρος सतलुज नदी Szatledzs Sutlej Sutlej サトレジ川 수틀레지강 Sutlej Satledź Sutlej Сатледж Sutlej Satlec Sutlej 象泉河 1159115241رود ستلج סוטלג' Сатледж دریائے ستلج 象泉河 4River Severnaya Dvina Northern Dvina 4.0 5.0Northern Dvina Severnaya Dvina Q8187 نهر دفينا الشمالي উত্তর ভিনা Nördliche Dwina Dviná Septentrional Dvina septentrionale Ντβινά सेवर्नया डिविना Északi-Dvina Severnaya Dvina Dvina Settentrionale 北ドヴィナ川 세베르나야드비나 강 Noordelijke Dvina Dwina Duína do Norte Северная Двина Norra Dvina Kuzey Dvina Bắc Dvina 北德维纳河 1159112289رود دوینای شمالی סברנאיה דבינה Північна Двіна سیورنایا ڈوینہ 北德维纳河 5River Svir 4.7 5.7Svir Svir Q213067 سفير এসভির Swir Svir Svir Σβιρ स्वीर Szvir Svir Svir' スヴィリ川 스비리강 Svir Świr Svir Свирь Svir Svir Svir 斯维里河 1159113225رودخانه سیویر סביר Свір سوئر 斯維里河 5River Syr Darya 4.7 5.7Syr Dar Syr Darya Q483159 نهر سيحون সির দরিয়া Syrdarja Sir Daria Syr-Daria Συρ Ντάρια सिर दरिया Szir-darja Syr Darya Syr Darya シルダリヤ川 시르다리야강 Syr Darja Syr-daria Sir Dária Сырдарья Syr-Darja Seyhun Syr Darya 锡尔河 1159113097سیردریا סיר דריה Сирдар'я دریائے سیحوں 錫爾河 4River São Francisco 4.0 5.0São Francisco São Francisco Q142148 نهر ساو فرانسيسكو সাঁও ফ্রাঁসিশকু নদী São Francisco São Francisco São Francisco Σάο Φραγκίσκο साओ फ़्रांसिस्को São Francisco São Francisco São Francisco サン・フランシスコ川 상프란시스쿠강 São Francisco São Francisco São Francisco Сан-Франсиску São Francisco São Francisco São Francisco 圣弗朗西斯科河 1159110245رود سائو فرانسیسکو סאו פרנסיסקו Сан-Франсіску ساؤ فرانسسکو 聖法蘭西斯科河 4River Sénégal 4.0 5.0Senegal Sénégal Q3569 نهر السنغال সেনেগাল নদী Senegal Senegal Sénégal Σενεγάλης सेनेगल Szenegál Senegal Senegal セネガル川 세네갈강 Sénégal Senegal Senegal Сенегал Senegalfloden Sénégal Sénégal 塞内加尔河 1159112231رود سنگال סנגל Сенегал دریائے سینیگال 塞内加尔河 5River Tajo 4.7 5.7Tagus Tajo Q14294 نهر تاجة তাজো Tajo Tajo Tage Τάγος तैजो Tajo Tagus Tago タホ川 타구스강 Taag Tag Tejo Тахо Tajo Tejo Tagus 塔霍河 1159112927تاقوس טחו Тахо تاجو 塔霍河 6River Tanana 5.0 6.0Tanana Tanana Q393769 تانانا তানানা Tanana Tanana Tanana Τανάνα तनाना Tanana Tanana Tanana タナナ川 타나나 Tanana Tanana Tanana Танана Tanana Tanana Sông Tanana 塔納諾河 1159114597رود تانانا טנאנה Танана تانانا 塔納諾河 5River Tapajós 4.7 5.7Tapajós Tapajós Q752674 نهر تاباجوس তাপজ Tapajós Tapajós Tapajós Ταπαγιός तपजोस Tapajós Tapajos Tapajós タパジョース川 타파조스 Tapajós Tapajós Tapajós Тапажос Tapajós Tapajós Tapajós 塔帕若斯河 1159113723تاپاژوس טפז'וס Тапажос تاپاجوس 塔帕若斯河 6River Tarim 5.0 6.0Tarim Tarim Q237901 نهر تاريم তারিম নদী Tarim Tarim Tarim Ταρίμ तारिम नदी Tarim Tarim Tarim タリム川 타림강 Tarim Tarym Tarim Тарим Tarim Tarım Tarim 塔里木河 1159117631رود تاریم תרים Тарим دریائے تاریم 塔里木河 6River Taritatu 5.0 6.0Taritatu Taritatu Q2324718 تاريتاتو তরিতাতু Taritatu Taritatu Taritatu Ταριτατού तारितातु Taritatu Taritatu Taritatu タリタウ川 타리타투 Idenburg Taritatu Taritatu река Таритату Taritatu Taritatu Taritatu 塔里塔图河 1159116935تاریتاتو טריטטו Тарітату تاریتاتو 塔里塔图河 6River Taz 5.0 6.0Taz Taz Q81555 تاز তাজ Tas Taz Taz Ταζ ताज़ी Taz Taz Taz タズ川 타스강 Taz Taz Taz Таз Taz Taz Sông Taz 塔茲河 1159114769تاز טאז Таз تاز 塔茲河 5River Tejo 4.7Tagus 5.7Tagus Tejo Q14294 نهر تاجة তেজো Tajo Tajo Tage Τάγος तेजो Tajo Tagus Tago タホ川 타구스강 Taag Tag Tejo Тахо Tajo Tejo Tagus 塔霍河 1159113655تاقوس טחו Тахо تیجو 塔霍河 5River Tennessee 4.7 5.7Tennessee Tennessee Q193737 نهر تينيسي টেনেসি নদী Tennessee Tennessee Tennessee Ποταμός Τενεσί टेनेसी Tennessee Tennessee Tennessee テネシー川 테네시강 Tennessee Tennessee Tennessee Теннесси Tennesseefloden Tennessee Tennessee 田纳西河 1159113053رودخانه تنسی טנסי Теннессі دریائے ٹینیسی 田納西河 3River Teslin 3.0 4.0Teslin Teslin Q284495 تسلين টেসলিন Teslin Telsin Teslin Τέσλιν टेस्लिन Teslin Teslin Teslin テスリン川 테슬린 Teslin Teslin Teslin Теслин Teslin Teslin Sông Teslin 特斯林河 1159123753تسلین טסלין Теслін تیسلن 特斯林河 6River Thames 5.0 6.0Thames Thames Q19686 نهر التمز টেম্স নদী Themse Támesis Tamise Τάμεσης थेम्स नदी Temze Thames Tamigi テムズ川 템스강 Theems Tamiza Tâmisa Темза Themsen Thames Thames 泰晤士河 1159116709تیمز תמזה Темза دریائے ٹیمز 泰晤士河 5River Thelon 4.7 5.7Thelon Thelon Q2416760 ثيلون থেলন Thelon Thelon Thelon Θέλον थेलोन Thelon Thelon Thelon セロン川 테론 Thelon Thelon Thelon Телон Thelon Thelon Sông Thelon 塞隆河 1159112783تلون תּלון Телон تھیلون 塞隆河 4River Tigris 4.0 5.0Tigris Tigris Q35591 دجلة দজলা Tigris Tigris Tigre Τίγρης ποταμός दजला नदी Tigris Tigris Tigri チグリス川 티그리스강 Tigris Tygrys Tigre Тигр Tigris Dicle Tigris 底格里斯河 1159112275دجله חידקל Тигр دریائے دجلہ 底格里斯河 6River Tisa 5.0 6.0Tisza Tisa Q134350 تيسا টিসা Theiß Tisza Tisza Τίσα तिसा Tisza Tisza Tibisco ティサ川 티서강 Tisza Cisa Tisza Тиса Tisza Tisza Tisza 蒂萨河 1159118059تیسزا טיסה Тиса ٹیسا 蒂薩河 6River Tisza 5.0 6.0Tisza Tisza Q134350 تيسا তিসজা Theiß Tisza Tisza Τίσα टिस्ज़ा Tisza Tisza Tibisco ティサ川 티서강 Tisza Cisa Tisza Тиса Tisza Tisza Tisza 蒂萨河 1159117275تیسزا טיסה Тиса ٹیسزا 蒂薩河 5River Tobol 4.7 5.7Tobol Tobol Q124653 نهر توبول টবল Tobol Tobol Tobol Ποταμός Τομπόλ टोबोल Tobol Tobol Tobol トボル川 토볼강 Tobol Toboł Tobol Тобол Tobol Tobol Tobol 托博尔河 1159113351رود توبول טוֹבוֹל Тобол ٹوبول 托博爾河 4River Tocantins 4.0 5.0Tocantins Tocantins Q156054 نهر توكانتين টোক্যান্টিনস Tocantins Tocantins Tocantins Τοκαντίνες टोकैन्तिंस Tocantins Tocantins Tocantins トカンチンス川 토칸칭스강 Tocantins Tocantins Tocantins Токантинс Tocantins Tocantins Tocantins 托坎廷斯河 1159111967توکانتینس טוקנטינס Токантінс ٹوکانٹنز 托坎廷斯河 6River Tom’ 5.0 6.0Tom Tom’ Q216188 توم টম Tom Tom Tom Τομ' टॉम' Tom Tom Tom' トミ川 톰강 Tom Tom Tom Томь Tom Tom Sông Tom 托木河 1159117019رود تام טום Том ٹوم 托木河 1River Tongtian 2.0 3.0Tongtian Q7821148 تونغتيان টংটিয়ান Zhi Qu Tongtian Fleuve Tongtian Τόγκτιαν टोंगटियन Tongtian Tongtian Tongtian 通天河 통천 Tongtian Tongtian Tongtian река Тунтянь Tongtian Tongtian Sông Thông Thiên 通天河 1159112343تونگتیان טונגטיאן Тонгтіан ٹونگٹیان 通天河 5River Trofimovskaya Protoka 4.7 5.7Trofimovskaya Protoka تروفيموفسكايا بروتوكا ট্রোফিমভস্কায়া প্রোটোকা Trofimovskaya Protoka Trofimovskaya Protoka Trofimovskaya Protoka Τροφιμόβσκαγια Πρότοκα ट्रोफिमोव्स्काया प्रोटोका Trofimovskaya Protoka Trofimovskaya Protoka Trofimovskaya Protoka トロフィモフスカヤ・プロトカ 트로피모프스카야 프로토카 Trofimovskaya Trofimowsko Trofimovskaya Protoka Трофимовская протока Trofimovskaja Protoka Trofimovskaya Protoka Sông Trofimovskaya Pro 特罗菲莫夫斯卡亚河 1159113751تروفیمووسکایا پروتوکا טרופימובסקאיה פרוטוקה протока Трофимовська ٹروفیموسکایا پروٹوکا 特菲莫夫斯卡亞河 6River Tshuapa 5.0 6.0Tshuapa Tshuapa Q2635327 تشوابا শুয়াপা Tshuapa (Fluss) Tshuapa Tshwapa Τσουαπά त्शुपा Tshuapa Tshuapa Tshuapa ツアパ川 추아파 Tshuapa Tshuapa Tshuapa Чуапа Tshuapa Tshuapa Tshuapa 楚阿帕河 1159116515تشواپا טשואפה Тшуапа شواپا 楚阿帕河 6River Tugaloo 5.0 6.0Tugaloo Tugaloo Q2459279 توجالو তুগালু Tugaloo Tugaloo Tugaloo Τούγκαλου तुगलू Tugaloo Tugaloo Tugaloo トガルー川 투갈루 Tugaloo Tugaloo Tugaloo река Тагалу Tugaloo River Tugaloo Sông Tugaloo 图加卢河 1159115015توگالو טוגאלו Тугалу ٹوگالو 圖加盧河 5River Tumatskaya Protoka 4.7 5.7Tumatskaya Protoka توماتسكايا بروتوكا টুমাতস্কায়া প্রোটোকা Tumatskaya Protoka Tumatskaya Protoka Tumatskaya Protoka Τουμάτσκαγια Πρότοκα तुमात्सकाया प्रोटोका Tumatskaya Protoka Tumatskaya Protoka Tumatskaya Protoka トゥマツカヤ・プロトカ 투마츠카야 프로토카 Tumatskaya Ujście Tumatskaja Tumatskaya Protoka Туматская протока Tumatskaja Protoka Tumatskaya Protoka Sông Tumatskaya Protok 图马茨卡亚河 1159113767توماتسکایا پروتوکا טומאצקאיה פרוטוקה протока Туматська ٹوماٹسکایا پروٹوکا 圖馬茨卡亞河 1River Tuotuo 2.0 3.0Tuotuo He Tuotuo Q1538813 توتو তুটুও Tuotuo He Tuotuo Tuotuo Τουότουο टूओटूओ Tuotuo Tuotuo Tuotuo 沱沱河 투오퉈 Tuotuo Tuotuo He Tuotuo река Тото Tuotuo He Tuotuo Đà Đà 沱沱河 1159112047توتو טוטו Туотуо ٹیوٹیو 沱沱河 3River Ubangi 3.0 4.0Ubangi Ubangi Q171649 أوبانغي উবাঙ্গি নদী Ubangi Ubangui Oubangui Ουμπάνγκι उबंगी नदी Ubangi Ubangi Ubangi ウバンギ川 우방기강 Ubangi Ubangi Ubangui Убанги Oubangui Ubangi Ubangi 乌班吉河 1159123505رود اوبانگی אובנגי Убангі اوبانگی 烏班吉河 1River Ucayali 2.0 3.0Ucayali Ucayali Q200952 نهر أوكايالي উকায়ালি নদী Ucayali Ucayali Ucayali ποταμός Ουκαγιάλι उकायाली Ucayali Ucayali Ucayali ウカヤリ川 우카얄리강 Ucayali Ukajali Ucayali Укаяли Ucayali Ucayali Ucayali 乌卡亚利河 1159111139رود اوکایالی אוקיאלי Укаялі اوکیالی 烏卡亞利河 3River Uele 3.0 4.0Uele Uele Q171436 يوالي উয়েল Uelle Uele Uele Ουέλε उएले नदी Uele Uele Uele ウエレ川 우엘레 Uele Uele Uele Уэле Uele Uele Uele 韦莱河 1159128035اوئوله נהר אואלה Уеле اوئلے 韋萊河 4River Ural 4.0 5.0Ural Ural Q80240 نهر الأورال ইউরাল নদী Ural Ural Oural Ποταμός Ουράλης यूराल नदी Urál Ural Ural ウラル川 우랄강 Oeral Ural Ural Урал Uralfloden Ural Ural 乌拉尔河 1159111461رود اورال אורל Урал دریائے اورال 烏拉爾河 6River Uruguay 5.0 6.0Uruguay Uruguay Q18278 نهر الأوروغواي উরুগুয়ে নদী Uruguay Uruguay Uruguay ποταμός Ουρουγουάης उरुग्वे नदी Uruguay Uruguay Uruguay ウルグアイ川 우루과이강 Uruguay Urugwaj Uruguai Уругвай Uruguayfloden Uruguay Uruguay 烏拉圭河 1159116455رود اروگوئه אורוגוואי Уругвай دریائے یوراگوئے 烏拉圭河 5River Usumacinta 4.7 5.7Usumacinta Usumacinta Q1139679 أوسوماسينتا উসুমাসিন্তা Usumacinta Usumacinta Usumacinta Ουσουματσίντα उसुमासिंटा Usumacinta Usumacinta Usumacinta ウスマシンタ川 우스마신타 Usumacinta Usumacinta Usumacinta Усумасинта Usumacinta Usumacinta Sông Usumacinta 乌苏马辛塔河 1159112671اوسوماسینتا אוּסוּמאסינטה Усумасінта اوسوماکنٹا 烏蘇馬辛塔河 4River Vaal 4.0 5.0Vaal Vaal Q209530 فال ভ্যাল Vaal Vaal Vaal Βάαλ वाल नदी Vaal Vaal Vaal バール川 바알 Vaalrivier Vaal Vaal Вааль Vaal Vaal Vaal 瓦尔河 1159109781رودخانه واله ואל Вааль وال 瓦爾河 6River Verde 5.0 6.0Verde Verde Q28457542 فيردي ভার্দে Verde River Verde Verde Βέρντε वर्डे Verde Verde Verde ベルデ川 베르드 Verde Verde Verde Río Verde Verde Sông Verde 佛得角河 1159117149ورده וֶרְדֶה Верде وردے 維德河 4River Verkhniy Yenisey 4.0 5.0Verkhniy Yenisey فيركني يانيساي ভার্কনি ইয়েনিসেই Verkhniy Yenisey Verkhniy Yenisey Grand Ienisseï Βερκνίι Γιενισέι वेर्खनी येनिसे Verkhniy Yenisey Verkhniy Yenisey Enisej ヴェルフニ・エニセイ川 베르크니 예니세이 Jenisej Verkhniy Yenisey Ienissei Superior река Верхний Енисей Verchnij Jenisej Verkhniy Yenisey Sông Verkhniy Yenisey 上叶尼塞河 1159112435ورکهنی ینسی ורחני יניסֶיי Верхній Єнісей ورکھنائی یینیسے 上葉尼塞河 1River Victoria Nile 2.0 3.0White Nile Victoria Nile Q4814791 النيل الأبيض শ্বেত নীল নদ Weißer Nil Nilo Blanco Nil Blanc Λευκός Νείλος श्वेत नील Fehér-Nílus Nil Putih Nilo Bianco 白ナイル川 백나일강 Witte Nijl Nil Biały Nilo Branco Белый Нил Vita Nilen Beyaz Nil Nin Trắng 白尼罗河 1159123335نیل سفید הנילוס הלבן Білий Ніл نیل ابیض 白尼罗河 6River Vilyuy 5.0 6.0Vilyuy Vilyuy Q26433 نهر فيليوي ভিলিউ Wiljui Viliui Viliouï Βιλιούι विलुयू Viljuj Vilyuy Viljuj ヴィリュイ川 빌류이강 Viljoej Wiluj Vilyuy Вилюй Viljuj Vilyuy Vilyuy 維柳伊河 1159115699رود ویلیوی וילוי Вілюй ولیوئے 維柳伊河 5River Vistula 4.7 5.7Vistula Vistula Q548 فيستولا ভিস্তুলা নদী Weichsel Vístula Vistule Βιστούλας विस्चुला नदी Visztula Vistula Vistola ヴィスワ川 비스와강 Wisła Wisła Vístula Висла Wisła Vistül Wisla 维斯瓦河 1159112951ویستولا ויסלה Вісла وسٹولا 维斯瓦河 3River Volga 3.0 4.0Volga Volga Q626 فولغا ভোলগা নদী Wolga Volga Volga Βόλγας वोल्गा नदी Volga Volga Volga ヴォルガ川 볼가강 Wolga Wołga Volga Волга Volga Volga Volga 伏尔加河 1159125629رودخانه ولگا וולגה Волга دریائے وولگا 伏尔加河 5River Volta 4.7 5.7Volta Volta Q192415 نهر فولتا ভোল্টা নদী Volta Volta Volta Βόλτα वोल्टा नदी Volta Volta Volta ヴォルタ川 볼타강 Volta Wolta Volta Вольта Volta Volta Volta 沃尔特河 1159113289رود ولتا וולטה Вольта وولٹا 沃爾特河 6River Vorma 5.0 6.0Vorma Vorma Q576337 فورما ভোরমা Vorma Vorma Vorma Βόρμα वोर्मा Vorma Vorma Vorma ヴォルマ川 보르마 Vorma Vorma Vorma Ворма Vorma Vorma Sông Vorma 沃马河 1159115961وورما וורמה Ворма وورما 沃馬河 6River Vuoksi 5.0 6.0Vuoksa Vuoksi Q819448 فووكسي ভুক্সি Vuoksi Vuoksi Vuoksi Βουόκσι वुओक्सी Vuoksi Vuoksi Vuoksi ヴオクサ川 복시 Vuoksi Vuoksi Vuoksi Вуокса Vuoksen Vuoksi Vuoksi 武克希河 1159115145رودخانه ویوکسی וווקסי Вуоксі ووکسی 武克希河 5River Vychegda 4.7 5.7Vychegda Vychegda Q65383 فيتشيجدا ভাইচেডা Wytschegda Víchegda Vytchegda Βιτσέγκντα व्याचेग्डा Vicsegda Vychegda Vyčegda ヴィチェグダ川 비체그다강 Vytsjegda Wyczegda Vychegda Вычегда Vytjegda Vıçegda Sông Vychegda 維切格達河 1159113541ویچگدا ויצ'גדה Вичегда وائےچیگدا 維切格達河 4River Waal 4.0 5.0Waal Waal Q216171 فال ওয়াল Waal Waal Waal Βααλ वाल Waal Waal Waal ワール川 발강 Waal Waal Waal Вал Waal Waal Sông Waal 瓦尔河 1159112531وال וואאל Вааль وال 瓦爾河 6River Wabash 5.0 6.0Wabash Wabash Q196183 واباش ওয়াবাশ Wabash Wabash Wabash Ουάμπας वाबाश Wabash Wabash Wabash ウォバッシュ川 와바시 Wabash Wabash Wabash Уобаш Wabash Wabash Wabash 沃巴什河 1159117199رود واباش ובאש Вобаш واباش 沃巴什河 6River Waikato 5.0 6.0Waikato Waikato Q1048219 نهر وايكاتو ওয়াইকাটো Waikato Waikato Waikato Ποταμός Γουαϊκάτο वायकाटो नदी Waikato Waikato Waikato ワイカト川 와이카토강 Waikato Waikato Waikato Уаикато Waikatofloden Waikato Sông Waikato 怀卡托河 1159129617رود وایکاتو וואיקאטו Ваїкато وائیکاٹو 怀卡托河 6River Waitaki 5.0 6.0Waitaki Waitaki Q2033279 وايتاكي ওয়াইটাকি Waitaki Waitaki Waitaki Γουαϊτάκι वेटाकी Waitaki Waitaki Waitaki ワイタキ川 와이타키 Waitaki Waitaki Waitaki Уаитаки Waitaki River Waitaki Sông Waitaki 怀塔基河 1159129481ویتاکی ווייטאקי Ваітакі وائٹاکی 威塔基河 3River Weir 3.0 4.0Weir Weir Q2556345 وير উয়ির Weir Weir Weir Γουέιρ वीयर Weir Weir Weir ウィアー川 위어 Weir Weir Weir Уир Weir Weir Sông Weir 韦尔河 1159127167ویر וֶויר Вейр ویئر 韋爾河 6River Willamette 5.0 6.0Willamette Willamette Q131071 ويلاميت উইল্যামেট নদী Willamette Willamette Willamette Γουιλαμέτε विल्मेट Willamette Willamette Willamette ウィラメット川 윌래밋강 Willamette Willamette Willamette Уилламетт Willamette Willamette Willamette 威拉米特河 1159117329ویلمت וילאמט Вілламетт ولامیٹے 威拉米特河 6River Winnipeg 5.0 6.0Winnipeg Winnipeg Q1400022 وينيبيغ উইনিপেগ Winnipeg Winnipeg Winnipeg Γουίνιπεγκ विनीपेग Winnipeg Winnipeg Winnipeg ウィニペグ川 위니펙 Winnipeg Winnipeg Winnipeg Виннипег Winnipeg Winnipeg Sông Winnipeg 溫尼伯河 1159115495وینیپگ נהר ויניפג Вінніпег ونیپیگ 溫尼伯河 6River Xar Moron 5.0 6.0Xar Moron Xar Moron Q1131680 نهر مورون জার মরন Xar Moron He Xar Moron Shira Mören Ξαρ Μόρον ज़ार मोरोन Xar Moron Xar Moron Xar Moron シラムレン川 시라무룬허 Xar Moron Xar Moron Xar Moron Шара-Мурэн Xar Moron He Xar Moron Sông Tây Lạp Mộc Luân 西拉木伦河 1159116877زار مورون שאר מורון Хар Морон زار مورون 西拉木倫河 4River Xi 4.0 5.0Xi Xi Q216941 একাদশ Westfluss Xi Xi Σι शी नदी Xi Xi Xi 西江 서강 Xi Xi Xi- Сицзян Xifloden Xi Tây Giang 西江 1159128943رود شی נהר שי Сі زائے 西江 6River Xiliao 5.0 6.0Xiliao Xiliao Q1416521 زيليو জিলিয়াও Xiliao He Xiliao Xiliao Ξιλιάο ज़िलियाओ Xiliao Xiliao Xiliao 西遼河 시랴오허 Xiliao Xiliao Xiliao Силяохэ Xiliao He Xiliao Sông Tây Liêu 西辽河 1159118017زیلیائو שיליאו Сіліао زیلاؤ 西辽河 5River Xingu 4.7 5.7Xingu Xingu Q49544 نهر شينجو শিঙ্গু নদী Xingu Xingú Xingu Ξινγκού ज़ींगू Xingu Xingu Xingu シングー川 싱구 강 Xingu Xingu Xingu Шингу Xingufloden Xingu Xingu 欣古河 1159113639رود خینگو שינגו Шінгу زنگو 欣古河 4River Xun 4.0 5.0Xunjiang Xun Q856509 شون জুন Xunjiang Xunjiang Xunjiang Ξουν ज़ुन Xunjiang Xun Xunjiang 浔江 슌 Xunjiang Xunjiang Xun Сюньцзян Xunjiang Xun Tầm Giang 浔江 1159112491 שון Хан زن 潯江 6River Yadkin 5.0 6.0Yadkin Yadkin Q1520726 يادكين ইয়াদকিন Yadkin Yadkin Yadkin Γιάντκιν याडकिन Yadkin Yadkin Yadkin ヤドキン川 야드킨 Yadkin Yadkin Yadkin река Ядкин Yadkin Yadkin Sông Yadkin 亞德金河 1159117235یادکین יאדקין Ядкін یادکن 亞德金河 6River Yamuna 5.0 6.0Yamuna Yamuna Q132726 نهر جمنة যমুনা নদী Yamuna Yamuna Yamunâ Γιαμούνα यमुना नदी Jamuna Yamuna Yamuna ヤムナー川 야무나강 Yamuna Jamuna Yamuna Джамна Yamuna Yamuna Yamuna 亚穆纳河 1159116803جمنا יאמונה Ямуна دریائے جمنا 亞穆納河 1River Yangtze 2.0 3.0Yangtze Yangtze Q5413 يانغتسي ছাং চিয়াং নদী Jangtsekiang Yangtsé Yangzi Γιανγκτσέ यांग्त्सीक्यांग Jangce Panjang Fiume Azzurro 長江 창 강 Jangtsekiang Jangcy Yangtzé Янцзы Yangtze Yangtze Trường Giang 长江 1159113707رود یانگتسه יאנגצה Янцзи دریائے یانگزے 長江 6River Yarkant 5.0 6.0Yarkand Yarkant Q559283 ياركند ইয়ারকান্ত Yarkant Yarkand Yarkand Γιαρκάντ यारकन्द नदी Jarkend-darja Yarkant Yarkand ヤルカンド川 예얼창 강 Yarkand Jarkend-daria Yarkant Яркенд Yarkandfloden Yarkent Sông Yarkant 叶尔羌河 1159114691زرفشان رود ירקנט Яркенд دریائے یارکند 葉爾羌河 2River Yarlung 2.1Brahmaputra 3.1Yarlung Yarlung Q2599627 يارلونج ইয়ারলুং Yarlung-Fluss Yarlung Yarlung Tsanpo Γιαρλούνγκ यारलुंग Yarlung Yarlung Yarlung ヤルン川 얄룽 Yarlung Yarlung Yarlung река Ярлунг-Цангпо Yarlung Yarlung Sông Yarlung 雅鲁藏布江 1159120261یارلونگ יארלונג Ярлунг یارلنگ 雅魯藏布江 4River Yenisey 4.0 5.0Yenisey Yenisey Q78707 نهر ينسي ইয়েনিসেই নদী Jenissei Yeniséi Ienisseï Γενισέι येनिसेय नदी Jenyiszej Yenisei Enisej エニセイ川 예니세이강 Jenisej Jenisej Ienissei Енисей Jenisej Yenisey Irmağı Enisei 葉尼塞河 1159111765رود ینیسئی יניסיי Єнісей یینیسے 葉尼塞河 6River Yuan 5.0 6.0Yuan Yuan Q1063190 يوان ইউয়ান Yuan Yuan Yuan Ποταμός Γιουάν युआन Yuan Yuan Yuan 沅江 위안 강 Yuan Yuan Yuan река Юаньцзян Yuanfloden Yuan Nguyên 沅水 1159114821رود یوان יואן Юань یوان 沅水 3River Yukon 3.0 4.0Yukon Yukon Q104437 نهر يوكون ইউকন নদী Yukon Yukón Yukon Γιούκον युकोन Yukon Yukon Yukon ユーコン川 유콘강 Yukon Jukon Yukon Юкон Yukonfloden Yukon Yukon 育空河 1159122327رود یوکون יוקון Юкон دریائے یوکون 育空河 2River Za 2.1 3.1Za زا জা Za Qu Za Za Ζα ज़ा Za Za Za ザ川 자 Za Qu Za Za река Дзачу Za Za Za 扎曲 1159117999زا זָה За زا 扎曲 3River Zambezi 3.0 4.0Zambezi Zambezi Q43106 نهر زمبيزي জাম্বেজি নদী Sambesi Zambeze Zambèze Ζαμβέζης जेम्बेजी नदी Zambézi Zambezi Zambesi ザンベジ川 잠베지강 Zambezi Zambezi Zambeze Замбези Zambezi Zambezi Zambezi 赞比西河 1159126215زامبزی זמבזי Замбезі زیمبیزی 赞比西河 6River _untitled_70 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 6River _untitled_71 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 6River _untitled_72 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 6River _untitled_73 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 6River _untitled_75 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 6River _untitled_76 5.0 6.0Great Bear Großer Bärenfluss Gran del Oso grande l'Ours Grande Fiume degli Orsi グレートベア川 Great Bear Большая Медвежья Stora Björnfloden 大熊河 1159117577 Велика Ведмежа 大熊河 5River _untitled_77 4.7 5.7 1159113739 5River _untitled_78 4.7 5.7 1159113739 5River _untitled_79 4.7 5.7 1159113739 5Lake Centerline _untitled_78 4.7 5.7 1159112807 6River Garonne 5.0 6.0Garonne Garonne Q5077 نهر غارون গারন নদী Garonne Garona Garonne Γαρούνας गैरोन Garonne Garonne Garonna ガロンヌ川 가론강 Garonne Garonna Garona Гаронна Garonne Garonne Garonne 加龍河 1159129239گارون גארון Гаронна گارونے 加龍河 5River Loire 4.7 5.7Loire Loire Q1469 لوار লোয়ার নদী Loire Loira Loire Λίγηρας लवार नदी Loire Loire Loira ロワール川 루아르강 Loire Loara Loire Луара Loire Loire Loire 卢瓦尔河 1159129677لوار לואר Луара لوار 卢瓦尔河 5River Loire Fixed in 4.0 4.7 5.7Loire Loire Q1469 لوار লোয়ার নদী Loire Loira Loire Λίγηρας लवार नदी Loire Loire Loira ロワール川 루아르강 Loire Loara Loire Луара Loire Loire Loire 卢瓦尔河 1159129677لوار לואר Луара لوار 卢瓦尔河 7Lake Centerline Suda 4.7 7.0Suda Suda Q1295629 سودا সুদা Suda Suda Souda Σούδα सुदा Suda Suda Suda スダ川 수다 Soeda Suda Suda Суда Suda Suda Suda 蘇達河 1159119561سودا סודה Суда سودا 蘇達河 9Lake Centerline Sheksna 4.7 8.1Sheksna Sheksna Q1147118 نهر شيكسنا শেক্সনা Scheksna Sheksná Cheksna Σέκσνα शेक्सना Sheksna Sheksna Šeksna シェクスナ川 셰크스나 Sjeksna Szeksna Cheksna Шексна Sjeksna Şeksna Sheksna 舍克斯纳河 1159109447شکنسا שקסנה Шексна شیکسنا 舍克斯納河 9River Sheksna 4.7 8.1Sheksna Sheksna Q1147118 نهر شيكسنا শেক্সনা Scheksna Sheksná Cheksna Σέκσνα शेक्सना Sheksna Sheksna Šeksna シェクスナ川 셰크스나 Sjeksna Szeksna Cheksna Шексна Sjeksna Şeksna Sông Sheksna 舍克斯纳河 1159109461شکنسا שקסנה Шексна شیکسنا 舍克斯納河 9Lake Centerline Sheksna 4.7 8.1Sheksna Sheksna Q1147118 نهر شيكسنا Scheksna Sheksná Cheksna Šeksna シェクスナ川 Sjeksna Szeksna Cheksna Шексна Sjeksna Şeksna 舍克斯纳河 1159122755 Шексна 舍克斯納河 12Lake Centerline Kovzha River 4.7 8.0Kovzha Kovzha River Q2305285 نهر كوفزا কোভঝা রিভার Kowscha Kovzha Kovja Ποταμός Κόβζα कोवझा नदी Kovzha-folyó Sungai Kovzha Kovža コフジャ川 코브자 리버 Kovzja Rzeka Kovzha Rio Kovzha Ковжа Kovzha Kovzha Nehri Sông Kovzha 科夫扎河 1729992317رودخانه کووژا נהר קובזה Ковжа کوزا ریور 科夫扎河 12River Kovzha River 4.7 8.0Kovzha Kovzha River Q2305285 نهر كوفزا কোভঝা রিভার Kowscha Kovzha Kovja Ποταμός Κόβζα कोवझा नदी Kovzha-folyó Sungai Kovzha Kovža コフジャ川 코브자 리버 Kovzja Rzeka Kovzha Rio Kovzha Ковжа Kovzha Kovzha Nehri Sông Kovzha 科夫扎河 1159112613رودخانه کووژا נהר קובזה Ковжа کوزا ریور 科夫扎河 12Lake Centerline Kovzha River 4.7 8.0Kovzha Kovzha River Q2305285 Kowscha Kovzha Kovja Kovža コフジャ川 Kovzja Ковжа 科夫扎河 1729992323 Ковжа 科夫扎河 5Lake Centerline Svir 4.7 5.7Svir Svir Q213067 سفير Swir Svir Svir Szvir Svir' スヴィリ川 스비리강 Svir Świr Svir Свирь Svir Svir Svir 斯维里河 1159122959رودخانه سیویر Свір 斯維里河 10Canal White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı 白海-波罗的海运河 1159127835کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал 白海-波羅的海運河 10Lake Centerline White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı 白海-波罗的海运河 1159127823کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал 白海-波羅的海運河 10Canal White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı 白海-波罗的海运河 1159127805کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал 白海-波羅的海運河 10Lake Centerline White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق হুয়াইট সী ক্যানেল Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Κανάλι Λευκής Θάλασσας व्हाइट सी नहर Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı Kênh Biển Trắng 白海-波罗的海运河 1159126025کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал وہائٹ سی کنال 白海-波羅的海運河 10Canal White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق হুয়াইট সী ক্যানেল Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Κανάλι Λευκής Θάλασσας व्हाइट सी नहर Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı Kênh White Sea 白海-波罗的海运河 1159127815کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал وہائٹ سی کنال 白海-波羅的海運河 6Canal Volga-Don Canal 4.7 6.0Volga–Don Canal Volga-Don Canal Q827505 قناة فولجا دون ভোলগা-ডন ক্যানেল Wolga-Don-Kanal Canal Volga-Don canal Don-Volga Κανάλι Βόλγα-Ντον वोल्गा-डॉन नहर Volga-Don csatorna Kanal Volga-Don Volga-Don ヴォルガ・ドン運河 볼가-돈 운하 Wolga-Donkanaal Kanał Wołga-Don Canal Volga-Don Волго-Донской канал Volga–Donkanalen Volga-Don Kanalı Kênh đào Volga-Don 伏尔加-顿河运河 1729992327کانال ولگا-دن תעלת הוולגה-דון Волго-Донський канал ڈون۔وولگا نہر 伏爾加-頓河運河 6Lake Centerline Volga-Don Canal 4.7 6.0Volga–Don Canal Volga-Don Canal Q827505 قناة فولجا دون ভোলগা-ডন ক্যানেল Wolga-Don-Kanal Canal Volga-Don canal Don-Volga Κανάλι Βόλγα-Ντον वोल्गा-डॉन नहर Volga-Don csatorna Kanal Volga-Don Volga-Don ヴォルガ・ドン運河 볼가-돈 운하 Wolga-Donkanaal Kanał Wołga-Don Canal Volga-Don Волго-Донской канал Volga–Donkanalen Volga-Don Kanalı Kênh đào Volga-Don 伏尔加-顿河运河 1729992329کانال ولگا-دن תעלת הוולגה-דון Волго-Донський канал ڈون۔وولگا نہر 伏爾加-頓河運河 10Lake Centerline White Sea Canal 4.7Belomorcanal 7.0White Sea – Baltic Canal White Sea Canal Q461457 قناة البحر الأبيض إلى بحر البلطيق Weißmeer-Ostsee-Kanal Canal Mar Blanco-Báltico canal de la mer Blanche Balti–Fehér-tenger-csatorna Bendungan Laut Putih–Baltik Mar Bianco-Mar Baltico 白海・バルト海運河 백해-발트 해 운하 Witte Zeekanaal Kanał Białomorsko-Bałtycki Canal Mar Branco–Báltico Беломорско-Балтийский канал Vitahavskanalen Beyazdeniz-Baltık Kanalı 白海-波罗的海运河 1159127845کانال دریای سفید–بالتیک תעלת הים הלבן-הים הבלטי Біломорсько-Балтійський канал 白海-波羅的海運河 Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.dbfawk0000664000175000017500000000236115151324131026324 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This file is used to set rendering rules for the Natural Earth Vector # file ne_50m_rivers_lake_centerlines.shp # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="scalerank:featurecla:name:note:min_zoom:name_alt:min_label:name_en:label:wikidataid:name_ar:name_bn:name_de:name_es:name_fr:name_el:name_hi:name_hu:name_id:name_it:name_ja:name_ko:name_nl:name_pl:name_pt:name_ru:name_sv:name_tr:name_vi:name_zh:ne_id:name_fa:name_he:name_uk:name_ur:name_zht"; dbffields="featurecla:name"; } # defaults: steel blue lines. Visible at max zoom. Labels off at 10k zoom. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=1; pattern=0; display_level=2147483647; label_level=10000; label_color=9; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^name=(.+)$/ {name="$1";next} # rivers thicker than lake centerlines and canals, with larger labels. # lake center lines dashed # canals double dashed /^featurecla=River/ {lanes=1; font_size=3; pattern=0; next} /^featurecla=Lake Centerline/ {lanes=1; font_size=2; pattern=1; next} /^featurecla=Canal/ {lanes=1; font_size=2; pattern=2; next} Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.prj0000664000175000017500000000022115151324131025652 0ustar hibbyhibbyGEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.shp0000664000175000017500000153437015151324131025673 0ustar hibbyhibby' \|}YΧdѼIp#m f@oUR@=H@ewK@ 1I@ЙK@ 1I@ЙK@~;I@ UK@P0I@A5FK@jI@K@@oI@p)6K@33I@(5K@`3I@/jϣK@nI@0"5K@0I@%5K@@I@05K@`T3EI@HVK@(98I@x5ʽK@x-'I@h*5ڻK@8x}I@5K@V1TjI@HZhK@HeXI@'5ƵK@4I@5ZK@@s I@0V6ȰK@5K@=H@ewK@ЂzI@D5K@@WL@`j@N@0!J@6hM@̬J@@6#M@NJ@/jϳ-M@H33J@5~2M@>|J@8355M@J@=57M@,J@5>M@XJ@866hAM@e23J@R5KM@X1ȰJ@05VM@XJ@B5cM@@33J@06iM@(J@5wM@̌J@(5rM@(J@iϻM@/J@5bM@23J@xI5ЖM@xehJ@(5ȚM@8l{J@XiM@`C̼tJ@8q5zM@hnJ@UiσM@33ChJ@ i3M@/XJ@H6pM@:NJ@x5M@pMJ@5M@MQJ@p{5M@8[WJ@jM@@/bJ@6M@fJ@h M@33nJ@60M@3uJ@P5M@|J@xhcM@n|J@x6M@h23#J@iϫM@@J@'6N@@J@h5N@OJ@D5&N@8efJ@5v N@23J@'5N@XB33cJ@o6N@(ef&J@XwhϛN@H33J@hσN@QJ@N@033J@X5"!N@`v/J@(ik%N@@J@5N)N@8ffK@)5*+N@33s K@(m5*N@8K@h5-N@"K@P5>.N@I(K@5"+N@PF332K@hs#N@/BK@?5N@33lK@5bN@|K@5N@+K@(N@ؤK@=5HN@(ܭK@5* N@K@75'N@ЀffK@ 5P5N@C33K@85">N@23K@`j@N@h\K@c5:N@L@(6@6N@4L@562N@PL@,5>1N@(sL@E5*N@8L@;5$N@0ef6L@5N@hL|L@52N@0L@5N@,L@R5JN@@o#L@8iN@p#L@5 N@h <&L@@<5N@8̬%L@25N@5'L@5M@@33+L@H45M@g.L@h5&M@r<1L@ 5RM@7L@xiM@efFL@PJ@z5:L@t?J@55L@33J@6H3L@x%0J@HiS2L@̼ؐJ@5.L@alK@@5+L@ K@5#L@P^ K@h+iϻL@K@jL@oK@5BL@ K@hicL@n̜ K@W5L@K@p5nL@)K@ jϳL@t33sJ@p5L@ J@ 5L@J@ȏ5L@JJ@ȏ5L@g23J@ iKL@J@j5K@@WJ@iϻK@POJ@>5K@J@c5K@ J@0+jϻK@hJ@`D5HK@P23J@X5xK@hJ@5K@xJ@XhϓK@H=LJ@P95K@XJ@5JK@O33J@5K@J@5VK@hx~J@05>K@33SuJ@X5K@0kJ@ h5K@OaJ@X5"K@ ZJ@h5K@pMJ@Ї5K@PCJ@6pK@x;J@5K@z70J@5VK@\{o*J@XzK@@8'J@@5K@l(J@@6K@C+J@]kK@`3gf-J@`5ZK@xZɴ*J@HK@fff#J@>5K@P J@D5K@sJ@_5nK@ЂzI@ЙK@HW?)wB@@6C'@B@G6'@W?)wB@@'@kp?B@p'@pLu*B@G6'@`9=աB@@,N'@h~B@,('@B@@6C'@h|SlC@ =kA@k"GC@&+B@ k"GC@ =kA@hҰf.C@zA@MDC@M#A@oC@م7B@f C@pE} B@|SlC@B@ C@ OUB@H~C@(ZFB@BC@0Өc$B@jC@&+B@RTdUt&g@@<ьU@+=@@TdUt@@DWUHiӁ@@xVU6@j@@׀Ut&g@@<ьU@+=@@x r|U08@@q<U;i@@$"!VhwI@IේV05gI@ 4VQI@$pVhwI@,VMuI@(AVI@ TRV0KJ͎I@IේVl=I@PcHDV`O罔I@cVxCI@xJVڪI@KVQI@<1V|I@Sge\Vt{I@8V(U!I@3V#{I@hP Vې]I@${S&Vf2RI@<yVh8I@$"!V05gI@8` [?@k@GDy?@4@W$]?@k@` [?@t@Da?@'nr@GDy?@4@Nk2a@(^0H@ gSga@#׾I@ <"a@+<:I@ȝ]~>#a@(&I@Eλ!a@ I@WIa@?I@ )a@(  I@`Ta[a@xCI@#ѭa@мH@Nk2a@XzH@ߌa@(^0H@ gSga@#׾I@V 4d~a@D3I@h}|a@xdI@r{a@( I@ qY@0~I@$NӟZ@̶L@8 .$NӟZ@H 1J@̳uZ@/5J@laZ@$3J@h|iZ@$$.J@,H6eZ@X!J@\d[yZ@J@T\ݞjnZ@C}I@\̍cZ@ɚe2I@I)WZ@(g2uI@p IZ@0~I@"̍Z?Z@\I@*g7Z@II@bY@4J@lY@ J@P^mY@0ީfJ@t_Y@xJ@,kY@jJ@4Y@Z!K@DY@i%K@$v/WY@̐K@zY@(XK@%Y@zwCnK@pRY@^K@LFY@@qK@ZY@`΅7lK@pY@ LJRL@4$Y@ AsJL@0s/WY@Y&L@pӢY@pۓ+L@Tq 5tY@pOgrL@ȶ+Y@q L@Q9wY@@j/ L@$ 6sY@耨 L@qY@hnH9L@\hsY@ho*(8%L@L/W"Y@̶L@d Y@Pi sL@L έY@5L@WɦY@((L@,|(Y@ 耝L@A%˛Y@YL@6—Y@, L@ Y@p^L@[PY@` L@Y@0byL@ 08_SלA@hDt?=-@H̞UJA@V-@H̞UJA@V-@ x8A@@ qm-@8_SלA@hDt?=-@ J4 [ˉT@M@ [ir dM@ [irXM@ V[ˉT@M@4 [ir dM@nR[H$\M@ [,mlYM@ [@~}wXM@ !"[k,#P@9?XP@!"[k,#P@ t [tM+P@v>I[Ts-P@צZح.P@\VTXT_{P@ *MXu.P@D.?ӭXZ2|P@XwP@0-X<`cP@\m~XpߝP@V&XpGGP@HX=ALP@7X8w蚬{P@sEX=pyP@p&؄X@kmxP@h Xt_zP@b`\Y(zP@L&Yt xP@`E<%YЎwP@-73Y(OIyP@0hѨ=>Y0%syP@z1MFYd\u?xP@OZTY׸xP@:KqY|R{|P@RQXU7X~P@9?XP@ 8ZU@ u&I@t]U@|I@t]U@ u&I@f#U@PdI@ԶU@I@ZU@|I@dMnGUp<>@xm$THjϐ.A@ jge=UX31>@g8Us^>@8#b8Up<>@H MDUd?@MnGUQP?@PYGU0j?@pm^DUX/w@@xm$THjϐ.A@?UN^A@8hh-PJ@{S]+PK"nJ@+PJ@hh-P`(J@|U\-PpPjbJ@{S]+PK"nJ@|gL}r\*(n A@tZD@. ,$n_\腹EA@Oھ\҆>A@(Ķ\\h7A@)\0Pw-A@Z$\ml(A@tK\ 3(A@2d \H!n$A@<w\*(n A@ Sҥ\D'A@*s\r A@VG_\A@`kJ\(9}A@|gL}r\ȺB@Sέ\ ߩ B@EӪ\B@ ?I\KJB@h&~V\gB@P\B@ e7\B@E\B@poێ\@>B@\8lB@ć*ۤ\Чp B@`{ \;9mB@#K\KvB@l`+|\hrB@ 5ܿp\IB@zh\`c[A@)ۈ[sB@xH [\B@f[xCB@A戛[`:BsB@ t]MZI@ Ux] >j3 I@`a]vaI@Ow]WcI@]tT J@;o]HY> J@xN/j\i(P@hE1[\MhP@¹\l9P@Xp:\.>p1P@hE1[8`-P@[i(P@$u\tmbhP@8AL\\MhP@KZ\@afP@xN/j\p#bP@Sn\n_P@Rn#\L1]P@A1\`z\9[P@\4\Ė4XP@1BWr\fL{UP@% W\GbSP@xԡA\#PP@,]N1\H~LP@l\n&\ KKP@TAm\o,KP@d\ܥjiHP@A\Xk[BP@g \{zU>P@@W\T[ks=P@ hl*@@0N@atj1@ N@ >o0@ȕAN@Ú:R0@@0N@atj1@~g2:AN@0atc1@Nv;N@c>1@hRj3N@KX0@\(N@`a0@Xc@ N@0հ0@h\[N@,0@8Q`N@B0@zN@ u]-@nlN@ C-@vN@@AY2u-@ipN@ X&^-@xlN@Zz-@P7gN@@ -@xY:]N@ So+@`4N@V#4X+@#N@j.+@][DN@!B*@ >N@x`*@HfN@ hl*@ N@8bfDB>@Z4 G@@Wsz>@88(G@@Wsz>@Z4 G@PyO>@G@bfDB>@^R$G@ $jD>@88(G@Jz>@@ifjG@x A@(nЛI@(5R@@@ifjG@hU@@i,3oG@@@KJ~zG@`qD@@pYXG@x0@@-~}G@G@@ o]RG@A*{@@npG@v]A@ȩG@T9A@LJgG@@[A@G@%yA@+G@EBA@ 1bG@ A@`G@x A@X,E(G@4RA@`-ŸG@0%Ԙ@@cH@?C6q@@X6ɜH@`*M@@T=֮H@?@vH@0l@Hp?@6MI@)z?@&FhH@:|?@5H@N)w?@-ﺈH@h>@(nЛI@Jz>@p,@sI@ z>@+_I@f>@0As]LI@( E@\G@wE@ީH@" E@\G@ئ&E@(iG@+S=E@gD>G@wTE@!DG@djE@8G@'~pE@9>G@HfvE@8J$G@O:lE@0廇H@7E@Ҝ%H@,H@WgT@GH@ QqU@+hH@C U@U!H@,\? U@H@U@H{H@PTlT@f^}H@Ć_T@zqH@hT@UdH@8IT@̏UH@^XT@ $qEH@xT@e-:H@!cT@`3H@t<˲T@c-H@9zT@eg(H@kϪjT@@"H@wT@X")eH@K?T@ȂH@8T@>AH@VN\U@2}G@0._ U@5G@^6U@`G@6U@0LJG@0qh^C@s hC@hC@p0b C@`GbC@s hC@hC@8oC@qh^C@p0b C@8S\@vSyG=@h[P ]@eZ=@S\@vSyG=@c3]@kQ=@(]@PIo=@h[P ]@eZ=@`>Iv5xz1FP E3xz1Fv5INFSa1jQ5a*1F 5 U:F`P 5HFP35۲bFS5L!F0Y54WSF@+4oZFpA4J_cFdά4F7ʶ4(ѯFD4XF0*4h_ GSrB4y)G`,:4D`GPH4Hwl^G6z48'KOGh {4X\ 8%KG ]q4`>I58 403nJIP E3pVDH31.I3(F[@z]ۭH@@)*[@N^@@)*[@z]ۭH@@F[@N^@@Z6IDX@jA@pX@HFA@$rRX@jA@OX@)qA@ /WeLX@`؋tA@6IDX@ #wA@pX@HFA@!%mX@As{A@D!%3jX@VtA@D(w8bX@!H pA@HL-,?-R@N A@>6R@ZTOA@t\P2R@ZTOA@l5R@ж/A@>6R@!A@ A9.5R@`^_A@h* M3R@qA@L-,?-R@N A@JH!A@qKS?@H ~A@8 #*s@@H!A@qKS?@`NA@Ӥ?@`hA@0B?!?@=A@0R?@H ~A@8 #*s@@Xk"A@@+12\@@ H \;@(P@>;@| xP@0Bb;@| xP@>;@P@Wp;@:P@j;@NP@в\;@0P@ \;@(P@!0H~ z^( E@ys^h.֞5E@ys^( E@"HDѿS@ :0@0d S@PQ0@DѿS@ :0@" S@;)<0@$S@L0@&IS@*m0@rBS@`u(ƃ0@0d S@PQ0@#gZSJ@DIQ!J@ DIQJ@$\Q(DQ](J@^QkϱJ@B5BQp%ߩJ@$ SRhFcJ@R J@PUqR(R-cJ@ yǽR&J@P>IHR.J@UzRPJHJ@|`TRziJ@0f-BRw J@D&~S@ sJ@PŌ*SKJ@ЪqBSpU!J@PjxLSTuJ@BSwSS( #J@gZS!J@$h؂Mj]0%0N@z'm\@ݩlN@ ؂Mj]XgN@WT(N]{`@N@4]̌N@lTn]P~}N@4>I\0%0N@bB\1b_N@}]N\N@lС\h JN@l\@ݩlN@z'm\ꤼ~N@%HM[p`F@A a[(oF@A a[p`F@p;[[PSWsnF@M[(oF@&X$]u-T@|'5@XNiT@䯄5@XNiT@|'5@|T@l8hS5@T5T@P+m5@{sT@䯄5@%T@w|5@|3T@0%S5@M6T@'Wl5@$]u-T@Z 5@'J ŨW`jG@\(W1`fG@#!W`jG@hW$G@OZ0W1`fG@\(W)eG@H3oWڝkG@ ŨWq{QG@(8 M'[E@LՅѣXL$VH@c9S\dHZXHq E@`iX@rWmE@AXP%qE@דXv_E@"L=HX UE@{ʮX+E@,q.X(r E@X(N E@xgXYE@G4ʿXȊQE@0X@s˜E@)rX0֌E@;l X)E@LՅѣXE@][`P.f.G@t[0 VF@dJ(Y[OF@L &Y8< JF@ #Y@)( GF@@4r#YCF@G#Y7@F@@S"YPSIiqY0WBG@P{~Y@8' G@TY`I۷YH@ǑYL$VH@zYЌvnH@t뮆Y ^ H@AY0aH@Au~Y}<H@QYqH@<]YhSH@gY8̧YH@XآmY8 8~H@x|Z`H@E>ZP̲0hG@PEdZM5G@f GZ8TG@PZX~:9G@@ֽZеMSG@vZxG@xZ6Z8^NG@4\IZr@G@$]&~Z``G@JZDG@ ;ZG@\ Z|AG@ D,Z@eG@,JN[8eG@VĐ [Ф#G@)XYK]g`B!@:<[=  !@YK]g`B!@fYU`]!@&̦=m!@  j !@ޣ!  !@/n̦=m!@‚ 7cJX!@:<[=¢_R!@*JL*]@b@ת B ԹMhb@@:BHzaab@ת B|I$3cb@0nB3Yeb@ B ԹMhb@(GBL*]@b@@:BFb@^K'B+8|0R!@, j;"@,0R!@Y $=!@|`b!@YIm j;"@,8)R@0bnD@u7SR@8iD@u7SR@8רZD@!;R@8iD@FT1R@;q D@)R@0bnD@-0tXW}I@ILWvީh2L@" cô?&XW}I@hj&X_{I@Ρ](X{྽I@3r-X l-I@\sR @#z$@@7Rv&@Xw$@[Z@T7%@ޛ 0p.@;R.@tX ~D.@4u/7@d\/@0^04?@9h5@wnu@@07@ "hp@@07@8Pt@@D7@0[bKs@@019h?7@aeo@@`?Jyd7@⛸_p@@{7@`)k"s@@TLj7@wnu@@0-ST7@Dsm@@P(57@8C(W@@`i7@0&K@@.#+6@ZI@@pSPo6@ A@@\L{6@H65@@p6@Fc)@@Po8#6@(cs\@@ӷ6@u-@@Н#Ļ6@.|3V@@M6@~?@N\'@6@?@#6@>@?@u7e6@K[?@b@6@׋df?@ 6@H\?@ 5@0o޽G?@@hy:5@^04?@9h5@1h(1TT@0\J@QZT@h/lK@ QZT@h/lK@"T@Xf>K@@T@-K@X_m/wT@v0*K@D9doT@ H~}l"K@hT@ +r K@DxiaT@HR K@_XT@WK@(1TT@J@ϰaUT@0\J@2Z+J8@gP۩>`9@Щ=`9@ЦǠ>9@+>pY69@%PҔ>m9@48ȥ>~9@gP۩>C十9@ [>+J8@Щ=cS8@lXC>3H S1E`@0S0X,h.`@@OP%"0d.Ĥ`@@OP%"0 S1E`@ tB1o0`@C0`@P90X,h.`@?40lzZ}`@0S04Xd͋SPF iG@h^S5G@h^SPF iG@;[S(d)ςG@,GSXA| G@lHSpZ_#G@آS8ШG@4aS`'G@d͋ShmlԽG@4ƑS5G@58RwS5"@܍1S+)"@܍1S5"@a gS*39"@`Gb Sa*N"@RwS+)"@6.?Ip/1;3 V 'GPtB+2 ,r>Ip/1;3.?I`2wuX:ItOj2C#/I+a2IOik2 IpAh22#H0PtB˝2a9H`mVQ2G&HW2a*yHpFIS2`:ލHBpc2 V 'GPtB+2ZG@&a2xr2G*r2`5Hp,o27&NKP#n9`>I+;3 &NKP#n9*ZI58 40s9-IK94Z9I^N4xҲIrBq48m-z5_X7K@@Jm\TZM@Фs0^ﺷL@$yܞ^еMZL@95^0L@tɻ^>\ L@L^`gL@6.8^،.L@ܤ&^X7K@ p^ީL@0r ^(Ag2=L@;ld^͘\L@bQ_ݼ L@|h_> L@~_B1L@)42!_͘=L@,'ˮ'_mc1KL@m-z5_`L@KMt\TZM@@Jm\]UM@9(EC^tSaD@;^yIdD@;^yIdD@EC^tSaD@:@fSx6G@,;S`5G@4;]S.G@X:+^SAMwG@4n^SpA"G@ϵ@aS?G@$|SeSps{G@uY?gS:cG@bgS-wG@pobSJG@y>TSgG@8{ESSp$G@dIPS?HnG@L MSpG@JSS3G@NGS@co_G@o]N{ESP)$G@aBSx6G@,;ShG@`EnVS G@'SJ G@@fS(WѵG@aSXEG@{daSީG@ bSPG@YkOdS`5G@;JVkXW$NH@,`kVtH@VkXW$NH@E1WhtDVH@,`kVhcjH@lJ)V0&IsH@Sr VtH@JVhh QnH@<: m-%!@@NΘmG@`*#@JG@H]nLA"@JG@ m-%!@(WѵG@]"@JG@`*#@@NΘmG@=HD@pi40G@v@h!7G@D@pi40G@%UvR@So*G@Xv7Zčk:@ ֓^XȽ@@  (5;l7X|~;@lbX;c ;@=k[X|:@Ox6XP*;:@ ֓^Xčk:@hy~BY}u=@lSY0:BS=@7ZXتt@@kZ \۠@@|qU  ;j&@H[3PUP,&@&~wU@ϟ2(@DqYgJ@9xzXKеJ@ ȭ!X7]J@p?X~QJ@HFXIf2۷J@9xzXbJ@ܣYPAsJ@L*q Y^jJ@1Yxp ٳJ@(~XzeSJ@SwXO,J@ 8O\XeJ@, XJ@p#XgJ@HaY@?0djiz>@"?H(A@-f݃-PA@U8-A@U8-PA@-f݃-I(l/WX@;9I@s%OX@鈴I@s%OX@;9I@l/WX@鈴I@JT8^\SE@ikB["LE@4y=T\SE@8^\3fVE@nF7\hE@Н(\$E@ikB[i#nE@`;,[>`xE@Ђ["LE@Kh][@#qQI@TrE(Z\[I@ Z\[I@TrE(ZI@-=Z];I@%B\ZPЅI@ ֦Z7 5{I@DiZs|hiI@Cp1Z4;\I@VZ TI@xdZ@#qQI@][:TI@L(}3.@@0;@.>@@WG@@Iyl>@@WG@@0;@.>@}3.@@Iyl>@M8׆C@:M@wDZ9C@X)M@׆C@X)M@NC@h3M@BC@^M@wDZ9C@:M@NZT2S@ I>@|RT@$l?@|RT@ I>@bLT@Љf">@ip0S@zOh?@̍/S@`iU?@]ο-S@P SgL?@*S@5*G?@Qy$&S@|mN?@T2S@$l?@OXi?@ZN@pni@@0SN@i?@ZN@PW6?@p.4N@0s3]?@6BN@`3% @@uPN@h♞-@@0SN@X Y7N@@ H LN@(̰fZ@@AEN@pni@@@ =N@Pt ?N@Q"D@pWbQ@PQG@  pWbQ@ "7D@ =bQ@Xjς/D@0NQ@Xj*(N*D@ԚLtQ@Q"D@+Q@HED@^m Q@hzD@4 :Q@.&D@F,Q@H.D@biP@$D@MN@G@ ?N@PQG@QIkFpWZ 3hD@Q!"h[[FpWZ 3@#F`aE2HgF@V]2`sԟF*R )2H/̭hFb?u2IkFC**a2|FpC 42eb1EFl5I&ŢQZE܈%xE@ )z%LdE%0QE Y2rF%T?E@@$p (8E %,$$ 9Eg(Y$Y3E;G.$(cB%}&Ez $ɽE`Ux#pmE`;#xD1S#d#D`(Jc#@JDD>KZ#Xn_Dr ;I#P}eD Z! ##( D"eiD@Q!"hD:g"RJ3:#wt C@]IP0X\D@3:#w) C@yxLgXFmPC@nt C@X XfiC@0i`nfCD@]IP0X\D@S\=c!VבIA@ECUȌB@ECUבIA@hayU aе`A@?SUphA@ q;UXBjA@g-8UOhA@jBUq+bA@lUУA@ 6;Vp LJA@!9wU`qB@VUG B@PSfU}B@PŀVp @-B@xVnW=B@N-Vj,ŏKB@84FVne|^B@\=c!VȌB@THL/է`hҵM@gw `xH^j9N@gw `hҵM@FH`ѡM@P)r`@sN@uMG`N@n`xO!N@L/է`xH^j9N@UF4#Y5Z&O@|OeW4q0P@% 4#Y5Z&O@q5.Z &fO@z΋,Z;O@ꂍ*-ZHRO@vn~X|JP@H0զW2 P@t)*!W\N P@d!Wx<-_P@5pW`TP@ dwWXcP@|OeWHVP@hsYh RP@DԅQbY|~P@p؆FX4q0P@TL=nJX3-P@|Ǘ{RX`-P@Բ0`XT&0P@d{qX\jd/P@ݨX^&+P@AXA*P@#P@NRXH#P@|\X"P@`3PXv'P@hu7XЉiP@iX N#P@ĤXTM%P@<>IXL՝e%P@TUX0n&P@Y1XLU;(P@ YER^(P@P9O Yȅ%P@Y9 $P@d#2Y&P@VX`H%V١wHҒ`HҒĆiH@ < 7H0W/Z 9H9dۣH}' ՚He\6(=H%V١wH06&6WH)TQ.A@h1dTpƜLA@)TpƜLA@`Tq dAA@5qT/dK@*{aKGE@`RAL@I_TE@7L@ȥE@ L@Hc]NE@/bCL@E@P͸L@hoE@lL@h\E@{1L@@~дIE@*-L@ЊTXB@pIp`L@u0pB@@֫v7dL@ 7^B@,nl_L@6Q:OB@-UL@`GcBB@pTCRL@em/B@,iZL@H,fB@[&9L@0B@(BtL@( C@h'h2L@*&C@+L@U׫D@`$L@46RaD@/L@D@R@L@%|D@0WZL@`qD@'`L@>)6kD@UL@ں=]ZD@qL@H?D@HȌqL@j%D@hKL@hD@L@o7C@(>M@ vEc)C@8wC M@ (C@H:o*M@9/4C@$M@8ZC@F{M@_:<[=ZOZ@?_R!@:<[=¢_R!@P 9`B/ƍ @&^=7Re @8ҿ" @Qÿ7@~l蹿3)P@ۦ˨mT @]^0Q@`rF ?@@ ?s:@h}?Cm@U?2]p@?@q\?W2@@ey?Txt@L4? s@@_?5@ī>?M@?@1^@hH v/?<@Hf?@g.3@)u?ZOZ@`R*;QP&@@_AM@mg&@&M@H$W&@@_AM@G g&@jM@mg&@aſM@T(,f&@0bM@c&@Х|`1M@` |tQ&@ FnM@*;QP&@&M@az U=@H+N@mA}i?@Lc[N@ r[z>@~IN@=L>@`5SN@P̲>@⤼VN@vBH=@H"nUN@t=@ M4VN@ U=@Lc[N@0R>>@ PN@PAU>@@tSN@0V*>@@ RKN@p"K(?@0=>N@mA}i?@H+N@b@\Өe@n"5xCEsf@XC\Өe@n"5xCpλe@HUTuC,@@`-/`e@@6bK/pD?@`2fU/?@L/'D>T?@fR/Pl6?@Wh/@k?@rh/ I>@6ŹH/f [PnlEM@AY >M@MAYoXM@AYPnlEM@ [@~}wXM@PSZ[v=_M@[ahM@h,9[QwM@hn[*(M@y[cd(M@gq[xpM@O/X[hVʢM@4F[@h5M@Ȋ:[(;9#M@7)![)AsM@sZM@OڳZ >M@Z#M@ɚϽZPeM@xv+Zv&M@P0/cZ/wXߩt&O@x֫jJYQ.O@j/YP-O@T/uY BO@lw-vY+.9O@|ptY84 1O@PhqY0n`x/(O@xiY񡟳%O@ pWYU.,O@aXMNO@ZX(7n[O@!FX@`O@smuX(DaO@ lXF<(iO@UThX0+Y}O@EaYXxTO@@cbbYx)9Y #0RO@t٨ѧY6JO@LZߜY#n8BO@:Y#4O@ {^`]Xq'O@83aRX8KJO@hR*6W0nlO@LDX` uO@ }uq$XxO@QP@0Wth P@h`ПJ}B@e=O&@c B@@k ˵'@ (?B@e=O&@`zςB@J{=b&@ПJ}B@T/&@B@@JOK&@.i^B@ ('@x[`B@@xfP'@FcbB@_Ef'@c B@}'@W?)wB@@k ˵'@iw;A@@#@AC@ D'@4 B@ D'@0[B@E$'@xB@Y"'@ԘB@7'@0 B@pڽ&@0B@)wD&@[rC@M_&@P&C@@]|%;&@@1(;C@ &@@ZL@C@ 8%@AC@]J%@6i@C@e%@p3=C@ 9$@ "8C@7Ff$@bZ0C@`|E$@0}3 %C@ N>$@(0"C@eS$@ZB@`"#@ȰfyB@@#@(ځB@@8ԙv#@ЍDǾB@ { $@MB@A$@ ^j^B@$$@襆 B@`ޙh$@DvB@ v$@h1եB@W#'$@`VtB@`'5$@|B@\ ?$@H}3&B@Gt5T$@%̘B@t^r$@8KWtSB@e$@ B@$@vVB@`Ctk$@W8EB@z%$@P AB@X$@G=B@` a$@ S׍9B@Rԙ~$@Vt2B@˝f$@)B@Gtv$@J!B@"hO$@ NB@; tI$@@}A@[ 8$@Pϩ,A@Z"$@X(FcA@`Q_5$@+SA@/$@5RA@`jH$@0GA@]z$@i5A@$#@H4LTA@D1)#@}Wt^A@!|$@<mA@XVS8D@І<A@D@'KU`5!A@mDO|]q־/@@UHS+/@@ҡUQ'1@@iIU|־/@@HU+2@@oULKJ3@@xÐUs2@@4UOgn/@@HÐAUH+@@@@DGU^k@@4rU(^@@/ UUp @@7rBU3] @@yGUz@@@$4U@@\tU8E@@xU?@DjVU8k6?@̗dUY?@\Y1U?@UGy5?@ U??@Lq,Ubi?@pѼzYU@?@RwUP?@,4aUk?@,bIUdi?@U5a?@hŞUQ?@*BUŎ6?@,U {(?@XU`|&?@#3U`#?@O]NUkj?@0ZU#S>@,x#UvL->@L"WV0 w>@V*>@aaVЎ%W>@q<U;i@@rqU `@@0r<Us@@0ٗUPv۩@@4UQHK@@\MƏUd<@@`]UĴ4@@/EU >V4@@DiqU@@@4U0 @@TdU0n$@@'KU`5!A@<`U][A@ jU"t/A@!lU 6rA@,|ӁnUNgA@c3nUHu7A@` ??mUA@ S$mU(QA@P44nUodA@Ԑ[qU~Lʱ A@AtUhA@PJduUH A@>PvU@ A@#8wUpf2cA@0bxUpf2cA@d|StyUnA@<yUMA@XyHzUVA@Y1|U\?A@jd}UE@@}Uc@@~U(O@@B]U&@@lI(UH`-I@@ ߜUk^@@q7U6a@@HUx "@@:UH T@@X0qU@xC@@0PьUXXi?@@lH %WQI@x6tT IJ@N?FHJYֹV W!ψI@4VQI@ູ]VQOϋI@T80wV@;;9II@,deV ㉣I@d[V ^I@)RVP78I@(tMV/MI@|}J IVI@h)FVFQI@x]BfCVHI@\L?VWI@(]:VĽI@@3VXMI@Xj,VrQI@4`L%V%:9I@: Vf7cI@EV @sqI@`t V8a, I@HgVزT.I@FU(I@4U8&?I@ʹ]U6/ @@I?@M! @г?@ @ |?@\ק@nAg?@S9@01(a?@gq!@ %7c?@9n@5qk?@ԌY(@jӧ o?@9 @pLm?@c5@K,s?@)ߴ@죀?@xÙ=@?@?@=y?@;n&4@n8*~r ^@aCL@0Ȳ`@xjϵO@>;^@aCL@H3_^@qGL@ |^@(cwGL@pd4^@^@L@9.r^@@CީL@E^@#nL@/W^@L@`#^@ M@Xu^@YM@`"^@PˁoM@^@"M@J^@yE%M@W_@ȉTN(M@v_@2 *M@X*_@p x*M@PA_@A.M@Z_@=6M@>_@j@M@ t_@h elPM@(L%_@p977\M@b)_@`Ng_M@-_@jO>_M@!0_@xir saM@Y2_@cvfM@`SZ 6_@wZziM@ <_@X{RjM@B_@XnM@H ;F_@ت @0tM@Pe̍2I_@ @yM@p^I_@D:9o~M@!M_@ >U M@g9pS_@`x}M@iU_@Ht&aM@JS_@8ҶM@`1S_@f51M@x*i|U_@(`ΕM@(J?U_@ @cM@A)T_@wCM@MT_@ppAsM@srU_@@lM@cY_@@Tc0M@Za_@tM@Ih_@ȇM@^/Wo_@{Z&M@}r"x_@tDʋM@po_@OHІM@`\_@[0bM@PL_@h.5zM@>3 _@P @rM@@;dz_@H`dnjM@_@}cM@$a_@F _M@`*Ъ_@5$_M@p8G+_@.eM@xu~_@ VgM@p%_@ TeM@la__@,LgM@p\P_@PݩkM@x2_@{lM@0s_@띧iM@}r(_@hbeM@XΎW_@k_M@;_@vZ[M@8f_@2XM@`@XR[M@`@XiZdM@h`@vhM@a[W`@HhM@dA- `@iXeM@* `@][`M@4 `@abM@LRKM@D8`@EM@`@]QBM@p{m%`@oKBM@ap*`@|耳EM@/`@DM@p5`@3?M@Tw:`@r CM@@ @`@hwRNM@fG`@RM@󨼿N`@ #nOM@r=R`@2ePM@ZxS`@TM@ȆߌS`@h$.s[M@@R`@@udM@[@S`@'jjM@јT`@xinM@IY`@`$sM@DV_`@PղxM@X;d`@wM@L|ûf`@,sM@𲓁h`@ޏsM@Bߌi`@ZFyM@zk`@Xșe{M@ m`@)xM@lL-p`@ؑ'yM@Lpet`@ѵ|M@HEx`@% >M@` c|`@hKʉM@T~`@;9ΎM@y i~`@p M@O`@H\AM@ a`@)M@S_`@oM@W`@0M@svl`@((M@Tə`@x@{M@ݶ`@0|OM@ldxܡ`@؛f2ɺM@OB;`@AsQM@a`@$CM@P R`@(`M@TVIP`@x.M%M@:`@N@@#S`@@7"N@hg`@/d8N@P@i`@HN:N@`@`R8N@e=`@1N@ĒW`@w Q 2N@##,`@@#9N@a`@@N@ZZj`@(a`@ @H`@X#rO@G`@.O@Kߌ`@QݐO@`@XhmlO@l'`@O@)ؤ`@(4GO@ `@Ћ$O@xI`@|O@d`@?O@( Y`@u,O@m;*`@&O@B`@ &O@ :`@ZO@Ts`@XO@ GWj`@Y5jO@'nf`@3WVO@ 9``@ #O@$%V`@pQO@|M`@EStO@#[C`@87O@$&F,`@xjϵO@ox{jSP N9D@\ wSx=eE@,\ wS~zD@p4rSD@|PS8\[D@,4S[o'D@XS @ZD@X"ySx񼇛D@LzSE@͋ޚS8<E@TJS8l E@ScE@ēESx=eE@SFV!RE@@=@SE@{Sx޾$ D@$ ĄS55D@ȾVS #D@i#S5nD@$"ES{D@aSPK3^D@];S@nW0D@4SD@SD@*S2 tD@4S#nnD@QS;D@ѨSxai޳D@tȝS8eЯD@S\ D@jSD@t]S8 aD@j"@S࿵MѡD@P*[SR?D@hSV!͓D@`]S˻}D@ (n_Sh:9D@0WShO~D@ԾST1b{D@htSO!xD@*SxCsD@ 9S`4qiD@O;Sh&QD@:lS #|BD@S8`:D@{jSP N9D@p ǂE_RO[UJ(#UJ(#oJ=4a!PAJQc@pE‹J*8MͭJW j UJ;Chm(JxT@KJ.bN2KBv4!-w6K ^"[K`8h ;KK!6CKQą-w5HK=0aQKMlZEyuVKX0pXVKXKܑ yP$]K6H.,eKAvcoKwx -szKFmHPׅK}5|UOQ*KƩ6q@?nK(؊M|KY&sf4ZpKn`rǐKc1`[K3u8cKyLءK$'I+K?4rjh~{KU IKML$wwsubVLLl`L<@vlL<6iֺyL9i[Lj/OVLNihGLP6~dG/L,RL<.8NL;S*Pxք}Lk_lP/LIW^K;LE88 pM$Y 1FM8sF;MΔMhQ wO"Mz+ն kp(ML۱ `¢Ѩ0Mrdl, HC9M s POFM%O g5RM=a2n Y2XM#s  gMT ]qMnÔ 0)}ML* QMP aћMt 8A5ӰMWy ۴MtMg@o#M ݉`vXM{h8NMgY M&^ `VM$˥ pdGM# aܾq N.q x4N n2#NU7j l4Nغf ˭LNJg -_N(H/ q;mN7vN `{sN ȫC%ܣN1J ,ػN{th h?NRb^`Nuk^ UN|o7}`BN{+qoO't*@\#Of #xր//O FY2Oc. 0ZB%56Okݑ 29O^j(S6EOQh//ZOmY C(snOܩn URO} rcO}WP1@|O@=@IQO@;b#=O&P2`B6O bO( E_OF[]O*֏`uXO[xVOȀZs&~EPMtQ&~Pye |`TPt0 zO$PW~/ Ե2P˴r tOZ9P$  vDPh|KP~mCe0kRP[D;AYPcy4[]PyTNY^P{oUn_cPPv Q䫩+P声RPQrDt~ǂPͣP0̓PKGT P ©\ݡRPXM;PļV*P_2l3PF=X)LPkh? h-8Pc}C غt9P܉ pRw Q<֫ 0QQ[l|t  &QT t!cEQQD O݄VQhk 䐲YQT> vqQk`Q>oʮQ lX\QăuDQÌ?Q PQK[{\QkWX竣Q^8uYQ (8O$Q;yQ)9^Ql8V#!Q*0 *mQzy^Qm1Qty(!QV?3 kQG. @NL Q.( IQP x?u~Q5 { RFm tѻR^ gtR%$ @z/Rg y78R©v $?R 'ER< q~KRg# EMR2MC<gLRO_@MLR^q@e@#'NR'V.QRb/_'`UR)6wl(gWR]N&uCWRFZ+ XR@;d'S[RG]RC[eX ǂE_RO[q:(M@:qyB@$ Q@~v6F@[$ Q@ȌB@WQ@:qyB@hOP@j|B@gP@N 7B@(ibP@`D$B@ |/P@B@$P@XAB@FP@p){B@kP@5*B@P@"B@MDP@ B@\+vP@ӚB@ؾo~P@H|B@h)hP@۪B@giP@7B@Xݞ2P@xךB@TMP@5B@P2=1oP@@͘oB@rT^P@{B@ {oUP@hiB@`NP@ tB@XcHP@}][B@F:P@`58 C@ݞ*#P@(g2C@pmP@ @S7C@\uP@ 1RC@p&O@ovWfC@mO@&sC@xCơO@0$T9C@0RbKӴO@FC@fO@(3EC@8(bO@x .C@xׁO@9C@%O@_HC@xFrO@PcC@ZO@wC@hZIO@U!C@P,8O@ D@N?)0O@*D@P-&&O@ .;D@Q: O@{EED@X8( O@&vWD@`0_@O@}grD@UN@D@,{N@9t&D@pyr\bN@MD@`|3N@0XD@8a N@ ~-VD@ᵭN@0bԢD@xN@hzRiD@h6N@D@ѯfN@~}ND@ ZN@xiD@J,tCN@.kϋD@ =N@VMD@5N@Hͭ D@ؾ +N@PqU!D@C%N@ɗ'E@h'bK!N@& E@ՄmN@0bE@u N@POYE@T(ފM@`K%E@XUM@x ;9+E@8jGM@HzH5E@gZҼM@~BE@1=M@HS;9zIE@=M@KE@@XM@ PE@2vިM@85DYE@o#M@9͘;_E@w)M@/bbE@ M@XAеggE@pYeM@lE@]M@PfsE@H M@P{E@x=ɑM@ЎFE@PdGM@7ȊE@@:mM@ QE@bK+M@x)mE@sM@*(ӤE@M@X/b)E@MDM@tJE@8|y%M@͘SE@9iM@oE@8ӈyM@9cE@r\`jM@S\E@ jSM@͘E@HM@([E@ovIM@`F@H\͎AM@87F@:(M@~v6F@r]dy_@uG@dAޚa@KީJ@cxߌa@(^0H@xVa@x*(UH@ha@p͘H@ha@ .$H@Ĥa@:H@ga@:FH@Pʙ a@FH@^| a@hZSH@\Ĥa@@U*(H@#Fa@H QH@`)-a@XeYV~H@,{dx*`@x]hH@DcL`@$gaH@Fe`@\F`H@@]I`@@GbH@<`@Ђ,IbH@By`@x@n_H@YT`@Y-ZH@Aw`@\NgRH@}k`@p"IH@88 `@xF+=H@,<`@5H@PaQ`@},ū1H@\`@@O 1H@`@R4H@Kr`@33H@ `@XN.H@;H`@0- #H@4Z!`@q H@ AX`@+H@п`@4o H@I`@hc H@} `@ H@夠`@X)ml>H@<;`@8\RG@Һ`@wCTG@X0`@p ?G@ta`@hiG@4:`@Je^G@Ũ=`@+G@;BV*`@"_G@xV˄`@P>QG@0r y`@uG@(q`@VLG@0L-n`@h녷~G@t4y&8j`@J(G@dӗ+c`@P KG@pn``@0 G@`^`@G@@P ]`@0AG@7 J]`@P?G@p([`@xoG@F3qW`@(AsvH@7#V`@@EWH@0Y`@0 H@<]Y`@pj+H@N'mX`@01H@HvW`@p77H@,}U`@`=H@S`@)eIH@tїQ`@MH@0iR`@}WH@lS`@XM=VbH@ZcQ`@Ho#;nH@`ݐq^K`@p7xCnH@EF`@hƴM!rH@;/A`@Nr|H@W\9`@ +tH@!y5`@ ͘H@2`@ο$H@*PJ1`@BeH@vu /`@JıH@;PJ.`@(.ٱH@DzeO,`@(.ٱH@4|3+`@xzaH@HQi)`@zJH@#'`@eFwH@{%`@bѰH@6'#`@WH@l"`@`ZH@o `@hJ@)RP@Hcye@Q'PP@&|e@TsKP@,)8e@E*IP@;e@4xIP@\brke@iiJP@lLZ!@e@MP@Hae@LU>0 QP@pe@xTP@mBVue@d_YP@We@HR]P@,8e@4xaP@p Le@ȊbP@~e@ntbP@(Je@hnaP@ثe@%`%`P@ fr%e@AM]P@te@$OZP@kz0e@lt@VP@ e@hSP@s|e@lJ`RP@|#ae@xOP@&Fce@̵JP@4be@ՒEGP@ ae@EP@Z%e@`@q#CP@Ae@LqRAP@.e@Ho@P@ +e@0|Y@`UsM@!=Y@آ GjM@aw8J4Y@`M@@IY$Y@8\[WM@T)Y@0>HPM@J?)Y@@ @LM@&/Y@lGM@qfY@?M@${B=Y@pߒ+$8M@0"Y@G/M@<Y@.R,M@X3Y@ku&.M@ "X@( ݬ4M@\*jX@(z>M@*;X@X.DM@ԩSX@aFM@О6X@8LM@lbX@PGqTM@ƜoX@LYM@e'7X@0Q[M@ *%X@ȺYM@lݞiX@hSM@ɟ3X@PQLM@X@(4Z2M@ 1;X@x <3M@ۘg6X@WF7M@(w0X@0]5>M@op X@#}CM@(CX@g26EM@PZW@VΘBM@*9./W@8ZJP1ab JVh1*vX͙J7M1Z?J(un51R2J y?1-w@J#0`.[pJ0z 0H-[pxJ H0P(eJA;y0 sWJt0 b*NJpw1m0s;EJ# T0 $HF2I`DwZ$2+I@q $H4qIou#`* I"@/wTH`ݸp"8o:HG "@OH HfE!P xHC!B=H nh!@1Hѳ i/HJ X9HKlG }QH CDLHS|1x+g4Hd02H[@ݒHFE <ݬHuV0i1H@Δb-pښH<.HlgHfihDSHH@]@xHH@n¶w]@H@wTg^ZR+@@wV+ QvC@wVR+@@da4rV.@@ؙnߓV`ާY@@~OZV@@{Vv6-@@8RV`KJ@@`+VX:@@E%V:D@@:,V8 }A@HǑV%A@\ VК[A@ 'BV}LJ|A@R#a3V A@Hx6V A@mVKA@.Vh)(A@DVȐݩ"A@V@T("A@!EVsd.#A@!W،p(A@\ČdW)H9A@ WH~HA@ WVA@hRdjW7`A@ HcWhA@tBWMApA@ W>A@sߡW`%A@&BW,TA@d܅W(㝩A@t 8ϨWֈTA@'WX,\A@ kWRA@ʂWx A@{ZW[{mA@ WCA@-W|ABA@3*W?A@dWvA@hGWf띆A@W}t&nA@Wh#TA@bmWA@b*WA@(!Wh:A@MW0wA@Hg(-WiA@@y,WidA@ mLWGA@iBSWVB@(BX-QB@`? gXN7hB@XVT XH-B@3XP`BB@gXx4BB@`a4r3X0KJ B@>4r'X`H3&B@ X褋q5)B@pJT!X(V'B@ ߜ"XI}*B@L!"X0B@#$X`͘5B@`L>I)X\37B@t-Xҝ}B@(`?XP7AB@|L>XHWVEB@KJc 8XptfB@vECu:X@Y>nB@8q;X}B@bZq?XpyB@DXPE-ŌB@`kHX% IwlX8Nq sB@O|X Dk1C@7X0)I,C@0ĐXp$,C@P[>ɡXf @s'C@XX){C@ XH6$C@\xNX".B@ckX@<3B@Nt*Xpz][B@]1Y3B@'HYPgIB@ssSY=`B@4WhYQKJB@#Y8>]nC@\.ģYxzC@\eOYz C@ RyY`lߩ] C@,2B&Y@~,EYC@YC@HY e C@EIY8iMxC@1ZpDC@;.ZowC@8L=GZ(KJB!C@g%)ZP1m_!C@"4ZF"&C@$.F]9$ J@ʮ;]ީOK@P$']LIK@4]8 9K@.8&] P"K@1s|]}K@$&\`K@0Z1T\hN K@|g\@7K@j;\OѝK@8dV\'m$K@lrZ\q j*K@tL=\0h^+K@@J\`,1K@‚ \`=K@j1B\THK@pCyvz\H% %RK@O\KfK@+'\#8JK@\HiK@ ;,p\t&?K@Uf\G-K@7]\@OEK@MgZ\ﭓYsK@:)\\pf5iK@ FEZ\Ȧ$bK@]NT\X _K@ЋP\.bK@P dM\TlK@|?D\nlXtK@wg+6\pzK@|WA.\ZQK@;E/\(K@4rh1\hZK@h;Y5\BK@q`6\X{`ՎK@H}4\ޤfL@zK[pWu&vL@tL=6[Q#L@$[+TL@-[@6HL@$/La[ \L@ƚ[ |L@->[ A۲L@]VT[.L@xn[0L@0U_[3:_L@?I[@FL@节 [ L@][eM@?[}M@[8M^ M@R([ЉrM@80Ua[,\M@S[|M@-8[M@4[DH%M@H]N![`;l[M+rM@;a[eyM@2I[8M@z5[W@0>d.0@t*37aX@;u9@vt*37aX@;u9@hĂ`X@P毌9@lv8`X@PkI9@pa]`X@?B9@m߻\X@Oj9@8G3YX@BV9@0|UX@AiY9@@AdRX@@w;^O9@dHZOX@,979@ OX@p '9@hCRX@pNIy9@#RX@05F9@W=QOX@P_F9@ d.0@{8{4[k,#P@WtPuP@C+9{4[k,#P@@W"[k,#P@ t [tM+P@;Y`NfeP@Y qfP@HiiYhnfP@(Sw`Y0)RhP@Y`GkP@@&Y`NnP@|&>1YofqP@.'ZY1x[uP@h:IqY:Ә|P@2XS{P@|kbX%exP@|JsXNxP@\ʐXTzP@DƖX7y{P@7giX<kxzP@rIXB{P@YeXH^}P@r.܃XTwP@\~X P@0vXe+рP@plX8:}P@"aXô|P@RQXU7X~P@ Qĵ?XxrP@])Xc/݅P@fX맳P@X 濈P@JD Xỡ5P@!XH YP@<ІWWTP@AWsٝP@&#WlP@WtPuP@|ٝ.-(Gp. %@[Un$oD+@9ٝ.-(b".%@#(V%@@ d'Gp. %@ FI'&%@ 6+Ռ'`vՙ<%@`eC'5/1v%@@w5t'2c%@`Wa'P%@v. >';$%@Svo4'J%@ 9'\V%@ ')' <,:%&@p'N`&@W&`U&@`j&X&@@X&D&@`Ďe&x;7&@A&t&@@"/&@-%'@P,&N2'@\&n[m&'@@R%tA%'@`N%0'@`a|%c4w'@[-%`[{'@`a$ ~G(@@u۾$ o[(@[U$Av(@Dex$smu(@Ұ$Ct7(@񌀔$`UZ)@ <+z$ E)@`,['$/a])@%C$4r)@[Un$mЖ)@@Wq$9G)@`11$`\)@9Z$@k)@@Wz$lX)@@F$ j0)@ d$ w )@՛W2$@|S *@$,F*@n $`ѭڅl*@%{*@7%/*@y5{%cW*@@K٪%`dO*@`n%@*@@|%@&,*@Fy%?: *@`u:x%o*@^jÁ%5q+@@ex%>wG+@`B%cx+@%R豀+@%oD+@}x0X)&>@@SУ@#?@P"@ 0X)&>@@SУ@Ŗ>@`2` @`Gy>@ڭl @pSf>@ @0"G>@@3!@0p6q>@!@(z>@`NUHH!@P>@{ !@f>@=pԾ!@oޫ>@`!@ >@`MF"@#?@P"@~Py%?@R @W҈@@?@O@pw?@g@h@?@*@Me?@)*M@ ?@@f,@`:v?@n1l@9?@`FA@ ᜢ?@=4D@&-?@gNX@p~1?@32@?@~3@о-?@@30[@9?@@A?@0P?@{MA4@@^$`>?@@,K@,u?@|t,m@KT?@@hwS@Py%?@@@kBj]@- >@@8@@$Kڝ>@_@ @">@&%@ dF]>@"-@?j>@+S@h:!>@DJ@">@@𨕝>@@;"@P!K>@@C20(@fl>@V! @@c\0]>@ G0? @էET>@SaEH @0bjR>@ RXSt @X>@ @b\0V>@` j8 @SYK>@@袠h!@IH>@@f5.!@V07L>@ N!@\FI>@@qh!@h?>@,U{!@y7>@ 3Ʒ!@08$93>@`6!@';>@ 1"R"@ &Q>@ xK"@@EY>@07y"@PҧCU>@љ"@#_ͤ^>@i-"@Pr&`u>@ %p"@27T>@@#@0~R>@ 11 #@V<?@kDt"@P8c?@s"@jX2@{&@VD3@!@ VD3@{&@P(3@=@Cy3@@xt$g@Cy3@0@a(3@"w@`?tc3@!m@ɢT3@@0@–xY3@ 3 @@[0I3@ с~~ @pu{Z3@2ƙ2!@3@`fO!@P%`n3@Mn!@jX2@!@xCP\@4w 1\@!М?@o\@!М?he'Ʒ\@DV?F\@3?i\@t =?\@̔?Ŝ*\@H^+O?3U2\@t?+^Ǩ\@d?pDf'\@$.?hw8b\@t?6/\@ b?`o[\@HH? 5\@(o/?Hla\@J?/WN\@0$Ԟ/?`L^\@ ]?p!@hC\@!{Ҥ?ݞ"\@pn ǥ\@vjphT\@@ ࣣ1\@P]ɿ0- \@@dibҿxCP\@bؿT\@m#\@~A [\@PŴN}\@% R\@~\@rߨ\@` ؝=g\@fn=K\@g~/忈;ɸ\@ \@@b1\@xЮ޹\@o:@4(\@5׭\@L g<\@ŗ1bJ\@) ܵX\@1+䝳\@$(|^\@JuZ`Ys\@52j+(J\@Q=\@U \@B\~s\@hyZ\@|B^(\@MXd ǜ\@ټKuG\@G5L \@Mƾ\@ XQy[\@4W[{ pd\@hF-l@"\@Ilk\@" .;V\@PM  \@Ișlaӭ\@^O2j8F\@ sp`\@5 h5\@4w >Cmb@`'>Vb@Vߎ<Vb@=S<b@' [<4b@Vߎۡb@pn-}<4bȟb@pBV b@p ?xf=b@ !=tޑb@x#=db@@Eʗ$=L- b@Pod$=zNb@ 8>>Cmb@`'>@˟@@%&@K#'@[8"@K#'@j*"@@Ы&'@[8"@@Y%'@NAt"@`b&@gu"@ؕ>b&@"@t%@rq$!@X3%@x_5!@|E%@`G}!@3aE%@%3j!@@߅$@]]!@`kgo$@`.!@@+$@ Й @ ?E#@"T @#@^ @`­a#@ = @4;LZ"@`P; @D"@@& y@?m-H"@vZ@a74!@@%&@`{ @|2@ P@ø@p@ڝɆ @G@@@@˟@ ,@ZCU@|I@ZU@܌PJ@ZU@|I@yTLU@D;9I@U@`4I@O*U@x ܌J@>U@8s`%J@\U@흰+J@ S{U@`|1J@oRU@ 6J@L@hU@r:J@<U@XY:J@?d U@As@J@فYU@2LJ@8iėU@܌PJ@H¶ƗU@@OY;OJ@D~\U@ VKJ@B[U@YVDJ@ЏU@jEJ@m+:U@F7MJ@~#:U@*(NJ@9G|U@ ml1JJ@LTvU@(8nIJ@RpU@uLJ@JSfU@ŁLJ@ YU@pyJJ@NU@oSDJ@ZCU@`D7J@H`,>D;@=VF@KB;@Ȗ7?_F@`,>D;@=VF@pu{;@h{k.F@~;@@͋:>F@KB;@][KF@0b;@|UF@m;@Ȗ7?_F@ Z-=I)PHou#!Z-=I)42Iz<)!%IW(K4Iq(2x I@/U(8NydI٭:(xZI#/j(3Izla/(T˭I`@9!(ЛHs (5UHif6{$(PH!QS( 8NHP'oWӾHuɜ'ЅEH`ơ'{Hb'[9H`94'PH|&EH U&]H@p]&5g~H`?Ko&J>H8&gH`es%Ќs>H (_%r%H $X"6QHja$&I}$ 8(Iu# I72f=#:(0I2X#9I`Ѱ #hKIΰD#H4qIou#M5gV@@Uu7@ϪfW@@ <@R OoV@@T8@,kmV@z"8@NmV@pˋ`7@0oV@`'7@P@hwV@b7@`:ZV@k7@^(„V@i˒7@#V@@Uu7@ OoV@@T8@.sV@P+8@{V@eB8@8ξgV@K7@%V@Pϡk|7@-b V@PU*7@zV@7@iĥV@ɾ7@{GV@5l7@03#{V@P#>7@LzV@~7@B_W@@ <@ϪfW@Pz5;@Hm_W@LE;@W@P—;@l+tW@$$²;@݀W@];@/WW@;@P*W@0Qr;@ЋTW@Xb;@ @hW@pPk;@[W@lt;@':W@ 1;@0W@K;@ 5M9@QpV@U*9@0lV@ax}9@Pv8lV@P9S9@ddkV@v+9@|1gV@@ o9@M5gV@@m8@=gV@[8@PnV@P*SP88@0doV@Ա|Si8@ OoV@@T8@ zuOq:t-CN @AzuOGh@@Q Ov7@`9NvO, #>@ʭOR@8dO0*N @+OJ @8uO; @;k'O @hi2O; @P$3O @^+O}A @P*Ot @z-O&,H @M|%O3C> @}OLP @(T7O @` 8O9g# @nO)Eho @pHKO @61OO=" @! Or7/ @aOi @(OdSxs @0]Oxc @c,N{7 @0_Nn&& @UkN=ތ @)N  @xN=V @XgN @/NRo @3_ .NL @!ANH @J_\Ne @ ¦(N {h @kiN1- @ 4UN @|NNE] @`! UHNy) @t-CN]* @(0b*IN~0%@\\NC@@>~fNR@~hNp/:@XoNX4E@|NRs@BCN@P,T6 N @@6bN=@P3}Ny?0-UN#?x@gN>8ȋ?H/T6ѠNTa?PNgo4?\,ںN?px N>j?P1N@m?8VN`ĿyN'ڿ ~r;N DQoX1oNV8DfgNp@4hO8N1JCp U|NsgPRB%Nq:`<@ T F@U=@9 QF@U=@8{`DF@c=@@-F@NS=@wF@`tVg=@9 QF@r;9=@HF@"=@F@ <@ F@B<@ ѧF@p<@F@@C<@@+V!F@)<@8)F@Iו<@pX>F@g<@R,מF@`<@X@F@L<@XPF@pl,<@ T F@hpl,<@ kO.uF@c=@ T F@ pl,<@ T F@TJ=@@ީʌF@@MU%=@'ĊF@",=@PAsjF@_fd4=@-BF@@pF=@_F@pU+Y=@Xe0|F@ _͎k=@[2|F@p&~=@_=֑yF@c=@ kO.uF@(0h x<@xhF@ 躭=@F@0h x<@F@ 躭=@xhF@@- Y]<@7)WPƋ@@`@- Y(gs@@6=Y8llxz@@48kYX>C@@g%VY-Ee@@X4rX e@@0XQ@@ |X(@@K*$X3̂@@H΋ Xp2D@@dgenX@@#Xk5t@@D3XPƋ@@,8Xv @@dcX@,ŭ@@̸sX ׻@@X@@@ؽ34X`@@w38X0@@#dXHbA@@ лXH@@'-xCXQ`@@35@@4?hXQ'1@@. DgX6-@@pE8@kXi+@@Z#lX`t&@@[kX(Z>!@@d{ExhXp 5@@غѨbX`>s@@0Yr|_Xp堟@@/T^X`>s@@dG]X"F@@@Kn]Xׂ@@{S]XH~ @@l#aZXxCd@@4&TX5m?@@'PX?@y6PXB?@LaLX`?@|ECXEa?@ts$>X 7hk?@(R9XĿ>?@8*)XPi>@t  XG֞2>@-80Xm{)>@iX rZ7|>@mX`ȏZ]i>@Wu|XP[`>@(c XhJ2a>@]ZeX@?\>@7X"S>@_4rOXpB>@- X؅)>@,r Xby>@XW >@8D*Xd=@0 XPԛ1$=@Xpm=@`\W`O=@P.WpN*=@pWi5ۙ=@؉ Wf=@XiXW@jV=@@RW0^'k=@kbW iAL=@f(W '4=@> WP M1$=@dwW1=@>L0Wۧ=@7)W0jv<@4(W]<@pw2@stҿ$t{4@к$t{4@G{ҿf4@stҿx݀4@oѿ0ҧSa4@!Ͽ;L4@@Ϳ4OA4@|=пQf84@XͿPJEA24@P燼ÿ@ޗ(4@xT"VX4@ÿ 4@As¿-3@к,f83@f庿0?3@¿U3@Z3ÿ0œ3@04 ,i3@ YrB0d"63@"ÿ 73@~ɿP%`n3@xϿ3@ Ɇпpw2@j ̿Pp~ _@0׈nR@:.x_@ȑ+!R@o#_@0׈nR@p~ _@Hz R@_@  R@_@ȑ+!R@_@RKd R@_@؈R@:.x_@qR@K#'@@@M+@j.#@`_ +@@@@GX+@"k@F|$o+@c@2~Vh+@> @`dx+@@ÜP$ @lE8+@YF @`x+@ +{ @ZN]+@`j @M+@a_ @@}A+@Zq @@n:+@`X3!@`g+@O1!@ze +@ Ws!@@X+@`I!@`+@~_!@\+@ A"@`AF!+@!!R }"@@ۂJ*@@j"@PO*@@^"@`jE\*@ˏUs"@/e*@ye"@2x+*@f4cr"@ 7)@@0sma"@8?)@"@:o)@س"@Tm))@[_"@o_(@["@(@׏U"@`COc(@j.#@K#'@j*"@̓ HRНbC :u$Q8eB jdQНbC :u$Q8pqsXC :u$Qm MCjdQ(4CxQ׀9-C䲣 QX#C {QX&Cx:Ql C<6QC,(QxB\BN*Q%BECQPU``vBg%QZIB OQh!cBl\HR<B VRНB{y RgB&`R( B5gRk)BZkR /XB ܡ$RBW(RBt_:,R0B>j/R8BV3R8&=B|n|8RʖBz2RtGtdP p:R3랧⿠y6R\⿴(2R<⿔E-Rz⿠='R俴j!RLilUdIR3\ rRd⿀SjURdŽRPRdcn㿨6Id R{TRRh/OI aQdi}迠tQM%\dQdQZBȹXQlmNX*XQMA,~ߜQH¢4QEsQ8Kn lQ!ah;-nfQ! /aQuͤ/]QS GrY@%W<@0;,H\@0 L?@GrY@<@_NY@t<@Z@%W<@$s^xZ@g6hʢ<@X3-0Z@ *_C<@DV5Z@ $<@o9Z@@/<@ 5 ›Z@γ=@T0Z@ײ=@Dn;Z@ ;o8=@DoZ@ \=@oTZ@W;=@ LZ@Pq5=@#|Z@2tr=@l XZ@1Z >@0 ¶[@]9\>@e' [@ >@W[@@;d>@[@\'>@đN\[[@0u>@λ[@Щ}Iv>@Lm0[@pk>@p][@Є?@Lb[@;?@H\ 5Gf[@ 3,?@$Rp]i[@2,?@̍uo[@ Z%?@LoFx[@07h ?@0զ~[@0 L?@`'b[@pX( ?@Nma![@'?@C8[@p ?@@,8#[@u+>@[@@xU>@`QyA[@0L>@h^+[@ m]>@db[@0\'>@P߿[@ X>@_[@ >@F[@@$]j>@pm[@O h>@" 5O[@db>@Htj[@pMY>@Ƚo[@ruQ>@k[@p3I>@=N܇[@%WI>@/[@0 oO>@$l[@ dc>@P^[@;m>@`[@",k>@E[@b>@ 1[@\OR>@(._\@Ф<J>@`p \@}@?hK>@}\@p G>@B,\@m8=>@[P"\@@\ 0>@Z@h \@`x >@ߟ\@0`JS>@:3\@5>@5\@p&I=@hȋa\@F=@~8\@0F9=@`z\@q .=@ 5"\@0U=@HIp$\@0#=@%\@ 7h=@Bữ&\@Tk=@w<(\@Tk=@؃)r(\@L=@V= *\@=@ʋ7-\@`5=@dJ/\@P%=@"c.\@=@l/\@MO=@ */W 2\@ RPs=@ g4\@Ƽ=@(8\@4=@F<\@`Q*=@x ^ =\@T Ӱ=@Ȟ}r'<\@bE'=@:\@l =@^$;\@ Ҭ=@` <\@н*=@pcE?\@0T=@ A\@7h~=@FA\@ƶ{=@p^C\@N?x=@a2F\@t=@0;,H\@Нuxv=@$,Z,@`=T!@jX2@ )@9'1jX2@!@t2@`=T!@2@!@Ė2@M!@8y2@ 7)"@08B;2@opt"@p:1@Kq#@0 &1@ !^#@``ߔ1@ߪ' $@@K@1@ B$@]A_1@\RK$@P1@ۮw $@渒?1@#Rq$@,O+1@Ψ$@p x1@P$@U3 1@$R %@1@` %@0nA0@ Ilf%%@C;0@P%@`0@!f$@@Z0d0@%$@@(M{0@ ] %@PWV0@@͢2%@`Cz#.0@rZj%@A0@-e%@ A/@ X%@`K4uk/@ު%@@S 4/@`6cT%@;); /@KPK%@`i.@ =: &@+.@ 05&@.@ 9ɤm&@`&.@ hQ&@.@j3&@3.@%F'@,YΤ.@|'@`Aې.@j'@&^.@ h(@ Cp&.@6+(@ Cp&.@6+(@`YN-@@Mj(@Hͯ-@B:%(@` S,b-@6I(@@*-@ % p(@ AL -@@-(@@,@ 1(@H7,@ (@de,@@zj(@$,Z,@>(@ Cp&.@6+(@@U-@^љB(@ 9-@A(@ r-@@Z)@4u…-@@%O)@j?-@k3u)@,-@iЙ)@מR-@ )@`KU]˾=@0T0[A@1 +F"8UT}>@ b*#9UTo8>@P&y=U0Í֒>@n"EUx*E>@ yGU4z+>@pی?GUp|>@huuBU o=@w1AU`*=@lK?BU=@8͋AU=@$x>U]˾=@>JDUؚ?@@(CUУ|?@S9EUP&rճK?@\BBPDUh?@jge=UX31>@?UN^A@VU A@x | UbA@8 U=V\@@?Upcz@@d#Uݜ@@Lv|U@@༺6$UP@@S.Up& Q@@v1:Uv@@_BUH}@@lf`DU`\%a@@LpEU HP@@ʞDU%g@@$Τ/*FU˾@@|eJSJU @@`KUw@@9JUpیf@@|#a@U*YC@@P`nT>Uhc4@@"!?Ux]q3.@@(=U(ڌ(@@ V:U`K|$@@Q;UZ @@@(Pڌ?U"@@`D7BU0J@@B!DU`J@@TrT0[A@.o?T`:YA@<>IT0oWTA@0T`H)(KA@L&4TsY}@A@ ˮIT0.A@@T8xCZA@ MVT K‰A@ MVT K‰A@]GTEA@Y T[~}iwA@OET)gA@T8xCZA@JPT%Q@pO=@PO([S@8z@@FR@q.?@|̍R@ͺ?@x R@i: ?@ Q@:>@Ʉ_Q@K9>@6nQ@A^'8>@oQ@ڕ'>@|Q@ &Ya>@p;>Q@5Z4>@8&Q@`1^'l=@p_mQ@TC=@3/Q@LIK=@4)\Q@03B=@IXQ@x'=@+Q@zE=@tsOQ@PC?s=@D?Q@kZd=@XQ@ S=@ 2Q@ IuYF=@,ȭ Q@Pm8<=@zXQ@t\'w8=@Pz߶Q@'W,9=@<Q@u-=@tZѮQ@ =@TƭëQ@! =@PT%Q@pO=@PO([S@%@@@AFHS@h+)}:@@W1&R@?@tߠ6R@RP?@01.R@_?@(/wD%R@`;%?@xQwR@ `֞V?@8~]R@Zu?@hhfR@Z8h:e?@XR@pT?@ e'BR@ș1A?@Vl;s.@D cV:K.@tnԅV`ͱ.@Ϥ,V ހ.@`VbN.@ IV .@D5V fa.@T!VA/@jV>/@V`)/)%R/@4V` gX/@40V/v d/@JijVyw/@ܡ VV Ftk/@x2ӮV d/@DkǨV50@ЉaV.0@4VpRō0@`nVpF)0@`-ΜVn B0@h0կV UY0@h0կV0d0@\JQbNET8-8BPоOE8\JQqEk;QEhLQxE]QpqE銹Q``GE\XQ8P,-GE.Q׹}EԪQHyET{H QHsEւXQ`jEE QXQj7Ed<9QeyE?>I6QpY,-En0QPEL\*Qبj!Edg"QދY0EAAQH\E%uYQ)uE Pu`E+PmfE@P %tEL dP)ED9PoE腪^PbNE:P`:EX}xPX&eEP)ѻES> UP@AE|GPpq[E˓޾P0nOExkP93gEɵʖP m7E(1GPjEq ކPxl:E̛E~PUJʺEPyP#EĬôrP4EDiPu0En`GcPi5E ^PH+tΤEVPWET8-8BPEJ?U@@#@I@$#_jV@ u&I@$#_jV@@#@I@<YV@8ѵLI@ligLV@q OI@viJ@@I_OȒ5{J@0+`OtJ@^[NXvqJ@5NXVdsJ@&N|NX{J@N>uJ@SN<~J@!}N-RJ@`L~\N[J@ vGNHq J@֟43+N`适J@*U`D*@4T@6.@:*U`D*@_U`Z+@$ U@ 8+@|%NUQE+@eR,U|<:L>+@(f-U-$+@#aۍU`c*@RwtUV*@x`+ЄU`Qw`*@XmDU`,l+@6S{U\ *@ vUJh)+@n>qU?Z"+@l'k’nUz+@51UnU{+)+@-ߜkU+@ueU`/tmu,@m^UQ큧7,@WU{|Dr,@4v&>0RU)Q,@ VUMU {,@|Qy|KU@pƯ,@]ΤLU6,@ALU ͏U,@|eJSJU`. -@GU:#$-@&>CU4y*-@(f`+VBUrm7-@G"CUOKJ-@ ScBU@:_-@01 ?U ̺>-@2|7U'-@`2U9,-@|3.UG>m-@q|W)UHwR-@nh"U`!&OD-@0:U pI-@ע1U /b-@qUi-@UQK_-@U`%pe-@:U`c z-@n_OU ~-@(JP UO^s-@⹦ U@Fp-@:RU@k_Gv-@ckUQ-@8jU 5c-@5UGc\x-@&~9T`̊-@XT@jȖ-@(-8T"+f-@XT(Ab-@īT -@dISwT`ӯw-@D[BfVT;-@T@6.@4Tœr-@˵\r~Ca* O v3D@ K^syD>PXDfC)&PP\kCH9ôPȉ\WpC0Pl2gtvC`i#OȮjCoFOc›ChE~kO[thC(O_`ުC;oOYCɨOeC,ZuO0.CB.YO@mCo@ BOCl'Oɏ0CKZp#O Ca* Or~COTQߤA)geFQȴmԖA\SۿQ@cAsQ /AĚXawQ%Ap+\pQ\]AXqlQ(EB,9/jQh?!B͋DlQro)Bq|`lQx(4B@ODkQ8nAB/mlQ2gMLB0q|oQĩUB L=:rQncB]4rsQHJ`vBGrQhYB?npQNO9BUqlQ@KBޜgQpBX ]Qg0;B,nNQ YBd>IDQe%B`L*@Q؏{HJBHgg7Q&B@C)Q)B Qu B*QRB̲;rQTjkB8ϙP@dqqBh PxNBxqP {Bl5dPB> $P+NOaBxpP@BOZPRCLvP f!CPHACJ!P'KCtE[PvNOClmP瑓B C0YP(*C!Ptv"C8gq|/P:e.C^ĎPXt7C\ͰP{HBC*[ЩP'HCtjP`MbNCԓ٤PUCܤj@PhnZCg%ϛPd\C']PC^CP6 yPbnaCmmxpPFfC!jP('nXgC\fPP!VdC@~`PBzHOeC|SZPpqQiC(4IQPY4jCD0>PXDfC\]$\& \@@)n\xKH@@iX\̘@@@]Nm\<띲>@@Ba\t45@@&~\+%@@"z\WdB@@ d\ }@@˵\xV!@@ ĉ\Q{@@Fn\=֓@@W\hv@@\0{@@( \E?@ ?\PWX?@آ@\]Q?@`k\1?@l~-ʾ\`x?@t\PW?@<w\*(n A@Hk\D-A@ha#!Ś\$A@yL\*>ֳ@@@m\o@@X*\@@@Y1a\wC@@؆\sAs@@/0\c%@@L\Ў͘@@xy;\tz@@V \GY@@h\3@@ЇAz\3Z>/@@ U;,<\C@@TEj\(wC}@@!\vt@@P%1Տ\%k@@ \b@@h0UB\x R ^@@K5#\& \@@ Sҥ\D'A@\G&A@4a\^%tA@[\{A@9e\PlA@pD5h\ XA@L[p-RPwB@X/[XػlB@ g[p6Ѵ_B@ 't[Q{LB@d[Fu>B@$!L[g25B@Ty6Y[L(B@x![OPB@ o_g[8LB@0L=[9W B@޲c[GR B@~j \c, B@ĸe\ LJbB@@5]\'͘NB@l-\szB@|K\<B@(M De\0RGB@,L=\v B@Dr\`3*($B@x]9!\s*B@Z1\Q.B@TN\h,1B@$"\ cH3B@`U@&\aG-e3B@YLZ,\/B@ojh8\E#B@7 wZ'@D@GZ@\[OD@X Z0o D@@)7Z% D@&Z(D@-ڞZf*^D@$ѨLZBC@ ۨZ 6qC@ѨFZ`@C@ |ZC@B]²ZhSC@Z(FC@> ZC@@+kBZAC@ ?sZ&eC@lVZC@2#aZ'axC@hZ`Ԗ"C@g0ZпzCC@Q kZpKJC@C[NC@M[:9CC@0 [( ҖC@Dd{์C@ܗ #[X7C@,7OE3[0+C@ Yz7[_q C@l<[7dC@p=C[i C@hVL[(oѵ5C@Q-P[C,ŲwC@(cS[zgC@8W[ϙe]C@Tm[[PYC@+8O_[ ZSC@c[HdJC@#;f[_FC@0HVNg[xbGC@-h[X} EC@d:i[h3>C@?Ej[H9C@Z1l[m9C@`kEn[ީ5C@Y1Jo[J,C@$ 5r[@|^#C@_ oy[($C@ia[{$B@LIۿ[ީB@ P[sB@vZ v3D@?tZP ގD@D$btZ0D@lt^F@.c\tT J@ Vaiuwn^x((F@V^F@L^QF@< ^!5PF@ #au^o=F@ܾů^KF@0O^`sR2F@]SI^`]G@؎;^{G@H^p:0bG@t^HG@Ê] AsH@dH؎]A H@I] H@ ]H@H]pOH@49!\]5Y H@S D]L H@,O]GcH@q鳽]xH@Yq]}G@R]kG@YE1]+^G@$u]oZG@>^DM?G@x^X:oG@̔-8 ^ HG@hSw^8ĉTG@D\E^`mlSG@`^t۶G@uj ^ܰG@F`^6G@\(^^h>G@^qNG@Ф^\LG@Pm9]VG@8B^՝G@Afw]"~G@ؼ]cG@-]^LVG@"]d$UUG@^I ]lWWG@Va]F[G@ ]/bVG@ H`]`%`HG@l)4c]f2d:G@n_*]+G@]_"G@ ]8ͨ[G@i]ʻG@IѪ]XU!2G@HN]nG@HL=] -G@{]l+G@@E]`i$ G@< 12]X6 G@0]G@:]]͘G@;c]hYbG@1]0|Z1Jk]0bCH@[ym]hH@C l]ȖȊH@̊wi]"H@?k]H@h]m]`i|H@QkBz]@W@mH@r W]0bwCaH@,[?]`j3 I@8nz]y I@0{]f2AI@z]v I@b||](@H@r`Ձ]& H@]@"H@W#!] OҗH@.c\P#$I@|5]DjϵKI@$IV]FaI@D-_]HqI@-X"]mlFI@r0]V^QI@PM'~;](6@I@ߜUC]D>I@AK]tHI@ J@]tT J@H{S3] BAJ@6]cI@^ۿ]FfI@Rw]-+I@̥I]X.I@3]XtI@4']PK I@L鐁\]Y>I@ d]0]wI@aS]LI@0y]4I@/]t"\I@x#]V^QI@OB&]Hzt5I@ xIV]I@tD҈]+$sI@p#!z]TgWI@޼"*@ C i?x ;@!(Em@pp:@ C B:@>+,dQ?p4?3@?-O$3@Ovv-?>Ѷ2@\? 4԰2@q ?@{o2@0~2?`vW2@6$?`32@|?p@bj1/2@#'? ,2@ .]ÿmZ1@lUٿ1@&iU1@: x]G1@￀=2Ԍ1@V3~R0@QZ'=0,C0@]U]0@B'\W"0@6R_Z0@.vm0@ݹ^/@.@xQ[4.@l*Ј.@Zi:`))l6.@#,`-@։Y-@e b@Cmj-@`⼗D-@@ciQO|-@DsPl',@'h,@{A Q]w,@@*O`gY(D,@?L,@s_@T,@@%=5Oo+@ diY 9+@i 6H+@s@Pө+@g+04>6+@06&6W+@'_b@O*+@'_b50x+@06&6@Ab+@X=an,?+@zQ2 |%+@@]{Ce+@##oK>L+@X[%0+@"@lbYyN@$ abjSmN@hbhcjN@mT&bjq ahN@-Ȁbp)8dN@]2DbTc[N@.GhbUR^XN@b0hSUN@(vu]Q#P@L[6t@mP@-L[R:H%P@c {[Q#P@-[8j#P@,Ţ[&&P@[XI\$H_rP@t \5@ 3fD)2$%0@N)Љ 10@ 3fD)c;0@֮Q)tI0@2Bs)r{S0@ |])pd]0@`9H*居kn0@ Z*!j0@),l+`{U0@`@26+`I0@ Jd,ҧE0@CW, &EK0@|,ߛ:Z0@`p+%-z>r0@`M4NH-;^0z0@`+ff-PFi0@ಟ+-Ի\0@lp.x0@C-:U.x0@9.pÉ)0@h.@KJ1@@!e.@iO1@f6.I1@@;ʜ9/@H`1@`J?/Ơd1@:/@RIv1@`Ҏm/@ҧ1@9J/P"1@T0[i&1@4K60P &M1@; k0PWX1@0P!0:Wi2@ 02Ԑ2@~l1 ֮ҷ2@p1Hԧu2@`ɗ,1@Aw2@p+a1P3Ԕ3@dR1003@ d1t`3@SR1f3@c1^1j3@P1314@׫1 d4@0.1,4@0(#1pt4@PXZ&1c۾4@`Id12Pc4@PD칎2t 5@1`׵I5@0 ?10w>5@ nk2 `d[MKF-Eܾ:pJ 9+&!`d[MKF- -Klp-% K gQ-@xK5N묌-ebpKz -"!Kc-xJ]_-y'=iJ~-eGhJOݭ.-# J@, ۯJ9l+LdJLQx+ )J!$]M+xLJ?ڋ*+eGiJ@cL+#>J`o*`vJɃ *Eܾ:pJ@Z)`ݛxJ``Xk)pW'|J I)PyJ 98)p Js)ܾJW@(}lOJ U(@q'=J[Fx(~ J@esR( SVJi&(~LJsz'#J@W_#'p7J@6-'غJkp'p(B%J@DF'(ظJ 9+&X 1~Y@/p<=@Y@_x@@H 1~Y@_x@@^ Y@hޏr@@l(cY@8Q)fk@@Y@~c@@ Y@h3GP@@`[pj'Y@[E@@D/Y@Xkt)>@@^@3Y@pV #6@@u[3Y@`#Z/@@u5Y@KJ)@@A¶:Y@z7%@@[>Y@%@@@'~yxY@+>@J?g{Y@>@TadЀY@6>@(%ؼY@şkΧ>@ L.Y@FW>@`]Y@̚1Ar>@"|׊Y@˥J>@kyY@,>@!oY@#>@؋Y@r]7>@TwY@@-=@llaY@=@iħY@p*i!=@\P2Y@lp=@puS>Y@|ԞP=@\ImY@LG=@ХLgY@ixY=@|wY@Y!P=@!c]Y@%߆G=@Y@<=@ĴفY@x<=@$فY@+3H=@twzկY@qI=@|iY@`-B=@:.Y@%WB=@ s'Y@@NUI=@laY@0(J=@!hY@@UB=@|Y@u\'B=@Y@MJ=@hY@O=@PZY@a5P=@}`Y@ϋJ=@g Y@έ<=@$}X3c.@5HEN@z.@`@N@ ~9/@iJ7N@ {S/@6G3N@D/@4N@qއ0@3 1N@0@RBs +N@`O0@hŐ#N@ 9 0@0 !N@@5q0@PoYN@Ú:R0@@0N@$-o+@N@']nr+@zN@`{+@b.XN@@H\+@1tdN@ʳ+@@N@[,@oiaN@`/,@kH-kN@`v,@&ގN@S-@PN@߱0(@5O@}l(@@Vo O@ݔ(@MLO@`Z4(@N@ hl*@ N@?@0:&>@s5q?@,rռ?@)?@0:&>@?@`,#S>@pJz?@PªB>k>@pYv5?@č>@M??@#>@ 9?@ )|>@U9?@Y>@|:>?@N>@P–\O?@?@ i|k?@P ?@LOi?@/?@h*?@ A1?@acի?@`W&G?@s5q?@,rռ?@-"41@WE@`<@ H@-"41@ H@` {1@ ệG@N 1@G@aj 1@bG@bjE%2@WG@02@H{G@t,g2@`RG@ 3@G@p)B3@P{;G@?|3@wýG@00&3@這G@=ɹ3@EG@3@؏G@Ѓt{\3@(L0bG@`F3@nԴG@zcu2@Z׭G@>2@u&GG@Q52@t~XG@@w2@pAG@@tp2@l{:G@pmA2@DG@ TY2@"]?qG@%`2@ЏzfG@Z02@^G@A2@0ީWG@F2@8h耳QG@0Ƥ2@XBJG@ӍƔ2@ CG@82@8p"6G@FƎ2@ׅ7"G@sH2@VG@O]2@@vG@0Obj2@G@p: xa2@` mF@Pcs{2@`r F@p(2@q0F@`߈)2@F@$2@ *$F@g&2@P ^lF@0 3@X>|F@Xu3@SRF@W3@GF@3@(vF@\13@E"F@`T3@ JJ F@E3@f2F@Pr{y3@Pݩ%F@P`3@ԝF@Pb6q 3@X\F@P+3@eF@U33@i+F@paj3@8LJ@F@[0x 4@7>ԗF@Pҧ)4@)(F@@4@,E/F@LOEH4@hTF@P4@ F@nAV4@`͘F@WS4@$ |F@pu~WZ4@H:AstF@Jk4@ ґnF@m4@شkF@RkP4@4plF@@4@h?& jF@PYR4@dF@?&u4@,^F@0LJ'4@XF@@@j4@ ZF@p-\5@`QiF@#5@Po!eF@0ؘ5@Xv5`F@3٢5@`ZF@)}5@8>u WF@I5@V!CUF@,6@P͘WOF@e6@ ^EF@} xq36@-GF@hY6@ VF@yg6@fZF@`9^6@RSF@6@XgMF@Pk6@HF@ШOe6@eeGF@ ž6@ǹGF@ h,Ӎ6@0b)EF@.G6@8~>F@`H~6@H7F@pf؇6@a0F@36@QN+F@N"6@q (F@`6@$F@@i6@F@ r6@zF@ h6@XJF@PK7@˴M F@ΎcC7@B, F@0ԤC6@(Ó+-F@qJ6@\E@H6@=VTE@b=6@LJE@> 6@8Q=֩E@ÖF6@`xE@97@A{E@P,و7@BE@ce7@ #E@W :8@&IE@:n8@hZKJE@ϧ(9@H5E@U@9@WE@B 9@0]tE@p9@ЪY'E@9@@fwCnE@0&`>7:@F@:=}:@ F@Ф:@耶F@Mdj?;@8mF@඙:8;@ ,IWF@`,>D;@=VF@uV;@\F@Udji;@8F@;@軣<F@f8;@8c!F@0wO<@H+F@0+u<@-ū5F@PnIX<@V!Cmb@gr=G>Cmb@`'>L-`hb@G>pfb@Ld>̛ߌeb@">$ᐱab@P@b1>86uYb@Pn= Tb@gr= ?ySb@R=x4FNb@h`=tFb@>]=H`Ab@I*= 'n@b@Nhk>d-(=b@@_>nO#6b@gST9>Es2b@`gۨP>S'0b@@Թ`>G.b@@uh>9*b@@uh>.y&(b@P;v>.'b@ 9{>H* %b@L]z>,u #b@`;>`XeĤb@`>äb@@,a>Ob@p\>nOb@@>b@ɗ>d$ b@d>I b@k a?lAb@02?Tjb@,*`,?8b@[@?<7rb@7EXU?pa@ d1g?;a@ ?Ru?`Sa@0L? a@0Jב?(yfa@h?𩞥&a@pQO?\^Wa@0?F}a@ ?da@0%'?a@s ??doQa@ 8|?Ca@ ?oRa@En?3rJa@?6?|,a@Od?lAa@H@1Oa@3Ez @ a@5@d8a@Ӵ*@T;a@0@@;ka@ f@u0a@7"y@dtIa@!@l|na@ZW@a@@a@mܪ@9a@@<7@ea@ d @ؤBVa@x@lFs]a@ @nOa@MO@!a@p &@hJ a@N@2a@.H`@娼\a@@AA: a@YA p$D 8@K@PK(@@8#vL@a A_ @@X>0tL@f@@CpL@xd @@z9nL@Ҙ@@ lL@Hf@@,P iL@PK(@@mY`L@,"@@P:ML@(2N@@8`{FL@XJ.@@4CL@`vD@@6:=L@r$ @@ 72L@}L @@@DV(L@D @@3t&L@7@@jOL@0@@& L@0Z0l?@_L@P;C}?@W$ L@GU?@L@`?H3?@ubL@y xz?@~L@08qc?@8&ȘK@D$a?@ iK@r?@nlK@3Rj?@PvK@@CG?@hK@)+?@𧲰K@BZI?@1K@m>@-EѷK@PUh>@H-GK@Kq6>@WrK@` *>@x'FK@n%>@ƐK@`k17f>@L@qK@ =@[cK@k=@=K@p=@K@ආ˹=@][K@|׸=@xxK@ү=@h׎K@P+m=@FK@t=@@@FK@h}=@K@ps=@XK@_"0p=@LJFK@`g=@hc"K@@?Z=@`K@ XP=@;@F|K@`;@O^K@SYu;@p5K@[Y;@@kmK@ ;@hK@:*:@u< K@7:@xvK@%9}:@/bK@Qfj:@pMK@-M]:@~L@W:@0L@ZK:@)(L@FD::@H"+L@cP%/:@ @!L@0v*:@0e+L@=t:@w5L@O,9@F?L@fL9@YFL@ pQY9@H+LL@"9@P:ML@`<)l9@(i)KL@` x9@}KL@@a͒q9@NL@hƒ[9@JOL@p4F9@avgLL@Pԧ,9@LL@`Ew 9@KNL@ x8@SuUL@V+K8@zaL@r{b8@aiL@JW8@0zimL@>f88@YlrL@Pԧ$8@0wL@@Gd8@hNg~L@p$D 8@8#vL@L'PXDfCD>Pxl2@8L'Pxl2@ P*0U@{Poqcf@&8P$qqOp@>!UP5K@0sPgН@(&~@Pc?@tLP0ϝ@qnP;t A'~fPAuJP\AqP@{HAmoP(nR"Ah;'P4E,A`@ҲP`Y8AL nPxb)eGATKpP bVApYEPP=>eA:싣P:uA\6#!hPU8A!x61PtOA2P{"A)mPH0 B*²P޹BTۿGPJ2BI P@KQBP n^fBPp4\qBKPu~Br|ֲPH\!B8OPG$B(EP;B-PhG,-+BqP`BĆqPp8BWPpeBd\PcBLSޑP EBPHlԎBt|DPvfBt:JPدMBȱ{S>zP+AB4,tPQB"KZsPph:C_tP`^ CPxwPzHC4 azP:C|PH,%5Cl azP-%'$C4sP0:o)C8~poPG_/CLPmP 4g5C/JhP8Y>Cn_P'fICւTPHTCD>PXDfCPC@XvB@4R30E@@415C@PC@@415C@l"]D@.u,C@p_,D@c'C@ͥD@ &e"C@v0D@x2 C@ D@=7C@9!D@pU!XC@0CfD@p(e C@ |3D@% C@!D@5C@L? D@b\[B@*{6D@#.B@{D@Pz@vB@awD@ QB@Ȳ0ܭD@U!=B@]D@{{B@pU vD@'FB@^D@p B@#AKD@%B@8_D@bAsB@2GD@83mB@vXD@x{`B@R E@xB@ОE@XR #5B@Xp (E@83cB@4R30E@XvB@|Ԩea@٦D#—a@ܤBl2$;ٕa@ܤBl@aa@D+D#—a@UG,ra@La@&eo/a@!`'84a@m$6#a@8p#|a@@ Oʡa@@P>a@ć욆a@@i0c;ra@@^Jwxra@@1O\a@ppk2Ca@= G* a@ptAyfҊa@X}'Ra@SYa[ʊa@W: >+a@@X/J`8a@@2vja@,TFFa@)t_r}a@ J5*aےa@VURIa@,}ka@}7p9]a@@t# `.7a@jCD(La@@Tta@Tc}a@0,Ptz1{a@@62 k4^ya@@62 k@dƫwa@ٌIva@(zhta@05@qta@@4PLra@oOX>qa@nrpa@٦,qoa@L˞na@dT3/na@,ovma@:edagla@wl@Xka@=*Hga@57p|Ԩea@X"9.ɖW@@ <@ @hW@p>=@("9.ɖW@@ML=O=@ GW@PQp=@%W@Х{=@ 2ދW@ @}=@N@hW@Mm=@pMnW@Poご=@lϺW@`kܢ=@ Do'W@б|=@|W\W@ {lc=@nW@PK|=@ W@-1=@2t,W@=@+W@p>=@ ,DKW@:=@@IH@~@Wsz>@Z4 G@t2~>@0(Q G@xu{6@8#^/H@t7@x͘H@Klc7@BsH@P*|7@IH@ ]7@8H@18@-őH@0`#8@ >V̷H@dj:8@0qH@rG8@,7*H@F\8@0EcH@ tJw8@X{&WH@#8@HH@H)Ҿ8@б6H@-?8@h"H@a8@h`SH@ 8q8@H@TVB9@$ uuH@f'9@PqpH@@>t/9@H~xCpH@`Ɇ59@x7qH@umA:9@>֟nH@%`0@9@hp_xkH@ ,IM9@hp_xkH@ (_V9@@ojH@PzXH@.19@;{`WTH@_q9@ЊvTH@PTv9@.SH@C)9@(:][MH@p:9@`z MH@@nAc:@NH@`` :@COH@`wFi:@@IH@0:@p&HH@P27`!:@-E;@عQ.H@`M=;@t&*H@pD <@7)H@pa&<@+%H@pɧ<@(+ H@ (<@TvH@@"J<@H@8X<@0KEH@nAS<@s)H@,W<@™e}H@m6c<@(RH@ڤMl<@|H@G'q<@P 8 H@FRYv<@󐎕 H@;U~<@x][G H@ <@NR H@И<@ީH@C_<@0H@Ḛ<@Yz%H@-;@<@p#1H@E<@rxCHG@է<@2G@ &`=@жG@;<@ G@wCy=@+G@EY=@HtG@VO}=@$G@p"=@`6۵G@C6q[=@4%G@ yD=@hu&+G@Й\=@(\G@>=@99G@=Oc'=@s G@`z%=@H3' *G@'\!=@0TG@o#=@XAsZG@pU,=@XAsZG@PE7=@CRG@jC=@٨YG@P~GP=@ NюG@[=@8-ŀG@`ӧ9\=@L3ÃG@Q=@0'G@CQYL=@}G@tO=@.{G@k~Rnl=@h3zG@-x=@M QtG@b!ã=@HtojG@0Y&`=@jyfG@ 縲=@xAiG@业=@(hG@w'`D=@õM`G@pm=@A[G@=@ o7XG@~=@݅UG@+–=@h RG@pmp=@µMkOG@&`=@07LG@@ x=@@5ZJG@0>=@xw FG@ɉ!>@ @'6G@O=8>@x6G@004 A>@zD3G@ $jD>@88(G@X>@X=V!NG@X [˘A@T%K@g'LI@@X=V!NG@R@@XW&SG@(ӂw@@XFw[G@'BƇ@@UߩaG@lJU@@؆tcG@PPQ:@@pUߩdG@r$Aù@@)gG@(5R@@@ifjG@ByA@8\[G@ؔ~A@hMiG@Hk+{A@ZdH@v͉A@UΘZ H@%)A@ș H@A@PSZH@}3A@H(F4H@X [˘A@pWlH@HGA@##H@MP:jA@0e2H@0b(޺zA@q=H@>)hA@8@~>H@m}3ZA@(l_CH@ 4A@8s&QH@FcA@0B^H@@mEA@(fgH@PP:@@Pi:xH@@@p{1bH@x@@d #_H@0%Ԙ@@cH@0^tT?@3H@pΰ?@p((mH@lq_v?@SH@0l@Hp?@6MI@">?@0q MH@a:?@:9I@>@P*}I@PlA>@HzjI@p5>@~}'I@ >@xCU5I@f>@0As]LI@u@@][guK@nB@@`i.~K@4R,}@@T%K@H6s@@@xC:~K@𔶠Ri@@@zK@y^@@|HuK@N@@ЉaK@8yA@@8gXK@0@@rXK@KLW@@WaK@@@@xcK@ za*?@tZK@؆G>@hiSK@p:>@XD@NK@07Z)>@8F=HK@PW>@D{EK@|A>@XFK@Ckjv>@8DK@##i>@aV![?K@@ 9\>@kd_6K@@(u{M>@)K@`˜ׁQ>@][K@Kg>@zK@Dh>@{xJ@[FR>@EJ@@/3oF>@ #J@PYB>@(G>J@@ǑH>@Е$J@`%_>@J@I3mG>@mFJ@ :B>@ ax]J@0q޿H>@0gJ@ `@>@̲aJ@,})>@}BsяJ@T>>@xJ@p` >@(җȎJ@>@8zJ@V临>@|4gJ@–$>@膗ZJ@v8>@6TJ@p".B>@nMJ@f@>@ڌ GJ@`KG>@М@J@٢oW>@@/;J@y]>@-Bs7J@-Y>@Hf2d4J@@VVe>@`0b0J@@@,̀>@ \ۿ+J@ L>@pAs$'J@VKi>@Q"J@Wz>@0o*J@Uf>@i5 J@,T>@rI@->@dI@EU>@`jI@ز>@II@p5>@mlI@p$>@o5I@pБc>@jϿI@ݽ\˜>@?٠I@/7X>@ f`xAI@h>@(nЛI@l(T.'C@HeG@ IE@H[8)K@o E@\G@E@\͸G@?w.D@-G@ pD@8)G@SD@XxAG@8P:D@XxAG@̥D@-G@($ኗD@#G@6RD@pOEG@6-D@"G@hfD@\MG@0|D@LG@0VtvD@.G@RKD@G@;4D@P`G@0I;$D@eG@aD@P zG@C$C@ 5cG@PVaKG@^C@W/G@(󪏥C@HeG@ IE@ީH@h!_E@KWJH@H2 iE@ Y*[H@҈E@)3H@ȱ>E@lzǮH@x6 ,E@fΘH@Vu8E@8nlyH@ ZbE@8jH@(= E@(3H@)~.E@QH@8irzE@/bH@՘jE@8ug2ZH@Pz|3eE@δMH@GbE@`ީHH@|3]E@wMoH@RE@XcH@@ðf&9E@u H@%E@ H@hE@0H@4䙑D@^ZH@Ȕ҈AD@ #H@ȻD@cwH@ %D@ީDH@O%%D@H-H@ D@)dH@ gD@x}H@ޤD@QH@ >D@0~nH@8oD@տH@@$fD@ H@<D@PvCH@uD@QBH@ tD@0\[{H@qD@u5H@YȱlD@\dH@ CpcD@ud^H@mVD@ `H@8]zRD@xH@g,OD@$H@xpFLD@LJfI@j2@D@ /biI@i =7D@pEI@d1D@` I@lI1)D@PeSUI@hAWD@LJT I@ίfD@c: I@/U.D@ _QI@D@I@HaKeD@xCI@$AC@$I@H9D?D@=,I@"%D@x̐?4I@D@I@pwiC@{I@<=C@u%I@t?)ΠC@o:I@XЋC@][-I@vC@I@8C@ЇѵhI@,}C@x~I@]6ǐC@AsI@0 C@{KJI@HKC@jOI@5RC@ #I@VĄC@(SI@hׇ DC@6|I@FcC@vqI@C@0yCI@(6݅C@%.I@h5MyC@ KI@ C@蛈TI@ តC@h/I@ wC@}MI@,C@0pJ@,C@ U`J@@)iC@@J@X-C@bZ J@e“C@0 J@PG^XC@J@j~C@`WAsJ@@FczC@_ %J@H8zC@})J@0sC@8J@`Cw wC@]ߩIJ@h|3dwC@kxCUJ@LtC@HYJ@gp{C@AseJ@*҈C@g&xJ@(C@~}J@CeC@haJ@JiJC@:jJ@~,C@KJaJ@_C@V!J@C@\[J@zk"oC@`F0!J@XQ RC@J@p=ӈCC@EyJ@aEEC@p @J@dCC@Hc1J@X#A2=C@(ׁJ@(T.'C@H[8)K@:p @-!G@-"41@HH@Dp @PH@4X @-!G@b#Dd!@juG@ ޼!@8_G@\-;!@0H@ "dC"@ H@@|7<"@㻇 H@K"@AsH@e#@K"H@fhi-#@9H@>KR#@%H@l#@q %H@UlE#@HU%1H@ <A$@P9H@j$@Bk=H@Sv"$@X<BH@*R$@{FH@ %@HwCMH@jSl%@x VH@,; &@_^H@b ]'@eH@޼''@xFzoH@K]c'@| sH@{V'@tjcvH@8d (@pzH@{S(@HH@ |(@HPH@ Y(@ļH@`&[)@@@vH@-"41@ H@ PC]*1@-H@0_^1@hoH@pV1@cH@`mA0@+H@폸0@PiH@ v|0@(]4H@fH\0@x$.)H@`050@`pD0H@ЎL0@pB5/H@M/@KJ0H@ʫb/@Hn4H@ %Nd%/@p+<6H@$2/@~{U5H@ k.@pcy/H@@s.@̘$H@c .@8HH@`JK.@R%cH@gN.@dMTH@" -@g2H@`U4W-@,EH@)s-@IAH@ej*-@дDH@q,@<`xQ%H@@>v|,@@Dc*H@ R]C:,@O*H@ h ,@0H-H@B>,@j3H@ yJ@+@'jO;H@>0**@ -yJH@݂*@DTMH@`}_f*@Q"uQH@@Si)*@HrXH@p*@x_H@@`t)@H65gH@N)@,EjH@@.ׂ)@,EjH@&h)@onH@`&[)@P4wH@hP-jY(gs@@@- YI!@@ P-jYI!@@vL=H[Yt6@@ܲ#TYQ@@ s)PY8@@{1UKYC@@lFY@@?Y0q4ۑ@@`qB5Yz+@@ZVZ-YX٧@@@- Y(gs@@Ƥ+@P ^lF@g&2@d0eG@.Ƥ+@+G@<}V,@A|`ݒG@"f-@EĚG@pHC=-@hBKJG@ -@Hv\G@퓣-@یdG@ҫf-@eҨG@`A.@IF}G@ QJ.@T Q8G@oj.@d0eG@&.@̵cG@Ӝ.@,ExG@@*x.@x3yG@`.@83ThG@$.@Hg)(TG@Cg.@V!D^G@@*g/@̅\G@# 0@kTG@0hk$60@IG@0 :R0@xGnDG@ z{m0@ǚeCG@0@H:>G@f0@ wH-M5G@ 0@{m+G@/s{0@x x G@)^1@tG@d_J&1@%G@z{=1@ީ G@:էO1@ v$F@O"h1@`uF@mAy1@@-S}F@P [e1@8_F@p|1@P &F@"ִ1@\{F@pX"1@R #,F@0[H1@XcF@aH2@kF@&ӧ2@`.8F@:J2@@smF@g&2@P ^lF@)fY!=D@IO|еD@.60|еD@7U)?}^D@SE`(`D@LMD@|E:p}TD@TnY D@dv~D@X  @D@O4Y@̘D@}hD@`9žD@˫'^@{D@MI #nZD@ . D@^K(({>D@ ќ8\[ D@CD@gh QtD@f ɍD@=D@ފ (( D@@Vx88vD@@iX87D@@"e?Z ?D@;֚Rj1D@@9x 0D@ XmlNJD@)i!V!TD@)fY!\[ƓD@@dA\u\D@f7?V!nE@7@dV!nE@@PC]hP8U0E@D8g2yE@Hhu46nE@éXiE@~@YlE@#}^nkE@Re^!YhE@틬 KީjE@Nk qE@ rE@NR- 77lE@L w:IgE@a v[eE@F< 3dE@IPC `E@ O>qXE@C tRE@ suMD@+@x[,K@@F+@*P:D@@~R+@_@@@ Wh+@L=@@`)+@PC)8@@ u9+@pڿ/@@T+@P%@@@mt,@x/@@`X,@@@0,@D@@?c\F-@pNY!@@2ƫ-@(V/@@`_\-@T0Y8@@ ƹB.@(>@@D/@(>@@"hO$@w;A@D/@= w;A@"hO$@`3٫A@Ι_$@XA@@($@g~A@@LK%@;҈ߒA@ꈸK%%@(g@A@`"I%@Hґ᜔A@]AzG&@ ҈lA@_g&@s9 A@ O&@pcA@ #RǗ&@Xg0A@~'@Dx)A@ 57c(@^o(A@6c(@g+A@\(@(Ћ&A@b8c@(@{oA@ qm(@X~A@ b\)@͕A@`sX$)@@)mA@)~F)@@ A@ }u)@pDZA@6 ˛)@.pYA@Q)@h=A@z)@9A@+N)@Cƛ@@,)@x<@@`NI*@(S@@W*@@N@@N0ƥ*@H[@@ ަ*@g3@@*@@Ŕ~@@2{D*@n! @@n*@01@@ "+@%@@"%+@p3=@@@⢠<+@@@@wV+@-@@@j+@Z@@|w+@pX@@+@X6[@@ +@ ~@@x+@E@@`PKo+@iDZ@@ǭ+@zl@@YB+@x@@@ +@D@@M\+@0J@@c["+@HEc@@3,@X0@@@=7,@N~@@pk36,@xn@@pn-@(@@6Ĉi-@h $@@/) .@8 !@@ګQ.@0"_@@?|.@k"}y@@@(Kv.@Xd?)k@@`hp­.@p ^@@~[.@0~NpP@@~>/@(F@@|>/@(>@@D/@$l#@vI@@8//@pcJ@a5ZJJ#^*/@XI@:/@XYNI@d@N/@iϹII@Ki/@]FI@2uw/@ BI@1x/@:9>I@T/@p$q V8I@@< u/@H,Fq2I@ 蓃/@/I@@8//@wC)I@ |/@0"I@ L);/@ +I@`2Nh/@P I@kZ/@}I@!.@vI@`ox.@XpI@ MQ.@hD I@Ό-.@yѵI@}ЫN-@`xI@R*Ȏ-@0M)I@jC-@*mI@@&,@p+I@`ִ,@48I@xV5,@Q:I@ S,@0@s8I@&Y*{,@!:I@ rq,@hW?I@$d-[,@QBI@ 铫7,@BI@aq,@نDI@@0,@`AHI@WD,@S:qKI@`҉g: ,@@ MI@@(A",@Pml+OI@#d#,@`rjRI@Я&*,@Hq|TI@K#R,@1bWI@Rg,@Ƃ_I@@ނRl,@M1lI@i7E,@O|uI@ +@QyI@*d+@~I@+@@-E?I@`@L|+@I@ڂ>+@S_I@z>^ +@2jI@@Do*@sAI@=*@0g2I@*@`I@`*@HI@*،*@^I@Rs*@0 `I@0b^*@[۟I@gEa*@[۟I@@LAS)@I@@)@I@Y4g)@(iU!I@nE{)@.I@`H()@pI@n(@ I@:LBK(@(.I@`P'@PI@@&'@POg)I@`0ʯ'@hvJ@lE'@5J@a'@HxC* J@ T-U'@" J@ P]V'@(J@`Xb'@ƗJ@ [ѵ'@HD"J@#jw'@a0a0J@@E}'@8J@ O(@GJ@ (@0ҙbJ@EQ'@w7uJ@@h>r'@0=c̀J@@ 4'@`MJ@ S!&@-J@,&@x̲J@g g&@As˒J@?LRG&@HHJ@@w:6&@hcJ@ %@8FJ@7%@,EJ@Ag]%@z>J@`A3%@(M$J@ s$@P[J@R&;$@8̘wJ@N]m$@q ״J@`C)$@q PJ@`C)$@q PJ@` O#@.*J@l#@pcJ@ #@`J@ ʫ#@nJ@NV$@Ȥ< J@`C)$@q PJ@*R@hiG@QU@ی'J@bQU@pGG@?Qy?U@HݽG@w8R8U@7G@l2ߘ4U@WG@0<˟.U@)^.G@nIe&U@x;G@ϪkU@hiG@6U@0LJG@$SGT@viH@|5T@0GH@('=gT@H@t_ԷT@O҉H@ AǏT@x.H@0hiėT@.I@ʄT@E I@@i%tT@V!I@T@ S7 I@q¶}T@QI@PGqT@5\[!I@!=T@0|22I@|7T@x .I@+9,T@".I@nSBT@)(/I@$zT@U!y4I@8q̍T@S@Țw wJ@0G({S@(n}J@J@@v,R@uDJ@R@ی'J@8QU@A~G@4ҔV@~tH@$4ҔV@ީ8G@4e'*V@jվG@h*V@ԸG@FSՌV@9G@okyV@.ZG@oV@ G@XBz=~V@(}wG@s%wV@X7BG@m9pV@ ڨG@pj}riV@0|G@Ж#bV@QG@< 5YV@A~G@(NV@0!RG@tFBV@5އG@vݞq3V@dYG@Xþ V@ԝG@6 V@x@P:G@h-(AA@`XFF@\I!N?@7F@:?@ЧaKF@B?/?@F@/.B%?@!G@ ?@Py.G@,">@ph=G@ %b>@80JG@>@ayXG@$č>@(mYqG@P1]'v>@G@ba>@kG@p9up>@<G@h>@hζG@"?@P:G@a>@h_w D@S6A@n=D@PҠ1A@yD@x((J2A@oD@dS7A@04ROD@|68A@ȱD@o7A@HP: D@ 7A@-G`D@Y>N8A@:D@g2~9A@;:D@ 7A@Ȑ͜D@vc9A@eȱD@`}6?A@~D@h-(AA@HB}3D@[c=A@@8 D@LJ9A@f E@4E/A@ E@8o&A@YhE@,$A@ E@֡)'A@HIE@XVT&A@W]!E@?V%A@P^$E@ff%A@?+{&E@d$*A@6;8*E@(>&Y,A@ ~.E@Y**A@H .E@耢&A@]*E@PiV!!A@x*E@pEA@`"28/E@PM7-A@Wt1E@h,A@e0E@ٓA@Lug5E@ A@.(9E@Q/A@X ?AE@pCA@p7fFE@`x@@. MEE@@]S@@jHE@89+g@@+{NE@F@@_ VE@@@D]E@3@@j¯_E@X@@h\E@oA@@ȮM6bE@p^@@8!FpE@Rnl@@<{E@ *(@@#E@.\@@٘E@@s@@@+{E@nY@@PwޓE@@i@@8Vt5E@PN+N@@8y*{ҤE@ Qn7@@HD;E@8xê@@+{'E@h@@.E@XG@@0G(E@t4@@iLE@4mܧ@@bbKE@P@@@@)E@0:9m@@8)E@0:9m@@ LE@=@@ .F@УKq@@ F@Ɔ@@ w F@ j@@0B6!F@ȃ~e@@f!F@h+]@@@?)IF@[[O@@P: F@ ҈?@@Eӈ )F@g2,@@un-F@ت.#@@DZ-F@Uz@@HL1F@iF @@ K9F@ 5?@6w =F@S?@0F@}Zg?@hCʚF@kZ?@X|F@@TAR?@ ĻF@\I!N?@@Pcs{2@`r F@W{2@'"G@W{2@'"G@郌2@YMD@ @D@N1`GbC@s hC@_FC@PƼNbC@ȱ9C@/[[C@p0v0C@HQC@Ѐmr-C@h_ZJC@Pp/C@31bFC@xv9C@@C@NC@KJ9C@\C@Qf2|6C@H1/cC@d7C@ plC@4C@uC@@S"-C@*?)C@'As*C@0C@Ekώ+C@5C@X ''C@5C@UC@PtDC@mߩAC@o,C@XOMlC@LŸC@C@vC@x C@( ԕC@@ |LC@8WtmC@pUtiB@hYMD@ @D@ s\D@D@h ~D@PjC@(LbD@xzC@ q6HD@`FC@`f2D@WBsC@^. D@4C@D@x6\[C@iz-D@2C@0bKD@sC@@ѯfbD@P=LC@ȱD@:9C@,D@.0C@gD@jC@0 YD@̻C@S0C@04C@0OɄC@j8C@bTC@/d{C@UثC@pmC@c}3 C@mA,C@6|C@ cC@hIaK^C@Y>C@Xpf>C@iC@p_6C@عիC@.GC@PW5CC@dFRC@o˕C@|3#XC@@wMnC@![C@7rC@qh^C@ 3 C@ =@h ^@8}2@h_@ "b1!@h_@ "b18}׿_@XJKt1`J?ѹ_@Q)az1x 5_@Q)az1@ɔ_@ p$u1()_@#z1xZ_@pj1 _@pFI 1J_@U1A_@ uw]iJ@hx>]wrJ@z3]\[}J@d:]HJ@3]6J@]hMJ@]ﺙJ@ؕ|Ӝ^_x9J@m*[+^HJ@KA^8I5J@_Y^XkJ@u&>ee^(J@,i^@J@\ki^j6K@mBo^qK@xy^y0K@^ K@sݒ^-K@,כ^_K@D;l^K@8!iC^$DK@d5֣^8 K@(F^5K@^ @0J@e^4xChJ@8^}J@PI R^ ^J@4ܪ^ J@$4rf^'u&J@l^#~J@(u^0J@-8^f2J@n>I^OdJ@Pl^CwJ@>^м7/fJ@x k^g2(RJ@IѨ^(y:9@J@t+'Õ^h42J@;l6^@Z!J@4D^ªvp J@-c^PI@~^L\[I@,!^ȯeI@*]^ظ*I@h.^@NI@,^ I@'^HQ^I@L}1Uh^8- I@;8^0EI@44 ^xUI@$m&}^xyV!ׄI@D9v^mlbsI@._v^I@>;,+h^R&I@ZV`^I@,w\^4:H@Dp~\^{'H@twU_^8]H@@GkBAe^x{UH@-i^o\NH@1Ul^{qH@'w^PGAH@ ݲl^2oH@4y^H@hT^5DH@$3ߜi^: zH@m'^ Ϳ$TH@^FH@8ʁf\@@88@P ]@vSyG=@78ʁf\@@88@p%mᱞ\@]S8@@\@P^E8@`F\@0;8@Pӄ\@`hd8@Pİ\@08@^X\@`Z+ 9@P!\@9@XUX\@H"9@JF\@Gy(29@\@eXJ9@ ໃ\@l n9@@6\@wUB9@ T\@ jD9@ w\@`v9@x`\@]9@c z\@@9@8L#'\@09@x@ C$2IPq|,^V@ljF6@F7[V@~6@/BWV@m8Ȕ6@,;.SV@0m6@,;.SV@0m6@PV@ Ԓ6@p|YPV@f]r6@|URV@vN6@8أVV@P )6@@ K?:XV@ 6@~rVV@`Z5@̘ZoVV@@ca5@ ~UV@@z5@8أVV@p;5@ę$V@ ؉6@8+;V@S26@%0V@P,96@Z V@ A6@L_V@k6@¶ V@ H~6@|!V@S i6@\ZV@@Y76@ę$V@ ؉6@,;S.!V@6:6@$D&V@_Ċ6@6+V@+6@@f0V@2d<6@$J?4V@EL6@w5V@S6@Gb 4V@d6@t6V@pC6@\ 7:V@`~y6@: 5,>V@S ̂6@f=K2CV@0NF6@ur 8@6V@P"Ҏ!8@#C;V@;'8@r@V@@&N8@DFV@7@bU@q]68@L ,U@ 8@\4V@Uu8@ws, V@0 c8@@[P<V@L;8@|` V@`]]78@Rw8% V@V7@ V@!Y7@(yQy V@X7@ b V@;:7@茭 V@7@ӭfV@QP\7@FqV@W7@`#V@0 Ç7@p_LV@ u7@+V@VU7@dy^V@cA7@~zՄV@0 :7@ZV@@;/7@wV@:k."7@5[V@ (* 7@ę$V@ ؉6@bU@q]68@ѭU@Ӆ8@`U@P2.T8@V@nj8@TO V@c\|8@2fV@pu8@X`V@@z8@DE%V@/t8@[gV@ic8@`݄S@5s>@dS@;:>@g  S@|y>@ S@p5ɸ>@zUS@ Zӭ>@h,^S@P>@k2S@`\1>@d߱S@  o>@S@@ ;Ό>@S@ !>@` 5 S@ BC?@_>@0GS@[M>@3+S@PHyH>@$AS@WL>@PkS@аsrJ>@oFS@2B>@oF̪S@Pd3>@4(IS@`䯠>@lD9.DS@/F>@HQyS@ئ>@4S@>@S@0J_b=@ NCS@p]'=@g鳋S@S}=@P4¶S@`N=@kS@ ~I=@*kS@Ou}=@8lyS@=T=@自ȆS@1N.=@}wYS@@I2 =@$iJS@/.<@ܶe'DS@2.ٞ<@8S@+<@ȂSXS@ g}q<@Xt(S@0u5Z<@S@g@<@h}rS@:{%<@3ڙS@x<@З件S@Eܻ;@IfS@x#;@RG"*S@P,;@`pLS@^m8J;@XBS@p;@}J?TS@O;@!S@Fe;@DǷ_S@>Ϟ;@Rf1S@PNY;@0S@pkw;@J ^S@`Q;@S@f2˩7;@luS@AԞ.%;@0 S@?g% ;@4S@ca];@ST@](:@Yi6T@:@TT@&QPu:@0hD"T@q#;Q:@d%T@ I8:@B)T@wk#:@v9.0T@ d:@57T@O" :@Ι>T@p :@@lQyGT@o9h 9@x5`ST@](9@H AYT@ }پ9@ N\|YT@Ǻ79@OzUH]T@0|V9@gdT@oea99@e%iT@ lH9@X=KkT@ D܅9@y[pT@`19@`svT@{k9@@ zT@@3˦|9@.zyT@`Ui9@T@5=O9@T@baH9@8mlaT@gK9@P[PōT@ E9@Ї9@YRMT@ 1=9@XGIT@Ёq>9@捑T@ПLC9@pi%1T@`MkB9@s`T@0p:9@,#T@eea99@89@pJLT@+$9@L 5>T@)MA$9@F#ĽT@`=i 09@HiDT@!=9@8 T@0u:K9@ T@T9@ST@h5 X9@Tf1T@Pְd`9@\^T@:BNm9@T@0),x9@LCT@`2˚9@uT@lӄ9@T@#b9@X|;"T@^.8w9@lOT@ LSq9@(T@2.7v9@(T@}F@9@H*)T@㩈9@ߎ_T@x$9@ T@8he9@6¶T@Pτ9@`6$T@Pl9@MijT@r؄9@[PpT@PK9@aT@#9@n%?U@Z9@2 U@0۸9@p1zU@s9@M%%U@iurw9@U@f9@ lU@ F9@lf'"U@aTP9@*Ǖ(U@T9@xk_-U@@V9@u4U@;9@la>U@0pZ9@ 5GU@9@̍NOU@2p9@pةUU@ XzA9@)_meZU@P[9@x_N0]U@~F9@`+: `U@=~9@LGcU@ +9@h;gU@ re~9@HJ?lU@jJy9@LMrU@`9~9@RxU@QSv9@o~U@P+o`9@iBU@WR9@ԍs&U@0M9@9U@@h>W9@dU@ o9@U@Ӟr9@bG"fU@7h^_9@8oxU@`9yP9@(ªU@1F9@DN܊U@"G9@`PzѵU@`ˏZS9@tzU@>Q9@,K?^U@q/.B9@FU@`#YD9@ U@*5"W9@ߜmU@a9@ܔhU@A-d9@45 U@@]9@U@pL9@2U@ A9@TZU@`F<9@@2tU@t19@h0U@9@ҋU@n:z9@(tNU@Ho8a9@PU@C3˸8@薷_U@0 8@bU@q]68@`[}E?g2@PE@2?'E@ W?g2@PE@2?}`XE@Iu?hҷ]E@u!?ԵMIdE@a7?KJmE@6?"+|E@K+Be?ߚeE@ }?sFE@[}E?'E@8{v\C@ƝnK@(2D@aRNk@$@cC@aRNk@{v\C@@&L)@(IaC@@-uC@8I@~C@f@N!C@T7@@C@@0x@>C@@@QC#C@a@c#A0C@ҏd.@C@;5Y@j"C@3Y@88hC@@哅@HД~C@+I@i1C@HA@hIC@T~@h}?)C@.Y|@(C@Ѓ@ND@@N@xQD@@Ԙu@"D@Gںz@'8D@@sc@|HPD@ pD@z}3|iD@@w@9zD@z@= D@xHޗ@ iaKWD@@ @XwD@@Z@ ! D@4*@sΤD@LЏt*@xjD@;yl\@x^D@2Y @ )D@f%94@ Y+D@@@s\D@@o:_e@(2D@ƝnK@ aKF@c#>@3G@@m+H@@@ aKF@@m+H@@@KF@xΘ 7@@`F@70@@%"F@H (@@F@(5!@@@h0UB\ zT@@O[%@@9\| [ԧYX@@ի[خ@@𱯆~[ ީ@@(k[H2@@'\e@@ș#s\@99ȫ@@PQ \0ujϐ@@AQ,\KJ@@,y1\P*(t@@P .\(@@t> -\n@@R-\n죄@@pn3\@7у@@tVE>\,Ŝ@@Lx[E\`g@@G\HRq @@L&>L\>@@ CT\d @R}@@a\{s@@ W>t\@ d@@$zhL\(\@@2 b\8K^@@WW\PQ\@@;*\x9UY@@`\صͰZ@@E\q a@@} Dg\P$Uc@@h0UB\x R ^@@uB& [%@@O[$\Ӵ@@_*[XƋ@@(42C[(I+@@е0[8)(@@44r#[-E~@@X'[`Pj@@t-[H. #[@@pE4[؝NcT@@T:'c<[ zT@@ؐ VOD[pQ[@@\uI[ |d@@`cM[p)(p@@MxP[XzUx@@TtЇT[ |`){@@-bY[gx@@yny_[V!#q@@Hfe[H*m@@`F*l[Pl@@$yv[Zw@@G[Xu+@@Lm*{[8Fɗ@@lwZ1u[@}@@'.xm["@@ܰEc[h)0@@@x [@@ h[@4@@-y[ABsz@@o[[hSq M@@N?%@ -CN@ C#(@WO@ ֔>&@WO@ ;#`&@t?O@&+&@H|8O@ ʧ%@42O@|a %@7S~'O@͐O%@.dO@GWC%@MO@N?%@cO@fzD%@,VO@@AI#f%@z"O@0V%@5O@ %@؉zN@@d #%@8nlNN@䀐%@iN@@L]{%@xJN@:%@FN@o%@`N@7ۂ"&@H&PKN@ڂ$&@]N@`HM~&@FN@* ɢ&@ΝN@`N-&@`4$N@`&@YN@@}*&@ݥuN@vR('@UlN@SdR'@ cQhN@@| y'@*(aN@@udy'@xHWN@{'@nlQN@*|'@P%eMN@T(@ХJN@ C#(@ -CN@H/WiR@pߞU0@جT@  N 4@s ؕHoT@v^'70@% HuT@6QPN0@ vT@5Q0@0vX3uT@D0@X&(.sT@-lw0@۾ oT@*p0@Fl5mT@ hf0@0wTmT@pߞU0@ؕHoT@v^'70@8sxT@ 0@ .T@0@جT@P]޴0@H/WiR@ E4@xsxR@(s}3@,maYR@4˶3@JI8R@՞4@`;YR@  N 4@mR@.4@N R@q3@FR@ 3@(-R@ ٹ3@XR@B3@&SR@ư3@` IR@ @k"3@HdR@@Ypi3@,BR@!2.l3@R@XPa3@h Ъ\R@b\3@Lg(8R@߄\3@9.R@@R5`3@|bR@b\3@XGXR@PG;nS3@ژZ1R@`jP3@hF&R@`$U3@IS@U?S3@w}rS@@efO3@5S@|J3@x)/WjS@ A3@xݞ8S@=3@S@S33@S@@S#3@`.N/S@`3@ $ S@3@9.VS@A?s3@఻|PS@073@GS@*3@AG6"S@n8M3@<:%S@P*3@0S'S@pt; 3@@ݞ*S@j3@ss-S@BJ2@F"/S@`2@\X3G1S@Ֆ3@" 6S@pT3@sM@S@ Ou3@CES@0{3@s^GS@Q3@%LS@3@L,lTS@^H"3@|k%YS@ЇL3@\S@4zY 3@p eS@@B?>2@(i'rS@y6hx2@f}S@ u2@lႈS@hJ2@d S@p2@m#S@Hy2@pS@#2@ҀS@@Å2@ rS@PR$2@|DS@p'N2@.!ԤS@P.k2@TVJ?#S@3@߬S@X3@tQyS@@?3@umS@0B|3@kS@- 3@0# -S@P3@sS@F2@IS@0AS2@| K?LS@2@,"cS@0`2@@4p2LH? &4XH$HJ4̟H`(y[4#H243pVDH3Qy.I3-7I+g3vX>I0ikw3OxJI`S83+O&A3i1?>aO@11 2\'Pm2{P 2Y1B P@8V2t/PpSpp f@A@-S@;A@j?S |.A@!Sszv&A@`%Sv$A@ߜ;SA@d SU!@@[SP@@|AS@@_S @@`SǼ|@@ѨS:)(@@#SV@@2"SS@@M~S# Qӳ@@h\P'0AP Ȝ$0AP'pn`BP/'좼:EP{'A^GP`OWx'|S!IP{4'4tJP@^'KPkp'-$LP !bk'I D9KPwb4K'M2MP ;)'ȚRP tG')TPԗ&hhTP`ĺ&lYUPQ&0u#aWP@rin&dXPw~&2L0YP` Y^&+آWP]<ڃ8&poTP@pp &d`UP %PpgYPf6m%o )\P%,%h\P9b%,0?[P $H-8OYP Ȝ$PYJu'@KL@@b [(@v/M@@b [(@v/M@CRW(@@M@`a,z9(@Ht@M@m͸5(@ؾ<M@`W(@L@ Y'@U\[L@YJu'@KL@n¶w]@hH@``^@jOH@n¶w]@H@sZz]@8jH@@F}]@ ϯH@hUL]@iH@0zR1]@V H@6=˱]@돎H@p<"]@pi߷H@`ǁ]@H@턬H]@HUnlsH@Щ*y]@(𺇡H@la˯]@XS1H@{]@hH@(F]@ظH@hd]@uH@o]@|D/H@8J?q]@8fΘ&H@(#^@(v՜H@(!^@ MkOΠH@nI:^@ɋqH@(M^@H@[^@.*H@8f/Wh^@n^PH@`9x^@PH@``^@jOH@oZ@%h>@v\@ǡ@@p9)*[@z]ۭH@@[G[@V ;@@4t[@̘&4@@([@(O-@@Cs[@(((!@@T[@8/b@@^[@ TC@@+o}\@ @@H \@>?@u \@ |?@Oom\@e?@_\@0N?@P\@<,?@hS\@E?@,6/\@P=~?@8@h\@R@c?@{ο\@TN?@E Q!\@F;?@xD#\@-1.8?@=˗$\@p,.?@@2 %\@@-S?@آLc$\@?@@"\@?@B;z!\@pB ?@xD#\@! T>@ y}rS&\@ o>@~(\@Pz>@hs(\@M>@h]@'\@@[>@&\@ЦL>@(%(\@@;>@,\@jw>@⟔-\@]>@y}rE-\@F>@p-\@P*R>@Px<0\@+p>@23\@Ѓ5j>@ݞS6\@pL̈́>@h}r8\@>@ \PE>\@C>@`5D\@y>@؀ kM\@]|1n>@`X\@%h>@([п`\@0I^q>@ f\@*՞׉>@hk\@>@03q\@P`9hG>@VKs\@pJQ>@9Ъu\@`4H>@w\@z>@>Iy\@`|>@u>{\@0 >@AG|\@>@!ma}\@%K>@\@j4P>@+\@ x>@v\@%Wt>@oZ@ )@@LFZ@ׁ4@@D:Z@:@*@@䕻Z@o@@5Z@g@@h|Z@b3@@ Z@U)@@%Z@x~}@@QyZ@mڕ@@sZ@N@@xo Z@^@@%|Z@ǡ@@h Z@@@ :.Z@^g@@ %7Z@/F\@@J?S[@ @@ [@3 @@[@h{@@s[@MMp@@oi[@Tg@@蟔[@zpi`@@P61J[@A]@@P61J[@8_Z@@65[@Ki-U@@`Z [@p0^F@@f)[@ @@@@p U-[@pVΘC@@+0[@@L@@ +2[@h6N@@3[@77O@@~Td4[@RM@@,9.}5[@(f#M@@p@6[@{M@@X;[@dQ@@ 5 D[@ ^@@\X2K[@ 0c@@\؇IxP[@ș`@@5/WT[@~}c@@̍$X[@ ptNk@@ 1_[@0QYq@@L;zm[@][w@@LPo[@Oiw@@2,q[@][w@@([@Pr0i@@ĶL[@Ig@@v8z[@ީk@@`C_[@c @k@@hSځ5[@S8h@@#ȭ[@MUh@@r b2I@o_@}6I@EQy_@7 :I@p_@MxCA?I@0k8_@@siFI@ p~2_@ BOI@`!¶_@x8dZI@شS_@h[7+jI@gN_@؈T1~I@ (0_@JJьI@ &,V_@{I@g и_@tI@Xs_@~}tI@G]_@$MI@ "cA_@p I@2_@pŴI@FXP_@-*YI@_@{I@8q_@I@@Qyc_@8|I@H%1_@ I@8p[Pڬ_@4iI@e'֩_@I@-"㬠_@XG^I@^_@hvJ@(_@P᣼/J@ZD_@!n%J@*_@HTtJ@Nj_@$J@K9.*_@3'J@Pڦο_@ Ss*J@Xݕ_@V.J@b_@X#*3J@ <4_@ kR8J@8K_@)=J@q_@|`sBJ@h6_@ :EJ@@Rځ_@0^cIJ@p_@{NJ@<|_@9LNRJ@I_@'R4VJ@a/Wك_@(pXJ@@t_@[J@L_@_@=AJ@ :_@J@(+t8_@X=J@`+3_@8!J@>̍(_@ bJ@΄_@(/ReJ@ޟ_@pJ@pZS_@J@b_@w4_J@HF _@ -EJ@P^@ݩJ@0k^@H^hJ@h^^@NqJ@Xe^@LjJ@8 8^@hIbJ@@S^@1J@9.#^@ J@^@:J@8w1^@q J@P*I^@`.J@D ^@gAsJ@(dN^@@>~J@̎T^@R4J@pJ?^@8J@~^@tɹJ@Y^@KJJ@TN@pC1>@W|PQ@ݙe+IA@:TN@P}IU4?@ZN@p>x?@8(FcN@MB>@xN@RPj>@O@SeO>@h@)0O@P97>@PȱWO@pC1>@(JwO@C?=>@H!~ؘO@@xW>@|O@Pр>@O@@ְ>@AO@>@舊*O@u͉>@3xO@ 9 o>@4BP@sr>@LM /P@!/>@P 5P@cd2>@Y P@`?@xP@:=?@H1P@`<]']?@\A;P@06m8|?@H5iP@2.?@wFP@N?@2#P@"H?@K(P@P';?@4G3P@L?@<;P@W;@@BDP@z$@@ r2LP@Xo /)@@[PGUP@7>@@7_^P@8~{d@@؆gP@T[{@@uP@jT@@$J{P@Ӊr@@,|P@oϙ@@EP@5ʩ@@d]P@X@@/XSP@8ewC{@@d˓P@Hzm@@)ĖP@/@@b P@@@Ⱥo~OP@S=p@@8:)P@IW@@<b P@G@@hbP@s6W@@PxP@脷@@$P@е@@[PP@?Z @@P@]@@/P@NA@ 5P@HG$ A@U P@A@;2P@pml'A@sP@32A@p! Q@8띨AA@J@Q@k?A@86Q@b@A@W|PQ@ݙe+IA@d[TdU`A@nZTȗc+B@nZTȗc+B@&)zlTNgUwB@TDǑxTYmB@| aT=VaB@ߜT "NB@#TxnlBB@xFTش[3B@"Tx)W/B@#aaT+n)B@`JTp0= B@yY1 TB@hiTP#B B@HŔT 9A@d[TYA@$32 TdU`A@j_ Y@\_I4@̻|&Z@00~Irq9@6̻|&Z@\_I4@(alŘZ@ q (Y4@oLZ@}I3[4@,nokZ@P??V4@$\BMZ@`opX4@fQyZ@T`4@Q Z@@Hye4@Z@`Zh4@^Z@ Ziw4@LȎZ@@Gyz4@Hm1Z@0/.x4@ܚ@hڄZ@PaIyb4@,$|Z@ 14@@M|Z@}{4@)zZ@ j4@McyZ@P54@@hyuZ@P 5@l&_hnZ@Pi<5@DhZ@ɴ])5@pqbZ@X"k+5@ݞ^Z@PZ@5@]~rO,Z@cō5@p*PZ@ 5qՕl6@tCY@pF6@H IY@p27@Y@P2u=7@KNY@xZ7@4Y@PW7@ZyY@p/j 7@ȣoY@?e7@|;{fY@B? 8@Lv`Y@p"K58@Mܟ]Y@baU8@B@ZY@Ԟ%o8@(!ZVY@=z]8@ 9dRY@pID8@*;OY@h׉8@'oGY@,ǧ8@;Y@0]8@*3Y@`#9@L10Y@.B.8@ zU)Y@`]'n9@XY@59@qY@Fs&9@cY@ L<9@j_ Y@00~Irq9@|h{dZ@0D#7@4ڇIa[@]'99@6|h{dZ@]'99@L Z@O99@J?\Z@0?039@DM׾Z@0a"9@<,[@0#7@0k߈0[@7@hlaJ5[@`+7@Y7[@PK@7@$,6[@097@(*7[@`l7@d:[@0D#7@B?[@;7@Hu+G[@5h77@CEL[@=p7@G;O[@8 7@X8zR[@sr7@,b_T[@04@7@UW[@Uf7@^ [[@  &7@T w^[@6D7@4ڇIa[@ca7@ |v X@t@@=,\@HoD@,)$rRX@jA@lpcX@!H pA@pX@HFA@Pu{X@73A@ʁX@؜{RA@DytX@@XxA@PpX@]oA@HVX@D&jA@n^xX@`*fA@l%TX@Mi_A@^홙X@@q :VA@X@PA@AX@x>LJKA@X@ #KJDA@XsX@ U~}8A@\0UX@pz1A@ėJLX@@.A@0 ,X@R0A@ 9.X@p0 7A@ +X@T`;A@X@@)NY@8o@@_.Y@ae@@ Y@#@@~~Y@4@@|!uY@Y=A@h[PkY@x|_SA@*aY@)A@ܲzUY@rz"A@ ϕxMY@H7#,A@!rJY@P͘9A@ 5EY@u&AA@l$X>Y@cHDA@6d^:Y@ #KA@Q48Y@PеVA@F#4Y@pݐZA@D[!+.Y@POWA@1M(Y@Pk.ZA@tU"Y@xQbA@H* Y@(ɅhA@BY@/biA@`dY@ٿwA@xLY@KJ͞A@#Y@}A@laY@MJA@4s Y@ȇv>A@? 5 Y@O{A@'9.PY@ΠA@!]Y@A@(OD2Y@X|A@<5"Y@D:GA@ôB/Y@Hg2aB@L@hv9Y@ @"B@$X3@Y@HcB@X DY@:IB@0/WoEY@xX^B@n>KY@\[a B@^UY@CMB@@_Y@`*E B@HLhY@KcB@еzpY@^gB@'yY@/ B@oY@A@<Y@0eA@@hЋY@cA@xBƖY@ԫvA@J?Y@o!A@DY@{iA@h9.WY@Ȑ=Z@0A+B@?Z@xB@XIZ@ ˽B@tŻ|[Z@HRB@| iZ@(zB@O9sZ@(WwCIB@p @hyZ@@+B@~r}Z@ذLJB@RD\Z@Xq5B@moZ@p7B@O9Z@ 5C@\6Z@~}C@Z@$C@8BZ@.r0C@Z@HX>?C@poȣZ@QC@|ݞZ@99cC@t?Z@XuC@*SqZ@v#'C@8p÷Z@8HC@ 3f'QZ@(:pC@X$Z@\*C@t_BZ@X˽C@d Z@h>*C@\x *Z@AsIC@(XZ@D@ U)Z@c$D@ÄZ@^2D@d:Z@L7D@"Z@q?D@ \@hDZ@_WKD@d$MZ@EMUD@8ו@Z@w^D@9. Z@8/eD@ 5Z@͂2kD@G"-Z@0 DnD@l;fs[@HoD@+ [@enD@kp~U[@ (nHjD@la[@84FhD@ [@yhD@t9v[@jϙcD@4~r]#[@p YD@Xz뒣)[@ЮEPD@ijJ1[@`)SID@8[@h EED@ܯF?[@PdFD@ZzՕH[@sDD@ܰS[@@{>D@"\[@>D@TN܋c[@)CD@2h[@DD@SNk[@ @??D@X9.|u[@Xj>D@Hs"[@CD@,+j[@Q =D@ U[@/b/D@LF+[@4&D@[@]["D@;ɺ[@H"D@ "c[@o$D@h [@XH-D@d[@D@; [@8D@(@[@8NC@ D[@f2C@58[@ C@[@C@[@OeC@Lx[@8ijC@ [@x5C@0 1[@C@[@,EC@XG[@70C@ء [@]C@h[@@yC@WN[@ZC@@ D[@\f2C@GE[@7C@'_5[@XL`xC@e 5[@ 9ƭC@{%[@ /WgzC@ rN[@ +uC@*I[@tjC@[@0Y>XC@@.[@`0LC@I/[@:FGC@ [@ *(8C@}rU[@h;{!C@\8[@Pt&C@Ik[@xqC@(l[@3B@Lӣ_[@P8B@h([@Q[@а:A@+Б[@hOA@0:.Ő[@hcoA@4E[@Ё#QA@OFƝ[@jLA@n9.[@ f2VMA@<[@ VRA@>3[@^WA@xϪ[@F\A@Tb[@2z_A@ {[@ȎOeA@\p[@@.CjA@la[@P& mA@&ά[@@5 sA@-[@B.a|A@r_m![@{ӃA@,+[@PG{A@ha^\@(@ÂA@8o#\@oA@6\@:gA@T@\@%)djA@0" I\@Hd=VoA@x?iR\@Y>MxA@P #6A@\@DA@*Dh\@hE|A@{!\@$%A@oI\@7A@\@hg2A@̍I]@Pv B@04]@~- B@֟k]@cLB@(?s]@ B@Xp]@Ц)(T+B@x1,%]@P+G8B@];%]@V>B@Ɏ8)]@GB@/W /]@ >SB@p*7]@H\B@PA]@ QbB@!ءI]@ QWnB@]O]@Ȩ&.B@(V]@JzB@pp _]@j9B@Sd]@PM0buB@[Pf]@u/B@uXl]@XmGȠB@sut]@ PΘBB@ 5~]@f2!B@X/]@+fB@PK{3]@xIB@ؐ]@4AB@Ha@h]@jLB@#ܟ]@89B@E]@B@̍]@ LB@8& ]@QlB@@"K?H]@8_ﺒB@gR+D@BgRpX F@1xvĄRpX F@fRhF@|c>R(+E@RcE@TR3E@샤JRXq oE@gR^"E@ZRеg2E@h*~R C$E@lBxR 8ޕE@ouRwCE@;%uRP~}E@P)wR0QE@L7wR@`E@Rw'vR0E@Q qR0$r E@ܜjRnjE@BgRѫE@`lHgR%E@p=nR0g|RڨٛE@ `|R(|D@J~RlD@ln_~RӺD@SZq}ROgfD@h#a~RCD@~R+D@lZX@hKީG@ ,Y@*H@ؔsX@hKީG@h(uvgX@ H@;D\X@hH@lZX@X>H@|u j\X@#H@b]X@0J*(-H@< ]\X@ݏ7H@aX@3xC9EH@*mX@[F-VH@pla9X@HnAs=^H@uX@0>h]H@,M%X@8l4YH@a1qX@x%WQH@,ߧX@06\H@b Y@zH@c/W>Y@H@C#Y@pH@F='Y@H@@k+*Y@0̑H@u+Y@SH@ ,Y@*H@p&id?GD*0Z4h[[FpWZ 3p&id?GZSJR4@~0)GD*0Z4zg G]X4P4Gd1V45FwYQ4q@FF-K4F0$'E4H<F];;4}F`4O,4ЅZpFP:#4H52eF-"4hFpȗ4@F@3hfFy3XDJ_F`g3 UF 3敜F 3pF4312FN3pzFy#'E3HgF,b3p<F 48H3`Rz@F\:3b F0EH)3h[[FpWZ 3x4Ra@@O@ 8b@jQ@|b@`DbO@\ hb@pp +O@HT b@XhmlO@tb@GO@)a@ZؖO@ sBa@h%O@hx&a@`+O@o9a@'mlO@_ 4Ca@XO@da@;9:O@4"a@K"?O@Ha@Ɔ7O@LGa@0@ O@x4Ra@(E]P@,va@ =P@`oca@>)B P@P]>a@HǢP@nϹa@d›P@N#Ha@-:S1P@OJ=a@4KcP@ʯa@YP@Lma@q`P@4a@| P@ZXa@co"P@X]>a@ q %P@G a@Ȣ+(P@D1E}a@m,P@<?ma@b/P@d:i`a@s2P@uIa@;׉7P@(E3a@<=&>P@ )a@&yCP@ ia@*蚙EP@qBַa@HP@{a@|LP@Rk2 a@2aOP@>#&a@-QP@ ea@qSP@Da@y\uVP@uI[a@ùWP@xa@!XP@*La@p=YP@ a@&[P@tnuaa@`]P@-^Na@N`P@5a@deP@|fa@ܹ,_GlP@Za@0rP@|&Wa@ xP@Lia@\JP@D};a@2YP@ Ԑq a@(pʓP@m* a@ Gg&P@Xյca@`dA ϝP@Hј)a@1äP@ IPa@hΜP@|a@0™XP@0Wa@kP@hdxa@|7P@k* a@Lt@BP@yUa@TP@'a@"H P@D/_a@܅P@#~a@0BP@<#a@QFP@M]a@X2P@ߌa@DjP@H] a@:0P@a@d0mP@@a۴a@LfP@5a@:"P@ Esxb@( P@$Sg b@vb@P9P@WZab@$ĒzP@V|b@MjiP@~#:b@|@P@<+b@mP@8Mb@nЏ-P@C b@o=0P@8z!b@l:P@Q@L-nb@.@Q@PbI7nb@8cDQ@ iob@U`IQ@DFob@)ͲNQ@ėlb@ 6HGRQ@hjmb@׉VQ@lisb@@ :SYQ@@4.ftb@ %(\Q@,]S#sb@A`Q@,4crb@CcQ@Kerb@x݅eQ@doO*rb@|xcXfQ@5qb@~ךgQ@8ǁ9nb@̪iQ@lOkmb@iQ@Hmb@d0jQ@4mb@x֙WkQ@Tnb@slQ@HVD(ob@~nQ@Q@O|Cob@Q@td{nb@P%Q@EYxlb@'{zDQ@x[kb@lٙQ@0@kb@TQ0Q@IյOlb@!Q@Hqlb@ԝ66xQ@x&kb@fK_Q@t$!lb@=pgQ@8uob@ԖbQ@0B8qb@ʕMQ@ pb@ Q@dx6qb@4Q@Lkrb@dQ@ ^ub@L}ĞQ@+ yb@ eQ@s|CJ{b@p#)֣Q@ Ĥ{b@4c/Q@艥b@AEQ@TP 4b@xQ@]b@8w3Q@H]>pb@B_Q@Xgb@[Q@D|êb@ҏfQ@ gb@PU;;Q@* b@<23Q@cb@}Q@@udx-b@/YXQ@v b@ Q@ #Q"b@,IQ@< 6b@cQ@\r쐼b@NgQ@Mb@h3Q@P)b@j(!Q@Vb@HeQ@ 8b@jQ@ 7b@`MbO@h4bI b@@O@/W4#Y@t'忨Y@L.\*տ/W4#Y@qS@8xCZA@la-S@X+A eA@` S@`%$;nA@^ S@.0b:vA@[ S@(U][A@TR@P}^sA@HUR@NњA@T[8R@ xCA@q6R@X--ӪA@43f'R@WA@ $UR@07A@lxR@x,qA@MR@ZcA@آGQR@PBA@R@ DzA@/f'KR@(g:9A@ R@p}A@DĴB%R@KߩA@NI]R@/"qA@2R@A@o ެR@1q A@T۩R@ ^A@lIbR@Gg2A@[sR@A@,_(ҤR@hA@S}R@JjA@R@h A@-R@PCgFA@(R@ʷA@3vR@P;9A@(bJiR@`U!A@P_[R@mlA@QyMSR@@OA@2QR@\7JA@z4KR@.%A@f ?R@`_ދA@$8R@A@ 57R@(M)(=xA@sD9R@HsqA@̦2=R@ 4lA@s-R@Pa A@)R@<LA@%R@lYA@lfL R@hA@|IR@ݩ@@_[R@2r@@^HR@8f2@@0m R@8.@@ĝ R@@@5SR@xW@@̋R@)\[@@AsR@`:@@H/WQ@h@-@@,T}Q@84@@xheQ@@@@xXQ@()Ҧ@@U64Q@tT @@[PQ@@0@@J?Q@0ac7@@h넬Q@8H5v@@h;b.Q@RKJ9k@@?iİQ@X>V-X@@JQ@(z{=@@r+xQ@899'@@@h~Q@?@w}Q@@dʑ?@!?Q@lL?@*Q@ z>@!CQ@M>@TǑQ@ 1s^>@ykQ@@韙>@@2kQ@BV_>@,zUQ@2F?6>@_Q@PUS>@<@ eP]Q@@B<<@;4ZQ@5^6<@/WXQ@P!,<@XNVQ@@ Y(<@XQ@|;@` E:@PASQ@kIy&1:@¶yQ@؟k#:@maMQ@F:@UJ? Q@ 9@4[PDQ@(i9@Dh[P>Q@x9@1NQ@Yda9@XdGQ@iuri9@4Q@y9@ Q@|9@QBQ@`9@~sQ@oJq9@bTQ@t΋U9@Q@ZB9@| Q@ଃ99@`]cQ@Љa19@^Q@0-(9@,2Q@`&|#9@ϪQ@@!9@bTQQ@V;9@,=Q@@Vur\9@d#Q@^Ā8@k Q@>8@ Q@YS'8@̍ Q@6;8@qGtQ@ |e8@{]Q@m88@pBQ@xB8@5P@PeY8@<LP@` n8@HiP@k8@P2w8gP@pd@e8@PAP@\8@M\PP@ "X8@$P@yV8@gP@eQ8@z^_P@`#-H8@|_P@#;=8@P@|08@S1P@gKC%8@zQy%P@\8@d^P@AS8@P@&S~8@hC P@b 7 8@^wW@ X/@T}# X@JKV1@H +ľW@ba0@5W@DY0@ ,W@`Qxn0@*W@.x0@$Kf'W@ ea 1@<p˹W@Ѕ*1@ 9( W@FA1@ŽW@MP1@4W@5Q@ kL@Q@FL@!Q@(%JL@PcQ@zoL@ XQ@g L@*wQ@$L@pQ@HL@lepQ@ L@XsQ@YL@Pl6Q@nrL@BQ@g/L@lcQ@\AsL@X_G4Q@ bOL@DOokQ@,L@dQ@`4L@ Q@"nmL@ݞ4Q@EL@"sQ@0LJvL@CRQ@puL@,Q@εM~L@LfגQ@HL@ ^Q@W QL@P=Q@j )L@Q@`.L@[P߆Q@wCL@|hQ@@H-M@BsX~Q@x0bM@s%xQ@hZ.M@xW3pQ@`bL@4oiQ@ {͘L@ L=GbQ@@8vL@4d^Q@L@|CO[Q@%):M@h7TQ@@HaL@hw)POQ@(1<M@D X3LQ@{$M@}HQ@>V"M@fuDQ@YvL@8J??Q@*(L@&9.;Q@&M@D17Q@:cM@d\4Q@/耼M@H9..Q@ީM@¶&Q@@;E M@bQ@]g2M@!9.tQ@`-M@̺| 7Q@@zN@/ځ@Q@fvN@wiKJQ@t|N@ZwQ@h#;M@{tQ@X4ZM@$qQ@M@hyzpQ@^M@ZBlQ@8ϡEM@}r~fQ@Po M@_Q@p ΘM@9.eUQ@ $M@AM@Q@B?M@xlaQ@PSQ@hPFM@|8Q@hKDM@|Wra@E@X a@XE@X a@TE@&y&Na@ҡE@w0a@@ㄷ^E@D]9a@XE@nOa@-ߩE@t}ga@GE@$%a@9cE@0 $a@j{E@$,a@x\a@OTE@ߐRa@kߔE@|Wra@hVsE@Xs@&@@>ї>@s@p ,;H?@ >@*R?@.>@C`?@p G>@bO{?@`>@ ?@~[{>@O:g?@!>@&@@>ї>@8ͤ/]Q˴r 1PS $ͤ/]QS HH\Q dH\QB+ЭUQ񹓮0--HQVT|צּ:QѩLط,Q #g%JQL3@< QǾT'P9HdPGhFSwIP*c3PxD P;84PP*0G =P &JF-~PesAjPاlʂ\P ExdôUPXg%QP('w2\LP@qCI(NPv4dKPx\ C <4u2DPȉ:Z@P'n:,@PUTqE>Pvt9Z:PD|/8PV7 *9PV+ռX7P;@?X@ ;@aX@0Qa:@CX@` L :@TuX@0I:@ȒY@96h:@,goY@ .;@,goY@Pca;@(\(Y@Agt8;@@s* Y@y8htP;@Y@` f;@W!c. Y@k8y;@F Y@pԞۍ;@ěG@Y@;@-Y@ ~;@4Y@`س|;@pf'Y@0L|m;@Y@"u?;@ZZY@Z;@+EY@pϨx;@-<Y@{;@(?!Y@A|1t;@ #"Y@+fd;@S6#Y@` $M;@~pv!Y@`N<;@l"SY@S3;@KkY@ߴA+;@ FY@l#;@,Y@0] ;@Y@^ca:@dj2tY@@ :@(#Y@P0.:@l/GY@)w:@yG"jY@|:@o9.Y@pf`:@`{C0Y@dSmS:@~N\eY@pca^G:@XY@Puy<:@ԣ1<%Y@D~I3:@L6 3Y@P*-:@82{=Y@u6:@ZDY@*L:@LY@`u[:@b,PVY@01}a:@d\Y@ #Eq:@p¶_Y@@*:@ѕeY@:@05nY@`WF:@e'uY@*:@QybzY@ ou:@+|Y@@?\:@1{Y@iB:@+yY@PU1:@^7wY@ЏE;(:@`„7vY@ q-:@𰥊vY@@y2:@#U_zY@ř1A9@dpY@0tIV9@IY@%W:@KmY@+:@(oQy,Y@k'D:@㟔IY@ dTW:@GY@&Q^:@艴B%Y@ kzZ:@(IЧY@FR:@PHY@pu9H:@Ty2Y@n@:@o߫Y@p S<:@\*Y@]PC:@9.Y@o8T:@@hY@q]:@t{Y@@@!v]:@Af]Y@@^')e:@@ϪY@[t:@LY@N:@HpY@@D:@V6/Y@k :@T,6-Y@`J:@SoY@P >;@@hY@ < M0;@qϹY@  P;@-/WY@ p o|b;@$Y@~Izi;@p=DY@P_]e;@fiDY@@e;@,hY@DS1o;@S~Y@j;@Hd2Y@ q;@ ǰY@ ;@HŁY@` י;@Z1_Y@Pp;@l!Y@0]ؘ;@6Y@Rr;@}Y@m՞U;@e<@*pY@.uQL<@CY@@@`<@^=Y@0z<@hzY@H鹐<@GrY@<@*X@č?@^1"X@@p?@X@pR?@{X@;B?@o9X@B?z@?@ umX@`·K?@ 5ͨX@ G?@^ZX@?~I4?@ևIЩX@ ?@d0X@PُZ ?@^1"X@1.>@ȣ1X@E毇>@X3)X@vL>@EDX@PS>@PFX@=>@(gf'кX@pEi>@ d[PWX@%z>@}r+X@Z3>@|֭yX@`5`=@t@X@lj=@qCX@B=@@s+X@ɦ @=@UX@W%<@*X@4\<@X@B] <@P'HA@F;?@dA@eU@@  X5R5A@1m8(S?@P'HA@F;?@Xk"A@@+12\@@xlA@FH2@@ 7A@v,r@@)_qA@+/ @@>GcA@C#?@=A@0R?@dA@eU@@<A@pf^%@@h9A@i1@@g!A@3 3@@H ~A@8 #*s@@(2D@ п`E@ƝnK@=(2D@ƝnK@?E@Ƹ)@X$$E@@,E@@/@(&ނE@5\@E@W@҈kEE@-E[@(aK?E@. @?E@o, @x=~DE@:-ݤ @;GHDE@K@/ @8>E@uU @GcE@ډۀ @P<BE@ct @(DGE@K@ύDIE@='1@87GE@A" (@h8@E@>-%@ N0Q2E@'H@YC,E@@a .E@k@>2,E@(@Ec&E@x@ qw%E@>1@M1D)E@@P0e(E@ÏY@9d#E@x"6@X GcHE@B>@x^fE@n@zE@ˌ1@E@f~@Pu~E@Ϋl>@pE@B>6@hLbK3E@"@0 E@)_$@PGӱE@"X@X0!E@:}@* &E@? 3#E@Ķ?]'E@/Z]?x1E@q`?(_6E@Ba4?00K5E@RaI)?(> ;6E@t?3?V6E@yd?,);E@?E6GE@8;?He/ME@ ?`R/LE@ ?XYPE@H?NJYE@D?n^E@?`E@L1?/j]E@7?`s\WE@"?xKLME@P&wBJE@`¿G.QE@ пP؉Mb0-|OM@D?%hZ[Mb0-;륄MEz,i݄M`c6,P؉MYQ?,G@OMܭR+X؊ZMnhi+tEvM jc6+hsM(!*\zM[*0,fwMJ+)xouM ,(snM9\(cMd(\]MS+'(\M g}'ʭmYM qP'hSMKȜ ,'*oPM (G'|OMd,& PM}X__&/UM b&hTVM~=x&eG^TM@D?%@`T|,@K؋u?o&UC0@u@6|;-@u@|;-@:e@w,@@S&@4u,@t@4Y.,@A^RZq@,@u@sM,@;@`4,@ě/@@`T|,@@d@`&#,@HQ۷@G,@Zhc*@8,@w7@B-@]Rv@`#-@mj@`q%-@LR{@ >-@@؃ǯ@0Z\-@¸@@j-@#@ ]U-@OA@@V,-@N@0~-@Ӗ@.-@@~x@ .@Exv@.7K.@@ \@'x.@n"@KP1.@8@5S.@@ /@6/@ @@-%(/@Vs@)r//@õ]@'M/@I0 @`>^/@uc @`"L/@Q2 @+0@F @P0@ӽN3 @ ~%0@` @P7qs(0@/@0<@0@%E@o&UC0@ c@`x>0@t@0)x,0@Ԍy@0(0@Ңq@p9Yq0@'@poS0@:@~"0@y@.0@&)@02i6-0@:a@&0@"W@W|0@=E@10@όi,@@L0@un?po*"0@ςC?gD"0@+(p? 0@K؋u?|Rp9@ ;=/<@;D@'QY_(;@;D@' л$;@ T'}R.;@w'`7'`Q;@ 6=(K];@ °N(@Oq;@a(Ce;@i (г;@ŭ(|K;@?K( L;@9(bYq<@(`л"<@ +) -+9<@9P)5Y=<@xO )& &M/<@`\XM*<@`{䂑*0TV<@e*7O;@ᕼ*/mR;@X_G*;@ʜ*Ö;@a*AH+;@@}+-_;@[ +W?;@4%+ѝ;@֦Q+;@L +ho;@U`+b9b;@m ,ʼn)ri;@0,Oh;@1UT, D4a;@ Qp,+Q;@ ,c8;@",X;@ ;O@,xm:@/fE,@q:@ [b,0:@@\v-"=c:@ K-~RJ:@=a-04:@JI-m&:@U`K-}+e :@ـf-Po%`j!:@`!Uy-):@E--:@`[-P폈-:@-AD:@@-P9@`6-|Rp9@Vu-_p:@gө-0 է:@'.` 9@Q8. Z09@N.L9@Mm+/`k)2 :@~/x&:@%9 /l5 I:@`[/y,s:@sqb/pLc:@@S/=@Ĺ!y >Pi>@Hd 9=@JAw TF=@g _>@dl ֭>@[ 0"F>@y Kfd>@8Ѐ0AHt>@Yϕ cAx>@b\n>@؀`]0l>@h`;Up>@`'Ň>@ nblA>@5@}aP>@;`1>@4!(>@&"sF(>@obp?h>@%PV>@w@+z؜ׅ>@Dj@?H>@l_ +>@G>@KV@~EYY "ȡ>@5?P!K>@)` Tp_x>@+򿐈z>@wS@ơt>@}GF>@j,;>@ h[P>@B0f(>@!o0+>@#6L–>@)~p"?@lI ?@tyB3pnAG?@4c&h?@7oe?@Php`mʒ?@~R?@|%0I'?@ޱ?@^KKA;c@ KEW K@WNd@O2L@7A;c@(%K@OZ1c@LK@ R]c@ KEW K@d) #c@x K@P0Ic@ FK@Y7oc@8%K@Ic@H.K@c@`ml_K@Pc@K@CZ!c@$K@dc@pdHvK@ȹMc@H. K@LHuc@1K@EFc@xɽK@tc@M4vK@Hwec@6kK@4c@*tK@+c@kK@7r,vc@K@8Mc@ЦX>CK@`7c@褼kK@=c@͘K@7c@>IK@Tc@}K@8VZc@h RiK@nߌ+c@PV@K@(|CHc@P #WL@c@h>>L@Rc@HL@<d@W4"L@e1d@.&L@,'d@`ӅM,L@0lm d@O2L@*d@8d1L@,TH8d@辸"L@Z0憌;5@!@hձ5@@U2*U4@޷r0]04@@|& ]0,4@}5 K4@4uSY4@fv<Iv4@e|. էGg4@@oK3p19_4@hiFPMZ4@@$9Sr`RƸR4@U@ajH4@+ Gv)%4@+BbS3@[/,p3@NS3@xT[I`?Hh3@ɫ`U2@gf h2@} pO2@d< S2@ةV 17i2@-]@Ā{@xS9.SF]@K@վJ]@4W @̍4L]@$<@NܭN]@)K@C1R]@m6@U]@|x@h(Y]@@^it]]@`@G`]@]m@87bmd]@g)o@f9?@pO@H2fA@GP@)'9?@BGO@;?@.O@i?@pO@P?@&O@3i8@@xۏ2O@)p%@@0ݣO@w-@@h,O@ o0@@C[P@-@@ ZP@Ѝg.@@@ɕP@j 1@@oV P@0jl+@@P@'~@@P@@@p{z"P@0 @@pw]P@p&@@w}P@t+@@P@Д=&@@8+ws$P@Sp@@8%\)P@PWta@@h.H.P@0a$A@@1/P@`O1@@vskP@ @@|jP@0a$A@@1/P@@@L3YW1P@ ;l"/!@@4st4P@ɺ:@@7P@ZkK@@xl;P@JzP@^1A@"rP@H2fA@Ft?P@:t{^?@׉G7P@0a$A@@1/P@Jӧà8@vP@[s{j<@dD*Q@& \;@(P@pWR;@$CP@hE;@P\~ݗP@="0;@,NP@X:@UȖP@03=g:@$NJP@@M :@]\6P@x9@`=P@Pb9@뷠P@pyQ9@(kDjnP@j:of9@35P@O3uM9@d@kTP@ #8@tP@?8@x\: P@I8@(x_zP@ӧà8@vP@@LG<@dD*Q@,2<@=Q@[s{j<@@P@7q<@tHP@^M<@<@DP@P7&`J<@:SP@TK/<@ĔD*P@ R><@TV}P@$F:<@|ɕ\P@3!<@3pP@U<@P@0<@UP@PĩK<@HP@O;@fP@0;@ P@3;@0xP@u{D;@v P@`:+;@<ρP@0Bb;@| xP@FY@ȑ"Q@{ݞ5IZ@qfL1R@{ݞ5IZ@qfL1R@7Z@0er/R@%f'Z@ؗf*R@\nZ@<Z)R@¶ Z@xb$R@/W Z@|MM!R@h@hY@h{zR@QsY@3R@"Y@آPR@J?Y@[YR@IY@Tt@ R@`XY@R@ (QY@p*)Q@FY@ȑ"Q@`3W@VlvQ@FY@ȑ"Q@2*`3W@H$Q@0}1 7W@"|Q@9NW@8b(B{Q@GgW@XxQ@nW@h2ѕvQ@dU[W@VlvQ@(wW@$@-_-wQ@)lW@\u{Q@hQNW@4cQ@HW@ [Q@MGW@{Q@/WW@TemQ@X̍W@@t Q@d?(W@pUĖQ@W@dpQ@FYW@6Q@x1W@(BQ@V#W@OYXQ@t~pW@ (Q@yUW@%V;aQ@Tv#W@ =Q@(bpW@LQ@,ҘW@VQ@ DW@lͯQ@X6W@x,_0Q@—W@Q@ma2EY@hj)Q@< Y@*KQ@@X@1Q@1X@jQ@X@$Q@<%X@~Q@:<@>)@:Gp>@F# @`%_>@>)@:Gp>@k8M@e+\>@tR|@ x)G>@@(\(>@B>&@K>@Ye@PDF=@gá1@o=@W:A@ =@nѿ@pjV=@|)2 @0,~=@ ` @P%`p=@ ̵f @TX=@9Vl @R>=@ @D"=@HEH @Dq=@F# @&ӧ<@E( @g<@mͰ @:<@3 @*4_hotڜD@`V;r^( E@"g%^蝓+pD@̵@^^^D@`8^pfD@9r| ^XD@P*o^_D@ `_D@4_0g,D@ys^( E@`V;r^/E@3s^hi/E@Dv^ QE@,y^`>V*E@t#a}^@慷E@89M^9nl<E@^а4E@ r^8p D@J^&&D@du^?)D@䇡^ΚD@TxŨ^}D@|V@^xČD@0^(7-D@nv^h)D@^dGD@foc^FD@B8@^ D@D/^h۠D@mM^p .D@t*g^ӨD@/^0`^D@nA^vvND@#4r^0o4D@jr^hotڜD@^ sD@h0C5@jN@1xA6@zN@ 1xA6@jN@tҧAf6@N@0 mfW6@xjON@DZX6@AۡN@ &)M6@'N@@ZK56@ zFN@Tr 6@L N@YOa5@u)~N@`5@HoN@0C5@zN@PTmA&b@N@Qdd@~mw2Q@TmA&b@}N@K0a3b@QN@4gƤ9b@H:N@WSg.>b@plorN@_Cb@3@N@`VXGb@pY^(N@cJb@N@|6Ob@)*5N@\# Ub@I.0N@ĒTYb@N@e^b@@N&N@ .hab@ڈN@E3cb@ f:N@M5gb@'N@$kb@K.N@ԩAmb@cҗN@А12mb@T+N@X-Xkb@hzN@^Nhb@oO@B+hb@;O@L:jb@h"O@9Ĥnb@0% e*O@l2a[sb@H(O@]vb@6&O@)wb@8$"O@\kzb@p>#O@H^S}b@h}SSO@\c̀b@O@ փb@Lg2! O@,, 4͇b@. O@t4rlb@':9GO@b@w O@Sgb@WFO@p͞3b@H$fN@`cb@RN@ Bb@\[{N@tb@ jT]N@Tb@ N@̮0b@FN@PL?b@[N@0̀b@`$7N@ ڠb@N@*Keb@@HhN@# b@WN@lb@b@}$ O@4Tb@( O@ b@@Θ< O@O@ Pʻb@xQ :O@b@ОL;O@zzb@-:9?O@P %b@-aHO@\xjb@c-GO@vc@h_FO@LAc@6 >CO@옔q c@4MO@zc@3.^O@n+c@ml^iO@/̘c@ZoO@(FHc@KJvO@l]1Ec@X"O@`4bcc@.O@c'c@o(O@xac@4O@#ѱc@ѵۘO@u c@<;O@`k2c@mlO@tLc@Q}BO@BVc@oaO@)1Ec@G`O@y]kc@P[5@O@P@$Eb@OBP@$b@k;GP@4bb@YJP@L->b@LP@`Lb@J9NP@pﲓab@h/,OP@=Lb@$PP@b@>phSP@b@p0UP@ؖ b@RNVP@L* b@SZP@:8b@ fbP@` b@L-fP@dxb@42/hP@b@"lP@Tb@{zlrP@བྷb@}\uxP@Wb@ tP@d&b@4qP@$ܐ1b@P@̏k2b@%âP@0Lb@9P@d>?b@<P@@S75b@lP@&^.b@g `P@ڏb@DP@D^b@D_sP@b@H¤ P@t$b@7ԁP@b@t׍P@ސIb@$OP@63c@HUP@4b0c@ P@0;1c@DP@4r4c@8f̨P@Bc@`1P@][c@NP@ Qkc@4E_P@X յqc@ uq#KP@Tyc@fP@`8:c@ѳP@DAc@,fP@#c@(>P@E3c@ &%LP@ܡc@p =P@8c@PUP@lTc@TW1P@`[Šc@@_ P@Ufc@d3nP@o0:c@0)BP@@4@4Qx@t{3@p:_@ h}R3@NF@VD3@{&@[czk6P@ 8b%Q@nbHb%Q@َb66P@]gbNkP@vlb 0OeP@Bv}Lbc/P@zUbpnKP@W[xbP] }aP@\Cb:ʕJP@ 8bnP@C+C;bxNP@?KbDXP@bĊc/P@kkb)BeP@bOṺP@cћb=߶P@( EbT9LP@Xb,P@iUb|TP@mcoC#P@vLc:SP@ cVP@CoNc,P@[j}cGG=P@p>cyP@ ]"cdgNuP@Ra&c/P@wx)cLTP@*c3P@YMLS-c4DRP@"T03cl/0jP@V=cйt@P@|"VJDc(::xP@VHc؞ĂP@vhNcT^{P@ɵ_Uc`%[uP@ 5[c0\urP@<84_ct~\sP@ac LuP@7ubcLEvP@S?xgc xP@hcqREzP@Oicl{P@QDΠkcD}zP@%}lcԬ{P@lcw]}P@K8mc33P@mpc-P@w&9tcH)Bf~P@7xcb~P@O!s{c17ӀP@5ScJoP@Q$cA P@e[c9-P@i2cə}P@ lcx,0|P@ّ{c0EE{P@%cGOzP@Wp c(7xP@f")cXHuP@1ک{acPgXpP@cqwnP@5SSc8ǧlP@/c 2#kP@.ǫcTiP@`K<[c\/KhP@0󛧢c\gP@D&Ϻc0ƅQxgP@XtЋcl@׉dP@ϕc̹{cP@;h/cx}10bP@? cLHaP@y7cFK@`P@)Vhc o,_P@D&Ϻc\J]P@ D1cE-%]P@WCcڦ7]P@?ctI]P@yic؇D* ^P@3#cȵ`l_P@đc-aP@azciicP@ qcdP@Fc dP@ !cD~bP@-U`co0]_P@ Qcp#_^P@Vchʌ_P@~[|cIh_P@ilc^P@vch ډZP@clA YYP@@XcHaXP@lc SWP@_޳c%t@TP@cac!KdSP@9QIczPP@ܴcx}MP@oN/cT=pzJP@chZEP@$<c=pCP@ds.c =pEP@W֭cDP@@cU:SBP@;鱬cZAP@eT&cƸAP@ cVnc#V;7@P@cʵ'}=P@*acxH:P@6cVz7P@[czk6P@he'rR@@"Z~/@ȡ9T@K 1@Y0d S@PQ0@\PS@h0@`S@@y0@4sVS@G0@8鰥S@-0@B/WT@P۞0@a(T@*0@(Ew T@Z0@T@ D{0@1bT@0@!T@Pb=0@dFO(T@Uy0@xC-T@d0@ k/W*2T@p*N0@v8\5T@@ o30@N~8T@.rՁ0@ȡ9T@ "/@T|9T@`!^/@1*8T@ ͩ/@v8X7T@@"Z~/@he'rR@K 1@4syR@V?1@\[ߑ}R@e 1@MoR@zX1@(R@ 31@ 5'R@#(1@%R@ Eܫ1@\v8R@\čXl1@$R@p.T1@ R@0YA1@`*\R@E|31@< K?܎R@_D(1@DR@`e1@b/ץR@xS1@zCR@ ]' 1@SR@ ?1@mR@@# 1@t;R@>1@ {R@v^'70@$XR@ lB0@8tbR@pp0@#S*R@p0@"uR@ K0@;J?)R@@ 0@M\R@ ,V˪0@hsdLJWN@)WcH>O@O)WcH>O@5!ZcظeO@>JO]c€O@,h4Q`cp7TO@B|ccp{TO@>]hcȡ#{O@ykcw~}){O@OsQmcO@8oNocɪvO@$sc-x|O@-Wsc-dLJWN@@,0@`4&j2@Sh Mj2@`4&{ 2@`z1%ɷ2@Ov%c#2@ P%3ݦ2@`Ym7%PR:2@ˆ %`:2@\i$` z2@Ĺ$@DL|2@ ;]}$@~2@s$ҹB{2@;ۏ$}3~2@KyGv$cO2@ tGW$CAH2@@m;$UN2@s%$=X2@`C(#42@#\2@@ #0kN2@iz#POŋ2@ൟ\#0'Zt2@@~B#@ڴ"\2@ 9X #ND2@@J"@r(h02@Y"D 2@`F%l"p82@wh"Pv_2@@焖a"@, 2@`(M"5 2@G:" 2@bQ%"P4r{2@:#!0\.1@%42n! aj1@ !QY81@& @1@ ι 1@ < K81@$,& `L>1@_/D~Wɱ'1@yzlL:1@16T1@ܷsU0@@5ȝY0@@x(ڠ`m<0@b?P^0@ZҦ[P3$0@fi:H40@@n@MyV,0@ &s0@@f9Sb3÷0@8*0@/7f0@<(Bup#:+0@p9(0@bC~0@@֦ːI1@K2 pR1@oa `imJ1@#\2 0- xSL1@Mנ PZ]1@M I`1@KmT\ HZ1@Sh h^W@4¥I@(X@x? #fI@ (X@ȀI@=K?xX@x? #fI@Hb*mX@^tI@SX@I@p5b!X@iYI@X@05I@@o' X@( I@J?WX@( I@_pW@&+˫I@^W@4¥I@N9S J@Ѩ*QT=J@& lPQ J@PQ8RBJ@-8˘Q7J@Ѩ*QdQJ@jGQhHJ@OQ J@l`yQ |J@ѾQfI-J@Qh}$J@֡>Q@ J@L@uNR聆J@|0 RR|J@SwR99J@DYRzJ@D>RI=J@ c6R3TJ@lRU|J@L,]N^R0逧J@,bRQeJ@@?* RpyJ@p9E,R "J@2.RxJ@@n_6RAJ@$&IR0J@,?TRT=J@8"ZRz #J@| LbR0ڌCJ@/8ϳmRKJJ@7ϓ}RxίJ@L4RxCJ@dqZS`^J@H hSxf2J@D3dtSE:J@uSX SJ@]ShNf2J@d籹Sx@sJ@adSP`wCfJ@9S0*jqJ@v8>@\T(XX@` o>@.3XX@@M>@طߵ_X@+7hK>@X )vX@@MG>@4|o}X@@cؒ)>@@5SbX@pS >@p,X@=@*HX@j=@8T/WdX@e=@;@BX@0՞?;@wJX@P;@]);@;X@Pur4;@oiĪX@p?:@,^X@ .:@PX@BGyá:@k*MX@p;:@}rX@7h:@ X@*Ga:@𯄬X@l,:@/WX@1Gy~:@8 X@ o9@V(X@`y{9@sX@I19@(X@Wm9@tSX@HC?:l9@(X@` P9@n*#X@:29@`Y{X@Nz!9@ RX@`|9@p X@r[9@$F=X@e/.q8@xҟX@ E 8@Y@/--8@ꕽY@ &W8@*Y@3ï8@\BY@㯐8@$^m Y@ )8@ Y@F8@{9Y@m88@/Y@՞8@i6 Y@@E{8@`Wd #Y@PJFc8@|!Y@"i68@,^ Y@F8@>QyY@ eK8@Y@X8@T̍Y@0;7@P\|Y@Ф7@laY@P7@`C Y@`87@Z|Y@pLy7@tH[PFY@<G7@RY@da-&7@LfY@G 7@;w8 Y@(6@d;Y@a6@Y;Y@po6@tQy!Y@@+6@ZH$Y@Ewg6@3)$Y@0}Zis6@h%Y@s=e6@+(Y@VW6@PlLe)Y@G]JN6@0'Y@ߞI6@lVio(Y@P|D6@߀R+Y@ oW?6@TPi-Y@pՆ46@d-Y@h1$6@G1Y@@.B 6@ 17Y@`P5@H6>Y@@P5@LͷbGY@5@0JY@P6h5@2@HY@P=5@8$4HY@Ix5@YiDmIY@Ӟ5@jz$EY@pK]w5@Yd\;Y@L]5@]Nr4Y@/ԞoP5@xwl0Y@; P5@*-Y@0i [@5@X%0*Y@P,A?a!5@aUF'Y@'05@D$Y@# 5@TP"Y@<]' 4@k!Y@ o4@D|(#Y@F\4@LJ'Y@94@(x#'Y@" 4@hi6+$Y@:4@!XY@0&W 4@tbY@ 4@x,"Y@α4@땽Y@I4@|N Y@ lϖ4@|NKY@@_I_4@d@h[Y@ l8A4@ئY@`>4@a/$ Y@P E4@ف Y@@LV4@6Y@ҏZ`4@fYY@@Xb4@@ZY@!W4@pTY@\d=4@uY@Bi /4@Dzh#Y@+4@XB%Y@]4@41:&Y@3@I)Y@2>3@ThzN0Y@p{53@u6Y@3@̠dX=Y@@:3@T̍XBY@8- 3@PmSEY@n o3@0DIY@ ^'O3@'SGNY@pԠk3@8ukTUY@0ug3@Hap^Y@x3@ 5lY@p13@~Y@ܫB4@4'QyňY@)4@^Y@ (4@Y@ qZ4@(Y@Pw4@lY@cK3@/W{Y@v3@:tY@?3@p(tY@F3@xi=uY@0Ѕs3@#UxY@@ ōRk3@lixY@`baJ_3@(+vY@@efO3@FUktY@JE.3@X^sY@ 2@HG"9tY@QP2@YbuY@м?2@\PtY@SP2@v8OqY@ J2@D/=jY@l2@4}=_Y@;Jy"C2@2!ZY@]Fo2@lkZY@ q1@XMoZ]Y@**1@?NdY@P@? 1@X@R V@{ȸI@ rS@wC>I@ rS@|BI@(0@E +I@@La@I@ %@ r WI@G:b@wnlI@ "@{ȸI@6y@Ө١I@@R V@wC>I@ ,У1yDZ@`PM#J@0eA`@0׈nR@6C)^@3N@x/^@2N@ t ^@P#,N@^mn^@{!N@i]@"VSN@6T]@VK N@ȫi]@#WN@82t]@&N@@DY]@zM@WΉ]@_$rM@p\]@xY`M@d#Ҥ]@FdM@/W]@XrM@ڞ]@fNM@Iښ]@TM@(J?]@cM@AB]@BsM@*\]@dDM@@hHH]@R/N@FB]@ N@Xu=]@@0_*N@Ԝ8]@p.0N@@;p*]@28N@_]@`@N@[]@؆TLN@8_X\@ٴM[N@ l-\@ӱ*cN@HiS\@bN@2 \@p^_N@0,\@poV!XN@+)\@`SHN@ 5\@8Hz0/N@!@hʈ\@J!N@~SӁ\@NgN@صt\@X N@轜=a\@(|LʯM@h(VO\@gM@06>\@c'M@Pt5\@x?4DM@13\@Xp M@q 5/\@ M@`(#)\@H*g2M@@Q"\@ HM@V9.2\@H M@xCF \@3M@H8#\@kI+M@da;E[@RכM@Z&[@(@M@#F[@Я]M@<[@t&mM@ܾ*[@QwM@`[@ djlM@ [@z`bM@,u[@Y^M@4[@`M@Zp[@=`_M@Bt[@ȀZM@8[@T##M@klE[@z!M@?0<[@h,M@F'.[@KM@ &[@( M@HT&[@@M@D#_#[@(S]L@[@x\[WL@F&[@螫vL@&9[@L@|^[@rwL@kk[@xL@([@x#L@ ޾[@h&L@'(?Z@8qOL@t Z@~GL@5:Z@p L@+:Z@L@vuZ@LL@êkZ@QL@(3Z@4L@<"cZ@`OwL@8LfZ@@YL@c"Z@L@X/W1Z@|DL@J31Z@P͸L@ K¶$Z@8q nL@Xe'Z@(BsL@:F\Z@`)(L@v8 Z@4VL@:maZ@h%rL@ 5Z@X)(L@dZ@XOL@h;DZ@UrL@+Z@]L@laZ@8L@$Z@x)L@dLeZ@XkU!L@[PYZ@@B}L@9ʯZ@P,rL@XZ@l`CL@T[5Z@iL@EZ@L@FeZ@J>iL@`FzՖZ@:YtL@QZ@(6jL@bpZ@@֫v7dL@ES kZ@8% _L@h]|mZ@H [L@Ԗ5uZ@K$YL@4Z@GvMYL@}rZ@UL@fZ@0PeNL@+̍Z@GL@Z@8a@L@D^Z@ti9L@@n2׌Z@๵M4L@GNZ@.L@dJ_mtZ@XxCc(L@LdulZ@"L@8TBkZ@1L@ mZ@(SZ>lL@tZ@HjOL@~p~vZ@g5K@BwsZ@ @@K@ nZ@`GDK@4M ?gZ@LxCK@t,"@aZ@ľK@xtF\Z@0ƣ>Q@ck_@|Q@ _t_@̻Q@G2_@tBQ@_@-zQ@es_@pUʦQ@0(_@)BQ@B_@H=0Q@(ʎ_@DQ@@^}_@0C+Q@pma=s_@^ œQ@(Eq_@0OQ@(9UQu_@L׉Q@B]_@4Q@X5_@%%Q@hCz_@)MQ@qq_@NiQ@̍__@J{zP~Q@X L_@h yQ@}r E_@'tQ@wZuA_@ȵU;mQ@9_@$eQ@@4._@`7YQ@H}z'_@4U;UQ@';_@rKQ@,_@x0(-FQ@8-ت_@PEAQ@+ ^@8HJ;Q@h'^@62Q@H{SV^@`(Q@ ^@p"[Q@ȦΈ^@[ZQ@h^@8&Q@pZ5^@ Q@й^@ԀQ@xơ^@wP@^@P@Hw8^@LUP@hD^@ ؈#P@@iv^@0VտP@N^@ -P@p(^@IE.P@柔^@`+P@;^@x)P@^@pP@̍_@`iP@w8 _@wP@ +A_@nP@#i_@|DffP@0J?%_@H E`P@*_@`@zO@P;`@#uO@&`@ rO@0c%,`@`O@|2`@w7O@l~e4`@/h2O@\4"K3`@hO@̣43`@x>WO@z@6`@HA|O@#q8`@mO@xf5|:`@ݩYO@Hr=`@X.HO@}|CI@`@a J=O@0eA`@X*.2O@R+A`@;)O@o?`@O"O@=`@4O@<`@}O@Ա;`@hO@R;9`@ߩ]N@m4`@؀0bN@s*=/`@ N@@&`@nN@ `@W\N@D Fsb`@5 N@~`@@[tN@xs(_@xAs&N@&o_@@# #N@\^_@A3N@Xо_@*-XN@XWp_@N@0*_@xx}N@ TG<_@H͘сN@H=bx_@:9wN@lDe_@!ȰmN@gf'?_@h2`N@@I##9_@ ZN@v8._@ XN@XI_@ P@hVN@_@h RN@Gi _@ SLN@@S^@XSU!IN@t^@xjϥIN@pi^@P@|LN@0/W/[^@As=RN@W%[J^@ ON@S7^@ DN@Qi,^@|}`uIgM@rҺ `0gM@ڝJ%`0mM@tôm_6 M@n__(kAM@Yg_xO~}N@|)4_q 7M@{uY_˞M@j_zM@tW֑_q M@Ŝ_M@H_M@0(D_nlzM@(آ_>0M@dH_a<^M@D\._vM@ 'j_5M@S_M@~ܙ_(3dM@XX_t&|M@ ~_f^rM@$8;w_HM@׹]s_X^jM@ k_q# M@\_\V=M@ڼzN_x+çM@sA_-M@(qP8_i5M@7v2_"3pM@._Pb]M@ yg+_M@LX)_U M@l|p#_@["GM@Jw_`M@5kBl_]M@0@ _:JM@ďQZ _LJM@p+_xPdM@0 _zM@&~^ MM@쭼z ^0Uе9M@2m^3*N@gZq^ԡN@\D8ϝ^Ho#N@/^Hfީ.N@XT^h8N@4+^8BN@D8n_^ɐxMN@PB&L^PH0UN@̏p^oZN@c^D"^N@8zE^DfN@h4M^\.ArN@P^RN@Ԩ-%N^ FxN@ *Q^.ŖN@xi*:@uX09hl"@@֬s%6Li*:@I-a7";@L79 xy%;@P?7@ /;@ \7ܕ=;@g-s}7P\,;P;@l7@ 1f;@`tk6b7a#ë;@r`K^7}R.;@AuS70H游;@8լ@7ȯԤ;@A770V|;@w8870+;@_27 g;@S&7%`;@v7 x;@\ZZ7Ńl;@ 7`;@f]6@L*<@g6`vc5<@@sB6@Ka<@Q 6ɹ<@60T<@`GI6P<@ ]{6 <@x)e6pbMu=@РdGG6pD?!=@pfΘ66cj`=@[16pr©=@֬s%6=@)/6P%0>@ NJ6+u>@:T6`$`.>@ Id=L6pug>@pljJ6 ?@peN6>D2?@nJX6zI?@ӱLf6pރd?@o6?@s6POe?@k6RR?@򁶵6Pg?@\f6v@@|6H4@@!4 7@@%7(@@#'!7 @@`[}47¶&@@ xUM7 2@@l7^ o>@@__7VbKI@@P7  V@@:,a#8 rvi@@ ȗL8q\o@@=rWg8H s@@PYp89@)x@@#p8`N@@)\|84pҍ@@PUm8H]@@@8,/@@I788Fcѡ@@8@@-8nh@@08@@@)-@@w78@<ȱ@@v>r8`Dj>@@K8UX@@P/8@@M788@@0#,8 @@p_8r@@P8hl"@@8f@@d 9@2@@.09r\@@ J;w$9z@@uX09(߉@*@I@F\4h-@*@"ڹ`T-@*@F\4h-@@TcRڤ@eM]_-@ 7V@@ʍ1-@\Œ@ T,@\5@ҫz,@@¿@E,@qw~@š,@@*@@u,@@\!@T',@`@!dg,@2:@``἟B,@ YA@kIT3,@@$@",@ `@ \0,@P~@;J+@$[Sm@@!+@@I1@+@]@P]C+@m@;m+@ U@ L]K+@g@E+@bR>}@Z[+@zǏL>@%0+@ӉK2@o+@3n@SO*@‡@@Yv*@|Nr@*@@I{:@ *|*@UYX@@R]7*@="O@q>*@79@]Y*@@7@ 3w*@'\@߉@*@I@߃U@HtgL@&[@ X}P@ 9.lZ@ YM@}rsZ@L@$o xZ@q L@ko}Z@P0U!L@`J?Z@@6M@p qZ@xH]M@߸Z@QL@8gs,Z@.L@4 =Z@L@LͰ%Z@8WL@sZ@0][L@8&¶BZ@NL@SHZ@L@T-Z@HtgL@(:Z@`lL@(?ilZ@@L@XZ@jZhL@Z@p$L@Z@ L@kN[@)s M@Hەs [@ZtM@(t[@u M@@[@bM@I[@{U!{+M@<\N@ @#,Z@w;9kN@D%Z@6uN@"c [@HmlO@pD[@pO@Z@(qV@]EeP@ BKV@m\aP@0^~V@YP@¶V@oGP@e'V@ZNFP@H@蘍V@L%R2DP@lvϪV@0AP@lV@ \u6=P@|ôBYV@8P@V@ q05P@V@,53P@(\ V@5AM2P@Ȼ8V@ᠨ1P@? V@䲝\-P@\/9.yV@gt&P@: V@)B"!P@(L6W@h RP@`0Di9@is]|'p:@ C :?:@is]|'0,l*:@W'0=X:@P'6qs:@ 9==['P:@[X['39@@N'@_5q9@w9>'"9@ i*' x99@9G&{L9@`lpp&渨9@n &p/9@4O~&_U9@`F9f&ࡏc9@ ЄV&qgP9@ kp(N&s{F9@`Ay:&Ш9@yv&8OM9@lp&7D19@2V%Թ9@7z%P$`69@`&v%c%`J9@ޭ6%09@@~%pGx9@;GN$_z}9@M$r9@U($@6qj9@(ɜ$@j9@0d$p&p9@d6$`BHp9@`Ϝu$`0Di9@lp@F$p9@8$DUr9@@B8=M#@9@@+Xu#0G`r9@ :a#yH}9@9ڧ,#`^V~9@Fu"PiO9@m"HT9@`nQ%u"Q㸘9@ա" wԧ9@@2*"`"9@Yfp"0H9@@ d"pRY9@ S~\h"ج69@@tF"bj] :@`/!:@!@:@`Ƨzo!pѱ:@`T%i!H9:@=! H:@`%bT!3D:@W֎ &`H:@$v АĖhS:@E p=KvX:@ 2 @~EW:@`e! }D@]:@9P p:@ C QrJ8@@Vp;;@?-S3:@@Vpp(;@(2;;@${f:@@\]LoAw:@/p}pce:@M^:@~06@:@f@ِc:@w]3, e:@Tp`v{2:@]rP:@@g݃p:@K)6 :@^]:3:@wP!2 @9@p& x9@w 0!:[9@0Jp 9@b.9@eJ9@+bn 3M9@T$; 3M9@Dv9@-x3TY9@7 PL9@`TDZ9@L]`{9@6y2ILj9@n}Gn꿀v9@^>0Vt\l9@brpjq9@`ؿSYv9@ ,ʿ9@v.:pt{R9@h?PcK}9@`$?@3h9@[?]A9@CTd?騮"9@Q"=?yf8@⏈;?`ӧo8@?u?38@d\fY? w8@|,l?P+x8@j?QrJ8@? kGN@;,-^(ZN@D˂7^`y$N@-tI^(ѠiN@ *Q^.ŖN@=W^gN@8VԴe^@مN@0pI ^O@b^hd@gO@8^80bO@\^E^%O@^hQR'O@`M*^)O@`^o3O@$xv^'FO@.x ^ZO@hD^qO@<ɓ@^PO@ʮ^̀O@ķ^؏jrO@=u^8,O@t^ yO@Ia^@(O@kB^(aIO@A^FO@\`L=]_O@4Hs _(O@3_c>O@ۿM_0L O@)_̯O@쪹]_P@q_P@Bz_dt# P@Н(_>P@PZc _fP@,a%_hP@ĭ+_2VP@@/΋2_h0P@)9_x"!P@d/<_JV'P@w]Na:_ox*P@X'u\<_t7G-P@̅B_$&V.P@6dG_pKd0P@ PI_t>4P@1a+X_L"7P@eEg_pL9P@q_t$:P@hu_84=P@;_,"$CP@xf_TaZKP@B\_Ӭ:OP@z_ RP@:,_A RP@B;_WP@P`p(fP@_ `LgP@`!iP@phT`DK}kP@tF2`D PoP@<'`@ˮrP@&a`}xwP@za"`(x|P@L D#`pjq#P@.9"`PP@Pi4!`$rtP@7vH` P@4ّ` cP@I/S`aԬP@'`@VYP@C`:\P@C `\ރP@`Zj"`?lP@³$-`H`jiP@NYC`2P@ F` Y9P@y%G`|1P@XRH` =*P@``L1Q@Vo`ο~=Q@`H2-Q@P)q`T:Q@ J`཮AQ@X^`!DQ@XG<[`X!GQ@.`z:IQ@n S`;mCLQ@ +`:S.PQ@Vo`ο~=Q@$i`Pf:Q@&%5`l9Q@2{>`T ;Q@J+TK`p;Q@~ e`ZfT:Q@kI-"P Dw^"'~P\"DJP@,F"lECfPc6"^] PT@"2|S$P!QPs!TPJl!@6P`-!@ZO@@w!tXӞOJyu! O߳W!O sOs_ G]Ohnpn hɐOyZ `qO@9X HnOlw5sO&6x@oy}O@O`_ia}O:gGrOτ#~`Z>tiO, NWp`O7pQ XONI߼NO@#iݣJsidCOY+ X6O+oz2HB} /Oi@u+O,T+O@ۈ0;I.O@Sdl,O@I'H 8$ONJd<6O<%w@5OL[ۡQO_2Of h*@ O=6 hc mODBh6No˦vXN 5NpN,6WMN@.sȴ;~N](60B%xNH}oJN@o@[N*ݷN(xQ.blVN@Sl$5N@]ZЦ-wUN*[OHM/wNXĦN!}ЉݾN@:uxCՄnNh6^Nk [p\N (B{RN+8>CN];:NEfiНit6N@>L1Ns_rT.N@[̒i_B!Nͦ#cI_Nࠦ(9Մx N++ڴN4ȥXE«MgT6'M{)XQ*MJ9{Met*M=a&/M@9 "|MsgwнIM@Ot|MV){X7kkM9Kv8Mgbgm_֣M!`^`ZpMXEa̭MO~RFGM'6fMy.bM Ȁ겝M,^plMnbhʭM6 (#Moi Y2XM#s  Lg%[SF@4hǘ[ .G@4hǘ[Hi]F@0xu[@еUF@pNX[SF@E;[iϯTF@Hut[XY9XF@\&[c_F@A a[p`F@[99*oF@$][boF@@G[0ˈTkF@D[NmF@i[8$rF@:Ǒ [Rs~F@qEb[8ψTF@Lg%[^F@T.n[q`F@~|R[?MF@Ѩh[hMO_F@][2 Rz? (,-8R /'(RೊXM'Q@Ũ( œ}QX(f]NQbl(5V Qt%)YgQz2),)ȡ'qQb2O)PVdQ 0fQR)PR]Q`+,4)8dYQ%h)Xԅ VQ`a)>ISQ@ ")V#QQ2)) OQAX&)P.SMQ 0f)KQ@:yz)IQY_%)tyFQ`ʵ!&)@hb DQ&)k@QCiә)];,Q@.'t|sPgX 'pP8ދ':_P`(,4h'P ` `'DP`ϑ/E'p~P`X'-x P ~ & Pn&O;P *&D42P QK'q| P''4P'L\JP@x&H`P`~&tYq#P?3&~zP`$C&XxPQ~&HVP@r& P` /&H>hP`y',&uTPtq&SB&P u&Z#P/h&HGPnBwjCrP0&D3gqP),0&6P & PÇ &hY1,P=٭B &PrG&<:Px-:%0P% dPlc%Q'P%xE!P %8!P`̸%Ȉx6P %4`P%,>KP1̚%>-x~P %$W({P)Μ%ôyP| %cyPts%(eVwP`46d%xtP td%8CMqP`2U%t qP`a6k2%VoP U!%XO)lP0#%,'JfP Z_ %H-8OYP Ȝ$ `/kBx Sh^V?(. pRǀ+8&@M0`/kBx S6ѯ/?,Sh^V?P,'q Sqa0\?;<Sx ],?~0R%9Vy@9*RI&@:,QR @R7]R4`@_3ORC@X]RDp5@1{R@IRොf$@сRk3]%@@^𭘮Rc\`%@8>R@d%@0,L} Rǀ+8&@h(T@< 4@|uU@I1.5@0h(T@@_Y4@xTX(T@}4@$u[P*T@0k4@0T@i#[4@Ʃ8T@`wc4@Ț[Pa@T@y 5@ JT@$\'^5@ŀYQT@?!Q85@*eVT@ Mt5@_[T@Y'W5@<˺bT@'#5@(biT@|5@=kT@0 5@Z9jlT@@ 5r5@P뒲oT@#@?5@}guT@P=5@zT@p8h 5@ 0T@I1.5@TwQT@`7h5@@}RKT@iSP 5@DT@pO!O5@dT@ 5@BT@0.85@$]u-T@Z 5@:a@t(l:a@D OTB;a@=P0/^;a@d0 a +;a@02b\, '=a@1˽.rvSP`k1/D{*P'7D{*P`k1/#>I.Pz//]N01P@IsY/\5P@8!U.8P`҄X=.3=Ply. E?P!P.LTAP-*.KAP`V  .1U?PF@-.ߜAP~b-\fʮ:EP+(O-pL=EP@o-h1DP`^_d-dwjAP;-&'>P Ϝ,d̿r>P`oU,*@7APX,4rvBP_we,K1BP24FN,tCP+,P/GP ̇+߮JP P D?+ELP#O+X8|MP_߭+Xx6LPQ+FNP` D+.rvSP@nc+ u#VSPݭ+yNP m*`2LP DCh*TJ>KP@I*tE'HP@Bwn9*xxGP`)*LZFPO/y *SL=CP@*A)OZAP)ԧRwAP ­)gCPEhc)\XHP9X)4JP@Ws(vIP`(^IP^p](djJP &1(\0JPFz䂕(@qgIP(\?IP`ݐx(͋ KPa:CT({IP`Fe@(Hd3GP@&~8(HEGP0Y)(BHP(tG (,3RGP=9'(pCP^'0AP'0DF@S6X1bG@gkyF5X1bG@S6DG@Nk5pD9G@\@L5P:|G@O Q5,sG@P-5phvpG@pL*5 ~p]G@Jv}5P۬fVG@`*5(uUG@\l5xF@ʗq50DF@鹨m5g҈iE@&50DF@@-P50DF@鹨m5 fF@Mp5WF@PK#5 F@-? 58gF@]956MHF@P.45@m O4F@p+5ž&F@!458|M9F@ HI5Ol"/F@a258N;xF@PikC5x9E@&5(_E@`m* 5VtE@HIm5E@R o5imyE@+5`bK2E@p(E5g҈iE@@-P5uT@ /.T =@"@U@Vi>@uT@Vi>@@gFAT@s]>@'^ϴT@^>@jځT@ 'WU>@/T@!hB>@^1T@06hI >@,%T@ ōT=@M8T@=@\PT@ `k=@Lx-T@&=@h7UU@;z=@:/WU@p:=@M U@ &=@dKU@_|=@u U@(s=@u!U@fU=@`Qy(U@prQP@=@PΥ6U@M#g5=@dcQy@U@č8=@kTVGU@ ōlJ=@(tNU@`}P=@ݞ'ZU@]>F=@5eU@0=4=@K?wU@1=@C,U@gV{9=@(tXU@0Wx5=@<8ѡS2id] SQ(|?I)S,+k]Sv9 еޜ˛SdJ >rS@_ôoS tьØS}Jj&jSeS!%E_mS@:6p{@r|S*/7$ʇS@l dvS@ _¤BS@:lS!%uTrSNyzJ, ԅS_B&|L}SXe doVpSl?G|PgSJŻ-nbS"_2h>J^SϦcH3}[S}t !ZSu/pcȅ]5ZS@jCJVXS}\wPUS+}TUS@pjB VSb|=US@ SSerR!@lRm(ɏRr`R'< "9YR@ m@]uuRU4bRNP}R[%XxRbw'@P/Wy>Z@@n&@<}rAZ@z; &@O#BZ@j3&@dX,vAZ@`>T1&@hMBZ@zl&@2;FZ@%@1SZ@%@8.uZ@%`$@E̍Y@`]F#2@s7Y@0Йd#2@s7Y@0Йd#2@-3Y@02$2@s7Y@0Йd#2@pGY@S82@ O{Y@kB2@eY@IG2@eFY@СC?N2@ZY@|V2@UY@ F_2@8ЪrY@h2@<#|Y@0^l2@;Y@ " k2@ LY@=a2@4 5Y@ Q2@lY@@@?K2@$0uY@~!Q2@<6Z@z72@- Z@p#1@dZ@x1@IgZ@021@JƂ"Z@`tB?1@)Z@p1@hwpV/Z@I;0v1@(^:4Z@zL1@J0Z@ 1@'/Z@cMf0@0z| 0Z@ Whĥ0@̍p4Z@?Pw0@; 5IZ@;0@ܦQy)UZ@@| 0@DpZZ@ nВ/@$ XZ@ _e/@GWZ@<㪃/@8JYZ@/@X]Z@ It/@P%_cZ@ z{/@"gZ@ bf/@\'̍iZ@.%P/@c/hZ@f,/@/fgZ@j.@1dZ@`ˆ.@S`Z@%ĸ.@ȥLaZ@).@-@hfZ@Gȥ.@jZ@.@9.rZ@`K_=.@xFΎwZ@`? j.@+zZ@-@^laA{Z@Gʦ-@XzZ@`e#Rm-@IRwZ@@pm!6-@BwZ@ i>,@QywZ@ Rf,@(MwZ@l ,@:>uZ@$P,@U#vZ@#,@@!{Z@wP,@8-f'~Z@W+@Z@ {+@tbZ@@/d\<+@и~Z@.+@gZ@F+@d¶_Z@`me+@0XKZ@k7+@x^)|Z@b*@x^,:zZ@ z*@zi|Z@e>*@L/sZ@Dd*@PG"Z@ *@|e~Z@`Ah)@ ~Z@`px])@~^Z@@ K(@ I1Z@N0(@uLxZ@ #(@upZ@_9(@d1hZ@kzv(@ZbZ@h(@|J?_Z@@K (@$ÎXZ@l'@̤ PZ@ઓ'@8rJZ@ PK'@Ha HZ@@ t'@ƻEZ@'@T^AZ@SKe'@|v%@Z@,'@|?@Z@@iE'@I@Z@ ~~'@If'=Z@Pi'@R&@ O;RFf@k8Rq@ R{5R6&!@&~/RҍK@@4R@s:S@`|'R@M}Kl@dR@>0H@vR#,@` R@@(eR9@lRwq@9Qoq@LQ&!@QMQN@ذ0IQBJ@ @Q`)v`@8mQP@@\OQF,W@,x6Qm@y9zQ3e@@''!qQ@X',@`edgQ֠99@w`Q¸(O@eѨ[Q@#80T}@I#aVQ@ҏ@ޜSQ}@ D)QQf@XrLQyv@EQIDjͼ@ آ;Q`@R V"/Qd~@>I1Q@>G@q|( QD>@Pf@lyPGT(@zPt:#@lK Pټ*@xY@@3˃<@(Ib 'Z@PU{=@ Y@PU{=@+Y@`:=@P;Y@F)b=@D jY@ЀLP=@Y@՞[J=@T۰%?Y@PYIS9=@j*D Z@0.=@}rZ@L: <@ƢZ@$<@TZ@b<@lƜXZ@0J;<<@(Ib 'Z@@3˃<@ rtW8<@ AVp@G@jch$4XV8<@tPVd'=@ AV -o83=@yPV>'=@YqxRVxr-=@YqxRVxr-=@$inߑKVPU=@YqxRVxr-=@,9L[V]K=@'8aV@)X=@egVpc=@X9jVЌ odj=@/jV ;q=@FmVuwS|=@#pV TUj=@ܢwV1Y=@VC~V`U=@l%#arV@@?=@ܗV=@uq|&V=@$nQ}VK;*=@g{VpQP=@ QSw {VFf=@ {V0~d&=@ 1U{V0\{=@)V\J=@LzV`Y=@LlgVк#=@ؠsV`斔>@@;VR|>@ݮYV@XS >@b-5V0ZA>@XkVmvr>@ PmVZp >@ :Z\V &WZ >@x6ZVЄd%>@&iVHzh.>@V`m:4>@u\Vau5>@p݊V4"):>@(JV0?>@  wV D>@X#!{VH>@@XcVPFT>@|VUZ>@3ypV|Q^>@"VL g>@4=QVp$z>@h~VGI>>@d-Vwr>@lR?sV@J鱐>@geV2.T>@ Vȴ>@ēV0c;j>@ V>@ԅVP6ˇ>@ 'ViI>@@JV @ o>@&E}V w>@eV5>@DdVrea>@'#V (>@ E\V5>@6y8Vp#>@:1V*>@zV ΐ?@= VVpI?@*V #?@쳤/_VP7?@3rVhIyF?@0VsurI?@gV,^X?@@.@Vtrr?@pV]VLɄ?@>xaV`?@̎mVգ?@`͋V06?@DUV@*K?@(zV~?@e]NVW@@:V@$mlT @@VQ@@Vhv{@@쵉GKVxR@@<ԅV`@@@:lVhzU#@@L$0VH|&@@L&uVT*@@n\VH$u&0@@荂 V@=6@@ #VxV>@@sV`քKE@@bnV K@@ؙnߓVO|`P@@@VV VT@@8 VqX@@V \@@L`VV6][`@@x3Vyig@@ PV/bHq@@>M&V0x@@؜H :V0c{@@]VvQ1@@$?V>@@܁VҞ@@L=tVݩ@@h7V0z@@ƼzVh @@tV𦒫@@l#aYVO0@@AfV0 #@@XϝVP@@Բ Vq@@bV(@@GJGV0b|@@XuV@@,\NkV8X;@@wVR+@@P߮_V0@@.ߜqV`@@ X4V @@X}V,Ų@@61V0%;9@@'V`%;]A@,[VCA@튺VH+9A@:8)V豝) A@--VtA@8VH~})A@PG DMVhOH A@(VX>p'A@P *ʰV-A@`2\Vp5#2A@hZVHt4A@pHkB`V qy@A@x7VHTA@` VP4]A@dHҟVȕy^A@(gbVJJIaA@ -VgA@$A枚VxzmA@,yVYsA@`cV#xA@lsǒVh4*|A@h̒VA@JaVM A@VXA@FbVؓ+A@<V@ 7A@}49ViA@r}VlA@8L{V|AA@?b|VA@ t@yVEA@(qV8"A@3VpVpiA@(qVXJJ1A@pv-FqVHA@x/56qVAA@3VpV(A@D>oVP A@ mV(oA@(g%lV@ A@#alV A@H3VemVxDA@VVlV8lB@`6iV@Y` B@DhVHKv~B@+kVX_;B@8&~iVpoB@H0hVP4f2 B@gfV\[5!B@XeVpt"B@XeVW$B@9&gVx;KJ6)B@ WfV -B@0;cVp/B@8x6bV6B@7cVdAB@ cVD7EB@h#a-cV{FB@h/ GbVGB@g?aV@sGB@tR _VXCB@8_V?B@$,^V>B@h\V%?B@X24oYV3LV"PB@AfJVX[B@iIHVgB@L1GVh2:9tB@B#aIVo~B@, dNV B@$EoQV0B֋B@xc~ZV W\B@a)_V蜠;B@&/`V @wB@hVȗi C@cgV 'C@Pa.CVoAs:C@\ΥVp QcC@L(PuVt&hC@VXWf2jC@@nߖVpʖ_lC@|EkBVFnC@uV rC@L:VwC@CB斞VS[yC@a]VwCntC@HGwVhf~C@H.V`? EC@DI ׺VXEㅱC@ oV (C@Og%=V`C@d\NAV`ǣxvV<D@, IV Z0D@H`kVH2D@qZVзI9D@ӨL:VpݰDD@hVp4FOMD@\uVHP$SD@\VsS_D@ V(YsD@ddVGD@KkBVh\cD@VD@| AVP;9[D@oGAVD@P;,V8->D@$xHV-cyD@xqBVD@F!VxCSD@0ԫiVH̹D@==VAsD@)\nVz=D@H V(sD@8VD@ĢMVKJD@VhƪvD@ S7V E@|aVPq E@ Vi϶E@?.V/E@{|EV:"E@l3V7)E@<^Vo1E@΋Vg28E@V8E"BE@7VNE@(zV@uVE@\koV@ 4\E@xsV0@dE@l V(LpE@hQ{VN@<~E@( .8SV+E@TurVPE@߮V耖E@ i*V88@cE@42jVVjE@MVPHE@"?V{YE@tJ Vؚf2E@%yVv.E@}Vx{uE@̾DV=^F@h3VX}u/F@eVV{F@bV$F@В*W/b-3F@\ W^8F@42aWp:&';F@ W0u?F@4{WMFF@xBW1KF@^"WOLF@Ldq/)WFiRF@eqx4W`F@0=W 7$eF@`AW`ߤ(F@4WF@JֺW0 mF@=W &G@|biW@<G@\K;WH0bG@2mWW @i$G@V]W:92G@)-8مW8ڌ=G@ WpnEG@lnOh}W`%`HG@طxsW~GG@ఓ^FlW@gKG@hWp~YSG@-8dWIYG@,]_W\G@袉YWYgG@ 5 TWmlxG@,E9SW@sG@ȋSwVWG@Āg%YW`&v|G@DGy\W~G@`W. G@eWH_G@gEkW#۟G@0#apWh^=G@LsW}G@ЫnrW8 #)G@82;l uW0V{G@yWP2G@t~WG@\(W)eG@tW eڌG@@WWԣG@}!WSȹG@2VղWp@G@ ŨWq{QG@~WYoG@#!W`jG@(t0P[@cJC@p V0b2H@k~LՅѣXE@@^+XH6U!mE@`Ѩ}XR&gE@<Ѽ`xXhflE@"QlXWoE@-ZXPpE@0بLHOXkD&nE@ʆJX8`hE@QGCAXX47MaE@= V}3XpLJYE@!]<+XȿQE@|p(XHE@Sw#Xz,CE@܋JX0@E@x/PZX(cy5E@*bXL!E@(ĴXH}cE@|XSw X _xE@<u XD@XqEC X(RD@$1fX|=֫D@$ZqX`U"D@ WgX8OgD@ L=X>D@(ШX FD@4XPg2D@kWcD@L~|W /D@<`+WګvD@4rcW`$D@d*#W*YuD@3WD@0WH]D@ HWh AwD@PWΤD@Z PW@\)(bD@r WW!D@2W`ܐ D@Lf.WmlHD@E`W(DqD@*?W6cD@(JIWH0-__D@vW5݌VD@]TWID@0WC#;D@/WWn.D@xWؤ%D@[Wv!D@XsWpS$ZD@^΋WȬH D@2WxCRD@doW͘C@BWvwCvC@LWBoC@t3VW vEC@+W WC@v|WC@lZmWX耧C@h NWC@OuW=vC@,EWx%%C@4 WP͘C@Y5jϐ$F@xd XPLF@X0^IF@|0X(0bF@X@+&F@ yX8xCF@(#XP-zF@qYq G@0?YhG@|0=Y )(G@Ḽ:Y})G@\/9YqiG@g%:Ypѵ~G@D9YsG@ai1Y\[G@ ZH@xZb7hH@E$Z0 #cH@)}Zp-H@HnZ̘dH@bZ\ H@NuYUZȜ H@`8;,GZD H@h@>Zht/ H@@0Q9ZЌvnH@!P/Z0b2H@C!Z0i}H@$ZH/4 H@鳿Y2,ŊH@ESjY.AG@XآmY8 8~H@p$`a@**{0a[a@ V> d. a[a@**{0Ima@OfZa0PTa@`0Za@\+aX0(Pkwa@:ɜQ/zja@//a@@/"Hba@͜].4; a@]_{.gUa@ajp}.$`a@ V> d.H,;z  g*R @YK]g@vy)@f,;z @=DG&@|A^ ?&@@gǣtm O&@@oV <`U=r&@*HY&@֧ @~y&@E]@,&@ȫߍx0)1&@ƫ7b&@*a(6&@m&\M&@@^ņ(Ht'@09 '@@~@d'@aaK'@r@$7Z(@D'v(@PE`|c(@s /)m(@T X(@ l c᪓(@ r I(@f @A)@/W #* n)@į @vy)@0'i? @`\p)@y6 әS)@Zܢ {aJ)@l8 5-U)@C3 %G)@8 `")@SM , (@ AZ(@f.|(@I0"FtO(@_aR(@J; %\"(@!@F,x(@P@XiM(@s=e[~2(@@'R&(@ i*RD (@  '@ԾR` j'@_[\4``w '@ϖ@G'@j@Nd|'@h"R Lb6'@9eܡ&@]G|&@;lF΋Us&@bo_T&@ly`ÈS&@9B}Dt%@m5Q}DE/%@bP@j%@*훲s$@OTh$@z8J`$@)u@tpҹ$@ShUJ$@]a7@$6-$@ ?! .@:y$@PN%b$@j=eD`Gt*$@=<%#@4.#@lЊ> /L}#@8 s,P#@u.D@`#@q'}@e "@}^`-"@CE/~u"@/d`W"@c3#]o"@h0 8"@P!@"@: "@a1}!@`B!@ltUv!@3ƐUC!@3`$!@0+}Ctg @h@G4 @?t[@ d @Bm5 g*R @tL{s U @qxN`@:0b @5G:%|y @o7p%j @2^ gA| @;$HWΙV @$#OCv @A X @ |Gt @E'>0`8 @x`6 @^H#cıw @&Fv%!@s#pm=@!@YK]g`B!@LnO@ia@@"Y&{BV=Mb@x)@^Sg)b@@"Y&{BA+b@Ky]BV=Mb@OBy}b@/EB#Qb@hCx'BhsT1b@xB4}b@3gbB8Ffxb@+OOWAx?9ub@v0AXņsb@h A9qb@AM#pb@gAknb@{H+Amb@pQOAkb@j|Bl P 7kb@Hj_`BSgUjb@ 4!VB ԹMhb@(GB8Tmab@x(R BX\b@3g B-:YXb@MхB*MRb@0 BHSg Ob@-m.A`Lb@U<Bt@Jb@XBFb@^K'BL*]@b@@:Bx::b@`nAxd*'6b@Ȋ*AxE2b@P){AdT-b@"Ap.'b@`@Aq"b@KYA޹MD b@\#A s;b@x}A&],b@t,A4b@녧B^ob@Q BSb@`GН B>yb@(yeBXocb@|D B6]b@H[?Atu b@KAP b@:AxE b@}slA`7b@6)6ALma@sAVa@ AEa@h ܩA|7a@@=A#rJa@i7A:a@Xq AP"Na@Ȑt}A4a@h,-OA~La@P{HA8Ha@"KpA$ja@^\dA<]a@]A]>a@<>XA`vRpa@YSAԖTa@X\åMAD a@2Н6KALSa@ LA8#a@@tSAH:a@hx\^A^a@8YHdAHa@{6cAL:a@8:[A}a@$KA;ka@8+>A(qa@õ1A,ua@`{*ADnO|a@nD)A;2a@$A"a@htНA`c a@PG*A: a@YA(Ya@2LAANa@ꅏADȿa@ؙꅁAa@kAlHB)a@h6KA (a@AJ Au a@X:%gAҠa@( A|(Za@˝jAnOUa@x)@t4$Ba@(/kAܺ`͙a@{AH"ka@7K: AP1ya@ A]0a@Aa@8?0=Arra@h}A 8a@nF(A;a@hF/ACa@x6A<>Pa@b7A uwa@`Dxt2AԞea@H!c)A|gBa@0tApVBa@P`mA#a@Dx+ALrlPa@`{~A@P4~a@nlA&n}a@(1cA}a@H\' AOX|a@ч Aި9wa@ Amua@`Aik2osa@t2g1AL-Nsa@_mԤEAdH8ta@vAPA'}Uta@(}XAlra@h5"]Aoo;ra@%dAGZsa@ rmAgra@ ѝkpA|L-oa@&,-nA]>la@'qA!ia@_#xAnO@ia@5}A04ka@6cA`Yka@W'AHja@$ދAp9a[ia@`2~AEia@P;"AO@$: bt9DP@$: b|JP@'s˛ct9DP@JO c9P@chpH P@F0c)›P@E c4P@|OXc@wC,O@ͩ{Oc@T1O@t&c#O@^.cJq O@'oj0c`O@_3cxO@q7c>hO@07;cߝO@>c7O@n3L@c@A*(O@мon @c`O@ݳEcxPO@)WcH>O@ "T/;"@ տ`+,@O Cq`+,@toq`k\+@i/!+@/Nj*@`9P%к*@.?f*@8 ب=F*@"T@"*@@6F;*@YWd\*@^&`*k3h*@T_ .+*@m- a\)@{˒`P)@;sm)@UL1l)@-s`q)@HXG)@QpWj)@#NV ASjlM)@3.NU)@ky@P)@m!R@eG?)@$wH(@R`Q8;N(@$PK)'@sm'@6c)'@Cs` +'@ CUG'@t2'翀rmk'@D yg'@6@AT&@Ը]߿M2&@q߿ ,)q&@b &@޿=&@,bEٿ`8c&@|W׿$R)&@ﭏؿ]È%@CL׿%@C? ֿ{%@(տQg%@L Lֿ D*%@ ׿(,p%@ տYXF%@8~x`Ck%@ai`Z"%@p|濠T]7%@|,6G%@nMy 9㪫H%@b[_#nF5%@{WC(쿀D %@/P$@)+m,r %@XRn`X %@p`}={$@I $@bi񿀩pλ$@QX$@`Jy,$@0]b N0Oi$@'L5cJR$@!>#`Lp;$@j#}@+%$@Z ￀%V#@?F@#@=XU1-d#@e'XSn#@  j`_#@y]Y"_7#@ͳ)P #@` "@t˓=ʷ"@O@%~l"@-,4`+"@L"T f"@Pq󿠾fP"@Vqdm/;"@!hH@aY@;h7@|h{dZ@࿎Z9@J(BY@࿎Z9@8dIY@9@Ph@h{Y@ d9@ #Y@R*9@Ё2Y@SiW9@yY@\'89@Y@p2B 9@/Y@0}I> 9@숱7Y@拽h8@Y@Y8@XY@_Č8@\[PY@;8@qZY@0 F9@dY@ Kza8@0"G"Y@ؗ8@6Y@x8@+jY@( 8@ NY@\Jy48@H@aY@MЛ8@tAY@08@OصY@ױ|8@_Y@,Iu8@Mw8&Y@5o8FR8@ DQY@au8@BY@P^'7@Y@p\7@IZ@ 8h8@l9.QMZ@U8@@NOZ@?8@SZ@` 8@3^XZ@`v`8@xtF\Z@8@<K_Z@p)n88@0IeZ@p708@0#nZ@N8@iPuZ@b8@ 5dxZ@Z?&8@'_L|Z@`#8@Z@&Wݩ8@L*Z@W8@윭Z@p`e8@K Z@0W8@ |iĥZ@0"~I|8@آCÎZ@V|8@# 5fZ@Pl8_9@t*Z@9@г KZ@##9@@hZ@#Q09@@SZ@`yP79@|h{dZ@]'99@"2GR@@E5@ T2dT@Y| 7@U T2dT@e6@`p+QT@  6@{,FT@ aL6@,XAT@*u6@ߟ@T@PTx6@\#E>T@0^'6@H :T@0ur6@ (%8T@0fba6@ĭ6T@ߟ7@` A5T@ptrT 7@صX3T@l<7@. .T@pԞ6@ԃp~%T@0Cܫ6@% T@P0$6@W1T@g6@<G"T@*6@|ZځT@@&L6@ݞ"T@9ho6@dxDZT@@6@ MHT@QPb6@YiDT@@q96@2@hST@`&Wh6@T@p6@dc{ T@#W6@( bT@[6@(S@pY6@pS@"6@S@PW| 7@d/dS@#7@%_mS@Y| 7@X@S@!7@RRS@;W7@p@hpS@խߏ7@"S@N7@pϿS@ * 7@btS@л{M 7@xlaS@ 7@hhS@œ77@,}IS@0#`6@,r S@@ba.6@ kuS@aWK6@uݞɌS@@>f6@p#S@;6@ꒄS@P֞6@( ,:˄S@,6@<%f~S@ 6@}rzS@P06@x^MxS@%4s6@rS@`H6@*iS@`Hd6@Df;]S@+6@#BES@V6@p7=˓8S@p+u6@sg3S@oh6@1S@W6@޺|-S@@l*J6@bX'S@Ta?6@~ !S@TP A6@<3TS@P?O6@* 5S@PA?L6@(S@0ؒ96@@oR@ 0.f%6@f+OR@c N6@,&/ڝR@IL6@GR˜R@F6@}R@5l 5@t5@0!cZR@`|Y5@DbBWR@;85@~SR@5@^mPR@05@UZOR@@5@+zOR@ҟ5@yMR@0Z"5@l |uJR@}k5@ңHR@U]D5@HR@p5@2GR@@E5@#pWbQ@ "7D@| 51S@D@-)R@0bnD@[R@PD@xt6R@I!D@jG R@D@WgR@ ܮD@ΰQ@O~~D@hUS5Q@@ o tD@BQ@$EoD@]@hzQ@4kD@h*Q@5iD@ oQ@^{gD@L 5Q@ȄzeD@Ԟ BQ@@y`D@h =˱Q@aBTD@pWbQ@ "7D@t'B.oS@D@̑~S@1D@| 51S@& D@p!yS@P5D@h 5pS@HeRD@kS@3D@da9|eS@XD@H*QS@?D@|[P0S@0 r VD@@S@D@2[PS@p|҂D@;qR@#κD@HTR@PWD@09zR@@2*(:D@hpR@òD@v8"R@x:,D@(:R@3#D@R@D@(R@h]@D@UGR@J>VD@DkR@ _xCD@`(R@PiQD@C|R@0XomD@LzL|R@0eD@8{{R@x(B!D@فxR@ D@bXsR@0OD@<^iR@wEIPnx D؃Y PU<DxkO*Y-DX9gOB:I:DgOE_D#OiDBz nOTHyDHq$fOzH D|SQYw@sn}Q,@%bkQME@b7aQP@YQ{@.(PQ*@ EQi;@P'L=;Qn&ï@dɤ/3QXa@<,QK @tK&Q~"@HQl:1@VQKr@QDG@4/ Q5AD@]`k=QP9@`A#Qbé@DOZTQZ:@x6oQϵQ@Td%P>V@(6dPm7LY@t0] P#哪@P)f@Pm7LY@0/P'@,*[ZP_ @L}PN+uտ&חP(ؿq<8PTտ0{PԿ$o%PL%,Կ0UE|PhiӿzD\yP1*ѿyuPfпx|jBaqP`wҿnkPD- =ӿZ&?dP&3ҿX\PP ;ԿT1:PPX'3ٿtY@PYGݿA3PSzܿ,LP8T{׿ PlԿt _Otzӿ(/wOQRvԿI_ODJuؿXߛO@|u߿0$ O|X?e7O03@xsrpOG1w]O&9((I7O D9T|N#1 RB%Nq:PZ5NB7PbN knXN| 10NUy{MNg*9DXNE;礷N;"xQiN8H9/4ND-NZ09Y2iȋNv&s68y9N$N܀R[psN2WmIN)`9N9 o2".NzS!N.@/N\ox'=Nv+' |M^D h8NMgY &(@n€X'u K@dcZ3WjvL@!hVnX'u K@ܻfX K@VodX((K@`VZgXax/K@ -gX7F6K@$4@eX X>K@{SBhXCK@8&rX@*IK@WyX0ZK@`e1U'{XXiNcK@p F}XАHgK@X8ٳiK@@n€Xp #nK@8\r|Xu\[_yK@BPX(K@nDX)ПK@d=Xp`K@RQ5X +4K@ē>.1XмYؽK@hOڞ0X K@8B-XNK@4r&XpK@4O#XhV K@\*_#XR L@qWho*(8%L@yWjj+L@ILWvީh2L@,2W5L@@PZWhXEFL@eW}dL@+PWZhtL@]Ar8W/buL@dcZ3WjvL@'0Ȏ7OkQ8||C QHரCB#Ȏ7OkQHரCB]ӬQpCJdtB( ~Q,-؉B?/rQvTBlQTB&QH?tB;Q@)&BA1QƦABQpTgBy*۞Q#0BєQطR|B俗QCxBTcUQm԰B$cQp BŐQ8MOBv]rQzCBX{QNB8xQx!B,vQGm6BhgsQ+ CZboQP!VKC%IlQF\aChȡkQE.+C$tfQ(37CAf\Q8=>DC0OTQ AۼKCP]QNQsLCFQp{HEC7y=Q7CM\6Qhl/C8L;21QSR.CtK&Qx K>9C|Q@mԊNCQ Q`bC Q8||C(h@J'(>@(|TM@Х" ?@6M@ Х" ?@6M@BHw?@8o^M@pF>@V!M@x>@`M@@t>@(|TM@?{>@pީM@:z>@\M@P,&X>@` W?M@O=8>@WGM@@J'(>@(>VM@)(\G:SXȔE@hOZS`^YE@hOZS`^YE@\G:SXȔE@* F$G%@yD)@@˟@ d1@ C 0<-@@t8@ @^ 0@@.}T@M`@@7 gO@@+q8@fR{@|eN@@yD)@<-@@t8@28x@'Dz@(C@91s@@$~@a@# 5@ojC@u$2@#`b@0@@M?"@.,Y@YPc@i)@'q]\@+f@ة@%@g$"@z¸`@jjC@7@bMf@Sɉ@(C@91s@PIi@&14@@Pd@XHk@@RR@D@@\U@=@I^n@`j@"j@}:@JeH@@ft@@a*@~a@@ ~@0a@@Emr>@<-@@t8@yO:@EB+@Bl@ފ@8Y@Ug4@4O@@@@<@s1@AB@5Oe@뱦@6@@hck@@JJ@!@ZF,e@?2C@@!]@%@ @ n@x^W@@@N?@@z@@N?@@q:Dz@x^W@@@^@pv%@."@`ltT%6N"@_U>%!Wx"@)%ѵ"@@'*%}D"@ jO%`!#@_H%@42#@t^%@#@u%v.>$@$G%`JL~$@`q{҆%4||$@0I~%Z¤$@U%` $@3rD%{$@.PI%` y$@[ :%~$@`%~$@[C$ c!R/$@Ыh$9f%@ڛ$@J %@ ћW$*)%@`o$z[$@߷ܱe$}$@ c$Y$v$@@d5gM$`3c$@yD$w*#%@`譢#&47%@l#`3%@`8e$[#@p?%@ FK#H%@ ?O#`I,S%@Q#`R[%@'# BPK%@ y"A%@`;2ϯ"'-!&@`' "cr"&@@޹ܹe"I/1&@CE"@wO&@Z!C;")z&@@G"6y&@_-"@ P&@om!@<:&@o*!GU'@ ! {='@[MKM!`&p'@:+ !p'@ -L'@Ѫ (@ 2 @LI(@CtY `_O|(@7h72 @ʴۿ(@:S *)@@Y |8@)@@ jX`pE)@]$J~)@@(uU)@ʗ b\@5*@vVOsr*@@Sv H*@}-&`Ta9*@|d"4@`j*@ߖ%xkXo*@- r&R*@B蓜`$+@@A``'/X+@:ؼ`k+@Y @-)o+@Q4$+zD}+@lNa @Dt3+@{O@q%h+@G7`7+@7I ՙ*,@B{ qmA(,@r& #2c0O,@:@x,@o2L+2 4`,@@? v t,@Sm`Wj,@@8Z`6-@w@h%$-@V +`sj3-@̔hЕ@%^-@`3]`'%.@F`5.@6<.Ɵ.@'9O8w.@.cރ .@ j\.@(@1 .@^.@ljiR.@*b@k'/@mWW]⪫4/@KK0K=/@*@fH/@j$@Q/@a~jX/@! ^/@>< `Dtv/@1? ע/@<9t ᪕/@ɼ? m3/@Y$ ́/@  `e0@4` ' 0@r@q #@雙@D#@:WC@AV#@8_@ ~\$#@r}X@ V"@8r@*)}"@@R@"@K@_+"@[@|"@;g$@@!R\"@@{Q@<:HR"@g,@@ߪ^"@@^I1:@L"@8p@]_"@W*@j0!@@a$@`j!@0}j@m!@" 5@@f{!@X@G!@܈@A$|!@Q*@k!@WՉ@@A!@@@ @].@% @@ G @@/@I @0},@`) @@˟@ ,@(@ڪr@@R@@T'g@@N''@9 @㛱@@%U#@fFL@@@f9@4wU*@@rh@n\[@@RMA@@.@[_v@(C@91s@D!;67 Y"/@@_ZZĈ=/@@mÒDВ]/@}9`Dtv/@x /@`77k/@*/@@JC@w/@X/@drO 0@̃ u0@M0r z.0@N8Z o89)0@4` ' 0@N8Z o89)0@N8Z o89)0@P"d 0 190@a"{ n B0@?훪 p';6D0@0{ ȹJ0@{ s5HV0@h% Purb0@S 5sh0@S 5sh0@? `L0@yPk ';@0@9 W90@+ P}I50@[* д20@j ;)0@$CY 0@k8* <0@4` ' 0@S 5sh0@ɚuV p0@$hZ0@o@< C 80@ W86hs0@ 0@^v0@UoJ|0@c^I@{IK0@`MUy0@6WMWP0@quF. .0@&vXp@0@:Ɖ0@͆`,O 1@P# d1@X`EԘF 1@MWI1@1}B\!0@vk1@˦ _0@opy;80@7PZ0@=7ݿ0_҅0@00%ֿP*q0@t;7ѿ0q˰0@豵ɿйϓ0@%S6¿.l|0@2⶿0$m0@Ef?,+0@c[^?Y/@s[?𻄾/@d lao?/@hD)?[/@t1J? f7i+/@@*? Y/@,{?E,.@$5S?`.@tB?iyD.@a@F?..@H‚?@I.@4S ?Vy.@XB֙?c-@? X;-@h?9-@4[?`p-@L!?;h-@V)?p²B-@]6?x ,@mWU?LK+,@#e@D/@@@pi>@f(>@@D/@ND@@X 0@DZsP@@ dA0@md@@ k0@v@@h 0@YÇ@@Í0@@@0@84P:͞@@p՞0@g@@pl敯0@Йof@@# 0@(9@@i=0@ȱ]@@`Oba0@v@@d1@H @@131@Ev@@j&1@PaK@@hsr?1@p%@@P4`1@`g@@)1@@@PVSѲ1@@@1@paK@@Fu2@H@@@PP5.G2@%,@@PSPN2@,h@@IF!]2@85R@@t2@ H@@0B2@=s@@p+o2@&ލ@@0$(R2@0-@@2@Ȁڋ@@LU2@Nn@@P+S 3@@8P:@@h5`,3@h,$A@@@@x;<3@`m@@0BZN3@@@ A?Rl3@@@93@L@@‚3@;N x@@0Qy3@o=Kk@@B#b3@`)Xt[@@^1<3@@SO@@y#)3@xE@@P.S&3@(Y;@@8=3@I#AV1@@Ӟ12@hi5'@@`՞2@]u@@5"2@1j@@p2@c @@, 2@x6@@ "O2@0-@@w}I2@PM@@32@ +?@0A?2@Y?@s2@[?@Zl892@i`y?@p52@`PK?@ ;2@X%?@ Ir2@ ?@ V 2@p >@ yM2@ >@SPP'2@mv>@A2@l>@ o8e2@U>@00.2@~>@#ݏ2@>@P12@f‚>@ 'W22@My|>@0 2@|>@7h9>3@9u>@bĚx3@{{e>@PI3@wxY>@n P3@ xY>@ph^3@@W^>@0=֞_3@8 >@3@f4>@؟3@,j&>@'՞ 4@ x>@m4@AHQ>@&W64@y%>@I֞J4@>@'WT4@t{R}>@\'Y4@~ l>@p|[4@:U]>@9Xj4@@4@Q>@5Ҥ4@5~/Z>@[4@.7\>@p V4@}]0^>@p64@Me>@`4@>@4@ O>@ kx4@pMA>@;34@! >@Й8 5@ lԯ>@p:5@Ћ>@*5@ز>@R=L-5@p[~[>@!?5@`QD>@:#EV5@0I>@k-f5@@V>@}o5@oF}>@d~5@^04?@9h5@ "hp@@07@0t@@T8@d!t@@8h8t8@( q@@ oXz8@p(r@@0\$ 8@u2u@@܀I8@ٍDu@@-8@6r@@58@eDoo@@JB 9@5ml@@9@T-b@@YDC&9@wzP@@@d*=9@'*E@@4Y9@hjB@@@@+{9@@Gc?@@@89@^B@@o89@ !Z@@!9@RLa@@P~I9@pha@@0H:@!]@@0 :@"s\V@@|):@zF@@"]$:@Ȼ5RK.@@wB:@\]D@@ {:@pVG@@+:@?) @@Pvur{0:@H@@J0:@X6@@0.:3:@7?@%+(?:@Et,?@pF#L:@Я?@`N'W_:@?@q:@ *?@ k`:@?@g=$;@-K$>@p [;@V\G>@c7h;@PL`͘>@`yY;@p9I>@ХS;@V[0>@ %W;@>@17;@0ma>@Z <@0u{>@<@">@P;<@Ƽ\>@P.[*<@`ҧq>@`x:<@>@-N<@Ɣ>@:f<@0#>@ 8h~<@D<>@pk<@k>@P}<@>@ w<@"ß>@gwk<@-3@%?@@("=@}6q8?@50H=@,#7?@ 7a=@Dn@s@,t*37aX@p;9@b ڗX@А"l<@¶~X@А"l<@p4JX@d?<@X@p*!<@0rX@r!<@@X@F;@T}6OX@Rr;@X*X@ KS;@4CՉX@ j5n;@oX@,E;@"G"X@@o8;@ \_mX@ v;@鱂X@g!;@IX@<~;@xX@q>T;@X@ca%";@df2X@pk::@b ڗX@`}:@xݞX@[:@ 5X@`q:@Զ#X@ o:@v8)X@C2.9@蟔X@]9@`Ps|~X@`h9@X%p~wX@ aZ9@ҴBqX@p;9@nX@ǭ9@]iX@pr4˵9@L=cX@xL9@t*37aX@;u9@-RPzH] @(I@E*DZ(\[IK@r\RPzH]`J@D_Ѳ@]! J@xUy;]HxC* J@,4S75] @(I@73."]J@$ ]Pt+ J@T]@tJ@-]pU#J@XOؿ]ȩs0J@͋g](D7J@L>J\9J@\r R8J@m*[4\Ф3J@@u ~\I1J@` ĵ\Q Q3J@Hqׁ\H`DJ2J@iL=\j`-J@`\p$,J@;le\hY}.J@U\X}>;J@O \p/b^RJ@`x\(W>ַ^J@PX\ħJ`J@V\@0ydJ@L\DkJ@o9\ YoJ@<*\p4rJ@ĥѨ\ g2[xJ@H\(W=J@94\0~~fJ@c\̘ՇJ@P\h%̜J@dEC[\^ʐJ@熪˵\轡JJ@0U\X7U! J@E,\2:2J@|S]\x™eAJ@dVg՘\/6J@`nZ\H٤J@T\\ #J@L4|\p'J@br\حȬJ@S2l\.ѱJ@|Ҽzi\KʲJ@8gend\0J@Rr\\莌J@XES\)rJ@0u I\`0yJ@.A\d/J@qJ:\)J@< 6\pg2J@ U^5\`~^K@ .\pzK@L=-#\<aK@E΋=\Qf2K@DѨ\(\[IK@LxnY \3K@\4\YVJ@[ cz3J@ '>S[`IcfJ@@-2[0QJ@tCL{[PJ@[xx J@1S[A͘J@[`șeJ@I[`E`J@o[F|]J@lJ`[F|]J@l a[؎V!ANJ@d˓^Z@֒+HJ@Z|GJ@ZjH@J@"-Z(ީp2J@v@ZpA+J@iZ8ݠ*J@(#Zg2+J@NģZpml.J@w\ZHAs8J@&ѨAZFHJ@iAZUaJ@,%䋖Zx.J@$m⚉Z#J@ԫoZw@sJ@4|&ZJ@ uZ8V!J@LIxZx{`͔J@kZhJ@|mߜ-]ZCJ@E*DZ]:ŞJ@.D&X@ ]4@؍LX@Х1.r>@`D&X@Х1.r>@<&7+X@b|q>@=-X@`˚1g>@9ma-X@tEPU>@^m6X@ }>>@PsGX@@=:$>@LRX@K>@XX@s=@pQy%[X@P=@HI[X@[=@,N^X@鑢=@X̭bX@Ջ$=@BjX@ ZOr=@;ctX@ ^=@H|X@f9=@lRX@P=@}1tX@N<@cX@@2.(<@vX@YƓ<@HrX@@3ˈ<@m%X@`x!<@לX@܇ f<@X@-8@,X@@dL7@ TX@ 'W7@ 6X@P:7@/WX@C?7@dDX@0Dª7@<ڨX@s 27@ЗX@ x7@KBX@mLj7@HGX@0A?e7@49(X@ B;N[7@0HX@@4K7@tG#ܩX@0?;?7@pY X@+?87@T4RX@ (Z,7@34X@0TP7@x̍X@LVd7@سe'X@ 7@)CX@M=7@o֠X@6@(|X@56@X3X@6@vEX@F 6@2X@`6@G"^X@`Bʴ6@GJX@/6@2Qy X@`fn6@(CX@ 'WV6@ɘX@ D@6@X@&P7-6@ԸFX@MW6@'dvX@H6@[PX@.5@L!㼦X@߃5@l.(X@25@@;LX@u5@3;X@F}5@h3X@PP5Ї5@NNX@TX{5@*phX@`Jyk5@SX@@RV5@@M܄X@0|<;5@<R~X@@l %5@܎zX@s5@BYX@'75@iāX@ ]4@/ȨC-V@]o>@D&X@j?@7ȨC-V@j?@luV@}I?@fV@Pg*?@(2V@`*,?@ SV@D?@^V@vz?@䦋8V@0j?@,5V@ l?@m?@| iW@SyK|?@^,W@@Hyb?@Lq?@MפW@L c?@AoءW@M?@maW@@ o1@?@4ZLW@00?@`3GAW@+?@$W@P. o"?@4=W@?@TW@57h>@l1W@r>@P$#W@Xi>@ -W@ga>@ X@>@Тi X@ 8>@|FX@@,>@lLX@PYt>@\X@p8hy>@dl/w#X@]o>@D&X@Х1.r>@0`v8Q@}nlq*J@ZCU@@vN@'ZCU@`D7J@|%U@;H5J@:U@P?2J@9 U@pϚe+J@Xք5U@}nlq*J@((F2T@TN.J@؍,T@й5J@\=6lT@x)>J@BT@PNKJ@(iκT@> eJ@кT@iO{J@кT@P })J@1JT@WJ@(LT@zJ@dT@xz]J@ NT@zJ@H BT@^ Q8J@p*T@vJ@4sT@FJ@7T@`muJ@澙T@X VJ@2T@X. J@T@ `J@P!cgT@/^J@̈́,T@pD5tJ@(T@訫vJ@olaT@AoڿJ@8=͘T@xaJ@9.RT@)DJ@`=T@؍5J@s*T@غ́J@K(ET@@+J@( =l}T@ J@*~wT@wCJ@/XyuT@P J@.XnT@ YJ@*bT@xJ@Ć%ZT@PKnltJ@ϰaUT@0\J@`v8Q@p ^N@Ͱ2Q@@vN@T1Q@W$N@ԭ.Q@Y,,N@KQyQ@DN@Q@HN@F,zQ@mlN@< Q@0trN@$%Q@Ј[N@HuQ@nloN@\!iR@=>֢N@{uBR@D١N@zUxR@X{oN@Ԃ#R@0,KJN@.WR@یZN@$_CR@)N@ KR@$N@w8R@ht逎N@ɕwR@ht逎N@MܼR@`>3N@FoR@PC#HN@$LR@coN@PubR@TiN@0@hR@h}wCN@UR@xԏN@@ {8R@\BN@[f'R@@eN@|R@XKN@oR@(:N@R@6^N@R@`TN@,%US@ȫvN@lS@0wN@T2S@0sN@!p!S@KJjvN@(S@p.rN@,0S@hN@`=s=S@KxCl_N@(ܞMS@șNVN@6YS@q0 SN@J޼`S@jUN@l6ufS@.;9TN@jS@4NPN@86mS@aKN@VnS@BsDN@ sS@15=N@<Ҷ|S@;95N@S@`2N@ǒS@Cml3N@{ѕS@ /N@4zS@ t*N@ݘS@X9ߩ&N@\\ 5S@H[X%N@dʞS@M0N@ pS@5!N@t޴BS@?O.N@ >X3CS@KN@Lĕ=S@ЦiN@8ķS@QN@8U@S@ N@Е0S@L7NN@hvBS@ڌN@X3S@؃1boN@ZS@#M@\PS@W=wM@l% S@&M@SCwS@(M@^OS@8͘ M@ 5S@o M@,G̍`S@BsM@.W}S@1M@v8S@)(M@DS@ Nt`M@@S@zu,M@ @S@$gM@ S@0,AsM@,I_S@.M@lT#S@`DjM@.bS@GM@yT@O8M@4K T@h.FM@y T@_ݺM@T@ M@ҷ_5HT@h耜M@82iPT@xWM@`WkVT@yC M@ȣ@hHZT@M@8ZT@D{M@Rop\T@MHxM@ ^T@EowM@?h_T@ #tM@l7fV`T@8][gqM@0}:bT@@;9lM@XtX3\dT@wCZjM@TdT@efM@(N bT@CEc_M@sz{cT@XA[M@tiT@YM@tRmT@dZM@MoT@P㒫\M@4zUqT@x;90^M@zvT@HیYM@G"yT@ط}TM@o~zT@HNM@܁}T@{,JM@LT@XEJM@pj!T@WΘMFM@`XT@^f=M@جT@}18M@4SÙT@XiT6M@X6ΛT@3M@BЛT@7/M@e'T@G.M@(W0T@ht0M@N(ʤT@O{.M@fT@+B)M@T@@s'M@|zUT@ӗH(M@h^eT@PQ@$M@5zɻT@ϪvM@?hT@MM@X U@PHL@ܸU@0:L@s>U@0+:/L@1@tU@v-.(L@@@U@!' {%L@XU@`!L@4`뒌U@][L@Q%T@=VL@3T@XLDL@$=pT@X/L@D >T@h^K@!cpT@T$K@pWT@h6K@J?T@P!yCK@$CT@|K@Z/WGT@(͘K@Cf'T@PoܼK@UsT@`ݷK@8 T@(׸K@kT@ЌOoK@5ԸT@QK@2/WT@|K@ɸT@@O K@/WT@'a!K@P޷ߘT@'}K@pBT@ZK@b T@H,ņ}K@,. kT@Pd!uK@QZT@h/lK@1hXل6Q@'"ߏN@`v8Q@p ^N@ Xل6Q@'"ߏN@Dc@Q@)NN@TFQ@HeQN@T^mLQ@xf2 N@diTRQ@(' N@5ZQ@@~Y>âN@\mdQ@} NN@H5,sQ@@I(N@P[Q@3N@`v8Q@p ^N@2l_CHP@oN@ d@Q@8}P@wdltXل6Q@'"ߏN@LO2Q@oN@L*%Q@]8N@ǻQ@{N@^>Q@ȴN@lbQ@@ɠN@ܞ@Q@0ߩN@QCQ@(yC?N@(=Q@¹N@+Q@XcwN@hP@H#_N@kgO@sP@14O@P6rP@0KO@TsurP@RiO@\k_sP@`ؗO@1_sP@fO@1yrP@`oP@CNܗsP@,P@(#vP@xڦhP@5xP@l8}P@+zxP@&%P@\-X}{P@De۹P@!N}P@ԙcP@9P@1 P@e'P@8~5 P@}P@P@h NyP@4)BP@sxP@KքP@~,{P@CP@v8zP@-P@X xP@ԑUAP@49.-sP@~P@N+lP@(_"P@kP@I %P@ )mP@h&%Y'P@u lP@(]HG1*P@lK 5ycP@@?Od-P@ `P@]0P@kaP@H 3P@魈bP@տ>5P@\`P@/8P@CJ?bP@)ʕ;P@L+dP@ރ>P@ uaP@GGAP@XZP@'mAP@8h=SP@8`CP@|qPP@ԑRFP@LuQP@q>KP@Dp.WP@6Q#RP@cp"]P@.)WP@ucP@GGPZP@x2fP@e"]P@8*fP@E*bP@^gP@ڦfP@,2̍jP@ckP@oP@pP@!,6uP@ :uP@AxP@"{P@DwP@o@P@uP@t P@XǐtP@$\5P@N뒶uP@:.P@#ڂxP@|_P@p=F}P@P@G-P@ ёP@ 0P@.[TP@s/WP@+P@hCsP@"P@2tP@P@ppP@`CRP@Xz(P@|7P@Xz(P@|7P@dP@x?P@SP@\P@M\ Q@~WhP@Q@__P@¶Q@hP@!"Q@U{;P@\b )Q@P@Xz(P@|7P@eP@5YXP@t)%MP@L P@ߣP@)BP@^XqQ@\)P@xIQ@8}P@NQ@dP@\b )Q@P@\b )Q@P@lX:Q@@$P@ d@Q@1R^tP@3(]OA,@ H@0B Q2@1xJ@Bp31@oH@@q1@ H@Pm3I1@ H@0 2@H@4gD$2@(lH@`92@+3H@N2@^\H@0B Q2@HwH@3@2@XQ I@>W#;2@.I@u@2@pFI@p&u/2@O)I@`9*2@ H~8I@0\M1@DI@*1@KI@081@G-TI@ a1@; Q_\I@J#1@TcI@0SmBs1@Dr pI@0h,K\1@@vI@03cL1@@#̼|I@D1@GI@>11@P!I@ x1@5ĐI@\{0@4GI@Xc0@Pz`I@컒0@Bs8I@@Yy0@p#TI@J%6C@\^iUAt,C@d3mU\0&C@tvrUX$C@ @vU+C@yUhMȢ C@d]|}Ux`C@t]U:U!B@wnߞU0睂B@7HUX>C@,× U(( C@*(UޏC@hOZ"U 0bC@UXC@{*!UC@D-آ3U\C@7uUPSUC@*d^U*(C@0cU(TKJC@YEU5aC@HMU C@\\U 1ZC@ XUh0bC@PEU`g2C@#ikUX}[B@IUibB@@oYU(yCB@䮆UPB@*MUHAB@8 U02B@#P U@,OB@t>IUd6wB@}UB@ė`U0q B@q7fU kB@(42U0b4B@DDUXYΘB@L.UB@dUyCB@@xU5@PB@h}U`H-TB@fO\Up %B@xvsU nlB@`gbU B@<*UG B@L?U=:B@煪{UtB@JôUȵD&B@H'4AU@QOB@۝UQB@U:7B@+΋Ut B@xHUPznB@t片UtB@p!fUV!B@0V UHjϛB@x>^Us)(B@"1dV0MtB@`;#V@B@V`ݩB@n@VhzB@VAsqB@@sV>ceB@$31 VOvB@AۿV DB@VҠB@kBl V RkB@ƉV8:zzB@V0o͖B@4OZV,iB@(/VzPB@ /aH'VQB@ 7VHcB@'BVxkB@kH`HV@یB@q|JVQQB@B#aIVo~B@{jSP N9D@l܈ T`ABD@84@TXL& JD@0͋TޛTD@p-Tp^WD@H<8!TUHRD@-?(TA7MD@&-*TxHD@K'TXzAD@ s&T8D@3&T .D@rE*Tg2D@TLl3T0^C@L7T8%C@,:7TC@=TXvC@@jHT{]C@|0PTp zC@zߜUUThpC@DOZYTP=ֲC@܉4#\ThjO?C@_TpүC@McTimC@?fTp4r C@;jTϢC@HslT:u&_C@Hm;l%oTeĒC@ȽRqT hNgC@]sTHt&C@JsTXL`xC@qT]|C@ @-xqTX&6yC@0rTОHyC@0kBsTBsyC@8X#vTHHwC@ʓyxTsurC@H cyT! _rC@C@?F*UPVQC@L>-U =mC@ u1UC@(b5U5@PPC5p/7.8@ nk2D!#(09p/7.8@PPC5@Nᜰ8@A/5̘8@u,a508fq8@SJ 555q]8@4C]8@p#4P^f8@`{|4os{vw8@/.4c<~8@)p4P0 {8@;h4K t8@`Yd4mէ7g8@Pr ܜd4@ZR8@pYZjX4@R68@i?4 #8@@*p:4PR 7@7a1~I4K)7@Ͼ$H47@c64pZէ7@Pay)47@7 4 -;u7@`zL4 :ug7@y'4`SY^7@ڨe47ԧM^7@g4P3Od7@b'3 4=7@Н3P]7@73@ӓ"7@ZZ30yzZ7@yI3pMo7@IE3@ӓ"7@ZZ3pA)F7@`Į3@ӓ"7@ZZ3 e:<7@2V30yzZ7@yI3 e:<7@2V3(lJ7@0c3pR^7@ug3p , p7@Pp3AH7@pM3p6@^72ߊ6@ o3p&}6@ȗH33pf\6@d%^30ÖT6@pV/y31}e6@ q3 7@Px30yzZ7@yI3p6@^72&6@ yS 3P丨6@ 5831 6@n3pE6@0WZ3@7@0@ʗv3" 7@XZ03P*H67@P3 e:<7@2V30w>5@ nk2C)5@pd2aԼ5@ko/2u5@@PV2yO5@j2DD 6@uk2HCq6@7빆2bj36@PL*2`z$`Q6@I2tp6@2p6@^726po^@0׈nR@o#_@L2:R@o#_@0׈nR@ 2t`_@GǐR@P"c_@ }nR@@_@d40|R@T9_@БfLxR@`ݞNr_@HR@(p[_@%%R@6/ת;_@s%R@@(N'_@*R@Ff _@L^ *R@,_@V{7,R@la^@00<1R@=%^@s2R@n=^@=p%1R@Pܜw^@c/1R@po^@L2:R@7Pla>=Z@DP@@L(^@Té>R@la>=Z@P"_P@hCUZ@P@4(]Z@zUȎ[@pwP@2J[@QP@@㰥J[@tmP@\-K?[@4@2P@x= [@X-P@U m[@@t@P@P m[@Lt( P@dV[@lوnKP@tQ[@ԅ9oP@a6[@N{P@ Ϫ[@-nP@삷_-[@\5P@ėL5[@hjiP@)[@1-_P@,&*ػ[@|,gP@p;Z[@ΕP@D~-[@\PP@(1[@OUP@@(p[@[RKP@~ t[@GgL1P@#+[@1OP@N̍[@tP@4F[@=YX~P@Ɏ[@oP@}rT[@3*P@Ȗ̍[@3P@)o[@\@,2Q@0(\@tRHGQ@G"\@xC8Q@6\@8BQ@@N\@> f Q@x1Gl\@Cw Q@ \@{KQ@N\ ]@8"EQ@PsG~]@s+Q@(I]@@᱊wQ@[ ]@mIP@8B~r ]@WP@@w ]@tP@L]@h2Kd`P@ZB-]@'k P@!!]@NP@eQy#]@XP@z(]@j1P@;8]@=pP@z՟?]@tkP@\GW=]@tP@b=]@PGqWP@H̍@]@ԠQ@`G]@ @Q@UɫR]@fLQ@xM]]@4 Q@PSh]@܍ Q@f]@XhQ@QyV]@AQ@a!ZN]@=Q@p6N]@HT&%Q@`^L]@Q@(gI]@/)nXQ@8]@DېZQ@zĐ]@I8(]Q@ i]@et4`Q@pX]@!BcQ@(k,U]@䮭dQ@DŽ]@ >p:hQ@( $]@p8HmiQ@.Rh]@xc/lQ@@?f']@OpQ@8i]@ tQ@6X3]@TwnxQ@pJe]@@wɕ|Q@H5\P]@R\jQ@Fd]@:Q@(Fr]@'Q@(ݞ]@kHQ@_+]@ԓ =Q@xoݞ»]@pJQ@( ]@@Q@<̍B]@m> Q@pmBH]@ߠ9Q@h2/]@H OQ@s]@` Q@@6]@3Q@X]@i)Q@]@@`ۦ(Q@𣱟 ^@йQ@hQyQ9^@,Gx]ПQ@ꒌn^@  Q@@^@2Q@H^@@r =tQ@仠^@Gx]¦Q@ݣ1*^@4wQ@4D^@`Q@(z^@wvQ@^@(mQ@ ^@2Q@P*^@A&յQ@I[^@0xQ@5^@D Q@pJ?^@ͲQ@Hzp^@lQ@C&^@/ Q@^@TQ@ɜ^@ܧQ@ZF^@_Q@"㲟^@`pt@Q@0@h^@.7 Q@8(^@\QQ@R@8PfA@@[R'@@GzB@`@A~M"@Gh[B@`@A~M"@ ZB@\)"@p˫ɕB@ǰw!@/8B@w!@X!B@`}!@B@`H.!@P/jB@{!@X B@BAXb!@6BB@fP!@_hB@^\\ @i YEB@| @58B@ Ҳwt @@GzB@`@Pt9 @==B@@-Nu@_oB@6q+@@_B@ @ *{GB@@@%@DZB@Fں@8FB@k%@TUB@10@~C B@@N7@{ нB@@At̖@DѹB@1I@NWt B@$H@ BگB@A@hٹ=B@̘ہ@ಟUgB@@EVH@]hB@-@<'B@1A0@ak"چB@~À@}B@@X@!!zB@R` @PқWpB@35@w`B@dC@(g)JB@ω@ m-B@@P:B@t@MB@@_@K_ B@URά@c@)B@x@Vt}B@98@x A@D>@,8A@~k@xJA@ `y@;A@@/@`5A@hU\@@e^VB@)@҈B@V3@0B@GKH@h7B@ lȫ@ȱ`B@[t`@ =9B@k_#@跊B@wt,@VtSB@>'@ B@@EԿ@ dB@G^R@0. B@@T{&@H%1 B@E8yt@ȮVtsB@&U@PB@w+@ B@)@Lu B@@U@@,*B@@u+?@8<1A@@-=@@;YB@@[R'@9Xr0@@Jyݭ>,=@W<qC十9@ [>;X9@ s>H&K69@:y>cS8@lXC>+J8@Щ=H}8@00z=0'–Nd8@ 2}W= c[8@]=:|K8@pV=48@Q =PWM8@*a=07@pj=Re7@@wp= Obj7@@md=J7@`]X=J7@`M=@K7@0-:=`ɥ7@P88=p 7@i^*=P–7@p|i4=9gx7@8=Es7@pn 8=Yi7@V3=]`7@p(6=p"Y7@o>=PױG7@p{I={m)7@0 U=1x7@@^=NMg7@c=qzG7@\yki= 5&`7@`(6@Uێ= 6@0=rџ=Ơ6@0qC=`M6@ο8=הҽ6@8ڜ=[A6@ L2~=@8ց6@Wikg='בY6@W=#7D6@`CD=acA6@i*f-=w56@=0lA76@ l:4@G88< #C;4@ Vw<` ),4@{|X<`'|4@)$ë4@0s<2p޹3@ U_ s`E3@W<@tBH3@П3@L< 4h)3@0QQ<@5q3@wn&<и &1@p;h< S u1@01@M];<'17^41@2<`W=01@&'!*l<<@ >}cQt<@ A]s >e_<@?>R-S<@%''>#z5<@ ȹ#>:<@{ >E;@*a>@%>;@@<y)>٪K`;@P4Q 6>$AH;@p>?> ;@7 C>pA;@ ?A>Е;@ТH>` ;@ V> 4]0 ;@p_>f8;@Kѵb>lOy;@`{|_>~Rrn;@V>@;cjh;@ [HS>tJc;@й%'S>0< 7c;@ nU>c;@RR EZ>`~R`;@1Y_>mPX;@PLb>uV;@Sf>0ܻ\eV;@j>QU;@; Qm>`ҧ[O;@488n>tK;@~dq>S mH;@pIy>&c9;@jn>`馮;@ߩ>0G ;@->8" ;@x߭>+:@*>N:@Њz|>px:@p~>Pg :@@Jyݭ>QƔ:@ߞ;]>P-|:@#'>Z0f:@;>27Q:@>7q?:@IB>]v-:@ ?<>/YE:@p:>`9@ЦǠ>:"hS_@c11ai`@( Ԙ.!hS_@ 銟1xw_@@yv138`@*1#NB`@0@Ex11 `@i1(8PJ` `@'1dc `@c11`@Y-1p]~^`@n1ҘB`@Ш'yn1n`@0TU1ai`@ iWB1j`@GV)41(C``@l&1̶]>`@ -1|^`@`ngh 1`@Nn0ȶLM`@ CZZL0!`@M]0 FsT`@`E0lzZ}`@0S0LdBV`@ 2"0U|}`@0W٨0(,hr`@@A40<7`@[/).(`@`:=/[r,`@ㄊM/ `@!Q{ /LHO`@p w/e `@@6/.t-A `@@TQ. `@@(.%`@( Ԙ.; ZP^8@Nnm#@px̷O{@ Oc݌@ Ow@PO#~@iIORD@@O^8@,]P)x@ DPx;ʛV@h܌dfPn+@ +Pn*"@H4\hAP@ILP'f²@hGdLP^&@@0OPӊ@DTnTP-zq@X%YP:c%@*kK\P¤w@`蓞\_Pe#e@PXbP# @H;gPWtԂ6 @M DlqPկ0" @<)L|PlxL @ gP=0 @XKPzPBk@i @-P)QJ @OmPv`0 @-J0P6Y @(dNP+n\ @l+IP+r@Px_X@8L P@*PҮ"@Pڅ@NǑP@Y@ ZP@ނK @ ZPjs@NǑP`&@p xP<@|7PEn@̲cuPk q@puP~C@ pPw1<@X4gPtd@xFSwPX,U@7'TP@,K@VP@2"@tA.P@Nz@lK Pټ*@cP@|xdlP@TpҜPnw%:@P@Ag@HSP:0!@,LfP@"@|0P\R@FVPS@8q|Pu*@Ĩ?P@@\ܠP$@d^zP@@\ 0qP@ -]@h]hPvZ@c'aPm@,VP@@PsԅNPӏm@$B&FPJ@w*E@Pr@pIk;Pf)Z@|V9PJd)@g8P 7 @a7P@e6P 7 @/*5Pzt@jB`2P(ѽ@Y1w/P@Nz@U9%P" @-x PT#L@XVt"P@$\@0Af"P{O{@0U!P@>@GkP7^@0LP D @|5Z1,PG2 @7fPw |! @Z//Pp @D>7 Prm @EMPxt@.S7Pd;@K,P@&=@ OZ@@pebAO@:U @QOJX. @xq O.~E @۾vO8cjJ @XkkO=a @ bObU @[O`?j @EyO`;Y @BeOL @ݱNO)6 @~6OG!@f O`ۆ!D!@p 8uO@GH!@p 8uO@GH!@H| OGL!@P2 DO62!@ ՄN ә *!@>@N@4!@,1N1!@x061N@kwf!@Nt !@-O zqИ"@sl OY!@ UHO{]!@P>CO!@eGO٧!@0ZkO@X!@p 8uO@GH!@X414Ns ,C#@,NG4#@KpNFCt"@76CNDM"@kOJ="@-O zqИ"@C9N_&Onm#@XC'O@P~#@!)O>]p#@415O`$R#@`~Q1O⪗"@h*w#O`G Q}"@$O`D"@XM~ O~-"@-O zqИ"@<*h^SɵF@*RPF iG@!4T$9S#9F@h4Sh^F@po>0SU!F@VEC*SX[[@F@)gf#S8bF@uSx`:9F@ H;FS(F@(?SF@D SCߩF@VRɵF@6yRDF@$aRp F@\ͨNRHj2F@d#Rx6;9`F@jBR93F@X)*RF@*R$F@0PWSc G@,/kQS(f%F@܎IS&F@`^9S@̠;F@lkSKG@m42WSۈT'G@lkSKG@PpkSȓG@LkS eG@lkSKG@h^SPF iG@0SȺMG@Xak͹Sk~}D>G@AS~}\2G@L:xS)(H'G@lkSKG@=అ--.@`f@`h^I2@@1Ƶ"@?అ--.@@`n.@U^@ .@@yxL@`im/@\Œ@nb/@]@ E_9/@G^@@IjE/@@~@Z/@S(@E;0@}aO@$70@,8@>.0@`f@F0@:q5@w[0@@'h)@]3eg0@@H@`H>i0@r?D@"Ry0@F޷=@3Ԛ0@@J'?@@,0@@Eڮ@~f0@@C'0@o@Pf0@I" @I0@ q@pS`1@W{N@> 1@4@},,1@@U7@P?)G1@Y@f1@"_@I1@ H;@К1@@x@pIn1@:0;@P;1@H/@`x1@@v3@3}R1@@P@f2@R@D2@@&?@0O 2@+Վ@C!A1@@&>@ƿ1@@~ r@<(1@j@|1@M@t1@=@`K1@HqBA @1@~r @E%1@E  @0}R1@j!@k(1@`>:|!@0L1@=!@i&1@ Ѡf"@ ͞A 2@@{ "@p2@`(2c"@*2@l@"@i:42@{f"@ YX!<2@@1Ƶ"@>P|_*R@+B@cSfR@]_B@cSfR@xB@p9.^R@]_B@ XR@ؗ0b+B@΃MR@(QJB@^P9R@@ON>B@LE%t0R@(LB@|_*R@+B@?JVKS@'P!@xNS@kN"@܍1S5"@8SUN!@xNS@'P!@RwS+)"@VKS@F"@ؐS@kN"@@0$ Q@ǗȍWB@|_*R@k:C@C|_*R@+B@!R@P}B@0Ɵ R@DsB@HQ@sbB@ATQ@ XB@$sQ@ǗȍWB@ 1XQ@X%,E4YB@$Z==Q@]B@u Q@HO+lB@T[PQ@(ީSB@XBRQ@P ,B@- 5Q@(nB@W$Q@جҟB@9.CQ@i}B@<̭SQ@pzp qB@XQy7Q@H~eHB@$Q@g2B@lKXzQ@?:oB@TRQ@AoB@$ Q@KJC@XpQyKQ@2ZC@l{`Q@j6J'C@WVQ@x|5C@+X3?Q@k:C@RQ@͘6C@ϪiQ@D*C@ph=0Q@fC@x^dQ@HEz C@yo Q@^B@bGQ@xf2yB@`pQ@ϵSB@ČQ@hB@\]dQQ@VB@NQ@[dB@GQ@(mB@(aN\Q@MB@HvN܂Q@h99 B@ p Q@ȂwB@H`3|Q@ &FB@hZdtQ@PB@|^la hQ@` 0b B@~_Q@^B@.ZQ@PȉTLB@D YQ@0OB@l} [Q@h̘:B@ 5ZQ@`DB@8w8VQ@75B@x.WsSQ@B@WBPQ@(lHB@־B@Wp~8Q@iB@\F6Q@x_WB@Ki5Q@xAsæB@8(4Q@% B@dX 2Q@ B@XI.Q@+$NB@x2*Q@$B@ B(Q@@œB@a "Q@@~{B@HdQ@0ȘB@++Q@jQB@xla9Q@[#B@Q@X!B@$ Q@ȌB@AAZpGp3ie7XEÂD[5.# jOF@$ 70֑F6O7 'F*Y7HF(78x\7eGF0d-Z7],FBh]7Fyd7 Fp3ie7AZpGY `7hsG0O7xqF0sB27x17Fph 7XFݾFЀ7%FFP狍 7yZFYǗ6S&F6@׉Fp}360RF h6Fpd60q9NrnF?6phjZF-g6 aQQSF+88(6XءKFФ#6nBFХ'96ZdGG.FEIEo60V Fql6P?F y_}6]F^6ܾ F"Sz6Մ)Fdz6xqEji6*!EVZ2p6pUܾEYZzL6EWE~&26P+Z{EW6&EW6@[!#EQ 50};D򂶹5H`MeD[5{=D;5p˭D05@hD5-95JȻDp٨I5 D\%'۶5iQD\%'۶5XEÂD _5Ba9H0,r+3}/(GpK2}/(G0,r+3NGG@,2 Մ*BGPب 2j(AG0!2dzDG Xo2P=[EGEʵ2{BGbTצ2LwDGE|2P] KG0r23z~G\4+B2pgG aF2hGS]:2 G d2[ѨGpK2 V 'GPtB+2X6KHRd6o2G&HW2`:ލHBpc2h] Hpa?g2PHw2Hd2YHP-M2~H2xCHE2حQH48"2Hu2a9H`mVQ2C H`NpɰA,r>I@ HN, \Lvx0=MxA)@A^ xM-@c5Mд<@T6M&lRMc=r;>PPMS*V>ԄsM0Yʗk>Mx|†>X8~Mhd>$ʷMp7`>PCM V`,jMt>&!NѸE?P̗&NPGI?+J9Nx|v?`9lbJNp ?p/=UN68?XYNؗ?Ȉ$ OZN`vщ?A$VN(l,@poVN"V]@3\N*@H`N;B@ dGD_NX^`R@LgYNEc@PN*n/u@0;(1ENt)І@ȍx1Nn@2@ a1NP,2@&NKP#n9oPKE|:܇iVKO:`N-`K3El:XuXiK:`uqKS :&wKP׳:ք'{Kpd:q1K+9Ղ:8}_K y1:K:x2fK]:@^K{;:`XBKC":g䜶K^;(LPK;ڟ4K0;]NKPg&;SrKʗ$5;xKPI;$ K G4m[;pixKS 1j;K)칖j;p% KP\;PbK@ObS;֞LON;гFLeLR;)L];H"a'Lv Tp;k/LжL; U7LtBǍ;؞XAL0v|;h[:ML֡w;z>[L9g~;o@gL4I|;CoLXup;ʭ|L`Oo;p|~PL0 Xx;h51L3I/n;L ȦuQ;7NM`4E;nkMMIp/1;3h2 DI fI3(xII3?&RIT3_8L[I )3X'Q`eI =3n lI@XHIO3g4oIP `3`ĦvoI [l30gnI7p3 ۾pIʏu3P>vIдv3ءk{Ip3xJI+;3}K@ HN,p5ZKu,=bqK7-0 '=L@K;L7HʪL T88N L(L!8{dGYLY)8X8ʕL0#69841]L [dQ81Lq$g8`zGL-uz8hɊL`J8fL a18X-aL@&R8%L^o82͛L_K8xlFL0g&8Pz Ll8hML0牍84̡LRʗ8L`49pZpL#|9@>+PL*98"ϿL+9`QL '9xLL68>9x-^ kL@T9x4'Lڨg9J_L`P&'Gy9/w-Lэ*9 s;LuD9oL 9Ϊ9QʝL@St9sL ܹ9}(L,a9mPLEa-9ЭoLPǗd9L:PQsLòL :Pr Ջ M0gx#:XWS9M*E".:8U1MpJV9:N.[M{|`@:hM8C:8:M  ܰN:8<MuVa:U DMdz:.wMpQ||:z@|MrG:lM`c: UMG:{@nMI$:"M/M:8al(Mg:{*M0S.:OI)M:r2-M#:#7My|:X|S6>M|:RVj@M@#;tsFM0;].OMPE!;8SQ%RMq42;nkMM F]t2L@HEF]8BL@pmF]/L@`iF] @HL@E] @ML@HE]gOvL@pH]8' L@-xI]89L@7tG]!M@V^C]`SwCM@\ 5=]l M@LѨ?5]8,^M@h%}+]jϢ M@{OZ%]t][M@i$]WM@4*$]@7͘M@hE&]A;M@/']8͘M@,-A&]M@X!o']0|Wr!M@Q)]PҌ#M@Zq/)]gTT%M@nd&]x'M@$_"]Z'M@]s4%'M@ ^]$#M@8_ak]$!M@LZs] 0b5!M@\4r]ީ~%M@/ĴU](_.M@XVT3 ]75M@(: .]ݢ9M@Љ\pB58M@d\XY0M@|\G.M@$y\1][l/M@l$uo\P_8M@x5\KS@JM@y\ TM@KMt\TZM@@Jm\]UM@xQUQ\(QcM@3 H\^jM@{H\nM@8lrF\p}qM@搁A\PZaxsM@tdb<\xx zM@x6\x=چM@h`k<1\M@XL,\0txM@3n!\kOWM@\M@h-\@M@\x?M@0W;p[ѭM@-[#gM@x>4[@gvM@$dW\d HM@d\0jE{M@b\X^oxM@ 4r[xFTxM@\:9zM@<{S[8]zM@ [tuM@`[vM@2I[8M@EXxJ@z|rN@N@kL@ieN@ lL@BN@EckL@p.*(N@8}3eL@@nN@x1Y]L@5$TO@NUL@p. O@# RL@F O@`wPL@`][O@aKPL@{isO@jRL@O@nYL@kWO@|3\L@^,O@ YnZL@#{>O@ PL@듫3LO@p^=L@}qTO@1.L@ \jOYO@`*z L@-E{[O@39=L@>q m`O@Ptr\L@ q7hO@twL@Ng-qO@@^4 L@nl~O@ 6K@PtO@SȱtK@TdO@^ZK@H9'šO@0K@X6.O@o/L@\[O@Мȱ8L@ps,ExO@HdP%L@O@ЫaKl/L@hu{`O@++{5L@^O@;l8L@XjìO@/T8L@`W3O@04}37L@xH:P@X>TUL@]&4?P@V>L@`zAP@,뎦L@P`'BP@0͠L@ STCP@s\L@J0L@6qxP@Pm C$L@mOӔP@HGK@x הP@@P:K@1MP@ DK@GʌP@ ڢȡK@ط%%P@xK@86`$P@@XK@<}P@ʺ=݋K@~8zP@ K@$m.xP@M kK@؎K pP@ZK@"HlP@X_=KK@lSxkP@x X:K@D*gP@jF(K@= aP@`FaK5 K@AN]P@h(J@6v\P@HQ:KJ@HrZP@xu*{J@|&WP@;ŘJ@> KUP@xsmzJ@AUP@8JUJ@ 4VP@ )J@\+ZP@hӣJ@HHx]]P@pZ4J@# bP@,J@IhP@%J@ ]pP@,J@Ɂ4wP@p?)@J@C&k}P@DHJ@xCP@CJ@c"P@Pw@J@P@(@J@ ш(P@@?6Q>J@cVP@9J@:SP@rj&:J@:ݙP@qɈ?J@؇OP@HɆ@J@|7q\P@j =J@&`P@`GDR 43-P|WQ3P?ɲ~P"]3ptPP FIq_3Q5PBڨ3X&~r+P3)%P@1<(43OZ$P0JnU4L#!Pp4EPz]x48P3*4으X P!4trPPS 48}4P4+ڼO@V59O.5 eOI-5Qr2O S-5x@fO0dy=5KQuOPL^5\!O;$'[w5˕COjrB5A#}O(.5S0tO 4uB]5б9UhOxد 6pJWM_O-(6(g'UO@ -a76(POB6#PO0O{|\J6$ȐQEO48Y6_Xӭ/Okp6PۃLjOFjkǜ6܎#Oи60-wNcP/7PZ5N$sB.7/9ND7}N`3hQ7&NeeH\7 #ŴNPBZd7.I_N`^u7PHN7pz׊N7h(=7N@&mv7 @kN'h74&@Nɗ7@,!Nȗ8/wN^]8 8L0L 9x[p,L/"9x-^ kL@T9H;^yIdD@z^pD@z^pD@4JD^pD@(-x ^D D@PLx+^8D@?Ѩ)>^̲D@cG^ D@4y&G^%:9oD@0FWH^h@^D@ʮJ^ɝ|D@D@N^p=}D@ޜ3R^vD@(P:V^F^D@4NLUZ^FD@X;,_^5D@|mf^H-ŘD@ l^ D@>Ip^i4}D@;,u^&~D@4q#x^LAsD@lЬ{^PꌂD@\Z1}^^@@~D@ ~^`,+yD@xd|^dRsD@@S*~^~^mD@;^yIdD@I@kp@؆UF@B )@(!F@8@kp@P0b^ZF@'|dM@؆UF@o@i%WF@(@ȠEeF@\+z@lF@b꼨@fvF@PKe@VB6F@@v^'@H)F@R L@EMF@RK@(!F@ ^ @{F@nV @F@bn @R{F@C-M0!@99kF@@I!@$KJF@`,b !@8 ܆F@[4r"@p"F@’"@F@`+ی#@T7F@x[#@HfHΎF@pj6#@F@@qM#@giF@ pe#@p<F@?* w#@zF@`.;#@0oPF@rH5#@yC0F@j#@~4F@#@XZӊF@eߩ#@ Ae F@@F#>#@p'F@ #@p̠F@ .$@`-F@@+$@~}F@0N$@mlNF@^$@%YF@6$@v|F@0$@(읧wF@@%@AvF@`]:LbA%@6yF@@}VT%@{9~F@OW%@xQF@`jz%@`QHF@.ۂʽ%@hq ?F@Mj &@F@`ނ`&@8{BF@G&@ ޴F@Y&@Уc{F@`d&@x]vF@@ &'@8p sF@4u*^'@g2quF@n-'@ ëv~F@@=L+(@F@ te(@UF@@*ؐ(@Pk|F@`u(@hzF@B )@v{F@Jpn>b.b̙8iP@"!/a"P@k˝ya̙8iP@մMwa:oP@Pva4O>sP@@FuayP@`2Sva{P@H2DuuawY}P@D+ sat;QHP@d5oaej!P@0ia &P@lOMeas P@T+ba)P@ k]a("SP@FqBWaD[XP@azQaP@փF$La0{P@16GabP@F9Ea;TP@8r+BahL(P@Ȋ>ab1P@Qi\/akN/P@"!/a#H P@0ahwxP@yR3a\nyP@b$3aԎP@Ш^1aj=P@̽1a7v]P@x8~q4ao~P@;5ahP@,j6aLFA+P@99a\uP@:aP@NR 9aD*P@vh8aTKLP@R<$9anIP@l o;a8$ P@^?aѧsfP@ICaHMP@novFaP@v*@Ja، 4P@R͢)Sap-"P@ Tap3xP@6_Tam.P@#Sa#EP@@TaAvP@zpUa"P@pv$+ia4t@P@\7 h^uaJP@^yamP@Ə agٿP@n$acnP@6$Ca ;P@^ aaX,P@5ţ`apqP@|qaXP@8̳Ra\ubGji~P@: b9uP@K! b|\3P@>9} bNP@ϑp b"\P@yb5YXP@aibb.blgP@KtҔSqC@0]n_ASoC@tҔS{C@ʗSoC@аBS` C@ݡS`C@|5*}SDC@v.xS }+C@Lѵ@vS8r C@rwSp#C@\ּvS/C@sS@+6C@`8qSO灾C@VJ sS^C@NPrSX5C@TgpSHC@DboSp6C@8LoSx[C@rjS|_C@\/bS C@ڿ^S+5EC@:#0`SHoC@Ixi`S8AC@@u^SxuC@7ESSNՆC@)]-LS`gΘ |C@8mPFSwC@r7eCS(uC@0]n_ASqC@L`\Ya۾a@bO]L)b@@݄)\Ya۾a@@݄Eqa@@H2-gna@wsBVa@iDua@@Bv$nOa@$t[ Qb@@%!x]b@ȷ.cT]>b@G!xT b@@'Hޜ b@@lb@@$ցGr,<b@(3<{b@uiQbib@}FoBBb@Nj b@wL*?9Gb@(Q\_WE#yL})Q@D0#q+Qe6&#j8QsY#,7OQe63"=VQ`UШ"gQ  *"mQ@;+l"jBQ9T"-8`Q s>"yuhQQ*"QCn'"X? zQl g5"oE9vQ@V3"ySw/tQ "!"hL#pQ'"lE>IjQ` "kBqgQF͜9"DeQ 9"\{dQ`P"xbQ>$"Ls}_Q@W_"xޜZQo! TQ@P@%!`P !P m! L.P bő P`7@3 VbP@~ B6P /*,l TP4 tP4P{8 vEPaM ,vYP + #aP > ྤP6+fL PCP@׃~# P`G~( $P@ EwdP_8xP(1YkP@ےb0P:H ?P; ]NPC%,MpP@$"aPxQ4PP̜|4P#t|tPu@SѨP+G4#8aP`iA|U鴦P{QFl<9nP2@U JPOApw ZqP@\RN\ŮP'5p*GPP@ u͋uPbd5P?PX!HP1آWP?gݣD VPTYhJP@$x1·P@?šdPAaLѨׂP-(q|:PK0UC}P/6-LzP@5ܸxP@^vP[0b xuP@)640ErP-noPN+6kPĢm:iPAs{gP@F-+kBdP7<(]1ոbPJLaaP#ep0_P+]9\P,Ӥbm[Pw8SD\Κ[P s>lsCZP92XPz5t@WP>[#jSXP;=juWPiSV u#VSPNPNyTLP HOEôJPl/IP-+6>lIP@9l6OP/GP!N>bAFPN:P-;BPM|/:T?PE= ?Pl>P[ nF=P? Z(Q;Pj< ]7P@f{2P@2Pxu",PY(_00;F)P귴\)Pd=pO_)P@a g'Pl&Y!$'PKMɿ'PFtݳ@cHa%Pi@1Lԅp%P}tƑ(PܷT`+(Pn5||;R$%P!dp($PLP ]%P@6R&P@(){%P5P)V#P`+P*dP>dGkB P@-Pf4z-Pde,D<"P=|PꙜ$1xP%e܌P b@_pPM"%ex-Paw;pP2IÙPkPХJ%DP*P@U2OP;CJ#aPTPQT> Pf@U}\έPWdLL Pm^g Po@}i읚 P@Cڅlg P@-PN5VPW)xT,P@bWk?:P@ [7O@jݓ\H^JO@b/ȉJOMjzh:O7mOe1xɦO.6_ǐ7O On$?'J|OqQ>hRO)2x~eO#!O0ZOl Ȕ.wO)bORsmOGT%ȄBO0gMpO@S9hdO]O@O7G;뙆OT+@O,}`rO)Jh}@QOh=b@SO@7L;p}O@%֦#˳zzOx xidwO3+OQZsO3+O51mO7`1jO]@`~ jO@kfkO(xT?nOKkO\W* f}dO@ lp2aO@Cr>0<~cO@pyW_Oy8pYO@z,TO:5 ZpNO@[pLOi"P8E]KO;AQFOnP,KAOg-5@XP"X`U5@ޜ8X|(5@4P]{X6@L4 Xhb 6@0#!X$ 6@hiX0u6@4dX`\16@\X0#<6@ȫX_6@`n3XpSP 6@XG>X8;6@@XfC6@XG>XZ6@`VX_'-6@t>}X>䯐56@@H`wX_&86@WbrXTG6@O4ڇIa[@oLg7@\3ݞ[@ca7@4ڇIa[@ca7@IFb[@ *7@ d[@$Q7@d:h[@C?97@hpiDi[@`L7@̵fi[@P87@[Ppj[@67@)m[@kp7@P.r[@;t7@Tj y[@7u!n7@}[@P>An7@l"[@$#t7@Z{W[@ Ҟs7@\3ݞ[@oLg7@P@4ƑShG@1kp4S0,G@$1kp4S:8G@T 9SG@H :S 0<G@,;ShG@y>TSgG@H/mWSax G@GZ1[S q >G@4;]S.G@S(WѵG@z1SG@hpYS0tG@(R|7S)G@nkS8YvG@4ƑS5G@pobSJG@aSXEG@ OdSxr7G@V(gS_MG@4E9nS:tG@x=r SvG@qS' _G@gϭS0:9G@`EnVS G@Q{WWBCH@'9VH}D!H@ `pXW\OH@ ]W`jGH@I-8dWjDH@0wKmWWBCH@>ImsWPfCFH@GvW̤MH@#!W`wZTH@<WHPf2 ZH@喼W _H@8W cH@P; WD}gH@{Wg2wnH@<˚IV nH@Z;)Vz[eH@P!vVaH@|V?U!%`H@,?Wp$9aH@*[yW(0bdH@|fZ1W`bH@E1WhtDVH@'9VH}D!H@w&@Vq H@LQåV]|H@xvpVyCH@,ɨVMzH@RaV8 #H@X`k:V9Z>H@n_V[|H@,`kVhcjH@Rj!@x/̑VG@ P6uv@#@JG@ j!@x/̑VG@`#U"@@o~}`G@ c"@zjG@DH"@zjG@ u-#@ ^tG@`P#@LF{G@L"@5n쉃G@z"@(jO{G@`B"@gxCG@,#@~5G@Y7#@4%G@ P6uv@#@(}ǻG@`*#@@NΘmG@H]nLA"@JG@]"@JG@S #@xB+G@ m-%!@841b{H@ m-%!@(WѵG@` |f!@MG@dQ=!@KJG@ [(!@G@S @|kϿG@Sԧ @WG@@HYe @WG@!Ы0 @|kϿG@ѱW@xB+G@@i@G@^8C@P}G@ #@X#OAG@'@q G@8T_@XMG@ o@p=YTH@@0V@p ;H@lkw@]H@l&@#H@'܊@o{4H@5T-@qEH@Z@0jQH@@&@QiYH@I-u @841b{H@T]?@841b{H@@ @I@@I-u @841b{H@@߼ @QdH@@u @hyIH@@ @ݲH@ S @tշH@@ f @P/H@` @fݦH@@ @`I@o@UGI@-\v@FOI@2@H_*VI@ko@@]I@C= @P)fI@4h@b:9"mI@4h@sI@l@pͫvxI@`# @I@P3@ !I@<+4@:I@Ehg@.pI@c@e͘őI@U2C@ mlI@D@@I@@T @I@@hTI@*8@I@@ų$@ᱰI@@#@`OLJI@Y@ufI@8@PjNI@U[@zI@@~~@`hݔI@@o ?_@b][I@b@@I@`ߛm@8o:94I@@x]"I@FAQ@PRBI@h'@໲I@2@(8I@դ@RI@,C/@|҃I@@F }@I@@-Hea@b4`I@@k5I@X #I@Pτ@D I@]?@WoI@U,%|@ؚ.bE@ 'j? @ؚT=G@@ 6&w=x@,E@[h@xX-E@5@(#sE@f@ 9E@@hlg2>E@@Qc@*(E@!-@ZE@/@~}E@,%|@E@D@pi40G@5ۛ@ﺱG@B@XhTG@Q",@띻F@@زvYF@.@F@@N٫J@Hg2&F@ @ILJ#F@W-f@aF@&N$@0jF@{@pCF@U<;@0F@a@طinF@{@P͘F@FK@hnH4F@yCe<@`xF@F@ )(F@6Ti@@BWF@U<]@`F@9o"@J/F@ƨ(@(.F@@"rn@8-F@@&}t@=֛tF@9@jF@L@0SnaF@@!U%@pYXF@x@еQF@AȚ@p #fIF@@ڌ,F@ϞW@PH3F@@Gr@ȯY> F@@! @v F@@IH@ @,F@@>_@-ŔF@yOH@E@fS<@xoE@$F@t.E@@v@z@PE@`@*ߩE@@ȳL@]E@7a@(5ZE@W @0͘E@@@X#g2lE@9T &@ؚ.bE@ 'j? @ؚT=G@" @ ./G@F<@+*G@@@1@"`)G@.@HQ)G@4@t#G@m@G@ouL[@,lG@@]@][1G@d,w@8r53G@V LZ,<9@q`[IXB@/bln ֓^Xčk:@ YX΃hr:@@(X}"f:@01;Xvra:@D X$W:@Ht@XF:@gJX#<:@ϗ{X03b}9:@.3X@Eܮ.:@pD1X&kw:@H{LXPt|~:@t]aJsX`w :@[n_eXп9@s-\Xi 9@E XX@.9@̥uVX,<9@>bVXŽ9@:{UXSC9@<RX9@q`[IXÍ"9@h|-xBY@u=@Ls AYp寑f=@p<-%;Y`P=@ DK0Y߸.=@Lِ'*Y0̖=@?(Y <@ ;.#YquC<@ѨY.O=<@#':Y<@+;HY07Jy|<@LY@QPm<@t^Yp>S<@ &>)Y4/.><@$#*Y Z+F,<@puY@&p? <@kX/ ;@4]EX{yݺ;@4 ǑXSɢ;@uWX^RP`;@o1Xw;@[X 1e;@D&X}IW;@2Xq"I;@q X3;;@ g%-X-L+;@QKXP;@p7Xv߁;@5?Z0J?@ Z~I?@4Zҭ?@ y]Zo?@,߹yZpTos?@`ZxZFe?@l:ltZ`Ǝ=?@ D`Zt4>@&QZpAy>@<#HFZ };v>@/>Z[>@p:ZP?V>@]N5Z`A?r>@+Z@e">@+ZY4˒=@@&V'Zر=@̠*A Z g{=@$1գZ0dS=@/Z݊=@% Z U#z=@hiVZP'Wb=@\rWYeaR=@;EY`BJ=@Xu~Yca4=@RY =@*~Y(zI=@n_Yp\@<@*;Y0x =@8vYY*!=@xZcI`YЅq=@PY~ ڤ=@P D[Y }=@zYW=@8*Yئ=@Ywn=@2r5Y`PI=@0EpYd;D=@`jYv=@dH&pYP=@@@p=Z0J?@|q@pi>@s@96?@Od#>@)?@0:&>@3p ?@@1>@P>@0n8>>@@ilAs>@iUMN>@tT>@ [|U>@7q>@RPZ>@ ]0>@@Wb>@!>@ ~x>@f4>@pd>@K x+>@iI>@ >@{Z>@ ƨ>@K>@p">@BHy>@ЃT>@>@PR>@@B?@ e;>@C?@:ק>@0D;?@-ۖ>@0+?@0}">@!:?@l>@;1K?@Bm|>@iBZ[?@ԧ#e>@B&u?@XXp@bj1/2@j ̿pw2@{5 ?pw2@j ̿2|2@ ߂`DY2@ Eı`7|y2@ h2\2@f? ҧ{Q2@Β?PE2@{5 ?p@bj1/2@#'?Y$8ήSȭI@Age iRAsI@!D`k\R I@HȝuR?YaI@dRmI@zxtRa{»I@LhR`#I@iR[[I@$g RI@g%^RxCֳI@ZpъR( &/I@yRg2pI@$Ѩ}R=;9I@?yR( ƺI@j/vR[נI@qquRޱWI@4awR0F:I@42*tRȭI@Age iRW4I@r? RU!I@]ΪRI@LyuYsRp3I@XtnxR99tI@tPRzI@}WRAsI@ #aRȚDI@`a1Ul#SAsI@8ήS(@TI@T^`(S`ZZ_I@-Ǒ@S= ŲI@ЫSbI@'mSUI@([EwSS"nrI@pY;SOgI@z4Sd(I@Z/vA@`in'U;D@`$/ A@ %حA@1sl% P:DA@2Qd%ӳA@@s%wu,A@%/vA@`ȳQ%҈&A@@.&HxǹA@2-'|A@{5' ";A@`^e4' A@ lJ)'C@`!&8+JeC@ 5u&l"g~C@ JU&ЧwC@.oU&PT(C@@d[>&='6C@;a&UC@A%=C@X%6C@ mp %CƍC@`?D%U;D@`$[*F]Z.srUO4@$Yz5@-&$Y.srUO4@ 㑲YF.^4@ nlY"e4@dsY0 |q4@07Y@F^z4@Ų#Y.k4@<`YP%'4@H (Yu4@duY>04@t;PY*bal4@@'BY` g4@8ntxY`4@EpYo8w5@0Yk%Y`kB 5@4rY5@x!1UUY)? 5@cYY4@ɲc[Y@I4@8q4rYX!4@sY`55@ AuYx5@SY0$95@ܦ@Z]45@$Z,Ԟ45@,/ Z@aC935@MZ-Zи6h=85@0ZP'W8C5@ULZ`HhdL5@ ?NZШn5@V!Z%aĂ5@]N(Z6hA5@ 4r~*Zp5@DPZ[.Z0B5@xA1Z b5@J9ZȘC5@<:*@Z5@d[AZGy 5@"BZ#5@KZ#5@`-8?MZP]Xr5@P9OZPϹ5@ZSC@d&S`0\>C@EL=̤SX/ѵ4C@3鶟SسDC@ęuS8/C@Q42USP7C@VSXoN]C@tҔS{C@];^bL C@z9`^:9X\D@.H?+e^RTC@m`^P6OC@z9`^I:@JC@lz-a^،DC@Rua^.I^=X3D@8 ^@dz\-D@yW^ᡟ)D@(L^(D@x̉^p $D@/^00aD@Wȋ^X)(vD@нj8^H͘VD@,^evD@p^Bs%C@Ў>^`C@63}^uC@r+}^?C@^NWC@ޜV^Hy͇C@ |w^l C@6|^p@sݗC@xqr|v^͖ȠC@TDžs^ z9C@܄΋s^@uC@ p^0lC@(yl^x neC@]Ni^(xbC@Ff^NEbC@di^e^F_C@ȡ*e^O5VTC@^AQiF@4dPi_G@9AQz|G@XyMQM(G@nGQ`_/G@,rc΄Q5G@Q]xCI?G@ļr}QHHAG@׉.yQ0LIv@G@1wQ(FdWBG@<p|wQ@c$qGG@#anQcYG@p?\Q)(xG@H: PQ^& DG@XH`JQXwiG@ݓ^+FQG@@6CQXDލG@0}0=QDWG@ آ 5Q0iG@<d*QpG@ﭾQ_G@:QXwG@DQHUqG@!ߜQi_G@+|SQxHG@hn1Q-G@Pp,~G@ P}G@L}P IoG@0ÂMmP0i"YG@|/PCYJG@#*P z"DG@kOPPPo>G@L ;,cPP#&;G@LBPw4G@(VPȩe)G@;lPG@Pp:9 G@PZRG@DVdȷP7 F@<-]ΪPpF@nVP8 F@!PZF@8/FP,SF@4m/ѻPؽKF@y>IPیF@TEPF@0ūP>3F@*PMoF@P/PF@A VdP-žF@dcPh+F@h+PKJUF@4dP@9dF@u/P)(F@*mPF@td|PxF@^&P*~F@2EñPiF@_^]wP`vщ?@VMN;Y58_^]wP;Y58 k{tP|j8͋vP8Y*uP٨?8pP4gf8iPp8͋_PS 9@ %[Peδ"9H=sO[PP@19sXP`#,<97RP B9MPA:9 ?P HP#58$9^3 CP4W9TtDS>Pl&9&;P 6FI39]_9P`>\xE9n_5PP2R9Z9.PpڨY9Dnt&Pd1TT9P A9PuZ/9P Q39|N4Pp94 P+a9hEC|P@,:9E[Pnv9p=(OPF 9v]O_9h{*OQ u9.wO)E9@1OwO_u:(=uO@A,:RQ~O b}AN:XOD*a2~:pa*Ov:bbyO :#O:Ou;rũ;(ҕO B;OhE&;H"/!O7{<zOb15<زOZVKq[N=T6_ZNӴ=p[N_>`kz9ZNo 9>`PyUN4B>6TNP\>X>|UN@R z>(!SN1k>nON_h>@VMN}ұ>`VON4>8ՄVN|8Ո>bN.>(iNV>J'=jN`?.>5;gN II?(=iNp!+?C%qN@&'G?9qNp,alW?(iN\y[?(_adNgbr?XbN-?Q*ucN;r?*r;hNn?ṱgNd?Ȉ$ OZN`vщ?`Xt0S=UX@%W70@h[X|X@ ]4@(iāX@ ]4@S&X@ @4@h#kX@74@tթk3X@0EHy4@DF9X@Fi4@h[X|X@E4@ 5XX@ &4@= X@q3@Z|X@3@@~_^wX@,X3@uuX@dX3@kpsX@@ۅ3@ؿv8SqX@Ђ3@FlX@sDZ3@|?maaX@0T3@ /D]X@0 8h2@[,\X@*2@CYX@`J2@!cVX@0`2@t0S=UX@PFK2@q/WUX@PdaG2@+\XX@L~2@p&Z\X@'W\2@؅aX@1K2@0[fX@ *M2@!%whX@P+TJ2@xfG"gX@ muB2@eiX@ y,2@nX@0M 2@`{2t[oX@5$p1@FlX@ob1@psXpX@ 5K1@doX@q1@lX@>%W]1@z2%jX@ U@1@4̍hX@@]RPl1@H/fX@ o0@ԎfX@`sǡ0@χIgX@P%@?0@ϪjX@%W70@ax42a^ugB@0 Յ&]ƙe(C@ ^]HDB@8'])(rB@(!]kB@ ^ugB@5]N(^iOnB@gD ^ ZMB@g&^@9+!B@m*t,^^B@6^/qB@e M^p^dB@0 Յ&]Pp IB@8yv]B@Q]:B@ ;]huB@Y1]`?\B@}'@](ZB@]3B@u]}:9WB@dkB]ЫDcB@ :]0! B@j ]͘fB@]r]XvB@03M^z`B@"IMP^:B@X[ R^8>:9B@t&~iS^.B@<1V^`QFB@hg\^(䒫|C@B]^؅C@l(r|_^X`eC@x42a^ƙe(C@bt( Ub1@L'PtNj(@+)#ZQ P eH?bYQEF?cKQ`D?`EQ@9vK?-xAQ*JGZ?P;@QaL'j?Q$@Q0+?{?LfVF-1@|ۖ,1@:q˿3%1@  ӿEg%1@D&ֿy%+1@S: ׿cj;,1@p6jٿ (1@h1 ܿP+1@PQ"޿Pt41@^f ߿`.帜:1@8 AD<1@^>@@HA:1@``:.1@Nh运ۚ*1@NsgPd\1@ $s w0@#0@9{U]0@B'\e 'QѼIB>QbI 'Qp"VI'G1Q0 IL'QJƀIQn:IP+!Q0e0I|ӀQh${HI(eQH!V'I n_IQpWI(]QQѼI!* Q4II$zuQCx I4҃QѝIY&uQcI<8nQQ=I0%jQ@| I#aQ,X& IRQRI%rIQw I@QG2IB>QbIf^E*DZJ@X8 K@( p#XgJ@X@`J@E*DZ]:ŞJ@80U9Z(JJ@ux6f4ZJ@t0ZJ@J$Zh{ޝJ@6J6ZdJ@?ZJ@I:YDHJ@g%YػFJ@)Y(6pJ@,',Y ^J@-Y'K@,ܑYeK@Y8 K@3YرK@̛Y(TJ@Hs>ZYPsTJ@8x#Y ȲJ@Tr|Y`74J@4 wY[_@iU1H@u@*@c4H@g;V~@۵M?H@š@GDH@j@ 7oJH@k@@SH@Mhn<@xdYH@Ex1q@@E<]H@Yp@HbH@<8;@P?gH@j@P*(jH@^@5mH@(@HpH@ǔ- @BtH@\qP@"tH@rӫb@sH@M'@NvH@ @(q WyH@)SL@8((zH@e-~@h%zH@E@WzH@փFj?XQH@)?H€H@r?{̼~H@a.}?KJ~H@?P|:H@D?x< H@:Fj(?H@5T^\?(<iH@G.C?(ZީƊH@T^5X?(QrH@yc?Q0H@sc?t H@eNe/u?XS1H@s?(~LAH@B =? {`@H@,?!YH@;2N?Tn=H@Bz?pH@ ?aH@Χҏ?0khH@q$H^?0ɋ˰H@?JWfH@?P.H@V?LH@ /O?8|H@?:9H@03?}:H@pC?^$H@xBV?H@H@Z@e% ;H@L0Z@0DH@nf'LZ@8zH@%ifZ@x0:H@DyFZ@`Cu I@J?OZ@"S0I@WZ@h&9I@8{Z@ش@I@^p~QZ@8 QGI@m׏Z@͘LI@/WTZ@¨jRI@ܩƒZ@/bVXI@;Z@4`I@`̍Z@>viI@xMܲZ@4}UqI@C:Z@pHvI@@h1Z@(|I@ CZ@iI@lzZ@{AI@dӰZ@pcBI@з~Z@@x=I@&/WuZ@ߩI@x8 Z@(II@$uZ@> 0I@<7Z@_I@DLZ@I@Z@LJI@7f'vZ@09I@bZ@p"I@\DZ@ZI@ 5Z@x0J@NZ@6j J@BZ@=@J@莕`Z@'J@|/W_Z@!J@UkZ@RG J@^2Z@ J@#2Z@  J@ YZ@' J@1_Z@j{J@1_Z@j{J@TZ@pђ+jJ@EQCZ@"J@ۣ1 Z@@_(J@1_Z@j{J@^=@˞KEvUz>@WII? Q=@)4>0=@z4B-c=@TapoMU=@#Aвy=@˞Kn=@]BL/he=@4p2>^=@`IIcj`=@Bw0ns=@H% l㿰=@+Xb=@?u{=@.?`'/7=@(?U;?P۬=@(!?5f=@t.&%?YL'=@¨?]e=@0@{?@z`=@ 9`?͌ >@F ?.>@&?!mz=>@!?0k1R>@t?EvUz>@WII?lxjA@`V"++@0JzB@hDt?=-@0JzB@`V"++@P0B@y+@~B@G+@pDZB@|f;,@pk2FB@g,@#AB@b Q,@jnB@ Y,@@BB@uv,@(B@ w,@o B@ˆ,@pީ,$B@ ƥ=C,@#yixB@ d?,@gB@`v J,@)8VB@ \Oz,@p_mEB@f%6,@f6B@`-=,@Uf*B@</,@ql"1B@[,@ B@@A{,@J_A@ j,@aKA@ۦ,@xjA@@ˆ,@8_SלA@hDt?=-@mP:G@x]=@h@P:G@a>@1wG@L>@cMG@PL>@?)G@`0. >@ش_%G@U H>@!G@?>@oG@S o>@+ȱG@Б>@[G@nEz>@6RwH@6B*u>@ 6RH@߶j>@WH@P5Z>@ ܐH@p;DR>@ w#H@*P>@UY_*H@@(I>@aK0H@8^':>@a3H@ )60>@`vڛ1H@(>@O:3H@`6]>@eɠ7H@`㋽ >@h@=H@P*>@h@@pSST@ z?@@, RT@K< @@RT@A6@@愬PT@0{@@LT@H|)@@;AT@995@@)S1T@ A@@7"T@P~F@@dT@ƬF@@T%T@v*C@@ܢݞS@8@@oО%_A@z|1A@7 v,PA@-f݃-A@` DW-GA@`.A@ .X^zA@d#m.x YoA@@i.kr\fA@ !\/ `A@}?/О%_A@Q^/h`A@ Osu/~?)eA@Q/jqA@L!0pp}3nvA@&jk90`U^wA@pFIR0 |A@Nld0mGA@S o0ё#A@B6041jA@"d0HA@@0>)MA@b*!1(EcFA@z|1A@U8-^ _x}K@w_(^K@";,_,ŸK@| 7_P4K@_bBK@&BO_%ZK@Bf_pVK@|)B_3K@x=Q_:WӳK@*_`ޯK@_LK@ G_0qK@E_TK@_DK@*_vK@ֵ %`PK@Dy/`{MfK@ U `0k?K@N`ٱ `h2{K@L} `XvvvK@.i h8 `XI{ToK@nh ` gK@Ta! `\K@BH`vAHK@•$y/`zK@@h[1`32K@}2`32K@|4`QyK@rOm\8M@ u[TXN@=2I[8M@ u[8C`M@ΨL$[p%IM@?iX[@)r M@dH@[cM@`z1U[|ޥM@d;7[(k@M@7P[M+M@3[p瀿M@.[TM@t[-irM@ތj[hM@gmZ[ M@WS[{M@Ds'[yCN@? [^WN@\@N@j. \Ps N@4!\Pe-ŻN@8\?(N@a q!\ t*N@d,#\hD,N@Tu"A#\F.N@P:l \:.H/N@6\dq 0N@Oڶ\=|4N@E]\hz8N@\x\yC;N@g\>N@  \eBN@{"\ke~EN@`/\*KN@ě@5\Hz]RN@l;6\0~YN@}n~9\ ^N@|;\PE _N@xc-x7=\``N@PcH=\XBsdN@<쐕>\xfN@8*@\٭fN@(C\(EugcN@%aMH\8.abN@!8K\YdN@,0UqN\ީojN@΋O\etN@ XN\Ă|N@I\#ȆN@ B&H\<܌N@GI\8ވN@p K\pAWN@<EL\eiN@f V?J\@fGN@ LʮJ\dN@lOXK\HٱAN@x]ΆM\PN@ΞuDN\0jςN@d\q WE@LsV\+9}E@D]pNrE@(&~t]vzE@"]ޭ!E@d (]jE@R]ܦE@@q!]9{yE@&]MHE@X*#=-]xցQE@]Q1]}E@T?2]컇E@\7]:E@,(i@] $vE@D]P.eE@ԅA]БoE@I=]xWhE@xi<] F@z{=][ F@y6<] i;F@R:]%F@e:]܉TF@=]QfF@(]NA]}D#F@87H]Q'%F@,RL]j,F@XxL] ~}7F@xRPZG]P((JF@$h<]bF@0 he6] rsF@!E5],~F@0/]h:F@Tm%#]HvF@d]@F@@V!]؝gF@T#z'] )(KF@ϨL0]M&F@0 ֠7]pF@8|S;]T)G@@xv<]b7G@5;](d<G@]sY<]xNG@QPZ@]?;91*G@~B]x2G@}WA]h7G@UxD]pN}9G@P%BfdJ]9G@0'M];G@XR?]N] 0BG@O'/R]'JG@\W(Y]ѵUG@<8`](YZG@nag]W[G@#l](JYG@4p] j7SG@lzw]0OG@8?]!KG@ ]&]2HIG@'](TKG@X;]5hCG@GV ]8by1G@] C%G@HN]nG@<>IR7\ gE@ FmA\(o #WE@,H\RE@4y=T\SE@* [POg`E@cI[WE@߹3[X.FE@8/[xݩE@[=E@ PZ>[@|E@J\*r E@$ #\X@E@ta\HE@R* \8.E@Lh\H*DȜE@f4(\rE@xm[[$E@;[pYME@M*[hXE@+y[ 6^|E@pܑ[pU5E@] ʴ[ vE@R1U[ iE@T-5[h6nE@j[hLE@_ H[.E@I#![E@0[xNSCE@ikB[i#nE@tz,+_@@αF@4:`@Je^G@L<,+_@8&F@ 4_@@>F@(7_@h$ȳF@h]u9_@0c[F@<_@0nSF@@_@~d]F@@|OC_@QF@uD_@kiԴF@pDII_@@αF@(nFLS_@tF@ o1Y_@+õF@ptB[_@KJF@{("c_@G|F@H o_@jXF@|J?x_@i ZF@~_@-eF@ئۆ_@|F@w8v_@r$OF@8]J?_@H F@1(_@F@+:S_@AF@XX_@e:9&F@O_@F@( 5 _@#F@W_@pOgF@ =-_@0FF@0_@G F@c _@"EF@#Һ_@RF@XM_@ G@¶_@NvG@b_@(ZF@@_@ݩF@v|C`@_U!F@dB`@#+?F@ `@`z5F@`Lg `@PF@}@`@)F@衂`@ȾF@4ba`@n?F@dT`@ ml`F@LY`@99 F@L'!`@x)HF@]$`@6F@Sg'`@ݩWG@3*`@{ewG@(6Z-`@Hzd#G@.h}0`@̘ )G@IPx2`@P0G@r3`@X1b:G@t_a[x6`@p )CG@u:`@%`xJG@;}H=`@`*TSG@R7>`@X\G@\nO@`@h7aG@W1B`@05*bG@|OC`@)idG@$* C`@,EhG@BVE`@KJjG@J`@zjG@4:`@Je^G@Hw@`@趡G@յ`@Е #xG@\v`@H?G@l ]l`@Ȑ0bG@Hi<`@zG@ Iv`@dG@$Rdd`@`?G@tIY`@.͘JG@4LZaW`@߫vG@dWT`@1tG@`cߌR`@@mlNG@pUP`@@8|G@|1P`@pmU@tG@dL\N`@cnG@D$ J`@$)kG@uh@tp2@l{:G@]K3@(L0bG@ Ѓt{\3@(L0bG@pNgZ3@H᠟,G@]K3@#ZyG@`3@磼tG@pij 3@FG@cm2@`t&CG@(2@#G@W2@hG@p&2@x݌G@@tp2@l{:G@vh(#]QH@E*DZ]:ŞJ@u(xzZU!I@ZXMI@-GZ8 dI@ZGI@ZKJI@|Z|I@TgZp I@L=ZRI@0K9Z4&I@K'Z4LI@ܝMZVI@/ߜZ ?V:I@PZ8"J@PZx{vJ@oZHJ@HגZأLJw8J@,߹yZ;NJ@,mZ؃m\J@p,:ZP-{hgJ@!FpZX8ToJ@jGyZBwJ@dL=iZ}J@_ZȉJ@xA>O\Zh }J@ WZ0iJ@0hzRZ+^ȑJ@v LZx*(`J@E*DZ]:ŞJ@h(#]$`xjI@]@)tXI@9k]QLJMI@ q[]AI@L;[*I@ [LI@`k[mI@@7[OXI@(m[@uAI@ Lge[ЬީH@n [(E)H@d X[QH@T[NH@q [SH@X-[8 I@,[8[(kCI@* [#I@Pô[GI@C[xI@L[P7 I@}[@ɮkI@C[0q %I@["-I@P[(I@Z[$|I@\l[p I@ԃj[8*(B&I@8[^٨3I@lkBӡ[Pca9I@H#[h@ߩj7I@[L5;I@$ [8mlDI@[)(wKI@{[lTOI@5 [ nlTI@b[H&Z[I@0Ev[+|z`I@ԌߜZ[XGjdI@Ux[P^gI@#΀[ȃ @RkI@ĝ0[_ynI@(*۶[@ûqI@@~[iMtI@'ky[P,xI@]> h[z,|I@pgL[I@KV6;[PMI@\L*6[Bs~{I@hK.[+3xI@$[@`ivI@Hi @[*mI@{S[TY^I@d1U [&iVI@][:TI@wXH~ z^P@3E@,Wp8^JE@,Wp8^P@3E@'C^rg8E@U3[^c=E@\v斣f^hX>(CE@ {k^JE@Ԍq^pg& JE@Yx^7:9AE@H~ z^h. AT`%F^E@q|Tp˲OE@oIT #nGE@yPSL@>V_bL@q|_(#L@Г)H_Ȗz_L@FCN_! eL@"y%`@kL@$p`puL@4+J``YL@WMG!`XEqL@IC&`g̰L@M!3*`AsL@ `.`c3L@Vjox7`XL@E`& M@Ra6O`͌M@ R\S`8 TM@<NX`v`1nގL@n x`P)L@9x`ď }L@ҷy`+_eL@Yy`Dh`L@^Cz`:t[L@ 4|`tZL@ d`x [L@6`F\[YL@[[`0QL@r}q`XmlPL@{R&@@2]U=@ phH@@`BA?@pmG@@P%w.>@ phH@@2]U=@`Jr\.@@Ipl>@&@@>ї>@Jw*@@wZN>@k"+@@ƺ>@ i)@@`BA?@|T+{SC@mgM@6+G@x%:aN@0-\(C@89M@X D@8EM@XmD@R&M@X^D@R ߵM@8!D@X-ŗM@CG!D@φMM@@f,D@mgM@]8 DD@phѵèM@МWD@X4M@ vgD@@M@xyguD@ -M@WtqD@zM@DZۓD@M@HB뢬D@آꅳM@@wzD@ M@UbD@8RM@+{8D@8M@XHbKD@$M@P/f%D@@M@jͧE@ bM@:E@HW M@n*E@psMM@௲;E@YM@NHE@_M@XSE@5yM@P`jZE@PHsM@{N"mE@̨M@:j|E@RN@ЊE@(9WN@~(F@H5c%N@q!]#F@P#4N@8oZ>F@WF@(bnlWN@+{G@DžjYN@@bK5G@^N@`8G G@x%:aN@6+G@`}_N@׆C@X)M@PvC@~-M@T+{SC@ h0bM@}P0v=b8s@EN@@:UbݩmO@'@:Ub( @O@|5!ZbFIO@8sk#\b hRNO@4JL\bΘRO@wƯ^b(-EVO@aMcb7ZO@guOgbS{YO@jb(p UO@]ob0$/XO@F"vbPtaO@bMw|b࡮gO@m2bP8kO@XDUbH]lO@RÕb8nlZkO@\,gbج gO@b\LJhO@yEğb I0blO@KM bݩmO@G|bpomO@Nl4bSfO@Svh,bUYO@ edbXΘ3OO@,bqlBO@eb&<7O@/B~,b^~-O@畎Vb뼇 O@vbhb>ְO@5)db GO@k#bԂO@4b.nl O@Wcb 9O@Y+j+bΘN@,WˁbeN@ bxJr N@/WbN@zEIb'N@0(-bh;|N@0v=b8lN@N&b8s@EN@~4XQ@ S=@v XT@M>?@c/v XT@ >@LJ?RT@T>@bLT@Љf">@t_7T@ ?@to.T@Ttr ?@(67(T@Ttr ?@8̍-"T@pE?@1^T@@] ?@ST@TC?[?@T@ 9?@8^T@C?@+ߴS@ H,?@PS@^?@pS@@P?@4S@?@XS@@QP?@T@Ϻ|XR@pu?>@a;R@2>@@w̍R@P[>@3p~R@lB >@3N܏sR@0K]>@h,X`R@p үD>@$oXR@ƚ1:>@hTR@ꖔ1>@[RR@^'&>@^z(QR@Od#>@n#OR@k)>@JR@ئ>@_S@R@`T>@&i6R@ =@$}rm-R@>=@f(R@7=@pœ'R@M=@z#R@u;=@J?ER@p@?=@^R@0{0=@S R@'ZJ=@d R@Dܶ=@^[PV R@:w=@@R@=@ wR@`Jq=@u5JG@ecN@#NG@ N@Q$ANG@X>ٗN@дШKG@H3ƤN@ ll" G@ٹoN@b%F@ kN@8Ϸ~F@xN@+{MF@D5yN@xA/jF@eN@PtЫF@(@ΘO@`F@ jϔO@A Y|F@hK^O@ FciF@h4!%O@,GcGF@8ީh,O@> F@(;@10O@.wE@ "8O@hE@ ZezEO@E@0,UO@8vE@otiO@@$TE@p+wO@`vME@Ѐ>O@p^>E@ҾO@]s\ E@AsJO@ S҈ E@(tO@Y6E@wCO@cWE@jO@hE@O@82D@WBO@pJD@x׽O@]KD@h8O@w"D@`i~O@"D@pn1bO@p/dD@+O@0\D@!O@`*{'D@&& nO@AD@0N$O@b*{D@.Z>O@`҈WD@țtO@6;D@P5O@oD@̯O@%4D@TP@D@:ӆP@(3~nD@r:SP@7D@Sq P@/D@ 'VQ P@XXtD@ڠP@k"D@P@tD@X5P@ aKwyD@xʦP@]CD@TR:S#P@\89D@mO(P@0024D@7P0P@!jh@@H[z=N@P,VlA@([hN@!jh@@5=N@ n@@H[z=N@|6v@@~MkAN@XMQ:@@SIN@x_-@@%|VN@T@@j{^N@XU@@F`N@C@@VgN@00@@x&uN@ӄ@@'$l{N@p2A@ȖzN@  A@6~vN@Ѝ%A@آ~}xN@P,VlA@([hN@VBùtN@S$D@ԚLtQ@tFG@ԚLtQ@Q"D@I1kQ@<\[&D@IdQ@Hnq $D@HUyZQ@D@4ހ"SQ@S$D@5MQ@o2!D@(;w8IQ@БC+D@XzCyFQ@@̘;D@k/EQ@>ED@EQ@U!ID@|D;EQ@`ݠLD@CAAQ@3TD@F_mB4Q@0eD@kp,Q@rD@0+Q@5,{D@x% 'Q@pY݂D@+Q@HED@biP@$D@8|ކQ@ DD@4nQ@X#WD@4=6Q@ϝ6D@tKQ@0yAD@sNQ@ vD@V(Q@(݂D@ZQy Q@@Qa E@`~Qy Q@>V E@A Q@2:9E@re'L Q@g2;E@o~ Q@Y@E@wMQ@ 8TE@p/6Q@PN&E@(Q@UF0E@z/Q@z8E@FΈ Q@-,@E@P@]}:F@L^~P@Е/AF@A}P@"EF@9.zP@9jJF@HVuP@ jOQF@rP@pY>WF@Ą,rP@`}\F@lAoP@(e$_F@ ЪngP@@`F@zՓ_P@pphF@WP@(/bvF@09NP@D1bF@XDP@F@)1=P@ëvF@9P@()(~F@L+2P@pHF@0&P@peF@0CP@(}F@, P@#F@숾eP@X@F@S`P@@耔F@#P@{F@$oP@f3F@dҤ P@0}^F@`#o,P@F@>CcO@ooF@4RO@jF@=O@v F@zCO@RF@UO@ ;ѵF@O@F@8mQO@qF@,4O@^GF@PNO@`xF@F@0/jO@8QF@8 m"O@hWF@P=sO@xxtF@@ODZgO@8hF@ ]O@X4f,(EM,(Ez2,蝘E +(I(E9+pr;]EP+~(E|*d UE Kh W*`+ZE@J9*H-Eb)XtիEn9)*[nE !5e)RzEb$)xŠE`s(`dGE@i2(-Euq(@xuE@LNZB(X[XE`X(H-/wE ']Ekp4'wE *'^ NE/za'OQ]Eh6S:'6 U.E%'X(E=#&eb1EFl5I&hD:g"hiUD{"X[pFDD"Ԅ4Dop<"k(D ""DKkp@J".w,D4" D@M~0"` DgQ3-"YD`I"8lsC!A " aC z!C_! 2=C^2޴!PC[C@98!C2!ܾC^@!AdCJ]!@C`/9=!,CQ!(f# ۩C'$!!(yנC G!QًC֒o!.ݾjCS!ȭLZC Aw~!؁2wUC`!4@OC`!7vJCQ{!@_ ECf6!pz@CTlp!ke=C _a!Pf4=C %,D!$C0fAh"رLC߭"!BQc#GBbB@ѥ@#(fuB@ke#PL9NjzB 72$H[GxBD*$ТɜpB!N$XeGlcBbܭvr$akyYBv$=+RBQ$`I_MB`~$a 8;JB`ui"$@AQDB`]_7$!=B`]_7$ 8BM+$ /4Ba6$zkb0oD+@%vṊ0@V%oD+@%N$+@@Vu%@|Q+@f_& +@ &T+@ LcIB&`%,@;+m&6%,@Sn^}&@G5,@@Yt& XF,@u&` 3b,@ 8I&bԈ,@Hc&`8cn,@ aٽ&@G ,@!C$&@Ci3,@i^D<'ߕ,.-@`Z z'E~2-@}^Mm'7cX9-@`lB%'nOK-@Ը?3( u-@`(oj3N-@kA=(@A,-@lau( A-@hK)=p.@@Q)q*.@qx) ?:6C.@.h)`G=_.@FW)ȣtr.@`")6-|.@?)`,V.@ +)j~N.@N涹)`SI.@`͊)9.@2)@esm/@kl*E.@6(*G,V/@W 2*%/@ 5*+$/@H*@4/@ai*)=;/@ *f/@*_-/@P*mn/@y*&0@,ʊ}*kT0@@)aQ*#0@ 2*5=0@ |o+"0@Qtm+@P$0@WB?+vrH0@`9ʊ^+ :~ 0@3 n+Xn85+0@@hg+@x),0@ @ȝ+ F]'V#0@樼+p%0@rܛ~+D!30@`+P͞A0@07+G|O0@U8+,L9k0@:ȣ,B?0@+hE-:0@4$Ȓ-#ӞX0@Cs-@M0@@IF-vṊ0@Wr0->ԞH0@9 .i0@`F.0@Uv_..n^'J0@@쬫9.a0@i$+>.%@0@[f$k.P%0@ !.0@`!n^/@\'~0@`Ѷ=/pFܯ0@".R//|0@@[.T/y}0@mkb0@Cܭ0@pG@0GE0@X +00՞ 0@Y1=0L0@PcM0 ҉s0@X[0UN0@01g0p_#90@}p005\40@z0@@0@$0f/@zkb0^=/@ `,uxH*AC@"q}(%gD@3:#w) C@D*M4qC@ΰ`!8z @C@Q~8&8C@͓kC@`,uxH*AC@v5p"CD@:"(55#D@uoh'D@l `E1 D@ )D@ӌF R][D@2zK rFlC@IK5PC&C@@Yw<ȣ--vaӿO@X4a؅cO@Tdya{O@Pa`VO@;by][O@uk b(xO@skb8 @DO@_b tO@KFҟbxO@w$pbbN"O@P"Eb o`*P@@!bpTP@D\%baP@n_Cui)b J3PP@!<.bP@U3b+@ P@W#97bq P@K2Ȁ:b P@sC@bȇ}P P@8>Ibn@P@O'PbP@Ubh@ fP@9b]bP@yـ`b[H+P@HE}`b%!P@bb@%e=%P@mLfb,G)P@1>Mjbh"|-P@aM̓nbtJ;0P@tb6k 2P@B+zb=2P@'/+JblKʕ2P@" 7b0J{zu.P@.bPJʕ'P@A/bTM%P@wcbB <%P@gb>&P@~'|b{Oj)P@2b :St/P@[v3bTHG!2P@Vţb(t3P@Vţbn4P@WFbHN6P@ brb"78P@Ljb$̱J9P@lhѩbUO:P@kvbU/:P@PVb8P@Zغb4P@b9B5P@LTb\ ;P@"bbi=>P@!~bLG>P@7$Pbʵ?8bN9P@TDJGbl9P@CQCb=P@b̅"?P@ 3kbLJAP@4b C%BP@b AP@bBmAP@GDPbfKvEP@-Wab, HP@e!c"JP@PeG^TM@D?%aQKhCPGeG^TM@D?%PֳbKML]-T%xvnAM8 %3M@lo$ٶd(MX$lMb\ $0/y8M࡞g#x5 M`7#r~-M"6"[AMsΜ"XWMM&"`RM*Z]"XRT6QM.ib#" QLM`Za !IAMvT!J1M` :!H-M{a!m/w6MY@U!X6Mj !`^ 4-M@1 ~*M@5= sPA-Me窟`lMJ*MxQ2!MZTMxLpʤMb/XyM#2nM}U\OM֦ H\:MLQg1M 18+L:Mc,$@7M@2 p/MeH8J_^"MM 5˭|M+8B LM畧LbE( fL@<z,LSaL'2H41LUkGh>LWd`vXnL@N1/jL)P H|L1p6 U~rL5 =} iL!<`_L0=rЃ2WLQnzbOPL!@GL@y+?ԡQU@ eD@dDzUDU@pщD@֣1MU@.fD@, ZU@(Р}D@la}gU@ D@LvU@ #D@GlU@ D@8aC݋U@ WmlRD@/_mnU@GDŽD@`_)U@RiD@'WU@(mlÌD@tlaU@HהD@ U@xϨmD@~@hȗU@wCD@ pU@g2D@dU@g{D@,aU@P̘6D@,U@AD@$N6mU@X`D@/̍U@D@d}U@,ŹD@hkxU@LD@tU@O{D@8SrU@<D@*LrU@`jXD@DE¶ uU@`xtD@LxU@\&fD@M~U@ƵMSD@ guU@y58D@ U@@LdD@T 5U@amJD@.ҀU@͚eD@@.1\U@g2D@dOU@pO>BD@ p7U@JJD@,xVa@© 0c;ra@6<& 0c;ra@© h]>'~a@f 6?ya@iLk 8ua@<9s: Wera@- p@ pa@U ԔLoa@Y XZLma@F1 Lla@3 ` 01źja@ F8fa@]w4 l@ca@D9 %U@5kqO@BzT5U@wC{O@|OU@MՉO@b`U@(1O@(LxgU@æO@fU@ S O@dM_m^U@0 O@m1XU@"O@p:UU@^ټO@XdKU@(oO@ (=U@0KJO@}3U@0mLO@DCX3C/U@ gO@Zl(U@qO@U@jjoO@f'U@7\T@1%P@C;_T@yT&P@2aT@U)P@lcabT@ER%+P@ aT@p=p7,P@jZaaT@,3,P@`Z]cT@,3,P@tշ@bT@D~.P@s ^T@<2P@A ]T@$(6P@oaT@+c8P@ȂaT@\0(:P@b]T@Cx;P@#[T@-_>P@#[T@T\uCP@TmaT@0.GP@"N\RnT@NZ2IP@-wxT@LVPLP@0X3T@ևPP@sT@< SP@d:eT@~"VP@oT@䉏WP@,T@KXP@e'XT@ZP@lMWT@|:S^P@$d櫂T@#KB_P@D8[PTT@"m^P@섬T@803^P@' T@L~_P@l,QyۇT@􌼡aP@}_FT@5cP@\T@& iP@DT@lP@ T@ ]pP@ssbT@h,%tP@LفyT@H(LxP@s¶֑T@X:|P@4xT@@dP@T@fɏP@8T@7P@`kT@HP@(~T@lJP@YҐT@XRP@5T@aqP@T@l+P@,?T@ǐT@{zP@iįT@H=:SP@BT@L([P@ߑyT@ !P@SaT@|P@ݞ[BT@gqP@!sm.T@4RP@hI%T@P:P@7"T@z0|P@ȶ1T#T@4P@SfYT@܎NP@ر HT@<蚓P@ĝjBUq+bA@͗;U MaA@ԍ:UlA@tjgVhwA@d*5 V҈ԊA@V\A@\y*V7A@lkB V4A@d;E VЯѭA@ VkA@ï0 V荮ʮA@6'VHEWA@d0V0pMA@EU[[A@h0U%V *ぷA@'VnlqA@#!UW`A@.0UN)A@4FVA@nߨV4A@hVU0A@\ ]U~}iA@lUУA@$32 TdU`A@XU%A@R7U"k.A@)۞U/iA@>U0LJCA@."UZxCA@*I&UXIA@|Q(UpօA@)U@A@( ,UxaA@VT1U~ƒA@<s4U'qxA@x>.7UP((A@\+]8UP$A@4-9U8xtA@ۿ);U5A@LD=UjA@u\@U(oA@mEUບeA@ KULA@JCRU@2ΘA@|1VU^A@HTuwWU;\!A@ YU}XA@*#[U[A@ ?s]U 'q YA@OZ `U nlTA@΋cUKA@DU&hUFTAA@ kU z?A@OZrlUH{A@HguU&KJfA@PWUCA@ӒU@X3A@<)U CO6A@`EU@o0b-=A@M DU`MIGA@0UeKA@ECUבIA@\=c!VȌB@(/VzPB@TO9``=+M@1f`p#N@ 1f`nl"M@˩l``=+M@ykp`(ߩM@Qi v`@M@ԡW[y` M@v.g{`PKƖM@Hd}`'MM@>,I`P=֊M@gw `hҵM@L/է`xH^j9N@ht19``#*(bN@+*`h7N@>[`ѵN@2`(p ,N@TO9`p#N@ h,X.:I@8m+?GI@!h,A;9I@wVL@I@&W0vI@{4"nI@BHK6I@]gI@^{I@4Mr JI@;쿐99tI@599I@FWPp#I@tᬘXYOI@kHwCI@l2 C3I@}QwC?I@d࿈z6I@n\ۿX.:I@>׿\[I@geԿMI@Կ(4I@@r˭WϿ`RhI@ b/I@4¶?x BsI@8m+?e}4O@G~SZ(.28O@آl1Z6:O@X{;%Z`ߩD>O@"Ze@O@lА1#ZS%BO@.VD&Z8 FO@XʮF+ZHi:IO@.ZhgKO@H#t0Zб]gMO@m/ZoOO@œ/Z?-ITO@0Z0TWO@3pe1ZHG0bZO@Oژ/ZyzO]O@-0Z@t`{aO@ Zd4ZFngO@D3Z(𱰏nO@)1U41ZX7sO@s 1Z|EwO@XSVH4ZZWyO@ |S6Zo}O@4#Y5Z&O@ꂍ*-ZHRO@Tś+Zpt O@М*'ZH][O@"QZ܌O@g:ZWYO@g! Z^kO@T_ZdWyO@YZx@O@4r Z@^O@K5ZO@XYf2O@LY,EP@ ďY]"S P@8)/KY"P@TȲ#YI4P@xyYxLtCP@ԽYP@dܤYNQP@xFYt1P@8b1Yܴ3 P@0Yȁg P@4clY㮭 P@0Rk*Y$" P@ohLY)P@Zu@zY TP@rآsYh RP@P;^W`Z&P@|L}qW8W+O@iW QO@DԅQbY|~P@d#2Y&P@p؆FX4q0P@( Ē.Xh1,P@~9#%XmF)P@8K"X,K'P@t: Xkm#P@4' DXSP@ pX$3P@PAKX|JP@84R30E@Ц]>@P:}G@XvB@d4R30E@XvB@ €7E@H<~B@xU;E@@ {B@0I.>E@8q{zB@=~1AE@py:gxB@AE@8zopB@GE@QﺎjB@NF[E@hsdB@paE@耩`B@ؒ!cE@>$]B@hbaE@8[@pl'mE@X?@ZB@LrE@h&|XB@m]sE@hTB@zkqE@@ERB@`1lE@zLnRB@ $AgE@0OMB@MLbE@H0bEB@8F_lE@Pe?=B@X҈E@Z6B@NE@"*B@0XuE@ KB@7ӈE@x B@P"jTE@*5A@0E@`,A@ kE@ mzA@hE@8A@~E@6A@2*{OE@GA@&\E@ZRA@(wɟE@/bA@@pE@;9#A@`KE@`AI-}A@jE@ȞeA@ps\E@ ʀA@ NoE@4zA@"pE@rAjA@uE@^PA@&DoE@9A@p#BE@PS]&A@~VE@Ј A@.E@JA@ E@= A@UF@8e A@hNF@PfA@V *F@nA@ L3F@ @@P`#A6F@^`@@@gu3F@x\[@@H^3F@((k@@PX5F@HP@@X*{33F@06u2@@Eӈ,F@͡@@(F@p<^@@ш'F@@@Hv)F@v@@16.F@@e@@12F@P @@h>2$7F@ީ1@@p=F@@@h0DEF@@@@(ѽYVF@q@@ h|oF@mv@@`8}F@:耏q@@%gF@"nr@@IpKF@s0p@@IpKF@Ecm@@0Ȇ F@h>Vj@@-F@ڵMf@@wޑF@0/ d@@(-ŜF@~}c@@H2NF@`& 5`@@PbdF@h KJY[@@2F@nDT@@pF@@M@@0bl"F@茪v"G@@ aKF@@m+H@@@x6G@`0O@@{G@͘P@@FcG@е4K@@Zp+G@h}RE@@HG@F?@@uXG@E8@@Xl ~]G@s1@@@^G@Yd&)@@hhZG@[\[@@ØuYG@h@@҈7[G@0V @@`G@& Z@@piG@x)4 @@ȂqG@(R@@MxG@ #?@=G@@N.?@(7Q:׋G@Y~?@@G@Pd?@6G@Pa^'޿?@CCG@?@ptG@E܋u?@G@:I?@P:}G@Ц]>@`&`4@hTF@І]0N4@ec!G@@3-4@ec!G@zC4@W ;G@34@P}% G@ЬI4@vG@,4@йf2 G@,4@hxC<G@`&`4@YiG@Hz4@ G@iۮ4@H :9F@C4@^F@W)$4@pF@c4@桟F@`4@vF@"#4@hSZF@o~"4@`F@+ 4@f2F@4@@c-F@@ 4@=F@4@`lF@f$04@H:ֽF@`lA 94@x'-F@.x54@F@NP%;4@4^F@@=J4@EF@І]0N4@P𺡘F@LOEH4@hTF@`~4@ec!G@~V8@5H@;톌X5@h#o^H@x.5@X.H@04~5@/G@ ,5@ G@U$4@XPG@#4@)KG@0,"hf4@TG@0no4@3G@ m4@xCG@Pi"t`4@#բG@mfTN4@G@64@`5G@D,4@X_?G@ 8qS04@ DiG@ W74@@f2΄G@N[0,14@dxCDG@Ћ'4@8`c}G@`丼$4@,!xG@`ؽ4@!tG@`~4@xOgoG@@Xi4@ #gG@е.7f*4@0g][\G@R 14@`SG@LO(4@jK@$R2tlP@pK@p3kP@0FK@mapP@0mf~L@>]{P@h L@hJE~P@(-@wL@1}P@R pL@49P@H# L@jݞ׋P@nlo'L@iP@@5tZ.L@LCP@11L@4ϑP@n_6L@ԫIP@ȑ=L@{ROP@(ꡟDL@iP@+IL@ۑ P@*(PL@fe'P@`ZL@kP@`X bL@L[PP@жzhL@FɝP@p lL@xIlaP@xnl`nL@pϪP@Л0qL@SP@Xd,ESuL@ GP@Pv {L@+sǨP@RSL@lw+®P@@L@DȻP@H9L@xwP@/bʗL@>ΩP@xFL@'pbP@x][L@MP@L@<ˏP@pܣL@|?FP@͘L@CP@ML@)ݞP@Bt^L@ _P@H1EL@@:_m"P@UL@H 52P@oL@kP@SL@>P@x0bL@Hz@P@=^L@| uP@Zߩ6L@l1/OP@`FHL@dbZP@3RL@DGqP@XL@@laP@o][L@lDRP@/BsL@ځ P@PBq cL@I-P@ç٣L@P@HbbL@WkQ@"L@^=Q@0bL@UQ@`RL@ 5Q@PYM@(TQ@逰M@x5 Q@`-M@ peH;=/ҲGR[8~w@rlH;=/إH (;/ȧ# H>s/|$HM',\D/)bH sM.ԗzH@9Bwj.@.H`a{.`*H -~TT.̸Hc63<.p4H`q .rKH2-hߊ͓H  ~-ȧL!H]8n-L/HA-0݊~H8,.HJ/,x0$ׁH@t,Hs ,P~vX|HV|,3 8eH ob63@,/I[HI8,4SH2K,фLH sN,x\EHop(B,zn/1H Y_+xa+H`+,H5~+ )H+@e"Hi&+p(=H`[+_H`(+iHIa+T H`(.+(鲷H`zc+P/2Hp~,*o_H1F*!Hc84*P=id*Hhp )8e$Hi=)XQ~H#) H[(H!!H@o (+"H9(̻ HϬ(`P'H`s_(дՄ5Hru(p`CH_E(y'=RH(E'`nRHQ'NLHG[&j?AHR2&Ȫx>Ht&P98EH@JNv8&MbFCH!&%_ 8H %9N]5Hv%FG9H]z3,%p-k :H`/$(=7Hy4$3HmG$?i-H*[!$`,H`0~$سb.HO@#0gl.H`#B%g+H=ipP#JY,HbD#w݈1H6^#hr;2HD[#8y0H@"5 I'Hma"XH/fi!@UEHoq!#H 6!"'HW7 !iՄ H9KN ]eEG@-VdG@*Hs UGbH WOGYl&geG:G@y$GD*6@H^/L |5HPap!( $HXQ`;c0HCS畤:H61vXCHRF2IH@_i'󩋵PHp MRx\Hk`HҒEH2$K `H+HZzpeH$(~Hli`@HR[8 ǕU@MJ@4YqV@1btL@Q4YqV@@ J@DYV@MJ@TJKV@G fJ@8K EV@ѽJ@oBV@0q 0J@UJ?n>V@z}J@/W:V@xJ@H/V@J@*(V@U!+J@ĀT9V@J@CDV@ѧYJ@CdV@X<7J@8YXU@wڌJ@ƟrU@wnJ@(wU@ jwJ@dU@ `wéJ@*GU@YJ@@?sU@@jM/J@s-U@`"1J@4eU@^J@M{U@A<K@`sU@z K@8[_U@tK@Pp~U@K@9U@?@$K@_U@`+K@TGU@9 3K@ =f'U@X/VIK@maU@ sBQK@ U@ho)WK@ U@o[K@\Y=qU@(wC_K@@NJU@MjK@ȭCU@QmK@;GU@`m rK@]f'U@(`xK@P#-U@0.1K@L21U@HOXK@(p;U@8VK@ GU@W!K@XB ʭU@K@E,:U@X #?K@U@)K@n U@( K@Ͱ%U@K$2K@U@xCK@iQ?U@F`K@S>U@: K@ltLM=U@^`MK@ԣ1Qy2U@=LL@s@-U@^TL@8JZ*U@Xe7`L@s:&U@pEZgL@dͺ{!U@j~}hL@xYlPU@m:WlL@ ǕU@1btL@ (?W@č?@*X@KJ^A@A(?W@ A@Z FW@@sA@sJ?PW@)(vA@#aW@zA@HkF8mW@DA@4kuW@X}W)A@sCW@p)@A@Q!W@03HA@0J?ʍW@`JA@xbW@t;9|PA@T iW@X\A@1 IW@KJ^A@;`W@MRXA@C)W@ OA@=KW@BDA@l>6W@6g4>A@`sGW@ 3>A@d}W@@_q8A@L,(W@k-A@䡒 W@ɈT%A@sf'W@/b A@@h"W@H$^A@<FW@_MA@q[PrW@hBA@DW@j _@@2xX@el@@ X@#h@@X X@X.@@ X@r@@H]d;X@0یy@@8*X@x>@@<;X@ē@@n X@HvA@@ؓ6X@R@@X@ @@Ƌ!X@pNH@@f,/)X@P]w@@!(,X@c@@瀏-X@t(@@ o=.X@i@@$^m0X@H@@LT1X@0\[@@8t2X@~)(ϰ@@ 3X@H(u@@񰥓4X@W@@7X@ @@ăځ=X@'MϪ@@t@X@g2@@̍(BAX@ĖȄ@@|5lEX@`Qc@@TX[P7MX@Ue@@@HlaRX@pov@@p-UX@SKs@@.3XX@~}l@@% nZX@_@@igX@\cN@@dX@`8@@w/WbX@a3*@@8؍X@`.#@@*|͑X@ v{@@9.@X@سG@@@$iĉX@u?@J?X@p,"?@`[PX@0-\'M?@*X@č?@x`Nf'q_@GǐR@80@`@D*QR@ 2t`_@GǐR@`Nf'q_@f R@e0_@HWt@&R@A_@\u+R@RD_@dU0R@XI_@D 4R@ i_@XXy9R@_@ lc/e>R@__@5x] BR@(`B_@UfDR@F_@DnHR@80@`@D*QR@$t{4@"hi p:8@:wȿ.v18@"hi p:8@ Q@u{:8@W~7 8@QMp8@`'PŢoc8@s?u^8@$pfVE8@o)y@?Hm8@* (Xej7@ fAP`ͤ7@rK'`7@ߒohnA7@ظM#7@2*M\0*7@ 4h^N|7@ڭSa󿐧|*7@V 6@QCL26@\\Um6@BHM6@2vO5Ԑ6@ 77u6@L.dje6@f! n&`6@k60eE6@"/`?6@sῠ@t{5@,F߿0٫Kܮ5@ܿ5@P_ؿ](5@ C^׿ '3 5@%YؿPky5@Jw׿d5@46QԿ3M5@_"<ҿW?@45@\\;ӿU 5@;ҿ`C}5@:Ͽ|QY5@l@Zп?5@ϿO4@74ʿ`&i4@:wȿ`:d4@Iv8ɿ{fJ4@_0y̿0,)4@9׽7ѿ$t{4@G{ҿ(T +}LA@P DT8xCZA@T8xCZA@P DT +}LA@X_@GǐR@` _@oUR@ 2t`_@GǐR@`_@1x]R@p'͓_@#R@X_@o׉k!R@Qy_@쮅Qu%R@9 ޓ_@!3+R@T_@ڦ /R@3%|_@c/1R@bQΗ_@Qqk4R@7V)4Y1hR+)gmRh6+J)lVsRa@N) |mzRԠ@(ԔR`3N+V(` R@jӹ(h߼:KRC!'ߜR0zo'(XR̲Q&?R`4&> rRe6 `&VRXN&jnR2O&A~R Dc`&pg}vR`*F& pR&GnR`bT&DYPmR`c&gpRT¨&7qRb6'%*pRJ-%qɌR@#3rҏR@ F"0(R9"Ro!m"MR"X#Rm"?JBR|"p)[R-f"0RZ5Fb"eRX_WG"$AѨR 9:"XQdR@k w-"Y1R'~";lPRP"nR2f"4wRC!dRT%w!R`h=!ݓ(R@ #!#OR@V˜*!R !̊G:RR߭~ R`O$ R#צS9 7ZRl._R@D4mRk YR%E!ER_/D~hVqR`;  Rm-6vl?R2YXh1R@ vX~RER ,6R'l9x6LR@ 7|R]uL6RxQ`mR@cdR@ ̓2R&3RU RhVP1UR@st;,R@cSRh!XNdueR+3|4҂ RR$Y]7Rvm[pmRY 7|RU}$dϨLhR@wY-8aR@&| R_R@`,;Ry|O~R=pPOZERW!(lgJeRKm0$.Rr&R.g4[R@4pM"+RI@mbR@! MĖظRQ!4(4RER@B4RLHXNL}R 4wjR@=sz^KeR@xWspR-psgiR\̊8dʛRȝ*XRCOeRH R> (jR@CtR@ pBR@Cd-R@"2pX RLR6pigSR@!hPDR*8 9t>Rt!TRw oR@20|4R@l݋У;,R%\2R(;Rܦ{ZR@XC“8 SwR#dia~TWӆR29a8R= 8YR `~R5"R`h! 1UR#$%}̹R<ǡ}Rl@ayRb:좨UtR!{ӇqRw=VpR9\/D4^oR@ _`mR@,0|F!mR@?s{SNnR@=(OlRv)8VThR,  fR44@dR[ cR@تОcR@ڞMbRƕ2lL&a_R(86muYS_Rl3&_`R `RMe ǂE_RO[Ո)F2@F46 @:<@O@_:<@3 @:m<@ - @`(Y<@& 3 @v,CJ<@6V9 @8=<@0 @ 1<@nOߎ @Z)$<@` @<@zq @Php;@r4 @MH;@@o[ @`@H';@Jx& @SY\;@ % @<^n;@ lՑ @@9O;@nOm@1>:;@ۿ@`>l/;@SXx@Gf+;@YbO@`L'.;@Bb @Q>B';@v` @SU;@qw74Y @y? ;@D! @;@4H @m:@G @xf:@s& @03_:@ G @+:@| @0=CH:@q @>R:@'@@S:@§@ ~R:@1 Ԁ @iO:@zá@IDU:@[@PY<:@zE;p @@g(:@W_Y @=.:@(n @~9@t @0 s{9@ʺh @@C9@T>@ @pH9@~j @`C 9@[LW @P3<9@_ȝ @{&`r9@˶t @MO9@`PP @kAm9@cÑ1 @0) P9@S? @0%c99@# @t*9@n` @ h<9@AR @]9@F46 @P%`8@V @%8@ti @ }R8@-j @`mA8@g E @#v8@]C @٘:F8@ Aʳ4 @u8@!Yf @"i7@ @Pl"7@ׇ @P{ə7@2@F~7@)@ Wj7@t>@0jL7@Y_@o37@ ]; @* 7@]&@ٔ6@t@t{6@ՌE@pfl6@k).@`|5@@0qݯ5@?j% @`h/75@@`@SƦY5@ZR{>@󧮵D5@3J@Vt:5@Pĸx5@pJ$ 5@@)T@SY4@P@PSY4@@b~4@q@@|ߎ4@@ f|4@DU*@@ajd4@@yt@94@olQ@P4@emb@ f3@cJ @}է{3@ukx[@&3@@HN{N|@Э>3@O@RR3@rH@BH3@@ٱ ͐@PiX2@r@&[0.2@@Ϗȇ@Pw2@}^b@Ո)F2@7f@>2@@Rkw@*q;2@^@@Ø2@ޕHm @*8I@.xG@x,M@xBK@~CFcPM@A I@~rPM@0F5I@(mcTM@U!I@@r\|\M@دI@&M`M@8YaI@8,{>_M@eB[I@0=7[M@<ȤI@CGTM@5I@Z,xCM@/$ÙI@(DZ)M@@WI@(q,M@.I@I1M@ߩEI@%M@EЈI@ML@n CI@&L@.I@,ΟL@78I@0tL@#8I@ppI@ P:L@rI@=L@B^\I@H YDK@87-I@wK@0{I@<%dK@RߩI@pZFcJK@U!I@&SK@"RI@0fK@@ی}I@` fJ@jI@8vJ@mvI@8^J@0ـI@肒ǬJ@h~I@(z^J@ &I@0wJ@c[I@CƉsJ@؎ĻI@X_iJ@@NI@Ec3]J@ WÿI@,|3PJ@#I@EcFJ@xÌI@AJ@I@p6J@ I@%&J@ )5zI@`mJ@jߵI@اJ@pf*I@ d*{iJ@(r I@@'ފJ@-H I@Ec~I@wq dI@ @ DI@I@*fI@XߩI@p,Q:I@8H9I@8I@I@޺=I@ ̢I@0e耨I@ȟI@ KI@H䡟sI@*{]I@k*(iI@g봙I@86TaI@7I@SRZI@(L/I@@i TI@PѬgI@z#LI@x+IƓI@99BI@h(I@HÂ;=I@ I@WU!:I@>)ڎI@@7I@pI@(Q3I@XQѐI@P&.I@8I@nl'I@ ~I@]zb I@x YiI@_QI@@CI@I@DZI@I@ I@=VFH@X mI@ H@ ?I@O H@nGFI@peKJH@(IɆI@ )H@<cI@-\[H@UI@{H@=I@NH@๳`I@W=H@puI@J7wH@0^I@!ΘyH@0sFc1I@p+H@WI@*ųH@(DpI@(H@HWtI@GH@hr\jI@kH@8I@?icH@Pf#I@?45H@x~6I@(T=5H@Ts\PI@h>4QH@EpI@8.H@I@Y>H@xI@h8)(H@`j8I@vH@ KI@`wDrH@hlI@*.oH@(5R I@PK^hH@h I@ OH@p,FI@0:JH@p܆ tI@EGH@(^I@سFH@I@AH@ؘI@E;H@8}3I@x_z8H@*w#I@N6H@lDI@軋3H@I@]wCa1H@I@3i/H@0EcYI@H/b(H@(N%I@-TH@(pI@x`\[1H@awI@8#nH@0ԡ~I@@8IH@fjI@XBQH@h;;iJ@9uB0;|I7sJsɗ4-;|-yJZ58-;DJ 48);\ǐJ-#;JoP$;zDJT';+)JEP#;ȡOJ`E&;@*Jʋs,;(AഡJ 48);6xJ^!;ʥJ';8S}J*;١J;XgoJ-n;@鱾J";@&J`,;LJ@|L2; J-a5;P!lJ`D;Q3;BքJ);a+;J /R(;6sJyE&*;zJy';0MJ]C);=#K:uBg>;PQF‘Ky|PF;FKpE@;HCEK;#J;ЫnL!Ka;])K`tjl;g[9K)Ir;Hx=K ]u;^ GK-aBt;QNK:(z;8:UKP}ˆ;஛ \K`;(6wcK`S;@/jK@GI;H|CpK#h;sK$';tK@b;@$ZzKD;NK:>r; UՈK ; v,K;@[pK;H~2Kak;>ZK;@ItKǮ

*,Lp/#>!L#:>xжPLpI1K>`|:L*Pkb>̳beL0oS~>@[L84O>ՄL0D>۾L@W]>X˕]Lpd>zrL7q>C UL9>^LEI?PF(L`ZWZ?dXLp2?s,dLprL?<fGM4j?4CM~?-w<Mjkˈ?"vLm?DܾL*)ߞ?8FBM *X?(kMp4?D M@8?gpMg?8Z2M0ћ?Y<M#?0!M@zMH<@`+Mc@(TMp@EM94)@@Mc_<@\慪r-W0d0@h0կV@i02@H7Bh0կV0d0@J&V@)Zp0@L٤VmCw0@p`𭔨V4˾0@$k™V9+0@I|V6FG0@h9V~0@ `sV`(0@8(V@^10@J XV@I1@\>mVph$31@VU<1@8qV WC1@XVaI1@LVP1@xyVuY1@oV*ib1@'Vzk1@`DV eTu1@@@V4{1@ A͸V,|1@xVzk˃1@cVPvM1@tIV#Ӗ1@uV!,1@*lVPC?q1@p=x6,V1@geV 1@XǑV o1@yLV oZ1@&V1X1@+Vrr1@j7V TFE1@kV@5//1@\XV8h31@AfJV1@tV0 61@*d9Vt1@(OVǕ1@Vp1@+Vp5k1@ Va1@ 1V5hE1@VV@x1@|#aV(1@\cVPxҩ1@ 4\V`;F1@ )[V.1@(bWнSM1@W`<2@c WԞ2@x); W-2@ W@Iy02@# W2.X42@# W2.X42@zWw ocA2@,!sWKQ2@L$WkU2@ܿ'W eaO2@_*[)WPEU2@'*WPWu5n2@PO-+W {2@@m+WQP2@n_ ,W@E2@慪r-Wp82@# W2.X42@LW sLO\2@|W`5m2@WWiw2@{E W oՇ2@ԃ&>W@i02@PԧǠ7@0tB=0K5>@q&b:V:EQ9@7E"; )]9@pn;=&99@@gL;}R 9@a];`^08@|V<DF8@@r<#)8@ 4 &^ɔ<]8@`a<`:78@p=^׍< >w8@؉<oAl8@0?9 8@V5<`]7@p<`$&7@A H@q&b:0K5>@z:9/720>@Z:p~ >@psB{: J07=@p:pUw=@P8n:0.Ee=@:v5y=@`:Јu=@06#:\5j=@@ʃ:pOV=@]':YGD=@0NL:0\06=@-e:py'=@pzV;.=@p6 ;=@-I ;x<@~; 0,<@j;@ x<@ -#(;T:<@񝞲;<@@R[:&U<@:'<@0 ?R::v<@0k;@<@u ;Cއ<@C ;{"<@};;c~<@@vr: DXଌ5@D#X Lw5@07XێZ5@(Y]X w5@BE/X['$5@0WX5@BfX;A?I5@,|SX Jy*5@uXpT5@ X%5@e3XM5@0Xߚ5@(i&X5@ ͐X 5@XX V5@N46X 5@0DXu 5@c:\X95@`X >-5@@?V@3qsI@6W@P M@T+6W@@QI@tpiD~W@f7UI@?]iW@3qsI@ =1W@XaI@)XaW@I@ W@P@I@laAW@pI@l7aW@xىJ@`VU0J@\!W@7J@$sW@xM?J@f%W@*XHJ@ W@)?\LJ@4,zCV@֒+LJ@ 3V@ ^NJ@V@HV!TJ@!cV@ IV!VJ@lRRV@PDTJ@\) V@P3RVJ@@?V@7'V[J@*3V@(PeJ@F/V@DiBvJ@("u V@`˲}J@V@xCJ@X%V@ٚeJ@(V@`euJ@4^kV@ZJ@fݞV@1J@T_nV@YzbJ@G 4V@P.^J@qV@J@ %V@PqJ@` J@]W@H1nL@[P!ZW@XL@(sVW@AL@ NW@qSoL@, ¶ZJW@L@+rIW@d L@\i;W@xvxL@#s!W@(^K@@ޜw/W@h"K@JW@DK@|@hKW@iHK@#W@v=K@s;W@PEoK@LlaW@͘7K@Z=˷W@h:|K@<$W@^fK@`͢]?@]0|g?@@Y@Qr@@?gp@@Y,?k"ڊ@@X?@@]0|g?`<@@H.?E@@(zY?`͢]?@7@um*c?@T@*?@˖@Pa?@Y@J+ @@@ȱ@@EpM@Л @@7dxK@(%%@@\m@P *@@"@D_,@@jח @|3,@@-hΝ?jv$@@G?8@@Rm? ek"W @@F^|-? ek"W @@C=ע?(@@LD p?ȱ@@I?rl Y@W=N@@_@o P@@_@P@1i_@0|9P@4 ֓_@ P@pD_@*NP@las_@8=gO@H*]_@nlHO@$]G_@ΘjO@la2_@ ީO@hmG"'_@Xi5O@13tR&_@SP@Hd_@Ŀ=IP@|_d^@PP@(e^@;O@ K?D^@"O@L^@O@Rצ^@P>qO@0@hƆ^@O@J?r^@X߸ O@ǎ/k^@p ]O@Qb 2`^@(cO@G"Q^@pMO@^I^@hO@PtE^@-O@땽|A^@7O@8^=^@̘O@x7^@i^O@/W1^@r)(GO@X0%*^@8.O@8G"^@΁tO@s^@V!+O@ Ry^@W O@XW^@(x{O@( 5^@,'O@h!]@MerO@໕l]@O@F]@x砟O@w]@@fO@pS/W]@F" O@`Jp4]@0 ݨO@dV]@zO@@%;`]@v"O@H ]@8o}O@]@@¡O@G"/q]@(/=O@Pi]@`O@Гzb]@P>SO@Yby^]@KΘjsO@0F@]]@`zthO@\-_]@0:[dO@H^]@8js`O@k¶\]@hib\O@Z]@HLJTO@xv8Z]@0>NIO@P6(]]@HzBO@8BN܇a]@LJ>O@0|ic]@8^1b8O@a]@|0O@ޣ1d]@U5'O@hTmk]@~$&O@dm]@ ߩO@hj]@P O@(g]@h5 O@HM܁d]@m O@Lda]@D O@ZC^]@H\O@ب VX]@@dN@!cO]@xY>N@x{@hB]@W=N@W2]@x/bN@`r8#]@N@Qh]@9O@P/ ]@~-X O@hp ]@|"XO@ z]@_O@ ]@HjO@uFu]@0ѻ&O@8Sj\@8d-O@G*\@5O@xk\@d;O@xk\@p @O@ݞ\@'GO@0l[P\@nU!JO@$)\@0_F)JO@P=˞\@KJKO@/%A\@nOO@If'\@.SO@r\@@@^YO@\@}^O@p@h,\@WcO@{J?\@/fO@(si\@xbhO@ \@lO@ G"q\@@tO@z\@\[yO@`+N\@8}O@)\@6O@jI\@^ߩO@ \@xvO@!\@P%O@(0N^\@W+O@Γ\@QzO@(K\@@+{`ׅO@_Ҩ\@HިY"O@0bh\@wCO@J?|\@8bj O@8M\@JV!O@h٩\@PStO@Pi\@ /h2O@ {;\@xCO@0+N\}\@ܝїO@I=\@wCO@(q\@jO@,({\@_O@ z\@ +VO@`Rsv\@o4/O@wp\@q nO@ph\@Pt{O@ `\@PZO@pI_\@>*(\O@x\̍]\@ۻ҇O@V66X\@HGO@ҴBV\@`j)O@@AW\@kczO@~W\@`3:9zO@ }rX\@XvwO@P=˨[\@`sO@8T[\@@̾oO@SX\@_gkO@p ~U\@-jO@@k@R\@UkO@PhBHP\@X#pO@p8eN\@0b}xO@(9J\@/W1}O@xjNHC\@V~O@q~?\@ xCO@X>\@0eO@Z<;\@(duO@Q!5\@k O@Hr2\@O@31\@,}O@X-\@zO@Q1\@̘O@l Y@6ԝP@$zUY@o P@G"=Y@XP@<܎Y@w{P@Z@,jsP@|K*Z@)nP@ d$Z@ 1kP@,O3Z@11giP@e'C>Z@hޙiP@tIZ@ 4kP@@VZ@,b oP@&=˨_Z@}:SpP@laeZ@2oP@J?mZ@kP@0"X_vZ@5eP@zZ@PnF`P@P 5zZ@ S ^P@{Z@ ׉[P@@X}Z@ ZP@ MSZ@ w[P@3Z@\P@%6ҍZ@$)B\P@C0Z@,)[P@ fZ@,=p[P@h *Z@\z:^P@yi Z@HIaP@ĭZ@$cP@L.*ܻZ@ԴtdP@dZ@ʋgP@}9.Z@Ŀ9eP@(Z@[dP@"pZ@-YnbP@D[Z@׉t`P@ Z@"m^P@bZ@KP]P@hZ@8co\P@f'Z@lHY[P@ :f'LZ@ЮȞXP@9Z@\GTP@vz[@RP@M [@l3TP@4N[@ GTP@x{X%[@\DOP@F3([@MP@lU~r([@12gLP@ w8'[@Hf{KP@W3*[@ =IP@!c]1[@]HGP@dΉ8[@8I FP@u9@[@HP@ =*F[@66HP@_)L[@MY+DP@DX"S[@5AP@l=ˬ[[@@ }$?P@TB._[@b"4@xI@@lA14@PCAI@`ؼ4@ j!I@`x4@h+V'I@@5@-)I@@C J5@H{Y1I@ })Z5@`v>I@0>5@`#JI@Q"5@Pdc#XI@ce5@+)@lI@]>5@RI@঩K5@LjI@35@0ީI@p)5@dڤI@A:k5@ڪI@r,5@`rI@85@@1"I@oާ5@ⱰI@Pqc5@ @-I@`5@nz I@L5@0vHbI@R5@8>}I@SYx5@ƸI@Js5@h-I@`xm5@qI@0{%`_5@I I@0F5@8 II@ K=5@?֋I@kAC5@xtI@]$`miF@8<9/H@p0.F@G=#-H@ډNF@>,)H@; G@ڏH@06RG@TH@VtG@HT5G@%G@PJީsG@Pjf%G@!G@`,G@~~}G@#aK.G@hG@p G@4RuG@fG@G@^7G@HG@"dG@B_*G@,lG@xSG@piG@hDZG@Hf4xG@?_G@Ȕ>qG@2%LG@AbmG@6f]G@xcmG@ pG@bG@BƉG@XtMG@zCH@p~.@G@#AG@iWV;G@LuG@ #5G@h?GG@(9Z/G@MG@X G@@)yG@PYXG@SG@F@018bG@}NgF@ G@&F@@+{G@5 F@viG@0F@8oG@H@#PJ@ Mn@H@`J@H҈GH@Q읛uJ@j@H@:c~hJ@p#A*H@Pr{XJ@(A¶H@hj@J@\ L@WcF@T L@p5RyF@gL@H F@}L@䚸ǯF@@dT L@TF@@EM L@UF@/bWL@ЦвF@TlL@gFcF@ xCL@DNF@`"OL@0?҈!F@XL@h;F@sL@`#GF@X xCL@b 4G@~ L@(}ӳG@HAsL@E҈%G@ 흶$L@PB>G@ # +L@ǐWG@YR'L@h6A@&`L@UUA@8AsL@QdA@OL@p+{PnA@%L@`6sA@4!+L@jUtA@jz8/L@htpA@r X1L@h rA@PC45L@axA@i:L@! VzA@лV@L@)}3wA@LJEL@f'A@E JL@" }A@šetNL@xNA@WZL@pA@@lk_L@hшA@XQIaL@hA@ CeL@ ŦA@hjL@@-A@!<*nL@B,DA@ nL@p[jB@APlL@K?)WB@@eFfL@ %i,B@85ީ aL@em/B@,iZL@vD@@L@@!mD@mlIL@~D@PtL@[fD@fȕL@xp-E@HW# L@@~дIE@*-L@hD@L@=9C@pFL@\(C@L@A*C@L@ +C@8hL@hOj0C@HohL@mC@5.L@8ZC@F{M@*&C@+L@0C% 9C@`eL@" e=C@!L@o7C@(>M@hDD?J @?ZOZ@ )u?ZOZ@DD?@h@Zk" ?G4it@|7 ?uB@O?G:+@1|?p.@<Le?@dLm4?q@0ot?@7R@?J @LzV%@ޕM@@7(@ -CN@ H$W&@@_AM@ "nH&@ yCaM@N]{*&@ߗϟM@LzV%@ޕM@T(,f&@0bM@@7[&@P"M@@@&@EFM@B A&@ȷgM@0r^&@[-EM@mg&@aſM@ C#(@ -CN@@7(@ ?N@80;(@]Q4N@Eg (@5"N@X>'@ N@s:'@P1v<N@a 'H'@8^#N@ k '@@gN@BP&@+ N@ K#b&@][SM@`8CP&@ٓM@b <@~IN@0R>>@,KJ"N@ r[z>@~IN@K>@@5\[0KN@Pł>@c*(NN@0R>>@ PN@ <@,KJ"N@`q<@ۼN@@PYD=@ީyN@ `I=@UlN@ U=@Lc[N@дШKG@H3ƤN@+bKK@pީ>AO@N4ХvJ@P͘-N@hJ@-N@%BHJ@#GN@Xl"J@ϠAN@wQJ@HbBN@8J@HDMN@;J@ؿ$N@PDZJ@p^N@`fs\J@@sN@sN@k" J@耥<N@gI@7N@XhhI@8VN@hcͻI@]N@EcI@qnl`N@@)G.I@PN@'@I@ON@܀I@0"N@p?pI@N@fI@AsN@0cI@"͘N@bI@и=N@HHk"aI@`+N@ hYI@xO@iIEI@Xmk1O@[(I@ @O@I@l͘HO@8%I@`~- O@ @)-&I@& O@Jp+I@#RO@m`*I@8`HO@pWt!I@NgXO@8k I@Qr O@H@X-FO@=H@F O@yH@4"j O@#yH@82HO@0bKssH@Ȫ,E O@xwfJH@a@N@93H@7N@(un-H@h6N@8Uu H@˨N@!/H@PwCN@sSלG@8pHZN@X(6IG@ȡN@XLiG@+hN@дШKG@H3ƤN@+bKK@@\Fa.O@IiK@ܫv8O@@fK@PH8O@ :tK@( @;O@_gK@pީ>AO@x&Z]K@@O@VK@#9O@xHK@t5O@3K@o`x6O@S&K@Y2O@//B K@hFe,O@㙔K@R#0&O@,s\K@0UC O@h>)5K@g2O@XJ&K@P3iO@a2K@XN@v$ACK@0N@`DZTK@`N@%gK@@:N@ rK@5N@mCtK@#n N@0sK@ԅN@pK@P!:9N@yK@{N@r=#J@xLeN@ЂJ@P͘-N@H@0*I@]?@oI@]?@WoI@Y@hZ>I@wP3S@0*I@8h@>ֹI@@Dž K@hµMI@@oI@0h_V@B@~(Up oD@C\0sL0U<>V-D@ g)U-D@~(Uc/D@WX.UPީ6D@|z0U("PgL8D@\O&1U =D@Z0Uz#CD@ԭi2UHHD@X8U0IKD@cv@U`}}&SD@ 63IUx6`D@sITUGiD@2ĴX_Up oD@1LkUHhkσnD@Tô&xU`fD@m6U0oaD@Tq$|U_D@\U )(yTD@@TUQ.?D@rBfUin4D@Uf5D@m}U1D@GUo+D@X(΋Up,hD@l/{U` QD@|]U6XD@;Up kC@(UFC@.UPxC@PUU`>C@Dg|ShU`ݪC@F8UٙeC@ttU0C@>IU@QC@UXeJC@t-UeC@n[UѽC@P mUH{C@mU C@^UFC@H/UhVtC@t!UFUgC@0Ul @_C@9r|\UVC@U!5tEC@eqU\[v>C@,U%IU8*C@d-nUmAs%C@D*Ue&C@,CU$C@G|Up;vC@ȨL=U"grC@p*UHșC@XPU4wC@HtbV44C@|4TVtQ C@͹]`UKJn C@hlZ1U(8 C@VP|C@ι]VheC@@XV0.B@l਌VmlB@w7V(%B@h_V"ߩB@`;#V@B@2.e@Лϝ1Cp#m f@8̤B#\1Ee@Лϝ1Ce@xGɁCdSg'e@Fc}C\Te@sf{C\Өe@n"5xCEsf@XCl'f@hrPCEsf@PiН*MC 2f@0LC#ѷ f@lԖHCp#m f@h{bBCF퀮 f@X:?CB}f@X&@CLWf@_`=CrY<f@ȍj76C@f@J3C^e@`&5C We@Xcg2Cte@p0+C, e@8u) #CT7e@xϝCZ!e@Cx Cl;e@xqCe@TJB0JrlXe@4"Bl/pe@e-BzIOe@8R BE8e@ B<e@nBje@HpB8?ge@? B3gVF @;UPe@P>3gVFX8`Le@Fh]Je@h7$FuHe@8U)F-F;He@().Fn Ge@@{H1F:j&Ge@F>FXTIe@0ϝKFp4Z!Oe@i7^F 5bQe@0"eFTe@(njFPK5\e@ة0rFl6_e@hu\tFVb@p V#=b@{|<b@kdAb@'ڨ<b@Q =t4յGb@]a=,.PJb@p V#=b@Щgδ=H_b@o-a\@@? 7@H\\@ᨥ7@ 63\@%7@Hk4\@Ѓō7@H! 9\@Z6@$=\@@<6@ؕ=CB\@uߘ6@ 63\@%7@e:\@D*7@MQyO>\@ l8U 7@ӎA\@p_F6@I E\@v,6@ [PM\@\y6@ǞU\@!6@L/J[@Y {7@[@'r7@s[@ o`7@([@Pu?7@ℬ?[@z7hS)7@S\@7@%V\@,4`$7@pݞ\@!7@x;[\@ C?u7@\@-u7@̍ $\@Pڸ"7@x{k!)\@6E*7@Pf!/\@pL| *7@ 63\@%7@7(0^@0'3E@ؽXs^@+aE@7(0^@0'3E@SC^@H@5E@ 5[V^@X>(E@0a n^@zE@'^@`E@`zb^@iL(ظJ 9+&8@@Jr &bJU`Y&XiJ`V & J@ݭ%>Jٓ/9%1J Ji%Ho5J$6˭#J`?ڛ$<}Jx䎗$i|J?$xcIJi$ې@cJsG$O$x}:J`@0$`ݛxJE˜i$!/wrkJ#f`J#X5naXJ@%#;kYQJ@DSn#[KJ@7CwzA# f`=J 1#(A&J 7=#FB>J`E/U+#0O@J`9x"(4JsΜ"uCgJ@vr"ՄJU0y"8 JtY"xu JI+"| JJ!VJ`MNv!@zJ0fɥ!9p%J}!2+J 9[_WI!04J_S)!Ns@JUr !(*:IJ!E !NuXeNJK p@QQJȜ SDJ #DJgۦ=JJ".jUJw9B q* `JCZy|&jJv!&pJ1HZp4tJDZ,mJ+_p /1cJ@> (\J@•QVJ8G\?\J@~(R{[a[J@5p34 1UJytQJu\ݾ~NJv}}MJD`xly&,Jb XJԁ xmLJd JE4 h^ J|[ *IF݇ ˭=I- ³bI X 畹I'8S nI19{ q;I; nIV;` ʵING Xk˭}I 6I_ I<< x}I_I_(992 ?̭qIF=IdC*HIF•cJrbu4It>PJ }dǼ JeF 9JF!-iWJhOTNf JsSm(J8V ,JLJI>`t^[@ oe7@L/J[@ o47@ t^[@@moh7@ ٌ[@E:7@0_[@ o47@l|Ч[@ ^'s7@$ 5[@e`w7@$[@`h`r7@Tj1[@ oe7@`=ʿ[@]f7@L/J[@Y {7@XPhdT0B@d^VTT@!B@PhdTm B@`>-naT0B@l]T@ B@B@$+T@!B@8aT+B@d^VTT\[B@`6DS@nUI9@#yT@YkH>@ S@YkH>@xxS@ o8׼>@Y%S@:HyT>@tL|S@Pk>@XQJAzS@P1>@شB$tS@Lт>@yiS@at>@X&BdS@г՞#d>@h#|dS@psr=G>@vaS@v3>@2U\S@# >@0ASS@>@bKS@,=@DxFS@Y-=@`6DS@5 =@FS@Ps=@t;FS@{Sx=@ܽ+ FS@;ZMs=@{ES@P ]om=@GS@zSf=@AAIS@`W=@HS@ []0=@۷IS@=@LS@0}<@ĵ#)NS@Sf<@ la8NS@ Zþ<@ $BOS@]<@H1TS@@<@]S@p(Wl<@(BQ_S@`jW_<@W^S@LU<@<6_S@P H<@@^/PaS@j6<@(VaS@ S%<@_S@ o<@0ZS_S@)Jy ;@Xz+NcS@;@ fS@ $;@ bjS@@F;@:RkS@n~I̿;@ԋ~jS@`M1;@d,jS@`J̙;@z 5[lS@`I;@9olS@Oؑ;@ ¶&lS@4@|;@qݞmS@Ww;@pS@=F^;@h\StS@`FN;@PxS@UD;@lizS@OC;@\^E|S@CI;@ĩ}S@2J;@S@"F;@|v8ȀS@>;@T>OS@P.3;@xdaS@ʍ.;@/WS@20.<0;@h!S@@p8*;@D/WvS@:;@8}/WS@`%5;@B밒S@Ar%;@XS@m;@5QS@k:;@doiDS@ 4;;@@1JS@P;@ S@;;@?S@\X:@^|S@Z :@dW3eS@!5:@n͢S@@^'W=:@qS@]:@x>6uS@R:@XAS@P,:@T۱S@_;:@@S@ &:@:@xMܕS@ek':@^xS@:@вS@'o:@ubS@k篲:@D`(S@ o :@XS@ o :@3S@PQ:@6KS@J=n:@H|G"1T@`3x5:@'#T@V8h :@T%T@}M:@А2t=T@-9@2F T@W9@:.LT@g_Ī9@ma!T@\'9@@h9"T@0w&9@t!T@`u9@8?|DT@9@{!T@PO8h 9@[Q(T@)Gy9@ G"-T@f1ѳ9@o~)2T@@..29@6T@;9@+g9T@27h79@Hغ|;T@aZ9@TpT@0I19@<*uU@T@`#q9@_ddAT@ښ9@(4AT@0}I49@RCT@q҇9@uIT@Ћ9@p 5KT@ְ|3w9@e'AKT@@=Nh9@`s-NT@!F^9@?B`TT@p;LX9@e''XT@0nQ9@XIYT@nUI9@J?6^T@ppzK9@p/WAfT@@s`GV9@`\nlT@pYY9@pT@ FFV9@unsT@pbZ9@ X{tT@0]e9@ 75vT@|j9@#yT@0$j9@0;,H\@Нuxv=@Qy^@0群 @@Q')0;,H\@Нuxv=@@bJ\@Hy|=@HW3jM\@=@Ta\@o5=@x.3l\@`;=@ p\@HZQ=@訦w\@@,=@s\@; >@cf'\@p>@P~r*z\@Q 2>@ؼ^x\@`~@?>@s0|\@xF>@5T\@PG>@d\@pe{@>@p\@=T>@v\@%Wt>@X 5h\@>ї>@ W\@ИQP>@dk5\@`@"I>@ȅ_m\@Vq>@P\\@PR >@( 5*\@> >@ѵ\@Pㅐ>@mR\@SPv{>@8t^\@cPl>@@VJ?ѿ\@c>@/;\@оU>@HDO\@_*D>@(\@`lέ:>@\¶D\@"/7>@ݞ\@p;C? >@ؤ; \@*y[=@xU H\@`=@ps\@'=@~,\@g=@|@\@P'W=@@h6\@0Iy=@8 ]@@I=@~p ]@!2.=@h[P ]@eZ=@~p ]@!2.=@~p ]@!2.=@@9]@pqկ=@']@u'=@"]@Nurp=@ȍ &]@`4ˊ>@ 5+]@P>@xz1]@k>@O=K06]@@*>@dP9]@ 5E>@pp2q:]@`eY>@o9]@pL f>@(4>]@E,r>@`>p~XH]@@]}>@iĔM]@бd>@qoM]@}>@5O]@V؊>@IT]@@LIܱ>@hZf]@Pi>@8|dn]@` >@# q]@ca? ?@+v]@|?@0#z]@`?@(}]@0Q+!?@l]@ 3?@'U]@pcaVA?@F[]@pdZJ?@/z]@2W?@%]@P{g?@8R]@@2.?@J]@F'?@hf']@7hT?@89E]@п @@`tU]@!&@@xߵ]@L@@]@ oJ@@HZ']@0群 @@ŜwW]@jO}@@֭z]@Z @@P\wA]@xBM@@Qy^@3]?@H 3R@ϫvA@ v88T@cT;D@Fle'aS@ϫvA@hS@KA@+,kS@=A@;UmS@h݌A@hqeS@@QA@(>9.;fS@Y>CA@4TmS@ 6j B@| lS@iU B@XWeS@@*B@J?`S@xek'B@b"^S@h1B@),VS@007B@KS@WL9B@(/WAS@{Y8B@+¶ 9S@(E3B@dG2S@R1B@+,S@ V2B@G!S@Β7B@QyS@p;B@/WS@xD0bCB@Lg@S@-KB@d6 S@XߩSB@^S@ Y`B@%¶R@JqB@ ,R@ݩqB@@hR@B@p;R@hr +B@ 3R@ӭޢB@bR@`wB@39. R@hȦB@I;aS@0UzB@,d!S@X.B@ S@4BsB@_# S@@B@U}rS@(ߩB@1 S@oB@XM S@(yCB@gS@`B@tXS@0,ŦB@XddS@H B@͇Iw!S@`Y>=B@i"S@=B@:D2&S@ B@@o-S@FB@4fR;S@z`B@pmaNS@#7C@p1/P@+_U@Lu\5z+P@UU@0ȵg &P@bU@=f !P@ZU@fQP@U@P@lU@_[P@`<3U@P@?hU@wP@l?bU@( O@kFU@8FXO@LZU@@޸O@pU6U@gO@_'U@XÆ7O@G"U@(@O@@u U@XT$O@<oU@XO@HںU@O@FU@^KO@̣U@@j~O@X%V@p؋O@tJ?V@lqO@P5V@8`N@lO`V@8cTN@8ZV@ɮlDN@V@:N@؋v8V@HP5N@dT#V@@`0N@\V@hTL'N@ÓV@@FN@D`J?V@pO]N@γV@@TM@ho2V@8bM@TxV@h2.iM@HZV@x.sM@{V@`M@T!QyqV@z&fM@<;TV@FĿM@Lt_9V@(2M@`ѷV@-4M@XKV@HƛM@\uV@zM@@Vk>V@tM@Tjw8eV@VeM@hCNV@HˆM@h LV@(zM@Yf'V@ uM@K0V@80DsM@v1V@<7rM@,sV@e,pM@@CW@8KjM@ iW@H¡eM@$rwV@@`M@hdV@]M@! W@dxZM@xX̍[W@FSM@TW@ @ GM@k|W@ܚ?M@W@}7g=M@xW@h9M@W@J4M@+QwW@;0M@NQW@(%-M@TfW@&)M@~[W@p$M@w>W@YM@^N"W@tM@w+W@ȇM@/Qy?W@P M@<IUZ@k):@0;,H\@Нuxv=@d`b/oNZ@p^8hlV:@IUZ@7Gy=:@>iD7Z@Xi1:@~fZ@k):@J? Z@p*:@#LZ@`P o7:@ثdZ@[:@DŽ7Z@|wn:@ĪZ@P FB|:@dZ@1.:@QZ@@Lc:@DdZ@î:@~̍U[@"V:@@[@`Z:@=b+ [@]':@(t[@՞:@W6?[@Џ:@l X[@ F:@TY[@2:@xb[@:@1~r[$[@p9Т:@EC)[@`4r!:@ 5+[@:@p U-[@[=,:@u/[@lI:@=K0[@ՎZ:@ໟ0[@0m8:@XT2[@['8:@7[@,\'L:@໅=[@Ȓ:@u(D[@寲:@/ZoL[@PE:@,#X[@e"~:@PW\[@PFܿ:@h\[@`HG:@G#[[@ ;@i3\[@/0.t;@ _[@d$;@Cc[@۩Bk;@(1-h[@|F*;@X{j[@"e-;@؜Z1k[@;$;@ Hl[@9| ;@Sm[@#!;@iXo[@&;@*iVp[@ ߼0;@)t[@nFW0;@2NY|[@SP%;@;[@0.0;@X[@S7l;@T>\[@V;@HU)[@P(;@Dc[@7h[;@Xvd#[@2H;@zs[@0 #ı;@ux[@`c!;@^¶1[@j7h;@t~(K[@Pr;@,+ė[@rM;@2[@ 4;@ީ뒑[@}I;@J [@@];@,;[@P8t;@x4ݞ"[@p;@=@9dq[@`>=@d)1![@_<@ [@p<@{@h[@@ Nu=@V\[@X*=@+o[@[<@<@h9\@1.=@[I?\@:%=@%oD\@`=c=@0;,H\@Нuxv=@ *}YΧdfN@\h`c/P@An=?G L`d`N@\h`&еoN@6xU`؍6N@N2F`:9$N@J``3ީqN@>6i`%N@’v(`N@җ`XtN@+`&N@$Qh`RO@?`To<O@`@(O@h5A`$O@zM< aX.O@5A a8][O@D a]1O@MvݎafLP@V}Va`Xk!P@߬qaQ !P@z$גa|H!P@2,Ca4yl#P@墁ŔaDK$P@F?ag$P@h]a`yn%P@>D +aܽf'P@$ݗa9 &(P@zua'P@(^:a@)P@[ܝa,*+P@&Z.a11,P@aAo.P@Laow/P@5!aO1P@45Aa X3P@ЅTa aO5P@ua~k7P@ban =8P@29aF9P@.'Va̸}s:P@>qaK{zYgP@5e\b xiP@.bD_R0nP@Z b\,sP@XbKxP@+wbhzzP@[bRP@Õ EbčP@?bZoP@UbhVP@emV bX,P@4K'bpK[P@n>b.blgP@:bq P@ԖMlHhdHO@gdXmlBN@YlѺgdPXN@)BidYZnN@+Kmldv!N@Ȁ;qd qN@!tdHyN@Ңꢎvd \;N@{&xd mllN@%zdh͘N@1L{diN@]{d5N@|d&' N@Fh~d0^N@x d8N@U0g؀d=N@^ǂdC}N@کمdbwN@-sd oN@ǔdE>N@+d&EN@Ƞd8N@XdJN@h4ݗd dzN@i->dH #N@X ($dx(QON@YVЛdoN@dyN@oPIŗdq N@MldpIN@{dmdx.$N@n-yP@_l1b|TxP@$ hֶb7\u;zP@1^sbTb/xP@Bs buP@EڊbsP@ \}b! rP@!3wbPgXpP@Nxb )rkP@#b$_iP@ܮMbjP@/ѢAbX{zhP@w>HP@7c{]EP@2yeCcR~>P@9"LcPT;P@0QɔRcg;P@'T& [cN9P@WCJdcH}7P@ 4lck2P@.[`jrcG0\0P@_\ xcv0P@wWc .P@AzcU-P@4c +P@qqclU*P@lNc<-,P@tc<6-P@u5aYc|.P@a?eğcTؙR0P@m%c^H2P@/c`m4P@bc Tu4P@q˺ Ncc/5P@[czk6P@cA!7P@g$0:c4/>6P@^cB3P@7J9>ec0/Κ+P@%lq*c 1#)P@?Fc,P@2EcPpP@Yrc|4P@ev(cp/|AP@^c'tP@T}cbxP@i(kc>O@cȠOcՌqcO@olc@z%O@l{cȢ^}O@v(cO@iִUc^O@4cp)ȧO@n\cS~O@\ 4cX +TO@~Cc 'O@űkcؓxO@629cX< G~O@d}5uO@e9dFiO@ed0`O@sRd[O@rdq TO@{sdH JO@2Ad)(BO@,Fd̘YN@OWs=dx][N@:$͔>d}fN@39~>d0N@L@dTYN@^ODdH=օN@K*Gd@-N@cT&KdFRN@}~Nd  SN@Od00N@RTPdhѿO@TퟡSdڣ<N@k4l_Udx*yN@pZVdpc{*N@ ŪWd@/bN@$Zd'هN@ !l\dȨ][SN@o^dRN@|o_`adNg)N@0Y9dd(Ȓ+!N@Ty׆fdN@ԖMlHhdHO@:bq P@9 !:bc/P@m+j:bc/P@:bq P@S`W@-?@v8>@6ŹH/Z@@`(/mkv@@ Ϝ+/ږ@@$bD/Z@@ GʜYs/({U@@@4~/h¢@@`[/%A&@@%0tJ@@`0pe@@py?0XWtMA@y0(wJA@ pf00zDZeA@}}+0hk"lA@E0#ArA@Pbf1Xt}A@SG1h NA@p2A1jA@1(EcFA@z|1ͱA@S1{A@ 1}A@b2A@ڨy2S'UA@ [%2u+{JA@p ?62hW㙁A@dYF2P:B@;y|TV2PUWC8@և&ɇ)S8@`]J&pFU8@Wz&@t{N8@5[HH&ZmA98@7@w3&B &8@s2z@&`(@H7@0Q'& aJ7@J&~ z7@ U0f!&(c7@> '`ڙ:T7@m+'='@v6@ [w':]06@@X%( &u6@/T($`6@vt( BH6@IzJ( k`6@iv )p_>6@@%=a)5Oy6@@U) U6@*) 6@ (\_*`6@TbC*p076@@*,7@G[µ*37@X[*#7@x~B+/7@mMs+o387@K]~+Pfp:7@ >ڻ+Ѓ47@Q +47@ F!+\:7@iN+0wU97@qϜ ",@_"W27@`IB,0ͩK17@@wGn,@ƈ)77@`[ڥ, xs07@^@,x.7x7@ԋ?%-0)7@f6-v6@`%7='.ÓV6@E/a.А,7@czG .pf7@ hT. "7@4 /p` 7@X@/H7qu7@@1LU/U7@`ܺ([y/3l07@#ʬ/еF?7@"\0p턌J7@gΖC0_}7@∌0ީK7@0208@`]#1cj<8@Q)az1–8@7칊1 G8@ GI!1.ejs9@419@@ c1Y,_B9@pC1Js9@Eo\1@쟎9@0R y1 9@p1ƄCe@E%F-F;He@().F(Fe@8U)FuHe@ xFFe@ xFuHe@8U)FQ*ZJq B:M@D2Yv&M@D2YJq B:M@uYH(EM@ЫJYirXM@THdYbM@peYpP$gM@7Y06$jM@pYoM@HʙY@vM@\; Zدg2E}M@luYZ_;9M@B^2Z q M@|O:ZJ5AM@h#$+a(xYviN@V0a|5fN@h@5axdeN@o8a`N@?N:aHWN@$;aHݩMN@^ML:aЌ#BN@a@N@";a`WN@B?<;a{N@ީ^};a M@Ɗv>aݥM@!?a`a|M@݀=aKM@ּ=a(|TM@}?azIM@<9?a@!|M@^q=aSQM@p:ak$M@.":aRnlM@n%3`:aV!MM@.>a0M@h?aog2˹M@Pn@aA2M@WAaPMEM@FEa`^M@wGa((M@|2DPHa g2M@h bHaJ'5M@MVGa BM@^g Fa@M@$QFa`h QFM@S8Ea{`M@EatڙM@Lّ Fa 4AM@ssFauM@2GavNM@+jGaxM@NaHisM@iOa()M@( zPa$P@eEg_pL9P@ FsDe@^w|HGe@TީFue@TީF| ].e@ " FPe@xmF FsDe@RFPk^e@PbFܞ'e@_`FX+`e@P3gFX"PJ6e@AFzle@]6Fܞee@{)kF`e@p"Ge@М G|úe@XnG1Ee@8cI9G8e@^w|HG@YVKR ]@G@q?R\[G@q?R\[G@pVER`GG@X7]IRPB5G@YVKR< G@ 42~JR ]@G@КY yN@ܞXwW@t3P@ 6 "*YwC̮N@@Y]<5N@@.Y_~,N@zY@Ho*N@КYtN@SY yN@UaYAs N@\xvYHeWN@  YH~tN@Kak Y^,N@J{XN&O@EX)A O@LqdX0UC O@K 5XpFu$O@E.X0O@aXMNO@ pWYU.,O@_TY<#,O@j/YP-O@TeS#YK5t-O@(N*%Y4O@l]ֺYFT(O@T/uY BO@EaYXxTO@! 8YNYXvO@VY?"uO@ԃYHqO@H`Y7jO@{ߜ:YwkO*eO@Tr|CYXX#9aO@UThX0+Y}O@ gZgX O@wIdX(NΘO@ {^`]Xq'O@H#!gRXhoO@ DOXʧbO@d}LKXO@hGXO@od`EXH ?O@t>ɇDXX;O@8@XHO@QWoO@?[W&&*O@?[W \=O@̫/[W AsO@PZW\YNO@ܞXwWXd[ P@`W@t3P@"X3{Z@@ɾ#@WZ@ }$@0n6Z@6c$@ lZ@ }$@,&,ΈZ@&$@,&,ΈZ@&$@"X3{Z@_5$@,&,ΈZ@&$@ܖËZ@_$@HfQy6Z@H I}$@MܰZ@@bA$@^Z@`x~$@`la Z@Qk$@dZ@`w;$@0TZ@ "$@|4Z@`)$@ܼZ@v09#@WZ@@ɾ#@(_TY<#,O@x֫jJYQ.O@x֫jJYQ.O@_TY<#,O@V'M&⿔'E@[}E?:F@[}E?'E@1@?MaE@3?E@˕?wC7E@.ϲ?Uq $E@^'?LٻE@`}oFQ? EF@XEs?TF@ּI? :̌F@l̳?`v%F@#%w?`? .F@RctG@? @ȝ_x"~G@e4,@[.G@ S@@/bĤG@>$@FG@ϫV@Q2G@w@ؿG@ O@M0bvG@-,@`zwG@^˚ @@=+G@~-)@@G@uu?X>ctG@Y?e>G@+K?0.G@1?#G@#C?HI-G@mVv?HG@?84kfG@?G@0*KT?XzkpG@G@b³)G@`s8α˿AsG@ڿ҂G@BUf d{G@>#@*G@bѰG@ra4JiG@8>m@ oF@\7H@2l~ gF@2ՀP@t(cF@麝@c$TiF@@DAB@]5$M@hY04C@=\M@DAB@=\M@hYB@]5.M@hYPC@]5uM@~-? C@ QM@hY04C@]5$M@PhYB@%M@ G4C@n ٔM@hYB@]5.M@ŮB@DM@z~6PB@#;M@C@%M@hY C@]5M@hY-C@mz8M@ G4C@n ٔM@\TB@n ٔM@HC@ N@ G4C@n ٔM@Z\>C@]5NM@SC@mz8M@Z\9C@%kM@HC@%M@hYH2C@]5NM@hY,C@]5M@hYC@mzXM@hY8"C@]5&M@hY!C@]5VM@Z\ C@]5"M@hYx C@mz`M@ C@]5jM@Z\C@%M@Z\] C@]5FN@\TB@ N@H^۱B@ N@\TB@]5N@^۱B@N@hYХB@mz N@ B@]5N@Z\EB@mzLN@hYB@mzN@\TB@ N@(B@]5N@ B@9N@B@9N@ B@]5N@8/_V!B@9N@B@ύN@B@9N@P›B@6v#N@c"ƊB@G6.N@7c֍B@t0N@ B@/u2N@}xB@ۇ5N@I wB@ћ8N@VbB@x X@N@hyܛB@ۭ'HN@r~B@x(JN@[B@mz,ON@hY`B@mzTN@Z\B@]5&eN@hYЈB@mzjN@hY0_B@%vN@hYUB@mzyN@hY(@B@mz{N@hY-B@mzԇN@+B@@wN@8/_V!B@ύN@(Z\A@ύN@8/_V!B@mzĢN@Z\A@mzĢN@8/_V!B@ύN@J)A@mzyN@Z\A@<`\DN@J)A@<`\DN@Z\/A@]5N@hYPA@]5BN@+uA@]5:N@hYA@%N@hYHA@mzN@Z\A@mzĢN@hYA@]5vN@A@mzyN@Z\A@]5N@hYA@]5N@hY0{A@mz|N@Z\oA@mz\N@hYlA@]5N@hYnA@]5N@P,VlA@([hN@8m8@gA@NjO@ynA@3333uO@lmhA@NjO@m8@gA@%lO@f(٩iA@Ӷ?qO@ynA@3333uO@P1.A@3333uO@:LśxA@BO@ynA@3333uO@:LśxA@)LYO@܄oqA@(O@1sSgA@oO@=a_A@G[O@x*5A@ϗGO@1.A@BO@0hYA@BO@1.A@.P@1.A@BO@hYA@%GO@hY0A@.P@@hY0A@.P@Z\%-A@ًŃP@hY0A@.P@K"A@ًP@(A@.kP@ *A@ًŇ P@Z\%-A@ًŃP@@Z\%-A@ًŃP@Z\%_A@.#P@Z\%-A@ًŃP@hY4A@ًœP@hYxVNH@ʻE@GZfUH@Lo=E@D->VNH@ʻE@GZfUH@hfff>A@%N@hY@A@sO@ hfff>A@sO@hYUA@]5eO@[kgA@q߭_O@hY@A@]5FO@hYA@]58O@hYA@]5.O@hY@A@]5B!O@hY@A@]5B O@hYA@]5N@hYA@%N@hYA@%N@[kgA@q߭_O@lmhA@NjO@Xastir-Release-2.2.4/NaturalEarthVector/ne_50m_rivers_lake_centerlines.shx0000664000175000017500000000752415151324131025676 0ustar hibbyhibby' }YΧdѼIp#m f@oUR@2HNhR  8  f0 J 8d~8N8(8P<0p8(ZH^JH0,HxXhHXlJ8XRJ88 0!L8!Z!"h#6Z#H#X$<8$x%&&(&'J(:(PH(v)j)T)(*(*48*p+"P+v8+J,(,,(,XT,h-(-H8-Z-X.>t./J/0H0F2.X2H2H3"r34T586@(6l9\:(R:~z:@;@;Z<><=?`@ABFrIIPxR$Y[`chffjl:q6quyp8{}x~ ~(p`<(Ht H lht(Pt\@JJl> 4 XX@Pp ʔp\Xd Xrl: hߌx,2$Z*8@&h x F&`8r X t,4dxPfR!#~ |,./0j1N7<8H~?^B,IJXJ8L(NrRzSUUWZJ\] `bcVHdff JgZgijH*kvhkPs6st~x z}htNX  x0(\TX, hv8J`^$Ƥx rҖ(p6H܂LhJ8 (0 hv( Fz~, H h(F""P*P-H2"48*9;P@XA` Lp P~XVWZ Z\p`>a2`b8jk~l @mNnVnoqsxyXz${D|~b~|`tXt`t^|\@\~R(pJNz^hX8(P|@R4P48^* :@~PrpjΊ  D`8՜ֈ~J X  x((T|0DX*Z\VrbZh8bfH@0t2 . P"&##b%>%b)P`)X*.1<H35$:<> *HNIJM60Mj(MNFOHP6P@QRS(STTV@VPWBWHXB(XnY*(YVY8Z.PZ0Z@Z@[>[([Xastir-Release-2.2.4/OSM_template0000664000175000017500000000271715151324131015604 0ustar hibbyhibby# # # THIS IS A TEMPLATE FILE # # Map data Copyright OpenStreetMap Contributors, CC-BY-SA # See www.openstreetmap.org and http://creativecommons.org/licenses/by-sa/2.0/ # # The string following OSMSTATICMAP-, is appended to the URL # The string is typically expected to select a layer, and possibly style # options. If not set it defaults to: # layer=osmarander # # The string following OSM_TILED_MAP-, is the name of a sub-directory in # the tile cache. It can be empty (delete the '-' too), though that is a # bad idea if multiple map styles are using the same TILE_DIR. # # Select only one of the two map types: OSMSTATICMAP or OSM_TILED_MAP # # #OSMSTATICMAP-STYLE # or #OSM_TILED_MAP-STYLE # # The url for tiled maps defaults to http://tile.openstreetmap.org/. For # static maps it defaults to http://ojw.dev.openstreetmap.org/StaticMap/ #URL tileURL # Tile extension defaults to png #TILE_EXT png #ZOOM_LEVEL_MIN 0 #ZOOM_LEVEL_MAX 18 # The tile cache can be changed from the default (~/.xastir/OSMtiles) by # setting the following variable. If path does not begin with a '/' then # it will be relative to ~/.xastir/. # #TILE_DIR OSMtiles # When defined: # OSM_OPTIMIZE_KEY will change the map scaling to the nearest OSM zoom level. # OSM_REPORT_SCALE_KEY will report the present, scale_x, scale_y, # and OSM zoom level, but only for debug level 512 (-v 512) # # The values are X KeySym values. # 65473 = F4 # 65474 = F5 OSM_OPTIMIZE_KEY 65473 OSM_REPORT_SCALE_KEY 65474 Xastir-Release-2.2.4/README0000664000175000017500000002564115151324131014211 0ustar hibbyhibby# README > [!IMPORTANT] > > This document makes a lot of references to the Xastir > wiki and mailing lists at xastir.org. At this time (December 2025) > that site is experiencing frequent downtime and may be unavailable. > This is being worked on. > > In the meantime, we have been trying to expand the documentation > available in the wiki on GitHub. Please look there first, as much > of the information on the xastir.org site is outdated. The > information on the Github wiki is very incomplete, but what is there > is more up-to-date than what's on the xastir.org wiki. > > Please use Github issues to report bugs and Github Discussions to > open topics of conversation until we get the mailing lists back on line. ------------------------------------------------------------------------ Please at least SKIM this document before asking questions. In fact, READ IT if you've never successfully set up Xastir before. PLEASE! READ IT! If you haven't read this file, and ask for help expect to be told to READ the README file first! or RTFM :) Contents: 0. Important notice 1. What is Xastir? 2. How do I get Xastir & Git usage 3. Quick startup 4. Upgrading 5. Identification notes 6. OS-specific notes 7. Gating weather alerts 8. Boring legal stuff 9. Mailing list 10. Documentation 11. Obtaining help ------------------------------------------------------------------------ 0. NOTICE Please read this file carefully before trying to set up Xastir. This software was developed to be used by licensed amateur radio operators. You are responsible for any information transmitted or propagated on any network. 1. WHAT IS XASTIR? Xastir is an open-source project to create a free X11 graphical APRS(tm) client. APRS(tm) use amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. Xastir currently runs under several flavors of Linux and BSD Unix. A few people are running Xastir on Solaris Unix, FreeBSD, Lindows and Mac OS X, but there may be small changes necessary in order to get Xastir to configure/compile on some systems. There are a few notes below which may help in this task. Most of the developers use Linux which makes it the best supported platform at the moment. Xastir is an open-source project: Most sources, documentation, and binaries are available under the GPL license, with a few modules available under other open-source or public domain licenses. More information on Xastir can be found here: * https://github.com/Xastir/Xastir/wiki * http://github.com/Xastir * http://xastir.org including the latest releases, Git access (lets you download the latest developers' code), and information on how to join Xastir mailing lists. Note that you must be subscribed in order to post to the mailing lists. SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used. Thanks to Tony and Steve for that contribution! -- The Xastir Group. 2. HOW TO GET XASTIR Xastir is currently developed at You can get the latest version of Xastir from there. You might try for help and information, particularly the Xastir mailing list (listed near the bottom of the page). * Git USAGE Obtain the *very latest* version of Xastir under development by using Git. See the file [README.GIT](README.GIT.md) for more details. * Release version tarballs You can get the latest packaged release source code without git at https://github.com/Xastir/Xastir/releases. Be warned that packaged source tarballs may be quite old and not representative of the current state of the project. We highly recommend not using this method unless you have a specific reason to stick to official releases. 3. QUICK STARTUP Please see the [Xastir wiki at github](https://github.com/Xastir/Xastir/wiki) for the most up-to-date documentation on getting started with Xastir. See [INSTALL.md](INSTALL.md) for a relatively quick overview of how to build and use Xastir. The Xastir wiki (http://xastir.org) might have OS-specific guidance for building Xastir on your system. WINDOWS USERS: Please refer to the [README.CYGWIN](README.CYGWIN) file for specific instructions. 4. UPGRADING Upgrading Xastir that has been built from a recent Git clone is as simple as running "git pull" in the source tree and recompiling. 5. IDENTIFICATION NOTES Packet radio modes, by their very nature, typically identify themselves with every transmission. Xastir has a few features targeted to people who used Xastir in demonstrations and other broadcasts where Xastir itself is used over radio. Xastir can auto-ID via voice if Festival is compiled in and/or via a message splashed across the screen. It does this identification every 9.5 minutes if enabled. These identification modes were designed for broadcasting Xastir across fast-scan television (for events perhaps). Set the "ATV_SCREEN_ID" variable to 1 to enable the screen message, and "SPEAK_ID" variable to 1 to enable festival to speak the message. These variables are in the ~/.xastir/config/xastir.cnf file. 6. OS SPECIFIC NOTES There are some OS-specific installation notes at https://github.com/Xastir/Xastir/wiki. We are working on expanding the section. There are more OS-specific installation notes at http://xastir.org in the "Installation Notes" section for OS-specific build guidance. Some are very outdated, but may still be helpful. 7. GATING WEATHER ALERTS, STATIONS, OBJECTS/ITEMS TO RF ## Gating NWS Weather Alerts to RF: If you wish to gate NWS weather alerts from the Internet onto RF, you'll need to create a text file in the users directory as ~/.xastir/data/nws-stations.txt List each NWS station that you would like to transmit via RF. Wildcards are implied for lengths of 3 or greater. Here's what an example file looks like: # # Seattle, WA SEANPW # # Portland, OR (any alert type) PDX # # Pendleton, OR PDTNPW # # Medford, OR MFRNPW # All text should start at the beginning of the line. Once that file is in place, you'll need to hook up to at least one Internet server that is feeding you the weather alerts. You'll also need to have at least one RF interface up and running with transmit enabled on that interface. Make sure that "Interfaces->Disable Transmit: All" is not selected. You should now be gating NWS weather messages to RF. Turn on igate logging and look at that log file to view what you're sending out via RF. Don't forget to turn off logging or set up auto-rollover of the log files, else your hard drive might fill up with logging info. Auto-rollover of log files is typically accomplished via CRON. ## Gating Stations, Objects/Items to RF: The latest code also allows gating packets from specific stations to RF using the above method (except object/item packets). You can also gate objects/items to RF by name. The same wildcarding rules apply as listed above. Callsigns or object/item names listed in this file are case-insensitive, so they'll match any case in received packets. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.aprs.org/aprs-jota.txt 8. BORING LEGAL STUFF Xastir is Copyright by Frank Giannandrea. Xastir is distributed according to the GNU General Public License. There should be a copy of this license in the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As of Xastir 0.4.0 all changes made by the Xastir development team to the Xastir source code and any related files are Copyright (C) 2000-2026 The Xastir Group. The source code will still be distributed according to the GNU General Public License as Frank Giannandrea did in the past. There is no warranty, implied or whatever. You use this software at your own risk, no matter what purpose you put it to. You didn't pay for it, so don't expect magic. 9. MAILING LIST There are currently a couple of mailing lists about Xastir. xastir@xastir.org is the one relevant for most users. The xastir@xastir.org mail-list is dedicated to Bug reports, technical questions, your thoughts or suggestions on new features being added to Xastir, things that should be removed or fixed, amazing problems that even stump the guru's, etc... are what we want to see here. You must be subscribed to the list in order to post messages. To subscribe to the Xastir mailing list, send email to: xastir-request@xastir.org In the body of the message, put "subscribe xastir"; or go to http://xastir.org and click on "XASTIR MAILING LISTS" (in the "Resources" section near the bottom) to subscribe. ### DO NOT SEND FRANK EMAIL ABOUT XASTIR ### Frank is no longer developing the Xastir code and has not participated in Xastir development for many years, so don't bother searching him out and emailing him. If you have a serious problem, open an issue on Github. You may also try posting to the xastir mailing list. Please, before posting to this list, see what things are like, and when you do post, read over your post for readability, spelling, and grammar mistakes. Obviously, we're all human (or are we?) and we all make mistakes (heck, look at this document! ;). Open discussion and debate is integral to change and progress. Don't flame others over mere form (grammar and spelling), or even substantive issues either for that matter. Please read and follow the mailing list rules. A second mailing list, xastir-dev@xastir.org is intended for developer's discussion. 10. DOCUMENTATION We're trying to get the documentation up to date. If you feel that anything is missing here, or that anything should be added etc, please email xastir@xastir.org about it, thank you. 11. OBTAINING HELP Please read the file FAQ, and make sure you've followed any relevant instructions in INSTALL. If the problem still exists, feel free to ask on the Xastir mailing-list, as described above. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/README.CYGWIN0000664000175000017500000004351115151324131015204 0ustar hibbyhibbyNovember 2017 Update This document offers a method of running Xastir on Windows using the Cygwin environment. Cygwin is a large collection of GNU and Open Source tools which provide functionality similar to a Linux distribution on Windows. Microsoft now offers their own Linux solution, using an Ubuntu Linux framework that runs under Windows. However, you must be running a 64 bit version of Windows 10 to use the Microsoft option. More information may be found in the Xastir Wiki at: http://xastir.org/index.php/HowTo:Win10 ------------------------------------ Installing Xastir on Windows/Cygwin: ------------------------------------ These directions were most recently validated on Windows 10, both 32 and 64 bit, with Cygwin version 2.882. SPACES IN FILENAMES/USERNAMES: Cygwin specifically, and Unix boxes in general, don't much like spaces in filenames, directories, or login names. Any of these may cause you headaches while playing with Cygwin. Create a new login that doesn't have spaces and log in as that user before installing Cygwin, and whenever you intend to run Cygwin/Xastir. It's very likely that Xastir won't work for you if you use a login that has spaces embedded in it. For additional info, see this link: https://cygwin.com/faq/faq.html#faq.using.filename-spaces The following steps direct you through installing Cygwin, Xastir, and a few optional map libraries that Xastir can use. Note that in most of the places below where the directions state to type commands, this must be done from within a Cygwin BASH shell, not a DOS window. Where you are asked to edit files, it's best to use Wordpad instead of Notepad, as Notepad doesn't do nice things to Unix-format files. Cygwin now allows you to have Xwindows apps and Windows apps all on the screen and visible at the same time! The instructions here set it up in that manner, so you can have Xastir as just another app on your Windows desktop. Please subscribe to the "xastir" mailing list at "http://xastir.org". There are lots of helpful people there that can aid you in installing/running Xastir. You must be subscribed in order to post messages there. [ ] Step 1) Install Cygwin, a free download. [ ] Step 1a) Go to https://cygwin.com/install.html with your web browser. Choose the 64 bit or 32 bit version as appropriate for your Windows operating system. This will download the Cygwin network installer program onto your computer. Remember where you decide to put this program. I put mine in my user "Downloads" folder. Note: It will be beneficial to re-run the Cygwin network installer from time to time in order to keep Cygwin up to date. Each time you run it you'll update any packages that have been changed since you last ran it. [ ] Step 1b) Find the "setup-x86.exe" program (32 bit) or the "setup-x86_64" (64 bit) program. Make note of which version you are using. Open a Windows Command Prompt as the Administrator and change directory to the directory where you just saved the setup program. If you have setup-x86.exe (32 bit), run this command to download and install the needed Cygwin components: setup-x86.exe --quiet-mode --packages autoconf,automake,binutils,^ db,font-util,gcc-core,git,GraphicsMagick,gv,libcurl-devel,libdb-devel,^ libgeotiff,libgeotiff-devel,libjasper-devel,libjbig-devel,^ liblcms2-devel,libpcre-devel,libshp-devel,libtiff-devel,libwebp-devel,^ libwmf-devel,libxml2-devel,libGraphicsMagick-devel,libX11-devel,^ libXext-devel,libXm-devel,make,nano,sox,unzip,wget,xfontsel,xinit,^ xorg-x11-fonts-Type1,xorg-x11-fonts-dpi100,libbz2-devel,libproj-devel If you have setup-x86_64.exe (64 bit), run this command to download and install the needed Cygwin components: setup-x86_64.exe --quiet-mode --packages autoconf,automake,binutils,^ db,font-util,gcc-core,git,GraphicsMagick,gv,libcurl-devel,libdb-devel,^ libgeotiff,libgeotiff-devel,libjasper-devel,libjbig-devel,^ liblcms2-devel,libpcre-devel,libshp-devel,libtiff-devel,libwebp-devel,^ libwmf-devel,libxml2-devel,libGraphicsMagick-devel,libX11-devel,^ libXext-devel,libXm-devel,make,nano,sox,unzip,wget,xfontsel,xinit,^ xorg-x11-fonts-Type1,xorg-x11-fonts-dpi100,libbz2-devel,libproj-devel [ ] Step 1c) Choose a Download Site and then click Next. [ ] Step 1d) The Select Packages screen will display. You don't have to actually select any, the right packages have been selected for you. But, if you wish, you can review the selection and make changes if you know what you are doing. Click Next and the Resolving Dependencies screen will display. [ ] Step 1e) Click Next and the packages will get downloaded and installed. Repeat the above if you have network difficulties, until the install succeeds completely. In addition to the base packages, the following packages required to compile and run Xastir, along with their dependencies, will be installed. [ ] autoconf [ ] automake [ ] binutils [ ] db [ ] font-util [ ] gcc-core [ ] git [ ] GraphicsMagick [ ] gv [ ] gzip [ ] libbz2-devel [ ] libcurl-devel [ ] libdb-devel [ ] libgeotiff [ ] libgeotiff-devel [ ] libjasper-devel [ ] libjbig-devel [ ] liblcms2-devel [ ] libpcre-devel [ ] libproj-devel [ ] libshp-devel [ ] libtiff-devel [ ] libwebp-devel [ ] libwmf-devel [ ] libxml2-devel [ ] libGraphicsMagick-devel [ ] libX11-devel [ ] libXext-devel [ ] libXm-devel [ ] make [ ] nano (a windows-style text editor, optional) [ ] patch [ ] sox [ ] unzip [ ] wget (Optional: Can use libcurl instead) [ ] xfontsel [ ] xinit [ ] xorg-x11-fonts-Type1 [ ] xorg-x11-fonts-dpi100 [ ] Step 1f) You may receive a Postinstall script errors screen. It is not necessarily an issue, but you are advised to check the contents of /cygwin/var/log/setup.log.full or /cygwin64/var/log/setup.log.full. Click Next to proceed. [ ] Step 1g) At the end of the install it'll ask you if you wish to create desktop icons and menu entries. Definitely select these! It doesn't mean that Cygwin will start automatically each time you reboot your computer or login (it doesn't start automatically). It _does_ mean that you'll have an icon to click on manually to get things going. This will create a Black/Green Cygwin icon on the desktop and a menu entry so that you can start Cygwin through the menu system as well. [ ] Step 1h) Click "Finish". Cygwin is now installed. One more pop-up informs you Cygwin has been installed. Sometimes this last dialog gets hidden behind other windows, and it does seem to need OK clicked to complete the installation. Click the OK button on that last dialog to _really_ complete the installation. The Command Prompt in the window will not return. When it prints "Ending Cygwin install" it is done. You can press enter and the prompt will reappear. The Black/Green Cygwin icon will start up a BASH window, without starting up Xwindows. Think of it as being similar to a DOS window, but with a lot more power. It understands Unix commands though, not DOS commands. [ ] Note: I've had the Cygwin network install fail before during the downloading stage without informing me in any recognizable manner. You might want to re-do step 1 to make sure nothing further gets downloaded/installed. Once you get to that point, Step 1 is complete. [ ] Step 2) Start the X Server: Click on the Windows menu icon or press the Windows button. Look for the Cygwin-X program group and click on the XWin Server. It will create a green "X" icon in the system tray. Right-click on green "X" icon in the system tray. Select Systems Tools, and then Cygwin Terminal. [ ] Step 3) Test Cygwin and create startup shortcuts: You should get a shell window that looks very much like a DOS window. It's a BASH shell window and understands Unix commands instead of DOS commands. Once you've gotten to this stage, you now have Cygwin and Xwindows installed and operational. Next we go after Xastir itself. [ ] Step 4) Download Xastir sources. Use the Cygwin Terminal window that you just started. Type the three lines below into the shell exactly as shown. mkdir git cd git git clone http://github.com/Xastir/Xastir The end result when it succeeds will be a new directory "~\git\Xastir\" which contains all of the Xastir source code. You can type "ls Xastir" (that's lower-case LS) to see the file listing. Side Note: Here's the coolest thing about Git: Once you've done this initial source-code download, you'll never have to do the whole Xastir download again. You'll just go into the "git/xastir" directory and type "git pull", which will snag just the _changes_ to the files since you last updated, and is very fast. Compile and install at that point and you'll be running the latest developer's version in just a few minutes! It's very easy to keep up with the developers this way. [ ] Step 5) Configure/compile/install Xastir. Type these commands into the BASH shell, waiting until each one completes before typing the next command: cd ~/git/Xastir ./bootstrap.sh mkdir -p build cd build ../configure make make install-strip NOTE: You'll probably want to run the configure step from an xterm window with the X11 server running of course. If you do this from a non-X11 window then the configure test for "gv" will fail, as "gv" requires an X11 server even when asking it for it's version number. Without "gv" support you won't be able to print from Xastir. Once you get through the above commands, Xastir is compiled and installed on your system, with minimal map support. Later sections of this document detail adding additional map libraries in order to give you access to the full mapping capability of Xastir. --------------------------------------------------------------------- [ ] Step 6) Actually run the darn thing: Let's start from scratch to make sure it all works. Close any Cygwin/BASH windows you may have. Click on the shortcut you created to start Xwindows. From the resulting BASH window, type "xastir &". Xastir should start up shortly. As built, using this documentation, the following map types are supported. Built-in map types: gnis USGS GNIS Datapoints pop USGS GNIS Datapoints w/population map APRSdos Maps map WinAPRS/MacAPRS/X-APRS Maps Support for these additional map types has been compiled in: geo Image Map (ImageMagick/GraphicsMagick library, many formats allowed) geo URL (Internet maps via libcurl library) geo URL (OpenStreetMaps via libcurl library Copyright OpenStreetMap and contributors, CC-BY-SA) shp ESRI Shapefile Maps (Shapelib library) tif USGS DRG Geotiff Topographic Maps (libgeotiff/libproj) xpm X Pixmap Maps (XPM library) The Xastir wiki at Github (https://github.com/Xastir/Xastir/wiki) has instructions for where to get maps and where to put them under the Xastir hierarchy. If you have any WinAPRS or APRSDOS maps, now is a good time to place them in the /cygwin/usr/local/share/xastir/maps folder (or a subdirectory of it). You can also use "*.geo" files and the associated image files with Xastir. You may place them in this directory (or a subdirectory of it) as well. FILESYSTEM PATHS (WINDOWS VS CYGWIN): From Windows, just prefix all paths with "/cygwin" or "/cygwin64" as appropriate. For instance, maps go into /cgwin/usr/local/share/xastir/maps instead of /usr/local/share/xastir/maps. Xastir will continue to see them as "/usr/local/share/xastir/maps" though from inside Cygwin. It kind of looks like a miniature Unix box from inside Cygwin. LANGUAGE OPTIONS: To set a new language or change the language current choice, use this command line instead from inside an Xterm: xastir -l Current choices are: Dutch English French German Italian Portuguese Spanish ElmerFudd MuppetsChef OldeEnglish PigLatin PirateEnglish This option will be stored in the users config file for the next time Xastir is run. On new installs Xastir will default to English until you use this command line option once. CYGWIN vs LINUX/UNIX: Another difference with Cygwin as opposed to Unix-like operating systems: You can't do the make install portion if Xastir is up and running. You have to kill Xastir first before you do "make install" or "make install-strip". Otherwise the newly compiled Xastir won't replace the old one. Another interesting "feature" of Cygwin/Xwindows is that some of the modifier keys like ScrollLock/CapsLock/NumLock must be pressed while that X-window is the active foreground window. If not, the event can be missed, and Xwindows can get out of sync with the actual state of the key. This doesn't appear to be an Xastir-specific problem, but a Cygwin/Xwindow problem. With just a BASH shell under Cygwin (not involving Xwindows), the problem doesn't appear to happen. Just inside Xwindows on Cygwin. When specifying serial ports to use with Xastir, "COM1" is called "/dev/ttyS0" in Cygwin (and Linux) "COM2" is called "/dev/ttyS1" in Cygwin (and Linux) Note the capital 'S'. OPTIONAL Please see the INSTALL file and the Help menu in Xastir itself for additional information not mentioned in this document. Additional info can be found on the cygwin web-site: http://www.cygwin.com or the Cygwin/XFree86 web-site: http://cygwin.com/xfree/ Keeping up-to-date: Once a week or once a month, run the Cygwin network installer program (setup-x86.exe or setup-x86_64.exe). After it finishes, open a Cygwin terminal window and type these commands to update the Xastir source code: cd ~/git/xastir git pull Every once in a while Windows will refuse to allow you to delete/rename one of the files. The only way I've found to get around this problem is to reboot. I sometimes see this when trying to do a "git pull", and Windows won't allow one or more files to get updated. You can now repeat step 5 to update Xastir. ------------------------------------------- OPTIONAL: ADDING ADDITIONAL MAP LIBRARIES: ------------------------------------------- These additional Xastir libraries have been tested on Cygwin: ImageMagick (no need to use if using GraphicsMagick) Festival Anyone testing additional libraries is encouraged to share their findings on the Xastir mailing lists (you must be subscribed in order to post messages there). The libraries which have _not_ been made to work yet on Cygwin are: AX25 GPSMan/gpsmanshp The AX25 libraries will probably never work, as they are for Linux only. GPSMan/gpsmanshp may work on Cygwin at some point if enough work is done to figure out and document the process. OPTIONAL: Install Festival support: ------------------------------------ Note: The most recent version of Festival is 2.4. According to the README for this version, "Do NOT use Windows with Cygwin". With that warning up front, here are instructions that were previously used to make a legacy version of Festival work with Xastir. They were not revalidated during the November 2017 update to this document. Allows using a synthesized voice from within Xastir for alerts, reading messages to you, and other cool things. Tom Russo did the initial work on this, Henk de Groot optimized it: 1) Start BASH shell in Cygwin 2) Make ~/festival download directory and /usr/local/festival installation directory 3) Download festival components from festvox.org into ~/festival, in the Windows environment the corresponding path is: C:\Cygwin\home\%USERNAME%\festival get the following files: speech_tools-1.2.95-beta.tar.gz festival-1.95-beta.tar.gz festlex-CMU.tar.gz festlex-POSLEX.tar.gz festvox-kallpc16k.tar.gz 4) Build festival and company: cd /usr/local/festival tar xzf ~/festival/speech_tools-1.2.95-beta.tar.gz tar xzf ~/festival/festival-1.95-beta.tar.gz tar xzf ~/festival/festlex_CMU.tar.gz tar xzf ~/festival/festlex_POSLEX.tar.gz tar xzf ~/festival/festvox_kallpc16k.tar.gz cd speech_tools ./configure && make cd ../festival ./configure && make These packages are build and used where they are compiled. 5) Test festival: cd /usr/local/festival/festival/examples sh saytime Festival should say the time if everything went fine 6) Add /festival/festival/bin to PATH in .profile and .bashrc. For me both files look like this: .profile and .bashrc: ------------------- export PATH=$PATH:/lib:/usr/lib:/usr/X11R6/lib:/usr/local/lib:/usr/local/bin:/usr/local/festival/festival/bin:~/bin:. ------------------- 7) Configure and build xastir. Configure should report that festival is found. 8) Start the festival server: festival --server & To do this automatically I added the following lines to my .bash_profile: ------------------- if [ `ps -ef | grep festival | wc -l` -eq 0 ] then festival --server & sleep 1 fi ------------------- 9) Run xastir, do File->Configure->Speech, add things to say, and listen. OPTIONAL: How to make Sound Alerts work under Cygwin: ------------------------------------------------------ There is currently (November 2017) a problem using sound alerts under Cygwin. It is recommended that sound alerts are turned off within Cygwin or you may experience lockups. You'll need to add the .wav files to Xastir. git clone http://github.com/Xastir/Xastir-sounds cd Xastir-sounds cp -r sounds/* /usr/local/share/xastir/sounds/ November 2017 documentation updates by K2DLS. There may be out-of-date items that remain in this document. Please report issues via the Xastir mailing list. APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/README.GIT.md0000664000175000017500000004317215151324131015231 0ustar hibbyhibby# Git Instructions for Xastir users and developers For those who think git might be a bit too complicated to deal with, here are (I think) the minimal commands. # Basics for USERS: ## Getting Your Initial Copy (Git Clone): 0. Make sure git is installed on your system. 1. Run ``` git config --global user.name "Your Name" user.email "Your@email.address" ``` The above is not strictly necessary, but if you ever try to make changes to Xastir and get them integrated with the project it is important.

If you already have a different git config If you already have a different git global config, you can create a local config for a particular repo by going into that repo and doing: git config --local user.name "Your Name" user.email "Your@email.address"
Check the config by: ``` git config --local -l git config --global -l git config -l # Doesn't differentiate between global and local though! ``` 2. Go to to access the project page. There you will find the URL of the git repository, just to the right of a button that says "HTTPS". Copy this URL to your clipboard. (At the time of this writing, the URL was https://github.com/Xastir/Xastir.git) 3. Open a shell, navigate to a directory where you want to store the Xastir source code, and enter this command: ``` git clone https://github.com/Xastir/Xastir.git ``` This will create a clone of the Xastir git repository in an "Xastir" subdirectory of the current directory. All done! You now have the latest development sources on your computer. Not only that, you have a complete copy of the entire project history and access to all prior releases. 4. Please set your default git commit message template for the project to the one included in the Xastir source tree: ``` cd Xastir cp git_commit_message_template ~ git config --global commit.template ~/git_commit_message_template ``` This will assure that when you make commits, your editor will start with a template that helps guide you through the process of writing commit messages that conform to the guidelines below in the section titled "Important: Git Commit Message Format". This template is quite generic and conforms to the guidelines of many other open source projects, so it is reasonable to make it a global git option. ## Updating Your Copy The copy you just cloned is the snapshot of the state of the code the day you did it. From time to time you'll want to update that to get the latest changes. It's easy. ``` cd Xastir git pull # Update your local repo (May be dangerous for developers) ./bootstrap.sh # "autoreconf -i" also works mkdir -p build # Build in a separate directory cd build ../configure (make clean;make -j3 2>&1) | tee make.log sudo make install # "make install-strip" can be used after the first # time: It removes debugging info from executable sudo chmod 4555 /usr/local/bin/xastir # Only needed if using kernel AX.25 xastir & # Start it up! ``` Note that you'll need autoconf 2.53 or newer and automake 1.16 or newer in order to run the "./bootstrap.sh" script.
autoreconf vs. bootstrap "autoreconf", a part of the autoconf package, does the same thing that bootstrap.sh does, in a more modern approach. The bootstrap.sh approach is very old and was the approach advocated by this document for many years, but invoking "autoreconf -i" does the same thing.
It is pointless to continue if autoreconf or bootstrap.sh give you error messages! The bootstrap.sh script or autoreconf is what creates the configure script. Running either requires having autoconf and automake installed, and it will fail if these are not installed. If bootstrap.sh fails, configure won't exist. If bootstrap.sh fails, stop, fix the problem and try again. There is no point continuing if bootstrap.sh gives you error messages about programs not being found (aclocal, autoconf, automake). This is a common problem reported to the Xastir team, and its solution is always the same: install all prerequisite tools before trying to build Xastir.
# Git details for DEVELOPERS: These instructions are by necessity very, very incomplete. Don't rely solely on this document to learn git. See a good resource like [Pro Git](https://git-scm.com/book/en/v2) before getting too involved in Xastir development. ## Initial Checkout: Since you will be uploading changes to the repo, it is important to get set up right. Choose your initial clone URL accordingly. ### HTTPS Method: ``` git clone https://github.com/Xastir/Xastir ``` ### SSH public key method [Add keys to GitHub](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) and then: ``` git clone git@github.com:Xastir/Xastir ``` Note that using the SSH method means that you won't have to answer the popups for user/password each time you do anything with the remote repo, although you will have to enter a passphrase if you added a passphrase to your SSH key. The SSH method is highly recommended for active developers! # Normal Development Worklow: ## The Xastir team prefers a "fork and pull request" development flow In this way of working with git, you create a fork on github (just click the "fork" button on the Xastir github main page). This creates a clone in your own account on github that is entirely yours, but is linked back to the main repo. See [this site](https://gist.github.com/Chaser324/ce0505fbed06b947d962) for a good summary of how the process works. ## Create your fork Go to Xastir's github repo, click the fork button, and make your fork in your own github account. ## Link your local clone to your fork When you cloned Xastir's main repo, git set up a "remote" for you that refers back to that main repo on github. It was called "origin" if you didn't do anything special to rename it. You now want to create a second remote that points at your own fork. Navigate to your fork on github and look at the "Code" button, which will show you the URL you would use to clone your repo. Use this URL in a command like the following in your Xastir clone directory: ``` git remote add myremote git@github.com:myusername/Xastir.git ``` You now have a way of working with your own fork and the main upstream repo from the same directory. You can confirm it's right with: ``` git remote -v ``` which should list your remotes: ``` origin git@github.com:Xastir/Xastir.git (fetch) origin git@github.com:Xastir/Xastir.git (push) myremote git@github.com:myusername/Xastir.git (fetch) myremote git@github.com:myusername/Xastir.git (push) ``` You should then actually fetch the contents of your fork: ``` git fetch myremote ``` This really doesn't do much because your fork only has the same stuff as the main repo right now. But at least executing this command and getting no errors shows you have no mistakes. ## Working with branches The best way to work in the fork-and-pull-request mode is for you to do your work on branches. Branches in git are very simple to create and switch between, but are substantially different in nature from branches in older version control systems like CVS. Please see a good reference about git (such as [Pro Git](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) and [Think like (a) Git](https://think-like-a-git.net/)) to get a good understanding of how they work. Assume you're getting ready to start some work on a new feature or bug fix. Update your master branch and create a new branch from it: ``` cd /path/to/Xastir git pull # updates the code to the latest git checkout -b my_feature_branch # Creates a new branch from the # latest code on master ``` That last command creates a new branch and then switches to it. Any commits you make will go on the branch instead of on the master branch. ## Doing your work ### verify you're on the right branch Commit your work to your LOCAL repo and your own branch. If you followed the steps in the previous heading you've already created that branch and switched to it. But just to be sure, run ``` git status ``` which should show you: ``` > git status On branch my_feature_branch nothing to commit, working tree clean ``` If it doesn't say you're on the branch you expected you would be on, switch to it with `git checkout my_feature_branch`. ### Do your work Now do your work, which will change some files. At any time, you can run `git status` and git should show you which files you've changed, any new files you've created that are not currently tracked in git, and so forth. You should always do a "git status" before taking the next step. ### Commit your work When you're ready to save your work, either because it's finished or because you've reached a good checkpoint and want to preserve it, add the files you've changed to the staging area and commit them: ``` git add ... # Adds all changed files git commit # actually saves the # changes in git ``` ### Repeat "do your work" and "commit your work" until done Typically, development will take a while and you'll have more than one commit to do to get it all done. It is best to make your commits "atomic" by doing small changes, testing them like crazy, and committing them rather than to make all of your work show up in one huge commit touching many files all at once. All of these small changes get committed to the clone on your machine, without updating github at all. ## Publish your work When your feature branch is done, push it *to your fork*. Assuming your fork has been added as a remote named "myremote" and your branch is named `my_feature_branch`, that is done with: ``` git push myremote my_feature_branch ``` This will create a new copy of your feature branch on your own fork on github. The main repository will not be touched. ### Open a pull request Go back to github to the main Xastir repository. You should see a banner near the top saying that you have added code to a branch on a fork, and it should have a button that says "Compare and make pull request" or some such words. Open a pull request using this button. The pull request is basically an announcement to the development team that there is a suggested change being made and provides a way for them to review those changes and accept them, or to make comments on the changes and request additional changes. ### Update your pull request If your pull request gets comments saying that more change is needed, you can continue to work on your branch, make more commits, and push them to your fork. Those commits will automatically be added to the pull request for the reviewers to see. ### Work In Progres (WIP) pull requests You can push your code to your fork and open a pull request at any time, even if your work isn't finished. The main reason to do this is if you think your work is going to be very involved and touching lots of code. If you push incomplete work to your fork and open a pull request for it before it's done, please put the text "WIP:" in the pull request's name, and select the "Convert to draft" option immediately after opening it. This will allow reviewers to see what you're doing as you do it, possibly relieving the burden of reviewing a single enormous set of changes all at once. By marking the pull request as a draft, nobody is allowed to merge it until you change it to "Ready for review." ## Once your pull request is merged When your pull request is accepted and merged into the master branch, make sure you update your local clone. Switch back to the master branch and pull it. ``` git status # should show you still on your feature branch, # and that the working directory is clean git checkout master # Switch back to the master branch, which is # now outdated git pull # get all the changes that have been made to # master, including your accepted PR ``` # Git Commit Message Format > [!IMPORTANT] > The Xastir team has a specific format we want you to use in commit > messages. Please read this section and follow it. Git commit messages need to be in a certain format to make the best use of the "git log" commands. In particular the first line needs to be 50 chars or less, then a BLANK LINE, then a detailed commit message. See this link for more info: http://chris.beams.io/posts/git-commit/ # Assorted git details ## Checking Out A Branch: All branches associated with the Xastir project are contained in the clone you made earlier. You can switch your current working directory to one of those branches easily: ``` cd Xastir git fetch (this updates your local repo copy from github, but doesn't merge changes into your working tree) git checkout (this switches all the files in your working tree to match those in the branch) git merge (This makes sure that all the changes that may have happened upstream on that branch get into your copy) ``` You do not have to do this in a new directory --- so long as you haven't changed any files in the source tree, git checkout automatically swaps out all files it knows about with versions from the branch. ## Keeping multiple working directories for multiple branches If you really want to keep more than one branch's code around to work on, you can do that if you have git version 2.5 or later with the following commands: ``` cd Xastir git worktree add ``` This will create a new directory tree called with the named branch checked out into it. ## There's a lot more. There are many more git commands and options. Many of them are more of use to the developers. Some of those are listed below. The above should be enough for most people to keep their copies in sync with the latest git development sources. ## If Using Multiple GitHub Accounts: You may have trouble getting your commits attributed to the correct GitHub login. GitHub uses the username/email in your git config settings for attribution. If it is wrong, you may have to do some of the below in order to set a LOCAL username and email for the one repository. The user.name and user.email are pulled from the global git config, but a local git config inside each repo will override those settings. Go to root of checked-out repo and set local user.name and user.email for this repo: ``` git config user.name git config user.email git config -l # Shows both local and global settings, hard to tell which is which git config --global # Shows global settings git config --local -l # Shows local repo configs, so should show new settings ``` Another method (but more error-prone) of editing local/global git config is: ``` git config edit # Edit local config git config --global edit # Edit global config ``` If new commits still aren't using the right email, make sure you have not set GIT_COMMITTER_EMAIL or GIT_AUTHOR_EMAIL environment variables. # For More Info: Make sure you know how git works. Read https://git-scm.com/book/en/v2 If you are very familiar with CVS, get used to working differently, because git is different. Read and understand http://chris.beams.io/posts/git-commit/ Read http://justinhileman.info/article/changing-history/ Read http://think-like-a-git.net/ Read "Visual Git Cheat Sheet" at http://ndpsoftware.com/git-cheatsheet.html Branching and merging in git is very simple, and is documented very well by all those links. We will not repeat it here. If you use SSH, set up your SSH keys on GitHub and do the "git clone" using the SSH path. This will save you having to put in your password each time you use the remote repository, although if you added a passphrase to your SSH key you'll have to enter that each time. # Useful Git Commands: Set up global user/email ``` git config --global user.name "Your Name" git config --global user.email "user@domain.com" ``` Set up user/email for a local repository ``` cd /path/repository git config user.name "Your Name" git config user.email "user@domain.com" ``` Configure Git's editor: ``` git config --global core.editor /path/to/editor ``` Colorizing Git output (set once and forget): ``` git config --global color.ui auto ``` Clone a repo: ``` git clone https://github.com/Xastir/Xastir git clone git@github.com:Xastir/Xastir ``` Status of local repo: ``` git status ``` Diff for a file: ``` git diff ``` See all branches, local and remote: ``` git branch -a ``` Visual Git viewer: ``` gitk (tcl/tk and generic X11 viewer, comes with git) or gitg (gnome git viewer) ``` Add files to the staging area: ``` git add ``` Commit changes to LOCAL repo: ``` git commit # If have files in staging area already git commit # Ignores staging area ``` Push local changes to remote repository: ``` git push ``` Update local repo from remote repo ``` git fetch ``` Update local repo and merge remote/local changes in local repo (May be dangerous for developers with modified code in their working tree who are unwisely working directly in the master branch): ``` git pull ``` Rebase local changes against latest master branch (can be a safer way of updating master if you've unwisely been changing things in that branch locally) ``` git fetch git rebase master ``` ------------------------------------------------------------------------ Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/README.MAPS0000664000175000017500000000146015151324131014741 0ustar hibbyhibbyAll of the information that used to be in this file is now on the Xastir wiki on Github. This file is no longer maintained as a user documentation file. Please see the Mapping Overview at https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview for the information that is most likely valuable to the average user. For links to sites that have good mapping data for use in Xastir, please see https://github.com/Xastir/Xastir/wiki/Mapping-Links For links related to useful map conversions see https://github.com/Xastir/Xastir/wiki/Map-Converters For advanced mapping topics such as converting maps from one datum to another, georeferencing scanned map images, using GIS tools for exploring or creating maps, and interesting advanced reading, please see https://github.com/Xastir/Xastir/wiki/Map-Converters Xastir-Release-2.2.4/README.OSM_maps0000664000175000017500000002037115151324131015661 0ustar hibbyhibby Copyright (C) 2000-2026 The Xastir Group Using OpenStreetMap in Xastir ------------------------------------------------------------------------ CONTENTS Introduction Map Types Map Sources and Renderings (Styles) Map Cache Sharing Tiles Map Definition Files Copyrights and Licenses Introduction ------------ What, you may ask is 'OpenStreetMap' (OSM)? From the web site, www.openstreetmap.org, we read that "OpenStreetMap is a free editable map of the whole world. It is made by people like you". The tag line for the map is "The Free Wiki World Map". Xastir will display bitmap versions of the OSM. There are multiple renderings of the OSM to choose from and, by default, three are available in Xastir. Map Types --------- Xastir can use two different map types based on OSM: static and tiled. Static maps are bitmaps that are least as large as the Xastir window. Tiled maps are built up from 256x256 pixel images. Static maps are also assembled from tiles, but the assembly occurs at the server and the full size image is downloaded to Xastir. There is a major disadvantage to static maps: even slight changes in map position requires a new map download. Most online maps, including OSM, use map tiles that follow the "Web Mercator" projection and tiling scheme. The Web Mercator projection was first popularized by Google Maps. It is a modified Mercator projection, using a hybrid spheroid/ellipsoid model that is faster to compute. Wikipedia has a nice description: https://en.wikipedia.org/wiki/Web_Mercator. Map tiles are referred to by their zoom level, and row and column number. Major providers (such as OSM, Google, Apple, Mapbox, and Bing) and open source projects (such as Open Layers and openmaptiles.org) use the same general tile numbering scheme, although they vary in the specific sequence of zoom/row/column numbers, and the supporting parts of the URL. The URL for a particular tile looks something like this: https://a.tile.openstreetmap.org/11/329/715.png (tile server a, zoom level 11, column 329, row 715). You can see more in this Wikiepedia article: https://en.wikipedia.org/wiki/Tiled_web_map. Bitmap images, whether static or tiled, are available for only a limited number of zoom levels. There are 18 possible zoom levels. It takes 2^zoom tiles to represent 360 degrees. Since the tiles are 256 pixel squares, there are 2^(zoom + 8) pixels in 360 degrees. When the Xastir scale is different from a bitmap image's zoom level, the bitmap image is scaled. However, scaled bitmaps tend to look ugly. The scaled bitmap can have jagged lines, unequal pixel sizes, and/or missing information. At best a scaled bitmap looks blurred, but more typically some pixels will be enlarged into visible blocks or compressed invisibility. You can use the F4 key to adjust the Xastir scale to approximate the OSM zoom level and refresh the display. (The key can be changed by modifying a variable in the OSM definition (GEO) files. Map Sources and Renderings (Styles) ----------------------------------- The OSM data is rendered into tiles using different styles. The easiest place to view and compare the styles is at http://ojw.dev.openstreetmap.org/StaticMap/?mode=Style& Tiles can be retrieved from a number of servers. The supplied map definitions will download tiles from http://tile.openstreetmap.org/ Map Cache --------- Static maps are cached with other bitmap map images in the ~/.xastir/map_cache/ directory. Tiles are cached separately to make it possible to share them with other applications. By default tiles are cached in ~/.xastir/map_cache/OSMtiles/, but that location can be changed on a by-style basis. The tiles are organized directories by style, zoom level, and longitude: ~/.xastir/map_cache/OSMtiles/ + / | + / | / | + [0 ... (2^zoom - 1)].png + / ... Note that 'longitude' is a tile number between 0 and (2^zoom -1). Xastir downloads tiles as needed. If Xastir is compiled with libcurl support, then it will check for updates to tiles that have been cached for 7 days or more. See http://wiki.openstreetmap.org/wiki/Tile_usage_policy If a tile can not be downloaded for any reason or if the downloaded file is not usable image, then the downloaded file (if any) will be deleted and a red area will be shown in it's place on the display. NOTE: Run Xastir at debug level 512 (-v 512) for more information on download issues. At debug level 512, corrupt tile files will not be deleted. Examining the contents of the corrupt files can be informative. If Xastir is compiled with libcurl support, then debug level 8192 will enable verbose output from libcurl. WARNING: Corrupt tile files will not be deleted when running at debug level 512. If you do not delete them manually before restarting Xastir, then the first time Xastir displays the tile it will be shown in red and then deleted from the cache. Sharing Tiles ------------- The directory structure used to cache tiles is common to other programs, though the style names are typically different. An example of a program that can share tiles with Xastir is TangoGPS (http://www.tangogps.org). Here are some examples of how you can share tiles with TangoGPS (the setup for other programs would be similar): 1) Setup a symlink at the style level of the caches $ cd ~/.xastir/OSMmaps/ $ ln ~/Maps// 2) Change the Xastir map definition file to specify the TangoGPS cache by changing the following variables (see the next section for more information): OSM_TILED_MAP- TILE_DIR /home//Maps 3) Share all styles and tiles by creating a symlink at the top level of the cache. This also requires changing the Xastir map definition files to specify the style names used by TangoGPS: $ cd ~/.xastir $ rm -rf OSMmaps/ $ ln -s ../Maps OSMmaps Map Definition Files -------------------- OSM map type, style, server, cache directory, and function keys are specified in Xastir GEO files. By default the files are located in the /usr/local/share/xastir/maps/Online/ directory. The supplied definition files have filenames of this form: OSM_.geo - static maps OSM_tiled_.geo - tiled maps Where is replaced with the style name. Note that could be any unique string and is not required to be the style. Read the comments in the supplied definition files for more information. Copyrights and Licenses ----------------------- Maps and tiles from the OpenStreetMap project are Copyright OpenStreetMap and contributors, CC-BY-SA http://www.openstreetmap.org/ http://creativecommons.org/licenses/by-sa/2.0/ TopOSM tiles are a composite of CC-BY-SA and public domain data, including MassGIS data. See http://wiki.openstreetmap.org/wiki/TopOSM for more information. Changing the Displayed Attribution ---------------------------------- The licenses from OpenStreetMap require attribution that is met, in part, by a label shown at the top left corner of the map. Two label images have been provided, one shows icons and the other shows black text on a white background. You can change between the two label styles by changing a symlink: $ cd /usr/local/share/xastir/maps/ # your installing may differ! $ rm CC_OpenStreetMap.png $ ln -s CC_OpenStreetMap_txt.png CC_OpenStreetMap.png or $ ln -S CC_OpenStreetMap_logo.png CC_OpenStreetMap.png ------------------------------------------------------------------------ Xastir-Release-2.2.4/README.developers.md0000664000175000017500000002236215151324131016754 0ustar hibbyhibby# Developer notes on creating releases Since the move to git, the old process we followed to push development snapshots and stable releases to SourceForge is no longer possible, nor especially helpful. With git and github, we are doing away with the concept of development snapshots, because one can always just download a tarball of the current repo state from github. We are also simplifying the stable release process, doing away with the difference between building a tarball release and building from a git clone. ## Development snapshots Xastir migrated to git and github instead of cvs and sourceforge, and therefore creating "development snapshots" isn't necessary, because every commit is essentially a development snapshot that can be checked out by referencing its SHA-1 hash. Furthermore, github allows users to download code as a tarball directly without needing to clone, so we need not make a duplicate process for it. ## Stable Releases Stable releases are the enduring, numbered releases that tend to make it into official package repositories (eventually). It is necessary to do more for these releases than just tag a repository state, because most package management systems require that a stable version of the code be downloadable, and don't support pulling versions-of-the-day out of source code management systems. Beginning with release 2.1.8 we stopped providing "configure" scripts and all the droppings from "bootstrap.sh" in release tarballs, and all users must now use "bootstrap.sh" as a first step in building Xastir. ### Stable release process in a nutshell - Get master ready for a release. - Update version number. - Test everything. - Tag the repo. - Push the repo and the tag to Github. - Define a release on github and associate it with the tag. - Email interested parties that there has been a release. - Go back and update the version number on master and move on. ### Stable release in gory detail - Make sure the current state of the master branch is what you want to release. This should include all documentation updates and help file updates. Only when the master branch is really ready to release do you perform the following steps. Let's assume we're creating release X.Y.Z, and that our Xastir clone and working directory is in ~/XASTIR/Xastir. - By our long-standing convention, stable releases are always even numbers in the last field of the release number, and odd numbers mean "this is a development version." So whatever version number appears in configure.ac on the master branch is going to be odd at the moment, and you're going to pick X.Y.Z so that the new Z is even. - Change the version number in configure.ac to X.Y.Z. There should no longer be any other places in the code where this version number appears, so changing it in this one place is sufficient. Commit this change: git add configure.ac git commit Mention why you're doing this in the commit message (e.g., "Update release version number"). Follow our commit log message guidance in CONTRIBUTING.md - Run bootstrap.sh or "autoreconf -i" - Make sure the program builds, and do so in a fresh build directory, just as a first-time user would have to do: mkdir build-release-check cd build-release-check ../configure [options] make cd .. If the code builds you should be in good shape, and you should also try querying the binary it produced to have it print its version: build-release-check/src/xastir -V Confirm that it is reporting the version you expect it to. It will have additional decorations indicating stuff about git, ignore those. For safety's sake, you should remove the build directory now, too. rm -rf build-release-check - You now have a working directory that should look like what we want to distribute to users. Check that there are no uncommitted changes: git status should tell you you're on master, and that you're one commit ahead of "origin/master", with nothing to commit and a clean working tree. If it says anything else, figure out why and get the current working tree to the right state, with all important changes committed properly. - Create an annotated tag marking the current state of the repo as your new release: git tag -a -m "Xastir Release X.Y.Z" Release-X.Y.Z Don't forget the "-a", as this is what allows our use of "git describe" to give the user an accurate description of what code they're running if they're running a development version later. - At this point, you are almost done, but all of your changes are only in your local repository clone. Double check that it really works by creating a tar file of your code from the tagged state, then try to build it somewhere other than in your git checkout directory: git archive --format=tar.gz --prefix=Xastir-Release-X.Y.Z/ Release-X.Y.Z > ~/src/Xastir-Release-X.Y.Z.tar.gz This process will exactly reproduce what Github will be doing when we're finished and actually create the release. Now make sure it builds: cd ~/src tar xzf Xastir-Release-X.Y.Z.tar.gz cd Xastir-Release-X.Y.Z ./bootstrap.sh # You could also use "autoreconf -i" mkdir build cd build ../configure [options] make This is strictly a sanity check to make sure that everything that's in the repository really, truly is ready to go. If you've been following good coding and testing practices and the continuous integration testing is working properly, this step isn't really necessary. But it's good to be sure. - If the sanity check above worked, you can throw away the testing tarball and unpacked code: cd ~/src rm -rf Xastir-Release-X.Y.Z Xastir-Release-X.Y.Z.tar.gz - If the sanity check did NOT work, then you need to go back to your original working directory and fix any problems you found. Commit your changes, and then MOVE THE TAG so it points to your NEW proposed release: git tag -d Release-X.Y.Z git tag -a -m "Xastir Release X.Y.Z" Release-X.Y.Z Now go back and redo the sanity check. Repeat until the tarball you created actually produces a working Xastir. - Now go back to your working directory and finish up by pushing the code and tag to Github: cd ~/XASTIR/Xastir git push origin master git push origin Release-X.Y.Z - Log in to github and go to the Xastir project releases page at http://github.com/Xastir/Xastir/releases. Click the "Draft a new release" button. Put your tag name (Release-X.Y.Z) into the dialog box that says "Tag version" and Github will display a note that it found a matching, existing tag. Fill in the rest of the form: - Give the release a name ("Xastir Release X.Y.Z") that will appear prominently above it in the releases list. - Enter some release notes in the large text box below the title where it says "Describe this release." Ideally, you should list release highlights (new features, bug fixes, etc.). Use Markdown to pretty up the text, using the Preview tab to render the markdown until it looks the way you want it to. - Click "Publish Release." - You have finished releasing the code as far as Github is concerned. This new release will now appear on the "Releases" page, along with links to tar and zip files for the source code and the release notes you just created. The fixed URL https://github.com/Xastir/Xastir/releases/latest will always point to the most recent release. The source code download link will be https://github.com/Xastir/Xastir/archive/Release-X.Y.Z/Xastir-Release-X.Y.Z.tar.gz with the obvious change for the zip version. - The last step here is to announce the new release in all the usual places. These days it is probably enough to announce it on the xastir mailing list, and possibly the aprssig and linux-hams groups. No need to spam every ham radio mailing list. On the other hand, the Xastir wiki does recommend sending notification of all releases (both development and stable) to: - xastir at xastir.org - nwaprssig at nwaprs.info - aprssig at tapr.org - aprsnews at tapr.org - macaprs at yahoogroups.com - aprs at yahoogroups.com and stable releases to: - SAR_APRS at yahoogroups.com - CSAR at yahoogroups.com - aprs at mailman.qth.net - linux-hams at vger.kernel.org - linux at tapr.org - linux-hams-using-ax25 at yahoogroups.com This list is probably excessive nowadays, and probably contains a lot of groups that are long gone. #### Getting master ready to move on All of this work got the X.Y.Z release done, which has now been finished and pushed to github. Now we need to change the version number on the master branch so that development versions show a different version than releases. - Make sure you're still in your master branch in your main clone: cd ~/src/Xastir git checkout master - Edit configure.ac and change the version number to be one higher than the release you just did. So if you just pushed release 2.1.8, set the version to 2.1.9. - Commit this change and push it to github. git add configure.ac git commit git push The release is done, and now the repo is ready for further development. Xastir-Release-2.2.4/README.md0000664000175000017500000002561515151324131014611 0ustar hibbyhibby# README > [!IMPORTANT] > > This document makes a lot of references to the Xastir > wiki and mailing lists at xastir.org. At this time (December 2025) > that site is experiencing frequent downtime and may be unavailable. > This is being worked on. > > In the meantime, we have been trying to expand the documentation > available in the wiki on GitHub. Please look there first, as much > of the information on the xastir.org site is outdated. The > information on the Github wiki is very incomplete, but what is there > is more up-to-date than what's on the xastir.org wiki. > > Please use Github issues to report bugs and Github Discussions to > open topics of conversation until we get the mailing lists back on line. ------------------------------------------------------------------------ Please at least SKIM this document before asking questions. In fact, READ IT if you've never successfully set up Xastir before. PLEASE! READ IT! If you haven't read this file, and ask for help expect to be told to READ the README file first! or RTFM :) Contents: 0. Important notice 1. What is Xastir? 2. How do I get Xastir & Git usage 3. Quick startup 4. Upgrading 5. Identification notes 6. OS-specific notes 7. Gating weather alerts 8. Boring legal stuff 9. Mailing list 10. Documentation 11. Obtaining help ------------------------------------------------------------------------ 0. NOTICE Please read this file carefully before trying to set up Xastir. This software was developed to be used by licensed amateur radio operators. You are responsible for any information transmitted or propagated on any network. 1. WHAT IS XASTIR? Xastir is an open-source project to create a free X11 graphical APRS(tm) client. APRS(tm) use amateur radio and Internet services to convey GPS mapping, weather, and positional data in a graphical application. It has been developed by and for amateur radio enthusiasts to provide real-time data in an easy to use package. Xastir currently runs under several flavors of Linux and BSD Unix. A few people are running Xastir on Solaris Unix, FreeBSD, Lindows and Mac OS X, but there may be small changes necessary in order to get Xastir to configure/compile on some systems. There are a few notes below which may help in this task. Most of the developers use Linux which makes it the best supported platform at the moment. Xastir is an open-source project: Most sources, documentation, and binaries are available under the GPL license, with a few modules available under other open-source or public domain licenses. More information on Xastir can be found here: * https://github.com/Xastir/Xastir/wiki * http://github.com/Xastir * http://xastir.org including the latest releases, Git access (lets you download the latest developers' code), and information on how to join Xastir mailing lists. Note that you must be subscribed in order to post to the mailing lists. SmartBeaconing(tm) was invented by Tony Arnerich (KD7TA) and Steve Bragg (KA9MVA) for the HamHUD project. They offer the algorithm to other authors as long as proper credit is given and the term SmartBeaconing(tm) is used. Thanks to Tony and Steve for that contribution! -- The Xastir Group. 2. HOW TO GET XASTIR Xastir is currently developed at You can get the latest version of Xastir from there. You might try for help and information, particularly the Xastir mailing list (listed near the bottom of the page). * Git USAGE Obtain the *very latest* version of Xastir under development by using Git. See the file [README.GIT](README.GIT.md) for more details. * Release version tarballs You can get the latest packaged release source code without git at https://github.com/Xastir/Xastir/releases. Be warned that packaged source tarballs may be quite old and not representative of the current state of the project. We highly recommend not using this method unless you have a specific reason to stick to official releases. 3. QUICK STARTUP Please see the [Xastir wiki at github](https://github.com/Xastir/Xastir/wiki) for the most up-to-date documentation on getting started with Xastir. See [INSTALL.md](INSTALL.md) for a relatively quick overview of how to build and use Xastir. The Xastir wiki (http://xastir.org) might have OS-specific guidance for building Xastir on your system. WINDOWS USERS: Please refer to the [README.CYGWIN](README.CYGWIN) file for specific instructions. 4. UPGRADING Upgrading Xastir that has been built from a recent Git clone is as simple as running "git pull" in the source tree and recompiling. 5. IDENTIFICATION NOTES Packet radio modes, by their very nature, typically identify themselves with every transmission. Xastir has a few features targeted to people who used Xastir in demonstrations and other broadcasts where Xastir itself is used over radio. Xastir can auto-ID via voice if Festival is compiled in and/or via a message splashed across the screen. It does this identification every 9.5 minutes if enabled. These identification modes were designed for broadcasting Xastir across fast-scan television (for events perhaps). Set the "ATV_SCREEN_ID" variable to 1 to enable the screen message, and "SPEAK_ID" variable to 1 to enable festival to speak the message. These variables are in the ~/.xastir/config/xastir.cnf file. 6. OS SPECIFIC NOTES There are some OS-specific installation notes at https://github.com/Xastir/Xastir/wiki. We are working on expanding the section. There are more OS-specific installation notes at http://xastir.org in the "Installation Notes" section for OS-specific build guidance. Some are very outdated, but may still be helpful. 7. GATING WEATHER ALERTS, STATIONS, OBJECTS/ITEMS TO RF ## Gating NWS Weather Alerts to RF: If you wish to gate NWS weather alerts from the Internet onto RF, you'll need to create a text file in the users directory as ~/.xastir/data/nws-stations.txt List each NWS station that you would like to transmit via RF. Wildcards are implied for lengths of 3 or greater. Here's what an example file looks like: # # Seattle, WA SEANPW # # Portland, OR (any alert type) PDX # # Pendleton, OR PDTNPW # # Medford, OR MFRNPW # All text should start at the beginning of the line. Once that file is in place, you'll need to hook up to at least one Internet server that is feeding you the weather alerts. You'll also need to have at least one RF interface up and running with transmit enabled on that interface. Make sure that "Interfaces->Disable Transmit: All" is not selected. You should now be gating NWS weather messages to RF. Turn on igate logging and look at that log file to view what you're sending out via RF. Don't forget to turn off logging or set up auto-rollover of the log files, else your hard drive might fill up with logging info. Auto-rollover of log files is typically accomplished via CRON. ## Gating Stations, Objects/Items to RF: The latest code also allows gating packets from specific stations to RF using the above method (except object/item packets). You can also gate objects/items to RF by name. The same wildcarding rules apply as listed above. Callsigns or object/item names listed in this file are case-insensitive, so they'll match any case in received packets. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.aprs.org/aprs-jota.txt 8. BORING LEGAL STUFF Xastir is Copyright by Frank Giannandrea. Xastir is distributed according to the GNU General Public License. There should be a copy of this license in the file COPYING. If not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. As of Xastir 0.4.0 all changes made by the Xastir development team to the Xastir source code and any related files are Copyright (C) 2000-2026 The Xastir Group. The source code will still be distributed according to the GNU General Public License as Frank Giannandrea did in the past. There is no warranty, implied or whatever. You use this software at your own risk, no matter what purpose you put it to. You didn't pay for it, so don't expect magic. 9. MAILING LIST >[!NOTE] > While there is hope that it may be restored, at the moment the > mailing lists described in this section are down with no ETA > on the restoration. Please use the "Discussions" section on Github > to ask questions or post comments instead. Please use the Issues > section for bug reports. There are currently a couple of mailing lists about Xastir. xastir@xastir.org is the one relevant for most users. The xastir@xastir.org mail-list is dedicated to Bug reports, technical questions, your thoughts or suggestions on new features being added to Xastir, things that should be removed or fixed, amazing problems that even stump the guru's, etc... are what we want to see here. You must be subscribed to the list in order to post messages. To subscribe to the Xastir mailing list, send email to: xastir-request@xastir.org In the body of the message, put "subscribe xastir"; or go to http://xastir.org and click on "XASTIR MAILING LISTS" (in the "Resources" section near the bottom) to subscribe. Please, before posting to this list, see what things are like, and when you do post, read over your post for readability, spelling, and grammar mistakes. Obviously, we're all human (or are we?) and we all make mistakes (heck, look at this document! ;). Open discussion and debate is integral to change and progress. Don't flame others over mere form (grammar and spelling), or even substantive issues either for that matter. Please read and follow the mailing list rules. A second mailing list, xastir-dev@xastir.org is intended for developer's discussion. 10. DOCUMENTATION We're trying to get the documentation up to date. If you feel that anything is missing here, or that anything should be added etc, please email xastir@xastir.org about it, thank you. 11. OBTAINING HELP Please read the file FAQ, and make sure you've followed any relevant instructions in INSTALL. If the problem still exists, feel free to ask on the Xastir mailing-list, as described above. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/README.sudo0000664000175000017500000000555515151324131015164 0ustar hibbyhibbySUDO Instructions: ------------------ "sudo" is a command that can make your life much simpler. After you set it up that is! By adding a couple of lines to your /etc/sudoers file (using the "visudo" command to edit this file), you'll be able to run a few commands as root without having to type the root password each time. Another thing you can do at that point is automate the entire "git pull; mkdir -p build; cd build; ../configure; su; make install" process via a script. Here's how to set all of this up: Type "su" to become the root user, then type "visudo". This will bring up the "vi" editor on the /etc/sudoers file. If you'd like to learn more about what I'm going to describe, type "man sudoers" in another window and read about this file. Another man-page that is useful here is the "man sudo" page. Back to the editing: There's a section in there for user alias. Mine is labeled "# User alias specification". Add a line there that reads like this: User_Alias XASTIR = username1, username2, username3 where username1, etc, are valid usernames that you wish to be able to do Xastir installs. For instance you might have: User_Alias XASTIR = mikey Next, add a line near the bottom that reads like this: XASTIR ALL = NOPASSWD: /bin/chmod, /usr/bin/make Now write out and close the file. At this point the "mikey" user will have root permissions when he/she runs the commands "/bin/chmod" or "/usr/bin/make". Make sure the paths to those programs are correct for your system. Exit from "su" so that you're a regular (non-root) user again. To update xastir when the upstream sources have changed, one need only pull the updated source code and rebuild the code. The process is: git pull autoreconf -i mkdir -p build # actually any new, empty directory will do cd build ../configure [options needed to help configure find dependencies] sudo make clean sudo make install sudo chmod 4755 /usr/local/bin/xastir This is actually overly conservative, as it forces a full rebuild of Xastir after each git update. You can keep your build directories around and just rerun configure and make in them and make will only recompile files that have changed. Windows users: You may need to remove the "sudo" keyword on each line to have it work properly for you. A note from Gerry Creager as to another way to set up the sudoers file: "I now consider it a good idea to add the "gifted" users to the 'wheel' group and then solely enable wheel in /etc/sudoers; I've seen a recent article also supporting this." ------------------------------------------------------------------------ Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/Regional.geo0000664000175000017500000000026315151324131015556 0ustar hibbyhibbyWMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Regional Xastir-Release-2.2.4/Sub_national.geo0000664000175000017500000000026715151324131016440 0ustar hibbyhibbyWMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_national Xastir-Release-2.2.4/Sub_regional.geo0000664000175000017500000000026715151324131016433 0ustar hibbyhibbyWMSSERVER URL http://geogratis.gc.ca/maps/CBMT?service=wms&version=1.1.1&request=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=Sub_regional Xastir-Release-2.2.4/USTigermap.geo0000664000175000017500000000173715151324131016045 0ustar hibbyhibbyWMSSERVER # # Census changed layer names from text to numbers. # these numbers correspond to: #Primary Roads (24) #Primary Roads Labels (23) #Secondary Roads #Secondary Roads Labels #Local Roads #Local Roads Labels #Railroads #Railroads Labels #Linear Hydrography #Linear Hydrography Labels #Areal Hydrography #Areal Hydrography Labels #Glaciers #Glaciers Labels #National Park Service Areas #National Park Service Areas Labels #Military Installations (2) #Military Installations Labels (1) # When in doubt, use the GetCapabilities request to check: #https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_PhysicalFeatures/MapServer/WMSServer?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetCapabilities URL https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_PhysicalFeatures/MapServer/WMSServer?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=1,2,7,8,10,11,12,13,14,15,17,18,19,20,21,22,23,24&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE #TRANSPARENT 0x999999 Xastir-Release-2.2.4/USTigermapBorders.geo0000664000175000017500000000074015151324131017357 0ustar hibbyhibbyWMSSERVER # # Census now uses numbers for layer numbers, not names. # Use #https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_Current/M\ apServer/WMSServer?VERSION=1.3.0&SERVICE=WMS&REQUEST=GetCapabilities # to list them URL https://tigerweb.geo.census.gov/arcgis/services/TIGERweb/tigerWMS_Current/MapServer/WMSServer?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=48,49,12,13,10,11&STYLES=&FORMAT=image/png&TRANSPARENT=TRUE TRANSPARENT 0x999999 Xastir-Release-2.2.4/WMS_USGS_Hydrography.geo0000664000175000017500000000034415151324131017705 0ustar hibbyhibbyWMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSHydroCached/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.4/WMS_USGS_ImageryOnly.geo0000664000175000017500000000034315151324131017643 0ustar hibbyhibbyWMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSImageryOnly/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.4/WMS_USGS_ImageryTopo.geo0000664000175000017500000000034315151324131017643 0ustar hibbyhibbyWMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSImageryTopo/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.4/WMS_USGS_ShadedReliefOnly.geo0000664000175000017500000000035015151324131020563 0ustar hibbyhibbyWMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSShadedReliefOnly/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 Xastir-Release-2.2.4/WMS_USGS_Topo.geo0000664000175000017500000000033615151324131016327 0ustar hibbyhibbyWMSSERVER URL https://basemap.nationalmap.gov:443/arcgis/services/USGSTopo/MapServer/WmsServer?service=WMS&VERSION=1.1.1&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE&STYLES=&LAYERS=0 # Xastir-Release-2.2.4/acinclude.m40000664000175000017500000007626715151324131015534 0ustar hibbyhibby# acinclude.m4 for Xastir # # Copyright (C) 2000-2026 The Xastir Group # # test for devices. Avoid the tests on Cygwin as they hang on some # WinXP boxes. # AC_DEFUN([XASTIR_DETECT_DEVICES], [ AC_MSG_CHECKING([for devices]) if test -d /proc/registry ; then ac_tnc_port=/dev/ttyS0 ac_gps_port=/dev/ttyS1 elif test -c /dev/cuaa0 ; then ac_tnc_port=/dev/cuaa0 ac_gps_port=/dev/cuaa1 elif test -c /dev/ttyS0 ; then ac_tnc_port=/dev/ttyS0 ac_gps_port=/dev/ttyS1 elif test -c /dev/cua/a ; then ac_tnc_port=/dev/cua/a ac_gps_port=/dev/cua/b else ac_tnc_port=none ac_gps_port=none fi AC_DEFINE_UNQUOTED([TNC_PORT], "$ac_tnc_port", [Default TNC port.]) AC_DEFINE_UNQUOTED([GPS_PORT], "$ac_gps_port", [Default GPS port.]) AC_MSG_RESULT(found $ac_tnc_port and $ac_gps_port) ]) # add search paths AC_DEFUN([XASTIR_ADD_SEARCH_PATHS], [ AC_MSG_CHECKING([for search paths]) test -d /usr/local/include && CPPFLAGS="-I/usr/local/include $CPPFLAGS" test -d /usr/local/lib && LDFLAGS="-L/usr/local/lib $LDFLAGS" for d in /sw /opt /opt/local /usr/dt/share /usr/sfw /opt/sfw; do test -d $d/include && CPPFLAGS="$CPPFLAGS -I$d/include" test -d $d/lib && LDFLAGS="$LDFLAGS -L$d/lib" done AC_MSG_RESULT([done]) ]) # add compiler flags AC_DEFUN([XASTIR_COMPILER_FLAGS], [ # brutal! # check for sed maybe? if test "$ac_cv_prog_ac_ct_CC" = "gcc"; then gcc --help | sed -e "/^[^ ]/d" -e "/^ [^ ]/d" -e "/^ [^-]/d" -e "s/ //" -e "s/ .*//" > gccflags # I need a test for -Wno-return-type and -DFUNCPROTO=15 # before adding them for f in -no-cpp-precomp -pipe; do grep -- $f gccflags > /dev/null && CFLAGS="$CFLAGS $f" done # delete temporary file rm -f gccflags # add any other flags that aren't added earlier # Can't add "-Wno-unused-parameter" as older compilers don't like # it. # for f in -W -Wall -Wpointer-arith -Wstrict-prototypes; do echo $CFLAGS | grep -- $f > /dev/null || CFLAGS="$CFLAGS $f" done # Now check whether to use -Wno-unused-parameter (gcc 3) or -Wno-unused AC_MSG_CHECKING([whether compiler accepts -Wno-unused-parameter]) save_CFLAGS=$CFLAGS CFLAGS="$CFLAGS -Wno-unused-parameter" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[]], [[int i;]])], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no, using -Wno-unused]); CFLAGS="$save_CFLAGS -Wno-unused"]) # end gcc-specific checks fi # add any pthread flags now CFLAGS="$CFLAGS $PTHREAD_CFLAGS" AC_MSG_CHECKING([for compiler flags]) AC_MSG_RESULT(using $CFLAGS) ]) AC_DEFUN([XASTIR_DETECT_BINARIES], [ BINPATH=$PATH for d in / /usr /usr/local /usr/X11 /usr/X11R6 /usr/sfw /opt/sfw /opt/local /sw; do test -d $d/bin && echo $BINPATH | grep -- $d/bin > /dev/null || BINPATH="$BINPATH:$d/bin" done # it would be much nicer to do this in a for loop AC_PATH_PROG(gm, [gm version], no, $BINPATH) AC_CHECK_FILE(/usr/bin/gm.exe, gm="/usr/bin/gm") if test "$gm" != "no"; then AC_DEFINE_UNQUOTED(HAVE_CONVERT, 1, [Define if you have gm or convert]) AC_DEFINE_UNQUOTED(CONVERT_PATH, "${gm} convert", [Path to gm or convert]) else AC_PATH_PROG(convert, [convert --version], no, $BINPATH) AC_CHECK_FILE(/usr/bin/convert.exe, convert="/usr/bin/convert") if test "$convert" != "no"; then AC_DEFINE_UNQUOTED(HAVE_CONVERT, 1, [Define if you have convert]) AC_DEFINE_UNQUOTED(CONVERT_PATH, "${convert}", [Path to convert]) fi fi AC_PATH_PROG(lpr, [lpr /dev/null], no, $BINPATH) if test "$lpr" != "no"; then AC_DEFINE_UNQUOTED(HAVE_LPR, 1, [Define if you have lpr]) AC_DEFINE_UNQUOTED(LPR_PATH, "${lpr}", [Path to lpr]) fi #Find gv executable AC_PATH_PROG(gv, [gv], no, $BINPATH) if test "$gv" != "no"; then # Test gv version AC_MSG_CHECKING([gv version]) gv_new="no"; gv_version=`gv --version` gv_test=`echo $gv_version | cut -d ' ' -f 1` if test "$gv_test" != "gv"; then gv_version=`gv -v` fi gv_test=`echo $gv_version | cut -d ' ' -f 1` if test "$gv_test" != "gv"; then # No gv found. Put an AC_PATH_PROG here so the "then" clause has # something to do and so that we get proper output to the user. AC_MSG_RESULT([gv version test likely exited with error, this is what it said: $gv_version]) else gv_short_version=`echo $gv_version | cut -d ' ' -f 2` gv_major=`echo $gv_short_version | cut -d '.' -f 1` gv_minor=`echo $gv_short_version | cut -d '.' -f 2` gv_tiny=`echo $gv_short_version | cut -d '.' -f 3` if test "$gv_major" -gt 3; then gv_new="yes"; elif test "$gv_major" -ge 3 -a "$gv_minor" -gt 6; then gv_new="yes"; elif test "$gv_major" -ge 3 -a "$gv_minor" -ge 6 -a "$gv_tiny" -ge 1; then gv_new="yes"; fi if test "$gv_new" != "no"; then AC_MSG_RESULT([new, >= 3.6.1]) AC_DEFINE_UNQUOTED(HAVE_GV, 1, [Define if you have gv]) AC_DEFINE_UNQUOTED(HAVE_NEW_GV, 1, [Define if you have old gv]) AC_DEFINE_UNQUOTED(GV_PATH, "${gv}", [Path to gv]) else AC_MSG_RESULT([old, pre 3.6.1]) AC_DEFINE_UNQUOTED(HAVE_GV, 1, [Define if you have gv]) AC_DEFINE_UNQUOTED(HAVE_OLD_GV, 1, [Define if you have old gv]) AC_DEFINE_UNQUOTED(GV_PATH, "${gv}", [Path to gv]) fi fi fi if test "$use_festival" != "no"; then AC_PATH_PROG(festival, [festival], no, $BINPATH) if test "$festival" != "no"; then AC_DEFINE_UNQUOTED(HAVE_FESTIVAL, 1, [Define if you have festival]) fi fi if test "$use_gpsman" != "no"; then AC_PATH_PROG(gpsman, [gpsman haslib gpsmanshp], no, $BINPATH) if test "$gpsman" != "no"; then AC_DEFINE_UNQUOTED(HAVE_GPSMAN, 1, [Define if you have gpsman]) AC_DEFINE_UNQUOTED(GPSMAN_PATH, "${gpsman}", [Path to gpsman]) fi fi if test "$use_err_popups" != "no"; then AC_DEFINE_UNQUOTED(HAVE_ERROR_POPUPS, 1, [Define if you have error popups enabled]) fi ]) AC_DEFUN([XASTIR_CHECK_POSTGIS], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # test for postgresql if test "${with_postgis+set}" = set; then PG_CONFIG="pg_config" if test "$with_postgis" != "yes"; then # get path if provided pg_path="$with_postgis" PG_CONFIG_PATH="${pg_path}/bin" BINPATH="${BINPATH}:${PG_CONFIG_PATH}" POSTGIS_LIB_DIR="-L${pg_path}/lib" AC_PATH_PROG(PG_CONFIG, [pg_config], no, $PG_CONFIG_PATH) else AC_PATH_PROG(PG_CONFIG, [pg_config], no) fi if test "$PG_CONFIG" != "no"; then # Check for postgis spatial extensions. # Look for lwpostgis.sql script in default location. # If found, is likely a postgis installation. # Need more definitive test for postgis, as this may fail to detect postgres # installations where this script was removed, and will incorrectly # detect postgres without postgis where this script has been installed but not run. AC_PATH_PROG(LWPOSTGIS, [lwpostgis.sql], no, "${pg_path}/share") if test "LWPOSTGIS" != "no"; then #postgres with postgis enabled use_postgis=yes use_spatial_db=yes save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" CPPFLAGS="$CPPFLAGS -I`${PG_CONFIG} --includedir` `${PG_CONFIG} --cppflags`" CXXFLAGS="$CXXFLAGS `${PG_CONFIG} --cflags`" LDFLAGS="$LDFLAGS `${PG_CONFIG} --ldflags`" LIBS="${POSTGIS_LIB_DIR} `${PG_CONFIG} --libs` -lpq $LIBS" AC_DEFINE(HAVE_POSTGIS, 1, Postgresql with postgis is present. ) else AC_MSG_WARN(*** Cannot find lwpostgis.sql: Building w/o Postgresql/Postgis support. ***) AC_MSG_WARN(*** Postgresql was found, but does not appear to have Postgis added. ***) AC_MSG_WARN(*** Install and enable postgis and leave the lwpostgis.sql script in ***) AC_MSG_WARN(*** ${pg_path}/share ***) fi else use_postgis=no AC_MSG_WARN(*** Cannot find pg_config: Building w/o Postgresql/Postgis support. ***) AC_MSG_WARN(*** Specify the path to the posgresql installation directory ***) AC_MSG_WARN(*** For example: --with-postgis=/usr/local/pgsql ***) fi fi ]) AC_DEFUN([XASTIR_CHECK_MYSQL], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # test for MySQL if test "${with_mysql+set}" = set; then MYSQL_CONFIG="mysql_config" if test "$with_mysql" != "yes"; then # get path to mysql_config if provided mysql_path="$with_mysql" BINPATH="${BINPATH}:${mysql_path}" AC_PATH_PROG(MYSQL_CONFIG, [mysql_config], no, $mysql_path) else AC_PATH_PROG(MYSQL_CONFIG, [mysql_config], no) fi use_mysql_spatial=no use_mysql_any=no if test "$MYSQL_CONFIG" != "no"; then # check for mysql version with spatial support # look for mysql 4.1.2 or greater for spatial support # and standardized prepared statements # 4.1.0 and 4.1.1 have spatial support, but only early versions # of prepared statement functions that changed in 4.1.2 AC_MSG_CHECKING([mysql version >= 4.1.2]) mysqlversion=`$MYSQL_CONFIG --version` mysqlversionmajor=`echo ${mysqlversion} | cut -d '.' -f 1` mysqlversionminor=`echo ${mysqlversion} | cut -d '.' -f 2` mysqlversiontiny=`echo ${mysqlversion} | cut -d '.' -f 3` if test "$mysqlversionmajor" -gt 4 ; then mysql_has_spatial="yes" elif test "$mysqlversionmajor" -ge 4 -a "$mysqlversionminor" -gt 1 ; then mysql_has_spatial="yes" elif test "$mysqlversionmajor" -ge 4 -a "$mysqlversionminor" -ge 1 -a "$mysqlversiontiny" -ge 2 ; then mysql_has_spatial="yes" else mysql_has_spatial="no" fi AC_MSG_RESULT($mysql_has_spatial) # if mysql version < 4.1, mysql present but no spatial support if test "$mysql_has_spatial" = "yes"; then # mysql with spatial support use_mysql_spatial=yes use_spatial_db=yes AC_DEFINE(HAVE_MYSQL_SPATIAL, 1, MySQL with spatial support is present.) else AC_MSG_WARN(*** MySQL version $mysqlversion detected is < 4.1.2 ***) AC_MSG_WARN(*** Spatial support enabled only for MySQL 4.1.2 and higher ***) AC_MSG_WARN(*** MySQL support for Lat/Long fields is available but ***) AC_MSG_WARN(*** not for Points Polygons or other spatial objects. ***) fi save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" CPPFLAGS="$CPPFLAGS `${MYSQL_CONFIG} --cflags`" CXXFLAGS="$CXXFLAGS `${MYSQL_CONFIG} --cflags`" LIBS=" `${MYSQL_CONFIG} --libs` $LIBS" use_mysql_any=yes AC_DEFINE(HAVE_MYSQL, 1, MySQL is present.) else AC_MSG_WARN(*** Cannot find mysql_config: Building w/o MySQL support. ***) AC_MSG_WARN(*** Specify the path to mysql_config ***) AC_MSG_WARN(*** For example: --with-mysql=/var/lib/mysql ***) fi fi #AC_MSG_RESULT($use_mysql_spatial) ]) AC_DEFUN([XASTIR_CHECK_IMAGEMAGICK], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # Check for ImageMagick # # First look for the needed Magick-config script, which tells us all # of the build options we need. # # Important: DO NOT use "use_imagemagick" as the variable here, # because AC_CHECK_PROG will do nothing if the variable is already set! # use_imagemagick=no AC_PATH_PROG(MAGIC_BIN, [MagickCore-config], no, $BINPATH) if test "$MAGIC_BIN" != "no"; then use_imagemagick=yes else AC_PATH_PROG(MAGIC_BIN, [Magick-config], no, $BINPATH) if test "$MAGIC_BIN" != "no"; then use_imagemagick=yes fi # AC_MSG_WARN(*** Cannot find Magick-config: Building w/o ImageMagick support. ***) fi if test "${use_imagemagick}" = "yes"; then # # # # Compute the ImageMagick revision number # # # magickversion=`${MAGIC_BIN} --version` # magickmajor=`echo $magickversion | cut -d '.' -f 1` # magickminor=`echo $magickversion | cut -d '.' -f 2` # magicktiny=`echo $magickversion | cut -d '.' -f 3` # if test "$magickmajor" -lt 5; then # magickold="yes"; # elif test "$magickmajor" -eq 5 -a "$magickminor" -lt 4; then # magickold="yes"; # elif test "$magickmajor" -eq 5 -a "$magickminor" -eq 4 -a "$magicktiny" -lt 9; then # magickold="yes"; # fi # save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" # # Figure out the build options using the Magick-config script # CPPFLAGS="$CPPFLAGS `${MAGIC_BIN} --cppflags`" CXXFLAGS="$CXXFLAGS `${MAGIC_BIN} --cflags`" LDFLAGS="$LDFLAGS `${MAGIC_BIN} --ldflags`" LIBS="${MAGIC_LIB_DIR} `${MAGIC_BIN} --libs` $LIBS" # AC_CHECK_HEADERS([MagickCore/MagickCore.h],[use_imagemagick="yes"], [AC_CHECK_HEADERS([magick/api.h],[use_imagemagick="yes"], [use_imagemagick="no"])]) if test "${use_imagemagick}" = "no" then AC_MSG_WARN([*** Cannot find ImageMagick include files: Building w/o ImageMagick support. ***]) else AC_MSG_CHECKING([if your ImageMagick is old enough for us to use]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #include #endif #if (MagickLibVersion > 0x0700) #error Your Magick is way too new #endif ])],[AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_WARN([***Your ImageMagick is too new and Xastir cannot use it***]) use_imagemagick="no" ]) if test "${use_imagemagick}" = "yes" then AC_SEARCH_LIBS([WriteImage],[Magick MagickCore], [AC_DEFINE(HAVE_IMAGEMAGICK, 1, [Imagemagick image library])], [use_imagemagick="no"]) if test "${use_imagemagick}" = "no" then AC_MSG_WARN(*** Cannot find ImageMagick library files: Building w/o ImageMagick support. ***) fi fi fi # if test "${use_imagemagick}" = "no"; then # # No ImageMagick found. Restore variables. # CPPFLAGS=$save_cppflags CXXFLAGS=$save_cxxflags LIBS=$save_libs LDFLAGS=$save_ldflags fi fi # End of ImageMagick checks ]) AC_DEFUN([XASTIR_CHECK_GRAPHICSMAGICK], [ BINPATH="${PATH}${EXTRA_BIN_PATH}" # Check for GraphicsMagick # # First look for the needed GraphicsMagick-config script, which tells us all # of the build options we need. # # Important: DO NOT use "use_graphicsmagick" as the variable here, # because AC_CHECK_PROG will do nothing if the variable is already set! # use_graphicsmagick=no AC_PATH_PROG(GMAGIC_BIN, [GraphicsMagick-config], no, $BINPATH) if test "$GMAGIC_BIN" != "no"; then use_graphicsmagick=yes #else # AC_MSG_WARN(*** Cannot find GraphicsMagick-config: Building w/o GraphicsMagick support. ***) fi # if test "${use_graphicsmagick}" = "yes"; then save_cppflags="$CPPFLAGS" save_cxxflags="$CXXFLAGS" save_cflags="$CFLAGS" save_libs="$LIBS" save_ldflags="$LDFLAGS" # # Figure out the build options using the GraphicsMagick-config script # CPPFLAGS="`${GMAGIC_BIN} --cppflags` $CPPFLAGS" CXXFLAGS="`${GMAGIC_BIN} --cflags` $CXXFLAGS" CFLAGS="`${GMAGIC_BIN} --cflags` $CFLAGS" LDFLAGS="`${GMAGIC_BIN} --ldflags` $LDFLAGS" LIBS="${MAGIC_LIB_DIR} `${GMAGIC_BIN} --libs` $LIBS" # AC_CHECK_HEADERS([magick/api.h], [use_graphicsmagick="yes"],[use_graphicsmagick="no"]) if test "${use_graphicsmagick}" = "no"; then AC_MSG_WARN(*** Cannot find GraphicsMagick include files: Building w/o GraphicsMagick support. ***) else AC_CHECK_LIB([GraphicsMagick], [WriteImage], AC_DEFINE(HAVE_GRAPHICSMAGICK, 1, [GraphicsMagick image library]), use_graphicsmagick="no") if test "${use_graphicsmagick}" = "no"; then AC_MSG_WARN(*** Cannot find GraphicsMagick library files: Building w/o GraphicsMagick support. ***) fi fi # if test "${use_graphicsmagick}" = "no"; then # # No GraphicsMagick found. Restore variables. # CPPFLAGS=$save_cppflags CXXFLAGS=$save_cxxflags CFLAGS=$save_cflags LIBS=$save_libs LDFLAGS=$save_ldflags fi fi # # End of GraphicsMagick checks ]) # things grabbed elsewhere # this is from Squeak-3.2-4's acinclude.m4 AC_DEFUN([AC_CHECK_GMTOFF], [AC_CACHE_CHECK([for gmtoff in struct tm], ac_cv_tm_gmtoff, [AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [struct tm tm; tm.tm_gmtoff;])], ac_cv_tm_gmtoff="yes", ac_cv_tm_gmtoff="no")]) test "$ac_cv_tm_gmtoff" != "no" && AC_DEFINE(HAVE_TM_GMTOFF,,X)]) dnl Available from the GNU Autoconf Macro Archive at: dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html dnl AC_DEFUN([ACX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) acx_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) AC_MSG_RESULT($acx_pthread_ok) if test x"$acx_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all. acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # pthread: Linux, etcetera # --thread-safe: KAI C++ case "${host_cpu}-${host_os}" in *solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthread or # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" ;; esac if test x"$acx_pthread_ok" = xno; then for flag in $acx_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[pthread_t th; pthread_join(th, 0); pthread_attr_init(0); pthread_cleanup_push(0, 0); pthread_create(0,0,0,0); pthread_cleanup_pop(0);]])], [acx_pthread_ok=yes], [acx_pthread_ok=no]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT($acx_pthread_ok) if test "x$acx_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$acx_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: threads are created detached by default # and the JOINABLE attribute has a nonstandard name (UNDETACHED). AC_MSG_CHECKING([for joinable pthread attribute]) AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[int attr=PTHREAD_CREATE_JOINABLE;]])], [ok=PTHREAD_CREATE_JOINABLE], [ok=unknown]) if test x"$ok" = xunknown; then AC_LINK_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[int attr=PTHREAD_CREATE_UNDETACHED;]])], [ok=PTHREAD_CREATE_UNDETACHED], [ok=unknown]) fi if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, [Define to the necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_RESULT(${ok}) if test x"$ok" = xunknown; then AC_MSG_WARN([we do not know how to create joinable pthreads]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case "${host_cpu}-${host_os}" in *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";; *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; esac AC_MSG_RESULT(${flag}) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: must compile with cc_r AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) else PTHREAD_CC="$CC" fi AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_CC) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$acx_pthread_ok" = xyes; then ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) : else acx_pthread_ok=no $2 fi AC_LANG_POP([C]) ])dnl ACX_PTHREAD # AC_DEFUN([XASTIR_PATH_MOTIF], [ # New stuff to check for Motif/Lesstif. Shamelessly borrowed from # the opendx project. Opendx in turn snarfed their test from AC_PATH_X. # Allow "--with-motif-includes" and "--with-motif-libs" so user can # force a specific set of includes. AC_ARG_WITH(motif-includes, [ --with-motif-includes Set path for motif includes (default none)],[with_motif_includes=$withval], [with_motif_includes=]) if test "$with_motif_includes" != "yes" && test -z "$with_motif_includes" then with_motif_includes= fi AC_ARG_WITH(motif-libs, [ --with-motif-libs Set path for motif libraries (default none)],[with_motif_libs=$withval], [with_motif_libs=]) if test "$with_motif_libs" != "yes" && test -z "$with_motif_libs" then with_motif_libs= fi # Guess where to find include files, by looking for this one Xm .h file. test -z "$xm_direct_test_include" && xm_direct_test_include=Xm/Xm.h # First, try using that file with no special directory specified. AC_MSG_CHECKING([for Motif headers]) AC_PREPROC_IFELSE( [AC_LANG_SOURCE([[#include <$xm_direct_test_include>]])], [ # We can compile using X headers with no special include directory. xm_includes= AC_MSG_RESULT([in default path]) ],[ # that test didn't work, we need to hunt a little # Look for the header file in a standard set of common directories. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in \ /usr/X11/include \ /usr/X11R6/include \ /usr/X11R5/include \ /usr/X11R4/include \ \ /usr/include/X11 \ /usr/include/X11R6 \ /usr/include/X11R5 \ /usr/include/X11R4 \ \ /usr/local/X11/include \ /usr/local/X11R6/include \ /usr/local/X11R5/include \ /usr/local/X11R4/include \ \ /usr/local/include/X11 \ /usr/local/include/X11R6 \ /usr/local/include/X11R5 \ /usr/local/include/X11R4 \ \ /usr/X386/include \ /usr/x386/include \ /usr/XFree86/include/X11 \ \ /usr/include \ /usr/local/include \ /usr/unsupported/include \ /usr/athena/include \ /usr/local/x11r5/include \ /usr/lpp/Xamples/include \ \ /usr/openwin/include \ /usr/openwin/share/include \ "$with_motif_includes" \ ; \ do if test -r "$ac_dir/$xm_direct_test_include"; then xm_includes=$ac_dir AC_MSG_RESULT([in $xm_includes]) break fi done if test "x$xm_includes" = "x"; then AC_MSG_ERROR([**** NO MOTIF HEADERS FOUND **** install Motif development headers or use --with-motif-includes to specify location of Xm/Xm.h ]) fi ]) # Check for the libraries. AC_MSG_CHECKING([for Motif libraries]) test -z "$xm_direct_test_library" && xm_direct_test_library=Xm test -z "$xm_direct_test_function" && xm_direct_test_function=XmGetDestination # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS="$LIBS" LIBS="-l$xm_direct_test_library $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM([ [#include <$xm_direct_test_include> #include ]], [[Display *foobar; ${xm_direct_test_function}(foobar)]])], [ LIBS="$ac_save_LIBS" # We can link Motif programs with no special library path. xm_libraries= AC_MSG_RESULT([in default path]) ],[ LIBS="$ac_save_LIBS" # First see if replacing the include by lib works. # Check X11 before X11Rn because it is often a symlink to the current release. for ac_dir in `echo "$xm_includes" | sed s/include/lib/` \ /usr/X11/lib \ /usr/X11R6/lib \ /usr/X11R5/lib \ /usr/X11R4/lib \ \ /usr/lib/X11 \ /usr/lib/X11R6 \ /usr/lib/X11R5 \ /usr/lib/X11R4 \ \ /usr/local/X11/lib \ /usr/local/X11R6/lib \ /usr/local/X11R5/lib \ /usr/local/X11R4/lib \ \ /usr/local/lib/X11 \ /usr/local/lib/X11R6 \ /usr/local/lib/X11R5 \ /usr/local/lib/X11R4 \ \ /usr/X386/lib \ /usr/x386/lib \ /usr/XFree86/lib/X11 \ \ /usr/lib \ /usr/local/lib \ /usr/unsupported/lib \ /usr/athena/lib \ /usr/local/x11r5/lib \ /usr/lpp/Xamples/lib \ /lib/usr/lib/X11 \ \ /usr/openwin/lib \ /usr/openwin/share/lib \ "$with_motif_libs" \ ; \ do dnl Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl; do if test -r $ac_dir/lib${xm_direct_test_library}.$ac_extension; then xm_libraries=$ac_dir AC_MSG_RESULT([in $xm_libraries]) break 2 fi done done if test "x$xm_libraries" = "x"; then AC_MSG_ERROR([**** MOTIF LIBRARIES NOT FOUND **** Install Motif development headers/libraries or use --with-motif-libraries to specify path to libXm.a ]) fi ]) ]) # Look for a library that contains the Berkeley DB function "db_create" # and put it into LIBS if it's not already found by the current setting of # LIBS # # If "--with-bdb-incdir" was specified, it will already have been added # to CPPFLAGS by the caller # # If "--with-bdb-libdir" was specified, we tentatively add it to LDFLAGS # here and add it to BDB_LIBADD. Only if we actually find the library # will this get added to LDFLAGS permanently # # if we find it, dblib will have "berkeley" in it, otherwise it will have # "no" # # Note that this is not perfectly safe. We only call this macro if we # have found a usable "db.h" header in the default CPP search path or # the path augmented by "--with-bdb-incdir", but we have no way of telling # (without actually running a program that calls db_version) whether # this header is actually for the most recent libdb installed on the # system. This can bite users who have multiple versions, but tell Xastir # that they want to use the older header in some nonstandard directory. # # In that case, the ONLY solution for forcing use of the old library is to # specify it in LIBS (e.g. "LIBS='-ldb-5.3'"). AC_DEFUN([XASTIR_BERKELEY_DB_CHK_LIB], [ BDB_SAVE_LDFLAGS=$LDFLAGS if test -d $with_bdb_lib; then LDFLAGS="-L$with_bdb_lib $LDFLAGS" BDB_LIBADD="-L$with_bdb_lib $BDB_LIBADD" else BDB_LIBADD="" fi AC_SEARCH_LIBS([db_create],[db-18.1 db-18 db-5.3 db5.3 db53 db-5.2 db-5.2 db52 db-5.1 db5.1 db51 db-5.0 db5.0 db50],[dblib="berkeley"],[dblib="no"]) LDFLAGS=$BDB_SAVE_LDFLAGS ]) AC_DEFUN([XASTIR_BERKELEY_DB_OPTS], [ AC_ARG_WITH(bdb-libdir, [ --with-bdb-libdir=DIR Berkeley DB lib files are in DIR], with_bdb_lib=$withval, [ test "${with_bdb_lib+set}" = set || with_bdb_lib=none]) AC_ARG_WITH(bdb-incdir, [ --with-bdb-incdir=DIR Berkeley DB include files are in DIR], with_bdb_inc=$withval, [ test "${with_bdb_inc+set}" = set || with_bdb_inc=none ]) ]) AC_DEFUN([XASTIR_BERKELEY_DB_CHK], [ AC_REQUIRE([XASTIR_BERKELEY_DB_OPTS]) xastir_save_CPPFLAGS=$CPPFLAGS if test -d $with_bdb_inc; then CPPFLAGS="$CPPFLAGS -I$with_bdb_inc" BDB_INCADD="-I$with_bdb_inc" else BDB_INCADD="" fi # check to see if the db.h we find first in the search # path will actually pass the test we do in map_cache.c. Don't even bother # looking for a library if not. AC_MSG_CHECKING([if db.h is exists and is usable]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [ #include ], [ #if (DB_VERSION_MAJOR < 4 ) #error DB_VERSION_MAJOR < 4 #endif ])], [ AC_MSG_RESULT([yes]) XASTIR_BERKELEY_DB_CHK_LIB() ], [ AC_MSG_RESULT([no]); dblib="no" ]) CPPFLAGS=$xastir_save_CPPFLAGS use_map_cache="no" if test "${dblib}" = "berkeley"; then CPPFLAGS="$CPPFLAGS $BDB_INCADD" LDFLAGS="$BDB_LIBADD $LDFLAGS" AC_DEFINE(USE_MAP_CACHE, 1, [Berkeley DB Map Caching]) use_map_cache="yes" fi ]) Xastir-Release-2.2.4/archived_docs/0000775000175000017500000000000015151324131016116 5ustar hibbyhibbyXastir-Release-2.2.4/archived_docs/INSTALL0000664000175000017500000017743215151324131017165 0ustar hibbyhibbyNOTE: This file gives a general overview of how to build Xastir. It is by necessity both extremely vague where it is general, and extremely dense when it tries to get specific. System-specific guidance for building Xastir can be found at http://xastir.org/index.php/Installation_Notes, and some of these build recipes may be more helpful than the general guidance in this file. General steps to configure/compile/install Xastir: (detailed steps and library installation instructions follow these general steps) ---------------------------------------------------------------------- 1) Get one of the source releases from Github at https://github.com/Xastir/Xastir/releases and explode it. (Replace X.Y.Z with the release number below) mkdir Xastir cp Xastir-Release-X.Y.Z.tar.gz Xastir cd Xastir tar xzvf Xastir-Release-X.Y.Z.tar.gz An alternative to the above steps is to use git to download the Xastir sources. See README.GIT for those instructions. Git allows you to easily keep up to date with the developers. 1a) Make sure your system has, at a minimum, these packages: Motif or OpenMotif or LessTiff Required The GUI widget set pthreads Required Threading capability There's no point going past this step if you can't get those installed. They should be in your system's package management system, and you will need both libraries and development headers for Xastir to build. A build of Xastir with only these two will be fairly limited, and you will almost certainly want to add libraries for additional features later. 2) Go into the xastir directory to build the executable: cd Xastir The first time you do this you need to create the "configure" script. To do this run: ./bootstrap.sh or autoreconf -i Note that bootstrap (or autoreconf) requires that you have GNU Autoconf and Automake installed on your system. Any error messages from bootstrap mean that something is missing and you will be unable to proceed, so fix those problems first. Then create a build directory, configure and build the code: mkdir -p build cd build ../configure make su (become the root user) make install chmod 4555 /usr/local/bin/xastir (only if you use kernel ax.25, see below) exit (from root) Note that if there are ANY errors reported by configure and it aborts early, this is generally a sign that something critical has been missed, such as a missing Motif library or missing Motif headers. If this happens, configure will not create a "Makefile" and the "make" step will report that no makefile has been found. Go back and look at the configure output and figure out what it was complaining about, fix that problem, and then try it all again. If your run of configure does not end with the text: xastir X.Y.Z has been configured to use the following options and external libraries: followed by a list of options and their status, and ending with: xastir will be installed in /usr/local/bin. Type 'make' to build Xastir (Use 'gmake' instead on some systems). then configure did NOT complete normally, and you need to figure out why. 3) Xastir should be installed in /usr/local/bin (the default on most systems). You can run it by typing this from a shell: xastir & Installing only the required libs gives you these capabilities: PocketAPRS maps aprsDOS maps WinAPRS maps MacAPRS maps GNIS labels Address searching serial port and Internet gateway connectivity. Short summary of additional libraries Xastir can use: ------------------------------------------------------------------------- Shapelib Recommended ESRI Shapefile maps and WX alerts pcre2 or pcre Required for Shapefile support Xpm Optional XPM images + Snapshots + Printing GraphicsMagick Optional MANY graphics images (you can also use ImageMagick 6, but GraphicsMagick is preferred) libtiff/libgeotiff/libproj Optional geoTIFF maps (USGS topos) AX.25 Optional Kernel AX.25 networking support festival Optional Speaking alerts libcurl or wget Optional Internet images as maps GPSMan/gpsmanshp Optional Converts GPS data to Shapefiles libdb (4.0 or newer) Optional Internet map caching (fast!) libpq Experimental Persistent data with Postgis libmysqlclient Experimental Persistent data with MySQL It is our experience in 2023 that ALL of the libraries that Xastir needs or which can be added optionally are available in every operating system's package management system, so it should be very unusual to have to build any from source. A lot of the information in the later parts of this file is very old, when that was NOT the case. Adding XPM or ImageMagick libs, ImageMagick's "convert" utility, and the "gv" utility gives you printing capability. Postscript or emulated postscript printing capability is required for this as well. Adding XPM or ImageMagick libs plus "convert" also give the capability to create automatic PNG images on disk from the map screen (useful for web pages!). Adding Shapelib support also gives you the capability to use Tiger 2000 maps which were converted to Shapefile format by ESRI. This allows you to use free detailed street maps for any point in the U.S. Shapelib support *requires* that you also install PCRE2 or PCRE libraries and development headers. Adding other libraries gives you the additional capabilities listed above. After you have a working version of Xastir you can always add additional features by installing the libraries required and then rerunning "configure" and rebuilding Xastir. ------------------------------------------------------------------------------ In the text below, we go into far more detail than most users need. It may also be very, very obsolete. ============================================================================== Library/Option Hierarchy: ------------------------- ImageMagick (Usually requires additional libraries) error_popups (Annoying popups, turned off by default) libgc (developer stuff: memory leak testing) "festival --server &" (Xastir connects to this server) | `-----------> Festival gprof | `-+---------> profiling (developer stuff) / | gprof-helper.so libax25 | `-----------> AX25 libProj | `-+-------+-> GeoTiff / / / / libtiff / / libgeotiff gpsmanshp | `-+------+--> GPSMan / / | / tcl/tk / / ShapeLib | +-----------> rtree | `-+---------> Dbfawk / | PCRE libcurl or wget | `-+--------> map_caching / | Berkeley DB MySQL --------> MySQL database interfaces (Experimental) | `-+---------> db2APRS (Xastir connects to this server) / | Meteo Postgresql | `-+--------> Postgis database interfaces (Experimental) | + / QGIS [station data in another GIS application] | Postgis --------------------------------- For those who would like to see the full list of libraries Xastir might use (to decide what packages to install), here's the ldd command run against a pretty much fully-loaded Xastir. Note that quite a few of these libraries are pulled in by the ImageMagick library, and your library list may look little like it due to differences in how ImageMagick was compiled: > ldd /usr/local/bin/xastir libXm.so.3 => /usr/X11R6/lib/libXm.so.3 (0x40030000) libXt.so.6 => /usr/X11R6/lib/libXt.so.6 (0x40287000) libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x402db000) libMagick.so.0 => /usr/lib/libMagick.so.0 (0x403d7000) liblcms.so.1 => /usr/lib/liblcms.so.1 (0x4052f000) libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0x40553000) libexif.so.9 => /usr/lib/libexif.so.9 (0x405a9000) libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x405be000) libSM.so.6 => /usr/X11R6/lib/libSM.so.6 (0x405cc000) libICE.so.6 => /usr/X11R6/lib/libICE.so.6 (0x405d5000) libbz2.so.1 => /usr/lib/libbz2.so.1 (0x405ed000) libz.so.1 => /usr/lib/libz.so.1 (0x405fd000) libpthread.so.0 => /lib/i686/libpthread.so.0 (0x4060c000) libm.so.6 => /lib/i686/libm.so.6 (0x4065d000) libdb-4.1.so => /usr/lib/libdb-4.1.so (0x40680000) libXpm.so.4 => /usr/X11R6/lib/libXpm.so.4 (0x40744000) librt.so.1 => /lib/librt.so.1 (0x40755000) libcurl.so.2 => /usr/lib/libcurl.so.2 (0x40768000) libXp.so.6 => /usr/X11R6/lib/libXp.so.6 (0x4078f000) libshp.so.1 => /usr/local/lib/libshp.so.1 (0x40797000) libpcre.so.0 => /usr/lib/libpcre.so.0 (0x4079f000) libproj.so.0 => /usr/local/lib/libproj.so.0 (0x407ab000) libtiff.so.3 => /usr/lib/libtiff.so.3 (0x407e2000) libgeotiff.so => /usr/local/lib/libgeotiff.so (0x4082b000) libax25.so.0 => /usr/lib/libax25.so.0 (0x4084d000) libc.so.6 => /lib/i686/libc.so.6 (0x40b64000) libdl.so.2 => /lib/libdl.so.2 (0x40c97000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) libssl.so.0.9.7 => /usr/lib/libssl.so.0.9.7 (0x40c9b000) libcrypto.so.0.9.7 => /usr/lib/libcrypto.so.0.9.7 (0x40ccb000) libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x40dbd000) libjasper-1.700.so.2 => /usr/lib/libjasper-1.700.so.2 (0x40ddd000) libpng.so.3 => /usr/lib/libpng.so.3 (0x40e2c000) libstdc++.so.5 => /usr/lib/libstdc++.so.5 (0x40e5b000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x40f1b000) Things you need for this version: --------------------------------- * Get Lesstif/OpenMotif from your favorite Linux/Unix distribution. -or- * Lesstif: www.lesstif.org (look below for RED-HAT instructions) -or- * OpenMotif: www.openmotif.org * AX25 packages: (if you want support for kernel AX25 interfaces) Lib AX25 AX25 apps AX25 tools The apps package is not required, but strongly suggested. These packages are in most Linux distributions but may be out of date. See the linux-hams mailing list for details. * You should have glibc on your system that supports threads! For geoTIFF support (such as USGS DRG topo maps) you also need: libtiff (should be in the package set of most distributions): ------------------------------------------------ http://www.simplesystems.org/libtiff/ libproj (proj-4.4.9 or later): --------------------- http://proj4.org/ Datum translations (proj-nad27 or proj-datumgrid): -------------------------------------------------- http://proj4.org/ libgeotiff (any version later than libgeotiff-1.1.5): -------------------------------------------------- http://geotiff.osgeo.org/ Please note that the order of installation for the above libraries is critical. Follow the instructions below carefully. Also, the particular libgeotiff you use depends on the version of libtiff you have installed. For Linux kernel AX.25 interfaces, you require these packages: Lib AX25 AX25 apps AX25 tools These packages are in most Linux distros. Source code and other information about them can be found at: http://www.linux-ax25.org/wiki/Main_Page The apps package is not required, but strongly suggested. See the AX.25 HOWTO and the linux-hams mailing list for details. For speech support via the festival speech synthesis software you need: festival. Many package management systems have it already but source and documentation are at: http://www.cstr.ed.ac.uk/projects/festival/ For ESRI Shapefile format maps/weather alert maps: Shapelib: http://shapelib.maptools.org/ pcre: http://www.pcre.org For ImageMagick support for maps in any of 68 major graphics formats, including the capability to use online maps and weather radar images: ImageMagick: http://www.imagemagick.org/ To use online maps or findu.com historical data, you'll need wget or libcurl/libcurl-devel installed. Many systems have these pre-installed, so check first. You may need to upgrade your installed version for this feature to work correctly from within Xastir: Wget: ftp://ftp.gnu.org/gnu/wget/ libcurl: http://curl.sourceforge.net/ To download GPS tracks/waypoints/routes from a Garmin GPS into Xastir, converting to Shapefile format maps as it runs, you'll need gpsmanshp and GPSMan. GPSMan 6.0 and later has command-line support built-in so that Xastir can control it directly, but only GPSMan 6.1 and later are currently usable with Xastir: gpsmanshp: http://www.ncc.up.pt/gpsmanshp/ GPSMan: http://www.ncc.up.pt/gpsman/ http://sunsite.unc.edu/pub/Linux/science/cartography See below for instructions on installing all of these libraries. Once the libraries are installed, ./configure should find the libraries and allow compiling in support for the new features. If you wish to enable/disable configure's testing of certain features, you can add any of the following flags to configure: --without-ax25 --without-festival --without-gpsman --without-imagemagick --without-libproj --without-geotiff --without-shapelib --without-map-cache --with-errorpopups --with-libgc --with-profiling --with-lsb --with-postgis --with-mysql For example, "./configure --without-ax25" will disable the AX.25 networking code in Xastir. If you have installed Xastir before, read the "UPGRADE" file for information on changes in file location and permissions. First Time Install: ------------------- 1. OPTIONAL: If you wish to use AX.25 interfaces, install the AX.25 packages. Verify that they are configured and working. Use "listen" to watch the packets fly by after getting AX.25 configured and hooked to a TNC. Use the AX.25 HOWTO document to guide you in this process. 2. Install LessTif or OpenMotif If you already have Motif or OpenMotif on your system, including the development headers, then you won't need to install LessTif. Most distributions include one of these; step 2a describes building from source, while 2b describes installing from pre-built packages on your distribution. Now that OpenMotif is available, you may be happier running it than LessTif, but either one should work with Xastir. Some users have had problems with OpenMotif, and others have had troubles with LessTif. Symptoms are often menu problems (menus don't draw correctly, menus won't respond to clicks). If you encounter these problems, then uninstall the current Motif and install the other. Several Mac users have reported problems with OpenMotif, so LessTif may be a better place to start. 2a. Download LessTif version 0.91.1 or higher or download OpenMotif. Follow the instructions provided, compile it and install it. Usually, ./configure make su (root) make install /sbin/ldconfig exit (from root) Or you can try any other OSF/Motif(R) version 1.2 2b. Install LessTif or OpenMotif (from a package) Download the lestif-devel (if it exists) and lestif, and install it as your distribution instructs you to install packages. 3. OPTIONAL: Install geoTIFF support. Allows using USGS DRG topo maps or other types of geoTIFF maps/images and has the ability to tile smaller maps into a larger contiguous map of an area: 3a. Check/Edit your startup files: ----------------------------- Check that /usr/local/lib, /usr/lib, and /usr/X11R6/lib are all listed in /etc/ld.so.conf, and run /sbin/ldconfig to re-create the system's cache file. If you don't have permission to edit this file: Edit ~/.bashrc, ~/.bash_profile, .cshrc, or .login and add: export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib:/usr/X11R6/lib This will let the loader find the shared libraries when it tries to load Xastir into memory. If you instead have a /etc/ld.so.conf.d directory, then this will add the /usr/local/lib directory to the search: Create a file in the /etc/ld.so.conf.d called "local.conf". The file should contain exactly one line: /usr/local/lib Use your favorite text editor or use these commands: echo "/usr/local/lib" > /etc/ld.so.conf.d/local.conf ldconfig -v Check that you aren't already defining LD_LIBRARY_PATH somewhere else. If so, just add the paths above to it. Make sure this environment variable is defined in the current shell you're using to compile Xastir. Note that if you're running Xastir SUID root, the LD_LIBRARY_PATH variable is ignored. 3b. Install libproj: -------------------- NOTE: You must install libproj BEFORE compiling libgeotiff, because libgeotiff uses libproj to do the datum translations. If you install libgeotiff first, datum translations won't work. proj-nad27-1.1.tar.gz or proj-datumgrid-1.3.zip must be decompressed in the nad subdirectory of the proj distribution directory before you run configure. tar xzvf proj-4.4.9.tar.gz (or newer) cd proj-4.4.9/nad unzip ../../proj-datumgrid-1.3.zip (or tar xzvf ../../proj-nad27-1.1.tar.gz) cd .. ./configure make su (root) make install /sbin/ldconfig exit (from root) libproj should now be installed in: /usr/local/include/ /usr/local/lib/ /usr/local/bin/ /usr/local/share/proj/ You may need to do this (as root) if the "make install" portion fails because it can't find "ginstall": cd /usr/bin ln -s install ginstall Then retry the "make install" portion above. 3c. Upgrade libtiff if needed: ----------------------------- The best way to install libtiff is to get it from the ftp site for your Linux distribution. You must have libtiff 3.5.5 or newer for libgeotiff 1.1.x to compile and run correctly, or libtiff 3.6.0 BETA or newer for libgeotiff 1.2.x to work correctly. If you're using libtiff 3.6.0 BETA or newer, things are simplified. Just use libgeotiff 1.2.x or newer and they should play nicely together. --------- Notes for older libtiff (less than 3.6.0 BETA): If you are compiling libtiff from source, you must use "make install_private" because the libtiff private include files are required for libgeotiff to compile and work correctly. You may also snag just the include files listed below from the source distribution or the source RPM, and copy them manually to their destinations. The errors you'll get if you don't match up the older libtiff and libgeotiff by way of the include files: Xastir will seg-fault when it tries to read a geotiff file. --------- If you upgrade libtiff, check that programs like XV, ImageMagick, and the Gimp still run (if you have these programs installed). Graphics programs that read/write TIFF format depend on libtiff. 3d. Install libgeotiff: ----------------------- NOTE: Depending on your version of libtiff, either libgeotiff-1.1.5 or libgeotiff-1.2.4 may compile properly. libgeotiff is intimately tied to your version of libtiff. libgeotiff 1.2.x or greater requires libtiff-3.6.0 BETA or later. If your version of libtiff is older, get libgeotiff 1.1.4 or 1.1.5. For the latter case you may also have to download the sources for your version of libtiff in order to copy one libtiff header file into the libgeotiff source directory. ----------------------- Pre 3.6.0 libtiff NOTE: You may need to snag some files from your exact libtiff source distribution and place them into your /usr/include directory before libgeotiff will compile. Note: I said use files from the EXACT same distribution of libtiff that you already have installed! libtiff/tiffconf.h libtiff/tiffiop.h libtiff/tif_dir.h contrib/dosdjgpp/port.h Drop all four files into the /usr/include/ directory, creating no subdirectories at all. This allows the libgeotiff code to "see" into the libtiff library so that it can use some functions that aren't normally (publicly) available. Try to make sure that you're not overwriting any files in /usr/include/ by the same name. Some of these files may already be present in /usr/local/. If so, they should be exact duplicates. "diff filename1 filename2" will tell you if there are any differences between two files. If you'd rather not mess with the /usr/include directory, you can drop the four files into the libgeotiff-1.1.5/libtiff_private/ directory instead. Libgeotiff will pick up the files there, issue a warning to you that you're using private include files, yet still compile in support for your particular version of libtiff. With libgeotiff-1.2.4/libtiff-3.6.0-beta or newer you shouldn't need to copy these files across. The newer libtiff and libgeotiff can work together using public interfaces. ------------------------ tar xzvf libgeotiff-1.2.4.tar.gz (or newer) cd libgeotiff-1.2.4 ./configure make su (root) make install /sbin/ldconfig (tells the loader about the new libraries) exit (from root) libgeotiff should now be installed in: /usr/local/include/ /usr/local/lib/ /usr/local/share/epsg_csv/ /usr/local/bin/ If you must re-run "configure" for any of these libraries, remember to delete "config.status" and "config.cache" files first. 4. RECOMMENDED: Install ESRI Shapefile support. Allows using many sources of online polygon, polyline, and point maps, including ones from NOAA. This is also the format for weather alert maps. This support is provided by the shapelib package. NOTE: There are TWO ways to install Shapelib, using the version of Shapelib that comes with Xastir (statically linked with Xastir), or using a separate Shapelib shared library (dynamically linked with Xastir). If you ONLY require Shapelib for Xastir and won't need it for any other program, then you may use the private copy distributed with Xastir, skipping the Shapelib install instructions in this section. If you have other programs which need Shapelib, then it is recommended that you install Shapelib first as a shared library, per the instructions below. If you skip the instructions in this sections, "./configure" will set the compile up so that the private Shapelib code will be statically linked to the executable. It isn't clear from the install instructions in shapelib, but just installing the library is sufficient, and just typing "make" and "make install" doesn't make or install the libraries. Take these steps: make lib su (root) make lib_install /sbin/ldconfig exit (from root) and you should have what you need. You may also need to tweak "/etc/ld.so.conf" to contain the proper path to the libraries and then run /sbin/ldconfig to update "/etc/ld.so.cache". Once this is done the loader should be able to find the Shapelib library. Must run /sbin/ldconfig as root for the system to be able to re-create its cache file. See the instructions earlier in this file if you have an /etc/ld.so.conf.d directory instead (section 3A). For MacOSX: Bill Owen, N2RKL, suggested the following for ShapeLib: "The shapelib Makefile wouldn't work out of the box, so I figured out what the important bits were and built them by hand:" ----------------------------------------------- cc -c shpopen.c cc -c shptree.c cc -c dbfopen.c ar cru libshp.a shpopen.o shptree.o dbfopen.o sudo cp libshp.a /sw/lib sudo ranlib /sw/lib/libshp.a sudo mkdir /sw/include/libshp sudo cp shapefil.h /sw/include/libshp/ ----------------------------------------------- Note that you'll have to set up /etc/sudoers file to allow those commands to be run by a normal user before sudo will work for you. See the README.Git file for sudo instructions. COMPILING OPTIONAL UTILITIES FOR SHAPELIB: These utilities are sometimes useful when writing dbfawk rules but aren't necessary for running Xastir. cd xastir/src/shapelib make -f Makefile_shapelib_orig cd contrib make -f Makefile_orig You'll be left with useful executables in the xastir/src/shapelib and xastir/src/shapelib/contrib directories. It's your choice whether to copy them to a directory in your path (perhaps /usr/local/bin?) to make them easier to use. 5. OPTIONAL: Install -either- GraphicsMagick or ImageMagick support as shown below. Xastir will use one or the other but not both. It'll prefer GraphicsMagick over ImageMagick if both are installed. Do step 5a -or- 5b below to get this type of image support compiled into Xastir. Allows using more than 68 different graphics format files as maps, by creating an associated .geo file for each with tie-points. This support will allow use of online Tiger and Terraserver maps with Xastir, and NOAA weather radar images. Other people are working on integrating even more online mapping sources. This will also allow you to use any GIF/JPG/XPM/ BMP/... image as an Xastir map. Installation instructions are included in the package. If you choose to install from a binary install, be sure that you have all the graphic format libraries that it was originally built with. The easiest way to install one of these is via a package from your linux distribution's CD or ftp site. If you install from such a package, make sure the header files are installed. These are often in a separate package called GraphicsMagick-devel or ImageMagick-devel or similar. 5a. OPTIONAL: Install GraphicsMagick support. Download the GraphicsMagick sources from: http://www.graphicsmagick.org Uncompress/un-tar them... tar -xzvf Gr* Change directory to the newly created GraphicsMagick directory and compile: cd Gr* ./configure --with-quantum-depth=16 --enable-shared make su -c 'make install' su -c '/sbin/ldconfig' Skip the next step (5b) as you only need ImageMagick support installed if you _don't_ install GraphicsMagick. 5b. OPTIONAL: Install ImageMagick graphics support. Note that Xastir's "./configure" stage may fail trying to compile in ImageMagick support. If this happens, make sure you have the ImageMagick development package installed if using RPM packages, or have installed the ImageMagick header files. If it still fails, check the "config.log" file _very_ carefully. Often ImageMagick tests fail due to some other library that ImageMagick depends upon being absent, such as liblcms, libbz2, or others. This can also cause AX.25 support to be dropped in our current "configure" script. We're working on that. Until the RPM packagers for ImageMagick include all of the dependent libraries in their RPM dependency list, the best way to assure that ImageMagick is installed properly is to install it from sources. ------------------------------------------------------------------------- Note: Red Hat 9.0's install of ImageMagick does not work with XASTIR. It will need to be removed and installed from sources. If w3m text based web browser is installed, you will need to remove it before removing ImageMagick: rpm -e w3m rpm -e ImageMagick Download the Imagemagick sources from: ftp://ftp.imagemagick.org/pub/ImageMagick/ At the time of writing, this was ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick-5.5.7-34.tar.gz But you may need to get a newer version by the time you read this. Uncompress/un-tar them... tar -xzvf im* Change directory to the newly created ImageMagick directory and compile: cd im* ./configure make su -c 'make install' su -c '/sbin/ldconfig' These instructions are courtesy of Wes Johnston. ------------------------------------------------------------------------- 6. OPTIONAL: If your system doesn't have wget or libcurl/libcurl-devel installed, and you want to use online maps, install either or both of those packages now. Installation instructions are included in the package. Some older versions of wget don't work properly with Xastir, so even if you already have wget you may need to upgrade it. Please refer to the wget man pages or the web pages at http://www.gnu.org/software/wget/wget.html for info concerning wget. Note that if the remote server is down, Xastir can appear to hang for a bit before wget times out. Xastir calls wget with no retries and a 30-second timeout, but one user reported that wget takes one minute fifteen seconds to time out. Also note that the users ~/.wgetrc and the system-wide wgetrc file can change the timeouts and retries as well. See the man pages for details. Pay particular attention to which file/command-line-options take priority over others. It looks like the command-line option "--execute command" will allow overriding the .wgetrc files, which means the user can override the hard-coded timeouts/retries in Xastir by specifying new defaults in their ~/.wgetrc file. Libcurl should be a drop-in replacement for the wget functionality that we use, and it's a faster and more secure method. 7. OPTIONAL: Installing gpsmanshp/GPSMan allows Xastir to fetch GPS waypoints/routes/tracks from a GPS. Xastir can fetch the data automatically, create a Shapefile map, then index/select/display the new map. Make sure you have Shapelib installed first (see above instructions). Note that you may have to change the gpsmanshp Makefile to call out "TCLVERSION = 8.4" instead of 8.3, depending upon which version of tcl is installed on your system. Use your package manager to determine this ("rpm -q -a | grep tcl"), or you may be able to find out in /usr/lib by typing "ls -ld tcl*". Install gpsmanshp: tar xzvf gpsmanshp_1.2.2.tgz cd gpsmanshp make su -c 'make install' Install GPSMan: tar xzvf gpsman-6.0.tgz cd gpsman-6.0 vi gpsman.tcl Change SRCDIR line to: "set SRCDIR /usr/lib/gpsman" su (root) mkdir /usr/lib/gpsman cp gpsman.tcl /usr/lib/gpsman ln -s /usr/lib/gpsman/gpsman.tcl /usr/X11R6/bin/gpsman cd gmsrc cp * /usr/lib/gpsman cp -R gmicons /usr/lib/gpsman chmod -R 755 /usr/lib/gpsman chmod 644 /usr/lib/gpsman/gmicons chmod 777 /usr/local/share/xastir/maps/GPS (IMPORTANT!) exit (from root) Verify that GPSMan will start up and will download information from a Garmin GPS in Garmin-Garmin mode. This also creates the configuration files needed to use GPSMan with Garmin GPS's from within Xastir (sets GPS type, serial port, etc within GPSMan's configs). 8. OPTIONAL: Install Festival for speech support To use speech you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival --server &". More info about the speech features is in the Xastir help file. An easy way to get festival installed on some systems is to go to rpmfind.com and search for both festival and festival-dev, then install the RPM's found. Red Hat RPM's installed onto SuSE 7.3 with no problems. Note that the default voice doesn't speak numbers very well. Edit /usr/share/festival/voices.scm and put "ked_diphone" at the first of the "defvar default-voice-priority-list". This will change the default voice to "ked_diphone". Note that you can start up the festival server and test it out manually by typing these commands: telnet localhost 1314 (SayText "Hello") To exit, press control-] and then type "quit". 9. OPTIONAL: Install Berkely DB Library to enable map caching of internet maps. Please note that segfaults (crashes) in Berkeley DB calls can be caused by having multiple versions of the library installed. The programming interface has changed between the versions. If you compile Xastir with one version's header files but Xastir links to another version's library, you can easily end up with segfaults when Xastir runs. SuSE Linux for instance has these available which you _should_ install: db db-devel Plus SuSE has these additional packages available which you should _not_ install. Remove them if they're on your system (using YaST or rpm): db-40 db42 Xastir will normally try to use /usr/include/db.h as the header file, and /usr/lib/libdb.so as the library it will link to (which is usually a symlink to something else, like /usr/lib/libdb-4.1.so). If the header file and the library file don't match, a segfault often occurs. The easiest way to avoid problems is to keep one and only one version of the Berkeley DB library on your system. Here's how to test what version of include file and library file you're using: Find the db.h file. It's usually in /usr/include/db.h. grep DB_VERSION db.h Mine shows this: #define DB_VERSION_MAJOR 4 #define DB_VERSION_MINOR 1 #define DB_VERSION_PATCH 25 #define DB_VERSION_STRING "Sleepycat Software: Berkeley DB 4.1.25: (October 2, 2003)" Now do this: ldd /usr/local/bin/xastir | grep libdb Mine shows this: libdb-4.1.so => /usr/lib/libdb-4.1.so (0x40680000) In this case, version 4.1 of the include file matches 4.1 of the library file, so it works fine. A mismatch in the first two numbers can cause segfaults when Xastir tries to do map caching. If you install the Berkeley DB library in an unusual place (something other than /usr/lib and /usr/include), you should still be able to tell configure where to find it. This comes courtesy of Tom Russo: > > Someone installed Berkeley DB Library here: > > > > /user/local/BerkeleyDB.4.3/include/db.h > > > > Perhaps I can assume that the library would be located here: > > > > /usr/local/BerkeleyDB.4.3/lib/libdb.so > > > > How does one go about specifying the location of the db.h file and > > the libdb.so file so that configure/compile/loading of Xastir work > > properly? > --with-bdb-libdir=/usr/local/BerkeleyDB.4.3/lib > and > --with-bdb-incdir=/usr/local/BerkeleyDB4.3/include 10. OPTIONAL: Compile db2APRS and install MySQL and Meteo to allow Davis weather station support. Install MySQL and Meteo. cd Davis ./bootstrap.sh # OR "autoreconf -i" ./configure make This should build db2APRS in the "src" directory. Start up db2APRS. Xastir should be able to connect to the db2APRS server in order to get the Davis weather station data. See further instructions in the Davis directory. 11. OPTIONAL: Experimental. Add GIS database support. Note: Database support is experimental and any aspect may change at any time, including database structures. Scripts to create database tables for MySQL and Postgres/Postgis are in the scripts directory as db_gis_postgis.sql and db_gis_mysql.sql. Warning: If you are connected to internet feeds for APRS data, it is possible to accumulate several million station records per day which could amount to around 300 MB of database records per day. Postgres + Postgis: Install Postgres. Include development packages (libpq). Add Postgis spatial object support to Postgres. Compile xastir with --with-postgis After building xastir: Create a database named xastir and a user with create rights on that database. Edit db_gis_postgis.sql to set username and password for an xastir user with select access to the xastir database. Default values are database=xastir, user=xastir_user You may also need to set permissions in pg_hba.conf. Run the queries in db_gis_postgis.sql. Run xastir and add a SQL Database interface, start with the postgis defaults, add the username and password of the xastir user. Other GIS applications (e.g. QGIS, Mapserver, GRASS) can access and display station data directly from the postgresql/postgis database. You can configure the database interface to read station from the database on startup and to save stations as they are heard to the database. This provides persistence of station data between xastir sessions. MySQL: Install MySQL. Include development packages (libmysqlclient). Compile xastir with --with-mysql After building xastir: Create a database named xastir and a user with create rights on that database. Edit db_gis_mysql.sql to set username and password for an xastir user with select access to the xastir database. Default values are database=xastir, user=xastir_user Run the queries in db_gis_mysql.sql mysql xastir -p < db_gis_mysql.sql Run xastir and add a SQL Database interface, start with the MySQL defaults, add the username and password of the xastir user. You can configure the database interface to read station from the database on startup and to save stations as they are heard to the database. This provides persistence of station data between xastir sessions. If you have one or more spatial database interfaces set to activate on startup, and this produces a situation that won't let you start xastir normally [e.g. Station data with unusual characters could concevable cause xastir to segfault when retrieved from the database, and interactions between multiple databases that are both writing are reading station data at the same time from each other could potentially be unstable], you should be able to start xastir by editing the device configuration in ~/.xastir/config/xastir.cnf Look for DEVICEn_TYPE:14 lines (where n is the interface number, between 0 and 14, TYPE:14 devices are sql database interfaces), and edit the device to set both query on startup and on startup values to 0. DEVICEn_QUERY_ON_STARTUP:0 DEVICEn_ONSTARTUP:0 If the cause is problematic data in your database, you may need to run a delete query to eliminate the problematic row(s). 12. Building XASTIR: Note that you'll need autoconf 2.53 or newer and automake 1.6.3 or newer in order to run the "./bootstrap.sh" script. "./bootstrap.sh" (This step needed only for those using Git) "mkdir -p build" "cd build" "../configure" "make" ("gmake" for Solaris or *BSD) This builds XASTIR, You should not get any error or warning messages. If you get the message from Xastir's configure script saying: "**** NO MOTIF HEADERS FOUND **** install Motif development headers or use --with-motif-includes to specify location of Xm/Xm.h" even though you've got the Motif libraries and headers installed in the proper places, you might need to add this to the configure line: "--x-includes=/usr/X11R6/include" If that option does not help, then Motif is installed somewhere other than with the standard X includes. You must locate the file "Xm.h," which should be in a subdirectory called "Xm" somewhere. Once located (let's say in /usr/include/Motif/Xm/Xm.h), use the configure option: "--with-motif-includes=/usr/include/Motif" If you get the message: "**** MOTIF LIBRARIES NOT FOUND **** Install Motif development headers/libraries or use --with-motif-libraries to specify path to libXm.a" then your Motif libraries are not installed in the same directory as your other X libraries, and you must find the file libXm.a, libXm.so, or libXm.sl. Once found (say in /usr/lib/Motif, for example), tell configure where to find it with: "--with-motif-libraries=/usr/lib/Motif" If you wish to install Xastir in a location other than the default ("/usr/local/bin" and "/usr/local/share/xastir" directories), you may add the "--prefix=" flag to configure before compiling. i.e. "./configure --prefix=/home/apps/xastir" Which will cause executables to be installed in "/home/apps/xastir/bin/" and the rest of Xastir to be installed under the "/home/apps/xastir/xastir/" directory. This is useful if you don't have root access on a machine, but still wish to install and use Xastir from your home directory. There are probably many other uses as well. If you want to disable optional "dbfawk" support (see README.MAPS) then add "--without-dbfawk" to your "./configure", i.e. "./configure --without-dbfawk" Most people will want the capability though. You'll need the "pcre" package installed in order to compile in dbfawk support. To enable spatial indexing of shapefiles you can also add "--with-rtree" to your configure command line. Using spatial indices can speed up access of shapefiles that cover large areas if you're only viewing a smaller area, but at the cost of some additional RAM to store the spatial index. This feature is still in the experimental phase, but some users have observed a noticeable speed-up in map redraws, especially with very large shapefiles. The spatial indexing library used is based on public domain code obtained from Melinda Green, http://www.superliminal.com, but this code is included in xastir so you don't need to download anything to use it. If you see some errors, they might be because you are missing GNU msgfmt or GNU gettext/xgettext? These packages are required to compile the latest Xastir sources. Beware of packages with the same names installed into /usr/openwin/bin, these are probably NOT the GNU flavor of the executables and will not work for compiling Xastir. For SuSE Linux: Install "development/gettext" using YaST. If you do see some errors/warnings read the FAQ. If this doesn't help, or you think you have a different problem, dump the errors/warnings to a file, and send the file and the following information to the developers: System type (cpu), speed, memory, Linux Distribution, Linux Version, X Window manager (KDE, GNOME, FVWM, etc..) To install, type (as root) "make install" (or make install-strip to remove debugging information) If you later install additional libraries and just can't get ./configure to see them, remove the config.cache file via this command: "rm config.cache", and then re-run configure. Also see the notes above about /sbin/ldconfig. 13. Kernel AX.25 Interfaces NOTE: Xastir is designed by amateur radio operators, for amateur radio operators. It is intended to be used only by them. If there's a way for unlicensed users to operate the amateur radio equipment (this usually includes sending messages through it which key up the transmitter), it is a violation of the rules and your license (and more) may be at risk. The same goes for igating: Be aware of the rules for your country with respect to gating traffic from the 'net onto RF. If there's any question, don't do it. Please read this entire section before typing anything, as there are serious security implications for some of this! Option 1) If you compiled support for AX.25 in and wish to use Kernel-mode AX-25 interfaces, you _may_ need to type this as root: chmod 4555 /usr/local/bin/xastir This command makes Xastir run as user "root", no matter who actually started it. This allows Xastir to talk to the kernel AX.25 networking. Note however that the above chmod command will prevent you from creating a core file in case Xastir of a major program fault. This core file aids in debugging to trace what went wrong. GENERAL SECURITY WARNING: Beware that Xastir has not been audited for security, and makes limited effort to drop extra privileges. Use this in a multi-user environment at your own risk! The developers have worked hard to fix remote buffer overflows in the code to make Xastir safer to use, but there are _MANY_ potential security risks remaining in the code. User beware! We will attempt to plug known security holes in future releases. Also be aware that turning on the Interface->Server ports (TCP and UDP) will allow other users who authenticate properly to send packets. In the case of TCP they can only get routed to other TCP ports and to the internet. UDP packets may also get routed to your RF ports (as third-party packets). LINUX-SPECIFIC SECURITY WARNING: If you're using Linux AX.25 kernel networking, you'll need to either make Xastir SUID-root, or use a shim (which itself is set to SUID-root) between Xastir and the AX.25 ports. See Option #2 below for the (possibly safer) shim method. If you're the paranoid type (and you should be if you're running a system with multiple users), you may wish to skip SUID-root mode/kernel AX.25 interfaces and use standard serial port TNC interfaces instead. Any program is safer if run as a normal user (not safe, but safer). It is currently impossible to use kernel-mode AX.25 interfaces without the program running with root privileges. Option 2) A more security-conscious option is to use a shim program written by Henk de Groot, PE1DNN. This program runs in SUID-root mode but is much smaller and so is easier to audit for security, and provides a new port that Xastir can connect to. The new port can be read/written without having to be the root user. The program is called aprs_tty and can be obtained here: http://we7u.wetnet.net/xastir/aprs_tty.0.0.2.tgz It actually responds to some TNC commands. The code is straight forward and works well. Run the program, telling it what port to use, and then in XASTIR set up the TNC to point to the new TTY at 19200. It transmits/receives UI frames, and sets the correct unproto path. In this case DO NOT perform the chmod 4555 command on the Xastir executable. Note again that the same SUID-root warnings that were giving in option #1 above also apply to aprs_tty. Buyer beware! As far as we know, aprs_tty has not been audited for security, and makes no effort to drop extra privileges. Use this in a multi-user environment at your own risk! 14. Serially-Connected TNC's NOTE: Xastir is designed by amateur radio operators, for amateur radio operators. It is intended to be used only by them. If there's a way for unlicensed users to operate the amateur radio equipment (this usually includes sending messages through it which key up the transmitter), it is a violation of the rules and your license (and more) may be at risk. The same goes for igating: Be aware of the rules for your country with respect to gating traffic from the 'net onto RF. If there's any question, don't do it. Please read this entire section before typing anything, as there are serious security implications for some of this! If you're using a serial TNC, configure your TNC startup files in the /usr/local/share/xastir/config directory: tnc-startup.sys is used to set up your TNC for Xastir and tnc-stop.sys is to change the TNC back to your normal settings. There are several example TNC startup files in the directory. Choose the one that best suits your TNC and edit to taste. See the note below about where to edit the files. You might be unpleasantly surprised if after you type "make install" next, all your custom changes to the startup files are lost. As always, keep a backup. Some people have had trouble getting Xastir to decode packets. While packets were scrolling quite nicely in the View->Incoming Packet Data dialog, stations weren't showing up on the Xastir screen at all. The cause was incorrect settings in the tnc-startup files for that specific TNC. If you change these files in the xastir source directories make sure to do a "make install" to install them into the /usr/local/share/xastir/config/ directory. Another option would be to edit the files in /usr/local/share/xastir/config/ directly. Keep a copy of them in a safe place in any case. You don't want to lose your custom mods you worked so hard to create. Some systems don't allow normal users to access the serial ports. It's a permissions thing, but is actually the _correct_ way to configure the serial ports. You can fix this in several ways: 1) Add the Xastir user to the group owning the serial ports. 2) Make Xastir run SGID-uucp (or whatever group owns the port). 3) Change the permissions of the device so that any user can access it. 4) Make Xastir run SUID-root. Solutions 3 and 4 are highly discouraged. It can be a security nightmare to start opening up files or devices to read/write access by all users, and the same for SUID-root programs. Don't do either of these. Exception: If you're going to be running AX.25 kernel networking, you may need to be running Xastir SUID-root anyway, or else you need to install a shim program between the port and Xastir. In the latter case the shim is running SUID-root, not Xastir. See the section above regarding AX.25 kernel networking. Here are what the default permissions usually look like for the two serial ports on a Linux box: crw-rw---- 1 root uucp 4, 64 Oct 19 08:15 ttyS0 crw-rw---- 1 root uucp 4, 65 Apr 14 2001 ttyS1 (NOTE: For a Windows/Cygwin installation, a few details are different, but the ttyS0 and ttyS1 keywords are the same. Verify that the permissions of these ports are set appropriately for a normal user to read and write to these devices.) Solution #1: The root user would run the commands necessary to add the Xastir user to the "uucp" group, which would then give the user the necessary permissions to use the port. Usually this involves editing the /etc/group file, but SysAdmin tools usually exist for doing this more easily. Solution #2: As root user, type these commands: chgrp uucp /usr/local/bin/xastir chmod 2555 /usr/local/bin/xastir If you want to restrict Xastir so that only one user can run it, (in this case "user1") type: chown user1 /usr/local/bin/xastir chmod 2500 /usr/local/bin/xastir chgrp uucp /usr/local/bin/xastir Solution #3: You can change the permissions of the serial port to allow use by all users, but this is highly discouraged. Here's what Jack Twilley had to say with regards to "chmod uog+rw" (same as chmod 555) for serial ports: > This is not necessary, and opens up the possibility of abuse. Not all > Xastir installations are Linux boxes used by a single person with a > single purpose -- I know of several instances that are multi-user > machines with access to the Internet by multiple parties, some of whom > are not licensed amateurs, and another couple of instances where the > serial port is not always used by a TNC but also by other devices such > as Palm HotSync cradles and GPS receivers. > > Here are two more secure solutions: > > * use non-root users > One way to use the setuid facilities in Unix would be to set > the xastir binary's user ID to match the user that owns the serial > port. Under Solaris, the default ownership of /dev/cua/a is > uucp:tty, with a default permission of 0600. The command 'chown > uucp /usr/local/bin/xastir' followed by the command 'chmod 4555 > /usr/local/bin/xastir' will allow xastir to run properly without > changing the serial port's permissions or ownership, thus > minimizing any impact on other applications that use the serial > port. Note from Curt: This chmod command will prevent creation of "core" file that are useful for debugging in case Xastir crashes. > > * use groups > A better way to use the setuid facilities in Unix is to set the > xastir binary's *group* ID to match a group that already has the > privilege to mess with the serial port. Under FreeBSD, the default > ownership of /dev/cuaa0 is uucp:dialer, with a default permission > of 0660. The command 'chgrp dialer /usr/local/bin/xastir' followed > by the command 'chmod 2555 /usr/local/bin/xastir' will change > Xastir's group to the serial port's group, and then add the setgid > privilege to the binary. Now when xastir starts up, it will have > the minimum privilege necessary to do what it needs to do, without > being yet another root exploit-in-waiting. 15. Serially-Connected Garmin RINO Radio/GPS If you have a Garmin RINO attached to a serial port, have GPSMan installed, and have support for GPSMan compiled into Xastir, then Xastir has the capability to periodically download waypoints from the RINO unit and create APRS(tm) Objects out of them. Any RINO waypoints that begin with "APRS" will be automatically created, placed on the map, and transmitted as your own Xastir APRS(tm) objects. If you wish to see them but not transmit them, turn off Object/Item transmit or global transmit in the interface menu. Another option is to turn off the transmit enable per interface. Please note that Xastir cannot cause the attached RINO to poll the other RINO units on the air. Xastir can only download the waypoints that the attached RINO has collected from the other RINO units that it is passively monitoring. Here's a blurb from Wes Johnston about the RINO's: "Lets say I have three RINO radios... two in the hands of the SAR teams on the ground, and a third radio in a plane circling above. It is preferred that the radio in the hands of the SAR teams be the nicer rino120 since it does mapping. The radio in the plane can be the lowly rino110 since it does not do mapping but you will have a copy of xastir with maps on the laptop with you anyway. If I set two of my rino radios to APRSSAR1 and APRSSAR2, and connect a third rino radio to xastir with serial in the plane, xastir will query rino radio #3 at any one minute interval between 0 and 30 minutes, get the APRS* waypoints, lop off the first four characters and publish the shorter named waypoints as SAR1 and SAR2 as APRS(tm) objects on to your TNC. The hitch to this is that the rino radio cannot automatically poll the RINO users' locations on the ground. You have to manually (on the radio) select a menu item called POLL and poll the users that way. The reason the first four characters of the rino callsign have to be "APRS" is that when you send a query, rino only asks about the first 4 chars... so any station with the first four that match will answer... ie all of them in your group. The other method is to simply fly the plane overhead and listen (eavesdrop) on the channel and passively pickup the locations of the groups as they converse with one another. The rino will send it's location just as you un-key the PTT if it has been >30 sec since the last time you sent your position. It would be practical to simply ask each team for an update... they just need to squeeze their PTT for a moment (ie kerchunk) to send a position." 16. Start up XASTIR and read the help files to configure it. If you have problems, please consult the FAQ file. You can now start XASTIR. On most systems that the path is set up in FHS format just type "xastir". On other systems type "/usr/local/bin/xastir" to start the program. If you see errors at this point that say something like "Can't load xxx library" this means you forgot to either update /etc/ld.so.conf (or /etc/ld.so.conf.d directory on some systems) and run /sbin/ldconfig, or add the LD_LIBRARY_PATH variable for your shell, and the "ld" loader can't link the libraries with the Xastir executable to get it running in memory. Note that if you're running Xastir as SUID root, the LD_LIBRARY_PATH variable is ignored. To set a new language or change the language current choice, use this command line: xastir -l Current choices are: Dutch English French German Italian Portuguese Spanish ElmerFudd MuppetsChef OldeEnglish PigLatin PirateEnglish This option will be stored in the users config file for the next time Xastir is run. On new installs Xastir will default to English unless you use this command line option. CONNECTING TO AN INTERNET SERVER: Here are some lists of Internet servers: http://members.aol.com/wa8lmf3/miscinfo/APRServe.txt http://www.wa6oft.com/APRServe.txt http://www.aprs-is.net/aprsservers.htm http://www.aprs-is.net/APRSServers.htm Filter port syntax (for those ports that allow user-selectable filtering): http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm The procedure to connect to one of them is this: *) Select Interface->Properties. *) Click Add. *) Select Internet Server, click Add. *) Fill in the "Host" and "Port" boxes. *) Enter the Pass-code found by running "callpass" with your callsign in an xterm window. *) Set the togglebuttons and filter parameters per your preferences. The "filter" keyword is added by Xastir, so you don't need to add that word to the box. If the box has anything in it, "filter" is prepended to the text when Xastir sends the string to the server *) Optionally put in a comment. That shows up in the Interface and Properties dialogs to remind you of the details for that connection. *) Click OK. A short list of the first-tier servers (you may want to connect to the second-tier servers or regional/local servers instead): first.aprs.net ports 10151 (history) or 10152 (no history) second.aprs.net ports 10151 (history) or 10152 (no history) third.aprs.net ports 10151 (history) or 10152 (no history) fourth.aprs.net ports 10151 (history) or 10152 (no history) FESTIVAL NOTE: From: J. Lance Cotton: One thing that I found that I had to do to finally get festival to work was to get rid of the 'only localhost can connect to the server' pref in the festival configuration. I don't know if that's the default on a source install (I installed festival from RPM's), but it might be. I don't know why it doesn't let localhost connect, even though it's the only one specifically allowed. Here's what to do: Open the 'festival.scm' file (I found mine in /usr/share/festival/' and look for the line that starts like: (defvar server_access_list ... Make it look like: (defvar server_access_list nil Then restart the festival server. -Lance KJ5O Additional note from Alan Crosswell: If you run the festival_server script instead of festival -server, then the permissions for localhost get set up for you. You probably want to download some maps and additional data files. The instructions for this are in the README.MAPS. ----------------------------------------------------------------------- NOTES FOR DEVELOPERS: --------------------- Profiling: ---------- 1) "./configure --with-profiling" This will add "-pg" to the CFLAGS section of the Makefiles, which turns on the collection of profiling data while the executable is running (on Linux anyway). 2) "make clean" 3) "make install" (Don't do "make install-strip" here, as that will strip off the symbol table information that gprof requires) 4) "xastir &" 5) Let Xastir run for some period of time. 6) Close Xastir 7) "gprof /usr/local/bin/xastir | tee profile.txt" Gprof will use the Xastir binary and the gmon.out file created from running Xastir to give you the profile listing. Add the "-l" flag to the gprof line to give you a line-by-line profile listing, but be prepared for a long run-time and a lot of CPU to be used by gprof to generate it: "gprof -l /usr/local/bin/xastir | tee profile.txt" Also see this link, which talks about how to profile multi-threaded applications: http://sam.zoy.org/writings/programming/gprof.html With the method described, you compile/install their library code, then invoke Xastir like this: LD_PRELOAD=xastir/src/gprof-helper.so xastir & mv gmon.out gmon.old; gprof /usr/local/bin/xastir gmon.old \ | tee profile.txt; gprof -l /usr/local/bin/xastir gmon.old \ | tee profile2.txt Checking for Memory Leaks: -------------------------- A simple method for just checking malloc's/free's is to set MALLOC_CHECK to a 1 or a 2, at least on Linux. See the malloc man page for more info. For more thorough checks, use libgc: 1) Install libgc, the conservative garbage collector for C and C++. SuSE packages needed are "libgc1" and "gc-devel". If you must compile from sources instead, find libgc at: http://www.hpl.hp.com/personal/Hans_Boehm/gc Configure/install libgc like this: ./configure --enable-threads=posix Make sure that "-DGC_LINUX_THREADS" and "-D_REENTRANT" are defined in the Makefile if you're compiling it on Linux. Optional: Change Makefile to add "-DSAVE_CALL_CHAIN" on the DEFS line. This will provide more of a stack trace each time a leak is found. This is sometimes useful but much more verbose. make make check su make install exit (from root) 2) Now, back in the xastir directory: ./configure --with-libgc Make sure that "-fomit_frame_pointer" is _NOT_ in the Makefiles. This will mess up the optional stack trace if present. make clean make install xastir & Let Xastir run for some period of time. Libgc will dump messages to the xterm as memory leaks are found. Any Xastir memory leaks should have a filename and a line number listed. Memory leaks from lower-level libraries will be missing the detailed information, so they are easy to spot (and mostly useless for the purpose of finding and patching memory leaks). Note also that libgc will take Xastir's memory usage up quite a bit, so don't be surprised if Xastir uses two or three times the normal amount of memory while you're debugging memory leaks with libgc. ------------------------------------------------------------------------ APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/archived_docs/README.Getting-Started0000664000175000017500000010601515151324131022005 0ustar hibbyhibby Hello new user, and welcome to Xastir! This document will take you through the steps necessary to get Xastir up and running in one of the following configurations: 1) Minimal install, which will get you up and running quickly. It's recommended that you try this configuration first then add to it. 2) Typical install including maps, weather alerts, geo-coding files, etc. so that full regular operation is achieved. 3) Maximum install with all configure options enabled and most of the useful maps loaded/enabled. All the bells and whistles. Note that you can start with either of the first two options and add only the options you wish in order to come up with your own custom configuration of Xastir. These instructions are written for Linux users. Windows users should refer to the README.CYGWIN document instead. Users of other operating systems should refer to the README document first, then the INSTALL document and the below instructions for further notes, and finally the Installation Notes section of the Xastir wiki at http://xastir.org/. Linux users may also benefit from reading the Installation Notes section of the wiki, because each distro of Linux has its own quirks, and many of those quirks are documented on the wiki. One question you might ask is whether you can just find a binary on the 'net somewhere and install it instead of compiling Xastir from sources. Yes, this is possible, but not what most Xastir users ultimately want. Xastir changes often enough (bug fixes and of course adding new features) that you're really limiting yourself by using pre-compiled binaries. Binaries are typically not updated all that often, if at all, so you'll forever be behind the curve. Most packaged versions of Xastir in package management systems tend to be a couple of years out of date, or even worse. Another reason to compile from sources is to customize it to use all of the features you have available on your system. As you add more libraries that Xastir can use, you can do a quick configure/compile/install and Xastir will be able to take advantage of them. For those that really must have the latest-latest: Download the Xastir sources using Git instead, then issue the command "git pull" periodically in order to snag the latest changes. If anything comes down the pipe, just configure/make/install and then use the latest version. This avoids large file downloads (after the initial download) as it just grabs _changes_ to the sources off the 'net each time you issue the "git pull" command. This is the power-user's method of keeping Xastir up-to-date. See README.GIT for details. After the three configuration sections there's a section on operating, which simply talks you through the initial configuration settings and how things work. After that you can refer to the Help menu option in Xastir itself, plus the INSTALL and README.* text files for additional information. Please note that the non-English help files lag severely behind the English help file. First of all, NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Before we begin, consider subscribing to the Xastir mailing list. That's where everyone is kept up-to-date on the latest features, plus lots of questions are asked/answered there on a weekly or sometimes daily basis. It's a great way to learn and to stay connected with the other Xastir users. See the mailing links on the left of the Xastir home page: http://xastir.org You must be subscribed in order to post messages there. So... Let's get started! -------------------------------------------------------------------- -------------------------------------------------------------------- Latest info: *) Xastir starts up with a default world map the first time you run it plus pops up a dialog where you can enter your callsign. Enter a callsign, then close/restart Xastir or save the configuration via "File->Configure->Save Config Now!". Either of these methods saves the callsign to disk. *) Xastir includes "Shapefile" map capability by default. Run the script: "/usr/local/share/xastir/scripts/get-NWSdata" as root to download/install NOAA Shapefile maps using the "wget" utility. You'll of course need wget installed in order to fetch the files using this method. Installing the NWS files enables weather alert support in Xastir. Verify that "Map->Enable Weather Alerts" is selected and that "Map->Disable All Maps" is _not_ selected, else you won't see weather alerts on your screen. -------------------------------------------------------------------- -------------------------------------------------------------------- Sources of help you may find useful: *) "FAQ" file *) "INSTALL" file: Non-Windows instructions for installing Xastir and optional map libraries may be found here. *) "README.md" file: General info and some OS-specific notes. *) "CONTRIBUTING.md" file: Info on how to contribute to the Xastir project. *) "README.GIT" file: Info on a more advanced way to keep up-to-date on the latest Xastir sources. *) "README.Getting-Started" file: The file you're reading. *) "README.MAPS" file: Much of the info about maps and where to get them may be found here. Also see the Xastir Documentation section, the Wiki pages, at *) "README.CYGWIN" file: For Windows/Cygwin users. *) "UPGRADE" file: Useful info for updating some old versions of Xastir. *) Xastir Web-based documentation, including a set of Wiki pages, found at *) Xastir man page, accessed by typing "man xastir" on a Unix or Unix-like system. This page is a bit out-of-date. *) "Help->Help Index" in the Xastir program itself. Note that only the English language variation of this is even approximately up-to-date. *) Mailing lists at *) User forums at -------------------------------------------------------------------- -------------------------------------------------------------------- Minimal Install: ---------------- First, let's describe it: This will get Xastir up and running with a few built-in map types. You'll be on the air or on the 'net quickly, then can build upon this working base to add more map libraries and other cool features later. Getting the package: -------------------- *) Option 1: Download one of release tarballs from http://xastir.org. There are links from that page or you can go to the github site (https://github.com/Xastir/Xastir) and click on "Releases" to see the entire set that is available. Once you have the file (which will generally be called "Xastir-Release-.tar.gz," create a subdirectory for it to reside. I usually do this: cd # Go to my home directory mkdir src # Make a "src" subdirectory cd src # Change to it mkdir xastir # Make an "xastir" subdirectory cd xastir # Change to it cp /path/filename . # Copy the downloaded file here tar xzvf filename # Un-archive the sources That last step will create a directory called Xastir-Release- underneath the first one, so your full path might be something like (starting at your home directory): ~/src/xastir/astir-Release-2.1.0 The path just listed is where you'll go in order to run the configure and make commands listed below. cd ~/src/xastir/Xastir-Release-2.1.0 from an xterm window should take you there. *) Option 2: An alternative is to use Git to snag the sources for you. Using this method you can periodically update to the latest released version, the latest "stable" version, or the latest development sources, and even switch back and forth between them at will. See README.GIT for info about that option. One of the advantages of Git is that you only pull down the changes since you last updated, instead of doing very large file downloads each time. Another advantage is that you can keep up with the latest features on a daily basis if you wish, nearly effortlessly. Configure: ---------- In order to complete the configure/compile/install of Xastir, you'll need some of the development tools and headers installed. Here's a list of a few items you'll need to have installed. Look for them in the development tools sections on your Linux distribution: autoconf automake bash binutils gcc gcc development headers cpp glibc glibc development headers? freetype2 freetype2 development headers openmotif (or Lesstiff or Motif) openmotif development headers (or Lesstiff or Motif) XFree86 XFree86 development headers XFree86 fonts XFree86 libraries make (GNU flavor, not BSD flavor) gzip m4 grep Note: Only install one of the Motif packages and the corresponding development package to go with it. Recommendation: OpenMotif. If you'd like to install additional packages at this point that may be needed later, install these as well: patch diffutils perl less bzip2 curl curl development headers git tar liblcms liblcms development headers libtiff less pcre2 pcre2 development headers (you can install the older PCRE library instead of PCRE2, but that is past its end of life and PCRE2 is preferred) tcl tcl development headers tk zip unzip wget ax25-apps ax25-doc ax25-tools libax25 festival festival development headers gawk ghostscript-x11 ghostscript-fonts ghostview gv GraphicsMagick GraphicsMagick development headers (ImageMagick 6 and ImageMagick6 development headers ONLY if you can't install GraphicsMagick) Note that some packages may have dependencies on yet more packages. Hopefully your package installation tool will take care of those for you. It's also common for at least one of these packages to forget to list some of it's dependencies (ImageMagick is known for that). In that case you may have to rely on the compiler to tell you what is missing, then go back and re-install a package or two. Note that the AX25 packages are only available on Linux systems. Now it is necessary to create the "configure" script that will be needed to configure Xastir for your system. In versions prior to release 2.1.8, this script was included in the Xastir tarballs, but it is no longer included. We're using "Release-X.Y.Z" generically here, replace X.Y.Z with the actual version you're downloading. cd ~/src/xastir/Xastir-Release-X.Y.Z/ ./bootstrap.sh You will then create a "build" directory in which to run the compilation of Xastir, and run Xastir's configure script in that directory. In the instructions below we describe making this build directory inside the Xastir source tree, so it would be mkdir -p ~/src/xastir/Xastir-Release-X.Y.Z/build cd ~/src/xastir/Xastir-Release-X.Y.Z/build ../configure If you do this, then the simplest path to Xastir's configure script is just "../configure". You could create this build directory anywhere, though, so long as you remember to replace "../configure" with the full path to Xastir's script, e.g, ~/src/xastir/Xastir-Release-X.Y.Z/configure. When you run the "../configure" step from the "build" directory, the script will attempt to figure out what facilities are available that Xastir can take advantage of. Sometimes the script guesses wrong and you must disable an option and try again. The correct way to do this is (Festival speech synthesizer is used as an example, not that I'm picking on Festival or anything): mkdir build cd build ../configure --without-festival That will guarantee that configure will skip Festival entirely, which will set up the Makefiles to skip it, and the Xastir binary will be created without any support for it. Some operating systems place their packaged third-party libraries into places where configure won't find them by default. In that case you may need to add additional options the help it out. Please look at the Installation Notes section of the Xastir wiki, where it is likely you'll find special instructions for your operating system. Other configure options are: --without-ax25 --without-festival --without-gpsman --without-shapelib --without-imagemagick --without-libproj --without-geotiff --without-dbfawk --without-map-cache --with-errorpopups That said, you probably won't have to use any of these! Type "../configure" all by itself and the script should eventually give you a summary of the packages that it will try to compile support into Xastir for. The only time you may want to add some of the above options is if the compile hangs up because of one of them. You can then add the option to configure, re-create the Makefiles to skip that feature, and get Xastir compiled without it. Once you get the problem solved, you can reconfigure and recompile to add that feature back in. At this point, if some things don't appear in the summary that you'd like/expect to appear, as long as you get to the "Type 'make' to build Xastir" message, you're doing fine. You can work on getting more things in there later. This is what you'd like to see at the end of the "../configure" run (minimum, there may be more "yes" answers): MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : no RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : no GraphicsMagick/ImageMagick (Raster maps) .. : no pcre (Shapefile customization) ............ : no Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : no FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no In other words, Xastir should build/compile with NO optional libraries installed! This will still give you USGS GNIS maps, APRSdos maps, WinAPRS maps, and PocketAPRS maps, plus audio alerts if you have a suitable audio player installed on your system. You'll also be able to attach a TNC either in command-line or KISS mode and connect it to Xastir. Mobile support will work with an attached serial GPS. Attached weather stations should work fine too. You won't get online maps or weather alerts with this configuration though. Worry about that stuff later once you get the minimal configuration working. Make: ----- Type "make". That stage should complete with no errors. You may have a warning or two show up, depending on your compiler version and your operating system. Make install: ------------- For this stage you need to have root privileges. "root" is the user on a Unix/Linux box that has the ultimate authority over everything. Follow these steps: su make install chmod 4755 /usr/local/bin/xastir (optional, see below) exit The first step takes you to root user privileges. You'll need to type in the root password when it asks for it. The "make install" step installs all of the pieces of Xastir in the appropriate places on your system. The "chmod" step sets up the Xastir executable so that it can assume root privileges at the points where it needs to, usually when it needs to access serial ports or AX.25 kernel networking ports. Note that if you don't need the above chmod command, don't use it. It will prevent creation of "core" files in case Xastir crashes, which makes debugging to figure out the root cause much more difficult. There are also some security risks in doing "chmod 4755", as it makes Xastir run as the root user at times. We've tried to minimize the risk by giving up root permissions when we don't absolutely require them, so the risks are smaller. At this point you have a minimal Xastir installed. Jump down to the "Operating Xastir" step below. -------------------------------------------------------------------- -------------------------------------------------------------------- Typical Install: ---------------- First, let's describe it: This will give you a working Xastir with local Shapefile maps, online street/topo/satellite-image maps, weather alerts, and audio alerts. Optionally you can add synthesized speech to the mix. You'll need to run /usr/local/share/xastir/scripts/get-NWSdata as root after you do the install in order to get the NOAA data files you'll need for the weather alerts. "get-NWSdata" requires "wget" in order to work. This is what you'd like to see at the end of the "./configure" run (minimum, there may be more "yes" answers): ------------------------------------------------------------------- MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : yes RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : yes GraphicsMagick/ImageMagick (Raster maps) .. : yes (GraphicsMagick) pcre (Shapefile customization) ............ : yes(PCRE2) Berkeley DB map caching-Raster map speedups : no internet map retrieval .................... : yes (libcurl) FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : no libproj (USGS Topos & Aerial Photos) ...... : no GeoTiff (USGS Topos & Aerial Photos) ...... : no Festival (Text-to-speech) ................. : no GPSMan/gpsmanshp (GPS downloads) .......... : no ------------------------------------------------------------------- Note: You may see "ImageMagick" instead of "GraphicsMagick" and/or "wget" instead of "libcurl" for your installation of Xastir. Those are alternative packages that give similar functionality. also. -------------------------------------------------------------------- -------------------------------------------------------------------- Maximum Install: ---------------- First, let's describe it: This will give you a working Xastir with all of the non-debug "configure" options enabled, local maps, online street/topo/satellite-image maps, weather alerts, audio alerts, synthesized speech, Garmin RINO support, GPS download support, search for street address capability, FCC/RAC callsign lookups, and all of the supported map types. This is what you'd like to see at the end of the "./configure" run: ------------------------------------------------------------------- MINIMUM OPTIONS: ShapeLib (Vector maps) .................... : yes RECOMMENDED OPTIONS: Xpm / Snapshots ........................... : yes GraphicsMagick/ImageMagick (Raster maps) .. : yes (GraphicsMagick) pcre (Shapefile customization) ............ : yes(PCRE2) Berkeley DB map caching-Raster map speedups : yes internet map retrieval .................... : yes (libcurl) FOR THE ADVENTUROUS: AX25 (Linux Kernel I/O Drivers) ........... : yes libproj (USGS Topos & Aerial Photos) ...... : yes GeoTiff (USGS Topos & Aerial Photos) ...... : yes Festival (Text-to-speech) ................. : yes GPSMan/gpsmanshp (GPS downloads) .......... : yes ------------------------------------------------------------------- Note: You may see "ImageMagick" instead of "GraphicsMagick" and/or "wget" instead of "libcurl" for your installation of Xastir. Those are alternative packages that give similar functionality. You may see "(legacy)" after the "yes" for PCRE if you've installed the old, obsolete package "pcre" instead of "pcre2" (many Linux systems are starting to drop the old one, so the new one is preferred, but Xastir will work with either). TBD -------------------------------------------------------------------- -------------------------------------------------------------------- Operating Xastir: ----------------- Again, NEVER RUN XASTIR AS THE ROOT USER! You're risking the security of your system by attempting it. Create another regular user on your system and use that user for all of your normal activity. This goes for any other normal activity on the system as well. Only use the "root" account for maintenance activities, not for regular user activities. You'll thank me later! Assuming you want to start Xastir up in the English language, you can type (from an xterm window): xastir which will start up the program without giving you back a command-prompt in your xterm window (until Xastir exits), or you can type (from an xterm window): xastir & which will start Xastir in the background, giving you back your xterm for more commands. The typical way to start it is with "xastir &". Of course you can get fancier and attach it to your window manager's menus or create an icon on your desktop which starts it. Those are operating system/window manager-specific, so we won't cover how to do that here. The first time you start Xastir it will show a default map of the world plus pop up the File->Configure->Station dialog. Enter a callsign on that dialog and press the OK button. Changing the Language: If you want to start Xastir using some other language, you do that with command-line switches when you start Xastir. Once you use one of these switches, that language option becomes "sticky", meaning you won't have to enter that command-line switch again unless you wish to change languages. There are some command-line switches that you can If you type "xastir -?", which is an invalid command-line option, you'll see this: xastir: invalid option -- h Xastir Command line Options -c /path/dir Xastir config dir -f callsign Track callsign -i Install private Colormap -geometry WxH+X+Y Set Window Geometry -l Dutch Set the language to Dutch -l English Set the language to English -l French Set the language to French -l German Set the language to German -l Italian Set the language to Italian -l Portuguese Set the language to Portuguese -l Spanish Set the language to Spanish -l ElmerFudd Set the language to ElmerFudd -l MuppetsChef Set the language to MuppetsChef -l OldeEnglish Set the language to OldeEnglish -l PigLatin Set the language to PigLatin -l PirateEnglish Set the language to PirateEnglish -m Deselect Maps -p Disable popups -t Internal SIGSEGV handler enabled -v level Set the debug level Ignore those for now unless you need to change the Language. OK, Xastir should show up on your screen at this point. We're assuming that you're already running X-Windows graphical environment at this point. If you're in command-line Linux/Unix only, Xastir won't run. If you've configured in ShapeLib capability, you'll need to run /usr/local/share/xastir/scripts/get-NWSdata as the root user in order to get the NOAA data files you'll need for the weather alerts. The script requires "wget" in order to work. Run this script periodically (once every six months perhaps?) to keep your weather alert maps up-to-date. If you're not in the U.S. or one of it's possessions then you can safely ignore this download. Various ways to manipulate Xastir: Context-Dependent Operations: ----------------------------- Normal Draw-CAD Measure Move ------ -------- ------- ---- Cursor Arrow Pencil Crosshairs Crosshairs LeftClick SelectObject LeftDrag ZoomToArea ZoomToArea MeasureArea MoveObject MiddleClick ZoomOut SetCADPoint ZoomOut ZoomOut Alt-F, Alt-V, etc to bring up main menus via the keyboard. Use arrow keys to navigate menus and/or single letters corresponding to the "hot" letter (underlined lettter) for each menu item. "ESC" to back out of the menu system. Global Operations: ------------------ LeftClick Select Menu or GUI Item (when in menus or dialogs) LeftDblClick FetchAlertText (when in View->Wx Alerts dialog) RightClick OptionsMenu Home Center the map on your home station PageUp ZoomOut PageDown ZoomIn ArrowUp PanUp ArrowDown PanDown ArrowLeft PanLeft ArrowRight PanRight "=" GridSize++ "+" GridSize++ "Num+" GridSize++ "-" GridSize-- "Num-" GridSize-- "Space" Activate current widget "Tab" Rotate among widgets "Back-Tab" Rotate among widgets backwards Other Possible External Stimuli: -------------------------------- Send a SIGUSR1 to cause a snapshot to be taken. Send a SIGHUP to cause Xastir to save/quit/restart. Send a SIGINT, SIGQUIT, or SIGTERM to cause Xastir to quit. Connect to TCP port 2023 if Server Port is enabled to send/receive packets. Send to UDP port 2023 via the xastir_udp_client program to inject packets. Note that you can also tweak a define/recompile to reverse the left/right button functions. Configuring Xastir: ------------------- *) Note that the menu's have a dashed line near the top. If you click on that dashed line it acts like a cut-line for the menu and detaches that menu from the main menu. You can then move that menu off to another area of your screen. You might try that with the File->Configure menu at this time. *) Go to File->Configure->Station and set your callsign. Set up other parameters/comment fields on this dialog that may need setting. *) Go to File->Configure->Defaults and set parameters there. You have the main parameters set now. Next is to enable some interfaces so that you can see some packets come across. Easiest might be the Internet interfaces, assuming the computer you're on has Internet access and is hooked up to it currently. *) Run "callpass" in another Xterm window in order to generate your Pass-code number. Save that number as you'll need it for each Interface dialog where you might need to authenticate your callsign. Of course you can always run callpass again if you forget it! *) Go to Interface->Properties then click on "Add". Click "Internet Server". Another dialog will come up that allows you to enter the Host, and the Port. Enter your Pass-code number here. People often check the "Activate on Startup?" and the "Reconnect on NET failure?" options on this box. You may also assign a comment to this interface which describes the interface better for you. Click "OK" to create the interface. If you checked "Activate on Startup?" then the interface will start as well and you'll be receiving packets. Browse "http://www.aprs2.net/" to find a reasonable set of servers to start with. Another possibility is to use "rotate.aprs2.net" port 14580, which theoretically should rotate among the available second-tier servers. See "http://www.aprs2.net" for more info. You'll need to put in a filter string, such as "r/35/-106/500" which shows you stations that are within 500km of 35dN/106dW (Thanks for that one Tom!). For additional filter settings check out: http://www.aprs-is.net/javaprssrvr/javaprsfilter.htm *) Start that interface from the Interface->Start/Stop dialog if it's not started already. You'll see icons in the lower right toggling and see callsigns in the lower left status box if packets are coming in. One thing about configuration: Most things don't get written to Xastir's config file until you choose either "File->Configure->Save Config Now!" or you exit Xastir. Map Selections however are immediate. *) Creating/starting interfaces for other types of devices is similar. If you're wanting to create AX.25 kernel networking ports you'll have to refer to the HAM HOWTO documents and perhaps the linux-hams mailing list for help. For AGWPE connections refer to that AGWPE docs and mailing list. It's recommended that if you run a local TNC, you run it in KISS mode. You can do that via the Serial KISS TNC interface, or via AX.25 Kernel Networking ports. Some of the more esoteric types of interfaces may require some questions on the Xastir list. Don't be afraid to ask them as we've all been there before. A Note About Paths: ------------------- New path methods were discussed early April, 2005, and are being implemented world-wide: "WIDE2-2" for fixed stations, balloons, aeronautical-mobile "WIDE1-1,WIDE2-1" for mobiles/portables With this system, "WIDE1-1" has replaced "RELAY". Never use "WIDE1-1" in anything but the first path slot. "RELAY", "WIDE", "TRACE", and "TRACEn-N" are deprecated and should not be used anymore. If you want to insert a single hop callsign later in the path use "WIDE2-1" instead, for example: "WIDE1-1,WIDE2-1" will go exactly two hops and use _either_ home fill-in digi's or mountaintop digi's for the first hop, mountaintop digi's only for the second hop. Home fill-in digi's (only where absolutely needed) should be set up to respond to "WIDE1-1" instead of "RELAY". A Note About the Map Directory: ------------------------------- The map directory (/usr/local/share/xastir/maps/) is free-form, meaning you can have links in there, subdirectories, etc. Organize it in any way that makes sense to you. From within the Map Chooser you can select a directory name, which will select every map underneath that directory, so keep that in mind while organizing your maps. Enabling Weather Alerts: ------------------------ You must have Shapelib compiled into Xastir. Xastir now comes with Shapelib support built-in. PRCE/dbfawk are optional. Install NOAA shapefile maps as specified in README.MAPS. These files must be installed into the /usr/local/share/xastir/Counties/ directory. You may use this script to download/install them for you: "/usr/local/share/xastir/scripts/get-NWSdata" which must be run as the root user, and requires "wget" to work. A neat trick: You can copy some of these maps into the /usr/local/share/xastir/maps directory somewhere (a new subdirectory under there is always fine), then you can select some of these maps as regular Xastir maps as well. Enabling FCC/RAC Callsign Lookup: --------------------------------- Run the /usr/local/share/xastir/scripts/get-fcc-rac.pl script as root, which will download and install the proper databases into the /usr/local/share/xastir/fcc/ directory. At that point the callsign lookup features in the Station Info dialog and in the "Station->Find Station" menu option should be functional. Enabling Map Feature Lookup: ---------------------------- Install USGS GNIS files into the /usr/local/share/xastir/GNIS/ directory. Call out the proper file when invoking the "Map->Locate Map Feature" menu option. Note that if you also link a subdirectory name under the maps directory back to the /usr/local/share/xastir/GNIS/ directory, you'll be able to use the GNIS files as maps under the Map Chooser as well. See README.MAPS for how to do this. Enabling Street Address Lookup: ------------------------------- Download the USA.geocode file and install it into the /usr/local/share/xastir/GNIS/ directory. This will enable the "Map->Find Address" menu option to work. Xastir will place a big "X" on the map at the street address it finds for you. This file is sometimes available at http://www.dementia.org/geocoder/tgr2003/ As an alternative you can download the individual state files that are located there. Enabling Audio Alarms: ---------------------- Download and install sample audio files from Xastir's GitHub download site: git clone http://github.com/Xastir/xastir-sounds Copy the files to your Xastir sounds directory, for instance: /usr/local/share/xastir/sounds/ Install a command-line audio player. Call out the path/name of that player in the File->Configure->Audio Alarms dialog. Common ones are vplay and auplay, but there are many others. Enable the types of alarms you desire in that same dialog. You should be able to test it manually from a shell by typing the command in something like this: vplay filename Once you find a command that works, type it into Xastir's Audio Alarms dialog exactly the same except omit the filename. Enabling Synthesized Speech: ---------------------------- *) MacOSX TBD *) Windows TBD *) Linux/FreeBSD/Solaris Install the Festival Speech Synthesizer. Configure/compile support for it into Xastir. Start up the Festival server before starting Xastir. Xastir should start up and connect to the server. Use the options in File->Configure->Speech to decide which things you'd like Xastir to speak to you about. Note that the Proximity Alert option in the File->Configure->Speech dialog uses the distances set in the File->Configure->Audio Alarms dialog. Enabling GPS Waypoint/Track/Route Download Support: --------------------------------------------------- Install GPSMan and gpsmanshp. Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. You'll see download options for each type on the Interface menu. Note that Xastir requires a version of gpsman at least as recent as 6.1. Older versions of gpsman may not work. Enabling Garmin RINO Support: ----------------------------- Install GPSMan (and gpsmanshp if you wish normal GPS download support as well). Configure/compile support for it in Xastir. Start up GPSMan separately and configure it for your GPS and serial port. In the "File->Configure->Timing" dialog you'll see an option for "RINO -> Objects Interval". That sets the interval at which Xastir will download waypoints from an attached RINO unit. Any waypoints that begin with "APRS" will have the "APRS" chopped off, and the remaining name will be used to create APRS(tm) Objects. Those objects will be plotted on the map and transmitted as well if transmit for objects/items is enabled. TBD Transmit Enable/Disable Options: -------------------------------- Each interface has a separate transmit enable. The Interface menu also has a few global transmit enables. All of these must be enabled for a particular interface to transmit. Also, for Internet servers, you typically need to authenticate with the server using your callsign/pass-code before you're allowed to inject packets into the Internet stream which may get gated out to RF. If you just want to talk to other Internet users, you don't need a pass-code to authenticate to the servers. Igating Options: ---------------- There are igating options on each local TNC interface. There are other global igating options on the File->Configure->Defaults dialog. The global option sets restrictions on all igating. Where stuff is kept: -------------------- Per-user configurations are kept in each user's ~/.xastir directory, by default. In particular the ~/.xastir/config/xastir.cnf file is where most of the configs are kept. This directory can be optionally specified using the -c /path/dir command line option. Make sure you specify a directory, not a file! Xastir will create the directory and several subdirectories if they do not exist when you start up. A few executables are installed in /usr/local/bin/. Scripts are installed in /usr/local/share/xastir/scripts. Maps are installed in /usr/local/share/xastir/maps/. Lots of other directories are under /usr/local/share/xastir/. More? ----- Anything else? Let's hear about what's still confusing or needs to be expanded in this document. Thanks! APRS(tm) is a Trademark of Bob Bruninga Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/bootstrap.sh0000775000175000017500000000100115151324131015665 0ustar hibbyhibby#!/bin/sh -e # # # Copyright (C) 2000-2026 The Xastir Group # # # This simple routine will run autostuff in the appropriate # order to generate the needed configure/makefiles # echo " 5) Removing autom4te.cache directory..." rm -rf autom4te.cache echo " 4) Running aclocal..." aclocal echo " 3) Running autoheader..." autoheader echo " 2) Running autoconf..." autoconf # Cygwin needs these parameters to be separate. echo " 1) Running automake..." automake -a -c echo "Bootstrap complete." Xastir-Release-2.2.4/callpass.10000664000175000017500000000137515151324131015213 0ustar hibbyhibby.TH callpass 1 2019-05-01 "The Xastir Group" .SH NAME callpass \- generate Pass-code associated with your callsign for authentication via xastir to APRS(tm) network. .SH SYNOPSIS .B callpass .I .SH DESCRIPTION Generate passcode for use in xastir authentication to APRS network for traffic delivery to cooperating systems. .SH EXAMPLES callpass nocall outputs 'Passcode for nocall is 12960' .SH NOTES There is no error or consistency check for callsign. This utility will generate a passcode for any string. .SH SEE ALSO xastir help file .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/callpass/0000775000175000017500000000000015151324131015123 5ustar hibbyhibbyXastir-Release-2.2.4/callpass/.vimrc0000664000175000017500000000143315151324131016245 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/callpass/Makefile.am0000664000175000017500000000030515151324131017155 0ustar hibbyhibby # Copyright (C) 2000-2026 The Xastir Group MAINTAINERCLEANFILES=Makefile.in bin_PROGRAMS = callpass callpass_SOURCES = callpass.c callpass_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.4/callpass/callpass.c0000664000175000017500000000431015151324131017067 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include #include #include #define kKey 0x73e2 // This is the seed for the key #define true 1 static short doHash(char *theCall) { char rootCall[11]; // need to copy call to remove ssid from parse char *p1 = rootCall; short hash; short i, len = 0; char *ptr = rootCall; while ( (*theCall != '-') && (*theCall != '\0') ) { *p1++ = toupper( (int)(*theCall++) ); len++; } *p1 = '\0'; hash = kKey; // Initialize with the key value i = 0; while (i < len) // Loop through the string two bytes at a time { hash ^= (unsigned char)(*ptr++) << 8; // xor high byte with accumulated hash hash ^= (*ptr++); // xor low byte with accumulated hash i += 2; } return (short)(hash & 0x7fff); // mask off the high bit so number is always positive } short checkHash(char *theCall, short theHash) { return (short)(doHash(theCall) == theHash); } int main(int argc, char *argv[]) { char temp[11]; if (argc>1) { memmove(temp, argv[1], 11); // Process up to 10 characters temp[10] = '\0'; // Forced string terminator if (temp[0] != '\0') { printf("Passcode for %s is %d\n", temp, doHash(temp)); } } else { printf("Usage:callpass \n"); } return(0); } Xastir-Release-2.2.4/changes.txt0000775000175000017500000005175615151324131015513 0ustar hibbyhibby Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Changes.txt 04.01.2001 See ChangeLog for software changes... 11/13/2000 codebase version changed to 0.4.0, starting next development release 11/08/2000 0.3.6-2 -- cb modified color.c to behave with gcc 2.96 added callpass delete object patch for db.c - J.Stueve KE4NFJ 09/24/2000 Alpha 0.3.6b added time/date to buletins list. modified PHG routines. added the beginings to view all message traffic. 09/19/2000 Alpha 0.3.6a fixed/added sorting for bulletins. * *fixes by KE4NFJ 09/16/2000 Alpha 0.3.6 add the usage of comments in the nws-stations.txt file, "#" as first char on a line. add bulletins within a radius view screen. added speedups for pixmaps. * added Italian language # *modifications by VE6LFM #additions by IK0YUP 08/27/2000 Alpha 0.3.5a bug fix for the PHG not displaying. 08/26/2000 Alpha 0.3.5 changed WX alert minimum refresh from a int to a long. Updated the French language file. fixed a network socket closing problem. changing all posits (in and out) to High precision, Compressed format will output high precision. added igating (net to RF) of NWS weather messages. (to use this build a text file in the xastir users directory as .xastir/data/nws-stations.txt list each call or NWS station like "SECIND" that you would like to transmit via RF) 07/14/2000 Alpha 0.3.4a fixed a minor problem for some solaris systems.* * fixes/additions by KE4NFJ 07/10/2000 Alpha 0.3.4 (no changes from the pre-release) fixed symbol decoding for stations with an overlay character. added AEA to TAPR2 path decoding to fix MIC-E decoding with AEA type TNCs. modified station trails.+ speed ups for Pixmaps images.@ fixed output logic on mobile data. removed unused data from makefile. modified altitude decoding for "/A=XXXXXX". added "/A=XXXXXX" altitude encoding on output of station positions (with GPS input and not WX data output). added NETWORK_WAITTIME to config file, this sets the network time out value when doing host lookups and socket connections, default is 10 (no GUI Interface for this yet). added WX_ALERTS_REFRESH_TIME to config file, this sets the minimum seconds allowed between a WX Alert starting a redraw of maps on the screen, default is 30 (no GUI Interface yet). updated help file. + modifications by WE7U @ fixes by PE1DNN 06/12/2000 Alpha 0.3.3 fixed data position information output logic. fixed missing E/W logic in compressed posit formats.* * fixes/additions by KE4NFJ 05/31/2000 Alpha 0.3.2 fixes for Solaris.* fixed a bug in sending data via TNC, the first few chars were dropped on MFJ's with Paccom software installed. added support for image maps (.xpm format only) with .geo files for location. fixed small problem with weather alerts expiring incorrectly for Daylight Savings Time.* fixed some conditions for alert matching on weather alerts.* fixed path length.@ fixed Dos map problem dropping data, as in Ilchicgo.map.* fixes for WX-Alerts.* changed line tracking to not display line when the object is faster then 900 MPH, however I may make this an option, or a soft limit. fixes for 0.91 of lesstif, some scrolled text was not positioned correctly. added wx gust reset. removed some filtering on AX.25 ports.@ fixed data command/transmission problem for some TNCs. changed the default code compiling to not include debugging information, this reduces the executable code size by a huge amount. However I also added an option in the Makefile to compile with this information. changed Segmentation faults operation, if the program Segfaults, it will terminate, but now it should happen cleaner. changed the way broken pipes are handled, hopefully you won't see those again. added white as a background color. modified MIC-E decode logic for more support of the protocol.+ added transmission of compressed position data.* cleaned up decoding of compressed data.* added jump to last map position. fixed map sorting for case insensitive. * fixes/additions by KE4NFJ @ fixes by PE1DNN + modifications by WE7U and me (KC2GJS). Also I changed my CALL from KC0DGE to KC2GJS. 03/30/2000 Alpha 0.3.1 changed Baro reading on WX-200 to Sea Level vs. Local Level. added more space for and digits for some WX station display fields. added changes.. so Xastir will run on FreeBSD.+ fixed object decoding. fixed compressed format symbol decoding added compressed object decoding. added course and speed to compressed decoding. added logic to AX.25 interface so a "*" would be added to the digipeater call that's transmitting the packet.@ fixed bug in AX.25 interface, seems as if all AX.25 packet data is transmitted through the interface. Even if it is from a device not used by Xastir. Added code to "filter out" incoming packets that are from another device. @ fixed tab groups for keyboard movement on message boxes, tracking, locate station, and misc dialogs. removed transmitter off message popups, some found this annoying. changed to case insensitive sort on stations.* fixed bug in WX data output, rain in past 24hr was switched with rain since midnight on output of data. fixed a possible crash on shutdown of the network connections. added/fixed max station now only has a memory limit. The station buffer now allocates memory as needed and the max station's error popup will only show when no more memory can be allocated for stations.* changed message time intervals. + Additions by N3NYN @ fixes by PE1DNN, modified by KC0DGE * fixes by KE4NFJ 03/23/2000 Alpha 0.3.0 changed the station Info box size. changed net connect and host lookup return a good connect faster. modified net connect procedure.. used terminate thread instead of sigalarm. modified the size of the raw WX buffer. Added Net WX interface. modified symbol routines.* Added new symbols.* misc include file fixes.* modified Makefile so that compiling on RH5.2 and using the old AX.25 utils works.+ fixed the AX.25 port lockup on start up problem. Added Radio Shack WX200/Oregon Scientific WM-918 support. misc WX station fixes and changes. fixed dialogs to work on older system/KDE combo. Added WX data decode for APRS POS/WX format. Added popup message when MAX_STATIONS is exceeded. * additions by KE4NFJ + fix by HI8GN 03/14/2000 Alpha 0.2.9 changed it so any data from a good call sign goes into data base. changed serial port start up, if serial lock file errors on opening, still try to open port. fixed Query response for ?IGATE? to number of "local" stations and added message counter. added a few General Queries to the menu. added Query response for ?APRSP. changed Widget shells (Major code change) to support main window over child windows. fixed/changed some misc gui stuff. fixed New fcc data lookup (too slow!).. However it requires the following: **** NOTE to use the NEW data base file it must be sorted first!!! **** Make sure you have plenty of disk space for this as the file is BIG! To sort the file: sort +4 -t \| EN.dat >EN.dat.sorted rm EN.dat mv EN.dat.sorted EN.dat removed previously added reject logic for bad rain data, caused a segfult. fixed interface gui causing segfault if windows closed out of order. moved fcc/rac test to after window's opens. Added status for fcc/rac rebuilding index files. removed usleep out of threaded routines read_port() & write_port() as usleep is not thread safe on solaris, replaced usleep with select. fixed baud rate selection, 38400 and 57600 were reversed. fixed a problem in the Makefile where it couldn't find Lesstif Libs on some systems. fixed some memory leaks. * fixed data entry screens to remove added spaces in data input. Added Peet Bros Complete data mode for WX Station. & modified WX Station screen for more info if in Complete data mode. fixed bug in heard_via_tnc_in_past_hour. added second chance transmit of message if heard via tnc but not in past hour then try the last net connection the station was heard. fixed German ',' vs '.', stupidity on my part. added busy cursor (to map etc..) when working with interfaces. fixed bug in adding a WX port at 2400 bps.. on startup would go to 4800. fixed bug in starting interface (manually) when it is already up. fixed bug in connection to the net where the host is found but the connection is not made. cleared out some possible "broken-pipe" errors on closing a errored interface. cleaned up a possible segfault on messages with out acks. added some more WX rain checks.. Please Check me.. added Spanish Language support. + * fix by KE4NFJ & additions by KD6VPE + additions by HI8GN 03/08/2000 Alpha 0.2.8 added/changed color lookups, now has it's own file and colors should be consistent across various X managers. added local stations list. added some Query buttons to station info window. cleaned up buttons on dialogs. added Query responses for ?APRST ?PING? ?APRSM ?APRSD ?IGATE. moved more gui stuff to separate files. Added popup message windows for errors, status, query responses, etc. fixed/added updates to local station for last path heard and position/packet time. fixed a bug when transmitting messages via RF to a local station. ### NOTE THIS IS A BIG ONE!!!! added more reject logic for bad rain data, for the WX Station. 03/03/2000 Alpha 0.2.7 changed formula used on Qualimetrics Q-Net WX station decoding (another minor difference). fixed WX wind gust. found a WX rain bug. changed some more background colors. fixed a broken pipe bug on write. changed wx alert display routines.* added sound for wx alerts.* fixed Motif popup menu on map problem (FINALLY!!!!!). fixed bug in station lists. added save of station list size. fixed clipboard copy for call sign on station list (as long as the call does not move in the list). changed gethostbyname2 to gethostbyname for older systems. * additions by KE4NFJ 02/27/2000 Alpha 0.2.6 changed zoom status window size fixed a bug in auto map directory. fixed a bug in config not saving if no backup file exists. changed formula used on Qualimetrics Q-Net WX station decoding (minor difference). changed some background colors. added some extra debugging on the serial ports. fixed Q-Net transmit wx data (original routine needed Course and Speed so it can TX WX data). 02/26/2000 Alpha 0.2.5 More Motif stuff.* More Makefile Mods. * (and me) fixed port shutdown but data to be written bug. fixed a bug when sending raw WX data. hopefully fixed mouse button popup menu (zooming/panning) for Motif. added Qualimetrics Q-Net WX station decoding. fixed? Peet bros packet mode for WX station reading (wind/rain problem). fixed? alignment problem for headers on station/wx/mobile lists. * additions by KE4NFJ 02/25/2000 Alpha 0.2.4 fixed a bug in AX.25 status (input bytes). fixed the map redraw bug? Modified the Makefile. added time stamp in message box. 02/24/2000 Alpha 0.2.3 Added code to remove stale serial lock files. Added option for WX Alert Counties maps to appear above or below other loaded maps. Added Station List, Mobile Station List, and WX Station List. Modified WX station decoding. Added Transmitting of Raw WX data - Peet Bros. UII, U2k (data logging), U2k (Packet). Added WX station logging. Added option to compile with out AX.25 (look at Makefile, Let me know how it works for you!).* Added Host name on top bar.* Modified WX Alerts.* Added some Motif Conditions (start of better Motif vs LessTif support).* * additions by KE4NFJ 02/19/2000 Alpha 0.2.2 Added more WX station stuff and WX transmit !! PLEASE CHECK THIS fixed a bug in AX.25 Gui restart. Modified Makefile to be a little more generic. Changed operation of WX Alerts so screen updates don't hold the system up. 02/18/2000 Alpha 0.2.1 Ok first round is through some had problems, some had none. Deleted a include file giving some of you problem. Modified some of the interface code for displaying status. Fixed some bugs in the interface status display code. 02/17/2000 Alpha 0.2.0 0.1.4 is dead. I've decided not to continue with this version number because A good part of Xastir has been rewritten for the threaded I/O. I have also brought the functionality up to warrant a much higher version number. This version allows multiple TNC's and Internet connections. Complete rewrite of I/O (Too many changes to list). Added AX.25 support built in. @ Changed RAC look up for "VE" and "VA" only, rather than just "V". Changed I/O menus. Changed default menus. Fixed some IGate problems. Changed HOST lookup Added $ULTW WX data support. Added support for WX stations (beginning support so far). Modified WX support. Added WX Alert List (with WX Alert county maps. * * additions by KE4NFJ @ AX.25 Parts adopted from: aprs_tty.c by Henk de Groot, modified by KC0DGE 12/30/1999 Alpha 0.1.4 changed Mapping for higher precision display (Still testing) (Example 28.255 min instead of 28.25 min) NOTE: Your zoom and position in your xastir.cnf file will be based on the previous data and when you upgrade you may find your position and zoom in the wrong place when you first start it. added TNC format (8N1, 7E1, 7O1) to the TNC. cleaned up a possible TNC over-run error. changed some tracking constants for new map precision. added WX port code and dialogs. cleaned up some display code. cleaned up TNC code. changed automap detection, it should work better on odd sized maps. added more map support and better decoding. * fixed a map pan up bug. fixed WX gust missing bug in station info box. added support for dos maps. * added the start of station queries. added gpsd support (networked GPS). @ added support for filled map types * (and me) added support for background map colors, Selection in Maps menu. added two methods for displaying station labels. fixed a bug in weather from a Peet Bros U2K with negative temp. disabled problem in alerts routine deleted old debug command line, now is -v . added new command line language options. changed Makefile to work with the new command line language options. deleted use of HELP_DATA key in xastir.cnf file changed start up to check and make missing directories for user data. * additions by KE4NFJ @ additions by WE7U 11/14/1999 Alpha 0.1.3 fixed rain to show in mm instead of cm (in metric mode). fixed update to display for new data, not just position. added support for compressed map format. * fixed time values to the correct time_t rather than unsigned long. added Canadian Callsign Lookup. + added fast search and indexing of US and Canadian Callsign Lookup. + added check for new file to rebuild the search index for above. added support for new FCC file format. fixed an error in the make install for new a install. added support for other languages (with the language.sys file) (more to do). added support for multi color tracking lines. @ fixed additional tracking line bugs. added support for station position ambiguity. added support for NET to RF IGATE for messages. fixed message data to fit in with the spec. added Proximity and band opening alarms. # fixed Red Hat core dump when no files in map directory and using the map chooser. added I-Gate logging. added some Reject I-Gate logic. added I-Gate on ack's (oops forgot this!) fixed I-Gate to net logic (or at least made it more sane). moved Proximity and band opening alarms to work on any incoming packet not just new ones. added Language install added GNU LICENSE * additions by KE4NFJ + additions by VE3UNW @ additions by WE7U # additions by KD5AMB 10/22/1999 Alpha 0.1.2 fixed net connect core dump if the server was not available. removed source directory copy to /usr/local/src/xastir on install. (no really needed just messed up the developers. changed the zoom level to match with the actual level. added GPS GLL string decoding. * cleaned up station data base code.* changed some makefile options (runs smoother). started work on Igate to RF. fixed mistake in map loading stuff. + * additions by KE4NFJ (A big THANKS!!) + fixes by Chris Bell (THANKS!!) 10/01/1999 Alpha 0.1.1 !!!! Added/changed file structure to fit in the more standard FHS format. !!! added GPS support via HSP cable. added GPS time value. added APRS(tm) output in mobile format when GPS is active. added/fixed net/tnc clean up. fixed net data decode for servers that put out Carriage returns not Line feeds. (*) added more aprs decode support (for decoding CsT characters on RMC and GGA strings). (*) added environment values XASTIR_USER_BASE and XASTIR_DATA_BASE to set alternative directory locations for user data and common data. (-) added more aprs decode support (for handling some compressed mode lat/lon). (+) added course and speed decode for aprs mobile stations. added decoding of altitude in some formats other than GGA strings. fixed Track line bug. added more track lines. fixed decoding of some missed status data. added changes as per WE7U for grid lines every degree, However this is an auto selection on zoom level. added changes for Humidex (chill factor) only displays in metric. @ fixed grid lines so they don't erase map lines. added zoom info. fixed GPS drop off of last digit on some GPS (I hope). added install feature in makefile (fits in with above). added support for other users than root (!!! you need to have access to the devices you want to use still !!!). fixed some window close problems. Tested with version 0.89 of Lesstif (seems ok, no problems yet!!). added sorting of map files in map chooser. fixed station info box/send message core dump when message box open and info box closed. added Display for incoming packet data (with selection of data type). added Station Tracking. * additions by KE4NFJ (A big THANKS!!) + additions by WE7U (Again A big THANKS!!) - additions by KE4NFJ and modified by me. @ additions by VE3UNW (Again A big THANKS!!) 08/17/1999 Alpha 0.1.0 Do not use Lesstif version 0.88.9! It makes the use of radio buttons crash the program. Not sure why.. perhaps a bug in this version of Lesstif?! Ok first official canning of Alpha characters in the version numbers, This would have been 0.0.Kt4, but it gets too confusing. From now on, test versions, for that matter any version will be numeric digits only and no special tX on the end for test versions. Trying to keep it simple. fixed a "major stupid" bug, put any object to the East off its real location. added decoding for Peet Bros UM2. fixed some bugs in displaying temp on the station info screen. added sound alerts for messages. added Send message button for Station Info. added Multi-hosts for Internet connections. added GPS Support. fixed some core dump problems on incoming data. 07/22/1999 Alpha 0.0.Kt3 (test version for K) !!!!! This is a test version !!!!!! added wx display on maps. added timeout indicator when loading maps. added Net/Tnc status indicators. added auto message responder. added Power-gain circles. fixed Metric values. Meters should have been kilometers. fixed some misspellings. fix/add wx data now changes MPH to KPH and temp goes for F to C, inches go to cm. added PHG to station info. fixed hear via TNC statement in station info.. added decoding for Peet Bros. data logging mode record format for over air data. Hopefully fixed: Red Hat tnc & net down/up core dump problem. 06/26/1999 Alpha 0.0.Kt2 (test version for K) !!!!! This is a test version !!!!!! Fixed some minor bugs. Changed some window layout code, Hopefully it will be more consistent across window managers. More Speed ups, Some major speed up to display writing. More Message fixes. Changed the way you zoom and scroll the display. Added preset zoom levels. Added Station info display. Added Station tracking, with a trailing tracking line. Beginning work on weather data, station info will report data if available. Fixed net connection drop bug (hopefully). Fixed Red Hat map chooser bug. New, if the connection is dropped there is a new option under configure, Internet, That will allow you to reconnect to the net if this option is checked. Changed, The messaging system is going through an overhaul, hopefully not so much of a kludge. 06/02/1999 Alpha 0.0.J Major bug fixes for Red Hat users.. I hope I got them all.. 06/01/1999 Alpha 0.0.I First release of Xastir! Lots of things are not working.. No station information windows. It doesn't decode all of the APRS(tm) packets. Messaging works, however it is not finished. Currently there is no support for GPS data for setting your position. Xastir will read window/mac APRS(tm) map format and automatically select the correct map for your area win auto maps on. Currently this is slow and will be corrected in future versions. Most of the APRS(tm) are in place and will position on the map. Net interface is live, but also needs more work. Configuration screens are very basic.. In other words it is the first release of FREE Alpha version software! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html" Xastir-Release-2.2.4/config/0000775000175000017500000000000015151324131014566 5ustar hibbyhibbyXastir-Release-2.2.4/config/.vimrc0000664000175000017500000000143315151324131015710 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/config/24kgrid.dbfawk0000664000175000017500000000363315151324131017221 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map USGS 24k grid shapefiles, which contains bounding # rectangles for USGS 1:24000 quadrangles. # The shapefile itself can be had from # http://data.geocomm.com/quadindex/ # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="NAME:STATE:LAT:LONG:MRC"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME:STATE"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=65535; label_level=512; label_color=2; font_size=1; symbol=""} # per-field rules are applied to the dbffields that are read from each record. /^NAME=(.*)$/ {name="$1; next} /^STATE=(.*)$/ {name="$(name),$1; next} Xastir-Release-2.2.4/config/Makefile.am0000664000175000017500000000664615151324131016636 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # configdir = ${pkgdatadir}/config EXTRA_DIST = \ language-Dutch.sys \ language-English.sys \ language-French.sys \ language-German.sys \ language-Italian.sys \ language-Portuguese.sys \ language-Spanish.sys \ language-ElmerFudd.sys \ language-MuppetsChef.sys \ language-OldeEnglish.sys \ language-PigLatin.sys \ language-PirateEnglish.sys \ xastir.rgb \ gps_wpt.dbfawk \ 24kgrid.dbfawk \ stored_track.dbfawk \ tgr2shp.dbfawk \ tgr2shppoly.dbfawk \ tgr2shppoly_2006.dbfawk \ tgrcty.dbfawk \ tgrkgl.dbfawk \ tgrlk.dbfawk \ tgrlpt.dbfawk \ tgrlpy.dbfawk \ tgrplc00.dbfawk \ tgrwat.dbfawk \ nwsc_ddmmyy.dbfawk \ nwsfz_ddmmyy.dbfawk \ nwsmzddmmyy.dbfawk \ nwsozddmmyy.dbfawk \ nwsw_ddmmyy.dbfawk \ nwsz_ddmmyy.dbfawk \ nwshzddmmyy.dbfawk \ OSM_Cloudmade_administrative.dbfawk \ OSM_Cloudmade_highway.dbfawk \ OSM_Cloudmade_natural.dbfawk \ OSM_Cloudmade_poi.dbfawk \ OSM_Cloudmade_water_and_coastline.dbfawk \ OSM_geofabrik_roads.dbfawk \ OSM_geofabrik_waterways.dbfawk \ OSM_geofabrik_2026_buildings.dbfawk \ OSM_geofabrik_2026_natural_and_water.dbfawk \ OSM_geofabrik_2026_roads.dbfawk \ OSM_geofabrik_2026_waterways.dbfawk \ predefined_EVENT.sys \ predefined_SAR.sys \ tl_2009_aiannh.dbfawk \ tl_2009_aits.dbfawk \ tl_2009_arealm.dbfawk \ tl_2009_areawater.dbfawk \ tl_2009_county.dbfawk \ tl_2009_cousub.dbfawk \ tl_2009_edges.dbfawk \ tl_2009_mil.dbfawk \ tl_2009_nn_county.dbfawk \ tl_2009_pointlm.dbfawk \ tl_2009_zcta5.dbfawk \ tl_2025_areawater.dbfawk \ tl_2025_arealm.dbfawk \ tl_2025_county.dbfawk \ tl_2025_cousub.dbfawk \ tl_2025_linearwater.dbfawk \ tl_2025_place.dbfawk \ tl_2025_pointlm.dbfawk \ tl_2025_roads.dbfawk \ tl_2025_rails.dbfawk \ tl_2025_uac.dbfawk \ tnc-startup.aea \ tnc-startup.d700 \ tnc-startup.d72_d710 \ tnc-startup.kam \ tnc-startup.kpc2 \ tnc-startup.kpc3 \ tnc-startup.null \ tnc-startup.paccomm \ tnc-startup.pico \ tnc-startup.sys \ tnc-startup.thd7 \ tnc-startup.tnc2 \ tnc-startup.tnc2-ui \ tnc-stop.d700 \ tnc-stop.d72_d710 \ tnc-stop.sys \ tnc-stop.thd7 \ tnc-stop.tnc2-ui \ areawater.dbfawk \ arealm.dbfawk \ tabblock.dbfawk \ cousub.dbfawk \ cousub00.dbfawk \ edge.dbfawk \ featnames.dbfawk \ pointlm.dbfawk \ gfe_public_weather.dbfawk \ gfe_metro_areas.dbfawk \ gfe_fire_weather.dbfawk \ gfe_coastal_waters_warnings.dbfawk \ gfe_coastal_waters.dbfawk config_DATA = ${EXTRA_DIST} install-exec-hook: -rm -f $(DESTDIR)$(configdir)/nwsfz_ddmmyy.dbfawk language-ElmerFudd.sys: language-English.sys $(top_srcdir)/scripts/langElmerFudd.pl -split >$@ <$(srcdir)/language-English.sys language-MuppetsChef.sys: language-English.sys $(top_srcdir)/scripts/langMuppetsChef.pl -split >$@ <$(srcdir)/language-English.sys language-OldeEnglish.sys: language-English.sys $(top_srcdir)/scripts/langOldeEnglish.pl -split >$@ <$(srcdir)/language-English.sys language-PigLatin.sys: language-English.sys $(top_srcdir)/scripts/langPigLatin.pl -split >$@ <$(srcdir)/language-English.sys language-PirateEnglish.sys: language-English.sys $(top_srcdir)/scripts/langPirateEnglish.pl -split >$@ <$(srcdir)/language-English.sys Xastir-Release-2.2.4/config/OSM_Cloudmade_administrative.dbfawk0000664000175000017500000000460215151324131023466 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_administrative.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NAME:ADMIN_LEVE"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NAME:ADMIN_LEVE"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=105; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=(.+)$/ {name="$1";next} /^ADMIN_LEVE=2/ {lanes=4; color=105; label_level=65536; font_size=1; next} /^ADMIN_LEVE=4/ {lanes=3; color=105; display_level=64; label_level=512; font_size=1; next} /^ADMIN_LEVE=6/ {lanes=2; color=105; display_level=64; label_level=512; font_size=1; next} /^ADMIN_LEVE=8/ {lanes=1; color=105; display_level=64; label_level=512; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_Cloudmade_highway.dbfawk0000664000175000017500000001350715151324131022107 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_highway.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="TYPE:NAME:ONEWAY:LANES"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="TYPE:NAME:ONEWAY:LANES"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=State Highway (.*)$/ {name="$(name)Hwy $1"; next} /^NAME=State Route (.*)$/ {name="$(name)SR-$1"; next} /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^NAME=Interstate (.*) Northbound$/ {name="$(name)I-$1 N"; next} /^NAME=Interstate (.*) Southbound$/ {name="$(name)I-$1 S"; next} /^NAME=Interstate (.*) Eastbound$/ {name="$(name)I-$1 E"; next} /^NAME=Interstate (.*) Westbound$/ {name="$(name)I-$1 W"; next} /^NAME=Interstate (.*)$/ {name="$(name)I-$1"; next} /^NAME=Washington Highway (.*)$/ {name="$(name)Hwy $1"; next} /^NAME=(.+)$/ {name="$1";next} #/^LANES=(.+)$/ {lanes="$1";} # TYPE: /^TYPE=abandoned/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=bridleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=construction/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=crossing/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=cycleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=driveway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=footway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=ford/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=living_street/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} # Note: No display_level or label_level /^TYPE=motorway/ {lanes=4; color=4; label_level=65536; font_size=3; next} # Note: No display_level /^TYPE=motorway_link/ {lanes=3; color=2; label_level=16; font_size=1; next} /^TYPE=path/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=pedestrian/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=platform/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=primary/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^TYPE=primary_link/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^TYPE=raceway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=ramp/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=residential/ {lanes=1; color=44; display_level=64; label_level=16; font_size=1; next} /^TYPE=road/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=secondary/ {lanes=2; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=secondary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=service/ {lanes=1; color=8; display_level=64; label_level=16; font_size=1; next} /^TYPE=service; residential/ {lanes=7; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=steps/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=tertiary/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=tertiary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^TYPE=t/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=track/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=trail/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^TYPE=tr/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=trunk/ {lanes=3; color=8; display_level=128; label_level=16; font_size=3; next} /^TYPE=trunk_link/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=unclassified/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^TYPE=unsurfaced/ {lanes=1; color=105; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_Cloudmade_natural.dbfawk0000664000175000017500000000427715151324131022121 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_natural.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NAME:TYPE"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NAME:TYPE:"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=4; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record /^NAME=(.+)$/ {name="$1";next} # TYPE: /^TYPE=water/ {lanes=1; color=9; display_level=64; label_level=16; font_size=1; next} /^TYPE=forest/ {lanes=1; color=10; fill-color=10; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_Cloudmade_poi.dbfawk0000664000175000017500000000470015151324131021231 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_poi.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="CATEGORY:NAME"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="CATEGORY:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=16; label_level=16; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^NAME=(.+)$/ {name="$1";next} /^CATEGORY=Automotive/ {color=4; font_size=1; next} /^CATEGORY=Eating&Drinking/ {color=4; font_size=1; next} /^CATEGORY=Government and Public Services/ {color=4; font_size=1; next} /^CATEGORY=Health care/ {color=4; font_size=1; next} /^CATEGORY=Leisure/ {color=4; font_size=1; next} /^CATEGORY=Lodging/ {color=4; font_size=1; next} /^CATEGORY=Night Life and Business/ {color=4; font_size=1; next} /^CATEGORY=Sports/ {color=4; font_size=1; next} /^CATEGORY=Tourism/ {color=4; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_Cloudmade_water_and_coastline.dbfawk0000664000175000017500000000441415151324131024451 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "Cloudmade" which are # named "*_water.dbf" and "*_coastline.dbf". Unfortunately both # DBF files have the same signature, so we need to have this dbfawk # file match both of them. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="NATURAL:NAME"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="NATURAL:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=34; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=15; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^NAME=(.+)$/ {name="$1";next} /^NATURAL=shoreline/ {lanes=1; display_level=65536; label_level=1; font_size=1; next} /^NATURAL=water/ {lanes=1; display_level=65536; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_geofabrik_2026_buildings.dbfawk0000664000175000017500000000206215151324131023126 0ustar hibbyhibby# Copyright (C) 2003-2016 The Xastir Group # # # This file is used to map OSM shapefiles by "geofabrik.ge" which are # named "gis_osm_buildings_free_1.dbf". These files can be found at # https://download.geofabrik.de/ BEGIN { dbfinfo="osm_id:code:fclass:name:type"; dbffields="fclass:name:type"; } BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=12; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # select the name given in the record /^name=(.+)$/ {name="$1";next} /^fclass=building$/ {lanes=1; color=40; display_level=8; label_level=4; fill_color=113; font_size=3; next} # Make commercial properties green with different stipples /^type=commercial$/ {color=75; fill_color=75; fill_style=2; fill_stipple=2; next;} /^type=retail$/ {color=75; fill_color=75; fill_style=2; fill_stipple=1; next;} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_geofabrik_2026_natural_and_water.dbfawk0000664000175000017500000000505015151324131024640 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This file is used to map OSM shapefiles by "geofabrik.ge" which are # named "gis_osm_natural_a_free_1.*". These files can be found at # https://download.geofabrik.de/ # # Because their signatures are the same, it also serves to render the # "gis_osm_water_a_free_1" shapefiles # BEGIN { dbfinfo="osm_id:code:fclass:name"; dbffields="fclass:name"; } BEGIN_RECORD {key=""; lanes=1; color=35; fill_color=35; name=""; filled=1; pattern=0; display_level=65536; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} /^name=(.+)$/ {name="$1"; next} /^fclass=tree$/ {color=114; fill_color=114; fill_style=2; fill_stipple=2; display_level=256; label_level=16; font_size=1; next} /^fclass=beach$/ {color=107; fill_color=107; fill_style=2; fill_stipple=2; display_level=8192; label_level=16; font_size=1; next} /^fclass=peak$/ {color=46; fill_color=46; display_level=256; label_level=16; font_size=1; next} /^fclass=cliff$/ {name="$(name)(cliff)"; color=74; fill_color=74; display_level=256; label_level=16; font_size=1; next} /^fclass=volcano$/ {color=68; fill_color=68; display_level=256; label_level=16; font_size=1; next} # color cave entrances and mines the same /^fclass=cave_entrance$/ {color=127; fill_color=127; display_level=256; label_level=16; font_size=1; next} /^fclass=mine$/ {color=127; fill_color=127; display_level=256; label_level=16; font_size=1; next} /^fclass=spring$/ {color=117; fill_color=117; fill_style=2; fill_stipple=2; display_level=64; label_level=8; font_size=1; next} /^fclass=glacier$/ {color=117; fill_color=117; fill_style=2; fill_stipple=1; display_level=256; label_level=16; font_size=1; next} # Water features /^fclass=water$/ {color=117; fill_color=117; fill_style=2; fill_stipple=0; display_level=256; label_level=64; label_color=117; font_size=1; next} /^fclass=river$/ {color=117; fill_color=117; fill_style=2; fill_stipple=2; display_level=8192; label_level=128; label_color=117; font_size=1; next} /^fclass=riverbank$/ {color=117; fill_color=117; fill_style=2; fill_stipple=1; display_level=8192; label_level=128; label_color=117; font_size=1; next} /^fclass=reservoir$/ {color=117; fill_color=117; fill_style=2; fill_stipple=1; display_level=8192; label_level=128; label_color=117; font_size=1; next} /^fclass=wetland$/ {color=101; fill_color=101; fill_style=2; fill_stipple=0; display_level=128; label_level=32; label_color=101 ;font_size=1; next} /^fclass=dock$/ {color=122; fill_color=122; fill_style=2; fill_stipple=2; display_level=64; label_level=8; label_color=122; font_size=1; next} Xastir-Release-2.2.4/config/OSM_geofabrik_2026_roads.dbfawk0000664000175000017500000001141615151324131022261 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This file is used to map OSM shapefiles by "geofabrik.ge" which are # named "gis_osm_roads_free_1.dbf". These files can be found at # https://download.geofabrik.de/ # # This file is a modification of an older set, using input from github user # @mthassler to improve the older one BEGIN { dbfinfo="osm_id:code:fclass:name:ref:oneway:maxspeed:layer:bridge:tunnel"; dbffields="fclass:name"; } BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # select the name given in the record /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=State Route (.*)$/ {name="$(name)SR-$1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Interstate (.*) Northbound$/ {name="$(name)I-$1 N"; next} /^name=Interstate (.*) Southbound$/ {name="$(name)I-$1 S"; next} /^name=Interstate (.*) Eastbound$/ {name="$(name)I-$1 E"; next} /^name=Interstate (.*) Westbound$/ {name="$(name)I-$1 W"; next} /^name=Interstate (.*)$/ {name="$(name)I-$1"; next} /^name=Washington Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=(.+)$/ {name="$1";next} # Select render style by fclass: /^fclass=trunk$/ {lanes=2; color=12; display_level=128; label_level=16; font_size=3; next} /^fclass=trunk_link/ {lanes=2; color=12; display_level=128; label_level=16; font_size=1; next} # Note: No display_level or label_level /^fclass=motorway$/ {lanes=4; color=4; label_level=65536; font_size=3; next} # Note: No display_level /^fclass=motorway_link$/ {lanes=3; color=4; label_level=65536; font_size=1; next} /^fclass=primary$/ {lanes=2; color=12; display_level=512; label_level=96; font_size=1; next} /^fclass=primary_link$/ {lanes=2; color=12; display_level=512; label_level=96; font_size=1; next} /^fclass=secondary$/ {lanes=2; color=99; display_level=256; label_level=32; font_size=1; next} /^fclass=secondary_link$/ {lanes=1; color=99; display_level=256; label_level=32; font_size=1; next} /^fclass=tertiary$/ {lanes=1; color=15; display_level=256; label_level=16; font_size=1; next} /^fclass=tertiary_link$/ {lanes=1; color=15; display_level=256; label_level=16; font_size=1; next} /^fclass=ramp/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=road/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=unsurfaced/ {lanes=1; color=105; display_level=64; label_level=16; font_size=1; next} /^fclass=unclassified/ {lanes=1; color=15; display_level=64; label_level=8; font_size=1; next} /^fclass=residential/ {lanes=1; color=15; display_level=64; label_level=8; font_size=1; next} /^fclass=living_street/ {lanes=1; color=15; display_level=64; label_level=8; font_size=1; next} /^fclass=pedestrian/ {lanes=1; color=15; display_level=8; label_level=4; font_size=1; pattern=1; next} # Very small roads /^fclass=service/ {lanes=1; color=67; display_level=8; label_level=4; font_size=1; pattern=1; next} /^fclass=track/ {lanes=1; color=4; display_level=16; label_level=8; font_size=1; pattern=1; next} /^fclass=trail/ {lanes=1; color=70; display_level=64; label_level=8; font_size=1; pattern=1; next} /^fclass=driveway/ {lanes=1; color=121; display_level=8; label_level=4; font_size=1; pattern=2; next} # Unsuitable for cars /^fclass=bridleway/ {lanes=1; color=70; display_level=16; label_level=8; font_size=1; pattern=1; next} /^fclass=cycleway/ {lanes=1; color=11; display_level=16; label_level=8; font_size=1; pattern=1; next} /^fclass=footway/ {lanes=1; color=79; display_level=8; label_level=4; font_size=1; pattern=1; next} /^fclass=path/ {lanes=1; color=96; display_level=16; label_level=8; font_size=1; pattern=1; next} /^fclass=steps/ {lanes=1; color=67; display_level=16; label_level=8; font_size=1; pattern=2; next} # Misc types --- these probably need some work /^fclass=abandoned/ {lanes=1; color=4; display_level=32; label_level=16; font_size=1; pattern=1; next} /^fclass=construction/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; pattern=2; next} /^fclass=crossing/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=ford/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=platform/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=raceway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=t/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=tr/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^fclass=unknown/ {lanes=1; color=4; display_level=32; label_level=16; font_size=1; pattern=1; next} Xastir-Release-2.2.4/config/OSM_geofabrik_2026_waterways.dbfawk0000664000175000017500000000200215151324131023166 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This file is used to map OSM shapefiles by "geofabrik.de" which are # named "gis_osm_waterways_free_1.dbf". These files can be found at # https://download.geofabrik.de/ # # This file is a modification of an older set, using input from github user # @mthassler to improve the older one BEGIN { dbfinfo="osm_id:code:fclass:width:name"; dbffields="name:fclass:width"; } BEGIN_RECORD {key=""; lanes=1; color=34; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=9; font_size=0; symbol=""; fill_style=0;} /^name=(.+)$/ {name="$1";next} /^fclass=river/ {lanes=2; color=9; display_level=65536; label_level=16; font_size=1; next} /^fclass=stream/ {lanes=1; color=9; pattern=0; display_level=128; label_level=16; font_size=1; next} /^fclass=canal/ {lanes=1; color=9; pattern=2; display_level=128; label_level=16; font_size=1; next} /^fclass=drain/ {lanes=1; color=9; pattern=1; display_level=32; label_level=16; font_size=1; next} Xastir-Release-2.2.4/config/OSM_geofabrik_roads.dbfawk0000664000175000017500000001406215151324131021610 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "geofabrik.ge" which are # named "roads.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="osm_id:name:ref:type:oneway:bridge:tunnel:maxspeed"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="type:name:oneway"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. # select the name given in the record # NOTE: Most of these came from the OSM Cloudmade dbfawk. They need to be re-done for the geofabrik.de files. /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=State Route (.*)$/ {name="$(name)SR-$1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=United States Highway (.*)$/ {name="$(name)US $1"; next} /^name=Interstate (.*) Northbound$/ {name="$(name)I-$1 N"; next} /^name=Interstate (.*) Southbound$/ {name="$(name)I-$1 S"; next} /^name=Interstate (.*) Eastbound$/ {name="$(name)I-$1 E"; next} /^name=Interstate (.*) Westbound$/ {name="$(name)I-$1 W"; next} /^name=Interstate (.*)$/ {name="$(name)I-$1"; next} /^name=Washington Highway (.*)$/ {name="$(name)Hwy $1"; next} /^name=(.+)$/ {name="$1";next} #/^LANES=(.+)$/ {lanes="$1";} # type: # NOTE: Most of these came from the OSM Cloudmade dbfawk. They need to be re-done for the geofabrik.de files. /^type=abandoned/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=bridleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=construction/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=crossing/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=cycleway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=driveway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=footway/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=ford/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=living_street/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} # Note: No display_level or label_level /^type=motorway/ {lanes=4; color=4; label_level=65536; font_size=3; next} # Note: No display_level /^type=motorway_link/ {lanes=3; color=2; label_level=16; font_size=1; next} /^type=path/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=pedestrian/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=platform/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=primary/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^type=primary_link/ {lanes=2; color=8; display_level=512; label_level=128; font_size=1; next} /^type=raceway/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=ramp/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=residential/ {lanes=1; color=44; display_level=64; label_level=16; font_size=1; next} /^type=road/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=secondary/ {lanes=2; color=8; display_level=256; label_level=64; font_size=1; next} /^type=secondary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=service/ {lanes=1; color=8; display_level=64; label_level=16; font_size=1; next} /^type=service; residential/ {lanes=7; color=4; display_level=64; label_level=16; font_size=1; next} /^type=steps/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=tertiary/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=tertiary_link/ {lanes=1; color=8; display_level=256; label_level=64; font_size=1; next} /^type=t/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=track/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=trail/ {lanes=1; color=66; display_level=64; label_level=16; font_size=1; next} /^type=tr/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=trunk/ {lanes=3; color=8; display_level=128; label_level=16; font_size=3; next} /^type=trunk_link/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=unclassified/ {lanes=1; color=4; display_level=64; label_level=16; font_size=1; next} /^type=unsurfaced/ {lanes=1; color=105; display_level=64; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/OSM_geofabrik_waterways.dbfawk0000664000175000017500000000422015151324131022521 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that # accompanies a shapefile into Xastir canonical values of: # # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near # awk compatible. # # This file is used to map OSM shapefiles by "geofabrik.de" which are # named "waterways.dbf". # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column # names in order. dbfinfo should match the dbf file that we say this # dbfawk file goes with. dbfinfo="osm_id:name:type:width"; # dbffields is which of the above fields we actually want to look # at. No point reading dbffields that are not looked at further. dbffields="name:type:width"; } # BEGIN_RECORD is called once per dbf record which contains multiple # fields. Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=34; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=32; label_color=15; font_size=0; symbol=""; fill_style=0;} # per-field rules are applied to the dbffields that are read from # each record. /^name=(.+)$/ {name="$1";next} #/^type=shoreline/ {lanes=1; display_level=65536; label_level=1; font_size=1; next} /^type=river/ {lanes=2; display_level=65536; label_level=16; font_size=1; next} # key: set the search key to be the Tiger/Line ID. Not currently # used. #/^TLID=(.*)$/ {key=$1; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/arealm.dbfawk0000664000175000017500000000422515151324131017212 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for AREALM # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:ANSICODE:AREAID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # buildings /^MTFCC=K/ {display_level=256; filled=1 color=2; fill_color=2; label_level=128; next} # PLCC /^MTFCC=L/ {display_level=0; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/areawater.dbfawk0000664000175000017500000000431615151324131017725 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for AREAWATER # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:ANSICODE:HYDROID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # water /^MTFCC=H20/ {filled=1; color=97; fill_color=97; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; color=97; fill_color=97; label_color=26; display_level=1024;skip} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/cousub.dbfawk0000664000175000017500000000436115151324131017252 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for COUSUB # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:UR:FUNCSTAT"; dbfinfo ="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CNECTAFP:NECTAFP:NCTADVFP:FUNCSTAT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=G/ {display_level=512;color=11; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/cousub00.dbfawk0000664000175000017500000000420315151324131017405 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for COUSUB00 # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP00:COUNTYFP00:COUSUBFP00:COSBIDFP00:NAME00:NAMELSAD00:LSAD00:CLASSFP00:MTFCC00:UR00:FUNCSTAT00"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME00:MTFCC00"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAME00=(.*)$/ {name="$1";next} # item locations /^MTFCC00=G/ {display_level=512;color=11; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/edge.dbfawk0000664000175000017500000000773415151324131016665 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for EDGES # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # dbfinfo="STATEFP:COUNTYFP:COUNTYNS:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH"; dbfinfo="STATEFP:COUNTYFP:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH:PERSIST:GCSEFLG:OFFSETL:OFFSETR:TNIDF:TNIDT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="MTFCC:FULLNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=C3/ {display_level=0; next} # water /^MTFCC=H20/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} # buildings /^MTFCC=K/ {display_level=128; next} # PLCC /^MTFCC=L/ {display_level=1024; next} # legal / statistical boundary /^MTFCC=P0001/ {display_level=0; next} # water shoreline /^MTFCC=P0002/ {display_level=1240; color=9; fill_color=9; next} # water intermittent shoreline /^MTFCC=P0003/ {display_level=1240; color=9; fill_color=9; next} # non-visible boundary /^MTFCC=P0004/ {display_level=0; next} # railroad /^MTFCC=R/ {lanes=2; color=8; pattern=1; display_level=128; next} # Limited access road /^MTFCC=S11/ {lanes=4; color=11; display_level=1024; label_level=512; font_size=3; next} # secondary road /^MTFCC=S12/ {display_level=512; lanes=3; color=8; label_level=256; font_size=2; next} # local road /^MTFCC=S14/ {display_level=128; label_level=16; color=48; lanes=1; next} # 4WD off-road trail /^MTFCC=S15/ {lanes=1; color=4; display_level=64; font_size=1; next} # Freeway access / service drive /^MTFCC=S16/ {color=11; display_level=64; next} # walkway / stairway /^MTFCC=S17[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} # alley / private road /^MTFCC=S17[34]/ {lanes=1; color=40; pattern=2; display_level=64; next} # bike / bridle path /^MTFCC=S18/ {lanes=1; color=40; pattern=2; display_level=64; next} # road median /^MTFCC=S20/ {lanes=1; color=40; pattern=2; display_level=64; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/featnames.dbfawk0000664000175000017500000000760215151324131017716 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for FEATNAMES # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="TLID:FULLNAME:NAME:PREDIRABRV:PRETYPABRV:PREQUALABR:SUFDIRABRV:SUFTYPABRV:SUFQUALABR:PREDIR:PRETYP:PREQUAL:SUFDIR:SUFTYP:SUFQUAL:LINEARID:MTFCC:PAFLAG"; dbfinfo="TLID:FULLNAME:NAME:PREDIRABRV:PRETYPABRV:PREQUALABR:SUFDIRABRV:SUFTYPABRV:SUFQUALABR:PREDIR:PRETYP:PREQUAL:SUFDIR:SUFTYP:SUFQUAL:LINEARID:MTFCC:PAFLAG"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations #/^MTFCC=C3/ {display_level=0; next} # water /^MTFCC=H20/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} /^MTFCC=H30/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;next} # buildings #/^MTFCC=K/ {display_level=256; color=25; next} # PLCC /^MTFCC=L/ {display_level=0; next} # legal / statistical boundary /^MTFCC=P0001/ {display_level=0; next} # water shoreline /^MTFCC=P0002/ {display_level=1240; color=9; fill_color=9; next} # water intermittent shoreline /^MTFCC=P0003/ {display_level=1240; color=9; fill_color=9; next} # non-visible boundary /^MTFCC=P0004/ {display_level=0; next} # railroad /^MTFCC=R/ {lanes=2; color=8; pattern=1; display_level=128; next} # Limited access road /^MTFCC=S11/ {display_level=2048; lanes=4; color=11; label_level=512; font_size=3; next} # secondary road /^MTFCC=S12/ {display_level=128; lanes=3; color=8; label_level=128; font_size=2; next} # local road /^MTFCC=S14/ {display_level=128; label_level=16; color=20; lanes=1; next} # 4WD off-road trail /^MTFCC=S15/ {lanes=1; color=69; display_level=64; font_size=1; next} # Freeway access / service drive /^MTFCC=S16/ {color=11; display_level=64; next} # walkway / stairway /^MTFCC=S17[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} # alley / private road /^MTFCC=S17[34]/ {lanes=1; color=40; pattern=2; display_level=64; next} # bike / bridle path /^MTFCC=S18/ {lanes=1; color=40; pattern=2; display_level=64; next} # road median /^MTFCC=S20/ {lanes=1; color=40; pattern=2; display_level=64; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/gfe_coastal_waters.dbfawk0000664000175000017500000000402315151324131021601 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canonical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DIST_NO:PT_1_NAME:PT_2_NAME:PART_STATE:DISP_ORDER:AREA_TYPE:NARR_FLAG:LEVEL:AAC_PARENT:RPT_SEAS:RPT_SWELL:ELEVATION"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/gfe_coastal_waters_warnings.dbfawk0000664000175000017500000000403115151324131023510 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:SEG:AAC_MW:PT_1_NAME:PT_2_NAME:PART_STATE:DISP_ORDER:AREA_TYPE:NARR_FLAG:LEVEL:AAC_PARENT:RPT_SEAS:RPT_SWELL:DESC_TEXT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/gfe_fire_weather.dbfawk0000664000175000017500000000401415151324131021232 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:SOURCE:FIREBAN_TH:BAN_FLAG:DISP_ORDER:NARR_FLAG:LEVEL:USE_GFDR:USE_FFDR:USE_SFDR:USE_HI_FDR:PW_AACS"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/gfe_metro_areas.dbfawk0000664000175000017500000000376115151324131021077 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DISP_ORDER:NARR_FLAG:AAC_PARENT:SUB_FLAG:DESCRIPTN:SURF_FLAG:ROAD_FLAG"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/gfe_public_weather.dbfawk0000664000175000017500000000400415151324131021562 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OFFICE:DIST_NO:DIST_NAME:STATE_CODE:STATE_NAME:TIME_ZONE:AAC:DISP_ORDER:NARR_FLAG:LEVEL:USE_GFDR:USE_FFDR:USE_SFDR:USE_HI_FDR:ALP_FLAG:SURF_FLAG:MW_AACS"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="DIST_NAME:AAC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^AAC=(.*)$/ {key="$1"; next} /^DIST_NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/gps_wpt.dbfawk0000664000175000017500000000125315151324131017432 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map dbf data that accompanies a shapefile created # by the "Fetch GPS Waypoints" option of Xastir. # # It simply attaches the name of the waypoint to the displayed waypoint. # BEGIN{ # identifies the signature we want to recognize dbfinfo="name:commt:date"; # and the fields we actually care about dbffields="name"; } # Executed at beginning of each record, reset defaults BEGIN_RECORD {key=""; lanes=1; color=3; name=""; filled=0; pattern=0; display_level=256; label_level=128; label_color=8; symbol="/. "} # Find the name, make sure it gets displayed along with the data. /^name=(.*)$/ {name="$1";} Xastir-Release-2.2.4/config/language-Dutch.sys0000664000175000017500000012156115151324131020164 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This is the Dutch Language file used for all the prompts in xastir # # Creator : Henk de Groot # Maintained by : The Xastir Group # Last Modified : Apr 28 2001, Henk de Groot # Modified 1.0.3 : Oct 19 2001, Han Sytsma # Modified 1.0.4 : Nov 22 2001, Henk de Groot # Modified 1.0.4 : Nov 25 2001, Henk de Groot # Modified 1.0.6 : Dec 16 2001, Henk de Groot # Modified 1.0.7 : Aug 27 2002, Han Sytsma # Modified 1.1.4 : Apr 15 2003, Han Sytsma # Modified 1.1.4 : May 20 2003, Han Sytsma # Modified 1.3.2 : Jun 08 2004, Han Sytsma # Modified 1.3.x : Sept 1 2004, Han Sytsma / # Henk de Groot # Modified 1.4.2 : Feb 14 2005, Han Sytsma # Modified 1.7.0 : Oct 15 2005, Han Sytsma # Modified 1.8.0 : Jan 9 2006, Han Sytsma # # comment lines with pound signs in front are ignored # File format as follows: # Id (10 chars alpha numeric)|(String associated with id)|QuickKeys|#comment # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|Bestand|B| MENUTB0002|Schermen|S| MENUTB0004|Kaarten|K| MENUTB0005|Beeld|l| MENUTB0006|Berichten|r| MENUTB0010|Interfaces|f| MENUTB0009|Help|H| # # Menu "File" PULDNFI001|Instelling|I| PULDNFI002|Open Log Bestand|O| PULDNFI003|Test|| PULDNFI004|Sluiten|S| PULDNFI007|Verander Debug Level|D| PULDNFI010|TNC Loggen|T| PULDNFI011|Net Loggen|N| PULDNFI012|IGate Loggen|G| PULDNFI013|WX Loggen|W| PULDNFI014|Activeer PNG Snapshots|A| PULDNFI015|Kaart Afdrukken|K| PULDNFI016|KML Snapshots|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Ontvangen Packets|P| PULDNVI003|Mobiele Stations|M| PULDNVI004|Alle Stations|A| PULDNVI009|Lokale Stations|S| PULDNVI012|Laatste Stations|L| PULDNVI005|Weerstations|W| PULDNVI008|Eigen Weer Gegevens|E| PULDNVI007|Weer Waarschuwingen|W| PULDNVI011|Berichten Verkeer|V| PULDNVI013|Tijdsduur Aktief|U| PULDNVI014|Tijdsduur Programma Beschikbaar|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistieken|| # # Menu "Configure" PULDNCF004|Station|t| PULDNCF001|Standaard|S| PULDNCF003|Tijdsinstelling|m| PULDNCF002|Coordinaten Aanduiding|C| PULDNCF006|Audio Alarm|A| PULDNCF007|Spraak|p| PULDNCF008|Instellingen nu bewaren!|I| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Kaart Kiezer|K| PULDNMP012|Ga naar Lokatie|G| PULDNMP014|Lokaliseer Kaart Functie|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Zet alle kaarten uit|Z| PULDNMP002|Automatische Kaart Keuze|A| PULDNMP003|Kaart Graadlijnen|G| PULDNMP004|Kaart Niveaus|| PULDNMP010|Kaartlabels|| PULDNMP009|Kleur Gevulde Gebieden|K| PULDNMP007|Kaart WX Waarschuwing|W| PULDNMP005|Achtergrond Kleur|c| PULDNMP006|Station Tekst Stijl|S| PULDNMP026|Icon Omranding Stijl|O| PULDNMP011|Muis Menu|M| PULDNMP008|Kaart Intensiteit|I| PULDNMP021|Automatische Kaartkeuze - Zet Raster Kaarten Uit|| PULDNMP022|Indexeer Kaarten bij het Starten|| PULDNMP023|Index: Voeg nieuwe kaarten toe|n| PULDNMP024|Index: Herindexeer ALLE kaarten|H| PULDNMP025|Fonts|| PULDNMP015|Xfont selectie|| PULDNMP027|Download Kaarten opnieuw (niet uit cache)|| PULDNMP028|Leeg de gehele kaarten cache!|| PULDNMP029|Zoek locatie|| PULDNMP030|Configureer USGS DRG|| PULDNMP031|Zet kaart begrenzing aan|| PULDNMP032|Geocodering instellingen|| MPUPTGR017|Internet Kaarten Timeout (sec)|| # # PopUp "Configureer USGS DRG" MPUPDRG001|Selecteer weer te geven items:|| MPUPDRG002|Kleur onderliggende kaart (XOR)|| MPUPDRG003|Zwart|| MPUPDRG004|Wit|| MPUPDRG005|Blauw|| MPUPDRG006|Rood|| MPUPDRG007|Bruin|| MPUPDRG008|Groen|| MPUPDRG009|Paars|| MPUPDRG010|Geel|| MPUPDRG011|Licht Blauw|| MPUPDRG012|Licht Rood|| MPUPDRG013|Licht Paars|| MPUPDRG014|Licht Grijs|| MPUPDRG015|Licht Bruin|| # # PopUp "Kaart kiezer" WPUPMCP001|Kaart Kiezer|| PULDNMMC01|Wis|N| PULDNMMC02|Vector|V| PULDNMMC03|250k Topogr.|2| PULDNMMC04|100k Topogr.|1| PULDNMMC05|24k Topogr.|4| PULDNMMC06|Vouw Dirs Uit||| PULDNMMC07|Dirs/Kaarten Geselecteerd:|| PULDNMMC08|Maak Directories leeg|C| PULDNMMC09|Selecteer Alles|S| # # PullDown "Map Background Color" PULDNMBC01|Grijs|| PULDNMBC02|Mistig Roze|| PULDNMBC03|Marine Blauw|| PULDNMBC04|Staal Blauw|| PULDNMBC05|Zee Groen|| PULDNMBC06|Pastel Groen|| PULDNMBC07|Pastel Geel|| PULDNMBC08|Goud Geel|| PULDNMBC09|Roze Bruin|| PULDNMBC10|Vuur Rood|| PULDNMBC11|Wit|| PULDNMBC12|Zwart|| # # PullDown "Station text Style" PULDNMSL01|Zwarte Rand|| PULDNMSL02|Zwarte Schaduw en gevulde achtergrond|| PULDNMSL03|Tekst op Zwarte achtergond|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|Geen Omranding|G| PULDNMIO02|Zwarte Omranding|Z| PULDNMIO03|Grijze Omranding|G| PULDNMIO04|Witte Omranding|W| # # Switches PULDNOT001|Aan|| PULDNOT002|Uit|| PULDNOT003|Kort|| # # Menu "Display" PULDNDP014|Zoek station|Z| PULDNDP001|Volg station|V| PULDNDP022|Spoor downloaden|p| PULDNDP032|Filter gegevens|| PULDNDP040|Deselecteer alles|| PULDNDP041|Selecteer mijn|| PULDNDP042|Selecteer TNC|| PULDNDP027|- Selecteer directe stations|| PULDNDP043|- Selecteer via digi|| PULDNDP034|Selecteer net|| PULDNDP019|Geef verlopen gegevens weer|| PULDNDP044|Selecteer stations|| PULDNDP028|- Selecteer vaste stations|| PULDNDP029|- Selecteer bewegende stations|| PULDNDP030|- Selecteer weer stations|| PULDNDP053|- Selecteer CWOP WX stations|| PULDNDP045|Selecteer Objecten/Items|| PULDNDP026|- Selecteer weer Objecten/Items|| PULDNDP039|- Selecteer water Hoogte Objecten/Items|| PULDNDP031|- Selecteer andere Objecten/Items|| PULDNDP057|- Selecteer Aircraft Object/Artikelen|| PULDNDP058|- Selecteer Vessel Objecten/Artikelen|| PULDNDP033|Filter weergave|| PULDNDP010|Roepnaam|R| PULDNDP012|Symbolen|y| PULDNDP011|- Draai symbolen|D| PULDNDP007|Station spoor|t| PULDNDP003|Koers|K| PULDNDP004|Snelheid|S| PULDNDP017|- Geef snelheid kort traject weer|| PULDNDP002|Hoogte|H| PULDNDP009|Weer informatie|W| PULDNDP046|- Weer tekst|| PULDNDP018|-- Geef alleen temperatuur weer|| PULDNDP047|- Wind indicator|| PULDNDP054|Geef Aloha cirkels weer|| PULDNDP013|Zet stations nadering aan|| PULDNDP008|Stations Vermogen/Winst|V| PULDNDP021|- Activeer standaard vermogen/winst|| PULDNDP020|- Activeer mobiel vermogen/winst|| PULDNDP023|Geef DF cirkels weer|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activeer berekening op geschatte waarden|| PULDNDP036|- Geef boogsegment weer|| PULDNDP037|- Geef richting weer|| PULDNDP038|- Geef symbool weer|| PULDNDP005|Afst/koers|A| PULDNDP024|Geeft tijd laatste rapport|| PULDNDP015|Wis alle stations|W| PULDNDP016|Wis Alle sporen|S| PULDNDP025|Wis Object/Item geschiedenis|| PULDNDP048|Herlaad Object/Item geschiedenis|| PULDNDP049|Wis alle gemarkeerde bijnamen|| PULDNDP050|Wis gemarkeerde bijnamen geschiedenis|| PULDNDP051|Selecteer alleen gemarkeerde bijnamen|| PULDNDP052|- Label route punten|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Units PULDNUT001|Engels|| PULDNUT002|Metrisch|| # # Menu "Messages" PULDNMG001|Zend Bericht Naar|Z| PULDNMG002|Open Groeps Bericht|O| PULDNMG003|Wis alle uitgaande berichten|W| PULDQUS001|Algemene Stations Aanvraag|G| PULDQUS002|IGate Stations Aanvraag|I| PULDQUS003|WX Stations Aanvraag|t| PULDNMG004|Automatisch Antwoord Bericht|A| PULDNMG005|Automatisch Beantwoorden|B| PULDNMG006|Sateliet Bevestigings Mode|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface besturing|| PULDNTNT03|Zet verzenden van alle data uit|| PULDNTNT05|Zet verzenden positie uit|| PULDNTNT06|Zet verzenden van objecten uit|| PULDNTNT11|Zet server poort aan|| PULDNTNT01|Zend nu!|Z| PULDNTNT07|Volg GPS spoor|F| PULDNTNT08|Volg GPS routes|R| PULDNTNT09|Volg GPS routepunten|W| PULDNTNT10|Laad Garmin RINO routepunten|G| # # Menu "Help" PULDNHEL01|Informatie|A| PULDNHEL02|Help Onderwerpen|I| PULDNHEL03|NOOD BAKEN BAKEN MODUS INSCHAKELEN|E| PULDNHEL04|!!! NOOD BAKEN MODUS !!!|| PULDNHEL05|Over Xastir|| # # Mouse Menu Popup POPUPMA001|Opties|| POPUPMA00c|Centreer|C| POPUPMA015|Stations informatie|S| POPUPMA002|Zoom in|i| POPUPMA003|Zoom uit|u| POPUPMA004|Zoom niveau|n| POPUPMA005|Niveau 1|1| POPUPMA006|Niveau 16|6| POPUPMA007|Niveau 64|4| POPUPMA008|Niveau 256|2| POPUPMA009|Niveau 1024|0| POPUPMA010|Niveau 8192|8| POPUPMA017|Hele Wereld|H| POPUPMA016|Vorige pos/zoom|p| POPUPMA018|Plaats een Object|O| POPUPMA019|Verander een Object|V| POPUPMA025|Verplaats mijn station naar dit punt|H| POPUPMA011|Schuif Omhoog|c| POPUPMA012|Schuif Omlaag|h| POPUPMA013|Schuif naar Links|l| POPUPMA014|Schuif naar Rechts|r| POPUPMA020|Afstand meten|| POPUPMA021|Verplaatsen|| POPUPMA022|Volg me|| POPUPMA023|Functie toetsen actief!|| POPUPMA024|Schakel CapsLock/NumLock/ScrollLock/andere Toetsen UIT|| POPUPMA026|Centreer & zoom|| POPUPMA027|Breedtegraden|| POPUPMA028| Lengtegraden|| POPUPMA029|Teken CAD objecten|| POPUPMA030|Draw|| POPUPMA031|Sluit polygoon|| POPUPMA032|Wis CAD polygonen|| POPUPMA033|**NIET GEBRUIKT**|| POPUPMA034|Handmatig Zoom Niveau|| POPUPMA035|10% uit|| POPUPMA036|10% in|| POPUPMA037|Gebied|| POPUPMA038|Vierkant|| POPUPMA039|Vierkante voet|| POPUPMA040|Vierkante meters|| POPUPMA041|Richting|| POPUPMA042|Graden|| POPUPMA043|Pas meerduidige positie aan||# origineel ambigious mag ook meervoudige zijn? POPUPMA044|Positie meerduidigheid is aan, uw nieuwe positie kan verspringen.||# idem POPUPMA045|Voor gedefinierde objecten|| POPUPMA046|CAD polygonen|| POPUPMA047|Zet CAD objecten aan|| POPUPMA048|Zet CAD labels aan|| POPUPMA049|Zet CAD opemerkingen aan|| POPUPMA050|Zet CAD waarschijnlijkheid aan|| POPUPMA051|Zet CAD omgevingsgrootte aan|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stations|| BBARSTA000|%-9s Nieuw Object!|| BBARSTA001|%-9s Nieuw station!|| BBARSTA002|%-9s||# Nieuwe Gegevens (geeft alleen roepnaam weer) BBARSTA003|Kaarten Laden|| BBARSTA004|Kaarten Geladen|| BBARSTA005|Kaart Graadlijnen Aan|| BBARSTA006|Kaart Graadlijnen Uit|| BBARSTA007|Auto. Kaartkeuze is nu AAN|| BBARSTA008|Auto. Kaartkeuze is nu UIT|| BBARSTA009|Auto. Niveaukeuze is nu AAN|| BBARSTA010|Auto. Niveaukeuze is nu UIT|| BBARSTA011|Auto. Beantwoorden is UIT!|| BBARSTA012|Bestand Gereed|| BBARSTA013|GPS Poort Openen|| BBARSTA014|GPS Poort Sluiten|| BBARSTA015|Kreeg GPS RMC tekst|| BBARSTA016|Kreeg GPS GGA tekst|| BBARSTA017|Net verbinding naar host verbroken|| BBARSTA018|Verbindingstijd netwerk verstreken!|| BBARSTA019|Zoeken naar host %s|| BBARSTA020|Verbonden met %s|| BBARSTA021|Net verbinding mislukt!|| BBARSTA022|Kon socket niet binden!|| BBARSTA023|Geen IP voor host!|| BBARSTA024|Geen host gespecificeerd|| BBARSTA025|Host gevonden, Verbinding maken met %d|| BBARSTA026|Wachten op GPS gegevens via HSP..|| BBARSTA027|HSP vrijmaken, TNC gegevens ophalen..|| BBARSTA028|%s wordt geladen|| BBARSTA029|WX poort openen|| BBARSTA030|WX poort sluiten|| BBARSTA031|Zoeken naar hostnaam %d|| BBARSTA032|WX gegevens gedecodeerd|| BBARSTA033|Echo van de digipeater|| BBARSTA034|Weer waarschuwings kaarten laden|| BBARSTA035|Wachten op GPS gegevens via AUX..|| BBARSTA036|HSP vrijmaken, TNC gegevens ophalen..|| BBARSTA037|GPS tekst gedecodeerd|| BBARSTA038|Positie verandering bij mijn station|| BBARSTA039|Bezig met indexeren van: %s|| BBARSTA040|Amateur APRS(tm) station %s|| BBARSTA041|Wacht op GPS gegevens..|| BBARSTA042|Uitzenden van objecten/items|| BBARSTA043|Log bijwerken|| BBARSTA044|ALOHA afstand is %d%s|| BBARSTA045|Symbolen laden...|| BBARSTA046|Opnieuw laden van symbolen...|| BBARSTA047|Initialiseer mijn station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # PopUp "View - Incoming Packet Data" WPUPDPD001|Ontvangen packets bekijken|| WPUPDPD002|Alleen TNC gegevens|| WPUPDPD003|Alleen Net gegevens|| WPUPDPD004|TNC en Net gegevens|| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # PopUp "View - Find Station" WPUPLSP001|Lokaliseer station|| WPUPLSP002|Lokaliseer roepnaam|| WPUPLSP003|Hoofdlettergevoelig|| WPUPLSP004|Zoek exact|| WPUPLSP005|Lokaliseer nu!|| WPUPLSP006|Spoed lokaliseren!|| WPUPLSP007|FCC/RAC lokalisatie|| # # PopUp "Configure - Defaults" WPUPCFD001|Standaardinstellingen aanpassen|| WPUPCFD002|Na hoeveel tijd moet een station als oud beschouwd worden?|| WPUPCFD003|15 Minuten|| WPUPCFD004|30 Minuten|| WPUPCFD005|45 Minuten|| WPUPCFD006|1 Uur|| WPUPCFD007|90 Minuten|| WPUPCFD008|2 Uur|| WPUPCFD009|Na hoeveel tijd moet een station van het scherm verwijderd worden?|| WPUPCFD010|6 Uur|| WPUPCFD011|12 Uur|| WPUPCFD012|1 Dag|| WPUPCFD013|2 Dagen|| WPUPCFD014|1 Week|| WPUPCFD015|Station Zend Opties|| WPUPCFD016|Vast Station|| WPUPCFD017|Mobiel Station m/lokale tijd|| WPUPCFD018|Mobiel Station m/Zulu datum-tijd|| WPUPCFD019|Mobiel Station m/Zulu tijd-secondes|| WPUPCFD021|Stations Positie m/weer|| WPUPCFD022|Stations Positie, Zulu datum-tijd en weer|| WPUPCFD023|Verzend ruwe WX gegevens?|| WPUPCFD024|Comprimeer Object/Item gegevens bij uitzenden?|| WPUPCFD025|Activeer alternatief net?|| WPUPCFD026|Met welk interval positie gegevens verzenden?|| WPUPCFD027|Nieuwe berichten weergeven|| WPUPCFD028|Waarschuw als speciale functie toetsen aanstaan|| WPUPCFD029|Geef bulletins zonder afstand weer|| WPUPCFD030|Zet positie duplicaat controle uit|| WPUPCFD031|Laad voor gedefinierde objecten uit bestand|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configureer tijdsinstelling||| WPUPCFTM02|Interval verzenden positie (min)|| WPUPCFTM03|Tijd tot vervagen station (min)|| WPUPCFTM04|Max interval verzenden Object/Item (min)|| WPUPCFTM05|Tijd tot verdwijnen van kaart (uren)|| WPUPCFTM06|GPS status controle interval (sec)|| WPUPCFTM07|Tijd tot wissen station (dagen)|| WPUPCFTM08|Timeout berekening geschatte waarden (min)|| WPUPCFTM09|Seriele Inter-Char vertraging (ms)|| WPUPCFTM10|Nieuwe volg tijd (min)|| WPUPCFTM11|Nieuw volg Interval (graden)|| WPUPCFTM12|RINO -> Objecten Interval (min), 0 = Uitgeschakeld|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configureer coordinaten stelsel|| WPUPCFC002|Selecteer coordinaten weergave|| WPUPCFC003|dd.dddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM w/speciale zones|| # # PopUp "Configure GPS" WPUPCFG001|GPS Instelling|| WPUPCFG003|Eigen GPS poort|| WPUPCFG002|Gebruik GPS positie?|| WPUPCFG004|GPS opties|| WPUPCFG005|Losse GPS|| WPUPCFG006|Via TNC verbonden GPS (HSP Kabel)|| WPUPCFG007|Via TNC verbonden GPS met gebruik van CTL-E|| WPUPCFG008|GPS tijd (Lees elke)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuut|| WPUPCFG013|2 minuten|| WPUPCFG014|5 minuten|| WPUPCFG015|10 minuten|| WPUPCFG016|Via netwerk verbonden GPS|| WPUPCFG017|GPSD Host|| WPUPCFG018|GPSD Poort|| WPUPCFG019|Netwerk GPS via GPSD|| WPUPCFG020|Opnieuw verbinden na een fout?|| WPUPCFG021|Via netwerk verbonden WX|| WPUPCFG022|WX Host|| WPUPCFG023|WX Poort|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|TNC instelling|| WPUPCFT002|Gebruik TNC?|| WPUPCFT003|TNC poort|| WPUPCFT004|Poort instelling|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto paden|| WPUPCFT012|Pad 1: %s via || WPUPCFT013|Pad 2: %s via || WPUPCFT014|Pad 3: %s via || WPUPCFT015|Poort stijl|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|TNC instelling m/HSP GPS|| WPUPCFT024|Data type|| WPUPCFT025|Auto detectie|| WPUPCFT026|Binair type|| WPUPCFT027|ASCII type|| WPUPCFT028|TNC instelling m/AUX GPS|| WPUPCFT029|TNC instelling m/ONGELDIG ENUM: %d|| WPUPCFT030|Configureer KISS TNC|| WPUPCFT031|TNC configuratie bestanden|| WPUPCFT032|Bestandsnaam activeren TNC|| WPUPCFT033|Bestandsnaam deactiveren TNC|| WPUPCFT034|KISS parameters|| WPUPCFT035|TXDelay (10 ms stappen)|| WPUPCFT036|Persistence (0 tot 255)|| WPUPCFT037|SlotTime (10 ms stappen)|| WPUPCFT038|TxTail (10 ms stappen)|| WPUPCFT039|Vol Duplex|| WPUPCFT040|Configureer Multi-Port KISS TNC|| WPUPCFT041|Radio poort|| WPUPCFT042|Twijfelachtige UNPROTO route!|| WPUPCFT043|Gebruik liever een kortere route zoals WIDE2-2 of WIDE1-1,WIDE2-2|| WPUPCFT044|Twijfelachtige IGATE route!|| WPUPCFT045|Uitzenden met twijfelachtige UNPROTO route!|| WPUPCFT046|Uitzenden met twijfelachtige IGATE route!|| WPUPCFT047|Initialisser KISS-modus bij opstarten|| # # PopUp "Configure WX Port" WPUPCFWX01|WX Poort instelling|| WPUPCFWX02|Weerstation apparaat|| WPUPCFWX03|Regenmeter correctie (globale instelling)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Geen correctie|| # # PopUp "Configure - Station" WPUPCFS001|Stations Instelling|| WPUPCFS002|Roepnaam|| WPUPCFS003|Breedte graden|| WPUPCFS004|gra|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Lengte graden|| WPUPCFS008|(E/W)|| WPUPCFS009|Station Symbool|| WPUPCFS010|Groep/overlay|| WPUPCFS011|Symbool|| WPUPCFS028|Selecteer|| WPUPCFS012|Vermogenswinst|| WPUPCFS013|PHG uitschakelen|| WPUPCFS014|Antenne winst|| WPUPCFS015|Antenne versterking|| WPUPCFS016|Omni|| WPUPCFS017|Commentaar:|| WPUPCFS018|Positie onzekerheid|| WPUPCFS019|Geen|| WPUPCFS020|.11 mijl omtrek|| WPUPCFS021|1.15 mijl omtrek|| WPUPCFS022|11.51 mijl omtrek|| WPUPCFS023|69.09 mijl omtrek|| WPUPCFS024|.18 kilometer omtrek|| WPUPCFS025|1.85 kilometer omtrek|| WPUPCFS026|18.53 kilometer omtrek|| WPUPCFS027|111.19 kilometer omtrek|| WPUPCFS029|Verstuur gecomprimeerde positie|C| # # PopUp "Object/Item" POPUPOB001|Object/Item|| POPUPOB002|Naam|| POPUPOB003|Plaats object|| POPUPOB004|Verwijder object|| POPUPOB005|Verander object|| POPUPOB006|Maak een nieuw object|| POPUPOB007|Oppervlakte object|| POPUPOB008|Activeer oppervlakte object|| POPUPOB009|Heldere kleur|| POPUPOB010|Kleur-Vulling|| POPUPOB011|Cirkel|| POPUPOB012|Rechtse lijn '/'|| POPUPOB013|Linkse lijn '\'|| POPUPOB014|Driehoek|| POPUPOB015|Rechthoek|| POPUPOB016|Zwart|| POPUPOB017|Blauw|| POPUPOB018|Groen|| POPUPOB019|Cyaan|| POPUPOB020|Rood|| POPUPOB021|Violet|| POPUPOB022|Geel|| POPUPOB023|Grijs|| POPUPOB024|Offset omhoog:|| POPUPOB025|Offset links (behalve '/'):|| POPUPOB026|Doorgang:|| POPUPOB027|Algemene Opties|| POPUPOB028|Lokatie|| POPUPOB029|Activeer markering|| POPUPOB030|Gegevens:|| POPUPOB031|Gemarkeerd object|| POPUPOB032|Activeer compressie|| POPUPOB033|Verwijder item|| POPUPOB034|Wijzig item|| POPUPOB035|Hoogte (voet):|| POPUPOB036|Snelheid (knopen):|| POPUPOB037|Richting:|| POPUPOB038|DF object|| POPUPOB039|Signaal - Hoogte(HAAT) - Versterking - Richting|| POPUPOB040|Straal breedte - Richting|| POPUPOB041|Rondstraler|| POPUPOB042|Richtantenne|| POPUPOB043|Onbruikbaar|| POPUPOB044|Neem object over|| POPUPOB045|Neem item over|| POPUPOB046|DF richting:|| POPUPOB047|Waarschijnlijkheids ringen|| POPUPOB048|Kaartbeeld Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Internet Instelling|| WPUPCFI002|Host || WPUPCFI003|Poort || WPUPCFI004|(Alternatieve hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Poort1|| WPUPCFI007|Host2|| WPUPCFI008|Poort2|| WPUPCFI009|Wachtwoord|| WPUPCFI010|(Bij Geen Blanco Laten)|| WPUPCFI011|Verbinding herstellen bij NET fout?|| WPUPCFI012|Laten Werken als I-Gate?|| WPUPCFI013|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFI014|I-Gate transacties loggen?||| WPUPCFI015|Filter parameters|| # # PopUp "Configure Database" WPUPCFID01|Database Instelling (TBD)|| WPUPCFID02|Host || WPUPCFID03|Poort || WPUPCFID04|(Alternatieve hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Poort1|| WPUPCFID07|Host2|| WPUPCFID08|Poort2|| WPUPCFID09|Wachtwoord|| WPUPCFID10|(Bij Geen Blanco Laten)|| WPUPCFID11|Verbinding herstellen bij NET fout?|| WPUPCFID12|Laten werken als I-Gate?|| WPUPCFID13|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFID14|I-Gate transacties loggen?||| WPUPCFID15|Filter parameters|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configureer AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Poort || WPUPCFIA04|(Alternatieve hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Poort1|| WPUPCFIA07|Host2|| WPUPCFIA08|Poort2|| WPUPCFIA09|Wachtwoord|| WPUPCFIA10|(Bij geen blanco laten)|| WPUPCFIA11|Verbinding herstellen bij NET fout?|| WPUPCFIA12|Laten werken als I-Gate?|| WPUPCFIA13|Bij I-Gate berichten verspreiden via TNC?|| WPUPCFIA14|I-Gate transacties loggen?|| WPUPCFIA15|Zend op radio poort|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Audio alarm instellen|| WPUPCFA002|Audio afspeel commando|| WPUPCFA003|Alarm bij|| WPUPCFA004|Audio bestand om af te spelen|| WPUPCFA005|Nieuw Station|| WPUPCFA006|Nieuw Bericht|| WPUPCFA007|Nadering|| WPUPCFA008|Band opening|| WPUPCFA009|Minimale afstand|| WPUPCFA010|Maximale afstand|| WPUPCFA011|Weer waarschuwing|| # # PopUp "Configure Speech" WPUPCFSP01|Spraak instellen|| WPUPCFSP02|Uitvoer spraak bij:|| WPUPCFSP03|Nieuw station|| WPUPCFSP04|Waarschuwing nieuw bericht|| WPUPCFSP05|Nieuwe bericht inhoud|| WPUPCFSP06|Naderings waarschuwing|| WPUPCFSP07|Band opening|| WPUPCFSP08|Nieuwe weer waarschuwing|| WPUPCFSP09|Naderings waarschuwing van gevolgd station|| # # PopUp "Track Station" WPUPTSP001|Volg station|| WPUPTSP002|Volg roepnaam|| WPUPTSP003|Hoofdlettergevoelig|| WPUPTSP004|Exact dit station|| WPUPTSP005|Volg nu!|| WPUPTSP006|Stop met volgen|| WPUPTSP007|Download spoor|| WPUPTSP008|Roepnaam|| WPUPTSP009|Begin volgen (uren geleden)|| WPUPTSP010|Volgduur (uren)|| # # PopUp "Messages" WPUPMSB001|Stuur bericht, venster %d|| WPUPMSB002|Stuur groeps bericht, venster %d|| WPUPMSB003|Stations roepnaam:|| WPUPMSB004|Groeps roepnaam:|| WPUPMSB005|Nieuwe/Refresh roepnaam|| WPUPMSB006|Nieuwe groep|| WPUPMSB007|Wis bericht geschiedenis|| WPUPMSB008|Bericht:|| WPUPMSB009|Stuur nu!|| WPUPMSB010|Pad:|| WPUPMSB011|Breek alle openstaande berichten af|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Zend uit|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*AFGEBROKEN*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # PopUp "Auto Reply" WPUPARM001|Automatich antwoord bericht|| WPUPARM002|Antwoord:|| # # PopUp "Help Index" WPUPHPI001|Help inhoud|| WPUPHPI002|Bekijken|| # # PopUp "Station Info" WPUPSTI000|Object van: %s|| WPUPSTI001|Stations informatie|| WPUPSTI002|Stuur bericht|| WPUPSTI003|Doorzoek FCC databank|| WPUPSTI004|Doorzoek RAC databank|| WPUPSTI005|Packets ontvangen: %d Laatst Gehoord: || WPUPSTI006|Gehoord via de TNC aan device %d, || WPUPSTI007|Gehoord || WPUPSTI008|laatste via lokaal|| WPUPSTI009|laatste via TNC op device %d|| WPUPSTI010|laatste via internet op device %d|| WPUPSTI011|laatste via bestand|| WPUPSTI012|laatste via onbekend|| WPUPSTI013|, en is van positie veranderd|| WPUPSTI014|Huidig Vermogen en Winst:|| WPUPSTI016|Hoogte: %.0f%s || WPUPSTI017|Richting: %s || WPUPSTI018|Snelheid: %.1fkm/h|| WPUPSTI019|Snelheid: %.1fmph|| WPUPSTI020|%0.1f Mijl|| WPUPSTI021|%0.1f km|| WPUPSTI022|Afstand vanaf mijn station %s, Koers vanaf mijn station %s|| WPUPSTI023|Laatste positie || WPUPSTI024|Weer Gegevens %c:%s|| WPUPSTI025|Wind Richting: %s Snelheid: %03d km/h|| WPUPSTI026|Wind Richting: %s Snelheid: %s mph|| WPUPSTI027| Piek: %03d km/h|| WPUPSTI028| Piek: %s mph|| WPUPSTI029|Temperatuur: %02.1fC || WPUPSTI030|Temperatuur: %sF || WPUPSTI031|Vochigheid: %s%% || WPUPSTI032|Gevoels temperatuur: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Sneeuw: %0.1f (cm/24h)|| WPUPSTI035|Sneeuw: %0.0f (inch/24h)|| WPUPSTI036|Regen: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (inch/h) || WPUPSTI039|%0.2f (mm/dag) || WPUPSTI040|%0.2f (inch/dag) || WPUPSTI041|%0.2f (mm/sinds middernacht)|| WPUPSTI042|%0.2f (inch/sinds middernacht)|| WPUPSTI043|Data pad: %s|| WPUPSTI044|Commentaar %02d/%02d %02d:%02d : %s|| WPUPSTI045|Wis spoor|| WPUPSTI046|Totaal regen: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (inch)|| WPUPSTI049|Vraag trace|| WPUPSTI050|Vraag uitstaande berichten|| WPUPSTI051|Vraag direkte stations|| WPUPSTI052|Vraag versie|| WPUPSTI053|Verander object|| WPUPSTI054|Sla spoor op|| WPUPSTI055|Echo vanaf:|| WPUPSTI056|Zet automatisch bijwerken aan|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF richting: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Ontbrandings temp: %02.1fC || WPUPSTI061|Ontbrandings temp: %sF || WPUPSTI062|Vochtigheids gehalte in brandstof: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Vraag NWS waarschuwing|| WPUPSTI065|Gemarkeerde bijnaam: %s|| WPUPSTI066|Geef station een bijnaam|| WPUPSTI067|Huidig bereik: %d miles|| WPUPSTI068|geen|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|bereik|| WPUPSTI073|SLECHTE PHG|| WPUPSTI074|SLECHTE SHG|| WPUPSTI075|DF bereik|| WPUPSTI076|Geen signaal gedetecteerd|| WPUPSTI077|Detecteerbaar signaal (Wellicht)|| WPUPSTI078|Detecteerbaar signaal maar niet bruikbaar)|| WPUPSTI079|Zwak signaal, nauwelijks leesbaar|| WPUPSTI080|Verruist maar bruikbaar signaal|| WPUPSTI081|Enige ruis, goed bruikbaar signaal|| WPUPSTI082|Goed signaal met enig waarneembare ruis|| WPUPSTI083|Bijna ruisvrij siganal|| WPUPSTI084|Volledig ruisvrij signaal|| WPUPSTI085|Extreem sterk & volledig ruisvrij signaal|| WPUPSTI086|VERKEERDE RICHTING|| WPUPSTI087|SLECHTE NRQ|| WPUPSTI088|DF openingshoek|| WPUPSTI089|DF Lengte|| WPUPSTI090|Ongeldig|| WPUPSTI091|Verander volgspoor kleur|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA omtrek: %d %s|| WPUPALO002|Stations binnen ALOHA omtrek: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiel (bewegend): %d|| WPUPALO005| Mobiel (anders): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Vaste stations: %d|| WPUPALO008|Laatst berekening %d %s %d %s geleden.|| WPUPALO666|ALOHA omtrek nog niet berekend|| # # # FCC-RAC Call Look up STIFCC0001|FCC databank doorzoeken|| STIFCC0002|RAC databank doorzoeken|| STIFCC0003|Naam:|| STIFCC0004|Straat:|| STIFCC0005|Plaats:|| STIFCC0006|Staat:|| STIFCC0007|Postcode:|| STIFCC0008|Basis || STIFCC0009|Geavanceerd || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # # FCC-RAC Call Look up STIFCC0100|FCC index is oud, bezig met herindexeren|| STIFCC0101|Zoeken roepnaam|| STIFCC0102|Roepnaam niet gevonden!|| STIFCC0103|RAC index is oud, bezig met herindexeren|| # # # Band open message UMBNDO0001|op een afstand van|| # # Universal Options UNIOP00001|OK|| UNIOP00002|Annuleren|| UNIOP00003|Sluiten|| UNIOP00004|Mijlen|| UNIOP00005|Km|| UNIOP00006|Device|| UNIOP00007|Toevoegen|| UNIOP00008|Wissen|| UNIOP00009|Eigenschappen|| UNIOP00010|Uitzenden toestaan?|| UNIOP00011|Activeren bij opstarten?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|inch|| UNIOP00018|mm/dag|| UNIOP00019|inch/dag|| UNIOP00020|mm/uur|| UNIOP00021|inch/uur|| UNIOP00022|mm/mid|| UNIOP00023|inch/mid|| UNIOP00024|graden|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Stel de systeem klok in vanuit GPS?|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Toepassen||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Station Kiezer|| # # DISPLAY WX ALERT WPUPWXA001|Wx Waarschuwing|| WPUPWXA002|Wx Waarschuwingen lijst|| # # PopUp "Configure - Interfaces" WPUPCIF001|Geinstalleerde interfaces|| WPUPCIF002|Kies interface type|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configureer AX.25 TNC|| WPUPCAX002|AX.25 device naam|| # # Interface device names IFDNL00000|Geen|| IFDNL00001|Serieele TNC|| IFDNL00002|Serieele TNC met GPS op een HSP kabel|| IFDNL00003|Serieele GPS|| IFDNL00004|Serieele WX|| IFDNL00005|Internet server|| IFDNL00006|AX25 TNC|| IFDNL00007|Netwerk GPS (via gpsd)|| IFDNL00008|Netwerk WX|| IFDNL00009|Serieele TNC met GPS op een AUX kabel|| IFDNL00010|Serieele KISS TNC|| IFDNL00011|Database via netwerk (nog niet geimplementeerd)|| IFDNL00012|AGWPE via Netwerk|| IFDNL00013|Serieele Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s via serieel device %s %s|| IFDIN00001|%s %2d %s verbonden met %s:%d %s|| IFDIN00002|%s %2d %s gebruikt device genaamd %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006|INACTIEF || IFDIN00007| ACTIEF || IFDIN00008| FOUT || IFDIN00009|ONBEKENDE|| # # PopUp "Interface control" IFPUPCT000|Interface Besturing|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Start Alle|| IFPUPCT004|Stop Alle|| # # IGate control IGPUPCF000|IGate Opties|| IGPUPCF001|Schakel al het IGate verkeer uit|| IGPUPCF002|Sta ALLEEN RF naar Inet verkeer toe|| IGPUPCF003|Sta RF->Inet en Inet->RF verkeer toe|| IGPUPCF004|IGate -> RF Path || # # WX Station WXPUPSI000|WX station|| WXPUPSI001|WX station type|| WXPUPSI002|Huidige gegevens|| WXPUPSI003|Wind koers|| WXPUPSI004|Wind snelheid|| WXPUPSI005|Wind piek|| WXPUPSI006|Temp|| WXPUPSI007|Regen totaal|| WXPUPSI008|Regen dag totaal|| WXPUPSI009|Baro|| WXPUPSI010|Vochtigheid|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (in gegevens logmode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (in packet mode)|| WXPUPSI014|Regen huidig uur tot.|| WXPUPSI015|Regen laatste 24uur tot.|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (complete mode)|| WXPUPSI018|Dauw punt|| WXPUPSI019|Wind piek|| WXPUPSI020|Wind koude gevoel|| WXPUPSI021|Warmte index|| WXPUPSI022|3-Uur Baro|| WXPUPSI023|Max Temp.|| WXPUPSI024|Min Temp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|Alle stations|| LHPUPNI001|Mobiele stations|| LHPUPNI002|Weer stations|| LHPUPNI003|Lokale stations (via TNC)|| LHPUPNI004|Laatste stations|| LHPUPNI005|Objecten & Items|| LHPUPNI006|Eigen Objecten & Items|| LHPUPNI010|#|| LHPUPNI011|Roepnaam|| LHPUPNI012|#Comprimeer|| LHPUPNI013|Pos Tijd|| LHPUPNI014|Pad|| LHPUPNI015|PHG|| LHPUPNI016|Commentaar|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Breedte gr|| LHPUPNI104|Lengte gr|| LHPUPNI105|#Comprimeer|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Breedte/Lengte of UTM|| # # Maps WX Alert styles PULDNMAT01|Waarschuwings kaarten boven de andere|| PULDNMAT02|Waarschuwings kaarten onder de andere|| # # Error/popup messages POPEM00001|Lokaliseer fout!|| POPEM00002|Station %s is niet gevonden!|| POPEM00003|Spoor-volg fout!|| POPEM00004|Interface fout!|| POPEM00005|Ongeldige AX.25 poort naam %s|| POPEM00006|Ongeldige AX.25 poort naam %s|| POPEM00007|Ongeldige roepnaam %s|| POPEM00008|Ongeldige AX.25 doeladres roepnaam of digipeater|| POPEM00009|Kan AX.25 socket niet openen, %s|| POPEM00010|Kan AX.25 socket niet binden, %s|| POPEM00011|Kan geen verbinding met AX.25 roepnaam maken, %s|| POPEM00012|AX.25 fout bij uitvoer van UI|| POPEM00013|AX.25 probleem met axports bestand|| POPEM00014|AX.25 ongeldige poort naam %s|| POPEM00015|Fout bij het openen van interface %d hardware Fout|| POPEM00016|Fout bij het openen interface %d Time Out|| POPEM00017|Geen interfaces meer beschikbaar!|| POPEM00018|Gegevens Aanvraag - Enkele Bericht Regel|| POPEM00019|Verzenden is uit voor poort %d|| POPEM00020|Database Fout!|| POPEM00021|AX.25 ondersteunig is niet mee gecompileerd in deze Xastir Versie!|| POPEM00022|Invoer Fout!|| POPEM00023|Geen lokatie naam gegeven!|| POPEM00024|Gegeven lokatie naam is in gebruik!|| POPEM00025|Niet gevonden!|| POPEM00026|Volgen begint op het moment van verschijnen|| POPEM00027|Incorrecte gegevens. Zijn er velden leeg?|| POPEM00028|Kan bestand niet openen|| POPEM00029|Gevonden!|| POPEM00030|Weer station symbool|| POPEM00031|Veranderd in WX symbool '/_', andere opties: '\_' '/W' and '\W'|| POPEM00032|Waarschuwing: gebruik nationaal weer service symbool!|| POPEM00033|Geen GPS gegevens!|| POPEM00034|Zet Mijn Positie TX uit totdat geldige GPS gegevens beschikbaar zijn!|| POPEM00035|Waarschuwing|| POPEM00036|Let op|| POPEM00037|HSP interface aanwezig: GPS timing is verhoogd|| POPEM00038|Naam komt overeen met bestaand Object/Item/Station|| POPEM00039|Niet toegestane tekens gevonden, deze worden door punten vervangen|| POPEM00040|Handmatig ingestelde uitgaande route is verloren gegaan|| POPEM00041|Bezig met een ander bestand te bewerken. Wacht even en probeer opnieuw|| POPEM00042|Niet een eigen object! Probeer het object eerst over te nemen.|| POPEM00043|Geen Object/Item!|| POPEM00044|Opzoeken in Findu database: Mislukt|| POPEM00045|Opzoeken in Findu database: Gereed|| POPEM00046|Berkeley DB headers en gedeelde bibliotheek komen niet overeen! Kaart cache uitgeschakeld.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Kaart lokatie|| JMLPO00002|GA!|| JMLPO00003|Nieuwe lokatie naam:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Beperk reikwijdte tot (0, is geen limiet)|| BULMW00003|Verander reikwijdte|| # # All Message Traffic AMTMW00001|Alle berichten verkeer|| AMTMW00002|Beperk reikwijdte tot (0, is geen limiet)|| # # Speech Strings SPCHSTR001|kilometers|| SPCHSTR002|meters|| SPCHSTR003|mijl|| SPCHSTR004|yards|| SPCHSTR005|%s, afstand is %d %s.|| SPCHSTR006|%s, afstand is %.1f %s.|| SPCHSTR007|%s, afstand is %d %s %s %s.|| SPCHSTR008|%s, afstand is %.1f %s %s %s.|| SPCHSTR009|Nieuwe weer waarschuwing|| SPCHSTR010|Nieuwe roepnaam|| SPCHSTR011|Gehoord, D X, %s, op een afstand van %.1f %s|| # # SPCHDIRN00|ten noorden van|| SPCHDIRS00|ten zuiden van|| SPCHDIRE00|ten oosten van|| SPCHDIRW00|ten westen van|| SPCHDIRNE0|ten noordoosten van|| SPCHDIRNW0|ten noordwesten van|| SPCHDIRSE0|ten zuidoosten van|| SPCHDIRSW0|ten zuidwesten van|| # # Symbol Selection Dialog SYMSEL0001|Selecteer symbool|| SYMSEL0002|Primaire symbolen Databank|| SYMSEL0003|Secondaire symbolen Databank|| # # Print Properties Dialog PRINT0001|Print eigenschappen|| PRINT0002|Papier formaat|| PRINT0003|Draai beeld automatisch|| PRINT0004|Draai beeld 90. CCW|| PRINT0005|Pas schaal beeld automatisch aan|| PRINT0006|Schaal:|| PRINT0007|Forceer standaard witte achtergrondkleur|| PRINT0008|Print in Zwart/Wit|| PRINT0016|Inverteer kleuren|| PRINT0009|Postscript resolutie:|| PRINT0010|Voorbeeld|| PRINT0011|Print naar bestand|| PRINT0012|Bezig met printen naar bestand...|| PRINT0013|Converteren naar postscript...|| PRINT0014|Gereed met aanmaken print bestand|| PRINT0015|Printer status|| # # Print Properties Dialog PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Locate Feature Dialog FEATURE001|Naam:|| FEATURE002|Provincie:|| FEATURE003|Land:|| FEATURE004|Kaart quadrant:|| FEATURE005|Type:|| FEATURE006|GNIS Bestand:|| FEATURE007|Adres:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding Bestand|| # # Geocoding Dialog (Nominatim) GEOCODE001|Zoek locatie|| GEOCODE002|Zoekopdracht:|| GEOCODE003|Landfilter:|| GEOCODE004|Zoeken|| GEOCODE005|Wissen|| GEOCODE006|Resultaten:|| GEOCODE007|Ga naar|| GEOCODE008|Markeren|| GEOCODE009|Sluiten|| GEOCODE010|Zoeken...|| GEOCODE011|Geen resultaten gevonden|| GEOCODE012|Fout: %s|| GEOCODE013|%d resultaat/resultaten gevonden|| GEOCODE014|Gegevens (C) OpenStreetMap-bijdragers|| GEOCODE015|Geen (Wereldwijd)|| GEOCODE023|Service niet beschikbaar|| GEOCODE024|Voer een locatie in om te zoeken|| GEOCODE025|Cache wissen|| GEOCODE026|Cache succesvol gewist|| GEOCODE027|Cache wissen mislukt|| GEOCODE028|Nominatim-server:|| GEOCODE029|Cache ingeschakeld:|| GEOCODE030|Cache-vervaldatum (dagen):|| GEOCODE031|Gebruikers-e-mail:|| GEOCODE032|Standaardland:|| GEOCODE033|Instellingen|| GEOCODE034|Opslaan|| GEOCODE035|Annuleren|| GEOCODE036|Toepassen|| GEOCODE037|Geocodering instellingen|| # # Geocoding Configuration Dialog GEOCFG001|Geocodering instellingen|| GEOCFG002|Server-URL:|| GEOCFG003|E-mailadres:|| GEOCFG004|(Optioneel maar aanbevolen)|| GEOCFG005|Standaardland:|| # # Coordinate Calculator Dialog COORD001|Coordinaten berekening|| COORD002|Bereken|| COORD003|Bereken|| COORD004|Wis|| COORD005|UTM|| COORD006|Breedtegraden of|| COORD007|Lengtegraden of|| COORD008|Zone|| COORD009|UTM Oostelijk|| COORD010|UTM Noordelijk|| COORD011| Decimale graden: || COORD012| Graden/Decimale minuten: || COORD013| Graden/Minuten/Dec. seconden: || COORD014| Universal Transverse Mercator: || COORD015| Militair Referentie raster: || COORD016| Maidenhead lokatie raster: || COORD017| ** Sorry, uw invoer is niet herkend! **|| COORD018| ** Gebruik een van onderstaande invoer formaten: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|Hoge Waarde (secs):|| SMARTB003|Hoge Snelheid (mph):|| SMARTB004|Hoge Snelheid (kph):|| SMARTB005|Lage Waarde (mins):|| SMARTB006|Lage Snelheid (mph):|| SMARTB007|Lage Snelheid (kph):|| SMARTB008|Minimale Draaiing (deg):|| SMARTB009|Draai Hoek:|| SMARTB010|Wacht Tijd (secs):|| SMARTB011|Schakel SmartBeaconing in(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Stel Gamma Correctie bij|| GAMMA002|Gamma Correctie|| # # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Miniem|| MAPFONT004|Map Font Klein|| MAPFONT005|Map Font Gemiddeld|| MAPFONT006|Map Font Groot|| MAPFONT007|Map Font Enorm|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV Font ID|| # # # # Distance/Bearing on status line PULDNDB001|Afst/Richting Status|| # # # GPS Transfer Operations GPS001|GPS overdracht|| GPS002|Bestandsnaam|| GPS003|Selecteer kleur|| GPS004|Rood|| GPS005|Groen|| GPS006|Zwart|| GPS007|Wit|| GPS008|Oranje|| GPS009|Blauw|| GPS010|Geel|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Kaart eigenschappen|| MAPP002|Max Min Kaart Teken USGS Auto|| MAPP003|Zoom Zoom Laag Vulling DRG Kaart Path/Bestandsnaam|| MAPP004|Verander Laag->|| MAPP005|Vulling->|| MAPP006|Ja|| MAPP007|Nee|| MAPP008|AutoKaart->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Dag|| TIME002|Dagen|| TIME003|Uur|| TIME004|Uren|| TIME005|Minuut|| TIME006|Minuten|| TIME007|Seconde|| TIME008|Secondes|| # # # Map Caching CACHE001|Kaart in cache|| CACHE002|Kaart uit cache laden|| CACHE003|Kaart niet in cache gevonden...|| # # # Map Screen Misc RANGE001|BEREIK SCHAAL|| # # # GPS Status GPSS001|WAAS of PPS|| GPSS002|DGPS|| GPSS003|Geldig SPS|| GPSS004|Ongeldig|| GPSS005|Sats/beeld|| GPSS006|Repareer|| GPSS007|!GPS data is ouder dan 30 seconden!|| GPSS008|Simulatie|| GPSS009|Handmatig|| GPSS010|Ingeschat op|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Opmerking:|| CADPUD004|Waarschijnlijkheid (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Toon/Bewerk details|| CADPUD008|Afbreken|| CADPUD009|Wis CAD objecten?|| CADPUD010|Wis alles|| CADPUD011|Wis selectie|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/language-English.sys0000664000175000017500000011235515151324131020507 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the English Language file used for all the prompts in xastir # # Creator : Frank Giannandrea # Maintained by : The Xastir Group # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|File|F| MENUTB0002|View|V| MENUTB0004|Map|M| MENUTB0005|Station|S| MENUTB0006|Message|e| MENUTB0010|Interface|I| MENUTB0009|Help|H| # # Menu "File" PULDNFI001|Configure|C| PULDNFI002|Open Log File|O| PULDNFI003|Test|T| PULDNFI004|Exit|x| PULDNFI007|Change Debug Level|D| PULDNFI010|TNC Logging|| PULDNFI011|Net Logging|| PULDNFI012|IGate Logging|| PULDNFI013|WX Logging|| PULDNFI014|PNG Snapshots|| PULDNFI015|Print|P| PULDNFI016|KML Snapshots|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Incoming Data|I| PULDNVI003|Mobile Stations|M| PULDNVI004|All Stations|A| PULDNVI009|Local Stations|S| PULDNVI012|Last Stations|L| PULDNVI005|Weather Stations|W| PULDNVI008|Own Weather Data|D| PULDNVI007|Weather Alerts|e| PULDNVI011|Message Traffic|T| PULDNVI013|Uptime|U| PULDNVI014|Program Uptime|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Menu "Configure" PULDNCF004|Station|S| PULDNCF001|Defaults|D| PULDNCF003|Timing|T| PULDNCF002|Coordinate System|o| PULDNCF006|Audio Alarms|A| PULDNCF007|Speech|p| PULDNCF008|Save Config Now!|C| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Map Chooser|M| PULDNMP012|Map Display Bookmarks|B| PULDNMP014|Locate Map Feature|F| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Disable All Maps|| PULDNMP002|Enable Auto Maps|| PULDNMP003|Enable Map Grid|| PULDNMP004|Enable Map Levels|| PULDNMP010|Enable Map Labels|| PULDNMP009|Enable Area Color Fills|| PULDNMP007|Enable Weather Alerts|| PULDNMP005|Background Color|C| PULDNMP006|Station Text Style|T| PULDNMP026|Icon Outline Style|O| PULDNMP011|Mouse Pointer Menu|P| PULDNMP008|Map Intensity|I| PULDNMP021|Auto Map - Disable Raster Maps|| PULDNMP022|Index New Maps on Startup|| PULDNMP023|Index: Add New Maps|N| PULDNMP024|Index: Reindex ALL Maps!|R| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Search Location|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| PULDNMP032|Geocoding Settings|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # PopUp "Map Chooser" WPUPMCP001|Map Chooser|| PULDNMMC01|Clear|C| PULDNMMC02|Vector|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Expand Dirs|| PULDNMMC07|Dirs/Maps Selected:|| PULDNMMC08|Clear Dirs|C PULDNMMC09|Select All|S| # # PullDown "Map Background Color" PULDNMBC01|Gray|| PULDNMBC02|Misty Rose|| PULDNMBC03|Navy Blue|| PULDNMBC04|Steel Blue|| PULDNMBC05|Med. Sea Green|| PULDNMBC06|Pale Green|| PULDNMBC07|Pale Goldenrod|| PULDNMBC08|Goldenrod Yellow|| PULDNMBC09|Rosy Brown|| PULDNMBC10|Fire brick Red|| PULDNMBC11|White|| PULDNMBC12|Black|| # # PullDown "Station text Style" PULDNMSL01|Black Border|B| PULDNMSL02|Black Shadow|S| PULDNMSL03|Text on Black|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|No Outline|N| PULDNMIO02|Black Outline|B| PULDNMIO03|Grey Outline|G| PULDNMIO04|White Outline|W| # # Switches PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Short|| # # Menu "Stations" PULDNDP014|Find Station|F| PULDNDP001|Track Station|T| PULDNDP022|Fetch Findu Trail|u| PULDNDP032|Filter Data|| PULDNDP040|Select None|| PULDNDP041|Select Mine|| PULDNDP042|Select TNC|| PULDNDP027|- Select Direct|| PULDNDP043|- Select Via Digi|| PULDNDP034|Select Net|| PULDNDP019|Include Expired Data|| PULDNDP044|Select Stations|| PULDNDP028|- Select Fixed Stations|| PULDNDP029|- Select Moving Stations|| PULDNDP030|- Select WX Stations|| PULDNDP053| - Select CWOP WX Stations|| PULDNDP045|Select Objects/Items|| PULDNDP026|- Select WX Objects/Items|| PULDNDP039|- Select Water Gauge Objects/Items|| PULDNDP057|- Select Aircraft Objects/Items|| PULDNDP058|- Select Vessel Objects/Items|| PULDNDP031|- Select Other Objects/Items|| PULDNDP033|Filter Display|| PULDNDP010|Display Callsign|| PULDNDP012|Display Symbol|| PULDNDP011|- Rotate Symbol|| PULDNDP007|Display Trail|| PULDNDP003|Display Course|| PULDNDP004|Display Speed|S| PULDNDP017|- Display Short Speed|| PULDNDP002|Display Altitude|| PULDNDP009|Display Weather Info|| PULDNDP046|- Display Weather Text|| PULDNDP018|-- Temperature Only|| PULDNDP047|- Display Wind Barb|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Display Position Ambiguity|| PULDNDP008|Display Power/Gain|| PULDNDP021|- Use Default Power/Gain|| PULDNDP020|- Display Mobile Power/Gain|| PULDNDP023|Display DF Attributes|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Enable Dead-Reckoning|| PULDNDP036|- Display Arc|| PULDNDP037|- Display Course|| PULDNDP038|- Display Symbol|| PULDNDP005|Display Dist/Bearing|| PULDNDP024|Display Last Report Age|| PULDNDP015|Clear All Stations!!!|A| PULDNDP016|Clear All Trails!!!|C| PULDNDP025|Clear Object/Item History|| PULDNDP048|Reload Object/Item History|| PULDNDP049|Clear All Tactical Calls|| PULDNDP050|Clear Tactical Call History|| PULDNDP051|Select Tactical Calls Only|| PULDNDP052|- Label Trailpoints|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Units PULDNUT001|Enable English Units|E| PULDNUT002|Metric|M| # # Menu "Messages" PULDNMG001|Send Message To|S| PULDNMG002|Open Group Messages|O| PULDNMG003|Clear All Outgoing Messages|C| PULDQUS001|General Stations Query|G| PULDQUS002|IGate Stations Query|I| PULDQUS003|WX Stations Query|W| PULDNMG004|Modify Auto Reply Message|A| PULDNMG005|Enable Auto Reply Message|| PULDNMG006|Satellite Ack Mode|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface Control|C| PULDNTNT03|Disable Transmit: ALL|| PULDNTNT05|Disable Transmit: My Position|| PULDNTNT06|Disable Transmit: Objects/Items|| PULDNTNT11|Enable Server Ports|P| PULDNTNT01|Transmit Now!|T| PULDNTNT07|Fetch GPS Track|F| PULDNTNT08|Fetch GPS Routes|R| PULDNTNT09|Fetch GPS Waypoints|W| PULDNTNT10|Fetch Garmin RINO Waypoints|G| # # Menu "Help" PULDNHEL01|About|A| PULDNHEL02|Help Index|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # # Mouse Menu Popup POPUPMA001|Options|| POPUPMA00c|Center|C| POPUPMA015|Station Info|S| POPUPMA002|In|I| POPUPMA003|Out|O| POPUPMA004|Zoom Level|L| POPUPMA005|Level 1|1| POPUPMA006|Level 16|6| POPUPMA007|Level 64|4| POPUPMA008|Level 256|2| POPUPMA009|Level 1024|0| POPUPMA010|Level 8192|8| POPUPMA017|Entire World|E| POPUPMA016|Last Map Pos/Zoom|P| POPUPMA018|Object/Item->Create|b| POPUPMA019|Object/Item->Modify|M| POPUPMA025|Move My Station Here|H| POPUPMA011|Pan up|u| POPUPMA012|Pan down|d| POPUPMA013|Pan left|l| POPUPMA014|Pan right|r| POPUPMA020|Measure|| POPUPMA021|Move|| POPUPMA022|TrackMe|| POPUPMA023|Modifiers Found!|| POPUPMA024|Please turn OFF CapsLock/NumLock/ScrollLock/other modifiers|| POPUPMA026|Center & Zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Draw CAD Objects|| POPUPMA030|Draw|| POPUPMA031|Close Polygon|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position ambiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stations|| BBARSTA000|%-9s New object!|| BBARSTA001|%-9s New station!|| BBARSTA002|%-9s||# new data (only display the call) BBARSTA003|Loading Maps...|| BBARSTA004|Maps Loaded|| BBARSTA005|Map Lat/Long Grid On|O| BBARSTA006|Map Lat/Long Grid Off|f| BBARSTA007|The use of Auto Maps, is now ON|| BBARSTA008|The use of Auto Maps, is now OFF|| BBARSTA009|The use of Map Levels is now ON|| BBARSTA010|The use of Map Levels is now OFF|| BBARSTA011|Auto Reply Message OFF!|| BBARSTA012|File done..|| BBARSTA013|Opening GPS Port|| BBARSTA014|Closing GPS Port|| BBARSTA015|Got GPS RMC String|| BBARSTA016|Got GPS GGA String|| BBARSTA017|Net disconnected from host|| BBARSTA018|Net connection timed out!|| BBARSTA019|Looking up host %s|| BBARSTA020|Connected to %s|| BBARSTA021|Net Connection Failed!|| BBARSTA022|Could not bind socket!|| BBARSTA023|No IP for Host!|| BBARSTA024|No Host Specified|| BBARSTA025|Host found, Connecting %d|| BBARSTA026|Waiting for GPS data via HSP..|| BBARSTA027|Clearing HSP getting TNC data..|| BBARSTA028|Loading %s|| BBARSTA029|Opening WX Port|| BBARSTA030|Closing WX Port|| BBARSTA031|Looking up hostname %d|| BBARSTA032|Decoded WX Data|| BBARSTA033|Echo from digipeater|| BBARSTA034|Loading Weather Alert Maps|| BBARSTA035|Waiting for GPS data via AUX..|| BBARSTA036|Clearing AUX getting TNC data..|| BBARSTA037|GPS Data Complete|| BBARSTA038|Position change on my station|| BBARSTA039|Indexing %s|| BBARSTA040|Amateur APRS(tm) Station %s|| BBARSTA041|Waiting for GPS data..|| BBARSTA042|Transmitting objects/items|| BBARSTA043|Logging|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # # PopUp "View - Incoming Packet Data" WPUPDPD001|Display Packet Data|| WPUPDPD002|TNC Data only|T| WPUPDPD003|Net Data only|N| WPUPDPD004|TNC and Net Data|a| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # PopUp "View - Find Station" WPUPLSP001|Locate Station|| WPUPLSP002|Locate Callsign|| WPUPLSP003|Match Case|C| WPUPLSP004|Match Exact|E| WPUPLSP005|Locate Now!|N| WPUPLSP006|Emergency Locate!|| WPUPLSP007|FCC/RAC Lookup|| # # PopUp "Configure - Defaults" WPUPCFD001|Configure Defaults|| WPUPCFD002|After what interval of time will a station be considered old?|| WPUPCFD003|15 min|1| WPUPCFD004|30 min|3| WPUPCFD005|45 min|4| WPUPCFD006|1 hr|H| WPUPCFD007|90 min|9| WPUPCFD008|2 hrs|2| WPUPCFD009|After what interval of time will a station not be displayed?|| WPUPCFD010|6 hrs|6| WPUPCFD011|12 hrs|o| WPUPCFD012|1 Day|D| WPUPCFD013|2 Days|y| WPUPCFD014|1 Week|W| WPUPCFD015|Transmit Station Option|| WPUPCFD016|Fixed Station|F| WPUPCFD017|Mobile Station w/local time|l| WPUPCFD018|Mobile Station w/Zulu date-time|Z| WPUPCFD019|Mobile Station w/Zulu time-seconds|u| WPUPCFD021|Station Position w/weather|S| WPUPCFD022|Station Position, Zulu date-time, and weather|t| WPUPCFD023|Transmit Raw WX data?|R| WPUPCFD024|Transmit compressed objects/items?|C| WPUPCFD025|Activate Alternate net?|A| WPUPCFD026|Send position reports at what intervals?|| WPUPCFD027|Pop up new bulletins|| WPUPCFD028|Warn if Modifier Keys|| WPUPCFD029|View zero-distance bulletins|| WPUPCFD030|Disable Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configure Timing|| WPUPCFTM02|Posit TX Interval (min)|| WPUPCFTM03|Station Ghosting Time (min)|| WPUPCFTM04|Object/Item Max TX Interval (min)|| WPUPCFTM05|Station Clear Time (hours)|| WPUPCFTM06|GPS Check Interval (sec)|| WPUPCFTM07|Station Delete Time (days)|| WPUPCFTM08|Dead-Reckoning Timeout (min)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|New Track Time (min)|| WPUPCFTM11|New Track Interval (degrees)|| WPUPCFTM12|RINO -> Objects Interval (min), 0 = Disabled|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configure Coordinate System|| WPUPCFC002|Select Coordinate System|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM w/special zones|| # # PopUp "Configure GPS" WPUPCFG001|Configure GPS|| WPUPCFG003|Stand alone GPS port|| WPUPCFG002|Use GPS Position?|| WPUPCFG004|GPS Options|| WPUPCFG005|Stand-alone GPS|| WPUPCFG006|TNC Connected GPS (HSP Cable)|| WPUPCFG007|TNC Connected GPS using CTL-E|| WPUPCFG008|GPS Time (Sample every)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 min|| WPUPCFG013|2 min|| WPUPCFG014|5 min|| WPUPCFG015|10 min|| WPUPCFG016|Network Connected GPS|| WPUPCFG017|GPSD Host|| WPUPCFG018|GPSD Port|| WPUPCFG019|Network GPS via GPSD|| WPUPCFG020|Reconnect on failure?|| WPUPCFG021|Network Connected WX|| WPUPCFG022|WX Host|| WPUPCFG023|WX Port|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|Configure TNC|| WPUPCFT002|Use TNC?|| WPUPCFT003|TNC Port|| WPUPCFT004|Port Settings|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto Paths|| WPUPCFT012|Path 1: %s via || WPUPCFT013|Path 2: %s via || WPUPCFT014|Path 3: %s via || WPUPCFT015|Port Style|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configure TNC w/HSP GPS|| WPUPCFT024|Data Type|| WPUPCFT025|Auto detect|| WPUPCFT026|Binary Type|| WPUPCFT027|ASCII Type|| WPUPCFT028|Configure TNC w/AUX GPS|| WPUPCFT029|Configure TNC w/INVALID ENUM: %d|| WPUPCFT030|Configure KISS TNC|| WPUPCFT031|TNC Configuration Files|| WPUPCFT032|TNC Setup Filename|| WPUPCFT033|TNC Shutdown Filename|| WPUPCFT034|KISS Parameters|| WPUPCFT035|TXDelay (10 ms units)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (10 ms units)|| WPUPCFT038|TxTail (10 ms units)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configure Multi-Port KISS TNC|| WPUPCFT041|Radio Port|| WPUPCFT042|Interface Properties: Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Interface Properties: Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # # PopUp "Configure WX Port" WPUPCFWX01|Configure WX Port|| WPUPCFWX02|Weather Station device|| WPUPCFWX03|Rain Gauge Correction (Global Setting)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|No Correction|| # # PopUp "Configure - Station" WPUPCFS001|Configure Station|| WPUPCFS002|Callsign|| WPUPCFS003|LAT|| WPUPCFS004|deg|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/W)|| WPUPCFS009|Station Symbol|| WPUPCFS010|Group/overlay|| WPUPCFS011|Symbol|| WPUPCFS028|Select|| WPUPCFS012|Power - Height (HAAT) - Gain - Directivity|| WPUPCFS013|Disable PHG|| WPUPCFS014|Antenna Height|| WPUPCFS015|Antenna Gain|| WPUPCFS016|Omni|| WPUPCFS017|Comment:|| WPUPCFS018|Position Ambiguity|| WPUPCFS019|None|| WPUPCFS020|.11 miles|| WPUPCFS021|1.15 miles|| WPUPCFS022|11.51 miles|| WPUPCFS023|69.09 miles|| WPUPCFS024|.18 kilometres|| WPUPCFS025|1.85 kilometres|| WPUPCFS026|18.53 kilometres|| WPUPCFS027|111.19 kilometres|| WPUPCFS029|Send compressed posits|C| # # PopUp "Object/Item" POPUPOB001|Object/Item|| POPUPOB002|Name:|| POPUPOB003|Create New Object|| POPUPOB004|Delete Object|| POPUPOB005|Modify Object|| POPUPOB006|Create New Item|| POPUPOB007|Area Object|| POPUPOB008|Area Object|| POPUPOB009|Bright Color|| POPUPOB010|Color-Fill|| POPUPOB011|Circle|| POPUPOB012|Line-Right '/'|| POPUPOB013|Line-Left '\'|| POPUPOB014|Triangle|| POPUPOB015|Rectangle|| POPUPOB016|Black|| POPUPOB017|Blue|| POPUPOB018|Green|| POPUPOB019|Cyan|| POPUPOB020|Red|| POPUPOB021|Violet|| POPUPOB022|Yellow|| POPUPOB023|Grey|| POPUPOB024|Offset Up:|| POPUPOB025|Offset Left (Except '/'):|| POPUPOB026|Corridor:|| POPUPOB027|Generic Options|| POPUPOB028|Location|| POPUPOB029|Signpost|| POPUPOB030|Signpost Text|| POPUPOB031|Signpost Object|| POPUPOB032|Enable Compression|| POPUPOB033|Delete Item|| POPUPOB034|Modify Item|| POPUPOB035|Altitude (ft):|| POPUPOB036|Speed (knots):|| POPUPOB037|Course:|| POPUPOB038|DF Object|| POPUPOB039|Signal - Height(HAAT) - Gain - Directivity|| POPUPOB040|Beam Width - Bearing|| POPUPOB041|Omni Antenna|| POPUPOB042|Beam Antenna|| POPUPOB043|Useless|| POPUPOB044|Adopt Object|| POPUPOB045|Adopt Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Configure Internet|| WPUPCFI002|Host || WPUPCFI003|Port || WPUPCFI004|(Secondary hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Port1|| WPUPCFI007|Host2|| WPUPCFI008|Port2|| WPUPCFI009|Pass-code|| WPUPCFI010|(Leave Blank if None)|| WPUPCFI011|Reconnect on NET failure?|| WPUPCFI012|Run as an I-Gate?|| WPUPCFI013|Broadcast messages via TNC when an I-Gate?|| WPUPCFI014|Log I-Gate Transactions?|| WPUPCFI015|Filter Parameters|| # # PopUp "Configure Database" WPUPCFID01|Configure Database (TBD)|| WPUPCFID02|Host || WPUPCFID03|Port || WPUPCFID04|(Secondary hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Port1|| WPUPCFID07|Host2|| WPUPCFID08|Port2|| WPUPCFID09|Pass-code|| WPUPCFID10|(Leave Blank if None)|| WPUPCFID11|Reconnect on NET failure?|| WPUPCFID12|Run as an I-Gate?|| WPUPCFID13|Broadcast messages via TNC when an I-Gate?|| WPUPCFID14|Log I-Gate Transactions?|| WPUPCFID15|Filter Parameters|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configure AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Port || WPUPCFIA04|(Secondary hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Port1|| WPUPCFIA07|Host2|| WPUPCFIA08|Port2|| WPUPCFIA09|Pass-code|| WPUPCFIA10|(Leave Blank if None)|| WPUPCFIA11|Reconnect on NET failure?|| WPUPCFIA12|Run as an I-Gate?|| WPUPCFIA13|Broadcast messages via TNC when an I-Gate?|| WPUPCFIA14|Log I-Gate Transactions?|| WPUPCFIA15|Transmit RadioPort|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Configure Audio Alarms|| WPUPCFA002|Audio Play Command|| WPUPCFA003|Alarm on|| WPUPCFA004|Audio file to Play|| WPUPCFA005|New Station|| WPUPCFA006|New Message|| WPUPCFA007|Proximity|| WPUPCFA008|Band Opening|| WPUPCFA009|Minimum Distance|| WPUPCFA010|Maximum Distance|| WPUPCFA011|Weather Alert|| # # PopUp "Configure Speech" WPUPCFSP01|Configure Speech|| WPUPCFSP02|Speech Output on:|| WPUPCFSP03|New Station|| WPUPCFSP04|New Message Alert|| WPUPCFSP05|New Message Body|| WPUPCFSP06|Proximity Alert|| WPUPCFSP07|Band Opening|| WPUPCFSP08|New Weather Alert|| WPUPCFSP09|Tracked Station Proximity Alert|| # # PopUp "Track Station" WPUPTSP001|Track Station|| WPUPTSP002|Track Callsign|| WPUPTSP003|Match Case|| WPUPTSP004|Match Exact|| WPUPTSP005|Track Now!|| WPUPTSP006|Clear Tracking|| WPUPTSP007|Download Trail|| WPUPTSP008|Callsign|| WPUPTSP009|Start Trail (hrs ago)|| WPUPTSP010|Trail Length (hrs)|| # # PopUp "Messages..." WPUPMSB001|Send Message Box %d|| WPUPMSB002|Send Group Message Box %d|| WPUPMSB003|Station's Call:|| WPUPMSB004|Group's Call:|| WPUPMSB005|New/Refresh Call|| WPUPMSB006|New Group|| WPUPMSB007|Clear Msg History|| WPUPMSB008|Message:|| WPUPMSB009|Send Now!|| WPUPMSB010|Path:|| WPUPMSB011|Cancel Pending Msgs|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # PopUp "Auto Reply" WPUPARM001|Change Auto Reply|| WPUPARM002|Reply:|| # # PopUp "Help Index" WPUPHPI001|Help Index|| WPUPHPI002|View|| # # PopUp "Station Info" WPUPSTI000|Object from: %s|| WPUPSTI001|Station Info|| WPUPSTI002|Send Message|| WPUPSTI003|Search FCC Database|| WPUPSTI004|Search RAC Database|| WPUPSTI005|Packets received: %d Last Heard: || WPUPSTI006|Heard via the TNC on device %d, || WPUPSTI007|Heard || WPUPSTI008|last via Local|| WPUPSTI009|last via TNC on device %d|| WPUPSTI010|last via Internet on device %d|| WPUPSTI011|last via File|| WPUPSTI012|last via Unknown|| WPUPSTI013|, and has moved|| WPUPSTI014|Current Power Gain:|| WPUPSTI016|Altitude: %.0f%s || WPUPSTI017|Course: %s || WPUPSTI018|Speed: %.1f km/h|| WPUPSTI019|Speed: %.1f mph|| WPUPSTI020|%0.1f miles|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distance from my station: %s Bearing from my station: %s|| WPUPSTI023|Last Position: || WPUPSTI024|Weather Data %c:%s|| WPUPSTI025|Wind Course: %s Speed: %03d km/h|| WPUPSTI026|Wind Course: %s Speed: %s mph|| WPUPSTI027| Gust: %03d km/h|| WPUPSTI028| Gust: %s mph|| WPUPSTI029|Temperature: %02.1fC || WPUPSTI030|Temperature: %sF || WPUPSTI031|Humidity: %s%% || WPUPSTI032| Humidex: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Snow: %0.1f (cm/24h)|| WPUPSTI035|Snow: %0.0f (inch/24h)|| WPUPSTI036|Rain: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (inch/h) || WPUPSTI039|%0.2f (mm/day) || WPUPSTI040|%0.2f (inch/day) || WPUPSTI041|%0.2f (mm/since midnight)|| WPUPSTI042|%0.2f (inch/since midnight)|| WPUPSTI043|Data path: %s|| WPUPSTI044|Comment %02d/%02d %02d:%02d : %s|| WPUPSTI045|Clear Track|| WPUPSTI046|Total Rain: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (inch)|| WPUPSTI049|Trace Query|| WPUPSTI050|Un-Acked Messages Query|| WPUPSTI051|Direct Stations Query|| WPUPSTI052|Station Version Query|| WPUPSTI053|Modify Object/Item|| WPUPSTI054|Store Track|| WPUPSTI055|Echoed from:|| WPUPSTI056|Enable Automatic Updates|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF Bearing: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Fuel Temp: %02.1fC || WPUPSTI061|Fuel Temp: %sF || WPUPSTI062|Fuel Moisture: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Fetch NWS Alert|| WPUPSTI065|Tactical Call: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # # FCC-RAC Call Look up STIFCC0001|FCC Database Lookup|| STIFCC0002|RAC Database Lookup|| STIFCC0003|Name:|| STIFCC0004|Street:|| STIFCC0005|City:|| STIFCC0006|State:|| STIFCC0007|Zip:|| STIFCC0008|Basic || STIFCC0009|Advanced || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # # FCC-RAC indexing/searching STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Band open message UMBNDO0001|at distance of|| # # # Universal Options UNIOP00001|OK|| UNIOP00002|Cancel|| UNIOP00003|Close|| UNIOP00004|miles|| UNIOP00005|km|| UNIOP00006|Device|| UNIOP00007|Add|| UNIOP00008|Delete|| UNIOP00009|Properties|| UNIOP00010|Allow Transmitting?|| UNIOP00011|Activate on Startup?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|inch|| UNIOP00018|mm/day|| UNIOP00019|inch/day|| UNIOP00020|mm/hr|| UNIOP00021|inch/hr|| UNIOP00022|mm/mid|| UNIOP00023|inch/mid|| UNIOP00024|deg|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Set System Clock from GPS Data?|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Apply|| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Station Chooser|| # # DISPLAY WX ALERT WPUPWXA001|Wx Alerts|| WPUPWXA002|Wx Alert List|| # # PopUp "Configure - Interfaces" WPUPCIF001|Installed Interfaces|| WPUPCIF002|Choose Interface Type|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configure AX.25 TNC|| WPUPCAX002|AX.25 Device name|| # # Interface device names IFDNL00000|None|| IFDNL00001|Serial TNC|| IFDNL00002|Serial TNC w/GPS on a HSP cable|| IFDNL00003|Serial GPS|| IFDNL00004|Serial WX|| IFDNL00005|Internet Server|| IFDNL00006|AX25 TNC|| IFDNL00007|Networked GPS (via gpsd)|| IFDNL00008|Networked WX|| IFDNL00009|Serial TNC w/GPS on AUX port|| IFDNL00010|Serial KISS TNC|| IFDNL00011|Networked Database (Not Implemented Yet)|| IFDNL00012|Networked AGWPE|| IFDNL00013|Serial Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s %s %s|| IFDIN00001|%s %2d %s %s:%d %s|| IFDIN00002|%s %2d %s device %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| DOWN || IFDIN00007| UP || IFDIN00008|ERROR || IFDIN00009|UNKNWN|| # # PopUp "Interface control" IFPUPCT000|Interface Control|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Start All|| IFPUPCT004|Stop All|| # # IGate control IGPUPCF000|IGate Options|| IGPUPCF001|Disable all IGate traffic|| IGPUPCF002|Allow RF to Inet traffic ONLY|| IGPUPCF003|Allow RF->Inet and Inet->RF traffic|| IGPUPCF004|Igate -> RF Path || # # WX Station WXPUPSI000|WX Station|| WXPUPSI001|WX Station Type|| WXPUPSI002|Current Data|| WXPUPSI003|Wind Course|| WXPUPSI004|Wind Speed|| WXPUPSI005|Wind Gust|| WXPUPSI006|Temp|| WXPUPSI007|Total Rain|| WXPUPSI008|Today's Rain Total|| WXPUPSI009|Baro|| WXPUPSI010|Humidity|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (Data Logging Mode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (Packet Mode)|| WXPUPSI014|Current HR Rain Tot.|| WXPUPSI015|Last 24 Rain Total|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Dew Point|| WXPUPSI019|High Wind|| WXPUPSI020|Wind Chill|| WXPUPSI021|Heat Index|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|High Temp.|| WXPUPSI024|Low Temp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|All Stations|| LHPUPNI001|Mobile Stations|| LHPUPNI002|Weather Stations|| LHPUPNI003|Local Stations (via TNC)|| LHPUPNI004|Last Stations|| LHPUPNI005|Objects & Items|| LHPUPNI006|Own Objects & Items|| LHPUPNI010|#|| LHPUPNI011|Call Sign|| LHPUPNI012|#Pack|| LHPUPNI013|Pos Time|| LHPUPNI014|Path|| LHPUPNI015|PHG|| LHPUPNI016|Comments|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon or UTM|| # # Maps WX Alert styles PULDNMAT01|Show Alert maps above other maps|| PULDNMAT02|Show Alert maps under other maps|| # # Error/popup messages POPEM00001|Locate Error!|| POPEM00002|Station %s was not found!|| POPEM00003|Tracking Error!|| POPEM00004|Interface Error!|| POPEM00005|Invalid AX.25 port name %s|| POPEM00006|Invalid AX.25 port name %s|| POPEM00007|Invalid callsign %s|| POPEM00008|Invalid AX.25 destination callsign or digipeater|| POPEM00009|Cannot open AX.25 socket, %s|| POPEM00010|Cannot bind AX.25 socket, %s|| POPEM00011|Cannot connect to AX.25 callsign, %s|| POPEM00012|AX.25 error on output of UI|| POPEM00013|AX.25 problem with axports file|| POPEM00014|AX.25 invalid port name %s|| POPEM00015|Error opening interface %d Hard Fail|| POPEM00016|Error opening interface %d Time Out|| POPEM00017|No more interfaces Available!|| POPEM00018|Data Query - Single Message Line|| POPEM00019|Port transmitting is off for port %d|| POPEM00020|Database Error!|| POPEM00021|AX.25 support not compiled into Xastir!|| POPEM00022|Input Error!|| POPEM00023|No location name specified!|| POPEM00024|Location name specified is in use!|| POPEM00025|Not Found!|| POPEM00026|Tracking will commence when it appears|| POPEM00027|Improper info. Some fields empty?|| POPEM00028|Can't open file|| POPEM00029|Found It!|| POPEM00030|Weather Station Symbol|| POPEM00031|Changed to WX symbol '/_', other options: '\_' '/W' and '\W'|| POPEM00032|Warning: Using National Weather Service Symbol!|| POPEM00033|No GPS Data!|| POPEM00034|Disabling My Position TX Until Valid GPS Data!|| POPEM00035|Warning|| POPEM00036|Notice|| POPEM00037|HSP interface present: GPS timing has been increased|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Map Display Bookmarks|| JMLPO00002|Activate!|| JMLPO00003|New Name:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Limit Range to (0, is no limit)|| BULMW00003|Change Range|| # # All Message Traffic AMTMW00001|All Message Traffic|| AMTMW00002|Limit Range to (0, is no limit)|| # # Speech Strings SPCHSTR001|kilometers|| SPCHSTR002|meters|| SPCHSTR003|miles|| SPCHSTR004|yards|| SPCHSTR005|%s, distance is %d %s.|| SPCHSTR006|%s, distance is %.1f %s.|| SPCHSTR007|%s, distance is %d %s %s %s.|| SPCHSTR008|%s, distance is %.1f %s %s %s.|| SPCHSTR009|New Weather Alert|| SPCHSTR010|New Station|| SPCHSTR011|Heard, D X, %s, at distance of %.1f %s|| # # SPCHDIRN00|north of|| SPCHDIRS00|south of|| SPCHDIRE00|east of|| SPCHDIRW00|west of|| SPCHDIRNE0|northeast of|| SPCHDIRNW0|northwest of|| SPCHDIRSE0|southeast of|| SPCHDIRSW0|southwest of|| # # Symbol Selection Dialog SYMSEL0001|Select Symbol|| SYMSEL0002|Primary Symbol Table|| SYMSEL0003|Secondary Symbol Table|| # # Print Properties Dialog PRINT0001|Print Properties|| PRINT0002|Paper Size|| PRINT0003|Auto-Rotate Image|| PRINT0004|Rotate Image 90 CCW|| PRINT0005|Auto-Scale Image|| PRINT0006|Scale:|| PRINT0007|Force default background color to white|| PRINT0008|Print in Black and White|| PRINT0016|Reverse Colors|| PRINT0009|Postscript Resolution:|| PRINT0010|Preview|| PRINT0011|Print to File|| PRINT0012|Dumping image to file...|| PRINT0013|Converting to Postscript...|| PRINT0014|Finished creating print file|| PRINT0015|Print Status|| # # Print Dialog PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Locate Feature and Find Address Dialogs FEATURE001|Name:|| FEATURE002|State/Province:|| FEATURE003|County:|| FEATURE004|Map Quad:|| FEATURE005|Type:|| FEATURE006|GNIS File:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Geocoding Dialog (Nominatim) GEOCODE001|Search Location|| GEOCODE002|Search Query:|| GEOCODE003|Country Filter:|| GEOCODE004|Search|| GEOCODE005|Clear|| GEOCODE006|Results:|| GEOCODE007|Go To|| GEOCODE008|Mark|| GEOCODE009|Close|| GEOCODE010|Searching...|| GEOCODE011|No results found|| GEOCODE012|Error: %s|| GEOCODE013|Found %d result(s)|| GEOCODE014|Data (C) OpenStreetMap contributors|| GEOCODE015|None (Worldwide)|| GEOCODE023|Service not available|| GEOCODE024|Enter a location to search|| GEOCODE025|Clear Cache|| GEOCODE026|Cache cleared successfully|| GEOCODE027|Failed to clear cache|| GEOCODE028|Nominatim server:|| GEOCODE029|Cache enabled:|| GEOCODE030|Cache expiry (days):|| GEOCODE031|User email:|| GEOCODE032|Default country:|| GEOCODE033|Settings|| GEOCODE034|Save|| GEOCODE035|Cancel|| GEOCODE036|Apply|| GEOCODE037|Geocoding Settings|| # # Geocoding Configuration Dialog GEOCFG001|Geocoding Settings|| GEOCFG002|Server URL:|| GEOCFG003|Email Address:|| GEOCFG004|(Optional but recommended)|| GEOCFG005|Default Country:|| # # Coordinate Calculator Dialog COORD001|Coordinate Calculator|| COORD002|Calc|| COORD003|Calculate|| COORD004|Clear|| COORD005|UTM|| COORD006|Latitude or|| COORD007|Longitude or|| COORD008|Zone|| COORD009|UTM Easting|| COORD010|UTM Northing|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|High Rate (secs):|| SMARTB003|High Speed (mph):|| SMARTB004|High Speed (kph):|| SMARTB005|Low Rate (mins):|| SMARTB006|Low Speed (mph):|| SMARTB007|Low Speed (kph):|| SMARTB008|Minimum Turn (deg):|| SMARTB009|Turn Slope:|| SMARTB010|Wait Time (secs):|| SMARTB011|Enable SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Adjust Gamma Correction|| GAMMA002|Gamma Correction|| # # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Tiny|| MAPFONT004|Map Font Small|| MAPFONT005|Map Font Medium|| MAPFONT006|Map Font Large|| MAPFONT007|Map Font Huge|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # # # Distance/Bearing on status line PULDNDB001|Dist/Bearing Status|| # # # GPS Transfer Operations GPS001|GPS Transfer|| GPS002|Filename|| GPS003|Select Color|| GPS004|Red|| GPS005|Green|| GPS006|Black|| GPS007|White|| GPS008|Orange|| GPS009|Blue|| GPS010|Yellow|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Map Properties|| MAPP002|Max Min Map USGS Auto|| MAPP003|Zoom Zoom Layer Fill DRG Map Path/Filename|| MAPP004|Change Layer->|| MAPP005|Filled->|| MAPP006|Yes|| MAPP007|No|| MAPP008|Automaps->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Day|| TIME002|Days|| TIME003|Hour|| TIME004|Hours|| TIME005|Minute|| TIME006|Minutes|| TIME007|Second|| TIME008|Seconds|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data and other CAD dialogs CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || #"XASTIR Map of (upper left) to (lower right). Lat/Long grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| #"XASTIR Map of (upper left) to (lower right). UTM zones, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # DB_POSTGIS XADBMST002|Postgreql with Postgis|| # DB_MYSQL_SPATIAL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| #XASTIR_SCHEMA_CAD XASCHEMA02|Xastir CAD Schema|| #XASTIR_SCHEMA_COMPLEX XASCHEMA03|Xastir full Schema|| #XASTIR_SCHEMA_APRSWORLD XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/language-French.sys0000664000175000017500000012307115151324131020320 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This is the French Language file used for all the prompts in xastir # # Creator : Richard VE2DJE ve2dje@amsat.org # Maintained by : The Xastir Group # Merci : Jacques Chion, F6CWO, qui a contribu une grande part des # traductions rcentes. (N7TAP) # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Main Menu MENUTB0001|Fichier|F| MENUTB0002|Examiner|E| MENUTB0004|Cartes|a| MENUTB0005|Stations|S| MENUTB0006|Messages|M| MENUTB0010|Interfaces|I| MENUTB0009|Aide|A| # # Menu "File" PULDNFI001|Configurer|C| PULDNFI002|Ouvrir le journal|O| PULDNFI003|Test|e| PULDNFI004|Quitter|Q| PULDNFI007|Changer niveau de dbogage|d| PULDNFI010|Activer archivage TNC|T| PULDNFI011|Activer archivage rseau|r| PULDNFI012|Activer archivage IGate|I| PULDNFI013|Activer archivage mto|m| PULDNFI014|Activer copie d'cran PNG|| PULDNFI015|Imprimer carte|p| PULDNFI016|Instantan KML|| # # Menu "View" PULDNVI001|Bulletins|B| PULDNVI002|Donnes entrantes|D| PULDNVI003|Stations mobiles|m| PULDNVI004|Toutes stations|T| PULDNVI009|Stations locales|l| PULDNVI012|Stations rcentes|r| PULDNVI005|Stations mto|m| PULDNVI008|Mes donnes mto|o| PULDNVI007|Alertes mto|A| PULDNVI011|Trafic des messages|i| PULDNVI013|Dure de fonctionnement|f| PULDNVI014|Dure de fonctionnement du logiciel|| PULDNVI015|Etat du GPS|| PULDNVI016|Statistiques ALOHA|| # # Menu "Configure" PULDNCF004|Station|S| PULDNCF001|Dfauts|D| PULDNCF003|Temporisations|T| PULDNCF002|Systme des coordonnes|C| PULDNCF006|Alertes sonores|A| PULDNCF007|Parole|P| PULDNCF008|Sauvegarder la configuration maintenant !|a| # (Units see PULDNDP006) # # Menu "Maps" PULDNMP001|Choix des cartes|C| PULDNMP012|Aller |l| PULDNMP014|Localiser lment cartographique|F| PULDNMP016|Dsactiver Zoom/Pan/Accueil rapide|| PULDNMP013|Dsactiver toutes cartes|D| PULDNMP002|Activer cartographie automatique|A| PULDNMP003|Activer quadrillage|q| PULDNMP004|Activer niveaux de cartes|n| PULDNMP010|Activer annotation des cartes|n| PULDNMP009|Activer remplissage de zones|r| PULDNMP007|Activer alertes mto|M| PULDNMP005|Couleur de fond|f| PULDNMP006|Style du texte de station|S| PULDNMP026|Style du contour d'icne|O| PULDNMP011|Menu souris|e| PULDNMP008|Intensit des cartes|I| PULDNMP021|Cartographie automatique - dsactiver cartes trames|| PULDNMP022|Indexer nouvelles cartes au dmarrage|| PULDNMP023|Index: Ajouter nouvelles cartes|R| PULDNMP024|Index: Re-indexer toutes cartes|A| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-tlcharger les cartes (pas partir du cache)|| PULDNMP028|Vider le cache des cartes|| PULDNMP029|Rechercher un lieu|| PULDNMP030|Configurer USGS DRG|| PULDNMP031|Activer bordure des cartes|| PULDNMP032|Paramtres de gocodage|| MPUPTGR017|Temporisation de carte Internet (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Slectionner ce qui doit tre affich :|| MPUPDRG002|Colorer la carte sous-jaante (XOR)|| MPUPDRG003|Noir|| MPUPDRG004|Blanc|| MPUPDRG005|Bleu|| MPUPDRG006|Rouge|| MPUPDRG007|Marron|| MPUPDRG008|Vert|| MPUPDRG009|Pourpre|| MPUPDRG010|Jaune|| MPUPDRG011|Bleu clair|| MPUPDRG012|Rouge clair|| MPUPDRG013|Pourpre clair|| MPUPDRG014|Gris clair|| MPUPDRG015|Marron clair|| # # PopUp "Map Chooser" WPUPMCP001|Choix de cartes|| PULDNMMC01|Effacer|A| PULDNMMC02|Vectorielles|V| PULDNMMC03|Topogr. 250k|2| PULDNMMC04|Topogr. 100k|1| PULDNMMC05|Topogr. 24k|4| PULDNMMC06|Agrandir rpertoires||| PULDNMMC07|Rps/cartes choisies:|| PULDNMMC08|Dselct. rps|C| PULDNMMC09|Choisir tout|S| # # PullDown "Map Background Color" PULDNMBC01|Gris|| PULDNMBC02|Rose|| PULDNMBC03|Bleu marine|| PULDNMBC04|Bleu acier || PULDNMBC05|Vert moyen|| PULDNMBC06|Vert ple|| PULDNMBC07|Jaune ple|| PULDNMBC08|Blanc crme|| PULDNMBC09|Brun ros|| PULDNMBC10|Rouge brique|| PULDNMBC11|Blanc|| PULDNMBC12|Noir|| # # PullDown "Station text Style" PULDNMSL01|Bordure noire|n| PULDNMSL02|Ombr avec toile de fond|O| PULDNMSL03|Blanc sur noir|B| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|Pas de contour|N| PULDNMIO02|Contour noir|B| PULDNMIO03|Contour gris|G| PULDNMIO04|Contour blanc|W| # # Switches PULDNOT001|Ouvrir|| PULDNOT002|Fermer|| PULDNOT003|Court|| # # Menu "Stations" PULDNDP014|Localiser une station|L| PULDNDP001|Suivre une station|S| PULDNDP022|Rcuprer piste Findu|| PULDNDP032|Filtrer donnes|| PULDNDP040|Ne rien afficher|| PULDNDP041|Ma station|| PULDNDP042|Choisir TNC|| PULDNDP027|- Stations en direct|| PULDNDP043|- Stations via digi|| PULDNDP034|Stations via le net|| PULDNDP019|Inclure donnes primes|| PULDNDP044|Afficher les stations|| PULDNDP028|- Stations fixes|| PULDNDP029|- Stations mobiles|| PULDNDP030|- Stations mto|| PULDNDP053| - Stations mto CWOP|| PULDNDP045|Objets/articles|| PULDNDP026|- Objets/articles mto|| PULDNDP039|- Objets/articles indicateurs d'eau||#' PULDNDP031|- Autres objets/articles|| PULDNDP057|- Selecte Aircraft objets/articles|| PULDNDP058|- Slectionnez l'objet du navire/Articles|| PULDNDP033|Filtrer affichage|| PULDNDP010|Afficher indicatif|n| PULDNDP012|Afficher symbole|c| PULDNDP011|- Pivoter symbole|o| PULDNDP007|Afficher piste|p| PULDNDP003|Afficher cap|r| PULDNDP004|Afficher vitesse|v| PULDNDP017|- Afficher vitesse abrge|| PULDNDP002|Afficher altitude|A| PULDNDP009|Afficher info mto|I| PULDNDP046|- Afficher texte mto|| PULDNDP018|-- Seulement la temprature|| PULDNDP047|- Indicateur de vent|| PULDNDP054|Afficher cercle Aloha|| PULDNDP013|Afficher ambigut de position|b| PULDNDP008|Afficher puissance/gain|g| PULDNDP021|- Activer puissance/gain dfaut|| PULDNDP020|- Activer puissance/gain mobile|| PULDNDP023|Afficher attributs DF|| PULDNDP123|Afficher largeur faiseau recherche auto (DF)|| PULDNDP223|Afficher relev recherche auto (DF)|| PULDNDP035|Activer point estim|| PULDNDP036|- Afficher arc|| PULDNDP037|- Afficher cap|| PULDNDP038|- Afficher symbole|| PULDNDP005|Afficher distance/relvement|d| PULDNDP024|Afficher ge du dernier rapport|| PULDNDP015|Effacer toutes stations !!!|E| PULDNDP016|Effacer toutes pistes !!!|f| PULDNDP025|Effacer histoire des objets/articles|| PULDNDP048|Recharger histoire des objets/articles|| PULDNDP049|Effacer indicatifs tactiques|| PULDNDP050|Effacer historique des indicatifs tactiques|| PULDNDP051|Choisir seulement les indicatifs tactiques|| PULDNDP052|- Annoter les points de piste|| PULDNDP055|Exporter Tout|E| PULDNDP056|Exporter vers fichier KML|| # # Units PULDNUT001|Activer mesures anglaises|| PULDNUT002|Mtres|| # # Menu "Messages" PULDNMG001|Composer un message |C| PULDNMG002|Ouvrir les messages de groupe|g| PULDNMG003|Effacer tout message expdier|E| PULDQUS001|Intrroger toutes les stations|I| PULDQUS002|Intrroger les stations IGate|n| PULDQUS003|Intrroger les stations mto|m| PULDNMG004|Configurer la rponse automatique|o| PULDNMG005|Activer la rponse automatique|R| PULDNMG006|Mode "Satellite Ack"|M| PULDNMG007|Voir les messages en attente|V| # # Menu "Interfaces" PULDNTNT04|Contrle de l'interface|C| PULDNTNT03|Dsactiver transmission: Tout|| PULDNTNT05|Dsactiver transmission: Ma position|| PULDNTNT06|Dsactiver transmission: Objets/Articles|| PULDNTNT11|Activer serveur sur port 2023|| PULDNTNT01|Transmettre maintenant !|T| PULDNTNT07|Extraire piste GPS|F| PULDNTNT08|Extraire routes GPS|R| PULDNTNT09|Extraire points de cheminement GPS|W| PULDNTNT10|Extraire points de cheminement Garmin RINO|G| # # Menu "Help" PULDNHEL01|Information|I| PULDNHEL02|Index de l'Aide|A|#' PULDNHEL03|ACTIVER MODE BALISE DE DETRESSE|E| PULDNHEL04|!!! MODE BALISE DE DETRESSE !!!|| PULDNHEL05| propos de Xastir|| # # # Mouse Menu Popup POPUPMA001|Options|O| POPUPMA00c|Centrer|C| POPUPMA015|Information sur la station|| POPUPMA002|Zoom +|s| POPUPMA003|Zoom -|i| POPUPMA004|Niveau de zoom|N| POPUPMA005|Niveau 1|1| POPUPMA006|Niveau 16|6| POPUPMA007|Niveau 64|4| POPUPMA008|Niveau 256|2| POPUPMA009|Niveau 1024|0| POPUPMA010|Niveau 8192|8| POPUPMA017|Monde entier|M| POPUPMA016|Pos/zoom prcdent|| POPUPMA018|Objet/Article->Crer|| POPUPMA019|Objet/Article->Modifier|| POPUPMA025|Dplacer ma station ici|H| POPUPMA011|Nord|| POPUPMA012|Sud|| POPUPMA013|Ouest|| POPUPMA014|Est|| POPUPMA020|Mesurer|| POPUPMA021|Dplacer|| POPUPMA022|Me suivre|| POPUPMA023|Modificateurs trouvs !|| POPUPMA024|SVP dsactiver CapsLock/NumLock/ScrollLock/autres|| POPUPMA026|Centre & zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Dessiner objets CAD|| POPUPMA030|Dessiner|| POPUPMA031|Fermer polygone|| POPUPMA032|Effacer polygones CAD|| POPUPMA033|**NOT USED**|| POPUPMA034|Changer niveau de zoom|| POPUPMA035|10% arrire|| POPUPMA036|10% avant|| POPUPMA037|Aire|| POPUPMA038|carr|| POPUPMA039|pieds carrs|| POPUPMA040|mtres carrs|| POPUPMA041|Relvement|| POPUPMA042|degrs|| POPUPMA043|Modifier ambigut de position|| POPUPMA044|Ambigut de position est active, votre nouvelle position pourra sauter.|| POPUPMA045|Objets prdfinis|| POPUPMA046|Polygones CAD|| POPUPMA047|Activer les objets CAD|| POPUPMA048|Activer les tiquettes CAD|| POPUPMA049|Activer les commentaires CAD|| POPUPMA050|Activer la probabilit CAD|| POPUPMA051|Activer la taille de la surface CAD|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|mtres|| POPUPMA055|mi| # # # Status line labels BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Sv|| BBARSTH001|%d/%d stations|| BBARSTA000|%-9s Nouvel objet !|| BBARSTA001|%-9s Nouvelle station !|| BBARSTA002|%-9s|| BBARSTA003|Chargement de cartes...|| BBARSTA004|Cartes charges|| BBARSTA005|Quadrillage de carte Lat/Long activ|| BBARSTA006|Quadrillage de carte Lat/Long dsactiv|| BBARSTA007|Carte automatique active|| BBARSTA008|Carte automatique dsactive|| BBARSTA009|Niveau de cartes activ|| BBARSTA010|Niveau de cartes dsactiv|| BBARSTA011|Rponse automatique dsactive|| BBARSTA012|Fichier termin...|| BBARSTA013|Ouverture du port GPS|| BBARSTA014|Fermeture du port GPS|| BBARSTA015|Rception de message GPS RMC|| BBARSTA016|Rception de message GPS GGA|| BBARSTA017|Rseau dconnect de l'hte|| BBARSTA018|Connexion rseau dpassement de temps !|| BBARSTA019|Recherche de l'hte %s||#' BBARSTA020|Connect %s|| BBARSTA021|chec de la connexion !|| BBARSTA022|Incapable de relier le socket !|| BBARSTA023|Hte inconnu !|| BBARSTA024|Serveur non spcifi||#' BBARSTA025|Hte trouv, connexion en cours %d|| BBARSTA026|Attente de donnes du GPS par HSP|| BBARSTA027|Fermeture port HSP rception donne TNC..|| BBARSTA028|Chargement de %s|| BBARSTA029|Ouverture port mto|| BBARSTA030|Fermeture port mto|| BBARSTA031|Recherche d'hte %d||#' BBARSTA032|Donnes mto dcodes|| BBARSTA033|cho de digipeater|| BBARSTA034|Chargement de cartes alertes mto|| BBARSTA035|Attente de dones du GPS par AUX|| BBARSTA036|Fermeture port GPS rception donne TNC..|| BBARSTA037|GPS mto dcodes|| BBARSTA038|Placez le changement sur ma station|| BBARSTA039|Cration de l'index de %s|| BBARSTA040|Station d'amateur APRS(tm) %s||#' BBARSTA041|Attente de donnes GPS..|| BBARSTA042|Transmission objets/articles|| BBARSTA043|Journalisation|| BBARSTA044|Le rayon ALOHA est de %d%s|| BBARSTA045|Chargement de symboles...|| BBARSTA046|Rechargement des symboles...|| BBARSTA047|Initialisation de ma station...|| BBARSTA048|Dmarrer interfaces...|| BBARSTA049|Lit les dalles...|| BBARSTA050|Tlcharge les dalles...|| BBARSTA051|Tlcharge dalle %li de %li|| # # # PopUp "View - Incoming Packet Data" WPUPDPD001|Affichage de donnes paquet|| WPUPDPD002|Donnes du TNC seulement|| WPUPDPD003|Donnes du rseau seulement|| WPUPDPD004|Donnes du TNC et du rseau|| WPUPDPD005|TNC|| WPUPDPD006|Rseau|| WPUPDPD007|Capacit Station|| WPUPDPD008|Seulement les miens|| # # PopUp "View - Find Station" WPUPLSP001|Localiser une station|| WPUPLSP002|Localiser l'indicatif||#' WPUPLSP003|Casse exacte|C| WPUPLSP004|Correspondance exacte|E| WPUPLSP005|Localiser maintenant !|L| WPUPLSP006|Localiser dtresse !|| WPUPLSP007|Recherche indicatif FCC/RAC|| # # PopUp "Configure - Defaults" WPUPCFD001|Configurer dfauts|| WPUPCFD002|Au bout de combien de temps une station sera-t-elle considre ge ?|| WPUPCFD003|15 min|1| WPUPCFD004|30 min|3| WPUPCFD005|45 min|4| WPUPCFD006|1 heure|h| WPUPCFD007|90 min|9| WPUPCFD008|2 heures|2| WPUPCFD009|Au bout de combien de temps une station ne sera-t-elle plus affiche ?|| WPUPCFD010|6 heures|6| WPUPCFD011|12 heures|e| WPUPCFD012|1 jour|j| WPUPCFD013|2 jours|o| WPUPCFD014|1 semaine|s| WPUPCFD015|Option de transmission|| WPUPCFD016|Station fixe|| WPUPCFD017|Station mobile + heure locale|| WPUPCFD018|Station mobile + date/heure Zulu|| WPUPCFD019|Station mobile + heure/secondes Zulu|| WPUPCFD021|Position de station + mto|| WPUPCFD022|Position de station + date/heure Zulu + mto|| WPUPCFD023|Transmettre les donnes mto non traites ?|| WPUPCFD024|Transmettre les objets/articles sous forme comprsss ?|| WPUPCFD025|Activer rseau alterne ?|A| WPUPCFD026|Transmettre position quel intervalle ?|| WPUPCFD027|Afficher bulletins nouveaux|| WPUPCFD028|Alerter si cls modificatrices (Verr.Num.)|| WPUPCFD029|Voir bulletins avec distance zro|| WPUPCFD030|Dsactiver identif. de duplic. posit.|| WPUPCFD031|Charger des objets prdfinis partir d'un fichier|| WPUPCFD032|Mon parcour en une seule couleur|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configurer temporisation|| WPUPCFTM02|Intervalle transmission de position (min)|| WPUPCFTM03|Dlai d'affichage faible d'une station (min)|| WPUPCFTM04|Intervalle maximum de transmission des objets/articles (min)||#' WPUPCFTM05|Dlai de suppression d'affichage d'une station (heures)|| WPUPCFTM06|Intervalle de lecture GPS (sec)|| WPUPCFTM07|Dlai de suppression d'une station (jours)|| WPUPCFTM08|Expiration de point estim (min)|| WPUPCFTM09|Dlai inter-char port srie (ms)|| WPUPCFTM10|Dlai nouvelle piste (min)|| WPUPCFTM11|Espace nouvelle piste (degrs)|| WPUPCFTM12|RINO -> Intervalle d'objets (min), 0 = Dsactiv|| WPUPCFTM13|Intervalle de capture instantan (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configurer systme de coordonnes|| WPUPCFC002|Choisir systme de coordonnes|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM avec zones spciales|| # # PopUp "Configure GPS" WPUPCFG001|Configurer GPS|| WPUPCFG003|Port GPS seulement|| WPUPCFG002|Utiliser la position GPS ?|| WPUPCFG004|Options du GPS|| WPUPCFG005|GPS seul|| WPUPCFG006|TNC branch au GPS (Cble HSP)|| WPUPCFG007|TNC branch au GPS avec CTL-E|| WPUPCFG008|Intervalle de temps GPS|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 min|| WPUPCFG013|2 min|| WPUPCFG014|5 min|| WPUPCFG015|10 min|| WPUPCFG016|GPS branch rseau|| WPUPCFG017|Hte GPSD|| WPUPCFG018|Port GPSD|| WPUPCFG019|GPS rseau via GPSD|| WPUPCFG020|Reconnexion sur chec ?|| WPUPCFG021|Connexion mto rseau|| WPUPCFG022|Hte mto|| WPUPCFG023|Port mto|| # # Configure TNC (baud/style are also for WX) WPUPCFT001|Configurer le TNC|| WPUPCFT002|Utiliser le TNC ?|| WPUPCFT003|Port TNC|| WPUPCFT004|Configuration du port|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Voies UnProto|| WPUPCFT012|Voie 1: %s via || WPUPCFT013|Voie 2: %s via || WPUPCFT014|Voie 3: %s via || WPUPCFT015|Type de port|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurer TNC +HSP GPS|| WPUPCFT024|Type de donnes|| WPUPCFT025|Auto detection|| WPUPCFT026|Type binaire|| WPUPCFT027|Type ASCII|| WPUPCFT028|Configurer TNC +AUX GPS|| WPUPCFT029|COnfigurer TNC +INVALID ENUM: %d|| WPUPCFT030|Configurer TNC KISS|| WPUPCFT031|Fichiers de configuration du TNC|| WPUPCFT032|Nom du fichier de dmarrage du TNC|| WPUPCFT033|Nom du fichier d'arrt du TNC||#' WPUPCFT034|Paramtres KISS|| WPUPCFT035|TXDelay (unit 10 ms)|| WPUPCFT036|Persistance (0 255)|| WPUPCFT037|SlotTime (unit 10 ms)|| WPUPCFT038|TxTail (unit 10 ms)|| WPUPCFT039|Full duplex|| WPUPCFT040|Configurer TNC Multi-Port KISS|| WPUPCFT041|Port radio|| WPUPCFT042|Proprits d'interface: Chemin UNPROTO douteux !|| WPUPCFT043|SVP choisissez un chemin plus court tel que WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Proprits d'interface: Chemin IGATE douteux !|| WPUPCFT045|Transmission avec chemin UNPROTO douteux !|| WPUPCFT046|Transmission avec chemin IGATE douteux !|| WPUPCFT047|Initialiser mode KISS au dmarrage|| # # # PopUp "Configure WX Port" WPUPCFWX01|Configurer port mto|| WPUPCFWX02|Port mto|| WPUPCFWX03|Correction globale de pluviomtre|| WPUPCFWX04|.1 pouce/2.5mm|| WPUPCFWX05|.01 pouce/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Pas de correction|| # # PopUp "Configure - Station" WPUPCFS001|Configurer la station|| WPUPCFS002|Indicatif|| WPUPCFS003|LAT|| WPUPCFS004|deg|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/O)|| WPUPCFS009|Symbole de station|| WPUPCFS010|Groupe/superposition|| WPUPCFS011|Symbole|| WPUPCFS028|Choisir|| WPUPCFS012|Puissance - Hauteur (HAAT) - Gain - Directivit|| WPUPCFS013|Dsactiver PHG|| WPUPCFS014|Hauteur de l'antenne||#' WPUPCFS015|Gain de l'antenne||#' WPUPCFS016|Omni|| WPUPCFS017|Commentaire:|| WPUPCFS018|Ambigut de position|| WPUPCFS019|Rien|| WPUPCFS020|.11 milles|| WPUPCFS021|1.15 milles|| WPUPCFS022|11.51 milles|| WPUPCFS023|69.09 milles|| WPUPCFS024|.18 kilomtres|| WPUPCFS025|1.85 kilomtres|| WPUPCFS026|18.53 kilomtres|| WPUPCFS027|111.19 kilomtres|| WPUPCFS029|Transmettre positions compresses|C| # # PopUp "Object/Item" POPUPOB001|Objet/Article|| POPUPOB002|Nom|| POPUPOB003|Crer nouvel objet|| POPUPOB004|Supprimer objet|| POPUPOB005|Modifier objet|| POPUPOB006|Crer nouvel article|| POPUPOB007|Objet polygonal|| POPUPOB008|Objet polygonal|| POPUPOB009|Couleur vive|| POPUPOB010|Remplis de couleur|| POPUPOB011|Cercle|| POPUPOB012|Ligne-droite '/'|| POPUPOB013|Ligne-gauche '\'||#' POPUPOB014|Triangle|| POPUPOB015|Rectangle|| POPUPOB016|Noir|| POPUPOB017|Bleu|| POPUPOB018|Vert|| POPUPOB019|Cyan|| POPUPOB020|Rouge|| POPUPOB021|Violet|| POPUPOB022|Jaune|| POPUPOB023|Gris|| POPUPOB024|Dcalage haut:|| POPUPOB025|Dcalage gauche (sauf '/'):|| POPUPOB026|Couloir:|| POPUPOB027|Options gnriques|| POPUPOB028|Placement|| POPUPOB029|Activer panneau|| POPUPOB030|Texte sur le panneau||#' POPUPOB031|Panneau|| POPUPOB032|Activer compression|| POPUPOB033|Supprimer article|| POPUPOB034|Modifier article|| POPUPOB035|Altitude (pieds):|| POPUPOB036|Vitesse (noeuds):|| POPUPOB037|Cap:|| POPUPOB038|Objet DF|| POPUPOB039|Signal - Hauteur (HAAT) - Gain - Directivit|| POPUPOB040|Largeur de faisceau - Relvement|| POPUPOB041|Antenne omni|| POPUPOB042|Antenne dirige|| POPUPOB043|Inutile|| POPUPOB044|Adopter objet|| POPUPOB045|Adopter article|| POPUPOB046|Relvement DF:|| POPUPOB047|Cercles de probabilit|| POPUPOB048|Objet Map View|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Configure Internet" WPUPCFI001|Configurer Internet|| WPUPCFI002|Hte || WPUPCFI003|Port || WPUPCFI004|(Hte secondaire)|| WPUPCFI005|Hte1|| WPUPCFI006|Port1|| WPUPCFI007|Hte2|| WPUPCFI008|Port2|| WPUPCFI009|Code d'accs||#' WPUPCFI010|(Laisser vide si nul)|| WPUPCFI011|Reconnexion sur erreur rseau ?|| WPUPCFI012|Fonction IGate ?|| WPUPCFI013|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFI014|Archivage des transactions IGate ?||| WPUPCFI015|Paramtres du filtre|| # # PopUp "Configure Database" WPUPCFID01|Configurer base de donnes (TBD)|| WPUPCFID02|Hte || WPUPCFID03|Port || WPUPCFID04|(Hte secondaire)|| WPUPCFID05|Hte1|| WPUPCFID06|Port1|| WPUPCFID07|Hte2|| WPUPCFID08|Port2|| WPUPCFID09|Code d'accs||#' WPUPCFID10|(Laisser vide si nul)|| WPUPCFID11|Reconnexion sur erreur rseau ?|| WPUPCFID12|Fonction IGate ?|| WPUPCFID13|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFID14|Archivage des transactions IGate ?||| WPUPCFID15|Paramtres du filtre|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configurer AGWPE|| WPUPCFIA02|Hte || WPUPCFIA03|Port || WPUPCFIA04|(Hte secondaire)|| WPUPCFIA05|Hte1|| WPUPCFIA06|Port1|| WPUPCFIA07|Hte2|| WPUPCFIA08|Port2|| WPUPCFIA09|Code d'accs||#' WPUPCFIA10|(Laisser vide si nul)|| WPUPCFIA11|Reconnexion sur erreur rseau ?|| WPUPCFIA12|Fonction IGate ?|| WPUPCFIA13|Diffusion de messages par le TNC lorsqu'en IGate ?||#' WPUPCFIA14|Archivage des transactions IGate ?||| WPUPCFIA15|RadioPort de transmission|| # # PopUp "Configure Audio Alarms" WPUPCFA001|Configurer alarmes sonores|| WPUPCFA002|Commande audio utiliser|| WPUPCFA003|Alarme pour:|| WPUPCFA004|Fichier sonore|| WPUPCFA005|Nouvelle station|| WPUPCFA006|Nouveau message|| WPUPCFA007|Proximit|| WPUPCFA008|Ouverture de bande|| WPUPCFA009|Distance minimum|| WPUPCFA010|Distance maximum|| WPUPCFA011|Alerte mto|| # # PopUp "Configure Speech" WPUPCFSP01|Configurer parole|| WPUPCFSP02|Parole pour:|| WPUPCFSP03|Nouvelle station|| WPUPCFSP04|Alerte nouveau message|| WPUPCFSP05|Texte nouveau message|| WPUPCFSP06|Proximit|| WPUPCFSP07|Ouverture de bande|| WPUPCFSP08|Alerte mto|| WPUPCFSP09|Station suivie proximit||#' # # PopUp "Track Station" WPUPTSP001|Suivre station|| WPUPTSP002|Suivre l'indicatif||#' WPUPTSP003|Casse exacte|| WPUPTSP004|Correspondance exacte|| WPUPTSP005|Suivre maintenant !|| WPUPTSP006|Annuler suivi|| WPUPTSP007|Tlcharger piste|| WPUPTSP008|Indicatif|| WPUPTSP009|Dbut de piste (depuis .. heures)|| WPUPTSP010|Longueur de piste (heures)|| # # PopUp "Messages..." WPUPMSB001|Boite d'envoi %d||#' WPUPMSB002|Boite d'envoi au groupe %d||#' WPUPMSB003|Indicatif de station:|| WPUPMSB004|Ident. du groupe:|| WPUPMSB005|Nouvel/Refresh indicatif|| WPUPMSB006|Nouveau groupe|| WPUPMSB007|Effacer histoire de messages|| WPUPMSB008|Message:|| WPUPMSB009|Transmettre maintenant !|| WPUPMSB010|Voie:|| WPUPMSB011|Annuler messages en suspens|| WPUPMSB012|RAZ minuterie Temporisateur|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*EXPIRATION*|| WPUPMSB017|*ANNULE*|| WPUPMSB018|*REJETE*|| WPUPMSB019|Changer chemin|| WPUPMSB020|Utiliser chemin(s) par dfaut|| WPUPMSB021|Direct (pas de chemin)|| WPUPMSB022|Chemin inverse (pour info):|| # # PopUp "Auto Reply" WPUPARM001|Modifier rponse automatique|| WPUPARM002|Rponse:|| # # PopUp "Help Index" WPUPHPI001|Index d'Aide||#' WPUPHPI002|Lire|| # # PopUp "Station Info" WPUPSTI000|Objet de: %s|| WPUPSTI001|Information de station|| WPUPSTI002|Composer un message|| WPUPSTI003|Chercher dans la base FCC|| WPUPSTI004|Chercher dans la base RAC|| WPUPSTI005|Paquets recu: %d Dernire transmission: || WPUPSTI006|Entendu sur le TNC %d, || WPUPSTI007|Entendu || WPUPSTI008|dernirement sur port local|| WPUPSTI009|dernirement sur TNC %d|| WPUPSTI010|dernirement sur Internet %d|| WPUPSTI011|dernirement dans fichier|| WPUPSTI012|dernirement sur inconnu|| WPUPSTI013|, et a boug|| WPUPSTI014|Puissance/gain/etc.:|| WPUPSTI016|Altitude: %.0f%s || WPUPSTI017|Cap: %s || WPUPSTI018|Vitesse: %.1f km/h|| WPUPSTI019|Vitesse: %.1f milles/h|| WPUPSTI020|%0.1f milles|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distance de ma station: %s Relvement de ma station: %s|| WPUPSTI023|Dernire position : || WPUPSTI024|Donnes mto %c:%s|| WPUPSTI025|Cap des vents: %s Vitesse: %03d km/h|| WPUPSTI026|Cap des vents: %s Vitesse: %s milles/h|| WPUPSTI027| Rafales: %03d km/h|| WPUPSTI028| Rafales: %s milles/h|| WPUPSTI029|Temprature: %02.1fC || WPUPSTI030|Temprature: %sF || WPUPSTI031|Humidit: %s%% || WPUPSTI032| Humidex: %02.1fC || WPUPSTI033|Baro: %s hPa|| WPUPSTI034|Neige: %0.1f (cm/24h|| WPUPSTI035|Neige: %0.0f (pouces/24h)|| WPUPSTI036|Pluie: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (pouces/h) || WPUPSTI039|%0.2f (mm/jour) || WPUPSTI040|%0.2f (pouces/jour) || WPUPSTI041|%0.2f (mm/depuis minuit)|| WPUPSTI042|%0.2f (pouces/depuis minuit)|| WPUPSTI043|Route des donnes: %s|| WPUPSTI044|Commentaire %02d/%02d %02d:%02d : %s|| WPUPSTI045|Effacer la piste|| WPUPSTI046|Pluie Totale: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (pouces)|| WPUPSTI049|Informations suivi|| WPUPSTI050|Messages non confirms|| WPUPSTI051|Info station en direct|| WPUPSTI052|Info station version|| WPUPSTI053|Modifier objet/article|| WPUPSTI054|Sauver piste|| WPUPSTI055|Echo de:|| WPUPSTI056|Activer actualisation automatique|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Relvement DF: %s|| WPUPSTI059|Etat %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp combustible: %02.1fC || WPUPSTI061|Temp combustible: %sF || WPUPSTI062|Humidit combustible: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|Chercher alerte NWS|| WPUPSTI065|Indicatif tactique: %s|| WPUPSTI066|Assigner un indicatif tactique|| WPUPSTI067|Porte actuelle : %d milles|| WPUPSTI068|nul|| WPUPSTI069|dfaut|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|porte|| WPUPSTI073|Mauvais PHG|| WPUPSTI074|Mauvais SHG|| WPUPSTI075|Porte DF|| WPUPSTI076|Pas de signal dtect|| WPUPSTI077|Signal dtect (peut-tre))|| WPUPSTI078|Signal dtect non dcodable|| WPUPSTI079|Signal faible, parfois dcodable|| WPUPSTI080|Signal brouill mais copiable|| WPUPSTI081|Un peu de bruit, avec un signal facilement dcodable|| WPUPSTI082|Bon signal avec un peu de bruit|| WPUPSTI083|Signal presque sans bruit|| WPUPSTI084|Signal sans bruit|| WPUPSTI085|Signal trs fort sans bruit|| WPUPSTI086|MAUVAIS RELEVEMENT|| WPUPSTI087|MAUVAIS NRQ|| WPUPSTI088|Largeur de faisceau DF|| WPUPSTI089|Longueur DF|| WPUPSTI090|Invalide|| WPUPSTI091|Changer la couleur de la piste|| WPUPSTI092|Effacer relvements DF|| # # # PopUp "ALOHA Statistics" WPUPALO001|Rayon ALOHA: %d %s|| WPUPALO002|Stations dans le cercle ALOHA: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (en mouvement): %d|| WPUPALO005| Mobiles (autres): %d|| WPUPALO006| Stations mto: %d|| WPUPALO007| Stations fixes: %d|| WPUPALO008|Dernier calcul il y a %d %s %d %s.|| WPUPALO666|Rayon ALOHA pas encore calcul|| # # # FCC-RAC Call Look up STIFCC0001|Recherche base de donnes FCC|| STIFCC0002|Recherche base de donnes RAC|| STIFCC0003|Nom:|| STIFCC0004|Adresse:|| STIFCC0005|Ville:|| STIFCC0006|Etat:|| STIFCC0007|Code postal:|| STIFCC0008|License de base || STIFCC0009|License avance || STIFCC0010|5 mots/min || STIFCC0011|12 mots/min || # # # FCC-RAC Call Look up STIFCC0100|Index FCC ancien, restauration|| STIFCC0101|Recherche d'indicatif|| STIFCC0102|Indicatif non trouv !|| STIFCC0103|Index RAC ancien, restauration|| # # # Band open message UMBNDO0001| une distance de|| # # # Universal Options UNIOP00001|OK|| UNIOP00002|Annuler|| UNIOP00003|Fermer|| UNIOP00004|milles|| UNIOP00005|km|| UNIOP00006|Priphrique|| UNIOP00007|Ajouter|| UNIOP00008|Supprimer|| UNIOP00009|Proprits|| UNIOP00010|Permettre transmission ?|| UNIOP00011|Activer au dmarrage ?|| UNIOP00012|km/h|| UNIOP00013|milles/h|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pouces|| UNIOP00018|mm/jour|| UNIOP00019|pouces/jour|| UNIOP00020|mm/h|| UNIOP00021|pouces/h|| UNIOP00022|mm/minuit|| UNIOP00023|pouces/minuit|| UNIOP00024|deg|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|pouces Hg|| UNIOP00028|mm Hg|| UNIOP00029|Rgler l'horloge systme sur celle du GPS ?|| UNIOP00030|Rpteur digi ?|| UNIOP00031|m|| UNIOP00032|Appliquer||| UNIOP00033|Annuler|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|jour|| UNIOP00037|Envoyer Ctrl+E pour obtenir les donnes GPS?|| UNIOP00038|Ajouter un dlai|| # # PopUp "Station Chooser" STCHO00001|Choix de station|| # # DISPLAY WX ALERT WPUPWXA001|Alerte mto|| WPUPWXA002|Liste d'alertes mto|| # # PopUp "Configure - Interfaces" WPUPCIF001|Interfaces installes|| WPUPCIF002|Choix du type d'interface|| # # PopUp "Configure AX.25 TNC" WPUPCAX001|Configurer TNC AX.25|| WPUPCAX002|Nom de l'interface AX.25||#' # # Interface device names IFDNL00000|Aucune|| IFDNL00001|TNC port srie|| IFDNL00002|TNC srie + GPS sur cble HSP|| IFDNL00003|GPS port srie|| IFDNL00004|Mto port srie|| IFDNL00005|Serveur Internet|| IFDNL00006|TNC AX25|| IFDNL00007|GPS rseau (par gpsd)|| IFDNL00008|Mto par rseau|| IFDNL00009|TNC srie + GPS sur cble AUX|| IFDNL00010|TNC KISS srie|| IFDNL00011|Base de donnes par rseau (pas encore implment)|| IFDNL00012|AGWPE par rseau|| IFDNL00013|TNC Multi-Port KISS srie|| IFDNL00014|Base de donnes SQL (Experimental)|| # # Interface device info IFDIN00000|%s %2d %s sur port srie %s %s|| IFDIN00001|%s %2d %s connect %s:%d %s|| IFDIN00002|%s %2d %s avec interface nomme %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006|INACTIF|| IFDIN00007| ACTIF || IFDIN00008|ERREUR || IFDIN00009|INCONNU|| # # PopUp "Interface control" IFPUPCT000|Contrle d'interface||#' IFPUPCT001|Dmarrer|| IFPUPCT002|Arrter|| IFPUPCT003|Dmarrer toutes|| IFPUPCT004|Arrter toutes|| # # IGate control IGPUPCF000|Options IGate|| IGPUPCF001|Arrter traffic Internet|| IGPUPCF002|Autoriser RF vers Internet seulement|| IGPUPCF003|Autoriser RF->Inet et Inet->RF|| IGPUPCF004|Voie Igate -> RF || # # WX Station WXPUPSI000|Station mto|| WXPUPSI001|Type de station mto|| WXPUPSI002|Donnes courantes|| WXPUPSI003|Cap des vents|| WXPUPSI004|Vitesse des vents|| WXPUPSI005|Rafales|| WXPUPSI006|Temprature|| WXPUPSI007|Prcipitation totale|| WXPUPSI008|Prcipitation totale journalire|| WXPUPSI009|Baromtre|| WXPUPSI010|Humidit|| WXPUPSI011|Peet Bros ULTIMETER 2000 (mode acquisition de donnes)|| WXPUPSI012|Peet Bros ULTIMETER II|| WXPUPSI013|Peet Bros ULTIMETER 2000 (mode paquet)|| WXPUPSI014|Prcipitation horaire totale|| WXPUPSI015|Total prcipitation 24 hrs|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 (mode complet)|| WXPUPSI018|Point de rose|| WXPUPSI019|Vents max.|| WXPUPSI020|Facteur olien|| WXPUPSI021|Facteur humidex|| WXPUPSI022|Baro 3 heures|| WXPUPSI023|Temprature max.|| WXPUPSI024|Temprature min.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Station Lists LHPUPNI000|Toutes stations|| LHPUPNI001|Stations mobiles|| LHPUPNI002|Stations mto|| LHPUPNI003|Stations locales (via TNC)|| LHPUPNI004|Dernires stations|| LHPUPNI005|Objets et articles|| LHPUPNI006|Mes objets et articles|| LHPUPNI010|No.|| LHPUPNI011|Indicatif|| LHPUPNI012|#Paq|| LHPUPNI013|Heure dernire pos.|| LHPUPNI014|Chemin|| LHPUPNI015|PHG|| LHPUPNI016|Commentaires|| LHPUPNI100|Cap|| LHPUPNI101|Vit.|| LHPUPNI102|Alt.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Paq|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|Cap|| LHPUPNI201|Vit|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon ou UTM|| # # Maps WX Alert styles PULDNMAT01|Voir cartes alertes au dessus des autres cartes|| PULDNMAT02|Voir cartes alertes en desous des autres cartes|| # # Error/popup messages POPEM00001|Erreur localisation !|| POPEM00002|Station %s non trouve !|| POPEM00003|Erreur de suivi !|| POPEM00004|Erreur d'interface !||#' POPEM00005|Nom de port AX.25 invalide %s|| POPEM00006|Nom de port AX.25 invalide %s|| POPEM00007|Indicatif invalide %s|| POPEM00008|Destination AX25 indicatif ou relais digi invalide|| POPEM00009|Erreur ouverture socket AX.25, %s|| POPEM00010|Erreur liaison socket AX.25, %s|| POPEM00011|Pas de connection l'indicatif AX.25 %s||#' POPEM00012|Erreur AX.25 sur sortie UI|| POPEM00013|Problme avec fichier axports|| POPEM00014|Nom de port AX.25 invalide %s|| POPEM00015|Erreur ouverture d'interface %d Erreur majeure||#' POPEM00016|Erreur ouverture d'interface %d Dpassement de temps||#' POPEM00017|Plus d'interfaces disponible !||#' POPEM00018|Demande de donne - Message une ligne|| POPEM00019|Transmission hors service port %d|| POPEM00020|Erreur base de donnes !|| POPEM00021|Support AX.25 non compil dans Xastir !||#' POPEM00022|Erreur d'entre !||#' POPEM00023|Aucun nom de lieu spcifi !|| POPEM00024|Le nom de lieu spcifi est en cours d'utilisation !||#' POPEM00025|Pas trouv !|| POPEM00026|Suivi commencera quand elle apparatra|| POPEM00027|Mauvaise info. Certains champs vides ?|| POPEM00028|Ne peut ouvrir fichier|| POPEM00029|Trouv !|| POPEM00030|Symbole de station mto|| POPEM00031|Chang en symbole mto '/_', autres possibilits: '\_' '/W' et '\W'|| POPEM00032|Attention: utilise symbole du "National Weather Service" !|| POPEM00033|Pas de donnes GPS !|| POPEM00034|TX de ma position dsactiv jusqu'a rception de bonnes donnes GPS !||#' POPEM00035|Avertissement|| POPEM00036|Avis|| POPEM00037|Interface HSP prsente: temporisation GPS augmente|| POPEM00038|Conflit de nom avec un Objet/Item/Station dj existant|| POPEM00039|Caractre illgal, remplac par un point|| POPEM00040|Le chemin de sortie personnalis a t perdu|| POPEM00041|Traitement d'un autre fichier en cours. Attendez, puis ressayez|| POPEM00042|L'object ne m'appartient pas ! Essayez d'adopter l'objet d'abord.|| POPEM00043|Ce n'est pas un objet ou article !|| POPEM00044|Rcupration de piste Findu : chec|| POPEM00045|Rcupration de piste Findu : Termin|| POPEM00046|La bibliothque Berkeley DB ne correspond pas ! Dsactivation du cache des cartes.|| POPEM00047|Toutes les transmissions sont DESACTIVEES. Les balises d'urgences ne seront PAS envoyes!|| POPEM00048|Mode balise d'URGENCE!|| POPEM00049|MODE BALISE D'URGENCE, transmission toutes les 60 secondes!|| POPEM00050|Interfaces ou trans.position DESACTIVEES. Les balises d'urgences ne seront PAS envoyes!|| POPEM00051|Rseau alternatif (ALTNET) activ (Menu Fichier->Configurer->Defauts)|| POPEM00052|Indicatif est VIDE!|| POPEM00053|Message est VIDE!|| POPEM00054|Vous essayez de communiquer avec vous mme!|| # # Jump Location JMLPO00001|Afficher Cartes Favorites|| JMLPO00002|Aller !|| JMLPO00003|Nouveau nom de lieu:|| # # Bulletins BULMW00001|Bulletins|| BULMW00002|Limiter la porte (0, aucune limite)|| BULMW00003|Changer porte|| # # All Message Traffic AMTMW00001|Tout trafic des messages|| AMTMW00002|Limiter la porte (0, aucune limite)|| # # Speech Strings SPCHSTR001|kilomtres|| SPCHSTR002|mtres|| SPCHSTR003|milles|| SPCHSTR004|yards|| SPCHSTR005|%s, distance est %d %s.|| SPCHSTR006|%s, distance est %.1f %s.|| SPCHSTR007|%s, distance est %d %s %s %s.|| SPCHSTR008|%s, distance est %.1f %s %s %s.|| SPCHSTR009|Nouvelle alerte mto|| SPCHSTR010|Nouvel indicatif|| SPCHSTR011|Reu, D X, %s, une distance de %.1f %s|| # # SPCHDIRN00|au nord de|| SPCHDIRS00|au sud de|| SPCHDIRE00| l'est de|| SPCHDIRW00| l'ouest de|| SPCHDIRNE0|au nord-est de|| SPCHDIRNW0|au nord-ouest de|| SPCHDIRSE0|au sud-est de|| SPCHDIRSW0|au sud-ouest de|| # # Symbol Selection Dialog SYMSEL0001|Choisir symbole|| SYMSEL0002|Table de symboles primaire|| SYMSEL0003|Table de symboles secondaire|| # # Print Properties Dialog PRINT0001|Proprits d'impression|| PRINT0002|Taille du papier|| PRINT0003|Rotation automatique d'image|| PRINT0004|Tourner image 90 gauche|| PRINT0005|Proportion automatique d'image|| PRINT0006|chelle:|| PRINT0007|Forcer le fond tre blanc|| PRINT0008|Imprimer en noir et blanc|| PRINT0016|Inverser couleurs|| PRINT0009|Rsolution Postscript:|| PRINT0010|Prvisualiser|| PRINT0011|Imprimer dans un fichier|| PRINT0012|Sauvegarde de l'image dans un fichier...|| PRINT0013|Conversion Postscript...|| PRINT0014|Cration du fichier d'impression finie|| PRINT0015|Etat d'impression|| # # Print Properties Dialog PRINT1001|Directement :|| PRINT1002|Via Previewer:|| # # Locate Feature Dialog FEATURE001|Nom:|| FEATURE002|Etat/Province:|| FEATURE003|Comt:|| FEATURE004|Quadrant de carte:|| FEATURE005|Type :|| FEATURE006|Fichier GNIS :|| FEATURE007|Adresse :|| FEATURE008|Ville :|| FEATURE009|Marquer la destination|| FEATURE010|Code postal :|| FEATURE011|Fichier Geocoding|| # # Geocoding Dialog (Nominatim) GEOCODE001|Rechercher un lieu|| GEOCODE002|Recherche :|| GEOCODE003|Filtre pays :|| GEOCODE004|Rechercher|| GEOCODE005|Effacer|| GEOCODE006|Rsultats :|| GEOCODE007|Aller || GEOCODE008|Marquer|| GEOCODE009|Fermer|| GEOCODE010|Recherche en cours...|| GEOCODE011|Aucun rsultat trouv|| GEOCODE012|Erreur : %s|| GEOCODE013|%d rsultat(s) trouv(s)|| GEOCODE014|Donnes (C) Contributeurs OpenStreetMap|| GEOCODE015|Aucun (Monde entier)|| GEOCODE023|Service non disponible|| GEOCODE024|Entrez un lieu rechercher|| GEOCODE025|Vider le cache|| GEOCODE026|Cache vid avec succs|| GEOCODE027|chec du vidage du cache|| GEOCODE028|Serveur Nominatim :|| GEOCODE029|Cache activ :|| GEOCODE030|Expiration du cache (jours) :|| GEOCODE031|E-mail utilisateur :|| GEOCODE032|Pays par dfaut :|| GEOCODE033|Paramtres|| GEOCODE034|Enregistrer|| GEOCODE035|Annuler|| GEOCODE036|Appliquer|| GEOCODE037|Paramtres de gocodage|| # # Geocoding Configuration Dialog GEOCFG001|Paramtres de gocodage|| GEOCFG002|URL du serveur :|| GEOCFG003|Adresse e-mail :|| GEOCFG004|(Optionnel mais recommand)|| GEOCFG005|Pays par dfaut :|| # # Coordinate Calculator Dialog COORD001|Calculatrice de coordones|| COORD002|Calc|| COORD003|Calculer|| COORD004|Effacer|| COORD005|UTM|| COORD006|Latitude ou|| COORD007|Longitude ou|| COORD008|Zone|| COORD009|UTM vers l'est|| COORD010|UTM vers le nord|| COORD011| Degrs dcimaux: || COORD012| Degrs/Minutes dcimales: || COORD013| Degrs/Minutes/secondes dc.: || COORD014| Universal Transverse Mercator: || COORD015|Syst. de rf. grille militaire: || COORD016| Grille Locator Maidenhead: || COORD017| ** Dsol, entre non reconnue ! **|| COORD018| ** SVP utilisez l'un de ces formats d'entre: **|| # # # Smart Beaconing Dialog SMARTB001|Balise intelligente (Smart Beaconing)|| SMARTB002|Intervalle maximal (secs):|| SMARTB003|Vitesse haute (m/h):|| SMARTB004|Vitesse haute (k/h):|| SMARTB005|Intervalle minimal (mins):|| SMARTB006|Vitesse basse (m/h):|| SMARTB007|Vitesse basse (k/h):|| SMARTB008|Virage minimum (deg):|| SMARTB009|Pente de virage:|| SMARTB010|Temps d'attente (secs):||#' SMARTB011|Activer SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Ajuster correction de gamma|| GAMMA002|Correction de gamma|| # # # # Map labels font Dialog MAPFONT001|Changer police de caratres|| MAPFONT002|Police de caratres|| MAPFONT003|Police de caratre des cartes Minusc|| MAPFONT004|Police de caratre des cartes Petite|| MAPFONT005|Police de caratre des cartes Moyenne|| MAPFONT006|Police de caratre des cartes Large|| MAPFONT007|Police de caratre des cartes Enorme|| MAPFONT008|Police de caratre des cartes Border|| MAPFONT009|Police de caratre des menus|| MAPFONT010|Police de caratre des Stations|| MAPFONT011|Police de caratre de l'ID ATV|| # # # # Distance/Bearing on status line PULDNDB001|Etat dist/relvement|| # # # GPS Transfer Operations GPS001|Transfert GPS|| GPS002|Nom de fichier|| GPS003|Choisir couleur|| GPS004|Rouge|| GPS005|Vert|| GPS006|Noir|| GPS007|Blanc|| GPS008|Orange|| GPS009|Bleu|| GPS010|Jaune|| GPS011|Violet|| # # # Map Properties Dialog MAPP001|Caractristiques des cartes|| MAPP002|Max Min Carte Afficher USGS Auto|| MAPP003|Zoom Zoom Couche Remplie DRG Cartes Voie/Fichier|| MAPP004|Modifier Couche->|| MAPP005|Remplie->|| MAPP006|Oui|| MAPP007|Non|| MAPP008|AutoCartes->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|jour|| TIME002|jours|| TIME003|heure|| TIME004|heures|| TIME005|minute|| TIME006|minutes|| TIME007|seconde|| TIME008|secondes|| # # # Map Caching CACHE001|La carte se trouve dans le cache|| CACHE002|Chargement de la carte en mmoire|| CACHE003|Carte non trouve dans le cache...|| # # # Map Screen Misc RANGE001|CHELLE|| # # # GPS Status GPSS001|WAAS ou PPS|| GPSS002|DGPS|| GPSS003|SPS valide|| GPSS004|Invalide|| GPSS005|Sats/vue|| GPSS006|Repre|| GPSS007|! Les donnes GPS ont plus de 30 secondes !|| GPSS008|Simulation|| GPSS009|Manuel|| GPSS010|Estim|| GPSS011|RTK flottant|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Object surface|| CADPUD002|Etiquette surface:|| CADPUD003|Commentaire:|| CADPUD004|Probabilit (%):|| CADPUD005|OK|| CADPUD006|Dialogue CAD|| CADPUD007|Montrer/diter les dtails|| CADPUD008|Annulerl|| CADPUD009|Effacer les objets CAD ?|| CADPUD010|Tout effacer|| CADPUD011|Effacer la slection|| CADPUD012|Continue|| CADPUD013|pointillis|| CADPUD014|Double pointillis|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|Carte XASTIR de %s (haut gauche) %s (bas droit). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|carte XASTIR de %s (haut gauche) %s %s (bas droit). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|Carte XASTIR Map de %s (haut gauche) %s (bas droit). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql avec Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Schma simple Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Schma CAD Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Schma complet Xastir|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|Schma APRSWorld|| Xastir-Release-2.2.4/config/language-German.sys0000664000175000017500000011765115151324131020333 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the German Language file used for all the prompts in xastir # Dies ist die deutsche Sprachdatei fr Menus und Textausgaben in Xastir # # Creator : Kai Altenfelder, DL3LBA # Maintained by : The Xastir Group # Modified by : 08.04.2007, Rolf Bleher, DK7IN # # comment lines with pound signs in front are ignored # File format as follows: # ID (10 chars alpha+numeric)|(String associated with id)|QuickKeys|#comment # The ID is a unique uppercase char string for each block followed by a nummer # # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # Warnung: # Einige Texte enthalten Formatierungsbefehle wie %s oder %d, diese sollten # beibehalten werden. Falsche Formatbefehle knnen zu einem Programmabsturz # fhren. # # Hauptmenu MENUTB0001|Datei|D| MENUTB0002|Zeige|Z| MENUTB0004|Karten|K| MENUTB0005|Stationen|S| MENUTB0006|Nachrichten|N| MENUTB0010|Schnittstellen|i| MENUTB0009|Hilfe|H| # # Menu "Datei" PULDNFI001|Einstellungen|E| PULDNFI002|Protokolldatei laden|P| PULDNFI003|Test|T| PULDNFI004|Beenden|B| PULDNFI007|Debug Level ndern|D| PULDNFI010|TNC protokollieren|| PULDNFI011|Netz protokollieren|| PULDNFI012|IGate protokollieren|| PULDNFI013|Wetter protokollieren|| PULDNFI014|PNG-Schnapschsse|| PULDNFI015|Karte drucken|d| PULDNFI016|KML Snapshots|| # # Menu "Zeige" PULDNVI001|Bekanntmachungen|B| PULDNVI002|Packet Radio|P| PULDNVI003|Mobilstationen|M| PULDNVI004|Alle Stationen|A| PULDNVI009|Lokale Stationen|L| PULDNVI012|Letzte Stationen|S| PULDNVI005|Wetterstationen|W| PULDNVI008|Eigene Wetterdaten|d| PULDNVI007|Wetterwarnung|e| PULDNVI011|Nachrichten|N| PULDNVI013|Laufzeit|z| PULDNVI014|Programmlaufzeit|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistiken|| # # Menu "Einstellungen" PULDNCF004|Meine Stationsdaten|M| PULDNCF001|Grundeinstellungen|G| PULDNCF003|Zeitverhalten|Z| PULDNCF002|Koordinatensystem|K| PULDNCF006|Audio Alarm|A| PULDNCF007|Sprachausgabe|S| PULDNCF008|Einstellungen sichern|E| # (Einheiten siehe PULDNDP006) # # Menu "Karten" PULDNMP001|Kartenauswahl|K| PULDNMP012|Ausschnitte|A| PULDNMP014|Objekt in Karte suchen|O| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Alle Karten verbergen|| PULDNMP002|Automatische Karten|| PULDNMP003|Gitter|| PULDNMP004|Ebenen|| PULDNMP010|Kartenbeschriftung|| PULDNMP009|Flchen einfrben|| PULDNMP007|Wetterwarnung|| PULDNMP005|Hintergrundfarbe|H| PULDNMP006|Textdarstellung|T| PULDNMP026|Symbol Umrandung|U| PULDNMP011|Mauszeiger-Men|M| PULDNMP008|Intensitt|I| PULDNMP021|Autom. Karten - PixelKarten aus|| PULDNMP022|Neue Karten beim Start indizieren|| PULDNMP023|Index: Neue Karten hinzufgen|N| PULDNMP024|Index: ALLE Karten reindizieren|r| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Karten neu laden (nicht vom Cache)|| PULDNMP028|Lsche gesamten Karten-Cache!|| PULDNMP029|Standort suchen|| PULDNMP030|Konfiguration USGS DRG|| PULDNMP031|Kartenrand ein|| PULDNMP032|Geocoding-Einstellungen|| MPUPTGR017|Internet-Karten Timeout [Sek]|| # # PopUp "Configure USGS DRG" MPUPDRG001|Whle darzustellende Objekte:|| MPUPDRG002|frbe Hintergrundkarten (XOR)|| MPUPDRG003|Schwarz|| MPUPDRG004|Wei|| MPUPDRG005|Blau|| MPUPDRG006|Rot|| MPUPDRG007|Braun|| MPUPDRG008|Grn|| MPUPDRG009|Violett|| MPUPDRG010|Gelb|| MPUPDRG011|Hellblau|| MPUPDRG012|Rosa|| MPUPDRG013|Violett (hell)|| MPUPDRG014|Hellgrau|| MPUPDRG015|Hellbraun|| # # # PopUp "Kartenauswahl" WPUPMCP001|Kartenauswahl|| PULDNMMC01|Keine|K| PULDNMMC02|Vektor|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Verz. expandieren|e| PULDNMMC07|Verz/Karten gewhlt:|| PULDNMMC08|Verz. lschen|l| PULDNMMC09|Alles whlen|A| # # Karten - Hintergrundfarbe PULDNMBC01|Grau|| PULDNMBC02|Helles Grau|| PULDNMBC03|Dunkelblau|| PULDNMBC04|Hellblau|| PULDNMBC05|Grn|| PULDNMBC06|Hellgrn|| PULDNMBC07|Gelb|| PULDNMBC08|Zartes Gelb|| PULDNMBC09|Rtliches Braun|| PULDNMBC10|Rot|| PULDNMBC11|Wei|| PULDNMBC12|Schwarz|| # # Karten - Stil der Stationstexte PULDNMSL01|Schwarze Umrandung|U| PULDNMSL02|Schatten|S| PULDNMSL03|Schwarzer Hintergrund|H| PULDNMSL04|DropShadow|| # # PullDown "Symbol Umrandung" PULDNMIO01|Keine Umrandung|K| PULDNMIO02|Schwarze Umrandung|S| PULDNMIO03|Graue Umrandung|G| PULDNMIO04|Weie Umrandung|W| # # Schalter PULDNOT001|An|| PULDNOT002|Aus|| PULDNOT003|Kurz|| # # Menu "Stationen" PULDNDP014|Station finden|f| PULDNDP001|Verfolge Station|V| PULDNDP022|Spur von findu holen|h| PULDNDP032|Daten filtern|| PULDNDP040|Nichts|| PULDNDP041|Meine Daten|| PULDNDP042|TNC|| PULDNDP027|- Direkt|| PULDNDP043|- ber Digi|| PULDNDP034|Netzwerk|| PULDNDP019|Alte Daten einbeziehen|| PULDNDP044|Stationen|| PULDNDP028|- Feste Stationen|| PULDNDP029|- Bewegte Stationen|| PULDNDP030|- Wetterstationen|| PULDNDP053| - CWOP-Stationen|| PULDNDP045|Objekte|| PULDNDP026|- Wetter Objekte|| PULDNDP039|- Regenmengen Objekte|| PULDNDP031|- Andere Objekte|| PULDNDP057|- Whlen Sie Flugzeug Objekte/Items|| PULDNDP058|- Whlen Sie Schiff Objekte/Items|| PULDNDP033|Anzeige filtern|| PULDNDP010|Rufzeichen|| PULDNDP012|Symbol|| PULDNDP011|- Symbol drehen|| PULDNDP007|Spur|| PULDNDP003|Kurs|| PULDNDP004|Geschwindigkeit|| PULDNDP017|- kurz|| PULDNDP002|Hhe|| PULDNDP009|Wetterdaten|| PULDNDP046|- Wetter Text|| PULDNDP018|-- nur Temperatur|| PULDNDP047|- Windfahne|| PULDNDP054|ALOHA Kreis anzeigen|| PULDNDP013|Positionsverschleierung|| PULDNDP008|Leistung/Gewinn|| PULDNDP021|- mit Standardwert|| PULDNDP020|- bei Mobilstationen|| PULDNDP023|DF Kreise zeigen|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Positionsvoraussage|| PULDNDP036|- Kreis zeigen|| PULDNDP037|- Kurs zeigen|| PULDNDP038|- Symbol zeigen|| PULDNDP005|Entfernung/Richtung|| PULDNDP024|Alter des letzten Empfangs|| PULDNDP015|Stationen lschen|l| PULDNDP016|Spuren lschen|S| PULDNDP025|ObjektHistorie lschen|| PULDNDP048|ObjektHistorie erneut laden|| PULDNDP049|Lschen aller taktischen Calls|| PULDNDP050|Lschen Verlauf taktische Calls|| PULDNDP051|Nur taktische Calls whlen|| PULDNDP052|- Wegpunkte bezeichnen|| PULDNDP055|Exportieren|E| PULDNDP056|Export in KML-Datei|| # # Maeinheiten PULDNUT001|Englische Mae|| PULDNUT002|Metrisch|| # # Menu "Nachrichten" PULDNMG001|Schicke Nachricht an|N| PULDNMG002|ffne Gruppen Nachricht|G| PULDNMG003|Lsche alle ausgehenden Nachrichten|L| PULDQUS001|Abfrage Stationen allgemein|S| PULDQUS002|Abfrage Internet-Gateways|I| PULDQUS003|Abfrage Wetterstationen|W| PULDNMG004|Setze automatische Antwort|t| PULDNMG005|Automatische Antwort|A| PULDNMG006|Satelliten ACK Modus|M| PULDNMG007|Unerledigte Nachrichten zeigen|U| # # Menu "Schnittstellen" PULDNTNT04|Schnittstellensteuerung|| PULDNTNT03|Nicht senden: ALLES|| PULDNTNT05|Nicht senden: Meine Position|| PULDNTNT06|Nicht senden: Objekte|| PULDNTNT11|aktiviere Server-Port|| PULDNTNT01|Sende jetzt!|S| PULDNTNT07|Lade GPS Track|T| PULDNTNT08|Lade GPS Route|R| PULDNTNT09|Lade GPS Wegpunkte|W| PULDNTNT10|Garmin RINO Wegpunkte holen|G| # # Menu "Hilfe" PULDNHEL01|Version|V| PULDNHEL02|Hilfe Index|I| PULDNHEL03|NOTFALL BAKEN MODUS EINSCHALTEN|E| PULDNHEL04|!!! NOTFALL BAKEN MODUS !!!|| PULDNHEL05|ber Xastir|| # # Mauszeiger PopUp Menu POPUPMA001|Mauszeiger-Menu|| POPUPMA00c|Zentrieren|| POPUPMA015|Stations-Info|| POPUPMA002|Zoome hinein|| POPUPMA003|Zoome heraus|| POPUPMA004|Zoomebenen|| POPUPMA005|Ebene 1|| POPUPMA006|Ebene 16|| POPUPMA007|Ebene 64|| POPUPMA008|Ebene 256|| POPUPMA009|Ebene 1024|| POPUPMA010|Ebene 8192|| POPUPMA017|Ganze Welt|| POPUPMA016|Letzte Ansicht|| POPUPMA018|Objekt Neu|| POPUPMA019|Objekt ndern|| POPUPMA025|Meine Station hierhin!|h| POPUPMA011|nach oben|| POPUPMA012|nach unten|| POPUPMA013|nach links|| POPUPMA014|nach rechts|| POPUPMA020|Messen|| POPUPMA021|Bewegen|| POPUPMA022|Verfolge mich|| POPUPMA023|Modifikationstasten aktiv!|| POPUPMA024|Bitte Umschalt/Num/Rollen/andere Modifikationstasten ausschalten|| POPUPMA026|Zentrieren & Zoom|| POPUPMA027| Breite|| POPUPMA028| Lnge|| POPUPMA029|CAD-Objekte zeichnen|| POPUPMA030|Zeichnen|| POPUPMA031|Polygon abschlieen|| POPUPMA032|CAD-Polygone lschen|| POPUPMA033|**NICHT BENUTZT**|| POPUPMA034|Selbstdefinierter Zoom|| POPUPMA035|10% verkleinern|| POPUPMA036|10% vergrern|| POPUPMA037|Bereich|| POPUPMA038|Quadrat|| POPUPMA039|Quadratfuss|| POPUPMA040|Quadratmeter|| POPUPMA041|Peilung|| POPUPMA042|Grad|| POPUPMA043|Bearbeite mehrdeutige Position|| POPUPMA044|Mehrdeutige Position, Ihre Position kann sich sprunghaft verndern.|| POPUPMA045|Vordefinierte Objekte|| POPUPMA046|CAD-Polygone|| POPUPMA047|CAD-Objekte ein|| POPUPMA048|CAD-Label ein|| POPUPMA049|CAD-Kommentare ein|| POPUPMA050|CAD-Wahrscheinlichkeit ein|| POPUPMA051|CAD-Flchenma ein|| POPUPMA052|sq|| POPUPMA053|Fu|| POPUPMA054|Meter|| POPUPMA055|Meilen| # # Texte in Statuszeile BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stationen|| BBARSTA000|%-9s Neues Objekt!|| BBARSTA001|%-9s Neue Station!|| BBARSTA002|%-9s||# neue Daten (nur Call angezeigt) BBARSTA003|Lade Karten...|| BBARSTA004|Karten geladen|| BBARSTA005|Kartengitter An|| BBARSTA006|Kartengitter Aus|| BBARSTA007|Automatische Karte ist AN|| BBARSTA008|Automatische Karte ist AUS|| BBARSTA009|Kartenebenen sind AN|| BBARSTA010|Kartenebenen sind AUS|| BBARSTA011|Automatische Antwort AUS!|| BBARSTA012|Datei beendet..|| BBARSTA013|ffne GPS Port|| BBARSTA014|Schliee GPS Port|| BBARSTA015|GPS RMC String empfangen|| BBARSTA016|GPS GGA String empfangen|| BBARSTA017|Netz vom Host getrennt|| BBARSTA018|Timeout beim Verbindungsaufbau!|| BBARSTA019|Suche Host %s|| BBARSTA020|Verbunden mit %s|| BBARSTA021|Netzverbindung fehlgeschlagen!|| BBARSTA022|Konnte keinen Socket erstellen!|| BBARSTA023|Keine IP fr Host!|| BBARSTA024|Kein Host angegeben|| BBARSTA025|Host gefunden, verbinde %d|| BBARSTA026|Warte auf GPS Daten via HSP..|| BBARSTA027|Setze HSP auf TNC Daten..|| BBARSTA028|Laden von %s|| BBARSTA029|ffne WX Port|| BBARSTA030|Schliee WX Port|| BBARSTA031|Prfe Hostname %d|| BBARSTA032|Dekodiere Wetterdaten|| BBARSTA033|Echo vom Digipeater|| BBARSTA034|Lade Wetterwarnungs-Karten|| BBARSTA035|Warte auf GPS Daten via AUX..|| BBARSTA036|Setze AUX auf TNC Daten..|| BBARSTA037|Dekodiere GPS Daten|| BBARSTA038|eigene Position gendert|| BBARSTA039|Indizieren %s|| BBARSTA040|APRS(tm) Station %s|| BBARSTA041|Warten auf GPS Daten..|| BBARSTA042|Senden von Objekten|| BBARSTA043|Protokoll|| BBARSTA044|ALOHA Entfernung betrgt %d%s|| BBARSTA045|Lade Symbole...|| BBARSTA046|Lade Symbole neu...|| BBARSTA047|Initialisiere meine Station...|| BBARSTA048|Starte Schnittstellen...|| BBARSTA049|Lesen der Kacheln...|| BBARSTA050|Laden der Kacheln...|| BBARSTA051|Laden Kachel %li von %li|| # # PopUp "Zeige - Packet Radio" WPUPDPD001|Packet Radio Daten|| WPUPDPD002|Nur TNC Daten|| WPUPDPD003|Nur Internet Daten|| WPUPDPD004|TNC und Internet Daten|| WPUPDPD005|TNC|| WPUPDPD006|NET|| WPUPDPD007|Stations-Resourcen|| WPUPDPD008|Nur meine|| # # PopUp "Station - Station finden" WPUPLSP001|Finde Station|| WPUPLSP002|Rufzeichen|| WPUPLSP003|Gro/Klein||# ??? WPUPLSP004|Exakt||# ??? WPUPLSP005|Finde jetzt!|| WPUPLSP006|Notfall-Suche!|| WPUPLSP007|FCC/RAC Suche|| # # PopUp "Einstellungen - Grundeinstellungen" WPUPCFD001|Grundeinstellungen|| WPUPCFD002|Nach welcher Zeit gilt eine Station als alt?|| WPUPCFD003|15 Minuten|| WPUPCFD004|30 Minuten|| WPUPCFD005|45 Minuten|| WPUPCFD006|1 Stunde|| WPUPCFD007|90 Minuten|| WPUPCFD008|2 Stunden|| WPUPCFD009|Nach welcher Zeit wird eine Station nicht mehr angezeigt?|| WPUPCFD010|6 Stunden|| WPUPCFD011|12 Stunden|| WPUPCFD012|1 Tag|| WPUPCFD013|2 Tage|| WPUPCFD014|1 Woche|| WPUPCFD015|Sendeformat der Station|| WPUPCFD016|Feste Station|| WPUPCFD017|Mobile Station mit lokaler Zeit|| WPUPCFD018|Mobile Station mit UTC Tag/Zeit|| WPUPCFD019|Mobile Station mit UTC Zeit/Sekunden|| WPUPCFD021|Station mit Position und Wetter|| WPUPCFD022|Station mit UTC Zeit, Position und Wetter|| WPUPCFD023|Sende Wetter Rohdaten?|| WPUPCFD024|Komprimiertes Format beim Senden von Objekten?|| WPUPCFD025|Alternatives Netz?|| WPUPCFD026|Sende Positionsmeldung in folgenden Intervallen|| WPUPCFD027|PopUp-Fenster fr neue Bekanntmachungen|| WPUPCFD028|Warnung bei Modifikationstasten|| WPUPCFD029|Anzeige bei Entfernung Null|| WPUPCFD030|Position Dubletten-Prfung aus|| WPUPCFD031|Vordefinierte Objekte aus Datei laden|| WPUPCFD032|Meine Spuren in einer Farbe|| WPUPCFD033|ALTNET:|| # # PopUp "Zeitverhalten" WPUPCFTM01|Einstellung des Zeitverhaltens||| WPUPCFTM02|SendeIntervall Position [Min]|| WPUPCFTM03|Station schemenhaft nach [Min]|| WPUPCFTM04|Max SendeIntervall Objekt [Min]|| WPUPCFTM05|Alte Station anzeigen fr [Std]|| WPUPCFTM06|GPS Abfrage alle [Sek]|| WPUPCFTM07|Station lschen nach [Tage]|| WPUPCFTM08|Timeout Pos-Voraussage [Min]|| WPUPCFTM09|Abstand zw. seriellen Zeichen (ms)|| WPUPCFTM10|Neue Spur Zeit (Min)|| WPUPCFTM11|Neue Spur Intervall (Grad)|| WPUPCFTM12|RINO -> Objekt Intervall (min), 0 = Aus|| WPUPCFTM13|Schnapschu-Intervall (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Koordinatensystem" WPUPCFC001|Koordinatensystem|| WPUPCFC002|Koordinatensystem whlen|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM mit Spezialzonen|| # # PopUp "GPS Einstellungen" WPUPCFG001|GPS Einstellungen|| WPUPCFG003|GPS Port|| WPUPCFG002|GPS Position benutzen?|| WPUPCFG004|GPS Optionen|| WPUPCFG005|Eigenstndiger GPS|| WPUPCFG006|TNC mit GPS verbunden (HSP Kabel)|| WPUPCFG007|TNC mit GPS verbunden ber Ctrl-E|| WPUPCFG008|GPS-Abfrage alle|| WPUPCFG009|5 Sek|| WPUPCFG010|15 Sek|| WPUPCFG011|30 Sek|| WPUPCFG012|1 Minute|| WPUPCFG013|2 Minuten|| WPUPCFG014|5 Minuten|| WPUPCFG015|10 Minuten|| WPUPCFG016|GPS ber Netzwerk verbunden|| WPUPCFG017|gpsd Host|| WPUPCFG018|gpsd Port|| WPUPCFG019|GPS ber Netz via gpsd|| WPUPCFG020|Wiederverbinden nach Fehler?|| WPUPCFG021|Wetter ber Netzwerk|| WPUPCFG022|Wetterstation Host|| WPUPCFG023|Wetterstation Port|| # # TNC Einstellungen WPUPCFT001|TNC Einstellungen|| WPUPCFT002|TNC benutzen?|| WPUPCFT003|TNC Port|| WPUPCFT004|Port Geschwindigkeit|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|UnProto Pfade|| WPUPCFT012|Pfad 1: %s via || WPUPCFT013|Pfad 2: %s via || WPUPCFT014|Pfad 3: %s via || WPUPCFT015|Port Datenbits|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Einstellungen fr TNC mit GPS ber HSP-Kabel|| WPUPCFT024|Datenart|| WPUPCFT025|Automatisch|| WPUPCFT026|Binr|| WPUPCFT027|ASCII|| WPUPCFT028|Einstellungen fr TNC mit GPS ber AUX-Kabel|| WPUPCFT029|Einstellungen fr TNC mit GPS ber INVALID ENUM: %d|| WPUPCFT030|KISS TNC konfigurieren|| WPUPCFT031|TNC Konfigurationsdateien|| WPUPCFT032|Datei fr TNC-Setup|| WPUPCFT033|Datei fr TNC-Shutdown|| WPUPCFT034|KISS Parameter|| WPUPCFT035|TXDelay (in 10 ms Einheiten)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (in 10 ms Einheiten)|| WPUPCFT038|TxTail (in 10 ms Einheiten)|| WPUPCFT039|Voll-Duplex|| WPUPCFT040|Multi-Port KISS TNC konfigurieren|| WPUPCFT041|Funkgert Port|| WPUPCFT042|Unklarer UNPROTO Pfad!|| WPUPCFT043|Bitte kuerzeren Pfad eingeben, z.B. WIDE2-2 oder RELAY,WIDE2-2|| WPUPCFT044|Unklarer IGATE Pfad!|| WPUPCFT045|Senden eines unklaren/fehlerhaften UNPROTO-Pfades!|| WPUPCFT046|Senden eines unklaren/fehlerhaften IGATE-Pfades!|| WPUPCFT047|KISS-Modus beim Start aktivieren|| # # PopUp "Einstellungen Wetterstation" WPUPCFWX01|Einstellungen Wetterstation|| WPUPCFWX02|Device fr Wetterstation|| WPUPCFWX03|Regenmesser-Korrektur (globale Einstellung)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|keine Korrektur|| # # PopUp "Einstellungen - Stationsdaten" WPUPCFS001|Stationsdaten|| WPUPCFS002|Rufzeichen|| WPUPCFS003|Breite|| WPUPCFS004|Grad|| WPUPCFS005|Min|| WPUPCFS006|(N/S)|| WPUPCFS007|Lnge|| WPUPCFS008|(E/W)|| WPUPCFS009|Stations-Symbol|| WPUPCFS010|Gruppe/Overlay|| WPUPCFS011|Symbol|| WPUPCFS028|Auswahl|| WPUPCFS012|Leistung - Hhe - Gewinn - Richtung|| WPUPCFS013|Kein PHG|| WPUPCFS014|Antennen Hhe|| WPUPCFS015|Antennen Gewinn|| WPUPCFS016|Rundstrahler|| WPUPCFS017|Kommentar:|| WPUPCFS018|Positionsverschleierung|| WPUPCFS019|Keine|| WPUPCFS020|.11 Meilen Kreis|| WPUPCFS021|1.15 Meilen Kreis|| WPUPCFS022|11.51 Meilen Kreis|| WPUPCFS023|69.09 Meilen Kreis|| WPUPCFS024|.18 Kilometer Kreis|| WPUPCFS025|1.85 Kilometer Kreis|| WPUPCFS026|18.53 Kilometer Kreis|| WPUPCFS027|111.19 Kilometer Kreis|| WPUPCFS029|Position in komprimiertem Format senden|k| # # PopUp "Objekt/Item" POPUPOB001|Objekt/Item|| POPUPOB002|Name|| POPUPOB003|Objekt setzen|| POPUPOB004|Objekt lschen|| POPUPOB005|Objekt ndern|| POPUPOB006|Item setzen|| POPUPOB007|Flchenobjekt|| POPUPOB008|als Flchenobjekt|| POPUPOB009|Helle Farben|| POPUPOB010|Flchen fllen|| POPUPOB011|Kreis|| POPUPOB012|Linie-Rechts '/'|| POPUPOB013|Linie-Links '\'|| POPUPOB014|Dreieck|| POPUPOB015|Rechteck|| POPUPOB016|Schwarz|| POPUPOB017|Blau|| POPUPOB018|Grn|| POPUPOB019|Cyan|| POPUPOB020|Rot|| POPUPOB021|Violett|| POPUPOB022|Gelb|| POPUPOB023|Grau|| POPUPOB024|nach oben:|| POPUPOB025|nach links (auer '/'):|| POPUPOB026|Korridor:|| POPUPOB027|Allgemeine Optionen|| POPUPOB028|Position|| POPUPOB029|als Signpost-Objekt|| POPUPOB030|Signpost-Text|| POPUPOB031|Signpost Objekt|| POPUPOB032|Komprimierung einschalten|| POPUPOB033|Item lschen|| POPUPOB034|Item ndern|| POPUPOB035|Hhe [ft]:|| POPUPOB036|Geschwindigkeit [Knoten]:|| POPUPOB037|Kurs:|| POPUPOB038|als Peil-Objekt|| POPUPOB039|Leistung - Hhe - Gewinn - Richtung|| POPUPOB040|ffnungswinkel - Richtung|| POPUPOB041|Rundstrahlantenne|| POPUPOB042|Richtantenne|| POPUPOB043|unbekannt|| POPUPOB044|Objekt bernehmen|| POPUPOB045|Item bernehmen|| POPUPOB046|DF Peilung:|| POPUPOB047|Wahrscheinlichkeitskreise|| POPUPOB048|Map View Objekt|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # PopUp "Internet Einstellungen" WPUPCFI001|Internet Einstellungen|| WPUPCFI002|Host || WPUPCFI003|Port || WPUPCFI004|(Weitere Hosts)|| WPUPCFI005|Host1|| WPUPCFI006|Port1|| WPUPCFI007|Host2|| WPUPCFI008|Port2|| WPUPCFI009|Zugangs-Code|| WPUPCFI010|(freilassen falls keiner)|| WPUPCFI011|Wiederverbinden bei NET Fehler?|| WPUPCFI012|Als I-Gate verwenden?|| WPUPCFI013|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFI014|I-Gate Transaktionen protokollieren?||| WPUPCFI015|Filter-Parameter|| # # PopUp "Datenbank Einstellungen" WPUPCFID01|Datenbank Einstellungen (TBD)|| WPUPCFID02|Host || WPUPCFID03|Port || WPUPCFID04|(Weitere Hosts)|| WPUPCFID05|Host1|| WPUPCFID06|Port1|| WPUPCFID07|Host2|| WPUPCFID08|Port2|| WPUPCFID09|Zugangs-Code|| WPUPCFID10|(Freilassen falls keines)|| WPUPCFID11|Wiederverbinden bei NET Fehler?|| WPUPCFID12|Als I-Gate verwenden?|| WPUPCFID13|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFID14|I-Gate Transaktionen protokollieren?||| WPUPCFID15|Filter-Parameter|| # # PopUp "Configure AGWPE" WPUPCFIA01|AGWPE konfigurieren|| WPUPCFIA02|Host || WPUPCFIA03|Port || WPUPCFIA04|(Weitere Hosts)|| WPUPCFIA05|Host1|| WPUPCFIA06|Port1|| WPUPCFIA07|Host2|| WPUPCFIA08|Port2|| WPUPCFIA09|Zugangs-Code|| WPUPCFIA10|Freilassen falls keines)|| WPUPCFIA11|Wiederverbinden bei NET Fehler?|| WPUPCFIA12|Als I-Gate verwenden?|| WPUPCFIA13|Nachrichten aus Internet via TNC aussenden wenn I-Gate?|| WPUPCFIA14|I-Gate Transaktionen protokollieren?||| WPUPCFIA15|FunkPort Senden|| # # PopUp "Einstellungen fr Audio Alarm" WPUPCFA001|Einstellungen fr Audio Alarm|| WPUPCFA002|Audio Abspielkommando|| WPUPCFA003|Alarm an|| WPUPCFA004|abzuspielende Audio Datei|| WPUPCFA005|Neue Station|| WPUPCFA006|Neue Nachricht|| WPUPCFA007|Annherung|| WPUPCFA008|Bandffnung|| WPUPCFA009|Minimum Entfernung|| WPUPCFA010|Maximum Entfernung|| WPUPCFA011|Wetter Warnung|| # # PopUp "Sprachausgabe" WPUPCFSP01|Sprachausgabe|| WPUPCFSP02|Sprachausgabe bei:|| WPUPCFSP03|Neuer Station|| WPUPCFSP04|Neuer Nachricht|| WPUPCFSP05|Neuer Text in Nachricht|| WPUPCFSP06|Annherungswarnung|| WPUPCFSP07|Bandffnung|| WPUPCFSP08|Neuer Wetterwarnung|| WPUPCFSP09|Annherung verfolgter Station|| # # PopUp "Verfolge Station" WPUPTSP001|Verfolge Station|| WPUPTSP002|Rufzeichen|| WPUPTSP003|Gro/Klein|| WPUPTSP004|Exakt|| WPUPTSP005|Verfolge jetzt!|| WPUPTSP006|Verfolgung aufheben|| WPUPTSP007|Spur aus dem Internet|| WPUPTSP008|Rufzeichen|| WPUPTSP009|Start der Spur (vor ... Std)|| WPUPTSP010|Lnge der Spur (Std)|| # # PopUp "Nachrichten..." WPUPMSB001|Nachricht Fenster %d|| WPUPMSB002|Gruppennachricht Fenster %d|| WPUPMSB003|Stationsrufzeichen:|| WPUPMSB004|Gruppenrufzeichen:|| WPUPMSB005|Neues/Refresh Rufzeichen|| WPUPMSB006|Neue Gruppe|| WPUPMSB007|Lsche alte Nachrichten|| WPUPMSB008|Nachricht:|| WPUPMSB009|Sende jetzt!|| WPUPMSB010|Pfad:|| WPUPMSB011|Wartende Nachrichten zurcknehmen|| WPUPMSB012|Kick Timer|| WPUPMSB013|Seq|| WPUPMSB014|Typ|| WPUPMSB015|Rundmeldung|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*ABBRUCH*|| WPUPMSB018|*ZURCKGEWIESEN*|| WPUPMSB019|Pfad ndern|| WPUPMSB020|Standard-Pfad(e) benutzen|| WPUPMSB021|Direkt (kein Pfad)|| WPUPMSB022|Umgekehrter Pfad (Hinweis):|| # # PopUp "Automatische Antwort" WPUPARM001|Automatische Antwort ndern|| WPUPARM002|Antwort:|| # # PopUp "Hilfe Index" WPUPHPI001|Hilfe Index|| WPUPHPI002|Anzeigen|| # # PopUp "Stations-Info" WPUPSTI000|Objekt von: %s|| WPUPSTI001|Stations-Info|| WPUPSTI002|Sende Nachricht|| WPUPSTI003|Suche in FCC Datenbank|| WPUPSTI004|Suche in RAC Datenbank|| WPUPSTI005|Pakete empfangen: %d Zuletzt gehrt: || WPUPSTI006|Gehrt ber TNC auf Device %d, || WPUPSTI007|Gehrt || WPUPSTI008|zuletzt ber Lokal|| WPUPSTI009|zuletzt ber TNC auf Device %d|| WPUPSTI010|zuletzt ber Internet auf Device %d|| WPUPSTI011|zuletzt ber Datei|| WPUPSTI012|zuletzt ber Unbekannt|| WPUPSTI013|, und hat die Position gendert|| WPUPSTI014|Momentane Leistung/Gewinn:|| WPUPSTI016|Hhe: %.0f %s || WPUPSTI017|Kurs: %s || WPUPSTI018|Geschwindigkeit: %.1fkm/h|| WPUPSTI019|Geschwindigkeit: %.1fmph|| WPUPSTI020|%0.1f Meilen|| WPUPSTI021|%0.1f km|| WPUPSTI022|Entfernung von meiner Station %s, Richtung von meiner Station %s|| WPUPSTI023|Letzte Position: || WPUPSTI024|Wetter Daten %c:%s|| WPUPSTI025|Wind Richtung: %s Geschwindigkeit: %03d km/h|| WPUPSTI026|Wind Richtung: %s Geschwindigkeit: %s mph|| WPUPSTI027| Be: %03d km/h|| WPUPSTI028| Be: %s mph|| WPUPSTI029|Temperatur: %02.1fC || WPUPSTI030|Temperatur: %sF || WPUPSTI031|Feuchte: %s%% || WPUPSTI032|rel.Feuchte: %02.1fC || WPUPSTI033|Luftdruck: %s hPa|| WPUPSTI034|Schnee: %0.1f cm/24h|| WPUPSTI035|Schnee: %0.0f Inch/24h|| WPUPSTI036|Regen: || WPUPSTI037|%0.2f mm/h || WPUPSTI038|%0.2f Inch/h || WPUPSTI039|%0.2f mm/Tag || WPUPSTI040|%0.2f Inch/Tag || WPUPSTI041|%0.2f mm/seit 0:00|| WPUPSTI042|%0.2f Inch/seit 0:00|| WPUPSTI043|Datenpfad: %s|| WPUPSTI044|Kommentar %02d/%02d %02d:%02d : %s|| WPUPSTI045|Lsche Spur|| WPUPSTI046|Regen gesamt: || WPUPSTI047|%0.2f mm|| WPUPSTI048|%0.2f Inch|| WPUPSTI049|Trace Anfrage|| WPUPSTI050|Unbest. Nachrichten|| WPUPSTI051|Stationsanfrage|| WPUPSTI052|Stationsversion|| WPUPSTI053|Objekt/Item ndern|| WPUPSTI054|Spur speichern|| WPUPSTI055|Echo gehrt von:|| WPUPSTI056|Automatische Aktualisierung|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Peil-Richtung: %s|| WPUPSTI059|Status %02d/%02d %02d:%02d : %s|| WPUPSTI060|Brennstofftemp.: %02.1fC || WPUPSTI061|Brennstofftemp.: %sF || WPUPSTI062|Brennstofffeuchte: %s%% || WPUPSTI063|Baro: %0.2f in Hg|| WPUPSTI064|NWS Wetterwarnung holen|| WPUPSTI065|Taktisches Rufzeichen: %s|| WPUPSTI066|Taktischen Rufzeichen zuweisen|| WPUPSTI067|Aktuelle Reichweite: %d Meilen|| WPUPSTI068|keine|| WPUPSTI069|Standard|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|Reichweite|| WPUPSTI073|PHG fehlerhaft|| WPUPSTI074|SHG fehlerhaft|| WPUPSTI075|DF Bereich|| WPUPSTI076|Kein Signal erkannt|| WPUPSTI077|mgliches Signal|| WPUPSTI078|Signal erkannt, nicht lesbar|| WPUPSTI079|Schwaches Signal, schlecht lesbar|| WPUPSTI080|Verrauschtes Signal aber lesbar|| WPUPSTI081|Signal lesbar, etwas Rauschen|| WPUPSTI082|Gutes Signal mit Restrauschen|| WPUPSTI083|Sehr gutes Signal|| WPUPSTI084|Hervorragendes Signal|| WPUPSTI085|Auerordentlich starkes Signal|| WPUPSTI086|SCHLECHTE PEILUNG|| WPUPSTI087|NRQ fehlerhaft|| WPUPSTI088|DF ffnungswinkel|| WPUPSTI089|DF Lnge|| WPUPSTI090|ungltig|| WPUPSTI091|Wegfarbe ndern|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA Radius: %d %s|| WPUPALO002|Stationen innerhalb des ALOHA Kreises: %d|| WPUPALO003| Digis : %d|| WPUPALO004| Mobilstationen (in Bew.) : %d|| WPUPALO005| Mobilstationen (sonstige): %d|| WPUPALO006| Wetterstationen : %d|| WPUPALO007| Feststationen : %d|| WPUPALO008|zuletzt berechnet vor %d %s %d %s.|| WPUPALO666|ALOHA Radius noch nicht berechnet|| # # FCC-RAC Call Look up STIFCC0001|FCC Datenbank Abfrage|| STIFCC0002|RAC Datenbank Abfrage|| STIFCC0003|Name:|| STIFCC0004|Strae:|| STIFCC0005|Stadt:|| STIFCC0006|Staat:|| STIFCC0007|PLZ:|| STIFCC0008|Grundeinstellung || STIFCC0009|Erweitert || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC Call Look up STIFCC0100|FCC-Index zu alt, erstelle neu...|| STIFCC0101|Rufzeichensuche|| STIFCC0102|Rufzeichen nicht gefunden!|| STIFCC0103|RAC-Index zu alt, erstelle neu...|| # # # Band open message UMBNDO0001|in Entfernung von|| # # # Allgemeine Optionen UNIOP00001|Ok|| UNIOP00002|Abbrechen|| UNIOP00003|Schlieen|| UNIOP00004|Meilen|| UNIOP00005|km|| UNIOP00006|Geraet|| UNIOP00007|Hinzufgen|| UNIOP00008|Lschen|| UNIOP00009|Eigenschaften|| UNIOP00010|Senden erlaubt?|| UNIOP00011|Beim Start aktivieren?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|Inch|| UNIOP00018|mm/Tag|| UNIOP00019|Inch/Tag|| UNIOP00020|mm/h|| UNIOP00021|Inch/h|| UNIOP00022|mm ab 0:00|| UNIOP00023|Inch ab 0:00|| UNIOP00024||| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|Inch Hg|| UNIOP00028|mm Hg|| UNIOP00029|Systemzeit durch GPS einstellen|| UNIOP00030|Digipeater?|| UNIOP00031|m|| UNIOP00032|Anwenden||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|Tag|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # popUp "Stationsauswahl" STCHO00001|Stationsauswahl|| # # "Zeige - Wetterwarnungen" WPUPWXA001|Wetterwarnung|| WPUPWXA002|Liste der Wetterwarnungen|| # # PopUp "Einstellungen - Schnittstellen" WPUPCIF001|Installierte Schnittstellen|| WPUPCIF002|Whle Schnittstellentyp|| # # PopUp "Einstellungen AX.25 TNC" WPUPCAX001|Einstellungen AX.25 TNC|| WPUPCAX002|AX.25 Gertename|| # # Interface device names IFDNL00000|Kein|| IFDNL00001|Serieller TNC|| IFDNL00002|Serieller TNC + GPS mit HSP-Kabel|| IFDNL00003|Serieller GPS|| IFDNL00004|Serielle Wetterstation|| IFDNL00005|Internet Server|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS ber Netzwerk (via gpsd)|| IFDNL00008|Wetter ber Netzwerk|| IFDNL00009|Serieller TNC + GPS mit AUX-Kabel|| IFDNL00010|Serieller KISS TNC|| IFDNL00011|Datenbank ber Netz (Noch nicht implementiert)|| IFDNL00012|AGWPE ber Netz|| IFDNL00013|Serieller Multi-Port KISS TNC|| IFDNL00014|SQL Datenbank (experimentell)|| # # Interface device info IFDIN00000|%s %2d %s an ser. Schnittstelle %s %s|| IFDIN00001|%s %2d %s verbunden mit %s:%d %s|| IFDIN00002|%s %2d %s ber Geraet namens %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| INAKTIV || IFDIN00007| AKTIV || IFDIN00008| FEHLER || IFDIN00009| UNBEKANNT || # # PopUp "Schnittstellen-Steuerung" IFPUPCT000|Schnittstellen-Steuerung|| IFPUPCT001|Start|| IFPUPCT002|Stop|| IFPUPCT003|Alle starten|| IFPUPCT004|Alle stoppen|| # # Internet Gateway Steuerung IGPUPCF000|Internet Gateway|| IGPUPCF001|Alle Weiterleitungen verhindern|| IGPUPCF002|Weiterleitung NUR von HF nach Internet|| IGPUPCF003|Weiterleitung HF->Internet UND Internet->HF|| IGPUPCF004|Igate -> HF Pfad || # # Wetterstation WXPUPSI000|Wetterstation|| WXPUPSI001|Wetterstation Typ|| WXPUPSI002|Aktuelle Werte|| WXPUPSI003|Windrichtung|| WXPUPSI004|Windgeschwindigkeit|| WXPUPSI005|Wind Ben|| WXPUPSI006|Temperatur|| WXPUPSI007|Regenmenge|| WXPUPSI008|Regenmenge heute|| WXPUPSI009|Druck| WXPUPSI010|Luftfeuchtigkeit|| WXPUPSI011|Peet Bros ULTIMETER 2000 Type (Data Logging Mode)|| WXPUPSI012|Peet Bros ULTIMETER II Type|| WXPUPSI013|Peet Bros ULTIMETER 2000 Type (Packet Mode)|| WXPUPSI014|Regenmenge aktuelle Std.|| WXPUPSI015|Regenmenge letze 24 Std.|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Taupunkt|| WXPUPSI019|Wind Spitze|| WXPUPSI020|Windauskuehlungsfaktor (Windchill)|| WXPUPSI021|Gefhlte Temp.|| WXPUPSI022|3 Std. Druck|| WXPUPSI023|Hchsttemp.|| WXPUPSI024|Tiefsttemp.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Stationslisten LHPUPNI000|Stationsliste|| LHPUPNI001|Mobile Stationen|| LHPUPNI002|Wetterstationen|| LHPUPNI003|Lokale Stationen (ber TNC)|| LHPUPNI004|Letzte Stationen|| LHPUPNI005|Objekte & Punkte|| LHPUPNI006|Eigene Objekte & Punkte|| LHPUPNI010|#|| LHPUPNI011|Rufzeichen|| LHPUPNI012|Pakete|| LHPUPNI013|Pos Zeit|| LHPUPNI014|Pfad|| LHPUPNI015|PHG|| LHPUPNI016|Kommentar|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|Hhe|| LHPUPNI103|Breite|| LHPUPNI104|Lnge|| LHPUPNI105|Pakete|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|Ben|| LHPUPNI203|Temp|| LHPUPNI204|Feucht|| LHPUPNI205|Druck|| LHPUPNI206|Rn-h|| LHPUPNI207|Rn-0|| LHPUPNI208|Rn24|| LHPUPNI209|Breite/Lnge oder UTM|| # # Stil der Wetterwarnungskarten PULDNMAT01|Zeige Warnungen ber Karten|| PULDNMAT02|Zeige Warnungen unter Karten|| # # Fehlermeldungen POPEM00001|Suchfehler!|| POPEM00002|Station %s wurde nicht gefunden!|| POPEM00003|Tracking Fehler!|| POPEM00004|Schnittstellenfehler!|| POPEM00005|Ungltiger AX.25 Port Name %s|| POPEM00006|Ungltiger AX.25 Port Name %s|| POPEM00007|Ungltiges Rufzeichen %s|| POPEM00008|AX.25 Ziel-Rufzeichen oder Digipeater ungltig|| POPEM00009|Kann AX.25-Socket nicht ffnen, %s|| POPEM00010|Kann AX.25-Socket nicht binden, %s|| POPEM00011|Kann AX.25-Rufzeichen nicht konnektieren, %s|| POPEM00012|AX.25-Fehler auf Ausgang des UI|| POPEM00013|AX.25-Problem mit axports Datei|| POPEM00014|AX.25 ungltiger Port-Name %s|| POPEM00015|Fehler beim ffnen des Interface %d Hard Fail|| POPEM00016|Fehler beim ffnen des Interface %d Time Out|| POPEM00017|Keine weiteren Schnittstellen verfgbar!|| POPEM00018|Datenanfrage - Single Message Line|| POPEM00019|Senden abgeschaltet bei Port %d|| POPEM00020|Datenbankfehler!|| POPEM00021|AX.25-Untersttzung nicht in Xastir kompiliert!|| POPEM00022|Eingabefehler!|| POPEM00023|Es wurde kein Name angegeben!|| POPEM00024|Der angegebene Name ist nicht mehr frei!|| POPEM00025|Nicht gefunden!|| POPEM00026|Verfolgung wird bei Erscheinen der Station aufgenommen|| POPEM00027|Falsche Eingabe. Einige Felder leer?|| POPEM00028|Kann Datei nicht ffnen|| POPEM00029|Gefunden!|| POPEM00030|Symbol fr Wetterstation|| POPEM00031|Gendert auf Wettersymbol '/_', auch mglich: '\_' '/W' und '\W'|| POPEM00032|Warnung: Symbol des National Weather Service wird benutzt!|| POPEM00033|Keine GPS Daten!|| POPEM00034|Position wird nicht gesendet bis gltige GPS-Daten!|| POPEM00035|Warnung|| POPEM00036|Hinweis|| POPEM00037|HSP Interface vorhanden: GPS-Abfrageintervalle grer|| POPEM00038|Der Name steht im Konflikt mit einem bereits existierenden Objekt, einer Markierung oder Station|| POPEM00039|Nicht zulssige Zeichen gefunden|| POPEM00040|Der nutzerspezifische Pfad ging verloren|| POPEM00041|Erstelle andere Datei. Bitte etwas warten und danach neu versuchen|| POPEM00042|Kein eigenes Objekt! Versuchen Sie erst das Obkekt zu bernehmen.|| POPEM00043|Kein Objekt/Item!|| POPEM00044|Findu-Wegdaten: fehlgeschlagen|| POPEM00045|Findu-Wegdaten: fertig|| POPEM00046|Berkeley DB header/shared library passen nicht! Map-Cache aus.|| POPEM00047|Senden ist global GESPERRT. Notfall-Baken werden NICHT gesendet!|| POPEM00048|Notfall-Baken-Modus!|| POPEM00049|NOTFALL-BAKEN-MODUS, senden alle 60 Sekunden!|| POPEM00050|Schnittstellen oder Positionen/Senden GESPERRT. Notfall-Baken werden NICHT gesendet!|| POPEM00051|Altnet ist aktiv (Menu Einstellungen->Grundeinstellungen)|| POPEM00052|Rufzeichen ist LEER!|| POPEM00053|Nachricht ist LEER!|| POPEM00054|Wir versuchen mit uns selbst zu reden!|| # # Karten - Ausschnitt JMLPO00001|Gespeicherte Kartenausschnitte|| JMLPO00002|Aktivieren!|A| JMLPO00003|Neuer Name:|| # # "Zeige - Bekanntmachungen" BULMW00001|Bekanntmachungen|| BULMW00002|Bereich einschrnken auf (0: unbegrenzt)|| BULMW00003|neuen Bereich setzen|| # # "Zeige - Nachrichten" AMTMW00001|Nachrichtenverkehr|| AMTMW00002|Bereich einschrnken auf (0: unbegrenzt)|| # # Texte fr Sprachsynthese SPCHSTR001|kilometer|| SPCHSTR002|meter|| SPCHSTR003|meilen|| SPCHSTR004|yards|| SPCHSTR005|%s, entfernung ist %d %s.|| SPCHSTR006|%s, entfernung ist %.1f %s.|| SPCHSTR007|%s, entfernung ist %d %s %s %s.|| SPCHSTR008|%s, entfernung ist %.1f %s %s %s.|| SPCHSTR009|neue wetterwarnung|| SPCHSTR010|neues rufzeichen|| SPCHSTR011|D X gehrt, %s, in einer entfernung von %.1f %s|| # SPCHDIRN00|nrdlich von|| SPCHDIRS00|sdlich von|| SPCHDIRE00|stlich von|| SPCHDIRW00|westlich von|| SPCHDIRNE0|nordstlich von|| SPCHDIRNW0|nordwestlich von|| SPCHDIRSE0|sdstlich von|| SPCHDIRSW0|sdwestlich von|| # # Symbolauswahl Dialog SYMSEL0001|Symbol-Auswahl|| SYMSEL0002|Primre Symbol-Tabelle|| SYMSEL0003|Sekundre Symbol-Tabelle|| # # Druckereinstellungen Dialog PRINT0001|Druck Eigenschaften|| PRINT0002|Papiergre|| PRINT0003|Automatisch drehen PRINT0004|90 im Gegenuhrzeigersinn drehen|| PRINT0005|Automatisch skalieren|| PRINT0006|Skalierung:|| PRINT0007|Standardhintergrund durch Wei ersetzen|| PRINT0008|Schwarz/Wei-Druck|| PRINT0016|Farben invertieren|| PRINT0009|Postscript Auflsung:|| PRINT0010|Vorschau|| PRINT0011|In Datei drucken|| PRINT0012|Gebe Bild auf Datei aus...|| PRINT0013|Konvertiere in Postscript...|| PRINT0014|Erstellen der Druckdatei beendet|| PRINT0015|Druckerstatus|| # # Druckereinstellungen Dialog PRINT1001|Direkt an:|| PRINT1002|ber Vorschau:|| # # Locate Feature Dialog FEATURE001|Name:|| FEATURE002|Bundesland/Provinz:|| FEATURE003|County:|| FEATURE004|Map Quad:|| FEATURE005|Typ:|| FEATURE006|GNIS-Datei:|| FEATURE007|Adresse:|| FEATURE008|Stadt:|| FEATURE009|Zielmarkierung:|| FEATURE010|PLZ:|| FEATURE011|Geocoding Datei|| # # Geocoding Dialog (Nominatim) GEOCODE001|Standort suchen|| GEOCODE002|Suchanfrage:|| GEOCODE003|Lnderfilter:|| GEOCODE004|Suchen|| GEOCODE005|Lschen|| GEOCODE006|Ergebnisse:|| GEOCODE007|Gehe zu|| GEOCODE008|Markieren|| GEOCODE009|Schlieen|| GEOCODE010|Suche luft...|| GEOCODE011|Keine Ergebnisse gefunden|| GEOCODE012|Fehler: %s|| GEOCODE013|%d Ergebnis(se) gefunden|| GEOCODE014|Daten (C) OpenStreetMap-Mitwirkende|| GEOCODE015|Keine (Weltweit)|| GEOCODE023|Dienst nicht verfgbar|| GEOCODE024|Geben Sie einen Ort zum Suchen ein|| GEOCODE025|Cache leeren|| GEOCODE026|Cache erfolgreich geleert|| GEOCODE027|Cache leeren fehlgeschlagen|| GEOCODE028|Nominatim-Server:|| GEOCODE029|Cache aktiviert:|| GEOCODE030|Cache-Ablauf (Tage):|| GEOCODE031|Benutzer-E-Mail:|| GEOCODE032|Standardland:|| GEOCODE033|Einstellungen|| GEOCODE034|Speichern|| GEOCODE035|Abbrechen|| GEOCODE036|Anwenden|| GEOCODE037|Geocoding-Einstellungen|| # # Geocoding Configuration Dialog GEOCFG001|Geocoding-Einstellungen|| GEOCFG002|Server-URL:|| GEOCFG003|E-Mail-Adresse:|| GEOCFG004|(Optional aber empfohlen)|| GEOCFG005|Standardland:|| # # Koordinatenrechner Dialog COORD001|Koordinatenumrechnung|| COORD002|Umrechnen|| COORD003|Umrechnen|| COORD004|Lschen|| COORD005|UTM|| COORD006|Breitengrad oder|| COORD007|Lngengrad oder|| COORD008|Zone|| COORD009|UTM stlich|| COORD010|UTM nrdlich|| COORD011| Dezimal Grad: || COORD012| Grad/Dezimal Minuten: || COORD013| Grad/Minuten/Dezimal Sekunden: || COORD014| Universal Transverse Mercator: || COORD015|Militrisches Koordinatensystem: || COORD016| Maidenhead Grid Locator: || COORD017| ** Ihre Eingabe war fehlerhaft ! **|| COORD018| ** Bitte nutzen Sie eines der folgenden Eingabeformate: **|| # # # Smart Beaconing Dialog SMARTB001|Smart Beaconing|| SMARTB002|Hohe Rate [Sek] || SMARTB003|Hohe Geschwindigkeit [mph] || SMARTB004|Hohe Geschwindigkeit [km/h] || SMARTB005|Niedrige Rate [Min] || SMARTB006|Niedrige Geschwindigkeit [mph] || SMARTB007|Niedrige Geschwindigkeit [km/h]|| SMARTB008|Kurvenschwellwert [Grad] || SMARTB009|Kurvenparameter (Turn Slope) || SMARTB010|Wartezeit [Sek] || SMARTB011|SmartBeaconing(tm) einschalten|| # # # # Gamma Adjust Dialog GAMMA001|Gammakorrektur einstellen|| GAMMA002|Gammakorrektur|| # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Winzig|| MAPFONT004|Map Font Klein|| MAPFONT005|Map Font Mittel|| MAPFONT006|Map Font Gro|| MAPFONT007|Map Font Riesig|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Entfernung/Richtung auf der Statuszeile PULDNDB001|Entf./Richtung in Status|| # # # GPS Transfer Operations GPS001|GPS-bertragung|| GPS002|Dateiname|| GPS003|Farbe whlen|| GPS004|Rot|| GPS005|Grn|| GPS006|Schwarz|| GPS007|Wei|| GPS008|Orange|| GPS009|Blau|| GPS010|Gelb|| GPS011|Violett|| # # # Karten-Eigenschaften Dialog MAPP001|Karten-Eigenschaften|| MAPP002|Max Min Karten gefllt USGS automat.|| MAPP003|Zoom Zoom Ebene zeichnen DRG Karte Pfad/Dateiname|| MAPP004|Ebene ndern->|| MAPP005|gefllt->|| MAPP006|Ja || MAPP007|Nein|| MAPP008|aut.Karte->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Zeit Texte TIME001|Tag|| TIME002|Tage|| TIME003|Stunde|| TIME004|Stunden|| TIME005|Minute|| TIME006|Minuten|| TIME007|Sekunde|| TIME008|Sekunden|| # # # Map Caching CACHE001|Karte im Cache gespeichert|| CACHE002|Lade Karte aus dem Cache|| CACHE003|Karte nicht im Cache gefunden...|| # # # Map Screen Misc RANGE001|ENTFERNUNGS-SKALIERUNG|| # # # GPS Status GPSS001|WAAS oder PPS|| GPSS002|DGPS|| GPSS003|gltig SPS|| GPSS004|ungltig|| GPSS005|Sats/Anzeige|| GPSS006|Fix|| GPSS007|!GPS-Daten sind lter als 30 Sekunden!|| GPSS008|Simulation|| GPSS009|Manuell|| GPSS010|Schtzung|| GPSS011|FRTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Flchenobjekt|| CADPUD002|Flchen-Label:|| CADPUD003|Kommentar:|| CADPUD004|Wahrscheinlichkeit (%):|| CADPUD005|OK|| CADPUD006|CAD-Dialog|| CADPUD007|Details zeigen/ndern|| CADPUD008|Abbrechen|| CADPUD009|CAD-Objekte lschen?|| CADPUD010|Alle lschen|| CADPUD011|Ausgewhlte lschen|| CADPUD012|durchgezogen|| CADPUD013|gestrichelt|| CADPUD014|doppelt gestrichelt|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Karte von %s (oben links) to %s (unten rechts). UTM %d m Gitter, %s Datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Karte von %s (oben links) to %s %s (unten rechts). Breite/Lnge Gitter, %s Datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Karte von %s (oben links) to %s (unten rechts). UTM Zonen, %s Datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/language-Italian.sys0000664000175000017500000012121115151324131020466 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Xastir Version : 1.0.0 # Creator : Alessandro Frigeri, IK0YUP # Maintained by : The Xastir Group # Last Modified : Tue 31 Aug 11:00:00 CEST 2004 by IK0YUP # # comment lines with pound signs in front are ignored # Il formato del file il seguente: # ID (10 caratteri alfanum)|(Stringa associata all'ID)|TastiDiSceltaRapida|#commento # WARNING: # Some strings contain formatting commands like %s and %d, you should not # change these. Wrong format strings could produce a segfault! # # # Men Principale MENUTB0001|Dati|D| MENUTB0002|Liste|L| MENUTB0004|Mappe|M| MENUTB0005|Visualizza|V| MENUTB0006|Messaggi|e| MENUTB0010|Interfacce|I| MENUTB0009|Guida|G| # # Men Dati PULDNFI001|Configura|C| PULDNFI002|Apri file di registro|A| PULDNFI003|Test|| PULDNFI004|Esci|x| PULDNFI007|Cambia il livello di Debug|D| PULDNFI010|Registro TNC|T| PULDNFI011|Registro Rete|e| PULDNFI012|Accesso al Gateway Internet|G| PULDNFI013|Registro dati meteo|G| PULDNFI014|Cattura schermo in PNG|| PULDNFI015|Stampa|P| PULDNFI016|KML Snapshots|| # # Men Visualizza PULDNVI001|Bollettini|B| PULDNVI002|Dati Packet in arrivo|P| PULDNVI003|Stazioni Mobili|M| PULDNVI004|Stazioni|S| PULDNVI009|Stazioni Locali|o| PULDNVI012|Ultime Stazioni|L| PULDNVI005|Stazioni Meteo|W| PULDNVI008|Stazioni Meteo|t| PULDNVI007|Allarmi Meteo|A| PULDNVI011|Traffico Messaggi|T| PULDNVI013|Tempo trascorso dall'avvio|d| PULDNVI014|Uptime del programma|| PULDNVI015|Stato GPS|| PULDNVI016|ALOHA Statistics|| # # Menu' di Configurazione PULDNCF004|Dati Stazione|S| PULDNCF001|Configurazioni originali|D| PULDNCF003|Temporizzazione|T| PULDNCF002|Sistema di Coordinate|C| PULDNCF006|Allarmi Audio|A| PULDNCF007|Annunci Vocali|p| PULDNCF008|Salva la Configurazione Ora!|C| # (per unit vedere PULDNDP006) # # Men Mappe PULDNMP001|Scegli mappa|C| PULDNMP012|Vai alla posizione...|J|#NUOVA funzione dalla v. 0.3.2 PULDNMP014|Localizza Elemento Mappa|E| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Disattiva tutte le mappe|D| PULDNMP002|Mappe automatiche|A| PULDNMP003|Reticolato|G| PULDNMP004|Livelli delle Mappe|L| PULDNMP010|Abilita etichette delle mappe|F| PULDNMP009|Colora le aree chiuse|F| PULDNMP007|Mappe Allarme Meteo|W| PULDNMP005|Colore dello sfondo della mappa|B| PULDNMP006|Etichette Stazione|S| PULDNMP026|Stile Bordo Icone|O| PULDNMP011|Men sul puntatore del mouse|M| PULDNMP008|Intensit Mappa|I| PULDNMP021|Mappe Automatche - Disabilita Mappe Raster|| PULDNMP022|Indicizza Mappe all' Avvio|| PULDNMP023|Indice: Aggiungi Nuove Mappe|N| PULDNMP024|Indice: Riordina Tutte le Mappe|R| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Cerca posizione|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| PULDNMP032|Impostazioni geocodifica|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # # Finestra di dialogo mappe WPUPMCP001|Scegli mappa|| PULDNMMC01|Cancella|N| PULDNMMC02|Vettoriali|V| PULDNMMC03|Topografiche 250k|2| PULDNMMC04|Topografiche 100k|1| PULDNMMC05|Topografiche 24k|4| PULDNMMC06|Espandi Cartella||| PULDNMMC07|Cartella/Mappa Selezionata:|| PULDNMMC08|Clear Dirs|C| PULDNMMC09|Select All|S| # # Men Colori dello sfondo delle mappe. PULDNMBC01|Grigio|| PULDNMBC02|Rosa|| PULDNMBC03|Blu mare|| PULDNMBC04|Blu acciaio|| PULDNMBC05|Verde acqua|| PULDNMBC06|Verde chiaro|| PULDNMBC07|Oro forte|| PULDNMBC08|Oro chiaro|| PULDNMBC09|Marrone|| PULDNMBC10|Rosso fuoco|| PULDNMBC11|Bianco|| PULDNMBC12|Nero|| # # Stili delle etichette delle stazioni PULDNMSL01|Bordo nero|| PULDNMSL02|Ombra nera e sfondo uniforme|| PULDNMSL03|Testo su sfondo nero|T| PULDNMSL04|DropShadow|| # # PullDown "Stile Bordo Icone" PULDNMIO01|Nessun Bordo|N| PULDNMIO02|Bordo Nero|B| PULDNMIO03|Bordo Grigio|G| PULDNMIO04|Bordo Bianco|W| # # ATTIVO/DISATTIVO PULDNOT001|Attiva|| PULDNOT002|Disattiva|| PULDNOT003|Breve|| # # Man Stazioni PULDNDP014|Localizza Stazione|L| PULDNDP001|Segui Stazione|T| PULDNDP022|Scarica il percorso da Findu|| PULDNDP032|Filtra Dati|| PULDNDP040|Seleziona Nessuno|| PULDNDP041|Seleziona Miei|| PULDNDP042|Seleziona TNC|| PULDNDP027|- Seleziona Diretta|| PULDNDP043|- Seleziona Via Digi|| PULDNDP034|Seleziona Rete|| PULDNDP019|Visualizza dati scaduti|| PULDNDP044|Seleziona Stazioni|| PULDNDP028|- Seleziona Stazioni Fisse|| PULDNDP029|- Seleziona Stazioni Mobili|| PULDNDP030|- Seleziona Stazioni Meteo|| PULDNDP053| - Seleziona stazioni Meteo CWOP|| PULDNDP045|- Seleziona Oggetti/Dettagli|| PULDNDP026|- Seleziona Oggetti/Dettagli Meteo|| PULDNDP039|- Seleziona Oggetti/Dettagli Misura Acqua|| PULDNDP031|- Seleziona Altri Oggetti/Dettagli|| PULDNDP057|- Selezionare i Vessel Oggetti/Articol|| PULDNDP058|- Select Aircraft Oggetti/Articoli|| PULDNDP033|Visualizza Filtro|| PULDNDP010|Nominativo|l| PULDNDP012|Simboli|Y| PULDNDP011|- Ruota Simboli|R| PULDNDP007|Percorsi delle stazioni|i| PULDNDP003|Direzione|C| PULDNDP004|Velocit|S| PULDNDP017|- Visualizza basse velocit|| PULDNDP002|Altitudine||A PULDNDP009|Informazioni Meteo|W| PULDNDP046|- Visualizza Testo Meteo|| PULDNDP018|-- Visualizza solo Temperatura|| PULDNDP047|- Visualizza Vento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Ambiguit di posizione| PULDNDP008|Potenza/Guadagno|P| PULDNDP021|- Potenza/Guadagno - default|| PULDNDP020|- Potenza/Guadagno - stazioni mobili|| PULDNDP023|Visualizza i cerchi DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Abilita Conteggio|| PULDNDP036|- Visualizza Arc|| PULDNDP037|- Visualizza Rotta|| PULDNDP038|- Visualizza Simbolo|| PULDNDP005|Distanza/Direzione|D| PULDNDP024|Visualizza Et Ultimo Rapporto|| PULDNDP015|Elimina tutte le stazioni|C| PULDNDP016|Elimina tutti i percorsi|T| PULDNDP025|Cancella Storico Oggetti/Dettagli|| PULDNDP048|Ricarica Storico Oggetti/Dettagli|| PULDNDP049|Cancella tutte le chiamate tattiche|| PULDNDP050|Cancella lo storico delle chiamate tattiche|| PULDNDP051|Seleziona solo chiamate tattiche|| PULDNDP052|- Etichetta i punti percorso|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Sistema di misura PULDNUT001|Sistema inglese|| PULDNUT002|Metrico|| # # Messaggi PULDNMG001|Invia messaggio a...|S| PULDNMG002|Apri gruppo di messaggi|g| PULDNMG003|Elimina tutti i messaggi in uscita|C| PULDQUS001|Cerca tutte le stazioni|e| PULDQUS002|Cerca le stazioni Gateway|I| PULDQUS003|Cerca le stazioni meteo|W| PULDNMG004|Imposta risposta automatica ai messaggi in arrivo|S| PULDNMG005|Risposta automatica ai messaggi in arrivo|R| PULDNMG006|Modalit Satellite Ack|M| PULDNMG007|Show Pending Messages|P| # # Menu "Interfaces" PULDNTNT04|Interface Control|| PULDNTNT03|Disabilita Trasmissioni: TUTTE|| PULDNTNT05|Disabilita Trasmissioni: Mia Posizione|| PULDNTNT06|Disabilita Trasmissioni: Oggetti/Entit|| PULDNTNT11|Abilita la porta del Server|| PULDNTNT01|Trasmetti Ora!|T| PULDNTNT07|Carica tracciato GPS|F| PULDNTNT08|Carica rotte GPS|R| PULDNTNT09|Carica punti GPS|W| PULDNTNT10|Ricevi Waypoints Garmin RINO|G| # # Men Aiuto PULDNHEL01|Versione di Xastir|A| PULDNHEL02|Indice Guida|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # #Mouse Menu Popup POPUPMA001|Opzioni|| POPUPMA00c|Centra la mappa|| POPUPMA015|Informazioni stazione|| POPUPMA002|Zoom avanti|| POPUPMA003|Zoom indietro|| POPUPMA004|Livello di Zoom|| POPUPMA005|Livello 1|| POPUPMA006|Livello 16|| POPUPMA007|Livello 64|| POPUPMA008|Livello 256|| POPUPMA009|Livello 1024|| POPUPMA010|Livello 8192|| POPUPMA017|Tutto il mondo|| POPUPMA016|Ultima posizione e zoom|| POPUPMA018|Oggetto/Entit->Crea|| POPUPMA019|Oggetto/Entit->Modifica|| POPUPMA025|Muovi La mia Stazione Qu|H| POPUPMA011|Sposta in alto|| POPUPMA012|Sposta in basso|| POPUPMA013|Sposta a sinistra|| POPUPMA014|Sposta a destra|| POPUPMA020|Misurazione distanze|D| POPUPMA021|Muovi|| POPUPMA022|RintracciaMi|| POPUPMA023|Trovato Blocco Tastiera!|| POPUPMA024|Per Favore disabilita Blocco Maiuscole/BlocNum/Scorrimento/|| POPUPMA026|Center & Zoom|| POPUPMA027| Latitudine|| POPUPMA028| Longitudine|| POPUPMA029|Disegna oggetti CAD|| POPUPMA030|Draw|| POPUPMA031|Chiudi il poligono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # #Etichette barra di stato BBARZM0001|Zoom %s|| BBARZM0002|Zoom %s Tr|| BBARSTH001|%d/%d Stazioni|| BBARSTA000|%-9s Nuovo Oggetto!|| BBARSTA001|Nuova statione! %-9s|| BBARSTA002|Nuovi dati da %-9s|| BBARSTA003|Caricamento mappe...|| BBARSTA004|Mappe caricate|| BBARSTA005|Reticolato Lat/Long Attivo|| BBARSTA006|Reticolato Lat/Long Non Attivo|| BBARSTA007|Caricamento automatico delle mappe attivo|| BBARSTA008|Caricamento automatico delle mappe non attivo|| BBARSTA009|Livello mappe automatico attivato|| BBARSTA010|Livello automatico mappe disattivato|| BBARSTA011|Risposta automatica ai messaggi in arrivo disattivata!|| BBARSTA012|File caricato..|| BBARSTA013|Attivazione porta GPS|| BBARSTA014|Disattivazione porta GPS|| BBARSTA015|Ricezione stringa RMC dal GPS|| BBARSTA016|Ricezione stringa GGA dal GPS|| BBARSTA017|Disconnessione dall'host in rete|| BBARSTA018|Connessione con l'host perduta (Time-out)!|| BBARSTA019|Sto cercando l'host %s|| BBARSTA020|Connesso a %s|| BBARSTA021|Connessione fallita!|| BBARSTA022|Non posso utilizzare la porta di rete!|| BBARSTA023|Risoluzione IP host fallita!|| BBARSTA024|Non stato specificato nessun host|| BBARSTA025|Host trovato, connessione a %d|| BBARSTA026|Sto attendendo dati dal GPS via HSP..|| BBARSTA027|Libero HSP, ricezione dati da TNC..|| BBARSTA028|Caricamento %s|| # BBARSTA029|Apertura porta meteo||# BBARSTA030|Chiusura porta meteo||# BBARSTA031|Ricerca di %d in corso||#KEEP the %d BBARSTA032|Dati meteo rilevati||# BBARSTA033|Eco da digipeater|| BBARSTA034|Caricamento Mappe Allerta Meteo|| BBARSTA035|Sto attendendo dati del GPS via AUX..|| BBARSTA036|Libero AUX, ricezione dati da TNC..|| BBARSTA037|Dati GPS rilevati|| BBARSTA038|Posizionare il cambiamento sulla mia stazione|| BBARSTA039|Indicizzazione %s|| BBARSTA040|Stazione APRS(tm) %s|| BBARSTA041|Attendo dati GPS..|| BBARSTA042|Transmetto oggetti/dettagli|| BBARSTA043|Registro|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # #Visualizzazione dati packet WPUPDPD001|Visualizzazione dati packet|| WPUPDPD002|Solo dati da TNC|| WPUPDPD003|Solo dati dalla Rete|| WPUPDPD004|Dati da TNC e Rete|| WPUPDPD005|TNC|| WPUPDPD006|RETE|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # #Menu' localizza stazione WPUPLSP001|Localizza Stazione|| WPUPLSP002|Localizza Nominativo|| WPUPLSP003|Non rispetta Maius/Minus|| WPUPLSP004|Rispetta Maius/minus || WPUPLSP005|Localizza!|| WPUPLSP006|Localizzazione di Emergenza!|| WPUPLSP007|Ricerca su FCC/RAC|| # # Configure defaults popup WPUPCFD001|Parametri originali|| WPUPCFD002|Dopo quanto tempo una stazione da considerarsi vecchia?|| WPUPCFD003|15 Minuti|| WPUPCFD004|30 Minuti|| WPUPCFD005|45 Minuti|| WPUPCFD006|1 Ora|| WPUPCFD007|90 Minuti|| WPUPCFD008|2 Ore|| WPUPCFD009|Dopo quanto tempo una stazione verr cancellata?|| WPUPCFD010|6 Ore|| WPUPCFD011|12 Ore|| WPUPCFD012|1 Giorno|| WPUPCFD013|2 Giorni|| WPUPCFD014|1 Settimana|| WPUPCFD015|Opzione trasmissione dati stazione|| WPUPCFD016|Stazione fissa|| WPUPCFD017|Stazione mobile con ora locale|| WPUPCFD018|Stazione mobile con ora e data UTC|| WPUPCFD019|Stazione mobile con ora UTC (con secondi)|| WPUPCFD021|Posizione della Stazione con dati meteo|| WPUPCFD022|Posizione stazione, Data e ora UTC, dati meteo|| WPUPCFD023|Devo trasmettere i dati Meteo?|| WPUPCFD024|Comprimo i dati oggetti/dettagli quando trasmetto?|| WPUPCFD025|Attivare rete alternativa?|A| WPUPCFD026|Intervallo per invio rapporti posizione|| WPUPCFD027|Apparizione nuovi bollettini|| WPUPCFD028|Avvisa per utilizzo tasti inadatti|| WPUPCFD029|Vedi bollettini a distanza zero|| WPUPCFD030|Disattiva Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configure - Timing" WPUPCFTM01|Configura Temporizzazioni|| WPUPCFTM02|Intervallo TX posizione (min)|| WPUPCFTM03|Tempo di Ghosting della stazione (min)|| WPUPCFTM04|Max Intervallo TX Oggetto/Entit (min)|| WPUPCFTM05|Clear Time della stazione (ore)|| WPUPCFTM06|Intervallo controllo GPS (sec)|| WPUPCFTM07|Tempo eliminazione stazione (giorni)|| WPUPCFTM08|Fuori tempo Ricalcolo Assoluto (min)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|Nuovo tempo della traccia (min)|| WPUPCFTM11|Nuovo intervallo della traccia (gradi)|| WPUPCFTM12|RINO -> Intervallo oggetto (min), 0 = Non attivo|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Configure Coordinate System" WPUPCFC001|Configura Sistema Coordinate|| WPUPCFC002|Seleziona Sistema Coordinate|| WPUPCFC003|gg.ggggg|d| WPUPCFC004|gg mm.mmm|m| WPUPCFC005|gg mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM con zone speciali|| # # Configurazione GPS WPUPCFG001|Configura GPS|| WPUPCFG003|GPS collegato ad una porta autonoma|| WPUPCFG002|Usare la posizione data dal GPS?|| WPUPCFG004|Opzioni GPS|| WPUPCFG005|GPS Autonomo|| WPUPCFG006|GPS Collegato al TNC(con cavo HSP)|| WPUPCFG007|GPS Collegato al TNC usando CTL-E|| WPUPCFG008|Ora dal GPS (Rileva ogni)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 Minuti|| WPUPCFG014|5 Minuti|| WPUPCFG015|10 Minuti|| WPUPCFG016|GPS collegato ad una rete (gpsd)|| WPUPCFG017|Host GPSD|| WPUPCFG018|Porta GPSD|| WPUPCFG019|GPS in rete con GPSD|| WPUPCFG020|Riconnetti in caso di errore?|| WPUPCFG021|Dati Meteo rilevati dalla rete|| WPUPCFG022|Host Meteo|| WPUPCFG023|Porta Meteo|| # #Configure TNC (baud/style are also for Meteo) WPUPCFT001|Configura TNC|| WPUPCFT002|Usare TNC?|| WPUPCFT003|porta TNC|| WPUPCFT004|Impostazioni porta|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Percorsi UnProto|| WPUPCFT012|Percorso 1: %s via || WPUPCFT013|Percorso 2: %s via || WPUPCFT014|Percorso 3: %s via || WPUPCFT015|Stile porta|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configura TNC con cavo HSP per GPS|| WPUPCFT024|Tipi di dati|| WPUPCFT025|Riconoscimento automatico|| WPUPCFT026|Dati binari|| WPUPCFT027|Dati ASCII|| WPUPCFT028|Configura TNC con cavo AUX per GPS|| WPUPCFT029|Configura TNC con INVALID ENUM: %d|| WPUPCFT030|Configura TNC KISS|| WPUPCFT031|File di configurazione del TNC|| WPUPCFT032|Nome File configurazione TNC|| WPUPCFT033|Nome File dello Shutdown TNC|| WPUPCFT034|Parametri KISS|| WPUPCFT035|Ritardo TX (unit di 10 ms)|| WPUPCFT036|Persistenza (0 to 255)|| WPUPCFT037|SlotTime (unit di 10 ms)|| WPUPCFT038|Coda Tx (unit di 10 ms)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configura TNC Multi-Port KISS|| WPUPCFT041|Porta Radio|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-Mode|| # #Configura Porta Meteo WPUPCFWX01|Configura Porta Meteo|| WPUPCFWX02|Periferica della stazione|| WPUPCFWX03|Correzione Portata pioggia (Settaggio Globale)|| WPUPCFWX04|.1 inch/2.5mm|| WPUPCFWX05|.01 inch/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Nessuna Correzione|| # #Configure Stazione WPUPCFS001|Configura Dati Stazione|| WPUPCFS002|Nominativo|| WPUPCFS003|LAT|| WPUPCFS004|grad|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|LONG|| WPUPCFS008|(E/W)|| WPUPCFS009|Simbolo della Stazione|| WPUPCFS010|Raggruppa/Sovrapponi|| WPUPCFS011|Simbolo|| WPUPCFS028|Seleziona|| WPUPCFS012|Potenza-guadagno|| WPUPCFS013|Disattiva PHG|| WPUPCFS014|Altezza antenna|| WPUPCFS015|Guadagno antenna|| WPUPCFS016|Omni|| WPUPCFS017|Commenti:|| WPUPCFS018|Ambiguit posizione|| WPUPCFS019|Nessuna|| WPUPCFS020|cerchio di.11 miglia|| WPUPCFS021|cerchio di1.15 miglia|| WPUPCFS022|cerchio di11.51 miglia|| WPUPCFS023|cerchio di69.09 miglia|| WPUPCFS024|cerchio di.18 chilometri|| WPUPCFS025|cerchio di1.85 chilometri|| WPUPCFS026|cerchio di18.53 chilometri|| WPUPCFS027|cerchio di 111.19 chilometri|| WPUPCFS029|Invia posizioni compresse|C| # # PopUp "Oggetto/Entit" POPUPOB001|Oggetto/Entit|| POPUPOB002|Nome|| POPUPOB003|Imposta Oggetto|| POPUPOB004|Elimina Oggetto|| POPUPOB005|Modifica Oggetto|| POPUPOB006|Crea Nuova Entit|| POPUPOB007|Oggetto Area|| POPUPOB008|Abilita Oggetto Area|| POPUPOB009|Colore Brillante|| POPUPOB010|Riempimento|| POPUPOB011|Cerchio|| POPUPOB012|Linea a destra '/'|| POPUPOB013|Linea a sinistra '\'|| POPUPOB014|Triangolo|| POPUPOB015|Rettangolo|| POPUPOB016|Nero|| POPUPOB017|Blu|| POPUPOB018|Verde|| POPUPOB019|Azzurro|| POPUPOB020|Rosso|| POPUPOB021|Viola|| POPUPOB022|Giallo|| POPUPOB023|Grigio|| POPUPOB024|Spostamento lungo lat.:|| POPUPOB025|Spostamento lungo long.:|| POPUPOB026|Corridoio:|| POPUPOB027|Opzioni Generiche|| POPUPOB028|Posizione|| POPUPOB029|Abilita simbolo postazione|| POPUPOB030|Dati:|| POPUPOB031|Simbolo postazione|| POPUPOB032|Abilita compressione|| POPUPOB033|Elimina Entit|| POPUPOB034|Modifica Entit|| POPUPOB035|Altitudine (piedi):|| POPUPOB036|Velocit (nodi):|| POPUPOB037|Direzione:|| POPUPOB038|Oggetto DF|| POPUPOB039|Segnale - Altezza(HAAT) - Guadagno - Direttivit|| POPUPOB040|Larghezza fascio - Puntamento|| POPUPOB041|Antenna Omni|| POPUPOB042|Antenna Direzionale|| POPUPOB043|Sconosciuta|| POPUPOB044|Adotta l'Oggetto|| POPUPOB045|Adotte l'Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # #Configure Internet WPUPCFI001|Configura Rete|| WPUPCFI002|Host || WPUPCFI003|Porta || WPUPCFI004|(host secondari)|| WPUPCFI005|Host1|| WPUPCFI006|Porta 1|| WPUPCFI007|Host2|| WPUPCFI008|Porta 2|| WPUPCFI009|codice|| WPUPCFI010|(Lascia vuoto se non necessario)|| WPUPCFI011|Riconnettersi in caso di sconnessione?|| WPUPCFI012|Funzionare da Gateway?|| WPUPCFI013|Trasmetto i dati al TNC quando sono collegato ad Internet?|| WPUPCFI014|Scrivo nel log le trasmissioni dalla Rete al TNC?||| WPUPCFI015|Parametri Filtro|| # #Configure Database WPUPCFID01|Configura Database (TBD)|| WPUPCFID02|Host || WPUPCFID03|Porta || WPUPCFID04|(host secondari)|| WPUPCFID05|Host1|| WPUPCFID06|Porta 1|| WPUPCFID07|Host2|| WPUPCFID08|Porta 2|| WPUPCFID09|codice|| WPUPCFID10|(Lascia vuoto se non necessario)|| WPUPCFID11|Riconnettersi in caso di sconnessione?|| WPUPCFID12|Funzionare da Gateway?|| WPUPCFID13|Trasmetto i dati al TNC quando sono collegato ad Internet?|| WPUPCFID14|Scrivo nel log le trasmissioni dalla Rete al TNC?||| WPUPCFID15|Parametri Filtro|| # # PopUp "Configure AGWPE" WPUPCFIA01|Configura AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Porta || WPUPCFIA04|(Host secondari)|| WPUPCFIA05|Host1|| WPUPCFIA06|Porta1|| WPUPCFIA07|Host2|| WPUPCFIA08|Porta2|| WPUPCFIA09|Codice segreto|| WPUPCFIA10|((Lascia in Bianco se Nessuno)|| WPUPCFIA11|Riconnetti su errore NET?|| WPUPCFIA12|Opera come I-Gate?|| WPUPCFIA13|Manda messaggi Broadcast via TNC durante operazione I-Gate?|| WPUPCFIA14|Registra su Log I-Gate Transactions?|| WPUPCFIA15|Porta radio di trasmissione|| # #Configure Audio Alarms WPUPCFA001|Configura Suoni|| WPUPCFA002|Comando esecuzione audio|| WPUPCFA003|Allarme attivo|| WPUPCFA004|File audio da eseguire|| WPUPCFA005|Nuova stazione|| WPUPCFA006|Nuovo messaggio|| WPUPCFA007|Vicinanza|| WPUPCFA008|Apertura banda|| WPUPCFA009|Distanza minima|| WPUPCFA010|Distanza massima|| WPUPCFA011|Allarme meteo|| # # PopUp "Configure Speech" WPUPCFSP01|Configura Annuncio|| WPUPCFSP02|Annuncio su:|| WPUPCFSP03|Nuova stazione|| WPUPCFSP04|Nuovo Messaggio|| WPUPCFSP05|Nuovo corpo del messaggio|| WPUPCFSP06|Allarme di vicinanza|| WPUPCFSP07|Apertura di banda|| WPUPCFSP08|Allarme Meteo|| WPUPCFSP09|Avviso Prossimit Stazione Tracciata|| # # Track Stazione WPUPTSP001|Segui Stazione|| WPUPTSP002|Segui Nominativo|| WPUPTSP003|Corrispondenza a caso|| WPUPTSP004|Corrispondenza Esatta|| WPUPTSP005|Segui ora!|| WPUPTSP006|Annulla operazione|| WPUPTSP007|Scarica tracciato|| WPUPTSP008|Nominativo|| WPUPTSP009|Percorso iniziato (ore fa)|| WPUPTSP010|Durata percorso (ore)|| # #Messages WPUPMSB001|Casella messaggi %d|| WPUPMSB002|Casella messaggi a gruppo %d|| WPUPMSB003|Nominativi stazioni:|| WPUPMSB004|Nominativo gruppo:|| WPUPMSB005|Nuovo/Refresh nominativo|| WPUPMSB006|Nuovo gruppo|| WPUPMSB007|Cancella storico Msg|| WPUPMSB008|Messaggio:|| WPUPMSB009|Invia ora!|| WPUPMSB010|Percorso:|| WPUPMSB011|Cancella Msg in attesa|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # #Auto Reply WPUPARM001|Cambia risposta automatica|| WPUPARM002|Risposta:|| # #Help Index WPUPHPI001|Indice guida|| WPUPHPI002|Visualizza|| # #Stazione Info popup WPUPSTI000|Oggetto Inserito da: %s|| WPUPSTI001|Informazioni stazione|| WPUPSTI002|Invia messaggio|| WPUPSTI003|Cerca nel Database FCC|| WPUPSTI004|Cerca nel Database RFC|| WPUPSTI005|Pacchetti recevuti: %d Ultima stazione ascoltata: || WPUPSTI006|Ascoltata dal TNC sulla periferica %d, || WPUPSTI007|Ascoltata || WPUPSTI008|Ascoltata l'ultima volta in locale|| WPUPSTI009|Ascoltata l'ultima volta dal TNC, periferica %d|| WPUPSTI010|Ascoltata l'ultima volta da Internet sulla periferica %d|| WPUPSTI011|ultima via File|| WPUPSTI012|Ascoltata l'ultima volta via Unknown|| WPUPSTI013|, e ha cambiato posizione|| WPUPSTI014|Potenza attuale:|| WPUPSTI016|Altitudine: %.0f%s|| WPUPSTI017| Direzione: %s || WPUPSTI018| Velocit: %.1f km/ora|| WPUPSTI019| Velocit: %.1f miglia/ora|| WPUPSTI020|%0.1f Miglia|| WPUPSTI021|%0.1f chilometri|| WPUPSTI022|Distanza dalla mia Stazione: %s, direzione rispetto alla mia stazione: %s|| WPUPSTI023|Ultima posizione: || WPUPSTI024|Dati meteorologici %c:%s|| WPUPSTI025|Direzione del vento: %s, Velocit: %03d km/ora|| WPUPSTI026|Direzione del vento: %s, Velocit: %s miglia/ora|| WPUPSTI027| Picco: %03d km/ora|| WPUPSTI028| Picco: %s MPH|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031|Umidit: %s%% || WPUPSTI032|Humidex: %02.1fC || WPUPSTI033|Pressione: %s mb || WPUPSTI034|Neve: %0.1f (cm/24ora) || WPUPSTI035|Neve: %0.0f (inch/24ora) || WPUPSTI036|Pioggia: || WPUPSTI037|%0.2f (mm/ora) || WPUPSTI038|%0.2f (pollici/ora) || WPUPSTI039|%0.2f (mm/Giorno) || WPUPSTI040|%0.2f (pollici/Giorno) || WPUPSTI041|%0.2f (mm/da mezzanotte)|| WPUPSTI042|%0.2f (pollici/da mezzanotte)|| WPUPSTI043|Percorso dei dati: %s|| WPUPSTI044|Commenti %02d/%02d %02d:%02d : %s|| WPUPSTI045|Elimina traccia|| WPUPSTI046|Pioggia totale: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (pollici)|| WPUPSTI049|Richiesta traccia|| WPUPSTI050|Richiesta Messaggi non Riconosciuti|| WPUPSTI051|Richiesta Stazioni Dirette|| WPUPSTI052|Richiesta Versione Stazione|| WPUPSTI053|Modifica Oggetto/Entit|| WPUPSTI054|Registra Tracciato|| WPUPSTI055|Ripetuto da:|| WPUPSTI056|Abilita Aggiornamento Automatico|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Puntamento DF: %s|| WPUPSTI059|Stato %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp Carburante: %02.1fC || WPUPSTI061|Temp Carburante: %sF || WPUPSTI062|Umidit Carburante: %s%% || WPUPSTI063|Pressione: %0.2f in Hg|| WPUPSTI064|Ricevi avvisi NWS|| WPUPSTI065|Chiamata tattica: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC Call Look up STIFCC0001|Ricerca nel database FCC|| STIFCC0002|Ricerca nel database RAC|| STIFCC0003|Nome:|| STIFCC0004|Indirizzo:|| STIFCC0005|Citt:|| STIFCC0006|Stato:|| STIFCC0007|Codice Postale:|| STIFCC0008|Informazioni base|| STIFCC0009|Informazioni avanzate || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC Call Look up STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # #Band open message UMBNDO0001|ad una distanza di|| # #Universal Options UNIOP00001|OK|| UNIOP00002|Annulla|| UNIOP00003|Chiudi|| UNIOP00004|Miglia|| UNIOP00005|Chilometri|| UNIOP00006|Periferica|| UNIOP00007|Aggiungi|| UNIOP00008|Cancella|| UNIOP00009|Propriet|| UNIOP00010|Consenti la trasmissione?|| UNIOP00011|Attiva all'avvio?|| UNIOP00012|km/ora|| UNIOP00013|miglia/ora|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pollici|| UNIOP00018|mm/Giorno|| UNIOP00019|pollici/Giorno|| UNIOP00020|mm/ora|| UNIOP00021|pollici/ora|| UNIOP00022|mm da mezzanotte|| UNIOP00023|pollici da mezzanotte|| UNIOP00024|gradi|| UNIOP00025|hPa|| UNIOP00026|%|| UNIOP00027|in Hg|| UNIOP00028|mm Hg|| UNIOP00029|Regolare il tempo del sistema dal GPS|| UNIOP00030|Ripeti?|| UNIOP00031|m|| UNIOP00032|Apply||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # PopUp "Station Chooser" STCHO00001|Scelta Stazione|| # #DISPLAY Meteo ALERT WPUPWXA001|Allarmi Meteo|| WPUPWXA002|Lista allarmi meteo|| # # Configure Interfaces WPUPCIF001|Interfacce installate|| WPUPCIF002|Scelta tipo di interfaccia|| # #Configure AX.25 WPUPCAX001|Configura TNC AX.25|| WPUPCAX002|Periferica TNC AX.25|| # #Interface device names IFDNL00000|Nessuna|| IFDNL00001|TNC Seriale|| IFDNL00002|TNC Seriale con GPS connesso con cavo HSP|| IFDNL00003|GPS Seriale|| IFDNL00004|Meteo Seriale|| IFDNL00005|Server Internet|| IFDNL00006|TNC AX.25|| IFDNL00007|GPS in rete (via gpsd)|| IFDNL00008|Meteo in rete|| IFDNL00009|TNC Seriale con GPS connesso con cavo AUX|| IFDNL00010|TNC Seriale in KISS|| IFDNL00011|Database su Rete (Non ancora Implementato)|| IFDNL00012|AGWPE Via Rete|| IFDNL00013|TNC Seriale in Multi-Port KISS|| IFDNL00014|SQL Database (Experimental)|| # #Interface device info IFDIN00000|%s %2d %s sulla seriale %s %s|| IFDIN00001|%s %2d %s connettendo %s:%d %s|| IFDIN00002|%s %2d %s usa la porta %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| Disattiva || IFDIN00007| Attiva || IFDIN00008| ERRORE || IFDIN00009|SCONOSCIUTO|| # #Interface control IFPUPCT000|Controllo interfaccia|| IFPUPCT001|Avvia|| IFPUPCT002|Ferma|| IFPUPCT003|Avvia Tutte|| IFPUPCT004|Ferma Tutte|| # #IGate control IGPUPCF000|Opzioni Gateway|| IGPUPCF001|Disabilita tutto il traffico per il gateway|| IGPUPCF002|Permetti solo il traffico verso il Gateway|| IGPUPCF003|Permetti il traffico Radio->Rete e Rete->Radio|| IGPUPCF004|Igate -> RF Path || # #Stazione Meteo WXPUPSI000|Stazione Meteo|| WXPUPSI001|Tipo di Stazione meteo|| WXPUPSI002|Dati correnti|| WXPUPSI003|Direzione del vento|| WXPUPSI004|Velocit del vento|| WXPUPSI005|Raffiche|| WXPUPSI006|Temperatura|| WXPUPSI007|Pioggia totale|| WXPUPSI008|Pioggia totale odierna|| WXPUPSI009|Pressione|| WXPUPSI010|Umidit|| WXPUPSI011|Peet Bros ULTIMETER 2000 (Modalit Data Logging)|| WXPUPSI012|Peet Bros ULTIMETER II || WXPUPSI013|Peet Bros ULTIMETER 2000 (Modalit Packet)|| WXPUPSI014|Pioggia (ultima ora)|| WXPUPSI015|Pioggia (24 ore)|| WXPUPSI016|Qualimetrics Q-Net|| WXPUPSI017|Peet Bros ULTIMETER 2000 Type (Complete Mode)|| WXPUPSI018|Temp.rugiada|| WXPUPSI019|Velocit massima vento|| WXPUPSI020|Vento Freddo|| WXPUPSI021|Indice Termico|| WXPUPSI022|Pressione ultime 3 Ore|| WXPUPSI023|Temp. Massima|| WXPUPSI024|Temp. Minima|| WXPUPSI025|Radio Shack Meteo-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Stn Lists LHPUPNI000|Lista stazioni|| LHPUPNI001|Lista stazioni mobili|| LHPUPNI002|Lista stazioni meteo|| LHPUPNI003|Lista stazioni locali|| LHPUPNI004|Lista ultime stazioni|| LHPUPNI005|Oggetti e Dettagli|| LHPUPNI006|Oggetti e Dettagli personali|| LHPUPNI010|#|| LHPUPNI011|Sigla|| LHPUPNI012|#Pack|| LHPUPNI013|Data e Ora|| LHPUPNI014|Percorso|| LHPUPNI015|PHG|| LHPUPNI016|Commenti|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Latitudine|| LHPUPNI104|Longitudine|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temperatura|| LHPUPNI204|Umidit|| LHPUPNI205|Pressione|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon or UTM|| # # Maps Meteo Alert styles PULDNMAT01|Mostra allarmi sopra altre mappe|| PULDNMAT02|Mostra allarmi sotto altre mappe|| # # Error/popup messages POPEM00001|Localizza errore!|| POPEM00002|Stazione %s non trovata!|| POPEM00003|Errore nell'inseguimento!|| POPEM00004|Errore dell'interfaccia!|| POPEM00005|Nome della porta %s non valido|| POPEM00006|Nome della porta AX.25 %s non valido|| POPEM00007|Nominativo %s non valido|| POPEM00008|Destinazione AX.25, Nominativo o digipeater errati|| POPEM00009|Impossibile aprire la porta AX.25, %s|| POPEM00010|Non posso collegare la porta AX.25, %s|| POPEM00011|Connessione al nominativo AX.25 non riuscita, %s|| POPEM00012|AX.25 errore sull'uscita di UI|| POPEM00013|AX.25: problema nel file axports|| POPEM00014|AX.25: %s|| POPEM00015|Errore nell'apertura dell'interfaccia %d (Fallito)|| POPEM00016|Errore nell'apertura dell'interfaccia %d (Tempo scaduto)|| POPEM00017|Non sono disponibili altre interfacce!|| POPEM00018|Richiesta dati - Messaggio su linea singola| POPEM00019|La trasmissione dalla porta %d disattivata| POPEM00020|Errore del Database!| POPEM00021|Supporto AX.25 non compilato in Xastir!|| POPEM00022|Errore di input!| POPEM00023|Non e' stato specificato alcun nome per questo punto!| POPEM00024|Il nome assegnato al punto gi in uso!| POPEM00025|Non trovato!|| POPEM00026|Il tracciamento verr visualizzato quando appare|| POPEM00027|Informazione non completa. Campi vuoti?|| POPEM00028|Non possibile aprire il file|| POPEM00029|Trovato!|| POPEM00030|Simbolo Stazione Meteo|| POPEM00031|Cambiato al simbolo Meteo '/_', altre opzioni: '\_' '/W' e '\W'|| POPEM00032|Attenzione: Stai usando il simbolo Meteo del Servizio Nazionale!|| POPEM00033|Nessun dato GPS!|| POPEM00034|Disabilito TX Mia Posizione fino all'arrivo dei dati GPS!|| POPEM00035|Attenzione|| POPEM00036|Nota|| POPEM00037|presente interfaccia HSP: l'intervallo di lettura del GPS viene aumentato|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Jump Location JMLPO00001|Posizione Mappa|| JMLPO00002|Vai!|| JMLPO00003|Nome del nuovo punto:|| # # Bollettini BULMW00001|Bollettini|| BULMW00002|Raggio (0, senza limite)|| BULMW00003|Cambia raggio|| # # All Message Traffic AMTMW00001|Traffico di tutti i messaggi|| AMTMW00002|Raggio (0, senza limite)|| # # Speech Strings SPCHSTR001|chilometri|| SPCHSTR002|metri|| SPCHSTR003|miglia|| SPCHSTR004|yards|| SPCHSTR005|%s, distanza %d %s.|| SPCHSTR006|%s, distanza %.1f %s.|| SPCHSTR007|%s, distanza %d %s %s %s.|| SPCHSTR008|%s, distanza %.1f %s %s %s.|| SPCHSTR009|Nuovo Allarme Meteo|| SPCHSTR010|Nuovo Nominativo|| SPCHSTR011|Ascoltato, D X, %s, alla distanza di %.1f %s|| # SPCHDIRN00|nord di|| SPCHDIRS00|sud di|| SPCHDIRE00|est di|| SPCHDIRW00|ovest di|| SPCHDIRNE0|nordest di|| SPCHDIRNW0|nordovest di|| SPCHDIRSE0|sudest di|| SPCHDIRSW0|sudovest di|| # # Symbol Selection Dialog SYMSEL0001|Selezione simbolo|| SYMSEL0002|Tabella Primaria|| SYMSEL0003|Tabella Secondaria|| # # Finestra di dialogo proprieta di stampa PRINT0001|Propriet di Stampa|| PRINT0002|Formato Carta|| PRINT0003|Ruota Immagine automaticamente PRINT0004|Ruota Immagine di 90 in senso antiorario|| PRINT0005|Ridimensiona immagine|| PRINT0006|Scala:|| PRINT0007|Sfondo bianco|| PRINT0008|Stampa in bianco e nero|| PRINT0016|Inverti i colori|| PRINT0009|Risoluzione del file Postscript:|| PRINT0010|Anteprima|| PRINT0011|Stampa su file|| PRINT0012|Elaborazione immagine su file...|| PRINT0013|Conversione in Postscript...|| PRINT0014|Fine elaborazione file.|| PRINT0015|Stato del processo di stampa|| # # Finestra di dialogo proprieta di stampa PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Finestra di dialogo localizza elemento mappa FEATURE001|Nome:|| FEATURE002|Stato/Provincia:|| FEATURE003|Contea:|| FEATURE004|Quadrante:|| FEATURE005|Tipo:|| FEATURE006|File GNIS:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Geocoding Dialog (Nominatim) GEOCODE001|Cerca posizione|| GEOCODE002|Query di ricerca:|| GEOCODE003|Filtro paese:|| GEOCODE004|Cerca|| GEOCODE005|Cancella|| GEOCODE006|Risultati:|| GEOCODE007|Vai a|| GEOCODE008|Segna|| GEOCODE009|Chiudi|| GEOCODE010|Ricerca in corso...|| GEOCODE011|Nessun risultato trovato|| GEOCODE012|Errore: %s|| GEOCODE013|Trovato/i %d risultato/i|| GEOCODE014|Dati (C) Contributori OpenStreetMap|| GEOCODE015|Nessuno (Mondiale)|| GEOCODE023|Servizio non disponibile|| GEOCODE024|Inserisci una posizione da cercare|| GEOCODE025|Svuota cache|| GEOCODE026|Cache svuotata con successo|| GEOCODE027|Impossibile svuotare la cache|| GEOCODE028|Server Nominatim:|| GEOCODE029|Cache abilitata:|| GEOCODE030|Scadenza cache (giorni):|| GEOCODE031|Email utente:|| GEOCODE032|Paese predefinito:|| GEOCODE033|Impostazioni|| GEOCODE034|Salva|| GEOCODE035|Annulla|| GEOCODE036|Applica|| GEOCODE037|Impostazioni geocodifica|| # # Geocoding Configuration Dialog GEOCFG001|Impostazioni geocodifica|| GEOCFG002|URL server:|| GEOCFG003|Indirizzo email:|| GEOCFG004|(Opzionale ma consigliato)|| GEOCFG005|Paese predefinito:|| # # Coordinate Calculator Dialog COORD001|Calcolo Coordinate|| COORD002|Calc|| COORD003|Calcola|| COORD004|Cancella|| COORD005|UTM|| COORD006|Latitudine o|| COORD007|Longitudine o|| COORD008|Zona|| COORD009|UTM Est|| COORD010|UTM Nord|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Smart Beaconing Dialog SMARTB001|SmartBeaconing|| SMARTB002|Tasso Alto (secs):|| SMARTB003|Alta Velocit (mph):|| SMARTB004|Alta Velocit (kmh):|| SMARTB005|Tasso Basso (mins):|| SMARTB006|Bassa Velocit (mph):|| SMARTB007|Bassa Velocit (kmh):|| SMARTB008|Giro Minimo (gradi):|| SMARTB009|Inclinazione Giro:|| SMARTB010|Tempo di Attesa (secondi):|| SMARTB011|Abilita SmartBeaconing(tm)|| # # # # Gamma Adjust Dialog GAMMA001|Impostazione Correzione Gamma|| GAMMA002|Correzione Gamma|| # # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Minuscolo|| MAPFONT004|Map Font Piccolo|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distance/Bearing on status line PULDNDB001|Stato Distanza/Puntamento|| # # # GPS Transfer Operations GPS001|Trasferimento GPS|| GPS002|Nome File|| GPS003|Seleziona Colore|| GPS004|Rosso|| GPS005|Verde|| GPS006|Nero|| GPS007|Bianco|| GPS008|Arancione|| GPS009|Blu|| GPS010|Giallo|| GPS011|Viola|| # # # Map Properties Dialog MAPP001|Propriet Mappa|| MAPP002|Max Min Disegna Mappa USGS Auto|| MAPP003|Zoom Zoom Livello Riempi DRG Map Percorso/Nome File|| MAPP004|Cambia Livello->|| MAPP005|Riempito->|| MAPP006|Si|| MAPP007|No|| MAPP008|Automappe->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Time Strings TIME001|Giorno|| TIME002|Giorni|| TIME003|Ora|| TIME004|Ore|| TIME005|Minuto|| TIME006|Minuti|| TIME007|Secondo|| TIME008|Secondi|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/language-Portuguese.sys0000664000175000017500000012200115151324131021245 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # Este e o ficheiro da lingua Portuguesa, sem pontuacao, usado para todas as consultas # no Xastir. # # Criador : por CT1DRB, David Quental # # Linhas de comentarios com o simbolo de cardinal a frente sao ignorados # O formato do ficheiro e como segue: # Id (10 caracteres alfa numerico)|(Cadeia associada com id)|TeclaRapida|#comentario # # AVISO: # Algumas cadeias de letras conteem comandos de formato como %s e %d, voce nao # deve mudar isso. Cadeias de formatos errados poderao produzir um segfault! # # Menu principal MENUTB0001|Ficheiro|F| MENUTB0002|Visualizar|V| MENUTB0004|Mapas|M| MENUTB0005|Estacoes|s| MENUTB0006|Mensagens|g| MENUTB0010|Interfaces|I| MENUTB0009|Ajuda|j| # # Menu de ficheiro PULDNFI001|Configurar|C| PULDNFI002|Abrir o log|B| PULDNFI003|Testar|P| PULDNFI004|Sair|S| PULDNFI007|Muda nivel de debug|D| PULDNFI010|Abre o log do TNC|T| PULDNFI011|Abre o log da internet|I| PULDNFI012|Abre o log da I-Gate|G| PULDNFI013|Abre o log do tempo|W| PULDNFI014|Activa PNG instantanea|| PULDNFI015|Imprimir mapa|P| PULDNFI016|KML Snapshots|| # # Menu visor PULDNVI001|Boletins|B| PULDNVI002|Trafego recebido|D| PULDNVI003|Estacoes moveis|m| PULDNVI004|Todas as estacoes|e| PULDNVI009|Estacoes locais|t| PULDNVI012|Ultimas estacoes|U| PULDNVI005|Estacoes meteorologicas|t| PULDNVI008|A sua estacao meteorologica|s| PULDNVI007|Alerta de tempo|A| PULDNVI011|Trafego de mensagens|f| PULDNVI013|Aviso|v| PULDNVI014|Programar aviso|r| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Menu de configuracao PULDNCF004|Estao|E| PULDNCF001|Pre-definidos|P| PULDNCF003|Momento certo|T| PULDNCF002|Sistema de coordenadas|S| PULDNCF006|Audio dos alarmes|A| PULDNCF007|Sintetizador de voz|S| PULDNCF008|Guardar configuracao!|G| # (Unidades ver PULDNDP006) # # Menu de mapas PULDNMP001|Seleccionar mapas|M| PULDNMP012|Saltar para um local do mapa|S| PULDNMP014|Localizar faixa no mapa|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Desactivar todos os mapas|| PULDNMP002|Activar auto mapas|| PULDNMP003|Activar as coordenadas do mapa|| PULDNMP004|Niveis dos mapas|| PULDNMP010|Etiquetas dos mapas|| PULDNMP009|Activar areas coloridas|| PULDNMP007|Activar os alertas de WX|| PULDNMP005|Cor de fundo|C| PULDNMP006|Estilo de texto da estacao|E| PULDNMP026|Estilo da linha de fora do icon|O| PULDNMP011|Menu indicador do rato|r| PULDNMP008|Intensidade do mapa|I| PULDNMP021|Auto Map - desactivar raster mapas|| PULDNMP022|Indexar mapas no comeco|| PULDNMP023|Index: Acrescentar mapas novos|A| PULDNMP024|Index: Reindexar os mapas TODOS|R| PULDNMP025|Fonts|| PULDNMP015|Seleccionar a fonte do X|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Pesquisar local|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| PULDNMP032|Configuraes de geocodificao|| MPUPTGR017|Internet Map Timeout (sec)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # # Selecao de mapas WPUPMCP001|Escolher mapa|| PULDNMMC01|Limpar|N| PULDNMMC02|Vectores|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Direccoes expandidas||| PULDNMMC07|Selecionados dirs/mapas:|| PULDNMMC08|Limpar dirs|C| PULDNMMC09|Seleccionar tudo|S| # # Cores de fundo do mapa PULDNMBC01|Cinzento|| PULDNMBC02|Rosado mistico|| PULDNMBC03|Azul marinho|| PULDNMBC04|Azul escuro|| PULDNMBC05|Med. verde mar|| PULDNMBC06|Verde palido|| PULDNMBC07|Dourado palido|| PULDNMBC08|Dourado amarelado|| PULDNMBC09|Castanho rosado|| PULDNMBC10|Vermelho escuro|| PULDNMBC11|Branco|| PULDNMBC12|Preto|| # # Mapas de estacoes e estilos das etiquetas PULDNMSL01|Fundo negro|| PULDNMSL02|Fundo cinzento|| PULDNMSL03|Texto em negro|T| PULDNMSL04|DropShadow|| # # PullDown "Estilo da linha de fora do icon" PULDNMIO01|Nao ha limite|N| PULDNMIO02|Limite preto|B| PULDNMIO03|Limite cinzento|G| PULDNMIO04|Limite brando|W| # # Switches ON/OFF/Curto PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Curto|| # # Menu de mostragem de estacoes PULDNDP014|Localizar estacao|L| PULDNDP001|Rastrear estacao|R| PULDNDP022|Tirar o rasto de Findu|F| PULDNDP032|Filtrar dados|| PULDNDP040|Escolher nada|| PULDNDP041|Escolher meu|| PULDNDP042|Escolher TNC|| PULDNDP027|- Mostrar estacoes direct|| PULDNDP043|- Escolher via digi|| PULDNDP034|Mostrar estacoes net|| PULDNDP019|Mostrar infos expiradas|| PULDNDP044|Mostrar estacoes|| PULDNDP028|- Mostrar estacoes fixas|| PULDNDP029|- Mostrar estacoes moveis|| PULDNDP030|- Mostrar estacoes de tempo|| PULDNDP053| - Seleccionar estacoes CWOP WX|| PULDNDP045|Mostrar objectos/items|| PULDNDP026|- Mostrar objectos/items metereologicos|| PULDNDP039|- Mostrar objectos de medida de agua/Items|| PULDNDP031|- Mostrar outros objectos/Items|| PULDNDP057|- Selecionar objetos avio / Itens|| PULDNDP058|- Seleccione navio Objetos / Itens|| PULDNDP033|Filtrar monitor|| PULDNDP010|Mostrar indicativo|i| PULDNDP012|Mostrar simbolos|D| PULDNDP011|- Simbolos rodados|S| PULDNDP007|Rastos de estacoes|R| PULDNDP003|Mostrar curso|c| PULDNDP004|Mostrar velocidade|v| PULDNDP017|- Mostrar velocidade baixa|| PULDNDP002|Mostrar altura|a| PULDNDP009|Mostrar info do tempo|t| PULDNDP046|- Mostrar texto do tempo|| PULDNDP018|-- Mostrar so a temperatura|| PULDNDP047|- Mostrar intensidade do vento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Ambiguidade de posicao|| PULDNDP008|Estacao potencia/ganho|p| PULDNDP021|- Activar por defeito pot/ganho|| PULDNDP020|- Activar movel pot/ganho|| PULDNDP023|Mostrar circulos DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activar Dead-Reckoning|| PULDNDP036|- Activar arco Dead-Reckoning|| PULDNDP037|- Activar curso Dead-Reckoning|| PULDNDP038|- Activar simbolo Dead-Reckoning|| PULDNDP005|Mostrar dist/curso|d| PULDNDP024|Mostrar o ultimo reporte horario|| PULDNDP015|Anular todas as estacoes|A| PULDNDP016|Limpar rastos|L| PULDNDP025|Limpar historia de objecto/item|| PULDNDP048|Recarregar objecto/historia de item|| PULDNDP049|Limpar todos os indicativos tacticos|| PULDNDP050|Limpar a historia dos indicativos tacticos|| PULDNDP051|Seleccionar unicamente indicativos tacticos|| PULDNDP052|- Etiquetas de pontos de pista|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Inglesa/metrica PULDNUT001|Activar unidades Inglesas|| PULDNUT002|Metrica|| # # Menu de mensagens PULDNMG001|Enviar mensagem a|E| PULDNMG002|Abrir mensagens de grupos|g| PULDNMG003|Anular todas as mensagens a enviar|A| PULDQUS001|Pergunta geral a estacoes|r| PULDQUS002|Pergunta a estacoes I-Gate|I| PULDQUS003|Pergunta a estacoes WX|W| PULDNMG004|Modificar mensagem de resposta automatica|f| PULDNMG005|Activar mensagem de resposta automatica|A| PULDNMG006|Modo de reconhecimento por satelite|M| PULDNMG007|Show Pending Messages|P| # # Menu de interfaces PULDNTNT04|Interface Control|| PULDNTNT03|Desactivar transmitir: TODOS|| PULDNTNT05|Desactivar transmitir: A minha posicao|| PULDNTNT06|Desactivar transmitir: Objectos/Artigos|| PULDNTNT11|Activar porta de server|| PULDNTNT01|Transmitir agora..!|T| PULDNTNT07|Buscar rastro de GPS|F| PULDNTNT08|Buscar rotas de GPS|R| PULDNTNT09|Buscar waypoints de GPS|W| PULDNTNT10|Buscar pontos da Garmin RINO|G| # # Menu de ajuda PULDNHEL01|Acerca de|A| PULDNHEL02|Index de ajuda|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # Menu do rato POPUPMA001|Opcoes|| POPUPMA00c|Centro|| POPUPMA015|Info da estacao|| POPUPMA002|Aproximar|A| POPUPMA003|Afastar|f| POPUPMA004|Nivel de focagem|N| POPUPMA005|Nivel 1|1| POPUPMA006|Nivel 16|6| POPUPMA007|Nivel 64|4| POPUPMA008|Nivel 256|2| POPUPMA009|Nivel 1024|0| POPUPMA010|Nivel 8192|8| POPUPMA017|O mundo inteiro|E| POPUPMA016|Ultima pos/focagem do mapa|P| POPUPMA018|Criar objecto/artigo|C| POPUPMA019|Modificar objecto/artigo|M| POPUPMA025|Mover aqui a minha estacao|H| POPUPMA011|Ir para cima|u| POPUPMA012|Ir para baixo|d| POPUPMA013|Ir para a esquerda|l| POPUPMA014|Ir para a direita|r| POPUPMA020|Medida|| POPUPMA021|Movimento|| POPUPMA022|Siga-me|| POPUPMA023|Modificadores encontrados!|| POPUPMA024|Por favor desligue as teclas CapsLock/NumLock/ScrollLock/outros|| POPUPMA026|Centro e Zoom|| POPUPMA027| Latitude|| POPUPMA028| Longitude|| POPUPMA029|Desenhar objectos CAD|| POPUPMA030|Draw|| POPUPMA031|Fechar poligono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Menu dos estados das linhas de etiquetas BBARZM0001|Foco %s|| BBARZM0002|Foco %s Tr|| BBARSTH001|%d/%d estacoes|| BBARSTA000|%-9s novo objecto!|| BBARSTA001|%-9s nova estacao!|| BBARSTA002|%s|| BBARSTA003|Carregando mapas...|| BBARSTA004|Mapas carregados...|| BBARSTA005|Graduacao lat/long esta ON|| BBARSTA006|Graduacao lat/long esta OFF|| BBARSTA007|O uso dos auto mapas, esta ON|| BBARSTA008|O uso dos auto mapas, esta OFF|| BBARSTA009|Os niveis do mapa estao ON|| BBARSTA010|Os niveis do mapa estao OFF|| BBARSTA011|A mensagem de resposta automatica esta OFF!|| BBARSTA012|Ficheiro criado..|| BBARSTA013|Abrindo porta GPS|| BBARSTA014|Fechando porta GPS|| BBARSTA015|Obtendo a string do GPS RMC|| BBARSTA016|Obtendo a string do GPS GGA|| BBARSTA017|Rede desligada do servidor|| BBARSTA018|Ligacao fechada por excesso de tempo!|| BBARSTA019|A procurar servidor %s|| BBARSTA020|Ligado a %s|| BBARSTA021|Falha na ligacao rede!|| BBARSTA022|Pode nao ligar ao socket!|| BBARSTA023|Nao ha IP para o servidor!|| BBARSTA024|Nao ha servidor especificado|| BBARSTA025|Servidor encontrado, a ligar %d|| BBARSTA026|Esperando por infos do GPS via HSP..|| BBARSTA027|Limpando as infos de HSP obtidos do TNC..|| BBARSTA028|Carregando %s|| BBARSTA029|Abrindo porta WX|| BBARSTA030|A fechar porta WX|| BBARSTA031|A procura o servidor %d|| BBARSTA032|Infos de WX descodificados|| BBARSTA033|Eco desde o digipeater|| BBARSTA034|Carregando mapas de alerta WX|| BBARSTA035|Esperando por dados do GPS via AUX..|| BBARSTA036|Limpando AUX para obter dados do TNC..|| BBARSTA037|Dados do GPS completos|| BBARSTA038|Posicao alterada na minha estacao|| BBARSTA039|Indexando %s|| BBARSTA040|Estacao de radioamador de APRS(tm) %s|| BBARSTA041|Esperando pela data do GPS..|| BBARSTA042|Transmitindo objectos/items|| BBARSTA043|Registando|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # Visualizao do trafego de packet WPUPDPD001|Visualizacao do trafego|| WPUPDPD002|So dados do TNC|| WPUPDPD003|So dados da rede|| WPUPDPD004|Dados do TNC e da rede|| WPUPDPD005|TNC|| WPUPDPD006|REDE|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # Localizar estacao WPUPLSP001|Localizar estacao|| WPUPLSP002|Localizar indicativo|| WPUPLSP003|Maiscula/minuscula|M| WPUPLSP004|Exacta|E| WPUPLSP005|Localizar agora!|A| WPUPLSP006|Localizar emergencia!|| WPUPLSP007|FCC/RAC Lookup|| # # Configurar predefinidos WPUPCFD001|Configurar valores pre-definidos|| WPUPCFD002|desde que intervalo de tempo sera considerada uma estacao antiga?|| WPUPCFD003|15 minutos|1| WPUPCFD004|30 minutos|3| WPUPCFD005|45 minutos|4| WPUPCFD006|1 hora|H| WPUPCFD007|90 minutos|9| WPUPCFD008|2 horas|2| WPUPCFD009|desde que intervalo de tempo a estacao nao sera mostrada?|| WPUPCFD010|6 horas|6| WPUPCFD011|12 horas|o| WPUPCFD012|1 Dia|D| WPUPCFD013|2 Dias|s| WPUPCFD014|1 semana|n| WPUPCFD015|Opcao modo de transmissao da estacao|| WPUPCFD016|Estacao fixa|F| WPUPCFD017|Estacao movel c/hora local|l| WPUPCFD018|Estacao movel c/data-hora zulu|z| WPUPCFD019|Estacao movel c/horas-segundos zulu|u| WPUPCFD021|Posicao da estacao c/tempo|t| WPUPCFD022|Posicao da estacao, data-hora zulu e tempo|d| WPUPCFD023|Transmitir infos WX em Raw?|| WPUPCFD024|Comprimir objecto/item durante a transmissao?|| WPUPCFD025|Activar rede alternativa?|A| WPUPCFD026|Enviar reportes de posicao em que intervalos?|| WPUPCFD027|Pop up de novos boletins|| WPUPCFD028|Avisar se teclas foram modificadas|| WPUPCFD029|Ver boletins de distancia zero|| WPUPCFD030|Desactivar dupe-checks de posit|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # PopUp "Configurar - momento certo" WPUPCFTM01|Configurar momento certo||| WPUPCFTM02|Intervalo Posit TX (min)|| WPUPCFTM03|Tempo de estacao fantasma (min)|| WPUPCFTM04|Max Intervalo TX objecto/item (min)|| WPUPCFTM05|Tempo para limpar estacao (horas)|| WPUPCFTM06|Intervalo para verificar GPS (seg)|| WPUPCFTM07|Tempo para apagar estacao (dias)|| WPUPCFTM08|Tempo limite para dead-reckoning (min)|| WPUPCFTM09|Serie de atraso de inter-char (ms)|| WPUPCFTM10|Novo tempo de pista (min)|| WPUPCFTM11|Novo intervado de pista (degrees)|| WPUPCFTM12|RINO -> Intervalo de objectos (min), 0 = Desactivado|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # PopUp "Sistema de configuracao de coordenadas" WPUPCFC001|Sistema de configuracao de coordenadas|| WPUPCFC002|Sistema de selecao de coordenadas|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM com zonas especiais|| # # Configurar GPS WPUPCFG001|Configurar GPS|| WPUPCFG003|Porta exclusiva de GPS|| WPUPCFG002|Usar posicao GPS?|| WPUPCFG004|opcoes do GPS|| WPUPCFG005|GPS exclusivo|| WPUPCFG006|TNC ligado a GPS (cabo HSP)|| WPUPCFG007|TNC ligado a GPS usando CTL-E|| WPUPCFG008|GPS tempo (a mostrar cada)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 minutos|| WPUPCFG014|5 minutos|| WPUPCFG015|10 minutos|| WPUPCFG016|Rede ligada ao GPS|| WPUPCFG017|Servidor GPSD|| WPUPCFG018|Porta GPSD|| WPUPCFG019|Rede GPS via GPSD|| WPUPCFG020|Voltar a ligar quando falhar?|| WPUPCFG021|Rede ligada a WX|| WPUPCFG022|Servidor WX|| WPUPCFG023|Porta WX|| # # Configurar TNC (bauds tambem sao para WX) WPUPCFT001|Configurar TNC|| WPUPCFT002|Usar TNC?|| WPUPCFT003|Porta TNC|| WPUPCFT004|Velocidade da porta|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Rota do UnProto|| WPUPCFT012|Rota 1: %s via || WPUPCFT013|Rota 2: %s via || WPUPCFT014|Rota 3: %s via || WPUPCFT015|Modo da porta|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurar o TNC c/HSP GPS|| WPUPCFT024|Tipo de data|| WPUPCFT025|Auto deteccao|| WPUPCFT026|Tipo Binario|| WPUPCFT027|Tipo ASCII|| WPUPCFT028|Configurar TNC com GPS AUX|| WPUPCFT029|Configurar TNC com ENUM INVALIDO: %d|| WPUPCFT030|Configurar o TNC em KISS|| WPUPCFT031|Ficheiros de configuracao do TNC|| WPUPCFT032|Nome do ficheiro de definicoes do TNC|| WPUPCFT033|Nome do ficheiro de fecho do TNC|| WPUPCFT034|Parametros do KISS|| WPUPCFT035|TXDelay (10 unidades de ms)|| WPUPCFT036|Persistencia (0 a 255)|| WPUPCFT037|SlotTime (10 unidades de ms)|| WPUPCFT038|TxTail (10 unidades de ms)|| WPUPCFT039|Duplex completo (Full Duplex)|| WPUPCFT040|Configurar o TNC em Multi-Port KISS|| WPUPCFT041|Porta radio|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # Configurar a porta da estacao meteorologica WPUPCFWX01|Configurar a porta da estacao meteorologica|| WPUPCFWX02|Dispositivo da estacao meteorologica|| WPUPCFWX03|Correccao da medida de chuva (Definicoes globais)|| WPUPCFWX04|.1 polegadas/2.5mm|| WPUPCFWX05|.01 polegadas/.25mm|| WPUPCFWX06|.1mm|| WPUPCFWX07|Nao corrigido|| # # Configurar a estacao WPUPCFS001|Configurar a estacao|| WPUPCFS002|Indicativo|| WPUPCFS003|Latitude|| WPUPCFS004|grd|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Longitude|| WPUPCFS008|(E/W)|| WPUPCFS009|Simbolo da estacao|| WPUPCFS010|Grupo/sobreposto|| WPUPCFS011|Simbolo|| WPUPCFS028|Seleccione|| WPUPCFS012|Potencia - Altura (HAAT) - Ganho e direccao|| WPUPCFS013|Desactive PHG|| WPUPCFS014|Altura da antena|| WPUPCFS015|Ganho da antena|| WPUPCFS016|Omni|| WPUPCFS017|Comentarios:|| WPUPCFS018|Posicao ambigua|| WPUPCFS019|Nenhuma|| WPUPCFS020|.11 milha|| WPUPCFS021|1.15 milhas|| WPUPCFS022|11.51 milhas|| WPUPCFS023|69.09 milhas|| WPUPCFS024|.18 quilometro|| WPUPCFS025|1.85 quilometros|| WPUPCFS026|18.53 quilometros|| WPUPCFS027|111.19 quilometros|| WPUPCFS029|Enviar posits comprimidas|C| # # Dialogo de Objeto/Artigo POPUPOB001|Objecto/artigo|| POPUPOB002|Nome:|| POPUPOB003|Criar novo objecto|| POPUPOB004|Apagar objeto|| POPUPOB005|Modificar objecto|| POPUPOB006|Criar novo artigo|| POPUPOB007|Area do objeto|| POPUPOB008|Activar area do objecto|| POPUPOB009|Cor luminosa|| POPUPOB010|Area colorida|| POPUPOB011|Circulo|| POPUPOB012|Linha-direita '/'|| POPUPOB013|Linha-esquerda '\'|| POPUPOB014|Triangulo|| POPUPOB015|Rectangulo|| POPUPOB016|Negro|| POPUPOB017|Azul|| POPUPOB018|Verde|| POPUPOB019|Cinzento|| POPUPOB020|Vermelho|| POPUPOB021|Violeta|| POPUPOB022|Amarelo|| POPUPOB023|Cinzento|| POPUPOB024|Compensar em cima:|| POPUPOB025|Compensar a esq.(Excepto '/'):|| POPUPOB026|Corredor:|| POPUPOB027|Opcoes gerais|| POPUPOB028|Situacao|| POPUPOB029|Activar letreiro|| POPUPOB030|Data:|| POPUPOB031|Letreiro objecto|| POPUPOB032|Activar compressao|| POPUPOB033|Apagar artigo|| POPUPOB034|Modificar artigo|| POPUPOB035|Altitude (Pes):|| POPUPOB036|Velocidade (nos):|| POPUPOB037|Curso:|| POPUPOB038|DF objecto|| POPUPOB039|Sinal - Altura(HAAT) - Ganho - Direccao|| POPUPOB040|Dirigindo - Amplitude da direccao|| POPUPOB041|Antena omni-direcional|| POPUPOB042|Antena direcional|| POPUPOB043|Inutil|| POPUPOB044|Adoptar objecto|| POPUPOB045|Adoptar item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # Configurar Internet WPUPCFI001|Configurar internet|| WPUPCFI002|Servidor|| WPUPCFI003|Porta|| WPUPCFI004|(Servidores secundarios)|| WPUPCFI005|Servidor1|| WPUPCFI006|Porta1|| WPUPCFI007|Servidor2|| WPUPCFI008|Porta2|| WPUPCFI009|Senha|| WPUPCFI010|(Deixar em branco se nao houver nada)|| WPUPCFI011|Voltar a ligar em caso de falha de rede?|| WPUPCFI012|Correr como num I-Gate?|| WPUPCFI013|Difundir mensagens via TNC quando houver um I-Gate?|| WPUPCFI014|Registo de transacoes do I-Gate?||| WPUPCFI015|Parametros filtrados|| # # Configurar Database WPUPCFID01|Configurar Database (TBD)|| WPUPCFID02|Servidor|| WPUPCFID03|Porta|| WPUPCFID04|(Servidores secundarios)|| WPUPCFID05|Servidor1|| WPUPCFID06|Porta1|| WPUPCFID07|Servidor2|| WPUPCFID08|Porta2|| WPUPCFID09|Senha|| WPUPCFID10|(Deixar em branco se nao houver nada)|| WPUPCFID11|Voltar a ligar em caso de falha de rede?|| WPUPCFID12|Correr como num I-Gate?|| WPUPCFID13|Difundir mensagens via TNC quando houver um I-Gate?|| WPUPCFID14|Log de transacoes do I-Gate?||| WPUPCFID15|Parametros filtrados|| # # PopUp "Configurar AGWPE" WPUPCFIA01|Configurar AGWPE|| WPUPCFIA02|Host || WPUPCFIA03|Porta || WPUPCFIA04|(Hosts secundarios)|| WPUPCFIA05|Host1|| WPUPCFIA06|Porta1|| WPUPCFIA07|Host2|| WPUPCFIA08|Porta2|| WPUPCFIA09|Codigo de passagem|| WPUPCFIA10|(Deixar em branco se nao ha nada)|| WPUPCFIA11|Voltar a ligar se houver uma falha da NET?|| WPUPCFIA12|Funcionar como uma I-Gate?|| WPUPCFIA13|Divulgar mensagens via TNC quando estiver na I-Gate?|| WPUPCFIA14|Registo das transacoes I-Gate?|| WPUPCFIA15|Transmitir RadioPort|| # # Configurar Alarmas de Audio WPUPCFA001|Configurar alarme de audio|| WPUPCFA002|Aplicacao audio|| WPUPCFA003|Alarme ON|| WPUPCFA004|Ficheiros de audio|| WPUPCFA005|Nova estacao|| WPUPCFA006|Nova mensagem|| WPUPCFA007|Proximidade|| WPUPCFA008|Banda aberta|| WPUPCFA009|Minima distancia|| WPUPCFA010|Maxima distancia|| WPUPCFA011|Alerta de tempo|| # # Configurar o festival, o sintetizador de voz WPUPCFSP01|Configurar o festival como sintetizador de voz|| WPUPCFSP02|Fixar em 'ON' as opcoes do sintetizador de voz|| WPUPCFSP03|<- Anuncia nova estacao|| WPUPCFSP04|<- Anuncia alerta de nova mensagem|| WPUPCFSP05|<- Anuncia corpo de nova mensagem|| WPUPCFSP06|<- Anuncia a proximidade de estacoes|| WPUPCFSP07|<- Anuncia DX condio de banda aberta|| WPUPCFSP08|<- Anuncia alerta sobre condicoes do tempo|| WPUPCFSP09|Alerta de proximidade da estacao rastreada|| # # Rastreo da estacao WPUPTSP001|Rastrear estacao|| WPUPTSP002|Rastrear indicativo|| WPUPTSP003|Maiscula/minuscula|| WPUPTSP004|Exacto|| WPUPTSP005|Rastrear agora!|| WPUPTSP006|Limpar rastro|| WPUPTSP007|Receber caminho|| WPUPTSP008|Indicativo|| WPUPTSP009|Comecar rasto (horas atras)|| WPUPTSP010|Tamanho do rasto (horas)|| # # Menu de mensagens WPUPMSB001|Enviar mensagem %d|| WPUPMSB002|Enviar mensagem ao grupo %d|| WPUPMSB003|Indicativo de estacao:|| WPUPMSB004|Indicativos de grupos:|| WPUPMSB005|Novo/Refresh indicativo|| WPUPMSB006|Novo grupo|| WPUPMSB007|Limpar histria da mensagem|| WPUPMSB008|Mensagem:|| WPUPMSB009|Enviar agora!|| WPUPMSB010|Encaminhamento:|| WPUPMSB011|Cancelar mensagens pendentes|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # Auto resposta WPUPARM001|Mudar resposta automatica|| WPUPARM002|Reenviar:|| # # Auuda / Indice WPUPHPI001|Indice de ajuda|I| WPUPHPI002|Visualizar|V| # # Informacao da estacao WPUPSTI000|Objecto criado desde: %s|| WPUPSTI001|Info estacao|| WPUPSTI002|Enviar mensagem|| WPUPSTI003|Procurar infos FCC|| WPUPSTI004|Procurar infos RAC|| WPUPSTI005|%d: pacotes recebidos, ultimo recebido na data: || WPUPSTI006|Ouvido via TNC no dispositivo: %d, || WPUPSTI007|Ouvido || WPUPSTI008|Ultima vez via local|| WPUPSTI009|Ultima vez via TNC no dispositivo: %d|| WPUPSTI010|Ultima vez via internet no dispositivo: %d|| WPUPSTI011|Ultima vez via ficheiro|| WPUPSTI012|Ultima vez via desconhecida|| WPUPSTI013|, e mudou de posicao|| WPUPSTI014|Actual potencia/ganho:|| WPUPSTI016|Altitude: %.1f%s || WPUPSTI017|Curso: %s || WPUPSTI018|Velocidade: %.1f km/h|| WPUPSTI019|Velocidade: %.1f mph|| WPUPSTI020|%0.1f milhas|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distancia desde a minha estacao %s, curso desde a minha estacao %s|| WPUPSTI023|Ultima posicao: || WPUPSTI024|Dados da estacao meteorologica %c:%s|| WPUPSTI025|Curso do vento: %s Velocidade: %03d km/h|| WPUPSTI026|Curso do vento: %s Velocidade: %s mph|| WPUPSTI027| Rajada: %03d Km/h|| WPUPSTI028| Rajada: %s mph|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031|Humidade: %s%% || WPUPSTI032|Indice da humidade: %02.1fC || WPUPSTI033|Pressao barometrica: %s mb|| WPUPSTI034|Neve: %0.1f (cm/24h)|| WPUPSTI035|Neve: %0.0f (plg/24h)|| WPUPSTI036|Chuva: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (plg/h) || WPUPSTI039|%0.2f (mm/dia) || WPUPSTI040|%0.2f (plg/dia) || WPUPSTI041|%0.2f (mm/desde a meia noite)|| WPUPSTI042|%0.2f (mm/desde a meia noite)|| WPUPSTI043|Rota de dados: %s|| WPUPSTI044|Comentarios %02d/%02d %02d:%02d : %s|| WPUPSTI045|Limpar rastro|| WPUPSTI046|Total de chuva: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (plg)|| WPUPSTI049|Perguntar rastro|| WPUPSTI050|Perguntar por mensagens nao-confirmadas|| WPUPSTI051|Pergunta directa a estacao|| WPUPSTI052|Pergunta versao a estacao|| WPUPSTI053|Modificar objeto/artigo|| WPUPSTI054|Armazenar rastro|| WPUPSTI055|Repetido desde:|| WPUPSTI056|Activar actualizacao automatica|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|DF dirigido: %s|| WPUPSTI059|Estados %02d/%02d %02d:%02d : %s|| WPUPSTI060|Temp do combustivel: %02.1fC || WPUPSTI061|Temp do combustivel: %sF || WPUPSTI062|Mistura do combustevel: %s%% || WPUPSTI063|Baro: %0.2f em Hg|| WPUPSTI064|Procurar alerta de NWS|| WPUPSTI065|Indicativo tactico: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC procurar indicativo STIFCC0001|Procurar FCC banco de datos|| STIFCC0002|Procurar RAC banco de datos|| STIFCC0003|Nome:|| STIFCC0004|Rua/Av:|| STIFCC0005|Cidade:|| STIFCC0006|Estado:|| STIFCC0007|Codigo postal:|| STIFCC0008|Basica || STIFCC0009|Avancada || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC procurar indicativo STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Mensagem de banda aberta UMBNDO0001|a cerca de|| # # Opcoes universais UNIOP00001|Aceitar|| UNIOP00002|Cancelar|| UNIOP00003|Fechar|| UNIOP00004|milhas|| UNIOP00005|km|| UNIOP00006|Dispositivo|| UNIOP00007|Acrescentar|| UNIOP00008|Anular|| UNIOP00009|Propriedades|| UNIOP00010|Permitir transmissao?|| UNIOP00011|Activar no inicio?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|plg|| UNIOP00018|mm/dia|| UNIOP00019|plg/dia|| UNIOP00020|mm/hora|| UNIOP00021|plg/hora|| UNIOP00022|mm/med|| UNIOP00023|plg/med|| UNIOP00024|grd|| UNIOP00025|mb|| UNIOP00026|%|| UNIOP00027|inHg|| UNIOP00028|mm Hg|| UNIOP00029|Definir o relogio do sistema desde o GPS?|| UNIOP00030|Digipeater?|| UNIOP00031|m|| UNIOP00032|Aplicar||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # Seleccionar estacao STCHO00001|Seleccionar estacao|| # # Desligar alarme de WX WPUPWXA001|Alerta do tempo|| WPUPWXA002|Lista de alerta do tempo|| # # Configurar interfaces WPUPCIF001|Interfaces instalados|| WPUPCIF002|Escolher tipo de interface|| # # Configurar AX.25 TNC WPUPCAX001|Configurar AX.25 TNC|| WPUPCAX002|AX.25 nome da porta|| # # Nomes dos dispositivos do interface IFDNL00000|Nada|| IFDNL00001|TNC via a porta serie|| IFDNL00002|Serial TNC c/GPS mais (cabo HSP)|| IFDNL00003|GPS via porta serie|| IFDNL00004|Est. meteorologica via porta serie|| IFDNL00005|Ligacao a um servidor na internet|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS ligado via o servidor gpsd|| IFDNL00008|Est. meteorologica ligada a uma REDE|| IFDNL00009|TNC com GPS na porta AUX|| IFDNL00010|KISS TNC da porta serie|| IFDNL00011|Base de dados de rede (Nao implementado ainda)|| IFDNL00012|AGWPE em rede|| IFDNL00013|Multi-Port KISS TNC da porta serie|| IFDNL00014|SQL Database (Experimental)|| # # Info dispositivo interface IFDIN00000|%s %2d %s sobre serie %s %s|| IFDIN00001|%s %2d %s ligado a %s:%d %s|| IFDIN00002|%s %2d %s usando dispositivo nomeado %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| desligado || IFDIN00007| ligado || IFDIN00008| ERRO || IFDIN00009|DESCONHECIDO|| # # Controle da interface IFPUPCT000|Controle do interface|| IFPUPCT001|Iniciar|| IFPUPCT002|Parar|| IFPUPCT003|Iniciar todos|| IFPUPCT004|Parar todos|| # # Control de I-Gate IGPUPCF000|Opcoes I-Gate|| IGPUPCF001|Desactiva todo o trafego da IGate|| IGPUPCF002|So permite trafego de RF para Inet|| IGPUPCF003|Permite trafego de RF->Inet e Inet->RF|| IGPUPCF004|Caminho Igate -> RF || # # Estao meteorologica WXPUPSI000|Estacao meteorologica|| WXPUPSI001|Tipo de estacao meteorologica|| WXPUPSI002|Datos actuais|| WXPUPSI003|Curso do vento|| WXPUPSI004|Velocidade do vento|| WXPUPSI005|Rajada do vento|| WXPUPSI006|Temperatura|| WXPUPSI007|Total de chuva|| WXPUPSI008|Total de chuva hoje|| WXPUPSI009|Pressao barometrica|| WXPUPSI010|Humidade relativa|| WXPUPSI011|Peet Bros ULTIMETER 2000 Tipo (Modo dados log)|| WXPUPSI012|Peet Bros ULTIMETER II Tipo|| WXPUPSI013|Peet Bros ULTIMETER 2000 Tipo (Modo paquete)|| WXPUPSI014|Horas totais de chuva|| WXPUPSI015|Ultimas 24 tot. de chuvas|| WXPUPSI016|Qualimetricos Q-Net|| WXPUPSI017|Tipo Peet Bros ULTIMETER 2000 (Modo Completo)|| WXPUPSI018|Ponto de Rocio|| WXPUPSI019|Vento alto|| WXPUPSI020|Vento frio|| WXPUPSI021|Indice calorifico|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|Alta temperat.|| WXPUPSI024|Baixa temperat.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Listas das estacoes LHPUPNI000|Todas as estacoes|| LHPUPNI001|Estacoes moveis|| LHPUPNI002|Estacaos meteorologicas|| LHPUPNI003|Estacoes locais (via TNC)|| LHPUPNI004|Ultimas estacoes|| LHPUPNI005|Objectos e items|| LHPUPNI006|Objectos e items proprios|| LHPUPNI010| #|| LHPUPNI011|Indicativo|| LHPUPNI012|#Pack|| LHPUPNI013|Ult. posicao|| LHPUPNI014|Rota|| LHPUPNI015|PHG|| LHPUPNI016|Comentarios|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon ou UTM|| # # Tracar alertas WX sobre mapas PULDNMAT01|Mostra mapa de alarmes sobre outros mapas|| PULDNMAT02|Mostra mapa de alarmes debaixo de outros mapas|| # # Error/popup mensagens POPEM00001|Localiza erro!|| POPEM00002|A estacao %s nao foi encontrada!|| POPEM00003|Rastrear erro!|| POPEM00004|Erro do interface!|| POPEM00005|Nome invalido da porta AX.25 %s|| POPEM00006|Nome invalido da porta AX.25 %s|| POPEM00007|Indicativo invalido %s|| POPEM00008|Indicativo invalido AX.25 destinado ao digipeater|| POPEM00009|Nao posso abrir o interface AX.25, %s|| POPEM00010|Nao posso ligar o interface AX.25, %s|| POPEM00011|Nao posso ligar ao indicativo AX.25, %s|| POPEM00012|AX.25 erro na saida de UI|| POPEM00013|AX.25 problema com o ficheiro /etc/ax25/axports|| POPEM00014|AX.25 nome invalido da porta %s|| POPEM00015|Erro abrindo o interface %d, falha grave|| POPEM00016|Erro abrindo o interface %d tempo esgotado|| POPEM00017|Nao ha mais interfaces disponiveis!|| POPEM00018|Dado requerido - Simples linha de mensagem| POPEM00019|A porta de transmissao esta "off" para a porta %d| POPEM00020|Erro no banco de dados!| POPEM00021|AX.25 nao foi compilado no Xastir!|| POPEM00022|Erro de entrada!| POPEM00023|Nome de localizacao nao especificada!| POPEM00024|Nome de localizacao especificada em uso!| POPEM00025|Nao encontrado!|| POPEM00026|O rastreamento comeara quando ele aparecer|| POPEM00027|Info impropia. Alguns campos vazios?|| POPEM00028|Nao se pode abrir o ficheiro|| POPEM00029|Encontrado!|| POPEM00030|Simbolo da estacao meteorologica|| POPEM00031|Alterado para simbolo de WX '/_', outras opcoes: '\_' '/W' e '\W'|| POPEM00032|Atencao: usando simbolos do servico nacional meteorologico!|| POPEM00033|Nao ha dados GPS!|| POPEM00034|Desactivando a TX da minha posicao ate ter dados validos do GPS!|| POPEM00035|Atencao|| POPEM00036|Aviso|| POPEM00037|Interface HSP presente: tempo de GPS foi aumentado|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Salto de localizacao JMLPO00001|Localizacao de mapa|| JMLPO00002|IR!|| JMLPO00003|Nome da nova localizacao:|| # # Boletins BULMW00001|Boletins|| BULMW00002|Limite de alcance a (0, nao ha limite)|| BULMW00003|Mudanca de alcance|| # # Trafego de todas as mensagens AMTMW00001|Trafego de todas as mensagens|| AMTMW00002|Limite de alcance a (0, nao ha limite)|| # # Cadeias do sintetizador SPCHSTR001|Quilometros|| SPCHSTR002|metros|| SPCHSTR003|milhas|| SPCHSTR004|jardas|| SPCHSTR005|%s, distancia e %d %s.|| SPCHSTR006|%s, distancia e %.1f %s.|| SPCHSTR007|%s, distancia e %d %s %s %s.|| SPCHSTR008|%s, distancia e %.1f %s %s %s.|| SPCHSTR009|Novo alerta de tempo|| SPCHSTR010|Indicativo novo|| SPCHSTR011|Ouvido, D X, %s, na distancia de %.1f %s|| # SPCHDIRN00|norte of|| SPCHDIRS00|sul of|| SPCHDIRE00|este of|| SPCHDIRW00|oeste of|| SPCHDIRNE0|nordeste of|| SPCHDIRNW0|nordoeste of|| SPCHDIRSE0|sudeste of|| SPCHDIRSW0|sudoeste of|| # # Dialogo da seleo do simbolo SYMSEL0001|Selecionar simbolo|| SYMSEL0002|Tabela de simbolo primario|| SYMSEL0003|Tabela de simbolo secundario|| # # Dialogo das propriedades da impressora PRINT0001|Propriedades da impressora|| PRINT0002|Largura do papel|| PRINT0003|Auto-rodar imagem PRINT0004|Rodar imagem 90 CCW|| PRINT0005|Auto-balancear imagem|| PRINT0006|Balanca:|| PRINT0007|Forcar a pre-definida cor de fundo a branco|| PRINT0008|Imprimir em branco e preto|| PRINT0016|Cores invertidas|| PRINT0009|Resolucao do postscript:|| PRINT0010|Prevista|| PRINT0011|Imprimir o ficheiro|| PRINT0012|Guardar imagem num ficheiro...|| PRINT0013|Convertendo para postscript...|| PRINT0014|Criando arquivo de impressao finalizado|| PRINT0015|Estado da impressora|| # # Dialogo das propriedades da impressora PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Dialogo de localizar forma FEATURE001|Nome:|| FEATURE002|Estado/provincia:|| FEATURE003|Pas:|| FEATURE004|Mapa quad:|| FEATURE005|Tipo:|| FEATURE006|GNIS arquivo:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Geocoding Dialog (Nominatim) GEOCODE001|Pesquisar local|| GEOCODE002|Consulta de pesquisa:|| GEOCODE003|Filtro de pas:|| GEOCODE004|Pesquisar|| GEOCODE005|Limpar|| GEOCODE006|Resultados:|| GEOCODE007|Ir para|| GEOCODE008|Marcar|| GEOCODE009|Fechar|| GEOCODE010|Pesquisando...|| GEOCODE011|Nenhum resultado encontrado|| GEOCODE012|Erro: %s|| GEOCODE013|%d resultado(s) encontrado(s)|| GEOCODE014|Dados (C) Colaboradores do OpenStreetMap|| GEOCODE015|Nenhum (Mundial)|| GEOCODE023|Servio no disponvel|| GEOCODE024|Digite um local para pesquisar|| GEOCODE025|Limpar cache|| GEOCODE026|Cache limpo com sucesso|| GEOCODE027|Falha ao limpar o cache|| GEOCODE028|Servidor Nominatim:|| GEOCODE029|Cache habilitado:|| GEOCODE030|Expirao do cache (dias):|| GEOCODE031|E-mail do usurio:|| GEOCODE032|Pas padro:|| GEOCODE033|Configuraes|| GEOCODE034|Salvar|| GEOCODE035|Cancelar|| GEOCODE036|Aplicar|| GEOCODE037|Configuraes de geocodificao|| # # Geocoding Configuration Dialog GEOCFG001|Configuraes de geocodificao|| GEOCFG002|URL do servidor:|| GEOCFG003|Endereo de e-mail:|| GEOCFG004|(Opcional mas recomendado)|| GEOCFG005|Pas padro:|| # # Dialogo do calculo de coordenadas COORD001|Calcular coordenadas|| COORD002|Calc|| COORD003|Calcular|| COORD004|Limpar|| COORD005|UTM|| COORD006|Latitude ou|| COORD007|Longitude ou|| COORD008|Zona|| COORD009|UTM indo para este|| COORD010|UTM indo para norte|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # # Dialogo do smart beaconing SMARTB001|Beaconing esperto|| SMARTB002|Racio alto (secs):|| SMARTB003|Velocidade alta (mph):|| SMARTB004|Velocidade alta (kph):|| SMARTB005|Racio baixo (mins):|| SMARTB006|Velocidade baixa (mph):|| SMARTB007|Velocidade baixa (kph):|| SMARTB008|Voltar ao minimo (deg):|| SMARTB009|Virar encosta:|| SMARTB010|Tempo de espera (secs):|| SMARTB011|Activar SmartBeaconing(tm)|| # # # # Dialogo do gamma adjust GAMMA001|Correccao do ajuste gamma|| GAMMA002|Correccao gamma|| # # # Dialogo das fontes de etiquetas dos mapas MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Muito pequeno Font|| MAPFONT004|Map Font Pequeno|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distancia/rumo na linha de estados PULDNDB001|Estado dist/rumo|| # # # Operacoes transferencias de GPS GPS001|Transferir GPS|| GPS002|Ficheiro|| GPS003|Escolher cor|| GPS004|Vermelho|| GPS005|Verde|| GPS006|Preto|| GPS007|Branco|| GPS008|Laranja|| GPS009|Azul|| GPS010|Amarelo|| GPS011|Violeta|| # # # Dialogo de propriedades dos mapas MAPP001|Propriedades dos mapas|| MAPP002| Max Min Desenhar mapas USGS|| MAPP003| Zoom Zoom Camada Preenchido DRG AutoMapa Caminho/Ficheiro|| MAPP004|Mudar camada->|| MAPP005|Preenchido->|| MAPP006|Sim|| MAPP007|Nao|| MAPP008|Automapas->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # # Marcas do tempo TIME001|Dia|| TIME002|Dias|| TIME003|Hora|| TIME004|Horas|| TIME005|Minuto|| TIME006|Minutos|| TIME007|Segundo|| TIME008|Segundos|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/language-Spanish.sys0000664000175000017500000012170115151324131020516 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Este es el archivo del Lenguaje Espaol usado para todas, consultas en Xastir. # # Creador : por Jose R. Marte A. # Mantenido por : El Xastir Grupo # Ult. Revisin : 05/20/2003, Por Jose R. Marte A. # # Lneas de comentarios con un signo de libra en frente son ignorado # El formato del archivo es como sigue: # Id (10 caractres alfa numrico)|(Cadena asociada con id)|TeclaRpida|#comentario # # AVISO: # Algunas cadenas de letras contienen comando de formato como %s y %d, usted no # debera cambiar eso. Cadena de formatos errados podran producir un segfault! # # Men Principal MENUTB0001|Archivo|A| MENUTB0002|Visualizar|V| MENUTB0004|Mapas|M| MENUTB0005|Estaciones|S| MENUTB0006|Mensajes|e| MENUTB0010|Interfaces|I| MENUTB0009|Ayuda|y| # # Men archivo PULDNFI001|Configurar|C| PULDNFI002|Abrir Bitcora|B| PULDNFI003|Prueba|P| PULDNFI004|Salir|S| PULDNFI007|Cambia nivel Depuracin|D| PULDNFI010|Bitcora del TNC|T| PULDNFI011|Bitcora de Internet|I| PULDNFI012|Bitcora del I-Gate|G| PULDNFI013|Bitcora del WX|W| PULDNFI014|Activa PNG Instantnea|| PULDNFI015|Imprimir Mapa|P| PULDNFI016|KML Snapshots|| # # Men visor PULDNVI001|Boletines|B| PULDNVI002|Datos entrantes|D| PULDNVI003|Estaciones Mviles|M| PULDNVI004|Todas las Estaciones|T| PULDNVI009|Estaciones Locales|L| PULDNVI012|ltimas Estaciones|U| PULDNVI005|Estaciones Meteorolgicas|E| PULDNVI008|Su Estacin Meteorolgica|S| PULDNVI007|Alerta del tiempo|A| PULDNVI011|Trficos de Mensajes|f| PULDNVI013|Tiempo de Inicio|I| PULDNVI014|Tiempo Transcurrido|| PULDNVI015|GPS Status|| PULDNVI016|ALOHA Statistics|| # # Men de Configuracin PULDNCF004|Estacin|E| PULDNCF001|Predefinidos|P| PULDNCF003|Cronmetro|t| PULDNCF002|Sistema de Coordenada|C| PULDNCF006|Alarmas de Audio|A| PULDNCF007|Sintetizador de Voz|S| PULDNCF008|Guardar Configuracin!|G| # # Men de Mapas PULDNMP001|Seleccionar Mapas|M| PULDNMP012|Saltar a una Locacin|S| PULDNMP014|Localice rasgo del Mapa|L| PULDNMP016|Disable Fast Zoom/Pan/Home|| PULDNMP013|Desactive todos los Mapas|| PULDNMP002|Activar Auto Mapas|| PULDNMP003|Rejillas sobre Mapa|| PULDNMP004|Niveles de Mapas|| PULDNMP010|Etiquetas de Mapas|| PULDNMP009|Activar Areas Coloridas|| PULDNMP007|Alerta Mapa WX|| PULDNMP005|Color de fondo|C| PULDNMP006|Etiquetas de estiones|E| PULDNMP026|Icon Outline Style|O| PULDNMP011|Men Indicador del Ratn|R| PULDNMP008|Intensidad del Mapa|I| PULDNMP021|Auto Mapa - Desactivar Mapas de Trama|| PULDNMP022|Indezar Mapas en Inicio|| PULDNMP023|Indice: Agregar Nuevos Mapas|A| PULDNMP024|Indice: Reindezar TODOS los Mapas|T| PULDNMP025|Fonts|| PULDNMP015|Xfontsel|| PULDNMP027|Re-download Maps (Not from cache)|| PULDNMP028|Flush Entire Map Cache!|| PULDNMP029|Buscar ubicacin|| PULDNMP030|Configure USGS DRG|| PULDNMP031|Enable Map Border|| PULDNMP032|Configuracin de geocodificacin|| MPUPTGR017|Internet Map Timeout (segundo)|| # # PopUp "Configure USGS DRG" MPUPDRG001|Select items to be displayed:|| MPUPDRG002|Tint Underlying Map (XOR)|| MPUPDRG003|Black|| MPUPDRG004|White|| MPUPDRG005|Blue|| MPUPDRG006|Red|| MPUPDRG007|Brown|| MPUPDRG008|Green|| MPUPDRG009|Purple|| MPUPDRG010|Yellow|| MPUPDRG011|Light Blue|| MPUPDRG012|Light Red|| MPUPDRG013|Light Purple|| MPUPDRG014|Light Gray|| MPUPDRG015|Light Brown|| # # Seleccion de Mapas WPUPMCP001|Seleccin de Mapa|| PULDNMMC01|Limpiar|N| PULDNMMC02|Vectores|V| PULDNMMC03|250k Topo|2| PULDNMMC04|100k Topo|1| PULDNMMC05|24k Topo|4| PULDNMMC06|Expandir Dirs||| PULDNMMC07|Dirs/Mapas Seleccionado:|| PULDNMMC08|Clear Dirs|C| PULDNMMC09|Select All|S| # # Colores de fondo del mapa PULDNMBC01|Gris|| PULDNMBC02|Rosado Mstico|| PULDNMBC03|Azul Marino|| PULDNMBC04|Azul acerado|| PULDNMBC05|Med. Verde mar|| PULDNMBC06|Verde Plido|| PULDNMBC07|Dorado Plido|| PULDNMBC08|Dorado Amarillo|| PULDNMBC09|Marrn Rosado|| PULDNMBC10|Rojo ladrillo|| PULDNMBC11|Blanco|| PULDNMBC12|Negro|| # # Mapas Estaciones estilos de etiquetas PULDNMSL01|Fondo Negro|| PULDNMSL02|Fondo Gris|| PULDNMSL03|Texto en Negro|T| PULDNMSL04|DropShadow|| # # PullDown "Icon Outline Style" PULDNMIO01|No Outline|N| PULDNMIO02|Black Outline|B| PULDNMIO03|Grey Outline|G| PULDNMIO04|White Outline|W| # # Switches ON/OFF/Corto PULDNOT001|On|| PULDNOT002|Off|| PULDNOT003|Corto|| # # Men de Despliegue de Estaciones PULDNDP014|Localizar Estacin|L| PULDNDP001|Rastreo de Estacin|E| PULDNDP022|Sacar Rastro de Findu|F| PULDNDP032|Filtrar Datos|| PULDNDP040|- Seleccionar Nada|| PULDNDP041|- Seleccionar Mo|| PULDNDP042|- Seleccionar TNC|| PULDNDP027|- Seleccionar Directo|| PULDNDP043|- Seleccionar Va Digi|| PULDNDP034|- Seleccionar Red|| PULDNDP019|Incluir Datos Expirados|| PULDNDP044|- Seleccionar Estaciones|| PULDNDP028|- Seleccionar Estaciones Fijas|| PULDNDP029|- Seleccionar Estaciones Mviles|| PULDNDP030|- Seleccionar Estaciones de WX|| PULDNDP053| - Select CWOP WX Stations|| PULDNDP045|- Seleccionar Objetos/Artculos|| PULDNDP026|- Seleccionar Objetos/Artculos de WX|| PULDNDP039|- Seleccionar Objetos/Artculos Medidores de Agua|| PULDNDP031|- Seleccionar Otros Objetos/Artculos|| PULDNDP057|- Seleccione los objetos aeronuticos/Artculos|| PULDNDP058|- Seleccionar objetos del buque / Artculos|| PULDNDP033|Filtrar Visualizacin|| PULDNDP010|Mostrar Indicativo|I| PULDNDP012|Mostrar Smbolo|D| PULDNDP011|- Smbolo Rotado|S| PULDNDP007|Mostrar Rastros|R| PULDNDP003|Mostrar Curso|C| PULDNDP004|Mostrar Velocidad|V| PULDNDP017|- Mostrar Velocidad Corta|| PULDNDP002|Mostrar Altura|A| PULDNDP009|Mostrar Informe del Tiempo|T| PULDNDP046|- Mostrar Texto|| PULDNDP018|- Slo la Temperatura|| PULDNDP047|- Mostrar Indicacin de Viento|| PULDNDP054|Display Aloha Circle|| PULDNDP013|Mostrar Ambigedad de Posicin|| PULDNDP008|Mostrar Potencia/Ganancia|P| PULDNDP021|- Usar Pot/Ganancia por Defecto|| PULDNDP020|- Mostrar Pot/Ganancia Mviles|| PULDNDP023|Mostrar atributos DF|| PULDNDP123|Display DF Beamwidth|| PULDNDP223|Display DF Bearing|| PULDNDP035|Activar Conteo-Muerto|| PULDNDP036|- Mostrar Arco|| PULDNDP037|- Mostrar Curso|| PULDNDP038|- Mostrar Smbolo|| PULDNDP005|Mostrar Orientacin/Distancia|D| PULDNDP024|Mostrar Tiempo del Ultimo Informe|| PULDNDP015|Anular Todas las Estaciones|A| PULDNDP016|Limpiar Rastros|n| PULDNDP025|Limpiar Historia de Objeto/Artculo|| PULDNDP048|Recargar Historia de Objeto/Artculo|| PULDNDP049|Clear All Tactical Calls|| PULDNDP050|Clear Tactical Call History|| PULDNDP051|Select Tactical Calls Only|| PULDNDP052|- Label Trailpoints|| PULDNDP055|Export All|E| PULDNDP056|Export to KML File|| # # Inglesa/Mtrica PULDNUT001|Activar Unidades Inglesa|| PULDNUT002|Mtrica|| # # Men de Mensajes PULDNMG001|Enviar Mensaje A|E| PULDNMG002|Abrir Mensajes Grupos|G| PULDNMG003|Anular todos mensajes saliente|B| PULDQUS001|Pregunta General a Estaciones|P| PULDQUS002|Pregunta a Estaciones I-Gate|I| PULDQUS003|Pregunta a Estaciones WX|W| PULDNMG004|Fijar Mensaje en Contestacin Automtica|F| PULDNMG005|Activar Auto contestacin de Mensaje|A| PULDNMG006|Satlite Modo de Reconocimiento|M| PULDNMG007|Show Pending Messages|P| # # Men de Interfaces PULDNTNT04|Interface Control|| PULDNTNT03|Desactivar Transmitir: TODOS|| PULDNTNT05|Desactivar Transmitir: Mi Posicin|| PULDNTNT06|Desactivar Transmitir: Objetos/Artculos|| PULDNTNT11|Enable Server Port|| PULDNTNT01|Transmitir Ahora..!|T| PULDNTNT07|Coger Huella de GPS|F| PULDNTNT08|Coger Rutas de GPS|R| PULDNTNT09|Coger VaPuntos de GPS|W| PULDNTNT10|Fetch Garmin RINO Waypoints|G| # # Men de Ayuda PULDNHEL01|Acerca de|A| PULDNHEL02|Indice de Ayuda|I| PULDNHEL03|EMERGENCY BEACON MODE ENABLE|E| PULDNHEL04|!!! EMERGENCY BEACON MODE !!!|| PULDNHEL05|About Xastir|| # # Men de Ratn POPUPMA001|Opciones|| POPUPMA00c|Centro|| POPUPMA015|Info de estacin|| POPUPMA002|Acercar|A| POPUPMA003|Alejar|l| POPUPMA004|Nivel de Enfoque|N| POPUPMA005|Nivel 1|1| POPUPMA006|Nivel 16|6| POPUPMA007|Nivel 64|4| POPUPMA008|Nivel 256|2| POPUPMA009|Nivel 1024|0| POPUPMA010|Nivel 8192|8| POPUPMA017|El Mundo Entero|E| POPUPMA016|Ultima Pos/Enfoque del Mapa|P| POPUPMA018|Crear Objeto/Artculo|C| POPUPMA019|Modificar Objeto/Artculo|M| POPUPMA025||Mover Mi Estacin Aqu|A| POPUPMA011|Paneo arriba|u| POPUPMA012|Paneo abajo|d| POPUPMA013|Paneo izquierda|l| POPUPMA014|Paneo derecha|r| POPUPMA020|Medida|| POPUPMA021|Movimiento|| POPUPMA022|RastreMe|| POPUPMA023|Modificadores Encontrado!|| POPUPMA024|Por favor apague OFF CapsLock/NumLock/ScrollLock/otro modificadores|| POPUPMA026|Centre & Enfoque|| POPUPMA027| Latitud|| POPUPMA028| Longitud|| POPUPMA029|Dibuje Objetos CAD|| POPUPMA030|Draw|| POPUPMA031|Cierre el Polgono|| POPUPMA032|Erase CAD Polygons|| POPUPMA033|**NOT USED**|| POPUPMA034|Custom Zoom Level|| POPUPMA035|10% out|| POPUPMA036|10% in|| POPUPMA037|Area|| POPUPMA038|square|| POPUPMA039|square feet|| POPUPMA040|square meters|| POPUPMA041|Bearing|| POPUPMA042|degrees|| POPUPMA043|Modify ambiguous position|| POPUPMA044|Position abiguity is on, your new position may appear to jump.|| POPUPMA045|Predefined Objects|| POPUPMA046|CAD Polygons|| POPUPMA047|Enable CAD objects|| POPUPMA048|Enable CAD labels|| POPUPMA049|Enable CAD comments|| POPUPMA050|Enable CAD probability|| POPUPMA051|Enable CAD area size|| POPUPMA052|sq|| POPUPMA053|ft|| POPUPMA054|meters|| POPUPMA055|mi| # # Men de Estados de la lneas de Etiquetas BBARZM0001|Foco %s|| BBARZM0002|Foco %s Tr|| BBARSTH001|%d/%d Estaciones|| BBARSTA000|%-9s Nuevo objeto!|| BBARSTA001|%-9s Nueva estacin!|| BBARSTA002|%s|| BBARSTA003|Cargando mapas...|| BBARSTA004|Mapas cargados...|| BBARSTA005|Mapa Lat/Long Rejilla es ON|| BBARSTA006|Mapa Lat/Long Rejilla es OFF|| BBARSTA007|El uso de Auto Mapas, es ON|| BBARSTA008|El uso de Auto Mapas, es OFF|| BBARSTA009|Los Niveles del Mapa estn ON|| BBARSTA010|Los Niveles del Mapa estn OFF|| BBARSTA011|Auto contestacin de Mensaje es OFF!|| BBARSTA012|Achivo creado..|| BBARSTA013|Abriendo Puerto GPS|| BBARSTA014|Cerrando Puerto GPS|| BBARSTA015|Obtenido GPS RMC Cordn|| BBARSTA016|Obtenido GPS GGA Cordn|| BBARSTA017|Red desconectada del Servidor|| BBARSTA018|Conexin a Red tiempo vencido!|| BBARSTA019|Buscando Servidor %s|| BBARSTA020|Conectado al %s|| BBARSTA021|Fracaso en conexin de la Red!|| BBARSTA022|Podra no atar el scalo!|| BBARSTA023|No IP para el Servidor!|| BBARSTA024|No Servidor Especificado|| BBARSTA025|Servidor encontrado, Conectando %d|| BBARSTA026|Esperando por datos del GPS va HSP..|| BBARSTA027|Limpiando el HSP datos obtenido del TNC..|| BBARSTA028|Cargando %s|| BBARSTA029|Abriendo Puerto WX|| BBARSTA030|Cerrando Puerto WX|| BBARSTA031|Buscando el Servidor %d|| BBARSTA032|Datos de WX Decodificado|| BBARSTA033|Eco desde digipeater|| BBARSTA034|Cargando Mapas de alerta WX|| BBARSTA035|Esperando por datos del GPS va AUX..|| BBARSTA036|Limpiando el AUX datos obtenido del TNC..|| BBARSTA037|Datos de GPS Decondificado|| BBARSTA038|Coloque el cambio en mi estacin|| BBARSTA039|Indezando %s|| BBARSTA040|Estacin de Aficionado APRS(tm) %s|| BBARSTA041|Esperando por GPS data..|| BBARSTA042|Transmitiendo objetos/articulos|| BBARSTA043|Anotando|| BBARSTA044|ALOHA distance is %d%s|| BBARSTA045|Loading symbols...|| BBARSTA046|Reloading symbols...|| BBARSTA047|Initialize my station...|| BBARSTA048|Start interfaces...|| BBARSTA049|Reading tiles...|| BBARSTA050|Downloading tiles...|| BBARSTA051|Downloading tile %li of %li|| # # Despliegue Paquete de Datos WPUPDPD001|Despligue de Datos|| WPUPDPD002|slo datos del TNC|| WPUPDPD003|slo datos de la Red|| WPUPDPD004|Datos del TNC y la Red|| WPUPDPD005|TNC|| WPUPDPD006|RED|| WPUPDPD007|Station Capabilities|| WPUPDPD008|Mine Only|| # # Localizar Estacin WPUPLSP001|Localizar estacin|| WPUPLSP002|Localizar Indicativo|| WPUPLSP003|Macheo Sensible|S| WPUPLSP004|Macheo Exacto|E| WPUPLSP005|Localizar ahora!|A| WPUPLSP006|Localizar Emergencia!|| WPUPLSP007|FCC/RAC Lookup|| # # Configurar predefinidos WPUPCFD001|Configurar valores predefinidos|| WPUPCFD002|desde qu intrvalo de tiempo ser considerada una estacin vieja?|| WPUPCFD003|15 minutos|1| WPUPCFD004|30 minutos|3| WPUPCFD005|45 minutos|4| WPUPCFD006|1 hora|H| WPUPCFD007|90 minutos|9| WPUPCFD008|2 horas|2| WPUPCFD009|desde qu intrvalo de tiempo la estacin no ser desplegada?|| WPUPCFD010|6 horas|6| WPUPCFD011|12 horas|o| WPUPCFD012|1 Da|D| WPUPCFD013|2 Das|s| WPUPCFD014|1 semana|n| WPUPCFD015|Opcin modo de Transmisin de la estacin|| WPUPCFD016|Estacin Fija|F| WPUPCFD017|Estacin Mvil c/Hora local|l| WPUPCFD018|Estacin Mvil c/Fecha-hora Zlu|Z| WPUPCFD019|Estacin Mvil c/Horas-segundos Zlu|u| WPUPCFD021|Posicin de la estacin c/Tiempo|T| WPUPCFD022|Posicin de la estacin, fecha-hora Zulu, y Tiempo|f| WPUPCFD023|Transmitir datos WX en Raw?|| WPUPCFD024|Comprimir datos objeto/artculo cuando transmita?|| WPUPCFD025|Activar Red Alternada?|A| WPUPCFD026|Enviar reportes de posicin en qu intrvalos?|| WPUPCFD027|Mostrar bulletines Nuevo|| WPUPCFD028|Avisar si hay teclas Modificadora|| WPUPCFD029|Ver boletines de zero-distancia|| WPUPCFD030|Disable Posit Dupe-Checks|| WPUPCFD031|Load predefined objects from file|| WPUPCFD032|My trails in one color|| WPUPCFD033|ALTNET:|| # # Menu "Configurar - Cronmetro" WPUPCFTM01|Configurar Cronmetro|| WPUPCFTM02|TX Posicin Intrvalo (minutos)|| WPUPCFTM03|Desvanecimiento de la Estacin (minutos)|| WPUPCFTM04|Objeto/Artculo TX Max Intrvalo (minutos)|| WPUPCFTM05|Limpiar Tiempo de la Estacin (horas)|| WPUPCFTM06|Chequeo Intrvalo del GPS (segundos)|| WPUPCFTM07|Borrar Tiempo de la Estacin (das)|| WPUPCFTM08|Descanso Conteo-Muerto (minutos)|| WPUPCFTM09|Serial Inter-Char Delay (ms)|| WPUPCFTM10|Nuevo Tiempo Rastro (min)|| WPUPCFTM11|Nuevo Interval Rastro (grados)|| WPUPCFTM12|RINO -> Objects Interval (min), 0 = Disabled|| WPUPCFTM13|Snapshot Interval (min)|| WPUPCFTM14|Aircraft Ghost/Clear Time (min), 0 = Disabled|| # # Configurar Sistema de Coordenada" WPUPCFC001|Configurar Sistema de Coordenada|| WPUPCFC002|Seleccione Sistema de Coordenada|| WPUPCFC003|dd.ddddd|d| WPUPCFC004|dd mm.mmm|m| WPUPCFC005|dd mm ss.s|s| WPUPCFC006|UTM|U| WPUPCFC007|USNG/MGRS2|| WPUPCFC008|UTM con zonas especiales|| # # Configurar GPS WPUPCFG001|Configurar GPS|| WPUPCFG003|Puerto exclusivo de GPS|| WPUPCFG002|Usar Posicin GPS?|| WPUPCFG004|opciones del GPS|| WPUPCFG005|GPS Exclusivo|| WPUPCFG006|TNC conectado a GPS (Cable HSP)|| WPUPCFG007|TNC conectado a GPS usando CTL-E|| WPUPCFG008|GPS tiempo (Muestreo cada)|| WPUPCFG009|5 sec|| WPUPCFG010|15 sec|| WPUPCFG011|30 sec|| WPUPCFG012|1 minuto|| WPUPCFG013|2 minutos|| WPUPCFG014|5 minutos|| WPUPCFG015|10 minutos|| WPUPCFG016|Red conectada al GPS|| WPUPCFG017|Servidor GPSD|| WPUPCFG018|Puerto GPSD|| WPUPCFG019|Red GPS va GPSD|| WPUPCFG020|Reconectar en fallo?|| WPUPCFG021|Red Conectada a WX|| WPUPCFG022|Servidor WX|| WPUPCFG023|Puerto WX|| # # Configurar TNC (baudio tambin son para WX) WPUPCFT001|Configurar TNC|| WPUPCFT002|Usar TNC?|| WPUPCFT003|Puerto TNC|| WPUPCFT004|Velocidad del Puerto|| WPUPCFT005|300 bps|| WPUPCFT006|1200 bps|| WPUPCFT007|2400 bps|| WPUPCFT008|4800 bps|| WPUPCFT009|9600 bps|| WPUPCFT010|19200 bps|| WPUPCFT011|Rutas del UnProto|| WPUPCFT012|Ruta 1: %s va || WPUPCFT013|Ruta 2: %s va || WPUPCFT014|Ruta 3: %s va || WPUPCFT015|Modo del Puerto|| WPUPCFT016|8,N,1|| WPUPCFT017|7,E,1|| WPUPCFT018|7,O,1|| WPUPCFT019|38400 bps|| WPUPCFT020|57600 bps|| WPUPCFT021|115200 bps|| WPUPCFT022|230400 bps|| WPUPCFT023|Configurar el TNC c/HSP GPS|| WPUPCFT024|Tipo de Data|| WPUPCFT025|Auto deteccin|| WPUPCFT026|Tipo Binario|| WPUPCFT027|Tipo ASCII|| WPUPCFT028|Configurar el TNC c/AUX GPS|| WPUPCFT029|Configurar el TNC c/MAL ENUM: %d|| WPUPCFT030|Configurar un KISS TNC|| WPUPCFT031|Archivos de Configuracin del TNC|| WPUPCFT032|Arreglar Archivo del TNC|| WPUPCFT033|Archivo de apagar TNC|| WPUPCFT034|Parmetros TNC KISS modo|| WPUPCFT035|TXDelay (10 ms unidades)|| WPUPCFT036|Persistence (0 to 255)|| WPUPCFT037|SlotTime (10 ms unidades)|| WPUPCFT038|TxTail (10 ms unidades)|| WPUPCFT039|Full Duplex|| WPUPCFT040|Configurar un Multi-Port KISS TNC|| WPUPCFT041|Radio Port|| WPUPCFT042|Dubious UNPROTO Path!|| WPUPCFT043|Please consider a shorter path such as WIDE2-2 or WIDE1-1,WIDE2-2|| WPUPCFT044|Dubious IGATE Path!|| WPUPCFT045|Transmitting w/Dubious UNPROTO Path!|| WPUPCFT046|Transmitting w/Dubious IGATE Path!|| WPUPCFT047|Init KISS-mode on startup|| # # Configurar el Puerto de la Estacin Meteorolgica WPUPCFWX01|Configurar el Puerto de la Estacin Meteorolgica|| WPUPCFWX02|Dispositivo de la Estacin Meteorolgica|| WPUPCFWX03|Tipo Medida de lluvia (Configuracin Global)|| WPUPCFWX04|0.1 pg / 2.5 mm|| WPUPCFWX05|0.01 pg / 0.25 mm|| WPUPCFWX06|0.1 mm|| WPUPCFWX07|No Correccin|| # # Configurar la Estacin WPUPCFS001|Configurar la estacin|| WPUPCFS002|Indicativo|| WPUPCFS003|Latitud|| WPUPCFS004|grd|| WPUPCFS005|min|| WPUPCFS006|(N/S)|| WPUPCFS007|Longitud|| WPUPCFS008|(E/W)|| WPUPCFS009|Smbolo de la estacin|| WPUPCFS010|Grupo/sobrepuesto|| WPUPCFS011|Smbolo|| WPUPCFS028|Seleccione|| WPUPCFS012|Potencia - Altura (HAAT) - Ganancia y Direccin|| WPUPCFS013|Desactive PHG|| WPUPCFS014|Altura de la Antena|| WPUPCFS015|Ganancia de la Antena|| WPUPCFS016|Omni|| WPUPCFS017|Comentarios:|| WPUPCFS018|Posicin ambiga|| WPUPCFS019|Ninguna|| WPUPCFS020|.11 milla|| WPUPCFS021|1.15 millas|| WPUPCFS022|11.51 millas|| WPUPCFS023|69.09 millas|| WPUPCFS024|.18 kilmetro|| WPUPCFS025|1.85 kilmetros|| WPUPCFS026|18.53 kilmetros|| WPUPCFS027|111.19 kilmetros|| WPUPCFS029|Envo de posicin comprimida|C| # # Dilogo de Objeto/Artculo POPUPOB001|Objeto/Arculo|| POPUPOB002|Nombre:|| POPUPOB003|Crear Nuevo Objeto|| POPUPOB004|Borrar Objeto|| POPUPOB005|Modificar Objeto|| POPUPOB006|Crear Nuevo Artculo|| POPUPOB007|Area de Objeto|| POPUPOB008|Activar Area de Objeto|| POPUPOB009|Color Luminoso|| POPUPOB010|Area Colorida|| POPUPOB011|Crculo|| POPUPOB012|Lnea-Derecha '/'|| POPUPOB013|Lnea-Izquierda '\'|| POPUPOB014|Tringulo|| POPUPOB015|Rectngulo|| POPUPOB016|Negro|| POPUPOB017|Azul|| POPUPOB018|Verde|| POPUPOB019|Cian|| POPUPOB020|Rojo|| POPUPOB021|Violeta|| POPUPOB022|Amarillo|| POPUPOB023|Gris|| POPUPOB024|Compense Arriba:|| POPUPOB025|Compense Izq.(Excepto '/'):|| POPUPOB026|Corridor:|| POPUPOB027|Opciones Genricas|| POPUPOB028|Situacin|| POPUPOB029|Activar Letrero|| POPUPOB030|Data:|| POPUPOB031|Letrero Objeto|| POPUPOB032|Activar Compresin|| POPUPOB033|Borrar Artculo|| POPUPOB034|Modificar Artculo|| POPUPOB035|Altitud (Pies):|| POPUPOB036|Velocidad (Nudos):|| POPUPOB037|Curso:|| POPUPOB038|DF Objeto|| POPUPOB039|Seal - Altura(HAAT) - Ganancia - Direccin|| POPUPOB040|Dirigiendo - Ancho de la orientacin|| POPUPOB041|Antena Omni-direccional|| POPUPOB042|Antena Direccional|| POPUPOB043|Intil|| POPUPOB044|Adopt Object|| POPUPOB045|Adopt Item|| POPUPOB046|DF Bearing:|| POPUPOB047|Probability Circles|| POPUPOB048|Map View Object|| POPUPOB049|Min (mi):|| POPUPOB050|Max (mi):|| # # Configurar Internet WPUPCFI001|Configurar Internet|| WPUPCFI002|Servidor|| WPUPCFI003|Puerto|| WPUPCFI004|(Servidores Secundarios)|| WPUPCFI005|Servidor1|| WPUPCFI006|Puerto1|| WPUPCFI007|Servidor2|| WPUPCFI008|Puerto2|| WPUPCFI009|Palabra de Paso|| WPUPCFI010|Dejar en blanco si nada|| WPUPCFI011|Reconectar en fallo de la RED?|| WPUPCFI012|Correr como un I-Gate?|| WPUPCFI013|Difundir mensajes va TNC cuando un I-Gate?|| WPUPCFI014|Bitcora de Transacciones del I-Gate?||| WPUPCFI015|Parametros de Filtrado|| # # Configurar Base de datos WPUPCFID01|Configurar Base de datos(TBD)|| WPUPCFID02|Servidor|| WPUPCFID03|Puerto|| WPUPCFID04|(Servidores Secundarios)|| WPUPCFID05|Servidor1|| WPUPCFID06|Puerto1|| WPUPCFID07|Servidor2|| WPUPCFID08|Puerto2|| WPUPCFID09|Palabra de Paso|| WPUPCFID10|Dejar en blanco si nada|| WPUPCFID11|Reconectar en fallo de la RED?|| WPUPCFID12|Correr como un I-Gate?|| WPUPCFID13|Difundir mensajes va TNC cuando un I-Gate?|| WPUPCFID14|Bitcora de Transacciones del I-Gate?||| WPUPCFID15|Parametros de Filtrado|| # # Menu "Configurar AGWPE" WPUPCFIA01|Configurar AGWPE|| WPUPCFIA02|Servidor || WPUPCFIA03|Puerto || WPUPCFIA04|(Servidores Secundario)|| WPUPCFIA05|Servidor1|| WPUPCFIA06|Puerto1|| WPUPCFIA07|Servidor2|| WPUPCFIA08|Puerto2|| WPUPCFIA09|Codigo de Paso|| WPUPCFIA10|(dejar en blanco si Nada)|| WPUPCFIA11|Reconectar en fallo de RED?|| WPUPCFIA12|Correr como un I-Gate?|| WPUPCFIA13|Difundir mensajes via TNC cuando un I-Gate?|| WPUPCFIA14|Bitcora de Transacciones I-Gate?|| WPUPCFIA15|Transmitir RadioPuerto|| # # Configurar Alarmas de Audio WPUPCFA001|Configurar Alarma de Audio|| WPUPCFA002|Aplicacin Audio|| WPUPCFA003|Alarma ON|| WPUPCFA004|Archivos de Audio|| WPUPCFA005|Nueva estacin|| WPUPCFA006|Nuevo mensaje|| WPUPCFA007|Proximidad|| WPUPCFA008|Banda abierta|| WPUPCFA009|Mnima distancia|| WPUPCFA010|Mxima distancia|| WPUPCFA011|Alerta del Tiempo|| # # Configurar a Festival el sintetizador de Voz WPUPCFSP01|Configurar a Festival el Sintetizador de Voz|| WPUPCFSP02|Fijar en 'ON' la opciones del Sintetizador de Voz|| WPUPCFSP03|<- Anunciar Nueva Estacin|| WPUPCFSP04|<- Anunciar Alerta de Nuevo Mensaje|| WPUPCFSP05|<- Anunciar Cuerpo de Nuevo Mensaje|| WPUPCFSP06|<- Anunciar la Proximidad de estaciones|| WPUPCFSP07|<- Anunciar DX condicin de Banda Abierta|| WPUPCFSP08|<- Anunciar Alerta sobre condiciones del Tiempo|| WPUPCFSP09|<- Estacin Rastreada Alerta de Proximidad|| # # Rastreo de Estacin WPUPTSP001|Rastreo estacin|| WPUPTSP002|Rastreo Indicativo|| WPUPTSP003|Macheo Sensible|| WPUPTSP004|Macheo Exacto|| WPUPTSP005|Rastrear Ahora!|| WPUPTSP006|Limpiar Rastro|| WPUPTSP007|Abajar Rastro|| WPUPTSP008|Indicativo|| WPUPTSP009|Inicio Del Rastro (hace horas)|| WPUPTSP010|Longitud del Rastro (horas)|| # # Men de Mensajes WPUPMSB001|Enviar mensaje %d|| WPUPMSB002|Enviar Mensaje a grupo %d|| WPUPMSB003|Indicativo de Estacin:|| WPUPMSB004|Indicativos de Grupos:|| WPUPMSB005|Nuevo/Refresh Indicativo|| WPUPMSB006|Nuevo grupo|| WPUPMSB007|Clear Msg History|| WPUPMSB008|Mensaje:|| WPUPMSB009|Enviar ahora!|| WPUPMSB010|Ruta:|| WPUPMSB011|Cancel Pending Msgs|| WPUPMSB012|Kick Timer|| WPUPMSB013|seq|| WPUPMSB014|type|| WPUPMSB015|Broadcast|| WPUPMSB016|*TIMEOUT*|| WPUPMSB017|*CANCELLED*|| WPUPMSB018|*REJECTED*|| WPUPMSB019|Change Path|| WPUPMSB020|Use Default Path(s)|| WPUPMSB021|Direct (No path)|| WPUPMSB022|Reverse Path (Hint):|| # # Auto Contestacin WPUPARM001|Cambiar auto Contestacin|| WPUPARM002|Reenviar:|| # # Ayuda / Indice WPUPHPI001|Indice de Ayuda|I| WPUPHPI002|Visualizar|V| # # Informacin de la Estacin WPUPSTI000|Objeto creado desde: %s|| WPUPSTI001|Info Estacin|| WPUPSTI002|Enviar mensaje|| WPUPSTI003|Buscar datos FCC|| WPUPSTI004|Buscar datos RAC|| WPUPSTI005|%d: Paquetes recibidos, ltimo recibido en fecha: || WPUPSTI006|Odo va TNC en dispositivo: %d, || WPUPSTI007|Odo || WPUPSTI008|Ultima vez va Local|| WPUPSTI009|Ultima vez va TNC en dispositivo: %d|| WPUPSTI010|Ultima vez va Internet en dispositivo: %d|| WPUPSTI011|Ultima vez va Archivo|| WPUPSTI012|Ultima vez va Desconocida|| WPUPSTI013|, y ha cambiado posicin|| WPUPSTI014|Actual Potencia/Ganancia:|| WPUPSTI016|Altitud: %.1f%s || WPUPSTI017|Curso: %s || WPUPSTI018|Velocidad: %.1f km/h|| WPUPSTI019|Velocidad: %.1f mph|| WPUPSTI020|%0.1f millas|| WPUPSTI021|%0.1f km|| WPUPSTI022|Distancia desde mi estacin %s, Curso desde mi estacin %s|| WPUPSTI023|Ultima posicin: || WPUPSTI024|Datos de la estacin Meteorolgica %c:%s|| WPUPSTI025|Curso del viento: %s Velocidad: %03d km/h|| WPUPSTI026|Curso del viento: %s Velocidad: %s mph|| WPUPSTI027| Rfaga: %03d Km/h|| WPUPSTI028| Rfaga: %s mph|| WPUPSTI029|Temperatura: %02.1fC || WPUPSTI030|Temperatura: %sF || WPUPSTI031| Humedad: %s%% || WPUPSTI032|Indice de Humedad: %02.1fC || WPUPSTI033| Presin Baromtrica: %s mb|| WPUPSTI034|Nieve: %0.1f (cm/24h)|| WPUPSTI035|Nieve: %0.0f (plg/24h)|| WPUPSTI036|Lluvia: || WPUPSTI037|%0.2f (mm/h) || WPUPSTI038|%0.2f (plg/h) || WPUPSTI039|%0.2f (mm/da) || WPUPSTI040|%0.2f (plg/da) || WPUPSTI041|%0.2f (mm/desde medianoche)|| WPUPSTI042|%0.2f (mm/desde medianoche)|| WPUPSTI043|Ruta de Datos: %s|| WPUPSTI044|Comentarios %02d/%02d %02d:%02d : %s|| WPUPSTI045|Limpiar Rastro|| WPUPSTI046|Total lluvia: || WPUPSTI047|%0.2f (mm)|| WPUPSTI048|%0.2f (plg)|| WPUPSTI049|Preguntar rastro|| WPUPSTI050|Pregunta no-conocido Mensaje|| WPUPSTI051|Pregunta directa a estacin|| WPUPSTI052|Pregunta versin a estacin|| WPUPSTI053|Modificar Objeto/Artculo|| WPUPSTI054|Almacenar Rastro|| WPUPSTI055|Repetido desde:|| WPUPSTI056|Activar Actualizaciones Automtica|| WPUPSTI057|Omni-DF: %s|| WPUPSTI058|Orientando DF: %s|| WPUPSTI059|Estados %02d/%02d %02d:%02d : %s|| WPUPSTI060|Incendio Temp: %02.1fC || WPUPSTI061|Incendio Temp: %sF || WPUPSTI062|Humedad de Incendio: %s%% || WPUPSTI063|Baro: %0.2f en Hg|| WPUPSTI064|Fetch NWS Alert|| WPUPSTI065|Tactical Call: %s|| WPUPSTI066|Assign Tactical Call|| WPUPSTI067|Current Range: %d miles|| WPUPSTI068|none|| WPUPSTI069|default|| WPUPSTI070|HAAT|| WPUPSTI071|omni|| WPUPSTI072|range|| WPUPSTI073|BAD PHG|| WPUPSTI074|BAD SHG|| WPUPSTI075|DF Range|| WPUPSTI076|No signal detected|| WPUPSTI077|Detectible signal (Maybe)|| WPUPSTI078|Detectible signal but not copyable)|| WPUPSTI079|Weak signal, marginally readable|| WPUPSTI080|Noisy but copyable signal|| WPUPSTI081|Some noise, easy to copy signal|| WPUPSTI082|Good signal w/detectible noise|| WPUPSTI083|Near full-quieting signal|| WPUPSTI084|Full-quieting signal|| WPUPSTI085|Extremely strong & full-quieting signal|| WPUPSTI086|BAD BEARING|| WPUPSTI087|BAD NRQ|| WPUPSTI088|DF Beamwidth|| WPUPSTI089|DF Length|| WPUPSTI090|Not Valid|| WPUPSTI091|Change Trail Color|| WPUPSTI092|Clear DF Bearing|| # # # PopUp "ALOHA Statistics" WPUPALO001|ALOHA radius: %d %s|| WPUPALO002|Stations inside ALOHA circle: %d|| WPUPALO003| Digis: %d|| WPUPALO004| Mobiles (in motion): %d|| WPUPALO005| Mobiles (other): %d|| WPUPALO006| WX stations: %d|| WPUPALO007| Home stations: %d|| WPUPALO008|Last calculated %d %s %d %s ago.|| WPUPALO666|ALOHA radius not calculated yet|| # # FCC-RAC buscar Indicativo STIFCC0001|Buscar en Base de datos FCC|| STIFCC0002|Buscar en Base de datos RAC|| STIFCC0003|Nombre:|| STIFCC0004|Calle:|| STIFCC0005|Ciudad:|| STIFCC0006|Estado:|| STIFCC0007|Zona Postal:|| STIFCC0008|Bsica || STIFCC0009|Advanzada || STIFCC0010|5 wpm || STIFCC0011|12 wpm || # # FCC-RAC buscar Indicativo STIFCC0100|FCC index old, rebuilding|| STIFCC0101|Callsign Search|| STIFCC0102|Callsign Not Found!|| STIFCC0103|RAC index old, rebuilding|| # # # Mensaje de Banda abierta UMBNDO0001|en distancia de|| # # Opciones Universales UNIOP00001|Aceptar|| UNIOP00002|Cancelar|| UNIOP00003|Cerrar|| UNIOP00004|millas|| UNIOP00005|km|| UNIOP00006|Dispositivo|| UNIOP00007|Agregar|| UNIOP00008|Anular|| UNIOP00009|Propiedades|| UNIOP00010|Permitir Transmisin?|| UNIOP00011|Activar en Inicio?|| UNIOP00012|km/h|| UNIOP00013|mph|| UNIOP00014|C|| UNIOP00015|F|| UNIOP00016|mm|| UNIOP00017|pg|| UNIOP00018|mm/da|| UNIOP00019|pg/da|| UNIOP00020|mm/hora|| UNIOP00021|pg/hora|| UNIOP00022|mm/med|| UNIOP00023|pg/med|| UNIOP00024|grd|| UNIOP00025|mb|| UNIOP00026|%|| UNIOP00027|pg Hg|| UNIOP00028|mm Hg|| UNIOP00029|Fije el tiempo del sistema del GPS|| UNIOP00030|Digipeat?|| UNIOP00031|m|| UNIOP00032|Apply||| UNIOP00033|Reset|| UNIOP00034|min|| UNIOP00035|hr|| UNIOP00036|day|| UNIOP00037|Send Control-E to get GPS data?|| UNIOP00038|Add Delay|| # # Seleccionar Estacin STCHO00001|Seleccionar Estacin|| # # DESPLIEGUE ALARMA WX WPUPWXA001|Alerta del Tiempo|| WPUPWXA002|Lista de alerta del Tiempo|| # # Configurar Interfaces WPUPCIF001|Interfaces Instalados|| WPUPCIF002|Elegir Tipo de interfz|| # # Configurar AX.25 TNC WPUPCAX001|Configurar AX.25 TNC|| WPUPCAX002|AX.25 nombre de puerto|| # # Nombres de dispositivos de la Interfz IFDNL00000|Nada|| IFDNL00001|TNC va el Puerto Serial|| IFDNL00002|Serial TNC c/GPS ms (cable HSP)|| IFDNL00003|GPS va Puerto Serial|| IFDNL00004|Est. Meteorolgica va Puerto Serial|| IFDNL00005|Conexin a un Servidor en Internet|| IFDNL00006|AX.25 TNC|| IFDNL00007|GPS Enlazado va el Servidor gpsd|| IFDNL00008|Est. Meteorolgica Enlazada a una RED|| IFDNL00009|Serial TNC c/GPS ms (cable AUX)|| IFDNL00010|Serial KISS TNC|| IFDNL00011|Red Base de Datos (Aun No Implementada)|| IFDNL00012|Red AGWPE|| IFDNL00013|Serial Multi-Port KISS TNC|| IFDNL00014|SQL Database (Experimental)|| # # Info dispositivo Interfz IFDIN00000|%s %2d %s sobre serial %s %s|| IFDIN00001|%s %2d %s conectado a %s:%d %s|| IFDIN00002|%s %2d %s usando dispositivo nombrado %s %s|| IFDIN00003|%s %2d %s %s %s %s|| IFDIN00004|%s %2d %s %s %s:%d %s|| IFDIN00005|%s %2d %s %s %s %s|| IFDIN00006| ABAJO || IFDIN00007| ARRIBA || IFDIN00008| ERROR || IFDIN00009|DESCONOCIDO|| # # Control de la interfz IFPUPCT000|Control de Interfz|| IFPUPCT001|Iniciar|| IFPUPCT002|Detener|| IFPUPCT003|Iniciar todos|| IFPUPCT004|Detener todos|| # # Control de I-Gate IGPUPCF000|I-Gate Opciones|| IGPUPCF001|Desactiva todo el IGate trfico|| IGPUPCF002|Slo Permite trfico de RF->Inet|| IGPUPCF003|Permite ambos trficos RF<->Inet|| IGPUPCF004|Igate -> RF Ruta || # # Estacin Meteorolgica WXPUPSI000|Estacin meteorolgica|| WXPUPSI001|Tipo de estacin Meteorolgica|| WXPUPSI002|Datos Actuales|| WXPUPSI003|Curso del viento|| WXPUPSI004|Velocidad del viento|| WXPUPSI005|Rfaga del viento|| WXPUPSI006|Temperatura|| WXPUPSI007|Total lluvia|| WXPUPSI008|Hoy Total lluvia|| WXPUPSI009|Presin Baromtrica|| WXPUPSI010|Humedad Relativa|| WXPUPSI011|Peet Bros ULTIMETER 2000 Tipo (Modo Datos Log)|| WXPUPSI012|Peet Bros ULTIMETER II Tipo|| WXPUPSI013|Peet Bros ULTIMETER 2000 Tipo (Modo Paquete)|| WXPUPSI014|Actual Tot. hora lluvia|| WXPUPSI015|Ultimas 24 Tot. lluvias|| WXPUPSI016|Cualimtricos Q-Net|| WXPUPSI017|Tipo Peet Bros ULTIMETER 2000 (Modo Completo)|| WXPUPSI018|Punto de Roco|| WXPUPSI019|Viento Alto|| WXPUPSI020|Viento Fro|| WXPUPSI021|Indice Caluroso|| WXPUPSI022|3-Hr Baro|| WXPUPSI023|Alta Temperat.|| WXPUPSI024|Baja Temperat.|| WXPUPSI025|Radio Shack WX-200/Oregon Scientific WM-918|| WXPUPSI026|Davis Weather Monitor II/Wizard III/Vantage Pro|| WXPUPSI027|LaCrosse WX-23xx|| WXPUPSI028|Davis APRS Data Logger|| # # Listas de Estaciones LHPUPNI000|Todas las estaciones|| LHPUPNI001|Estaciones mviles|| LHPUPNI002|Estaciones Meteorolgicas|| LHPUPNI003|Estaciones locales (va TNC)|| LHPUPNI004|Ultimas Estaciones|| LHPUPNI005|Objetos y Artculos|| LHPUPNI006|Objetos y Artculos Propio|| LHPUPNI010| #|| LHPUPNI011|Indicativo|| LHPUPNI012|#Pack|| LHPUPNI013|Ult.Posicin|| LHPUPNI014|Ruta|| LHPUPNI015|PHG|| LHPUPNI016|Comentarios|| LHPUPNI100|CSE|| LHPUPNI101|SPD|| LHPUPNI102|ALT.|| LHPUPNI103|Lat|| LHPUPNI104|Long|| LHPUPNI105|#Pack|| LHPUPNI106|LSV|| LHPUPNI107|CFMS|| LHPUPNI108|DFMS|| LHPUPNI200|CSE|| LHPUPNI201|SPD|| LHPUPNI202|GST|| LHPUPNI203|Temp|| LHPUPNI204|Hum|| LHPUPNI205|Baro|| LHPUPNI206|RN-H|| LHPUPNI207|RNSM|| LHPUPNI208|RN24|| LHPUPNI209|Lat/Lon o UTM|| # # Traza Alertas WX sobre mapas PULDNMAT01|Muestra mapa de alarma sobre otros mapas|| PULDNMAT02|Muestra mapa de alarma bajo otros mapas|| # # Error/popup mensajes POPEM00001|Localiza Error!|| POPEM00002|La estacin %s no fue encontrada!|| POPEM00003|Rastreo Error!|| POPEM00004|Interfz Error!|| POPEM00005|Invlido nombre de puerto AX.25 %s|| POPEM00006|Invlido nombre de puerto AX.25 %s|| POPEM00007|Invlido Indicativo %s|| POPEM00008|Invlido Indicativo AX.25 destinacin o digipeater|| POPEM00009|No puedo abrir el scalo AX.25, %s|| POPEM00010|No puedo atar el scalo AX.25, %s|| POPEM00011|No puedo conectar al Indicativo AX.25, %s|| POPEM00012|AX.25 error en la salida de UI|| POPEM00013|AX.25 problema con el archivo axports|| POPEM00014|AX.25 invlido nombre de puerto %s|| POPEM00015|Error abriendo la interfz %d, duro fallo|| POPEM00016|Error abriendo la interfz %d Tiempo agotado|| POPEM00017|No hay mas interfz disponible!|| POPEM00018|Dato requerido - Simple Lnea de Mensaje| POPEM00019|El Puerto de transmisin est "off" para puerto %d| POPEM00020|Error banco de Datos!| POPEM00021|El soporte de AX.25 no est compilado en Xastir!|| POPEM00022|Error de entrada!| POPEM00023|Nombre de locacin no especificada!| POPEM00024|Nombre de Locacin especificada en uso!| POPEM00025|No Encontrado!|| POPEM00026|El Rastreo empezar cuando el aparezca|| POPEM00027|Info Impropia. Algunos campos vaco?|| POPEM00028|No se puede abrir el archivo|| POPEM00029|Encontrado!|| POPEM00030|Smbolo de Estacin Meteorolgica|| POPEM00031|Cambiado a smbolo WX '/_', otras opciones: '\_' '/W' y '\W'|| POPEM00032|Aviso: Usando Smbolo del National Weather Service!|| POPEM00033|No GPS Data!|| POPEM00034|Disactivando TX de Mi Posicin Hasta ver Data de GPS Vlido!|| POPEM00035|Warning|| POPEM00036|Notice|| POPEM00037|HSP interface present: GPS timing has been increased|| POPEM00038|Name Conflicts With Existing Object/Item/Station|| POPEM00039|Illegal characters found, substituting periods in their place|| POPEM00040|Custom outgoing path was lost|| POPEM00041|Processing another file. Wait a bit, then try again|| POPEM00042|Object not owned by me! Try adopting the object first.|| POPEM00043|Not an Object/Item!|| POPEM00044|Fetch Findu Trail: Failed|| POPEM00045|Fetch Findu Trail: Complete|| POPEM00046|Berkeley DB header/shared library do NOT match! Disabling map cache.|| POPEM00047|Global transmit is DISABLED. Emergency beacons are NOT going out!|| POPEM00048|Emergency Beacon Mode!|| POPEM00049|EMERGENCY BEACON MODE, transmitting every 60 seconds!|| POPEM00050|Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!|| POPEM00051|Altnet is enabled (Configure->Defaults dialog)|| POPEM00052|Callsign is EMPTY!|| POPEM00053|Message is EMPTY!|| POPEM00054|We're trying to talk to ourselves!|| # # Salto de Locacin JMLPO00001|Localizacin de Mapa|| JMLPO00002|IR!|| JMLPO00003|Nombre de Nueva Localizacin:|| # # Boletines BULMW00001|Boletines|| BULMW00002|Lmite de Rango a (0, no hay lmite)|| BULMW00003|Cambio de Rango|| # # Trfico de todo los mensajes AMTMW00001|Trfico de todos los mensajes|| AMTMW00002|Lmite de Rango a (0, no hay lmite)|| # # Cadenas del Sintetizador SPCHSTR001|kilmetros|| SPCHSTR002|metros|| SPCHSTR003|millas|| SPCHSTR004|yardas|| SPCHSTR005|%s, distancia es %d %s.|| SPCHSTR006|%s, distancia es %.1f %s.|| SPCHSTR007|%s, distancia es %d %s %s %s.|| SPCHSTR008|%s, distancia es %.1f %s %s %s.|| SPCHSTR009|Nueva Alerta de WX|| SPCHSTR010|Nueva LLamada|| SPCHSTR011|Odo, D X, %s, en distancia de %.1f %s|| # SPCHDIRN00|norte de|| SPCHDIRS00|sur de|| SPCHDIRE00|este de|| SPCHDIRW00|oeste de|| SPCHDIRNE0|noreste de|| SPCHDIRNW0|noroeste de|| SPCHDIRSE0|sureste de|| SPCHDIRSW0|suroeste de|| # # Dilogo de selecin de Smbolo SYMSEL0001|Seleccione Smbolo|| SYMSEL0002|Tabla de Smbolo primario|| SYMSEL0003|Tabla de Smbolo Secundario|| # # Dilogo de la Propiedades de Impresora PRINT0001|Propiedades de Impresora|| PRINT0002|Ancho del Paper|| PRINT0003|Auto-Rotar Imagen PRINT0004|Rotar Imagen 90 CCW|| PRINT0005|Auto-Balancear Imagen|| PRINT0006|Balanza:|| PRINT0007|Forza el predefinido color de fondo a blanco|| PRINT0008|Imprime en Blanco y Negro|| PRINT0016|Colores Revertidos|| PRINT0009|Resolucin de Postscript:|| PRINT0010|Prevista|| PRINT0011|Imprimir al archivo|| PRINT0012|Guardar imagen a un archivo...|| PRINT0013|Convirtiendo a Postscript...|| PRINT0014|Creando archivo de impresin Finalizado|| PRINT0015|Estado de Impresora|| # # Dilogo de la Propiedades de Impresora PRINT1001|Direct to:|| PRINT1002|Via Previewer:|| # # Dilogo de localizar forma FEATURE001|Nombre:|| FEATURE002|Estado/Provincia:|| FEATURE003|Pais:|| FEATURE004|Cuadratura del Mapa:|| FEATURE005|Tipo:|| FEATURE006|GNIS Archivo:|| FEATURE007|Address:|| FEATURE008|City:|| FEATURE009|Mark Destination|| FEATURE010|Zip Code:|| FEATURE011|Geocoding File|| # # Geocoding Dialog (Nominatim) GEOCODE001|Buscar ubicacin|| GEOCODE002|Consulta de bsqueda:|| GEOCODE003|Filtro de pas:|| GEOCODE004|Buscar|| GEOCODE005|Borrar|| GEOCODE006|Resultados:|| GEOCODE007|Ir a|| GEOCODE008|Marcar|| GEOCODE009|Cerrar|| GEOCODE010|Buscando...|| GEOCODE011|No se encontraron resultados|| GEOCODE012|Error: %s|| GEOCODE013|Se encontr/encontraron %d resultado(s)|| GEOCODE014|Datos (C) Colaboradores de OpenStreetMap|| GEOCODE015|Ninguno (Mundial)|| GEOCODE023|Servicio no disponible|| GEOCODE024|Introduzca una ubicacin para buscar|| GEOCODE025|Vaciar cach|| GEOCODE026|Cach vaciada exitosamente|| GEOCODE027|Error al vaciar la cach|| GEOCODE028|Servidor Nominatim:|| GEOCODE029|Cach habilitada:|| GEOCODE030|Expiracin de cach (das):|| GEOCODE031|Correo electrnico del usuario:|| GEOCODE032|Pas predeterminado:|| GEOCODE033|Configuracin|| GEOCODE034|Guardar|| GEOCODE035|Cancelar|| GEOCODE036|Aplicar|| GEOCODE037|Configuracin de geocodificacin|| # # Geocoding Configuration Dialog GEOCFG001|Configuracin de geocodificacin|| GEOCFG002|URL del servidor:|| GEOCFG003|Direccin de correo electrnico:|| GEOCFG004|(Opcional pero recomendado)|| GEOCFG005|Pas predeterminado:|| # # Dilogo de Calcular Coordenada COORD001|Calcula Coordenada|| COORD002|Calc|| COORD003|Calcular|| COORD004|Limpiar|| COORD005|UTM|| COORD006|Latitud o|| COORD007|Longitud o|| COORD008|Zona|| COORD009|UTM Hacia Este|| COORD010|UTM Hacia Norte|| COORD011| Decimal Degrees: || COORD012| Degrees/Decimal Minutes: || COORD013| Degrees/Minutes/Dec. Seconds: || COORD014| Universal Transverse Mercator: || COORD015|Military Grid Reference System: || COORD016| Maidenhead Grid Locator: || COORD017| ** Sorry, your input was not recognized! **|| COORD018| ** Please use one of the following input formats: **|| # # Dilogo Baliza Inteligente SMARTB001|Baliza Inteligente|| SMARTB002|Alta Proporcin (secs):|| SMARTB003|Alta Velocidad (mph):|| SMARTB004|Alta Velocidad (kph):|| SMARTB005|Baja Proporcin (mins):|| SMARTB006|Baja Velocidad (mph):|| SMARTB007|Baja Velocidad (kph):|| SMARTB008|Mnima Vuelta (grados):|| SMARTB009|Vuelta de declive:|| SMARTB010|Tiempo de Espera (secs):|| SMARTB011|Activar Baliza Inteligente(tm)|| # # Dilogo Ajuste de Gamma GAMMA001|Ajuste Correccin de Gamma|| GAMMA002|Correccin Gamma|| # # Map labels font Dialog MAPFONT001|Change Fonts|| MAPFONT002|Fonts|| MAPFONT003|Map Font Minsculo|| MAPFONT004|Map Font Pequeo|| MAPFONT005|Map Font Medio|| MAPFONT006|Map Font Grande|| MAPFONT007|Map Font Enorme|| MAPFONT008|Map Font Border|| MAPFONT009|Menu Font|| MAPFONT010|Station Font|| MAPFONT011|ATV ID Font|| # # Distancia/Orientacin en lnea de estado PULDNDB001|Estado de Distancia/Orientacin|| # # Transferir Operaciones de GPS GPS001|Transferir GPS|| GPS002|Nombre de Archivo|| GPS003|Seleccionar Color|| GPS004|Rojo|| GPS005|Verde|| GPS006|Negro|| GPS007|Blanco|| GPS008|Naranja|| GPS009|Azul|| GPS010|Amarillo|| GPS011|Violeta|| # # Dilogo de Propiedades de Mapa MAPP001|Propiedades de Mapa|| MAPP002|Max Min Dibuja Mapa USGS Auto|| MAPP003|Zoom Zoom Capa Llenado DRG Mapa Sendero/NombreArchivo|| MAPP004|Cambie Capa->|| MAPP005|Llenado->|| MAPP006|S|| MAPP007|No|| MAPP008|Automapas->|| MAPP009|Max Zoom->|| MAPP010|Min Zoom->|| MAPP011|Auto|| MAPP012|USGS DRG->|| # # Cadenas del Tiempo TIME001|Da|| TIME002|Das|| TIME003|Hora|| TIME004|Horas|| TIME005|Minuto|| TIME006|Minutos|| TIME007|Segundo|| TIME008|Segundos|| # # # Map Caching CACHE001|Map now cached|| CACHE002|Loading Cached Map|| CACHE003|Map not found in cache...|| # # # Map Screen Misc RANGE001|RANGE SCALE|| # # # GPS Status GPSS001|WAAS or PPS|| GPSS002|DGPS|| GPSS003|Valid SPS|| GPSS004|Invalid|| GPSS005|Sats/View|| GPSS006|Fix|| GPSS007|!GPS data is older than 30 seconds!|| GPSS008|Simulation|| GPSS009|Manual|| GPSS010|Estimated|| GPSS011|Float RTK|| GPSS012|RTK|| # # # Popup cad_dialog to obtain CAD object data CADPUD001|Area Object|| CADPUD002|Area Label:|| CADPUD003|Comment:|| CADPUD004|Probability (%):|| CADPUD005|OK|| CADPUD006|CAD Dialog|| CADPUD007|Show/Edit Details|| CADPUD008|Cancel|| CADPUD009|Delete CAD objects?|| CADPUD010|Delete All|| CADPUD011|Delete Selected|| CADPUD012|Solid|| CADPUD013|Dashed|| CADPUD014|Double Dash|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA001|XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. || # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA002|XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum.|| # # # Format strings for map metadata in top border #"XASTIR Map of (upper left) to (lower right). UTM m grid, datum. ", MDATA003|XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum.|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST001|MySQL (lat/long)|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST002|Postgreql with Postgis|| # # Text interpretation of integer values of database type and schema type # used for sql database configuration in interface_gui.c # DB_MYSQL XADBMST003|MySQL (spatial)|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA01|Xastir Simple Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA02|Xastir CAD Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA03|Xastir full Schema|| # XASTIR_SCHEMA_SIMPLE] XASCHEMA04|APRSWorld Schema|| Xastir-Release-2.2.4/config/nwsc_ddmmyy.dbfawk0000664000175000017500000000474315151324131020313 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # label_color - color for label # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county polygon shapefiles # which are named c_ddmmyy.dbf. These are used for WX alerts but can also # be used as a map of all US counties. For the WX alert feature, the # key is set to the concatenation of the STATE and FIPS county code # in the same format as the alert->title (e.g. WI_C037). # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:CWA:COUNTYNAME:FIPS:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTYNAME:STATE:FIPS"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=1; fill_color=7; color=8; name=""; filled=1; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} # name: name is just the county name. /^COUNTYNAME=(.*)$/ {name="$1"; font_size=4; next} # also append "County" to the name except for Louisiana, use Parish # (is this the only state that calls them something other than county?): # XXX check this whole LA thing. I think they call them parishes. /^STATE=(LA)$/ {name="$name Parish"; key="$1"; next} /^STATE=(..)$/ {name="$name County"; key="$1"; next} /^FIPS=..(...)$/ {key="$(key)_C$1"; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/nwsfz_ddmmyy.dbfawk0000664000175000017500000000366215151324131020507 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:ZONE:CWA:NAME:STATE_ZONE:TIME_ZONE:FE_AREA:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/nwshzddmmyy.dbfawk0000664000175000017500000000357315151324131020353 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="WFO:NAME:LAT:LON:id"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} #/^ID=(..)(.*)$/ {key="$1_$2"; next} #/^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/nwsmzddmmyy.dbfawk0000664000175000017500000000350715151324131020355 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:GL_WFO:NAME:LON:LAT"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/nwsozddmmyy.dbfawk0000664000175000017500000000360715151324131020360 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS offshore marine zone area polygon shapefiles # which are named ozddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the ID code reformated # to match the alert->title. For example AN_Z081. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:WFO:LON:LAT:LOCATION:NAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="ID:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^ID=(..)(.*)$/ {key="$1_$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/nwsw_ddmmyy.dbfawk0000664000175000017500000000362415151324131020334 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS county warning area polygon shapefiles # which are named w_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the CWA code # reformated to match alert->title. For example: CW_ATAE for CWA TAE. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="OBJECTID:CWA:WFO:LON:LAT:REGION:FULLSTAID:CITYSTATE:CITY:STATE:ST"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="WFO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^WFO=(.*)$/ {name="$1"; key="CW_A$1"; next} Xastir-Release-2.2.4/config/nwsz_ddmmyy.dbfawk0000664000175000017500000000367215151324131020342 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map NWS state zone area polygon shapefiles # which are named z_ddmmyy.dbf. These are used for WX alerts. # For the WX alert feature, the key is set to the STATE_ZONE code, # reformatted to match alert->title (e.g. KS033 is KS_Z033). # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATE:CWA:TIME_ZONE:FE_AREA:ZONE:NAME:STATE_ZONE:LON:LAT:SHORTNAME"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="STATE_ZONE:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key="BOGUS"; lanes=2; fill_color=7; color=8; name=""; filled=0; fill_style=0; pattern=0; display_level=65536; label_level=512; label_color=20; font_size=2; symbol=""} /^STATE_ZONE=(..)(.*)$/ {key="$1_Z$2"; next} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/pointlm.dbfawk0000664000175000017500000000520115151324131017426 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for POINTLM # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUNTYNS:POINTID:FULLNAME:MTFCC"; dbfinfo="STATEFP:COUNTYFP:ANSICODE:POINTID:FULLNAME:MTFCC"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="FULLNAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^FULLNAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=C3/ {display_level=512;color=50; next} # Hospitals /^MTFCC=K12/ {filled=1; fill_color=12; label_color=12; display_level=256; label_level=128; font_size=12; next} # Schools /^MTFCC=K25/ {filled=1; fill_color=5; label_color=5; display_level=256; label_level=64; font_size=10; next} # Airports /^MTFCC=K24/ {filled=1; fill_color=13; label_color=13; display_level=256; label_level=128; font_size=12; next} # buildings /^MTFCC=K/ {filled=1; fill_color=2; label_color=2; display_level=256; next} # PLCC /^MTFCC=L/ {display_level=0; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/predefined_EVENT.sys0000664000175000017500000000620515151324131020377 0ustar hibbyhibby# # # Copyright (C) 2000-2026 The Xastir Group # # This file contains definitions for the Create SAR objects menu # # The objects defined here are typical Public Service Event objects. # # The objects defined here are ones that might be used in a public # service event such as a 5k race. Customize this file to fit your # needs. # # Typical modifications include internationalizing the names and menu text # and adding your own custom objects. # # To select this file as the source of custom objects in the Create SAR # objects menu, use the Load SAR objects menu options in the Configure # defaults dialog (File/Configure/Defaults). # # Lines beginning with # are comments and will be ignored. # # Each line contains a tab separated variable and value pair. # Each set of lines defines an object as specified on the prepared # objects menu. Each set of lines must have variables defined in the # following order: # # NAME The name of the object. # Maximum length = MAX_CALLSIGN - 1 or - 2, to allow for Name1, Name2 # incrementing numbers with multiple objects. # If name ends with a - then the first object will be called Name-1, # the second Name-2, and so on. If name does not end with a - then # The first object will be called Name, the second Name2. # PAGE The APRS symbol code page, / or \ # Maximum length = 1 character. # SYMBOL The APRS symbol specifier. Maximum length = 1 character. # DATA Additional data (such as probability circles) to follow the symbol in # the APRS string for the object # Use DATA NULL if there is no additional data, or omit the DATA line. # Maximum length = PREDEFINED_OBJECT_DATA_LENGTH = 44 # MENU The text to appear on the prepared objects menu for this object. # Maximum length = 25 characters. # HIDDENCHILD NO for entries that appear on the menu. YES for a second # object to be created at the same time as the one above it. # This is a workaround to create an IPP and an IPP_ with different # probability circles in the same place at the same time. # YES is case sensitive. # HIDDENCHILD must be the last line in each object. # # NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required for each object. # # Each set of lines specifying an object should be separated by a blank line # for clarity. Blank lines are ignored. # # The maximum number of objects that can be shown on the predefined object # menu is defined by the constant MAX_NUMBER_OF_PREDEFINED_OBJECTS. NAME ICP PAGE / SYMBOL c DATA NULL MENU ICP: Command Post HIDDENCHILD NO NAME Water PAGE / SYMBOL w DATA NULL MENU Water HIDDENCHILD NO # FirstAid post # "FirstAid" as name will only allow FirstAid1 to FirstAid9 # due to the default length constraint on object names. NAME Aid #NAME FirstAid #NAME Aid- PAGE / # A is blue field with white cross, + is red cross SYMBOL A #SYMBOL + DATA NULL MENU Aid: First Aid #MENU First Aid #MENU Aid-n: First Aid HIDDENCHILD NO NAME Staging PAGE S SYMBOL 0 DATA NULL MENU Staging HIDDENCHILD NO NAME Waypt- PAGE \ SYMBOL m DATA NULL MENU Waypt-n: Waypoint HIDDENCHILD NO NAME Toilets PAGE \ SYMBOL r DATA NULL MENU Toilets HIDDENCHILD NO Xastir-Release-2.2.4/config/predefined_SAR.sys0000664000175000017500000000676415151324131020155 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This file contains definitions for the Create SAR objects menu # # The objects defined here are typical Search and Rescue and ICS objects. # # You may modify this file to produce a custom set of prepared objects. # Typical modification would be changing probability circles from # miles to kilometers, placing probability circles around the PLS # instead of the IPP, internationalizing the names and menu text, # and adding your own standard objects. # # To select this file as the source of custom objects in the Create SAR # objects menu, use the Load SAR objects menu options in the Configure # defaults dialog (File/Configure/Defaults). # # Lines beginning with # are comments and will be ignored. # # Each line contains a tab separated variable and value pair. # Each set of lines defines an object as specified on the prepared # objects menu. Each set of lines must have variables defined in the # following order: # # NAME The name of the object. # Maximum length = MAX_CALLSIGN - 1 or - 2, to allow for Name1, Name2 # incrementing numbers with multiple objects. # If name ends with a - then the first object will be called Name-1, # the second Name-2, and so on. If name does not end with a - then # The first object will be called Name, the second Name2. # PAGE The APRS symbol code page, / or \ # Maximum length = 1 character. # SYMBOL The APRS symbol specifier. Maximum length = 1 character. # DATA Additional data (such as probability circles) to follow the symbol in # the APRS string for the object # Use DATA NULL if there is no additional data, or omit the DATA line. # Maximum length = PREDEFINED_OBJECT_DATA_LENGTH = 44 # MENU The text to appear on the prepared objects menu for this object. # Maximum length = 25 characters. # HIDDENCHILD NO for entries that appear on the menu. YES for a second # object to be created at the same time as the one above it. # This is a workaround to create an IPP and an IPP_ with different # probability circles in the same place at the same time. # YES is case sensitive. # HIDDENCHILD must be the last line in each object. # # NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required for each object. # # Each set of lines specifying an object should be separated by a blank line # for clarity. Blank lines are ignored. # # The maximum number of objects that can be shown on the predefined object # menu is defined by the constant MAX_NUMBER_OF_PREDEFINED_OBJECTS. NAME ICP PAGE / SYMBOL c DATA NULL MENU ICP: Command Post HIDDENCHILD NO NAME Staging PAGE S SYMBOL 0 DATA NULL MENU Staging HIDDENCHILD NO NAME IPP PAGE / SYMBOL / #circles at .75 and 1 miles DATA Pmin0.75,Pmax1.0 #circles at 2 and 3 kilometers #DATA Pmin1.24,Pmax1.86 MENU IPP: InitialPlanningPoint HIDDENCHILD NO NAME IPP_ PAGE / SYMBOL / # circles at .25 and .5 miles DATA Pmin0.25,Pmax0.5 # circles at .5 and 1 kilometers #DATA Pmin0.31,Pmax0.62 MENU [not shown] HIDDENCHILD YES NAME PLS PAGE / SYMBOL / DATA NULL MENU PLS: Point Last Seen HIDDENCHILD NO NAME LKP PAGE / SYMBOL . DATA NULL MENU LKP: Last Known Point HIDDENCHILD NO NAME Base PAGE B SYMBOL 0 DATA NULL MENU Base HIDDENCHILD NO NAME Helibase PAGE H SYMBOL 0 DATA NULL MENU Helibase HIDDENCHILD NO # Using Heli- will produce an object named Heli-1 # with subsequent objects Heli-2, Heli-3, etc. NAME Heli- PAGE / SYMBOL / DATA NULL MENU Heli-n Helispot HIDDENCHILD NO NAME Camp PAGE C SYMBOL 0 DATA NULL MENU Camp HIDDENCHILD NO Xastir-Release-2.2.4/config/stored_track.dbfawk0000664000175000017500000000050515151324131020432 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # BEGIN { dbfinfo="Credits:DateTime:Label; dbffields="Label:DateTime"; } BEGIN_RECORD {key=""; lanes=3; color=12; name=""; filled=0; pattern=0; display_level=65536; label_level=256; label_color=12; symbol=""} /^Label=(.*)$/ {name="$1";} /^DateTime=(.*)$/ {name="$name ($1)";} Xastir-Release-2.2.4/config/tabblock.dbfawk0000664000175000017500000000447515151324131017541 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2008 TigerMaps for TABBLOCK # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March, 2009 # # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line Shapefiles as available at: # http://www.census.gov/geo/www/tiger/tgrshp2008/tgrshp2008.html # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. # 2007FE = dbfinfo="STATEFP:COUNTYFP:COUNTYNS:STATEFP00:COUNTYFP00:TRACTCE00:BLOCKCE00:SUFFIX1CE:BLKIDFP:NAME:MTFCC:UR00:UACE00:FUNCSTAT"; dbfinfo="STATEFP:COUNTYFP:COUNTYNS:STATEFP00:COUNTYFP00:TRACTCE00:BLOCKCE00:SUFFIX1CE:BLKIDFP:NAME:MTFCC:UR:UACE:FUNCSTAT"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="UR:NAME:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=11; fill_color=26; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=26; font_size=0; symbol=""; fill_style=0 } #/^NAME=(.*)$/ {name="$1";next} # item locations /^MTFCC=G5/ {next} /^UR=U/ {display_level=2048;filled=1;color=99;fill_color=99; skip} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tgr2shp.dbfawk0000664000175000017500000002514515151324131017346 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the command: # ogr2ogr -f "ESRI Shapefile" -t_srs "EPSG:4326" out_directory in_directory # # THis file is identical to the file "tgrlk" except for the "dbfinfo" variable # that is used to recognize the signature of the shapefiles. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="MODULE:TLID:SIDE1:SOURCE:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC:FRADDL:TOADDL:FRADDR:TOADDR:FRIADDL:TOIADDL:FRIADDR:TOIADDR:ZIPL:ZIPR:AIANHHFPL:AIANHHFPR:AIHHTLIL:AIHHTLIR:CENSUS1:CENSUS2:STATEL:STATER:COUNTYL:COUNTYR:COUSUBL:COUSUBR:SUBMCDL:SUBMCDR:PLACEL:PLACER:TRACTL:TRACTR:BLOCKL:BLOCKR"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="TLID:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^TLID=(.*)$/ {key=$1; next} # name: concatenate FEDIRP (direction prefix), FENAME (name), # FETYPE (type: Rd, Ln, Pky, etc.) and FEDIRS (direction suffix). # also abbreviate United States Highway to US, etc. /^FEDIRP=(.+)$/ {name="$1 ";next} /^FENAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^FENAME=State Highway (.*)$/ {name="$(name)State $1";next} /^FENAME=State Route (.*)$/ {name="$(name)SR $1";next} /^FENAME=(.*)$/ {name="$(name)$1"; next} /^FETYPE=(.+)$/ {name="$(name) $1"; next} /^FEDIRS=(.+)$/ {name="$(name) $1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway # "P" types denote "Provisional" streets that had not been field checked # or verified through aerial photography as of the date of preparation of # the TIGER/Line data. They are otherwise equivalent to "A" types, and # we'll just display them the same way. /^CFCC=[AP]1/ {lanes=4; color=4; label_level=512; font_size=3; next} /^CFCC=[AP]2/ {lanes=3; color=8; label_level=256; font_size=2; next} /^CFCC=[AP]3/ {lanes=2; color=8; label_level=128; font_size=1; next} /^CFCC=[AP]3[1-6]/ {display_level=256; next} /^CFCC=[AP]3[7-8]/ {display_level=128; next} /^CFCC=[AP]4/ {display_level=96; label_level=16; color=40; lanes=1; next} /^CFCC=[AP]5/ {lanes=2; color=40; display_level=64; font_size=1; next} /^CFCC=[AP]65/ {lanes=2; color=8; pattern=2; font_size=1; next} /^CFCC=[AP]6[^5]/ {color=40; display_level=64; next} /^CFCC=[AP]7[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} /^CFCC=[AP]7[03-9]/ {lanes=1; color=40; pattern=2; display_level=64; next} # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F10$/{color=255; fill_color=255; label_level=32; display_level=512; pattern=0; next} /^CFCC=F/{display_level=0; next} # (G not used by census; tig2aprs uses for special maps) # H: hydrography # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean # H60 - gravel pit or quarry filled with water # H70 - nonvisibile.... # H80 - special water features # H81 - glacier # Don't display hydrology unless zoomed all the way in --- adjust to taste, # in NM anything more than this looks absurd coz every intermittent wash # would show up as a blue line, which is just wrong. /^CFCC=H/ {lanes=0; color=26; fill_color=26; label_color=26; display_level=1;} /^CFCC=H01/ {pattern=0; display_level=512; lanes=1; next} /^CFCC=H02/ {pattern=2; display_level=1; next} /^CFCC=H[124]2/ {lanes=1; pattern=2; display_level=128; next} # These filled patterns don't actually work: the tiger shapefiles produced # by ogr2ogr do not have the polygon features readily accessible! /^CFCC=H[34][01]/ {lanes=1; pattern=0; filled=1; fill_style=0; display_level=512; next} /^CFCC=H32/ {lanes=1; pattern=1; filled=1; fill_style=1; display_level=512; next} /^CFCC=H[1-6][013-9]/ {lanes=1; display_level=512; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1; display_level=1} /^CFCC=H81/ {color=15; fill_color=15; display_level=256; next} # X00 - feature not yet classified # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tgr2shppoly.dbfawk0000664000175000017500000002544715151324131020257 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the Xastir_tigerpoly.py utility # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="MODULE:FILE:CENID:POLYID:STATECU:COUNTYCU:TRACT:BLOCK:BLOCKSUFCU:RS_A1:AIANHHFPCU:AIANHHCU:AIHHTLICU:ANRCCU:AITSCECU:AITSCU:CONCITCU:COUSUBCU:SUBMCDCU:PLACECU:SDELMCU:SDSECCU:SDUNICU:RS_A20:RS_A21:RS_A22:CDCU:ZCTA5CU:ZCTA3CU:RS_A4:RS_A5:RS_A6:RS_A7:RS_A8:RS_A9:CBSACU:CSACU:NECTACU:CNECTACU:METDIVCU:NECTADIVCU:RS_A14:RS_A15:RS_A16:RS_A17:RS_A18:RS_A19:STATE:COUNTY:BLKGRP:AIANHHFP:AIANHH:AIHHTLI:ANRC:AITSCE:AITS:CONCIT:COUSUB:SUBMCD:PLACE:SDELM:SDSEC:SDUNI:MSACMSA:PMSA:NECMA:CD106:CD108:PUMA5:PUMA1:ZCTA5:ZCTA3:TAZ:TAZCOMB:UA:UR:VTD:SLDU:SLDL:UGA:POLYLONG:POLYLAT:WATER:LAND:SOURCE:CFCC:LANAME:LALONG:LALAT:FILLER"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="WATER:CFCC:LANAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=0; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0; fill_stipple=0 } # Name -- only features that have landmark records get names /^LANAME=None$/ {next} /^LANAME=(.*)$/ {name="$1"; next} #We need this just in case there is no CFCC code to tell us we're a water # feature #Perennial water /^WATER=1$/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;} #intermittent water /^WATER=2$/ {filled=1; fill_style=2; fill_stipple=0; color=117; fill_color=117; label_color=26; display_level=512;pattern=1;} # These are *all* the allowed feature classes, even those that aren't # polygon types. We won't actually bother testing for anything other # than the ones we expect to find, lest we spend too much time filtering. # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway #Roads are not going to be polygons, don't even check # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram # /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway # /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # color is RosyBrown2 /^CFCC=D1/ { filled=1; color=112; fill_color=112; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission /^CFCC=D2/ {filled=1; color=14; fill_color=14; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm /^CFCC=D3/ {filled=1; color=13; fill_color=13; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution /^CFCC=D4/ { filled=1; color=20; fill_color=20; fill_style=2; fill_stipple=0; display_level=64; font_size=1; next} # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D57 - Airport # color is "gray81" /^CFCC=D5/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=1; display_level=512; font_size=1; next} # D60 - Employment center # D61 - Shopping center # D62 - Industrial Building or Ind. park # D63 - Office Building or office park # D64 - Amusement Center # D65 - Government Center # D66 - Other emplyoment center /^CFCC=D6/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # D70 - tower # D71 - lookout tower /^CFCC=D7/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D80 - open space # D81 - golf course # D82 - cemetery # Color is "tgr_park_1" /^CFCC=D8[01]/ {filled=1; color=114; fill_color=114; fill_style=2; fill_stipple=0; display_level=512; font_size=1; next} # D83 - national park # D84 - national forest # D85 - state or local park or forest # color is "tgr_forest_1" /^CFCC=D8[3-5]/ {filled=1; color=116; fill_color=116; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D9/ {filled=1; color=101; fill_color=101; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # Don't display the E's # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F/{filled=1; color=115; fill_color=115; fill_style=0; label_level=32; display_level=512; pattern=0; next} #/^CFCC=F/{display_level=0; next} # Don't bother with the F's either for now # (G not used by census; tig2aprs uses for special maps) # H: hydrography # Color is "tgr_water_1" /^CFCC=H/ {filled=1; color=117; fill_color=3; label_color=26; display_level=512;} # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " /^CFCC=H0/ {filled=1; fill_style=2; fill_stipple=2; display_level=4096; label_level=16; lanes=1} /^CFCC=H02/ {filled=1; fill_stipple=0; pattern=1; next} # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean /^CFCC=H[1-5]/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} /^CFCC=H[1-4]2/ {filled=1; fill_stipple=0; pattern=1; next} # H60 - gravel pit or quarry filled with water /^CFCC=H6/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H81/ {filled=1; color=15; fill_color=15; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} Xastir-Release-2.2.4/config/tgr2shppoly_2006.dbfawk0000664000175000017500000002566115151324131020724 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line shapefiles which are # converted to shapefiles using the Xastir_tigerpoly.py utility # # It differs from the "tgr2shppoly.dbfawk" file only in the DBF signature, # which changed between the 2004 and 2006 TIGER/Line releases. # BEGIN is called once per dbf file which contains multiple records. BEGIN { dbfinfo="MODULE:FILE:CENID:POLYID:STATECU:COUNTYCU:TRACT:BLOCK:BLOCKSUFCU:RS_A1:AIANHHFPCU:AIANHHCU:AIHHTLICU:ANRCCU:AITSCECU:AITSCU:CONCITCU:COUSUBCU:SUBMCDCU:PLACECU:SDELMCU:SDSECCU:SDUNICU:RS_A20:RS_A21:RS_A22:CDCU:ZCTA5CU:ZCTA3CU:RS_A4:RS_A5:RS_A6:RS_A7:RS_A8:RS_A9:CBSACU:CSACU:NECTACU:CNECTACU:METDIVCU:NECTADIVCU:RS_A14:UACU:URCU:RS_A17:RS_A18:RS_A19:STATE:COUNTY:BLKGRP:AIANHHFP:AIANHH:AIHHTLI:ANRC:AITSCE:AITS:CONCIT:COUSUB:SUBMCD:PLACE:SDELM:SDSEC:SDUNI:MSACMSA:PMSA:NECMA:CD106:CD108:PUMA5:PUMA1:ZCTA5:ZCTA3:TAZ:TAZCOMB:UA:UR:VTD:SLDU:SLDL:UGA:POLYLONG:POLYLAT:WATER:LAND:SOURCE:CFCC:LANAME:LALONG:LALAT:FILLER"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="WATER:CFCC:LANAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=0; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0; fill_stipple=0 } # Name -- only features that have landmark records get names /^LANAME=None$/ {next} /^LANAME=(.*)$/ {name="$1"; next} #We need this just in case there is no CFCC code to tell us we're a water # feature #Perennial water /^WATER=1$/ {filled=1; fill_style=2; fill_stipple=2; color=117; fill_color=117; label_color=26; display_level=1024;} #intermittent water /^WATER=2$/ {filled=1; fill_style=2; fill_stipple=0; color=117; fill_color=117; label_color=26; display_level=512;pattern=1;} # These are *all* the allowed feature classes, even those that aren't # polygon types. We won't actually bother testing for anything other # than the ones we expect to find, lest we spend too much time filtering. # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway #Roads are not going to be polygons, don't even check # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram # /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway # /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # color is RosyBrown2 /^CFCC=D1/ { filled=1; color=112; fill_color=112; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission /^CFCC=D2/ {filled=1; color=14; fill_color=14; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm /^CFCC=D3/ {filled=1; color=13; fill_color=13; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution /^CFCC=D4/ { filled=1; color=20; fill_color=20; fill_style=2; fill_stipple=0; display_level=64; font_size=1; next} # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D57 - Airport # color is "gray81" /^CFCC=D5/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=1; display_level=512; font_size=1; next} # D60 - Employment center # D61 - Shopping center # D62 - Industrial Building or Ind. park # D63 - Office Building or office park # D64 - Amusement Center # D65 - Government Center # D66 - Other emplyoment center /^CFCC=D6/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # D70 - tower # D71 - lookout tower /^CFCC=D7/ {filled=1; color=113; fill_color=113; fill_style=2; fill_stipple=0; display_level=128; font_size=1; next} # D80 - open space # D81 - golf course # D82 - cemetery # Color is "tgr_park_1" /^CFCC=D8[01]/ {filled=1; color=114; fill_color=114; fill_style=2; fill_stipple=0; display_level=512; font_size=1; next} # D83 - national park # D84 - national forest # D85 - state or local park or forest # color is "tgr_forest_1" /^CFCC=D8[3-5]/ {filled=1; color=116; fill_color=116; fill_style=2; fill_stipple=0; display_level=1024; font_size=1; next} # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D9/ {filled=1; color=101; fill_color=101; fill_style=2; fill_stipple=0; display_level=256; font_size=1; next} # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # Don't display the E's # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F/{filled=1; color=115; fill_color=115; fill_style=0; label_level=32; display_level=512; pattern=0; next} #/^CFCC=F/{display_level=0; next} # Don't bother with the F's either for now # (G not used by census; tig2aprs uses for special maps) # H: hydrography # Color is "tgr_water_1" /^CFCC=H/ {filled=1; color=117; fill_color=3; label_color=26; display_level=512;} # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " /^CFCC=H0/ {filled=1; fill_style=2; fill_stipple=2; display_level=4096; label_level=16; lanes=1} /^CFCC=H02/ {filled=1; fill_stipple=0; pattern=1; next} # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean /^CFCC=H[1-5]/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} /^CFCC=H[1-4]2/ {filled=1; fill_stipple=0; pattern=1; next} # H60 - gravel pit or quarry filled with water /^CFCC=H6/ {filled=1; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H81/ {filled=1; color=15; fill_color=15; fill_style=2; fill_stipple=2;display_level=256; label_level=16; lanes=1} Xastir-Release-2.2.4/config/tgrcty.dbfawk0000664000175000017500000000414215151324131017263 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "cty" polygon shapefiles # which are named tgrSSCCCcty00.dbf, where SSCCC are the FIPS state and # county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:FIPSSTCO:STATE:COUNTY"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="COUNTY:FIPSSTCO"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; fill_color=11; color=8; name=""; filled=0; pattern=0; display_level=8192; label_level=512; label_color=20; font_size=4; symbol=""} # name: name is just the county name. /^COUNTY=(.*)$/ {name="$1"; next} # key: set the search key to be the FIPS code. Not currently used. # also append County to the name except for Louisiana, use Parish: /^FIPSSTCO=(22.*)$/ {name="$name Parish"; key=$1; next} /^FIPSSTCO=(.*)$/ {name="$name County"; key=$1; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tgrkgl.dbfawk0000664000175000017500000000510515151324131017241 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "kgl" (Key Geographic # Location) shapefiles which are named tgrSSCCCkgl.dbf, where SSCCC # are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:POLYID:COUNTY:CFCC:KGLNAME"; # dbffields is which of the above fields we actually want to look at. dbffields="KGLNAME:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; fill_color=255; color=8; name=""; filled=1; pattern=0; display_level=0; label_level=0; label_color=8; font_size=2; symbol="/. "} # name and key are both the KGL name /^KGLNAME=(.*)$/ {name=$1; key=$1; next} # CFCC=D.. for landmarks. Use the same code here and for tgrlk. #D2: residence? #D23: trailer park #D28: campground /^CFCC=D2/ {symbol="/- "; display_level=64; label_level=32} /^CFCC=D23$/ {symbol="/R "; next} /^CFCC=D28$/ {symbol="/; "; next} /^CFCC=D2/ {next} #D31: hospital /^CFCC=D31$/ {color=9; symbol="/h "; display_level=128; label_level=64; next} #D40: unknown educational or religious #D41: sorority or fraternity #D42: convent or monastery #D43: educational institution #D44: religious institution /^CFCC=D4/ {color=8; symbol="/K "; display_level=64; label_level=32} /^CFCC=D4[03]$/ {color=14; next} #D51: airport #D54: harbor /^CFCC=D51$/ {symbol="/' "; display_level=128; label_level=32; next} /^CFCC=D54$/ {symbol="\\s "; display_level=128; label_level=32; next } #DB: state forests, etc. /^CFCC=D8/ {color=73; display_level=64; label_level=32; next} # don't need special end case handling... #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tgrlk.dbfawk0000664000175000017500000002246215151324131017077 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lk" shapefiles which are # named tgrSSCCClk[A-H].dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="TLID:FNODE:TNODE:LENGTH:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC:FRADDL:TOADDL:FRADDR:TOADDR:ZIPL:ZIPR:CENSUS1:CENSUS2:CFCC1:CFCC2:SOURCE"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="TLID:FEDIRP:FENAME:FETYPE:FEDIRS:CFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=8; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^TLID=(.*)$/ {key=$1; next} # name: concatenate FEDIRP (direction prefix), FENAME (name), # FETYPE (type: Rd, Ln, Pky, etc.) and FEDIRS (direction suffix). # also abbreviate United States Highway to US, etc. /^FEDIRP=(.+)$/ {name="$1 ";next} /^FENAME=United States Highway (.*)$/ {name="$(name)US $1"; next} /^FENAME=State Highway (.*)$/ {name="$(name)State $1";next} /^FENAME=State Route (.*)$/ {name="$(name)SR $1";next} /^FENAME=(.*)$/ {name="$(name)$1; next} /^FETYPE=(.+)$/ {name="$(name) $1"; next} /^FEDIRS=(.+)$/ {name="$(name) $1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # CFCC A..: roads # A11 - primary limited access road or interstate highway, unseparated # A12 - primary limited access road or interstate highway, unseparated in tunnel # A13 - primary limited access road or interstate highway, unseparated, underpassing # A14 - primary limited access road or interstate highway, unseparated, with rail line in center # A15 - primary limited access road or interstate highway, separated # A16 - primary limited access road or interstate highway, separated, in tunnel # A17 - primary limited access road or interstate highway, separated, underpassing # A18 - primary limited access road or interstate highway, separated, with rail line in center # A21 - primary road without limit access, US highways, unseparated # A22 -primary road without limit access, US highways, unseparated, in tunnel # A23 - primary road without limit access, US highways, underpassing # A24 - primary road without limit access, US highways, unseparated, with rail line in center # A25 - primary road without limit access, US highways, separated # A26 - primary road without limit access, US highways, separated, in tunnel # A27 - primary road without limit access, US highways, separated, underpassing # A28 - primary road without limit access, US highways, separated, with rail line in center # A31 - secondary and connection road, state highways, unseperated # A32 - " in tunnel # A33 - " underpassing # A34 - " with rail line in center # A35 - secondary and connection road, state highways, separated # A36 - " in tunnel # A37 - " underpassing # A38 - " with rail line in center # A41 - local, neighborhood and rural road, city street, unseparated # A42 - " in tunnel # A43 - " underpassing # A44 - " with rail line in center # A45 - local, neighborhood and rural road, city street, separated # A46 - " in tunnel # A47 - " underpassing # A48 - " with rail line in center # A51 - vehicular trail, unseparated # A52 - " in tunnel # A53 - " underpassing # A61 - cul-de-sac # A62 - traffic circle # A63 - access ramp # A64 - service drive # A65 - ferry crossing # A71 - walkway or trail # A72 - stairway # A73 - alley # A74 - driveway /^CFCC=A1/ {lanes=4; color=4; label_level=512; font_size=3; next} /^CFCC=A2/ {lanes=3; color=8; label_level=256; font_size=2; next} /^CFCC=A3/ {lanes=2; color=8; label_level=128; font_size=1; next} /^CFCC=A3[1-6]/ {display_level=256; next} /^CFCC=A3[7-8]/ {display_level=128; next} /^CFCC=A4/ {display_level=96; label_level=16; color=40; lanes=1; next} /^CFCC=A5/ {lanes=2; color=40; display_level=64; font_size=1; next} /^CFCC=A65/ {lanes=2; color=8; pattern=2; font_size=1; next} /^CFCC=A6[^5]/ {color=40; display_level=64; next} /^CFCC=A7[12]/ {lanes=1; color=12; pattern=2; display_level=64; next} /^CFCC=A7[03-9]/ {lanes=1; color=40; pattern=2; display_level=64; next} # need to implement these: # B: railroads # B01 - railroad track # B02 - " in tunnel # B03 - " underpassing # B11 - railroad main line # B12 - " in tunnel # B13 - " underpassing # B21 - railroad spur # B22 - " in tunnel # B23 - " underpassing # B31 - railroad yard track # B32 - " in tunnel # B33 - " underpassing # B40 - railroad ferry crossing # B50 - other rail line # B51 - carline (streetcars, etc.) # B52 - cog railroad, incline railway or logging tram /^CFCC=B/ {lanes=1; color=8; pattern=1; display_level=128; next} # C: transmission lines # C00 - misc ground transportation # C10 - pipeline # C20 - power transmission line # C30 - other ground transportation # C31 - aerial tramway /^CFCC=C/ {display_level=0; next} # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) # E: physical featuers # E00 - unknown physical feature # E10 - fence line # E20 - topgraphic feature # E21 - ridge line # E22 - mountain peak # E23 - island # F: legal boundaries # F00 - nonvisible boundary # F10 - jurisdictional boundary # F11 - offset boundary # F12 - corridor boundary # F13 - interpolate boundary across water # F14 - superseded boundary # F15 - superseded boundary, corrected # F20 - data base topology # F21 - automated feature extension to lengthen physical feature # F22 - irregular feature extension, determined manually # F23 - closure extension # F24 - separation line # F25 - centerline # F30 - point-to-point line # F40 - property line # F50 - Zip Code boundary # F60 - map edge # F70 - statistical boundardy # F71 - 1980 " # F72 - 1990 " # F73 - internal use # F74 - 1990 " ... # F80 - other tabulation boundary # F81 - internal use # F82 - internal use /^CFCC=F10$/{color=255; fill_color=255; label_level=32; display_level=512; pattern=0; next} /^CFCC=F/{display_level=0; next} # (G not used by census; tig2aprs uses for special maps) # H: hydrography # H00 - water feature # H01 - shoreline of perennial water feature # H02 - shoreline of intermittent " # H10 - stream # H11 - perennial stream # H12 - intermittent stream # H13 - braided stream or river # H20 - canal, ditch or aqueduct # H21 - perennial " # H22 - intermittent " # H30 - lake or pond # H31 - perennial " # H32 - intermittent " # H40 - reservoir # H41 - perennial " # H42 - intermittent " # H50 - bay, estuary, gulf, sound, sea, ocean # H51 - bay, estuary, gulf or sound # H52 - sea or ocean # H60 - gravel pit or quarry filled with water # H70 - nonvisibile.... # H80 - special water features # H81 - glacier /^CFCC=H/ {lanes=0; color=26; fill_color=26; label_color=26} /^CFCC=H02/ {pattern=2; next} /^CFCC=H[1-6]2/ {lanes=1; pattern=2; next} /^CFCC=H[1-6][013-9]/ {lanes=1; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1} /^CFCC=H81/ {color=15; fill_color=15; next} # X00 - feature not yet classified # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tgrlpt.dbfawk0000664000175000017500000000750315151324131017267 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lpt" landmark point shapefiles which are # named tgrSSCCClpt.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:CFCC:NAME"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="CFCC:NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=2; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^NAME=(.*)$/ {name="$1"; next} # Census Feature Class Codes are used to set lanes, color, display_level, etc. # D: landmarks # D00 - unknown # D10 - military installation # D20 - multihousehold or transient quarters # D21 - apartment building or complex # D22 - rooming or boarding house # D23 - trailer cour or mobile home park # D24 - marina # D25 - crew-of-vessel area # D26 - housing facility for workers # D27 - hotel, motel, resort, spa, YMCA, YWCA # D28 - campground # D29 - shelter or mission # D30 - custodial facility # D31 - hospital # D32 - halfway house # D33 - nursing home # D34 - county home or poor farm # D35 - orphanage # D36 - jail # D37 - federal penetentiary, state prison, or prison farm # D40 - unknown educational or religious # D41 - sorority or fraternity # D42 - convent or monastery # D43 - educational institution # D44 - religious institution # D50 - transportation terminal # D51 - airport # D52 - train station # D53 - bus terminal # D54 - marine terminal # D55 - seaplane anchorage # D70 - tower # D71 - lookout tower # D80 - open space # D81 - golf course # D82 - cemetery # D83 - national park # D84 - national forest # D85 - state or local park or forest # D90 - special purpose landmark # D91 - post office box-only ZIP Code location # D92 - urbanizacion (Puerto Rico) /^CFCC=D28/ {color=10; symbol="/] "; next} /^CFCC=D28/ {color=10; symbol="/\; "; next} /^CFCC=D31/ {color=9; symbol="/h "; next} /^CFCC=D40/ {color=5; next} /^CFCC=D41/ {color=2; next} /^CFCC=D42/ {color=1; next} /^CFCC=D43/ {color=2; symbol="/K "; next} /^CFCC=D44/ {color=1; next} /^CFCC=D51/ {color=14; symbol="/' "; next} /^CFCC=D52/ {color=14; symbol="/= "; next} /^CFCC=D53/ {color=14; symbol="/U "; next} /^CFCC=D54/ {color=1; symbol="/s "; next} /^CFCC=D70/ {color=1; symbol="/r "; next} /^CFCC=D8/ {color=2; next} # X - APRS extension to get all the various APRS symbols. # Useful for home made maps. Perhaps I shouldn't overload tiger/line # stuff with this and just define a new .dbfawk.... # are table, symbol, and overlay, /^CFCC=X(.*)$/ {symbol="$1"; next} Xastir-Release-2.2.4/config/tgrlpy.dbfawk0000664000175000017500000000423215151324131017270 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "lpy" landmark polygon shapefiles which are # named tgrSSCCClklpy.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:POLYID:CENID:COUNTY:CFCC:LANDNAME:LANDPOLY"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="CFCC:LANDNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; fill_color=11; color=8; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=2; symbol=""} # per-field rules are applied to the dbffields that are read from each record. # key: set the search key to be the Tiger/Line ID. Not currently used. /^NAME=(.*)$/ {name="$1"; next} /^CFCC=H/ {lanes=0; color=26; fill_color=26} /^CFCC=H02/ {pattern=2; next} /^CFCC=H[1-6]2/ {lanes=1; pattern=2; next} /^CFCC=H[1-6][013-9]/ {lanes=1; next} /^CFCC=H7/ {display_level=0; label_level=0; next} /^CFCC=H8/ {lanes=1} /^CFCC=H81/ {color=15; fill_color=15; next} Xastir-Release-2.2.4/config/tgrplc00.dbfawk0000664000175000017500000000330415151324131017401 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "plc" shapefiles which are # named tgrSSCCCplc00.dbf, where SSCCC are the FIPS state and county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:COUNTY:PLACE:NAME"; # dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=3; color=4; fill_color=103; name=""; filled=1; pattern=0; display_level=8192; label_level=256; label_color=8; font_size=2; symbol=""} /^NAME=(.*)$/ {name="$1"; next} Xastir-Release-2.2.4/config/tgrwat.dbfawk0000664000175000017500000000426315151324131017263 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line "wat" polygon shapefiles # which are named tgrSSCCCwat.dbf, where SSCCC are the FIPS state and # county codes. # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="ID:COUNTY:CFCC:LANDNAME:LANDPOLY"; # dbffields is which of the above fields we actually want to look at. # Note that the order we list these is important since we are appending the # word County or Parish depending on what state the county is in. dbffields="CFCC:LANDNAME"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. BEGIN_RECORD {key=""; lanes=1; color=26; fill_color=26; name=""; filled=1; pattern=0; display_level=8192; label_level=512; label_color=8; font_size=2; symbol=""} # name: name is just the county name. /^COUNTY=(.*)$/ {name="$1"; next} # key: set the search key to be the FIPS code. Not currently used. # also append County to the name except for Louisiana, use Parish: # XXX - find out what the FIPS code is for Louisiana and replace 99 with it: /^FIPSSTCO=(99.*)$/ {name="$name Parish"; key=$1; next} /^FIPSSTCO=(.*)$/ {name="$name County"; key=$1; next} # don't need special end case handling... #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tl_2009_aiannh.dbfawk0000664000175000017500000000350415151324131020357 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { # dbfinfo extracted from tl_2009_27_aiannh.dbf: dbfinfo="AIANNHCE:AIANNHNS:AIANNHID:NAME:NAMELSAD:LSAD:CLASSFP:COMPTYP:AIANNHR:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON:STATEFP:AIANNHFP:PARTFLG"; dbffields="NAMELSAD:MTFCC"; } /^NAMELSAD=(.*)$/ {name="$1";next} /^MTFCC=G21/ { display_level=128; color=65; label_level=96; label_color=6; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_aits.dbfawk0000664000175000017500000000346515151324131020067 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { # dbfinfo extracted from tl_2009_27_aits.dbf: dbfinfo="AIANNHCE:TRSUBCE:TRSUBNS:TRSUBID:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON:STATEFP:TRSUBFP:PARTFLG"; dbffields="NAMELSAD:MTFCC"; } /^NAMELSAD=(.*)$/ {name="$1";next} /^MTFCC=G23/ { display_level=128; color=65; label_level=96; label_color=6; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_arealm.dbfawk0000664000175000017500000001060115151324131020356 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:AREAID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=40; label_color=48; fill_style=0; display_level=128; label_level=96; font_size=0; symbol=""; fill_stipple=0; } /^FULLNAME=(.*)$/ {name="$1";next} /^MTFCC=C3023/ { # Island color=40; label_color=48; font_size=1; display_level=256; label_level=128; next; } /^MTFCC=C3/ { # Other "C3" features not drawn - less than 20 in the whole dataset. display_level=0; next; } # Dwelling areas: /^MTFCC=K1121/ { # Apartment complex display_level=32; label_level=24; next; } /^MTFCC=K1228/ { # Campground display_level=64; label_level=48; filled=1; color=114 fill_color=114; fill_style=2; fill_stipple=2; label_color=0; font_size=1; next; } /^MTFCC=K122/ { # Trailer court, dormitory, hotel/resort, shelter/mission display_level=32; label_level=24; next; } /^MTFCC=K1231/ { # Hospital/hospice/urgent care facility display_level=64; label_level=48; filled=1; fill_color=112; fill_style=2; label_color=12; font_size=1; next; } /^MTFCC=K123[349]/ { # Nursing/retirement home, County home/poor farm, religious quarters display_level=32; label_level=24; next; } /^MTFCC=K123[567]/ { Juvenile Institution/Local Jail or Detention Center/Federal Penitentiary, State Prison display_level=32; label_level=24; filled=1; fill_style=2; fill_stipple=1; label_color=67; font_size=1; next; } # Government facilities: /^MTFCC=21[046]/ { # Governmental/Community Center/Government Center display_level=64; label_level=48; filled=1; fill_color=67; fill_style=2; fill_stipple=2; label_color=15; font_size=1; next; } /^MTFCC=K218/ { # Park/NPS land/Nat'l forest or other federal land/State, regional, county or city park display_level=64; label_level=32; filled=1; color=114 fill_color=114; fill_style=2; label_color=0; font_size=1; next; } # Commercial facilities /^MTFCC=K23/ { # We don't draw "K23" features display_level=0; next; } # Transit /^MTFCC=K24/ { # Marina/Airport/Train Station/Bus Terminal/Marine Terminal/Seaplane Anchorage/etc display_level=128; label_level=64; filled=1; color=115 fill_color=115; fill_style=2; label_color=0; font_size=1; next; } # Education/recreation/misc /^MTFCC=K254[03]/ { # University/College/School/Academy display_level=64; label_level=48; filled=1; fill_color=103; fill_style=2; font_size=0; next; } /^MTFCC=K2561/ { # Golf course display_level=64; label_level=48; filled=1; color=114 fill_color=100; fill_style=2; label_color=10; font_size=1; next; } /^MTFCC=K2582/ { # Cemetery (don't display - overlap w/ pointlm database) display_level=0; next; } /^MTFCC=K3544/ { # Place of worship (don't display - overlap w/ pointlm database) display_level=0; next; } /^MTFCC=K25/ { # All others (Amusement Center, Zoo) display_level=128; label_level=64; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_areawater.dbfawk0000664000175000017500000000530715151324131021077 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:HYDROID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # defaults for items below name=""; filled=1; pattern=0; key=""; lanes=1; fill_color=42; label_color=3; fill_style=0; display_level=128; label_level=32; font_size=0; symbol=""; } /^FULLNAME=(.*)$/ {name="$1";next} /^MTFCC=H2025/ { # Swamp/marsh color=42; fill_style=2; display_level=64; fill_stipple=0; next} /^MTFCC=H2030/ { # Lake/Pond, Reservoir, Bay/Estuary/Gulf/Sound, Ocean/Sea color=42; fill_style=0; next} /^MTFCC=H2040/ { # Reservoir color=42; fill_style=2; fill_stipple=2; display_level=64; next} /^MTFCC=H20[48]1/ { # Treatment Pond, Glacier color=42; fill_style=2; fill_stipple=1; display_level=64; next} /^MTFCC=H205/ { # Bay/Estuary/Gulf/Sound, Ocean/Sea color=42; fill_style=0; display_level=256; next} /^MTFCC=H2060/ { # Quarry filled w/ water color=42; fill_style=2; fill_stipple=2; display_level=64; name="$name (Quarry/Pit)"; next} /^MTFCC=H3010/ { # Stream/river color=42; next} /^MTFCC=H3013/ { # Braided stream color=42; display_level=64; next} /^MTFCC=H302/ { # Canal/ditch/aqueduct color=42; display_level=32; next} #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_county.dbfawk0000664000175000017500000000406715151324131020447 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:COUNTYNS:CNTYIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CSAFP:CBSAFP:METDIVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAMELSAD:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^NAMELSAD=(.*)$/ {name="$1"} /^MTFCC=G/ { # Counties/Parishes display_level=5000; color=254; label_level=2048; label_color=254; next} #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_cousub.dbfawk0000664000175000017500000000417215151324131020423 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo ="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:COSBIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CNECTAFP:NECTAFP:NCTADVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAMELSAD:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^NAMELSAD=(.*)$/ {name="$1";next; } /^MTFCC=G/ { # "County Subdivisions" - better known as cities, towns and townships. display_level=128; label_level=96; color=115; label_color=115; next} #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_edges.dbfawk0000664000175000017500000001112515151324131020206 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:TLID:TFIDL:TFIDR:MTFCC:FULLNAME:SMID:LFROMADD:LTOADD:RFROMADD:RTOADD:ZIPL:ZIPR:FEATCAT:HYDROFLG:RAILFLG:ROADFLG:OLFFLG:PASSFLG:DIVROAD:EXTTYP:TTYP:DECKEDROAD:ARTPATH:PERSIST:GCSEFLG:OFFSETL:OFFSETR:TNIDF:TNIDT"; dbffields="MTFCC:FULLNAME"; # level presets l_metro=256; l_county=80; l_city=32; l_town=16; l_hood=8; } BEGIN_RECORD { color=11; # color 11 used on things we missed. # Set defaults for other values: name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=20; fill_style=0; display_level=64; label_level=32; font_size=0; symbol=""; fill_stipple=0; } /^FULLNAME=(.*)$/ {name="$1";next; } # Non-road items: /^MTFCC=L4031/ { # Ski Lift or Arial Tramway display_level=l_city; color=12; pattern=2; name="$name (Ski Lift/Tramway)"; next; } /^MTFCC=L4165/ { # Ferry crossing lanes=3; pattern=2; color=72; label_color=72; display_level=l_metro; label_level=l_county; next; } /^MTFCC=[CHKLP]/ { # Don't draw other non-road items display_level=0; next; } /^MTFCC=R101/ { # Freight Rail (heavy/freight) color=80; label_color=48; pattern=1; lanes=2; display_level=128; label_level=64; next; } /^MTFCC=R105/ { # Passenger Rail (light/mass transit/cog rail) color=67; label_color=67; pattern=2; display_level=128; label_level=64; next; } # Public Roadways /^MTFCC=S11/ { # Freeways/major highways lanes=4; color=102; label_color=102; display_level=1024; label_level=256; font_size=2; next; } /^MTFCC=S12/ { # Secondary roads display_level=256; lanes=3; color=36; label_color=36; label_level=128; font_size=2; next; } /^MTFCC=S14/ { # Local roads, ramps and service drives/frontage roads display_level=40; color=44; label_color=44; label_level=16; color=48; lanes=1; next; } /^MTFCC=S15/ { # 4WD off-road trail color=99; label_color=99; display_level=64; font_size=1; name="$name (OHV/4WD trail)"; next; } /^MTFCC=S16/ { # ramps and service roads for Freeways/major highways color=102; label_color=102; display_level=32; next; } /^MTFCC=S20/ { # road median color=44; label_color=44; pattern=1; display_level=16; next; } /^MTFCC=S173/ { # alley color=44; label_color=44; pattern=1; display_level=32; name="$name (alley)"; next; } # Non-public roads (and public non-roads) /^MTFCC=S171/ { # walkway / pedestrian trail lanes=1; color=65; label_color=65; pattern=1; display_level=64; label_level=32; name="$name (walkway)"; next; } /^MTFCC=S172/ { # stairway lanes=1; color=12; label_color=12; pattern=2; display_level=32; label_level=20; name="$name (stairs)"; next; } /^MTFCC=S174/ { # private road lanes=1; color=23; label_color=23; pattern=2; display_level=32; label_level=20; name="$name (private road)"; next; } /^MTFCC=S17/ { # business park / townhome road / parking lane / "internal census use only" lanes=1; color=23; label_color=23; pattern=1; display_level=32; label_level=20; name="$name (parking/private)"; next; } /^MTFCC=S182/ { # bike path lanes=1; color=65; label_color=65; pattern=1; display_level=64; label_level=32; name="$name (bikeway)"; next; } /^MTFCC=S183/ { # bridle path lanes=1; color=65; label_color=65; pattern=2; display_level=64; label_level=32; name="$name (bridle path)"; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_mil.dbfawk0000664000175000017500000000343615151324131017706 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="ANSICODE:AREAID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON:PARTFLG"; dbffields="FULLNAME:MTFCC"; } /^FULLNAME=(.*)$/ {name="$1"; next; } /^MTFCC=K21/ { # Military installation display_level=128; color=116; label_level=64; label_color=116; fill_style=2; fill_stipple=0; fill_color=116; filled=1; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_nn_county.dbfawk0000664000175000017500000000440315151324131021134 0ustar hibbyhibby# tl_2009_nn_county.dbfawk # # Copyright (C) 2000-2026 The Xastir Group # # Census.gov 2009 TigerMaps for state counties or equivalent areas. # # Based on work by: # Richard Polivka, N6NKO - April, 2008 # Craig Anderson, N6YXK - May, 2008 # Dale Seaburg, KG5LT - March 2009 # Edited for 2009 data by: # Peter Gamache, KC0TFB - June, 2010 # # This dbfawk file is used to map arbitrary dbf data that accompanies # a shapefile into Xastir canoncical values of: # key - search key # lanes - width of feature (usually a road but applies to rivers, etc. too) # color - color to draw the road # name - name of the road for labels # filled - whether a polygon is drawn filled or not # fill_color - color to fill polygon with # pattern - line pattern for road, river, etc. (0 - solid; 1 - dash; 2 - double dash) # display_level - highest zoom level at which to display the feature # label_level - highest zoom level at which to display the label # symbol - 3 char 'TIO': table, ID, overlay # NOTE: This file format is modeled after awk but is nowhere near awk # compatible. # # This file is used to map US Census Tiger/Line 2009 Shapefiles. # # BEGIN is called once per dbf file which contains multiple records. BEGIN { # dbfinfo is the "signature" of the dbf file listing the column names in order. # dbfinfo should match the dbf file that we say this dbfawk file goes with. dbfinfo="STATEFP:COUNTYFP:COUNTYNS:CNTYIDFP:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CSAFP:CBSAFP:METDIVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; #dbffields is which of the above fields we actually want to look at. # No point reading dbffields that are not looked at further. dbffields="NAMELSAD:MTFCC"; } # BEGIN_RECORD is called once per dbf record which contains multiple fields. # Use this rule to re-initialize variables between records. # use color 11 to highlight stuff that isn't properly mapped. BEGIN_RECORD {key=""; lanes=1; color=6; fill_color=11; name=""; filled=0; pattern=0; display_level=8192; label_level=32; label_color=8; font_size=0; symbol=""; fill_style=0 } /^NAMELSAD=(.*)$/ {name="$1"} # counties /^MTFCC=G/ {display_level=6000; filled=0; color=45; label_level=2048; label_color=37; next} # just a demo of the END_RECORD and END rules: #END_RECORD {name="$name ($key)";} #END {} Xastir-Release-2.2.4/config/tl_2009_pointlm.dbfawk0000664000175000017500000001074415151324131020607 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style (w/ filled=1) 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="STATEFP:COUNTYFP:ANSICODE:POINTID:FULLNAME:MTFCC"; dbffields="FULLNAME:MTFCC"; # level presets l_metro=128; l_county=64; l_city=32; l_town=16; l_hood=8; } BEGIN_RECORD { # Defaults key=""; lanes=1; color=70; fill_color=70; name=""; filled=0; pattern=0; display_level=48; label_level=32; label_color=70; font_size=0; symbol=""; fill_style=0; } /^FULLNAME=(.*)$/ {name="$1"; next; } # Geography /^MTFCC=3022/ { # Mountain Peak or Summit display_level=l_county; next; } /^MTFCC=3022/ { # Islands should be in edges.dbf, not here. display_level=0; next; } /^MTFCC=3026/ { # Quarry next; } /^MTFCC=3027/ { # Dam should be in areawater, not here. display_level=0; next; } # Road features /^MTFCC=C306/ { # ignore cul-de-sacs, roundabouts, gates and toll booths display_level=0; next; } # Towers /^MTFCC=C307[014]/ { # Towers (beacon/observation/lighthouse, antenna and water) display_level=l_city; color=50; label_color=50; symbol="\L"; next; } /^MTFCC=C3072/ { display_level=l_city; color=50; label_color=50; name="$name (antenna tower)"; symbol="/r"; next; } /^MTFCC=C3073/ { display_level=l_city; color=50; label_color=50; name="$name (water tower)"; symbol="/r"; next; } /^MTFCC=C307/ { # ignore other towers (tanks, windmills and monuments) display_level=0; next; } # Locality points /^MTFCC=C308/ { # city names; redundant with cousub.dbf display_level=0; next} # Potential housing (for disaster relief) /^MTFCC=K1231/ { # Hospitals label_color=12; display_level=l_county; symbol="/h"; next} /^MTFCC=K12/ { # Don't display other types display_level=0; next} # other gov't items /^MTFCC=K2110/ { # Military; redundant with mil.dbf display_level=0; next; } /^MTFCC=K2146/ { # Community center display_level=l_city; symbol="/?"; next} /^MTFCC=K2165/ { # Gov't center display_level=l_city; symbol="/?"; next} /^MTFCC=K218/ { # Parks not shown; redundant with arealm.dbf display_level=0; next} /^MTFCC=K2193/ { # fire dept label_color=12; display_level=l_county; symbol="/d"; next} /^MTFCC=K2194/ { # police/sheriff station label_color=9; display_level=l_county; symbol="/!"; next} /^MTFCC=K2196/ { # City hall display_level=l_city; symbol="/?"; next} /^MTFCC=K219/ { # other buildings not shown display_level=0; next} # Transportation /^MTFCC=K2400/ { # Transportation terminal? display_level=l_city; symbol="/U?"; next} /^MTFCC=K245[156]/ { # Airport/airfield, seaplane terminal display_level=l_county; symbol="\^@"; next; } /^MTFCC=K2452/ { # train/trolley/light rail station display_level=l_city; symbol="/=@"; next} /^MTFCC=K2453/ { # bus terminal display_level=l_city; symbol="/U@"; next} /^MTFCC=K2454/ { # marine terminal display_level=l_county; symbol="\s@"; next} # Education/entertainment/misc /^MTFCC=K254[03]/ { # University/school display_level=l_town; symbol="/K"; next} /^MTFCC=K2561/ { # golf course; redundant w/ arealm display_level=0; next; } /^MTFCC=K2582/ { # cemeteries display_level=0; next} /^MTFCC=K3544/ { # religious display_level=0; next} # catch-all rule: /^MTFCC=K/ {display_level=16; label_level=16; next} #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2009_zcta5.dbfawk0000664000175000017500000000336415151324131020153 0ustar hibbyhibby# Written for the Tiger/Line 2009 dataset # NB: Colors have been chosen with a black background in mind. # # # Copyright (C) 2010 Peter Gamache, KC0TFB # # This program is free software; you can redistribute it and/or # modify # it under the terms of the GNU General Public License as published # by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # # see file COPYING for details # # color,label_color,fill_color sets object colors # lanes sets width of lines drawn (in pixels) # name sets the text that will be used as the label for the feature # symbol "XYZ", where X=group (/ or \), Y=symbol and Z=overlay # fill_style 0=solid, 1=tiled, 2=stippled, 3=Opaque Stippled # fill_stipple 0 is a 13 percent stipple, 1 is 25%, 2 is 50%. # pattern line pattern: 0=solid, 1=dashed, 2=double dash # display_level maximum zoom level for object display # label_level maximum zoom level for label display # font_size 0="Tiny", 4="Huge" BEGIN { dbfinfo="ZCTA5CE:CLASSFP:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="ZCTA5CE:MTFCC"; } /^ZCTA5CE=(.*)$/ {name="$1";next} /^MTFCC=G6350/ { # Zip code tabulation area, 5-digit display_level=128; color=103; label_level=64; label_color=103; font_size=1; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2025_arealm.dbfawk0000664000175000017500000001477015151324131020367 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line area landmarks shapefiles BEGIN { dbfinfo="STATEFP:ANSICODE:AREAID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON:PARTFLG"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=127; # color 127 used on things we missed. #Only here so I can spot when I've forgot a good rule for something name=""; pattern=0; key=""; lanes=1; filled=1; fill_style=2;fill_stipple=0; fill_color=127; label_color=127; display_level=8192; label_level=8192; font_size=1; symbol="/."; } /^FULLNAME=(.+)$/ {name=$1; next;} #Mountain peaks /^MTFCC=C3022$/ {symbol="\n"; display_level=1024; label_level=512; next;} #Islands /^MTFCC=C3023$/ {symbol="/i"; display_level=1024; label_level=64; color=115; fill_color=115; label_color=8; next;} #Quarries /^MTFCC=C3026$/ {symbol="/i"; display_level=1024; label_level=64; color=70; fill_color=70; label_color=8; next;} # cul-de-sacs and traffic circles (barely show these!) /^MTFCC=C3061$/ {symbol="\o"; display_level=8; label_level=8; next;} /^MTFCC=C3062$/ {symbol="\o"; display_level=10; label_level=8; next;} # gates /^MTFCC=C3066$/ {symbol="//"; display_level=8; name="$name(gate)"; next;} # Towers /^MTFCC=C3071$/ {symbol="/r"; display_level=128; label_level=16; next;} #Lighthouse beacon /^MTFCC=C3074/ {symbol="\L"; display_level=128; label_level=32; next;} # Tank or tank farm /^MTFCC=C3075$/ {symbol="\0T"; display_level=128; label_level=16; next;} # Monument or memorial /^MTFCC=C3078$/ {symbol="//"; display_level=128; label_level=16; next;} # Windmill farms and windmills /^MTFCC=C3076$/ {symbol="\0W"; display_level=1024; label_level=16; next;} /^MTFCC=C3081$/ {symbol="\0W"; display_level=64; label_level=16; next;} # Solar farms /^MTFCC=C3077$/ {symbol="\0S"; display_level=1024; label_level=16; color=115; fill_color=115; label_color=8; next;} # "Locality point" /^MTFCC=C3081$/ {symbol="\)"; display_level=128; label_level=64; next;} #Alaska Native Village Official Point /^MTFCC=C3085$/ {symbol="\)"; display_level=128; label_level=64; next;} #Apartment buildings /^MTFCC=K1121$/ {symbol="/-"; display_level=64; label_level=32; color=98; fill_color=98; next;} #RV parks /^MTFCC=K1223$/ {symbol="/-"; display_level=64; label_level=32; color=98; fill_color=98; next;} #Crew of vessel location /^MTFCC=K1225$/ {symbol="/s"; display_level=256; label_level=128; next;} # hostels and youth centers, housing authorities /^MTFCC=K1226$/ {symbol="/-"; display_level=64; label_level=32; color=114; fill_color=114; next;} /^MTFCC=K1227$/ {symbol="/-"; display_level=64; label_level=32; color=114; fill_color=114; next;} #campgrounds /^MTFCC=K1228$/ {symbol="/-"; display_level=64; label_level=32; color=114; fill_color=114; next;} #Shelter or mission /^MTFCC=K1229$/ {symbol="/-"; display_level=64; label_level=32; color=115; fill_color=115; next;} #Hospitals and other medical-type facilities /^MTFCC=K123[13]$/ {symbol="/h"; display_level=256; label_level=63; color=98; fill_color=98; fill_stipple=2; next;} # jails and things like them /^MTFCC=K123[5678]$/ {symbol="\AJ"; display_level=64; label_level=32; color=37; fill_color=37; next;} # Convents, monasteries, other religious facilities /^MTFCC=K1239$/ {symbol="\+M"; display_level=128; label_level=32; next;} # Military installations /^MTFCC=K2110$/ {symbol="\aM"; display_level=128; label_level=32; next;} # Community center /^MTFCC=K2146$/ {symbol="\AC"; display_level=128; label_level=64; next;} # Government center /^MTFCC=K2165$/ {symbol="\AG"; display_level=256; label_level=64; next;} # Convention center /^MTFCC=K2167$/ {symbol="\AF"; display_level=256; label_level=64; next;} # All other governmental... /^MTFCC=K21..$/ {symbol="\AG"; display_level=256; label_level=64; fill_color=115; color=115; label_color=8; next;} # Parks of all flavors (\; would be better, but dbfawk is broken!), plus # amusement centers /^MTFCC=K218.$/ {symbol="\AP"; display_level=1024; label_level=64; color=114; fill_color=114; label_color=73; next;} /^MTFCC=K2190$/ {symbol="\AP"; display_level=1024; label_level=64; color=114; fill_color=114; label_color=73; next;} /^MTFCC=K2564$/ {symbol="\AP"; display_level=1024; label_level=64; color=114; fill_color=114; label_color=73; next;} #post offices /^MTFCC=K2191$/ {symbol="/]"; display_level=256; label_level=64; next;} #Fire stations /^MTFCC=K2193$/ {symbol="/d"; display_level=256; label_level=64; next;} #Police stations /^MTFCC=K2194$/ {symbol="/P"; display_level=256; label_level=64; next;} #libraries /^MTFCC=K2195$/ {symbol="\AL"; name="$name (library)"; display_level=256; label_level=64; next;} # All manner of commercial spaces /^MTFCC=K23..$/ {display_level=256; label_level=128; color=113; fill_color=113; label_color=80; next;} #Town halls /^MTFCC=K2196$/ {symbol="\AT"; display_level=256; label_level=64; next;} #Transportation terminal (Symbol is a bus, but we are limited in choices) /^MTFCC=K2400$/ {symbol="/U"; display_level=256; label_level=128; next;} #Marinas and docks /^MTFCC=K2424$/ {symbol="/s"; display_level=256; label_level=128; color=117; fill_color=117; fill_stipple=2; next;} /^MTFCC=K2432$/ {symbol="/s"; display_level=256; label_level=128; color=117; fill_color=117; fill_stipple=2; next;} #airports (/' would be better, but dbfawk is broken) /^MTFCC=K245[17]$/ {symbol="/^"; display_level=256; label_level=128; color=98; fill_color=98; label_color=80; next;} #Train station /^MTFCC=K2452$/ {symbol="/="; display_level=256; label_level=128; next;} #Bus station /^MTFCC=K2453$/ {symbol="/U"; display_level=256; label_level=128; next;} #Marine terminal /^MTFCC=K2454$/ {symbol="/s"; display_level=256; label_level=128; next;} #Seaplane anchorage (No good symbol, use S overlaid on circle /^MTFCC=K2455$/ {symbol="\0S"; display_level=256; label_level=128; next;} #heliports/landing pads /^MTFCC=K2460$/ {symbol="\0H"; display_level=256; label_level=128; next;} # Schools (universities and other) /^MTFCC=K254[03]$/ {symbol="/K"; display_level=256; label_level=128; color=98; fill_color=98; label_color=8; next;} # Museums and other tourist attractions /^MTFCC=K2545$/ {symbol="\AM"; display_level=256; label_level=128; next;} # Golf Courses /^MTFCC=K2561$/ {symbol="/5"; display_level=64; label_level=32; color=114; fill_color=114; next;} # Cemetery and churches /^MTFCC=K2582$/ {symbol="\+"; display_level=128; label_level=32; color=113; fill_color=113; next;} /^MTFCC=K3544$/ {symbol="\+"; display_level=128; label_level=32; color=113; fill_color=113; next;} # Zoos /^MTFCC=K2586$/ {symbol="//"; display_level=128; label_level=32; next;}Xastir-Release-2.2.4/config/tl_2025_areawater.dbfawk0000664000175000017500000000340515151324131021072 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line areawater shapefiles BEGIN { dbfinfo="ANSICODE:HYDROID:FULLNAME:MTFCC:ALAND:AWATER:INTPTLAT:INTPTLON"; # Adding area of water in case we want to change display level based on # area... possible enhancement dbffields="FULLNAME:AWATER:MTFCC"; } BEGIN_RECORD { color=127; # color 127 used on things we missed. #Only here so I can spot when I've forgot a good rule for something name=""; pattern=0; key=""; lanes=1; filled=0; fill_style=0;fill_stipple=0; fill_color=127; label_color=127; display_level=64; label_level=8; font_size=1; symbol=""; } /^FULLNAME=(.+)$/ {name="$1";next;} #Rivers (filled with 50% stipple) /^MTFCC=H3010$/ {color=117; lanes=1; pattern=0; display_level=1024; label_color=26; filled=1; fill_color=117; fill_style=2; fill_stipple=2; next;} # braided streams/rivers (25% stipple) /^MTFCC=H3013$/ {color=117; lanes=1; pattern=0; display_level=1024; label_color=26; filled=1; fill_color=117; fill_style=2; fill_stipple=1; next;} # canals, ditches, aquaducts (slightly different shade of blue, 13% stipple) /^MTFCC=H3020$/ {color=101; lanes=1; pattern=1; display_level=1024; label_color=26; filled=1; fill_color=117; fill_style=2; fill_stipple=0; next;} # Reservoirs /^MTFCC=H2030$/ {color=101; lanes=1; pattern=0; display_level=1024; label_color=26; filled=1; fill_color=101; fill_style=2; fill_stipple=2; next;} #Lakes (filled with 50% stipple) /^MTFCC=H2040$/ {color=117; lanes=1; pattern=0; display_level=1024; label_color=26; filled=1; fill_color=117; fill_style=2; fill_stipple=2; next;} Xastir-Release-2.2.4/config/tl_2025_county.dbfawk0000664000175000017500000000151515151324131020440 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line "county" (counties) shapefiles # # This one's simple. All shapes are G4020 for MTFCC, all will render the #same. Just set color and display level in BEGIN_RECORD, name per record, # and we're done. # # For best results, the "tl_2025_us_county.shp" file should be a fairly low layer # as it otherwise covers other features in vector layers. # BEGIN { dbfinfo="STATEFP:COUNTYFP:COUNTYNS:GEOID:GEOIDFQ:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:CSAFP:CBSAFP:METDIVFP:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAME"; } BEGIN_RECORD { color=80; name=""; filled=1; pattern=0; key=""; lanes=1; label_color=80; fill_style=2; fill_stipple=1; fill_color=78; display_level=8192; label_level=1024; font_size=4; symbol=""; } /^NAME=(.+)$/ {name="$1"; next;} Xastir-Release-2.2.4/config/tl_2025_cousub.dbfawk0000664000175000017500000000151315151324131020415 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line "cousub" (county subdivisions) shapefiles # # This one's simple. All shapes are G4040 for MTFCC, all will render the #same. Just set color and display level in BEGIN_RECORD, name per record, # and we're done. # # For best results, the "tl_2025_??_cousub.shp" files should be a fairly low layer # as it otherwise covers other features in vector layers. # BEGIN { dbfinfo="STATEFP:COUNTYFP:COUSUBFP:COUSUBNS:GEOID:GEOIDFQ:NAME:NAMELSAD:LSAD:CLASSFP:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAME"; } BEGIN_RECORD { color=81; name=""; filled=1; pattern=0; key=""; lanes=1; label_color=81; fill_style=2; fill_stipple=0; fill_color=42; display_level=4096; label_level=1024; font_size=4; symbol=""; } /^NAME=(.+)$/ {name="$1"; next;} Xastir-Release-2.2.4/config/tl_2025_linearwater.dbfawk0000664000175000017500000000172615151324131021440 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line linearwater shapefiles BEGIN { dbfinfo="ANSICODE:LINEARID:FULLNAME:ARTPATH:MTFCC"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=127; # color 127 used on things we missed. #Only here so I can spot when I've forgot a good rule for something name=""; pattern=0; key=""; lanes=1; filled=0; fill_style=0;fill_stipple=0; fill_color=127; label_color=127; display_level=64; label_level=8; font_size=1; symbol=""; } /^FULLNAME=(.+)$/ {name="$1";next;} #Rivers /^MTFCC=H3010$/ {color=117; lanes=1; pattern=0; display_level=256; label_color=26; next;} # braided streams/rivers /^MTFCC=H3013$/ {color=117; lanes=1; pattern=0; display_level=256; label_color=26; next;} # canals, ditches, aquaducts (slightly different shade of blue, dashed lines) /^MTFCC=H3020$/ {color=101; lanes=1; pattern=1; display_level=256; label_color=26; next;}Xastir-Release-2.2.4/config/tl_2025_place.dbfawk0000664000175000017500000000175415151324131020210 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line "place" (Places) shapefiles # # All shapes are G4110 or G4210 for MTFCC, all will render the # same for our purposes. # Just set color and display level in BEGIN_RECORD, name per record, # and we're done. # # For best results, the "tl_2025_??_place.shp" file should be a fairly low layer # as it otherwise covers other features in cities. They are mostly # city-sized polygons, and aren't much different from the UAC polygons (so # we're going to color them the same, as users probably don't need to display # both. # BEGIN { dbfinfo="STATEFP:PLACEFP:PLACENS:GEOID:GEOIDFQ:NAME:NAMELSAD:LSAD:CLASSFP:PCICBSA:MTFCC:FUNCSTAT:ALAND:AWATER:INTPTLAT:INTPTLON"; dbffields="NAME"; } BEGIN_RECORD { color=115; name=""; filled=1; pattern=0; key=""; lanes=1; label_color=8; fill_style=2; fill_stipple=0; fill_color=115; display_level=8192; label_level=512; font_size=1; symbol=""; } /^NAME=(.+)$/ {name="$1"; next;} Xastir-Release-2.2.4/config/tl_2025_pointlm.dbfawk0000664000175000017500000001066315151324131020605 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line point landmarks shapefiles BEGIN { dbfinfo="STATEFP:ANSICODE:POINTID:FULLNAME:MTFCC"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=127; # color 127 used on things we missed. #Only here so I can spot when I've forgot a good rule for something name=""; pattern=0; key=""; lanes=1; filled=0; fill_style=0;fill_stipple=0; fill_color=127; label_color=127; display_level=8192; label_level=8; font_size=1; symbol="/."; } /^FULLNAME=(.+)$/ {name=$1; next;} #Mountain peaks /^MTFCC=C3022$/ {symbol="\n"; display_level=1024; label_level=512; next;} # cul-de-sacs and traffic circles (barely show these!) /^MTFCC=C3061$/ {symbol="\o"; display_level=8; label_level=8; next;} /^MTFCC=C3062$/ {symbol="\o"; display_level=10; label_level=8; next;} # gates /^MTFCC=C3066$/ {symbol="//"; display_level=8; name="$name(gate)"; next;} # Towers /^MTFCC=C3071$/ {symbol="/r"; display_level=128; label_level=16; next;} #Lighthouse beacon /^MTFCC=C3074/ {symbol="\L"; display_level=128; label_level=32; next;} # Tank or tank farm /^MTFCC=C3075$/ {symbol="\0T"; display_level=128; label_level=16; next;} # Monument or memorial /^MTFCC=C3078$/ {symbol="//"; display_level=128; label_level=16; next;} # Windmill farms and windmills /^MTFCC=C3076$/ {symbol="\0W"; display_level=1024; label_level=16; next;} /^MTFCC=C3081$/ {symbol="\0W"; display_level=64; label_level=16; next;} # "Locality point" /^MTFCC=C3081$/ {symbol="\)"; display_level=128; label_level=64; next;} #Alaska Native Village Official Point /^MTFCC=C3085$/ {symbol="\)"; display_level=128; label_level=64; next;} #Crew of vessel location /^MTFCC=K1225$/ {symbol="/s"; display_level=256; label_level=128; next;} #Hospitals and other medical-type facilities /^MTFCC=K123[13]$/ {symbol="/h"; display_level=1024; label_level=64; next;} # jails and things like them /^MTFCC=K123[678]$/ {symbol="\AJ"; display_level=128; label_level=64; next;} # Convents, monasteries, other religious facilities /^MTFCC=K1239$/ {symbol="\+M"; display_level=128; label_level=32; next;} # Military installations /^MTFCC=K2110$/ {symbol="\aM"; display_level=128; label_level=32; next;} # Community center /^MTFCC=K2146$/ {symbol="\AC"; display_level=128; label_level=64; next;} # Government center /^MTFCC=K2165$/ {symbol="\AG"; display_level=256; label_level=64; next;} # Convention center /^MTFCC=K2167$/ {symbol="\AF"; display_level=256; label_level=64; next;} # Parks of all flavors (\; would be better, but dbfawk is broken!) /^MTFCC=K218.$/ {symbol="\AP"; display_level=256; label_level=64; next;} /^MTFCC=K2190$/ {symbol="\AP"; display_level=256; label_level=64; next;} #post offices /^MTFCC=K2191$/ {symbol="/]"; display_level=256; label_level=64; next;} #Fire stations /^MTFCC=K2193$/ {symbol="/d"; display_level=256; label_level=64; next;} #Police stations /^MTFCC=K2194$/ {symbol="/P"; display_level=256; label_level=64; next;} #libraries /^MTFCC=K2195$/ {symbol="\AL"; name="$name (library)"; display_level=256; label_level=64; next;} #Town halls /^MTFCC=K2196$/ {symbol="\AT"; display_level=256; label_level=64; next;} #Transportation terminal (Symbol is a bus, but we are limited in choices) /^MTFCC=K2400$/ {symbol="/U"; display_level=256; label_level=128; next;} #airports (/' would be better, but dbfawk is broken) /^MTFCC=K2451$/ {symbol="/^"; display_level=256; label_level=128; next;} #Train station /^MTFCC=K2452$/ {symbol="/="; display_level=256; label_level=128; next;} #Bus station /^MTFCC=K2453$/ {symbol="/U"; display_level=256; label_level=128; next;} #Marine terminal /^MTFCC=K2454$/ {symbol="/s"; display_level=256; label_level=128; next;} #Seaplane anchorage (No good symbol, use S overlaid on circle /^MTFCC=K2455$/ {symbol="\0S"; display_level=256; label_level=128; next;} #heliports/landing pads /^MTFCC=K2460$/ {symbol="\0H"; display_level=256; label_level=128; next;} # Schools (universities and other) /^MTFCC=K254[03]$/ {symbol="/K"; display_level=256; label_level=128; next;} # Museums and other tourist attractions /^MTFCC=K2545$/ {symbol="\AM"; display_level=256; label_level=128; next;} # Golf Courses /^MTFCC=K2561$/ {symbol="/5"; display_level=64; label_level=32; next;} # Cemetery and churches /^MTFCC=K2582$/ {symbol="\+"; display_level=128; label_level=32; next;} /^MTFCC=K3544$/ {symbol="\+"; display_level=128; label_level=32; next;} # Zoos /^MTFCC=K2586$/ {symbol="//"; display_level=128; label_level=32; next;}Xastir-Release-2.2.4/config/tl_2025_rails.dbfawk0000664000175000017500000000112415151324131020225 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line "rails" (railroads) shapefiles # # This one's simple. All shapes are R1011 for MTFCC, all will render the #same. Just set color and display level in BEGIN_RECORD, name per record, # and we're done. # BEGIN { dbfinfo="LINEARID:FULLNAME:MTFCC"; dbffields="FULLNAME"; } BEGIN_RECORD { color=8; name=""; filled=0; pattern=0; key=""; lanes=1; label_color=8; fill_style=0; fill_stipple=0; fill_color=8; display_level=8192; label_level=512; font_size=1; symbol=""; } /^FULLNAME=(.+)$/ {name="$1"; next;} Xastir-Release-2.2.4/config/tl_2025_roads.dbfawk0000664000175000017500000000425615151324131020234 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line roads and "prisecroads" shapefiles BEGIN { dbfinfo="LINEARID:FULLNAME:RTTYP:MTFCC"; dbffields="FULLNAME:MTFCC"; } BEGIN_RECORD { color=11; # color 11 used on things we missed. name=""; filled=0; pattern=0; key=""; lanes=1; fill_color=20; label_color=78; fill_style=0; display_level=64; label_level=8; font_size=1; symbol=""; fill_stipple=0; } # only label non-null names /^FULLNAME=(.+)$/ {name="$1";next; } /^MTFCC=S1100$/ { # Freeways/major highways lanes=3; color=106; label_color=8; display_level=4096; label_level=256; font_size=3; next; } /^MTFCC=S1200$/ { # Secondary roads display_level=256; lanes=2; color=107; label_color=8; label_level=128; font_size=2; next; } /^MTFCC=S1400$/ { # Local roads, ramps and service drives/frontage roads display_level=64; color=80; label_color=80; label_level=8; color=48; lanes=1; font_size=2; next; } /^MTFCC=S1500$/ { # 4WD off-road trail color=4; label_color=4; display_level=64; label_level=8; font_size=1; name="$name (off-road trail)"; next; } /^MTFCC=S16[34]0$/ { # ramps and service roads for Freeways/major highways color=80; label_color=80; lanes=2; display_level=64; next; } /^MTFCC=S1710$/{ #pedestrian walkways/trails color=4; label_color=4; pattern=1; display_level=16; label_level=8; next;} /^MTFCC=S172/ { # stairway lanes=1; color=12; label_color=12; pattern=2; display_level=16; label_level=8; name="$name (stairs)"; next; } /^MTFCC=S1730$/ { # alley color=47; label_color=47; pattern=1; display_level=16; name="$name (alley)"; label_level=8; next; } /^MTFCC=S1740/ { # service road lanes=1; color=23; label_color=23; pattern=2; display_level=32; label_level=8; name="$name (service road)"; next; } /^MTFCC=S1780/ { # parking lot road lanes=1; color=23; label_color=23; pattern=2; display_level=32; label_level=8; name="$name (parking lot road)"; next; } /^MTFCC=S1820$/ { # bike path lanes=1; color=65; label_color=65; pattern=1; display_level=64; label_level=8; name="$name (bikeway)"; next; } /^MTFCC=S1830/ { # bridle path lanes=1; color=65; label_color=65; pattern=2; display_level=64; label_level=8; name="$name (bridle path)"; next; } #END_RECORD {} #END {} Xastir-Release-2.2.4/config/tl_2025_uac.dbfawk0000664000175000017500000000145715151324131017674 0ustar hibbyhibby# Copyright (C) 2000-2026 The Xastir Group # # # dbfawk designed for 2025 Tiger/Line "uac" (urban/cities) shapefiles # # This one's simple. All shapes are G3500 for MTFCC, all will render the #same. Just set color and display level in BEGIN_RECORD, name per record, # and we're done. # # For best results, the "tl_2025_us_uac20.shp" file should be a fairly low layer # as it otherwise covers other features in cities. # BEGIN { dbfinfo="UACE20:GEOID20:GEOIDFQ20:NAME20:NAMELSAD20:LSAD20:MTFCC20:FUNCSTAT20:ALAND20:AWATER20:INTPTLAT20:INTPTLON20"; dbffields="NAME20"; } BEGIN_RECORD { color=115; name=""; filled=1; pattern=0; key=""; lanes=1; label_color=8; fill_style=2; fill_stipple=0; fill_color=115; display_level=8192; label_level=512; font_size=1; symbol=""; } /^NAME20=(.+)$/ {name="$1"; next;} Xastir-Release-2.2.4/config/tnc-startup.aea0000664000175000017500000000152015151324131017520 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for AEA TNC's. # lines that begin with a pound sign are comments. # # This has not been tweaked yet to be specific to AEA's. # Please modify it and send the patches to the mailing lists. # Thanks. # HID on #CWID off EXP on ECHO off # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on FLow off FUll off HEA off #LFadd off #LFSup ON #AUTOLF off #MCOM off MFILTER 0 MON ON # # Important! Only monitor PID 0xf0 packets: MPROTO OFF # #MResp OFF MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off #SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.4/config/tnc-startup.d7000000664000175000017500000000254015151324131017447 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # TNC Init file for KENWOOD D700. Also reported to work with the # Alinco DR-135TP radio (with the EJ-41U TNC which also uses a Tasco # TNC just like the Kenwoods). Perhaps works with the Alinco DR-635 # radio (with the EJ-50U TNC) too. # # NOTE: TXD on a D700A is fixed at 500ms (1/2 second) in "APRS" # mode. In "packet" mode we can change the txd to other values. # # #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META #Put the TNC in packet mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TNC 2 # Pause for two seconds ##META ##META ##META ##META # Enable 4800 baud GPS # Change to 2 for 9600 baud GPS # Disable both the META line and the GU line for no change ##META GU 1 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META HID off #CWID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off HBAUD 1200 TXDELAY 25 HEADERLN off # Delete following lines if without GPS GBAUD 4800 GPSTEXT $GPRMC LTMH OFF LTM 10 # Xastir-Release-2.2.4/config/tnc-startup.d72_d7100000664000175000017500000000140615151324131020124 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # TNC Init file for KENWOOD TM-D710 or TH-D72 radios. # Contributed by Kai Günter, LA3QMA. # # If using a GPS you must change GBAUD, GPSTEXT, LTMH. # # #Don't send CONTROL-C before this line ##META #TC 1 ##Pause for one second ##META ##META #Put the TNC in packet mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TN 2,0 # Pause for two seconds ##META ##META ##META ##META HID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off HBAUD 1200 TXDELAY 25 HEADERLN off # Delete following lines if without GPS #GBAUD 4800 #GPSTEXT $GPRMC #LTMH OFF # # Xastir-Release-2.2.4/config/tnc-startup.kam0000664000175000017500000000137215151324131017547 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for a Kantronics KAM TNC. # lines that begin with a pound sign are comments. # Edit this file for your tnc! # # Important! Only uncomment if really needed as a fill-in digi: #myalias WIDE1-1 # INTF TERM #One KAM user reports this command does not exist on his KAM #txu on xflow off MONITOR ON MSTAMP OFF HEADERLN OFF #One KAM user reports this command does not exist on his KAM #SCREENLN 0 AUTOLF OFF LFADD OFF CD SOFT MCOM OFF/OFF MCON OFF FILT OFF AUTOCR 0 BEACON EVERY 0 BT % BUDL OFF/OFF CMS DISC CONL OFF CT APRS Network no connected messages supported! ECHO OFF FLOW OFF HID OFF/OFF #CWID EVERY 0 MSTAMP OFF PASSALL OFF # # Important! Monitor only PID 0xf0 packets: PID OFF Xastir-Release-2.2.4/config/tnc-startup.kpc20000664000175000017500000000061415151324131017634 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. # # HID off #CWID every 0 B E 0 DIGI on ECho off FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MON ON MResp OFF MRPt on MSTamp off # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # NEWmode off SCR 0 # Xastir-Release-2.2.4/config/tnc-startup.kpc30000664000175000017500000000340315151324131017634 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. # # This configuration sets up Control-E mode for a KPC-3+ (GPS # connected to the 2nd serial port). When Xastir is actively # getting GPS fixes, the TNC beacons only what Xastir sends to it. # When Xastir stops getting GPS data from the TNC, the TNC will # revert to dumb-tracker mode and start sending NMEA strings out all # by itself at a 20-minute rate. If the GPS get disconnected or # turned off, the dumb-tracker mode will cease to send out beacons. # This last function is done by the "CLEAR" parameter for the BLT # commands. # # Some people prefer to turn off the GPS but still have the TNC # beacon their last good GPS position when in dumb-tracker mode. # To do this, remove the "CLEAR" parameters from the BLT command # lines. # int terminal # Clear out the LT buffers so we don't have old data in there: LT 1 LT 2 LT 3 LT 4 # Clear out the buffer regularly to prevent stale data: BLT 1 00:20:00 CLEAR BLT 2 00:20:00 CLEAR BLT 3 00:00:00 BLT 4 00:00:00 # Set up the NMEA strings to capture: GPSHEAD 1 $GPRMC GPSHEAD 2 $GPGGA # GPSPORT 4800 NORMAL CHECKSUM LGETCHAR $05 # HID off #CWID every 0 # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on ECho off FILT off FLow off FUll off HEA off LFadd off LFSup ON AUTOLF off MCOM off MON ON MResp OFF MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off # # Important! Monitor only PID 0xf0 packets: PID off # SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.4/config/tnc-startup.null0000664000175000017500000000000015151324131017734 0ustar hibbyhibbyXastir-Release-2.2.4/config/tnc-startup.paccomm0000664000175000017500000000164115151324131020415 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for a Pac-Comm TNC with v5.x firmware. # Adapted from Kantronics startup file by Kurt Freiberger, WB5BBW # lines that begin with a pound sign are comments. HID off #CWID every 0 MON 0 ECHO off #MYCall WB5BBW # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # # # #MY1Alias LOCAL #MY2Alias REGION #MY3Alias WORLD # # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. B E 0 # This enables DIGI On and DIGI-SWAP,DIGI-NOT-OWN, DIGI-ONCE enabled. DIGI 7 FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MFILT $00 MRPt on MSTamp off NEWmode off PASSALL off SCR 0 MON 1 # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # # End of tnc-startup.pac # Xastir-Release-2.2.4/config/tnc-startup.pico0000664000175000017500000000240115151324131017723 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for a dual-port Paccomm PicoPacket TNC. # lines that begin with a pound sign are comments. ECHO off AUTOLF on BEACON EVERY 0 # # Clear the GPS buffers LTEXT % L1TEXT % L2TEXT % L3TEXT % # # Set up the NMEA strings we wish to capture: #GPSTEXT % GPSTEXT $GPRMC # #LG1TEXT % LG1TEXT $GPGGA # LG2TEXT % #LG2TEXT $GPVTG # LG3TEXT % #LG3TEXT $PGRME # # Digipeat,callsign substitution, # no digi of own packets, and digi-once DIGIPEAT 7 ELOC 0 FLOW off FULLDUP off GPS off HEADERLI off HID off #CWID every 0 INTERVAL 0 LFADD off LGETCHAR $05 LOC E 0 # MALL ON MCOM off MCON on MFILTER 0 MONITOR 3 MRPT on MSTAMP off # # Important! Only uncomment if really needed as a fill-in digi: #MYALIAS WIDE1-1 # #MY1ALIAS SAR #MY2ALIAS ESAR #MY3ALIAS ESAR2 NEWMODE off NOMODE on #PACLEN 128 # # Only used in KISS mode? PERSIST 128 # PASSALL off # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # PMS off SCREENLN 0 # # Only used in KISS mode? SLOTTIME 15 # TXDELAY 30 XFLOW off # # # BEACON EVERY 0 must be set to 0 or both Xastir and your TNC will send # beacons which will alternate in everyones lists and fill up their # logs. Do NOT set BEACON EVERY to anything other than 0 while Xastir # is running. Xastir-Release-2.2.4/config/tnc-startup.sys0000664000175000017500000000156015151324131017614 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for Kantronics TNC. # lines that begin with a pound sign are comments. int terminal ECHO off HID off #CWID off #CWID every 0 # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # B E 0 DIGI on EXP on Filt off FLow off FUll off HEA off LFadd off LFSup on AUTOLF off MCOM off MFILT off MON on MResp off MRPt on MSTamp off MXMit off NEWmode off #PACLen 128 PASSALL off # # # Important! Monitor only PID 0xf0 packets: # *Kantronics* PID off # *TAPR2* MNOAX25 off # *Paccomm* PIDCHECK on # *AEA* MPROTO OFF # End of monitor only PID 0xf0 packets section # # SCR 0 # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. Xastir-Release-2.2.4/config/tnc-startup.thd70000664000175000017500000000324515151324131017646 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # TNC Init file for KENWOOD TH-D7 # #-------------------------------------------------- # Note: Terminal Control commands are send without # CONTROL-C before the lines. #-------------------------------------------------- # #-------------------------------------------------- # Turn on Terminal Control # # This will make the TH-D7 drop out of Packet mode. # Once out of Packet mode, the TH-D7 will forget # all old TNC settings and even KISS mode, so we # can start from a clean situation. #-------------------------------------------------- # ##META TC 1 # Pause one second ##META ##META # #-------------------------------------------------- # Turn off Terminal Control # # This will make the TH-D7 switch to Packet mode. #-------------------------------------------------- # ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # #-------------------------------------------------- # Initialize the TNC # # This will setup the TH-D7 TNC for use with APRS. #-------------------------------------------------- # HID off #CWID off AWlen 8 BBSMsgs ON B E 0 LOC E 0 Echo off FLow off AUTOLF off MCOM off MON ON MRPt on PACLen 128 PASSALL off # # Enable this line ONLY if you're running 9600 baud packet. It # changes the on-the-air speed from the default 1200 baud. #HBAUD 9600 # TXDELAY 25 # #-------------------------------------------------- # Initialize the GPS # # Enable the commands if running with GPS. # If running without GPS, leave them disabled. #-------------------------------------------------- # #GBAUD 4800 #GPSTEXT $GPRMC #LTMH OFF #LTM 10 # Xastir-Release-2.2.4/config/tnc-startup.tnc20000664000175000017500000000167715151324131017655 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for a TAPR TNC2 style of TNC. This # includes many TNC's from TAPR, Paccomm, MFJ, AEA, etc that were # based on the original TAPR-2 design. # lines that begin with a pound sign are comments. HID off #CWID every 0 MON 0 ECHO off #MYCall WB5BBW # # Important! Only uncomment if really needed as a fill-in digi: #MYAlias WIDE1-1 # #MY1Alias WIDE #MY2Alias REGION #MY3Alias WORLD # B E 0 must be set to 0 or both APRS and your TNC will send BCNS # Which will alternate in everyones L and A lists and fill up # their logs. Do NOT set B E to anything other than 0 while APRS # is running. B E 0 # This enables DIGI On and DIGI-SWAP,DIGI-NOT-OWN, DIGI-ONCE enabled. DIGI 7 FLow off FUll off HEA off LFadd off AUTOLF off MCOM off MFILT $00 MRPt on MSTamp off NEWmode off PASSALL off SCR 0 MON 1 # # Important! Monitor only PID 0xf0 packets: PIDCHECK on # # End of tnc-startup.tnc2 # Xastir-Release-2.2.4/config/tnc-startup.tnc2-ui0000664000175000017500000000037715151324131020264 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for the TNC2-UI TNC. # lines that begin with a pound sign are comments. HID off #CWID off MONITOR OFF ECHO OFF LF OFF BEACON 0 LTIME 0 HEADER OFF MCOM OFF AXLF OFF MONITOR ON Xastir-Release-2.2.4/config/tnc-stop.d7000000664000175000017500000000165115151324131016734 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # #TNC STOP FILE # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! UNPROTO CQ AUTOLF ON ECHO ON #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META # Turn off AUX port ##META GU 0 ##META #Put the TNC in internal mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TNC 1 # Pause for two seconds ##META ##META ##META ##META # Enable 4800 baud GPS # Change to 2 for 9600 baud GPS # Disable both the META line and the GU line for no change ##META GU 1 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # Xastir-Release-2.2.4/config/tnc-stop.d72_d7100000664000175000017500000000136315151324131017411 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # TNC STOP FILE for Kenwood TM-D710 or TH-D72 radios. # Contributed by Kai Günter, LA3QMA. # # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! # # UNPROTO CQ AUTOLF ON ECHO ON #Don't send CONTROL-C before this line ##META TC 1 ##Pause for one second ##META ##META ##META #Put the TNC in internal mode since this is where we want to end up # Change the 1 to 0 to go to normal radio mode ##META TN 0,0 # Pause for two seconds ##META ##META ##META ##META #Turn off Terminal Control ##META TC 0 # Pause for two seconds just in case ##META ##META ##META ##META # Xastir-Release-2.2.4/config/tnc-stop.sys0000664000175000017500000000023615151324131017076 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # #TNC STOP FILE # Undo any settings make in tnc-startup.sys # Edit this file for your tnc! UNPROTO CQ AUTOLF ON Xastir-Release-2.2.4/config/tnc-stop.thd70000664000175000017500000000167715151324131017140 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # TNC Stop file for KENWOOD TH-D7 # #-------------------------------------------------- # Note: Terminal Control commands are send without # CONTROL-C before the lines. #-------------------------------------------------- # #-------------------------------------------------- # Turn on Terminal Control # # This will make the TH-D7 drop out of Packet mode. # Once out of Packet mode, the TH-D7 will forget # all TNC settings. No need to restore anything. #-------------------------------------------------- # ##META TC 1 # Pause one second ##META ##META # #-------------------------------------------------- # Resume standalone APRS use. # # GPS en Beacon settings are not changed. Once back # in APRS mode, the GPS and Beacon are resumed as # they were. #-------------------------------------------------- # ##META TNC 1 # Pause one second ##META ##META # Xastir-Release-2.2.4/config/tnc-stop.tnc2-ui0000664000175000017500000000027515151324131017544 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # This is the TNC Startup file for the TNC2-UI TNC. # lines that begin with a pound sign are comments. MONITOR OFF LF ON ECHO ON MONITOR ON Xastir-Release-2.2.4/config/xastir.rgb0000664000175000017500000000406615151324131016602 0ustar hibbyhibby000 000 000 black 069 069 069 gray27 047 079 079 DarkSlateGray 089 089 089 gray35 135 135 135 gray53 169 169 169 darkgray 186 186 186 gray73 204 204 204 gray80 207 207 207 gray81 211 211 211 lightgray 219 219 219 gray86 255 255 255 white 000 000 255 blue 000 000 238 blue2 000 000 205 blue3 000 000 139 blue4 173 216 230 lightblue 030 144 255 DodgerBlue 065 105 225 RoyalBlue 070 130 180 SteelBlue 000 191 255 DeepSkyBlue 000 000 205 MediumBlue 000 000 128 NavyBlue 000 255 000 green 000 238 000 green2 000 205 000 green3 000 139 000 green4 152 251 152 PaleGreen 050 205 050 LimeGreen 060 179 113 MediumSeaGreen 034 139 034 ForestGreen 000 100 000 DarkGreen 000 255 255 cyan 000 238 238 cyan2 000 205 205 cyan3 000 139 139 cyan4 224 255 255 LightCyan 255 000 000 red 238 000 000 red2 205 000 000 red3 139 000 000 red4 255 000 255 magenta 238 000 238 magenta2 205 000 205 magenta3 139 000 139 magenta4 255 255 000 yellow 238 238 000 yellow2 238 238 150 yellow3 139 139 000 yellow4 250 250 210 LightGoldenrodYellow 238 232 170 PaleGoldenrod 255 248 220 cornsilk 255 165 000 orange 238 154 000 orange2 205 133 000 orange3 205 102 000 DarkOrange3 255 069 000 OrangeRed 178 034 034 firebrick 188 143 143 RosyBrown 255 180 180 RosyBrown2 165 042 042 brown 255 064 064 brown1 205 051 051 brown3 255 130 071 sienna1 064 224 208 turquoise 186 085 211 mediumorchid 153 050 204 DarkOrchid 160 032 240 purple 127 255 000 chartreuse 230 230 250 lavender 221 160 221 plum 238 174 238 plum2 250 128 114 salmon 255 192 203 pink 255 228 225 MistyRose 255 174 185 LightPink1 255 105 180 HotPink 219 088 055 tgr_prird_1 242 164 085 tgr_secrd_1 127 255 127 tgr_park_1 255 247 159 tgr_city_1 175 215 127 tgr_forest_1 0 159 255 tgr_water_1 000 032 077 cividis_1 000 057 109 cividis_2 057 084 111 cividis_3 094 110 108 cividis_4 130 136 101 cividis_5 165 163 094 cividis_6 204 190 056 cividis_7 245 219 083 cividis_8 255 249 076 cividis_9 228 026 028 set1_1 055 126 184 set1_2 077 175 074 set1_3 152 078 163 set1_4 255 127 000 set1_5 255 255 051 set1_6 166 086 040 set1_7 247 129 191 set1_8 153 153 153 set1_9 Xastir-Release-2.2.4/configure.ac0000664000175000017500000007055615151324131015624 0ustar hibbyhibby# Process this file with autoconf to produce a configure script. # # # Copyright (C) 2000-2026 The Xastir Group ######################################################################### # SET VERSION HERE! # # Note that the most standard OSS method of doing numbering is: # Major.Minor.PatchLevel # # If we are only doing patches, change the PATCHLEVEL number. # If we add new features, change the MINOR number. # If we feel we've added enough new features or rewritten enough # code to warrant it, change the MAJOR number. # # Also: We adopted the convention of using odd numbers for development # or development releases, even numbers for STABLE releases. # # # AC_INIT(): # It should look something like this: ([xastir], [2.0.8], [xastir@xastir.org]) # The revision number must contain at least one '.' and two digits. AC_INIT([xastir], [2.2.4], [xastir@xastir.org]) ######################################################################### AC_PREREQ(2.60) AC_CONFIG_SRCDIR([src/xastir.h]) #AM_CONFIG_HEADER(config.h) AC_CONFIG_HEADERS(config.h) AM_INIT_AUTOMAKE([subdir-objects 1.16]) AM_SILENT_RULES(yes) echo "" echo "Configuring AC_PACKAGE_NAME AC_PACKAGE_VERSION" echo "" # Take out the dots in order to create the TOCALL AC_DEFINE_UNQUOTED(XASTIR_TOCALL, "`echo AC_PACKAGE_VERSION | sed -e 's/^/APX/' -e 's/\.//g'`", [Defines the version tocall]) # Check for host type AC_CANONICAL_HOST # Define _GNU_SOURCE if appropriate # doesn't work with older (heh) autoconfs # This macro is now obsolete as of autoconf 2.60 and should no longer # be used: AC_GNU_SOURCE # autoconf 2.60 was released in 2006, so it should be safe to assume all # users have at least this version by now. AC_USE_SYSTEM_EXTENSIONS(_GNU_SOURCE) # Checks for programs. AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_AWK AC_PROG_RANLIB #AC_PROG_YACC AM_PROG_CC_C_O # test for devices XASTIR_DETECT_DEVICES # add includes and libs XASTIR_ADD_SEARCH_PATHS # check for pthread first ACX_PTHREAD # add compiler flags XASTIR_COMPILER_FLAGS # Check for binaries use_festival=yes use_gpsman=yes use_err_popups=no use_spatial_db=no use_postgis=no use_mysql_spatial=no AC_ARG_WITH(festival,[ --without-festival Disable festival features.],use_festival=$withval) AC_ARG_WITH(gpsman,[ --without-gpsman Disable gpsman features.],use_gpsman=$withval) AC_ARG_WITH(errorpopups,[ --with-errorpopups Send error popups to stderr.],use_err_popups=$withval) # Now that all the various "use_" variables are set, probe for binaries. XASTIR_DETECT_BINARIES # if the probes failed, then make sure the "use_" variables are set to no, # even if we requested them. if test "x${festival}" = "xno"; then use_festival=no fi if test "x${gpsman}" = "xno"; then use_gpsman=no fi # JMT - XXX - what is this and why is it relevant? #AC_DEFINE(_REENTRANT, 1, [Use reentrant code if available.]) AC_DEFINE_UNQUOTED(STIPPLE, 1, [Legacy stuff, use crowbar and lets keep going]) # Checks for libraries. # # # Find the X11 include and library directories. # AC_PATH_XTRA if test "$no_x" = "yes"; then AC_MSG_ERROR(*** No X11! Install the X Window System development headers/libraries! ***) fi CPPFLAGS="$CPPFLAGS $X_CFLAGS" LDFLAGS="$LDFLAGS $X_LIBS" LIBS="$LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS" AC_SEARCH_LIBS(tan,math m) AC_CHECK_LIB([Xext], [XextAddDisplay]) #*********************************** # Check for libXp removed on 31 Oct 2015 # This was in place for a very long time, but libxp is now deprecated and # has even been removed from some distros # # XpGetDocumentData is not used *anywhere* in Xastir, but some distros have # a Motif library that is linked against it. This is supposed to be # taken care of by the shared library loader, not by explicit linking, but # as late as 2007 some distros had it linked wrong. It appears as of 2015 # that nobody still does that, and this check causes more harm than good. # # If the build of Xastir fails at link time looking for XpGetDocumentData, # then somebody *does* still do that incorrect shared library linking, # and y9ou'll need to re-enable this on your system # #AC_CHECK_LIB([Xp], [XpGetDocumentData]) #************************************ AC_CHECK_LIB([Xt], [XtDisplay]) AC_CHECK_LIB([Xm], [XmTextFindString]) #use_html2text=no #AC_PATH_PROG(html2text, [html2text --version], no, $BINPATH) #if test "$html2text" != "no"; then # AC_DEFINE_UNQUOTED(HAVE_HTML2TEXT, 1, [Define if you have html2text]) # AC_DEFINE_UNQUOTED(HTML2TEXT_PATH, "${html2text}", [Path to html2text]) # use_html2text=yes #fi use_sed=no AC_PATH_PROG(sed, [sed --version], no, $BINPATH) if test "$sed" != "no"; then AC_DEFINE_UNQUOTED(HAVE_SED, 1, [Define if you have sed]) AC_DEFINE_UNQUOTED(SED_PATH, "${sed}", [Path to sed]) use_sed=yes fi use_mv=no AC_PATH_PROG(mv, [mv --version], no, $BINPATH) if test "$mv" != "no"; then AC_DEFINE_UNQUOTED(HAVE_MV, 1, [Define if you have mv]) AC_DEFINE_UNQUOTED(MV_PATH, "${mv}", [Path to mv]) use_mv=yes fi use_xfontsel=no AC_PATH_PROG(xfontsel, xfontsel, no, $BINPATH) if test "$xfontsel" != "no"; then AC_DEFINE_UNQUOTED(HAVE_XFONTSEL, 1, [Define if you have xfontsel]) AC_DEFINE_UNQUOTED(XFONTSEL_PATH, "${xfontsel}", [Path to xfontsel]) use_xfontsel=yes fi use_curl=no curl_desired=yes # Note: Had to move AC_CHECK_HEADER here instead of inside the first # "if" statement: It corrupted later tests, don't know why. The # only downside is that we check for the libcurl headers even if # --without-libcurl was specified on the command-line. AC_CHECK_HEADER(curl/curl.h, CURL_INC="yes", CURL_INC="no") AC_ARG_WITH(libcurl,[ --without-libcurl Disable libcurl features.],curl_desired=$withval) if test "${curl_desired}" = "yes"; then if test "${CURL_INC}" = "yes"; then # Important: when using the three-argument version of AC_CHECK_LIB, you # must do all of what is normally the default behavior in the third argument, # not just the extra stuff you want to accomplish: AC_CHECK_LIB([curl], [curl_global_init], [use_curl="yes" LIBS="${LIBS} -lcurl" AC_DEFINE(HAVE_LIBCURL, 1, [Define to 1 if your `curl' library has curl_global_init.]) ]) fi fi # Test for wget only if above libcurl tests fail use_wget=no if test "${use_curl}" = "no"; then AC_PATH_PROG(wget, [wget --version], no, $BINPATH) if test "$wget" != "no"; then AC_DEFINE_UNQUOTED(HAVE_WGET, 1, [Define if you have wget]) AC_DEFINE_UNQUOTED(WGET_PATH, "${wget}", [Path to wget]) use_wget=yes fi fi # Check for cJSON library (optional - enables Nominatim geocoding) use_nominatim=no AC_ARG_WITH(nominatim, [ --without-nominatim Disable Nominatim geocoding support.], [nominatim_desired=$withval], [nominatim_desired=yes]) if test "${nominatim_desired}" = "yes"; then if test "${use_curl}" = "yes"; then AC_CHECK_HEADERS([cjson/cJSON.h], [AC_CHECK_LIB([cjson], [cJSON_Parse], [use_cjson="yes" use_nominatim="yes" LIBS="${LIBS} -lcjson" AC_DEFINE(HAVE_CJSON, 1, [Define to 1 if you have cJSON]) AC_DEFINE(HAVE_NOMINATIM, 1, [Define to 1 to enable Nominatim geocoding]) ], [AC_MSG_WARN([cJSON library not found, disabling Nominatim geocoding])] )], [AC_MSG_WARN([cjson/cJSON.h not found, disabling Nominatim geocoding])] ) else AC_MSG_WARN([libcurl is required for Nominatim geocoding, disabling Nominatim]) fi fi # Make nominatim conditional available to Makefile.am AM_CONDITIONAL(HAVE_NOMINATIM, test x$use_nominatim = xyes) use_retrieval=no if test "${use_curl}" = "yes"; then use_retrieval="yes (libcurl)" else if test "${use_wget}" = "yes"; then use_retrieval="yes (wget)" fi fi # Test for libgps, used for accessing GPSD daemon #use_libgps=no #AC_CHECK_HEADER(gps.h, GPS_INC="yes", GPS_INC="no") #if test "${GPS_INC}" = "yes"; then # AC_CHECK_LIB([gps], [gps_open], # [use_libgps="yes" # LIBS="${LIBS} -lgps" # AC_DEFINE(HAVE_LIBGPS, 1, # [Define to 1 if your `libgps' library has gps_open.]) # ]) #fi # JMT - XXX - why is this here? AC_CHECK_LIB(compat, main, [LIBCOMPAT="-lcompat" AC_SUBST(LIBCOMPAT)]) # Check for sched_yield in librt (Needed for Solaris) AC_CHECK_LIB(rt, sched_yield, LIBS="-lrt $LIBS") # Check for endian AC_C_BIGENDIAN # Our old stuff. Doesn't work in all cases. # Checks for header files. #AC_CHECK_HEADERS([Xm/Xm.h],MOTIF_INC="yes", AC_MSG_ERROR(*** Cannot find Motif include files: Please install one of Motif/OpenMotif/Lesstif development packages. ***)) XASTIR_PATH_MOTIF if test "x$xm_includes" != "x" ; then CFLAGS="$CFLAGS -I$xm_includes" CPPFLAGS="$CPPFLAGS -I$xm_includes" fi if test "x$xm_libraries" != "x" ; then LDFLAGS="-L$xm_libraries $LDFLAGS" fi AC_SUBST(LDFLAGS) AC_SUBST(LIBS) # AC_FUNC_ALLOCA AC_HEADER_DIRENT AC_HEADER_SYS_WAIT # We still check for stdarg.h even though it's standard, because a legacy # file (snprintf.c) still uses its symbol. AC_CHECK_HEADERS([stdarg.h]) AC_CHECK_HEADERS([sys/file.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h signal.h]) AC_CHECK_HEADERS([termios.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. # AC_C_CONST AC_TYPE_UID_T AC_C_INLINE AC_TYPE_PID_T AC_TYPE_SIZE_T AC_STRUCT_TIMEZONE #Some (Mac?) systems don't define this where it should be, so we kludge AC_CHECK_TYPES(socklen_t,,,[#include #include ]) # some BSD systems do not define sighandler_t, but rather sig_t AC_CHECK_TYPES(sighandler_t,,,[#include ]) AC_CHECK_TYPES(sig_t,,,[#include ]) # some BSD systems do not define sighandler_t, but rather sig_t AC_CHECK_TYPES(sigjmp_buf,,,[#include ]) #Force this into config.h.in AH_BOTTOM([#ifndef HAVE_SOCKLEN_T #define socklen_t int #endif]) # Check for tm_gmtoff in tm AC_CHECK_GMTOFF # Checks for library functions. # AC_FUNC_FORK AC_FUNC_GETPGRP AC_FUNC_MALLOC AC_FUNC_MKTIME AC_FUNC_MMAP AC_FUNC_STAT AC_FUNC_STRFTIME AC_FUNC_STRTOD AC_CHECK_FUNCS([getcwd getpgrp gethostbyname gethostname gettimeofday]) AC_CHECK_FUNCS([getwd inet_ntoa memmove mempcpy memset mkdir munmap pow]) AC_CHECK_FUNCS([putenv select setenv setlocale settimeofday signal sigignore]) AC_CHECK_FUNCS([snprintf socket sqrt stpcpy strcasecmp strchr strdup]) AC_CHECK_FUNCS([strerror strncasecmp strpbrk strptime strrchr strstr]) AC_CHECK_FUNCS([strtof strtol strtoul tzset vsnprintf]) # Check for deprecated/current pthread functions AC_CHECK_FUNCS([pthread_mutexattr_setkind_np pthread_mutexattr_settype]) # this is a GNU extension and not present on all systems. AC_CHECK_FUNCS([strndup]) #this is also a recent extension that should not be counted on AC_CHECK_FUNCS([roundf]) # Check for libproj (need to do this before test for geotiff, which is the # only thing we have that uses proj use_proj=yes AC_ARG_WITH(libproj,[ --without-libproj Disable libproj features.],use_proj=$withval) if test "${use_proj}" = "yes"; then use_proj=no AC_CHECK_LIB([proj], [proj_create_crs_to_crs], [use_proj=yes LIBS="$LIBS -lproj" AC_DEFINE(HAVE_PROJ, 1, Define to 1 if you have the `libproj' library (-lproj). )], [ AC_CHECK_LIB([proj], [pj_init], [use_proj=yes LIBS="$LIBS -lproj" AC_DEFINE(HAVE_PROJ, 1, Define to 1 if you have the `libproj' library (-lproj). )])] ) fi # Check for Shapelib use_shapelib=yes shapelib_desired=yes AC_ARG_WITH(shapelib,[ --without-shapelib Disable shapelib features.],shapelib_desired=$withval) if test "${shapelib_desired}" = "no"; then use_shapelib=no fi if test "${shapelib_desired}" = "yes" ; then use_shapelib=no AC_CHECK_HEADERS([shapefil.h libshp/shapefil.h], [AC_CHECK_LIB([shp], [DBFOpen], [use_shapelib=yes LIBS="$LIBS -lshp" AC_DEFINE(HAVE_LIBSHP, 1, [Define to 1 if you have the `shp' library (-lshp).]) ]) break ]) fi # Shapelib requires pcre now use_pcre=no if test "${shapelib_desired}" = "yes" -a "${use_shapelib}" = "yes"; then AC_CHECK_HEADERS([pcre2.h], [AC_CHECK_LIB([pcre2-8],[pcre2_compile_8], [use_pcre="yes (PCRE2)" LIBS="$LIBS -lpcre2-8" ], [use_pcre=no AC_MSG_WARN([Found pcre2 headers but not libraries]) ]) ], [use_pcre=no], [ #define PCRE2_CODE_UNIT_WIDTH 8 ]) if test "${use_pcre}" = "no" then AC_MSG_WARN([Modern PCRE2 not found, checking for legacy version]) AC_CHECK_HEADERS([pcre.h pcre/pcre.h], [AC_CHECK_LIB([pcre], [pcre_compile], [use_pcre="yes (legacy)" LIBS="$LIBS -lpcre" AC_DEFINE(XASTIR_LEGACY_PCRE, 1, Define to 1 if you have the legacy `pcre' library (-lpcre). ) ]) break ]) fi if test "${use_pcre}" = "no" then AC_MSG_ERROR([Shapelib support requires PCRE, and we could not find PCRE. Either disable shapelib by specifying "--without-shapelib" or install PCRE libraries and headers]) fi fi if test "${shapelib_desired}" = "yes" -a "${use_shapelib}" = "no"; then AC_MSG_WARN([**************************************************************** ]) AC_MSG_WARN([Your system does not have shapelib installed. ]) AC_MSG_WARN([Install shapelib on your system to eliminate this warning. ]) AC_MSG_WARN([**************************************************************** ]) use_shapelib=no fi # Check for XPM use_xpm="no" AC_CHECK_HEADERS(X11/xpm.h, [ #action if found in addition to setting HAVE_X11_XPM_H AC_SEARCH_LIBS(XpmWriteFileFromPixmap, [Xpm], [ # action if found (in addition to adding -lXpm to LIBS use_xpm="yes" AC_DEFINE(HAVE_LIBXPM, 1, [Define to 1 if you have the `Xpm' library (-lXpm).] ) ]) ], [ # Action if X11/xpm.h is not found: look for Xm/XpmI.h instead AC_CHECK_HEADERS(Xm/XpmI.h, [ # Action if found, in addition to setting HAVE_XM_XPMI_H AC_SEARCH_LIBS(XmeXpmWriteFileFromPixmap, [Xm], [ # action if -lXm is found, in addition to adding -lXm to LIBS use_xpm="yes" AC_DEFINE(HAVE_LIBXPM_IN_XM, 1, [Define to 1 if the `Xm' library (-lXm) is used for Xpm.]) ], [ #action if -lXm not found: issue warning AC_MSG_WARN([**************************************************************** ]) AC_MSG_WARN([Your system does not have a library that contains XpmWriteFileFromPixmap]) AC_MSG_WARN([PNG snapshots cannot work. ]) AC_MSG_WARN([**************************************************************** ]) ]) ]) ]) use_geotiff=yes AC_ARG_WITH(geotiff, [ --without-geotiff Disable geotiff features.], use_geotiff=$withval) if test "${use_geotiff}" = "yes"; then if test "${use_proj}" = "yes" ; then AC_CHECK_HEADER(xtiffio.h, , use_geotiff="no") if test "${use_geotiff}" = "yes"; then AC_CHECK_LIB(tiff, TIFFClose, use_tiff=yes LIBS="$LIBS -ltiff" AC_DEFINE(HAVE_TIFF, 1,Define to 1 if you have the 'tiff' library (-ltiff))) if test "${use_tiff}" = "yes"; then use_geotiff=no AC_CHECK_LIB(geotiff, GTIFNew, use_geotiff=yes LIBS="$LIBS -lgeotiff" AC_DEFINE(HAVE_LIBGEOTIFF, 1,Define to 1 if you have the `geotiff' library (-lgeotiff).)) else echo "*** Warning: geotiff requires libtiff." use_geotiff=no fi else echo "*** Warning: geotiff include files not found." fi else echo "*** Warning: geotiff requires libproj." use_geotiff=no fi fi # Check for spatial database support use_postgis=no AC_ARG_WITH(postgis, [ --with-postgis Enable Postgresql with PostGIS.],use_postgis=$withval) if test "${use_postgis}" != "no"; then XASTIR_CHECK_POSTGIS fi use_mysql=no AC_ARG_WITH(mysql, [ --with-mysql Enable MySQL, with spatial support if available.],use_mysql=$withval) if test "${use_mysql}" != "no"; then XASTIR_CHECK_MYSQL fi if test "${use_postgis}" = "yes"; then use_spatial_db=yes AC_DEFINE(HAVE_SPATIAL_DB, 1, [Spatial database support available] ) AC_DEFINE(HAVE_DB, 1, [Database support available] ) fi if test "${use_mysql_spatial}" = "yes"; then use_spatial_db=yes AC_DEFINE(HAVE_DB, 1, [Database support available] ) AC_DEFINE(HAVE_SPATIAL_DB, 1, [Spatial database support available] ) elif test use_mysql_any = "yes"; then AC_DEFINE(HAVE_DB, 1, [Database support available] ) fi # Check for AX.25 library use_ax25=yes AC_ARG_WITH(ax25,[ --without-ax25 Disable ax25 features.],use_ax25=$withval) if test "${use_ax25}" = "yes"; then use_ax25=no AC_CHECK_HEADERS(netax25/ax25.h, [AC_CHECK_LIB(ax25, ax25_config_load_ports, use_ax25=yes LIBS="$LIBS -lax25" AC_DEFINE(HAVE_LIBAX25, 1, Define to 1 if you have the `ax25' library (-lax25). ) break)]) fi AC_ARG_ENABLE(davis, [ --enable-davis Turn on Davis support], [case "${enableval}" in yes) davis=true ;; no) davis=false ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-davis) ;; esac],[davis=false]) AM_CONDITIONAL(DAVIS, test x$davis = xtrue) if test "${davis}" = "true"; then davis=yes else davis=no fi # Check for LIBGC, a Garbage Collection library. If found, allow # linking it with Xastir, but require the "--with-libgc" flag to # enable it. use_libgc=no AC_ARG_WITH(libgc,[ --with-libgc Enable libgc features.],use_libgc=$withval) if test "${use_libgc}" = "yes"; then AC_CHECK_HEADERS([gc.h], LIBGC_INC="yes", use_libgc=no) AC_CHECK_LIB([gc], [GC_init], , use_libgc=no) fi # Check whether profiling was requested. If so, add the "-pg" flag # to CFLAGS. Require "--with-profiling" flag to enable it. use_profiling=no AC_ARG_WITH(profiling,[ --with-profiling Enable profiling features.],use_profiling=$withval) if test "${use_profiling}" = "yes"; then CFLAGS="$CFLAGS -pg" fi # Check for Berkeley DB. use_map_cache=yes AC_ARG_WITH(map_cache,[ --without-map-cache Disable Berkeley DB Map Caching.],use_map_cache=$withval) if test "${use_map_cache}" = "yes"; then XASTIR_BERKELEY_DB_CHK fi # Check for GraphicsMagick. If not available/desired then check for # ImageMagick. These checks are VERY important to have as the last, # as they mess up previous checks if they fail. # use_graphicsmagick=yes use_imagemagick=no AC_ARG_WITH(graphicsmagick,[ --without-graphicsmagick Disable graphicsmagick features.],use_graphicsmagick=$withval) if test "${use_graphicsmagick}" = "yes"; then XASTIR_CHECK_GRAPHICSMAGICK fi # # Note: This must be a separate "if" as the use_graphicsmagick # variable gets set to "no" if GM is not available above. # if test "${use_graphicsmagick}" = "no"; then use_imagemagick=yes AC_ARG_WITH(imagemagick,[ --without-imagemagick Disable imagemagick features.],use_imagemagick=$withval) if test "${use_imagemagick}" = "yes"; then XASTIR_CHECK_IMAGEMAGICK fi fi # # # if test "${use_imagemagick}" = "yes" -o "${use_graphicsmagick}" = "yes"; then AC_DEFINE(HAVE_MAGICK, 1, [GraphicsMagick or ImageMagick library]) fi # Set XASTIR_DATA_BASE in CPPFLAGS due to Gnu coding standard that requires # datadir expansion to be deferred until make time. if test "x${datadir}" = "x"; then CPPFLAGS="$CPPFLAGS -DXASTIR_DATA_BASE=\\\"${ac_default_prefix}/share/xastir\\\"" else CPPFLAGS="$CPPFLAGS -DXASTIR_DATA_BASE=\\\"${datadir}/xastir\\\"" fi # Add a special option that makes Cygwin link much faster (from # Henk de Groot) AC_MSG_CHECKING([if linker supports --no-keep-memory]) save_LDFLAGS="$LDFLAGS" LDFLAGS="-Wl,--no-keep-memory $LDFLAGS" AC_LINK_IFELSE( [AC_LANG_PROGRAM([], [[return(0);]])], [xa_cv_no_keep_memory=yes], [xa_cv_no_keep_memory=no]) if test "${xa_cv_no_keep_memory}" = "no"; then LDFLAGS="$save_LDFLAGS" AC_MSG_RESULT([no]) else AC_MSG_RESULT([yes]) fi # # Assure we have this order for these LIBS: "-lXm -lXt -lX11" by # adding them to the beginning. Add spaces around them for the # following steps. Here I'm adding them to the beginning so the # dupe-check portion will take out the later ones that might be in # the wrong order. If they're in the wrong order, we can get # "Error: Shell widget xastir has zero width and/or height" when # Xastir is started up. Can also get "Error: attempt to add # non-widget child "DropSiteManager" to parent", but that can also # be caused by other problems with libraries. # LIBS=" -lXm -lXt -lX11 $LIBS" # # Change the compiler optimization if using Windows/Cygwin in order # to reduce memory usage and speed up the compile. Here we change # "-O2" to "-O1" or " " in CFLAGS/CPPFLAGS to reduce the level of # optimization. # We also wish to remove "-no-undefined" from LDFLAGS on Cygwin, as # we use GCC for our linking instead of libtool, and GCC doesn't # like that flag at the link stage. # case "$host_os" in cygwin*) changequote(,) CFLAGS=`echo "$CFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-O2") s = s " " $i} print s}'` CPPFLAGS=`echo "$CPPFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-O2") s = s " " $i} print s}'` LDFLAGS=`echo "$LDFLAGS" | awk '{for(i=1;i<=NF;++i) {if ($i != "-no-undefined") s = s " " $i} print s}'` changequote([,]) ;; esac # Create the ILIBS defined variable. We add spaces here in the else # clauses in order to make the REGRESSION_TESTS format nicely. We # take them back out before we define the variable that Xastir uses # for it's Help->About dialog. # if test "${use_ax25}" = "yes"; then ILIBS="AX25" else ILIBS=" " fi if test "${use_festival}" = "yes"; then ILIBS="$ILIBS Festival" else ILIBS="$ILIBS " fi if test "${use_gpsman}" = "yes"; then ILIBS="$ILIBS GPSMan" else ILIBS="$ILIBS " fi if test "${use_graphicsmagick}" = "yes"; then ILIBS="$ILIBS GraphicsMagick" else if test "${use_imagemagick}" = "yes"; then ILIBS="$ILIBS ImageMagick " else ILIBS="$ILIBS " fi fi if test "${use_proj}" = "yes"; then ILIBS="$ILIBS libProj" else ILIBS="$ILIBS " fi if test "${use_geotiff}" = "yes"; then ILIBS="$ILIBS GeoTiff" else ILIBS="$ILIBS " fi if test "${use_shapelib}" = "yes"; then ILIBS="$ILIBS ShapeLib" else ILIBS="$ILIBS " fi if test "${use_pcre}" != "no"; then if test "${use_pcre}" = "yes(legacy)" then ILIBS="$ILIBS PCRE" else ILIBS="$ILIBS PCRE2" fi else ILIBS="$ILIBS " fi if test "${use_map_cache}" = "yes"; then ILIBS="$ILIBS map_caching" else ILIBS="$ILIBS " fi if test "${use_err_popups}" = "yes"; then ILIBS="$ILIBS error_popups" else ILIBS="$ILIBS " fi if test "${use_libgc}" = "yes"; then ILIBS="$ILIBS libgc" else ILIBS="$ILIBS " fi if test "${use_profiling}" = "yes"; then ILIBS="$ILIBS profiling" else ILIBS="$ILIBS " fi ILIBS="$ILIBS " if test "${use_curl}" = "yes"; then ILIBS="$ILIBS libcurl" else if test "${use_wget}" = "yes"; then ILIBS="$ILIBS wget " else ILIBS="$ILIBS " fi fi if test "${use_nominatim}" = "yes"; then ILIBS="$ILIBS nominatim" else ILIBS="$ILIBS " fi # Write out the library information to "summary.log". Here we want # the spaces for the undefined pieces, so REGRESSION_TESTS formats # nicely. echo "$ILIBS" >summary.log # # Remove extraneous spaces from output variables (aesthetic) # ILIBS=`echo $ILIBS | sed -e 's/ */ /g'` X_CFLAGS=`echo $X_CFLAGS | sed -e 's/ */ /g'` X_PRE_LIBS=`echo $X_PRE_LIBS | sed -e 's/ */ /g'` X_LIBS=`echo $X_LIBS | sed -e 's/ */ /g'` X_EXTRA_LIBS=`echo $X_EXTRA_LIBS | sed -e 's/ */ /g'` CC=`echo $CC | sed -e 's/ */ /g'` CFLAGS=`echo $CFLAGS | sed -e 's/ */ /g'` CPPFLAGS=`echo $CPPFLAGS | sed -e 's/ */ /g'` CXXFLAGS=`echo $CXXFLAGS | sed -e 's/ */ /g'` LDFLAGS=`echo $LDFLAGS | sed -e 's/ */ /g'` TESTED_LIBS=`echo $LIBS | sed -e 's/ */ /g'` MAGICK_DEP_LIBS=`echo $MAGICK_DEP_LIBS | sed -e 's/ */ /g'` LIBS=`echo $LIBS | sed -e 's/ */ /g'` tmp_path="$ac_default_prefix" tmp_bin_path="$ac_default_prefix" if test "x$prefix" != xNONE; then tmp_path="$prefix" tmp_bin_path="$prefix" fi if test "x$exec_prefix" != xNONE; then tmp_bin_path="$exec_prefix" fi AC_DEFINE_UNQUOTED(XASTIR_PATH, "`echo $tmp_path`", [Path to installed Xastir files.]) AC_DEFINE_UNQUOTED(XASTIR_BIN_PATH, "`echo $tmp_bin_path`", [Path to installed Xastir binaries.]) AC_DEFINE_UNQUOTED(XASTIR_INSTALLED_LIBS, "`echo $ILIBS`", [Defines the installed libs]) AC_SUBST(LDFLAGS) AC_SUBST(LIBS) #AC_SUBST(CPPFLAGS) AC_SUBST(X_CFLAGS) #AC_SUBST(LDFLAGS) #AC_SUBST(X_PRE_LIBS) #AC_SUBST(X_LIBS) #AC_SUBST(X_EXTRA_LIBS) # Configure autotest support AC_CONFIG_TESTDIR([tests]) AC_CONFIG_FILES([Makefile \ callpass/Makefile \ config/Makefile \ help/Makefile \ scripts/Makefile \ src/Makefile \ src/rtree/Makefile \ symbols/Makefile \ tests/Makefile \ tests/atlocal \ ]) AC_CONFIG_FILES([scripts/get-BOMdata],[chmod +x scripts/get-BOMdata]) AC_CONFIG_FILES([scripts/get-NWSdata],[chmod +x scripts/get-NWSdata]) AC_CONFIG_FILES([scripts/get-fcc-rac.pl],[chmod +x scripts/get-fcc-rac.pl]) AC_CONFIG_FILES([scripts/icontable.pl],[chmod +x scripts/icontable.pl]) AC_OUTPUT # Please leave these in as they're very useful for debug when we # port to new platforms! Leave them commented out unless doing # debugging on the configure scripts. # #echo "" #echo " LIBS: $LIBS" #echo " LDFLAGS: $LDFLAGS" #echo " CFLAGS: $CFLAGS" #echo " CPPFLAGS: $CPPFLAGS" #echo " X_LIBS: $X_LIBS" #echo " X_PRE_LIBS: $X_PRE_LIBS" #echo "X_EXTRA_LIBS: $X_EXTRA_LIBS" echo =========================================== echo echo AC_PACKAGE_NAME AC_PACKAGE_VERSION has been configured to use the following echo options and external libraries: echo echo MINIMUM OPTIONS: echo " ShapeLib (Vector maps) .................... : $use_shapelib" echo echo RECOMMENDED OPTIONS: echo " Xpm / Snapshots ........................... : $use_xpm" echo -n " GraphicsMagick/ImageMagick (Raster maps) .. : " if test "${use_graphicsmagick}" = "yes"; then echo "yes (GraphicsMagick)" else if test "${use_imagemagick}" = "yes"; then echo "yes (Legacy ImageMagick)" else echo "no" fi fi echo " pcre (Shapefile customization) ............ : $use_pcre" echo " Berkeley DB map caching-Raster map speedups : $use_map_cache" echo " internet map retrieval .................... : $use_retrieval" echo " Nominatim Geocoding ....................... : $use_nominatim" echo echo FOR ADDITIONAL FEATURES: echo " AX25 (Linux Kernel I/O Drivers) ........... : $use_ax25" echo " libproj (used by libgeotif) ............... : $use_proj" echo " GeoTiff (Georeferenced TIFF files) ........ : $use_geotiff" echo " Festival (Text-to-speech) ................. : $use_festival" echo " GPSMan/gpsmanshp (GPS downloads) .......... : $use_gpsman" #echo " GPSD Client (libgps) ...................... : $use_libgps" if test "${use_err_popups}" = "yes" -o "${use_libgc}" = "yes" -o "${use_profiling}" = "yes" -o "${use_spatial_db}" = "yes" -o "$use_mysql_any" = "yes"; then echo echo DEVELOPER OPTIONS: echo " ErrorPopups (Old Method) .................. : $use_err_popups" echo " libgc (Debug memory usage) ................ : $use_libgc" echo " profiling (Debug code efficiency) ......... : $use_profiling" echo " Spatial database support .................. : $use_spatial_db" echo " Spatial database Postgresql/Postgis ....... : $use_postgis" echo " MySQL ..................................... : $use_mysql_any" echo " MySQL Spatial database support ............ : $use_mysql_spatial" fi #echo Davis/MySQL............................. : $davis echo echo AC_PACKAGE_NAME will be installed in $prefix/bin. if test "x$xastirpath" != "x" ; then echo Warning: You have an old copy of Xastir at $xastirpath. fi echo "Type 'make' to build Xastir (Use 'gmake' instead on some systems)." Xastir-Release-2.2.4/git_commit_message_template0000664000175000017500000000022315151324131020773 0ustar hibbyhibby#If applied, this commit will... # Explain why this change is being made # Provide links to tracker entries, articles or other resources below Xastir-Release-2.2.4/help/0000775000175000017500000000000015151324131014251 5ustar hibbyhibbyXastir-Release-2.2.4/help/.vimrc0000664000175000017500000000143315151324131015373 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/help/Makefile.am0000664000175000017500000000064615151324131016313 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # helpdir = ${pkgdatadir}/help EXTRA_DIST = \ help-Dutch.dat \ help-English.dat \ help-French.dat \ help-German.dat \ help-Italian.dat \ help-Portuguese.dat \ help-Spanish.dat help_DATA = \ help-Dutch.dat \ help-English.dat \ help-French.dat \ help-German.dat \ help-Italian.dat \ help-Portuguese.dat \ help-Spanish.dat Xastir-Release-2.2.4/help/help-Dutch.dat0000664000175000017500000043037615151324131016755 0ustar hibbyhibbyHELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group 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. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: http://www.xastir.org http://github.com/Xastir/Xastir There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See http://www.xastir.org to subscribe. For more information on the GNU License look at: http://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X-windows Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html". A great deal of information on APRS(tm) can be found in the APRSdos documentation written by Bob Bruninga. An additional source of information is the APRS(tm) specification, available from http://www.tapr.org . HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA. See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.ew.usna.edu/~bruninga/aprs.html "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degreees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have recieved one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: http://web.usna.navy.mil/~bruninga/dfing.html and the APRSdos documentation for details on these useful techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In hundredth of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In hundredth of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (http://wxsvr.net/) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects [CAD object support has moved from the right click menu to Map/Draw CAD Objects]. CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normaly) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Find Address This option brings up a search dialog where you can enter an address. It will center on the map if the address is found. The path to the geo-coder file is saved between calls. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with ImageMagick support, and does not apply to geoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Configure Tigermap Turning this option on causes Xastir to download the map from the US census bureau's online tiger mapping server. The dialog that comes up allows one to select which layers are displayed, as well as the brightness of the resulting map. This is only available if you have compiled with ImageMagick support. Tigermaps are always loaded as the bottom layer; they do not have layering settings in the Map Chooser. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser and/or Tiger Maps dialog will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions in the README.MAPS file. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the currently available vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported, as well as PocketAPRS format maps and GNIS (Geographic Names Information System) label files. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with ImageMagick support, enabling support for many graphic formats as maps (see "http://www.imagemagick.org/www/formats.html"). Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. Details of locations to obtain many of the above types of maps are found in the file README.MAPS Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in README.MAPS. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with ImageMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/ImageMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (ImageMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. ImageMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use ImageMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. ImageMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: TIGERMAP A file with just the word "TIGERMAP" will cause Xastir to retrieve an online Tiger map of the area on screen. These are not available for every place in the world. "tigermap.geo" is automatically installed in the maps directory. TERRASERVER-SATELLITE A file with just the word "TERRASERVER-SATELLITE" will cause Xastir to retrieve a Terraserver satellite photo of the area on screen. Those services are not available for every place in the world. Note that using the Terraserver maps at any zoom above 256 will probably take a long time to load, won't show much detail, and probably won't display correctly. This is a limit of Microsoft's Terraserver, not Xastir. Also note that crossing UTM zone boundaries is not supported by Terraserver. "terraserver.geo" is automatically installed in the maps directory. TERRASERVER-TOPO A file with just the word "TERRASERVER-TOPO" will cause Xastir to retrieve a topographic map of the area on screen. Those services are not available for every place in the world. Note that using the maps at any zoom above 256 will probably take a long time to load, won't show much detail, and probably won't display correctly. This is a limit of Microsoft's Terraserver, not Xastir. Also note that crossing UTM zone boundaries is not supported by Terraserver. "terraserver-topo.geo" is automatically installed in the maps directory. TERRASERVER-URBAN Same as above but with Terraserver colored urban-area satellite images. "terraserver-urban.geo" is automatically installed in the maps directory. TERRASERVER-REFLECTIVITY Same as above but with Terraserver reflectivity images. "terraserver-reflectivity.geo" is automatically installed in the maps directory. TOPORAMA-250k Canadian 1:250k scale topo maps, downloaded from findu.com. "CanadaTopo250k.geo" is automatically installed in the maps directory. TOPORAMA-50k Canadian 1:50k scale topo maps, downloaded from findu.com. "CanadaTopo50k.geo" is automatically installed in the maps directory. WMSSERVER Allows use of Web Map Services (WMS). An example "WMSRadar.geo" is automatically installed in the maps directory. geoTIFF maps are a combination of two files as well: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS geoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. GNIS (Geographic Names Information System) data is a collection of names of locations, or geographic features. These labels behave like map labels in Dos/WinAPRS maps. As you zoom in, more labels will appear, assuming you've selected the GNIS file as a map and have enabled Map Labels in the Maps menu. If you have some of them in the xastir/GNIS directory, you can also search for map labels within Xastir. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in README.MAPS. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the README.MAPS file. Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: ImageMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the ImageMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapblast2geo.pl This script creates .geo files for Mapblast pixel maps. It includes usage information. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. split_gnis.bash This will take a GNIS data-point file (typically for a whole state, 8+MB), break it down into smaller chunks (typically for a county, 30-200k) it will also throw away the trailing spaces and s at EOL. split_gnis.pl This is a Perl version of the above script. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases [MySQL,Postgis] (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxilliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found in the APRS(tm) Reference which you could get from http://www.tapr.org Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>What was new in Xastir 1.0 Over the past year, Xastir has been under active development, and this new release is the culmination of those efforts. Development has been run by Chuck Byam, who agreed to take over for Frank Giannandrea. Many other individuals have contributed to this project, and are listed in the AUTHORS file. The Xastir package now uses GNU autoconf to build makefiles and select features based on the libraries and software one has installed. No more editing makefiles as in previous releases! Starting Xastir 1.0, one probably won't immediately notice any major changes. The familiar interface of previous Xastir versions has been retained for the most part. The great majority of the changes are improvements in efficiency under the hood: * Startup time for the program has been improved. * Memory usage has greatly improved, with dynamic allocation of separate station, trail, and weather data on an as-needed basis. No longer will memory be wasted on stationary stations for trail data, nor will non-weather stations waste memory for weather information. With these modifications, Xastir can even be connected to the internet link comfortably on a 16MB machine. * Improvements have been made to avoid having to reload maps from disk at every minor change; Weather alerts and changes to the display and tracking options no longer cause the maps to reload, rather the trails and symbols are redrawn alone. * Improvements have been made to various dialog boxes that re-drew often, to redraw less often, to allow them to be usable on slower systems. This is also true of tracking a station, with the map redrawing only if the station approaches the edge of the screen. Thanks to these changes, Xastir is perfectly usable on slower Pentium(tm) machines. Native GeoTIFF support is now included, and will be compiled into one's copy of Xastir if they have the GeoTIFF libraries installed on their system. These map files are of very high quality, and are especially useful in search and rescue operations. Maps on this format are available from the USGS, and commercially on CD-ROM. Xastir understands how to convert from the NAD-27 datum to the new WGS-84 datum, so maps of both format can be read accurately. New shortcut buttons have been added to the map selection dialog to enable one to pick all maps of a specific type. Support for the Festival Speech Synthesis System is now available to announce new stations and band openings. The old system of alert sounds has been retained as well. Xastir now supports adding and deleting objects. Finally, Xastir users are able to manage resources with this useful feature. Objects are helpful for coordinating events, directing travelers, and doing search and rescue work. The County Warning Area maps that display weather alerts are no longer painted onto the maps below, but are shaded onto the maps. While this does make the colors unpredictable, it is now possible to see the road-maps below the alert! A new and useful feature is the change in the orientation of a symbol based on the direction in which it is moving. Even without a trail, a quick glance can tell you a mobile station's bearing. There are several more new options in the display menu, enabling one to decide more precisely what is displayed and what isn't. Panning and control over the map has been enhanced: There are now arrow buttons visible at the top of the screen to pan the map. The map can also be panned with the arrow keys, and the zoom can be adjusted with the page up and page down keys. There are new option in the click menu, to center the map where you clicked or to place an object where you clicked. The panning options in this menu have been removed in favor of the new controls at the top of the screen. Support for altnet has been added, enabling one to have a private APRS(tm) network for special events, search and rescue, storm chasing, or whenever else the user doesn't want to be bothered by the hundreds of APRS(tm) stations around. There are numerous small changes, both visible and invisible to the user. The interface control dialog now has a "Start all" and "Stop all" option, to save the user the time of performing these actions for each interface. The station setup dialog now shows you your symbol, so you don't have to exit the dialog to see which symbol you chose. Several buffer overflows that caused unpredictable behavior and/or crashes have been fixed. And many minor improvements have been made to the source code to ensure that it compiles correctly on various systems. Enjoy the new Xastir! HELP-INDEX>What was new in Xastir 1.1 What was new in Xastir 1.1 This new release, Xastir 1.1, adds significant new features and enhancements to the user interface. Unlike 1.0, the interface changes will take some getting used to, but the flexibility and versatility of the enhanced interface will more than make up for the troubles. Among the improvements to the user interface: * Keyboard shortcuts for menus and dialogs, menu reorganization, and mouse behavior changes. * The ability to move objects or measure distance with the mouse, using the appropriate check-boxes in the toolbar. * A scale has been added to allow one to judge distance on a map. * Map labels for windows-style APRS(tm) maps are rotated to match the marked map features. * The user interface for dealing with objects has been entirely redesigned. * Station info boxes can be set to automatically update. * Tear-off menus. Allow you to keep a menu on the screen and play with different options. Tear off a menu by clicking on the dashed-line portion. Map support has been greatly enhanced, with PocketAPRS, ESRI Shapefiles, GNIS labels and many graphics formats with ImageMagick. Additionally, support for downloading graphical maps from web-servers has been added, allowing Xastir to use online radar, Tiger, and Terraserver maps. Xastir 1.1 supports much more of the APRS(tm) protocol than its predecessor: * It can add, modify, move and view area objects, signpost objects, and items. These features are invaluable for event coordination and search and rescue use. Objects and items are also periodically retransmitted. * Support for displaying position ambiguity squares, pre-calculated radio ranges, Maidenhead grid squares, and weather objects. These features aren't extremely common, but do come up occasionally. * Support for the APRS(tm) radio direction finding features. These features are useful for anything from tracking jammers to locating lost hikers. Xastir supports both Omni and Beam reports. Other notable improvements: * Xastir can now search for a specified location or landmark using GNIS data. * Track logs can now be exported to file. * Maps can be printed if certain tools and libraries are present. * Support for retrieving historical track data from findu.com. * Xastir now compiles and runs on Mac OS X, Solaris and FreeBSD with only minimal changes; see README for details. * Several major bugs found in 1.0 have been corrected, including the problems loading DOS maps and the problems with the weather reporting. Other minor bugs and memory leaks have been fixed. And several more errors have been corrected in the parsing routines, so Xastir should remain stable no matter what is thrown at it! HELP-INDEX>What was new in Xastir 1.2 What was new in Xastir 1.2 The latest Xastir release adds numerous new capabilities, keeping Xastir a benchmark for APRS(tm) programs on any operating system. Xastir's hardware support has been enhanced, with * Support for Serial KISS TNCs * Support for Serial TNCs with GPS on the AUX port * Support for using AGWPE as a TNC * Support for Dallas One-Wire weather station (see http://melhuish.info/simon/projects/oww/) * Support for more weather stations via the wx200d daemon (WX-200/WM-918/ WMR-918/WMR-968) * Support for the different sized rain gauges of the Peet Brothers weather stations. Additionally, several bugs in the weather reporting code were corrected, and support for setting the system clock based on the GPS was added. There have been many additions and improvements to the Xastir user interface: The most notable is the addition of dead-reckoning. This means that stations that are moving will continue to move on your screen in the direction and at the speed speed that they last reported. The estimated location can be shown with any combination of a ghosted icon, a dashed line from the last position, or an arc of expected possible distance and angle. Also very notable are the improvements to the Map Chooser. Maps can now be selected a directory at a time, or individually. And the new map properties dialog allows individual control of map layering, map color filling, and consideration for auto-maps. Additionally, with extent caching under the hood, auto-maps regains much of its formal usefulness even with many maps installed! Bulletins pop up on screen, and emergency beacons cause an alert with the locate station dialog on hand. These changes are helpful in emergencies and event coordination. Xastir can now be set to use one of several coordinate systems, including UTM, dd.ddddd, dd mm.mmm, and dd mm ss.s. This is helpful for coordinating with other groups using a different system. The online Tiger maps can now be enabled from the map menu, and options can be adjusted to request maps with just the data you want displayed. The stations menu has been reorganized, allowing more intuitive filtering of stations shown and of accompanying data. Other smaller interface changes include: * The density of the grid-lines can be adjusted with the +, =, and - keys. * Objects and item lists have been added to the view menu. * Station maidenhead grid squares are now shown in station info and the coordinate calculator. * There is a check-box "Track me" to enable easily tracking your own station * The length of trails downloaded from findu.com can now be specified. * Xastir can now ID via voice IDs or Screen IDs, by editing the configuration file. This is intended for configurations when the Xastir screen is seen remotely via fast-scan TV. * Timestamps are written to log files every 30 seconds of operation, to keep a record of when data was heard. * The status bar can display the course/distance to your station when enabled in the file|configure menu. * Range scales are now shown opposite the map scale. This is an attempt to standardize various APRS(tm) client approaches to zoom levels. New additions under-the-hood: * Tracked proximity alarms. * Export waypoints within proximity boundaries. Your GPS can show you the locations of APRS(tm) stations as waypoints on the GPS map screen. * Export trail as ESRI Shapefile. New feature if you have Shapelib compiled in. Station Info->Store Track button also creates a Shapefile map of the station's track now. The weather reporting features have been improved, with the addition of optional wind barbs to weather stations and decoding of storm wind radius data. Weather alert shading is now done with pixmap stipples showing the type of alert. Further information on an alert is available over the internet from the WXSVR by simply double-clicking the alert in the weather alerts list. Weather alerts now use the newer ESRI Shapefile-format maps. Xastir's map support has been improved with enhancements to the ESRI Shapefile code to handle point-type ESRI Shapefiles. Additionally, speed improvements have been made in the ImageMagick graphical map loading, and many color-correction features have been added. As mentioned above, the Map Chooser has been greatly improved, and weather alerts use ESRI Shapefile-format maps. Under the hood, Xastir has had several major improvements: The messaging system has been largely rewritten, and the annoying timed updates to dialogs no longer occur. The new messaging system allows multiple messages to be queued, and implements reply-ack's for speed. Xastir also attempts to specify a reasonable path for the message based on received messages. This improves speed and congestion control. The messaging GUI has been largely untouched, and remains high on the list of future improvements. The build process has been significantly improved; Xastir is now able to be built on numerous operating systems with few manual interventions. Xastir now supports GPSMan/gpsmanshp, allowing the importing of waypoints, tracks, and routes from several types of GPS receivers. This allows you to create ESRI Shapefile-format maps out of GPS data. Xastir now implements SmartBeaconing(tm), which greatly improves trail quality and reduces unneeded channel usage. See the "Configure SmartBeaconing" help topic. IGating support has also improved, with the ability to configure a specific RF path for IGated packets, and the addition of a 29 second anti-dupe queue to reduce unnecessary redundancy on the RF channel. Map extents and filenames are now cached, so maps will not be loaded from disk unless they are on screen. This is a major improvement for map types that did not specify this information. Additionally, auto-maps uses this information, making it usable even with many maps installed. Objects controlled by Xastir are now stored in a file, so a restart of Xastir will not cause them to be lost. Additionally, Xastir now supports the compressed format for objects and items, which can help reduce RF channel congestion. It also gives you better location accuracy of the placed objects. See the help topic "Configure Default Operation". Xastir now drops root privileges when not needed if run setuid root. Please read the information about this in INSTALL; this change provides only limited protection. Xastir now supports using a private colormap with the command-line argument "-i". This is recommended for systems running in 8-bit color mode. Additionally, several more buffer overruns and other errors were corrected in Xastir's data parser, and numerous other bugs have been fixed. Enjoy the new Xastir! HELP-INDEX>What's new in Xastir 1.3 What's new in Xastir 1.3 This latest Xastir release greatly improves on the efficiency and usability of Xastir, and adds many helpful and often-requested new features. .geo files can now have REFRESH tags, to specify how often the file is reloaded. This is useful for weather radars and other dynamic images. .geo files can also have a TRANSPARENT tag to make a certain color transparent, and a CROP tag to specify a specific region to display. Some Opentrac packets are now decoded and displayed. See http://opentrac.org/ for more details. The default main Xastir directory is now /usr/local/share/xastir; please see the upgrade notes in README for migration information. This more closely mirrors the behavior of other applications. If you're installing from a binary package (rpm/deb/etc), the default install location may be /usr/share/xastir. Xastir efficiency has been greatly improved. Changes in data structures and timing values have made this Xastir release the most efficient yet. Additionally, map redraw sequences are interruptible, so map panning speed has been improved. dbfawk support - Experimental support for configurable shapefile metadata, in an awk-like language. See README.MAPS for more details; this must be turned on with a specific switch to the configure command. GDAL/OGR support - Experimental support for GDAL and loading of native Tiger data (.RT1 files). This is automatically enabled if the GDAL library is found. Support for UTM w/special zones and MGRS coordinate systems. Cad drawing mode allows one to draw regions on your screen using the center mouse button. This feature is not yet complete, but is functional. User interface changes: * Several of the menus have been reorganized to have a hierarchical design. * Additionally, a few colors have been modified for better visibility. * The map label font and style are more configurable * The cursor changes to let one know if they're in move object or measure mode. * If the coordinate system is set to UTM, and "Map Grid" is selected, an UTM grid is displayed. Snapshot mode now generates a .geo file, allowing the image to later be used as a map. Tiger maps have been moved back the chooser, as was the pre-1.2 behavior. This is more consistent. Xastir-Release-2.2.4/help/help-English.dat0000664000175000017500000033675015151324131017300 0ustar hibbyhibbyHELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README.md file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group 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. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: https://github.com/Xastir/Xastir https://github.com/Xastir/Xastir/wiki https://www.xastir.org There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See https://www.xastir.org to subscribe. For more information on the GNU License look at: https://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) was created by Bob Bruninga and originally trademarked by him. It is currently a trademark of the Tucson Amateur Radio Packet Corporation. When Bob Bruninga became a silent key, maintenance and documentation of APRS for the community was taken over by the APRS Foundation, whose web site is https://how.aprs.works/ . This is the best modern source for up-to-date information about APRS. A historical copy of Bob Bruninga's original APRS web site is maintained at https://aprs.org/ . HELP-INDEX>What's new in Xastir The "What's New" section of this help file has been long neglected, and has not been updated in every release. As of release 2.2.4 we have removed all the old entries and will not update it further. The best way to see what's new in any release of Xastir is to view the release notes we provide with each release on Github. These may be viewed at https://github.com/Xastir/Xastir/releases. HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degrees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL.md for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: https://www.cstr.ed.ac.uk/projects/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have received one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: https://www.aprs.org/dfing.html for Bob Bruninga's discussion of how to use these techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In 1/1500 of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In 1/1500 of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (https://www.aprs-is.net/WX/Default.aspx) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normally) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Search Location This feature generally requires an internet connection. This option brings up a search dialog where you can enter an address or name of a business or location. It will generate an internet request to a "Nominatim" server that queries OpenStreetMap data to find the location. If any are found, the dialog will be filled in with a list of matching locations. Choose one by clicking on it and then click either "Go To" or "Mark." Either option will center the map on the location chosen, the "Mark" button will also place a large blue "X" over the location. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with GraphicsMagick support, and does not apply to GeoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps NOTE: "Auto maps" is a deprecated feature that is best left turned off! When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions at https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview and its various links. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the historical vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported with no additional external libraries needed. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with GraphicsMagick support, enabling support for many graphic formats as maps. Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. See the Github wiki page https://github.com/Xastir/Xastir/wiki/Installing-Xastir for details. Details of locations to obtain many of the above types of maps are found in the file https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview and links below it. Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in the Xastir Github wiki at https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with GraphicsMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/GraphicsMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (GraphicsMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. GraphicsMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use GraphicsMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. GraphicsMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: WMSSERVER Allows use of Web Map Services (WMS). Several example of this type of online map source are automatically installed in the maps directory such as "USTigermap.geo" and the weather radar maps in the "NWS" directory. OSMSTATICMAP OSM_TILED_MAP Allows use of OpenStreetMap servers that provide either a single static image or small map tiles. Several examples whose names begin with "OSM_" are installed in the maps directory. GeoTIFF maps are a variant of the TIFF image format with extra georeferencing tags embedded. Those in the US usually have come with two files: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file is a metadata file that conforms to a federal standard, but for Xastir's purposes need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS GeoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. Furthermore, unless your shapefile set matches those that Xastir already has rendering rules for, you will have to construct a "dbfawk" file to get Xastir to make it pretty. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Currently, Xastir recognizes any station that begins with the letters C through G, whose second letter is "W", and which has four digits following as CWOP stations. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the "Helper Scripts" page on the wiki, https://github.com/Xastir/Xastir/wiki/Helper-Scripts Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: GraphicsMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the GraphicsMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL.md HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxiliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found at https://github.com/hessu/aprs-symbols. Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat Xastir-Release-2.2.4/help/help-French.dat0000664000175000017500000043021215151324131017100 0ustar hibbyhibbyHELP-INDEX>ME LIRE EN PREMIER - License ME LIRE EN PREMIER pour XASTIR Traduction Francaise par Google Translate. KM5VY a essayé de les faire correspondre avec les traductions utilisée dans le logiciel soi-même, mais il y a peut-être des erreurs. Les traductions du logiciel a été initialement fait par VE2DJE, F1SJE, et F1IOL il y a longtemps. Si vous n'aimez pas cette traduction, on sera ravis d'avoir vos corrections! Pour obtenir les informations les plus récentes, veuillez consulter le fichier README.md dans le répertoire Xastir. Consultez également les fichiers LICENSE et COPYING pour plus d'informations. Ce programme est destiné à la communauté des radioamateurs. Aux États-Unis, la FCC interdit l'émission par radiofréquence aux personnes non titulaires d'une licence de radioamateur. Les utilisateurs résidant en dehors des États-Unis sont invités à se renseigner sur la réglementation en vigueur dans leur pays. LICENSE : XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Ce programme est un logiciel libre ; vous pouvez le redistribuer et/ou le modifier conformément aux termes de la Licence publique générale GNU, telle que publiée par la Free Software Foundation ; soit la version 2 de la Licence, soit (à votre choix) toute version ultérieure. Ce programme est distribué SANS AUCUNE GARANTIE ; sans même la garantie implicite de QUALITÉ MARCHANDE ou d'ADÉQUATION À UN USAGE PARTICULIER. Consultez la Licence publique générale GNU pour plus de détails. Vous devriez avoir reçu une copie de la Licence publique générale GNU avec ce programme ; si ce n'est pas le cas, veuillez écrire à la Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, États-Unis. Vous trouverez plus d'informations sur le programme à l'adresse suivante : https://github.com/Xastir/Xastir https://github.com/Xastir/Xastir/wiki https://www.xastir.org Des listes de diffusion spécifiques à Xastir sont disponibles. Veuillez vous abonner à l'une ou aux deux pour obtenir les dernières informations sur Xastir. Consultez https://www.xastir.org pour vous abonner. Pour plus d'informations sur la licence GNU, consultez : https://www.gnu.org HELP-INDEX>Bienvenue! Et notes de l'auteur. Bienvenue ! et Notes des auteurs XASTIR, ou X Amateur Station Tracking and Information Reporting (Suivi et rapport d'informations des stations radioamateurs X). Xastir est un programme APRS™ open source, gratuit et librement distribuable. Actuellement en développement, ce programme ne doit pas être considéré comme un produit fini ! Votre aide est précieuse pour l'améliorer. Si vous avez des compétences en programmation et/ou en rédaction de documentation, votre contribution est la bienvenue ! Nous avons beaucoup d'idées, mais peu de temps. Si vous pensez pouvoir apporter votre contribution, n'hésitez pas à nous contacter ! APRS™ a été créé par Bob Bruninga et initialement déposé comme marque par lui. Il s'agit actuellement d'une marque déposée de la Tucson Amateur Radio Packet Corporation. Après le décès de Bob Bruninga, la maintenance et la documentation d'APRS pour la communauté ont été reprises par la Fondation APRS, dont le site web est https://how.aprs.works/. C'est la meilleure source d'informations à jour sur APRS. Une copie historique du site web original d'APRS de Bob Bruninga est disponible à l'adresse https://aprs.org/. HELP-INDEX>Nouveautés de Xastir La section « Nouveautés » de ce fichier d'aide a été longtemps négligée et n'a pas été mise à jour à chaque version. À partir de la version 2.2.4, nous avons supprimé toutes les anciennes entrées et ne la mettrons plus à jour. Pour connaître les nouveautés de chaque version de Xastir, le mieux est de consulter les notes de version que nous publions sur GitHub. Vous pouvez les consulter à l'adresse suivante : https://github.com/Xastir/Xastir/releases. HELP-INDEX>Débuter Débuter Lors du premier lancement de Xastir, il est recommandé de le démarrer depuis une fenêtre de terminal afin de visualiser les éventuels messages d'avertissement ou d'erreur. Sur la plupart des systèmes, un chemin d'accès est configuré pour exécuter les programmes dans /usr/local/bin ; il vous suffit alors de taper « xastir & » à l'invite de commande. Sur les systèmes où ce chemin n'est pas configuré, tapez « /usr/local/bin/xastir & » pour démarrer le programme. Le caractère « & » permet de lancer Xastir en arrière-plan, libérant ainsi la fenêtre du terminal pour d'autres utilisations. Vous pouvez également choisir la langue à ce moment-là. Pour définir la langue ou modifier la langue actuelle, lancez Xastir avec l'option « -l » : xastir -lEnglish Options de langue disponibles : xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish La langue choisie sera enregistrée dans votre fichier de configuration et conservée pour les lancements ultérieurs de Xastir. Lors d'une nouvelle installation, Xastir utilise l'anglais par défaut jusqu'à ce que vous modifiiez la langue à l'aide de cette option de ligne de commande. Les menus supérieurs sont accessibles à la souris ou à l'aide de raccourcis clavier. Les raccourcis clavier peuvent ne pas fonctionner correctement si le verrouillage numérique est activé. Vous devrez configurer les interfaces pour pouvoir utiliser Xastir. La configuration des interfaces est détaillée dans la rubrique d'aide « Configuration des interfaces » et ses sous-rubriques. Si vous travaillez dans un contexte où un système de coordonnées autre que le système par défaut DD MM.MMMM serait plus approprié, vous pouvez sélectionner votre système préféré en allant dans Fichier | Configurer | Système de coordonnées. Tous les systèmes de coordonnées pris en charge peuvent être utilisés en entrée grâce au calculateur de coordonnées. HELP-INDEX>Configuration des informations de la station Configuration des informations de la station Cliquez sur Fichier, puis sur Configurer, puis sur Station. Saisissez l'indicatif d'appel de votre station radioamateur. Saisissez la position de votre station si vous n'utilisez pas Xastir avec un récepteur GPS. Vous pouvez localiser votre position approximative sur la carte avec Xastir et utiliser la position indiquée par le curseur sur la carte. Cette position sera visible dans la zone située en bas de l'écran Xastir, à la deuxième position à partir de la gauche, lorsque la souris survole la zone de dessin. Vous pouvez également sélectionner « Déplacer ma station ici » dans le menu contextuel (clic droit) lorsque votre souris se trouve sur votre emplacement. Si vous possédez un GPS, vous pouvez igniter cette étape et configurer le GPS ultérieurement. L'option « Transmettre positions compressées », si elle est sélectionnée, transmettra les données au nouveau format compressé. Ce format réduit la quantité de données transmises, augmentant ainsi la capacité du réseau APRS™. La précision maximale de la position transmise est également supérieure. Certains programmes plus anciens, y compris les versions récentes de WinAPRS, ne décodent pas encore ce format. Findu.com pourrait également rencontrer des difficultés avec ce format. Nous transmettons le cap et la vitesse dans ce format, mais pas l'altitude. L'envoi du cap, de la vitesse ET de l'altitude nécessite l'ajout de neuf caractères au paquet, ce qui annule en partie l'intérêt d'utiliser les positions compressées. Pour sélectionner un symbole pour votre station, vous devez spécifier un groupe et un caractère de symbole. Vous pouvez remplir ces champs manuellement ou appuyer sur « Sélectionner » pour choisir un symbole graphiquement. Deux groupes de symboles sont disponibles. Une description textuelle de chaque symbole est disponible dans l'aide, rubrique « Table des symboles ». Pour certains symboles du deuxième groupe, vous pouvez spécifier une superposition. Un symbole sera alors affiché avec un caractère de superposition supplémentaire, par exemple un symbole de voiture avec le chiffre 1 superposé. Pour utiliser les superpositions, vous devez sélectionner un symbole dans la table des symboles secondaires et saisir le caractère de superposition à afficher dans le champ groupe/superposition. Seuls les chiffres et les majuscules sont autorisés comme caractères de superposition. Conformément à la spécification APRS™, tous les symboles ne peuvent pas être superposés. Xastir n'applique pas cette restriction, mais certains autres programmes peuvent le faire. Veuillez noter que tous les symboles n'ont pas encore été implémentés dans le sélecteur graphique, et certains ne sont pas encore conformes à la spécification APRS(tm). Ensuite, saisissez les données relatives à la puissance, à la hauteur et au gain de votre station. Ces informations sont utiles mais non obligatoires ; il vous suffit de sélectionner « Désactiver PHG » pour les désactiver. Ces options offrent une représentation détaillée de la portée de votre station. Sélectionnez la combinaison de valeurs la plus proche de la description de votre station. Veuillez utiliser la hauteur au-dessus du terrain moyen (HAAT) pour la valeur de hauteur. N'utilisez PAS la hauteur moyenne au-dessus du niveau de la mer ni la hauteur au-dessus du sol. Toutes les valeurs doivent être spécifiées si vous souhaitez transmettre les informations PHG. Une autre option consiste à spécifier la portée (RNG) en miles dans le champ de commentaire au lieu d'utiliser le PHG. Consultez la spécification APRS(tm) pour plus de détails. Pour le gain, utilisez le gain de votre antenne en dBi. (À CORRIGER : dBd ? La spécification n'est pas claire, je pense qu'il s'agit de dBi car il est indiqué que « en l'absence de données, les stations sont censées fonctionner avec une puissance de 10 W et une antenne omnidirectionnelle de 3 dB à 6 mètres de hauteur. Une antenne omnidirectionnelle typique n'a qu'un gain de 3 dBi… ») Remarque : Le réglage du gain est destiné aux antennes verticales ; le réglage du gain pour une antenne directionnelle doit être nettement inférieur au gain avant de l'antenne. En effet, avec la directivité définie, le cercle PHG n'est décalé que d'un tiers de sa taille vers la direction spécifiée. Un réglage de gain plus élevé agrandirait le cercle de manière irréaliste, au lieu d'augmenter la directivité. Il a été question il y a plusieurs années de modifier les spécifications pour mieux prendre en compte les antennes directionnelles, mais aucune modification n'a été apportée. Saisissez un commentaire (facultatif), qui apportera des informations supplémentaires sur votre station. Vous pouvez par exemple indiquer votre adresse e-mail préférée. Elle sera transmise avec vos positions. L'ambiguïté de position vous permet de contrôler la précision de la transmission de votre position. Le réglage « Aucun » permet à votre station de transmettre la position exacte que vous avez saisie ou reçue d'un GPS. Les autres options vous positionneront dans la plage de l'option sélectionnée. Notez que cela peut perturber certaines stations non conformes aux spécifications. Findu.com ne prend pas en charge l'ambiguïté de position. Cliquez sur OK pour enregistrer vos modifications. Cliquez sur Annuler pour conserver les paramètres précédents. HELP-INDEX>Configuration des paramètres par défaut Configuration des paramètres par défaut Cliquez sur Fichier, puis sur Configurer, puis sur Paramètres par défaut. Cette page permet de configurer certains paramètres par défaut pour le fonctionnement du programme. L'option «Option de transmission» définit le type de paquet que votre station utilisera pour transmettre ses données. Les options IGate permettent de configurer votre station comme passerelle Internet-RF. Cette option doit être utilisée avec prudence ; en tant qu'opérateur radioamateur, vous êtes responsable des données reçues via Internet et transmises par radio. Vous devrez également choisir une option IGate pour chaque interface afin que la passerelle IGate fonctionne. Si vous souhaitez que votre passerelle IGate transmette les alertes météorologiques du NWS par radio, vous devez créer un fichier ~/.xastir/data/nws-stations.txt listant chaque indicatif ou station NWS (comme « PHISVR ») que vous souhaitez transmettre par radio. Cette fonctionnalité permet également de transmettre des indicatifs spécifiques par radio. L'option « Transmettre les objets/éléments compressés ? », si elle est sélectionnée, transmettra les objets et les éléments au format compressé plus récent. La précision maximale de la position transmise est plus élevée et la transmission est plus courte, mais certains programmes plus anciens ne décodent pas encore ce format. Actuellement, cette option ne compresse que les objets/éléments « standard » avec une vitesse/direction optionnelle. Elle ne compressera pas les objets/éléments de zone, de panneau ou de radiogoniométrie, et ne représente pas actuellement l'altitude dans les objets/éléments « standard ». L'option « Afficher bulletins nouveaux », si elle est sélectionnée, affichera la boîte de dialogue des bulletins lorsque des bulletins se trouvant dans la plage configurée sont reçus. L'option « Afficher les bulletins à distance nulle » permet de ne pas afficher les bulletins sans position connue ni d'afficher de fenêtres contextuelles. L'option « Alerter si clés modificatrices (Verr.Num.) » affichera un avertissement si vous tentez d'utiliser Xastir alors que les touches Verr. Num, Arrêt défil. ou Verr. Maj sont activées. Certains utilisateurs signalent un écran noir et des problèmes similaires lorsqu'ils tentent d'utiliser Xastir avec l'une de ces touches de modification activée. Vous pouvez également sélectionner « Activer réseau alterne ? » et choisir un indicatif de réseau alternatif dans cette boîte de dialogue. Le réseau alternatif vous permet de disposer d'un réseau APRS™ privé entre les stations qui ont également configuré le réseau alternatif et qui ont saisi le même indicatif de réseau alternatif. L'option « Désactiver identif. de duplic. posit. » désactive la vérification des positions en double. Cette option ne doit être utilisée que si une station est susceptible de revenir exactement à la même position (à 60 pieds près environ pour les positions non compressées) et que vous souhaitez afficher les positions et/ou les traces en double sur la carte. Cette option est rarement nécessaire en pratique, mais peut s'avérer utile pour des événements spéciaux tels que les opérations de recherche et de sauvetage. L'option « Mon parcour en une seule couleur » affiche toutes les traces associées à votre indicatif d'appel, mais avec des SSID différents, dans la même couleur. Si cette option est sélectionnée, mycall-1 et mycall-2 s'affichent dans la même couleur. Si elle est désactivée, mycall-1 et mycall-2 s'affichent dans des couleurs différentes. L'option « Charger des objets prédéfinis à partir d'un fichier » et la liste déroulante qui la suit vous permettent de remplacer la liste des objets prédéfinis accessibles depuis le menu contextuel (clic droit) par votre propre liste d'objets. Un ensemble d'objets standard pour les opérations de recherche et de sauvetage et un ensemble d'objets typiques pour les événements publics sont fournis dans les fichiers predefined_SAR.sys et predefined_EVENT.sys. Vous pouvez également utiliser ces fichiers comme modèle pour créer un fichier predefined_USER.sys. Consultez les instructions dans les fichiers predefined_SAR.sys et predefined_EVENT.sys pour plus de détails sur la manière de définir des objets pour un menu d'objets prédéfinis personnalisé. Si l'option « Charger les objets prédéfinis à partir d'un fichier » est sélectionnée et qu'un fichier existant dans le répertoire xastir/config/ est sélectionné, les objets définis dans ce fichier s'afficheront dans le menu Objets prédéfinis. Le fichier predefined_SAR.sys non modifié définit les mêmes objets que le menu par défaut. HELP-INDEX>Configuration de la temporisation Configuration de la temporisation Cliquez sur Fichier, puis sur Configurer, puis sur Temporisation. Intervalle transmission de position (Posit TX Interval) spécifie la fréquence à laquelle la position de votre station sera transmise. Pour les stations fixes, il est recommandé de transmettre toutes les 30 minutes, et en aucun cas moins de 10 minutes. Les stations mobiles peuvent souhaiter utiliser une fréquence plus rapide. Notez que si vous utilisez SmartBeaconing, ce curseur est ignoré. Intervalle maximum de transmission des objets/articles (min) (Object/Item Max TX Interval) est l'intervalle maximal utilisé pour l'envoi des objets et des articles. Essayez de maintenir ces intervalles raisonnables, car la transmission sur une longue distance toutes les 5 minutes consommera beaucoup de temps d'antenne. Un algorithme d'intervalle décroissant est déclenché chaque fois qu'un objet est créé, modifié ou supprimé. L'intervalle de transmission augmentera jusqu'à atteindre l'intervalle maximal indiqué par le curseur. L'intervalle de lecture GPS (GPS Check Interval) définit l'intervalle de temps pendant lequel le GPS est interrogé pour de nouvelles données. Cette option est disponible pour les stations utilisant un HSP ou un câble partagé avec leur TNC. Expiration de point estimé (min) (Dead-Reckoning Timeout) ajuste la durée pendant laquelle une position est considérée comme valide pour l'estimation de sa position actuelle. Délai nouvel piste (min) (New Track Time) ajuste le nombre de minutes qui doivent s'écouler avant qu'une nouvelle trace distincte ne soit démarrée. Attention : régler le temps de nouvelle trace à 0 désactivera l'affichage de toutes les traces. Rino->Intervalle d'objets (min) (RINO -> Objects Interval) ajuste la fréquence à laquelle les points de repère sont téléchargés à partir d'une unité radio/GPS Garmin RINO connectée. Les objets APRS™ sont créés à partir de tous les points de repère commençant par « APRS ». Le préfixe « APRS » est supprimé lors de la création des noms d'objets. Délai d'affichage faible d'une stations (min) (Station Ghosting Time) spécifie l'intervalle d'affichage des stations fantômes. Les stations qui n'ont pas été entendues pendant la période donnée apparaîtront en mode fantôme à l'écran. Délai de suppression d'affichage d'une station (Station Clear Time) spécifie le moment où une station sera supprimée de l'écran. Délai de suppression d'une station (Station Delete Time) spécifie le nombre de jours complets avant que les données d'une station ne soient entièrement supprimées de la base de données Xastir. Délai inter-caractères port série (Serial Inter-Char Delay) spécifie un temps d'attente en millisecondes entre chaque caractère envoyé à un TNC connecté. Espace nouvelle piste (en degrés) (New Track Interval (degrees)) spécifie la distance en degrés de latitude/longitude à laquelle un nouveau segment de trace est démarré. Attention : régler l'intervalle de nouvelle trace à 0 degrés désactivera l'affichage de toutes les traces. L'intervalle de capture instantané (en minutes) spécifie la fréquence à laquelle les fichiers de capture d'écran seront enregistrés si les options Fichier > Activer copie d'écran PNG ou Fichier > Instantané KML sont sélectionnées. HELP-INDEX>Configuration des alarmes sonores Configuration des alarmes sonores Cliquez sur Fichier, puis sur Configurer, puis sur Alarmes sonores. Pour utiliser cette option, vous devez disposer d'une carte son et d'un programme capable de lire les fichiers WAV. La commande de lecture audio doit contenir le programme que vous souhaitez exécuter pour lire le fichier audio (ainsi que les options de ligne de commande éventuelles). Cela ne fonctionne évidemment pas si la seule carte son du système est utilisée par un modem audio... Chaque type d'alerte possède une case à cocher pour l'activer. Les champs contiennent le nom du fichier à lire. Les champs situés sous l'option permettent de définir les paramètres de cette option. Les options disponibles sont les suivantes : Émettre un son lors de la détection d'une nouvelle station. Émettre un son lors de la réception d'un nouveau message. Émettre un son lors de la réception de données d'une station située dans la plage de distance définie par vos paramètres de proximité. Émettre un son lors de la réception de données d'une station (via TNC) située dans la plage de distance définie par vos paramètres d'ouverture de bande. Émettre un son lors de la réception et de l'affichage d'une nouvelle alerte météo. Un ensemble de sons standard est disponible dans la plupart des endroits où Xastir peut être téléchargé. Veuillez consulter le fichier INSTALL.md pour plus d'informations. HELP-INDEX>Configuration de la synthèse vocale Configurer la synthèse vocale Pour utiliser cette option, vous devez disposer d'une carte son et du logiciel de synthèse vocale « Festival » installé. Installez Festival et lancez-le en mode « serveur » avant de démarrer XASTIR. La commande habituelle est « festival_server & ». Si vous utilisez l'option « festival --server » (ancienne méthode), vous risquez de rencontrer des problèmes de connexion refusée par le serveur. Une fois Festival installé, Xastir pourra utiliser la synthèse vocale avec les options suivantes : Nouvelle station : Annonce l'indicatif d'une nouvelle station. Alerte nouveau message : Annonce l'arrivée d'un nouveau message. Contenu du message : Lit le contenu d'un message. Alerte de proximité : Annonce la réception de données d'une station située dans la plage de distance définie dans les paramètres de proximité. Cette option utilise les paramètres de proximité du menu Alarmes audio. Alerte de proximité de la station suivie : Annonce la réception de données d'une station située dans la plage de distance définie pour la station suivie. Cette option utilise les paramètres de proximité du menu Alarmes audio. Ouverture de bande : Annonce la réception de données d'une station (via TNC) située dans la plage de distance définie dans les paramètres d'ouverture de bande. Cette option utilise les paramètres de distance du menu Alarmes audio. Nouvelle alerte météo : Non implémenté. Des informations sur Festival sont disponibles à l'adresse suivante : https://www.cstr.ed.ac.uk/projects/festival/ HELP-INDEX>Configuration de Smart Beaconing Cliquez sur Fichier, puis sur Configurer, puis sur Smart Beaconing. L'option principale « Balise intelligente (Smart Beaconing) » permet à Xastir de transmettre les positions à différentes fréquences et à différents endroits en fonction des déplacements de la station. Elle génèredes tracés plus réalistes et améliore considérablement la précision de la navigation à l'estime. Cette option n'est utile que pour une station mobile équipée d'un GPS. Plusieurs options sont disponibles pour personnaliser le fonctionnement de SmartBeaconing : Intervalle maximal L'intervalle (en secondes) entre l'envoi des balises lorsque la vitesse est supérieure au seuil de vitesse élevée. Ce paramètre est également utilisé pour calculer la fréquence d'envoi des balises en fonction de la vitesse lorsque celle-ci se situe entre les vitesses basse et élevée. Vitesse haute Le seuil de vitesse qui déclenche l'envoi des balises à la fréquence spécifiée ci-dessus. Intervalle minimal L'intervalle (en minutes) entre l'envoi des balises lorsque la vitesse est inférieure au seuil de vitesse basse. Il s'agit de la fréquence d'envoi des balises à l'arrêt. Ce paramètre n'est pas utilisé lorsque la vitesse est supérieure au seuil de vitesse basse. Vitesse basse Le seuil de vitesse qui déclenche l'envoi des balises à la fréquence spécifiée ci-dessus. Virage minimum L'angle minimum (en degrés) à partir duquel un virage est détecté à vitesse élevée ou supérieure. À des vitesses inférieures, un angle de virage plus important sera nécessaire pour déclencher l'envoi d'une position, en fonction de la valeur du paramètre « Pente de virage » ci-dessous. Pente de virage Facteur d'ajustement permettant de rendre les virages moins sensibles à basse vitesse. Ce paramètre n'a pas d'unité. Son comportement est non linéaire sur la plage de vitesses, conformément au fonctionnement de l'algorithme SmartBeaconing™ original. Temps d'attente Le temps (en secondes) entre l'envoi de deux balises consécutives lors d'un virage. Permet d'éviter l'envoi de plusieurs balises en succession rapide. HELP-INDEX>Configurer les unités de mesure Configurer les unités de mesure Par défaut, le système métrique est sélectionné : mm, cm, km/h, etc. Pour sélectionner les unités impériales (pouces, pieds, mph, etc.), cliquez sur Fichier, puis sur Configurer, et cochez la case « Active mesures anglaises ». HELP-INDEX>Sauvegarder la configuration maintenant ! Sauvegarder la configuration maintenant ! Ce bouton enregistre toute la configuration actuelle dans le fichier de configuration. Notez que lorsque Xastir est fermé, il enregistre également la configuration dans le fichier de configuration. HELP-INDEX>Barre d'état inférieure Barre d'état inférieure Au bas de la fenêtre, divers messages d'état sont affichés : Dans la première case à gauche, des messages d'état généraux s'affichent brièvement. La deuxième case affiche les coordonnées latitude/longitude ou UTM, ainsi que la position de la souris sur la carte selon le système de grille Maidenhead. Si l'option Fichier | Configurer | État distance/cap est sélectionnée, cette case affichera également le cap et la distance de cette position par rapport à votre station. Une troisième case indique le nombre de stations affichées à l'écran et le nombre de stations présentes dans la base de données. La quatrième case affiche le niveau de zoom actuel et affiche « Tr » si le suivi des stations est activé. À certains niveaux de zoom, « Tr » n'est pas affiché correctement en raison de la taille de la case. La cinquième case indique si l'enregistrement est activé. La dernière zone affiche l'état de chaque interface. Les interfaces sont affichées de gauche à droite, de 0 à 9. L'état de chaque interface est divisé en trois parties : type de périphérique (en haut), flux de données (au centre) et état de fonctionnement de l'interface (en bas). Le type de périphérique indique les interfaces configurées. La couleur indique le type de périphérique configuré pour l'interface. Le bleu correspond aux différents périphériques TNC ; le vert aux périphériques GPS ; le jaune aux serveurs Internet ; l'orange aux interfaces météo. La partie centrale indique le flux de données entrant (flèche vers la gauche) ou sortant (flèche vers la droite) pour cette interface. Un carré vert en bas indique si l'interface est active. Un carré rouge indique que l'interface est active mais en état d'erreur. Sinon, rien n'est affiché si l'interface n'est pas active. HELP-INDEX>Déplacement de la carte et du menu Options Déplacement de la carte et du menu Options Le déplacement de la carte est très simple ; la fluidité et la rapidité des mouvements dépendent de la vitesse de votre processeur et de la quantité de détails chargés. Astuce : Vous pouvez désactiver toutes les cartes dans le menu Cartes afin de vous déplacer rapidement, puis les réactiver. Zoom : Le zoom s'effectue en cliquant avec le bouton droit de la souris sur la carte (et en maintenant le bouton enfoncé). Un menu d'options s'affiche, proposant de zoomer ou de dézoomer d'un niveau, ou de choisir l'un des niveaux de zoom prédéfinis. Toutes les fonctions de zoom du menu Options effectuent un zoom avant ou arrière au point où vous avez cliqué avec le bouton droit de la souris. Les niveaux de zoom sont organisés en menu déroulant. Les niveaux 1 à 64 correspondent à des zones très locales et les niveaux 256 et supérieurs à de grandes zones. Plus le niveau est bas, plus la zone est locale. Une fonction de zoom avant plus rapide consiste à maintenir le bouton gauche de la souris enfoncé, à le faire glisser sur la zone d'intérêt et à le relâcher. La carte effectuera un zoom à peu près à la taille du carré que vous venez de dessiner avec la souris. Les cases à cocher « Déplacer » et « Mesurer » de la barre d'outils doivent être désactivées pour que cette fonction soit opérationnelle. Cliquer sur le bouton central effectue un zoom arrière d'un facteur 2, en centrant la carte sur le point où vous avez cliqué. La carte peut également être zoomée à l'aide des touches Page précédente/Page suivante du clavier, ou des boutons « Zoom avant » et « Zoom arrière » de la barre d'outils. Dans ce cas, le centre de la carte reste le même (pas de centrage). Déplacement/Centrage : La carte peut être centrée sur un emplacement spécifique en sélectionnant « Centrer » dans le menu contextuel (clic droit). Le déplacement s'effectue également à l'aide du menu Options ou des flèches de la barre d'outils. La position de la carte se déplace d'une partie de l'écran. Suffisamment de données de l'écran précédent doivent être disponibles pour vous permettre de vous réorienter. La carte peut également être déplacée à l'aide des flèches du clavier. Plus d'informations sur le menu Options : Marque-pages d'affichage de carte Voir la rubrique d'aide « Création et utilisation des marque-pages d'affichage de carte » La sélection « Informations sur la station » dans le menu Options recherche la station la plus proche de l'endroit où vous avez cliqué avec le bouton droit de la souris. Si plusieurs stations se trouvent à proximité de cette position, une liste de sélection de stations s'affichera, vous permettant de choisir les données de la station que vous souhaitez consulter. Si une seule station se trouve à proximité du pointeur de la souris, ses données s'afficheront immédiatement. Pour les stations mobiles disposant de nombreuses données de suivi, cette opération peut prendre un certain temps sur les ordinateurs lents. Notez que les données des stations expirées sont toujours stockées dans la base de données Xastir, et si vous connaissez l'ancien emplacement d'une station, vous pouvez toujours consulter ses informations de cette manière. Utilisez l'option « Inclure donnèes périmées » pour afficher certaines données qui disparaissent pour les stations inactives, comme la vitesse, l'altitude, etc. Avec « Pos/zoom précédent », vous pouvez restaurer la vue précédente de la carte en rétablissant les valeurs précédentes de zoom et de centrage. Pour plus d'informations sur les objets et les éléments, veuillez consulter la rubrique d'aide « Objets et Articles ». L'option « Dessiner objets CAD » vous permet de créer des polygones à l'écran, à des fins tactiques ou de présentation. Cette fonctionnalité est encore en cours de développement. « Déplacer ma station ici » vous permet de déplacer votre station vers un emplacement spécifié sur la carte sans modifier la configuration de la station. HELP-INDEX>Objets et articles Une station peut placer plusieurs objets différents sur la carte, leur position étant transmise aux autres stations. Les noms d'objets sont moins restrictifs que les noms de stations habituels. Les objets et les articles sont presque identiques, mais leur utilisation peut différer légèrement. Les objets sont généralement utilisés pour des articles mobiles ou variables tels que les orages, tandis que les articles sont généralement utilisés pour des articles plus statiques, comme les points d'eau. Comme les articles peuvent ne pas être décodés par certaines versions des programmes APRS™, les objets sont souvent également utilisés pour les articles statiques. Outre les objets normaux avec un symbole à leur position, il existe des objets spéciaux. Les objets de zone sont utiles pour diverses opérations permettant de dessiner ou de mettre en évidence une zone d'intérêt sur la carte. Ils peuvent également être utilisés pour dessiner des sentiers/routes/frontières, des zones de surveillance météorologique, des pistes d'atterrissage, le périmètre d'une zone de recherche ou d'un événement de service public, des zones endommagées, des zones à éviter, des bâtiments non représentés sur la carte, des échiquiers pour jouer sur APRS™. :-) Notez que les objets de zone ne sont pas implémentés dans toutes les versions des programmes APRS™, et certains détails de leur affichage peuvent également différer selon les programmes. Pour les trois autres types d'objets (cercles de probabilité, panneaux et objets DF), voir ci-dessous. Les objets/articles sont retransmis à un rythme décroissant jusqu'à l'intervalle maximal spécifié dans Fichier|Configurer|Synchronisation. Les objets/articles « supprimés » sont également retransmis de cette manière jusqu'à ce qu'ils soient retirés de la file d'attente (actuellement 20 transmissions). Les objets/articles sont conservés entre les sessions Xastir et sont stockés dans ~/.xastir/config/object.log. Ce fichier peut être vidé en sélectionnant « Effacer histoire des objets/articles » dans le menu Stations. L'option de création d'objet/article dans le menu contextuel (clic droit) affiche une boîte de dialogue avec la position de votre objet pré-remplie en fonction de l'endroit où vous avez cliqué. Vous pouvez renseigner les détails et ajouter un objet/article à partir de ce menu. L'option de modification d'objet/article affiche la boîte de dialogue de modification d'objet. Ceci est similaire à la boîte de dialogue de création d'objet, à la différence que les informations actuelles de l'objet sont déjà renseignées et que son nom ainsi que certaines autres options ne peuvent pas être modifiés. Vous pouvez également supprimer l'objet à l'aide de cette option. Les objets et les articles peuvent être déplacés à la souris si la case à cocher « Déplacer » de la barre d'outils est activée. L'option Objets prédéfinis du menu contextuel permet de placer rapidement des objets standard de recherche et de sauvetage sans avoir à passer par la boîte de dialogue de création d'objet/article. Ces objets comprennent les symboles standard du système de commandement des incidents pour le poste de commandement (ICP), la zone de rassemblement (Staging), la base et l'héliport, ainsi que les objets SAR pour PLS, IPP (avec 4 cercles de zone) et LKP. Si un objet portant le même nom qu'un objet sélectionné dans la liste existe déjà, un nouvel objet sera créé avec un numéro ajouté à la fin. Par exemple, la première fois que vous sélectionnez Staging dans le menu Objets prédéfinis, un objet nommé Staging sera créé. Si vous créez ensuite un autre objet Staging à partir du menu Objets prédéfinis, il sera nommé Staging2. Les objets commençant par « Heli- » (et les objets définis par l'utilisateur se terminant par un « - ») seront créés sous les noms Heli-1, Heli-2, Heli-3, etc. Si vous avez reçu l'un de ces objets standard transmis par une autre station, votre premier objet sera nommé avec un numéro ajouté. Vous pouvez attribuer un indicatif tactique à votre objet dans ce cas (par exemple, remplacer ICP2 par un indicatif tactique). Le menu Objets prédéfinis est personnalisable en modifiant les fichiers predefined_SAR.sys, predefined_EVENT.sys et predefined_USER.sys, puis en sélectionnant l'un de ces fichiers via la boîte de dialogue Fichier/Configuration/Paramètres par défaut. Voir le fichier predefined_SAR.sys pour plus de détails. Description des entrées dans la boîte de dialogue d'objet : = Panneau = Ceci fait de l'objet un panneau. Ces panneaux peuvent contenir un à trois caractères et apparaissent actuellement dans Xastir comme un panneau vide. Les informations de la station affichent la valeur contenue sur le panneau. = Objet polygonal = Ceci fait de l'objet un objet de zone et active les commandes d'objet de zone décrites ci-dessous. = Objet DF = Il s'agit d'un rapport de radiogoniométrie. L'activer vous permet de choisir un rapport omnidirectionnel ou directionnel, et de spécifier les paramètres pour chacun. Voir : https://www.aprs.org/dfing.html pour la description de Bob Bruninga sur l'utilisation de ces techniques. (À FAIRE : Section séparée sur les techniques de radiogoniométrie ?) = Cercles de probabilité = Cela vous permet de définir le rayon (en miles) de deux cercles centrés sur l'objet ou l'article. Min correspond au rayon (en miles) du plus petit cercle intérieur, et Max au rayon (en miles) du plus grand cercle extérieur. Ces cercles sont tracés en rouge. Ils peuvent être utilisés pour faciliter la planification des opérations de recherche et de sauvetage. Pour créer plus de deux cercles, ajoutez des objets de cercle de probabilité supplémentaires au même emplacement. Les cercles de probabilité peuvent ne pas être affichés par d'autres logiciels clients. = Nom = Il s'agit du nom de l'objet ou de l'article. Il peut contenir jusqu'à 9 caractères. Les espaces sont autorisés dans le nom. Lors de la modification d'un objet, ce champ ne peut pas être modifié. Pour renommer un objet, vous devez supprimer l'original, puis créer un nouvel objet. Notez que si vous sélectionnez Panneau/Objet de zone/Objet DF, ce champ et éventuellement d'autres sont effacés. Saisissez le nom APRÈS avoir sélectionné le type d'objet. = Symbole de station = Vous pouvez sélectionner un symbole pour l'objet. Appuyez sur Sélectionner pour choisir graphiquement, ou consultez la section d'aide du tableau des symboles pour obtenir des descriptions de chaque symbole. Notez également que les objets de zone, les objets de panneau et les objets DF ont des symboles fixes spéciaux et ne peuvent donc pas être sélectionnés ici. Ces symboles particuliers sont automatiquement attribués lorsque vous changez de type d'objet. = Emplacement = L'emplacement de l'objet est spécifié ici. Si vous avez sélectionné « Créer objet/élément » dans le menu contextuel, l'emplacement sur lequel vous avez cliqué sera renseigné. Si vous avez déplacé un objet avec la souris, le nouvel emplacement s'affichera dans ces champs. Vous pouvez également saisir un emplacement, par exemple si vous placez un objet à partir d'un rapport vocal reçu par radio. = Options génériques = Vous pouvez spécifier la vitesse, la direction et l'altitude des objets ici. Certains types d'objets ne peuvent pas avoir de vitesse ou de direction, auquel cas les champs sont grisés. = Texte du panneau = Si l'objet est un panneau, vous pouvez spécifier le numéro à 1 à 3 chiffres qui apparaît sur le panneau ici. Notez que Xastir n'affiche pas encore correctement les objets de panneau. = Objet polygonal = Les objets de zone sont utilisés pour mettre en évidence des parties spécifiques des cartes ou pour ajouter des détails supplémentaires aux cartes. Cela se fait à l'aide des entrées suivantes : = Couleur vive = Utilisez la version plus claire des couleurs autorisées. = Remplissage de couleur = La zone doit être remplie, et non simplement délimitée. Cela peut être utile pour exclure une zone d'une recherche ou d'un autre événement. = Type d'objet = Choisissez parmi les formes géométriques autorisées. = Couleur de l'objet = Choisissez la couleur dans laquelle l'objet sera affiché. Cette option est également affectée par l'option « Couleur vive » ci-dessus. = Décalage vertical de l'objet = En 1/1500 de degré de latitude. Un détail regrettable de la spécification, et difficile à calculer facilement. Sachez simplement que vous pouvez modifier la taille de l'objet une fois qu'il est placé. = Décalage de l'objet vers la gauche = En 1/1500 de degré de longitude. Voir ci-dessus. = Couloir d'objet = Il s'agit de la largeur d'un objet de type zone linéaire. Utile pour les pistes d'atterrissage, les zones de surveillance météorologique, la description d'une zone d'intérêt ou d'une zone d'exclusion, etc. Supprimez toujours vos objets et éléments une fois que vous n'en avez plus besoin ! Ne les laissez pas simplement expirer de votre cache, car ils pourraient rester affichés sur les écrans d'autres utilisateurs pendant une période prolongée. Description des zones de surveillance météorologique : Les zones de surveillance et les « zones de préoccupation maximale » (AOMC) générées par le WXSVR (https://www.aprs-is.net/WX/Default.aspx) sont colorées comme suit : Jaune pointillé = Alerte d'orage violent (ressemble à un ruban de scène de crime) Jaune uni = AOMC pour alerte d'orage violent Rouge pointillé = Alerte de tornade Rouge uni = AOMC pour alerte de tornade Vert pointillé = Zone de discussion à méso-échelle (plus grande) Bleu pointillé = Alerte de test Bleu uni = Avertissement de test HELP-INDEX>Objets CAD Objets CAD La prise en charge des objets CAD est actuellement en phase préliminaire. Les fonctionnalités et l'interface utilisateur sont susceptibles d'être modifiées. Les objets CAD sont des formes arbitraires que vous pouvez dessiner sur les cartes dans Xastir, mais qui ne peuvent pas être transmises par APRS. Les objets CAD actuellement pris en charge sont : Polygones : Zones fermées composées d'au moins trois points. Pour créer un objet CAD, cliquez d'abord sur le bouton radio Dessiner dans la barre d'outils. Le curseur se transforme alors en crayon. Commencez à dessiner un polygone en cliquant avec le bouton central de la souris (ou les deux boutons sur une souris à deux boutons, pour laquelle vous devrez activer l'émulation de souris à trois boutons). Cela place un point sur la carte. Déplacez ensuite le curseur à un autre endroit (les fonctions de navigation et de zoom par clic gauche/droit fonctionnent toujours normalement) et cliquez à nouveau sur le bouton central de la souris. Cela trace une ligne entre les deux points sélectionnés. Cliquez à nouveau avec le bouton central pour tracer un autre segment de ligne et répétez l'opération jusqu'à ce que vous ayez tracé tous les segments, à l'exception du dernier. Pour fermer le polygone, sélectionnez Carte/Dessiner Objets CAD/Fermer le polygone. Cela fermera votre polygone et affichera une boîte de dialogue vous permettant de saisir un nom, un commentaire et une probabilité pour le polygone. Lorsque vous avez terminé de dessiner des objets CAD, quittez le mode de dessin CAD en désélectionnant le bouton radio Dessiner dans la barre d'outils. Les objets CAD peuvent être modifiés à partir du menu Affichage/Polygones CAD et du menu Carte/Dessiner Objets CAD/Polygones CAD. Les objets CAD peuvent être supprimés à partir du menu Carte/Dessiner Objets CAD/Effacer les polygones CAD. HELP-INDEX>Menu Examiner Options du menu Examiner Le menu Examiner présente différentes façons de visualiser les données dans Xastir. Bulletins Il s'agit du tableau d'affichage APRS(tm), où sont publiées les annonces importantes. Si vous êtes connecté via l'interface Internet, il est conseillé de définir le champ de portée à quelques centaines de kilomètres afin d'ignorer les messages provenant d'autres régions du monde. « 0 » dans le champ de portée signifie le monde entier. Cliquez sur le bouton « Modifier la portée » pour appliquer les modifications apportées à ce champ. Xastir ne prend pas encore en charge l'envoi de bulletins. Les bulletins entrants ouvriront automatiquement cette boîte de dialogue si vous sélectionnez « Afficher les nouveaux bulletins » dans la boîte de dialogue Configurer | Paramètres par défaut. Le bouton « Afficher les bulletins sans distance » permet d'afficher les bulletins pour lesquels vous n'avez pas encore de portée (ils n'ont pas encore envoyé de position, mais vous avez reçu un bulletin de leur part). Si cette option est désactivée, vous devez obtenir une position d'une station, et la station doit se trouver dans la portée sélectionnée (ou la portée doit être définie sur zéro) pour que le bulletin soit affiché. Données entrantes Cette option affiche les données entrantes sur votre TNC ou votre interface Internet. Les boutons radio ci-dessous permettent de sélectionner si vous souhaitez afficher uniquement les données TNC, uniquement les données Internet ou les deux. Stations mobiles Il s'agit d'une liste des stations en mouvement. Les stations sont incluses dans cette liste si elles se sont déplacées (plus d'une position a été reçue pour elles), le symbole de la station n'est pas pris en compte. Les informations affichées comprennent le cap, la vitesse, l'altitude, la position, le nombre de paquets reçus, le nombre de satellites GPS visibles, le cap depuis votre station et la distance par rapport à votre station. Toutes les stations Cette option affiche un tableau de toutes les stations triées par ordre alphabétique. Il comprend le nombre de paquets reçus, l'heure de la dernière réception de la station, le chemin emprunté par le paquet le plus récent, le PHG et le commentaire de la station. Stations locales Cette option affiche uniquement les stations reçues via votre TNC. Elle comprend le nombre de paquets reçus, l'heure de la dernière réception de la station, le chemin emprunté par le paquet le plus récent, le PHG et le commentaire de la station. Stations récentes Cette option affiche un tableau de toutes les stations triées de la plus récemment entendue à la moins récemment entendue. Il inclut le nombre de paquets reçus, l'heure de la dernière réception, le chemin emprunté par le dernier paquet, le PHG et le commentaire de la station. Objets et articles Cette option affiche uniquement les objets et les articles. Elle inclut le nombre de paquets reçus, l'heure de la dernière réception de l'objet/article, le chemin emprunté par le dernier paquet, le PHG et le commentaire de l'objet/article. Mes objets et articles Cette option affiche uniquement les objets et les articles que vous contrôlez (c'est-à-dire ceux pour lesquels vous avez envoyé la dernière mise à jour). Elle inclut le nombre de paquets reçus, l'heure de la dernière réception de l'objet/article, le chemin emprunté par le dernier paquet, le PHG et le commentaire de l'objet/article. Une icône grisée indique que l'objet a été supprimé. Stations météo Cette option affiche un tableau de toutes les stations météorologiques APRS™ et leurs données. Les données comprennent la direction du vent, la vitesse du vent, la vitesse des rafales, la température, l'humidité, la pression barométrique, les précipitations de la dernière heure, les précipitations depuis minuit et les précipitations des dernières 24 heures. Mes données météo Affiche vos données météorologiques si vous possédez une station météorologique et que vous avez configuré Xastir pour y accéder. Alertes météo Affiche les alertes météorologiques reçues, y compris les indicateurs d'alerte, la source/le type d'alerte, la destination de l'alerte, l'expiration, le message et le lieu concerné. Ces données sont utilisées pour la mise en évidence des alertes. Un double-clic sur une alerte permet de demander des informations supplémentaires via Finger auprès du serveur WXSVR en ligne. Cela ne fonctionne que si vous avez accès à Internet ; les versions futures pourront également accéder à ces données par radio. Trafic des messages Affiche tout le trafic de messages tant que la fenêtre est ouverte. Il inclut la source, la destination, l'interface et le message. L'option de portée permet de limiter cet affichage aux stations proches, comme pour le contrôle de portée des bulletins. Une portée de 0 affiche tous les messages. État du GPS Affiche l'état de votre récepteur GPS, y compris le type de positionnement et le nombre de satellites acquis. Durée de fonctionnement du logiciel Affiche la durée écoulée depuis le démarrage de Xastir. HELP-INDEX>Menu des cartes et sélecteur de cartes Menu des cartes et Choix de cartes Menu des cartes : choix de cartes Cette option affiche une liste de répertoires et/ou de fichiers de cartes dans votre répertoire de cartes. L'option « Agrandir répertoires » permet d'afficher les fichiers de cartes individuels contenus dans les répertoires. La boîte de dialogue des propriétés offre des options de contrôle plus avancées, décrites ci-dessous. Cliquez sur les noms des cartes pour les sélectionner ; elles seront affichées lorsque vous cliquerez sur le bouton OK. Vous pouvez sélectionner autant de cartes que vous le souhaitez. Cliquer sur « Effacer » désélectionne toutes les cartes, cliquer sur « Vectorielles » sélectionne uniquement les cartes vectorielles. Les trois options « topogr. » sélectionnent automatiquement toutes les images USGS GeoTIFF de la taille indiquée. Cliquer sur le bouton OK affiche les cartes sélectionnées. Annuler annule toutes les modifications. Caractéristiques des cartes Cliquer sur le bouton Caractéristiques affiche une boîte de dialogue où vous pouvez spécifier la couche dans laquelle les cartes apparaissent et les niveaux de zoom auxquels elles sont affichées. Les numéros de couche supérieurs sont affichés au-dessus des numéros inférieurs. La plage peut être spécifiée de -99999 à 99999 ; il est conseillé d'espacer largement vos numéros de couche pour permettre l'insertion ultérieure de couches de cartes supplémentaires. À partir de cette boîte de dialogue, vous pouvez spécifier si une carte vectorielle est dessinée avec des remplissages de couleur. Cette option est définie par carte ; l'option de désactivation globale dans le menu Cartes peut la remplacer. Le paramètre « Rempli » est ignoré pour les cartes raster (images). Un paramètre « auto » permet à un fichier dbfawk de contrôler directement ce paramètre (utilisable uniquement si dbfawk est compilé et que la carte en question est un fichier Shapefile). Vous pouvez également sélectionner si une carte est prise en compte par la fonction « AutoCartes ». Enfin, vous pouvez spécifier les niveaux de zoom minimum et maximum auxquels une carte est affichée. Ceci est utile pour empêcher le chargement de cartes locales très détaillées à des niveaux de zoom très larges, et inversement. Un zoom minimum de 10 signifie qu'une carte sera affichée à tous les niveaux de zoom égaux ou supérieurs à 10. De même, un zoom maximum de 256 signifie qu'une carte sera affichée à tous les niveaux de zoom inférieurs ou égaux à 256. Marque-pages d'affichage de carte Voir la rubrique d'aide « Création et utilisation des marque-pages d'affichage de carte » Localiser une entité cartographique Cette option affiche une boîte de dialogue de recherche permettant de rechercher des étiquettes dans un fichier GNIS afin de trouver un emplacement spécifique. La carte sera centrée sur le nouvel emplacement s'il est trouvé. L'entrée « Fichier GNIS : » est enregistrée entre les appels et entre les exécutions de Xastir. Vous devez placer les fichiers GNIS dans le répertoire xastir/GNIS pour utiliser cette fonctionnalité. Rechercher un emplacement Cette fonctionnalité nécessite généralement une connexion Internet. Cette option affiche une boîte de dialogue de recherche où vous pouvez saisir une adresse ou le nom d'une entreprise ou d'un lieu. Elle générera une requête Internet vers un serveur « Nominatim » qui interroge les données OpenStreetMap pour trouver l'emplacement. Si des résultats sont trouvés, la boîte de dialogue sera remplie avec une liste d'emplacements correspondants. Choisissez-en un en cliquant dessus, puis cliquez sur « Aller à » ou « Marquer ». Ces deux options centreront la carte sur l'emplacement choisi. Le bouton « Marquer » placera également une grande croix bleue « X » sur l'emplacement. Calculatatrice de coordonnées Cette option ouvre une calculatrice simple permettant de convertir entre différents systèmes de coordonnées. Ceci est utile pour convertir des positions aux différents formats utilisés par différents groupes d'utilisateurs. Cette même calculatrice peut être appelée par le bouton « Calculer » dans certaines autres boîtes de dialogue. Elle est utile pour saisir des coordonnées dans d'autres formats. Menu Configurer : Colorer la carte sous-jaçante (XOR) Cette option contrôle la couleur de l'arrière-plan derrière les cartes affichées. La couleur d'arrière-plan est souvent entièrement masquée par les cartes remplies (voir ci-dessous). Intensité de la carte Ceci contrôle la luminosité des graphiques utilisés comme cartes. Cette option n'apparaît que si vous avez compilé avec la prise en charge de GeoTIFF. Ajuster correction de gamma Cela vous permet d'appliquer une correction gamma à tous les graphiques cartographiques chargés. Les cartes peuvent être ajustées individuellement dans leurs fichiers .geo. Voir la section sur les fichiers .geo dans « Fichiers cartographiques et comtés WX ». Cette option n'apparaît que si vous avez compilé le programme avec la prise en charge de GraphicsMagick et ne s'applique pas aux cartes GeoTIFF ; voir l'option ci-dessus. Police des étiquettes de carte Permet de définir le style et la taille de la police utilisée pour les étiquettes des cartes. Style du texte des stations Permet de choisir la police et le style à utiliser pour le texte des stations et autres éléments. Style du contour des icônes Permet de spécifier un contour autour des icônes des stations. Cela améliore la visibilité sur différents arrière-plans. Désactiver toutes les cartes Cette option désactive le chargement de toutes les cartes. Elle est particulièrement utile lors des zooms ou des déplacements rapides, car elle évite de charger les cartes à chaque rafraîchissement de l'affichage. Notez que cette option n'est pas enregistrée entre les sessions. Activer cartographie automatiques REMARQUE : La fonction « Cartographie automatiques » est obsolète et il est préférable de la désactiver ! Lorsque cette option est activée, toutes les cartes présentes dans le répertoire des cartes (ou dans l'un de ses sous-répertoires) seront affichées si elles se trouvent dans la zone d'affichage actuelle. Vous pouvez ajouter autant de niveaux de répertoires que vous le souhaitez sous le répertoire principal des cartes. La fonction de cartes automatiques parcourra tous les répertoires pour lesquels cette option est activée (dans la boîte de dialogue Caractéristiques des cartes), les vérifiera tous et déterminera quelle carte (ou quelle partie de carte) doit être affichée. Toutes les cartes seront fusionnées dans la zone d'affichage. Si vous avez un grand nombre de cartes, des cartes très détaillées ou un ordinateur lent, cette opération peut être assez lente. Lorsque cette option est désactivée, seules les cartes sélectionnées avec le choix de cartes seront affichées. Cartographie automatique - désactiver les cartes tramées Cette option empêche les cartes automatiques de charger les cartes graphiques (images). Seules les cartes vectorielles seront affichées dans ce cas. Activer quadrillage Lorsque cette option est activée, une grille s'affiche sur la carte. Si le système de coordonnées est UTM, une grille UTM sera affichée. Si le système de coordonnées est latitude/longitude, une grille de latitude et de longitude sera affichée. Lorsque vous zoomez, la grille passe à une résolution plus fine. L'espacement de la grille de latitude et de longitude peut être ajusté manuellement avec les touches « + » et « - ». Activer bordure des carte Lorsque les options Activer la grille cartographique et Activer la bordure de la carte sont activées, une fine bordure blanche est tracée autour de la carte et les lignes de la grille sont étiquetées à l'aide du système de coordonnées sélectionné (Fichier/Configurer/Système de coordonnées) et de la police de bordure sélectionnée (Carte/Configurer/Police des étiquettes de carte/Police de la bordure). Si les systèmes de coordonnées UTM ou MGRS sont sélectionnés, les lignes de la grille seront étiquetées avec les valeurs d'est et de nord uniquement aux niveaux de zoom inférieurs à environ 2048. Niveau de cartes activé Lorsque cette option est activée, le programme tente de filtrer les données lorsque le niveau de zoom affiche de grandes zones. Cela ne fonctionne pas avec toutes les cartes, mais fonctionne avec les cartes générées à partir des cartes Tiger Line du site aprs.rutgers.edu et avec les cartes au format ESRI Shapefile. Cela ne réduit pas beaucoup les temps de chargement des cartes, mais réduit simplement l'encombrement de l'écran. Activer annotation des cartes Cette option active ou désactive l'affichage des étiquettes de carte intégrées aux cartes aux formats DosAPRS, WinAPRS, GNIS et ESRI Shapefile. Activer le remplissage des zones de couleur Cette option contrôle le remplissage des cartes vectorielles. Dans certains cas, vous pourriez souhaiter désactiver le remplissage pour visualiser les cartes situées sous les cartes supérieures. Il s'agit d'un paramètre global ; le remplissage des cartes peut être activé ou désactivé individuellement dans la boîte de dialogue des propriétés du choix de cartes. Activer les alertes météorologiques par comté Cette option active l'affichage des cartes des zones d'alerte par comté pour les conditions météorologiques extrêmes. Ces cartes peuvent être obtenues et installées conformément aux instructions disponibles à l'adresse https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview et ses différents liens. Elles s'affichent à l'écran lors de la réception de messages d'alerte météorologique et expirent après un certain temps ou peuvent être annulées à distance. Le texte des alertes météorologiques est accessible via Affichage | Alertes météorologiques. Le répertoire xastir/Counties doit contenir les fichiers appropriés de la NOAA et la prise en charge de Shapelib doit être compilée dans Xastir pour activer cette fonctionnalité. Index: nouvelles cartes au démarrage Cette option contrôle la création du fichier d'index des cartes au démarrage. La plupart des utilisateurs devraient laisser cette option activée. Si l'horodatage du fichier de carte est plus récent que celui du fichier d'index des cartes, la carte sera indexée. Index : Ajouter nouvelles cartes Cette option ajoute les nouvelles cartes à l'index. Les mêmes règles que pour la fonction « Indexer les nouvelles cartes » s'appliquent, mais il s'agit d'une méthode d'activation manuelle. Index : Réindexer toutes les cartes Cette option réinitialise l'indexation et indexe toutes les cartes reconnues dans le répertoire des cartes. Cette fonction est utile si la fonction « Ajouter nouvelles cartes » ignore certaines cartes, peut-être en raison d'horodatages obsolètes sur les fichiers de cartes. Cette fonction peut prendre un certain temps si vous avez beaucoup de cartes. Menu souris Cette option affiche le menu d'options normalement accessible par un clic droit. Remarque concernant les cartes : La plupart des cartes vectorielles historiques pour les États-Unis ont été créées avec le système de référence NAD 1927, tandis que Xastir et d'autres programmes APRS™ utilisent le système de référence WGS 1984. En cas de zoom sur une petite zone de la carte, le décalage de système de référence peut être très perceptible. Les cartes topographiques de l'USGS voient leur système de référence corrigé par Xastir lors de l'affichage ; les positions seront donc généralement plus précises avec ces cartes topographiques. HELP-INDEX>Fichiers cartographiques et comtés météo Fichiers cartographiques et comtés météo Types de cartes Xastir fonctionne avec différents types de fichiers cartographiques. Tous les fichiers cartographiques DosAPRS et Windows/Mac APRS(tm) sont pris en charge sans qu'aucune bibliothèque externe supplémentaire ne soit nécessaire. Xastir peut également être compilé pour utiliser des bibliothèques externes afin de prendre en charge les images XPixmap (XPM), les cartes topographiques GeoTIFF et les cartes au format Shapefile ESRI. La capacité de gestion graphique de Xastir peut être considérablement étendue en compilant avec la prise en charge de GraphicsMagick, ce qui permet de prendre en charge de nombreux formats graphiques comme cartes. Xastir prend en charge les cartes d'alertes météorologiques au format Shapefile ESRI, disponibles auprès de la NOAA. Consultez la page wiki Github https://github.com/Xastir/Xastir/wiki/Installing-Xastir pour plus de détails. Des informations détaillées sur les emplacements où obtenir la plupart des types de cartes mentionnés ci-dessus se trouvent dans le fichier https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview et les liens ci-dessous. Emplacements des cartes Tout fichier cartographique doit être stocké dans le répertoire /usr/local/share/xastir/maps sur votre ordinateur. Cet emplacement peut être différent sur certains systèmes, selon la manière dont Xastir a été compilé/installé. Vous pouvez créer autant de répertoires que vous le souhaitez sous ce répertoire pour organiser et séparer vos données. Les cartes seront chargées par ordre alphanumérique, sauf si une superposition est spécifiée. Des conseils sur l'installation et l'organisation des cartes se trouvent sur le wiki Github de Xastir à l'adresse https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview. Les cartes au format graphique pixelisé nécessitent en réalité une combinaison de deux fichiers : un fichier de données avec une image bitmap (.xpm) (ou un autre format si vous avez compilé avec GraphicsMagick) et un fichier de calibration (.geo). Le fichier .xpm est le format graphique standard, disponible sans bibliothèques supplémentaires. Si vous souhaitez économiser de l'espace de stockage, vous pouvez utiliser gzip pour compresser ces fichiers (« gzip map.xpm » créera « map.xpm.gz »). Xastir détecte cela automatiquement lors du chargement des cartes. Vous pouvez utiliser XView/Gimp/GraphicsMagick et d'autres programmes pour convertir les images gif, jpg et tif dans ce format si vous ne disposez pas de la prise en charge de nombreux types d'images (GraphicsMagick). Si vous rencontrez des problèmes avec les cartes au format xpm, essayez de charger et d'enregistrer les graphiques avec Gimp au préalable, afin de convertir tous les noms de couleurs inconnus en représentation binaire. Le fichier .geo est un fichier de données texte qui associe l'image à un emplacement dans le monde. Voici un exemple de fichier .geo qui couvrira le monde entier avec la carte world1.xpm : FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 Les fichiers .geo peuvent contenir plusieurs éléments : FILENAME Spécifie le nom du fichier image de la carte à charger depuis le disque local. URL Spécifie l'URL d'une image de carte à charger depuis un site web ou FTP. Uniquement avec GraphicsMagick. TIEPOINT Deux points de liaison sont requis, et plus de deux seront ignorés. Ces deux lignes permettent de relier une position de pixel x,y dans l'image à une position de latitude et de longitude sur la Terre. Les points doivent être aussi proches que possible du coin supérieur gauche et du coin inférieur droit de l'image pour une précision optimale. La latitude/longitude est spécifiée en degrés décimaux. IMAGESIZE Spécifie la taille de l'image en pixels. Si cette option n'est pas définie, l'image sera chargée à chaque redessin de la carte, qu'elle soit visible à l'écran ou non. IMAGESIZE est une option OBLIGATOIRE si une URL est spécifiée. Pour les fichiers locaux, il s'agit d'un paramètre facultatif (nous utilisons GraphicsMagick pour interroger la taille de l'image pour les fichiers locaux). DATUM Cette fonctionnalité n'est pas implémentée. PROJECTION Cette fonctionnalité n'est que partiellement implémentée. La valeur par défaut est « LatLon », l'autre possibilité est « TM » pour spécifier que la carte est en projection Mercator transverse. # Toute ligne commençant par un « # » sera ignorée. Améliorations d'image spécifiques à GraphicsMagick : GAMMA Exemple : GAMMA 1.2 ou GAMMA 1.2,2.0,1.2 Le premier modifie le gamma global de l'image, le second éclaircit le vert plus que le rouge ou le bleu. CONTRAST Exemple : CONTRAST 0 ou CONTRAST 1 Ne semble pas avoir beaucoup d'effet, les autres valeurs ne font aucune différence. NEGATE Exemple : NEGATE 0 ou NEGATE 1 0 inverse toutes les couleurs, 1 uniquement les couleurs en niveaux de gris. EQUALIZE Aucun argument. NORMALIZE Aucun argument. LEVEL Exemple : LEVEL 0,1,65535 Ces valeurs semblent être les valeurs par défaut. MODULATE Exemple : MODULATE 90,150,100 Ce sont des pourcentages, 100,100,100 est la valeur par défaut. REFRESH Exemple : REFRESH 900 Cette balise est utilisée pour les URL dynamiques telles que les radars météorologiques, où vous souhaitez que Xastir redessine automatiquement la carte à un intervalle spécifié. En ajoutant cette balise aux fichiers .geos des radars météorologiques, vous pouvez observer le déplacement des phénomènes météorologiques sur votre écran. Xastir ne contient qu'un seul compteur d'intervalle, donc le plus petit intervalle REFRESH chargé prend effet pour toutes les cartes sélectionnées. TRANSPARENT Couleur à supprimer de l'image. Utilisez un nombre, 0 = noir. Les images avec correspondance de couleurs utilisent la valeur de la carte, donc le blanc est généralement 0xffffffff (32 bits de 1). Les valeurs doivent être en hexadécimal, et sont précédées de « 0x ». La valeur peut être obtenue en utilisant le niveau de débogage 16. Le premier des quatre nombres après « Couleur allouée est » est l'indice de la table des couleurs. CROP Supprime les bordures (les rend transparentes). Les valeurs sont en pixels avec (0,0) en haut à gauche. Une bonne valeur pour les images radar NWS 620x620 est « CROP 35 20 616 600 » Fichiers .geo spéciaux/non standard : WMSSERVER Permet l'utilisation des services de cartes web (WMS). Plusieurs exemples de ce type de source de carte en ligne sont automatiquement installés dans le répertoire des cartes, tels que « USTigermap.geo » et les cartes radar météorologiques dans le répertoire « NWS ». OSMSTATICMAP OSM_TILED_MAP Permet l'utilisation des serveurs OpenStreetMap qui fournissent soit une seule image statique, soit de petites tuiles de carte. Plusieurs exemples dont les noms commencent par « OSM_ » sont installés dans le répertoire des cartes. Les cartes GeoTIFF sont une variante du format d'image TIFF avec des balises de géoréférencement supplémentaires intégrées. Celles utilisées aux États-Unis sont généralement fournies avec deux fichiers : un fichier .tif et un fichier .fgd. Le fichier .tif contient les données de la carte. Le fichier .fgd est un fichier de métadonnées conforme à une norme fédérale, mais pour les besoins de Xastir, il ne doit contenir que quatre lignes comme celles-ci (il peut cependant en contenir beaucoup d'autres) : 1.5.1.1 COORDONNÉE OUEST : -122.000000 1.5.1.2 COORDONNÉE EST : -120.000000 1.5.1.3 COORDONNÉE NORD : 48.000000 1.5.1.4 COORDONNÉE SUD : 47.000000 Xastir utilise uniquement ces quatre lignes dans ses calculs pour déterminer les points d'angle d'une carte, afin de vérifier si la carte s'affiche correctement dans la zone d'affichage (et ainsi décider de l'afficher ou non). Si vos données cartographiques proviennent de cartes topographiques USGS, le fichier .fgd devrait être facilement disponible. Si ce n'est pas le cas, le script mapfgd.pl peut le créer pour vous. Si vous ne disposez pas de fichier .fgd, la carte se chargera correctement, mais les bordures blanches ne seront pas recadrées et la taille et la rotation peuvent être légèrement incorrectes. Une fonctionnalité supplémentaire de Xastir est la possibilité d'effectuer des translations de datum du NAD 1927 au WGS 84, ce qui rend les cartes topographiques USGS beaucoup plus précises sur l'écran de Xastir. Xastir peut utiliser les cartes topographiques GeoTIFF USGS directement depuis le lecteur CD. Montez manuellement le disque ou utilisez un outil de montage automatique, et assurez-vous d'avoir créé un lien symbolique dans votre répertoire de cartes pointant vers l'emplacement de votre lecteur CD-ROM. C'est tout ! Les cartes au format ESRI Shapefile sont également une combinaison de plusieurs fichiers : un fichier .shp, un fichier .dbf et un fichier .shx. Il vous suffit de sélectionner le fichier .shp pour charger la carte, mais les autres fichiers doivent être présents pour que la carte se charge correctement. De plus, à moins que votre ensemble de fichiers Shapefile corresponde à ceux pour lesquels Xastir dispose déjà de règles de rendu, vous devrez créer un fichier « dbfawk » pour que Xastir puisse les afficher correctement. Cartes du comté WX Toutes les cartes du comté WX doivent être stockées dans le répertoire /usr/local/share/xastir/Counties. Xastir prend uniquement en charge le format ESRI Shapefile pour ces cartes. L'installation est expliquée sur https://github.com/Xastir/Xastir/wiki/Xastir-Mapping-Overview. Vous devez avoir compilé Shapelib. À la réception des messages du NWS, différentes zones sont colorées pour indiquer les zones concernées. Ces couleurs correspondent aux différents types d'alertes : cyan pour les avis, jaune pour les veilles, rouge pour les alertes, orange pour les alertes annulées, bleu roi pour les tests et vert pour les niveaux d'alerte indéterminés. La coloration est réalisée à l'aide d'un motif de pixmap qui affiche le type d'alerte, si celui-ci peut être déterminé. Ces modifications ont été apportées afin que les cartes sous-jacentes restent visibles sous les zones d'alerte météorologique et que le type d'alerte soit plus facilement identifiable, car il est parfois difficile de faire correspondre les alertes affichées à l'écran et celles du dialogue des alertes météorologiques. L'affichage des alertes météorologiques peut être activé ou désactivé via le menu Carte. HELP-INDEX>Menu Stations Menu Stations Ces options vous permettent de contrôler les données affichées autour des stations sur la carte. Elles vous permettent également de suivre et de localiser des stations, ainsi que d'effacer des stations et des traces dans la base de données et sur la carte. Localiser une station Consultez la rubrique d'aide « Localisation d'une station ». Suivre une station Consultez la rubrique d'aide « Suivi d'une station ». Récupérer piste Findu Télécharge les données de trace historiques depuis findu.com. Les curseurs permettent de contrôler le point de départ et la durée des données téléchargées. Par exemple, si vous souhaitez afficher la trace d'il y a deux jours, sur toute la journée, vous pouvez régler le premier curseur sur 48 heures (heure de début il y a deux jours) et le second sur 24 heures pour obtenir exactement les données d'une journée, du début jusqu'à 24 heures plus tard. Exporter tout Ce sous-menu permet d'enregistrer les données de toutes les stations dans des fichiers [ou des bases de données]. Exporter vers fichier KML Enregistre toutes les stations et leurs traces dans un fichier Keyhole Markup Language dans ~/.xastir/tracklogs. Le nom du fichier sera la date et l'heure actuelles avec l'extension .kml, par exemple 20080125-033045.kml Des fichiers KML peuvent également être créés régulièrement à l'aide des instantanés KML du menu Fichier. Base de données par réseau [Non encore implémenté] [L'enregistrement dans les interfaces de base de données n'est actuellement implémenté que via les boîtes de dialogue d'interface de base de données SQL individuelles] Pour enregistrer un instantané PNG de la carte actuelle, utilisez Fichier->Activer copie d'écran PNG Filtrer les données Ce sous-menu permet de filtrer les symboles affichés : Ne rien afficher Détermine si les symboles doivent être affichés sur la carte. Les autres options dépendent de l'activation de cette option. Ma station Détermine si votre propre station est affichée sur la carte. Choisir TNC Activation/désactivation globale de l'affichage des données reçues via un TNC, mais peut être affinée : Stations en direct Cette option affiche uniquement les stations entendues directement (non relayées). Stations via Digi Cette option affiche les stations entendues indirectement via un répéteur. Stations via le net Cette option affiche les stations dont les données ont été reçues via Internet. Inclure données périmées Permet à Xastir de continuer à afficher les données de station qui disparaissent normalement lorsque le symbole est masqué. Le délai d'expiration peut être ajusté dans le menu Fichier|Configurer|Paramètres par défaut. Afficher les stations Activation globale de l'affichage des stations, mais peut être affinée: Stations fixes Cette option affiche les stations fixes. Stations mobiles Cette option affiche les stations avec plusieurs positions ou une vitesse non nulle. Stations météo Cette option affiche les stations météorologiques. Stations météo CWOP Cette option inclut l'affichage des données météorologiques des stations citoyennes (non radioamateurs). Actuellement, Xastir reconnaît comme stations CWOP toute station commençant par les lettres C à G, dont la deuxième lettre est « W », et suivie de quatre chiffres. objets/articles Activation globale de l'affichage des objets/articles, mais peut être affinée : Objets/articles météo Cette option affiche les objets et articles météorologiques. Cela inclut les tempêtes tropicales et les stations météorologiques distantes. Objets/articles indicateurs d'eau Cette option active ou désactive l'affichage des objets de jauge d'eau (/w). Autres objets/articles Cette option active ou désactive l'affichage des objets autres que ceux énumérés ci-dessus. Filtrer affichage Ce sous-menu permet de filtrer les données affichées : Afficher indicatif Détermine si l'indicatif d'appel est affiché. Annoter les points de piste Cette option inclut les indicatifs d'appel le long des traces, pour aider à identifier quels points appartiennent à quelles stations. Afficher symbole Détermine si le symbole est affiché à gauche de l'indicatif d'appel. pivoter symbole Certains symboles changent d'orientation pour indiquer la direction dans laquelle ils se déplacent. Afficher piste Lorsqu'elle est activée, toute station mobile affiche une ligne colorée. Nous affichons désormais autant de positions que nous en avons dans notre base de données (l'ancienne limite était de 100). Les segments de trace longs (plus de 2 degrés de latitude ou 2 degrés de longitude), ou les segments avec un délai de réception de plus de 45 minutes entre les points ne seront pas affichés. Les points en double sont également éliminés de la trace (équipe de recherche et de sauvetage revenant à la base : le dernier segment peut ne pas être affiché car le point de départ apparaît deux fois dans la liste des traces). Afficher cap Lorsqu'elle est activée, un texte vert apparaît sous l'indicatif d'appel. Il affiche le dernier cap connu (en degrés) de la station. Afficher vitesse Lorsque cette option est activée, un texte rouge s'affiche sous l'indicatif d'appel (ou le cap). Il indique la dernière vitesse connue de la station. Afficher vitesse abrégée Cette option supprime l'affichage des unités de mesure de la vitesse. Afficher altitude Lorsque cette option est activée, un texte bleu s'affiche au-dessus de l'indicatif d'appel. Il indique la dernière altitude connue de la station. Affichage info météo Option globale pour l'affichage des informations météorologiques, qui peut être affinée : Afficher texte météo Lorsque cette option est activée, les dernières données météorologiques (température, vitesse/direction/rafales du vent, humidité) sont affichées. Ce paramètre peut être ajusté avec l'option suivante : Seulement la température Affiche uniquement les données de température pour la station. Indicateur de vent Lorsque cette option est activée, une flèche de vent indiquant la direction et la vitesse du vent est dessinée pour toutes les stations affichées qui transmettent ces informations. Afficher ambiguïté de position Lorsque cette option est activée, la zone dans laquelle la station utilisant l'incertitude de position peut se trouver est ombrée, avec la station concernée au centre. Afficher puissance/gain Lorsque cette option est activée, les cercles de puissance/gain seront affichés. Les cercles qui se chevauchent indiquent que les stations sont théoriquement à portée simplex l'une de l'autre. Cette indication n'est qu'approximative, surtout dans les zones à relief variable. Activer puissance/gain défaut Active un réglage de puissance/gain par défaut tel que spécifié dans la norme APRS™. Activer puissance/gain mobile Active les cercles de puissance/gain pour les stations mobiles. Afficher attributs DF Lorsque cette option est activée, tous les cercles/lignes DF seront affichés à l'écran. Activer point estimé Lorsque cette option est activée, les positions des stations sont estimées en fonction de leur trajectoire et de leur vitesse passées. Le taux de recalcul doit être raisonnable, mais peut être ajusté dans le fichier de configuration. Afficher arc Affiche un arc en expansion indiquant la distance de déplacement maximale attendue, la position et la trajectoire, compte tenu de la trajectoire et de la vitesse passées. L'arc se transforme progressivement en cercle à mesure que le rapport de position vieillit. Afficher cap Affiche la trajectoire et la distance parcourue attendues par la station, en supposant que la trajectoire n'a pas changé. Afficher symbole Affiche une version estompée du symbole de la station à la position attendue, en supposant que la station a continué à sa trajectoire et à sa vitesse actuelles. Afficher distance/relèvement Lorsque cette option est activée, deux lignes de texte seront affichées sur le côté gauche de l'icône de la station. La ligne supérieure indiquera la distance entre votre station et cette station. La ligne inférieure indiquera le relèvement de votre station à cette station. Afficher âge du dernier rapport Affiche le temps écoulé depuis le dernier contact avec la station. Recharger histoire des objets/articles Cette option recharge le fichier ~/.xastir/config/objects.log utilisé pour la persistance des objets et des éléments. Cette opération est nécessaire si vous modifiez le fichier pendant que Xastir est en cours d'exécution. Effacer histoire des objets/articles : Cette option effacera le fichier ~/.xastir/config/objects.log utilisé pour la persistance des objets et des éléments. Il est recommandé de sélectionner et de supprimer manuellement tous les objets et éléments que vous possédez avant d'effectuer cette opération, sinon ils risquent de rester affichés sur les écrans des autres utilisateurs APRS™. Effacer indicatifs tactiques : Cette option efface tous les indicatifs tactiques attribués. La modification prendra effet lors du prochain rafraîchissement de l'écran. Notez que cela n'effacera PAS les indicatifs tactiques sur les écrans des autres utilisateurs si vous les avez publiés via un message à « TACTICAL » (voir l'aide pour « Envoyer un message »). Effacer historique des indicatifs tactiques : Cette option supprime le fichier d'historique des indicatifs tactiques, ce qui signifie que les indicatifs tactiques attribués ne seront pas conservés entre les redémarrages de Xastir. Notez que cela n'effacera PAS les indicatifs tactiques sur les écrans des autres utilisateurs si vous les avez publiés via un message à « TACTICAL » (voir l'aide pour « Envoyer un message »). Effacer toutes pistes : Cette option effacera toutes les données de suivi des lignes de la base de données des stations et rafraîchira l'écran. Cette option peut être utile si vous manquez de mémoire ou si vous souhaitez simplement un écran plus clair. Vous pouvez également effacer les traces des stations individuelles à partir de la boîte de dialogue Informations sur la station. Effacer toutes stations : Cette option effacera toutes les données de la base de données des stations, à l'exception des vôtres. Cette option peut être utile si vous manquez de mémoire ou si vous souhaitez simplement désencombrer votre écran. HELP-INDEX>Messages et menu Messages Messages et menu Messages Envoyer un message à et Ouvrir les messages de groupe Ces deux fonctions sont très similaires. « Composer un message à » permet d'envoyer vos messages à une seule station et de ne recevoir des données que de cette station. Les messages de groupe sont plus généraux : vous pouvez recevoir tous les messages destinés au groupe et envoyer vos messages à ce groupe. Le code des messages de groupe n'est pas encore entièrement implémenté et divers problèmes restent à résoudre. Le fichier « groups » est recherché dans ~/.xastir/config. C'est là que sont stockés les groupes dont vous êtes membre. Comme mentionné précédemment, la fonctionnalité « groupes » n'est peut-être pas encore complète. Dans un avenir proche, l'envoi de bulletins devrait également être ajouté à ce menu. Cette fonctionnalité n'est pas encore codée. Chacun de ces deux écrans contient une zone de message, une ligne d'appel, une ligne de message et divers boutons. Vous devez d'abord saisir l'indicatif du groupe ou de la station que vous souhaitez contacter. Une fois cela fait, tout nouveau message reçu de cette station s'affichera. Si la station vous envoie des informations et qu'aucune fenêtre de message n'est ouverte, une nouvelle fenêtre s'ouvrira automatiquement (jusqu'à 10) avec l'indicatif de cette station déjà renseigné. Vous pouvez alors saisir un message dans la ligne de message. Le message peut être plus long que la ligne de message et sa longueur maximale est d'environ 250 caractères. Une fois votre message saisi, cliquez sur le bouton « Transmettre maintenant ! » pour l'envoyer. Le bouton « Transmettre maintenant ! » sera grisé jusqu'à ce que votre message soit entièrement confirmé. Tous les messages que vous recevez sont triés par numéro de ligne et affichés dans la fenêtre de message. En mode groupe, chaque ligne affiche l'indicatif de la station émettrice, suivi du message. Actuellement, les messages de groupe sont triés par indicatif, puis par numéro de ligne. Lorsque vous avez terminé d'envoyer des messages, cliquez sur le bouton de sortie pour fermer la fenêtre. D'autres boutons sont également disponibles : le bouton « Nouvel/Refresh indicatif » vous permet de consulter les anciennes données envoyées par une station. Saisissez l'indicatif et cliquez sur ce bouton ; les anciennes informations s'afficheront. Vous pouvez également utiliser ce bouton pour modifier l'indicatif de la station avec laquelle vous communiquez. Saisissez le nouvel appel et cliquez sur le bouton. Le bouton « Effacer histoire de messages » effacera tous les messages affichés dans la fenêtre des messages. Le bouton « Annuler messages en suspens » annulera tous les messages en file d'attente de transmission qui n'ont pas encore été confirmés par la station distante. Après avoir annulé les messages en attente ou reçu un accusé de réception de la station distante, vous pouvez envoyer de nouveaux messages à cette station. Xastir vous permet de saisir du texte à l'avance ; vous pouvez donc continuer à taper sans attendre les accusés de réception. Les messages en réponse à des messages précédents tenteront d'utiliser le chemin du message reçu afin d'éviter de saturer le système avec des messages diffusés. Vous pouvez modifier le chemin dans la boîte de dialogue d'envoi de message, ou les chemins par défaut définis dans les paramètres de l'interface seront utilisés si vous laissez ce champ vide. Le chemin peut être défini pour chaque message envoyé, mais une fois le message envoyé, le chemin reste fixe pour ce message. Chaque message sortant reste mis en évidence jusqu'à ce qu'il soit confirmé par la station distante. S'il expire ou si vous annulez les messages en attente, ces messages resteront mis en évidence, sauf si vous effacez l'historique des messages. Pour publier des indicatifs tactiques vers d'autres stations Xastir et APRS+SA, et les attribuer localement : Envoyez un message à « TACTICAL » dont le corps contient des lignes similaires à : indicatif-1=TAC1;indicatif-2=TAC2;indicatif-3=TAC3 Pour supprimer ultérieurement ces indicatifs tactiques des écrans locaux ET distants, assurez-vous que le(s) message(s) d'origine les ayant attribués a/ont expiré ou a/ont été annulé(s), puis envoyez un message comme celui-ci et laissez-le se répéter jusqu'à expiration (ce qui attribue des indicatifs tactiques vides aux indicatifs d'origine, supprimant ainsi l'attribution) : indicatif-1=;indicatif-2=;indicatif-3= Effacer tout message à expédier Cela effacera tous les messages non acquittés que vous avez envoyés. Intérroger toutes les stations Ceci envoie un paquet « ?APRS? », ce qui devrait inciter toutes les stations locales à signaler leur position et/ou leur statut. La plupart des logiciels ignorent cette requête, car y répondre provoquerait un flux de données massif. Intérroger les statsion IGate Ceci envoie un paquet « ?IGATE? », ce qui devrait inciter toutes les stations IGate locales à répondre avec leurs capacités. Intérroger les station météo Ceci envoie un paquet « ?WX? », ce qui devrait inciter toutes les stations météorologiques locales à signaler leur position et les conditions météorologiques. Configurer la réponse automatique Cela définit le message envoyé en réponse automatique. Activer la réponse automatique Cela active la réponse automatique lorsqu'un message entrant est reçu. Mode "Satellite Ack" Ce mode désactive l'envoi de messages d'accusé de réception en réponse aux messages reçus. Les messages sont toujours acquittés à l'aide du système de réponse-accusé de réception. Lors d'une communication par satellite, il est évident que votre message a bien été transmis, car vous l'entendrez répété. L'envoi d'un accusé de réception indépendant par la station réceptrice ne fait qu'ajouter des interférences. HELP-INDEX>Menu Interfaces Menu Interfaces Ce menu contient les options relatives aux interfaces. Contrôle de l'interface Cette option affiche une fenêtre permettant d'activer et de désactiver vos interfaces configurées, ainsi que d'ajouter, de supprimer ou de configurer des interfaces. Consultez la rubrique d'aide « Configurer les interfaces ». Options de désactivation de la transmission Ces options désactivent la transmission de toutes les données, de votre position ou de vos objets. Ce sont des options globales qui affectent toutes les interfaces. La plupart des interfaces disposent également d'une option permettant de désactiver la transmission sur cette interface spécifique dans leurs menus de configuration. Activer le port serveur Cette option active/désactive les sockets d'écoute TCP et UDP sur le port 2023. Vous pouvez connecter d'autres clients APRS(tm) au port TCP afin d'envoyer/recevoir des données APRS(tm). Une fois authentifiés, ils pourront envoyer des données à Xastir. Sans authentification, ils pourront recevoir toutes les données TNC et INET que Xastir reçoit. Notez que TOUT utilisateur disposant des identifiants appropriés peut se connecter aux ports TCP ou UDP s'ils sont activés. Actuellement, seul le port serveur UDP peut transmettre des données par radiofréquence. Le port TCP ne le peut pas. « user WE7U-13 pass XXXX vers XASTIR 1.3.3 » Connectez un autre client APRS(tm) à ce port ; il devrait s'authentifier et pouvoir envoyer des données à tous les serveurs auxquels Xastir est connecté, ainsi que recevoir des paquets de tous les ports/serveurs auxquels Xastir est connecté. Vous devriez également disposer d'un exécutable appelé « xastir_udp_client » qui peut envoyer des paquets au port d'écoute UDP. Exécutez-le comme suit: xastir_udp_client localhost 2023 "Paquet APRS ici" Actuellement, cela injectera le paquet dans les routines de décodage de Xastir et l'enverra à tous les clients connectés en TCP. Il l'enverra également à l'INET si la fonction d'envoi à l'INET est activée. Il enverra le paquet via les ports RF en tant que paquet tiers uniquement si vous ajoutez l'option « -to_rf » après le mot de passe, comme ceci : xastir_udp_client localhost 2023 -to_rf "Paquet APRS" Le client UDP est utile pour générer et injecter des paquets APRS à partir de scripts externes. Il peut également être utilisé pour récupérer l'indicatif du serveur Xastir distant en utilisant l'option « -identify » : xastir_udp_client localhost 2023 -identify Transmettre maintenant! Cette option permet à toutes les interfaces pour lesquelles la transmission est activée (voir Configuration | Interfaces) d'envoyer un paquet de position. Elle sera grisée si l'option « Désactiver la transmission : TOUT » est sélectionnée. Si GPSMan est installé, les options de menu supplémentaires suivantes s'affichent: Extraire piste GPS Télécharger un ensemble de points de trace depuis un GPS connecté. Extraire routes GPS Télécharger un ensemble d'itinéraires depuis un GPS connecté. Extraire points de cheminement GPS Télécharger un ensemble de points de repère depuis un GPS connecté. Extraire points de cheminement Garmin RINO Récupérer les points de repère d'un Garmin RINO connecté et créer des objets APRS™ à partir de tous les points de repère commençant par « APRS ». HELP-INDEX>Boîte d'informations de station - Recherche FCC et RAC Boîte d'informations de station - Recherche FCC et RAC Les informations de station affichent les données décodées par Xastir. Vous pouvez attribuer des indicatifs tactiques (locaux uniquement) aux stations à partir d'ici en cliquant sur le bouton « Assigner un indicatif tactique ». La station s'affichera alors à l'écran avec son indicatif tactique au lieu de son indicatif d'appel. Attribuer un indicatif tactique vide désactive cette fonction, qui peut également être désactivée pour toutes les stations dans le menu Stations. Cette fonction attribue des indicatifs tactiques uniquement à la station Xastir locale, mais consultez la section ci-dessous pour les partager avec d'autres stations. Pour partager les indicatifs tactiques par radio avec d'autres stations Xastir et APRS+SA (en plus de les attribuer localement), consultez la section d'aide « Composer un message ». L'option « Activer actualisation automatiques » actualise régulièrement la fenêtre avec les dernières informations. Les informations disponibles peuvent inclure : le nombre de paquets reçus, l'heure de la dernière réception, l'appareil d'origine du paquet, les commentaires de la station, la puissance/hauteur/gain de la station, le cap/la distance par rapport à votre station, les informations météorologiques et les positions actuelles et précédentes. Pour les stations mobiles, un journal de suivi s'affiche avec les entrées les plus récentes en haut. Un « + » indique le début d'une nouvelle trace (en cas d'intervalle important dans le temps ou la position). Une étoile à la fin d'une ligne indique que cette station a pu être entendue directement (sans répéteur) à cette position. Les positions sont suivies du carré de grille Maidenhead à 6 chiffres où se trouvait la station à ce moment-là. Pour votre propre station, un champ « Echo de » affiche les six derniers répéteurs qui vous ont entendu directement. Ceci est utile pour définir des trajets non génériques. Actuellement, deux rangées de quatre boutons apparaissent dans la fenêtre d'informations de la station. Certains libellés des boutons changent en fonction du type de station concernée. Pour les objets/articles : Sauver Modifier Vide Fermer piste objet/ article Info Informations Messages Info Station suivi non station Version confirmés en direct Pour les autres stations : Sauver Composer Chercher Fermer Piste un message dans la base FCC (RAC) Info Informations Messages Info Station suivi non station Version confirmés en direct « Info station version » devient « Effacer la piste » pour les stations mobiles. Le bouton « Effacer la piste » supprime tout tracé de ligne pour cette station, qu'il soit actuellement stocké ou affiché sur la carte. « Sauver piste » enregistre le tracé de la station dans un fichier sur le disque. Le format est similaire à celui utilisé par les récepteurs GPS, mais ses spécifications pourraient être modifiées (améliorées) dans les versions futures. Il n'est actuellement pas possible de relire ces données de tracé, mais cette fonctionnalité est prévue. L'objectif est également de lire et d'afficher les journaux de suivi GPS de manière similaire. Ces fichiers de journal de suivi seront placés dans le répertoire ~/.xastir/tracklogs avec un nom correspondant à l'indicatif d'appel de la station et l'extension « .trk ». « Sauver piste » enregistre simultanément le tracé de la station sous forme de fichier Keyhole Markup Language (.kml) avec un nom de fichier correspondant à l'indicatif d'appel de la station, la date et l'heure actuelles et l'extension « .kml ». Si la prise en charge des fichiers de formes est activée, le tracé de la station sera également enregistré sous forme d'un ensemble de quatre fichiers (.dbf, .prj, .shp, .shx). Les pressions successives sur « Sauver piste » pour la même station ajouteront des lignes supplémentaires au fichier .trk et créeront de nouveaux fichiers .kml (et fichiers de formes) (chacun contenant toutes les positions du tracé de la station). « Modifier objet/article » affiche la fenêtre de modification d'objet. « Composer un message » ouvre la fenêtre de message et vous permet d'envoyer un message à cette station. L'indicatif d'appel sera automatiquement renseigné. Si la base de données de la FCC (Commission fédérale des communications des États-Unis) ou de la RAC (Radio Amateurs du Canada) est installée et que l'indicatif d'appel semble être un indicatif canadien ou américain, le bouton « Chercher dans la base FCC/RAC » devient actif ; sinon, il reste inactif. Les fichiers FCC et RAC doivent être placés dans le répertoire /usr/local/share/xastir/fcc, et la casse est importante ! Cliquer sur ce bouton ajoute le nom et l'adresse de la station dans le champ « Informations sur la station ». Les instructions d'installation de ces bases de données se trouvent sur la page « Scripts d'aide » du wiki : https://github.com/Xastir/Xastir/wiki/Helper-Scripts Xastir crée des fichiers d'index pour chaque fichier de base de données au démarrage. Si un fichier d'indicatifs d'appel plus récent est placé dans ce répertoire pendant que Xastir est en cours d'exécution, l'index sera créé ou mis à jour lors de la prochaine recherche. Les préfixes spéciaux ne sont PAS pris en charge. HELP-INDEX>Création d'un journal Création d'un journal Xastir peut enregistrer les données provenant d'Internet ou d'un TNC pour une lecture ultérieure ou à des fins de débogage. ATTENTION : L'enregistrement des données peut saturer votre disque dur ; utilisez cette fonction avec précaution ou configurez la rotation automatique des fichiers journaux via cron. Une indication s'affichera dans la barre d'état lorsque l'enregistrement est activé. Toutes ces options sont accessibles via le menu Fichier : Activer archivage TNC Enregistre toutes les données TNC reçues et transmises. Ces journaux peuvent être lus à l'aide de la fonction « Ouvrir le fichier journal ». Activer archivage réseau Enregistre toutes les données Internet reçues et transmises. Ces journaux peuvent être lus à l'aide de la fonction « Ouvrir le fichier journal ». Si aucune interface n'est démarrée mais que vous souhaitez tout de même enregistrer vos positions et objets localement, cette option est également disponible. Activer archivage IGate Enregistre toutes les données transmises dans les deux sens, ainsi que les transmissions rejetées avec les raisons du rejet. Inclut les messages NWS transmis par radiofréquence. Activer archivage météo Enregistre toutes les données météorologiques reçues de votre station météo. HELP-INDEX>Relecture d'un journal Relecture d'un journal Cliquez sur « Fichier », puis sur « Ouvrir le journal ». Une fenêtre de sélection de fichier s'affichera. Vous pouvez l'utiliser pour parcourir votre disque dur et sélectionner n'importe quel fichier contenant des données TNC brutes, comme ceux créés par les options d'enregistrement TNC et réseau. Votre station continuera de fonctionner normalement, en réception et en transmission. Si vous enregistriez des données, l'emplacement habituel de ces fichiers est ~/.xastir/logs/ REMARQUE : Cette fonction ne lit pas les journaux de suivi de station enregistrés. HELP-INDEX>Localisation d'une station Localisation d'une station Cliquez sur « Stations », puis sur « Localiser une station ». Une fenêtre s'ouvrira. Vous pouvez maintenant saisir un indicatif ou une partie d'indicatif. Par défaut, la recherche s'effectue sur une correspondance exacte (indicatif complet, et non partiel) et n'est pas sensible à la casse. Si vous recherchez une correspondance partielle, l'option « Correspondance exacte » ne doit pas être sélectionnée. Pour les objets pouvant contenir des minuscules, vous devez cocher « Casse exacte » ! Contrairement à ce que son nom indique, sans l'option « Casse exacte », le texte de recherche sera converti en majuscules. Cliquer sur le bouton « Localiser maintenant ! » centrera la première station trouvée au centre de votre écran, au niveau de zoom actuel. Cliquer sur « Recherche indicatif FCC/RAC » affichera les informations de l'utilisateur si les bases de données FCC ou RAC sont installées. Cliquer sur « Annuler » fermera la fenêtre. Cette boîte de dialogue s'affiche lorsqu'une station envoie un paquet Mic-e « Urgence ! », afin d'encourager les utilisateurs à localiser et éventuellement à aider la station concernée. HELP-INDEX>Création et utilisation des signets d'affichage de carte Création et utilisation des signets d'affichage de carte Cliquez sur « Cartes », puis sur « Aller à ». Une fenêtre s'ouvrira. Si c'est la première fois que vous utilisez cette fonction, la liste sera vide. Pour ajouter un signet : positionnez la carte principale sur la zone et le niveau de zoom souhaités. Saisissez un nom unique dans le champ « Nouveau nom de lieu », puis cliquez sur « Ajouter ». Votre signet sera ajouté à la liste (par ordre alphabétique). Vous pouvez ajouter autant de signets d'affichage de carte que vous le souhaitez. Pour utiliser un signet, sélectionnez son nom et cliquez sur « Aller ! ». La carte principale affichera alors la zone et le niveau de zoom enregistrés. Vous pouvez également supprimer un signet en cliquant sur son nom, puis sur le bouton « Supprimer ». « Cartes > Localiser élément cartographique » est une autre méthode pour accéder à un emplacement, si vous connaissez le nom de l'emplacement et que les fichiers GNIS sont installés. HELP-INDEX>Suivi d'une station Suivi d'une station Cliquez sur « Stations », puis sur « Suivre station ». Saisissez l'indicatif d'appel de la station à suivre (en entier ou en partie), puis cliquez sur le bouton « Suivre maintenant ! ». La station restera visible dans la fenêtre principale de la carte pendant son déplacement. Lorsque la station s'approche du bord de la fenêtre, celle-ci se recentre automatiquement afin que l'objet reste toujours visible. Pour arrêter le suivi de cette station, cliquez sur le bouton « Annuler suivi ». Pendant le suivi, la mention « Tr » s'affiche dans la barre d'état, à côté du niveau de zoom. Si la station n'est pas encore visible sur la carte, le suivi commencera dès son apparition. HELP-INDEX>Impression Impression de l'écran de la carte Remarque : L'impression n'est pas configurée sous Windows/Cygwin. Ces instructions sont destinées aux systèmes d'exploitation Unix et similaires. Xastir peut imprimer la zone de dessin en noir et blanc ou en couleur. Pour ce faire, il enregistre d'abord l'image dans un fichier XPixmap sur le disque, puis utilise des outils externes pour la convertir au format PostScript, la redimensionner, la faire pivoter, l'afficher en aperçu, puis l'imprimer. Votre système d'impression oit être configuré pour gérer le format PostScript (cela nécessite généralement l'installation de Ghostscript et d'un filtre d'impression, ainsi que des gestionnaires d'impression lp ou lpr). Vous devez également installer les outils suivants : les outils GraphicsMagick (en particulier « convert »), Ghostscript, les polices Ghostscript et « gv ». Une fois tous ces paquets installés et fonctionnels, une fenêtre « gv » devrait s'afficher peu après que vous ayez demandé à Xastir de créer un fichier d'impression. Vous pourrez alors visualiser l'image imprimée et, si elle vous convient, demander à « gv » de l'imprimer. Notez qu'il est parfois recommandé de choisir un fond blanc par défaut pour les cartes, selon les cartes affichées. Cela permet de réaliser d'importantes économies d'encre. HELP-INDEX>Création d'instantanés Création d'instantanés automatiques Xastir peut créer automatiquement des instantanés de l'écran de la carte à intervalles réguliers. La période par défaut est de cinq minutes. Si vous avez installé l'outil « convert » de GraphicsMagick, Xastir créera un fichier au format XPM dans ~/.xastir/tmp/, puis le convertira en fichier PNG ~/.xastir/tmp/snapshot.png. Ce fichier est utile pour afficher une image « en direct » de votre écran Xastir sur une page web. Activez cette fonctionnalité via le bouton bascule « Fichier->Active copie d'écran PNG ». La fréquence est d'une fois toutes les cinq minutes (configurable dans la boîte de dialogue Configuration des temporisations, accessible via « Fichier->Configurer->Temporisations »), ou à chaque activation du bouton. Un fichier .geo est créé pour vous permettre d'utiliser l'instantané comme carte. Un fichier .kml est également généré pour vous permettre d'utiliser l'instantané comme superposition graphique sur le terrain dans les applications compatibles KML. Consultez les fichiers kml_snapshot_to_web.sh et kml_snapshot_feed.kml dans le répertoire des scripts pour plus d'informations sur l'utilisation des fichiers snapshot.png et snapshot.kml afin de produire un flux KML à partir des instantanés. Création d'instantanés KML automatiques Xastir peut enregistrer toutes les stations et traces actuelles dans un fichier KML à intervalles réguliers. Activez cette fonctionnalité via le bouton bascule « Fichier->Instantanés KML ». La fréquence de génération de ces instantanés est la même que celle des instantanés PNG, configurée dans « Fichier->Configurer->Temporisations » en définissant l'intervalle de temps des instantanés. Chaque instantané est enregistré dans un fichier .kml dans ~/.xastir/tracklogs, avec un nom de fichier basé sur la date et l'heure de l'instantané, par exemple 20080206-000720.kml. Ce comportement pourrait être modifié pour que les instantanés KML soient enregistrés dans un seul fichier, comme les instantanés PNG. HELP-INDEX>Scripts inclus Scripts inclus Xastir inclut plusieurs scripts Perl et un script shell qui peuvent être utiles : get-fcc-rac.pl Ce script shell automatise la récupération et l'installation des bases de données d'indicatifs d'appel de la FCC et du RAC. Notez que ces bases de données sont très volumineuses ! icontable.pl Ce script génère une image bitmap xpm de tous les symboles primaires et secondaires de Xastir à partir du fichier symbols.dat. Les superpositions et les symboles spéciaux sont ignorés. La sortie est envoyée vers STDOUT ; un appel typique serait donc « icontable.pl > symbols.xpm ». inf2geo.pl Ce script crée des fichiers .geo à partir de fichiers .inf de UI-View. Pour créer un fichier map.geo à partir d'un fichier map.inf, l'utilisation typique serait « inf2geo.pl map ». kiss-off.pl Ce script envoie les commandes nécessaires pour désactiver le mode KISS d'un TNC. mapfgd.pl Ce script crée des fichiers .fgd minimaux pour les images GeoTIFF qui en sont dépourvues, en se basant sur les informations trouvées dans le fichier GeoTIFF. Les fichiers créés permettent à Xastir de recadrer les bordures blanches et de faire pivoter/redimensionner la carte correctement. L'utilisation typique serait « mapfgd.pl mapdir » où mapdir est le répertoire contenant les images GeoTIFF. overlay.pl Ce script crée des fichiers au format .log à partir de fichiers de superposition séparés par des virgules. Consultez les commentaires du script pour obtenir des informations complètes sur son utilisation. ozi2geo.pl Ce script crée des fichiers .geo à partir de fichiers .map d'OziExplorer. permutations.pl Ce script convertit différents formats de latitude/longitude. Consultez les commentaires du script pour plus de détails. test_coord.pl Tests pour le module Perl Coordinate.pm. track-get.pl Ce script télécharge le journal de suivi d'un objet spécifié à partir d'un GPS Garmin. Il nécessite le module GPS::Garmin. Il demande le nom de l'objet et écrit le journal de suivi dans le répertoire ~/.xastir/logs. update_langfile.pl Ce script est destiné aux développeurs. Il reconstruit un fichier de langue spécifié pour qu'il contienne toutes les chaînes d'un autre fichier. Il est généralement utilisé pour régénérer les fichiers de langue autres que l'anglais lorsque des modifications importantes ont été apportées au fichier anglais. Lorsque le fichier de la deuxième langue ne contient pas une chaîne présente dans le fichier principal, la chaîne non traduite est insérée. L'utilisation typique serait « update_langfile.pl language-German.sys ». Le fichier de langue principal est codé en dur, mais facilement modifiable. waypoint-get.pl Ce script similaire télécharge les points de passage d'un GPS Garmin et crée un fichier journal dans le répertoire ~/.xastir/logs contenant les points de passage sous forme d'objets. Il nécessite également le module GPS::Garmin. db_gis_mysql.sql db_gis_postgis.sql Ces fichiers créent des tables pour stocker les données des stations dans une base de données MySQL ou PostgreSQL/ PostGIS. La prise en charge des bases de données SQL Server est expérimentale. Voir la section « OPTIONNEL : Expérimental. Ajouter la prise en charge des bases de données SIG » dans le fichier INSTALL.md. HELP-INDEX>Configuration des interfaces Configuration des interfaces Cliquez sur Interfaces, puis sur Contrôle de l'interface. Une fenêtre « Interfaces installées » devrait apparaître. Cette fenêtre vous permettra d'ajouter, de supprimer et de modifier les propriétés des différents périphériques que vous souhaitez utiliser avec Xastir. Types d'interfaces pris en charge : TNC port série TNC série + GPS sur câble HSP GPS port série Méteo port série Serveur Internet TNC AX25 GPS réseau (par gpsd) Météo par réseau TNC série + GPS sur câble AUX TNC KISS série Base de données par réseau (non encore implémenté) AGWPE par réseau TNC Multi-Port KISS série Bases de données SQL (expérimental) Pour ajouter un périphérique, cliquez sur le bouton Ajouter. Une fenêtre « Choisir du type d'interface » apparaîtra. Cliquez sur le type de périphérique que vous souhaitez ajouter. Cliquez ensuite sur le bouton Ajouter dans la fenêtre « Choisir du type d'interface ». Les propriétés de ce périphérique s'afficheront. Remplissez les informations demandées et cliquez sur OK. Pour supprimer un périphérique, cliquez sur le périphérique que vous souhaitez supprimer, puis cliquez sur le bouton Supprimer. Pour modifier les propriétés d'un périphérique, cliquez sur le périphérique que vous souhaitez modifier, puis cliquez sur le bouton Propriétés. Les propriétés de ce périphérique s'afficheront. Modifiez les informations souhaitées et cliquez sur OK. Une aide plus détaillée est disponible dans les rubriques d'aide de chaque type d'interface. Les bases de données SQL n'apparaîtront comme option que si vous avez compilé le support MySQL ou Postgis. HELP-INDEX>Configuration des périphériques TNC série Configuration des périphériques TNC série Cette section décrit l'ajout ou la modification des TNC série ou des TNC série avec GPS sur un câble HSP. Si vous disposez d'un câble HSP, qui vous permet de partager le port TNC avec une unité GPS, vous pouvez choisir un TNC avec GPS (câble HSP). Il s'agit d'un câble spécial qui peut ne pas fonctionner avec toutes les combinaisons d'ordinateurs/GPS/TNC. Si vous utilisez ce périphérique, le TNC et le GPS doivent être configurés avec les mêmes paramètres de communication. Généralement 4800 bps, 8 bits de données, pas de parité et 1 bit d'arrêt. Options du port TNC : Sélectionner « Activer au démarrage » indique à Xastir de rechercher ce périphérique et d'établir la communication avec celui-ci au premier démarrage du programme. Sélectionner « Permettre transmission » indique à Xastir que toutes les données RF sortantes peuvent être envoyées à ce périphérique pour diffusion. Sélectionner « Ajouter un délai » indique à Xastir d'insérer un délai d'une seconde entre l'envoi de la commande de passage en mode « Conversation » et l'envoi effectif des données. Cette option est uniquement destinée à gérer le TNC Kantronics KAM, qui ne parvient souvent pas à passer en mode conversation s'il reçoit des données immédiatement après l'envoi de la commande de conversation. Si vous possédez un KAM, cochez cette case ; sinon, laissez-la décochée. Le port TNC est le périphérique Unix auquel le TNC (ou le TNC et le GPS) est connecté. Normalement, vous pouvez utiliser /dev/ttyS0 (com1), /dev/ttyS1 (com2), etc. Le champ Commentaire vous permet de définir un nom convivial ou un commentaire pour le port. Définissez maintenant le débit en bps dans les paramètres du port, et les paramètres dans le style du port. Le paramètre Style du port 8N1 est utilisé pour 8 bits de données, pas de parité et 1 bit d'arrêt. 7E1 est utilisé pour 7 bits de données, parité paire et 1 bit d'arrêt. 7O1 est utilisé pour 7 bits de données, parité impaire et 1 bit d'arrêt. Ces paramètres doivent correspondre à ceux de votre TNC et de votre GPS. Choisissez le mode de fonctionnement IGate approprié pour ce périphérique. Vous pouvez avoir plusieurs périphériques TNC, et cette option peut être différente pour chaque périphérique. Si vous n'utilisez pas d'iGate, laissez l'option par défaut « Désactiver ». Saisissez jusqu'à trois chemins UNPROTO. Xastir ajoutera automatiquement la partie XX VIA du chemin UNPROTO. Trois chemins sont autorisés afin que votre signal soit reçu même dans de mauvaises conditions. Xastir utilisera successivement chaque chemin renseigné, un par transmission. Si vous êtes proche d'un digipeater, WIDE2-2 peut être un bon choix. Si vous utilisez une faible puissance et/ou êtes éloigné d'un digipeater, WIDE1-1, WIDE2-2 peut être plus efficace. Si vous connaissez l'indicatif de votre digipeater le plus proche, vous pouvez utiliser XXXCALL, WIDE2-2. La plupart d'entre vous n'auront besoin que d'un seul chemin. Si vous êtes dans une zone isolée et que votre signal a du mal à être reçu, vous pourriez en avoir besoin de plusieurs. Renseignez-vous auprès d'un groupe local pour savoir quel chemin est le plus adapté à votre région. Si aucun chemin n'est saisi, WIDE2-2 sera utilisé par défaut. Si vous utilisez une passerelle iGate vers la radiofréquence (RF), vous pouvez saisir un chemin spécifique pour les paquets que vous envoyez en RF. Si vous laissez ce champ vide, les chemins UNPROTO ci-dessus seront utilisés. Si les chemins UNPROTO sont vides, WIDE2-2 sera utilisé. Nom du fichier de démarrage et d'arrêt du TNC. Ces champs spécifient un nom de fichier situé dans le répertoire /usr/local/share/xastir/config. Chaque fichier est un fichier texte standard contenant les commandes que vous souhaitez envoyer à votre TNC lors de l'activation (fichier de démarrage) ou de l'arrêt de l'appareil. HELP-INDEX>Configurer le TNC série avec GPS sur câble HSP ou port AUX Configurer le TNC série avec GPS sur câble HSP ou port AUX Ces types d'interface hybrides combinent les fonctionnalités des TNC série et des GPS. Veuillez consulter l'aide à la configuration des TNC série et des GPS série pour plus d'informations sur la configuration de ces appareils. « Envoyer Ctrl+E pour obtenir les données GPS? » Cette case à cocher détermine si Xastir envoie un caractère Ctrl+E au TNC chaque fois qu'il a besoin des données GPS. Certains TNC prenant en charge un GPS sur un port auxiliaire nécessitent que Xastir envoie un caractère Ctrl+E au TNC pour obtenir les données GPS à chaque fois que cela est nécessaire. Parmi ces appareils, on trouve le Kantronics KPC-3+. Certains appareils, comme les radios APRS Kenwood (D700, etc.), ne nécessitent PAS cette manipulation, et l'envoi du caractère Ctrl+E peut même perturber leur bon fonctionnement. Comme l'envoi de Ctrl+E était requis par la plupart des TNC courants disposant d'un port auxiliaire pour le GPS au moment de la création de ce type d'interface, il s'agit du comportement par défaut de Xastir. Si vous utilisez une radio Kenwood dans ce mode, vous devez DÉSÉLECTIONNER la case à cocher « Envoyer Ctrl+E pour obtenir les données GPS ? » dans la boîte de dialogue de configuration de ce type d'interface. HELP-INDEX>Configuration du TNC série KISS Configuration du TNC série KISS Cette section traite de l'ajout ou de la modification des TNC série KISS. Le mode KISS est également pris en charge par la plupart des TNC standard et élimine la nécessité de configurer les options spécifiquement dans les fichiers de démarrage, au prix d'une légère augmentation de l'utilisation du processeur. Cela permet bien sûr d'utiliser des TNC purement KISS, comme celui décrit dans le numéro de novembre 2000 de QST, sans programme ni module noyau séparé. Options Sélectionner « Activer au démarrage » indique à Xastir de rechercher ce périphérique et d'établir la communication avec lui au démarrage du programme. Sélectionner « Permettre transmission » indique à Xastir que toutes les données RF sortantes peuvent être envoyées à ce périphérique pour diffusion. Sélectionner « Digipeat ? » indique à Xastir de répéter le trafic. Il le fera si l'indicatif du premier répéteur non utilisé dans le chemin correspond à votre indicatif ou à un indicatif répertorié dans votre fichier de configuration Xastir (ligne « RELAY_DIGIPEAT_CALLS », par défaut « WIDE1-1 »). Cette option est recommandée uniquement pour les stations de base dans les régions où il y a peu d'autres répéteurs de remplissage. Consultez un groupe local pour connaître le meilleur réglage pour votre région. Vous pouvez modifier manuellement le fichier de configuration Xastir lorsque Xastir n'est pas en cours d'exécution afin de modifier cette chaîne pour qu'elle corresponde aux recommandations locales. Aux États-Unis, « WIDE1-1 » est le paramètre recommandé. Le port TNC est le périphérique série Unix auquel le TNC est connecté. Normalement, vous pouvez utiliser /dev/ttyS0 (com1), /dev/ttyS1 (com2), etc. Le champ Commentaire vous permet de définir un nom convivial ou un commentaire pour le port. Définissez maintenant le débit en bps dans les paramètres du port. Choisissez le mode de fonctionnement IGate approprié pour ce périphérique. Vous pouvez avoir plusieurs périphériques TNC, et cette option peut être différente pour chaque périphérique. Si vous n'utilisez pas d'IGate, laissez l'option par défaut « Désactiver ». Saisissez jusqu'à trois chemins UNPROTO. Xastir prendra en compte la partie XX VIA du chemin UNPROTO. Trois chemins sont autorisés pour que votre signal soit entendu même dans de mauvaises conditions. Xastir alternera entre chaque chemin configuré, à raison d'un par transmission. Si vous êtes proche d'un digipeater, un simple WIDE2-2 peut être un bon choix. Si vous utilisez une faible puissance et/ou êtes éloigné d'un digipeater, WIDE1-1,WIDE2-2 peut être plus efficace. Ou si vous connaissez l'indicatif de votre digipeater le plus proche, vous pouvez utiliser XXXCALL,WIDE2-2. La plupart d'entre vous n'auront besoin que d'un seul chemin. Si vous êtes dans une zone isolée et que votre signal a du mal à passer, vous pourriez en avoir besoin de plus. Renseignez-vous auprès d'un groupe local et demandez quel chemin est le plus adapté à votre région. Si aucun chemin n'est configuré, la valeur par défaut sera WIDE2-2. Si vous utilisez l'iGate vers la radiofréquence, vous pouvez spécifier un chemin particulier pour les paquets que vous envoyez en radiofréquence. Si vous laissez ce champ vide, les chemins UNPROTO ci-dessus seront utilisés. Si les chemins UNPROTO sont vides, WIDE2-2 sera utilisé. Configurez ensuite les paramètres KISS : TXdelay correspond au temps (en unités de 10 ms) nécessaire entre l'activation de l'émetteur et le moment où il est prêt à envoyer des données. La persistance et le temps d'accès au canal sont les paramètres d'accès au canal : le temps d'accès au canal indique la fréquence d'exécution de l'algorithme d'accès au canal et doit généralement être réglé sur 10. La persistance indique la fréquence à laquelle votre station tente d'accéder au canal lorsqu'il est libre et doit idéalement être réglée sur 255 divisé par le nombre de stations présentes sur le canal. Le mode duplex intégral permet de commencer la transmission même si des paquets sont reçus sur le canal ; cette option doit être désactivée dans la plupart des cas (réglée sur « 0 »). HELP-INDEX>Configuration des périphériques TNC AX.25 Configuration des périphériques TNC AX.25 Cette section décrit l'ajout ou la modification des périphériques TNC AX.25. Les périphériques AX.25 peuvent être n'importe quel périphérique utilisant les pilotes Linux AX.25. Il s'agit d'un pilote de niveau noyau, et des périphériques tels qu'un Baycom ou un modem audio peuvent être utilisés comme TNC. Ces périphériques doivent être configurés et opérationnels avant que Xastir puisse les utiliser. Sélectionner « Activer au démarrage » indiquera à Xastir de rechercher ce périphérique et d'établir la communication avec lui au démarrage du programme. Sélectionner « Permettre transmission » indiquera à Xastir que toutes les données RF sortantes peuvent être envoyées à ce périphérique pour diffusion. Sélectionner « Digipeat ? » indiquera à Xastir de relayer le trafic. Il le fera si l'indicatif du premier répéteur numérique inutilisé sur le chemin correspond à votre indicatif ou à un indicatif répertorié dans votre fichier de configuration Xastir (ligne « RELAY_DIGIPEAT_CALLS », la valeur par défaut est « WIDE1-1 »). Cette option est recommandée uniquement pour les stations de base dans les régions où il y a peu d'autres stations de répéteurs numériques. Consultez un groupe local pour connaître le meilleur réglage pour votre région. Cette option est nécessaire uniquement si vous n'utilisez pas d'autre logiciel effectuant cette fonction, tel que aprsdigi ou DIGI_NED. Vous pouvez modifier manuellement le fichier de configuration Xastir lorsque Xastir n'est pas en cours d'exécution afin de modifier cette chaîne pour qu'elle corresponde à vos recommandations locales. Aux États-Unis, « WIDE1-1 » est le paramètre recommandé. Saisissez le nom du périphérique AX.25 que vous avez spécifié dans le fichier axports pour ce périphérique. Le champ Commentaire vous permet de définir un nom convivial ou un commentaire pour le port. Choisissez le mode de fonctionnement IGate approprié pour ce périphérique. Vous pouvez avoir plusieurs périphériques TNC et cette option peut être différente pour chaque périphérique. Si vous n'utilisez pas d'IGate, laissez l'option par défaut « Désactiver ». Saisissez jusqu'à trois chemins UNPROTO. Xastir prendra en compte la partie XX VIA du chemin UNPROTO. Trois chemins sont autorisés afin que votre signal soit entendu même dans de mauvaises conditions. Xastir parcourra successivement chaque chemin configuré, à raison d'un par transmission. Si vous êtes proche d'un relais numérique (digipeater), un simple WIDE2-2 peut être un bon choix. Si vous utilisez une faible puissance d'émission et/ou êtes éloigné d'un relais numérique, WIDE1-1,WIDE2-2 peut être plus efficace. Si vous connaissez l'indicatif de votre relais numérique le plus proche, vous pouvez utiliser XXXCALL,WIDE2-2. La plupart d'entre vous n'auront besoin que d'un seul chemin. Si vous êtes dans une zone isolée et que votre signal a du mal à passer, vous pourriez en avoir besoin de plusieurs. Renseignez-vous auprès d'un groupe local pour savoir quel chemin est le plus adapté à votre région. Si aucun chemin n'est configuré, le chemin par défaut sera WIDE2-2. Si vous utilisez la fonction IGate vers la radiofréquence (RF), vous pouvez spécifier un chemin particulier pour les paquets que vous envoyez en RF. Si vous laissez ce champ vide, les chemins UNPROTO mentionnés ci-dessus seront utilisés. Si les chemins UNPROTO sont également vides, WIDE2-2 sera utilisé. REMARQUE : Pour utiliser les périphériques AX.25 avec Xastir, vous devez exécuter le programme en tant que « root ». Si vous souhaitez exécuter Xastir avec un autre utilisateur, vous pouvez définir le bit SUID sur le fichier exécutable de Xastir. Veuillez consulter le fichier INSTALL pour plus d'informations ; la version actuelle de Xastir abandonne les privilèges supplémentaires, mais n'a pas fait l'objet d'un audit de sécurité. L'utilisation de cette manière dans un environnement multi-utilisateur se fait à vos propres risques ! HELP-INDEX>Configuration des appareils GPS série Configuration des appareils GPS série Définissez le port série de votre récepteur GPS. Les valeurs courantes sont /dev/ttyS0 (COM1) ou /dev/ttyS1 (COM2). Le champ « Commentaire » vous permet d'attribuer un nom ou un commentaire au port. L'option « Activer au démarrage » indique à Xastir de rechercher cet appareil et d'établir la communication avec lui au lancement du programme. L'option « Régler l'horloge system sur celle du GPS » indique à Xastir de tenter de synchroniser l'horloge du système avec le signal horaire de haute précision du récepteur GPS. Cette opération nécessite les privilèges d'administrateur sur la plupart des systèmes. Définissez ensuite le débit en bauds dans les paramètres du port, et les paramètres dans « StyleType du port ». Le paramètre « Type du port » 8N1 correspond à 8 bits de données, aucune parité et 1 bit d'arrêt. 7E1 correspond à 7 bits de données, parité paire et 1 bit d'arrêt. 7O1 correspond à 7 bits de données, parité impaire et 1 bit d'arrêt. Ces paramètres doivent correspondre à ceux de votre GPS. La plupart des récepteurs GPS utilisent 4800 bauds et 8,n,1. HELP-INDEX>Configuration des appareils GPS en réseau Configuration des appareils GPS en réseau Si vous devez partager les données GPS avec différents programmes ou machines, cette option est la plus appropriée. Xastir fonctionne avec gpsd, ce qui permet à plusieurs connexions de partager vos données GPS. Définissez le nom d'hôte (ou l'adresse IP) et le numéro de port de l'hôte gpsd sur votre réseau. Le champ « Commentaire » vous permet d'attribuer un nom convivial ou un commentaire au port. L'option « Activer au démarrage » indique à Xastir de rechercher cet appareil et d'établir la communication avec lui au lancement du programme. L'option « Reconnexion sur erreur réseau? » indique à Xastir de tenter de se reconnecter en cas d'interruption du flux de données. L'option « Régler l'horloge système sur celle du GPS ? » indique à Xastir de synchroniser l'horloge du système avec le signal horaire de haute précision du récepteur GPS. Cette opération nécessite les privilèges administrateur sur la plupart des systèmes. HELP-INDEX>Configuration du serveur Internet Configuration du serveur Internet Les serveurs Internet vous permettent d'envoyer et de recevoir des données dans le monde entier. Sélectionner « Activer au démarrage » indique à Xastir de rechercher cet appareil et d'établir la communication avec lui au lancement du programme. Sélectionner « Permettre transmission » indique à Xastir que toutes les données Internet sortantes peuvent être envoyées à cet appareil. Saisissez le nom d'hôte (ou l'adresse IP) et le numéro de port du serveur Internet que vous souhaitez contacter. Saisissez un mot de passe valide pour valider votre connexion ; cela permettra la transmission de vos données via une passerelle IGate. Si vous n'avez pas de mot de passe, utilisez le programme « callpass » fourni pour en générer un. Notez que les mots de passe dépendent des indicatifs d'appel. Depuis le répertoire src, la commande « make callpass » devrait créer l'exécutable s'il n'est pas déjà compilé. Saisissez les paramètres de filtrage. Cela envoie un message spécial au serveur demandant que les données soient filtrées d'une certaine manière. Le format exact de ce champ est entièrement spécifié ; veuillez consulter APRSSIG pour plus d'informations. Le champ « Commentaire » vous permet de définir un nom ou un commentaire pour le port. Sélectionner « Reconnexion sur erreur réseau? » indique à Xastir de tenter de se reconnecter lorsque le flux de données est interrompu. HELP-INDEX>Configuration d'une station météo série Configuration d'une station météo série Définissez le périphérique du port série pour votre station météo. Les valeurs courantes /dev/ttyS0 (COM1) ou /dev/ttyS1 (COM2) peuvent être utilisées. Le champ « Commentaire » vous permet de définir un nom ou un commentaire pour le port. En sélectionnant « Activer au démarrage », Xastir recherchera ce périphérique et établira la communication avec celui-ci au lancement du programme. Définissez ensuite le débit en bauds dans les paramètres du port, et les paramètres dans le style du port. Le style de port 8N1 correspond à 8 bits de données, aucune parité et 1 bit d'arrêt. 7E1 correspond à 7 bits de données, parité paire et 1 bit d'arrêt. 7O1 correspond à 7 bits de données, parité impaire et 1 bit d'arrêt. Ces paramètres doivent correspondre à ceux de votre station météo. L'option « Type de données » vous permet de spécifier le type de données série que le programme recherchera. La fonction de détection automatique recherche d'abord les données météorologiques au format binaire, comme celles utilisées par la station Radio Shack WX-200. Si aucune donnée binaire n'est trouvée dans le flux, Xastir recherchera une station météo de type ASCII (comme Peet Bros.). Définissez maintenant le facteur de correction du pluviomètre. Xastir exige que le pluviomètre fournisse des données par incréments de 0,01 pouce. Si l'unité fournit des données par incréments de 0,1 pouce ou 0,1 millimètre, une correction doit être spécifiée pour obtenir des mesures précises. HELP-INDEX>Configurer une station météo en réseau Configurer une station météo en réseau Xastir peut utiliser des serveurs de données météorologiques tels que wx200d. wx200d permet plusieurs connexions réseau, partageant ainsi les données météorologiques avec plusieurs programmes ou ordinateurs. Saisissez le nom d'hôte (ou l'adresse IP) et le numéro de port du serveur de données météorologiques que vous souhaitez contacter. Le champ « Commentaire » vous permet d'attribuer un nom convivial ou un commentaire au port. L'option « Activer au démarrage » indique à Xastir de rechercher cet appareil et d'établir la communication avec lui au lancement du programme. L'option « Reconnexion sur erreur réseau? » indique à Xastir de tenter de se reconnecter si le flux de données est interrompu. Comme précédemment, le type de données remplace la détection automatique. Définissez maintenant le facteur de correction du pluviomètre. Xastir exige que le pluviomètre affiche les précipitations par incréments de 0,01 pouce. Si l'appareil affiche les précipitations par incréments de 0,1 pouce ou de 0,1 millimètre, une correction doit être spécifiée pour obtenir des mesures précises. HELP-INDEX>Configuration d'une connexion AGWPE Configuration d'une connexion AGWPE Xastir peut utiliser une interface réseau AGWPE fonctionnant sous Windows comme interface TNC. Il prend également en charge la sécurité par identifiant et mot de passe intégrée à AGWPE, mais vous devez configurer le compte dans l'application AGWPE en utilisant votre indicatif d'appel comme nom d'utilisateur, en majuscules. Par exemple : « AB7CD ». Les autres options sont décrites dans les sections relatives aux interfaces TNC série et aux interfaces réseau. HELP-INDEX>Configurer une connexion à une base de données SQL Configurer une connexion à une base de données SQL [Expérimental] Xastir peut, à titre expérimental, stocker et récupérer les données des stations à partir d'une base de données MySQL ou d'une base de données PostgreSQL + PostGIS. Consultez la section « OPTIONNEL : Expérimental. Ajouter la prise en charge des bases de données SIG » dans le fichier INSTALL pour plus d'informations. Les données des stations et des objets sont stockées sous forme de données spatiales et peuvent être récupérées par d'autres applications SIG. Par exemple, Xastir peut écrire les emplacements des stations dans une base de données PostGIS, à partir de laquelle elles peuvent également être visualisées à l'aide de QGIS. Les connexions aux bases de données SQL permettent également la persistance des données entre les sessions Xastir. Tous les aspects de la prise en charge des bases de données spatiales, y compris les structures de base de données, sont actuellement expérimentaux et peuvent être modifiés à tout moment. Vous pouvez configurer plusieurs connexions à des bases de données SQL, mais une seule doit être active à la fois. Avant de créer une connexion à une base de données dans Xastir, vous devrez créer une base de données à laquelle vous connecter, créer un ensemble de tables appropriées (voir les scripts db_gis_xxxxx.sql dans le répertoire scripts) et ajouter un utilisateur avec un mot de passe et les droits d'accès à la base de données. Pour les bases de données PostGIS, vous devrez peut-être également configurer l'utilisateur de manière appropriée dans pg_hba.conf. Les options de configuration de la boîte de dialogue de la base de données SQL incluent : Base de données : MySQL (lat/long) pour les très anciennes bases de données MySQL, PostGIS pour PostgreSQL + PostGIS, et MySQL (Spatial) pour les bases de données MySQL actuelles. Avec les tables pour : Actuellement, seul Xastir est pris en charge. Avant de créer une connexion à une base de données dans Xastir, vous devrez créer une base de données à laquelle vous connecter, créer un ensemble de tables approprié (voir les scripts db_gis_xxxxx.sql dans le répertoire scripts) et ajouter un utilisateur avec un mot de passe et les droits d'accès à la base de données. Pour les bases de données PostGIS, vous devrez peut-être également configurer correctement l'utilisateur dans pg_hba.conf. Les options de configuration de la boîte de dialogue de la base de données SQL incluent : Base de données : MySQL (lat/long) pour les très anciennes bases de données MySQL, PostGIS pour PostgreSQL + PostGIS, et MySQL (Spatial) pour les bases de données MySQL actuelles. Avec les tables pour : Actuellement, seul le schéma simple de Xastir est pris en charge - une table plate très basique contenant des informations minimales sur les stations. Hôte : Adresse IP ou nom d'hôte du serveur de base de données, la valeur par défaut est localhost. Port : La valeur par défaut est 3306 pour MySQL et 5432 pour PostgreSQL. La base de données peut être sur un serveur distant, mais le port approprié devra être ouvert dans les pare-feu. Nom d'utilisateur : Peut être unique à votre base de données, par exemple xastir_user Mot de passe : Unique à votre base de données. Nom du schéma : Nom de votre base de données. par exemple xastir Socket MySQL : vérifiez my.cnf ou mysql --help | grep socket Laissez vide pour les bases de données PostGIS. Reconnexion en cas de panne réseau : [Non encore implémenté] Les valeurs par défaut de MySQL et PostGIS fournies par les boutons peuvent être correctes ou non pour votre base de données. Trois options contrôlent le comportement de l'interface de la base de données SQL : Activer au démarrage : Tente de se connecter à cette base de données et de commencer à stocker les données des stations dès le démarrage de Xastir (si l'option « Stocker les données entrantes » est également sélectionnée). Stocker les données entrantes : Stocke chaque rapport de station (y compris les objets et les éléments) sous forme d'enregistrement dans la base de données. Toutes les stations entendues sur toutes les interfaces seront stockées dans la base de données - si vous êtes connecté à des flux Internet et que vous laissez Xastir en fonctionnement, cela peut facilement représenter un million d'enregistrements par jour. Charger les données au démarrage : Récupère toutes les données des stations de la base de données lors du redémarrage de Xastir. Actuellement, c'est le seul moyen de récupérer des données persistantes à partir d'une base de données. Tentera de se connecter à la base de données et de récupérer les données indépendamment des paramètres « Activer au démarrage » ou « Stocker les données entrantes ». En raison d'erreurs d'arrondi et de conversion, les stations non mobiles peuvent se déplacer légèrement. La zone « Dernière erreur » peut contenir ou non un message d'erreur permettant d'identifier les problèmes de connexion. Lorsque Xastir ne parvient pas à se connecter à une base de données, l'interface affiche « ERREUR » dans la liste des interfaces, et la dernière erreur peut être affichée ici. L'exécution de Xastir depuis la console et l'observation des messages d'erreur qui y apparaissent, ou l'exécution de Xastir depuis la console avec l'option `xastir -v1`, peuvent aider à identifier la cause des problèmes de connexion, tout comme l'examen des journaux d'erreurs de la base de données. Vous ne pourrez configurer une interface de base de données SQL que si vous avez compilé Xastir avec la prise en charge du SGBD correspondant (--with-mysql ou --with-postgis). HELP-INDEX>Table des symboles Table des symboles Symbole Groupe / Groupe \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat Xastir-Release-2.2.4/help/help-German.dat0000664000175000017500000026075115151324131017115 0ustar hibbyhibbyHELP-INDEX>Einfhrende Worte / Lizenzbestimmungen Einfhrende Worte / Lizenzbestimmungen Fr die aktuellsten Informationen und genauere Installationshinweise lesen sie bitte die README Datei im Xastir Hauptverzeichnis. Beachten Sie auch die Dateien LICENCE und COPYING fr weitere Informationen. Bitte denken sie daran, da dieses Programm fr den Einsatz im Amateurfunk bestimmt ist. In Deutschland mu man im Besitz eines Funkzeugnises sein, um auf Amateurfunkfrequenzen senden zu drfen. Informationen zum Erwerb eines Funkzeugisses findet man beim Amateurfunkclub DARC http://www.darc.de. Auch in anderen Lndern gelten hnliche Bestimmungen, die zu beachten sind. Die Entwicklung der Software und die Dokumentation erfolgte zunchst in Englisch, so da im Zweifelsfall die englische Version aktueller sein knnte. Die vorliegende deutsche Hilfedatei wurde von DK7IN bersetzt. Korrekturen und Anregungen bitte an xastir@dk7in.de LIZENZBESTIMMUNGEN fr XASTIR: XASTIR steht unter der GNU Lizenz, im Folgenden der englische Wortlaut. Die Details der GNU-Lizenz finden sich in der Datei LICENCE. XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group 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. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA Weitere Informationen zum Programm findet man unter: http://www.xastir.org http://github.com/Xastir/Xastir Es gibt einige Mailinglisten zu XASTIR. Melden sie sich zu einer oder beiden unter http://www.xastir.org an, um die neuesten Diskussionen rund um XASTIR zu verfolgen. Weitere Informationen zur GNU Lizenz finden sich auf: http://www.gnu.org Informationen ber Freie Software in deutscher Sprache finden Sie bei der Free Software Foundation Europe http://fsfeurope.org/index.de.html HELP-INDEX>Willkommen! und Anmerkungen der Autoren Willkommen! und Anmerkungen der Autoren XASTIR (X-Window Amateur Station Tracking and Information Reporting) XASTIR ist ein APRS(tm)-Programm, das als Open Source frei benutzt und an andere weitergegeben werden darf. Das Programm befindet sich momentan im Entwicklungsstadium und sollte nicht als fertiges Produkt angesehen werden! Mit ihrer Mitarbeit kann dieses Programm besser werden. Wenn sie also Programmiererfahrung haben, oder Dokumentation schreiben knnen, knnen wir ihre Hilfe gebrauchen. Wir haben eine Menge Ideen aber nur begrenzte Zeit. Wenn sie also denken, einen Beitrag leisten zu knnen, lassen sie es uns wissen! APRS[tm] ist ein Warenzeichen von Bob Bruninga, seine Homepage ist "http://web.usna.navy.mil/~bruninga/aprs.html" Beachten Sie bitte, da sehr viel Information zu APRS(tm) in der von Bob Bruninga geschriebenen Dokumentationen zu APRSdos enthalten ist. Eine weitere Informationsquelle ist die von http://www.tapr.org als PDF-Dokument erhltliche APRS Spezifikation. HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Der erste Aufruf von Xastir Der erste Aufruf von Xastir Beim ersten Start von Xastir sollten sie das Programm aus einem Terminalfenster heraus aufrufen, um mgliche Fehlermeldungen sehen zu knnen. Da auf den meisten Systemen der Pfad so eingerichtet ist, da Programme in /usr/local/bin gefunden werden, reicht es am Prompt "xastir &" einzugeben. Auf anderen Systemen mu "/usr/local/bin/xastir &" eingegeben werden, um das Programm zu starten. Das '&' sorgt dafr, da Xastir im Hintergrund gestartet wir, so da das Terminalfenster noch anderweitig verwendet werden kann. Sie knnen beim Aufruf auch gleich die Sprache whlen. Um die Sprache zu ndern, rufen sie Xastir mit der Option -l auf: xastir -lGerman Weitere Mglichkeiten sind: xastir -l Dutch xastir -l English xastir -l French xastir -l Italian xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish Die so gewhlte Sprache wird in der Konfigurationsdatei des Benutzers gespeichert und auch beim nchsten Aufruf ohne diese Option verwendet. Bei einem neu installierten Xastir ist die Voreinstellung Englisch bis zu einer nderung mit dieser Option. Die Menus am oberen Rand knnen auch mit Tastenkrzeln erreicht werden. Diese funktionieren gegebenenfalls nicht, wenn NumLock eingeschaltet ist. Vor der Benutzung mu Xastir und einige Schnittstellen konfiguriert werden. Die Schnittstellenkonfiguration ist detailliert in der Hilfe unter "Schnittstellen" beschrieben. HELP-INDEX>Stationsdaten Stationsdaten Klicken sie auf Datei, Einstellungen, dann auf Meine Stationsdaten Tragen sie ihr Amateurfunk-Rufzeichen ein. Tragen sie die Position ihrer Station ein, wenn sie Xastir nicht zusammen mit einem GPS-Empfnger einsetzen. Sie knnen ihre ungefhre Position auch mit einer Karte in Xastir bestimmen indem sie die Maus auf der Karte plazieren und die Position in der Statuszeile ablesen. Wenn sie einen GPS-Empfnger haben knnen sie diesen Schritt berspringen und stattdessen spter den GPS-Empfnger einrichten. Whlen sie ein Symbol fr ihre Station, hierzu ist die Angabe der Gruppe und des eigentlichen Symbolzeichens erforderlich. Sie knnen dies manuell eintragen, oder nach Drcken auf Auswahl aus einer grafischen Symbolbersicht auswhlen. Es stehen zwei Gruppen von Symbolen zur Verfgung. Eine Beschreibung der Symbolbedeutung findet sich im Hilfetext "Symboltabelle". Fr einige Symbole der sekundren Gruppe kann auch ein Overlay spezifiziert werden. Hierbei wird das Symbol zusammen mit dem Overlay-Zeichen dargestellt, z.B. ein Autosymbol mit der Zahl 1. Um Overlays zu nutzen mssen sie ein Symbol der sekundren Gruppe whlen und das gewnschte berlagerungszeichen in das Feld Gruppe/Overlay eintragen. Nur Zahlen und Grobuchstaben sind als Overlay zulssig. Nach den APRS-Spezifikationen kann nicht jedes Symbol berlagert werden, aber Xastir erzwingt dies nicht, wie mglicherweise andere Programme. Beachten sie, da bisher auch nicht alle Symbole belegt sind und manche eventuell nicht ganz den APRS-Spezifikationen entsprechen. Tragen sie als nchstes die Daten fr Leistung, Hhe, Gewinn und Vorzugsrichtung fr ihre Station ein. Es ist eine sinnvolle Information wird aber nicht unbedingt bentigt. Whlen sie einfach "Kein PHG", wenn sie diese Daten nicht aussenden wollen. Diese Einstellungen geben eine grobe Vorstellung von der Reichweite ihrer Station. Whlen sie die Werte, die den ihren am nchsten kommen. Eine andere Mglichkeit wre es, stattdessen die Reichweite RNG in Meilen im Kommentar zu spezifizieren. Fr Details ziehen sie bitte die APRS-Spezifikationen zu Rate. Benutzen sie hier bitte die nicht die Hhe ber dem Boden oder Meereshhe, sondern die Hhe gegenber dem durchschnittlichen Gelnde. Die Angabe ist in Fu, Meter mssen mit 3,28 multipliziert werden. Als Gewinn tragen sie den Antennengewinn in dBi ein. Anmerkung: Die Angabe des Gewinns ist primr fr Vertikalantennen gedacht, fr Beams sollten kleinere Werte eingetragen werden. Die Grund hierfr ist, da bei gesetzter Vorzugsrichtung, die Ellipse fr die Reichweite nur um ein Drittel in die angegebene Richtung vergrert wird. Wird der Gewinn eines Beams grer angegeben, so wird nur die Reichweitenmarkierung unrealistisch gro, statt da die deren Richtwirkung erhht wrde. Bei der Angabe einer Vorzugsrichtung ihrer Antenne wren z.B. 90 eine Antenne, die nach Osten weist. Geben sie einen Kommentar ein, dies ist nicht notwendig, erlaubt aber die bermittlung sinnvoller Informationen, wie z.B. den Namen und die E-Mail-Adresse. Es wird zusammen mit den Positionsmeldungen bertragen. Die Positionsverschleierung erlaubt ihnen einszustellen, wie genau ihre Position bermittelt wird. Bei "Keine" werden die exakten eingetragenen oder vom GPS empfangenen Daten ausgesendet. Die anderen Mglichkeiten setzen die bermittelte Position irgendwo in den gewhlten Bereich. Einige Stationen, die nicht ganz den Spezifikationen entsprechen, verstehen jedoch keine Positionsverschleierung, so z.B. auch findu.com. Bei einem Klick auf OK werden die nderungen gesichert, bei Abbrechen bleiben die vorherigen Einstellungen erhalten. HELP-INDEX>Grundeinstellungen Grundeinstellungen Klicken sie auf Datei, Einstellungen, dann auf Grundeinstellungen Auf dieser Seite werden einige Standardwerte fr den Programmablauf eingestellt. Alte Stationen werden nach einiger Zeit schemenhaft dargestellt und die zugehrigen Spuren gestrichelt. In der ersten Zeile wird festgelegt, nach welcher Zeit eine Station nur noch schemenhaft angezeigt wird. In der nchsten Zeile wird festgelegt, nach welcher Zeit eine Station ganz vom Bildschirm verschwindet. Nach dem Doppelten dieser Zeit wird die Station dann auch aus den internen Datenbanken gelscht. Die dritte Zeile legt fest, in welchen Abstnden die eigene Position bermittelt wird. Fr Feststationen sind 30 Minuten ein guter Wert, es sollten auf alle Flle nicht unter 10 Minuten sein. Bei Mobilstationen kann ein krzeres Intervall sinnvoll sein. Diese Einstellung wird auch verwendet, um Objekte und Items wiederholt zu senden. Versuchen sie hier eine sinnvolle Einstellung zu finden, um nicht zu viel unntigen Verkehr zu produzieren. GPS Zeit legt das Zeitintervall fest, nach dem nach neuen GPS Daten geschaut wird. Diese Option ist fr Stationen mit gemeinsamen Zugriff auf TNC und GPS ber ein HSP-Kabel. Mit dem Sendeformat der Station wird festgelegt, welche Art von Paketen die Station sendet. IGate Options ermglicht die Errichtung einer Brcke zwischen Internet und Funk. Diese Option sollte mit Vorsicht benutzt werden. Als Fumkamateur sind sie selbst dafr verantwortlich, was aus dem Internet kommt und ber ihre Funkanlage ausgesendet wird. Sie mssen auerdem bei jeder Schnittstelle eine IGate-Einstellung machen, damit dies funktioniert. Wenn sie wollen, da ihr IGate NWS Wetterwarnungen ber Funk weitergibt, mssen sie eine Datei ~/.xastir/data/nws-stations.txt anlegen, in der alle Stationen aufgefhrt sind (wie z.B. "PHISVR"), deren Daten sie ber Funk weiterreichen wollen. Bei Aktivierung von "Sende komprimierte Position" wird die Position in einem neueren, komprimierten Format gesendet. Hierdurch werden die gesendeten Pakete krzer, so da die Kapazitt des APRS(tm) Netzwerks steigt. Die maximale Auflsung der gesendeten Position ist ebenfalls hher. Allerdings knnen einige ltere Programme, einschlielich krzlich erschienener Versionen von WinAPRS, dieses Format noch nicht dekodieren. Auch findu.com kann damit Probleme haben. Wenn "Sende Wetter Rohdaten" gewhlt wurde, werden auch Pakete gesendet, die unverarbeitete Wetterstationsdaten enthalten. Dies ist ntzlich fr Wetterstationen mit ASCII-Daten, wie Peet Bros. Wetterstationen. Sie knnen auerdem Alternatives Netz aktivieren, und dort ein eigenes Krzel eintragen. Alternatives Netz erlaubt ihnen damit, ein privates APRS-Netzwerk aufzubauen, mit Stationen, die ebenfalls Alternatives Netz aktiviert haben und das gleiche Rufzeichen benutzen. HELP-INDEX>Audio Alarm Audio Alarm Klicken sie auf Datei, Einstellungen, dann Audio Alarm. Um diese Option zu nutzen, bentigen sie eine Soundkarte und ein Programm, das Audiodateien im WAV-Format abspielt. Tragen sie als Kommando dieses Programm ein und eventuell bentigte Kommandozeilen- parameter. Das ganze funktioniert natrlich nicht, wenn die einzige Soundkarte im System fr ein Soundmodem benutzt wird... Fr verschiedene Ereignisse kann eine Datei eingetragen werden, z.B. eine wav-Datei, die abgespielt werden soll. Bei einigen Ereignissen knnen zustzliche Parameter gendert werden. Fr jedes Ereignis kann einzeln festgelegt werden, ob eine akustische Meldung erfolgen soll. Momentan steht zur Verfgung: Abspielen einer Ansage beim Auftauchen einer neuen Station Abspielen einer Ansage bei einer neuen Nachricht Abspielen einer Ansage, wenn Daten von einer Station empfangen werden, die sich innerhalb einer min/max Entfernung gem den Annherungs-Einstellungen befindet Abspielen einer Ansage, wenn Daten von einer Station ber TNC empfangen werden, die sich innerhalb einer min/max Entfernung gem den Bandffnungs-Einstellungen befindet Abspielen einer Ansage bei einer Wetterwarnung HELP-INDEX>Sprachausgabe Sprachausgabe Klicken sie auf Datei, Einstellungen, dann Sprachausgabe. Um diese Option zu nutzen, bentigen sie neben einer Soundkarte die 'Festival' Sprachsynthese Software. Installieren sie Festival und starten sie es als Server bevor sie Xastir aufrufen. Das Kommando hierfr heit blicherweise "festival --server &". Nachdem Festival installiert ist, kann Xastir fr folgende Flle eine Sprachausgabe vornehmen: o Ansagen des Rufzeichens einer neuen Station. o Ansagen, da eine neue Nachricht eingetroffen ist. o Den Text einer Nachricht vorlesen. o Eine Ansage, wenn Daten von einer Station empfangen wurden, die sich innerhalb einer min/max Entfernung gem den Annherungs-Einstellungen (siehe Audio Alarm) befindet. o Eine Ansage, wenn Daten von einer Station ber TNC empfangen werden, die sich innerhalb einer min/max Entfernung gem den Bandffnungs-Einstellungen (siehe Audio Alarm) befindet. o Die Ansage einer Wetterwarnung ist bisher noch nicht verfgbar. Informationen zu Festival erhalten sie ber: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Maeinheiten Maeinheiten Als Standardeinstellung wird das metrische System mit mm, cm, m, km, km/h, usw. verwendet. Wenn sie englische Maeinheiten bevorzugen, klicken sie auf Datei, Einstellungen und aktivieren sie Englische Mae, um Zoll, Fu, mph, usw. anzuzeigen. HELP-INDEX>Einstellungen sichern Einstellungen sichern ber Datei, Einstellungen, Einstellungen sichern knnen alle vorgenommenen Einstellungen sofort in der Konfigurationsdatei gespeichert werden. Aber auch beim Verlassen des Programms werden die Einstellungen gespeichert. HELP-INDEX>Statuszeile Statuszeile Am unteren Rand des Bildschirms werden verschiedene Statusmeldungen dargestellt: Im ersten Feld (links) werden allgemeine Statusmeldungen angezeigt, sie werden nach kurzer Zeit wieder gelscht. Das zweite Feld zeigt bei Mausbewegungen die aktuelle Position auf der Karte unter dem Mauszeiger an. Ein drittes Feld zeigt die Anzahl der insgesamt empfangenen Stationen in der Datenbank an. Das vierte Feld zeigt den aktuellen Zoomstatus an und ein "Tr", wenn eine Station verfolgt wird (Tracking). Das letzte Feld zeigt mit Symbolen den Status fr jedes Gert an, wobei die Schnittstellen von links nach rechts (0 bis 9) gezhlt werden. Der Status wird vertikal in drei Bereiche unterteilt. Oben Art des Gerts, in der Mitte der Datenflu und unten der Betriebszustand. Die Art des Gerts kann anhand der Farbe unterschieden werden. Blau steht fr die verschiedenen TNC Gerte, grn sind GPS-Empfnger, gelb Internet Server und orange Wetterstationen. In der Mitte zeigt ein links weisender Pfeil empfangene Daten an, ein rechtsweisender Pfeil steht fr ber dieses Gert gesendete Daten. Ein grnes Rechteck im unteren Bereich zeigt, da diese Schnittstelle aktiviert ist. Ein rotes Rechteck deutet auf eine aktive Schnittstelle hin, bei der aber ein Fehler aufgetreten ist. Anderenfalls wird nichts angezeigt, wenn die Schnittstelle nicht aktiv ist. HELP-INDEX>Verschieben der Karte und Mauszeiger-Menu Verschieben der Karte und Mauszeiger-Menu Das Verschieben der Karte ist sehr einfach, die Geschwindigkeit des Bildaufbaus hngt jedoch von der Rechnerleistung und dem Umfang der zu ladenden Kartendaten ab. Zoomen: Man kann in der Karte zoomen, indem man auf der Karte mit der rechten Maustaste klickt (und diese gedrckt hlt). Es erscheint ein PopUp-Menu, mit der Mglichkeit, hinein oder heraus zu zoomen, oder auf eine der vordefinierten Skalierungsfaktoren zu wechseln. Die Zoom-Funktionen zentrieren die Karte gleichzeitig an dem Punkt, an dem die rechte Maustaste gedrckt wurde. Bei "Zoomebenen" erhlt man ein Untermenu. Die Skalierungen 1-64 sind fr die nhere Umgebung, whrend 256 und hher grere Bereiche darstellen. Je kleiner die Zahl, umso lokaler wird der Kartenausschnitt. Ein schnelleres Hineinzoomen in einen Kartenausschnitt kann mit der Maus erreicht werden, wenn man auf mit der linken Maustaste auf eine Ecke des gewnschten Ausschnitts klickt, bei gedrckter Maustaste zur gegenberliegeden Ecke fhrt und dort die Taste loslt. Die Karte wird in der Mitte des gewhlten Ausschnitts neu zentriert, fr die Skalierung wird nur die Hhe des Ausschnitts verwendet, die Breite wird der Bildschirmgre entsprechend angepat. Die Schaltknpfe "Messen" und "Bewegen" drfen hierfr nicht aktiviert sein. Weiterhin besteht die Mglichkeit die PgUp und PgDn Tasten zum Zoomen zu verwenden. Hierbei bleibt das Zentrum er Karte erhalten. Verschieben/Zentrieren: Die Karte kann bei gleicher Auflsung neu zentriert werden, indem man mit der linken Maustaste auf das neue Zentrum klickt. Beim Klicken mit der mittleren Maustaste wird die Karte neu zentriert, auerdem wird die Auflsung durch Herauszoomen auf die Hlfte reduziert. Ein Verschieben kann ber das Mauszeiger-Menu oder durch die Pfeile am oberen Bildschirmrand erfolgen. Die Karte wird nur um einen Teil der Bildschirmgre verschoben, so da gengend Daten bestehen bleiben, um sich wieder zurechtzufinden. Auch die Cursortasten verschieben die Karte. Informationen zum Mauszeiger-Menu: "Stationsinfo" versucht zunchst die Station zu finden, die der Stelle, an der die rechte Maustaste gedrckt wurde, am nchsten liegt. Befinden sich dort mehrere Stationen, so kommt zunchst ein PopUp-Fenster mit einer Stationsliste, aus der man die gewnschte whlen kann. Danach, oder wenn nur eine Station direkt in unmittelbarer Nhe ist, ffnet ein Fenster mit verschiedenen Daten zu dieser Station. Bei Mobilstationen mit vielen Daten kann dies auf langsamen Computern etwas Zeit bentigen. Um alte Stationen zu sehen, kann vorbergehend "Alte Daten zeigen" im Menu "Ansicht" eingeschaltet werden. ber den Menupunkt "Letzte Ansicht" kann der vorherigen Kartenausschnitt wieder hergestellt werden. Fr Informationen zu Objekten siehe den Hilfetext "Objekte und Items" HELP-INDEX>Objekte und Items Objekte und Items Eine Station kann verschiedene Objekte auf der Karte setzen, deren Position auch ber Funk an andere Stationen weitergegeben wird. Bei den Namen fr Objekte bestehen nicht so viele Einschrnkungen wie fr die Stationsnamen. Objekte und Items sind ziemlich das gleiche, sie werden manchmal fr etwas unterschiedliche Zwecke angewandt. Objekte werden oft fr bewegliche oder vernderliche Dinge eingsetzt, wie z.B. Wirbelstrme, whrend Items im Allgemeinen fr unbewegliche Dinge, z.B. eine Wasserstation, eingesetzt werden. Da Items von einigen APRS-Programmen nicht dekodiert werden knnen, werden aber oftmals auch unbewegliche Objekte verwendet. ber das Mauszeiger-Menu hat man Zugriff zu "Objekt Neu" und "Objekt ndern. Mageblich fr das Objekt ist dabei die Position des Mauszeigers bei Aufruf des Mauszeiger-Menus. Neben normalen Objekten mit einem Symbol an der Position gibt es noch spezielle Objekte. Flchenobjekte sind geeignet, wenn es darum geht einen greren Bereich auf der Karte zu markieren. Man kann damit auch Wege, Straen oder Grenzen zeichnen, ein Suchgebiet abstecken, oder wenn es sein mu auch ein Schachbrett um ber APRS zu spielen :-) Beachten sie, da Flchenobjekte nicht in allen APRS-Programmen implementiert sind und wenn, dann auch teilweise unterschiedlich dargestellt werden. Die anderen beiden, Signpost und Peil-Objekte werden weiter unten beschrieben. Objekte werden in den gleichen Abstnden wie die eigenen Stationsdaten, die in "Datei-Einstellungen-Grundeinstellungen" festgelegt sind, wiederholt ausgesendet, insgesamt bis zum Doppelten der ebenfalls dort definierten Anzeigezeit fr Stationen. Auch gelschte Objekte werden wiederholt gesendet, bis sie in der Datenbank auslaufen. Bei "Objekt Neu" wird die Position, an der das Mauszeiger-Menu geffnet wurde, als Vorgabe fr ein neu zu erstellendes Objekt verwendet. Nach Eingabe eines Namens kann man ein anderes Symbol fr das Objekt whlen, einen Kommentar eintragen und es ber das Menu ein neues Objekt oder Item erstellen. Bei "Objekt ndern" erhlt man einen hnlichen Dialog, bei dem allerdings die Daten des Objekt an der Position des Mauszeigers bereits eingetragen sind. Einige Daten, wie z.B. der Objektname, knnen nicht gendert werden. Hierber ist auch das Lschen eines Objekts mglich. Objekte und Items knnen auch mit der Maus auf der Karte verschoben werden, wenn der Schaltknopf "Bewegen" auf der oberen Leiste aktiviert ist. Erluterung der einzelnen Eintrge im Objekt-Dialog: = Signpost-Objekt = Durch Aktivieren wird aus dem Objekt ein Signpost-Objekt, auf einem Hinweisschild knnen drei Zeichen dargestellt werden, die sichtbar werden, wenn an der betreffenden Position hineingezoomt wird. Hinweis: Das funktioniert SO noch nicht... = Flchenobjekt = Hierdurch wird das Objekt als ein Flchenobjekt definiert, zustzlich werden die unten erluterten Steuerfunktionen fr Flchenobjekte eingeschaltet. = Peil-Objekt = Hierbei handelt es sich um eine Peilmeldung, die mit dem DF-Symbol markiert wird. Sie knnen zwischen einer Meldung mit Rundstrahl- oder Richtantenne whlen und die spezifischen Daten eintragen. Nhere Details ber diese Techniken finden sich unter http://web.usna.navy.mil/~bruninga/dfing.html und in der APRSdos Dokumentation. = Name = Dies ist der Name des Objekts, der aus bis zu neun Zeichen bestehen kann, wobei auch Leerzeichen innerhalb des Namens zulssig sind. Beim ndern eines Objekts kann der Name nicht mehr gendert werden. Falls trotzdem erforderlich, mu das Objekt zunchst gelscht und dann mit neuem Namen neu erstellt werden. Wenn Sie das Objekt als Flchenobjekt, Signpost- oder Peil-Objekt definieren, wird der dann unntige Name gelscht. = Stations-Symbol = Whlen sie ein Symbol fr das Objekt, hierzu ist die Angabe der Gruppe und des eigentlichen Symbolzeichens erforderlich. Sie knnen dies manuell eintragen, oder nach Drcken auf "Auswahl" aus einer grafischen Symbolbersicht auswhlen. Es stehen zwei Gruppen von Symbolen zur Verfgung. Eine Beschreibung der Symbolbedeutung findet sich im Hilfetext "Symboltabelle". Bei Signpost-, Flchen- und Peil-Objekten lt sich das Symbol nicht ndern. = Position = Hier wird die Position des Objekts eingegeben. Wenn Sie ein neues Objekt erstellen, so wurde dort bereits die Position eingetragen, an der Sie mit der rechten Maustaste geklickt hatten, um das Mauszeiger-Menu aufzurufen. Wenn Sie das Objekt verschoben haben, so steht dort die neue Position. Sie knnen die Daten aber auch manuell eintragen, z.B. wenn Ihnen jemand eine Position ber Sprechfunk durchgegeben hat. = Allgemeine Optionen = Hier knnen Sie die Geschwindigkeit, die Bewegungsrichtung und die Hhe des Objekts eintragen. Bei einigen Objekten ist die Angabe von Geschwindigkeit und Richtung nicht mglich, die Felder sind dann in Grau dargestellt. = Signpost Text = Hier knnen Sie fr ein Signpost-Objekt den Text (ein bis drei Zeichen) angeben, der auf dem Hinweisschild erscheinen soll. Beachten Sie, da Xastir Signpost-Objekte momentan noch nicht richtig anzeigt. = Flchenobjekt = Flchenobjekte werden eingesetzt, um spezielle Teile einer Karte herauszuheben oder zustzliche Details zu zeichnen. Hierzu dienen die folgenden Eintrge: = Helle Farben = Wenn aktiviert, werden hellere, sonst dunklere Farben fr die Flchen verwendet. = Flchen fllen = Wenn markiert, werden die Flchen mit Objektfarbe gefllt, ansonsten wird nur die Umrandung dargestellt. = Objekt-Typ = Verschiedene geometrische Grundformen knnen hier gewhlt werden: Kreis/Ellipse, Linie nach rechts, Linie nach links, Dreieck, Rechteck = Objektfarbe = Hier wird die Farbe gewhlt in der das Objekt gezeichnet wird. Dies wird auch durch das Markieren von "Helle Farben" (siehe oben) beeinflut. Es stehen zur Verfgung: Schwarz, Blau, Grn, Cyan, Rot, Violett, Gelb, Grau = nach oben = Ausdehnung des Flchenobjekts nach oben in 1/100 Grad. = nach links = Ausdehnung des Flchenobjekts nach links in 1/100 Grad. = Korridor = Gibt die Breite eines Linienobjekts an und wird in Meilen spezifiziert. Denken Sie daran, Ihre Objekte zu lschen, wenn sie nicht mehr bentigt werden. Anderenfalls werden sie wiederholt gesendet und erscheinen auf dem Bildschirm anderer Stationen bis sie verfallen. HELP-INDEX>Listendarstellungen Listendarstellungen ber den Menupunkt "Zeige" knnen verschiedene Daten der Stationen meist in Form von Listen dargestellt werden. = Berichte = Berichte (bulletin boards) sind eine Mglichkeit, ber APRS Nachrichten und wichtige Ankndigungen an alle zu senden. Wenn Sie mit dem Internet verbunden sind, ist es sinnvoll, den Einzugsbereich auf wenige 100km einzustellen um so Berichte aus anderen Teilen der Welt zu ignorieren. Der Eintrag einer '0' im Feld Bereich bedeutet keinerlei Einschrnkungen, d.h. alle Berichte werden empfangen. Klicken Sie auf "neuen Bereich setzen" um den eingegebenen Wert zu bernehmen. Xastir untersttzt das Senden von Berichten momentan noch nicht. = Packet Radio = Hier werden die ber Packet Radio oder das Internet ankommenden Rohdaten dargestellt. Es kann gewhlt werden, ob nur Daten vom TNC, nur Daten aus dem Internet, oder beides angezeigt werden soll. = Mobilstationen = Dies ist eine Liste von Stationen, die sich bewegen, typischerweise also Mobilstationen. Die Bedeutung des Symbols wird dabei ignoriert, es wird nur festgestellt, ob sich die Station bewegt. Die angezeigte Information umfat neben der letzten bekannten Position auch Geschwindigkeit, Bewegungsrichtung, Hhe, Anzahl der empfangenen Pakete, Anzahl der sichtbaren Satelliten sowie Abstand und Richtung von unserer eigenen Station. = Alle Stationen = Hier wird eine Tabelle mit allen Stationen in alphabetischer Reihenfolge angezeigt. Es umfat auch die Anzahl der gehrten Pakete, die Zeit zu der die Station zuletzt gehrt wurde, den Pfad, den das letzte Paket genommen hatte, PHG und natrlich den Kommentar. = Lokale Stationen = Eine hnliche Tabelle wie zuvor, allerdings werden nur Stationen angezeigt, die ber den eigenen TNC gehrt wurden. = Letzte Stationen = Eine Liste mit allen Stationen in der Reihenfolge, in der sie gehrt wurden. Die zuletzt gehrten Stationen stehen oben am Beginn der Liste. Angezeigt wird wiederum die Anzahl der gehrten Pakete, die Zeit zu der die Station zuletzt gehrt wurde, den Pfad, den das letzte Paket genommen hatte, PHG und der Kommentar. = Wetterstationen = Diese Liste umfat nur APRS Wetterstationen mit deren Daten. Aufgefhrt werden Windgeschwindigkeit- und richtung, Geschwindigkeit von Ben, die Temperatur, die Luftfeuchtigkeit, den Druck, Regenmenge whrend der letzten Stunde, seit Mitternacht und whrend der letzten 24 Stunden. = Eigene Wetterdaten = Wenn eine eigene Wetterstation vorhanden ist und in Xastir konfiguriert wurde, so werden deren Wetterdaten hier angezeigt. = Wetterwarnung = Zeigt die empfangenen Wetterwarnungen des amerikanischen NWS an. = Nachrichten = Zeigt den Nachrichtenverkehr zwischen den verschiedenen Stationen solange das Fenster geffnet ist. Dies beinhaltet Quelle und Ziel, ber welche Schnittstelle sie lif und den Inhalt der Nachricht. ber "Bereich" kann die Anzeige auf Nachrichten von Stationen in der Umgebung beschrnkt werden, bei Eingabe von '0' werden alle Nachrichten angezeigt. = Laufzeit = Zeigt an, seit wie lange Xastir bereits luft. HELP-INDEX>Kartenauswahl und Einstellungen Kartenauswahl und Einstellungen = Kartenauswahl = Hiermit erhalten sie eine Liste aller Dateien im Kartenverzeichnis. Wenn sie einen Dateinamen markieren, so wird die Karte beim Klicken auf OK geladen und angezeigt, wenn sie in den aktuellen Bildauschnitt fllt. Sie knnen mehrere Karten gleichzeitig auswhlen. Abbruch verwirft die nderungen in der Kartenauswahl. Es gibt auch Buttons um alle Karten gleichzeitig abzuwhlen oder bestimmte Kartentypen zu laden. = Ausschnitte = Genaueres siehe im Hilfetext zu "Gespeicherte Kartenausschnitten" = Objekt in Karte suchen = Hiermit erhalten Sie einen Dialog zur Suche eines bestimmten Objekts in einer GNIS Datei. Falls gefunden wird die Karte an dieser Stelle neu zentriert. Die zuletzt befragte GNIS-Datei wird beim nchsten Aufruf wiederum als Vorgabe gewhlt. = Alle Karten verbergen = Hiermit kann das Laden aller Karten vorbergehend verhindert werden. Dies ist vor allem dann vorteilhaft, wenn man die Karte oft verschiebt oder zoomt und der langsame Kartenaufbau dazwischen strend wirkt. Bei einem Neustart von Xastir ist diese Option immer ausgeschaltet. = Automatische Karte (An/Aus) = Falls eingeschaltet, wird jede Karte im Kartenverzeichnis oder einem Unterverzeichnis geladen, die fr den aktuell dargestellten Ausschnitt gltig ist. Sie knnen beliebig viele Uterverzeichnis-Ebenen unterhalb des Kartenverzeichnisses anlegen, die automatisch durchsucht werden. Alle Karten werden im dargestellten Ausschnitt berlagert. Die Reihenfolge hngt von der alphabetischen Sortierung ab, gegebenenfalls kann man Links auf andere Namen anlegen, um die Sortierung flexibler handhaben zu knnen. Wenn sie viele oder komplexe Karten haben, oder einen langsamen Computer, dann kann das Laden der Karten sehr lange dauern. Wenn diese Option ausgeschaltet ist, werden die in der Kartenauswahl markierten Karten geladen. = Gitter (An/Aus) = Wenn eingeschaltet wird ein Kartengitter mit, je nach Zoomebene, 10 Grad bzw. 1 Grad Abstand gezeichnet. = Ebenen (An/Aus) = Falls eingeschaltet, werden Details bei der Darstellung herausgefiltert wenn grere Bereiche durch herauszoomen dargestellt werden. Dies funktioniert nicht mit allen Karten, es verringert auch nicht die Ladezeit, sondern sorgt nur dafr, da der Bildschirm lesbar bleibt. Ein Beispiel hierfr sind Karten die aus den Tiger Line Karten von aprs.rutgers.edu erzeugt wurden. = Kartenbeschriftungen = Hiermit knnen Kartenbeschriftungen ein- oder ausgeschaltet werden, die in Karten im dosAPRS, WinAPRS, GNIS und ESRI Shapefile Format enthalten sind. = Flchen einfrben (An/Aus) = Diese Option legt das Einfrben bei Vektorkarten fest. In manchen Fllen ist es sinnvoll, die Fllung zu entfernen, um darunterliegende weitere Karten sehen zu knnen. Die Karten werden in alphabetischer Reihenfolge geladen, so da ein Umbenennen oder ein Link eine weitere Mglichkeit in diesem Fall darstellt. = Wetterwarnung Counties = Bei Wetterwarnungen des amerikanischen NWS knnen einzelne Counties, fr die eine Wetterwarnung vorliegt, eingefrbt werden. Dies kann hiermit gesteuert werden. = Hintergrundfarbe (An/Aus) = Ermglicht die Auswahl der bei transparenten Karten durchscheinenden Hintergrundfarbe. = Intensitt = Hiermit kann die Farbsttigung der Karte gesteuert werden. Dieser Menupunkt erscheint nur, wenn Xastir mit GeoTIFF-Untersttzung und/oder ImageMagick zusammen kompiliert wurde. = Textdarstellung = Ermglicht die Auswahl zwischen zwei verschiedenen Arten der Schriftdarstellung fr Stationsinformationen auf der Karte. = Mauszeiger-Menu = ffnet das Mauszeiger-Menu, das sonst beim Klick mit der rechten Maustaste erscheint. Eine Anmerkung zu Karten: Viele der zur Zeit erhltlichen Vektorkarten fr die USA sind mit dem NAD-27 Datum erstellt worden, whrend Xastir und andere APRS Programme das aktuelle WGS-84 Datum verwenden. Wenn man sehr weit auf einen kleinen Kartenausschnitt herein zoomt werden die Abweichungen durch das falsche Kartendatum deutlich. Bei den USGS Topographischen Karten wird die Datumsabweichung von Xastir korrigiert, so da Positionen hiermit im Allgemeinen genauer sind als mit anderen topographischen Karten. HELP-INDEX>Kartendateien und County-Daten fr Wetterwarnungen Kartendateien und County-Daten fr Wetterwarnungen Kartentypen Xastir kann mit den verschiedensten Kartentypen arbeiten. Alle DosAPRS-, WinAPRS- und MacAPRS-Karten werden untersttzt. Zustzlich untersttzt Xastir von Haus aus Karten im PocketAPRS-Format, Bezeichnungen aus GNIS- Dateien (Geographic Names Information System) und Karten im XPixmap- Grafikformat. Xastir kann so kompiliert werden, da externe Bibliotheken eingebunden werden knnen, um topographische Karten im GeoTIFF-Format und ESRI Shapefiles zu untersttzen. Die Fhigkeit mit Karten in den verschiedensten Grafikformaten umzugehen kann durch das Kompilieren mit ImageMagick-Untersttzung stark erweitert werden (siehe "http://www.imagemagick.org/www/formats.html"). Xastir untersttzt die Darstellung von Bereichen von Wetterwarnungen auf Karten, hierzu knnen die Daten im klassischen dosAPRS/WinAPRS-Format vorliegen, die Einbindung im neuen ESRI Shapefile-Format wird in Krze vollstndig sein. Einen Hinweis auf die Quellen von verschiedenen Kartenformaten finden Sie in der Datei README.1ST. Karten-Verzeichnisse Alle Kartendateien sollten unter /usr/local/share/xastir/maps auf Ihrm Computer gespeichert werden. Zur besseren Organisation und Trennung der Karten knnen sie dort auch beliebige Unterverzeichnisse anlegen. Bei der Kartenauswahl werden die Karten mit ihrem ralativen Pfad alphabetisch sortiert angezeigt. Symbolische Links knnen helfen, um die Reihenfolge gegebenenfalls zu ndern. Hinweise zur Installation und Organisation der Karten finden sich ebenfalls in README.1ST. Fr Karten im Pixelgrafikformat werden immer zwei Dateien bentigt, zum einen die Grafikdatei im .xpm Format (oder andere Formate bei ImageMagick-Untersttzung) und eine Kalibrierungsdatei (.geo). Das Standardgrafikformat ohne zustzliche Bibliotheken ist .xpm, um Platz zu sparen knnen diese Dateien aber auch mit gzip gepackt werden ("gzip map.xpm" erzeugt die komprimierte Datei "map.xpm.gz"). Dies wird von Xastir automatisch erkannt und beim Laden der Karte bercksichtigt. Sie knnen XView, Gimp, ImageMagick oder andere Programme benutzen, um Grafiken zu konvertieren, die als gif, jpg oder tiff-Dateien vorliegen, wenn Sie nicht ImageMagick hinzukompilieren wollen. Sollten Sie Probleme mit Karten im .xpm-Format haben, versuchen Sie zunchst, die Grafik in Gimp zu laden und wieder abzuspeichern, hierdurch werden alle, evtl. unbekannten, Farbnamen in Binrdarstellung umgewandelt. Die .geo-Datei ist eine Textdatei, die Kartenposition in der Welt festlegt. Zur Erluterung hier die Datei world1.geo: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Dieses einfache Beispiel besteht aus vier grundlegenden Komponenten. Die erste Zeile (FILENAME) legt die Grafikdatei fest, die fr diese Karte benutzt werden soll. Bei einer komprimierten .xpm-Datei ist die Angabe der Endung ".gz" optional. Wenn kein Pfad angegeben wird, wird die Grafikdatei im gleichen Verzeichnis wie die .geo-Datei gesucht. Unter FILENAME kann auch eine URL angegeben werden, unter der Xastir die Kartengrafik mittels wget herunterladen kann. Dies bedeutet, da so ziemlich jedes Bild, da ber HTTP oder FTP im Internet verfgbar ist, als Karte dienen kann. Die zweite Zeile ist eine Kommenarzeile, dies wird durch ein '#' als erstes Zeichen einer Zeile festgelegt. Die letzten beiden Zeilen binden x-y-Positionen in der Grafikdatei an Koordinaten (Lngen- und Breitengrade) in der realen Welt. Zwei solche Punkte werden bentigt und sie sollten fr eine hohe Genauigkeit mglichst weit auseinander in den Ecken der Grafikdatei liegen, z.B. oben links und unten rechts. Um eine solche Karte zu verwenden, whlen Sie in der Kartenauswahl die zugehrige .geo-Datei. Die Gre der Grafikdatei kann optional ebenfalls in der .geo-Datei angegeben werden: FILENAME Agnes_Mountain.xpm.gz # # X Y Lon Lat # ---- ---- ------------- ----------- TIEPOINT 0 0 -121.00120491 48.37481943 TIEPOINT 1337 1999 -120.87619806 48.24982052 # IMAGESIZE 1338 2000 Mit IMAGESIZE wird die Bildgre in Pixel angegeben. Xastir benutzt diese Information, um Karten, die nicht in den aktuell dargestellten Ausschnitt fallen, mglichst schnell aussortieren zu knnen. Wird dies nicht angegeben, mu Xastir die Grafikdatei zum Berechnen auf alle Flle immer laden. Wenn Xastir mit Untersttzung von ImageMagick kompiliert wurde, so stehen auer .xpm smtliche Grafikformate zur Verfgung, die von ImageMagick selbst oder seinen Bibliotheken untersttzt werden. Es gibt verschiedene "spezielle" .geo-Dateien, die von Xastir verwendet werden knnen: o Eine Datei mit dem Wort "FINDU" und einer weiteren Zeile "CALL " ldt historische Spurdaten der mit dem Call spezifizierten Station. Dies ist allerdings inzwischen ber das Stationsmenu einfacher zu bewerkstelligen. geoTIFF Karten sind ebenfalls eine Kombination aus zwei Dateien, einer .tif und einer .fgd Datei. Die .tif-Datei enthlt die eigentlichen Kartendaten, die .fgd-Kalibrierungsdatei bentigt nur vier Eintrge wie im folgenden Fall, kann aber viele Andere Eintrge zustzlich enhalten: 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir benutzt diese vier Zeilen, um die Eckpunkte der Karte zu berechnen, und um festzustellen, ob die Karte in den gerade angezeigten Ausschnitt fllt. Wenn es sich bei Ihren Daten um topographische USGS-Karten handelt, sollten auch die .fgd-Dateien vorliegen. Xastir ist in der Lage das Datum von NAD27 in WGS84 umzurechnen, so da auch USGS-Karten unter Xastir eine hhere Genauigkeit erreichen. Wenn Sie keine .fgd-Datei haben, wird die Karte problemlos geladen, allerdings werden die weien Rnder am Kartenrand nicht beschnitten und die Karte knnte eine leicht falsche Gre und Rotation besitzen. Xastir kann nun USGS geoTIFF topographische Karten direkt von einer CD laden. Mounten Sie das CD-ROM manuell oder automatisch durch automounter, und achten Sie darauf, da ein symbolischer Link im Kartenverzeichnis auf das gemountete Laufwerk zeigt. Das war es! Auch Shapefiles sind eine Kombination aus mehreren Dateien, .shp, .dbf und .shx. Sie mssen nur die .shp-Datei auswhlen, um die Karte zu laden. Die anderen Dateien mssen jedoch vorhanden sein, um die Karte ordnungsgem laden zu knnen. GNIS (Geographic Names Information System) Daten bestehen aus einer Sammlung von Namen von Orten oder geographischen Objekten mit ihren jeweiligen Positionen. Diese Bezeichnungen werden wie die in Dos/WinAPRS Karten dargestellt. Je weiter man hineinzoomt, umso mehr detailiertere Bezeichnungen erscheinen, unter der Annahme, da eine GNIS-Datei als Karte gewhlt wurde und die Darstellung von Bezeichnungen im Kartenmenu eingeschaltet wurden. County Karten fr Wetterwarnungen Alle County-Karten sollten im Verzeichnis /usr/local/share/xastir/Counties gespeichert werden. Es gibt verschiedene Formate fr diese Karten, aber dieses Verzeichnis wird immer Unterverzeichnisse fr jeden Staat/Marine- Bereich haben (Abkrzung aus zwei Buchstaben). Das alte Format benutzt .map, whrend das neue Format Z.map benutzt. Die Installation wird ausfhrlicher in README.1ST im Abschnitt ber die Quelle von Karten beschrieben. Wenn eine NWS Nachricht empfangen wird, so werden die entsprechenden Bereiche eingefrbt, um den Bereich der Warnung zu kennzeichnen. Die verschiedenen Farben beschreiben dabei die Art der Warnung. Ursprnglich wurden folgende Farben verwendet: Cyan for advisory, yellow for watch, red for warning, orange for cancelled alert, royal blue for tests, and green for undetermined alert levels. Inzwischen knnen die Farben davon etwas abweichen, da die Flchen nun nicht mehr gefllt werden, sondern nur noch in der Farbe gendert werden, so da man die darunterliegende Karte noch erkennen kann. Die Darstellung von Wetterwarnungen kann im Kartenmenu ein- bzw. ausgeschaltet werden. HELP-INDEX>Ansicht Ansicht Die Optionen in diesem Menu erlauben ihnen festzulegen, welche Daten zu den Stationen auf der Karte angezeigt werden sollen. Es erlaubt Ihnen auch Stationen zu suchen und zu verfolgen, oder Stationen oder deren Spur zu lschen. = Station finden = Siehe hierzu unter "Stationen finden". = Verfolge Station = Siehe hierzu unter "Verfolgen von Stationen". = Spur von Findu holen = Ldt alte Spurdaten einer Station aus dem Internet von findu.com. Momentan werden die Daten der letzten beiden Wochen geladen. = Symbole = Hiermit kann festgelegt werden, ob Symbole auf der Karte gezeichnet werden sollen. Die meisten folgenden Optionen hngen hiervon ebenfalls ab. Bei alten Stationen wird das Symbol nur noch schememhaft in der Standardausrichtung gezeichnet, die zugehrige Spur wird gestrichelt und alle Daten auer dem Rufzeichen verschwinden vom Bildschirm. = Symbole drehen = Wenn eingeschaltet, werden einige Symbole auf der Karte gedreht, um so die Richtung, in die sich Mobilstationen bewegen, anzudeuten. = Rufzeichen = Zeigt das Rufzeichen der Station rechts vom Symbol an. = Geschwindigkeit = Zeigt die Geschwindigkeit einer Station in roter Schrift unterhalb von Rufzeichen und Richtung an, sofern eine Geschwindigkeit bermittelt wird. = - kurz = Wenn markiert wird die Geschwindigkeit in Kurzform ohne Einheit angezeigt. = Hhe = Zeigt die Hhe oberhalb des Rufzeichens in blauer Schrift an, sofern sie bermittelt wurde. = Kurs = Zeigt die Richtung, in die sich die Station bewegt, unterhalb des Rufzeichens in grner Schrift an, sofern die Station einen Kurs bermittelt. = Entfernung/Richtung = Ermglicht die Anzeige der Entfernung von der eigenen Station und der Richtung, in der sich die Station von der eigenen Station aus befindet. Diese beiden Werte werden links vom Symbol dargestellt. = Wetterdaten = Wenn eingeschaltet, werden bei Wetterstationen unterhalb des Symbols die letzten Wetterdaten aufgelistet (Temperatur, Wind- und Ben- geschwindigkeit, Windrichtung und Feuchtigkeit. = - nur Temperatur = Wenn markiert wird nur die Temperatur angezeigt. = Leistung/Gewinn = Wenn PHG-Daten bermittelt werden, wird ein Kreis um die Station gezeichnet, dessen Radius aus Leistung, Hhe und Antennengewinn berechnet wird. Wenn sich zwei Kreise berschneiden sind die Stationen theoretisch in Reichweite fr eine Simplexverbindung. In der Praxis is dies aber nur eine sehr grobe Nherung, vor allem in Gegenden mit sich nderndem Gelnde. = - mit Standardwert = Fr Stationen, die keine PHG-Daten bermitteln, wird stattdessen ein Standardwert gen den APRS-Spezifikationen verwendet. = - bei Mobilstationen = Hiermit knnen auch fr Mobilstationen Entfernungskreise gezeichnet werden. = Positionsverschleierung = Wenn eingeschaltet, wird die Flche markiert, in der sich eine Station mit Positionsverschleierung befinden kann. Die betreffende Station wird in der Mitte dieses Bereichs positioniert. = Alte Daten zeigen = Xastir zeigt Daten auch noch an, nachdem sie eigentlich bereits als alt deklariert wurden. Diese Zeiten knnen unter Datei-Einstellungen- Grundeinstellungen gemdert werden. = DF Kreise zeigen = Wenn eingeschaltet, werden auch alle Kreise fr Peilungen (Direction Finding) angezeigt. = Spuren = Wenn markiert, wird fr Mobilstationen eine farbige Spur mit den letzten maximal 100 Positionen gezeichnet. Jeder neuen Mobilstation wird hierzu eine neue Farbe aus einer Tabelle zugewiesen. = Stationen lschen = Dies lscht alle Stationsdaten auer den eigenen. Dies ist z.B. ntzlich, wenn der Speicher knapp bemessen ist. = Spuren Lschen = Lschen alle Spuren der Mobilstationen. Dies ist z.B. ntzlich, wenn der Speicher knapp bemessen ist. Die Spur einzelner Stationen kann auch ber das StationsInfo Menu gelscht werden. HELP-INDEX>Nachrichten Nachrichten = Schicke Nachricht an = Hiermit knnen Nachrichten mit einer einzelnen Station ausgetauscht werden. Dies ist auch ber das Menu StationsInfo mglich. = ffne Gruppen Nachricht= Dies funktioniert hnlich, nur da die Nachrichten an einen Gruppennamen geschickt werden. Die Gruppen werden in der Datei "groups" in ~/.xastir/config definiert. Gruppennachrichten sind noch nicht voll implementiert und einige Probleme mssen noch beseitigt werden. In Zukunft wird es auch mglich sein, Bulletins zu verschicken, dies ist aber momentan noch nicht implementiert. Im Nachrichtenfenster mu zunchst das Rufzeichen der Station eingetragen werden, der man eine Nachricht schicken will. Darunter kann man dann eine Zeile des Nachrichtentexts (max. 250 Zeichen) eingeben und mit "Sende jetzt!" abschicken. Bis zu einer Besttigung (ACK) durch die Gegenstation bleibt dieser Button inaktiv (grau). Es stehen maximal zehn Fenster fr Nachrichten an verschiedene Rufzeichen zur Verfgung. Beim Empfang einer an die eigene Station gerichteten Nachricht ffnet sich automatisch das Nachrichtenfenster, wobei das Rufzeichen des Absenders bereits eingetragen ist. Im groen Fenster sind oben die ausgehenden und unten die eingetroffenen Nachrichten sortiert nach ihrer Zeilennummer aufgelistet. Mit "Beenden" wird das Nachrichtenfenster verlassen. Mit "Neues Rufzeichen" kann man nachschauen, welche Nachrichten eine Station frher gesendet hatte. Sie knnen dies auch einsetzen, um mit einer anderen Station Nachrichten auszutauschen. Mit "Lsche Nachrichten" wird die angezeigte Liste mit Nachrichten gelscht. = Lsche alle ausgehenden Nachrichten = Hiermit werden alle noch nicht besttigten gesendeten Nachrichten gelscht. Anderenfalls wird mehrfach versucht, diese zuzustellen. = Stationen Allgemein = Dies sendet ein ?APRS? Paket, wodurch alle lokalen Stationen mit ihrer Position und/oder ihrem Status antworten sollten. Viele Programme ignorieren diese Anfrage, da eine Antwort zu einer Flut von Daten fhren kann. = IGate Stationen = Dies sendet ein ?IGATE? Paket, wodurch alle IGate-Stationen antworten und ihre Mglichkeiten mitteilen sollten. = Wetterstationen = Dies sendet ein ?WX? Paket, wodurch alle lokalen Wetterstationen ihre Position und die Wetterdaten senden sollten. = Setze automatische Antwort = Legt den Text fest, der als automatische Antwort gesendet wird. = Automatische Antwort = Hiermit kann ein vorbereiteter Standardtext bei jeder ankommenden Nachricht als Antwort versandt werden. HELP-INDEX>Schnittstellen Schnittstellen In diesem Menu knnen Einstellungen zu den vershiedenen Schnittstellen gemacht werden. = Schnittstellen Ein/Aus = Diese Option ffnet ein Fenster, in dem Sie alle Ihre konfigurierten Schnittstellen ein- oder ausschalten knnen. = Einstellungen = Eine Liste mit den installierten Schnittstellen erscheint und erlaubt Ihnen deren Einstellungen zu nden und weitere Schnittstellen hinzuzufgen bzw. vorhandene zu lschen. Nheres finden Sie unter "Schnittstellen Konfiguration" = Nicht senden: ALLES = Wenn markiert wird berhaupt NICHT gesendet. Fr diese und die folgenden beiden Optionen gilt, da es sich um globale Einstellungen handelt, die fr alle Schnittstellen gelten. Die meisten Schnittstellen bieten auch die Mglichkeit, das Senden ber diese spezielle Schnittstelle einzeln auszuschalten. = Nicht senden: Meine Position = Wenn markiert wird die eigene Position nicht gesendet. = Nicht senden: Objekte = Wenn markiert wird die eigenen Objekte nicht gesendet. = Sende jetzt! = Fhrt dazu, da alle eingeschalteten Schnittstellen ein Positions- Paket senden. Es ist nicht funktionsfhig (grau), wenn das Senden grundstzlich ausgeschaltet ist. HELP-INDEX>Stations-Info Stations-Info Das Fenster Stations-Info zeigt alle Daten an, die von Xastir fr diese Station dekodiert wurden. Es knnen die folgenden Informationen angezeigt werden: Die Anzahl der gehrten Pakete, die Uhrzeit, zu der die Station zuletzt gehrt wurde, ber welche Schnittstelle dies erfolgte, den Kommentar, PHG (aus Leistung, Hhe und Gewinn), Entfernung und Richtung von meiner Station, Wetterdaten und die letzte Position. Bei Stationen, die sich bewegen, folgt ein Tracklog mit den neuesten Daten ganz oben. Ein '+' vor einer Zeile markiert den Start eines neuen Tracks (wenn zuvor eine groe Zeit- bzw. Ortsdifferenz vorlag). Ein Stern am Ende einer Zeile weist darauf hin, da die Station an der jeweiligen Position auf direktem Weg gehrt werden konnte (ohne Digipeater). Nur fr die eigene Station gibt es ein Feld "Echo von", das die letzten sechs Digipeater auffhrt, die mein Paket als erste weitergegeben haben. Am unteren Rand des Fensters befinden sich zwei Reihen mit vier Aktions- feldern, deren Funktion abhngig von der Art der dargestellten Station ist. Fr Objekte/Items: Track speichern Objekt ndern --leer-- Schlieen ? Stationsversion ? Trace ? unbest. Nachrichten Stationsanfrage Fr andere Stationen: Track speichern Nachricht senden FCC/RAC Datenbank Schlieen ? Stationsversion ? Trace ? unbest. Nachrichten Stationsanfrage Bei sich bewegenden Stationen fehlt die Anfrage nach der Stationsversion, stattdessen findet sich dort "Spur lschen". Hiermit werden alle Bewegungsdaten dieser Station in der Datenbank und vom Bildschirm gelscht. Mit "Spur speichern" wird die Position und falls vorhanden, alle Bewegungsdaten in einer Datei auf der Festplatte gespeichert. Das derzeit benutzte Format ist dem hnlich, das bei GPS-Empfngern zum Einsatz kommt, die Spezifikationen knnten sich aber in zuknftigen Versionen noch ndern. Es gibt momentan keinen Weg, diese Daten wieder einzulesen, dies ist aber fr die Zukunft geplant. Das Ziel ist es auch GPS Tracklog-Dateien in hnlicher Art laden und darstellen zu knnen. Diese Tracklog-Dateien werden im Verzeichnis ~/.xastir/tracklogs abgelegt, der Dateiname besteht aus dem jeweiligen Rufzeichen mit der Erweiterung ".trk". "Objekt/Item ndern" ffnet das Fenster zum ndern von Objekten. "Sende Nachricht" ffnet fr diese Station ein Nachrichtenfenster und ermglicht an diese Station eine Nachricht zu senden. Wenn die FCC (U.S. Federal Communications Commission) oder RAC (Radio Amateurs of Canada) Datenbank installiert ist und das Rufzeichen aus dem US-amerikanischen bzw. kanadischen Kontingent stammt, so ist das "FCC/RAC Suche"-Feld vorhanden, sonst nicht. Die FCC- und RAC-Dateien sollten sich im Verzeichnis /usr/local/share/xastir/fcc befinden, wobei auf Gro-/Kleinschreibung zu achten ist. Wenn die Suche erfolgreich ist, wird Name und Adresse der Station im Stations-Info Fenster angezeigt. Anweisungen zur Installation dieser Datenbanken finden sich in der Datei README.1ST. Xastir erzeugt beim Start eine Indexdatei fr jede dieser Datenbanken. Wenn eine Rufzeichendatei aktualisiert wird, whrend Xastir luft, so wird der Index bei der nchsten Suche erstellt oder neu aufgebaut. Spezielle Prfixe werden NICHT bercksichtigt. HELP-INDEX>Erstellen von Protokolldateien Erstellen von Protokolldateien Xastir kann empfangene Daten in Protokolldateien schreiben, so da sie spter wieder eingespielt werden, oder zu Debuggingzwecken analysiert werden knnen. Alle diese Einstellungen werden im Menu "Datei" vorgenommen. = TNC protokollieren = Protokolliert alle Daten, die ber den TNC empfangen bzw. gesendet werden. Dieses Protokoll kann ber "Protokolldatei laden" zu einem spteren Zeitpunkt wieder eingelesen werden. = Netz protokollieren = Protokolliert alle Daten, die ber das Internet empfangen bzw. gesendet werden. Dieses Protokoll kann ber "Protokolldatei laden" zu einem spteren Zeitpunkt wieder eingelesen werden. Wenn Sie keine Schnittstelle gestartet haben und Ihre Position oder die eigenen Objekte lokal protokollieren wollen, ist dies die geeignete Methode. = IGate protokollieren = Protokolliert alle weitergereichten Daten in beide Richtungen, bei unterdrckten Weiterleitungen auch den Grund hierfr. Dies beinhaltet auch NWS Nachrichten, die in Richtung Funk weitergeleitet werden (gem ~/.xastir/data/nws-stations.txt: eine Textdatei, die alle Rufzeichen bzw. NWS Station wie z.B. "SECIND" angibt, deren Daten ber Funk weitergegeben werden sollen). = Wetter protokollieren = Protokolliert alle Wetterdaten, die von Ihrer Wetterstation empfangen werden. HELP-INDEX>Wiedergeben einer Protokolldatei Wiedergeben einer Protokolldatei Klicken sie auf Datei, dann auf "Protokolldatei laden". In einem Auswahlfenster knnen sie eine Datei auswhlen, deren Inhalt von Xastir geladen werden soll. Es mu sich dabei um eine Datei mit TNC Rohdaten handeln, wie sie auch von Xastir als Protokolldatei geschrieben werden kann. Die Station funktioniert dabei weiterhin wie gewohnt, die eingespielten Daten werden aber nicht wieder ausgesendet. Wenn sie Daten protokollieren, finden sie diese Dateien blicherweise in ~/.xastir/logs/ HELP-INDEX>Finden einer Station Finden einer Station Klicken sie auf Ansicht, dann auf "Station finden". Ein Fenster erscheint, in dem sie das Rufzeichen der zu suchenden Station eingeben knnen. In der Standardeinstellung wird nach bereinstimmung mit dem kompletten Rufzeichen (Exact Match) gesucht. Bei Objekten, die Kleinbuchstaben enthalten, mu "Match Case" gewhlt werden! Entgegen dem Namen wird ohne "Match Case" der Suchbegriff nur in Grobuchstaben umgesetzt... Mit "Finde jetzt!" wird der Suchvorgang gestarted und bei Erfolg der Bildausschnitt so justiert, da die Station mit einer bereinstimmung in der Mitte zu sehen ist. HELP-INDEX>Gespeicherte Kartenausschnitte Gespeicherte Kartenausschnitte Klicken sie auf Karten, dann auf "Ausschnitte" und sie erhalten ein PopUp-Fenster mit frher gespeicherten Kartenausschnitten. Beim ersten Aufruf wird diese Liste noch leer sein. Sie knnen den aktuellen Kartenausschnitt unter einem Namen speichern. Geben sie diesen Namen unter "Neuer Name" ein und whlen anschlieend "Hinzufgen". Nach Markieren eines Namens aus der Liste knnen sie den gespeicherten Kartenausschnitt durch "Aktivieren!" wieder herstellen. Durch Markieren und "Lschen" knnen Eintrge aus der Liste auch wieder entfernt werden. "Karte - Objekt in Karte suchen" ist eine weitere Mglichkeit, um einen Kartenausschnitt zu ndern, indem ein bestimmtes Objekt bei installierten GNIS-Dateien gesucht werden kann. HELP-INDEX>Verfolgen einer Station Verfolgen einer Station (Tracking) Klicken sie auf Ansicht, dann auf "Verfolge Station". Geben sie das Rufzeichen ein und drcken sie "Verfolge jetzt!". Die verfolgte Station bleibt nun immer auf dem Bildschirm sichtbar. Wenn die Station nahe an den Rand des Kartenausschnitts gelangt, wird die Karte nachgefhrt. Um das Tracking wieder aufzuheben klicken sie auf "Verfolgung aufheben". HELP-INDEX>Schnittstellen Konfiguration Schnittstellen Konfiguration Klicken sie auf Schnittstellen, dann auf Einstellungen Es erscheint ein Fenster "Installierte Schnittstellen", fr die verschiedenen Gerte, die sie mit Xastir zusammen benutzen wollen. Dort knnen sie Schnittstellen hinzufgen, lschen und deren Eigenschaften ndern. Durch Klick auf "Hinzufgen" knnen sie ein neues Gert anmelden, es erscheint ein Fenster zur Auswahl des Schnittstellentyps. Momentan sind verfgbar: Serieller TNC Serieller TNC plus GPS mit HSP-Kabel Serieller GPS-Empfnger Serielle Wetterstation Internet Server AX.25 TNC GPS ber Netzwerk (via gpsd) Wetterstation ber Netzwerk Markieren sie das gewnschte Gert aus der Liste und Klicken auf "Hinzufgen", es erscheint dann ein Fenster, indem sie die verschiedene Eigenschaften fr dieses Gert festlegen knnen. Tragen sie die bentigten Werte ein und besttigen sie mit OK. Ein Gert kann nach Markierung mit einem Klick auf "Lschen" wieder entfernt werden. Mit "Einstellungen" erhalten sie fr das markierte Gert aus der Schnittstellenliste ein Fenster, indem sie verschiedene Parameter ndern knnen. Weiterfrende Hilfe findet man in den Abschnitten fr die einzelnen Schnittstellentypen. HELP-INDEX>Serieller TNC Serieller TNC Dieser Abschnitt behandelt das Hinzufgen oder ndern von seriellen TNCs und seriellen TNCs mit einem GPS ber ein HSP-Kabel. Wenn sie ein HSP-Kabel besitzen, knnen sie diesen Eintrag auswhlen und dann sowohl den TNC als auch den GPS-Empfnger ber die gleiche serielle Schnittstelle anschlieen. Es handelt sich um ein spezielles Kabel, bei dem die Empfangsleitung durch den Computer zwischen den beiden Gerten umgeschaltet werden kann. Es arbeitet mglicherweise nicht mit allen mglichen Kombinationen von Computer, TNC und GPS. Der TNC und der GPS mssen auf die gleichen Kommunikationsparameter eingestellt werden, blicherweise also 4800 bps, 8 Datenbits, keine Paritt und 1 Stopbit. Optionen fr die TNC-Schnittstelle: Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten gesendet werden drfen. Als TNC Port wird das Unix Device eingetragen, mit dem der TNC (oder TNC und GPS) verbunden ist. Normalerweise geben sie hier /dev/ttyS0 (COM1), /dev/ttyS1 (COM2) etc. an. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr 8 Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Bei Verwendung des HSP-Kabels mssen diese Einstellungen fr TNC und GPS identisch sein. Mit den IGate Optionen knnen sie festlegen, in welche Richtung Internetverkehr ber diese Schnittstelle erfolgen kann. Dies kann fr jedes Gert getrennt eingestellt werden. Wenn sie kein IGate betreiben, lassen sie die Einstellungen auf "Disable". Tragen sie bis zu drei UNPROTO Pfade ein, Xastir gibt dabei das Zielrufzeichen vor. Falls mehrere Pfade (bis zu drei) eingetragen wurden, so verwendet Xastir diese abwechselnd bei jeder Aussendung, um so auch in schwierigen Situationen gehrt zu werden. Wenn sie nur lokalen Verkehr haben, so gengt ein einzelnes WIDE2-2. Bei wenig Leistung oder grerer Entfernung von einem Digipeater drfte "WIDE1-1,WIDE2-2" besser funktionieren. Wenn sie das Rufzeichen eines benachbarten Digis kennen, knnen sie auch alle Pakete ber diesen schicken, indem sie es an erster Stelle nennen, also z.B. "DB0XYZ,WIDE2-2". Fr die meisten Stationen wird ein Pfad gengen, in abgelegenen Gegenden oder unter schwierigen Bedingungen kann es sinnvoll sein, mehrere einzutragen. Am besten lt es sich mit rtlichen Funkamateuren abklren, welcher Pfad geeignet ist, um einerseits gut gehrt zu werden, andererseits aber die Frequenzen nicht unntig zu belasten. In Gegenden mit intelligenten Digis, die Wiederholungsschleifen weitgehend vermeiden, kann auch z.B. WIDE3-3 oder "WIDE1-1,WIDE3-3" verwendet werden. Die TNC Startup und Shutdown Dateien befinden sich im Verzeichnis /usr/local/share/xastir/config und werden beim Starten bzw. Stoppen der TNC-Verbindung zur Initialisierung ausgefhrt. Es handelt sich um normale Textdateien mit Kommandos, die an den TNC gesendet werden. HELP-INDEX>AX.25 TNC Schnittstellen AX.25 TNC Schnittstellen Als AX.25 TNC Device kann jedes Gert verwendet werden, da ber ein Linux AX.25 Treiber angesprochen werden kann. Hierbei handelt es sich um einen Kernel-Treiber, der z.B. auch das Baycom-Modem oder ein Packet Radio ber die Soundkarte untersttzt. Diese Gerte mssen vor dem Start von Xastir in Linux eingerichtet werden, bevor sie benutzt werden knnen. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten gesendet werden drfen. Mit den IGate Optionen knnen sie festlegen, in welche Richtung Internetverkehr ber diese Schnittstelle erfolgen kann. Dies kann fr jedes Gert getrennt eingestellt werden. Wenn sie kein IGate betreiben, lassen sie die Einstellungen auf "Disable". Geben sie den fr das AX.25-Gert festgelegten Device-Namen an, wie er in der Datei /etc/ax25/axports steht. Tragen sie bis zu drei UNPROTO Pfade ein, Xastir gibt dabei das Zielrufzeichen vor. Falls mehrere Pfade (bis zu drei) eingetragen wurden, so verwendet Xastir diese abwechselnd bei jeder Aussendung, um so auch in schwierigen Situationen gehrt zu werden. Wenn sie nur lokalen Verkehr haben, so gengt ein einzelnes WIDE2-2. Bei wenig Leistung oder grerer Entfernung von einem Digipeater drfte "WIDE1-1,WIDE2-2" besser funktionieren. Wenn sie das Rufzeichen eines benachbarten Digis kennen, knnen sie auch alle Pakete ber diesen schicken, indem sie es an erster Stelle nennen, also z.B. "DB0XYZ,WIDE2-2". Fr die meisten Stationen wird ein Pfad gengen, in abgelegenen Gegenden oder unter schwierigen Bedingungen kann es sinnvoll sein, mehrere einzutragen. Am besten lt es sich mit rtlichen Funkamateuren abklren, welcher Pfad geeignet ist, um einerseits gut gehrt zu werden, andererseits aber die Frequenzen nicht unntig zu belasten. In Gegenden mit intelligenten Digis, die Wiederholungsschleifen weitgehend vermeiden, kann auch z.B. WIDE3-3 oder "WIDE1-1,WIDE3-3" verwendet werden. Anmerkung: Um die AX.25 Treiber verwenden zu knnen, mu Xastir unter "root"-Rechten laufen. Um Xastir als normaler Benutzer zu starten, mu das suid Bit beim Xastir-Programm gesetzt werden. Hierzu dient das folgende Kommando (als root): "chmod a+s /usr/local/bin/xastir". Beachten sie bitte, da jedes Programm, das auf diese Weise luft, als Sicherheitsrisiko angesehen werden kann. Es wurde nicht besonders auf mgliche Sicherheitsrisiken hin getestet, benutzen sie es also in einer Mehrbenutzer-Umgebung mit Vorsicht und auf eigenes Riskio! HELP-INDEX>Serieller GPS Serieller GPS Setzen sie die serielle Schnittstelle fr den GPS Empfnger. Gngige Eintrge sind hier /dev/ttyS0 (COM1) oder /dev/ttyS1 (COM2). Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr acht Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Die Daten mssen mit denen des GPS-Empfngers bereinstimmen, die meisten Gerte verwenden im bentigten NMEA-Modus 4800 bps und 8N1. HELP-INDEX>GPS ber Netzwerk GPS ber Netzwerk Wenn sie die GPS-Daten fr verschiedene Programme bzw. Computer bentigen, ist diese Auswahl die geeignetste. Hierzu mu vorher der gpsd eingerichtet worden sein, von dem Xastir dann, neben anderen Programmen, die GPS-Daten beziehen kann. Tragen sie Namen (oder IP-Adresse) und Port-Nummer fr den gpsd Rechner in ihrem Netzwerk ein. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. HELP-INDEX>Internet Server Internet Server Internet Server erlauben ihnen Daten aus der ganzen Welt zu empfangen und lokale Daten ins Internet zu senden. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. "Senden erlaubt" legt fest, ob ber diese Schnittstelle berhaupt Daten ins Internet gesendet werden drfen. Tragen sie Namen (oder IP-Adresse) und Port-Nummer des Internet Servers ein, den sie ansprechen wollen. Geben sie einen gltigen Schlssel (Pass-Code) ein um Daten ber ein IGate senden zu knnen. Wenn sie keinen Schlssel passend zu ihrem Rufzeichen haben, knnen sie einen mit dem beigefgten Programm "callpass" erzeugen. Wenn es noch nicht bereits kompiliert wurde, geben hierzu sie im src Verzeicnis "make callpass" ein. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. HELP-INDEX>Serielle Wetterstation Serielle Wetterstation Tragen sie die serielle Schnittstelle fr die Wetterstation ein. Gngige Eintrge sind hier /dev/ttyS0 (COM1) oder /dev/ttyS1 (COM2). Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Setzen sie nun die Baudrate und die Anzahl der Datenbits. 8N1 steht fr acht Datenbits, keine Paritt und 1 Stopbit, 7E1 fr 7 Datenbits, gerade Paritt und 1 Stopbit und 7O1 arbeitet mit ungerader Paritt. Die Daten mssen mit denen ihrer Wetterstation bereinstimmen. Durch die Angabe der "Datenart" kann festgelegt werden, welche Daten das Programm ber die serielle Schnittstelle erwartet. Bei "Automatisch" wird zunchst nach Wetterdaten im Binrformat geschaut, wie es die Radio Shack WX-200 Wetterstation liefert. Falls keine Binrdaten im Datenstrom gefunden werden, versucht Xastir eine Wetterstation mit ASCII-Daten zu finden (wie Peet Bros.). HELP-INDEX>Wetterstation ber Netzwerk Wetterstation ber Netzwerk Xastir kann Wetterdaten Server wie den wx200d ansprechen. wx200d erlaubt mehrere Netzwerkverbindungen, so da Wetterdaten gleichzeitig verschiednen Programmen oder Computern zur Verfgung steht. Tragen sie Namen (oder IP-Adresse) und Port-Nummer des Wetterdaten Servers in ihrem Netzwerk ein. Durch Markieren von "Beim Start aktivieren" wird Xastir bei jedem Programmstart versuchen, diese Schnittstelle einzuschalten. Durch Markieren von "Wiederverbinden nach Fehler" versucht Xastir die Netzwerkverbindung nach einem Fehler wieder herzustellen. Wie im vorigen Abschnitt kann durch Angabe von "Datenart" die automatische Auswahl berschrieben werden. HELP-INDEX>Ausdrucken des Bildschirms Ausdrucken des Bildschirms Xastir kann den dargestellten Kartenausschnitt in Schwarz-Wei oder in Farbe ausdrucken. Hierbei wird das Bild zunchst als XPixmap-Datei gespeichert, dann werden externen Zusatzprogramme gestartet, um es ins PostScript-Format zu konvertieren, zu skalieren und rotieren, eine Vorschau zu ermglichen und es schlielich zu drucken. Hierfr mu Ihr System so eingerichtet sein, da Sie PostScript-Dateien drucken knnen, gewhnlich wird hierfr ghostscript, installierte Druckerfilter sowie ein lp oder lpr Druckerspooler bentigt. Fr die Erstellung der Ausdrucke mssen dann die folgenden Pakete installiert sein: ImageMagick (speziell "convert"), Ghostscript nebst Schriften, und "gv". Wenn diese Pakete funktionsfhig sind, so sollte kurz nach dem Druckbefehl in Xastir ein "gv"-Fenster aufgehen, in dem man das Druckbild zunchst begutachten kann. Falls das Ergebnis zufriedenstellend ist, kann es von gv aus ausgedruckt werden. Beachten Sie, da es in Abhngigkeit von den dargestellten Karten sinnvoll sein kann, den Kartenhintergrund auf weie Farbe zu ndern, hierdurch kann gegebenenfalls einiges an Tinte gespart werden. HELP-INDEX>Erstellen automatischer Schnappschsse Erstellen automatischer Schnappschsse Xastir hat die Fhigkeit, wiederholt automatische Schnappschsse des dargestellten Kartenausschnitts anzufertigen. Momentan erfolgt dies alle fnf Minuten. Unter der Voraussetzung, da "convert" aus dem ImageMagick- Paket installiert ist, erzeugt Xastir eine XPM-Datei in /var/tmp und konvertiert diese dann in die PNG-Datei /var/tmp/xastir_snap.png. Hiermit kann das aktuelle Geschehen z.B. auf einer regelmig aktualisierten Webpage dargestellt werden. Schnappschsse werden ber Datei - Schnappschsse eingeschaltet. HELP-INDEX>Symboltabelle Symboltabelle Dies sind die Definitionen der fr ihre Station oder fr Objekte whlbaren Symbole. Es stehen zwei Gruppen zur Verfgung, mit teilweise unterschiedlichen Symbolen bei gleichem Symbolbuchstaben. Die Grafiken aus der alternative Gruppe "\" werden auch herangezogen, wenn ein Overlay erfolgen soll. Hierzu wird als Gruppe ein Buchstabe [A-Z] oder eine Zahl [0-9] eingegeben, dies erscheint dann berlagert ber dem Symbol. Die aktuelle Liste findet man in der APRS Reference, die es bei http://www.tapr.org gibt. Symboltabelle Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>Was war neu in Xastir V1.0 Was war neu in Xastir V1.0 Whrend des vergangenen Jahres wurde Xastir weiterentwickelt und dieses Release ist das Ergebnis dieser Bemhungen. Die Entwicklung wurde von Chuck Byam geleitet, der das Projekt mit dem Einverstndnis von Frank Giannandrea bernommen hat. Viele andere haben zum Erfolg des Projects beigetragen, eine Auflistung findet sich in der Datei AUTHORS. Das Xastir Paket benutzt nun GNU autoconf um die Makefiles zu erstellen und verschiedene Eigenschaften aufgrund der installierten Bibliotheken und Software auszuwhlen. Beim Start von Xastir V1.0 werden sie womglich nicht sofort grere nderungen entdecken. Die bekannte Bedienoberflche wurde weitgehend beibehalten. Der grte Teil der nderungen bleibt im Verborgenen und dient einer Steigerungen der Effizienz: o Die Startzeit des Programms wurde verbessert o Der Speicherbedarf wurde durch dynamische Speicherzuweisung fr Stationen, Spuren und Wetterdaten stark verbessert. D.h. es wird kein Speicher mehr verschwendet fr nicht vorhandene Spurdaten bei festen Stationen oder Wetterdaten bei den meisten Stationen. Mit diesen nderungen ist es mglich, Xastir komfortabel mit dem Internet zu verbinden, auch wenn nur sehr wenig Speicher vorhanden ist. o Das Laden der Karten wurde verbessert, indem nun nicht mehr bei jeder kleinen nderung die Karte neu von der Festplatte geladen werden mu. Wetterwarnungen und nderungen an den Einstellungen fr die Darstellung und Tracking Optionen erfordern kein Neuladen der Karten, stattdessen werden nur die Symbole und die Spuren neu gezeichnet. o Verschiedene Dialog-Fenster, die frher hufig neu gezeichnet wurden, werden nun nur bei Bedarf aktualisiert und sind damit auch auf langsameren Systemen akzeptabel. Dies gilt auch fr das Verfolgen einer Station (Tracking), wobei die Karte nun nur neu gezeichnet wird, wenn die Station sich dem Rand des Bildschirms nhert. Dank dieser nderungen kann Xastir problemlos auch auf langsameren Pentium(tm) Rechnern eingesetzt werden. Untersttzung fr das GeoTIFF Kartenformat ist nun vorhanden und wird in Xastir einkompiliert, wenn die GeoTiff Bibliotheken auf dem System installiert sind. Diese Karten sind von hoher Qualitt und besonders fr Such- und Rettungsoperationen zu gebrauchen. Karten in diesem Format sind vom USGS und kommerziell auf CD-ROM erhltlich. Xastir wei, wie das Datum von NAD-27 in WGS-84 umzurechnen ist, so da Karten in beiden Formaten ohne Genauigkeitsverlust gelesen werden knnen. Zustzliche Tasten wurden in der Kartenauswahl hinzugefgt, um schnell alle Karten einer bestimmten Art auszuwhlen. Das oben gesagte gilt in erster Linie fr die USA, wo es jede Menge Karten gibt. Bei uns gibt es zwar schnere topgraphische Karten, dafr gibt es aber so gut wie nichts kostenlos, und damit auch kein verbreitetes Standardformat. Xastir untersttzt nun das Setzen und Lschen von Objekten. Objekte knnen verwendet werden, um Treffen anzuzeigen, Reisenden Hinweise zu geben oder Such- und Rettungseinstze durchzufhren. Die amerikanischen County Wetterwarnungs-Karten werden nicht mehr direkt auf die Karten gezeichnet, sondern mit der Karte berlagert. Einerseits sind die Farben dadurch verflscht, aber es ist nun mglich, die Straenkarten auch im Warnungsgebiet zu erkennen. Eine neue und ntzliche Eigenschaft ist, da sich die Ausrichtung einiger Symbole ndert, je nachdem in welche Richtung sich z.B. ein Fahrzeug bewegt. Auch ohne die zurckgelegte Spur kann man die Richtung einer Mobilstation mit einem Blick erfassen. Es gibt einige weitere Optionen im Menu Darstellung mit denen man genauer festlegen kann, was angezeigt werden soll und was nicht. Das Verschieben und die Kontrolle ber den Kartenausschnitt wurde verbessert: Es gibt nun Pfeile oben rechts im Menu, um die Karte mit der Maus zu verschieben. Die Karte kann auch mit den Cursortasten verschoben werden und die Vergrerung kann mit den PgUp und PgDn Tasten eingestellt werden. Im PopUp-Menu der linken Maustaste gibt es neue Optionen um die Karte an der aktuellen Position zu zentrieren oder dort ein Pbjekt zu platzieren. Die Verschiebemglichkeiten ber dieses Menu wurden zugunsten der oben genannten entfernt. Untersttzung fr Alternative Netzwerke wurde hinzugefgt, hiermit wird es mglich, ein privates APRS(tm) Netzwerk einzurichten fr Veranstaltungen, fr Such- und Rettungseinstze, Sturmjagd, oder fr alles wo der Benutzer nicht von Hunderten von APRS(tm)-Stationen um ihn herum genervt werden will. Es gibt viele kleine nderungen, sichtbar oder unsichtbar fr den Benutzer. Die Schnittstellen-Steuerung hat nun eine Option, um alle Schnittstellen gleichzeitig zu starten oder zu stoppen, um dem Benutzer es zu ersparen, dies fr jede Schnittstelle einzeln tun zu mssen. Die Stationseinstellungen zeigen nun das gewhlte Symbol, so da man das Fenster nicht mehr verlassen mu, um es zu sehen. Einige Pufferberlufe, die unvorhersagbares Verhalten oder Programmabstrze hervorgerufen hatten, wurden beseitigt. Und viele kleinere nderungen wurden am Quelltext vorgenommen, damit Xastir auf verschiedenen Systemen fehlerfrei bersetzt werden kann. Viel Freude mit dem neuen Xastir! Xastir-Release-2.2.4/help/help-Italian.dat0000664000175000017500000014277515151324131017272 0ustar hibbyhibbyHELP-INDEX>Leggimi - Licenza Leggimi - Licenza Per informazioni sulla versione corrente del programma leggere README.1ST nella cartella di Xastir. Questo programma sviluppato per essere usato all'interno della comunit radioamatoriale, negli Stati Uniti la FCC non autorizza a trasmettere per radio se non sei radioamatore. Gli utenti di altri paesi devono attenersi alle leggi locali in merito. LICENZA: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Questo programma un software libero; pu' essere ridistribuito e modificato secondo i termini della Licenza GNU GPL, pubblicata dalla Free Software Foundation; anche la versione 2 della licenza valida, come anche le versioni seguenti. ma SENZA ALCUNA GARANZIA; senza la garanzia di COMMERCIABILITA' o ADATTAMENTO PER UN PARTICOLARE USO. Vedere la Licenza GNU GPL per maggiori dettagli. Dovrebbe essere pervenuta a voi la licenza GNU assieme al programma; se cos non fosse segnalate l'evento alla Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Ulteriori informazioni sul software possono essere ottenute via: Web, http://www.xastir.org http://github.com/Xastir/Xastir Per maggiori informazioni riguardo la licenza pubblica GNU GPL: http://www.gnu.org HELP-INDEX>Benvenuti! e note dell'Autore Benvenuti! - note dell'autore XASTIR, o X-windows Amateur Station Tracking and Information Reporting. un programma APRS(tm) sviluppato liberamente e di libero uso, pu essere liberamente distribuito. Attualmente il programma in fase di sviluppo e non deve essere visto come un prodotto finito! Il tuo aiuto servir a renderlo migliore. Se sai programmare o vuoi scrivere documentazione, il tuo aiuto mi risulter molto gradito! Ho molte idee ma cos poco tempo! Quindi se pensi che manchi qualcosa, fammelo sapere. 73, Frank Giannandrea Traduzione della guida a cura di Alessandro Frigeri, IK0YUP. APRS[tm] un marchio registrato di Bob Bruninga, la sua pagina "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Avviare Xastir Avviare Xastir per la prima volta La prima volta che si lancia Xastir, dovrebbe essere fatto da un terminale in maniera tale che qualsiasi messaggio di errore salti alla vista. Nella maggior parte dei sistemi il percorso di ricerca dei file eseguibili comprende la cartella /usr/local/bin e tutto quello che serve per avviare il programma dare il comando xastir al prompt. Nei sistemi dove il percorso "/usr/local/bin" non impostato bisogner digitare "/usr/local/bin/xastir" per avviare il programma. Si pu anche impostare un linguaggio diverso dall'originale. Per impostare o cambiare il linguaggio usato da xastir bisogna utilizzare la seguente sintassi: xastir -l Attualmente le scelte sono: English Dutch French German Spanish Italian ElmerFudd MuppetsSwedishChef OldeEnglish PigLatin PirateEnglish Questa opzione viene memorizzata nel file di configurazione dell'utente e resa disponibile per i seguenti usi del programma. Per le nuove installazioni Xastir user l'inglese a meno che non venga specificato un linguaggio differente con l'opzione -l. NOTA: Nei menu, le opzioni in grigio sono quelle selezionate, come anche nelle opzioni di on/off, la scelta attivata sar evidenziata dalla colorazione grigia. HELP-INDEX>Informazioni sulla configurazione della stazione Informazioni sulla configurazione della stazione Seleziona Configura la Stazione Imposta il tuo nominativo nella apposita casella. Compila le caselle relative alla posizione (Lat,Long) se non si intende usare Xastir con un GPS. Se la posizione non disponibile possibile individuare la posizione sulla mappa e copiare i dati. Latitudine e longitudine potranno essere rilevati nella seconda casella partendo da destra, nella parte bassa della finestra principale. Se si intende utilizzare un GPS si pu saltare questa sezione e configurare il GPS in un secondo momento. Il simbolo o il gruppo della stazione possono essere cambiati in qualsiasi momento, per fare questo si faccia riferimento alla guida ai simboli. Indicare ora i dati tecnici della stazione: questi dati sono interessanti ma non necessari al corretto funzionamento del programma. Utilizzare il seguente codice per indicare la potenza che pi si avvicina a quella della vostra stazione: Codice 0 1 2 3 4 5 6 7 8 9 Potenza (watts) 0 1 4 9 16 25 36 49 64 81 Esempio: Se si sta trasmettendo con 36 watt, indicare "6". Lo stesso discorso vale per l'altezza, ma bisogna indicare l'altitudine e non l'altezza dell'antenna sul terreno. Codice 0 1 2 3 4 5 6 7 8 9 Altitudine (piedi)10 20 40 80 160 320 640 1280 2560 5120 Esempio: se l'altitudine della stazione 1280 piedi, il codice da usare sar "7". Per impostare il guadagno scrivere semplicemente il valore dello stesso espresso in dB, nella apposita casella. La direzione ha bisogno di un codice che esprime la direzione dell'antenna espressa in gradi dal Nord. Codice 0 1 2 3 4 5 6 7 8 9 Direzione(gradi) * 45 90 135 180 225 270 315 360 Nessuna Esempio: Se la vostra antenna omnidirezionale, impostare "0". Se la direzionalit verso nord, impostare "8". Inserire un commento, non necessario al programma, ma utile agli altri operatori. L'ambiguit della posizione permette di trasmettere quanto precisa la posizione fornita dalla nostra stazione. Una impostazione con ambiguit nulla permetter di comunicare alle altre stazioni esattamente la posizione che abbiamo impostato o che arriva dal GPS. Le altre scelte posizioneranno la stazione nel raggio indicato dal codice impostato. Selezionando OK, verranno applicati tutti i cambiamenti effettuati, mentre il tasto Annulla manterr le opzioni correnti. HELP-INDEX>Configurazione delle Unit di Misura Configurazione delle Unit di Misura L'impostazione originale del programma per il sistema metrico, mm, cm, Km/ora ecc. Per selezionare il sistema di misura anglosassone (pollici,piedi,miglia/ora) selezionare Configura, Unit, quindi il sistema che si vuole usare. L'opzione attiva quella marcata dal grigio. HELP-INDEX>Configurazione delle Operazioni Base Configurazione delle Operazioni Base Selezionare Configura e quindi Predefinito Questa scheda imposta una configurazione standard. Le vecchie stazioni saranno visualizzate con un'icona fantasma. Il "tempo lettura GPS" imposter l'intervallo di tempo per acquisire nuovi dati dal GPS. Questa opzione disponibile per le stazioni dotate di HSP o di un cavo condiviso con il proprio TNC. L'opzione "Trasmissioni Stazione" imposta con quali packet la stazione trasmetter i propri dati. L'opzione "Trasmetti codici WX", se selezionato, mander anche un pacchetto di dati provenienti dalla stazione meteo.Questa opzione utile per i tipi di stazioni meteo che trasmettono i dati gi in formato ASCII come le Peet Bros. Le opzioni Gateway permetteranno di impostare la stazione come un gateway tra internet e la rete radio. Questa opzione va usata con cautela, come radioamatore ognuno di noi responsabile per i dati che trasmette, e quindi anche per quelli che provengono da internet e vengono trasmessi per radio in una simile configurazione. HELP-INDEX>Configurazione Interfacce Configurazione Interfacce Selezionare Configura e quindi Interfacce. Dovrebbe apparire una scheda che indica le "Interfacce installate". Questa scheda vi permetter di aggiungere, cancellare, e modificare le propriet delle varie periferiche che possono essere utilizzate con Xastir. Le opzioni sono: TNC Seriale TNC Seriale con GPS tramite un cavo HSP GPS Seriale WX Seriale Server Internet TNC AX25 GPS in rete (via gpsd) WX in rete Per aggiungere una periferica, selezionare aggiungi. Apparir la scheda "Scegli il tipo di interfaccia". Seleziona il tipo di interfaccia che vuoi aggiungere. Appariranno i parametri di quella periferica. Fornire le impostazioni richieste e selezionare "ok" Per eliminare una periferica, selezionarla e in seguito cliccare sul bottone Elimina. Per modificare le propriet di una periferica, seleziona la periferica e quindi il bottone "Propriet". La scheda con i parametri della periferica appariranno e potranno essere modificati a piacere. Per rendere effettive le impostazioni schiacciare il bottone OK dopo aver fatto le modifiche. HELP-INDEX>Configurazione di TNC Seriali Configurazione di TNC Seriali CONFIGURAZIONE DI UN TNC SERIALE Questa sezione tratta l'impostazione di un TNC Seriale o di un TNC seriale con un cavo HSP per il collegamento del GPS. Se si ha il cavo HSP, che permette di condividere la porta del TNC con quella del GPS, la configurazione da selezionare sar "TNC con GPS". Il cavo HSP un cavo speciale che pu non essere compatibile con tutte le combinazioni computer/TNC/GPS possibili. Se si usa questa configurazione, il TNC e il GPS devono avere una impostazione dei parametri di comunicazione che in genere prevede: 4800 bps, 8 bit di dati, nessuna parit, 1 bit di stop. Opzioni della Porta TNC: Selezionando "Attivare all'avvio" si indica a Xastir di caricare questa periferica automaticamente all'avvio del programma. Selezionando "Permetti la Trasmissione", ordina a Xastir che ogni dato inviato all'interfaccia pu essere trasmesso. La porta del TNC la porta Unix alla quale collegato il TNC. In genere sono chiamate /dev/ttyS0 (Dos com1), /dev/ttyS1 (Dos com2) Ora impostare la velocit e il tipo di comunicazione in "Impostazioni porta", e i parametri in "Stile porta". Uno stile di porta 8N1 indica 8 bit di dati, Nessuna parit e 1 bit di stop. 7E1 indica 7 bit di dati, parit e 1 bit di stop. 7O1 indica 7 bit di dati, parit dispari, e 1 bit di stop. Questi parametri DEVONO essere comuni sia al TNC che al GPS. Scegliere ora la corretta impostazione per il Gateway di questa interfaccia. Potresti avere diversi TNC e questa opzione pu essere diversa per ogni TNC. Se non intendi attivare le funzionalit di gateway lascia l'opzione "Disabilitato". Inserisci ora fino a tre percorsi UNPROTO. Xastir assume la parte XX VIA del percorso UNPROTO. possibile impostare tre percorsi differenti in modo da avere alternative nel caso le condizioni non siano buone. Se uno dei percorsi occupato allora Xastir passer al successivo ad ogni trasmissione e cos via. Se sei in una condizione di stazioni locali, semplicemente un WIDE2-2 pu essere una buona scelta. Se stai usando poca potenza e/o sei distante dal digipeater allora WIDE1-1,WIDE2-2 potrebbe essere la scelta giusta. Se conosci il nominativo del tuo pi vicino digipeater allora si potr usare NOMINATIVO_DIGI,WIDE2-2. La maggior parte di voi avr bisogno di un solo percorso. Se ci si trova in un area remota e il segnale difficilmente ascoltabile dalle altre stazioni allora potrebbe essere necessario aggiungere dei percorsi. Una buona norma quella di chiedere al gruppo di radioamatori locali quale il miglio percorso per i pacchetti in quella data area. File di inizializzazione e di spegnimento del TNC. Questi campi specificano i nomi di file presenti nelle cartella /usr/local/share/xastir/config. Ognuno di questi file di test contiene i comandi che si vogliono mandare al TNC all'avvio del programma e al termine dello stesso. CONFIGURAZIONE DEL TNC AX.25 Questa sezione descrive l'aggiunta e la modifica di interfacce TNC AX.25. Per interfacce AX.25 si intendono tutte quelle periferiche che usano i driver AX.25 di Linux. Questo driver a livello di kernel e periferiche come i Baycom o soundmodem possono essere usati come TNC. Queste periferiche devono essere rese disponibili (funzionanti) al programma prima del suo avvio. Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Permetti la Trasmissione", si permetter che i dati vengano trasmessi per radio. Scegliere ora la corretta impostazione per il Gateway di questa interfaccia. Potresti avere diversi TNC AX.25 o TNC Seriali e questa opzione pu essere diversa per ogni TNC. Se non si intende attivare le funzionalit di gateway lascia l'opzione "Disabilitato". Impostare il nome della periferica AX.25 come specificato dal file axports. Inserisci ora fino a tre percorsi UNPROTO. Xastir assume la parte XX VIA del percorso UNPROTO. possibile impostare tre percorsi differenti in modo da avere alternative nel caso le condizioni non siano buone. Se uno dei percorsi occupato allora Xastir passer al successivo ad ogni trasmissione e cos via. Se sei in una condizione di stazioni locali, semplicemente un WIDE2-2 pu essere una buona scelta. Se stai usando poca potenza e/o sei distante dal digipeater allora WIDE1-1,WIDE2-2 potrebbe essere la scelta giusta. Se conosci il nominativo del tuo pi vicino digipeater allora si potr usare NOMINATIVO_DIGI,WIDE2-2. La maggior parte di voi avr bisogno di un solo percorso. Se ci si trova in un'area remota e il segnale difficilmente ascoltabile dalle altre stazioni allora potrebbe essere necessario aggiungere dei percorsi. Una buona norma quella di chiedere al gruppo di radioamatori locali quale il miglio percorso per i pacchetti in quella data area. NOTA: Per usare le periferiche AX.25 con Xastir bisogna avere i privilegi di root. Se si vuole far eseguire Xastir da un utente qualsiasi, bisogner cambiare il suid del programma Xastir. Il comando seguente eseguito da root potr servire allo scopo: chmod a+s /usr/local/bin/xastir Come qualsiasi programma che venga eseguito in questa modalit, questo da considerarsi un rischio di sicurezza, visto che il programma ancora non stato sperimentato per reagire a tentativi di intrusione. Configurazione del GPS Configurazione GPS Seriali Imposta la porta seriale che usata dal vostro GPS. Valori comuni sono /dev/ttyS0 (dos com1) e /dev/ttyS1 (dos com2). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Ora seleziona la velocit di trasmissione espressa in bps e i parametri della porta sotto il menu "stile". Uno stile di porta 8N1 significa 8 but di dati, nessuna parit e 1 bit di stop. 7E1 indica 7 bits di dati, parit pari e 1 stop bit. 701 indica 7 bit di dati, parit dispari e 1 stop bit. Questi parametri devono essere gli stessi che usa il GPS. La maggior parte dei GPS usa 4800 bps 8N1. HELP-INDEX>Configurare un GPS in rete Configurazione di un GPS in rete. Questa opzione permette di condividere i dati provenienti dal GPS con pi programmi, e con pi computer in rete. Xastir pu ottenere i dati dal GPS attraverso il demone gpsd che permette, attraverso diverse connessioni, di condividere i dati del GPS con altrettante applicazioni. Impostare il nome dell'host (o l'indirizzo IP) e il numero della porta che gpsd utilizza per le connessioni (di solito la 5678). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Riconnetti su Errore", indicher ad Xastir di riconnettersi una volta che il flusso di dati si per qualche motivo interrotto. HELP-INDEX>Configurare il Server Internet Configurazione del Server Internet I server internet permettono di ricevere ed inviare dati a tutto il mondo attraverso internet. Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Permetti la Trasmissione", indicher che Xastir potr trasmettere via radio tutti i dati. Inserisci il nome dell'host (o l'indirizzo IP) e il numero della porta del server internet che vuoi connettere. Inserisci un codice di accesso valido per attivare la connessione, che permetter ai tuoi dati di essere trasmessi attraverso Internet. Se non hai un codice di accesso puoi spedire un mail a fgiannan@earthlink.net con tutti i tuoi dati e informazioni radio, per ricevere il codice. Selezionare Riconnetti in caso di errore, che indica a Xastir di riconnettersi nel caso la comunicazione sia interrotta. HELP-INDEX>Configurare una Stazione Meteo Configurare una stazione meteo Configurare una stazione meteo Seriale. Impostare la porta seriale alla quale connessa l'unit Meteo. Valori comuni sono /dev/ttyS0 (COM1) o /dev/ttyS1 (COM2). Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Ora bisogna selezionare la velocit della porta in bps sotto Configurazione della Porta, e i parametri sotto 'Stile di Porta'. Lo 'Stile della Porta' 8N1 indica 8 bit di dati, nessuna parit e 1 bit di stop. 7E1 indica 7 bit di dati, parit e 1 bit di stop. 7O1 usato per 7 bit di dati, parit, un bit di stop. Questi parametri devono essere gli stessi della porta dell'apparecchio meteo. L'opzione 'Tipi di dati permette di aggiornare per quale tipo di comunicazione seriale il programma dovr cercare. La funzione di autoriconoscimento (auto-detect) cercher per primi dei dati in formato binario come quelli della stazione meteo Radio Shack WX-200. Nel caso non vengano rilevati dati binari allora Xastir cercher per dati ASCII (utilizzati dalla stazione Peer Bros.). Configurare una stazione Meteo in Rete Xastir pu usare dati meteo reperendoli da server come il wx200d. wx200d permette pi connessioni, permettendo di condividere i dati meteo con pi programmi o computer. Inserisci il nome dell'host (o l'indirizzo IP) e il numero della porta del server Meteo che si vuole connettere . Selezionando "Attiva all'avvio" si ordiner a Xastir di caricare questa interfaccia all'avvio. Selezionando "Riconnetti se sconnesso", indicher a Xastir di riconnettersi in caso di errore. Come prima, selezionando il "Tipo di dati" si escluder l'auto-riconoscimento. HELP-INDEX>Configurzione allarmi Audio Configurazione Suoni Selezionare Configurazione, e quindi Suoni. Per usare questa opzione bisogna avere una scheda sonora e un programma che esegua i file con estensione .wav. Il "Comando per eseguire i suoni" il programma (e relative opzioni) che si vuole usare per ascoltare i suoni che vengono da Xastir. I campi conterranno il nome del file da eseguire, i campi sotto le opzioni imposteranno i parametri per le opzioni. Le possibili scelte sono: -Esegui un suono quando viene rilevata una nuova stazione. -Esegui un suono quando viene ricevuto un nuovo messaggio. -Esegui un suono quando arrivano dati da una stazione ad una distanza Min/Max come segnalato dall'utente. -Esegui un suono quando viene rilevata una stazione (via TNC) con una distanza min/max impostata nei limiti di apertura di banda.. HELP-INDEX>Configurazione delle unit di misura (Inglese/Metrico) Configurazione delle unit di misura (Inglese/Metrico) Questo seleziona che in che unit le grandezze verranno visualizzate dal programma. Il programma si configura automaticamente sul sistema metrico ma possibile cambiare questa possibilit. HELP-INDEX>Barra di stato inferiore Barra di stato inferiore Nella parte inferiore della finestra principale sono disponibili diversi messaggi di controllo. I messaggi di controllo generale sono visualizzati nella paste sinistra. Nella seconda casella da sinistra visualizzata la posizione sulla mappa del mouse in lat/lon. La terza casella visualizza il numero di stazioni ricevute e presenti nel database. La quarta casella visualizza il livello di zoom e visualizzer Tr se sulla stazione selezionata attivata la funzione di inseguimento. L'ultima casella visualizza lo stato di funzionamento delle periferiche, che sono visualizzate nell'ordine di inserimento da 0 a 9. Il controllo di stato delle interfacce diviso in tre aree, la parte alta indica il tipo di periferica, in mezzo indicato lo stato di flusso di dati e nella parte bassa indicato lo stato operazionale della periferica, blu per i vari TNC, verde per i GPS, giallo per per i servizi Internet, arancio per le periferiche Meteo. Nella parte centrale il flusso di dati entrante indicato con una freccia a sinistra per dati uscenti e a destra per dati entranti. Nella parte inferiore il verde indica che l'interfaccia collegata e funziona correttamente, il rosso che l'interfaccia collegata ma in uno stato di errore, l'assenza di colore indica che l'interfaccia non collegata. HELP-INDEX>Spostare la mappa e opzioni. Spostare la mappa e Opzioni Il movimento della mappa molto semplice e la velocit di visualizzazione della stessa dipendente dal tipo di sistema in uso e dalla quantit di dettagli visualizzata. Tutti i movimenti e ingrandimenti sono possibili cliccando il tasto sinistro del mouse (tenendolo premuto) sulla mappa. Questa azione visualizzer un menu di Opzioni. Tutte le funzioni di Zoom sono riferite al punto della mappa dove stato cliccato il bottone sinistro del mouse. Il menu degli zoom mostrer ulteriori opzioni: livelli di zoom da 1 a 3 sono per aree locali mentre livelli da 4 a 6 sono per aree maggiori, quindi pi il numero piccolo e pi l'area visualizzata stretta. Dal menu delle opzioni si pu anche spostare la vista della mappa con la funzione Pan, che provocher uno spostamento del centro della mappa. Le "informazioni della stazione" cerca per la stazione pi vicina al punto selezionato dal click del mouse. Se pi stazioni sono presenti apparir una finestra di selezione che permetter di indicare di quale stazione veramente si ha bisogno di informazioni. HELP-INDEX>Map Options and Map Chooser Opzioni della Mappa e Scelta della Mappa Opzioni della Mappa e Scelta della mappa Opzioni della Mappa: Mappe Automatiche (Attiva/Disattiva) Quando attivato, qualsiasi mappa trovata nella directory delle mappe verr visualizzata se nella sua area ricade la visualizzazione corrente. Questa funzione cercher in tutte le sottocartelle della directory delle mappe. Se pi mappe sono disponibili allora verranno sovrapposte, in questo caso un computer poco veloce pu produrre una visualizzazione lenta. Tuttavia possibile disattivare questa funzione e selezionare manualmente la mappa da visualizzare. Griglia (Attiva/Disattiva) Quando attiva, questa funzione visualizza una griglia ogni 10 gradi. Se si effettua uno zoom in avanti la risoluzione della griglia passer ad 1 grado. Livelli della Mappa (Attiva/Disattiva) Quando attivata, questa funzione permette di filtrare i dati di mappe su grandi aree. Questa opzione funziona solo con le mappe Tiger Line maps reperibili presso http://aprs.rutgers.edu. Ci non velocizzer il caricamento delle mappe ma produrr una visualizzazione di dettagli appropriata alla scala di visualizzazione. Colore in Aree Chiuse (Attiva/Disattiva) Questa opzione controlla il colore di riempimento delle mappe vettoriali. In alcuni casi pu essere necessario eliminare il riempimento di un'area per permettere la visualizzazione dei livelli sottostanti. Le mappe sono caricate in ordine alfabetico e quindi i livelli rispetteranno tale ordine. Scelta della mappa. Questa funzione visualizza tutte le mappe disponibili. Si potr selezionare pi di una mappa e poi premere OK per confermare la selezione. Il bottone Cancella chiude la finestra di dialogo della scelta delle mappe. Nota: Xastir utilizza il Datum WGS 1984 per le mappe. HELP-INDEX>File di mappe, Dos, Windows, Pixmaps e WX Counties File di mappe, Dos, Windows, Pixmaps e WX Counties Tipi di Mappa Xastir funziona con vari tipi di mappa. Tutte le mappe per il programma APRS[TM] Dos,Windows,Mac sono supportate. Dalla versione 0.3.2 possibile caricare anche mappe in formato Pixmap. possibile anche caricare le mappe di supporto per gli Allarmi Meteo Statunitensi. Dove posizionare le mappe Qualsiasi mappa Dos, Windows/Mac o Pixmap deve essere messa nella directory /usr/local/share/xastir/maps. Si possono creare sottocartelle per oridare il contenuto. Per esempio si pu creare una cartella ITALIA per mettere tutte le mappe che comprendono il territorio italiano, oppure si possono dividere le mappe per tipo: Pixmap e Dos. Esempio /usr/local/share/xastir/maps/ /italia/nord /italia/centro /italia/sud /dos/italia/ /dos/germania/ /pixmaps/italia/ /pixmaps/germania/ Le mappe Pixmap sono una combinazione di due file, un file binario grafico pixmap (.xpm) e un file di dati di locazione (.geo). Il file .xpm grafico in formato .xpm standard modificabile con qualsiasi programma di grafica che supporti questo formato. Il file di dati .geo permette di posizionare la mappa nel mondo. Ecco un esempio di file .geo: world1.geo FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Questo semplice file ha 4 componenti. La prima riga indica il file grafico a cui sono riferiti i dati che deve essere nella stessa directory del file di dati. La seconda linea imposta un commento alla mappa. Ogni linea che inizia con un # (cancelletto) indica un commento che non verr letto dal programma. Le ultime due linee connettono un pixel di coordinate x,y ad un punto della terra con coordinate lat/long. Due punti sono necessari e dovrebbero essere presi in alto a sinistra e in basso a destra dell'immagine. Per usare la mappa Pixmap, selezionare la scelta di mappa e in seguito il file .geo Mappe di Allerta Meteo USA Tutte le mappe di Allerta meteo USA dovrebbero essere posizionate in /usr/local/share/xastir/Counties. Dovranno poi essere create delle sottocartelle per lo stato USA a cui appartiene la mappa chiamate con l'abbreviazione di due lettere dello stato. /usr/local/share/xastir/Counties /CO/ /CO/COPARK.map /CO/CODOUGLA.map /CO/COJEFFER.map /CO/COZ001.map /CO/COZ002.map /CO/COZ003.map /NJ/ /NJ/NJOCEAN.map /NJ/NJBERGEN.map /NJ/NJMONMOU.map /NJ/NJZ001.map /NJ/NJZ002.map /NJ/NJZ003.map Ecco due siti dove possibile avere questo tipo di mappe: ftp://aprs.rutgers.edu/pub/hamradio/APRS/NWSCounties/ http://home.att.net/~kg5qd1/Maps.html HELP-INDEX>Informazioni stazione - Ricerca nel database FCC e RAC Informazioni stazione - Ricerca nel database FCC e RAC Informazioni Stazione mostrer tutti i dati acquisiti da Xastir per quel determinato nominativo. Il bottone Annulla Inseguimento toglier tutti i percorsi che sono stati memorizzati nello schermo. Il bottone Spedisci Messaggio aprir una finestra per spedire un messaggio. Se si installato il database FCC o RAC si pu fare una ricerca dei dati della stazione. I file di databse RAC e FCC devono essere posizionati in /usr/local/share/xastir/fcc. Questa funzione aggiunger l'indirizzo della stazione alle informazioni ricevute via radio. Per usare il database FCC bisogna scaricarlo (40Mb) da: ftp://ftp.fcc.gov/pub/XFS_AlphaTest/amateur/appl.zip o la nuova versione da: ftp://ftp.fcc.gov/pub/Bureaus/Wireless/Databases/uls/complete/l_amat.zip (The only file needed form this 40Meg zip is the EN.dat file) **** NOTA: per usare la nuova versione, il database deve essere prima ordinato!!! **** Assicurarsi di avere spazio disco libero (100Mb) Per ordinare il file eseguire i seguenti comandi: sort +4 -t \| EN.dat >EN.dat.sorted rm EN.dat mv EN.dat.sorted EN.dat Il database RAC si pu scaricare da: ftp://ftp.rac.ca/pub/cdncaldb.zip Xastir creer degli indici per ogni database, se un nuovo callsign immesso nel database allora Xastir creer dei nuovi indici e render subito disponibile il nuovo callsign. I prefissi speciali NON sono inclusi nei database. HELP-INDEX>Opzioni di Visualizzazione Opzioni di visualizzazione Queste opzioni permettono di visualizzare i dati delle stazioni attorno all'icona che indica la posizione della stazione sulla mappa. Altitudine (on/off) Quando attivo, una linea blu di dati appare sopra al nominativo, ad indicare l'altitudine della stazione nell'ultima posizione ricevuta. Direzione (on/off) Quando attivo, una linea verde di dati apparir sotto al nominativo. Questa indica la direzione in gradi del movimento della stazione l'ultima volta che stata ascoltata. Velocit Speed (on/off) Quando attiva, una linea di dati rossi indica la velocit della stazione l'ultima volta che stata ricevuta. Distanza/direzione (on/off) Quando attivata, due linee di dati verranno visualizzate alla sinistra dell'icona della stazione. La linea superiore indica la distanza dalla propria stazione, mentre la linea inferiore la direzione dalla propria stazione. Tracce della Stazione (on/off) Quando attiva, qualsiasi stazione in movimento lascer una traccia della posizione precedente fino ad un numero di 100 posizioni. Quando i dati della stazione diventano vecchi e l'icona della stazione diventa trasparente, la traccia indicata con un tratteggio. Potenza/Guadagno (on/off) Quando attiva, visualizza i cerchi di potenza e guadagno. Insegui stazione Questa funzione visualizza una finestra di dialogo simile a quella di localizzazione. Si pu inserire un nominativo o parte di esso e quindi selezionare "Insegui ora!" per centrare lo schermo su quella stazione e mantenerlo centrato per ogni successivo spostamento. Selezionando "Elimina Inseguimento" si eliminer la funzione. Il bottone "Annulla" nasconder la finestra senza apportare cambiamenti. Informazioni Meteo (on/off) Quando selezionato, verranno visualizzate le ultime informazioni meteo (temperature,velocit del vento/direzione/gust,umidit). HELP-INDEX>Messaggi Messaggi Spedire Messaggi e Apri Gruppo Queste funzioni sono molto simili. "Spedisci messaggio a" spedir un messaggio solo ad una stazione. I messaggi di gruppo sono pi generali. (ndt: la funzione messaggi di gruppo al momento non completamente funzionante) Ognuna di queste finestre visualizza una scheda di messaggio, una linea per il nominativo/nome gruppo e vari bottoni. Una volta inserito il nominativo della stazione, tutti i messaggi ricevuti da essa verranno visualizzati. Se non ci sono messaggi allora una nuova finestra permetter di inserire un nuovo messaggi da spedire. La lunghezza massima del messaggio di 250 caratteri. "Spedisci ora!" invier il messaggio al destinatario. Il bottone "Spedisci ora!" rimarr grigio fino a quando il messaggio non sar correttamente inviato. Qualsiasi messaggio ricevuto sar ordinato secondo la linea # e messo nella finestra dei messaggi. Se si nella funzione Gruppo, la lista dei messaggi visualizzer anche il nominativo del mittente. "Nuovo nominativo" visualizzer i vecchi messaggi della stazione oppure permetter la comunicazione con un'altra stazione. Il bottone "Cancella Messaggi" eliminer tutti i messaggi. Elimina i messaggi in uscita. Questo eliminer tutti i messaggi che sono stati spediti. Risposta automatica Questa funzione attiva la risposta automatica ai messaggi in entrata. Imposta risposta automatica Render possibile impostare il messaggio di risposta automatico. HELP-INDEX>Eliminare i percorsi dallo schermo Eliminare i percorsi dallo schermo Selezionare File e quindi "Elimina Percorsi" per eliminare tutti i percorsi delle dallo schermo e dal database interno. HELP-INDEX>Ripulire lo schermo dai simboli di stazioni Ripulire lo schermo dai simboli di stazioni Selezionare File e quindi "Elimina tutte le Stazioni". Questo eliminer tutti dati delle stazioni ricevute fino a quel momento eccetto la vostra. HELP-INDEX>Rispondere ad un log Rispondere ad un log Selezionare "Apri file log" e selezionare un file di log creato dal TNC o dalla rete con la funzione sotto le opzioni di rete. La stazione user il file di log come se fosse direttamente connessa al TNC. HELP-INDEX>Localizzare una Stazione Localizzare una Stazione Selezionare Vista e quindi "Localizza Stazione" per fare apparire una finestra di dialogo che permette di inserire un nominativo (completo, non case sensitive). Se si vuole cercare un nominativo parziale allora bisogna deselezionare "Nome esatto". Selezionando "Maius/Minus Esatti" verranno osservati anche i criteri di Maiuscole/minuscole. Selezionando "Localizza Ora!" il Display verr centrato sulla stazione cercata al livello di zoom corrente. "Annulla" chiuder la finestra di dialogo. HELP-INDEX>Creare ed usare i Salti alla Stazione Creare ed usare i Salti alla Stazione Selezionare Visualizza e quindi "Vai alla Stazione" per visualizzare una finestra di dialogo. La prima volta che si usa questa funzione la finestra di dialogo sar vuota. Si pu creare una nuova vista selezionando "Nuova posizione", inserire il nome e quindi Aggiungi. Per usare le posizioni registrate baster selezionare la posizione e quindi il tasto "Vai!" per centrare la posizione registrata. E' possibile eliminare una posizione selezionandola e selezionando "Elimina". HELP-INDEX>Inseguimento di una stazione Inseguimento di una stazione Selezionare Visualizza e quindi Insegui stazione. Inserire il nominativo da inseguire (tutto o parte di esso) e quindi selezionare "Insegui Ora!". Appena la stazione si muove, essa viene centrata nello schermo. Per disattivare questa funzione bisogna selezionare "Annulla Inseguimento". HELP-INDEX>Tabella dei simboli Tabella dei Simboli Simbolo Gruppo / Gruppo \ ! Triangolo w/! Triangolo w/! " Nuvola Nera Nuvola da Pioggia # Digi DIGI $ Telefono Simbolo $ % DX DX & GATEWAY-HF GATE ' Piccolo Aereo Incidente Aereo ( Nuvola Nuvola ) TBD * Fiocco di neve Fiocco di neve + Croce rossa , L inversa - Casa con antenna Omnidirezionale . Piccola x / Punto rosso 0 0 in un quadrato Cerchio 1 1 in un quadrato 2 2 in un quadrato 3 3 in un quadrato 4 4 in un quadrato 5 5 in un quadrato 6 6 in un quadrato 7 7 in un quadrato 8 8 in un quadrato 9 9 in un quadrato GAS : Fuoco ? ; Tenda Tenda < Motocicletta Banderuola = Locomotiva > Auto Auto ? POS Antenna ? in un quadrato @ URAGANO/TEMPESTA URAGANO/TEMPESTA A Pronto Soccorso Quadrato B BBS Neve a vento C Canoa D D in un cerchio E E in un cerchio Fumogeno F F in un cerchio G Antenna Grid Square ? H Hotel/Letto I TCP/IP ? J J in un cerchio Fulmine K Scuola Casa L Faro Faro M Mac N NTS ? O Pallone Aerostatico P Auto Polizia Rx Q Cerchio con Cerchietti Cerchio con Cerchietti R RV Ristorante S Shuttle Satellite T Temporale (cloud/bolt) Temporale (cloud/bolt) U Scuolabus Sole V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Elicottero Y Barca a vela Z Windows [ Corridore Bagno \ Triangolo DF ] Packet Mail Box ^ Grande Aereo Grande Aereo _ Stazione meteo WS-Digi ` Antenna parabolica a Ambulanza b Bicicletta Nuvola a vento c antenna DX d Caserma Pompieri Antenna DX e Cavallo Nuvola a Cirro f Mezzo Pompieri FC Cloud g aliante Banderuola (2) h Ospedale HAM i Isola Isola j Jeep Jeep k Camion Camion l Puntino Puntino m MIC Pietra Miliare n N Small Triangle o EOC Punto con cerchietti p Cagnolino Punto con cerchietti q GS Antenna GS Antenna r Traliccio Antenna Traliccio s Nave Nave t TS ? u 18 Wheel Truck v Van Punto con cerchietti w H20 Inondazione x X Windows Punto Rosso y House w/Yagi Casa con Yagi z X Windows { NEBBIA NEBBIA | Linea Nera Linea Nera } TCP TCP ~ Barca a vela Barca a vela Xastir-Release-2.2.4/help/help-Portuguese.dat0000664000175000017500000042420415151324131020041 0ustar hibbyhibbyHELP-INDEX>READ ME FIRST - License READ ME FIRST - License For the most current information please read the README file in the Xastir directory. Also see the LICENSE and COPYING files for additional information. Remember this program is intended to be used by the HAM community, in the USA the FCC restricts you from transmitting over RF if you are not a licensed HAM. Users in countries outside the USA should seek their local government restrictions. LICENSE: XASTIR, Amateur Station Tracking and Information Reporting Copyright (C) 1999,2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group 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. but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. More information on the program can be found at: http://www.xastir.org http://github.com/Xastir/Xastir There are some mailing lists available that are Xastir-specific. Please subscribe to one or both of them for the latest Xastir information. See http://www.xastir.org to subscribe. For more information on the GNU License look at: http://www.gnu.org HELP-INDEX>Welcome! and Notes from the Authors Welcome! and Notes from the Authors XASTIR, or X-windows Amateur Station Tracking and Information Reporting. Xastir is an APRS(tm) program that is Open Source and free to use and pass out to others. Currently this program is in development and should not be seen as a finished product! Your help will be needed to make this a better program. If you have programming skills and/or can write documentation, your help may be needed! We have a lot of ideas but very little time, so if you think you can add something to the effort let us know! APRS(tm) is a Trademark of Bob Bruninga, his home page is at "http://web.usna.navy.mil/~bruninga/aprs.html". A great deal of information on APRS(tm) can be found in the APRSdos documentation written by Bob Bruninga. An additional source of information is the APRS(tm) specification, available from http://www.tapr.org . HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Starting Xastir for the first time Starting Xastir for the first time When first running Xastir, you should start it from a terminal window so that any warning or error messages can be seen. On most systems a path is set up to run programs in /usr/local/bin and all you need to do is type "xastir &" at the prompt. On systems that do not have this path installed type "/usr/local/bin/xastir &" to start the program. The '&' character will cause Xastir to start in the background, leaving the terminal window available for other uses. You may also set the language choice at this time. To set the language or change the current language choice, call Xastir with the option '-l': xastir -lEnglish Language options are: xastir -l Dutch xastir -l English xastir -l French xastir -l German xastir -l Italian xastir -l Portuguese xastir -l Spanish xastir -l ElmerFudd xastir -l MuppetsSwedishChef xastir -l OldeEnglish xastir -l PigLatin xastir -l PirateEnglish The chosen language will be stored in your config file, so it is preserved for the next time you call Xastir. For new installs Xastir will default to English until you change the language with this command line option. The menus on the top may be accessed with the mouse or with keyboard shortcuts. The keyboard shortcuts may not work correctly with num-lock on. You will need to configure interfaces in order to actually use Xastir. Interface configuration is detailed under the "Configuring Interfaces" help topic and its subtopics. If you are operating in a situation where a coordinate system other than the default DD MM.MMMM system would be helpful, you may select your preferred system by going to File|Configure|Coordinate system. Any of the supported coordinate systems my be used as input by using the Coordinate Calculator. HELP-INDEX>Configure the Station Information Configure the Station Information Click on File, then Configure, then Station. Fill in your Amateur Station call sign. Fill in your station position if you are not using Xastir with a GPS unit. You can locate your general position on the map with Xastir and use the position given by the cursor placement over the map. This position will be viewable in the box at the bottom of the Xastir screen 2nd from the left, whenever the mouse is over the drawing area. You can also choose "Move My Station Here" from the right-click menu while your mouse is over your location. If you have a GPS you can skip this and set up the GPS later. "Send Compressed posits", if selected, will transmit in the newer compressed format. This format will reduce the amount of data on the air, thereby increasing the capacity of the APRS(tm) network. The maximum precision of the transmitted position is also higher. Some older programs, including recent versions of WinAPRS, do not decode this format yet. Findu.com might also have trouble with it. We transmit course/speed in this format but not altitude. In order to send course/speed AND altitude requires adding nine characters to the packet which negates part of the reason to use compressed posits. To select a symbol to be used for your station you need to specify a group and a symbol character. You can manually fill in these fields, or press select to graphically choose a symbol. There are two groups of symbols available. A text description of each symbol can be found in the "symbol table" help topic. For some symbols of the secondary group you can specify an overlay. With that a symbol will be displayed together with an additional overlay character, e.g. a car symbol with the number 1 overlay-ed on top of the symbol. For using overlays you need to select a symbol from the secondary symbol table and enter the overlay character to be shown in the group/overlay field. Only numbers and uppercase characters are allowed as overlay characters. According to the APRS(tm) specification not every symbol can be overlay-ed, Xastir doesn't enforce this, but some other programs may. Note that not all of the symbols have been implemented in the graphics chooser yet, and some of them are not per the APRS(tm) spec yet. Next, enter the data for the power/height/gain of your station. This is useful information but is not required; simply select "Disable PHG" to disable it. These choices present a granular representation of your stations range. Select the combination of values closest to the description of your station. Please use height above average terrain (HAAT) for the height value. Do NOT use average height above sea level or height above ground. All values must be specified if you wish to transmit PHG information. Another option would be to specify the RNG in the comment field in miles instead of using PHG. See the APRS(tm) spec for details. For Gain use the gain of your antenna in dBi. (FIXME: dBd? spec is unclear, I think it's implying dBi because it says "in absence of any data, stations are assumed to be running 10w to a 3dB omni at 20ft. A typical omni is only 3dBi.....) Note: The gain setting is really intended for vertical antennas; the gain setting for a beam should be quite a bit below the forward gain of the beam. This is because with directivity set, the PHG circle is only offset by 1/3rd of its size toward the specified direction. Setting gain higher will enlarge the whole circle unrealistically, rather than increasing the directivity. There was talk several years ago about amending the specifications to better deal with beam antennas, but nothing was changed. Enter a comment, not required but it will add insight on your station. A common thing to enter here is your preferred e-mail address. It will be transmitted along with your posits. Position ambiguity will allow you control how accurately you transmit your position. A setting of none will allow your station to transmit the exact position you have entered or received from a GPS. The other choices will place you somewhere in the range of the choice you selected. Note that this may throw some non-spec compliant stations for a loop. Findu.com doesn't understand position ambiguity. Clicking OK will save your changes, Clicking on Cancel will keep the previous settings. HELP-INDEX>Configure Default Operation Configure Default Operation Click on File, then Configure, then Defaults. This page sets up some standard defaults for the program operation. Transmit Station Option sets the type of packet your station will transmit its data as. IGate Options will set your station up as an Internet-RF gateway. This option should be used with caution; As a ham you are responsible for the data that comes in via the Internet and is transmitted via RF. You also will need to choose an IGate option on each interface in order for the IGate to function. If you want to have your IGate forward NWS weather alerts to RF, you must create a ~/.xastir/data/nws-stations.txt file listing each call or NWS station (like "PHISVR") that you would like to transmit via RF. This feature also works for gating specific callsigns to RF. Bob Bruninga, WB4APR, recommends gating these calls to RF: SCOUTS, SATERN, KIDS, REDCROSS, FOUR-H, YOUTH, GUARD, MARS, JOTA. See his link: "Generic Callsigns for National Events" off this web page for his current list of recommended callsigns: http://www.ew.usna.edu/~bruninga/aprs.html "Transmit Compressed objects/items?", if selected, will transmit objects and items in the newer compressed format. The maximum precision of the transmitted position is higher, and the transmission is shorter, but some older programs do not decode this format yet. Currently this only compresses "standard" objects/items with an optional speed/course. It won't compress area, signpost, or DF objects/items, and won't currently represent altitude in "standard" objects/items. "Pop up new Bulletins", if selected, will cause Xastir to bring up the bulletin dialog when bulletins within the configured range are received. "View zero-distance bulletins" will cause bulletins with no known location not to be displayed or cause pop-ups. "Warn if Modifier keys" will cause Xastir to print a warning if you attempt to use Xastir while num-lock, scroll-lock, or caps-lock is engaged. Some users report the screen blanking on them and similar problems when they attempt to use Xastir with one of these modifier keys on. You can also select "Activate alternate net?" and choose an altnet call from this dialog. Altnet allows you to have a private APRS(tm) network among the stations that also have altnet configured, and have the same altnet call entered. "Disable Posit Dupe-Checks" disables the check for duplicate copies of a position. This should only be used when a station might return to exactly the same position (within 60' or so for non-compressed positions) and you wish to see the duplicate positions and/or tracks displayed on the map. This option is almost never needed in practice, but can be useful for special events like search and rescue operations. "My Trails in one color" shows all trails with your callsign but different ssids in the same color. With My trails in one color selected, mycall-1 and mycall-2 are shown in the same color. With My trails in one color unchecked, mycall-1 and mycall-2 are shown in different colors. "Load predefined objects from file" and the pick list which follows it allows you to replace the list of Predefined objects that are accessible from the right click pop-up menu with your own list of objects. A set of standard Search and Rescue objects and a set of typical public event objects are supplied in the predefined_SAR.sys and predefined_EVENT.sys files. You may also use these files as a template to create a predefined_USER.sys file. See the instructions in the predefined_SAR.sys and predefined_EVENT.sys file for details on how to define objects for a custom predefined objects menu. If both "Load predefined objects from file" is selected and a file that exists in the xastir/config/ directory is selected, then the objects defined in that file will be shown on the Predefined objects menu. The unaltered predefined_SAR.sys file defines the same objects as the default menu. HELP-INDEX>Configure Timing Configure Timing Click on File, then Configure, then Timing. Posit TX Interval specifies how often your station's position will be transmitted. For fixed stations a good recommendation is every 30 minutes, and definitely no less than 10 minutes. Mobile stations may wish to use a faster rate. Note that if you're using SmartBeaconing, this slider is ignored. Object/Item Max TX Interval is the maximum interval used for sending out objects and items. Try to keep these intervals reasonable, as transmitting to a long path every 5 minutes will really take up a lot of the air time. A decaying interval algorithm is triggered any time an object is created, modified, or killed. The transmit interval will increase until it hits the max interval indicated by the slider. GPS Check Interval will set the interval of time to look at the GPS for new data. This is available for stations using an HSP or shared cable with their TNC. Dead-Reckoning Timeout adjusts how long a position is assumed valid for the purpose of estimating its current position. New Track Time adjusts how many minutes must elapse before a new separate track is started. Caution: setting the new track time to 0 will turn off the display of all tracks. RINO -> Objects Interval adjusts how often waypoints are downloaded from an attached Garmin RINO radio/GPS unit. APRS(tm) Objects are created out of any waypoints beginning with "APRS". The "APRS" prefix is removed when creating the Object names. Station Ghosting Time specifies the ghosting interval. Stations that have not been heard in the given period will appear ghosted on screen. Station Clear Time specifies when a station will be removed from the screen. Station Delete Time specifies the number of full days before data from a station will be entirely removed from the Xastir database. Serial Inter-Char Delay specifies a wait time in milliseconds between each character sent to an attached TNC. New Track Interval (degrees) specifies distance in lat/long degrees at which a new track segment is started. Caution: setting new track interval to 0 degreees will turn off the display of all tracks. Snapshot Interval (minutes) specifies how often snapshot files will be written if either File->PNG Snapshots or File->KML Snapshots are selected. HELP-INDEX>Configure Audio Alarms Configure Audio Alarms Click on File, then Configure, then Audio Alarms. To use this option you must have a sound card and a program that will play wav files. The Audio Play Command should contain the program you want to execute to play the audio file (and any command line options). That of course doesn't work if the only sound card in the system is used for a soundmodem... Each type of alert has a check-box to enable it. The fields will contain the name of the file to play. Fields under the option will set parameters for the option. The current choices are: Play message on hearing a new station. Play message on receiving a new message. Play message on receiving data from a station within the min/max distance of your proximity settings. Play message on receiving data from a station (via TNC) within the min/max distance of your band opening settings. Play message on receiving and displaying a new weather alert. There is a standard set of sounds available most places where Xastir can be obtained, please see the file INSTALL for more information. HELP-INDEX>Configure Speech Configure Speech Synthesis To use this option you must have a sound card and the 'festival' speech synthesis software installed. Install Festival and start it in 'server' mode prior to starting up XASTIR. The normal command for this is "festival_server &". If you use the "festival --server" option instead (old method), you may run into problems with connections getting rejected by the server. Once you have festival installed, Xastir will have the ability to speak using the following choices: New Station - Announce the call of a new station. New Message Alert - Announce the arrival of a new message. New Message Body - Speak the contents of a message. Proximity Alert - Announce when receiving data from a station within the min.max distance of your proximity settings. This option uses the proximity settings found in the Audio Alarms menu. Tracked station Proximity Alert - Announce when receiving data from a station within the min.max distance of the tracked station. This option uses the proximity settings found in the Audio Alarms menu. Band Opening - Announce when receiving data from a station (via TNC) within the min/max distance of your band opening settings. This option uses the distance settings found in the Audio Alarms menu. New Weather Alert - Not implemented yet. Info on Festival may be obtained from: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configure Smart Beaconing Click File, then Configure, then Smart Beaconing. The main "Enable SmartBeaconing(tm)" Will cause Xastir to transmit positions at various rates and locations based on the movement of the station. It creates more realistic trails and makes dead-reckoning much more accurate. This option is only useful in a mobile station with a GPS attached. There are several options available to customize the operation of SmartBeaconing: High rate The interval (in seconds) at which beacons are sent when the speed is above the High speed setting. This parameter is also used to compute a beacon rate based on speed when traveling between the high and low speeds. High speed The speed threshold that will cause beacons at the rate specified above. Low rate The interval (in minutes) at which beacons are sent when the speed is below the Low speed setting. Basically consider this to be the stopped beacon rate. This parameter is not used at all when traveling at a rate of speed higher than "Low speed". Low speed The speed threshold that will cause beacons at the rate specified above. Minimum Turn The minimum degrees that corner pegging can occur at "High speed" or above. Lower speeds will require more degrees of turn to trigger a posit, based on the value of "Turn Slope" below. Turn Slope Fudge factor for making turns less sensitive at lower speeds. The parameter doesn't have any units. It ends up being non-linear over the speed range the way the original SmartBeaconing(tm) algorithm works. Wait Time The time in seconds between corner-pegging beacons, prevents multiple beacons in short succession. HELP-INDEX>Configure Units of Measure Configure Units of Measure The default selection is for the Metric System: mm, cm, km/h, etc. To select English units, inches, feet, MPH, etc. Click on File, then Configure, then toggle the "Enable English Units" check-box. HELP-INDEX>Save Config Now! Save Config Now! This button will save all of the current configuration to the config file. Note that when Xastir is closed, it also saves configuration to the config file. HELP-INDEX>Bottom Status Bar Bottom Status Bar At the bottom of the window various status messages are available: In the first box on the left general status messages are displayed for a short time. The second box displays the current lat/long or UTM, and Maidenhead grid square position of the mouse over the map. If file|configure|Dist/Bearing Status is selected, this box will also contain the course and bearing of this position relative to your station. A third box is used to display how many stations are on screen, and how many are in the database. The fourth box will display the current zoom level and will display "Tr" if the station tracking is on. At some zoom levels the Tr is not displayed properly due to the size of the box. The fifth box indicates whether logging is enabled. The last area will display the device status for each interface. Each will display in order first to last or 0 to 9. The interface status is separated into three areas, top device type, center data flow, and bottom interface operational status. The device type will show what interfaces are configured. The color will show what type of device the interface is configured for. Blues are for the various TNC devices; Greens will show the GPS devices; Yellow for Internet Servers; Orange for WX interfaces. The center will show data flow in (arrow pointing left) or data flow out (arrow pointing right) for that interface. A green box at the bottom will show if that interface is active. A red box will show if the interface is active but in an error condition. Otherwise nothing will show if the interface is not active. HELP-INDEX>Moving the Map and the Options Menu Moving the Map and the Options Menu Map movement is very simple, ease and quickness of movement is dependent on your processor speed and the amount of detail you load. Hint: You can disable all maps in the maps menu in order to move around quickly, then enable maps again. Zooming: Zooming can be accomplished by right clicking on the map (and holding the button down). This will bring up an options menu, with choices to zoom in or out a single level, or to change to one of the preset zoom levels. All zooming functions from the options menu will zoom in or out at the point on the map where you clicked the right mouse button. Zoom levels have a cascade menu. Levels 1-64 are for very local areas and levels 256 and above are for large areas. The lower number the level, the more local the area. A quicker zoom in function is to push and hold the left mouse button, drag it across the area of interest and let go. The map will zoom to approximately the size of the square you just described with the mouse drag operation. The "move" and "measure" toolbar check-boxes must be disabled for this feature to work. Clicking the middle button zooms out with a factor of 2, centering where you clicked as well. The map can also be zoomed with the keyboard Page-Up/Page-Down keys, or the "In" and "Out" buttons in the toolbar. The zooming in this case keeps the same map center (no centering). Panning/Centering: The map can be centered at a specific location by choosing center in the right-click options menu. Panning is also accomplished by using the options menu, or by using the arrow buttons on the toolbar. The map position will shift a portion of a screen. Enough data from the previous screen should be available to re-orient yourself. The map can also be panned with the keyboard arrow keys. More About Options Menu: Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" The "Station Info" selection on the options menu will look for the station closest to where you right-clicked the mouse. If more than one station is close to that position a "Station chooser" list will appear, then you can choose what station's data you want to look at. If only one station is close to the mouse pointer then that station's data will display immediately. For mobile stations with a lot of track data this could need some time on slow computers. Note that expired stations still have their data stored in the Xastir database, and if one knows a station's former location, one can still view its info in this manner. Use the "Display Expired Data" option to display some data that disappears for ghosted stations, like speed/altitude, etc. With "Last Pos/Zoom" you can restore the previous map view by restoring the previous values of the map zoom and centering values. For Object and Item information, please see the help topic "Objects and Items" Draw CAD objects lets you create polygons on screen, for tactical or presentation use. This feature is still under construction. "Move my Station here" Allows you to move your station to a specified map location without editing the station configuration. HELP-INDEX>Objects and Items A station could place several different objects on the map, with their position transmitted to other stations. The object names are less restrictive than the normal station names. Objects and items are nearly the same things, but their use could differ a bit. Objects are generally used for moving or variable things such as thunderstorms, while items are generally used for more inanimate things, such as water stations. Because items may not be decoded by some flavors of APRS(tm) programs, objects are often used for inanimate things, too. Besides normal objects with a symbol at its position there are some special objects available. Area objects are useful for a variety of operations in which you want to draw or highlight an area of interest on the map. They can also be used to draw trails/roads/boundaries, watch boxes for severe weather, runways, perimeter of a search area or of a public service event, areas of damage, areas to stay out of, buildings that aren't on the map, checker/chess boards for gaming on APRS(tm). :-) Note that area objects are not implemented on all versions of APRS(tm) programs, and some of the details of how they are displayed may also be different on other programs. For the other three, probability circles, signposts and DF objects, see below. Objects/Items are retransmitted at a decaying rate up to the max interval specified in File|Configure|Timings. "killed" objects/items are also retransmitted in this manner until they expire from the queue (currently 20 transmits). Objects/Items are persistent across Xastir sessions, and are stored in ~/.xastir/config/object.log. This file may be cleared by selecting "Clear Object/Item history" from the Stations menu. The Object/Item creation option in the right click menu will bring up a dialog with the position of your object filled in based on where you clicked the mouse. You may fill in the details, and add an object/item from this menu. The Object/Item modification option brings you the object modification dialog. It is similar to the object creation dialog, except the object's current information is already filled out, and the object's name and a few of the other options can't be changed. You could also delete the object with this option. Objects and items can be moved with the mouse if the "Move" check-box on the toolbar is enabled. The Predefined Objects option in the right click menu allows you to rapidly place standard Search and Rescue objects without having to go through the Object/Item creation dialog. These objects include standard Incident Command System symbols for ICP, Staging, Base, and Helibase, as well as SAR objects for PLS, IPP (with 4 area circles), and LKP If an object of the same name as an object you select off the list allready exists, a new object will be created with a number appended to the end. For example, the first time you select Staging from the Predefined objects menu, an object named Staging will be created. If you then create an additional Staging object from the Predefined objects menu, it will be named Staging2. Heli- (and user defined objects ending in a "-") will be created as Heli-1, Heli-2, Heli-3, etc. If you have recieved one of these standard objects that was transmitted by another station, your first object will be named with an appended number. You may wish to assign a tactical call to your object in this situation (for example, replacing ICP2 with a tactical call). The Predefined Objects menu is customizable by modifying the files predefined_SAR.sys, predefined_EVENT.sys, and predefined_USER.sys, and then selecting one these files through the File/Configuration/Defaults dialog. See the predefined_SAR.sys file for details. Description of the entries in the object dialogue: = Signpost = This makes the object a signpost object. These signs can contain one to three characters, and currently appear in Xastir as a blank sign. Station Info shows the value contained on the sign. = Area Object = This makes the object an area object, and enables the area object controls described below. = DF Object = This is a direction-finding report. Enabling it allows you to choose Omni or Beam report, and allows you to put in the specifics for each. See: http://web.usna.navy.mil/~bruninga/dfing.html and the APRSdos documentation for details on these useful techniques. (FIXME: Separate section on DF'ing techniques?) = Probability Circles = This allows you to define the radius (in miles) of two circles centered on the object or item. Min is the radius (in miles) of the smaller, inner circle, and Max is the radius (in miles) of the larger, outer circle. These circles are drawn in red. They can be used to assist in planning Search and Rescue operations. To create more than two circles, add additional probability circle objects to the same location. Probability circles may not be displayed by other client software. = Name = This is the name of the object or item. It may be up to 9 characters long, with spaces allowed inside the name. When modifying an object, this may not be changed. To rename an object you must delete the original and then create a new object. Note that if you select Signpost/Area Object/DF Object that this field and perhaps others are cleared. Enter the name AFTER you've selected the type of object it will become. = Station Symbol = You may select a symbol for the object. Press select to choose graphically, or see the symbol table help section for descriptions of each symbol. Note also that area objects, signpost objects, and DF objects have special fixed symbols and therefore can't be selected here. Those particular symbols get automatically assigned when you change to that type of object. = Location = The location of the object is specified here. If you selected "Create Object/Item" from the right-click menu, the location you clicked will be filled in. If you moved an object with the mouse, the new location will be in these fields. You can also type in a location, for instance you may be placing an object from an over-the-air voice report. = Generic Options = You may specify the speed, direction, and altitude of objects here. Some object types cannot have a speed or direction, in which case the fields are grayed out. = Signpost Text = If the object is a signpost object, you may specify the 1 to 3 digit number that appears on the sign here. Note that Xastir doesn't display signpost objects properly yet. = Area Object = Area Objects are used to highlight specific parts of maps, or to draw extra detail onto maps. This will be done with the following entries: = Bright Color = Use the brighter version of the colors allowed. = Color-Fill = The area should be filled, not just outlined. This may be useful to exclude an area from a search or other event. = Object Type = Choose from the geometric shapes allowed. = Object Color = Choose the color in which the object will display. This is also affected by the "Bright Color" option above. = Object Offset Up = In hundredth of a degree latitude. An unfortunate detail of the spec, and hard to calculate easily. Suffice it to say that you can change the size of the object once you place it. = Object Offset Left except / = In hundredth of a degree longitude. See above. = Object corridor = This is the width of a line area object. Useful for runways, weather watch boxes, describing an area of interest or an area of exclusion, etc. Always delete your objects and items when you are done with them! Don't just allow them to expire from your cache, as they may hang around on other peoples' screens for an extended period. Description of weather watch boxes: Watch boxes and "areas of maximum concern" (AOMC) generated by the WXSVR (http://wxsvr.net/) are colored as follows: Yellow dashed = Severe Thunderstorm Watch (looks like crime scene tape) Yellow solid = AOMC for Severe Thunderstorm Warning Red dashed = Tornado Watch Red solid = AOMC for Tornado Warning. Green dashed = Mesoscale (larger) discussion area Blue dashed = Test Watch Blue solid = Test Warning HELP-INDEX>CAD Objects CAD Objects [CAD object support has moved from the right click menu to Map/Draw CAD Objects]. CAD object support is preliminary at this time. Features and the user interface are subject to change. CAD objects are arbitrary shapes that you can draw on maps in xastir, but can't transmit by APRS. Currently supported CAD objects are: Polygons: Closed areas of at least three points. To create a CAD object, first press the Draw radio button on the toolbar. This will change the cursor to a pencil. Begin drawing a polygon by clicking with the middle mouse button (or both buttons on a two button mouse, for which you will need to have three button mouse emulation enabled). This places a point on the map. Now move the cursor somewhere else (the normal left click/right click navigation and zoom functions still work normaly) and click the middle mouse button again. This draws a line between the two points you have selected. Middle click again to draw another line segment and keep repeating until you have drawn all except for the closing line segment of your polygon. To close the polygon, select Map/Draw CAD Objects/Close Polygon. This will close your polygon and bring up a dialog that will allow you to enter a name, comment, and probability for the polygon. When you have finished drawing CAD objects, exit the CAD drawing mode by deselecting the Draw radio button on the toolbar. CAD objects can be edited from the View/CAD Polygons menu and from the Map/Draw CAD Objects/CAD Polygons menu. CAD objects can be deleted from the Map/Draw CAD Objects/Erase CAD Polygons menu. HELP-INDEX>View Menu View Menu Options The View menu presents various ways to look at data in Xastir. Bulletins This is the APRS(tm) bulletin board, where important announcements are posted. If you are connected with the internet interface, it is a good idea to set the range field to a few hundred miles, to ignore posts from other portions of the world. "0" in the range field means the entire world. Click the "Change range" button to make changes to this field effective. Xastir currently does not support sending bulletins. Incoming bulletins will open this dialog automatically if you select "pop up new bulletins" in the Configure|Defaults dialog. The "View zero-distance bulletins" button enables viewing bulletins for which you don't have a range yet (they haven't sent a posit yet, but you received a bulletin from them). If this is unchecked, you must get a position from a station, and the station must be within the range selected (or range must be set to zero), in order for the bulletin to be viewed. Incoming packet data This displays the incoming data on your TNC or internet interface. The radio buttons below select if you want to see only TNC data, only internet data, or both. Mobile Stations This is a list of stations that are moving. Stations qualify for this list if they have moved (more than one position received for them), the symbol of the station is not considered. Information shown includes course, speed, altitude, position, number of packets received, number of visible GPS satellites, course from your station, and distance from your station. All Stations This option displays a table of all stations sorted alphabetically. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Local stations This option displays only stations that are heard via your TNC. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Last Stations This option displays a table of all stations sorted from most recently heard to least recently heard. It includes the number of packets heard, the time the station was last heard, the path that the most recent packet took, the PHG, and the comment of the station. Objects & Items This option displays only objects and items. It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. Own Objects & Items This option displays only objects and items that you control (i.e.: Have sent the most recent update for). It includes the number of packets heard, the time the objects/item was last heard, the path that the most recent packet took, the PHG, and the comment of the object/item. A ghosted icon indicates that the object has been deleted. Weather Stations This option displays a table of all the APRS(tm) weather stations and their data. Data includes wind course, wind speed, wind gust speed, temperature, humidity, barometric pressure, rain in the past hour, rain since midnight, and rain in the last 24 hours. Own weather data Displays your weather data if you have a weather station and have configured Xastir to access it. Weather Alerts Displays weather alerts received, including the alert flags, alert source/type, alert destination, expiration, message, and effected location. This data is used for the alert highlighting. Double-clicking on an alert will request further information about it via finger from the online WXSVR. This only works if you have internet access; future versions may access this data over radio as well. Message Traffic Shows all message traffic while the window is open. It includes the source, destination, interface, and message. The range option can limit this display to nearby stations, much like the range control on bulletins. A range of 0 causes all messages to be displayed. GPS Status Shows the status of your GPS unit, including the type of fix and number of satellites acquired. Uptime Shows the amount of time elapsed since Xastir was started. HELP-INDEX>Map Menu and the Map Chooser Map Menu and the Map Chooser Map Menu: Map Chooser This will present you with a list of map directories and/or files in your map directory. Checking the "Expand Dirs" option toggles the expansion of directories into individual map files. The properties dialog allows more advanced controls, and is described below. Click on map names to highlight them, this will cause them to be displayed when you click the OK button. You may select any number of maps. Clicking "Clear" will select no maps, clicking "Vector" will select only vector maps. The three "topo" options will automatically select all GeoTIFF images of the listed size. Clicking the OK button will display the selected maps. Cancel will abandon any changes. Map Chooser Properties Clicking the Properties button will bring up a dialog where you can specify the layer in which maps appear, and in which zoom levels they appear. Higher layer numbers are displayed on top of lower numbers. The range may be specified from -99999 to 99999; it is suggested that you space your layering numbers widely to allow later insertion of additional map layers. From this dialog you may specify whether a vector map is drawn with color fills. This is a per-map setting; the global disable option on the Maps menu can override this. The Filled setting is ignored for raster maps (images). A setting of "auto" allows a dbfawk file to control this parameter directly (usable only if dbfawk is compiled in and the map in question is a Shapefile). You can also select whether a map is considered by the "Auto maps" feature here. Finally, you can specify the minimum and maximum zoom levels at which a map is displayed. This is useful to prevent very detailed local maps from loading at very wide zoom positions, and visa-versa. A minimum zoom of 10 means a map will be displayed at all zooms including and above 10. Likewise, a maximum zoom of 256 means a map will be displayed at all zooms below and including 256. Map Display Bookmarks See the help topic "Creating and using Map Display Bookmarks" Locate Map Feature This option brings up a search dialog where you can search through the labels in a GNIS file to find a specific location. It will center the map on the new location if it is found. The "GNIS File:" entry is saved between calls and between invocations of Xastir. You must put GNIS files into the xastir/GNIS directory in order to use this feature. Find Address This option brings up a search dialog where you can enter an address. It will center on the map if the address is found. The path to the geo-coder file is saved between calls. Coordinate Calc This option opens a simple calculator that can convert between coordinate systems. This is useful for converting positions to the various formats used by different groups of people. This same calculator can be called up by the Calc button on some of the other dialogs. It's useful for entering coordinates in other formats. Configure menu: Background color This option controls the color of the background behind the maps you have displayed. The background color is often entirely hidden by filled maps (see below). Map Intensity This controls the brightness of any graphics used as maps. This option only appears if you have compiled with GeoTIFF support. Adjust Gamma Correction This allows you to apply gamma connection to all loaded map graphics. Maps can be adjusted individually in their .geo files, see the section on .geos in "Map files and WX Counties". This option only appears if you've compiled with ImageMagick support, and does not apply to geoTIFF maps; see the above option. Map labels font This allows you to set the font style and size used for map labels. Station Text Style Controls which font and style to use for station text and others. Icon Outline Style This allows you to specify an outline that surrounds station icons. This helps improve visibility on various backgrounds. Disable All Maps This option disables the loading of any maps. It is most useful when doing rapid zooming or panning, because it saves the need to load the maps on each redraw. Note that this option is not saved between sessions. Enable Auto Maps When enabled, any map found in the map directory (or any directory under it) will be displayed if it falls within the current display region. You can add any number of directory levels under the main map directory for your maps. Auto maps will go through any that have Auto Maps enabled (in the Map Chooser Properties dialog) check them all and find what map (or part) should be displayed. All Maps will be merged into the viewing area. If you have a large quantity of maps, very detailed maps or a slower computer this can be quite slow. When this option is off, maps selected with the Map Chooser will be displayed. Auto Maps - disable Raster maps This option prevents Auto Maps from loading maps which are graphics (images). Only vector maps will be displayed in this case. Enable Map Grid When enabled, this option will display a grid on the map. If the coordinate system is UTM a UTM grid will be displayed. If the coordinate system is latitude/longitude then a latitude and longitude grid will be displayed. As you zoom in the grid switches to a finer resolution. The spacing of the latitude and longitude grid may be manually adjusted with the "+" and "-" keys. Enable Map Border When both Enable Map Grid and Enable Map Border are enabled, a narrow white border is drawn around the map and the grid lines are labeled using the selected coordinate system (File/Configure/Coordinate System), and the selected border font (Map/Configure/Map Labels font/Border Font). If the UTM or MGRS coordinate systems are selected, the grid lines will be labeled with easting and northing values only at zoom levels smaller than about 2048. Enable Map Levels When enabled, this option will try to filter out data when the zoom level shows large areas. This does not work will all maps but will work with the maps generated from Tiger Line maps at the aprs.rutgers.edu site, and with ESRI Shapefile maps. This does not decrease the loading times of the maps very much, rather it simply reduces screen clutter. Enable Map Labels This option toggles the display of map labels embedded in DosAPRS, WinAPRS, GNIS, and ESRI Shapefile format maps. Enable Area Color Fills This option controls the filling of vector maps. In certain cases, you may want to eliminate the fill to see maps below the top maps. This is a global control, maps may individually have color fill toggled in the properties dialog of the Map Chooser. Enable Weather Alert Counties This toggles the display of county warning area maps for severe weather. These maps can be obtained and installed according to the directions in the README.MAPS file. They are displayed on screen when special weather alert messages are received, and expire after a time or can be remotely canceled. The weather alert text can be seen under View|Weather Alerts. The xastir/Counties directory must be populated with the correct files from NOAA and Shapelib support must be compiled into Xastir in order to enable this functionality. Index New Maps on Startup This option controls if the map index file is built on startup. Most users should leave this enabled. If the timestamp of the map file is newer than the map index file, the map will be indexed. Index: Add New Maps This option adds any new maps to the max index. Same rules as the above Index New Maps feature, but a manual method of invoking it. Index: Reindex ALL Maps This option starts over from scratch, indexing every map it recognizes in the maps directory. This is useful if the Add New Maps function is skipping some maps, perhaps because of old timestamps on the map files. This function may take quite a while to complete if you have a lot of maps. Mouse pointer menu This option brings up the options menu normally available by right clicking. One note on maps: Many of the currently available vector maps for the U.S. were created in NAD 1927 datum, while Xastir and other APRS(tm) programs use WGS 1984 datum. If zoomed in to a small area on the map the datum shift may be very noticeable. The USGS topographic maps have their datum corrected by Xastir as they are displayed, so positions will generally be more accurate with those topographic maps. HELP-INDEX>Map files and WX Counties Map files and WX Counties Map Types Xastir will work with various types of map files. All DosAPRS, Windows/Mac APRS(tm) map files are supported, as well as PocketAPRS format maps and GNIS (Geographic Names Information System) label files. Xastir also can be compiled to use external libraries to support XPixmap (XPM) images, GeoTIFF topographic maps, and ESRI Shapefile maps. The graphics handling capability of Xastir can be greatly extended by compiling with ImageMagick support, enabling support for many graphic formats as maps (see "http://www.imagemagick.org/www/formats.html"). Xastir supports weather alert maps in ESRI Shapefile format, available from NOAA. Details of locations to obtain many of the above types of maps are found in the file README.MAPS Map Locations Any map file should be stored in the /usr/local/share/xastir/maps directory on your computer. This location may be different on some systems, depending on how Xastir was compiled/installed. You can create any number of directories under this directory to help organize and separate your data. The maps will be loaded in alphanumerical order unless layering is specified. Hints on installing and organizing maps are found in README.MAPS. Maps in a pixel graphics format actually need a combination of two files, a data file with a graphic pixmap (.xpm) (or other format if you compiled with ImageMagick), and a calibration file (.geo). The .xpm file is the standard graphic format, available without additional libraries. If you want to save storage space you can use gzip to compress those files ("gzip map.xpm" will result in "map.xpm.gz"). Xastir detects this automatically during map loading. You can use XView/Gimp/ImageMagick and other programs to convert gif, jpg, and tif images into this format if you don't have support for many image types compiled in (ImageMagick). If you have problems with maps in xpm format, try to load and save the graphics with Gimp first, to convert all unknown color names into the binary representation. The .geo file is a text data file that will tie the image to a location in the world. Here is an example of a .geo file that will cover the entire world with the map world1.xpm: FILENAME world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 639 319 180 -90 IMAGESIZE 640 320 .geo files can have many elements: FILENAME This specifies the filename of a map image to be loaded from the local disk. URL This specifies the URL of a map image to be loaded from a web or ftp site. ImageMagick only. TIEPOINT Two tie-points are required, and more than 2 will be ignored. these two lines are for connecting an x,y pixel position in the image to a lat and long position on the earth. The points should be as close as possible to the upper left corner and the lower right corner of the image for best accuracy. The latitude/longitude are specified in decimal degrees. IMAGESIZE This specifies the size of the image in pixels. If this is not set, the image will be loaded each map redraw, regardless if it is on screen or not. IMAGESIZE is a REQUIRED OPTION if a URL is specified. For local files, it's an optional parameter (we use ImageMagick to query the image size for local files). DATUM This feature is not implemented. PROJECTION This feature is only partially implemented, default is "LatLon", other possibility is "TM" to specify that the map is in Transverse Mercator projection. # Any line with the first character of a '#' will be ignored. ImageMagick specific image enhancements: GAMMA eg: GAMMA 1.2 or GAMMA 1.2,2.0,1.2 The first will change overall gamma for this image, the second will lighten green more than red or blue. CONTRAST eg: CONTRAST 0 or CONTRAST 1 Doesn't seem to do that much, other values make no difference. NEGATE eg: NEGATE 0 or NEGATE 1 0 will negate all colors, 1 just grayscale colors. EQUALIZE No argument. NORMALIZE No argument. LEVEL eg: LEVEL 0,1,65535 These values seem to be the defaults. MODULATE eg: MODULATE 90,150,100 These are percents, 100,100,100 is the default. REFRESH eg: REFRESH 900 This tag is used for dynamic URLs such as weather radar, where you wish Xastir to auto-redraw the map at a specified interval. By adding this tag to weather radar .geos, you can watch the weather move across your screen. Xastir contains only one interval counter, so the smallest REFRESH interval loaded takes effect for all selected maps. TRANSPARENT Color to remove from the background (make it transparent). Use a number, 0=black. Color-mapped images use the map value, so white is usually 0xffffffff (32-bits of 1s). Values must be in hexadecimal, and are preceeded by "0x". The value can be obtained by using debug level 16. The first of the four numbers after "Color allocated is" is the colormap index. CROP Removes borders (makes them transparent). Values are in pixels with (0,0) at the upper left. A good value for the 620x620 NWS radar images is "CROP 35 20 616 600" Special/nonstandard .geo files: TOPORAMA-250k Canadian 1:250k scale topo maps, downloaded from findu.com. "CanadaTopo250k.geo" is automatically installed in the maps directory. TOPORAMA-50k Canadian 1:50k scale topo maps, downloaded from findu.com. "CanadaTopo50k.geo" is automatically installed in the maps directory. WMSSERVER Allows use of Web Map Services (WMS). An example "WMSRadar.geo" is automatically installed in the maps directory. geoTIFF maps are a combination of two files as well: a .tif and a .fgd file. The .tif file is the actual map data. The .fgd file need only contain four lines like this (but may contain many other lines): 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir uses only those four lines in its calculations to determine the corner points of a map, to see whether the map fits in the current viewport (so it can decide whether to skip it). If your map data are USGS topographic maps, the .fgd file should be readily available to you. If it is not, the mapfgd.pl script can create it for you. If you don't have a .fgd file, the map will load fine, but the white borders won't be cropped and the size and rotation may be off a tad bit. An added feature in Xastir is the ability to do datum translations from NAD 1927 to WGS 84 datum, which makes the USGS topographic maps much more accurate on the Xastir screen. Xastir can use USGS geoTIFF topographic maps directly from the CD drive. Manually mount the disk or use auto-mounter to do it for you, and make sure you have a sym-link created in your maps directory that points to where you mounted your CD-ROM drive. That's it! ESRI Shapefile maps are also a combination of several files, a .shp file, a .dbf file, and a .shx file. You only need to select the .shp file to load the map, but the other(s) must be present for the map to load correctly. GNIS (Geographic Names Information System) data is a collection of names of locations, or geographic features. These labels behave like map labels in Dos/WinAPRS maps. As you zoom in, more labels will appear, assuming you've selected the GNIS file as a map and have enabled Map Labels in the Maps menu. If you have some of them in the xastir/GNIS directory, you can also search for map labels within Xastir. WX County Maps All WX County maps should be stored in the /usr/local/share/xastir/Counties and Xastir only supports the ESRI Shapefile standard for these. Installation is explained in README.MAPS. You must have Shapelib compiled in. As NWS messages are received, different areas will get tinted to designate areas of concern. They are color-coded to specify different types of alerts. The colors are: Cyan for advisory, yellow for watch, red for warning, orange for canceled alert, royal blue for tests, and green for undetermined alert levels. The coloring is done with a pixmap stipple that displays the type of alert, if it is able to be determined. These changes were made so that the underlying maps may still be seen underneath the weather alert areas, and so the alert type may be more easily determined, as sometimes matching the alerts on screen and in the weather alerts dialog is difficult. The display of weather alerts may be turned on/off via the Map menu. HELP-INDEX>Stations Menu Stations Menu These options will allow you to control the data displayed around the stations on the map. It will also let you track and find stations, and clear stations and trails in the database and from the map. Find Station See the help topic "Locating a Station". Track Station See the help topic "Tracking a Station" Fetch Findu Trail Downloads historic trail data from findu.com. Slider bars control the starting point and duration of data downloaded. For an example, if you wished to see the track that happened two days ago, all day long, you might set the first slider to 48 hours (start time of two days ago) and the second slider to 24 hours to snag exactly one day's worth of data, from the start until 24 hours later. Export all This sub-menu allows saving data for all stations to files [or databases] Export to KML file Saves all stations and their trails to a Keyhole Markup Language file in ~/.xastir/tracklogs. The filename will be the current date and time with a .kml extension, e.g. 20080125-033045.kml KML files can also be written on a regular basis using KML Snapshots on the file menu. Store to open databases [Not yet implemented] [Store to database interfaces is currently only implemented through individual SQL database interface dialogs] To save a png snapshot of the current map, use File->PNG Snapshots Filter Data This sub-menu allows filtering of the displayed symbols: Select None Determines if symbols should be drawn on the map. The other options depend on this being enabled. Select Mine Determines if your own station is shown on the map. Select via TNC Global toggle for displaying data received via a TNC, but may be narrowed: Select Direct This option only displays stations heard directly (not digipeated). Select via Digi This option displays stations heard indirectly via a digipeater. Select Net This option displays stations with data received via the Internet. Include Expired Data Causes Xastir to continue to display the station data that normally goes away when the symbol is ghosted. The expiration time can be adjusted in the File|Configure|Defaults menu. Select Stations Global toggle for displaying stations, but may be narrowed: Select Fixed Stations This option displays stationary stations. Select Moving Stations This option displays stations with multiple positions or non-zero speed Select WX Stations This option displays Weather Stations. Select CWOP WX Stations This option includes the display of citizen weather (non-ham) weather data. Select Objects/Items Global toggle for displaying objects/items, but may be narrowed: Select WX Objects/Items This option displays weather Objects and Items. This includes tropical storms and remote weather stations. Select Water Gauge Objects/Items This option toggles the display of water gauge (/w) objects. Select Other Objects/Items This option enables or disables the display of objects other than those listed above. Filter Display This sub-menu allows filtering of the displayed data: Display Callsign Determines if the callsign is displayed. Label Trailpoints This option includes callsigns along trails, to help identify which points belong to which stations. Display Symbol Determines if the symbol is shown to the left of the callsign. Rotate Symbol Some symbols will change their orientation to show the direction in which they are traveling. Display Trail When enabled, any moving station will trail a colored line. We now display as many locations as we have in our database (old limit was 100). Long trail segments (over 2 degrees latitude or 2 degrees long), or segments with more than 45 minutes receive delay between the points will not be displayed. Duplicate points are also eliminated from the track (SAR team returning to base: Last segment may not be displayed due to the starting point appearing twice in the trail list). Display Course When enabled, green text will appear below the call sign. This will display the last known course (in degrees) the station was traveling. Display Speed When on, red text will appear below the call sign (or course). This will display the last known speed of the station. Display Short Speed This option removes display of the measurement units for speed. Display Altitude When enabled, blue text will appear above the call sign. This will display the last known altitude of the station. Display Weather Info Global toggle for displaying weather information, but may be narrowed: Display Weather Text When enabled, the latest weather data (temp,wind speed/course/gust, humidity) is displayed. This may be adjusted with the following option: Display Temperature Only Displays only the temperature data for the station. Display Wind Barb When enabled, a wind barb showing the direction and speed of the wind is drawn for all displayed stations reporting this information. Display Position Ambiguity When enabled, the area in which station using position ambiguity may be located within is shaded, with the relevant station in the center. Display Power/Gain When on, Power/Gain Circles will be displayed. Overlapping circles indicate that the stations are theoretically within simplex range of one another. This is only roughly accurate, especially in areas of variable terrain. Use Default Power/Gain Enables a default power/gain setting as specified in the APRS(tm) specification. Display Mobile Power/Gain Enables power/gain circles for mobile stations. Display DF Attributes When enabled, any DF circles/lines will be displayed on the screen. Enable Dead-Reckoning When enabled, the positions of stations are estimated based on past course and speed. The recalculation rate should be reasonable, but can be adjusted in the configuration file. Display Arc Displays an expanding arc of expected maximum travel distance, location and course given the past course and speed. The arc slowly becomes a circle as the position report gets older. Display Course Displays an expected course and distance traveled by the station, assuming the course hasn't changed. Display Symbols Displays a ghosted version of the stations symbol at the expected position, assuming the station has continued at its current course and speed. Display Dist/Bearing When enabled, two lines of text will be displayed on the left side of the stations' icon. The top line will contain the distance from your station to this station. The bottom line will contain the course from your station to this station. Display Last Report Age Display the time since the station was last heard. Reload Object/Item History This will reload the ~/.xastir/config/objects.log file used for Object and Item persistence. This is needed if you edit the file while Xastir is running. Clear Object/Item History This will clear the ~/.xastir/config/objects.log file used for Object and Item persistence. It is recommended that you manually select and delete all Objects and Items that you own before doing this, otherwise they may remain on the screens of other APRS(tm) users. Clear All Tactical Calls Clears all assigned tactical calls. This will take effect the next redraw. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message"). Clear Tactical Call History This removes the tactical call history file, meaning that tactical calls assigned will not remain permanent between Xastir restarts. Note that this will NOT clear tactical calls on other peoples' screens if you've published them via a message to "TACTICAL" (see the help text for "Send Message". Clear All Trails This will wipe all the line tracking data from the station database and refresh the screen. This option is perhaps useful if you're low on memory or just want an uncluttered screen. You may also clear individual stations' trails from the Station Info dialog. Clear All Stations This will wipe all the data from the station database except yours. This option is perhaps useful if you're low on memory or just want to unclutter your screen. HELP-INDEX>Messages and the Messages menu Messages and the Messages menu Send Message to and Open group messages These are very similar. "Send message to" will send your messages to one station and will only receive data from that station. Group messages are more general: you can receive any message for the group and you will send out your messages to that group name. Group messages code is not fully implemented yet and various problems still need to be worked out. The "groups" file is looked for in ~/.xastir/config. This is where the groups you are a member of are stored. As was said before the "groups" functionality may not be complete yet. At some point in the near future sending of bulletins should be added to this menu as well. It's not coded yet. Each of these two screens contains a message box, a call line, a message line, and various buttons. You must first enter the call of the group or station you want to contact. Once that is done any new message that has come in from that station to you will be displayed. If the station is sending you information and no message window is up it will automatically pop up a new window (up to 10) with that station's call sign filled in for you. You can now enter a message on the message line. The message can be longer that the message line, and will max out at about 250+ characters. Once your message is entered, clicking on the "Send Now!" button will send your message. The "Send Now!" button will gray out until your message is completely ack'ed. Any message you receive will be sorted by the line # and be placed in the message window. If you are in a group mode each line will display the call sign from where the message was sent followed by the message itself. Currently group messages are sorted by call and then line #. When you are done sending messages clicking on the exit button will close the window. Other buttons are also available: The "New Call" button will allow you to look at old data a station has sent. Type in the call and click on this button, any old information will be displayed. You can also use this button to change the call of the station you're talking with. Enter the new call and click the button. The "Clear Msg History" button will clear any message displayed in the message window. "Cancel Pending Msgs" will cancel any messages in the transmit queue that haven't been acknowledged by the remote station yet. After canceling the pending messages or receiving and acknowledgment packet from the remote station, you may send new messages to the remote station. Xastir will allow you to type ahead, so you can just keep typing if you don't want to wait for the acknowledgments. Messages in reply to previous ones will attempt to use the path of the received message to avoid flooding the system with broadcast messages. You may adjust the path in the send message dialog, or the default path(s) set in the interface control will be used if you leave this blank. The path can be set for each message sent, but once a message is sent the path remains fixed for that particular message. Each outgoing message remains highlighted until it is ack'ed by the remote station. If it times out or if you cancel the pending messages, those messages will remain highlighted unless you clear the message history. To publish TACTICAL calls to other Xastir and APRS+SA stations as well as assign those tactical calls locally: Send a message to "TACTICAL" with the body of the message containing lines something like: callsign-1=TAC1;callsign-2=TAC2;callsign-3=TAC3 To remove these tactical calls later from local AND remote screens, assure that the original message(s) assigning them has timed-out or been cancelled, then send a message like this and let it retry until it times out (assigns blank tactical calls to the original callsigns, thereby removing the assignment): callsign-1=;callsign-2=;callsign-3= Clear all outgoing messages This will clear all un-ack'ed messages you have sent. General Stations Query This sends an ?APRS? packet, which should cause all local stations to report their position and/or status. Most software ignores this query, because responding to it would cause massive floods of data. IGate Stations Query This sends an ?IGATE? packet, which should cause all local IGates to respond with their capabilities. WX Stations Query This sends an ?WX? packet, which should cause all local weather stations to report their position and weather. Modify Auto reply message This will set the message that is sent as an Auto Reply. Enable Auto Reply Msg This will turn on an automatic reply when an incoming message is received. Satellite Ack Mode This mode disables the sending of ack messages in response to received messages. Messages are still acknowledged using the reply-ack system. When operating over a satellite it is clear that your message made it, because you will hear it repeated. The receiving station sending an independent ack only adds QRM. HELP-INDEX>Interfaces Menu Interfaces menu This menu contains interface related options. Interface Control This option displays a window where you can turn on and off your configured interfaces, as well as add, delete, or configure interfaces. See the "Configure Interfaces" help topic. Disable Transmit options These options disable the transmission of everything, one's position, or one's objects. These are global options and affect all interfaces. Most interfaces have an option to disable transmission on that specific interface in their configuration menus as well. Enable Server Port This enables/disables TCP and UDP listening sockets at port 2023. You may connect other APRS(tm) clients to the TCP port in order to send/receive APRS(tm) data. Once they authenticate, they'll be able to send data to Xastir. Without authentication, they'll be able to receive every bit of TNC and INET data that Xastir receives. Note that ANY user with the proper credentials can come in on the TCP or UDP ports if they are enabled. The only one of these two ports currently that can send to RF is the UDP Server port. The TCP port cannot. "user WE7U-13 pass XXXX vers XASTIR 1.3.3" Connect another APRS(tm) client to that port and it should authenticate and be able to send to any server that Xastir is connected to, as well as receive packets from all ports/servers Xastir is hooked to. You should also have a binary called "xastir_udp_client" which can send packets into the UDP listening port. Invoke it like this: xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 -to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the -identify flag: xastir_udp_client localhost 2023 -identify Transmit now Causes all interfaces that have transmit enabled (see configure|interfaces) to transmit a position packet. It will be grayed out if Disable Transmit: ALL is selected. If you have GPSMan installed, you have these additional menu options displayed: Fetch GPS Track Download a set of trackpoints from an attached GPS. Fetch GPS Routes Download a set of routes from an attached GPS. Fetch GPS Waypoints Download a set of waypoints from an attached GPS. Fetch Garmin RINO Waypoints Snag waypoints from an attached Garmin RINO, create APRS(tm) Objects out of any waypoints which begin with "APRS". HELP-INDEX>Station info box - FCC and RAC lookup Station info box - FCC and RAC lookup Station Info will display any data decoded by Xastir. You can assign (local only) tactical calls to stations from here, by clicking the "Assign Tactical Call" button. This will cause the station on screen to display as the tactical call instead of its callsign. Assigning a blank tactical call clears this feature, and it can also be cleared for all stations in the Stations menu. This feature assigns tactical calls to the local Xastir station only, but see below to publish them to others. To publish tactical calls across the air to other Xastir and APRS+SA stations (as well as assign them locally), see the "Send Message" help section. "Enable Automatic Updates" will cause the window to refresh frequently with the latest information. The information available may include: Number of packets heard, the time last heard, the device the packet came from, station comments, power/height/gain of the station, course/distance from your station, weather information, and current and previous positions. For moving stations a track-log follows with the most recent entries on top. A '+' in front indicates that a new track starts at that point (if there was a large gap in time or position). A star at the end of a line indicates that this station could be heard direct (without a digi) at that specific position. Positions are followed by the 6 digit Maidenhead grid square the station was located in at that point. For your own station, there is an "Echoed from" field, listing the last six digipeaters that heard you directly. This is useful for setting non-generic paths. Currently two rows of four buttons appear in the Station Info window. Some of the labels on the buttons change based on the type of station that you're dealing with. For objects/items: Store Modify Blank Close Track Object/ Item Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query For other stations: Store Send Search Close Track Message FCC (RAC) Database Station Trace Un-Acked Direct Version Query Messages Stations Query Query Query "Station Version Query" changes to "Clear Track" for mobile stations. The Clear Track button will clear any line tracking for this station that is currently stored or on the map display. "Store Track" will save the track of the station to a file on disk. The format is similar to that used by GPS receivers but its specification might be changed (enhanced) in future versions. There is currently no way to read that track data back in, but it is planned for the future. The goal is to also read and display GPS track-logs in a similar manner. These track-log files will be placed in the directory ~/.xastir/tracklogs with a name equal to the stations call with ".trk" as extension. "Store Track" will simultaneously save the station's track as a Keyhole Markup Language (.kml) file with a filename equal to the station's call, the current date and time and .kml as extension. If shapefile support has been included, the station's track will also be saved as a set of four files (.dbf,.prj,.shp,.shx). Subsequent presses of Store Track for the same station will write additional lines into the .trk file, and create new .kml (and shapefile) files (each containing all positions in the station's track. "Modify Object/Item" will bring up the Object Modify window. "Send message" will open up the message window and allow you to send a message to this station. It will fill in the call sign for you. If the FCC (U.S. Federal Communications Commission) or RAC (Radio Amateurs of Canada) database is installed and the callsign appears to be a Canadian or U.S. callsign, the "Search FCC/RAC Database" button will become active, otherwise this button will be inactive. The FCC and RAC files should be placed in the /usr/local/share/xastir/fcc directory, and case is important! Pressing this button adds the station's name and address into the Station Info box. Instructions for installing these databases are in the README.MAPS file. Xastir will create index files for each database file upon startup. If a newer callsign file is placed there while Xastir is running, it will create or rebuild the index on the next lookup. Special prefixes are NOT handled. HELP-INDEX>Creating a log Creating a log Xastir can log data from the internet or TNC for later playback, or for debugging purposes. WARNING: Logging can fill up your hard drive, so be careful using it, or make preparations for rolling over the log files automatically via cron. An indication will be shown on the status bar when logging is enabled. All these choices are accessible via the File menu: Enable TNC Logging Logs all TNC data received and transmitted. These logs can be played back using the "Open Log File" feature. Enable Net logging Logs all internet data received and transmitted. These logs can be played back using the "Open Log File" feature. If you have no interfaces started but still want to log your posits and objects locally, this is the option to enable for that as well. Enable IGate logging Logs all data forwarded in both directions, and rejected forwards with reasons for rejection. Includes NWS messages forwarded to RF. Enable WX logging Logs all weather data received from your weather station. HELP-INDEX>Replaying a log Replaying a log Click on "File", then "Open Log File" and a file selector window will display. You can use it to browse your hard drive and select any file containing raw TNC data like those created by the TNC and Net logging options. Your station will still function the same way, receiving and transmitting. If you were logging data, the typical place to look for those files would be ~/.xastir/logs/ NOTE: This function doesn't read the saved station tracklogs. HELP-INDEX>Locating a Station Locating a Station Click on "Stations", then "Find Station". A window will pop up. You can now enter a call or part of a call. By default it will search for an exact match (full call, not partial) and is not case sensitive. If you are looking for a partial match, "Match Exact" should not be selected. For objects which could contain lower case letters you have to check "Match Case"! Opposite to the name, without "Match Case" the search text will only be converted to upper case... Clicking on the "Locate Now!" button will center the first station found in the center of your screen at the current zoom level. Clicking "FCC/RAC Lookup" will look up the user's information if the FCC or RAC database, of those databases are installed. Clicking on "Cancel" will close the window. This dialog will pop up if a station sends a Mic-e "Emergency!" packet, to encourage users to locate and perhaps help the listed station. HELP-INDEX>Creating and using Map Display Bookmarks Creating and using Map Display Bookmarks Click on "Maps", then "Map Display Bookmarks" and a window will pop up. If this is the first time you have used this then the box will have no entries in it. To add a bookmark to the list: Position the main map to the area and zoom level you want to use. Enter a unique name in the "New Name" area, then click on add. Your entry will be added to the list (in alphabetical order). You can add as many map display bookmarks as you want. To use one of the bookmarks mark its name and click "Activate!". The main map will then show the stored area and zoom level. You can similarly delete a bookmark by clicking on the bookmark name and then the "Delete" button. "Maps->Locate Map Feature" is another method to jump to a location, if the name of the location is known and you have GNIS files installed. HELP-INDEX>Tracking a Station Tracking a Station Click on "Stations", then "Track Station". Enter the callsign to track (all or part) then click on the "Track Now!" button. As the station moves it will remain viewable in the main map window. As the stations starts to get close to the edge of the map window the window will re-center so that the object is always visible. To stop tracking this station click on the "Clear Tracking" button. While tracking is active, a "Tr" is shown in the status bar next to the zoom level. If the station is not on the map yet, tracking will begin as soon as it shows up. HELP-INDEX>Printing Printing the Map Screen Note: Printing has not been set up on Windows/Cygwin. These instructions are for Unix and Unix-like operating systems. Xastir can print the drawing area in either black & white or color. It does this by first dumping the image to an XPixmap file on disk, then using external tools to convert it to postscript, scale it, rotate it, preview it, then print it. You must have your system printing set up to handle postscript (usually this requires Ghostscript and a print filter installed, as well as lp or lpr print spoolers). You must also have the following tools installed for this capability: ImageMagick tools (specifically "convert"), "Ghostscript", Ghostscript fonts, and "gv". Once all of these packages are installed and functional, you should get a "gv" window popping up shortly after you tell Xastir to create a print file. From there you can view the printed image, and if acceptable, tell "gv" to print it. Note that sometimes changing to a white default background for the maps is recommended, depending on what maps you have viewable. This can save greatly on ink. HELP-INDEX>Creating Snapshots Creating Automatic Snapshots Xastir has the capability to create automatic snapshots of the map screen on a recurring basis. The default time period is set at once per five minutes. Assuming that you have "convert" from the ImageMagick tools installed, Xastir will create an XPM format file in ~/.xastir/tmp/, then convert it to the PNG file ~/.xastir/tmp/snapshot.png. This file is useful for embedding in web pages to show a "live" image of what is on your Xastir screen. Enable this feature via the "File->PNG Snapshots" toggle-button. The rate is once every five minutes (configurable from the Configure Timing dialog from "File->Configure->Timing"), or every time the button is toggled from off to on. A .geo is created to allow you to use the snapshot as a map. A .kml file is also written to allow you to use the snapshot as a graphic overlay on terrain in applications capable of reading kml. See kml_snapshot_to_web.sh and kml_snapshot_feed.kml in the scripts directory for more information on using the snapshot.png and snapshot.kml file to produce a kml feed using the snapshots. Creating Automatic KML Snapshots Xastir is capable of writing all current stations and tracks to a kml file on a recurring basis. Enable this feature via the "File->KML Snapshots" toggle button. The rate at which these snapshots are generated is the same as that of PNG snapshots, configured from "File->Configure->Timing" by setting the snapshot time interval. Each snapshot is written to a .kml file in ~/.xastir/tracklogs, with a filename based on the date and time of the snapshot, e.g. 20080206-000720.kml This behavior may change to make KML snapshots write to a single file like PNG snapshots. HELP-INDEX>Included Scripts Included Scripts Xastir includes several Perl scripts and a shell script that may be useful: get-fcc-rac.pl This shell script automates retrieving and installing the FCC and the RAC callsign databases. Note that these databases are very large! icontable.pl This script generates an xpm bitmap of all Xastir's primary and secondary symbols from the symbols.dat file. The overlays and specials are ignored. Output is to STDOUT, so a typical call would be "icontable.pl > symbols.xpm". inf2geo.pl This script creates .geo files from UI-View .inf files. To create a map.geo from a map.inf, typical usage would be "inf2geo.pl map". kiss-off.pl This script sends the commands needed to turn off a TNC's KISS mode. mapblast2geo.pl This script creates .geo files for Mapblast pixel maps. It includes usage information. mapfgd.pl This script creates minimal .fgd files for GeoTIFF images lacking them, based on information found in the GeoTIFF file. The created files allow Xastir to crop the white borders and rotate/scale the map properly. Typical usage would be "mapfgd.pl mapdir" where mapdir is the directory containing the GeoTIFF images. overlay.pl This script creates .log format files from comma-separated overlay files. See the script comments for full usage information. ozi2geo.pl This script creates .geo files from OziExplorer .map files. permutations.pl This script converts between different lat/lon formats. See the script comments for further details. split_gnis.bash This will take a GNIS data-point file (typically for a whole state, 8+MB), break it down into smaller chunks (typically for a county, 30-200k) it will also throw away the trailing spaces and s at EOL. split_gnis.pl This is a Perl version of the above script. test_coord.pl Tests for the Coordinate.pm Perl module. track-get.pl This script downloads the track-log of a specified object from a Garmin GPS. It requires the GPS::Garmin module. It prompts for an object name, and writes the track-log to the ~/.xastir/logs directory. update_langfile.pl This script is targeted toward developers. It rebuilds a specified language file to contain all the strings of another. It is usually used to regenerate the non-English language files when significant changes have been made to the English file. When the second language file lacks a string in the main file, the untranslated string is inserted. Typical usage would be "update_langfile.pl language-German.sys" . The main language file is hard-coded but easily editable. waypoint-get.pl This similar script downloads the waypoints from a Garmin GPS, and creates a log in the ~/.xastir/logs directory containing the waypoints as objects. It also requires the GPS::Garmin module. db_gis_mysql.sql db_gis_postgis.sql These will create tables for storing station data in a mysql or postgresql/ postgis database. SQL Server database support is experimental. See the "OPTIONAL: Experimental. Add GIS database support" section in INSTALL HELP-INDEX>Configuring Interfaces Configuring Interfaces Click on Interfaces, then Interface Control. An "Installed Interfaces" box should appear. This box will allow you to add, delete, and modify the properties of various devices you may want to use with Xastir. Supported interface types are: Serial TNC Serial TNC w/GPS on HSP cable Serial GPS Serial WX Internet Server AX.25 TNC Networked GPS (via gpsd) Networked WX Serial TNC w/GPS on AUX port Serial KISS TNC Networked Database (Not Implemented Yet) Networked AGWPE Serial Multi-Port KISS TNC SQL Databases [MySQL,Postgis] (Experimental) To add a device, click on the add button. A "Choose Interface Type" box will appear. Click on the type of device you would like to add. Then click the Add button in the "Choose Interface Type" box. Properties for that device will appear. Fill out the requested information and click OK. To delete the device, click on the device you wish to delete and then click the delete button. To modify the properties of a device, click on the device you wish to modify, then click the properties button. The properties for that device will appear. Change the information you want and click OK. More specific help is available under the help topics of each interface type. SQL Databases will only appear as an option if you have MySQL or Postgis support compiled. HELP-INDEX>Configure Serial TNC Devices Configure Serial TNC Devices This section covers adding or modifying Serial TNCs or Serial TNCs with a GPS on a HSP cable. If you have a HSP cable, which allows you to share the TNC port with a GPS unit you may choose a TNC with GPS (HSP Cable). This is a special cable and may not work on all computers/GPS/TNC combinations. If you use this device the TNC and the GPS should be set to the same communications parameters. Generally 4800 bps, 8 data bits, no parity, and 1 stop bit. TNC Port Options: Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "Add Delay" will tell xastir to insert a one second delay between issuing the command to enter "Converse" mode and the actual data to be sent. This options exists solely to deal with the Kantronics KAM TNC, which will often fail to enter converse mode if it receives data immediately after the converse command is given. If you have a KAM, check this box, if not, leave it unchecked. The TNC Port is the Unix device that the TNC (or TNC and GPS) is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your TNC and GPS. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. XASTIR will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1, WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL, WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. TNC Startup and Shutdown files. These fields specify a filename that is located in the /usr/local/share/xastir/config directory. Each file is a standard text file containing any commands you would like to send your TNC at the time the device is activated (startup file) or shut down. HELP-INDEX>Configure Serial TNC w/GPS on HSP cable or AUX port Configure Serial TNC w/GPS on HSP cable or AUX port These hybrid interface types implement the options of both serial TNCs and GPSs. Please consult the configuration help for both serial TNCs and serial Gpsd for further information on the configuration of these devices. "Send Control-E to get GPS Data?" This checkbox controls whether Xastir sends a Control-E to the TNC every time it needs GPS data. Some TNCs that support a GPS on an auxilliary port require that Xastir send a Control-E to the TNC in order to get the GPS data each time it is needed. Devices in this class include the Kantronics KPC-3+. Some devices, like Kenwood APRS radios (D700, etc.) do NOT require this, and in fact the Control-E interferes with correct operation of these devices. Because Control-E was required by the most common TNCs that had an aux port for GPS at the time that this interface type was written, this is the default behavior of Xastir. If you have a Kenwood radio that you are using in this mode, you must DESELECT the "Send Control-E to get GPS data?" checkbox in the configuration dialog for this interface type. HELP-INDEX>Configure Serial KISS TNC Configure Serial KISS TNC This section covers adding or modifying Serial KISS TNCs. KISS mode can be done by most standard TNCs too, and it eliminates the necessity to set the options specially in the startup files, at the expense of slightly higher processor usage. And of course this enables the use of purely KISS TNCs, such as the one described in the November 2000 issue of QST, without a separate program or kernel module. Options Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeaters in the area. Consult with a local group about the best setting for your region. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. The TNC Port is the Unix serial device that the TNC is hooked to. Normally you can use /dev/ttyS0 (com1), /dev/ttyS1 (com2) etc. Comment will allow you to set a friendly name or comment for the port. Now set the bps rate under port settings. Choose the correct IGate operation for this device. You may have several TNC devices, and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. Next configure the KISS parameters: TXdelay is the time (in 10ms units) needed between the keying of the radio and when it is ready to send data. Persistence and slottime are the channel access parameters: Slottime is how often the channel access algorithm is executed, and should usually be set to 10. Persistence is how aggressively your station tries to grab the channel when free, and should be ideally set to 255 divided by the number of stations on the channel. Full duplex allows the transmission to begin while there are packets being received on the channel, this should be disabled in most cases (set to "0"). HELP-INDEX>Configure AX.25 TNC Devices Configure AX.25 TNC Devices This section covers adding or modifying AX.25 TNC devices. AX.25 devices can be any device that uses the Linux AX.25 drivers. This is a kernel level driver, and device such as a Baycom or a sound modem can be used as a TNC. These devices must be set up and running before Xastir can use them. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing RF data can be sent to this device for broadcast. Selecting "RELAY Digipeat?" will tell Xastir to digipeat traffic. It will do this if the first unused digipeater call in the path matches your callsign or a callsign listed in your Xastir config file ("RELAY_DIGIPEAT_CALLS" line, default is "WIDE1-1"). This option is only recommended for base stations in regions where there are few other fill-in digipeater stations in the area. Consult with a local group about the best setting for your region. This is only needed if you are not using any other software that performs this function, such as aprsdigi or DIGI_NED. You may hand-edit the Xastir config file when Xastir is not running in order to change this string to match your local recommendations. In the U.S., "WIDE1-1" is the recommended setting. Enter the AX.25 Device name you specified in the axports file for this device. Comment will allow you to set a friendly name or comment for the port. Choose the correct IGate operation for this device. You may have several TNC devices and this option can be different for each device. If you are not running an IGate leave it at the default option of "Disable". Enter in up to three UNPROTO paths. Xastir will assume the XX VIA part of the UNPROTO path. There are three paths allowed so that your signal will be heard if conditions are bad. Xastir will cycle through each one that is filled in, one per transmission time. If you are local to a digi, just a WIDE2-2 may be a good choice. If you are using low power and/or are distant from a digi then WIDE1-1,WIDE2-2 may work better. Or if you know the call of your closest digi you may use XXXCALL,WIDE2-2. Most of you will only need one path. If you are in a remote area and your signal is difficult to get out you may need more. Check with a local group and ask what path may be best for your area. If no paths are entered it will default to WIDE2-2. If you are IGating to RF, you may enter a specific path to use for the packets you send to RF. If you leave this blank, the UNPROTO paths above will be used. If the UNPROTO paths are blank, WIDE2-2 will be used. NOTE: To use AX.25 devices with Xastir you will need to run the program as "root". If you want to run Xastir as another user you may want to set the suid bit on the Xastir program file. Please see INSTALL file for more information; current Xastir drops the extra privileges but has not been audited for exploits. Use in this fashion in a multi-user environment at your own risk! HELP-INDEX>Configure Serial GPS Devices Configure Serial GPS Devices Set the serial port device for your GPS unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your GPS. Most GPS units will use 4800 bps and 8,n,1. HELP-INDEX>Configure Networked GPS Devices Configure Networked GPS Devices If you need to share the GPS data with different programs or machines, this option is best. Xastir will work with gpsd which will allow several connections to share your GPS data. Set the host name (or IP address) and the port number for the gpsd host on your network. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. Selecting "Set system clock from GPS data" will tell Xastir to try setting the system's clock to the highly accurate time signal from the GPS receiver. This requires root privileges on most systems. HELP-INDEX>Configure the Internet Server Configure the Internet Server Internet Servers allow you to send and receive data for all over the world. Selecting "Activate on start up" will tell Xastir to look for this device and setup communications with it when the program first starts. Selecting "Allow Transmitting" will tell Xastir that any outgoing Internet data can be sent to this device. Enter the host name (or IP address) and the port number of the Internet Server you want to contact. Enter a valid pass-code to validate your connection, this will allow your data to be transmitted via an IGate. If you don't have a pass-code, use the included "callpass" program to generate one. Note that passcodes are dependent on callsigns. From the src directory, "make callpass" should create the executable if it isn't already compiled. Enter any filter parameters. This causes a special message to be sent to the server requesting that the data be filtered in a certain way. The exact format of this field is fully specified, please consult APRSSIG for more information. Comment will allow you to set a friendly name or comment for the port. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. HELP-INDEX>Configure a Serial WX Station Configure a Serial WX Station Set the serial port device for your WX unit. Common values of /dev/ttyS0 (COM1) or /dev/ttyS1 (COM2) can be used. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Now set the bps rate under port settings, and the parameters under port style. Port Style setting 8N1 is used for 8 data bits, No parity and 1 stop bit. 7E1 is used for 7 data bits, even parity and 1 stop bit. 7O1 is used for 7 data bits, odd parity, and 1 stop bit. These parameters must match your WX unit. The Data Type option will allow you to override what type of serial data the program will look for. The auto-detect feature will first look for Weather data in a binary type as the Radio Shack WX-200 uses. If no binary data is found in the stream, Xastir will look for an ASCII type of WX station (like Peet Bros.). Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure a Networked WX Station Configure a Networked WX Station Xastir can use WX data servers such as wx200d. wx200d will allow several network connections, thus sharing the Weather data with several programs or computers. Enter the host name (or IP address) and the port number of the WX data server you want to contact. Comment will allow you to set a friendly name or comment for the port. Selecting "Activate on start up" will tell Xastir to look for this device and set up communications with it when the program first starts. Selecting "Reconnect on failure" will tell Xastir to try to reconnect when the data stream has failed. As before the Data Type will override the auto detection. Now set the Rain Gauge correction factor. Xastir requires that the rain gauge report in .01 inch increments. If the unit reports in .1 inch or .1 millimeter increments, a correction must be specified to obtain accurate measurements. HELP-INDEX>Configure an AGWPE Connection Configure an AGWPE Connection Xastir can use an AGWPE network interface running on a Windows box as a TNC interface. It can also use the login/password security that AGWPE has built-in, but you must set up the account in the AGWPE application with your callsign for the username, in all capital letters. For instance: "AB7CD". The other options are described in the sections for Serial TNC and for Network interfaces. HELP-INDEX>Configure a SQL Database Connection Configure a SQL Database Connection [Experimental] Xastir can experimentally store and retrieve station data from either a MySQL database or a Postgresql + Postgis database. See the "OPTIONAL: Experimental. Add GIS database support." section in the INSTALL file for more information. Station and object data are stored as spatial data, and can be retrieved from other GIS applications, for example Xastir can write station locations into a Postgis database from which they can also be viewed using QGIS. SQL database connections also allow for the persistence of data between Xastir sessions. All aspects of spatial database support, including database structures, are currently experimental and may change at any time. You may configure multiple SQL database connections, but you should only have one active at a time. Before creating a database connection in Xastir, you will need to create a database to connect to, create an appropriate set of tables (see the db_gis_xxxxx.sql scripts in the scripts directory), and add a user with a password and rights to access the database. For postgis databases you may also need to appropriately configure the user in pg_hba.conf Configuration options on the SQL database dialog include: Database: MySQL (lat/long) for very old MySQL databases, Postgis for postgresql + postgis, and MySQL (Spatial) for current MySQL databases. With tables for: Currently only the Xastir simple schema - a very basic flat table holding minimal information about stations. Host: IP address or hostname for the database server, default is localhost. Port: Default is 3306 for MySQL and 5432 for Postgresql. The database can be on a remote server, but the appropriate port will need to be open in any firewalls. Username: Can be unique to your database, e.g. xastir_user Password: Unique to your database. Schema name: Your database name. e.g. xastir MySQL Socket: check my.cnf, or mysql --help | grep socket Leave blank for postgis databases. Reconnect on Net Failure: [Not yet implemented] MySQL defaults and Postgis defaults provided by the buttons may or may not be correct for your database. Three options control the behavior of the SQL Database interface: Activate on Startup: Try to connect to this database and begin storing heard station data as soon as Xastir starts (if store incoming data is also selected). Store incoming data: Stores each station (including objects and items) report as a record in the database. All stations heard on all interfaces will be stored to the database - if you are connected to internet feeds and leave xastir running this can easily be a million records per day. Load data on startup: Retrieve all station data from the database when restaring Xastir. Currently the only way to retrieve persistent data from a database. Will attempt to connect to database and retrieve data independent of the settings of either activate on startup or store incoming data. Due to rounding and conversion errors, non-mobile stations may move slightly. The "Most Recent Error" box may or may not contain an error message to help identify connection problems. When Xastir fails to connect to a database, the interface will show ERROR on the interface list, and the most recent error may be shown here. Running xastir from the console and observing error messages there, or running xastir from the console with xastir -v1 may help identify the cause of connection problems, as may examination of the database's error logs. You will only be able to configure a SQL Database interface if you have compiled Xastir with support for that DBMS (--with-mysql or --with-postgis). HELP-INDEX>Symbol Table These are the symbols that you can select for your station under the "Station Information" configuration menu. The current list can be found in the APRS(tm) Reference which you could get from http://www.tapr.org Symbol Table Symbol Group / Group \ ! Triangle w/! Triangle w/! " Rain Cloud Rain Cloud # Digi DIGI $ Phone Symbol $ Symbol % DX DX & GATE-HF GATE ' Small Aircraft Aircraft Crash ( Cloud Cloud ) TBD * SNOW Flake SNOW Flake + Red Cross , Reverse L - House w/omni . Small x / Red Dot 0 0 in a box Circle 1 1 in a box 2 2 in a box 3 3 in a box 4 4 in a box 5 5 in a box 6 6 in a box 7 7 in a box 8 8 in a box 9 9 in a box GAS : Fire ? ; Tent Tent < Motorcycle Pennant = Train Engine > Car Car ? POS Antenna ? in a box @ HURRICANE/STORM HURRICANE/STORM A First Aid Box B BBS Blowing Snow C Canoe D D in a circle E E in a circle Smoke Stack F F in a circle G Grid Square Antenna ? H Hotel/Bed I TCP/IP ? J J in a circle Lightening K School House L Light House Light House M Mac N NTS ? O Balloon P Police car Rx Q Circle with in Circles Circle with in Circles R RV Restaurant S Shuttle Satellite T Thunderstorm (cloud/bolt) Thunderstorm (cloud/bolt) U School Bus Sun V VOR TAC VOR TAC Symbol W National Weather Service NWS-Digi X Helicopter Y Sail Boat Z Windows [ Runner WC \ DF Triangle ] Packet Mail Box ^ Large Aircraft Large Aircraft _ Weather Station WS-Digi ` Satellite Dish a Ambulance b Bike blowing cloud c DX antenna d Fire dept. DX Antenna e Horse Sleet cloud f Fire Truck FC Cloud g glider Pennant (2) h Hospital HAM i Island Island j Jeep Jeep k Truck Truck l Small dot Small Dot m MIC Mile Post n N Small Triangle o EOC Dot with in Circles p Puppy Dot with in Circles q GS Antenna GS Antenna r Antenna Tower Antenna Tower s Boat Boat t TS ? u 18 Wheel Truck v Van Dot with in Circles w H20 Flood x X Windows Red Dot y House w/Yagi House w/yagi z X Windows { FOG FOG | Black Line Black Line } TCP TCP ~ Sail Boat Sail Boat HELP-INDEX>What was new in Xastir 1.0 Over the past year, Xastir has been under active development, and this new release is the culmination of those efforts. Development has been run by Chuck Byam, who agreed to take over for Frank Giannandrea. Many other individuals have contributed to this project, and are listed in the AUTHORS file. The Xastir package now uses GNU autoconf to build makefiles and select features based on the libraries and software one has installed. No more editing makefiles as in previous releases! Starting Xastir 1.0, one probably won't immediately notice any major changes. The familiar interface of previous Xastir versions has been retained for the most part. The great majority of the changes are improvements in efficiency under the hood: * Startup time for the program has been improved. * Memory usage has greatly improved, with dynamic allocation of separate station, trail, and weather data on an as-needed basis. No longer will memory be wasted on stationary stations for trail data, nor will non-weather stations waste memory for weather information. With these modifications, Xastir can even be connected to the internet link comfortably on a 16MB machine. * Improvements have been made to avoid having to reload maps from disk at every minor change; Weather alerts and changes to the display and tracking options no longer cause the maps to reload, rather the trails and symbols are redrawn alone. * Improvements have been made to various dialog boxes that re-drew often, to redraw less often, to allow them to be usable on slower systems. This is also true of tracking a station, with the map redrawing only if the station approaches the edge of the screen. Thanks to these changes, Xastir is perfectly usable on slower Pentium(tm) machines. Native GeoTIFF support is now included, and will be compiled into one's copy of Xastir if they have the GeoTIFF libraries installed on their system. These map files are of very high quality, and are especially useful in search and rescue operations. Maps on this format are available from the USGS, and commercially on CD-ROM. Xastir understands how to convert from the NAD-27 datum to the new WGS-84 datum, so maps of both format can be read accurately. New shortcut buttons have been added to the map selection dialog to enable one to pick all maps of a specific type. Support for the Festival Speech Synthesis System is now available to announce new stations and band openings. The old system of alert sounds has been retained as well. Xastir now supports adding and deleting objects. Finally, Xastir users are able to manage resources with this useful feature. Objects are helpful for coordinating events, directing travelers, and doing search and rescue work. The County Warning Area maps that display weather alerts are no longer painted onto the maps below, but are shaded onto the maps. While this does make the colors unpredictable, it is now possible to see the road-maps below the alert! A new and useful feature is the change in the orientation of a symbol based on the direction in which it is moving. Even without a trail, a quick glance can tell you a mobile station's bearing. There are several more new options in the display menu, enabling one to decide more precisely what is displayed and what isn't. Panning and control over the map has been enhanced: There are now arrow buttons visible at the top of the screen to pan the map. The map can also be panned with the arrow keys, and the zoom can be adjusted with the page up and page down keys. There are new option in the click menu, to center the map where you clicked or to place an object where you clicked. The panning options in this menu have been removed in favor of the new controls at the top of the screen. Support for altnet has been added, enabling one to have a private APRS(tm) network for special events, search and rescue, storm chasing, or whenever else the user doesn't want to be bothered by the hundreds of APRS(tm) stations around. There are numerous small changes, both visible and invisible to the user. The interface control dialog now has a "Start all" and "Stop all" option, to save the user the time of performing these actions for each interface. The station setup dialog now shows you your symbol, so you don't have to exit the dialog to see which symbol you chose. Several buffer overflows that caused unpredictable behavior and/or crashes have been fixed. And many minor improvements have been made to the source code to ensure that it compiles correctly on various systems. Enjoy the new Xastir! HELP-INDEX>What was new in Xastir 1.1 What was new in Xastir 1.1 This new release, Xastir 1.1, adds significant new features and enhancements to the user interface. Unlike 1.0, the interface changes will take some getting used to, but the flexibility and versatility of the enhanced interface will more than make up for the troubles. Among the improvements to the user interface: * Keyboard shortcuts for menus and dialogs, menu reorganization, and mouse behavior changes. * The ability to move objects or measure distance with the mouse, using the appropriate check-boxes in the toolbar. * A scale has been added to allow one to judge distance on a map. * Map labels for windows-style APRS(tm) maps are rotated to match the marked map features. * The user interface for dealing with objects has been entirely redesigned. * Station info boxes can be set to automatically update. * Tear-off menus. Allow you to keep a menu on the screen and play with different options. Tear off a menu by clicking on the dashed-line portion. Map support has been greatly enhanced, with PocketAPRS, ESRI Shapefiles, GNIS labels and many graphics formats with ImageMagick. Additionally, support for downloading graphical maps from web-servers has been added, allowing Xastir to use online radar, Tiger, and Terraserver maps. Xastir 1.1 supports much more of the APRS(tm) protocol than its predecessor: * It can add, modify, move and view area objects, signpost objects, and items. These features are invaluable for event coordination and search and rescue use. Objects and items are also periodically retransmitted. * Support for displaying position ambiguity squares, pre-calculated radio ranges, Maidenhead grid squares, and weather objects. These features aren't extremely common, but do come up occasionally. * Support for the APRS(tm) radio direction finding features. These features are useful for anything from tracking jammers to locating lost hikers. Xastir supports both Omni and Beam reports. Other notable improvements: * Xastir can now search for a specified location or landmark using GNIS data. * Track logs can now be exported to file. * Maps can be printed if certain tools and libraries are present. * Support for retrieving historical track data from findu.com. * Xastir now compiles and runs on Mac OS X, Solaris and FreeBSD with only minimal changes; see README for details. * Several major bugs found in 1.0 have been corrected, including the problems loading DOS maps and the problems with the weather reporting. Other minor bugs and memory leaks have been fixed. And several more errors have been corrected in the parsing routines, so Xastir should remain stable no matter what is thrown at it! HELP-INDEX>What was new in Xastir 1.2 What was new in Xastir 1.2 The latest Xastir release adds numerous new capabilities, keeping Xastir a benchmark for APRS(tm) programs on any operating system. Xastir's hardware support has been enhanced, with * Support for Serial KISS TNCs * Support for Serial TNCs with GPS on the AUX port * Support for using AGWPE as a TNC * Support for Dallas One-Wire weather station (see http://melhuish.info/simon/projects/oww/) * Support for more weather stations via the wx200d daemon (WX-200/WM-918/ WMR-918/WMR-968) * Support for the different sized rain gauges of the Peet Brothers weather stations. Additionally, several bugs in the weather reporting code were corrected, and support for setting the system clock based on the GPS was added. There have been many additions and improvements to the Xastir user interface: The most notable is the addition of dead-reckoning. This means that stations that are moving will continue to move on your screen in the direction and at the speed speed that they last reported. The estimated location can be shown with any combination of a ghosted icon, a dashed line from the last position, or an arc of expected possible distance and angle. Also very notable are the improvements to the Map Chooser. Maps can now be selected a directory at a time, or individually. And the new map properties dialog allows individual control of map layering, map color filling, and consideration for auto-maps. Additionally, with extent caching under the hood, auto-maps regains much of its formal usefulness even with many maps installed! Bulletins pop up on screen, and emergency beacons cause an alert with the locate station dialog on hand. These changes are helpful in emergencies and event coordination. Xastir can now be set to use one of several coordinate systems, including UTM, dd.ddddd, dd mm.mmm, and dd mm ss.s. This is helpful for coordinating with other groups using a different system. The online Tiger maps can now be enabled from the map menu, and options can be adjusted to request maps with just the data you want displayed. The stations menu has been reorganized, allowing more intuitive filtering of stations shown and of accompanying data. Other smaller interface changes include: * The density of the grid-lines can be adjusted with the +, =, and - keys. * Objects and item lists have been added to the view menu. * Station maidenhead grid squares are now shown in station info and the coordinate calculator. * There is a check-box "Track me" to enable easily tracking your own station * The length of trails downloaded from findu.com can now be specified. * Xastir can now ID via voice IDs or Screen IDs, by editing the configuration file. This is intended for configurations when the Xastir screen is seen remotely via fast-scan TV. * Timestamps are written to log files every 30 seconds of operation, to keep a record of when data was heard. * The status bar can display the course/distance to your station when enabled in the file|configure menu. * Range scales are now shown opposite the map scale. This is an attempt to standardize various APRS(tm) client approaches to zoom levels. New additions under-the-hood: * Tracked proximity alarms. * Export waypoints within proximity boundaries. Your GPS can show you the locations of APRS(tm) stations as waypoints on the GPS map screen. * Export trail as ESRI Shapefile. New feature if you have Shapelib compiled in. Station Info->Store Track button also creates a Shapefile map of the station's track now. The weather reporting features have been improved, with the addition of optional wind barbs to weather stations and decoding of storm wind radius data. Weather alert shading is now done with pixmap stipples showing the type of alert. Further information on an alert is available over the internet from the WXSVR by simply double-clicking the alert in the weather alerts list. Weather alerts now use the newer ESRI Shapefile-format maps. Xastir's map support has been improved with enhancements to the ESRI Shapefile code to handle point-type ESRI Shapefiles. Additionally, speed improvements have been made in the ImageMagick graphical map loading, and many color-correction features have been added. As mentioned above, the Map Chooser has been greatly improved, and weather alerts use ESRI Shapefile-format maps. Under the hood, Xastir has had several major improvements: The messaging system has been largely rewritten, and the annoying timed updates to dialogs no longer occur. The new messaging system allows multiple messages to be queued, and implements reply-ack's for speed. Xastir also attempts to specify a reasonable path for the message based on received messages. This improves speed and congestion control. The messaging GUI has been largely untouched, and remains high on the list of future improvements. The build process has been significantly improved; Xastir is now able to be built on numerous operating systems with few manual interventions. Xastir now supports GPSMan/gpsmanshp, allowing the importing of waypoints, tracks, and routes from several types of GPS receivers. This allows you to create ESRI Shapefile-format maps out of GPS data. Xastir now implements SmartBeaconing(tm), which greatly improves trail quality and reduces unneeded channel usage. See the "Configure SmartBeaconing" help topic. IGating support has also improved, with the ability to configure a specific RF path for IGated packets, and the addition of a 29 second anti-dupe queue to reduce unnecessary redundancy on the RF channel. Map extents and filenames are now cached, so maps will not be loaded from disk unless they are on screen. This is a major improvement for map types that did not specify this information. Additionally, auto-maps uses this information, making it usable even with many maps installed. Objects controlled by Xastir are now stored in a file, so a restart of Xastir will not cause them to be lost. Additionally, Xastir now supports the compressed format for objects and items, which can help reduce RF channel congestion. It also gives you better location accuracy of the placed objects. See the help topic "Configure Default Operation". Xastir now drops root privileges when not needed if run setuid root. Please read the information about this in INSTALL; this change provides only limited protection. Xastir now supports using a private colormap with the command-line argument "-i". This is recommended for systems running in 8-bit color mode. Additionally, several more buffer overruns and other errors were corrected in Xastir's data parser, and numerous other bugs have been fixed. Enjoy the new Xastir! HELP-INDEX>What's new in Xastir 1.3 What's new in Xastir 1.3 This latest Xastir release greatly improves on the efficiency and usability of Xastir, and adds many helpful and often-requested new features. .geo files can now have REFRESH tags, to specify how often the file is reloaded. This is useful for weather radars and other dynamic images. .geo files can also have a TRANSPARENT tag to make a certain color transparent, and a CROP tag to specify a specific region to display. Some Opentrac packets are now decoded and displayed. See http://opentrac.org/ for more details. The default main Xastir directory is now /usr/local/share/xastir; please see the upgrade notes in README for migration information. This more closely mirrors the behavior of other applications. If you're installing from a binary package (rpm/deb/etc), the default install location may be /usr/share/xastir. Xastir efficiency has been greatly improved. Changes in data structures and timing values have made this Xastir release the most efficient yet. Additionally, map redraw sequences are interruptible, so map panning speed has been improved. dbfawk support - Experimental support for configurable shapefile metadata, in an awk-like language. See README.MAPS for more details; this must be turned on with a specific switch to the configure command. GDAL/OGR support - Experimental support for GDAL and loading of native Tiger data (.RT1 files). This is automatically enabled if the GDAL library is found. Support for UTM w/special zones and MGRS coordinate systems. Cad drawing mode allows one to draw regions on your screen using the center mouse button. This feature is not yet complete, but is functional. User interface changes: * Several of the menus have been reorganized to have a hierarchical design. * Additionally, a few colors have been modified for better visibility. * The map label font and style are more configurable * The cursor changes to let one know if they're in move object or measure mode. * If the coordinate system is set to UTM, and "Map Grid" is selected, an UTM grid is displayed. Snapshot mode now generates a .geo file, allowing the image to later be used as a map. Tiger maps have been moved back the chooser, as was the pre-1.2 behavior. This is more consistent. Xastir-Release-2.2.4/help/help-Spanish.dat0000664000175000017500000025070615151324131017310 0ustar hibbyhibbyHELP-INDEX>LAME PRIMERO - Licencia LAME PRIMERO - Licencia !!! NOTA: Este Documento se actualiz en Fecha 04/09/02 !! Para la informacin ms actualizada por favor lea el archivo README.1ST en el directorio de Xastir. Recuerde que este programa es usado por la comunidad HAM, en los EE.UU la FCC le restringe de transmitir sobre RF si usted no es un HAM con licencia. Usuarios autorizados en otros pases fuera de los EE.UU. Deben buscar sus restricciones gubernamentales locales. LICENCIA: XASTIR, Estacin de Aficionado de Rastreo y Reportes de Informacin. Copyright (C) 1999-2000 Frank Giannandrea Copyright (C) 2000-2026 The Xastir Group Este programa es software libre; usted puedes redistribuirlo y/o modificarlo bajo los trminos del GNU Licencia Pblica General como publicado por la Fundacin del Software Libre; cualquier versin 2 de la Licencia, o (a su opcin) cualquier versin ms atrazada. pero SIN NINGUNA GARANTIA; an sin la garanta implcita de COMERCIABILIDAD o APTITUD PARA UN PROPOSITO PARTICULAR. Vea el (GNU) Licencia Pblica General para ms detalles. Usted debes de haber recibido una copia del GNU Licencia Pblica General junto con este programa; si no, escriba al Software Libre Fundacin, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, EE.UU.. Ms informacin sobre el programa puede encontrarse en: http://www.xastir.org/ http://github.com/Xastir/Xastir Hay algunos Forum de discusiones disponibles que son especficamente sobre Xastir. Usted puedes subscribirse en uno o en ambos de ellos para recibir las ltimas informaciones y novedades sobre el desarrollo de Xastir. Visite esta direccin para subscribirse en http://www.xastir.org/. Para ms informacin sobre la Licencia GNU busque en: http://www.gnu.org/ HELP-INDEX>Bienvenido! y Notas de los Autores Bienvenido! y Notas de los Autores XASTIR, Significa, X-ventanas Estacin de Aficionado de Rastreo y Reportes de Informacin. El significado en ingls es como sigue: XASTIR, or (X)windows (A)mateur (S)tation (T)racking and (I)nformation (R)eporting. Es un APRS(tm) como programa que es Fuente Abierta y libre para usarlo y pasarlo a otros. Actualmente este programa est en desarrollo y no debe verse como un producto finalizado! Su ayuda ser necesaria para hacer de este un mejor programa. Si usted tienes habilidades programando y/o puede escribir documentacin, su ayuda puede ser necesaria! Yo tengo muchas ideas pero el tiempo muy corto. As que si usted piensas que usted puedes anexar algo al esfuerzo djemelo saber! 73, Frank Giannandrea fgiannan@eazy.net APRS[tm] es una Marca de fbrica de Bob Bruninga, su pgina est en "http://web.usna.navy.mil/~bruninga/aprs.html" Por favor note que mucha de la informacin sobre APRS(tm) puede encontrarse en la documentacin de APRSdos escrita por Bob Bruninga. Una adicional fuente de informacin es el APRS(tm) especificacin, disponible en http://www.tapr.org HELP-INDEX>What's new in Xastir 2.0.9 The "What's New" section of this help file has been long neglected, and has not been updated in every release. In general, the best way to see what has changed in Xastir is to view the git log. What follows is an abbreviated summary, long after the fact, of what has changed since the last time this "What's New" was updated for release 2.0.1 (which was in 2012!). The Xastir project has migrated from SourceForge and CVS to Github and git. This changes how Xastir releases are distributed, and also how one accesses the latest development code. The Xastir project is now hosted at https://github.com/Xastir/Xastir, and the wiki is still at http://xastir.org. -Added support for IPv6 in both Xastir server code and APRS-IS connection code. -Added "wxnowsrv.pl" script to support feeding Xastir weather data via the WXNOW.TXT mechanism. -Fixed compressed weather alert handling. -Added correct dbfawk files for most recent NWS shapefiles. -Added a few on line maps from geograits.gc.ca. -Fixed area computation of CAD objects. -Added support for proportional fonts in map labels. -New scripts added to support feeding ADS-B and AIS data into Xastir. -Many old GEO files for online maps stopped working when servers they referenced were taken down. Most of these have been removed. If you find other .geos that don't work, please report this on the xastir mailing list. -Added new fosm OpenStreetmaps tile server GEO. -Map cache code updated to work with any version of Berkeley db after 4.1 (including the 5.x series). HELP-INDEX>What's new in Xastir 2.0.1 (Changes between 1.7 and 2.0.0 were never recorded here,this block describes a few of the changes from 1.9.8 to 2.0.0 that occured right before release of 2.0.0, but otherwise documents only changes from 2.0.0 to 2.0.1) Added tiling for OpenStreetMaps (2.0.0). Added "setlocale()" calls to assure we aren't confused by user LANG variable settings. Improved speed of config file processing. Fixes for new One-Wire-Daemon protocol, allowing both old and new to work with Xastir. Fixed segfaults that could happen when closing list dialogs. Fix OSM code to support 16-bit quanta in Graphics/ImageMagick. Fixed broken makefile that was ignoring DESTDIR. Fixed broken build so internal shapelib builds correctly when proj.4 is not installed. Add dbfawk files for several generations of new NWS shapefiles. Update get-NWSdata to pull current NWS shapefiles. Add start/stop files for Kenwood D72 and D710 radios. Added a script to convert GeoPDF files to usable GeoTIFF files. Make the command to set a TNC into CONVERSE mode a run-time configurable option in the TNC Interface Properties dialog. Add support for Australian Bureau of Metrology weather alerts. Fixes for Davis APRS Data Logger, Davis Meteo and LaCrosse support so it gets rain totals correct. Allow "posit interval" in File->Configure->Timing to go all the way to zero, meaning "never send posits on a schedule." Add signal support so that Xastir will emit a posit when it receives SIGUSR2. Combined with zero "posit interval," this allows Xastir to emit a posit only when told to by an external script. Fixed error in logic for band-opening alerts (speech and audio alarms) so it does not incorrectly report third party traffic as a band opening. Add "Send Control-E to get GPS data?" to TNC interface properties for the "Serial TNC w/ GPS on AUX port" interface type. Defaults to enabled, which is correct for KPC-3+ TNCs, but should be turned off for any TNC that automatically streams GPS NMEA strings, such as Kenwood APRS radios. Update GPSMAN support to reflect changes in the gpsman command line. Add a small delay between sending the converse-mode command and sending data for transmission, because KAM TNCs don't work if you send the data immediately. Fix a bug in the OSM tile download loop that could prevent further downloading of tiles if any one tile download fails. Fixed a thread-unsafeness bug that could cause Xastir to start using corrupted file names when multiple logging options (TNC, NET, WX, IGATE, etc.) selected simultaneously. Fixed get-fcc-rac.pl script to reflect changes in RAC download site. HELP-INDEX>What's new in Xastir 1.7 Added REGRESSION_TESTS in order to test interoperability of the configure-time flags. Added a replacement for malloc() for those cases where the OS provides a faulty one. Added more to the summary.log file: The tests and results from config.log. GDAL configure probe now uses gdal-config if it's in the user's path. Tweaked configure so that dependent libraries cause other library searches to fail, and to provide more user output. Added ASCII-art drawing to INSTALL showing most of the library dependencies. Updated symbols.dat to more closely correspond to the current spec. Implemented EMERGENCY BEACON transmit capability under the Help menu. Added decoding for "EMERGENCY" anywhere in the packet plus any of these in the TO: field: ALARM, ALERT, WARNING, WXALARM, EM. Any of these will invoke the normal emergency popup dialog. Waypoint symbols now have a line drawn between them and the station transmitting them, per the spec. Now using font metrics to determine size of font. We use that to determine size of black rectangle to draw underneath. Fixed the Fetch Findu Trail function so that it matches what Findu can provide. Fixed track->shapefile function so that it works on Cygwin too. Added reset button to Change Debug Levels dialog. Enable WX Alerts menu item is now grey'ed out if Shapelib isn't installed. RINO Download timing slider is now visible but grey'ed out if gpsman isn't installed. Added a custom zoom option to the right-click zoom levels menu. Moved the center & zoom dialog to the map menu. Changed a memcpy() to an xastir_snprintf() function in alert.c to assure that a string is terminated. Free'ing some malloc'ed space for cases where hash inserts fail. Added probe for sighandler_t definition. Changed includes, added leak_detector.h. A few small changes here and there to get rid of compiler warnings. Freeing some malloc'ed space for the cases where hash inserts fail. Fixed initializers for awk_rule[]. Changed hash add functions so that they do a delete first instead of replacing hash values. Moved some wx-alert related code to debug level 2. Changed leak detect interval from 5 minutes to 60 seconds. Fixed a big memory leak in draw_nice_string() function. Changed include files around so memory leak detection stuff is in leak_detection.h. Added new compiler flags and cleaned up the code to eliminate many warnings created. Fixed Incoming Data dialog code so that packets transmitted to local interfaces would appear there. TNC/NET toggles work for those now too. Fixed memory leak in font metrics code. Simplfied get_long() and get_int() functions and callouts. Tweaks for sighandler_t and sigjmp_buf. Added a sign-on message for server connects. FCC/RAC lookup or Locate Now buttons don't destroy the dialog anymore. Fixing up strings.h includes. Added a new popup for EMERGENCY packets. Changed signal() with SIG_IGN to sigignore for some cases. Added a test for sigignore() to configure.ac. Changes to allow different versions of "gv" to be used. Moved "-lgdal" to end of link line to avoid conflict with other libraries. Added UDP server and client. Added more language strings for previously hard-coded values. Changed config file get_int and get_long functions to provide better output when config file entries are missing or out-of-range. We now allow gating to the internet and to RF for user-defined packets and telemetry packets. Changing to for the TCP server signon message. Changing to timestamp per packet for log files, with long int seconds at the beginning. Added icon. Added support for -geometry command-line parameter. Added fast creation of standard SAR objects via mouse menu, including adding digits to the end of the object name if name would conflict with pre-existing objects. HELP-INDEX>What's new in Xastir 1.6 Fix for DF lines having incorrect angles at times. Configurable display of layers for USGS topo maps. Better Map Feature Search: Shows up to 50 matches, user selects which one to center map on. Configurable "relay" digipeater calls: Up to 50 callsigns can be specified in the Xastir config file to use for relay digipeating. "WIDE1-1" is now the default. Added support for Web Map Service (WMS). Tweaked the GPGGA and GPRMC GPS sentence decoding. Added speed-ups for lat/long geotiff's. Added Aloha circle. Added new #defines in interface.h for specifying "conv" or 'k' command to TNC. Added new tnc-startup file for TAPR-2 style TNC's. Added transparency capability to WMS. Fixed digpeating code for "wide1-1,wide2-1" case. Fixed some compile errors that are seen on FC4 and OSX Tiger. Added new terraserver .geo file options. Changed Map Properties "fill" option to allow NO/YES/AUTO. Auto uses dbfawk if present, no/yes force fill to that state. Fixed some #ifdefs here and there so that compiles will work if some libraries aren't present. Added map caching for nearly all internet maps, plus two new toggles on the map menu for clearing out current-view maps or all maps from the cache. Moved Tigermap timeout slider to main timing dialog, renamed it, and made it function for ALL internet map fetches. Added timestamps to x_spider log messages. A fix for the emacs tempfile bug w.r.t. dbfawk files went in, but hasn't been verified to have fixed the problem yet. More bulletproofing added to the map_cache code. Fixed a compile problem that happens if ImageMagick isn't installed. Changed stipple style to solid for polygons drawn with dbfawk. Another fix so that linking works without map caching. HELP-INDEX>What's new in Xastir 1.5 Optional Rtree shapefile extent caching Optional berkelydb-based internet map caching Modifier keys fix Improvements to the message GUI Tactical call support re-written, hashtable based Warnings on crazy paths Hashtable weather alert speedups Dead-reconing for Objects/items Igate of specific stations (in the nws-stations.txt) Fixed DF object properties Measure function more accurate Decoding for "Position with Timestamp no APRS messaging" packets. More thorough checking for scanf/sscanf/fscanf function calls Fixing 100% humidity for some weather stations, plus added more data for Davis stations Changed active internet connection check from 1 min to 5 minutes Fixed decoding of compressed DF objects Fixes to allow new WHO-IS server to be used from Xastir Got rid of extra 0x00 byts between transmitted KISS frames Tweak to not start an interface upon changing its properties Tweaks to allow use of http proxy servers for online map accesses (.netrc file) HELP-INDEX>What's new in Xastir 1.4 Comment fields for interfaces split_gnis and ozi2geo scripts, need to add to section on scripts serial mkiss interface move objects without confirm new timing params w.r.t. trails, need to add to config|timing part geo-coder (already in docs) exponential/random back-off for almost everything dbfawk default, memory leaks fixed click+drag zoom boxes tactical callsign support numerous small memory leaks, uninitialized data uses, and similar bugs fixed. GPS quality info RINO waypoints downloading label trackpoints comment/status timestamps listener socket/ability to act like a limited internet server HELP-INDEX>Iniciando a Xastir por primera vez Iniciando a Xastir por primera vez Cuando Xastir se inicie por primera vez, usted debes ejecutarlo en una ventana terminal asi que cualquier mensaje de advertencia o error puedan verse. En la mayora de los sistemas una ruta es configurada para correr el programa en /usr/local/bin y todo lo que usted necesitas hacer es tipear "xastir" en la lnea de comando. En sistemas que no tienen este tipo de ruta instalado "/usr/local/bin/xastir" para empezar el programa. Usted tambin puedes poner la opcin del Idioma en este momento. Para poner el idioma o cambiar el idioma actual, use sta lnea: xastir -l Los Idomas Actuales son: Alemn (German) Espaol (Spanish) Francs (French) Holands (Dutch) Ingls (English) Italiano (Italian) ElmerFudd (English) MuppetsSwedishChef (English) OldeEnglish (English) PigLatin (English) PirateEnglish (English) Si Usted quieres correr el Xastir en espaol use sta lnea: Ej: xastir -lSpanish o xastir -l Spanish Esta opcin ser guardada en el archivo de configuracin de usuario para que la prxima vez que Xastir se ejecute corra con el idioma Espaol. En nueva instalacin xastir tendr como valor predefinido el idioma ingls a menos que usted uses sta opcin de lnea de comando. NOTA: En mens, se seleccionan artculos que son encanecido, como en las opciones del ON/OFF, si 'ON' es seleccionado se opacar o se pondr transparente (encanecido). HELP-INDEX>Configurando la informacin de la Estacin Configure la Informacin de la Estacin Pulse el botn del ratn en Archivo luego Configurar despus en Estacin llene la casilla con su Indicativo de Radioaficionado. llene su posicin de la estacin si usted no ests usando Xastir con una unidad de GPS. Si usted no la conoce, usted puedes localizar su posicin general en el mapa con Xastir y puedes usar la posicin dada por colocar el puntero del ratn sobre el mapa. Esta posicin ser visible en la barra del fondo de Xastir cuadro 2 de la izquierda. Si usted tienes un GPS usted puedes saltar esta opcin. Los smbol/grupo de la estacin pueden configurarse aqu. Pulse seleccionar grficamente y escoja un smbolo, o manualmente rellene los campos. Una descripcin de texto de cada uno de los smbolos pueden encontrarse en la "Tabla de smbolo" tema de ayuda. Las cubiertas son cumplidas seleccionando un smbolo de la tabla alternada, y poniendo el campo de la tabla a el carcter que usted desea recubrir encima del smbolo. Letras maysculas y los nmeros pueden ser recubierto. El APRS(tm) especificacin slo permite cubiertas sobre smbolos especficos; Xastir no forza esto, pero algunos otros programas pueden. Note que no todos los smbolos se han llevado a cabo en el selector grfico todava, y algunos de ellos no estn por el APRS(tm) especificacin todava. Luego, entre en los datos para la potencia/altura/ganancia de su estacin. Esta es una informacin til pero no se requiere; absolutamente seleccione "Desactive PHG" desactivarlo. Estas opciones presentan una representacin granular de su estacin. Seleccione la combinacin de valores cerca a la descripcin de su estacin. Otra opcin sera especificar el RNG en el campo de comentario en millas en lugar de usar PHG. Vea el APRS(tm) especificacin para detalles. Por favor use altura sobre el promedio del terreno para el valor de altura. No use el promedio de altura sobre el nivel del mar o altura sobre tierra. Para el uso de Ganancia la ganancia de su antena en dBi. (CORRIGEME: dBd? la especificacin no es clara, yo pienso que est implicando dBi porque dice "en ausencia de cualquier datos, las estaciones son asumida a estar corriendo 10w a un 3dB omni en 20pies. Una antena omni tpica es slo 3dBi.....) Para Altura, use el HAAT (altura sobre el promedio del terreno) de su estacin, NO la altura sobre el nivel del mar o altura sobre geo-id. Nota: La ganancia puesta es realmente pensada para las antenas verticales; la ganancia puesta para una antena direcional debera ser por debajo de la ganancia hacia delante de una antena direcional. Esto es porque con la direccionabilidad puesta, el crculo de PHG es compensado slo a travs de 1/3rd de su tamao hacia la direccin especificada. Poniendo la Ganancia ms alta agrandar el crculo entero no-realisticamente, en lugar del aumentado direccionalmente. Haba charla hace varios aos sobre el enmendando las especificaciones para mejorar trato con antenas direccional, pero nada fue cambiado. Entrar un comentario, no requerido pero agregar visin en su estacin. Una cosa comn para entrar aqu es su direccin de e-mail preferida. Que ser transmitido a lo largo con su postula. La ambigedad de la posicin permitir usted controlar que tan exacto usted transmite su posicin. Si usted no pone nada, xastir permitir a su estacin transmitir la exacta posicin que usted ha entrado o ha recibido de un GPS. Las otras opciones lo pondrn en alguna parte en el rango de la opcin que usted seleccion. Note que esto puede tirar estaciones dciles a alguna no-especificacin para un bucle. Findu.com no entiende la ambigedad de posicin. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" conservars las actuales configuraciones. HELP-INDEX>Configurar Operacin Predefinida Configurar Operacin Predefinida Pulse el botn en Archivo despus en Configurar luego en Predefinidos Esta pgina prepara algunos valores por defecto normales para el funcionamiento del programa. Viejas estaciones se desplegarn con un icono fantasma, y el sendero correspondiente se fragmentar. El primer juego de botones de barra especifica el intervalo de desdoblamiento. El segundo juego de botones que especifica cuando una estacin ser removida de la pantalla. Las estaciones tambin son removida del banco de datos interno en el doble este tiempo, as si usted lo pusiera durante 6 horas, se anularn estaciones del banco de datos a las 12 horas. El tercer juego de botones especifica qu a menudo la identificacin de su estacin ser transmitido. Para las estaciones fijas una recomendacin buena es cada 30 minutos, y definitivamente ninguno menos de 10 minutos. Las estaciones mviles pueden desear una ms rpida proporcin. Este intervalo tambin se usa para mandar objetos y artculos. Pruebe mantener este intervalo algo razonable, como transmitir hacia un largo camino, cada 30 segundo realmente subir mucho el tiempo areo. GPS Tiempo pondr el intervalo de tiempo mirar el GPS por nuevos datos. Esto es disponible para estaciones que usan un cable compartido HSP con su TNC. La Opcin Trasmite Estacin fija el tipo de paquete que su estacin transmitir sus datos como. Transmite datos Raw WX si seleccionado tambin enviar un paquete que contiene Datos raw de una Estacin Meteorolgica. Esto es til en los tipos de ASCII de estaciones WX, como la Peet Bros. Estacin WX. Las Opciones de IGate prepararn su estacin como un portal de Internet-RF. Esta opcin podra ser usada con cuatela, Como un HAM usted es responsable por el data que viene va el Internet y es transmitido hacia el Puerto de RF. Usted tambin necesitar escoger una opcin del igate en cada interface para que el igate funcione. Si usted quiere tener su igate enve NWS alarmas WX hacia el RF, usted debe crear un archivo ~/.xastir/data/nws-stations.txt listando cada llamada o estacin de NWS (como "PHISVR") que le gustara transmitir va RF. "Transmitir datos de WX RAW", si seleccionado, tambin enviar un paquete que contiene crudo (raw) Datos de estacin meteorolgica. Esto es til en los tipos de ASCII de estaciones WX, como la Peet Bros. estacin meteorolgica. "Los datos de posicin comprimida pueden ser transmitida"?, si es seleccionado, transmitir en el ms nuevo formato comprimido. Este formato reducir la cantidad de datos en el aire, por eso aumentando la capacidad de la red APRS(tm). La mxima precisin de la posicin transmitida tambin es ms alta. Algunos programas ms viejos, incluyendo las recientes versiones de WinAPRS, no decodificar este formato todava. Findu.com tambin podran tener problema con el. Activar Red Alternada ? esta opcin se usa para desplegar grupos de estaciones que muestran en el unproto en el campo '>To' la versin del software como el Xastir que muestra la versin en el unproto como esto: HI8GN>APX090. Usted tambin puede seleccionar Altnet y puede escoger una llamada del altnet de este dilogo. Altnet le permite tener un privado APRS(tm) red entre las estaciones que tambin tenga altnet configurado, y tiene la misma llamada del altnet entrada. Si cambiamos el valor por defecto que es XASTIR por ejemplo por APX110 desplegar toda las estaciones que tengan versiones de APX11x donde valor de 'x' puede ser desde 0-9. HELP-INDEX>Configurando las Alarmas de Audio Configurando las alarmas de Audio Para usar esta opcin usted debes tener una tarjeta de sonido y un programa que reproduzcan los archivos wav. El programa reproductor de Audio debe tener comando el cual usted quieres ejecutar para tocar el audio archivo (y cualquier opcin en la lnea de comando). Los campos tendrn el nombre del archivo a reproducir, campos bajo la opcin pondr parmetros para la opcin. Las opciones Actuales son: Reproducir mensaje al encontrar una nueva estacin. Reproducir mensaje al recibir un nuevo mensaje. Reproducir mensaje de datos recibidos de una estacin dentro de la distancia min/max de su proximidad. Reproducir mensaje de datos recibidos de una estacin (va TNC) con la distancia de min/max de su banda abrierta. HELP-INDEX>Configurar el Sintetizador de Voz Configurar el Sintetizador de Voz Para usar esta opcin del sintetizador de voz usted debes tener una tarjeta de sonido configurada para poder reproducir sonido. Tambin usted necesita tener instalado y corriendo al Servidor Festival ms el Speech_tools con su biblioteca de soporte para el Sistema Festival de Voz Sntetizada y asi poder escuchar el sintetizador de voz anunciar nuevas estaciones y aperturas de banda proximidad de una estacin. El sistema de alarmas de sonidos ha sido tambin retenido. Con el Sintetizador de Voz adaptado por Curt Mills (we7u) ajuste las casillas en las cuales usted quieres ejecutar el sintetizador para las alarmas (y cualquier opcin en la lnea de comando). Los campos tendrn el nombre del archivo a reproducir, campos bajo la opcin pondr parmetros para la opcin. Las opciones Actuales son: Anunciar un mensaje al encontrar una nueva estacin. Anunciar un mensaje al recibir un nuevo mensaje. Anunciar un mensaje al recibir el cuerpo un nuevo mensaje. Anunciar un mensaje de datos recibidos de una estacin dentro de la distancia min/max de su proximidad. Anunciar un mensaje de datos recibidos de una estacin (va TNC o INET) con la distancia de min/max de su banda abierta. Anunciar un mensaje al recibir una nueva alerta sobre el tiempo climatolgico. Info sobre Festival puede ser obtenida desde: http://www.speech.cs.cmu.edu/festival/ HELP-INDEX>Configurando las Unidades de Medida Configure Unidades de Medida La seleccin predefinida es para el Sistema Mtrico, mm, cm, KPH, etc. Seleccionar Ingls, pulgadas, pies, MPH, etc. Pulse el botn de Configurar, luego en Unidades, despus la unidad de medida que usted quieres usar. Recuerde encanecida opciones son selecciona actualmente. HELP-INDEX>Salvar Configuracin Ahora! Salvar Configuracin Ahora! Este botn salvar todas la configuracin actual al archivo de configuracin. Note que cuando Xastir est cerrado, tambin salva configuracin al archivo de configuracin. HELP-INDEX>Barra de Estado de fondo Barra de Estado de fondo En el fondo de la ventana varios mensajes de estado estn disponibles: En la primera parte en la barra de estados general los mensajes son desplegados. La segunda parte se muestra la posicin lat/long actual moviendo el ratn sobre el mapa. En la tercera parte es usada para mostrar cuntas estaciones estn en el banco de datos. La cuarta parte de la barra desplegar el nivel de enfoque actual y desplegar "Tr" si el rastreo de estacin est encendida (on). El ltima rea desplegar el estado de dispositivo para cada interfz. Cada una desplegar en orden primero hasta el ltimo o de 0 a 9. El estado de la interface est separado en tres reas, tipo de dispositivo cima, datos de centro fluyendo, y interface de fondo estado operacional. El tipo de dispositivo mostrar qu interfaces se configuraron. El color mostrar qu tipo de dispositivo de la interface se configur. Azul es para los varios dispositivos TNC; Verde mostrar los dispositivos de GPS; Amarillo para los Servidores de Internet; Naranja para las interfaces de WX. El centro mostrar que los datos fluyen en rx (flecha que apunta a l a izquierda) o los datos fluyen fuera tx (flecha que apunta a la derecha) para eso interface. Una caja verde al fondo mostrar si esa interface es activa. Una caja roja mostrar si la interface es activa pero en una condicin de error. Por otra parte nada mostrar si la interface no est activa. Las ltimas dos partes mostrarn el estado del tnc y de la red. Una "=>" indicar si el dato est siendo enviado, y una "<=" si el dato est entrando desde la interfaz. HELP-INDEX>Moviendo el Mapa y el Men de Opciones Moviendo el Mapa y el Men de Opciones Movimiento en el mapa es muy simple, la facilidad y rapidez de movimiento son dependientes de la velocidad de su procesador y la cantidad de detalle que usted carga. Subiendo verticalmente: Subiendo verticalmente puede ser logrado por pulsar el botn derecho de ratn sobre el mapa (y sosteniendo el botn abajo). Est o plantear un men de opciones, con opciones para hacer subir verticalmente o fuera a un solo nivel, o para cambiar a uno de l os niveles del enfoque prefijado. Todas las funciones de enfoque desde el men de opciones harn acercarse o alejarse al punto en el mapa donde usted puls el botn del ratn correcto. El nivel de enfoque tiene una men en cascada. Niveles 1-64 son par a las reas muy locales y niveles 256 y superior es para reas grandes. El nmero ms bajo del nivel, la rea ms local. Una funcin de enfoque ms rpida es empujar y sostener el botn del ratn izquierdo, arrstrelo por el rea de inters y permitida vaya. El mapa har subir verticalmente aproximadamente a el tamao del cuadrado usted apenas descrito con el ratn la funcin de arrastre. El programa usa el componente vertical para decidir en el nivel de enfoque, y el componentes verticales y horizontales para computar el nuevo centro del mapa. El "movimiento" y "medida" que deben desactivarse checkboxes de la bara de herramienta de este rasgo para trabajar. El mapa tambin puede acercarse con el teclado las llaves de PageUp/PageDown. El acercar en este caso guarda el mismo centro del mapa. Paneando/Centrando: El mapa puede centrarse a una situacin especfica por pulsar el botn izquierdo del ratn. Pulsando el botn los enfoques del botn medio aleja con un factor de 2, centrando donde usted puls el botn. Paneando tambin es cumplido usando el men de opciones, o usando la flecha botones en la tope de la pantalla. La posicin del mapa cambiar una porcin de pantalla. Bastantes datos de pantalla anterior deben estar disponibles reorientarlo . El mapa tambin puede ser paneado con las llaves de flecha del teclado. Ms Sobre el Men de Opciones: La seleccin de "Estacin Info" en el men de opciones buscar la estacin cerca a donde usted puls el botn derecho del ratn. Si ms de una estacin est cerca de esa posicin un "escogedor de Estacin" de lista aparecer, entonces usted puede escoger los datos de qu estacin que usted quiere ver. Si slo una estacin es vista entonces el indicador del ratn es cerrad o y los datos de esa estacin se desplegarn inmediatamente. Note que expiradas estaciones todava tienen sus datos guardados en el banco de datos de Xastir, y si uno sabe la situacin anterior de una estacin, uno todava puede ver su info de esta manera. Tambin es posible desplegar estaciones viejas encendiendo el "el Despliegue de Datos Expirados" opcin en el men de las estaciones. CORRIGEME: Si no es completamente verdad. Esto slo despliega algunos de los datos que desaparecen como estaciones fantasma, Velocidad/altitud, etc., Para informacin de Objeto y Artculo, por favor vea el tema de ayuda "Objetos y Artculos" HELP-INDEX>Objetos y Artculos Objetos y Artculos La opcin de crear Objeto/Artculo en el botn derecho pulsado el men traear un dilogo con la posicin de basado objeto en donde usted puls el botn del ratn. Usted puede rellenar los detalles, y agregar un objeto/artculo desde este men. La opcin de modificar Objeto/Artculo le traer un dilogo de modificacin de objeto. Es similar al dilogo de creacin de objeto, excepto por la actual informacin de objeto que ya estn publicada, y el nombre del objeto y unas de las pocas otras opciones que no pueden ser cambiada. Los objetos son retransmitido dentro de la proporcin de posicin de la estacin reportada, configurada en Archivo|Configurar|P redefinidos, y cesar la retransmisin despus doblar el tiempo de despliegue de la estacin, tambin configurada all. "muerta" los objetos tambin son retransmitido de esta manera, hasta que ellos expiren desde la cola. Generalmente se usan los objetos para movimiento o cosas inconstantes como tormentas, mientras que los artculos generalmente son usando para las cosas ms inanimadas, como agua, estaciones. Cualquiera puede moverse con el ratn si el "Movimiento" el checkbox en la barra de botones se habilita. Note que los artculos no pueden ser descifrados por uno cuantos programas APRS(tm) . Las rea de objetos son tiles para una variedad de funcionamientos en lo que usted quiere dibujar o resaltar una rea de inters en el mapa. Ellos tambin pueden ser personalizados para dibujar rastros/caminos/fronteras, sitios de vijilancia para mal el tiempo, las pistas de aterrizaje, permetros, de una rea de bsque da o de un evento de servicio pblico, reas de dao, reas para quedarse fuera de, edificios que no estn en el mapa, la tabla checker/chess para juego por dinero en APRS(tm).: -) Note que las rea de objetos no son llevada a cabo en todas las versiones de programas APRS(tm), y algunos de los detalles de cmo ellos se despliegan tambin pueden ser diferente en otros programas. Nombre ste es el nombre del objeto o artculo. Puede depender de hasta 9 carcteres. Cuando modifica un objeto, este no puede ser cambiado. Para renombrar un objeto usted debe anular el original y entonces crear un nuevo objeto. Note que si usted selecciona Signpost/Area Object/DF Objeto que este campo y quizs otros sern aclarado. Entre en el nombre DESPUS que usted ha seleccionado el tipo de objeto que volver. Poste indicador Este hace al objeto un poste indicador de objeto. Estas seales pueden ser 3 carcteres, visible en un poste indicador a la locacin cuando el enfoque es acercado. (CORRIGEME: Nosotros no hacemos el despliegue de los postes indicadores todava de esta manera). Objeto del rea Esto hace un objeto del rea al objeto, y habilita los mandos de objeto de rea descrito debajo. Objeto DF ste es un informe de contrada-direccin. Habilitndolo le permite escoger reporte Omni o direccional, y le permite poner en el especifico para cada uno. Vea: http://web.usna.navy.mil/~bruninga/dfing.html y la documentacin de APRSdos para los detalles en estas tcnicas tiles. (CORRIGEME: la seccin Separada en las tcnicas de DFing?) Smbolo Estacin Usted puede seleccionar un smbolo para el objeto. Pulse seleccionar para escoger grficamente, o ver la seccin tabla de ayuda de smbolo para las descripciones de cada smbolo. Note que no todos los smbolos se han llevado a cabo todava en el escogedor de grficos, y algunos no estn por el APRS(tm) especificacin. Tambin note esa rea de objeto, poste indicador de objetos, y los objetos d e DF tienen smbolos fijos especiales y por consiguiente no pueden ser seleccionado aqu. Localizacin La localizacin del objeto se especifica aqu. Si usted seleccionara "Crear Objeto/Artculo" pulsando el botn derecho del men, la locacin que usted pulsado se llenar . Si usted moviera un objeto con el ratn, la nueva posicin estar en esos campos. Usted tambin puede teclear en una posici n, por ejemplo usted puede estar poniendo un objeto de un informe de voz sobre el aire. Opciones genricas Usted puede especificar la velocidad, direccin, y altitud de objetos aqu. Algunos tipos de objetos no pueden tener una velocidad o direccin en tales casos los campos son desgrisado . Objeto del poste indicador Si el objeto es un objeto de poste indicador, usted puede especificar de 1 a 3 carcter de mensaje que aparece en la seal aqu. Note que Xastir no despliega los objetos de poste indicador a propiamente todava. Objeto rea Se usan Objetos de rea para resaltar partes especficas del mapas, o para dibujar excepcionalmente detalle dentro de los mapas . Color luminoso. Use la versin ms luminosa de los colores permitidos. Colorido El rea debe llenarse, no slo perfilado. Esto puede ser til para excluir una rea de una bsqueda u otro evento. Tipo de objeto Escoge desde las formas geomtricas permitidas. Color del objeto Escoge el color en el que el objeto se desplegar. Esto tambin es afectado por el "Color Luminoso" la opcin anteriormente. El objeto Compensado En centsima de un grado latitud. Un detalle infortunado de la especificacin, y duro de calcular fcilmente. Basta decir que usted puede cambiar el tamao del objeto una vez usted lo ponga. El Desplazamiento izquierdo del objeto excepto / En centsima de un grado latitud. Vea anteriormente. Objeto corredor ste es el ancho de una lnea de rea de objeto. Util para las pistas de aterrizaje, tiempo watchboxes, describiendo una rea de inters o una rea de exclusin, etc., (CORRIGEME: Escriba esta parte! (el rea objeto) La especificacin es incierta a m, el cdigo, es incierto a m, pero en el futuro yo lo deducir todos!) Siempre anule sus objetos y artculos cuando usted halla terminado con ellos! No les permita simplemente expirar desde su escondite, como ellos pueden colgarse alrededor de las pantallas de otras personas por un periodo extendido. HELP-INDEX>Men Visualizador Opciones del Men de Visualizar El men de Visualizar presenta varias maneras de ver datos en Xastir. Boletines ste es el APRS(tm) tabla de anuncios, donde importantes anuncios son puesto. Si usted se conecta con la interfz del internet, es una buena idea para poner el rango del campo a unas cientas millas, para ignorar postes de otras porciones del mundo. "0" es el rango del campo, significa el mundo entero. Pulse el botn "Cambio de rango" pulse para hacer cambios a este campo eficaz. Xastir actualmente no soporta el envo de boletines. Datos de paquete entrantes Esto despliega los datos entrantes en su TNC o interfz del internet. Los botones radio debajo selecciona si usted quiere ver slo datos de TNC, slo datos del internet, o ambos. Estaciones mviles sta es una lista de estaciones que se estn moviendo. Las estaciones califican para esta lista si ellas se han movido (ms de una posicin recibida para ellas), el smbolo de la estacin no es considerada. Informacin mostrada incluyendo curso, velocidad, altitud, posicin, nmero de paquetes recibido, nmero de satlites de GPS visibles, curso, de su estacin, y distancia de su estacin. Todas las Estaciones Esta opcin despliega una tabla de todas las estaciones ordenada alfabticamente. Incluyendo el nmero de paquetes odo, el tiempo que la estacin fue oda ltima vez, el camino ms reciente paquete tomado, el PHG, y el comentario de la estacin. Estaciones locales Esta opcin despliega slo estaciones que se oyen va su TNC. Incluye el nmero de paquetes odo, el tiempo que la estacin fue oda ltima vez, el camino ms reciente paquete tomado, el PHG, y el comentario de la estacin. Ultimas Estaciones Esta opcin despliega una tabla de todas las estaciones ordenada recientemente oda a menor recientemente escuchada. Incluye el nmero de paquetes odo, el tiempo, la estacin fue oda ltima vez, el camino que el ms reciente paquete tom, el PHG, y el comentario de la estacin. Estacin WX Esta opcin despliega una tabla de todo el APRS(tm) estaciones del tiempo y sus datos. El datos incluyen curso del viento, velocidad del viento, velocidad de rfaga dle viento, temperatura, humedad, presin baromt rica, lluvia en la ltima hora, lluvia medianoche subsecuentemente, y lluvia en las ltimas 24 horas. Estacin Meteorolgica Propia Despliega sus datos del tiempo si usted tiene una estacin del tiempo y la ha configurado Xastir para accederla. Alerta del Tiempo Los despliegues alarmas recibidas, incluso las banderas de alertas, la alerta fuente/tipo, destino alerta, expiracin, mensaje, y efectuada situacin. Esto datos se usa por el resalto de condado, y no es particularmente humanamente-leble. Usted generalmente puede deducir el estado y condado para la mayora de las alarmas. Trfico de mensaje Muestras todo el trfico de mensaje mientras la ventana est abierta. Incluye la fuente, destino, interfz, y mensaje. La opcin de rango puede limitar este despliegue a las estaciones cercanas, mucho como el mando del rango en boletines. Un rango de 0 causas todos los mensajes a ser desplegados. SobreHora Muestras la cantidad de tiempo pasado subsecuentemente que Xastir fue iniciado. HELP-INDEX>Mapas Opciones y Seleccionar Mapas Mapas Opciones y Seleccionar Mapas Mapas Opciones: Auto mapas (on/off) Cuando cualquier mapa es encontrado, en el directorio de mapas (o cualquier directorio bajo l) ser desplegado, si el cae dentro de la regin de despliegue actual. Usted puedes agregar cualquier nmero de niveles de directorios bajo el directorio del mapa principal para sus mapas. El Auto mapa pasar por todos ellos y hallar que mapa (o parte) debe desplegarse. Todos los Mapas se unirn en el rea de visin. Si usted tienes una cantidad grandes de mapas, mapas muy detallados o una computadora muy lenta, esto puede ser mostrado bastante lento. Cuando esta opcin est apagada, se desplegarn mapas seleccionados con el selector de Mapas. Rejillas sobre Mapa (on/off) Cuando est en 'ON', esta opcin desplegar una lnea de reja cada 10 grados. Niveles de mapas (on/off) Cuando est en 'ON', esta opcin intentar filtrar fuera los datos cuando el nivel de enfoque muesta grandes reas. Esto no trabajar con todos los mapas pero trabajar con los mapas generados de 'Tiger line maps' en el sitio de aprs.rutgers.edu. Areas rellena en colores (on/off) Esta opcion controla el relleno del vector del mapa. En ciertos casos, usted podria querer enliminar el relleno para ver el mapa bajo el tope de mapas. Los mapas son cargados en orden alfabertico por tipo, asi que renombrando mapas es un segundo pero la via es menos elegante archivar la vista deseada. Seleccionar Mapas Esta se presentar con una lista de todos los archivos en su directorio de mapas. Cualquier mapa que usted desearas incluirlo en los datos desplegados, simplemente tiene que pulsar el botn del ratn sobre el nombre. Esto resaltar el nombre del mapa, Usted puedes seleccionar cualquier nmero de mapas. Pulsando en el botn "Aceptar" se desplegarn los mapas seleccionados. Oprimiendo el Botn de "Cancelar" abandonara cualquier cambio. Tambien hay botones de atajo para seleccionar todos de un cierto tipo de mapa, o de-seleccionar todos los mapas de una vez. Una nota sobre mapas: Muchos de los actuales mapas de vectores disponibles para los EE.UU. fueron creado en NAD 1927 datum, mientras Xastir y otros programas de APRS usan el WGS 1984 datum. Si es enfocado hacia una rea pequea en el mapa la variacin del datum puede ser muy notable. Los mapas topo USGS tienen sus datum corregido por Xastir como ellos son desplegados, asi que la posiciones generalmente sern ms exacta con los mapas topo. HELP-INDEX>Archivos Mapas, Dos, Windows, Pixmaps, geoTIFF y Condados WX Archivos mapas, Dos, Windows, Pixmaps, geoTIFF y Condados WX Tipos de mapas Xastir trabajar con varios tipos archivos de mapas. Todo el Dos, Windows/MacAPRS[TM] son archivos de Mapas que son soportados. Un nuevo formato de Pixmap se ha agregado en versin 0.3.2. Xastir tambin soportar mapas para las Alertas de condados WX. El ltimo formato de mapa soportado es geoTIFF, tales mapas como son USGS DRG topo mapas. Locaciones de Mapas Cualquier Dos, Windows/Mac o archivo Pixmap y geoTIFF, deben guardarse en el Directorio de /usr/local/share/xastir/maps en su computadora. Usted puedes crear cualquier nmeros de directorios bajo este directorio para ayudar a separar sus datos. Por ejemplo usted puedes querer crear un directorio de USA. y despus uno por cada estado bajo el Directorio de USA. O tiene un directorio separado para DOS o Pixmaps y geoTIFF. /usr/local/share/xastir/maps/ /usa/ /usa/CO/ /usa/NJ/ /dos/CO/ /dos/NJ/ /pixmaps/CO/ /pixmaps/NJ/ Pixmaps realmente son una combinacin de dos archivos, un archivo de dato con un, pixmap (.xpm), grfico y un archivo de locacin (.geo). El archivo .xpm es una estructura de grfico normal, con una imagen de cualquier tipo. Usted puedes usar XView para convertir gif, jpg, y tif imgenes en este formato. El archivo geo es un archivo de dato que atar la imagen a una locacin en el mundo. Aqu est un ejemplo de mi archivo world1.geo ARCHIVO world1.xpm # x y lon lat TIEPOINT 0 0 -180 90 TIEPOINT 640 320 180 -90 Este es un archivo simple, con 4 componentes bsicos. La primera lnea especifica este archivo data .geo es usado, este archivo debe estar en el mismo directorio como el archivo de .geo. La segunda lnea muestra un comentario; cualquier lnea con el carcter como un "#" ser ignorado. Las ltimas dos lneas son para conectar un pixel en la posicin x,y en la imagen a una posicin lat y long en la mundo. Dos puntos unidos son necesitado y debe estar cerca de la esquina izquierda superior y la esquina derecha ms abajo de la imagen. Usar archivo pixmap con xastir, use el selector de mapa y seleccione el archivo .geo para incluir la imagen en la vista del mapa actual. Por razones de velocidad, otras lneas de opciones pueden ser anexada en el archivo .geo. Aqu algunos ejemplos del formato modificado: ARCHIVO Agnes_Mountain.xpm.gz # # X Y Lon Lat # ---- ---- ------------- ----------- TIEPOINT 0 0 -121.00120491 48.37481943 TIEPOINT 1337 1999 -120.87619806 48.24982052 # #EDGES BOTTOM TOP LEFT RIGHT EDGES 48.24982052 48.37481943 -121.00120491 -120.87619806 La lnea EDGES especifica el min/max bordes del mapa. El mencionado mapa arriba es inclinado ligeramente, el cual es el porqu los nmeros no corresponden a la esquina 'tiepoints' exactamente. Xastir usar esa informacin saltar el mapa si no encaja en la vista actual. Mapas geoTIFF son una combinacin de dos archivos tambin: un archivo .tif y un .fgd. El archivo .tif es el actual data mapa. El archivo .fgd necesita solamente tener cuatro lneas como estas: 1.5.1.1 WEST BOUNDING COORDINATE: -122.000000 1.5.1.2 EAST BOUNDING COORDINATE: -120.000000 1.5.1.3 NORTH BOUNDING COORDINATE: 48.000000 1.5.1.4 SOUTH BOUNDING COORDINATE: 47.000000 Xastir usa esas cuatro lneas en su calculaciones para determinar los puntos de la esquina del mapa, y si o no el mapa vuelve al actual punto de vista (asi que el puede decidir si saltarlo). Si su data mapa es un mapa topo USGS, el archivo .fgd podra ser ledamente disponible a usted. Una forma anexada en Xastir es la abilidad hacer traslaciones datum desde NAD 1927 a WGS 84 datum, el cual hace el mapa topo USGS mucho ms posicionalmente exacto sobre la pantalla en Xastir. Mapas Condado WX Todos los mapas Condado WX deben guardarse en el directorio de /usr/local/share/xastir/Counties. Hay formatos diferentes para los mapas, pero de cualquier modo este directorio tendr directorios (usted podras necesitar crearlos) bajo este para cada estado (2 abreviaciones de letras). /usr/local/share/xastir/Counties /CO/ /CO/COPARK.map /CO/CODOUGLA.map /CO/COJEFFER.map /CO/COZ001.map /CO/COZ002.map /CO/COZ003.map /NJ/ /NJ/NJOCEAN.map /NJ/NJBERGEN.map /NJ/NJMONMOU.map /NJ/NJZ001.map /NJ/NJZ002.map /NJ/NJZ003.map Aqui estan dos lugares en el Internet donde usted puedes obtener esos mapas: ftp://aprs.rutgers.edu/pub/hamradio/APRS/NWSCounties/ http://home.att.net/~kg5qd1/Maps.html Como los mensajes NWS son recibidos, diferentes areas obtendrn un tintado hacia las reas designadas. Ellas son coloreadas para especificar diferentes tipos de alertas. Los colores originales fueron: Cian para el asesor, amarillo para alerta del tiempo, rojo para advertencia, naranja para alerta cancelada, azul real para pruebas, y verde para niveles de indeterminadas alarmas. Con la ltima versin de Xastir los colores pueden ser diferentes debido a un cambio mayor: Las reas que ahora son tintadas en lugar de relleno de color, y la dependencia en el tintado debajo los colores. Este cambio fue hecho asi que los mapas estando debajo de esto pueden mantenerse visible debajo en las reas de alertas del tiempo. Las alertas del tiempo podran ser fijada en on/off va el men del mapa tambin. HELP-INDEX>Configurar Interfaces Configurar Interfaces Pulse el botn en Configurar luego en Interfaces Un dilogo de "Interfaces Instalados" debe aparecer. Este dilogo le permitirs a usted Agregar, Anular, y modificar las Propiedades en varios dispositivos que usted puedes querer usar con Xastir. Las opciones actuales son: TNC va el Puerto Serial TNC va un Puerto Serial con (GPS ms cable HSP) GPS va un Puerto Serial Estacin Meteorolgica va Puerto Serial Conexin a un Servidor en Internet TNC va la Uilidades del AX.25 GPS Enlazado va el Servidor gpsd Estacin Meteorolgica Enlazada a una RED TNC va un Puerto Serial con (GPS ms AUX puerto) Para agregar un dispositivo, pulse el botn de agregar. Un dilogo "Elegir Tipo de Interfaz" aparecer. Pulse el botn en el tipo de dispositivo que le gustara agregar. Luego pulse el botn de Agregar en el dilogo "Elegir Tipo de Interfaz". Las propiedades para ese dispositivo aparecer. Rellene la informacin pedida y pulse el botn en Aceptar, anular el dispositivo, pulse el botn en el dispositivo usted deseas anular y entonces pulse el botn Anular. Para modificar las propiedades de un dispositivo, pulse el botn en el dispositivo usted deseas modificar, luego pulse sobre el botn de propiedades. Las propiedades para ese dispositivo aparecer. Cambie la informacin que usted quieres y pulsar el botn en Aceptar. HELP-INDEX>Configurando el Serial sobre un TNC Configurando el Serial sobre un TNC SERIAL TNC CONFIGURACION Pulse el botn "Configurar" luego en "Interfaces" despus en "Agregar" despus en "Serial TNC" luego "Agregar" y por ltimo en "Puerto TNC" Si usted tienes un TNC y planea usarlo con XASTIR seleccione "Puerto TNC". El valor por defecto no, es seleccionado. Ahora entre en el puerto que el TNC est, es decir /dev/ttyS0 para com1 Seleccione los valores del puerto que se acoplan a su TNCs velocidad del puerto. Entre en tres rutas de UNPROTO. Xastir asumir los XX VIA la parte de la ruta de UNPROTO. Hay tres Rutas permitidas para que su seal sea escuchada si las condiciones son mala. Si cualquiera de stos es llenado en XASTIR ciclar a travs de uno de ellos a cada intervalo de transmision. Si usted ests local, slo un WIDE2-2 puede ser una buena opcin. Si usted ests usando baja potencia y/o ests distante de un digi entonces WIDE1-1,WIDE2-2 puede trabajar mejor. O si usted conoces el indicativo de su digi ms cercano que usted puedes usar XXXCALL,WIDE2-2. La mayora de ustedes necesitarn slo una ruta. Si usted ests en una rea remota y su seal es difcil de conseguirla usted puedes necesitar ms. Verifique con un grupo local y pregntele que ruta puede ser mejor para su rea. Algunas areas usan el flujo de protocolos ms eficientes, en tales caso usted podra usar WIDE3-3 o WIDE1-1,WIDE3-3. Los archivos de Inicio y Salida del TNC. Estos campos especifican a nombre de archivo qie es localizado en el directorio /usr/local/share/xastir/config. Cada archivo es un archivo de texto estandar conteniendo algunos comandos que usted le gustaria enviarle a su TNC a la vez que el dispositivo es activado (Archivo de Inicio - Startup file) o de deshabilitar (shut down). Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardar la configuracion actual. HELP-INDEX>Opciones del TNC Opciones del TNC Permitir Transmisin (on/off) Esto controla la transmisin de datos a travs del TNC. Usted puedes querer Simplemente escuchar en RF o si usted no es un HAM y no debes transmitir. Con Esta opcin (el cual est apagado por defecto) usted puedes controlar transmisin de cualquier datos va RF. Bitcora (log) del TNC (on/off) Si est en 'ON', un archivo de log (Bitcora) se crear en el directorio logs. El archivo se llamar tnc.log y se aadir con toda la informacin oda va RF. Transmitir Ahora! Este transmitir su position/info de su estacion cuando usted pulses el botn en esta seleccin. No transmitir si la opcin "Serial TNC" no est seleccionada (en la seccin Configurar/Interfaces/Agregar/Serial TNC/Adregar/Puerto TNC) o si la opcin arriba mencionada permitir transmisin est fijada en off. HELP-INDEX>Configurar TNC via Serial c/GPS en HSP cable o AUX puerto Configurar TNC via Serial c/GPS en HSP cable o AUX puerto Esos tipos de interfaces hbridos implementan las opciones de ambos serial TNCs y GPSs. Por favor consulte la configuracin de ayuda para ambos serial TNCs y serial GPSs para ms detalles de informacin sobre la configuracin de esos dispositivos. HELP-INDEX>Configurando el AX.25 TNC Configurando el AX.25 TNC AX.25 TNC CONFIGURACION Esta seccin cubre agregando o modificando AX.25 TNC dispositivos. AX.25 dispositivos pueden sea cualquier dispositivo que use controladores AX.25 en Linux. ste es un controlador de nivel del ncleo (kernel), y el dispositivo como un Baycom o una tarjeta de sonido como mdem puede usarse como un TNC. Estos dispositivos deben ser configurado y correrlo antes de que Xastir pueda usarlos. Seleccionando Activar en Inicio, le dir a Xastir que busque este dispositivo y fije las comunicaciones con l cuando el programa de su primer inicio. Seleccionando Permite Transmitir, le dir a Xastir que cualquier salida de datos de RF puede ser enviado a este dispositivo para la transmisin. Escoja la operacin correcta de IGate para este dispositivo. Usted puedes tener varios dispositivos TNC, y esta opcin puede ser diferente por cada dispositivo. Si usted no ests ejecutando un IGate usted puedes dejar sta opcin predefinida de "Desactivar todo el trfico". Entre el nombre del Dispositivo AX.25 que usted especific en el archivo del axports para este dispositivo. Entre en tres rutas de UNPROTO. Xastir asumir el XX VIA parte de la ruta del UNPROTO. Hay tres rutas permitidas para que su seal sea escuchada si las condiciones son mala. Si cualquiera de sas son llenada en XASTIR ciclar a travs de uno de ellos en cada momento de la transmisin. Si usted es local, slo un WIDE2-2 puede ser una buena opcin. Si usted ests usando baja potencia y/o ests distante de un digi entonces WIDE1-1,WIDE2-2 pueden trabajar mejor. O si usted sabes el indicativo de su digi ms cercano a usted puedes usar XXXCALL,WIDE2-2. La mayora de ustedes necesitarn slo una ruta. Si usted ests en una rea remota y su seal es difcil de conseguir usted puedes necesitar ms. Verifique con un grupo local y pregntele qu ruta puede ser mejor para su rea. Algunas areas usan el flujo de protocolos ms eficientes, en tales caso usted podra usar WIDE3-3 o WIDE1-1,WIDE3-3. NOTA: Para usar dispositivos AX.25 con Xastir usted necesitars ejecutar el programa como "raz" ("root"). Si usted quieres ejecutar Xastir como otro usuario usted necesitars fijar el suid en ON en el archivo de programa de xastir. El orden siguiente como raz debe fijar esto para usted. chmod a+s /usr/local/bin/xastir. como con cualquier programa que este corriendo de esta forma, por favor note que esto puede ser considerado como una seguridad de riesgo, como el programa no ha sido probado para explotar. Uselo en este modo en un multi-usuarios en su propio riesgo! HELP-INDEX>Cmo uso yo mi GPS con Xastir? Usando UN GPS con Xastir Para usar una unidad de GPS con Xastir usted tienes tres opciones, un GPS Conectado a una red o a un serial GPS, o a un serial GPS con un TNC y cable HSP. GPS conectado a una red: La ventaja de usar un GPS conectado a una red es que usted puedes compartir el GPS con otros programas. Xastir usa un programa llamado gpsd para hacer una connexin a una red. Este programa entrega datos de GPS normales en un scalo de conexin de redes. Algunas versiones tambin permiten correccin de GPS va un servidor de Internet. Una vez que usted tengas bajado e Instalado el gpsd en su mquina (u otra mquina), usted puedes fijar el Xastir para conectar a l creando una interfaz. Pulse el botn en "Configurar" y despus en "Interfaces". Cuando el dilogo de Interfaces aparezca Pulse el botn de "Agregar". Un nuevo dilogo aparecer con los tipos de Interfaces, Elegir en "Enlazado GPS (via el gpsd)", y luego pulse el botn en Agregar. Hay 4 opciones a elegir. Primero entre el nombre del servidor del programa gpsd que est ejecutando. Si est en el mismo computador que Xastir entonces entre localhost. Luego entre en el puerto que usted puso el programa gpsd para escuchar. Si usted seleccionas "Activar en Inicio", Xastir tratar de conectar al programa gpsd tan pronto se inicia y tan pronto usted hagas click en el botn "Aceptar". La ltima opcin, si seleccionado, intentar hacer la reconexin al gpsd si un fallo fu encontrado. Serial GPS: Un serial GPS es cualquier unidad de GPS normal que conecte al puerto serial y transmita datos en el NMEA normal. Permitir a Xastir a usar este tipo de GPS pulse el botn de "Configurar" luego en "Interfaces". Cuando el dilogo de Interfaces aparezca pulse el botn de "Agregar". Un dilogo con los tipos de Interfaces aparecer, Pulse sobre el "Serial GPS" y despus en el botn Agregar. Unas pocas opciones para fijar. Primero entre el puerto serial en donde el dispositivo est conectado (como "/dev/ttyS1 (COM2)"). Prximo si usted seleccionas "Activar en Inicio", Xastir intentar inicializar el "serial GPS" cuando l se inicie y cuando usted pulses el botn "Aceptar". Las prximas opciones pondrn la velocidad del puerto serial y modo. Para la mayora de las unidades de GPS los valores predefinidos estn bien. Pero Chequee usted el manual del GPS slo en caso de dudas. HSP TNC/GPS: Mire en "Cmo uso yo mi TNC con Xastir?" HELP-INDEX>Configurando el Puerto/GPS Configurando el Puerto/GPS Pulse el botn en "Configurar" luego en "Interfaces" luego en "Agregar" elija "Serial GPS" luego "Agregar" despus ajuste los parmetros del Puerto/GPS. Para usar una posicin "Serial GPS" en el puerto serial, pulse el botn en Posicin Serial GPS. Este puerto puede especificarse en la Posicin "Slo el puerto de GPS". Usted puedes usar un dispositivo serial como /dev/ttyS1 (COM2). Si usted tienes un cable de HSP que le permitas compartir el Serial TNC con una unidad GPS usted puedes seleccionar "Serial TNC c/GPS ms (Cable HSP). ste es un cable especial y el mo no trabaja en todas las combinaciones de computadores/GPS/TNC. Ahora usted puedes escoger un GPS muestreo y TNC relacin, Recuerde usarlo con precaucin aqui, que sean amigables por sus estaciones cercanas. Activar el uso de los datos de GPS seleccione el "Uso Posicin GPS?" opcin. Con esta seleccin hecha la unidad de GPS pondr al da su posicin. Si esto no se selecciona la posicin actual vendr desde la locacin en configuracin informacin de la Estacin. Cuando active los datos de GPS tambin pondrs al da la posicin en configuracin de informacin de la Estacin. Cuando use el GPS sus paquetes cambian, usted obtendrs una estacin mvil con curso y velocidad an cuando la suya no est moviendose (yo puedo cambiar esto despus a una opcin). El tiempo del GPS le permitir seleccionar proporciones de la relacin de muestra para el GPS y sobre pasar el tiempo del paquete normal por transmitir su estacin. Si usted ests estacionado entonces use 10 minutos. Si usted ests haciendo algn especial/rastreo etc.. use la seleccin que encajarn mejor los datos que usted necesitas. Por favor no haga sobre transmisin, si usted no lo necesitas hacer. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardars las configuraciones actuales. HELP-INDEX>Cmo uso yo mi TNC con Xastir? Usando UN TNC con Xastir Para usar un TNC con Xastir usted tienes tres opciones, un "serial TNC" o un "Serial TNC c/GPS ms (cable HSP)" o un TNC Conectado a una red "AX.25 TNC". AX.25 o un TNC en una red: Este tipo de tnc le permitir compartir el TNC con otros programas. Al usarlo usted debes tener la librera AX.25 , y el HamRadio soporte instalado en el ncleo (kernel) de su Linux OS. Ellos son un poco ms difciles de configurar para usarlo pero hay muy buenas opciones y ventajas en su uso. Usando el soporte del "AX.25 TNC", usted tienes varios dispositivos que usted puedes usar con Xastir. Algunos de ellos son serial TNC que usan AX.25, tarjetas de sonidos como TNC's, Baycom, etc. SERIAL TNC: SERIAL TNC con (GPS ms cable HSP): HELP-INDEX>Configurando la conexin de Internet Configurando la conexin de Internet La conexion a los Servicios de Internet le permite a usted enviar y recibir datos desde y hacia todo el mundo. Para configurar el Internet usted necesitars conocer un host y un nmero de puerto. El host predefinido es www.aprs.net y el puerto es 10151. Usted puedes escoger otros pero este debe trabajar. Una Palabra de paso vlida le permitir a su estacin transmitir por el Internet. Permitir a su estacin salir de una I-Gate y conseguir retransmitir va RF. Para conseguir un cdigo de paso usted necesitars contactar con Frank, email fgiannan@earthlink.net, Enviarle su nombre, Indicativo, etc. Una vez l verifique su estado como un HAM l puede enviarle su cdigo. Usted puedes mantenerse recibiendo y transmitiendo datos va el Internet aunque usted no tengas un passcode. Pero sin el cdigo de paso sus datos no sern directamente retransmitido va RF. Cualquiera que est conectado al Internet directamente conseguir su mensaje. Host1 y Host2 son servidores opcionales que sern contactado si el servidor primario est fuera. Cada servidor ser intentado dos veces, siguiendo al prximo si la conexin fracasa. Si usted quieres que XASTIR reconecte despus de una conexin perdida en el net entonces seleccione la opcin "Reconecte en fracaso de la RED?" en la que por defecto est en ON. Las ltimas opciones son para preparar su estacin para ser un IGate. Esto permite a su estacin con su cdigo de paso simplemente actuar como una puerta (gateway), pero en lugar de otra banda sus datos atravesarn el Internet. Esta opcin no debe ser tomada ligeramente. Primero usted debes coordinar con otros en su rea para que usted puedas agregar verdadera informacin que puede estar perdiendo. Usted tambin debes avisar a Steve sobre esto. Esta versin puede enviar informacin recibida desde su TNC hacia el Internet y transmitir cualquier mensaje procedente de Internet a travs de su estacin via RF. Enviar slo datos va RF si usted tienes el opcin seleccionada de transmisin de mensajes. Slo estaciones que usted has odo (va RF) en las ltimas horas tendrn mensajes enviados a ellos en sta va. Note tambin usted es responsable por los datos transmitidos por su estacin asi que tenga cuidado con esta opcin (otros pueden enviarle mensajes que usted no quieres transmitir). Si usted quieres ver que su I-Gate esta haciendo encienda la opcin Log I-Gate de transacciones. esto construir un archivo de igate.log en su "logs" los directorios mostrarn todos los datos pasados de RF local hacia la red con lnea que tiene "IGATE-RF->NET": y conteniendo todo los datos. Tambin mostrar todo el trfico entrante desde la red con "NET->RF-IGATE:". Note aqu usted no vers la completa salida de paquetes, como su estacin y ruta son asumida. Solamente mostrar el data como un mensaje de tercera persona. Pulsando el botn "Aceptar" guardars sus cambios. Pulsando el botn en "Cancelar" guardars los cambios actuales. APRS[tm] es una Marca de fbrica de Bob Bruninga, su pgina est en "http://web.usna.navy.mil/~bruninga/aprs.html" HELP-INDEX>Opciones de RED Opciones de RED Permitir Transmisin (on/off) Esto controla la transmisin de datos a travs del Internet. El valor por defecto es apagado. Con esto en (off) apagado ningn dato ser enviado al Internet. Bitcora de Internet (on/off) Si esto est en 'ON', un archivo log se crear en el directorio logs. El archivo se llamar net.log y se aadir con toda la informacin oda va el Internet. Transmitir Ahora! Esto transmitir su position/info de la estacin cuando usted pulses el botn en esta seleccin. No transmitir si la opcin est apagada en Permitir transmisin. HELP-INDEX>Configurando una Estacin Meteorolgica sobre un Puerto Serial. Configurando una Estacin Meteorolgica sobre un Puerto Serial. Configurar el puerto serial para su estacin Meteorolgica. A los valores comunes de /dev/ttyS0 (COM1) o /dev/ttyS1 (COM2) pueden ser usado. Seleccionado "Activar en Inicio" le dirs a Xastir buscar este dispositivo y fijar comunicanciones con el cuando el programa se inicie primero. Ahora fije el bps bajo el puerto de configuracin, y los parmetros bajo el puerto estilo. El seteo del puerto estilo 8N1, es usado para 8 bitios de datos, No paridad y 1 bitio de parada (stop bit). 7E1 es usado para 7 bitios de datos, even paridad y 1 bitio de parada. 7O1 es usado para 7 bitios de datos, odd paridad y 1 bitio de parada. Esos parmetros deben de machar con su estacin Meteorolgica. El tipo de opcin de data le perimitir sobrepasar que tipo de serial data el progrma ver. La forma de auto-deteccin primero buscar datos del tiempo en un modo binario como lo usa el Radio Shack WX-200. Si no dato binario es encontrado, Xastir buscar un tipo ASCII de estacin Meteorolgica (como la Peet Bros.) HELP-INDEX>Configurando una Estacin Meteorlgica en la RED Configurando una Estacin Meteorlgica en la RED Xastir puede usar servicios de dato de una estacin Meteorolgica tales como la wx200d. La wx200d le permitirs varias conexiones de redes, asi compartiendo el informe del tiempo con varios programas o computadores. Entre el nombre del host (o la direccin numrica IP) y el nmero del puerto de la estacin Meteorolgica servidora que usted quieres contactar. Seleccionado "Activar en Inicio" le dirs a Xastir buscar este dispositivo y fijar comunicanciones con el cuando el programa se inicie primero. Seleccionado "Reconectar en fallo de la RED" le dir a Xastir tratar de reconectar cuando el data conexin haya fracasado. Como antes el tipo de data sobrepasar el auto-deteccin. HELP-INDEX>Dilogo info estacin - bsqueda FCC y RAC Dilogo info estacin - bsqueda FCC y RAC Info estacin desplegar cualquier dato descifrado por Xastir. Actualmente dos o tres botones aparecen aqu adems del botn Cerrar. Los botones de Anular Rastro anularn cualquier lnea de rastro para esa estacin que es actualmente guardada o en el despliegue de mapa. Enve mensaje abrir la ventana de mensaje y le permitir enviar a mensje a esta estacin. El llenar en el indicativo por usted. Si el banco de datos de FCC se instala, un botn de Bsqueda en el Banco de datos FCC aparecer en este Dilogo. Si el RAC (RadioAficionados de Canad) banco de datos se instala, un botn de bsqueda RAC Banco de datos aparecer para indicativo que empiezan con una "V". El archivo FCC y RAC deben colocarse en el directorio /usr/local/share/xastir/fcc, y el caso es importante! Usted puedes usar este botn para agregar los nombres de estaciones y dirjase al Dilogo de Estacin Info. Para usar la bsqueda de FCC bajelo de aqui: ftp://ftp.fcc.gov/pub/XFS_AlphaTest/amateur/appl.zip o el Nuevo banco de datos en: ftp://ftp.fcc.gov/pub/Bureaus/Wireless/Databases/uls/complete/l_amat.zip (El nico archivo necesitado forma este 40Meg zip es el archivo EN.dat) * * * * NOTA para usar el NUEVO archivo base de datos debe ordenarse primero!!! * * * * Asegrese que usted tienes espacio en el disco suficiente para esto como el archivo es GRANDE! Para ordenar el archivo: sort +4 -t \ | EN.dat >EN.dat.ordenado rm EN.dat mv EN.dat.ordenado EN.dat Para usar la bsqueda de RAC bjelo de: ftp://ftp.rac.ca/pub/cdncaldb.zip Xastir crear archivos ndice por cada archivo del banco de datos en el inicio. Si un archivo de indicativo es eliminado mientras Xastir est corriendo, crear o reconstruir el ndice en la prxima bsqueda. No se manejan prefijos especiales. HELP-INDEX>Opciones de Despliegue Opciones de Despliegue Estas opciones le permitirn desplegar datos sobre la estacin alrededor del cono de las estaciones en el mapa. Indicativo (on/off) Cuando est en 'ON', todo los indicativos de las estaciones se desplegarn. Si este esta en 'OFF' los indicativos no se desplegarn sobre el mapa. Para viejas estaciones el smbolo es dibujado como fantasma y en su orientacin estandar. Corespondiendo al arrastre que son subrayado ms que slido y todo el data excepto el indicativo desaparece de la pantalla. Callsign (on/off) Determines if the callsign is displayed on the right side of the symbol. Altura (on/off) Cuando est en 'ON', una lnea azul de datos aparecer sobre el indicativo. Este desplegar la ltima altitud conocida de la estacin. Curso (on/off) Cuando est en 'ON', una lnea verde de dato aparecer debajo del indicativo. Esto desplegar el ltimo curso conocido (en grados) de la estacin que est en movimiento. Velocidad (on/off) Cuando est en 'ON', una lnea roja aparecer debajo del indicativo (o curso). Esto despliegar la ltima velocidad conocida de la estacin que est en movimiento. Dist/curso (on/off) Cuando est en 'ON', se desplegarn dos lneas de informacin en el lado izquierdo del cono de la estacin. La lnea de arriba tendr la distancia de su estacin hacia esta estacin. La lnea de abajo tendr el curso desde su estacin hacia esta estacin. Rastros de estaciones (on/off) Cuando est en 'ON', cualquier estacin en movimiento arrastrar una lnea coloreada con las ltimas 100+ localizaciones. Cuando la estacin se pone vieja el cono es opaco la lnea de rastro se volver intermitente en lugar de la lnea contnua. Estacin Potencia/Ganancia (on/off) Cuando est en 'ON', se desplegarn Crculos de Poder/Ganancia. Sobrepasando los crculos indicado que las estaciones estn tericamente con simple rango uno del otro. Esto es aproximandaemnte exacto, especialmente in reas de terreno variable. Rastreo Estacin Traer una caja abierta similar a la opcin localizar estacin. Usted puedes entrar todos o parte del indicativo. Al seleccionar "Rastrear Ahora!" El despliegue saltar a la posicin de la estacin (si es encuentrada). Cuando nuevos datos para esa estacin son encuentrados el despliegar el rastro a lo largo de esa estacin. El botn "Borrar Rastro" limpiar todo el rastro. El botn de "Cancelar" terminar sin cambios realizados. Informe del Tiempo (on/off) Cuando est en 'ON', los ltimos datos del tiempo (velocidad/curso/rfaga,Humedad,temperatura,viento) son desplegados. Smbolos (on/off) Determina si los smbolos podran ser dibujado en el mapa. Rotar Smbolos (on/off) Si 'ON', algunos smbolos deberan cambiar su orientacin y mostrar la direccin en la cual una estacin mvil se est moviendo. HELP-INDEX>Mensajes Mensajes Enviar mensaje a y Mensajes De grupo abierto stos son muy similares. El "Enviar mensaje a" enviar sus mensajes a una estacin y recibir slo forma de datos de la estacin. Los mensajes de grupo son ms en general usted puedes recibir cualquier mensaje para el grupo y usted enviars sus mensajes a ese nombre de grupo. Los mensajes de grupo no pueden trabajar mejor por el momento hay varios problemas que necesitan ser solucionado. Sin embargo, volviendo atrs al uso de estas pantallas. Cada una de estas pantallas contienen una caja de mensaje, una lnea de llamada, una lnea de mensaje, y varios botones. Usted debes primero entrar la llamada del grupo o estacin que usted quieres avisar. Una vez que eso se hace cualquier nuevo mensaje que ha entrado de esa estacin hacia usted sers desplegado. Si la estacin est envindole informacin y ninguna ventana de mensaje est abierta l abrir automticamente a una nueva ventana (hasta 10) con esos indicativos de estaciones para usted. Usted puedes ahora entrar un mensaje en la lnea de mensaje. El mensaje puede ser ms largo que la lnea de mensaje, y la mxima salida es aproximadamente 250+ carcteres. Una vez su mensaje es entrado, pulsando el botn "Enviar Ahora!" mandar su mensaje. El botn "Enviar Ahora!" se pondr opaco hasta que su mensaje sea completamente Reconocido. Cualquier mensaje que usted recibas ser ordenado por la lnea # y ser puesto en la ventana de mensaje. Si usted ests en un modo de grupo cada lnea desplegar el indicativo de donde el mensaje se envi seguido por el propio mensaje. Los mensajes de grupos actuales son ordenados por llamada y despus la lnea #. Cuando usted hayas enviado el mensaje pulsando el botn de "Cerrar" cerrar la ventana. Dos otros botones son tambin disponible. El botn "Nuevo Indicativo" le permitir mirar datos viejos que una estacin ha enviado. Teclee el indicativo y pulse en este botn, cualquier informacin vieja ser desplegada. Usted tambin puedes usar este botn para cambiar el indicativo de la estacin con la que usted ests hablando. Entre el nuevo indicativo y pulse el botn. El botn de "Borrar Mensajes" limpiar cualquier mensaje desplegado en la ventana de mensajes. Borrar todos los mensajes salientes Esto limpiar todo los mensajes no-conocidos que usted has enviado. Auto Contestacin de Msj Esto encender una contestacin automtica cuando un mensaje entrante se recibe. Fijar Mensaje en contestacin Automtica Esto fijar un mensaje que se enviar en ausencia automticamente. HELP-INDEX>Limpiando el despliegue de lnea de rastros Limpiando el despliegue de lnea de rastros Pulse el botn en "Archivo" y despus "Borrar Todo rastro". Esto limpiar todo el dato de la lnea de rastreo del banco de datos de la estacin y actualiza la pantalla. HELP-INDEX>Limpiando el despliegue de estaciones Limpiando el despliegue de estaciones Pulse el botn en "Archivo" y luego el botn "Borrar Toda las Estaciones". Esto limpiar todo los datos del banco de datos de las estaciones excepto la suya. HELP-INDEX>Reenviando un log (Bitcora) Reenviando una Bitcora Pulse el botn en "Archivo" y despus en "Abrir Bitcora" una ventana de seleccin de archivo se desplegar. Usted puedes usarlo hojear su unidad de disco duro y seleccionar cualquier archivo que contenga un TNC datos raw como aqullos creados por el TNC y opciones de red. Su estacin todava funcionar de la misma manera, recibiendo y transmitiendo. Y debe haber una palabra de advertencia aqu, si su dato contiene una sessin de mensaje y usted tienes su estacin lista para transmitir, responder al archivo como si el dato fu recibido sobre el TNC o Internet. HELP-INDEX>Localizando una Estacin Localizando una Estacin Pulse el botn sobre "Visualizador" luego en, "Localizar Estacin" o sobre el botn de "Desplegar" luego en "Estacin Rastreo" una ventana se abrir. Usted puedes ahora entrar una estacin o parte de una estacin. Por defecto buscar un macheo exacto (llamada completa, no parcial) y no es caso sensible. Si usted ests buscando un macheo parcial, "Macheo Exacto" podra no ser seleccionado. Realmente usted puedes usar esto para localizar una estacin o un objeto. Qu es donde nosotros venimos a la opcin "Macheo Sensible". Yo he notado que algunos objetos estn en caso mixto o minscula. Con "Macheo Sensible" seleccionado, el localizador buscar mayscula y minscula cuando usted la entr. Si "Macheo Sensible" no se selecciona, el localizador asumir cualquier caso que usted teclees es mayscula y investigar en eso. Pulsando el botn "Localizar Ahora!" centrar la primera estacin encontrada en el centro de su pantalla al nivel del enfoque actual. Pulsando el botn "Cancelar" cerrar la ventana. HELP-INDEX>Creando y usando Salto a Localizaciones Creando y usando Salto a Localizaciones Pulse el botn "Visualizador", luego en "Saltar a la posicin" una ventana aparecer. Si sta es la primera vez usted has usado este dilogo no tendrs ninguna entrada en l. Agregar una posicin en la lista de posicin vaya al rea del mapa principal y enfoque el nivel que usted quieres usar. Entre un nico nombre en el rea "Nombre de Nueva localizacin", luego pulse el botn agregar. Su entrada se agregar a la lista (en orden alfabtico). Usted puedes agregar tantas locacin de mapas que usted quieras de esta manera. Para usar uno de la posicin pulsar el botn en el nombre de la posicin y pulsar el botn "IR!", el mapa principal entonces mostrar esa posicin. Usted puedes anular una posicin similarmente pulsando el botn sobre el nombre de la posicin y luego el botn "Anular". HELP-INDEX>Rastreando una Estacin Rastreando una Estacin Pulse sobre el botn de "Desplegar" luego en "Rastreo Estacin". Entre en el indicativo para rastrear (todos o parte) luego pulse el botn "Rastrear Ahora!". Como la estacin lo mueve ser centrado en la ventana del mapa principal. Dejar de rastrear esta estacin pulsar el botn "Anular Rastro". HELP-INDEX>Trfico de mensajes Trfico de todos los mensajes Pulse sobre la opcin de "Trfico de Mensajes" luego un dilogo se abrir e iniciar el Monitoreo de todas las estaciones alrededor del mundo, en chat o enviando mensaje de prueba etc. HELP-INDEX>Imprimiendo Imprimiendo la Pantalla del Mapa Xastir puede imprimir el rea de dibujo en cualquier blanco y negro o color. Hace esto primero descargando la imagen a un archivo XPixmap en disco, entonces usando una herramienta externa para convertirlo al posdata, balancearlo, rotarlo, prevista, entonces la impresin . Usted debe tener su sistema que configure la impresin para manejar posdata (normalmente esto requiere Ghostscript y un filtro de impresin instalados, as como lp o lpr imprime spoolers). Usted tambin debe tener las herramientas siguientes instaladas para esta capacidad: Herramientas de ImageMagick (especficamente "convertido"), "Ghostscript", Conjuntos de caracteres de Ghostscript, y "gv". Una vez todos esos paquetes son instalando y funcional, usted debe una "gv" ventana sobre salte brevemente despus que usted le diga a Xastir crear un archivo de impresin. De all usted puede ver la imagen impresa, y si aceptable, diga a "gv" imprimirlo. Note que algunas veces cambiando a un blanco el fondo predefinido para los mapas se recomienda, dependiendo de qu mapas usted tienen visualizable. Esto puede ahorrar le grandemente la tinta. HELP-INDEX>Creando Captura Instantnea Automticamente Creando Captura Instantnea Automticamente Xastir tiene la capacidad para crear captura instantnea automticamente en pantalla del mapa recurriendo al algo bsico. Este periodo de tiempo es actualmente fijado por cinco minutos. Asumiendo que usted tiene "convertir" de la herramienta de ImageMagick instalado, Xastir crear un archivo de formato XPM en /var/tmp, entonces lo converte, al archivo de PNG /var/tmp/xastir_snap.png. Este archivo es til para ponerlo en pginas web para mostrar una imagen viva de lo que est en su pantalla de Xastir. Habilite este rasgo va el "Archivo->Activar PNG Instantnea". HELP-INDEX>Tabla de Smbolo Eso son los smbolos que usted puedes selecionar para su estacin bajo la "Informacin de la Estacin" men de configuracin. La lista actual puede ser encontrada en el APRS Referencia en el cual usted puedes obtenerlo desde http://www.tapr.org/ Tabla de smbolo Smbolo Grupo/ Grupo/ ! Tringulo w/! Tringulo w/! " Lluvia Nube Lluvia Nube # Digi DIGI $ Smbolo telefnico $ Smbolo % DX DX & GATE-HF GATE ' Avin pequeo Avin Cado ( Nube nube ) TBD * NIEVE Hojuela NIEVE Hojuela + Cruz roja , Inverso L - w/omni casa . X pequea / Punto rojo 0 0 en una caja Crculo 1 1 en una caja 2 2 en una caja 3 3 en una caja 4 4 en una caja 5 5 en una caja 6 6 en una caja 7 7 en una caja 8 8 en una caja 9 9 en un GAS de la caja : Bombero ? ; Tienda tienda < motocicleta Bandern = Mquina de tren > Automvil automvil ? Antena POS ? en una caja @ HURRICAN/TORMENTA HURRICAN/TORMENTA A Primero auxilio Caja B BBS Blowing Nieve C Canoa D D en un crculo E E en un circulo Pila de Humo F F en un crculo G Reja Antena Cuadrada ? H Hotel/Cama I TCP/IP ? J J en un crculo descarga K Escuela L Casa Iluminada Casa Iluminada M Mac N NTS ? O Globo P Carro de Patrulla Rx Q Circle con Crculos Crculo con Crculos R RV Restaurante S Transbordador Satlite T Tormenta (cloud/bolt) Tormenta (cloud/bolt) U Autobs escolar Sol V VOR TAC VOR TAC Smbolo W Servicio del Tiempo Nacional NWS-Digi X Helicptero Y Velero Z Windows [ corredor WC \ DF Tringulo ] Packet Mail Box ^ Avin grande Avin Grande _ Estacin Meteorolgica WS-Digi ` Plato de satlite a Ambulancia b Bicicleta vuela nube c antena de DX d depto de bombero. Antena de DX e Caballo Aguanieve nube f Camin de bombero FC Nube g planeador Bandern (2) h Hospital HAM i Isla Isla j Jeep Jeep k Camin Camin l Punto pequeo Punto pequeo m MIC Milla Poste n N Tringulo Pequeo o EOC Punto en Crculos p Cachorro Punto en Crculos q GS Antena Antena de GS r Antena Torre Antena Torre s Bote Barco t TS ? u 18 Rueda de Camin v Carro de mudanzas Punto en Crculos w H20 Diluvio x X Windows Punto Rojo y Casa w/Yagi Casa w/yagi z X Windows { NIEBLA NIEBLA | Lnea Negra Lnea negra } TCP TCP ~ Velero Velero Xastir-Release-2.2.4/placeholder0000664000175000017500000000012515151324131015524 0ustar hibbyhibby This file was needed in order to the directory created. Delete this file at will. Xastir-Release-2.2.4/scripts/0000775000175000017500000000000015151324131015010 5ustar hibbyhibbyXastir-Release-2.2.4/scripts/.vimrc0000664000175000017500000000143315151324131016132 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/scripts/BUILDRPMS0000775000175000017500000001272515151324131016306 0ustar hibbyhibby#!/bin/sh # This is an example script used by one of the developers to ease # the workload. It's not intended to be used by the general # userbase. It's included with the Xastir sources so that it # doesn't get lost if the developer should suddenly drop out of # sight. # Run this as root from the xastir source directory (top-level). # It runs some # of the below commands as "archer", others as "root". # When the build is complete it copies the RPM files to the Wetnet server. # Run these commands as "root". # echo echo echo "***********************************" echo "***** Cleaning up Directories *****" echo "***********************************" rm -rf /usr/src/packages/SOURCES/xastir* rm -rf /usr/src/packages/RPMS/x86_64/xastir* rm -rf /usr/src/packages/SRPMS/xastir* # Run these commands as "archer". # echo "Davis..." su -c " cd Davis; ./bootstrap.sh; ./configure; make clean" archer echo "LaCrosse..." su -c " cd LaCrosse; ./bootstrap.sh; ./configure; make clean" archer # These are just to get the configure and spec files in shape. # Configure options don't matter yet here. echo echo echo "********************************************" echo "***** Setting up CONFIG and SPEC files *****" echo "********************************************" su -c " cd Davis; ./bootstrap.sh; ./configure; make clean" archer su -c " cd LaCrosse; ./bootstrap.sh; ./configure; make clean" archer # # NOTE: CPPFLAGS below is for OpenSUSE specifically: Remove it if building RPMs for other Linux OS'es. su -c " ./bootstrap.sh; ./configure CPPFLAGS='-I/usr/include/libgeotiff'; make clean; make dist" archer # Run these commands as "root": # cp xastir-*.tar.gz /usr/src/packages/SOURCES/. # Run these commands as "root": # # Build minimum system (only ImageMagick and internal Shapelib # included), binary package only. Rename this file so that the # following rpmbuild doesn't overwrite it. echo echo echo "*******************************************" echo "***** Creating MINIMUM binary package *****" echo "*******************************************" (cd /usr/src/packages/SOURCES; tar xzf xastir-*.tar.gz; rpmbuild -bb --clean xastir-2.0.8/xastir-min.spec) mv /usr/src/packages/RPMS/x86_64/xastir-2.0.8-1.x86_64.rpm /usr/src/packages/RPMS/x86_64/xastir-2.0.8-min.x86_64.rpm # # # Build maximum system (all optional libraries included), binary and # source packages. echo echo echo "***************************************************************" echo "***** Creating MAXIMUM binary package plus source package *****" echo "***************************************************************" (cd /usr/src/packages/SOURCES; tar xzf xastir-*.tar.gz; rpmbuild -ba --clean xastir-2.0.8/xastir.spec) mv /usr/src/packages/RPMS/x86_64/xastir-2.0.8-1.x86_64.rpm /usr/src/packages/RPMS/x86_64/xastir-2.0.8-max.x86_64.rpm # Run these commands as "root": # # Create a local yum repository in the correct format: mkdir /usr/tmp/repo /usr/tmp/repo/x86_64 /usr/tmp/repo/src cp /usr/src/packages/RPMS/x86_64/* /usr/tmp/repo/x86_64 cp /usr/src/packages/SRPMS/* /usr/tmp/repo/src # # Create repo (cd /usr/tmp/repo/x86_64; createrepo .) (cd /usr/tmp/repo/src; createrepo .) # # Create a .tgz of the repo (cd /usr/tmp/repo; tar czvf xastir-repo.tgz *) # Run these commands as "archer": # echo echo echo "**************************************************************" echo "***** Copying packages to Wetnet and setting permissions *****" echo "**************************************************************" #su -c " cd /usr/bin; scp /usr/src/packages/RPMS/x86_64/xastir-2.0.5-max.x86_64.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/." archer #su -c " cd /usr/bin; scp /usr/src/packages/RPMS/x86_64/xastir-2.0.5-min.x86_64.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/." archer #su -c " cd /usr/bin; scp /usr/src/packages/SRPMS/xastir-2.0.5-1.src.rpm we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/." archer #su -c " cd /usr/bin; ssh -l we7u wetnet.net 'chmod 644 /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/*.rpm'" archer #su -c " cd /usr/bin; ssh -l we7u wetnet.net 'chmod 644 /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/*.rpm'" archer # # Copy the tgz of the repo up to Wetnet: su -c " cd /usr/bin; scp /usr/tmp/repo/xastir-repo.tgz we7u@wetnet.net:/home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/." archer # # Remove the repodata files so we don't get multiples: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'rm -rf /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/x86_64/repodata /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/SuSE-12.1/src/repodata'" archer # # Untar the repo. Will merge the files in with our other repo files: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'cd /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM; tar xzvf xastir-repo.tgz'" archer # # Remove tgz file: su -c " cd /usr/bin; ssh -l we7u wetnet.net 'rm /home/we7u/public_html/Downloads/aprs/xastir/SUSE-RPM/xastir-repo.tgz'" archer echo echo echo "***********************************" echo "***** Cleaning up build files *****" echo "***********************************" rm -rf /usr/src/packages/SOURCES/xastir* #rm -rf /usr/src/packages/RPMS/x86_64/xastir* #rm -rf /usr/src/packages/SRPMS/xastir* #rm -rf /usr/tmp/repo # NOTE: Will have to set priority of the new repository to 100 (default is 99) in order to override the OpenSuSE-distributed version of Xastir tends to be older. Xastir-Release-2.2.4/scripts/Coordinate.pm0000664000175000017500000020737215151324131017450 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # Coordinate.pm: Perl module for: # # 1) Creating and manipulating Coordinate objects, # 2) Translating coordinates between UTM and Latitude/Longitude, # 3) Translating coordinates between ~231 different datums, # 4) Formatting coordinates into decimal degrees, degrees/minutes, # and degrees/minutes/seconds. # # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # Reference ellipsoids derived from Peter H. Dana's website- # New: http://www.Colorado.EDU/geography/gcraft/notes/datum/elist.html # # Old: http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html # Department of Geography, University of Texas at Austin # Internet: pdana@mail.utexas.edu # 3/22/95 # # # Reference datums derived from Peter H. Dana's website- # http://www.Colorado.EDU/geography/gcraft/notes/datum/datum.html#GeoDat # # # UTM<->LAT/LON translations were originally written in C++ by # Chuck Gantz- chuck.gantz@globalstar.com. Permission received # by Chuck Gantz via e-mail to release it under the GPL license. # Re-coded into Perl by Curt Mills. # # Datum translations were originally written in C by # John F. Waers - jfwaers@csn.net. His code was released to # the public domain. Re-coded into Perl by Curt Mills. # # # TODO: # ----- # Please note that I didn't pay a lot of attention to # keeping the "double" notation in the form of higher # precision floating point routines. This means that # the Perl5 code won't be as accurate as the original # C-code. It doesn't matter for my purposes. If # anyone converts to Math::BigFloat for higher precision, # please send me the changes. As it is I did a # quick check and found a difference of only 1.4 meters # between my Perl results and the results from a web-based # datum-shift calculator on the 'net. -- Curt. # # Should probably add return values for each method. Check # for error conditions and return 0 if problem. # # Add method to tell distance in meters of datum shift (verbose flag?) # # Get rid of print statements unless verbose or debug mode. # # POD documentation. # #------------------------------------------------------------------------------------------------ package CoordinateFormat; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # Conversions between decimal degrees, degrees/decimal minutes, and # degrees/minutes/seconds. These are methods which all work on # "CoordinateFormat" objects. # # These routines probably need a bit of work yet. It'd be nice # to be able to specify field widths. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{RAW} = shift if @_; # Input string $self->{FORMATTED} = shift if @_; # Output string, formatted } sub raw # Set'er/Get'er for input string { my $self = shift; $self->{RAW} = shift if @_; return $self->{RAW}; } sub formatted # Set'er/Get'er for formatted string { my $self = shift; $self->{FORMATTED} = shift if @_; return $self->{FORMATTED}; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # # Degrees and Decimal Minutes # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub degrees_minutes { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $degrees = $minutes = $seconds = $input; $degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/; $seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/; $minutes = $minutes + ($seconds / 60.0); $self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $degrees = int ($input); $minutes = ($input - $degrees) * 60.0; $self->formatted( sprintf( "%02d %02.8f", $degrees, abs($minutes) ) ); return( $self->formatted() ); } else { print "degrees_minutes() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } # # Degrees/Minutes/Seconds # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub degrees_minutes_seconds { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $degrees = $minutes = $input; $degrees =~ s/(\d+)\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+\.*\d*)/$1/; $seconds = $minutes; $minutes = int ($minutes); $seconds = ($seconds - $minutes) * 60.0; $self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $degrees = int ($input); $minutes = int ( ($input - $degrees) * 60.0 ); $seconds = ( ( ($input - $degrees) * 60.0) - $minutes) * 60.0; $self->formatted( sprintf( "%02d %02d %02.8f", $degrees, abs($minutes), abs($seconds) ) ); return( $self->formatted() ); } else { print "degrees_minutes_seconds() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } # # Decimal Degrees # # Fills in the FORMATTED variable in the object and also returns # the string. If unsuccessful, returns an empty string. # sub decimal_degrees { my $self = shift; # Get the object to work on my $input = $self->raw(); my ($degrees, $minutes, $seconds); if ( $input =~ /\d+\s+\d+\s+\d+\.*\d*/ ) # Input is in "DD MM SS.SS" format { $degrees = $minutes = $seconds = $input; $degrees =~ s/(\d+)\s+\d+\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+)\s+\d+\.*\d*/$1/; $seconds =~ s/\d+\s+\d+\s+(\d+\.*\d*)/$1/; $self->formatted( sprintf( "%02.8f", $degrees + ($minutes/60.0) + ($seconds/(60.0 * 60.0) ) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\s+\d+\.*\d*/ ) # Input is in "DD MM.MM" format { $degrees = $minutes = $input; $degrees =~ s/(\d+)\s+\d+\.*\d*/$1/; $minutes =~ s/\d+\s+(\d+\.*\d*)/$1/; $self->formatted( sprintf( "%02.8f", $degrees + ($minutes / 60.0) ) ); return( $self->formatted() ); } elsif ( $input =~ /\d+\.*\d*/ ) # Input is in "DD.DDDD" format { $self->formatted( $input ); # No translation necessary return( $self->formatted() ); } else { print "decimal_degrees() method: Input format not recognized: $input\n"; $self->formatted( "" ); return( "" ); # Should I die here instead? } } #------------------------------------------------------------------------------------------------ package Ellipsoid; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # Ellipsoid: Equatorial_Radius is the ellipsoid semimajor axis (a) # Polar_Radius is the ellipsoid semiminor axis (b). # First_Ecc_Squared is the first eccentricity squared, defined as: 2f - (f^2) # Inverse_flattening (1/f) is the inverse of ellipsoid flattening 'f' # Flattening (f) is defined as: (a-b)/a. # # This object is used to create the Ellipsoid_Table object below, # containing all of the parameters to describe the various # ellipsoids that we need for datum and UTM<->Lat/Lon translations. # # Equatorial_Radius and First_Ecc_Squared are used by the UTM<->Lat/Lon code. # Equatorial_Radius and Inverse_flattening are used by the datum_shift code. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } # # Notice that we compute first_ecc_squared, flattening, and polar_radius # from the other parameters. # sub _init { my $self = shift; my $f; my $b; my $inverse_f; $self->{NAME} = shift if @_; # Name of ellipsoid $a = $self->{EQUATORIAL_RADIUS} = shift if @_; # Semi-major axis, meters $inverse_f = $self->{INVERSE_FLATTENING} = shift if @_; # Inverse of the ellipsoid flattening 'f' if ($inverse_f) { $f = 1.0 / $inverse_f; $self->{FLATTENING} = $f; # Store the flattening value as well $self->{FIRST_ECC_SQUARED} = (2 * $f) - ($f**2); # Compute First Eccentricity Squared from 'f' if ($a) { # f = (a-b)/a # f = a/a - b/a # f = 1 - b/a # b/a + f = 1 # b/a = 1 - f # b = (1-f)a # $b = (1.0 - $f) * $a; $self->{POLAR_RADIUS} = $b; } } } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub name { my $self = shift; $self->{NAME} = shift if @_; return $self->{NAME}; } sub equatorial_radius { my $self = shift; $self->{EQUATORIAL_RADIUS} = shift if @_; return $self->{EQUATORIAL_RADIUS}; } # # Note that you can override the computed POLAR_RADIUS value # by using this method to store a new value in the hash. # sub polar_radius { my $self = shift; $self->{POLAR_RADIUS} = shift if @_; return $self->{POLAR_RADIUS}; } # # Note that you can override the computed FIRST_ECC_SQUARED value # by using this method to store a new value in the hash. # sub first_ecc_squared { my $self = shift; $self->{FIRST_ECC_SQUARED} = shift if @_; return $self->{FIRST_ECC_SQUARED}; } # # Note that you can override the computed FLATTENING value # by using this method to store a new value in the hash. # sub flattening { my $self = shift; $self->{FLATTENING} = shift if @_; return $self->{FLATTENING}; } sub inverse_flattening { my $self = shift; $self->{INVERSE_FLATTENING} = shift if @_; return $self->{INVERSE_FLATTENING}; } #----------------------------------------------------------------------------------------------- package EllipsoidTable; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # I could have created this table as a hash of anonymous arrays, which might have been # faster/more efficient. Oh well. # # All of the methods here are class methods. There isn't even a way to make an # EllipsoidTable object given here. This class is merely a large collection # of Ellipsoid objects, collected in the %_ellipsoid hash. # my %_ellipsoid; # Class data # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # Note that this method is really useless. The name is the same as the # hash key used in the %_ellipsoid hash. Redundant. # sub name { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->name(); } sub equatorial_radius # (a) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->equatorial_radius(); } sub polar_radius # (b) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->polar_radius(); } sub first_ecc_squared # (ecc) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->first_ecc_squared(); } sub flattening # (f) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->flattening(); } sub inverse_flattening # (1/f) { shift; # Object reference (don't need it) my $ellipsoid_name = shift; return $_ellipsoid{$ellipsoid_name}->inverse_flattening(); } # # This method allows printing out each defined Ellipsoid. # sub enumerate { my $self = shift; print "\nEllipsoid\t\tEquatorial Radius (a)\tPolar Radius (b)\tFirst Eccentricity^2\tFlattening (f)\t\t1/f\n"; print "---------\t\t---------------------\t----------------\t--------------------\t--------------\t\t---\n"; foreach my $key (sort keys %_ellipsoid) { printf("%23s,\t%s,\t%s,\t%s,\t%s,\t%s\n", $key, $self->equatorial_radius($key), $self->polar_radius($key), $self->first_ecc_squared($key), $self->flattening($key), $self->inverse_flattening($key) ); } return(1); } # # Auto-run code # # Fill in the hash containing Ellipsoid objects (fill in the Class data) # # Name, Equatorial_Radius (a), Inverse_Flattening (1/f). # # Name: Reference Ellipsoid Name # Equatorial_Radius: (a) = Semi-Major Axis (WGS-84 value = 6378137.0 meters) # Polar_radius: (b) = Semi-Minor Axis (WGS-84 value = 6356752.3142 meters) # Flattening: f = (a-b)/a (WGS-84 value = 0.00335281066475) # First_Eccentricity_Squared: ecc = 2f - (f^2) (WGS-84 value = 0.00669437999013) # Inverse_flattening: Reciprocal Flattening (1/f) (WGS-84 value = 298.257223563) # # We can calculate Polar_Radius (b), Flattening (f), and First_Eccentricity_Squared (ecc) # from the values for Equatorial_Radius (a) and Inverse_flattening (1/f), so the table # includes only the latter two parameters. # #print "Creating ellipsoid data\n"; # Equatorial # Name Name Radius Inverse_flattening $_ellipsoid{"Airy"} = Ellipsoid->new( "Airy", 6377563.396, 299.324964600 ); $_ellipsoid{"Modified Airy"} = Ellipsoid->new( "Modified Airy", 6377340.189, 299.324964600 ); $_ellipsoid{"Australian National"} = Ellipsoid->new( "Australian National", 6378160.000, 298.250000000 ); $_ellipsoid{"Bessel 1841"} = Ellipsoid->new( "Bessel 1841", 6377397.155, 299.152812800 ); $_ellipsoid{"Bessel 1841 (Namibia)"} = Ellipsoid->new( "Bessel 1841 (Namibia)", 6377483.865, 299.152812800 ); $_ellipsoid{"Clarke 1866"} = Ellipsoid->new( "Clarke 1866", 6378206.400, 294.978698200 ); $_ellipsoid{"Clarke 1880"} = Ellipsoid->new( "Clarke 1880", 6378249.145, 293.465000000 ); $_ellipsoid{"Everest (India 1830)"} = Ellipsoid->new( "Everest (India 1830)", 6377276.345, 300.801700000 ); $_ellipsoid{"Everest (Sabah Sarawak)"} = Ellipsoid->new( "Everest (Sabah Sarawak)",6377298.556, 300.801700000 ); $_ellipsoid{"Everest (India 1956)"} = Ellipsoid->new( "Everest (India 1956)", 6377301.243, 300.801700000 ); $_ellipsoid{"Everest (Malaysia 1969)"} = Ellipsoid->new( "Everest (Malaysia 1969)",6377295.664, 300.801700000 ); $_ellipsoid{"Everest (Malay. & Sing)"} = Ellipsoid->new( "Everest (Malay. & Sing)",6377304.063, 300.801700000 ); $_ellipsoid{"Everest 1948"} = Ellipsoid->new( "Everest 1948", 6377304.063, 300.801700000 ); $_ellipsoid{"Everest (Pakistan)"} = Ellipsoid->new( "Everest (Pakistan)", 6377309.613, 300.801700000 ); $_ellipsoid{"Fischer 1960 (Mercury)"} = Ellipsoid->new( "Fischer 1960 (Mercury)", 6378166.000, 298.300000000 ); $_ellipsoid{"Fischer 1968"} = Ellipsoid->new( "Fischer 1968", 6378150.000, 298.300000000 ); $_ellipsoid{"Modified Fischer 1960"} = Ellipsoid->new( "Modified Fischer 1960", 6378155.000, 298.300000000 ); $_ellipsoid{"GRS 1967"} = Ellipsoid->new( "GRS 1967", 6378160.000, 298.247167427 ); $_ellipsoid{"GRS 1980"} = Ellipsoid->new( "GRS 1980", 6378137.000, 298.257222101 ); $_ellipsoid{"Helmert 1906"} = Ellipsoid->new( "Helmert 1906", 6378200.000, 298.300000000 ); $_ellipsoid{"Hough 1960"} = Ellipsoid->new( "Hough 1960", 6378270.000, 297.000000000 ); $_ellipsoid{"Indonesian 1974"} = Ellipsoid->new( "Indonesian 1974", 6378160.000, 298.247000000 ); $_ellipsoid{"International 1924"} = Ellipsoid->new( "International 1924", 6378388.000, 297.000000000 ); $_ellipsoid{"Krassovsky 1940"} = Ellipsoid->new( "Krassovsky 1940", 6378245.000, 298.300000000 ); $_ellipsoid{"South American 1969"} = Ellipsoid->new( "South American 1969", 6378160.000, 298.250000000 ); $_ellipsoid{"WGS 60"} = Ellipsoid->new( "WGS 60", 6378165.000, 298.300000000 ); $_ellipsoid{"WGS 66"} = Ellipsoid->new( "WGS 66", 6378145.000, 298.250000000 ); $_ellipsoid{"WGS 72"} = Ellipsoid->new( "WGS 72", 6378135.000, 298.260000000 ); $_ellipsoid{"WGS 84"} = Ellipsoid->new( "WGS 84", 6378137.000, 298.257223563 ); #------------------------------------------------------------------------------------------------ package Datum; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # These are the objects and methods used to create the DatumTable in the next package. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{NAME} = shift if @_; $self->{ELLIPSOID} = shift if @_; $self->{DX} = shift if @_; $self->{DY} = shift if @_; $self->{DZ} = shift if @_; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } # # This is mostly a useless method. We store the name here, but it # is also present as the hash key in the %_datum hash. Redundant. # sub name # Name of datum { my $self = shift; $self->{NAME} = shift if @_; return $self->{NAME}; } sub ellipsoid # Name of ellipsoid used in datum { my $self = shift; $self->{ELLIPSOID} = shift if @_; return $self->{ELLIPSOID}; } sub dx # X-offset from WGS84 ellipsoid center { my $self = shift; $self->{DX} = shift if @_; return $self->{DX}; } sub dy # Y-offset from WGS84 ellipsoid center { my $self = shift; $self->{DY} = shift if @_; return $self->{DY}; } sub dz # Z-offset from WGS84 ellipsoid center { my $self = shift; $self->{DZ} = shift if @_; return $self->{DZ}; } #------------------------------------------------------------------------------------------------ package DatumTable; $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; # # I could have created this table as a hash of anonymous arrays, which might have been # faster/more efficient. Oh well. # # All of the methods here are class methods. There isn't even a way to make a # DatumTable object given here. This class is merely a large collection # of Datum objects, collected in the %_datum hash. # my %_datum; # Class data # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub name # Name of datum { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->name(); } sub ellipsoid # Name of ellipsoid used in datum { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->ellipsoid(); } sub dx # X-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dx(); } sub dy # Y-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dy(); } sub dz # Z-offset from WGS84 ellipsoid center { shift; # Object reference (don't need it) my $datum_name = shift; return $_datum{$datum_name}->dz(); } # # This method allows printing out each defined Datum. # sub enumerate { my $self = shift; print "\nDatum\t\t\t\t\t\t\t\tEllipsoid\tDx\tDy\tDz\n"; print "-----\t\t\t\t\t\t\t\t---------\t--\t--\t--\n"; foreach my $key (sort keys %_datum) { printf("%s\n\t\t\t\t\t\t%23s,\t%s,\t%s,\t%s\n", $key, $self->ellipsoid($key), $self->dx($key), $self->dy($key), $self->dz($key) ); } return(1); } # # Auto-run code # # Fill in the Class data. # # This code fills in the %_datum hash which has entries consisting of Datum objects. # # From the original C code: # # "Dx, Dy, Dz: ellipsoid center with respect to WGS 84 ellipsoid center # x axis is the prime meridian # y axis is 90 degrees east longitude # z axis is the axis of rotation of the ellipsoid" # # Most of the current data is from Peter Dana's website. # This increased the number of datums to around 231. -- Curt. # # # NOTE: Consider adding a field for "region of use". # # # Name Name Ellipsoid Dx Dy Dz $_datum{"Adindan (Burkina Faso)"} = Datum->new( "Adindan (Burkina Faso)", "Clarke 1880", -118, -14, 218 ); $_datum{"Adindan (Cameroon)"} = Datum->new( "Adindan (Cameroon)", "Clarke 1880", -134, -2, 210 ); $_datum{"Adindan (Ethiopia)"} = Datum->new( "Adindan (Ethiopia)", "Clarke 1880", -165, -11, 206 ); $_datum{"Adindan (Mali)"} = Datum->new( "Adindan (Mali)", "Clarke 1880", -123, -20, 220 ); $_datum{"Adindan (MEAN for Ethiopia/Sudan)"} = Datum->new( "Adindan (MEAN for Ethiopia/Sudan)", "Clarke 1880", -166, -15, 204 ); $_datum{"Adindan (Senegal)"} = Datum->new( "Adindan (Senegal)", "Clarke 1880", -128, -18, 224 ); $_datum{"Adindan (Sudan)"} = Datum->new( "Adindan (Sudan)", "Clarke 1880", -161, -14, 205 ); $_datum{"Afgooye"} = Datum->new( "Afgooye", "Krassovsky 1940", -43, -163, 45 ); $_datum{"Ain el Abd 1970 (Bahrain)"} = Datum->new( "Ain el Abd 1970 (Bahrain)", "International 1924", -150, -250, -1 ); $_datum{"Ain el Abd 1970 (Saudi Arabia)"} = Datum->new( "Ain el Abd 1970 (Saudi Arabia)", "International 1924", -143, -236, 7 ); $_datum{"American Samoa 1962"} = Datum->new( "American Samoa 1962", "Clarke 1866", -115, 118, 426 ); $_datum{"Anna 1 Astro 1965"} = Datum->new( "Anna 1 Astro 1965", "Australian National", -491, -22, 435 ); $_datum{"Antigua Island Astro 1943"} = Datum->new( "Antigua Island Astro 1943", "Clarke 1880", -270, 13, 62 ); $_datum{"Arc 1950 (Botswana)"} = Datum->new( "Arc 1950 (Botswana)", "Clarke 1880", -138, -105, -289 ); $_datum{"Arc 1950 (Burundi)"} = Datum->new( "Arc 1950 (Burundi)", "Clarke 1880", -153, -5, -292 ); $_datum{"Arc 1950 (Lesotho)"} = Datum->new( "Arc 1950 (Lesotho)", "Clarke 1880", -125, -108, -295 ); $_datum{"Arc 1950 (Malawi)"} = Datum->new( "Arc 1950 (Malawi)", "Clarke 1880", -161, -73, -317 ); $_datum{"Arc 1950 (MEAN)"} = Datum->new( "Arc 1950 (MEAN)", "Clarke 1880", -143, -90, -294 ); $_datum{"Arc 1950 (Swaziland)"} = Datum->new( "Arc 1950", "Clarke 1880", -134, -105, -295 ); $_datum{"Arc 1950 (Zaire)"} = Datum->new( "Arc 1950", "Clarke 1880", -169, -19, -278 ); $_datum{"Arc 1950 (Zambia)"} = Datum->new( "Arc 1950", "Clarke 1880", -147, -74, -283 ); $_datum{"Arc 1950 (Zimbabwe)"} = Datum->new( "Arc 1950", "Clarke 1880", -142, -96, -293 ); $_datum{"Arc 1960 (MEAN)"} = Datum->new( "Arc 1960 (MEAN)", "Clarke 1880", -160, -6, -302 ); $_datum{"Arc 1960 (Kenya)"} = Datum->new( "Arc 1960 (Kenya)", "Clarke 1880", -157, -2, -299 ); $_datum{"Arc 1960 (Tanzania)"} = Datum->new( "Arc 1960 (Tanzania)", "Clarke 1880", -175, -23, -303 ); $_datum{"Ascension Island 1958"} = Datum->new( "Ascension Island 1958", "International 1924", -205, 107, 53 ); $_datum{"Astro B4 Sorol Atoll"} = Datum->new( "Astro B4 Sorol Atoll", "International 1924", 114, -116, -333 ); $_datum{"Astro Beacon E 1945"} = Datum->new( "Astro Beacon E 1945", "International 1924", 145, 75, -272 ); $_datum{"Astro DOS 71/4"} = Datum->new( "Astro DOS 71/4", "International 1924", -320, 550, -494 ); $_datum{"Astro Tern Island (FRIG) 1961"} = Datum->new( "Astro Tern Island (FRIG) 1961", "International 1924", 114, -116, -333 ); $_datum{"Astronomical Station 1952"} = Datum->new( "Astronomical Station 1952", "International 1924", 124, -234, -25 ); $_datum{"Australian Geodetic 1966"} = Datum->new( "Australian Geodetic 1966", "Australian National", -133, -48, 148 ); $_datum{"Australian Geodetic 1984"} = Datum->new( "Australian Geodetic 1984", "Australian National", -134, -48, 149 ); $_datum{"Ayabelle Lighthouse"} = Datum->new( "Ayabelle Lighthouse", "Clarke 1880", -79, -129, 145 ); $_datum{"Bellevue (IGN)"} = Datum->new( "Bellevue (IGN)", "International 1924", -127, -769, 472 ); $_datum{"Bermuda 1957"} = Datum->new( "Bermuda 1957", "Clarke 1866", -73, 213, 296 ); $_datum{"Bogota Observatory"} = Datum->new( "Bogota Observatory", "International 1924", 307, 304, -318 ); $_datum{"Bukit Rimpah"} = Datum->new( "Bukit Rimpah", "Bessel 1841", -384, 664, -48 ); $_datum{"Camp Area Astro"} = Datum->new( "Camp Area Astro", "International 1924", -104, -129, 239 ); $_datum{"Campo Inchauspe"} = Datum->new( "Campo Inchauspe", "International 1924", -148, 136, 90 ); $_datum{"Canton Astro 1966"} = Datum->new( "Canton Astro 1966", "International 1924", 298, -304, -375 ); $_datum{"Cape"} = Datum->new( "Cape", "Clarke 1880", -136, -108, -292 ); $_datum{"Cape Canaveral"} = Datum->new( "Cape Canaveral", "Clarke 1866", -2, 151, 181 ); $_datum{"Carthage"} = Datum->new( "Carthage", "Clarke 1880", -263, 6, 431 ); $_datum{"CH-1903"} = Datum->new( "CH-1903", "Bessel 1841", 674, 15, 405); $_datum{"Chatham Island Astro 1971"} = Datum->new( "Chatham Island Astro 1971", "International 1924", 175, -38, 113); $_datum{"Chua Astro"} = Datum->new( "Chua Astro", "International 1924", -134, 229, -29 ); $_datum{"Corrego Alegre"} = Datum->new( "Corrego Alegre", "International 1924", -206, 172, -6 ); $_datum{"Dabola"} = Datum->new( "Dabola", "Clarke 1880", -83, 37, 124 ); $_datum{"Deception Island"} = Datum->new( "Deception Island", "Clarke 1880", 260, 12, -147 ); $_datum{"Djakarta (Batavia)"} = Datum->new( "Djakarta (Batavia)", "Bessel 1841", -377, 681, -50 ); $_datum{"DOS 1968"} = Datum->new( "DOS 1968", "International 1924", 230, -199, -752 ); $_datum{"Easter Island 1967"} = Datum->new( "Easter Island 1967", "International 1924", 211, 147, 111 ); $_datum{"Estonia 1937"} = Datum->new( "Estonia 1937", "Bessel 1841", 374, 150, 588 ); $_datum{"European 1950 (Cyprus)"} = Datum->new( "European 1950 (Cyprus)", "International 1924", -104, -101, -140 ); $_datum{"European 1950 (Egypt)"} = Datum->new( "European 1950 (Egypt)", "International 1924", -130, -117, -151 ); $_datum{"European 1950 (England/Channel Is/Scotland/Shetland Is)"} = Datum->new( "European 1950 (England/Channel Is/Scotland/Shetland Is)", "International 1924", -86, -96, -120 ); $_datum{"European 1950 (England/Ireland/Scotland/Shetland Is)"} = Datum->new( "European 1950 (England/Ireland/Scotland/Shetland Is)", "International 1924", -86, -96, -120 ); $_datum{"European 1950 (Finland/Norway)"} = Datum->new( "European 1950 (Finland/Norway)", "International 1924", -87, -95, -120 ); $_datum{"European 1950 (Greece)"} = Datum->new( "European 1950 (Greece)", "International 1924", -84, -95, -130 ); $_datum{"European 1950 (Iran)"} = Datum->new( "European 1950 (Iran)", "International 1924", -117, -132, -164 ); $_datum{"European 1950 (Italy:Sardinia)"} = Datum->new( "European 1950 (Italy:Sardinia)", "International 1924", -97, -103, -120 ); $_datum{"European 1950 (Italy:Sicily)"} = Datum->new( "European 1950 (Italy:Sicily)", "International 1924", -97, -88, -135 ); $_datum{"European 1950 (Malta)"} = Datum->new( "European 1950 (Malta)", "International 1924", -107, -88, -149 ); $_datum{"European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)"} = Datum->new( "European 1950 (MEAN for Austria/Belgium/Denmark/Finland/France/W Germany/Gibraltar/Greece/Italy/Luxembourg/Netherlands/Norway/Portugal/Spain/Sweden/Switzerland)", "International 1924", -87, -98, -121 ); $_datum{"European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)"} = Datum->new( "European 1950 (MEAN for Austria/Denmark/France/W Germany/Netherlands/Switzerland)", "International 1924", -87, -96, -120 ); $_datum{"European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)"} = Datum->new( "European 1950 (MEAN for Iraq/Israel/Jordan/Lebanon/Kuwait/Saudi Arabia/Syria)", "International 1924", -103, -106, -141 ); $_datum{"European 1950 (Portugal/Spain)"} = Datum->new( "European 1950 (Portugal/Spain)", "International 1924", -84, -107, -120 ); $_datum{"European 1950 (Tunisia)"} = Datum->new( "European 1950 (Tunisia)", "International 1924", -112, -77, -145 ); $_datum{"European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)"} = Datum->new( "European 1979 (MEAN for Austria/Finland/Netherlands/Norway/Spain/Sweden/Switzerland)", "International 1924", -86, -98, -119 ); $_datum{"Finland Hayford"} = Datum->new( "Finland Hayford", "International 1924", -78, -231, -97 ); $_datum{"Fort Thomas"} = Datum->new( "Fort Thomas", "Clarke 1880", -7, 215, 225 ); $_datum{"Gandajika Base 1970"} = Datum->new( "Gandajika Base 1970", "International 1924", -133, -321, 50 ); $_datum{"Geodetic Datum 1949"} = Datum->new( "Geodetic Datum 1949", "International 1924", 84, -22, 209 ); $_datum{"Graciosa Base SW 1948"} = Datum->new( "Graciosa Base SW 1948", "International 1924", -104, 167, -38 ); $_datum{"Guam 1963"} = Datum->new( "Guam 1963", "Clarke 1866", -100, -248, 259 ); $_datum{"Gunung Segara"} = Datum->new( "Gunung Segara", "Bessel 1841", -403, 684, 41 ); $_datum{"GUX 1 Astro"} = Datum->new( "GUX 1 Astro", "International 1924", 252, -209, -751 ); $_datum{"Herat North"} = Datum->new( "Herat North", "International 1924", -333, -222, 114 ); $_datum{"Hermannskogel Datum (Namibia)"} = Datum->new( "Hermannskogel Datum (Namibia)", "Bessel 1841", 653, -212, 449 ); $_datum{"Hjorsey 1955"} = Datum->new( "Hjorsey 1955", "International 1924", -73, 46, -86 ); $_datum{"Hong Kong 1963"} = Datum->new( "Hong Kong 1963", "International 1924", -156, -271, -189 ); $_datum{"Hu-Tzu-Shan"} = Datum->new( "Hu-Tzu-Shan", "International 1924", -637, -549, -203 ); $_datum{"Indian (Bangladesh)"} = Datum->new( "Indian (Bangladesh)", "Everest (India 1830)", 282, 726, 254 ); $_datum{"Indian (India/Nepal)"} = Datum->new( "Indian (India/Nepal)", "Everest (India 1956)", 295, 736, 257 ); $_datum{"Indian (Pakistan)"} = Datum->new( "Indian (Pakistan)", "Everest (Pakistan)", 283, 682, 231 ); $_datum{"Indian 1954 (Thailand)"} = Datum->new( "Indian 1954 (Thailand)", "Everest (India 1830)", 217, 823, 299 ); $_datum{"Indian 1960 (Vietnam:Con Son Is)"} = Datum->new( "Indian 1960 (Vietnam:Con Son Is)", "Everest (India 1830)", 182, 915, 344 ); $_datum{"Indian 1960 (Vietnam:Near 160N)"} = Datum->new( "Indian 1960 (Vietnam:Near 160N)", "Everest (India 1830)", 198, 881, 317 ); $_datum{"Indian 1975 (Thailand)"} = Datum->new( "Indian 1975 (Thailand)", "Everest (India 1830)", 210, 814, 289 ); $_datum{"Indonesian 1974"} = Datum->new( "Indonesian 1974)", "Indonesian 1974)", -24, -15, 5 ); $_datum{"Ireland 1965"} = Datum->new( "Ireland 1965", "Modified Airy", 506, -122, 611 ); $_datum{"ISTS 061 Astro 1968"} = Datum->new( "ISTS 061 Astro 1968", "International 1924", -794, 119, -298 ); $_datum{"ISTS 073 Astro 1969"} = Datum->new( "ISTS 073 Astro 1969", "International 1924", 208, -435, -229 ); $_datum{"Johnston Island"} = Datum->new( "Johnston Island", "International 1924", 189, -79, -202 ); $_datum{"Kandawala"} = Datum->new( "Kandawala", "Everest (India 1830)", -97, 787, 86 ); $_datum{"Kerguelen Island 1949"} = Datum->new( "Kerguelen Island 1949", "International 1924", 145, -187, 103 ); $_datum{"Kertau 1948"} = Datum->new( "Kertau 1948", "Everest (Malay. & Sing)", -11, 851, 5 ); $_datum{"Kusaie Astro 1951"} = Datum->new( "Kusaie Astro 1951", "International 1924", 647, 1777, -1124 ); $_datum{"Korean Geodetic System"} = Datum->new( "Korean Geodetic System", "GRS 1980", 0, 0, 0 ); $_datum{"L. C. 5 Astro 1961"} = Datum->new( "L. C. 5 Astro 1961", "Clarke 1866", 42, 124, 147 ); $_datum{"Leigon"} = Datum->new( "Leigon", "Clarke 1880", -130, 29, 364 ); $_datum{"Liberia 1964"} = Datum->new( "Liberia 1964", "Clarke 1880", -90, 40, 88 ); $_datum{"Luzon (Philippines:Except Mindanao)"} = Datum->new( "Luzon (Philippines:Except Mindanao)", "Clarke 1866", -133, -77, -51 ); $_datum{"Luzon (Philippines:Mindanao)"} = Datum->new( "Luzon (Philippines:Mindanao)", "Clarke 1866", -133, -79, -72 ); $_datum{"M\'Poraloko"} = Datum->new( "M\'Poraloko", "Clarke 1880", -74, -130, 42 ); $_datum{"Mahe 1971"} = Datum->new( "Mahe 1971", "Clarke 1880", 41, -220, -134 ); $_datum{"Marco Astro"} = Datum->new( "Marco Astro", "International 1924", -289, -124, 60 ); $_datum{"Massawa"} = Datum->new( "Massawa", "Bessel 1841", 639, 405, 60 ); $_datum{"Merchich"} = Datum->new( "Merchich", "Clarke 1880", 31, 146, 47 ); $_datum{"Midway Astro 1961"} = Datum->new( "Midway Astro 1961", "International 1924", 912, -58, 1227 ); $_datum{"Minna (Cameroon)"} = Datum->new( "Minna (Cameroon)", "Clarke 1880", -81, -84, 115 ); $_datum{"Minna (Nigeria)"} = Datum->new( "Minna (Nigeria)", "Clarke 1880", -92, -93, 122 ); $_datum{"Montserrat Island Astro 1958"} = Datum->new( "Montserrat Island Astro 1958", "Clarke 1880", 174, 359, 365 ); $_datum{"Nahrwan (Oman:Masirah Is)"} = Datum->new( "Nahrwan (Oman:Masirah Is)", "Clarke 1880", -247, -148, 369 ); $_datum{"Nahrwan (Saudi Arabia)"} = Datum->new( "Nahrwan (Saudi Arabia)", "Clarke 1880", -243, -192, 477 ); $_datum{"Nahrwan (United Arab Emirates)"} = Datum->new( "Nahrwan (United Arab Emirates)", "Clarke 1880", -249, -156, 381 ); $_datum{"Naparima BWI"} = Datum->new( "Naparima BWI", "International 1924", -10, 375, 165 ); $_datum{"NAD27 Alaska:Except Aleutian Is"} = Datum->new( "NAD27 Alaska:Except Aleutian Is", "Clarke 1866", -5, 135, 172 ); $_datum{"NAD27 Alaska:Aleutian Is E of 180W"} = Datum->new( "NAD27 Alaska:Aleutian Is E of 180W", "Clarke 1866", -2, 152, 149 ); $_datum{"NAD27 Alaska:Aleutian Is W of 180W"} = Datum->new( "NAD27 Alaska:Aleutian Is W of 180W", "Clarke 1866", 2, 204, 105 ); $_datum{"NAD27 Bahamas:Except San Salvador Is"} = Datum->new( "NAD27 Bahamas:Except San Salvador Is", "Clarke 1866", -4, 154, 178 ); $_datum{"NAD27 Bahamas:San Salvador Is"} = Datum->new( "NAD27 Bahamas:San Salvador Is", "Clarke 1866", 1, 140, 165 ); $_datum{"NAD27 Canada (Alberta/B.C.)"} = Datum->new( "NAD27 Canada (Alberta/B.C.)", "Clarke 1866", -7, 162, 188 ); $_datum{"NAD27 Canada (Manitoba/Ontario)"} = Datum->new( "NAD27 Canada (Manitoba/Ontario)", "Clarke 1866", -9, 157, 184 ); $_datum{"NAD27 Canada MEAN"} = Datum->new( "NAD27 Canada MEAN", "Clarke 1866", -10, 158, 189 ); $_datum{"NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)"} = Datum->new( "NAD27 Canada (New Brunswick/Newfoundland/Nova Scotia/Quebec)", "Clarke 1866", -22, 160, 190 ); $_datum{"NAD27 Canada (Northwest Territories/Saskatchewan)"} = Datum->new( "NAD27 Canada (Northwest Territories/Saskatchewan)", "Clarke 1866", 4, 159, 188 ); $_datum{"NAD27 Canada (Yukon)"} = Datum->new( "NAD27 Canada (Yukon)", "Clarke 1866", -7, 139, 181 ); $_datum{"NAD27 Canal Zone"} = Datum->new( "NAD27 Canal Zone", "Clarke 1866", 0, 125, 201 ); $_datum{"NAD27 Caribbean"} = Datum->new( "NAD27 Caribbean", "Clarke 1866", -7, 152, 178 ); $_datum{"NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands"} = Datum->new( "NAD27 MEAN:Antigua/Barbados/Barbuda/Caicos Islands/Cuba/Dominican Republic/Grand Cayman/Jamaica/Turks Islands", "Clarke 1866", -3, 142, 183 ); $_datum{"NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua"} = Datum->new( "NAD27 MEAN:Belize/Costa Rica/El Salvador/Guatemala/Honduras/Nicaragua", "Clarke 1866", 0, 125, 194 ); $_datum{"NAD27 CONUS MEAN"} = Datum->new( "NAD27 CONUS MEAN", "Clarke 1866", -8, 160, 176 ); # Added for compatibility reasons. Same as above. $_datum{"NAD27 CONUS"} = Datum->new( "NAD27 CONUS", "Clarke 1866", -8, 160, 176 ); $_datum{"NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota"} = Datum->new( "NAD27 CONUS MEAN:E of Mississippi/Louisiana/Missouri/Minnesota", "Clarke 1866", -9, 161, 179 ); $_datum{"NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri"} = Datum->new( "NAD27 CONUS W of Mississippi/Except Louisiana/Minnesota/Missouri", "Clarke 1866", -8, 159, 175 ); $_datum{"NAD27 Cuba"} = Datum->new( "NAD27 Cuba", "Clarke 1866", -9, 152, 178 ); $_datum{"NAD27 Greenland (Hayes Peninsula)"} = Datum->new( "NAD27 Greenland (Hayes Peninsula)", "Clarke 1866", 11, 114, 195 ); $_datum{"NAD27 Mexico"} = Datum->new( "NAD27 Mexico", "Clarke 1866", -12, 130, 190 ); $_datum{"NAD27 San Salvador"} = Datum->new( "NAD27 San Salvador", "Clarke 1866", 1, 140, 165 ); $_datum{"NAD83 Alaska (Except Aleutian Is)"} = Datum->new( "NAD83 Alaska (Except Aleutian Is)", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 Aleutian Is"} = Datum->new( "NAD83 Aleutian Is", "GRS 1980", -2, 0, 4 ); $_datum{"NAD83 Canada"} = Datum->new( "NAD83 Canada", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 CONUS"} = Datum->new( "NAD83 CONUS", "GRS 1980", 0, 0, 0 ); $_datum{"NAD83 Hawaii"} = Datum->new( "NAD83 Hawaii", "GRS 1980", 1, 1, -1 ); $_datum{"NAD83 Mexico/Central America"} = Datum->new( "NAD83 Mexico/Central America", "GRS 1980", 0, 0, 0 ); $_datum{"North Sahara"} = Datum->new( "North Sahara", "Clarke 1880", -186, -93, 310 ); $_datum{"Nahrwn Masirah Ilnd"} = Datum->new( "Nahrwn Masirah Ilnd", "Clarke 1880", -247, -148, 369 ); $_datum{"Nahrwn Saudi Arbia"} = Datum->new( "Nahrwn Saudi Arbia", "Clarke 1880", -231, -196, 482 ); $_datum{"Nahrwn United Arab"} = Datum->new( "Nahrwn United Arab", "Clarke 1880", -249, -156, 381 ); $_datum{"Naparima BWI"} = Datum->new( "Naparima BWI", "International 1924", -2, 374, 172 ); $_datum{"Observatorio Meteorologico 1939"} = Datum->new( "Observatorio Meteorologico 1939", "International 1924", -425, -169, 81 ); $_datum{"Old Egyptian 1907"} = Datum->new( "Old Egyptian 1907", "Helmert 1906", -130, 110, -13 ); $_datum{"Old Hawaiian Hawaii"} = Datum->new( "Old Hawaiian Hawaii", "Clarke 1866", 89, -279, -183 ); $_datum{"Old Hawaiian Kauai"} = Datum->new( "Old Hawaiian Kauai", "Clarke 1866", 45, -290, -172 ); $_datum{"Old Hawaiian Maui"} = Datum->new( "Old Hawaiian Maui", "Clarke 1866", 65, -290, -190 ); $_datum{"Old Hawaiian MEAN"} = Datum->new( "Old Hawaiian MEAN", "Clarke 1866", 61, -285, -181 ); $_datum{"Old Hawaiian Oahu"} = Datum->new( "Old Hawaiian Oahu", "Clarke 1866", 58, -283, -182 ); $_datum{"Oman"} = Datum->new( "Oman", "Clarke 1880", -346, -1, 224 ); $_datum{"Ordnance Survey Great Britain 1936 England"} = Datum->new( "Ordnance Survey Great Britain 1936 England", "Airy 1830", 371, -112, 434 ); $_datum{"Ordnance Survey Great Britain 1936 England/Isle of Man/Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 England/Isle of Man/Wales", "Airy 1830", 371, -111, 434 ); $_datum{"Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 MEAN:England/Isle of Man/Scotland/Shetland Is/Wales", "Airy 1830", 375, -111, 431 ); $_datum{"Ordnance Survey Great Britain 1936 Scotland/Shetland Is"} = Datum->new( "Ordnance Survey Great Britain 1936 Scotland/Shetland Is", "Airy 1830", 384, -111, 425 ); $_datum{"Ordnance Survey Great Britain 1936 Wales"} = Datum->new( "Ordnance Survey Great Britain 1936 Wales", "Airy 1830", 370, -108, 434 ); $_datum{"Pico De Las Nieves"} = Datum->new( "Pico De Las Nieves", "International 1924", -307, -92, 127 ); $_datum{"Pitcairn Astro 1967"} = Datum->new( "Pitcairn Astro 1967", "International 1924", 185, 165, 42 ); $_datum{"Point 58"} = Datum->new( "Point 58", "Clarke 1880", -106, -129, 165 ); $_datum{"Pointe Noire 1948"} = Datum->new( "Pointe Noire 1948", "Clarke 1880", -148, 51, -291 ); $_datum{"Porto Santo 1936"} = Datum->new( "Porto Santo 1936", "International 1924", -499, -249, 314 ); $_datum{"Provisional South American 1956 Bolivia"} = Datum->new( "Provisional South American 1956 Bolivia", "International 1924", -270, 188, -388 ); $_datum{"Provisional South American 1956 Chile Northern/Near 19S"} = Datum->new( "Provisional South American 1956 Chile Northern/Near 19S", "International 1924", -270, 183, -390 ); $_datum{"Provisional South American 1956 Chile Southern/Near 43S"} = Datum->new( "Provisional South American 1956 Chile Southern/Near 43S", "International 1924", -305, 243, -442 ); $_datum{"Provisional South American 1956 Columbia"} = Datum->new( "Provisional South American 1956 Columbia", "International 1924", -282, 169, -371 ); $_datum{"Provisional South American 1956 Ecuador"} = Datum->new( "Provisional South American 1956 Ecuador", "International 1924", -278, 171, -367 ); $_datum{"Provisional South American 1956 Guyana"} = Datum->new( "Provisional South American 1956 Guyana", "International 1924", -298, 159, -369 ); $_datum{"Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela"} = Datum->new( "Provisional South American 1956 MEAN:Bolivia/Chile/Columbia/Ecuador/Guyana/Peru/Venezuela", "International 1924", -288, 175, -376 ); $_datum{"Provisional South American 1956 Peru"} = Datum->new( "Provisional South American 1956 Peru", "International 1924", -279, 175, -379 ); $_datum{"Provisional South American 1956 Venezuela"} = Datum->new( "Provisional South American 1956 Venezuela", "International 1924", -295, 173, -371 ); $_datum{"Provisional South Chilean 1963 Near 53S"} = Datum->new( "Provisional South Chilean 1963 Near 53S", "International 1924", 16, 196, 93 ); $_datum{"Puerto Rico/Virgin Is"} = Datum->new( "Puerto Rico/Virgin Is", "Clarke 1866", 11, 72, -101 ); $_datum{"Pulkovo 1942"} = Datum->new( "Pulkovo 1942", "Krassovsky 1940", 28, -130, -95 ); $_datum{"Qatar National"} = Datum->new( "Qatar National", "International 1924", -128, -283, 22 ); $_datum{"Qornoq"} = Datum->new( "Qornoq", "International 1924", 164, 138, -189 ); $_datum{"Reunion"} = Datum->new( "Reunion", "International 1924", 94, -948, -1262 ); $_datum{"Rome 1940"} = Datum->new( "Rome 1940", "International 1924", -225, -65, 9 ); $_datum{"RT 90"} = Datum->new( "RT 90", "Bessel 1841", 498, -36, 568 ); $_datum{"S-42 (Pulkovo 1942) Hungary"} = Datum->new( "S-42 (Pulkovo 1942) Hungary", "Krassovsky 1940", 28, -121, -77 ); $_datum{"S-42 (Pulkovo 1942) Poland"} = Datum->new( "S-42 (Pulkovo 1942) Poland", "Krassovsky 1940", 23, -124, -82 ); $_datum{"S-42 (Pulkovo 1942) Czechoslavakia"} = Datum->new( "S-42 (Pulkovo 1942) Czechoslavakia", "Krassovsky 1940", 26, -121, -78 ); $_datum{"S-42 (Pulkovo 1942) Latvia"} = Datum->new( "S-42 (Pulkovo 1942) Latvia", "Krassovsky 1940", 24, -124, -82 ); $_datum{"S-42 (Pulkovo 1942) Kazakhstan"} = Datum->new( "S-42 (Pulkovo 1942) Kazakhstan", "Krassovsky 1940", 15, -130, -84 ); $_datum{"S-42 (Pulkovo 1942) Albania"} = Datum->new( "S-42 (Pulkovo 1942) Albania", "Krassovsky 1940", 24, -130, -92 ); $_datum{"S-42 (Pulkovo 1942) Romania"} = Datum->new( "S-42 (Pulkovo 1942) Romania", "Krassovsky 1940", 28, -121, -77 ); $_datum{"S-JTSK Czechoslavakia"} = Datum->new( "S-JTSK Czechoslavakia", "Bessel 1841", 589, 76, 480 ); $_datum{"Santo (DOS) 1965"} = Datum->new( "Santo (DOS) 1965", "International 1924", 170, 42, 84 ); $_datum{"Sao Braz"} = Datum->new( "Sao Braz", "International 1924", -203, 141, 53 ); $_datum{"Sapper Hill 1943"} = Datum->new( "Sapper Hill 1943", "International 1924", -355, 21, 72 ); $_datum{"Schwarzeck"} = Datum->new( "Schwarzeck", "Bessel 1841 (Namibia)", 616, 97, -251 ); $_datum{"Selvagem Grande 1938"} = Datum->new( "Selvagem Grande 1938", "International 1924", -289, -124, 60 ); $_datum{"Sierra Leone 1960"} = Datum->new( "Sierra Leone 1960", "Clarke 1880", -88, 4, 101 ); $_datum{"South American 1969 Argentina"} = Datum->new( "South American 1969 Argentina", "South American 1969", -62, -1, -37 ); $_datum{"South American 1969 Bolivia"} = Datum->new( "South American 1969 Bolivia", "South American 1969", -61, 2, -48 ); $_datum{"South American 1969 Brazil"} = Datum->new( "South American 1969 Brazil", "South American 1969", -60, -2, -41 ); $_datum{"South American 1969 Chile"} = Datum->new( "South American 1969 Chile", "South American 1969", -75, -1, -44 ); $_datum{"South American 1969 Colombia"} = Datum->new( "South American 1969 Colombia", "South American 1969", -44, 6, -36 ); $_datum{"South American 1969 Ecuador"} = Datum->new( "South American 1969 Ecuador", "South American 1969", -48, 3, -44 ); $_datum{"South American 1969 Ecuador:Baltra/Galapagos"} = Datum->new( "South American 1969 Ecuador:Baltra/Galapagos", "South American 1969", -47, 26, -42 ); $_datum{"South American 1969 Guyana"} = Datum->new( "South American 1969 Guyana", "South American 1969", -53, 3, -47 ); $_datum{"South American 1969 MEAN"} = Datum->new( "South American 1969 MEAN", "South American 1969", -57, 1, -41 ); $_datum{"South American 1969 Paraguay"} = Datum->new( "South American 1969 Paraguay", "South American 1969", -61, 2, -33 ); $_datum{"South American 1969 Peru"} = Datum->new( "South American 1969 Peru", "South American 1969", -58, 0, -44 ); $_datum{"South American 1969 Trinidad/Tobago"} = Datum->new( "South American 1969 Trinidad/Tobago", "South American 1969", -45, 12, -33 ); $_datum{"South American 1969 Venezuela"} = Datum->new( "South American 1969 Venezuela", "South American 1969", -45, 8, -33 ); $_datum{"South Asia"} = Datum->new( "South Asia", "Modified Fischer 1960", 7, -10, -26 ); $_datum{"Southeast Base"} = Datum->new( "Southeast Base", "International 1924", -499, -249, 314 ); $_datum{"Southwest Base"} = Datum->new( "Southwest Base", "International 1924", -104, 167, -38 ); $_datum{"Tananarive Observatory 1925"} = Datum->new( "Tananarive Observatory 1925", "International 1924", -189, -242, -91 ); $_datum{"Timbalai 1948"} = Datum->new( "Timbalai 1948", "Everest (Sabah Sarawak)", -679, 669, -48 ); $_datum{"Tokyo Japan"} = Datum->new( "Tokyo Japan", "Bessel 1841", -148, 507, 685 ); $_datum{"Tokyo MEAN"} = Datum->new( "Tokyo MEAN", "Bessel 1841", -148, 507, 685 ); $_datum{"Tokyo Okinawa"} = Datum->new( "Tokyo Okinawa", "Bessel 1841", -158, 507, 676 ); $_datum{"Tokyo South Korea"} = Datum->new( "Tokyo South Korea", "Bessel 1841", -147, 506, 687 ); $_datum{"Tristan Astro 1968"} = Datum->new( "Tristan Astro 1968", "International 1924", -632, 438, -609 ); $_datum{"Viti Levu 1916"} = Datum->new( "Viti Levu 1916", "Clarke 1880", 51, 391, -36 ); $_datum{"Voirol 1960"} = Datum->new( "Voirol 1960", "Clarke 1880", -123, -206, 219 ); $_datum{"Wake Island Astro 1952"} = Datum->new( "Wake Island Astro 1952", "International 1924", 276, -57, 149 ); $_datum{"Wake-Eniwetok 1960"} = Datum->new( "Wake-Eniwetok 1960", "Hough 1960", 102, 52, -38 ); $_datum{"WGS 72"} = Datum->new( "WGS 72", "WGS 72", 0, 0, 0 ); $_datum{"WGS 84"} = Datum->new( "WGS 84", "WGS 84", 0, 0, 0 ); $_datum{"Yacare"} = Datum->new( "Yacare", "International 1924", -155, 171, 37 ); $_datum{"Zanderij"} = Datum->new( "Zanderij", "International 1924", -265, 120, -358 ); #------------------------------------------------------------------------------------------------ package Coordinate; # # Note that we export NOTHING! This module strives to be object-oriented, # therefore exporting is a bad thing. You can get to any of the public # methods by using normal method calls on an object. # $VERSION = do { my @r=(q$Revision$=~/\d+/g); sprintf "%d."."%02d"x$#r,@r }; use Math::Trig; #use Math::BigFloat; # Allows arbitrary length floating point operations #use strict; # # Here is a Coordinate object. It contains all of the data # for describing a single point on the earth and the methods # for setting/getting these values. # # # This constructor can be used to create and initialize an object # with Latitude/Longitude/Datum fields. # sub new { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init(@_); # Call _init with remaining args return $self; } sub _init { my $self = shift; $self->{LATITUDE} = shift if @_; $self->{LONGITUDE} = shift if @_; $self->{DATUM} = shift if @_; } # # This constructor can be used to create and initialize an object # with easting/northing/zone/datum fields (UTM grid). # sub new_utm { my $class = shift; # What class are we constructing? my $self = { }; # Allocate new memory bless $self, $class; # Mark it of the right type $self->_init_utm(@_); # Call _init with remaining args return $self; } sub _init_utm { my $self = shift; $self->{EASTING} = shift if @_; $self->{NORTHING} = shift if @_; $self->{ZONE} = shift if @_; $self->{DATUM} = shift if @_; } # # Returns the version number (RCS version tag) of this module. # sub version { return $VERSION; } sub latitude { my $self = shift; $self->{LATITUDE} = shift if @_; return $self->{LATITUDE}; } sub longitude { my $self = shift; $self->{LONGITUDE} = shift if @_; return $self->{LONGITUDE}; } sub formatted_latitude { my $self = shift; $self->{FORMATTED_LATITUDE} = shift if @_; return $self->{FORMATTED_LATITUDE}; } sub formatted_longitude { my $self = shift; $self->{FORMATTED_LONGITUDE} = shift if @_; return $self->{FORMATTED_LONGITUDE}; } sub easting { my $self = shift; $self->{EASTING} = shift if @_; return $self->{EASTING}; } sub northing { my $self = shift; $self->{NORTHING} = shift if @_; return $self->{NORTHING}; } sub zone { my $self = shift; $self->{ZONE} = shift if @_; return $self->{ZONE}; } sub datum { my $self = shift; $self->{DATUM} = shift if @_; return $self->{DATUM}; } # # Converts lat/lon to UTM coordinates. Equations from USGS Bulletin 1532 # (According to comments in the original C code). # # East Longitudes are positive, West are negative. # North latitudes are positive, South are negative. # Latitude and longitude are in decimal degrees. # # This method fills in the Easting/Northing/Zone fields in the object. # The Zone field will look something like: "10U" when filled in. # sub lat_lon_to_utm { my $position = shift; # Snag the pointer to the object. my $PI = 3.14159265358979323846; my $deg_2_rad = $PI / 180; my $k0 = 0.9996; # First get the datum used in the position from the object: my $datum = $position->datum(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); # Do a lookup in the $ellipsoid{} hash to find the Radius value. my $a = EllipsoidTable->equatorial_radius( $ellipsoid ); # Do a lookup in the $ellipsoid{} hash to find the Ecc value. my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid ); my $Lat = $position->latitude(); my $Long = $position->longitude(); # Make sure the longitude is between -180.00 .. 179.9 my $Long_Temp = ($Long+180)-int(($Long+180)/360)*360-180; # -180.00 .. 179.9; my $Lat_Rad = $Lat * $deg_2_rad; my $Long_Rad = $Long_Temp * $deg_2_rad; my $Zone_Number = int(($Long_Temp + 180)/6) + 1; if( $Lat >= 56.0 && $Lat < 64.0 && $Long_Temp >= 3.0 && $Long_Temp < 12.0 ) { $Zone_Number = 32; } # Special zones for Svalbard if( $Lat >= 72.0 && $Lat < 84.0 ) { if( $Long_Temp >= 0.0 && $Long_Temp < 9.0 ) { $Zone_Number = 31 } elsif( $Long_Temp >= 9.0 && $Long_Temp < 21.0 ) { $Zone_Number = 33 } elsif( $Long_Temp >= 21.0 && $Long_Temp < 33.0 ) { $Zone_Number = 35 } elsif( $Long_Temp >= 33.0 && $Long_Temp < 42.0 ) { $Zone_Number = 37 }; } my $Long_Origin = ($Zone_Number - 1)*6 - 180 + 3; # +3 puts origin in middle of zone my $Long_Origin_Rad = $Long_Origin * $deg_2_rad; # Compute the UTM Zone from the latitude and longitude # NOTE: Need to check for out-of-range here. # my $Zone_Letter = &_utm_letter_designator($Lat); #printf( "Zone_Number: %d\t\tZone_Letter: %s\n", $Zone_Number, $Zone_Letter ); my $UTM_Zone = sprintf( "%d%s", $Zone_Number, $Zone_Letter ); my $ecc_Prime_Squared = ($ecc_Squared)/(1-$ecc_Squared); my $N = $a/sqrt(1-$ecc_Squared*sin($Lat_Rad)*sin($Lat_Rad)); my $T = tan($Lat_Rad) * tan($Lat_Rad); my $C = $ecc_Prime_Squared * cos($Lat_Rad) * cos($Lat_Rad); my $A = cos($Lat_Rad) * ($Long_Rad-$Long_Origin_Rad); my $M = $a * ((1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256) * $Lat_Rad - (3 * $ecc_Squared/8 + 3 * $ecc_Squared * $ecc_Squared/32 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(2 * $Lat_Rad) + (15 * $ecc_Squared * $ecc_Squared/256 + 45 * $ecc_Squared * $ecc_Squared * $ecc_Squared/1024) * sin(4 * $Lat_Rad) - (35 * $ecc_Squared * $ecc_Squared * $ecc_Squared/3072) * sin(6 * $Lat_Rad)); my $UTM_Easting = ($k0 * $N * ($A + (1 - $T + $C) * $A * $A * $A/6 + (5 - 18 * $T + $T * $T + 72 * $C - 58 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A/120) + 500000.0); my $UTM_Northing = ($k0 * ($M + $N * tan($Lat_Rad) * ($A * $A/2 + (5 - $T + 9 * $C + 4 * $C * $C) * $A * $A * $A * $A/24 + (61 - 58 * $T + $T * $T + 600 * $C - 330 * $ecc_Prime_Squared) * $A * $A * $A * $A * $A * $A/720))); if($Lat < 0) { $UTM_Northing += 10000000.0; # 10000000 meter offset for southern hemisphere } # Write the results back to our position object $position->easting( $UTM_Easting ); $position->northing( $UTM_Northing ); $position->zone( $UTM_Zone ); return(1); } # # This routine determines the correct UTM letter designator for the given latitude. # Returns 'Z' if latitude is outside the UTM limits of 84N to 80S. # # Note that this is a normal subroutine, not an object method. It is to # be used inside this module only and is not exported. # sub _utm_letter_designator { my $Lat = shift; my $Letter_Designator; if (( 84 >= $Lat) && ($Lat >= 72)) { $Letter_Designator = 'X' } elsif (( 72 > $Lat) && ($Lat >= 64)) { $Letter_Designator = 'W' } elsif (( 64 > $Lat) && ($Lat >= 56)) { $Letter_Designator = 'V' } elsif (( 56 > $Lat) && ($Lat >= 48)) { $Letter_Designator = 'U' } elsif (( 48 > $Lat) && ($Lat >= 40)) { $Letter_Designator = 'T' } elsif (( 40 > $Lat) && ($Lat >= 32)) { $Letter_Designator = 'S' } elsif (( 32 > $Lat) && ($Lat >= 24)) { $Letter_Designator = 'R' } elsif (( 24 > $Lat) && ($Lat >= 16)) { $Letter_Designator = 'Q' } elsif (( 16 > $Lat) && ($Lat >= 8)) { $Letter_Designator = 'P' } elsif (( 8 > $Lat) && ($Lat >= 0)) { $Letter_Designator = 'N' } elsif (( 0 > $Lat) && ($Lat >= -8)) { $Letter_Designator = 'M' } elsif (( -8 > $Lat) && ($Lat >= -16)) { $Letter_Designator = 'L' } elsif ((-16 > $Lat) && ($Lat >= -24)) { $Letter_Designator = 'K' } elsif ((-24 > $Lat) && ($Lat >= -32)) { $Letter_Designator = 'J' } elsif ((-32 > $Lat) && ($Lat >= -40)) { $Letter_Designator = 'H' } elsif ((-40 > $Lat) && ($Lat >= -48)) { $Letter_Designator = 'G' } elsif ((-48 > $Lat) && ($Lat >= -56)) { $Letter_Designator = 'F' } elsif ((-56 > $Lat) && ($Lat >= -64)) { $Letter_Designator = 'E' } elsif ((-64 > $Lat) && ($Lat >= -72)) { $Letter_Designator = 'D' } elsif ((-72 > $Lat) && ($Lat >= -80)) { $Letter_Designator = 'C' } else { $Letter_Designator = 'Z' }; # An error flag: Latitude is outside UTM limits return $Letter_Designator; } # # Converts UTM coordinates to lat/lon. Equations from USGS Bulletin 1532. # East longitudes are positive, West are negative. # North latitudes are positive, South are negative. # Latitude and longitude are in decimal degrees. # Zone should look something like: "10U" before starting the conversion. # sub utm_to_lat_lon { my $position = shift; # Input is in the form of a "Coordinate" object my $PI = 3.14159265358979323846; my $rad_2_deg = 180.0 / $PI; my $k0 = 0.9996; # First get the datum used in the position from the object: my $datum = $position->datum(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); # Do a lookup in the $ellipsoid{} hash to find the Radius value. my $a = EllipsoidTable->equatorial_radius( $ellipsoid ); # Do a lookup in the $ellipsoid{} hash to find the Ecc value. my $ecc_Squared = EllipsoidTable->first_ecc_squared( $ellipsoid ); my $x = $position->easting(); my $y = $position->northing(); my $Zone_Letter = $position->zone(); my $Zone_Number = $Zone_Letter; $Zone_Number =~ s/(\d+).*/$1/; # Convert to an integer my $e1 = (1-sqrt(1-$ecc_Squared))/(1+sqrt(1-$ecc_Squared)); $Zone_Letter =~ s/\d+(\w)/$1/; # Convert UTM zone to just a letter #print "$Zone_Letter\n\n"; my $Northern_Hemisphere; # 1 for northern hemisphere, 0 for southern $x = $x - 500000.0; # Remove 500,000 meter offset for longitude $y = $y; if(($Zone_Letter ge 'N')) { $Northern_Hemisphere = 1; # 'N' or higher is in the northern hemisphere #print "Northern Hemisphere\n"; } else { $Northern_Hemisphere = 0; # Point is in southern hemisphere $y -= 10000000.0; # Remove 10,000,000 meter offset used for southern hemisphere #print "Southern Hemisphere\n"; } #print "Zone_Number: $Zone_Number\n"; my $Long_Origin = ($Zone_Number - 1) * 6 - 180 + 3; # +3 puts origin in middle of zone my $ecc_Prime_Squared = ($ecc_Squared)/(1 - $ecc_Squared); my $M = $y / $k0; my $mu = $M/($a * (1 - $ecc_Squared/4 - 3 * $ecc_Squared * $ecc_Squared/64 - 5 * $ecc_Squared * $ecc_Squared * $ecc_Squared/256)); my $phi1_Rad = $mu + (3 * $e1/2 - 27 * $e1 * $e1 * $e1/32) * sin(2 * $mu) + (21 * $e1 * $e1/16 - 55 * $e1 * $e1 * $e1 * $e1/32) * sin(4 * $mu) +(151 * $e1 * $e1 * $e1/96) * sin(6 * $mu); my $phi1 = $phi1_Rad * $rad_2_deg; my $N1 = $a/sqrt(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad)); my $T1 = tan($phi1_Rad) * tan($phi1_Rad); my $C1 = $ecc_Prime_Squared * cos($phi1_Rad) * cos($phi1_Rad); my $R1 = $a * (1 - $ecc_Squared)/(1 - $ecc_Squared * sin($phi1_Rad) * sin($phi1_Rad)**1.5); my $D = $x/($N1 * $k0); $Lat = $phi1_Rad - ($N1 * tan($phi1_Rad)/$R1) * ($D * $D/2 - (5 + 3 * $T1 + 10 * $C1 - 4 * $C1 * $C1 - 9 * $ecc_Prime_Squared) * $D * $D * $D * $D/24 +(61 + 90 * $T1 + 298 * $C1 + 45 * $T1 * $T1 - 252 * $ecc_Prime_Squared - 3 * $C1 * $C1) * $D * $D * $D * $D * $D * $D/720); $Lat = $Lat * $rad_2_deg; $Long = ($D - (1 + 2 * $T1 + $C1) * $D * $D * $D/6 + (5 - 2 * $C1 + 28 * $T1 - 3 * $C1 * $C1 + 8 * $ecc_Prime_Squared + 24 * $T1 * $T1) *$D * $D * $D * $D * $D/120)/cos($phi1_Rad); $Long = $Long_Origin + $Long * $rad_2_deg; # Write the results back to our position object $position->latitude( $Lat ); $position->longitude( $Long ); return(1); } # # Function to convert latitude and longitude in decimal degrees between WGS 84 and # another datum. The arguments to this function are a Coordinate object ($position) # and a direction flag ($from_WGS84). The Datum you're translating to/from is # stored in the Datum() field of the object (the other Datum is by default WGS 84). # sub _datum_shift { my $position = shift; # This is our position object my $from_WGS84 = shift; # If 1, then we're converting from WGS 84 # to the datum listed in the position object # If 0, we're going the other way. my $PI = 3.14159265358979323846; my $rad_2_deg = 180.0 / $PI; my $deg_2_rad = $PI / 180; #printf("%s\n", $position->datum() ); my $datum = $position->datum(); # Snag the parameters from the position object # (Get the "other" datum). my $latitude = $position->latitude(); my $longitude = $position->longitude(); # Now find out the ellipsoid used by consulting the DatumTable: my $ellipsoid = DatumTable->ellipsoid( $datum ); my $dx = DatumTable->dx($datum); # Grab the parameters for the "other" datum. my $dy = DatumTable->dy($datum); # Offsets between "other" datum and WGS84 my $dz = DatumTable->dz($datum); # ellipsoid centers. #print "$dx\t$dy\t$dz\n"; my $WGS_a = EllipsoidTable->equatorial_radius("WGS 84"); # WGS 84 semimajor axis my $WGS_inv_f = EllipsoidTable->inverse_flattening("WGS 84"); # WGS 84 1/f my $phi = $latitude * $deg_2_rad; my $lambda = $longitude * $deg_2_rad; my ($a0, $b0, $es0, $f0); # Reference ellipsoid of input data my ($a1, $b1, $es1, $f1); # Reference ellipsoid of output data my $psi; # geocentric latitude my ($x, $y, $z); # 3D coordinates with respect to original datum my $psi1; # transformed geocentric latitude if ($datum eq "WGS 84") # do nothing if current datum is WGS 84 { return(1); } if ($from_WGS84) # convert from WGS 84 to new datum { $a0 = $WGS_a; # WGS 84 semimajor axis $f0 = 1.0 / $WGS_inv_f; # WGS 84 flattening $a1 = EllipsoidTable->equatorial_radius($ellipsoid); $f1 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid); } else # convert from old datum to WGS 84 { $a0 = EllipsoidTable->equatorial_radius($ellipsoid); # semimajor axis $f0 = 1.0 / EllipsoidTable->inverse_flattening($ellipsoid); # flattening $a1 = $WGS_a; # WGS 84 semimajor axis $f1 = 1 / $WGS_inv_f; # WGS 84 flattening $dx = -$dx; $dy = -$dy; $dz = -$dz; } $b0 = $a0 * (1 - $f0); # semiminor axis for input datum $es0 = 2 * $f0 - $f0*$f0; # eccentricity^2 $b1 = $a1 * (1 - $f1); # semiminor axis for output datum $es1 = 2 * $f1 - $f1*$f1; # eccentricity^2 # Convert geodedic latitude to geocentric latitude, psi if ($latitude == 0.0 || $latitude == 90.0 || $latitude == -90.0) { $psi = $phi; } else { $psi = atan((1 - $es0) * tan($phi)); } # Calculate x and y axis coordinates with respect to the original ellipsoid if ($longitude == 90.0 || $longitude == -90.0) { $x = 0.0; $y = abs($a0 * $b0 / sqrt($b0*$b0 + $a0*$a0* ( tan($psi)**2.0) ) ); } else { $x = abs(($a0 * $b0) / sqrt( (1 + (tan($lambda)**2.0) ) * ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) ) ); $y = abs($x * tan($lambda)); } if ($longitude < -90.0 || $longitude > 90.0) { $x = -$x; } if ($longitude < 0.0) { $y = -$y; } # Calculate z axis coordinate with respect to the original ellipsoid if ($latitude == 90.0) { $z = $b0; } elsif ($latitude == -90.0) { $z = -$b0; } else { $z = tan($psi) * sqrt( ($a0*$a0 * $b0*$b0) / ($b0*$b0 + $a0*$a0 * (tan($psi)**2.0) ) ); } # Calculate the geocentric latitude with respect to the new ellipsoid $psi1 = atan(($z - $dz) / sqrt(($x - $dx)*($x - $dx) + ($y - $dy)*($y - $dy))); # Convert to geocentric latitude and save return value $latitude = atan(tan($psi1) / (1 - $es1)) * $rad_2_deg; # Calculate the longitude with respect to the new ellipsoid $longitude = atan(($y - $dy) / ($x - $dx)) * $rad_2_deg; # Correct the resultant for negative x values if ($x-$dx < 0.0) { if ($y-$dy > 0.0) { $longitude = 180.0 + $longitude; } else { $longitude = -180.0 + $longitude; } } # Write the results back to our position object $position->latitude($latitude); $position->longitude($longitude); if (! $from_WGS84) # If we're converting to WGS 84 datum { $position->datum( "WGS 84" ); # Change the datum to correspond to # the new data in the object } #print "New one: $latitude, $longitude\n"; return(1); } # # Method to convert latitude and longitude in decimal degrees from another # datum to WGS 84. The only argument to this method is a Coordinate object # with the lat/lon/datum fields filled in. # # This method returns a NEW Coordinate object with lat/lon/datum fields # filled in and the other fields empty. The original object is not changed. # sub datum_shift_to_wgs84 { my $old_position = shift; # This is our original position object my $to_WGS84 = 0; # Create a new object and fill in a few fields my $new_position = Coordinate->new( $old_position->latitude(), $old_position->longitude(), $old_position->datum() ); &_datum_shift( $new_position, $to_WGS84 ); return( $new_position ); # Return the datum-shifted object } # # Method to convert latitude and longitude in decimal degrees from WGS 84 to # another datum. The arguments to this method are a Coordinate object # with the lat/lon/datum fields filled in (the datum field must be "WGS 84"), # AND a datum (string) to shift to. # # This method returns a NEW Coordinate object with lat/lon/datum fields # filled in. The original object is not changed. # sub datum_shift_from_wgs84_to { my $old_position = shift; # This is our original position object my $new_datum = shift; # The datum we wish to shift to my $from_WGS84 = 1; # Create a new object and fill in a few fields my $new_position = Coordinate->new( $old_position->latitude(), $old_position->longitude(), $new_datum ); &_datum_shift( $new_position, $from_WGS84 ); return( $new_position ); # Return the datum-shifted object } # # Degrees and Decimal Minutes # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub degrees_minutes { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->degrees_minutes() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->degrees_minutes() ); # process it & fill in our finished string return(1); } # # Degrees/Minutes/Seconds # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub degrees_minutes_seconds { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create the temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->degrees_minutes_seconds() ); # Process it & fill in our finished string return(1); } # # Decimal Degrees # # Fills in the Formatted_latitude and Formatted_longitude variables # in the object. # sub decimal_degrees { my $self = shift; # Get the object to work on $temp = CoordinateFormat->new(); # Create the temporary object $temp->raw( $self->latitude() ); # Fill in with raw data $self->formatted_latitude ( $temp->decimal_degrees() ); # Process it & fill in our finished string $temp->raw( $self->longitude() ); # Fill in with raw data $self->formatted_longitude( $temp->decimal_degrees() ); # Process it & fill in our finished string return(1); } #------------------------------------------------------------------------------------------------ # # Auto-run code # # This code will get run automatically whenever this file gets "required" # or "used" in another Perl program. # 1; # Needed to prevent exception when loading this module Xastir-Release-2.2.4/scripts/Makefile.am0000664000175000017500000000154615151324131017052 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # scriptsdir=${pkgdatadir}/scripts dist_scripts_DATA = \ ads-b.pl \ ais.pl \ ais_pp.pl \ Coordinate.pm \ coord-convert.pl \ geopdf2gtiff.pl \ get-BOMdata \ get-fcc-rac.pl \ get-NWSdata \ gpx2shape \ icontable.pl \ inf2geo.pl \ kiss-off.pl \ langElmerFudd.pl \ langMuppetsChef.pl \ langOldeEnglish.pl \ langPigLatin.pl \ langPirateEnglish.pl \ mapblast2geo.pl \ mapfgd.pl \ object2shp.pl \ overlay.pl \ ozi2geo.pl \ permutations.pl \ pos2shp.pl \ ridge_radar.pl \ slideshow.pl \ test_coord.pl \ toporama50k.pl \ toporama250k.pl\ track-get.pl \ update_langfile.pl \ waypoint-get.pl \ wms.pl \ wxnowsrv.pl install-data-hook: cd $(DESTDIR)$(scriptsdir) && \ chmod a+x *.pl get-* gpx2* Xastir-Release-2.2.4/scripts/UIView2XastirLog.pl0000775000175000017500000000312715151324131020442 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # Script to convert a UI-View log file to an Xastir log file. # # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # NOTE: Run it against an input file and tell it where to put the # output: # # ./UIView2XastirLog.pl output_file.log # # No timestamp info is converted or saved by this script. while (<>) { chomp; if (m/START UTC/) { # Skip it next; } # If line starts with date field, chop off the date, time1, # time2 fields. # if (m/^\d\d\d\d\-\d\d\-\d\d\s.*/) { s/^\d\d\d\d\-\d\d\-\d\d\s+\d\d\:\d\d:\d\d\s+\d\d\:\d\d:\d\dR//; # Get rid of " " s/\s\:\r/:/; # Save current line $temp = $_; # Read next line $_ = <>; chomp; # Concatenate the two $temp = $temp . $_ . "\n"; print $temp; } } Xastir-Release-2.2.4/scripts/XastirGitStamp.sh0000775000175000017500000000066715151324131020303 0ustar hibbyhibby#!/bin/sh #This script prints the short-format git SHA-1 string if the source directory # has a ".git" directory. # # This will typically only be called from a Makefile, with $(top_srcdir) as the # first argument. Its purpose is so we can inject the git commit ID # into the "Help->About" dialog box. SRCDIR=$1 SHASTRING="" cd $SRCDIR if [ -e .git ] then GITSHA=`git describe --dirty` SHASTRING=" (${GITSHA})" fi echo $SHASTRING Xastir-Release-2.2.4/scripts/ads-b.pl0000775000175000017500000031031615151324131016342 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2026 The Xastir Group # # Converts "dump1090" telnet port output to Xastir UDP input, for decoding # packets directly from aircraft. This script will parse packets containing # lat/long, turn them into APRS-like packets, then use "xastir_udp_client" # to inject them into Xastir. Must have "dump1090" running, and optionally # "dump978" to dump packets into "dump1090" from the other frequency/protocol # for ADS-B. # # # TODO: Create probability circle around my position for aircraft sending altitude # but no lat/long. Change the size of the circle based on altitude and/or RSSI # (Need to tie into Beast-mode port, raw data port, or JSON port to get RSSI). # Would need to keep track of these objects and kill them when the aircraft timed-out # or sent lat/long. Could switch back to the circle when lat/long times out but # altitude is still coming in as well. # # TODO: Check everywhere that we set a variable to "". Make sure we're not setting # it when a sentence including it comes in, then resetting it on all other sentences # so that it never gets seen. "squawk_txt" and "squawk" were 2 of these. # Check everywhere that $fields[] are checked/saved/used. # # TODO: Expire data values from hashes XX minutes after receiving them. # # # Invoke it as: # ./ads-b.pl planes [--circles] [--logging] # # If you add " --circles" to the end you'll also get a red circle around plane # symbols at your current location which represent the area that a plane might # be min, if it's only reporting altitude and not lat/long. # # If you add " --logging" to the end, this script will save the APRS portion of # the output to a file called "~/.xastir/logs/planes.log". You can later suck # this file back in to see the planes move around the map in hyperspeed. Useful # for a quick demo. # # Injecting them from "planes" or "p1anes" assures that Xastir won't try to adopt # the APRS Item packets as its own and re-transmit them. # # # I got the "dump1090" program from here originally: # https://github.com/antirez/dump1090 # Newer fork: # https://github.com/MalcolmRobb/dump1090 # Newer-yet fork, seems to decode much better: # https://github.com/mutability/dump1090 # # Invoke Mutability's "dump1090" program like so: # "./dump1090 --interactive --net --net-sbs-port 30003 --phase-enhance --oversample --fix --ppm -1 --gain -10 --device-index 0 # # # NOTE: There's also "dump978" which listens to 978 MHz ADS-B transmissions. You can # invoke "dump1090" as above, then invoke "dump978" like this: # # rtl_sdr -f 978000000 -s 2083334 -g 0 -d 1 - | ./dump978 | ./uat2esnt | nc -q1 localhost 30001 # # which will convert the 978 MHz packets into ADS-B ES packets and inject them into "dump1090" # for decoding. I haven't determined yet whether those packets will come out on "dump1090"'s # port 30003 (which this Perl script uses). The above command also uses RTL device 1 instead of 0. # If you're only interested in 978 MHz decoding, there's a way to start "dump1090" w/o a # device attached, then start "dump978" and connect it to "dump1090". # # Then invoke this script in another xterm using "planes" as the callsign: # "./ads-b.pl planes " # # NOTE: Do NOT use the same callsign as your Xastir instance, else it will # "adopt" those APRS Item packets as its own and retransmit them. Code was # added to the script to prevent such operation, but using "planes" as the # callsign works great too! # # # This script snags packets from port 30003 of "dump1090", parses them, then injects # APRS packets into Xastir's UDP port (2023) if "Server Ports" are enabled in Xastir. # # # Port 30001 is an input port (dump978 connects there and dumps data in). # # Port 30002 outputs in raw format, like: # *8D451E8B99019699C00B0A81F36E; # Every entry is separated by a simple newline (LF character, hex 0x0A). # The "callsign" (6 digits of hex) in chunk #4 = ICAO (airframe identifier). # Decoding the sentences: # https://www.sussex.ac.uk/webteam/gateway/file.php?name=coote-proj.pdf&site=20] # http://adsb-decode-guide.readthedocs.org/en/latest/ # # Port 30003 outputs data is SBS1 (BaseStation) format, and is used by this script. # Decoding the sentences: # http://woodair.net/SBS/Article/Barebones42_Socket_Data.htm # NOTE: I changed the numbers by -1 to fit Perl's "split()" command field numbering. # Field 0: # Message type (MSG, STA, ID, AIR, SEL or CLK) # Field 1: # Transmission Type MSG sub types 1 to 8. Not used by other message types. # Field 2: # Session ID Database Session record number # Field 3: # AircraftID Database Aircraft record number # Field 4: # HexIdent Aircraft Mode S hexadecimal code (What we use here... Unique identifier) # Field 5: # FlightID Database Flight record number # Field 6: # Date message generated As it says # Field 7: # Time message generated As it says # Field 8: # Date message logged As it says # Field 9: # Time message logged As it says # Field 10: # Callsign An eight digit flight ID - can be flight number or registration (or even nothing). # Field 11: # Altitude Mode C altitude. Height relative to 1013.2mb (Flight Level). Not height AMSL.. # Field 12: # GroundSpeed Speed over ground (not indicated airspeed) # Field 13: # Track Track of aircraft (not heading). Derived from the velocity E/W and velocity N/S # Field 14: # Latitude North and East positive. South and West negative. # Field 15: # Longitude North and East positive. South and West negative. # Field 16: # VerticalRate 64ft resolution # Field 17: # Squawk Assigned Mode A squawk code. # Field 18: # Alert (Squawk change) Flag to indicate squawk has changed. # Field 19: # Emergency Flag to indicate emergency code has been set # Field 20: # SPI (Ident) Flag to indicate transponder Ident has been activated. # Field 21: # IsOnGround Flag to indicate ground squat switch is active # # # Squawk Codes: # https://en.wikipedia.org/wiki/Transponder_%28aeronautics%29 # # # For reference, using 468/frequency (MHz) to get length of 1/2 wave dipole in feet: # # 1/2 wavelength on 1090 MHz: 5.15" # 1/4 wavelength on 1090 MHz: 2.576" or 2 9/16" # # 1/2 wavelength on 978 MHz: 5.74" # 1/4 wavelength on 978 MHz: 2.87" or 2 7/8" # # # NOTE: In the tables below, lines marked with "Per Countries.dat file" are derived # from the work of "Alexis" of the Group "https://mode-s.groups.io/g/mode-s" # most likely arrived at via observation of Mode-S transponder activity. They are # not guaranteed to represent reality in any way. Find the file in the Files section # of the group. # # Most of the rest of the data in the tables was derived from: # http://www.kloth.net/radio/icao24alloc.php (Created 2003-01-12, Last modified 2011-06-23). # Which in turn came from: # "ICAO Annex 10 Volume III Chapter 9. Aircraft Addressing System" # # eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' & eval 'exec perl -S $0 $argv:q' if 0; use IO::Socket; $my_alt = 600; # In feet. Used by probability circles. # Fetch my lat/long from Xastir config file $my_lat = `grep STATION_LAT ~/.xastir/config/xastir.cnf`; if (! ($my_lat =~ m/STATION_LAT:/) ) { die "Couldn't get STATION_LAT from Xastir config file\n"; } $my_lon = `grep STATION_LONG ~/.xastir/config/xastir.cnf`; if (! ($my_lon =~ m/STATION_LONG:/) ) { die "Couldn't get STATION_LONG from Xastir config file\n"; } chomp $my_lat; chomp $my_lon; $my_lat =~ s/STATION_LAT://; $my_lon =~ s/STATION_LONG://; $my_lat =~ s/(\d+\.\d\d)\d(.)/$1$2/; $my_lon =~ s/(\d+\.\d\d)\d(.)/$1$2/; #print "$my_lat $my_lon\n"; $udp_client = "xastir_udp_client"; $dump1090_host = "localhost"; # Server where dump1090 is running $dump1090_port = 30003; # 30003 is dump1090 default port $xastir_host = "localhost"; # Server where Xastir is running $xastir_port = 2023; # 2023 is Xastir default UDP port $plane_TTL = 1; # Secs after which posits too old to create APRS packets from $log_file = "~/.xastir/logs/planes.log"; $xastir_user = shift; if (defined($xastir_user)) { chomp $xastir_user; } if ( (!defined($xastir_user)) || ($xastir_user eq "") ) { print "Please enter a callsign for Xastir injection, but not Xastir's callsign/SSID!\n"; die; } $xastir_user =~ tr/a-z/A-Z/; $xastir_pass = shift; if (defined($xastir_pass)) { chomp $xastir_pass; } if ( (!defined($xastir_pass)) || ($xastir_pass eq "") ) { print "Please enter a passcode for Xastir injection\n"; die; } $enable_circles = 0; $enable_logging = 0; $flag1 = shift; if (defined($flag1)) { chomp $flag1; if ( ($flag1 ne "") && ($flag1 eq "--circles") ) { $enable_circles = 1; } if ( ($flag1 ne "") && ($flag1 eq "--logging") ) { $enable_logging = 1; } } $flag2 = shift; if (defined($flag2)) { chomp $flag2; if ( ($flag2 ne "") && ($flag2 eq "--circles") ) { $enable_circles = 1; } if ( ($flag2 ne "") && ($flag2 eq "--logging") ) { $enable_logging = 1; } } # Connect to the server using a tcp socket # $socket = IO::Socket::INET->new(PeerAddr => $dump1090_host, PeerPort => $dump1090_port, Proto => "tcp", Type => SOCK_STREAM) or die "Couldn't connect to $dump1090_host:$dump1090_port : $@\n"; # Flush output buffers often select((select(STDOUT), $| = 1)[0]); # Check Xastir's callsign/SSID to make sure we don't have a collision. This # will prevent Xastir adopting the Items as its own and retransmitting them. # xastir_udp_client localhost 2023 -identify # Received: WE7U-13 # $injection_call = $xastir_user; $injection_call =~ s/-\d+//; # Get rid of dash and numbers $injection_ssid = $xastir_user; $injection_ssid =~ s/\w+//; # Get rid of letters $injection_ssid =~ s/-//; # Get rid of dash if ($injection_ssid eq "") { $injection_ssid = 0; } # Find out Callsign/SSID of Xastir instance $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass -identify`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } ($remote_call, $remote_ssid) = split('-', $result); chomp($remote_call); $remote_call =~ s/Received:\s+//; if ( !defined($remote_ssid) ) { $remote_ssid = ""; } if ($remote_ssid ne "") { chomp($remote_ssid); } if ($remote_ssid eq "") { $remote_ssid = 0; } #print "$remote_call $remote_ssid $injection_call $injection_ssid\n"; #if ($remote_call eq $injection_call) { print "Call matches\n"; } #if ($remote_ssid == $injection_ssid) { print "SSID matches\n"; } if ( ($remote_call eq $injection_call) && ($remote_ssid == $injection_ssid) ) { $remote_ssid++; $remote_ssid%= 16; # Increment by 1 mod 16 $xastir_user = "$remote_call-$remote_ssid"; print "Injection conflict. Corrected. New user = $xastir_user\n"; } while (<$socket>) { # For testing: # #$_ = "MSG,3,,,A0CF8D,,,,,,,28000,,,47.87670,-122.27269,,,0,0,0,0"; #$_ = "MSG,5,,,AD815E,,,,,,,575,,,,,,,,,,"; #$_ = "MSG,4,,,AAB812,,,,,,,,454,312,,,0,,0,0,0,0"; #$_ = "MSG,3,,,ABB2D5,,,,,,,40975,,,47.68648,-122.67834,,,0,0,0,0"; # Lat/long/altitude (ft) #$_ = "MSG,1,,,A2CB32,,,,,,BOE181 ,,,,,,,,0,0,0,0"; # Tail number or flight number #$_ = "MSG,4,,,A0F4F6,,,,,,,,175,152,,,-1152,,0,0,0,0"; # Ground speed (knots)/Track chomp; if ( $_ eq "" ) { next; } # Sentences have either 10 or 22 fields, assuming they aren't cut off / collided with. @fields = split(","); # Check whether we have a sentence type, message type, and plane ID. If not we're done with this loop iteration if ( (!defined($fields[0])) || (!defined($fields[1])) || (!defined($fields[4])) || ($fields[4] eq "") ) { next; } $plane_id = $fields[4]; $print1 = $plane_id; # Decode the country of registration via this webpage: # http://www.kloth.net/radio/icao24alloc.php # Add it to the APRS comment field. Remove the Tactical call # from the comment field since it is redundant. # Match on more specific first (longer string). # # NOTE: The above link has the countries arranged alphabetically. # The code below is arranged in this order (because of the order # in which they must be decoded): # # 1024 addresses (14 bits defined) # 4096 addresses (12 bits defined) # 32768 addresses (9 bits defined) # 262144 addresses (6 bits defined) # 1048576 addresses (4 bits defined) # # The code below is basically the 1024 column from the chart in # alphabetical order, then the 2nd column, and so on. The chart # should be reviewed against the code periodically, perhaps yearly. # You'll see longer bits decoded here and there prior to the normal # bit lengths in each section, for instance "Azerbaijan Military" # just prior to the "Azerbaijan" entry in the 14-bit address section. # $registry = "Registry?"; # Convert $plane_id to binary string $binary_plane_id = unpack ('B*', pack ('H*',$plane_id) ); # NOTE: In the code below, more specific addresses (more bits) should # appear prior to less specific. The code will snag the first match. # # 4-bit addresses (column "1048576" in the table): # ------------------------------------------------ if ($binary_plane_id =~ m/^0001/) { $registry = "Russia"; } # Russian Federation elsif ($binary_plane_id =~ m/^1010/) { $registry = "U.S."; # United States if ($binary_plane_id =~ m/^1010111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^1010110111111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^1010110111110111111/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^10101101111101111101/) { $registry = "U.S. Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^101011011111011111001/) { $registry = "U.S. Military"; } # Per Countries.dat file } # # 6-bit addresses (column "262144" in the table): # ----------------------------------------------- elsif ($binary_plane_id =~ m/^111000/) { $registry = "Argentina"; if ($binary_plane_id =~ m/^111000010100110000110001/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110000110010/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110000110011/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111000010100110001110000/) { $registry = "Argentina Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011111/) { $registry = "Australia"; if ($binary_plane_id =~ m/^0111111/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011111001001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110010001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111110010000011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000101/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011111001000001001/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000100011/) { $registry = "Australia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01111100100000100010111/) { $registry = "Australia Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^111001/) { $registry = "Brazil"; if ($binary_plane_id =~ m/^11100100000/) { $registry = "Brazil Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^111001001000100110111001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001000111110111111110/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001000111111001000000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000000111110110/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000000111110111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110111010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110111011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100101101010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001011000010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001011000011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010001000011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010001000100/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111100111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111101000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000010111101001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100011111/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100100000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000100100100001/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101000/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101010/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111001001000001110101011/) { $registry = "Brazil Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^110000/) { $registry = "Canada"; if ($binary_plane_id =~ m/^1100001/) { $registry = "Canada Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011110/) { $registry = "China"; if ($binary_plane_id =~ m/^0111100000000001000/) { $registry = "China"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111100000000001/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001000/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000101000/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111100000001010010/) { $registry = "China Hong Kong"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001100111/) { $registry = "China Macau"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011110000000001101000/) { $registry = "China Macau"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^001110/) { $registry = "France"; if ($binary_plane_id =~ m/^00111011/) { $registry = "France Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^001110101/) { $registry = "France Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^001110000000001001011011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000000110100011011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001111001111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001110000111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001111000111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000001101110111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^001110000000110100111011/) { $registry = "France Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001111/) { $registry = "Germany"; if ($binary_plane_id =~ m/^0011111010/) { $registry = "Germany Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0011111101/) { $registry = "Germany Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0011111110/) { $registry = "Germany Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100000/) { $registry = "India"; if ($binary_plane_id =~ m/^1000000000000010/) { $registry = "India Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^100000000000001100001101/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000001111000/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000001111001/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000000000000011010110/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100000011110000011100011/) { $registry = "India Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001100/) { $registry = "Italy"; if ($binary_plane_id =~ m/^0011001111111111/) { $registry = "Italy Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100001/) { $registry = "Japan"; if ($binary_plane_id =~ m/^100001111100110000001010/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100000000000000/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100000000000001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000000001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001011/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001000/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100001111100110000001001/) { $registry = "Japan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^001101/) { $registry = "Spain"; if ($binary_plane_id =~ m/^0011011/) { $registry = "Spain Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00110100/) { $registry = "Spain Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010000/) { $registry = "U.K."; # United Kingdom if ($binary_plane_id =~ m/^010000100100010110111010/) { $registry = "Montserrat"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110100/) { $registry = "Falkland Is."; } # Per Countries.dat file specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110101/) { $registry = "Falkland Is."; } # Per Countries.dat file specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110110/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000100100000111110111/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000111011111001011011/) { $registry = "Falkland Is."; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111101/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111110/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010000000000110111111111/) { $registry = "U.K. Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^01000011111100101100111/) { $registry = "U.K. Jersey"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000011111001110001011/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001001101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001001100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100000000000000100010/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000011010/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000010000/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110011100011/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100000100111/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100100011011/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000010010/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000100011/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010000010011/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000010010010100000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000001100/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001110111110100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111100111001/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001100/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001110/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000001000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000010100/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000110000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001001000111/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110011101/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100000101/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000100100001001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000110/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000001/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000111/) { $registry = "Cayman Islands"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000000000000000/) { $registry = "U.K. MoD"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000011111001111/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000000000000010/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111101010/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000000/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001000101/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001001001001/) { $registry = "Bermuda"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010000111110100/) { $registry = "Isle of Man"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111101/) { $registry = "U.K. Guernsey"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100001111/) { $registry = "U.K. Military"; } # Per Countries.dat file } # # 9-bit addresses (column "32768" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^000010100/) { $registry = "Algeria"; if ($binary_plane_id =~ m/^000010100100/) { $registry = "Algeria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001000/) { $registry = "Austria"; if ($binary_plane_id =~ m/^0100010001/) { $registry = "Austria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001001/) { $registry = "Belgium"; if ($binary_plane_id =~ m/^010001001111/) { $registry = "Belgium Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001001100000111100001/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100101/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100111/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111101000/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100011/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001100000111100100/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000001/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000010/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001001110110110000011/) { $registry = "Belgium Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001010/) { $registry = "Bulgaria"; if ($binary_plane_id =~ m/^010001010111/) { $registry = "Bulgaria Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010010011/) { $registry = "Czech"; # Czech Republic if ($binary_plane_id =~ m/^0100100110000100/) { $registry = "Czech Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011100100/) { $registry = "North Korea"; } # Democratic People's Republic of Korea elsif ($binary_plane_id =~ m/^010001011/) { $registry = "Denmark"; if ($binary_plane_id =~ m/^0100010111110100/) { $registry = "Denmark Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^000000010/) { $registry = "Egypt"; if ($binary_plane_id =~ m/^00000001000000000111/) { $registry = "Egypt Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00000001000000001000/) { $registry = "Egypt Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000010000000100101100/) { $registry = "Egypt Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001100/) { $registry = "Finland"; if ($binary_plane_id =~ m/^0100011001111000/) { $registry = "Finland Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010001101/) { $registry = "Greece"; if ($binary_plane_id =~ m/^01000110100000/) { $registry = "Greece Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000110111101011001001/) { $registry = "Greece Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001101010000010010001/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001101010000010010011/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001101010000010010101/) { $registry = "Greece Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001110/) { $registry = "Hungary"; if ($binary_plane_id =~ m/^01000111001111/) { $registry = "Hungary Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111011111111111/) { $registry = "Hungary Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^100010100/) { $registry = "Indonesia"; if ($binary_plane_id =~ m/^100010100010100100000001/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100010100100000010/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100000000000100100/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010100000000000101001/) { $registry = "Indonesia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100110/) { $registry = "Iran"; # Iran, Islamic Republic of if ($binary_plane_id =~ m/^011100110100110100011110/) { $registry = "Iran Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100101/) { $registry = "Iraq"; if ($binary_plane_id =~ m/^011100101000000111111/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111001010000010000000/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01110010100000011111011/) { $registry = "Iraq Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100101000000111110101/) { $registry = "Iraq Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100111/) { $registry = "Israel"; if ($binary_plane_id =~ m/^0111001110001010/) { $registry = "Israel Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101000/) { $registry = "Jordan"; } elsif ($binary_plane_id =~ m/^011101001/) { $registry = "Lebanon"; } elsif ($binary_plane_id =~ m/^000000011/) { $registry = "Libya"; # Libyan Arab Jamahiriya if ($binary_plane_id =~ m/^000000011000001111101011/) { $registry = "Libya Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011101010/) { $registry = "Malaysia"; if ($binary_plane_id =~ m/^011101010000000101010110/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011010100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000001100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000001111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100100/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100110/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000000100111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000010111101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011000101/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101010000000011010111/) { $registry = "Malaysia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000011010/) { $registry = "Mexico"; if ($binary_plane_id =~ m/^000011010000011000010101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010011000010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000110111010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010101000110/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000010101000111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000000011011/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000000111111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000001010111001/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000001000101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000000001011010/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000011001001111/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011010000011001001101/) { $registry = "Mexico Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000100/) { $registry = "Morocco"; if ($binary_plane_id =~ m/^00000010000000001011/) { $registry = "Morocco Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000100000000011000/) { $registry = "Morocco Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^000000100000000001011101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001011110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100010/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010100101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000010101100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001000110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001101/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001001110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000110001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000110111/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111000/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111010/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111011/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000000111110/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000001000001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000011001001/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000100000000011001100/) { $registry = "Morocco Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010000/) { $registry = "Netherlands"; # Netherlands, Kingdom of the if ($binary_plane_id =~ m/^010010000000/) { $registry = "Netherlands Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010010000100000010010101/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010010110/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010001001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100001111/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100010001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000100010010/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010001011/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000000/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000001/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010000010/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010100100/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100000010100101/) { $registry = "Netherlands Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010000100/) { $registry = "Aruba"; } # Per Countries.dat file (In Netherlands block) } elsif ($binary_plane_id =~ m/^110010000/) { $registry = "New Zealand"; if ($binary_plane_id =~ m/^1100100001111111/) { $registry = "New Zealand Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^110010000010010100011100/) { $registry = "New Zealand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^110010000010010100011101/) { $registry = "New Zealand Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010001111/) { $registry = "Norway"; if ($binary_plane_id =~ m/^0100011110000001/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0100011110000000111/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111100000001101/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010001111000000011001/) { $registry = "Norway Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^01000111100000001100011/) { $registry = "Norway Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101100/) { $registry = "Pakistan"; if ($binary_plane_id =~ m/^011101100000000011101001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100000000000011001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000000110000/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000011010110/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000011011000/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000000111111/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001001011/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010001/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010010/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001010100/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100001000001011101/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100011100110000111/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010101011110011/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010101111110100/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100000001011110101/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101100010000010011010/) { $registry = "Pakistan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011101011/) { $registry = "Philipines"; } elsif ($binary_plane_id =~ m/^010010001/) { $registry = "Poland"; if ($binary_plane_id =~ m/^0100100011011000/) { $registry = "Poland Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^010010001000000110001110/) { $registry = "Poland Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010010/) { $registry = "Portugal"; if ($binary_plane_id =~ m/^0100100101111100/) { $registry = "Portugal Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011100011/) { $registry = "South Korea"; # Republic of Korea if ($binary_plane_id =~ m/^011100011111101100000001/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111101100000010/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111100100001010/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100011111100100000110/) { $registry = "South Korea Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010100/) { $registry = "Romania"; if ($binary_plane_id =~ m/^010010100011010110101010/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100011010110101011/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100011010110101100/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001011100101010/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001100000010110/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010100001100000101111/) { $registry = "Romania Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100010/) { $registry = "Saudi Arabia"; if ($binary_plane_id =~ m/^0111000100000010011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111000100000010100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^0111000100000011100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100010000001001011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100010000000100001010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000000100001011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100001/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011010101/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011100100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001011111001/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011010/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011011/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011100/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011110/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100010000001001011101/) { $registry = "Saudi Arabia Military"; } # Per Countries.dat file (specific plane) } # Serbia: See Yugoslavia slot elsif ($binary_plane_id =~ m/^011101101/) { $registry = "Singapore"; if ($binary_plane_id =~ m/^011101101110001100000011/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000010/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000100/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101110001100000001/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011101101000010011000011/) { $registry = "Singapore Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000001/) { $registry = "South Africa"; } elsif ($binary_plane_id =~ m/^011101110/) { $registry = "Sri Lanka"; } elsif ($binary_plane_id =~ m/^010010101/) { $registry = "Sweden"; if ($binary_plane_id =~ m/^010010101000000110000001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000011/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000101/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000110/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110000111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110001000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111100110/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000100010100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000011111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000000111/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110011/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110100/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111110101/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000011010000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111111001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000111111000/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000000110011001/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010010101000001000101010/) { $registry = "Sweden Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^010010110/) { $registry = "Switzerland"; if ($binary_plane_id =~ m/^010010110111/) { $registry = "Switzerland Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^011101111/) { $registry = "Syria"; } # Syrian Arab Republic elsif ($binary_plane_id =~ m/^100010000/) { $registry = "Thailand"; if ($binary_plane_id =~ m/^100010000101001100110011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000010001001001000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110100011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110110000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010000000001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000011101011000001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000000100111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000000101100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110100111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101000/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101101/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101110/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000010110101111/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000000001001001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000101001100110010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100001/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100010/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100011/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000001110001100100/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010000000110110110110/) { $registry = "Thailand Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000000101/) { $registry = "Tunisia"; } elsif ($binary_plane_id =~ m/^010010111/) { $registry = "Turkey"; if ($binary_plane_id =~ m/^0100101110000010/) { $registry = "Turkey Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^010100001/) { $registry = "Ukraine"; } elsif ($binary_plane_id =~ m/^000011011/) { $registry = "Venezuela"; if ($binary_plane_id =~ m/^000011011000000000110010/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011011000000001100000/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000011011000000001101100/) { $registry = "Venezuela Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010001/) { $registry = "Viet Nam"; } elsif ($binary_plane_id =~ m/^010011000/) { $registry = "Serbia"; # Was Yugoslavia if ($binary_plane_id =~ m/^010011000000000101010101/) { $registry = "Serbia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^111100000/) { $registry = "ICAO(1) Temp. Address"; } # # 12-bit addresses (column "4096" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^011100000000/) { $registry = "Afghanistan"; } elsif ($binary_plane_id =~ m/^000010010000/) { $registry = "Angola"; } elsif ($binary_plane_id =~ m/^000010101000/) { $registry = "Bahamas"; if ($binary_plane_id =~ m/^000010101000000000100001/) { $registry = "Bahamas Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010010100/) { $registry = "Bahrain"; if ($binary_plane_id =~ m/^100010010100000000010001/) { $registry = "Bahrain Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010100000000010110/) { $registry = "Bahrain Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^011100000010/) { $registry = "Bangladesh"; if ($binary_plane_id =~ m/^011100000010110000000010/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100000010110000000011/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100000010110000000100/) { $registry = "Bangladesh Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^111010010100/) { $registry = "Bolivia"; if ($binary_plane_id =~ m/^111010010100000011111010/) { $registry = "Bolivia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111010010100000100000100/) { $registry = "Bolivia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010011100/) { $registry = "Burkina Faso"; } elsif ($binary_plane_id =~ m/^000000110010/) { $registry = "Burundi"; } elsif ($binary_plane_id =~ m/^011100001110/) { $registry = "Cambodia"; } elsif ($binary_plane_id =~ m/^000000110100/) { $registry = "Cameroon"; if ($binary_plane_id =~ m/^000000110100010001000011/) { $registry = "Cameroon Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000110100010001000101/) { $registry = "Cameroon Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000001101100/) { $registry = "Central African Rep."; } # Central African Republic elsif ($binary_plane_id =~ m/^000010000100/) { $registry = "Chad"; } elsif ($binary_plane_id =~ m/^111010000000/) { $registry = "Chile"; if ($binary_plane_id =~ m/^1110100000000110/) { $registry = "Chile Military"; } # Per Countries.dat file } elsif ($binary_plane_id =~ m/^000010101100/) { $registry = "Colombia"; if ($binary_plane_id =~ m/^000010101100000000000101/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000000111011/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001100110/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001100111/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000001110001/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000100001100/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000010101100000000110110/) { $registry = "Columbia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010001100/) { $registry = "Congo DRC"; } # Democratic Republic of the Congo elsif ($binary_plane_id =~ m/^000000110110/) { $registry = "Congo ROC"; } elsif ($binary_plane_id =~ m/^000010101110/) { $registry = "Costa Rica"; } elsif ($binary_plane_id =~ m/^000000111000/) { $registry = "Cote d Ivoire"; } elsif ($binary_plane_id =~ m/^000010110000/) { $registry = "Cuba"; } elsif ($binary_plane_id =~ m/^000011000100/) { $registry = "Dominican Republic"; } elsif ($binary_plane_id =~ m/^111010000100/) { $registry = "Ecuador"; if ($binary_plane_id =~ m/^111010000100000000110101/) { $registry = "Ecuador Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^111010000100000000110000/) { $registry = "Ecuador Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010110010/) { $registry = "El Salvador"; } elsif ($binary_plane_id =~ m/^000001000010/) { $registry = "Equatorial Guinea"; } elsif ($binary_plane_id =~ m/^000001000000/) { $registry = "Ethiopia"; } elsif ($binary_plane_id =~ m/^110010001000/) { $registry = "Fiji"; } elsif ($binary_plane_id =~ m/^000000111110/) { $registry = "Gabon"; } elsif ($binary_plane_id =~ m/^000010011010/) { $registry = "Gambia"; } elsif ($binary_plane_id =~ m/^000001000100/) { $registry = "Ghana"; } elsif ($binary_plane_id =~ m/^000010110100/) { $registry = "Guatemala"; } elsif ($binary_plane_id =~ m/^000001000110/) { $registry = "Guinea"; } elsif ($binary_plane_id =~ m/^000010110110/) { $registry = "Guyana"; } elsif ($binary_plane_id =~ m/^000010111000/) { $registry = "Haiti"; } elsif ($binary_plane_id =~ m/^000010111010/) { $registry = "Honduras"; } elsif ($binary_plane_id =~ m/^010011001100/) { $registry = "Iceland"; } elsif ($binary_plane_id =~ m/^010011001010/) { $registry = "Ireland"; if ($binary_plane_id =~ m/^010011001010000000100011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000100111110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000100111111/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000101011000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001000000100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111100111/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101001/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101101/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010000111101110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001010001100/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001010001011/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100011010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100011110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110000/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110001/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110010/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110101/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010011001010001100110110/) { $registry = "Ireland Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010111110/) { $registry = "Jamaica"; } elsif ($binary_plane_id =~ m/^000001001100/) { $registry = "Kenya"; } elsif ($binary_plane_id =~ m/^011100000110/) { $registry = "Kuwait"; } elsif ($binary_plane_id =~ m/^011100001000/) { $registry = "Laos"; } # Lao People's Democratic Republic elsif ($binary_plane_id =~ m/^000001010000/) { $registry = "Liberia"; } elsif ($binary_plane_id =~ m/^000001010100/) { $registry = "Madagascar"; } elsif ($binary_plane_id =~ m/^000001011000/) { $registry = "Malawi"; } elsif ($binary_plane_id =~ m/^000001011100/) { $registry = "Mali"; } elsif ($binary_plane_id =~ m/^000000000110/) { $registry = "Mozambique"; } elsif ($binary_plane_id =~ m/^011100000100/) { $registry = "Myanmar"; } elsif ($binary_plane_id =~ m/^011100001010/) { $registry = "Nepal"; } elsif ($binary_plane_id =~ m/^000011000000/) { $registry = "Nicaragua"; } elsif ($binary_plane_id =~ m/^000001100010/) { $registry = "Niger"; } elsif ($binary_plane_id =~ m/^000001100100/) { $registry = "Nigeria"; if ($binary_plane_id =~ m/^000001100100000001010001/) { $registry = "Nigeria Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001100100000011110000/) { $registry = "Nigeria Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000011000010/) { $registry = "Panama"; if ($binary_plane_id =~ m/^000011000010000001001110/) { $registry = "Panama Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^100010011000/) { $registry = "Papua New Guinea"; } elsif ($binary_plane_id =~ m/^111010001000/) { $registry = "Paraguay"; } elsif ($binary_plane_id =~ m/^111010001100/) { $registry = "Peru"; if ($binary_plane_id =~ m/^111010001100000000000111/) { $registry = "Peru Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000001101110/) { $registry = "Rwanda"; } elsif ($binary_plane_id =~ m/^000001110000/) { $registry = "Senegal"; } elsif ($binary_plane_id =~ m/^000001111000/) { $registry = "Somalia"; } elsif ($binary_plane_id =~ m/^000001111100/) { $registry = "Sudan"; } elsif ($binary_plane_id =~ m/^000011001000/) { $registry = "Suriname"; } elsif ($binary_plane_id =~ m/^000010001000/) { $registry = "Togo"; } elsif ($binary_plane_id =~ m/^000011000110/) { $registry = "Trinidad and Tobago"; } elsif ($binary_plane_id =~ m/^000001101000/) { $registry = "Uganda"; } elsif ($binary_plane_id =~ m/^100010010110/) { $registry = "United Arab Emirates"; if ($binary_plane_id =~ m/^100010010110110000/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^100010010110000100100110/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101001/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101010/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101011/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101110/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^100010010110000000101100/) { $registry = "United Arab Emirates Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^000010000000/) { $registry = "Tanzania"; } # United Republic of Tanzania elsif ($binary_plane_id =~ m/^111010010000/) { $registry = "Uruguay"; } elsif ($binary_plane_id =~ m/^100010010000/) { $registry = "Yemen"; } elsif ($binary_plane_id =~ m/^000010001010/) { $registry = "Zambia"; } # 14-bit addresses (column "1024" in the table): # ---------------------------------------------- elsif ($binary_plane_id =~ m/^01010000000100/) { $registry = "Albania"; } elsif ($binary_plane_id =~ m/^00001100101000/) { $registry = "Antigua and Barbuda"; } elsif ($binary_plane_id =~ m/^01100000000000/) { $registry = "Armenia"; } elsif ($binary_plane_id =~ m/^01100000000010/) { $registry = "Azerbaijan"; if ($binary_plane_id =~ m/^011000000000100000000001/) { $registry = "Azerbaijan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^00001010101000/) { $registry = "Barbados"; } elsif ($binary_plane_id =~ m/^01010001000000/) { $registry = "Belarus"; } elsif ($binary_plane_id =~ m/^00001010101100/) { $registry = "Belize"; } elsif ($binary_plane_id =~ m/^00001001010000/) { $registry = "Benin"; } elsif ($binary_plane_id =~ m/^01101000000000/) { $registry = "Bhutan"; } elsif ($binary_plane_id =~ m/^01010001001100/) { $registry = "Bosnia and Herzegovina"; } elsif ($binary_plane_id =~ m/^00000011000000/) { $registry = "Botswana"; if ($binary_plane_id =~ m/^000000110000000000010010/) { $registry = "Botswana Military" } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000000110000000000011010/) { $registry = "Botswana Military" } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001010100/) { $registry = "Brunei Darussalam"; } elsif ($binary_plane_id =~ m/^00001001011000/) { $registry = "Cape Verde"; } elsif ($binary_plane_id =~ m/^00000011010100/) { $registry = "Comoros"; } elsif ($binary_plane_id =~ m/^10010000000100/) { $registry = "Cook Islands"; } elsif ($binary_plane_id =~ m/^01010000000111/) { $registry = "Croatia"; if ($binary_plane_id =~ m/^010100000001110100010011/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000001111110000101/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000001111110000110/) { $registry = "Croatia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01001100100000/) { $registry = "Cyprus"; } elsif ($binary_plane_id =~ m/^00001001100000/) { $registry = "Djibouti"; } elsif ($binary_plane_id =~ m/^00100000001000/) { $registry = "Eritrea"; } elsif ($binary_plane_id =~ m/^01010001000100/) { $registry = "Estonia"; } elsif ($binary_plane_id =~ m/^01010001010000/) { $registry = "Georgia"; } elsif ($binary_plane_id =~ m/^00001100110000/) { $registry = "Grenada"; } elsif ($binary_plane_id =~ m/^00000100100000/) { $registry = "Guinea-Bissau"; } elsif ($binary_plane_id =~ m/^01101000001100/) { $registry = "Kazakhstan"; } elsif ($binary_plane_id =~ m/^11001000111000/) { $registry = "Kiribati"; } elsif ($binary_plane_id =~ m/^01100000000100/) { $registry = "Kyrgyzstan"; } elsif ($binary_plane_id =~ m/^01010000001011/) { $registry = "Latvia"; } elsif ($binary_plane_id =~ m/^00000100101000/) { $registry = "Lesotho"; } elsif ($binary_plane_id =~ m/^01010000001111/) { $registry = "Lithuania"; if ($binary_plane_id =~ m/^010100000011111111010010/) { $registry = "Lithuania Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000011111111010011/) { $registry = "Lithuania Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01001101000000/) { $registry = "Luxembourg"; if ($binary_plane_id =~ m/^0100110100000011110/) { $registry = "NATO"; } # Per Countries.dat file (In Luxembourg block) } # Also see NATO in the Luxembourg block above elsif ($binary_plane_id =~ m/^010001110111111111110001/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001110111111111110010/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010001110111111111110011/) { $registry = "NATO Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^00000101101000/) { $registry = "Maldives"; } elsif ($binary_plane_id =~ m/^01001101001000/) { $registry = "Malta"; if ($binary_plane_id =~ m/^010011010010000001011000/) { $registry = "Malta Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10010000000000/) { $registry = "Marshall Islands"; } elsif ($binary_plane_id =~ m/^00000101111000/) { $registry = "Mauritania"; } elsif ($binary_plane_id =~ m/^00000110000000/) { $registry = "Mauritius"; } elsif ($binary_plane_id =~ m/^01101000000100/) { $registry = "Micronesia"; } # Micronesia, Federated States of elsif ($binary_plane_id =~ m/^01001101010000/) { $registry = "Monaco"; } elsif ($binary_plane_id =~ m/^01101000001000/) { $registry = "Mongolia"; } elsif ($binary_plane_id =~ m/^01010001011000/) { $registry = "Montenegro"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^00100000000100/) { $registry = "Namibia"; } elsif ($binary_plane_id =~ m/^11001000101000/) { $registry = "Nauru"; } elsif ($binary_plane_id =~ m/^01110000110000/) { $registry = "Oman"; if ($binary_plane_id =~ m/^01110000110000000111/) { $registry = "Oman Military"; } # Per Countries.dat file elsif ($binary_plane_id =~ m/^011100001100000010001100/) { $registry = "Oman Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^011100001100000010001011/) { $registry = "Oman Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01101000010000/) { $registry = "Palau"; } elsif ($binary_plane_id =~ m/^00000110101000/) { $registry = "Qatar"; if ($binary_plane_id =~ m/^000001101010001001001010/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001011/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001100/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001101/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010000011011001/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010000011011010/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001000/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001001001/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001010101/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^000001101010001001010110/) { $registry = "Qatar Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000010011/) { $registry = "Moldova"; } # Republic of Moldova elsif ($binary_plane_id =~ m/^11001000110000/) { $registry = "Saint Lucia"; } elsif ($binary_plane_id =~ m/^00001011110000/) { $registry = "Saint Vincent and the Grenadines"; } elsif ($binary_plane_id =~ m/^10010000001000/) { $registry = "Samoa"; } elsif ($binary_plane_id =~ m/^01010000000000/) { $registry = "San Marino"; } elsif ($binary_plane_id =~ m/^00001001111000/) { $registry = "Sao Tome and Principe"; } elsif ($binary_plane_id =~ m/^00000111010000/) { $registry = "Seychelles"; } elsif ($binary_plane_id =~ m/^00000111011000/) { $registry = "Sierra Leone"; } elsif ($binary_plane_id =~ m/^01010000010111/) { $registry = "Slovakia"; if ($binary_plane_id =~ m/^010100000101111101101100/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100011/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100001/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101100010/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101101010/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) elsif ($binary_plane_id =~ m/^010100000101111101101000/) { $registry = "Slovakia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000011011/) { $registry = "Slovenia"; if ($binary_plane_id =~ m/^0101000001101111/) { $registry = "Slovenia Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001011100/) { $registry = "Solomon Islands"; } elsif ($binary_plane_id =~ m/^00000111101000/) { $registry = "Swaziland"; } elsif ($binary_plane_id =~ m/^01010001010100/) { $registry = "Tajikistan"; } elsif ($binary_plane_id =~ m/^01010001001000/) { $registry = "Macedonia"; } # The former Yugoslav Republic of Macedonia elsif ($binary_plane_id =~ m/^11001000110100/) { $registry = "Tonga"; } elsif ($binary_plane_id =~ m/^01100000000110/) { $registry = "Turkmenistan"; if ($binary_plane_id =~ m/^011000000001100001100010/) { $registry = "Turkmenistan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^01010000011111/) { $registry = "Uzbekistan"; } elsif ($binary_plane_id =~ m/^11001001000000/) { $registry = "Vanuatu"; } elsif ($binary_plane_id =~ m/^00000000010000/) { $registry = "Zimbabwe"; } elsif ($binary_plane_id =~ m/^10001001100100/) { $registry = "Taiwan"; # Per Countries.dat file (In ICAO(2) Flight Safety block below) if ($binary_plane_id =~ m/^100010011001000101100000/) { $registry = "Taiwan Military"; } # Per Countries.dat file (specific plane) } elsif ($binary_plane_id =~ m/^10001001100100/) { $registry = "ICAO(2) Flight Safety"; } elsif ($binary_plane_id =~ m/^11110000100100/) { $registry = "ICAO(2) Flight Safety"; } # NOTE: ICAO blocks are different in Countries.dat file # # Blocks of addresses for anything that hasn't matched so far, from : # ------------------------------------------------------------ elsif ($binary_plane_id =~ m/^00100/) { $registry = "Africa Region"; } # AFI Region elsif ($binary_plane_id =~ m/^00101/) { $registry = "South America Region"; } # SAM Region elsif ($binary_plane_id =~ m/^0101/) { $registry = "Europe/North Atlantic Regions"; } # EUR and NAT Regions elsif ($binary_plane_id =~ m/^01100/) { $registry = "Middle East Region"; } # MID Region elsif ($binary_plane_id =~ m/^01101/) { $registry = "Asia Region"; } # ASIA Region elsif ($binary_plane_id =~ m/^1001/) { $registry = "North America/Pacific Regions"; } # NAM and PAC Regions elsif ($binary_plane_id =~ m/^111011/) { $registry = "Carribean Region"; } # CAR Region elsif ($binary_plane_id =~ m/^1011/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^1101/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^1111/) { $registry = "Country Code RESERVED"; } # Reserved for future use elsif ($binary_plane_id =~ m/^000000000000000000000000/) { $registry = "Country Code DISALLOWED"; } # Shall not be assigned elsif ($binary_plane_id =~ m/^111111111111111111111111/) { $registry = "Country Code DISALLOWED"; } # Shall not be assigned # Parse altitude if MSG Type 2, 3, 5, 6, or 7, save in hash. $print2 = " "; if ( $fields[1] == 2 || $fields[1] == 3 || $fields[1] == 5 || $fields[1] == 6 || $fields[1] == 7 ) { if ( defined($fields[11]) && $fields[11] ne "" && $fields[11] ne 0 ) { $old = ""; if (defined($altitude{$plane_id})) { $old = $altitude{$plane_id}; } # Save new altitude $altitude{$plane_id} = sprintf("%06d", $fields[11]); if ($old ne $altitude{$plane_id}) { $print2 = sprintf("%5sft", $fields[11]); $newdata{$plane_id}++; # Found a new altitude! } } } # Parse ground speed and track if MSG Type 2 or 4, save in hash. $print3 = " "; $print4 = " "; if ( $fields[1] == 4 || $fields[1] == 2 ) { if ( defined($fields[12]) && $fields[12] ne "" ) { $old = ""; if (defined($groundspeed{$plane_id})) { $old = $groundspeed{$plane_id}; } # Save new ground speed $groundspeed{$plane_id} = $fields[12]; if ($old ne $groundspeed{$plane_id}) { $print3 = sprintf("%3skn", $fields[12]); $newdata{$plane_id}++; # Found a new ground speed! } } if ( defined($fields[13]) && $fields[13] ne "" ) { $old = ""; if (defined($track{$plane_id})) { $old = $track{$plane_id}; } # Save new track $track{$plane_id} = $fields[13]; if ($old ne $track{$plane_id}) { $print4 = sprintf("%3s", $fields[13]); $newdata{$plane_id}++; # Found a new track! } } } # Parse lat/long if MSG Type 2 or 3, save in hash. $print5 = " "; if ( ( $fields[1] == 2 || $fields[1] == 3 ) && defined($fields[14]) && $fields[14] ne "" && defined($fields[15]) && $fields[15] ne "" ) { $oldlat = ""; if (defined($lat{$plane_id})) { $oldlat = $lat{$plane_id}; } $lat = $fields[14] * 1.0; if ($lat >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $lat = abs($lat); } $latdeg = int($lat); $latmins = $lat - $latdeg; $latmins2 = $latmins * 60.0; # Save new latitude $lat{$plane_id} = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); $oldlon = ""; if (defined($lon{$plane_id})) { $oldlon = $lon{$plane_id}; } $lon = $fields[15] * 1.0; if ($lon >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $lon = abs($lon); } $londeg = int($lon); $lonmins = $lon - $londeg; $lonmins2 = $lonmins * 60.0; # Save new longitude $lon{$plane_id} = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); if ( ($oldlat ne $lat{$plane_id}) || ($oldlon ne $lon{$plane_id}) ) { $print5 = sprintf("%8s,%9s", $lat{$plane_id},$lon{$plane_id}); # Save most recent posit time $last_posit_time{$plane_id} = time(); $newdata{$plane_id}++; # Found a new lat/lon! # Tactical callsign: # Have new lat/lon. Check whether we have a tactical call # already defined. If not, assign one that includes # the plane_id and the country of registration. if ( !defined($tactical{$plane_id}) ) { # Assign tactical call = $plane_id + registry # Max tactical call in Xastir is 57 chars (56 + terminator?) # $tactical{$plane_id} = $plane_id . " (" . $registry . ")"; $tactical{$plane_id} =~ s/\s+/ /g; # Change multiple spaces to one $aprs = $xastir_user . '>' . "APRS::TACTICAL :" . $plane_id . "=" . $tactical{$plane_id}; $print6 = sprintf("%-18s", $tactical{$plane_id}); print("$print1 $print2 $print3 $print4 $print6 $aprs\n"); # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } } # Save tail or flight number in hash if MSG Type 1 or "ID" sentence. if ( ($fields[0] eq "ID" || $fields[1] == 1) && defined($fields[10]) && $fields[10] ne "????????" && $fields[10] ne "" && !($fields[10] =~ m/^\s+$/) ) { $old = ""; if (defined($tail{$plane_id})) { $old = $tail{$plane_id}; } # Save new tail number or flight number, assign tactical call $temp_tail = $fields[10]; $temp_tail =~ s/[^a-zA-Z0-9,]//g; # Filter out all but alphanumeric chars $tail{$plane_id} = $temp_tail; $tail{$plane_id} =~ s/\s//g; # Remove spaces if ($old ne $tail{$plane_id}) { $print6 = sprintf("%-18s", $temp_tail); $newdata{$plane_id}++; # Found a new tail or flight number! # Assign tactical call = tail number or flight number + registry (if defined) # Max tactical call in Xastir is 57 chars (56 + terminator?) # $tactical{$plane_id} = $temp_tail; if ($registry ne "Registry?") { $tactical{$plane_id} = $temp_tail . " (" . $registry . ")"; $tactical{$plane_id} =~ s/\s+/ /g; # Change multiple spaces to one } $aprs = $xastir_user . '>' . "APRS::TACTICAL :" . $plane_id . "=" . $tactical{$plane_id}; print("$print1 $print2 $print3 $print4 $print6 $aprs\n"); # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } $squawk_txt = ""; if ( defined($fields[17]) && ($fields[17] ne "") ) { $old = ""; if (defined($squawk{$plane_id})) { $old = $squawk{$plane_id}; } $squawk{$plane_id} = $fields[17]; if ($old ne $squawk{$plane_id}) { $newdata{$plane_id}++; # Found a new squawk! } } if (defined($squawk{$plane_id})) { $squawk_txt = sprintf(" SQUAWK=%04d", $squawk{$plane_id}); } $emerg_txt = ""; $emergency = "0"; if ( defined($fields[19]) ) { $emergency = $fields[19]; } if ( $emergency eq "-1" ) { # Emergency of some type $emerg_txt = " EMERGENCY="; # Keyword triggers Xastir's emergency mode!!! # Check squawk code if ( defined($squawk{$plane_id}) ) { if ($squawk{$plane_id} eq "7500") { # Unlawful Interference (hijacking) $emerg_txt = $emerg_txt . "Hijacking"; } if ($squawk{$plane_id} eq "7600") { # Communications failure/problems $emerg_txt = $emerg_txt . "Comms_Failure"; } if ($squawk{$plane_id} eq "7700") { # General Emergency $emerg_txt = $emerg_txt . "General"; } } $newdata{$plane_id}++; } $onGroundTxt = ""; if ( defined($fields[21]) ) { $onGround = $fields[21]; if ($onGround eq "-1") { $onGroundTxt = " On_Ground"; $newdata{$plane_id}++; } } $newtrack = "360"; if ( defined($track{$plane_id}) ) { if ($track{$plane_id} == 0) { $newtrack = "360"; } else { $newtrack = sprintf("%03d", $track{$plane_id} ); } } $newspeed = "000"; if ( defined ($groundspeed{$plane_id}) ) { $newspeed = sprintf("%03d", $groundspeed{$plane_id} ); if ( ($groundspeed{$plane_id} > 0) && ($groundspeed{$plane_id} < 57) ) { $symbol = "X"; # Switch to helicopter symbol } if ($groundspeed{$plane_id} > 126) { $symbol = "^"; # Switch to large aircraft symbol } } $newtail = ""; if ( defined($tail{$plane_id}) ) { $newtail = " $tail{$plane_id}"; } # Auto-switch the symbol based on speed/altitude. # Symbols: # Small airplane = /' # Helicopter = /X # Large aircraft = /^ # Aircraft = \^ (Not used in this script) # # Cessna 150: 57 knots minimum. # Twin Cessna: 215 knots maximum. # UH-1N Huey: 110 knots maximum. # Landing speed Boeing 757: 126 knots. # # If <= 10000 feet and 1 - 56 knots: Helicopter # If <= 20000 feet and 57 - 125 knots: Small aircraft # If > 20000 feet : Large aircraft # if > 126 knots: Large aircraft # $symbol = "'"; # Start with small aircraft symbol $newalt = ""; if ( defined($altitude{$plane_id}) ) { $newalt = " /A=$altitude{$plane_id}"; if ($altitude{$plane_id} > 20000) { $symbol = "^"; # Switch to large aircraft symbol } elsif ($symbol eq "^") { # Do nothing, already switched to large aircraft due to speed } elsif ($symbol eq "X" && $altitude{$plane_id} > 10000) { $symbol = "'"; # Switch to small aircraft from helicopter } } # Above we parsed some message that changed some of our data, send out the # new APRS string if we have enough data defined. # if ( defined($newdata{$plane_id}) && $newdata{$plane_id} ) { # Count percentage of planes with lat/lon out of total planes that have altitude listed. # This should show an approximate implementation percentage for ADS-B transponders. $alt_planes = 0; $lat_planes = 0; $print_adsb_percentage = ""; foreach $key (keys %lat) { $lat_planes++; } foreach $key (keys %altitude) { $alt_planes++; } if ($alt_planes != 0) { $adsb_percentage = ( ($lat_planes * 1.0) / $alt_planes) * 100.0; $print_adsb_percentage = sprintf("ADS-B:%-1.1f%% ($lat_planes/$alt_planes)", $adsb_percentage); } # Do we have a lat/lon and is it recent enough? if ( defined($lat{$plane_id}) && defined($lon{$plane_id}) ) { # # Yes we have a lat/lon # # Check the age of the lat/lon $age = time() - $last_posit_time{$plane_id}; if ( $age > $plane_TTL ) { # # We have a lat/lon but it is too old # $print_age1 = sprintf("(%s%s)", $age, "s"); $print_age2 = sprintf("%18s", $print_age1); $print_aprs = sprintf("%-96s", "$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"); print("$print1 $print2 $print3 $print4 $print_age2 $print_aprs $print_adsb_percentage\n"); } else { # # We have a recent lat/lon # $aprs="$xastir_user>APRS:)$plane_id!$lat{$plane_id}/$lon{$plane_id}$symbol$newtrack/$newspeed$newalt$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"; $print_aprs = sprintf("%-95s", $aprs); if ( $age > 0 # Lat/lon is aging a bit || $print5 eq " " ) { # Didn't parse lat/lon this time $print_age1 = sprintf("%s%s", $age, "s"); $print_age2 = sprintf("%18s", $print_age1); print("$print1 $print2 $print3 $print4 $print_age2 $print_aprs $print_adsb_percentage\n"); } else { print("$print1 $print2 $print3 $print4 $print5 $print_aprs $print_adsb_percentage\n"); } # xastir_udp_client {-identify | [-to_rf] } # $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs [Pmin0.0,]\"`; $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } else { # # No, we have no lat/lon # $print_age = sprintf("%18s", "-"); $print_aprs = sprintf("%-96s", "$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry)"); print("$print1 $print2 $print3 $print4 $print_age$print_aprs $print_adsb_percentage\n"); if ($enable_circles == 1) { $radius = 10.0; # Set a default of 10 miles if ( defined($altitude{$plane_id}) ) { $radius = ( ( ($altitude{$plane_id} - $my_alt) / 1000 ) * 2 ); # 40k = 80 miles, 20k = 40 miles, 10k = 20 miles, 1k = 2 miles } $print_radius = sprintf("%2.1f", $radius); $aprs="$xastir_user>APRS:)$plane_id!$my_lat/$my_lon$symbol$newtrack/$newspeed$newalt$newtail$emerg_txt$squawk_txt$onGroundTxt ($registry) [Pmin$print_radius,]"; # print "$aprs\n"; # xastir_udp_client {-identify | [-to_rf] } $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } if ($enable_logging == 1) { `echo \"$aprs\" >> $log_file`; } } } # Reset the newdata flag $newdata{$plane_id} = 0; } # Convert altitude to altitude above MSL instead of altitude from a reference barometric reading? # Info: http://forums.flyer.co.uk/viewtopic.php?t=16375 # How many millibar in 1 feet of air? The answer is 0.038640888 @ 0C (25.879232 ft/mb). # How many millibar in 1 foot of air [15 C]? The answer is 0.036622931 @ 15C (27.3053 ft/mb). # Flight Level uses a pressure of 29.92 "Hg (1,013.2 mb). # Yesterday the pressure here was about 1013, so the altitudes looked right on. Today the planes # are reporting ~500' higher via ADS-B when landing at Paine Field. Turns out the pressure today # is 21mb lower, which equates to an additional 573' of altitude reported using the 15C figure! # # /A=aaaaaa feet # CSE/SPD, i.e. 180/999 (speed in knots, direction is WRT true North), if unknown: .../... # )AIDV#2!4903.50N/07201.75WA # ;LEADERVVV*092345z4903.50N/07201.75W>088/036 # )A19E61!4903.50N/07201.75W' 356/426 /A=29275 # Example Small Airplane Object # end of while loop } close($socket); Xastir-Release-2.2.4/scripts/ais.pl0000775000175000017500000026633715151324131016145 0ustar hibbyhibby#!/usr/bin/env perl use warnings; ########################################################################### # # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2026 The Xastir Group # # "ais.pl", a Perl script to connect aisdecoder and Xastir for receiving # packets from ships. This script will create a UDP server at localhost:10110 # for aisdecoder to send packets into. It decodes AIS sentences, creates APRS # packets out of them and sends them to Xastir's server port (2023) via UDP. # # AIS is the international tracking system for ships. They transmit on Marine # VHF frequencies between 156.025 and 162.025, using a low power output of 1W, # high power output of either 5W or 12.5W, at a bit rate of 9600 bits/s using # NRZI data encoding and GMSK/FM at 0.5 modulation index. # # The two default AIS channels are: # Ch 87B, AIS-1: 161.975 MHz # Ch 88B, AIS-2: 162.025 MHz # # The two long-range channels are: # Ch 75: 156.775 MHz # Ch 76: 156.825 MHz # # # You'll need "libusb", "libpthread", "librtlsdr" installed to be able to # compile "rtl_ais". # # Get aisdecoder (rtl-ais). # git clone https://github.com/dgiardini/rtl-ais/ # cd rtl_ais # make # # # Run "rtl_ais" like this (create a simple script!) for the two default channels: # # ./rtl_ais -h 127.0.0.1 -P 10110 -d 0 -l 161.975M -r 162.025M -n -p -2 # # Change to marine channels 75 (156.775 MHz) and 76 (156.825 MHz) to pick # up long-range AIS (Type 27 packets), perhaps with another dongle: # # ./rtl_ais -h 127.0.0.1 -P 10110 -d 1 -l 156.775M -r 156.825M -n -p -2 # # Note that "-p -2" is the frequency error of the RTL dongle. # Set that to the proper number determined from "Kal". # # "-d 0" or "-d 1" selects which dongle you're attaching to. # # Don't use "-g " and instead use auto-gain, which appears to work # better. This also works better than enabling AGC in the chipset itself. # # # Run "ais.pl" like this (again, create a simple script!): # ./ais.pl boats [--pipe] [--logging] # # You may add the "--pipe" flag in order to have "ais.pl" accept data # from a pipe instead of setting up a UDP server for "rtl_ais" to send # packets to. This is very useful for debugging or for processing # stored log files. # # If you add " --logging" to the end, this script will save the APRS portion of # the output to a file called "~/.xastir/logs/ships.log". You can later suck # this file back in to see the ships move around the map in hyperspeed. Useful # for a quick demo. # # # Antenna length should be: # 1/2 wave dipole: 2.89' -or- 2' 10.7" -or- 2' 10 5/8" # 1/4 wave: 1.44' -or- 1' 5.3" -or- 1' 5 5/16" # # # Excellent AIS info: # http://catb.org/gpsd/AIVDM.html # Eric Raymond/GPSD # https://www.itu.int/dms_pubrec/itu-r/rec/m/R-REC-M.1371-5-201402-I!!PDF-E.pdf # ITU Spec # http://www.navcen.uscg.gov/pdf/AIS/AIS_Special_Notice_and_AIS_Encoding_Guide_2012.pdf # # Example packets w/decoding of fields, plus large sample NMEA data file: # http://fossies.org/linux/gpsd/test/sample.aivdm # # Possible live data feed (Too many connections when I try): # ais.exploratorium.edu:80 # ########################################################################### use IO::Socket; use Storable; #use File::HomeDir; #use Data::Dumper; # Only used for debugging vessel_hash # Enable sending APRS packets to Xastir $enable_tx = 1; # Enable the printing of a statistics line every 100 messages # The format is: total type1 type2 ... type27 # Example: 3600 62 0 15 857 0 0 0 0 0 0 0 0 0 0 113 0 0 0 0 685 1868 0 0 0 0 0 0 $statistics_mode = 1; # Turn on/off printing of various types of messages. Enables debugging of a few # sentence types at a time w/o other messages cluttering up the output. $print_123 = 1; $print_4 = 1; $print_5 = 1; # (includes vesselName and shipType) $print_9 = 1; $print_18 = 1; $print_19 = 1; # (includes vesselName) $print_21 = 1; $print_24_A = 1; # A Variant (includes vesselName) $print_24_B = 1; # B Variant (includes shipType $print_27 = 1; $print_others = 1; # Not decoded yet # Keep statistics on each type (28 slots) @message_type_count = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); $statistics_count = 0; # Number of messages before printing stats # Hash to store tac-calls in, to minimize tac-call assignment packets # This stores the complete tactical call, including whatever name # the ship goes by currently + the country of registry. my %tactical_hash; # Create external copy of vessel_hash for persistent store. # This contains only the vessel name, not the country of registry # or the 9-digit MMSI number. $home = `echo ~`; chomp $home; $persistentFileSpec = "$home/.xastir/config/vessel_hash"; #$persistentFileSpec = File::HomeDir->my_home . "/.xastir/config/vessel_hash"; # # # Hash to store vessel names in, for assigning tactical calls # If it doesn't exist, create it with some initial values # For final release this should simply create a dummy file my %vessel_hash; if ( !(-e $persistentFileSpec )) { %vessel_hash = ( ); # Create the new hash file store \%vessel_hash , $persistentFileSpec; } # Retrieve the cache %vessel_hash = %{retrieve($persistentFileSpec)}; # Debug - print the hash values #print Dumper(\%vessel_hash); $udp_client = "xastir_udp_client"; $xastir_host = "localhost"; # Server where Xastir is running $xastir_port = 2023; # 2023 is Xastir default UDP port $log_file = "~/.xastir/logs/ships.log"; %countries = ( "201" => "Albania", #"Albania (Republic of)" "202" => "Andorra", # "Andorra (Principality of)" "203" => "Austria", "204" => "Azores", # "Azores - Portugal" "205" => "Belgium", "206" => "Belarus", # "Belarus (Republic of)" "207" => "Bulgaria", # "Bulgaria (Republic of)" "208" => "Vatican", # "Vatican City State" "209" => "Cyprus", # "Cyprus (Republic of)" "210" => "Cyprus", # "Cyprus (Republic of)" "211" => "Germany", # "Germany (Federal Republic of)" "212" => "Cyprus", # "Cyprus (Republic of)" "213" => "Georgia", "214" => "Moldova", # "Moldova (Republic of)" "215" => "Malta", "216" => "Armenia", # "Armenia (Republic of)" "218" => "Germany", # "Germany (Federal Republic of)" "219" => "Denmark", "220" => "Denmark", "224" => "Spain", "225" => "Spain", "226" => "France", "227" => "France", "228" => "France", "229" => "Malta", "230" => "Finland", "231" => "Faroe Is.", # "Faroe Islands - Denmark" "232" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "233" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "234" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "235" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "236" => "Gibraltar", # "Gibraltar - United Kingdom of Great Britain and Northern Ireland" "237" => "Greece", "238" => "Croatia", # "Croatia (Republic of)" "239" => "Greece", "240" => "Greece", "241" => "Greece", "242" => "Morocco", # "Morocco (Kingdom of)" "243" => "Hungary", "244" => "Netherlands", # "Netherlands (Kingdom of the)" "245" => "Netherlands", # "Netherlands (Kingdom of the)" "246" => "Netherlands", # "Netherlands (Kingdom of the)" "247" => "Italy", "248" => "Malta", "249" => "Malta", "250" => "Ireland", "251" => "Iceland", "252" => "Liechtenstein", # "Liechtenstein (Principality of)" "253" => "Luxembourg", "254" => "Monaco", # "Monaco (Principality of)" "255" => "Madeira", # "Madeira - Portugal" "256" => "Malta", "257" => "Norway", "258" => "Norway", "259" => "Norway", "261" => "Poland", # "Poland (Republic of)" "262" => "Montenegro", "263" => "Portugal", "264" => "Romania", "265" => "Sweden", "266" => "Sweden", "267" => "Slovakia", # "Slovak Republic" "268" => "San Marino", # "San Marino (Republic of)" "269" => "Switzerland", # "Switzerland (Confederation of)" "270" => "Czech Rep.", # "Czech Republic" "271" => "Turkey", "272" => "Ukraine", "273" => "Russian Fed.", # "Russian Federation" "274" => "Macedonia", # "The Former Yugoslav Republic of Macedonia" "275" => "Latvia", # "Latvia (Republic of)" "276" => "Estonia", # "Estonia (Republic of)" "277" => "Lithuania", # "Lithuania (Republic of)" "278" => "Slovenia", # "Slovenia (Republic of)" "279" => "Serbia", # "Serbia (Republic of)" "301" => "Anguilla", # "Anguilla - United Kingdom of Great Britain and Northern Ireland" "303" => "Alaska,U.S.", # "Alaska (State of) - United States of America" "304" => "Antigua & Barbuda", # "Antigua and Barbuda" "305" => "Antigua & Barbuda", # "Antigua and Barbuda" "306" => "Sint Maarten", # "Sint Maarten (Dutch part) - Netherlands (Kingdom of the)" "306" => "Bonaire, Sint Eustatius & Saba", # "Bonaire, Sint Eustatius and Saba - Netherlands (Kingdom of the)" "306" => "Curaao", # "Curaao - Netherlands (Kingdom of the)" "307" => "Aruba", # "Aruba - Netherlands (Kingdom of the)" "308" => "Bahamas", # "Bahamas (Commonwealth of the)" "309" => "Bahamas", # "Bahamas (Commonwealth of the)" "310" => "Bermuda", # "Bermuda - United Kingdom of Great Britain and Northern Ireland" "311" => "Bahamas", # "Bahamas (Commonwealth of the)" "312" => "Belize", "314" => "Barbados", "316" => "Canada", "319" => "Cayman Is.", # "Cayman Islands - United Kingdom of Great Britain and Northern Ireland" "321" => "Costa Rica", "323" => "Cuba", "325" => "Dominica", # "Dominica (Commonwealth of)" "327" => "Dominican Rep.", # "Dominican Republic" "329" => "Guadeloupe", # "Guadeloupe (French Department of) - France" "330" => "Grenada", "331" => "Greenland", # "Greenland - Denmark" "332" => "Guatemala", # "Guatemala (Republic of)" "334" => "Honduras", # "Honduras (Republic of)" "336" => "Haiti", # "Haiti (Republic of)" "338" => "U.S.", # "United States of America" "339" => "Jamaica", "341" => "St. Kitts & Nevis", # "Saint Kitts and Nevis (Federation of)" "343" => "St. Lucia", "345" => "Mexico", "347" => "Martinique", # "Martinique (French Department of) - France" "348" => "Montserrat", # "Montserrat - United Kingdom of Great Britain and Northern Ireland" "350" => "Nicaragua", "351" => "Panama", # "Panama (Republic of)" "352" => "Panama", # "Panama (Republic of)" "353" => "Panama", # "Panama (Republic of)" "354" => "Panama", # "Panama (Republic of)" "355" => "Panama", # "Panama (Republic of)" "356" => "Panama", # "Panama (Republic of)" "357" => "Panama", # "Panama (Republic of)" "358" => "Puerto Rico,U.S.", # "Puerto Rico - United States of America" "359" => "El Salvador", # "El Salvador (Republic of)" "361" => "St. Pierre & Miquelon", # "Saint Pierre and Miquelon (Territorial Collectivity of) - France" "362" => "Trinidad & Tobago", # "Trinidad and Tobago" "364" => "Turks & Caicos Is.", # "Turks and Caicos Islands - United Kingdom of Great Britain and Northern Ireland" "366" => "U.S.", # "United States of America" "367" => "U.S.", # "United States of America" "368" => "U.S.", # "United States of America" "369" => "U.S.", # "United States of America" "370" => "Panama", # "Panama (Republic of)" "371" => "Panama", # "Panama (Republic of)" "372" => "Panama", # "Panama (Republic of)" "373" => "Panama", # "Panama (Republic of)" "374" => "Panama", # "Panama (Republic of)" "375" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "376" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "377" => "St. Vincent & Grenadines", # "Saint Vincent and the Grenadines" "378" => "British Virgin Is.", # "British Virgin Islands - United Kingdom of Great Britain and Northern Ireland" "379" => "U.S. Virgin Is.", # "United States Virgin Islands - United States of America" "401" => "Afghanistan", "403" => "Saudi Arabia", # "Saudi Arabia (Kingdom of)" "405" => "Bangladesh", # "Bangladesh (People's Republic of)" "408" => "Bahrain", # "Bahrain (Kingdom of)" "410" => "Bhutan", # "Bhutan (Kingdom of)" "412" => "China", # "China (People's Republic of)" "413" => "China", # "China (People's Republic of)" "414" => "China", # "China (People's Republic of)" "416" => "Taiwan", # "Taiwan (Province of China) - China (People's Republic of)" "417" => "Sri Lanka", # "Sri Lanka (Democratic Socialist Republic of)" "419" => "India", # "India (Republic of)" "422" => "Iran", # "Iran (Islamic Republic of)" "423" => "Azerbaijan", # "Azerbaijan (Republic of)" "425" => "Iraq", # "Iraq (Republic of)" "428" => "Israel", # "Israel (State of)" "431" => "Japan", "432" => "Japan", "434" => "Turkmenistan", "436" => "Kazakhstan", # "Kazakhstan (Republic of)" "437" => "Uzbekistan", # "Uzbekistan (Republic of)" "438" => "Jordan", # "Jordan (Hashemite Kingdom of)" "440" => "Korea", # "Korea (Republic of)" "441" => "Korea", # "Korea (Republic of)" "443" => "Palestine", # "State of Palestine (In accordance with Resolution 99 Rev. Guadalajara, 2010)" "445" => "N. Korea", # "Democratic People's Republic of Korea" "447" => "Kuwait", # "Kuwait (State of)" "450" => "Lebanon", "451" => "Kyrgyzstan", # "Kyrgyz Republic" "453" => "Macao", # "Macao (Special Administrative Region of China) - China (People's Republic of)" "455" => "Maldives", # "Maldives (Republic of)" "457" => "Mongolia", "459" => "Nepal", # "Nepal (Federal Democratic Republic of)" "461" => "Oman", # "Oman (Sultanate of)" "463" => "Pakistan", # "Pakistan (Islamic Republic of)" "466" => "Qatar", # "Qatar (State of)" "468" => "Syria", # "Syrian Arab Republic" "470" => "United Arab Emirates", "471" => "United Arab Emirates", "472" => "Tajikistan", # "Tajikistan (Republic of)" "473" => "Yemen", # "Yemen (Republic of)" "475" => "Yemen", # "Yemen (Republic of)" "477" => "Hong Kong", # "Hong Kong (Special Administrative Region of China) - China (People's Republic of)" "478" => "Bosnia & Herzegovina", # "Bosnia and Herzegovina" "501" => "Adelie Land", # "Adelie Land - France" "503" => "Australia", "506" => "Myanmar", # "Myanmar (Union of)" "508" => "Brunei Darussalam", "510" => "Micronesia", # "Micronesia (Federated States of)" "511" => "Palau", # "Palau (Republic of)" "512" => "New Zealand", "514" => "Cambodia", # "Cambodia (Kingdom of)" "515" => "Cambodia", # "Cambodia (Kingdom of)" "516" => "Christmas Is.", # "Christmas Island (Indian Ocean) - Australia" "518" => "Cook Is.", # "Cook Islands - New Zealand" "520" => "Fiji", # "Fiji (Republic of)", "523" => "Cocos (Keeling) Is.", # "Cocos (Keeling) Islands - Australia" "525" => "Indonesia", # "Indonesia (Republic of)" "529" => "Kiribati", # "Kiribati (Republic of)" "531" => "Laos", # "Lao People's Democratic Republic" "533" => "Malaysia", "536" => "N. Mariana Is,U.S.", # "Northern Mariana Islands (Commonwealth of the) - United States of America" "538" => "Marshall Is.", # "Marshall Islands (Republic of the)" "540" => "New Caledonia", # "New Caledonia - France" "542" => "Niue", # "Niue - New Zealand" "544" => "Nauru", # "Nauru (Republic of)" "546" => "French Polynesia", # "French Polynesia - France" "548" => "Philippines", # "Philippines (Republic of the)" "553" => "Papua New Guinea", "555" => "Pitcairn Is.", # "Pitcairn Island - United Kingdom of Great Britain and Northern Ireland" "557" => "Solomon Islands", "559" => "American Samoa,U.S.", # "American Samoa - United States of America" "561" => "Samoa", # "Samoa (Independent State of)" "563" => "Singapore", # "Singapore (Republic of)" "564" => "Singapore", # "Singapore (Republic of)" "565" => "Singapore", # "Singapore (Republic of)" "566" => "Singapore", # "Singapore (Republic of)" "567" => "Thailand", "570" => "Tonga", # "Tonga (Kingdom of)" "572" => "Tuvalu", "574" => "Viet Nam", # "Viet Nam (Socialist Republic of)" "576" => "Vanuatu", # "Vanuatu (Republic of)" "577" => "Vanuatu", # "Vanuatu (Republic of)" "578" => "Wallis & Futuna Is.", # "Wallis and Futuna Islands - France" "601" => "S. Africa", # "South Africa (Republic of)" "603" => "Angola", # "Angola (Republic of)" "605" => "Algeria", # "Algeria (People's Democratic Republic of)" "607" => "St. Paul & Amsterdam Is.", # "Saint Paul and Amsterdam Islands - France" "608" => "Ascension Is.", # "Ascension Island - United Kingdom of Great Britain and Northern Ireland" "609" => "Burundi", # "Burundi (Republic of)" "610" => "Benin", # "Benin (Republic of)" "611" => "Botswana", # "Botswana (Republic of)" "612" => "Central African Rep.", # "Central African Republic" "613" => "Cameroon", # "Cameroon (Republic of)" "615" => "Congo", # "Congo (Republic of the)" "616" => "Comoros", # "Comoros (Union of the)" "617" => "Cape Verde", # "Cabo Verde (Republic of)" "618" => "Crozet Archipelago", # "Crozet Archipelago - France" "619" => "Cte d'Ivoire", # "Cte d'Ivoire (Republic of)" "620" => "Comoros", # "Comoros (Union of the)" "621" => "Djibouti", # "Djibouti (Republic of)" "622" => "Egypt", # "Egypt (Arab Republic of)" "624" => "Ethiopia", # "Ethiopia (Federal Democratic Republic of)" "625" => "Eritrea", "626" => "Gabonese Rep.", # "Gabonese Republic" "627" => "Ghana", "629" => "Gambia", # "Gambia (Republic of the)" "630" => "Guinea-Bissau", # "Guinea-Bissau (Republic of)" "631" => "Equatorial Guinea", # "Equatorial Guinea (Republic of)" "632" => "Guinea", # "Guinea (Republic of)" "633" => "Burkina Faso", "634" => "Kenya", # "Kenya (Republic of)" "635" => "Kerguelen Is.", # "Kerguelen Islands - France" "636" => "Liberia", # "Liberia (Republic of)" "637" => "Liberia", # "Liberia (Republic of)" "638" => "S. Sudan", # "South Sudan (Republic of)" "642" => "Libya", "644" => "Lesotho", # "Lesotho (Kingdom of)" "645" => "Mauritius", # "Mauritius (Republic of)" "647" => "Madagascar", # "Madagascar (Republic of)" "649" => "Mali", # "Mali (Republic of)" "650" => "Mozambique", # "Mozambique (Republic of)" "654" => "Mauritania", # "Mauritania (Islamic Republic of)" "655" => "Malawi", "656" => "Niger", # "Niger (Republic of the)" "657" => "Nigeria", # "Nigeria (Federal Republic of)" "659" => "Namibia", # "Namibia (Republic of)" "660" => "Reunion", # "Reunion (French Department of) - France" "661" => "Rwanda", # "Rwanda (Republic of)" "662" => "Sudan", # "Sudan (Republic of the)" "663" => "Senegal", # "Senegal (Republic of)" "664" => "Seychelles", # "Seychelles (Republic of)" "665" => "St. Helena", # "Saint Helena - United Kingdom of Great Britain and Northern Ireland" "666" => "Somalia", # "Somalia (Federal Republic of)" "667" => "Sierra Leone", "668" => "Sao Tome & Principe", # "Sao Tome and Principe (Democratic Republic of)" "669" => "Swaziland", # "Swaziland (Kingdom of)" "670" => "Chad", # "Chad (Republic of)" "671" => "Togolese Rep.", # "Togolese Republic" "672" => "Tunisia", "674" => "Tanzania", # "Tanzania (United Republic of)" "675" => "Uganda", # "Uganda (Republic of)", "676" => "Dem. Rep. of Congo", # "Democratic Republic of the Congo" "677" => "Tanzania", # "Tanzania (United Republic of)" "678" => "Zambia", # "Zambia (Republic of)" "679" => "Zimbabwe", # "Zimbabwe (Republic of)" "701" => "Argentine Rep.", # "Argentine Republic" "710" => "Brazil", # "Brazil (Federative Republic of)" "720" => "Bolivia", # "Bolivia (Plurinational State of)" "725" => "Chile", "730" => "Columbia", # "Colombia (Republic of)" "735" => "Ecuador", "740" => "Falkland Is.", # "Falkland Islands (Malvinas) - United Kingdom of Great Britain and Northern Ireland" "745" => "Guiana", # "Guiana (French Department of) - France" "750" => "Guyana", "755" => "Paraguay", # "Paraguay (Republic of)" "760" => "Peru", "765" => "Suriname", # "Suriname (Republic of)" "770" => "Uruguay", # "Uruguay (Eastern Republic of)" "775" => "Venezuela", # "Venezuela (Bolivarian Republic of)" ); $xastir_user = shift; if (defined($xastir_user)) { chomp $xastir_user; } if ( (!defined($xastir_user)) || ($xastir_user eq "") ) { print "Please enter a callsign for Xastir injection, but not Xastir's callsign/SSID!\n"; die; } $xastir_user =~ tr/a-z/A-Z/; $xastir_pass = shift; if (defined($xastir_pass)) { chomp $xastir_pass; } if ( (!defined($xastir_pass)) || ($xastir_pass eq "") ) { print "Please enter a passcode for Xastir injection\n"; die; } # Enable pipe mode by adding the "--pipe" flag, then can pipe # packets into the program's STDIN for testing. Without this flag # we'll get our packets from "rtl_ais" via a UDP server we set up. # Enable logging mode by adding the "--logging" flag. $pipe_mode = 0; $logging_mode = 0; $pipe_flag = shift; if (defined($pipe_flag) && $pipe_flag ne "") { chomp $pipe_flag; if ($pipe_flag eq "--pipe") { $pipe_mode = 1; } if ($pipe_flag eq "--logging") { $logging_mode = 1; } } # Try again in case there are two flags $pipe_flag = shift; if (defined($pipe_flag) && $pipe_flag ne "") { chomp $pipe_flag; if ($pipe_flag eq "--pipe") { $pipe_mode = 1; } if ($pipe_flag eq "--logging") { $logging_mode = 1; } } if ($enable_tx) { # Check Xastir's callsign/SSID to make sure we don't have a collision. This # will prevent Xastir adopting the Items as its own and retransmitting them. # "xastir_udp_client localhost 2023 -identify" # "Received: WE7U-13" # $injection_call = $xastir_user; $injection_call =~ s/-\d+//; # Get rid of dash and numbers $injection_ssid = $xastir_user; $injection_ssid =~ s/\w+//; # Get rid of letters $injection_ssid =~ s/-//; # Get rid of dash if ($injection_ssid eq "") { $injection_ssid = 0; } # Find out Callsign/SSID of Xastir instance $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass -identify`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } ($remote_call, $remote_ssid) = split('-', $result); chomp($remote_call); $remote_call =~ s/Received:\s+//; if ( !defined($remote_ssid) ) { $remote_ssid = ""; } if ($remote_ssid ne "") { chomp($remote_ssid); } if ($remote_ssid eq "") { $remote_ssid = 0; } #print "$remote_call $remote_ssid $injection_call $injection_ssid\n"; #if ($remote_call eq $injection_call) { print "Call matches\n"; } #if ($remote_ssid == $injection_ssid) { print "SSID matches\n"; } if ( ($remote_call eq $injection_call) && ($remote_ssid == $injection_ssid) ) { $remote_ssid++; $remote_ssid%= 16; # Increment by 1 mod 16 $xastir_user = "$remote_call-$remote_ssid"; print "Injection conflict. Corrected. New user = $xastir_user\n"; } } if ($pipe_mode) { # # Debug mode: # Read from pipe in a loop # while () { &process_line($_); } } else { # # Not debug mode: # Create UDP server which connects to rtl_ais to get AIS data # Listen on localhost port 10110 for UDP packets # my $host = "localhost"; my $port = 10110; my $protocol = 'udp'; my $server = IO::Socket::INET->new( #PeerAddr => $host, LocalPort => $port, Proto => $protocol, Type => SOCK_DGRAM ) or die "Socket could not be created, failed with error: $!\n"; # Main processing loop. Fetch packets as they are received via # UDP from port 10110. Create APRS packets out of the interesting # ones and inject them into Xastir at port 2023 using UDP. # while ($server->recv($received_data, 1024)) { #my $peer_address = $server->peerhost(); #my $peer_port = $server->peerport(); #print "Message was received from: $peer_address, $peer_port\n"; #print "$received_data"; &process_line($received_data); } # End of main processing loop } sub process_line () { $received_data = shift; if ($pipe_mode) { $received_data =~ s/\n//; # Remove LF if present $received_data =~ s/\r//; # Remove CR if present } else { # Live mode, receiving from rtl-ais. CRLF line-ends. chop($received_data); chop($received_data); } # Check for empty line if ($received_data eq "") { return; } # Verify the checksum: Refuse to process a message if it's bad. # Computed on entire sentence including the AIVDM tag but excluding # the leading "!" character. my $str = $received_data; $str =~ s/^!//; # Chop off leading '!' #$str =~ s/(,\d)\*../$1/; # Chop to '*' char with leading digit and two trailing chars $str =~ s/(,\d)\*...*/$1/; # Chop to '*' char with leading digit and at least two trailing chars #print "$str\n"; # Received checksum. Catches the correct bytes except # for those cases where the NMEA sentences continues # on past the checksum. my $str2 = $received_data; #$str2 =~ s/.*(..)/$1/; # Catches only a checksum at the end $str2 =~ s/.*,\d\*(..).*/$1/; # Catches checksum at end or middle # Compute the checksum on the string between the '!' and the '*' chars. $j = length($str); my $sum = 0; my $i; for ($i = 0; $i <= $j; $i++) { my $c = ord( substr($str, $i, 1) ); $sum = $sum ^ $c; } my $sum2 = sprintf( "%02X", $sum); if ($str2 ne $sum2) { #print "$received_data\n"; #print "$str\t$str2\t$sum2\n"; printf("***** Bad checksum: Received:%s Computed:%s $received_data\n\n", $str2, $sum2); return(); # Skip this sentence } else { #print "$str2\t$sum2\n"; } @pieces = split( ',', $received_data); # $pieces[0] = NMEA message type # $pieces[1] = Number of sentences # $pieces[2] = Sequential Message ID # $pieces[3] = Sentence number # $pieces[4] = AIS Channel # $pieces[5] = Encoded AIS data # $pieces[6] = End of data & NMEA Checksum $data = $pieces[5]; # Encoded AIS data: Each ASCII character represents 6 bits. # Subtract 48. If still a decimal number > 40, subtract 8. # Convert to binary. $bin_string = ""; $len = length($data); for ($i = 0; $i < $len; $i++) { $c = substr($data, $i, 1); #print("$c"); $d = ord($c) - 48; if ($d > 40) { $d = $d - 8; } #print "\t$d\n"; # Convert each character to 6 bits of binary. # Add the binary strings together to make one # long binary string. Pull out the bits we need # to decode each piece of the message. # $b = &dec2bin($d); #print "\t$b\n"; $bin_string = $bin_string . $b; } #print "$bin_string\n"; #printf("%d\n", length($data) ); #printf("%d\n", length($bin_string) ); # If first six bits are 000001 (message type 1): # MMSI Number - bit 8 for 30 bits # HDG - bit 128 for 9 bits # COG - bit 116 for 12 bits (and divide by 10) # SOG - bit 50 for 10 bits (and divide by 10) # Lat - bit 89 for 27 bits (a signed binary number, divide by 600,000) # Lon - bit 61 for 28 bits (a signed binary number, divide by 600,000) # #if (substr($bin_string,0,6) eq "000001") { # print "Message Type: 1\n"; #} #else { # printf"Message Type: %s\n", substr($bin_string,0,6); # die; #} $bmessage_type = substr($bin_string, 0, 6); $message_type = &bin2dec($bmessage_type); if ($statistics_mode) { # Keep a count of the received message types if ($message_type < 28) { $message_type_count[$message_type] += 1; } # Since there's no message type 0 use it's array location for total $message_type_count[0] += 1; # Print the totals every 100 messages if ( ++$statistics_count >= 100 ) { printf("Stats: "); for (my $jj = 0; $jj < 28; $jj++) { if ($jj == 0) { printf("%d", $message_type_count[$jj]); } else { printf(",%d", $message_type_count[$jj]); } } print "\n\n"; $statistics_count = 0; } } # The escape clause for bad message types is here # so that they get included in the total count above. # Don't move this escape above that code. if ( ($message_type > 27) || ($message_type == 0) ) { # print "***** Undefined Msg Type $message_type: $received_data\n\n"; return(); } #print "Message Type: $message_type\n"; # If not messages types 1, 2, 3, skip for now if ( $message_type != 1 && $message_type != 2 && $message_type != 3 && $message_type != 4 && $message_type != 5 && $message_type != 9 && $message_type != 18 && $message_type != 19 && $message_type != 21 && $message_type != 24 && $message_type != 27 ) { # Not something we decode so don't process the sentence. if ($print_others == 1) { print " Msg Type: $message_type\n\n"; } return; } if ( $message_type == 1 || $message_type == 2 || $message_type == 3 ) { if ($print_123) { print " Msg Type: $message_type\n"; } &process_types_1_2_3($message_type); } elsif ( $message_type == 4 ) { if ($print_4) { print " Msg Type: $message_type\n"; } &process_type_4($message_type); } elsif ( $message_type == 5 ) { if ($print_5) { print " Msg Type: $message_type\n"; } &process_type_5($message_type); } elsif ( $message_type == 9 ) { if ($print_9) { print " Msg Type: $message_type\n"; } &process_type_9($message_type); } elsif ( $message_type == 18 ) { if ($print_18) { print " Msg Type: $message_type\n"; } &process_type_18($message_type); } elsif ( $message_type == 19 ) { if ($print_19) { print " Msg Type: $message_type\n"; } &process_type_19($message_type); } elsif ( $message_type == 21 ) { if ($print_21) { print " Msg Type: $message_type\n"; } &process_type_21($message_type); } elsif ( $message_type == 24 ) { #if ($print_24) { print " Msg Type: $message_type\t"; } # This is printed from the subroutine instead &process_type_24($message_type); } elsif ( $message_type == 27 ) { if ($print_27) { print " Msg Type: $message_type\n"; } if ($print_27) { print "$received_data\n"; } &process_type_27($message_type); } } # End of "process_line" # Message types 1, 2 and 3: Position Report Class A # These messages should have 168 bits total # sub process_types_1_2_3() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("123\t%s\t%d\n", $bin_string, length($bin_string)); #printf("123\t%d\n", length($bin_string)); if ($print_123) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type #my $brepeat_indicator = substr($bin_string, 6, 2); my $bUserID = substr($bin_string, 8, 30); # MMSI my $bnavStatus = substr($bin_string, 38, 4); #my $brateOfTurn = substr($bin_string, 42, 8); my $bSpeedOverGnd = substr($bin_string, 50, 10); ##### #my $bpositionAccuracy = substr($bin_string, 60, 1); my $bLongitude = substr($bin_string, 61, 28); ##### my $bLatitude = substr($bin_string, 89, 27); ##### my $bCourseOverGnd = substr($bin_string, 116, 12); ##### #my $btrueHeading = substr($bin_string, 128, 9); #my $btimestamp = substr($bin_string, 137, 6); #my $bspecialManeuver = substr($bin_string, 143, 2); #my $bspare = substr($bin_string, 145, 3); #my $bRAIM = substr($bin_string, 148, 1); #my $bCommState = substr($bin_string, 149, 19); my $userID = &bin2dec($bUserID); if ($print_123) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_123) { print " Country: $country\n"; } my $navStatus = &bin2dec($bnavStatus); my $navStatusTxt = ""; if ($navStatus == 0) { $navStatusTxt = "Under_way:engine"; } elsif ($navStatus == 1) { $navStatusTxt = "At_anchor"; } elsif ($navStatus == 2) { $navStatusTxt = "Not_under_command"; } elsif ($navStatus == 3) { $navStatusTxt = "Restricted_maneuverability"; } elsif ($navStatus == 4) { $navStatusTxt = "Constrained_by_draught"; } elsif ($navStatus == 5) { $navStatusTxt = "Moored"; } elsif ($navStatus == 6) { $navStatusTxt = "Aground"; } elsif ($navStatus == 7) { $navStatusTxt = "Fishing"; } elsif ($navStatus == 8) { $navStatusTxt = "Under_way:sailing"; } #elsif ($navStatus == 9) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 10) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 11) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 12) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 13) { $navStatusTxt = "Reserved"; } elsif ($navStatus == 14) { $navStatusTxt = "AIS-SART_is_active"; } #elsif ($navStatus == 15) { $navStatusTxt = "Not defined"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_123) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_123) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_123) { print "\n"; } return(); } my $NS; if ($print_123) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_123) { print "\n"; } return(); } my $EW; if ($print_123) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed $navStatusTxt$vesselTag"); if ($print_123) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_123) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_123) { print "\n"; } return(); } # Message type 4: Base station report # These messages should have 168 bits total # sub process_type_4() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("123\t%s\t%d\n", $bin_string, length($bin_string)); #printf("123\t%d\n", length($bin_string)); if ($print_4) { print "Msg too short\n\n"; } return; } my $bUserID = substr($bin_string, 8, 30); # MMSI my $bLongitude = substr($bin_string, 79, 28); ##### my $bLatitude = substr($bin_string, 107, 27); ##### my $userID = &bin2dec($bUserID); if ($print_4) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_4) { print " Country: $country\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { return(); } my $NS; if ($print_4) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { return(); } my $EW; if ($print_4) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "/"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " Fixed Base Station"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol $vesselTag"); if ($print_4) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; # if ( defined( $vessel_hash{$userID}) ) { # $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars # } # else { # # No vessel name # # N7IPB: Display country of registry # $temp = substr("($country)", 0, 56); # Chop at 56 chars # # # WE7U: Display the 9-digit MMSI + country of registry # #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars # } # Force the tactical call to be FS since there are no names for Base Stations # $temp = "FS"; if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_4) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_4) { print "\n"; } return(); } # Message type 5: Static and Voyage Related Data (Vessel name, callsign, ship type) # This message should have 424 bits total # sub process_type_5() { #if ( length($bin_string) < 424 ) { if ( length($bin_string) < 240 ) { #printf("5\t%s\t%d\n", $bin_string, length($bin_string)); #printf("5\t%d\n", length($bin_string)); if ($print_5) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 2); # AIS Version # substr($bin_string, 40, 30); # IMO Number #my $bCallsign = substr($bin_string, 70, 42); # Call Sign my $bVesselName = substr($bin_string, 112, 120); # Vessel Name ##### my $bShipType = substr($bin_string, 232, 8); # Ship Type: Page 114 of ITU spec, Table 53 # substr($bin_string, 240, 9); # Dimension to Bow # substr($bin_string, 249, 9); # Dimension to Stern # substr($bin_string, 258, 6); # Dimension to Port # substr($bin_string, 264, 6); # Dimension to Starboard # substr($bin_string, 270, 4); # Position Fix Type # substr($bin_string, 274, 4); # ETA month (UTC) # substr($bin_string, 278, 5); # ETA day (UTC) # substr($bin_string, 283, 5); # ETA hour (UC) # substr($bin_string, 288, 6); # ETA minute (UTC) # substr($bin_string, 294, 8); # Draught # substr($bin_string, 302, 120); # Destination # substr($bin_string, 422, 1); # DTE # substr($bin_string, 423, 1); # Spare my $userID = &bin2dec($bUserID); if ($print_5) { print " User ID: $userID\n"; } #my $callSign = &bin2text($bCallsign); #print "Callsign: $callSign\n"; my $country = &decode_MID($userID); if ($print_5) { print " Country: $country\n"; } my $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_5) { print " Vessel: $vesselName\n"; } my $shipTypeTxt = &decodeShipType($bShipType); if ($print_5) { print "Ship Type: $shipTypeTxt\n"; } # Assign tactical call = $vesselName + $country # Max tactical call in Xastir is 57 chars (56 + terminator?) # # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars my $temp = substr($vesselName . " ($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_5) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_5) { print "\n"; } return(); } # Message type 9: Standard SAR Aircraft Position Report # This message should have 168 bits total # sub process_type_9() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 128 ) { #printf("9\t%s\t%d\n", $bin_string, length($bin_string)); #printf("9\t%d\n", length($bin_string)); if ($print_9) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI my $bAltitude = substr($bin_string, 38, 12); # Altitude my $bSpeedOverGnd = substr($bin_string, 50, 10); # SOG # substr($bin_string, 60, 1); # Position Accuracy my $bLongitude = substr($bin_string, 61, 28); # Longitude my $bLatitude = substr($bin_string, 89, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 116, 12); # Course Over Ground # substr($bin_string, 128, 6); # Time Stamp # substr($bin_string, 134, 1); # Altitude sensor # substr($bin_string, 135, 7); # Spare # substr($bin_string, 142, 1); # DTE # substr($bin_string, 143, 3); # Spare # substr($bin_string, 146, 1); # Assigned mode # substr($bin_string, 147, 1); # RAIM flag # substr($bin_string, 148, 1); # Comm state selector flag # substr($bin_string, 149, 19); # Radio status my $userID = &bin2dec($bUserID); if ($print_9) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_9) { print " Country: $country\n"; } # NOTE: 4095 = N/A # NOTE: 4094 = 4094 meters or higher. my $altitude_meters = &bin2dec($bAltitude); my $altitude = ""; if ($altitude_meters != 4095) { if ($altitude_meters == 4094) { $altitude = sprintf( "%s%06d%s", " /A=", $altitude_meters * 3.28084, "(Higher than)" ); } else { $altitude = sprintf( "%s%06d", " /A=", $altitude_meters * 3.28084 ); } if ($print_9) { print " Altitude: $altitude\n"; } } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_9) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_9) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_9) { print "\n"; } return(); } my $NS; if ($print_9) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_9) { print "\n"; } return(); } my $EW; if ($print_9) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "^"; # "^" = Large Aircraft. Could be "'" for small aircraft, "X" for helicopter. my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$altitude SAR Aircraft$vesselTag"); if ($print_9) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_9) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_9) { print "\n"; } return(); } # Message type 18: Standard Class B CS Position Report # This message should have 168 bits total # sub process_type_18() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 124 ) { #printf("18\t%s\t%d\n", $bin_string, length($bin_string)); #printf("18\t%d\n", length($bin_string)); if ($print_18) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 8); # Spare my $bSpeedOverGnd = substr($bin_string, 46, 10); # Speed Over Ground # substr($bin_string, 56, 1); # Position Accuracy my $bLongitude = substr($bin_string, 57, 28); # Longitude my $bLatitude = substr($bin_string, 85, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 112, 12); # Course Over Ground # substr($bin_string, 124, 9); # True Heading # substr($bin_string, 133, 6); # Time Stamp # substr($bin_string, 139, 2); # Spare # substr($bin_string, 141, 1); # CS Unit # substr($bin_string, 142, 1); # Display flag # substr($bin_string, 143, 1); # DSC Flag # substr($bin_string, 144, 1); # Band flag # substr($bin_string, 145, 1); # Message 22 flag # substr($bin_string, 146, 1); # Assigned mode # substr($bin_string, 147, 1); # RAIM flag # substr($bin_string, 148, 1); # Comm state selector flag # substr($bin_string, 149, 19); # Radio status my $userID = &bin2dec($bUserID); if ($print_18) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_18) { print " Country: $country\n"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_18) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_18) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_18) { print "\n"; } return(); } my $NS; if ($print_18) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_18) { print "\n"; } return(); } my $EW; if ($print_18) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$vesselTag"); if ($print_18) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_18) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_18) { print "\n"; } return(); } # Message type 19: Extended Class B CS Position Report # This message should have 312 bits total # sub process_type_19() { #if ( length($bin_string) < 312 ) { if ( length($bin_string) < 263 ) { #printf("19\t%s\t%d\n", $bin_string, length($bin_string)); #printf("19\t%d\n", length($bin_string)); if ($print_19) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 8); # Spare my $bSpeedOverGnd = substr($bin_string, 46, 10); # Speed Over Ground # substr($bin_string, 56, 1); # Position Accuracy my $bLongitude = substr($bin_string, 57, 28); # Longitude my $bLatitude = substr($bin_string, 85, 27); # Latitude my $bCourseOverGnd = substr($bin_string, 112, 12); # Course Over Ground # substr($bin_string, 124, 9); # True Heading # substr($bin_string, 133, 6); # Time Stamp # substr($bin_string, 139, 4); # Spare my $bVesselName = substr($bin_string, 143, 120); # Name # substr($bin_string, 263, 8); # Type of ship and cargo # substr($bin_string, 271, 9); # Dimension to Bow # substr($bin_string, 280, 9); # Dimension to Stern # substr($bin_string, 289, 6); # Dimension to Port # substr($bin_string, 295, 6); # Dimension to Starboard # substr($bin_string, 301, 4); # Position Fix Type # substr($bin_string, 305, 1); # RAIM flag # substr($bin_string, 306, 1); # DTE # substr($bin_string, 307, 1); # Assigned mode flag # substr($bin_string, 308, 4); # Spare my $userID = &bin2dec($bUserID); if ($print_19) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_19) { print " Country: $country\n"; } # NOTE: 0-359 degrees # NOTE: 360 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd) / 10 ; my $course = ""; if ($courseOverGnd == 360) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_19) { print " Course: $courseOverGnd\n"; } # NOTE: 0 to 102 knots # NOTE: 102.3 = N/A # NOTE: 102.2 = 102.2 knots or higher # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd) / 10; my $speed = ""; if ($speedOverGnd == 102.3) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_19) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { if ($print_19) { print "\n"; } return(); } my $NS; if ($print_19) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { if ($print_19) { print "\n"; } return(); } my $EW; if ($print_19) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $vesselName = ""; if ($bVesselName ne "") { $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end } my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed$vesselTag"); if ($print_19) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } if ($vesselName ne "") { $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_19) { print " Vessel: $vesselName\n"; } # Assign tactical call = $vesselName # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_19) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } if ($print_19) { print "\n"; } return(); } # Message type 21: Aid to Navigation report # These messages should have between 272 and 360 bits total # We don't use the full message and don't parse the name extension # sub process_type_21() { #if ( length($bin_string) < 168 ) { if ( length($bin_string) < 272 ) { #printf("21\t%s\t%d\n", $bin_string, length($bin_string)); #printf("21\t%d\n", length($bin_string)); if ($print_21) { print "Msg too short\n\n"; } return; } my $bUserID = substr($bin_string, 8, 30); # MMSI my $bAidType = substr($bin_string, 38, 5); my $bVesselName = substr($bin_string, 43, 120); # Vessel Name ##### my $bLongitude = substr($bin_string, 164, 28); ##### my $bLatitude = substr($bin_string, 192, 27); ##### my $userID = &bin2dec($bUserID); if ($print_21) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_21) { print " Country: $country\n"; } my $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_21) { print " Vessel: $vesselName\n"; } my $AidTypeTxt = &decodeAidType($bAidType); if ($print_21) { print "Navaid Type: $AidTypeTxt\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A my $latitude = &signedBin2dec($bLatitude) / 600000.0; if ($latitude == 91) { return(); } my $NS; if ($print_21) { printf(" Latitude: %07.5f\n", $latitude); } if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A my $longitude = &signedBin2dec($bLongitude) / 600000.0; if ($longitude == 181) { return(); } my $EW; if ($print_21) { printf("Longitude: %08.5f\n", $longitude); } if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "N"; # Set up to add country or vessel_name + country to comment field my $vesselTag = " (nav-aid)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs= &escape_from_shell("$xastir_user>APRS:)$userID!$lat\\$lon$symbol $AidTypeTxt"); if ($print_21) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = $vesselName + $country # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName, 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_21) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_21) { print "\n"; } return(); } # Message type 24: Static Data Report (Vessel name, callsign, ship type) # This one has three variations: # # If Part Number field is 0, it's a Type A message. # If Part Number is 1, it's a Type B. # # Part B has two variations as well: # If the MMSI is that of an auxiliary craft, then the Mothership MMSI # is that of the mothership. # If not, then those 30 bits represent vessel dimmensions. # # This message should have: # Type A: 160 bits total # Type B: 168 bits total # sub process_type_24() { #if ( length($bin_string) < 160 ) { if ( length($bin_string) < 160 ) { #printf("24\t%s\t%d\n", $bin_string, length($bin_string)); #printf("24\t%d\n", length($bin_string)); if ($print_24_A || $print_24_B) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI my $bPartNumber = substr($bin_string, 38, 2); # Part Number my $userID = &bin2dec($bUserID); # Check for Type A/B Variant (Type B also has two variants!) $PartNumber = &bin2dec($bPartNumber); if ($PartNumber == 0) { # It is a Type A Variant if ($print_24_A) { print " Msg Type: $message_type\tType A Variant\n"; } if ($print_24_A) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_24_A) { print " Country: $country\n"; } # Type A Variant format starts at bit 40: my $bVesselName = substr($bin_string, 40, 120); # Vessel Name # substr($bin_string, 160, 8); # Spare. my $vesselName = ""; if ($bVesselName ne "") { $vesselName = &bin2text($bVesselName); $vesselName =~ s/\s+$//; # Remove extra spaces at end } if ($vesselName ne "") { $vessel_hash{$userID} = $vesselName; # Update the persistent store store \%vessel_hash , $persistentFileSpec; if ($print_24_A) { print " Vessel: $vesselName\n"; } # Assign tactical call = $vesselName # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_24_A) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } if ($print_24_A) { print "\n"; } } else { # It is a Type B Variant. There are two variants of this type! if ($print_24_B) { print " Msg Type: $message_type\tType B Variant\n"; } if ($print_24_B) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_24_B) { print " Country: $country\n"; } # Check the UserID to see if it is an Auxiliary Craft, # to determine which Type B Variant to decode. # Auxiliary craft: MMSI of form 98XXXYYYY, the XXX digits are the country code. if ( !($userID =~ m/^98/)) { # It is NOT an auxiliary craft: # Alternate format starting at bit 40: $bShipType = substr($bin_string, 40, 8); # Ship Type: Page 114 of ITU spec, Table 53 # substr($bin_string, 48, 18); # Vendor ID # substr($bin_string, 66, 4); # Unit Model Code # substr($bin_string, 70, 20); # Serial Number) # substr($bin_string, 90, 42); # Call Sign # substr($bin_string, 132, 9); # Dimension to bow # substr($bin_string, 141, 9); # Dimension to Stern # substr($bin_string, 150, 6); # Dimension to Port # substr($bin_string, 156, 6); # Dimension to Starboard # substr($bin_string, 162, 4); # Type of fix # substr($bin_string, 166, 2); # Spare my $shipTypeTxt = &decodeShipType($bShipType); if ($print_24_B) { print "Ship Type: $shipTypeTxt\n"; } # Assign tactical call = $vesselName + $shipTypeTxt # Max tactical call in Xastir is 57 chars (56 + terminator?) # #my $temp = substr($vesselName . " (" . $country . ")", 0, 56); # Chop at 56 chars my $temp; if (defined($vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " ($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars } else { $temp = substr("($shipTypeTxt:$country)", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) || $tactical_hash{$userID} ne $temp ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_24_A) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } } else { # It IS an auxiliary craft: # Alternate format starting at bit 132: # substr($bin_string, 132, 30); # Mothership MMSI # substr($bin_string, 162, 6); # Spare } if ($print_24_B) { print "\n"; } } return(); } # Message type 27: Position Report For Long-Range Applications (rare) # This message should have 96 bits total # sub process_type_27() { #if ( length($bin_string) < 96 ) { if ( length($bin_string) < 94 ) { #printf("27\t%s\t%d\n", $bin_string, length($bin_string)); #printf("27\t%d\n", length($bin_string)); if ($print_27) { print "Msg too short\n\n"; } return; } # substr($bin_string, 0, 6); # Message Type # my $brepeat_indicator = substr($bin_string, 6, 2); # Repeat Indicator my $bUserID = substr($bin_string, 8, 30); # MMSI # substr($bin_string, 38, 1); # Position Accuracy # substr($bin_string, 39, 1); # RAIM flag my $bNavStatus = substr($bin_string, 40, 4); # Navigation Status my $bLongitude = substr($bin_string, 44, 18); # Longitude my $bLatitude = substr($bin_string, 62, 17); # Latitude my $bSpeedOverGnd = substr($bin_string, 79, 6); # Speed Over Ground my $bCourseOverGnd = substr($bin_string, 85, 9); # Course Over Ground # substr($bin_string, 94, 1); # GNSS Position latency # substr($bin_string, 95, 1); # Spare my $userID = &bin2dec($bUserID); if ($print_27) { print " User ID: $userID\n"; } my $country = &decode_MID($userID); if ($print_27) { print " Country: $country\n"; } my $navStatus = &bin2dec($bNavStatus); my $navStatusTxt = ""; if ($navStatus == 0) { $navStatusTxt = "Under_way:engine"; } elsif ($navStatus == 1) { $navStatusTxt = "At_anchor"; } elsif ($navStatus == 2) { $navStatusTxt = "Not_under_command"; } elsif ($navStatus == 3) { $navStatusTxt = "Restricted_maneuverability"; } elsif ($navStatus == 4) { $navStatusTxt = "Constrained_by_draught"; } elsif ($navStatus == 5) { $navStatusTxt = "Moored"; } elsif ($navStatus == 6) { $navStatusTxt = "Aground"; } elsif ($navStatus == 7) { $navStatusTxt = "Fishing"; } elsif ($navStatus == 8) { $navStatusTxt = "Under_way:sailing"; } #elsif ($navStatus == 9) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 10) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 11) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 12) { $navStatusTxt = "Reserved"; } #elsif ($navStatus == 13) { $navStatusTxt = "Reserved"; } elsif ($navStatus == 14) { $navStatusTxt = "AIS-SART_is_active"; } #elsif ($navStatus == 15) { $navStatusTxt = "Not defined"; } # NOTE: 0-359 degrees # NOTE: 511 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $courseOverGnd = &bin2dec($bCourseOverGnd); my $course = ""; if ($courseOverGnd == 511) { $course = "..."; } elsif ($courseOverGnd == 0) { $course = "360"; } else { $course = sprintf("%03d", $courseOverGnd); } if ($print_27) { print " Course: $courseOverGnd\n"; } # NOTE: 0-62 knots # NOTE: 63 = N/A # APRS spec says can set to "000", "...", or " " if unknown my $speedOverGnd = &bin2dec($bSpeedOverGnd); my $speed = ""; if ($speedOverGnd == 63) { $speed = "..."; } else { $speed = sprintf("%03d", $speedOverGnd); } if ($print_27) { print " Speed: $speedOverGnd\n"; } # NOTE: -90 to +90 # NOTE: 91 = N/A = D548h or 54600 decimal. Divide by 91 to get 600 (our factor). my $latitude = &signedBin2dec($bLatitude) / 600.0; if ($latitude == 91) { if ($print_27) { print "\n"; } return(); } if ($print_27) { #printf(" bLatitude: %s\n", $bLatitude); printf(" Latitude: %07.5f\n", $latitude); } my $NS; if ($latitude >= 0.0) { $NS = 'N'; } else { $NS = 'S'; $latitude = abs($latitude); } my $latdeg = int($latitude); my $latmins = $latitude - $latdeg; my $latmins2 = $latmins * 60.0; my $lat = sprintf("%02d%05.2f%s", $latdeg, $latmins2, $NS); # NOTE: -180 to +180 # NOTE: 181 = N/A = 1A838h or 108600 decimal. Divide by 181 to get 600 (our factor). my $longitude = &signedBin2dec($bLongitude) / 600.0; if ($longitude == 181) { if ($print_27) { print "\n"; } return(); } if ($print_27) { #printf("bLongitude: %s\n", $bLongitude); printf("Longitude: %08.5f\n", $longitude); } my $EW; if ($longitude >= 0.0) { $EW = 'E'; } else { $EW = 'W'; $longitude = abs($longitude); } my $londeg = int($longitude); my $lonmins = $longitude - $londeg; my $lonmins2 = $lonmins * 60.0; my $lon = sprintf("%03d%05.2f%s", $londeg, $lonmins2, $EW); my $symbol = "s"; my $vesselTag = " ($country)"; if ( defined($vessel_hash{$userID}) ) { $vesselTag = " " . $vessel_hash{$userID} . " (" . $country . ")"; } my $aprs = &escape_from_shell("$xastir_user>APRS:)$userID!$lat/$lon$symbol$course/$speed $navStatusTxt$vesselTag"); if ($print_27) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { my $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } # Assign tactical call = "$userID + $country" or "$vesselName + $country" # Max tactical call in Xastir is 57 chars (56 + terminator?) # my $temp; if ( defined( $vessel_hash{$userID}) ) { $temp = substr($vessel_hash{$userID} . " (" . $country . ")", 0, 56); # Chop at 56 chars } else { # No vessel name # N7IPB: Display country of registry $temp = substr("($country)", 0, 56); # Chop at 56 chars # WE7U: Display the 9-digit MMSI + country of registry #$temp = substr($userID . " (" . $country . ")", 0, 56); # Chop at 56 chars } if ( !defined($tactical_hash{$userID}) ) { $tactical_hash{$userID} = $temp; $aprs = &escape_from_shell($xastir_user . '>' . "APRS::TACTICAL :" . $userID . "=" . $temp); if ($print_27) { print " APRS: $aprs\n"; } &log_aprs($aprs); if ($enable_tx) { $result = `$udp_client $xastir_host $xastir_port $xastir_user $xastir_pass \"$aprs\"`; if ($result =~ m/NACK/) { die "Received NACK from Xastir: Callsign/Passcode don't match?\n"; } } } if ($print_27) { print "\n"; } return(); } # Convert binary string $bShipType into text string $shipType # sub decodeAidType() { my $bAidType = shift; my $aidType = sprintf("%02d", &bin2dec($bAidType)); my $aidTypeTxt = "$aidType:"; # Special Craft if ($aidType == 1) { $aidTypeTxt = $aidTypeTxt . "Reference point"; } elsif ($aidType == 2) { $aidTypeTxt = $aidTypeTxt . "RACON"; } elsif ($aidType == 3) { $aidTypeTxt = $aidTypeTxt . "Fixed structure off shore"; } elsif ($aidType == 4) { $aidTypeTxt = $aidTypeTxt . "Reserved"; } elsif ($aidType == 5) { $aidTypeTxt = $aidTypeTxt . "Light, without sectors"; } elsif ($aidType == 6) { $aidTypeTxt = $aidTypeTxt . "Light, with sectors"; } elsif ($aidType == 7) { $aidTypeTxt = $aidTypeTxt . "Leading Light Front"; } elsif ($aidType == 8) { $aidTypeTxt = $aidTypeTxt . "Leading Light Rear"; } elsif ($aidType == 9) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal N"; } elsif ($aidType == 10) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal E"; } elsif ($aidType == 11) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal S"; } elsif ($aidType == 12) { $aidTypeTxt = $aidTypeTxt . "Beacon, Cardinal W"; } elsif ($aidType == 13) { $aidTypeTxt = $aidTypeTxt . "Beacon, Port hand"; } elsif ($aidType == 14) { $aidTypeTxt = $aidTypeTxt . "Beacon, Starboard hand"; } elsif ($aidType == 15) { $aidTypeTxt = $aidTypeTxt . "Beacon, Preferred Channel port hand"; } elsif ($aidType == 16) { $aidTypeTxt = $aidTypeTxt . "Beacon, Preferred Channel starboard hand"; } elsif ($aidType == 17) { $aidTypeTxt = $aidTypeTxt . "Beacon, Isolated danger"; } elsif ($aidType == 18) { $aidTypeTxt = $aidTypeTxt . "Beacon, Safe water"; } elsif ($aidType == 19) { $aidTypeTxt = $aidTypeTxt . "Beacon, Special mark"; } elsif ($aidType == 20) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark N"; } elsif ($aidType == 21) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark E"; } elsif ($aidType == 22) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark S"; } elsif ($aidType == 23) { $aidTypeTxt = $aidTypeTxt . "Cardinal Mark W"; } elsif ($aidType == 24) { $aidTypeTxt = $aidTypeTxt . "Port hand Mark"; } elsif ($aidType == 25) { $aidTypeTxt = $aidTypeTxt . "Starboard hand Mark"; } elsif ($aidType == 26) { $aidTypeTxt = $aidTypeTxt . "Preferred Channel Port hand"; } elsif ($aidType == 27) { $aidTypeTxt = $aidTypeTxt . "Preferred Channel Starboard hand"; } elsif ($aidType == 28) { $aidTypeTxt = $aidTypeTxt . "Isolated danger"; } elsif ($aidType == 29) { $aidTypeTxt = $aidTypeTxt . "Safe Water"; } elsif ($aidType == 30) { $aidTypeTxt = $aidTypeTxt . "Special Mark"; } elsif ($aidType == 31) { $aidTypeTxt = $aidTypeTxt . "Light Vessel / LANBY / Rigs"; } return($aidTypeTxt); } # Convert binary string $bShipType into text string $shipType # sub decodeShipType() { my $bShipType = shift; my $shipType = sprintf("%02d", &bin2dec($bShipType)); my $shipTypeTxt = "$shipType:"; # Special Craft if ($shipType == 50) { $shipTypeTxt = $shipTypeTxt . "Pilot_Vessel"; } elsif ($shipType == 51) { $shipTypeTxt = $shipTypeTxt . "Search_and_Rescue"; } elsif ($shipType == 52) { $shipTypeTxt = $shipTypeTxt . "Harbor_Tug"; } elsif ($shipType == 53) { $shipTypeTxt = $shipTypeTxt . "Fish,Offshore_or_Port_Tender"; } elsif ($shipType == 54) { $shipTypeTxt = $shipTypeTxt . "Anti-pollution"; } elsif ($shipType == 55) { $shipTypeTxt = $shipTypeTxt . "Law_Enforcement"; } elsif ($shipType == 56) { $shipTypeTxt = $shipTypeTxt . "Local"; } elsif ($shipType == 57) { $shipTypeTxt = $shipTypeTxt . "Local"; } elsif ($shipType == 58) { $shipTypeTxt = $shipTypeTxt . "Medical_Transport_or_Public_Safety"; } elsif ($shipType == 59) { $shipTypeTxt = $shipTypeTxt . "Neutral_State_Vessel"; } # U.S. Specific Vessels elsif ($shipType =~ m/^2/) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . "Wing_in_Ground"; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "Tow-Push"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "Tow-Push"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "Light_Boat"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "Mobile_Offshore_Drilling"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "Offshore_Supply_Vessel"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "Processing_Vessel"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "School/Scientific/Research/Training_Vessel"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "U.S._Public_or_Govt"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . "Autonomous_or_Remotely-Operated"; } } # Other Vessels elsif ($shipType =~ m/^3/) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . "Fishing"; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "Towing-Pull"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "Towing-Big"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "Dredging_or_Underwater_Ops"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "Diving_Ops"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "Military_Ops"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "Sailing"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "Pleasure_Craft"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "Other:Reserved"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . "Other:Reserved"; } } elsif ($shipType =~ m/^0/) { $shipTypeTxt = $shipTypeTxt . "Not-Available"; } elsif ($shipType =~ m/^1/) { $shipTypeTxt = $shipTypeTxt . "Reserved"; } elsif ($shipType =~ m/^4/) { $shipTypeTxt = $shipTypeTxt . "Passenger_or_High_Speed"; } elsif ($shipType =~ m/^6/) { $shipTypeTxt = $shipTypeTxt . "Passenger-Big"; } elsif ($shipType =~ m/^7/) { $shipTypeTxt = $shipTypeTxt . "Cargo"; } elsif ($shipType =~ m/^8/) { $shipTypeTxt = $shipTypeTxt . "Tanker"; } elsif ($shipType =~ m/^9/) { $shipTypeTxt = $shipTypeTxt . "Other"; } # Decode 2nd digit for 1/4/6/7/8/9 types: if ( ($shipType =~ m/^1/) || ($shipType =~ m/^4/) || ($shipType =~ m/^6/) || ($shipType =~ m/^7/) || ($shipType =~ m/^8/) || ($shipType =~ m/^9/) ) { if ($shipType =~ m/0$/) { $shipTypeTxt = $shipTypeTxt . ""; } if ($shipType =~ m/1$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:A/X"; } if ($shipType =~ m/2$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:B/Y"; } if ($shipType =~ m/3$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:C/Z"; } if ($shipType =~ m/4$/) { $shipTypeTxt = $shipTypeTxt . "-Haz_Cat:D/O"; } if ($shipType =~ m/5$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/6$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/7$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/8$/) { $shipTypeTxt = $shipTypeTxt . "-Reserved"; } if ($shipType =~ m/9$/) { $shipTypeTxt = $shipTypeTxt . ""; } } return($shipTypeTxt); } # Convert a 6-digit binary string to ASCII text # Encoded AIS data: Each 6 bits represents one ASCII character. # # Each six-bit nibble maps to an ASCII character. # Decimal 0-31 map to "@" ( ASCII 64) through "\_" (ASCII 95) # Decimal 32-63 map to " " (ASCII 32) though "?" (ASCII 63) # Lowercase, backtick, right/left braces, pipe, tilde and DEL can't be encoded sub bin2text() { my $input = shift; my $final_string = ""; my $len = length($input); my $i; for ($i = 0; $i < $len; $i+=6) { my $binary_char = substr($input, $i, 6); # Convert from binary to decimal (ord) my $d = unpack("N", pack("B32", substr("00000000000000000000000000000000" . $binary_char, -32))); if ($d > 0) { # Skip NULL characters if ($d < 32) { $d += 64; } $final_string = $final_string . chr($d); } } $final_string =~ s/\s\s/ /g; return($final_string); } ## Convert a signed binary string of ASCII 0's and 1's to a decimal #sub signedBin2dec { # my $input = shift; # # if ( substr($input, 0, 1) eq "1") { # Negative number # # Pad to 32 bits with 1's ## return unpack("i", pack("B32", substr("11111111111111111111111111111111" . $input, -32))); # # Invert all the bits. Add 1. Convert to decimal. Negate. # my $ii; # my $input2 = ""; # my $len = length($input); # for ($ii = 0; $ii < $len; $ii++) { # my $j = substr($input, $ii, 1); # if ($j eq "0") { $j = "1"; } # else { $j = "0"; } # $input2 = $input2 . $j; # } ##print "$input\n"; ##print "$input2\n"; # my $binary = pack("B32", substr("00000000000000000000000000000000" . $input2, -32, 32)); # my $decimal = unpack("N", $binary); # $decimal++; # $decimal = -$decimal; # return $decimal; # } # else { # Positive number # # Pad to 32 bits with 0's # return unpack("N", pack("B32", substr("00000000000000000000000000000000" . $input, -32))); ##### # # } #} # Convert a signed binary string of ASCII 0's and 1's to a decimal the hard way. # This subroutine should be platform-agnostic as it does all the work internally. sub signedBin2dec { my $input = shift; my $input2 = ""; my $decimal; my $multiplier; #print "\n$input\n"; if ( substr($input, 0, 1) eq "1") { # Negative number # Invert all the bits. Add 1. Convert to decimal. Negate. my $ii; my $len = length($input); for ($ii = 0; $ii < $len; $ii++) { my $j = substr($input, $ii, 1); if ($j eq "0") { $j = "1"; } else { $j = "0"; } $input2 = $input2 . $j; } $decimal = &toDecimal($input2); $decimal++; $decimal = -$decimal; return $decimal; } else { # Positive number return &toDecimal($input); } } # Convert to decimal from positive binary string. # Used by above signedBin2dec subroutine. sub toDecimal { my $input = shift; my $multiplier = 1; my $decimal = 0; my $len = length($input); # Start at LSB bit, work toward MSB bit for (my $ii = $len-1; $ii >= 0; $ii--) { if (substr($input, $ii, 1) == 1) { $decimal = $decimal + $multiplier; #print "1\tMult: $multiplier\n"; } else { #print "0\n"; } $multiplier = $multiplier * 2 ; } return $decimal; } # Convert an unsigned binary string of ASCII 0's and 1's to a decimal sub bin2dec { my $temp = shift; if (!defined($temp) || $temp eq "") { return; } return unpack("N", pack("B32", substr("00000000000000000000000000000000" . $temp, -32))); ##### } # Convert a decimal string (ASCII) to a binary string (ASCII) sub dec2bin { my $input = "00000000000000000000000000" . shift; my $str = unpack("B32", pack("N", $input)); my $str2 = substr($str, -6); return $str2; } # Decode MID out of MMSI ($userID) too: # 8MIDXXXXX Diver's radio (not used in the U.S. in 2013) # MIDXXXXXX Ship # 0MIDXXXXX Group of ships; the U.S. Coast Guard, for example, is 03699999 # 00MIDXXXX Coastal stations # 111MIDXXX SAR (Search and Rescue) aircraft # 99MIDXXXX Aids to Navigation # 98MIDXXXX Auxiliary craft associated with a parent ship # 970MIDXXX AIS SART (Search and Rescue Transmitter) # 972XXXXXX MOB (Man Overboard) device # 974XXXXXX EPIRB (Emergency Position Indicating Radio Beacon) AIS # # NOTE: U.S. ships sometimes incorrectly send "669" for those first 3 digits. # http://www.itu.int/online/mms/glad/cga_mids.sh?lng=E # sub decode_MID { my $userID = shift; my $MID = $userID; if ($userID =~ m/^8.*/) { # Diver's radio $MID =~ s/^8(...).*/$1/; } elsif ($userID =~ m/^00.*/) { # Coastal station $MID =~ s/^00(...).*/$1/; } elsif ($userID =~ m/^0.*/) { # Group of ships $MID =~ s/^0(...).*/$1/; } elsif ($userID =~ m/^111.*/) { # SAR aircraft $MID =~ s/^111(...).*/$1/; } elsif ($userID =~ m/^99.*/) { # Navigation aid $MID =~ s/^99(...).*/$1/; } elsif ($userID =~ m/^98.*/) { # Auxiliary craft $MID =~ s/^98(...).*/$1/; } elsif ($userID =~ m/^970.*/) { # AIS SART $MID =~ s/^970(...).*/$1/; } elsif ($userID =~ m/^972.*/) { # Man overboard device $MID = "MOB"; } elsif ($userID =~ m/^974.*/) { # EPIRB $MID = "EPIRB"; } else { # Ship $MID =~ s/^(...).*/$1/; } my $country = ""; if (defined($countries{$MID})) { $country = $countries{$MID}; } else { $country = "Unknown"; } return $country; } # Escape characters from the shell # # Between double quotes the literal value of all characters is preserved except # for dollar sign, backticks (backward single quotes, ``) and backslash. # # The backslash retains its meaning only when followed by dollar, backtick, double quote, # backslash or newline. Within double quotes, the backslashes are removed from the input # stream when followed by one of these characters. Backslashes preceding characters that # don't have a special meaning are left unmodified for processing by the shell interpreter. # sub escape_from_shell { $temp = shift; $temp =~ s/\\/\\/g; # Look for \ and escape it. Do this one FIRST! $temp =~ s/"/\\"/g; # Look for " and escape it $temp =~ s/\$/\\\$/g; # Look for $ and escape it $temp =~ s/\`/\\`/g; # Look for ` and escape it return ($temp); } # Log messages to log file if logging enabled # sub log_aprs { $sentence = shift; if ($logging_mode) { `echo \"$sentence\" >> $log_file`; } } Xastir-Release-2.2.4/scripts/ais_pp.pl0000775000175000017500000004531515151324131016633 0ustar hibbyhibby#!/usr/bin/env perl use warnings; ########################################################################### # # XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 2000-2026 The Xastir Group # # "ais_pp.pl", a Perl script that prints a formatted list of the # ships found in the vessel hash checkpoint file created by ais.pl # ########################################################################### #use IO::Socket; use Storable; #use File::HomeDir; use Data::Dumper; # Only used for debugging vessel_hash $home = `echo ~`; chomp $home; $persistentFileSpec = "$home/.xastir/config/vessel_hash"; #$persistentFileSpec = File::HomeDir->my_home . "/.xastir/config/vessel_hash"; # # # Hash to store vessel names in, for assigning tactical calls # If it doesn't exist, create it with some initial values # For final release this should simply create a dummy file my %vessel_hash; if ( !(-e $persistentFileSpec )) { %vessel_hash = ( ); # Create the new hash file # store \%vessel_hash , $persistentFileSpec; } # Retrieve the cache %vessel_hash = %{retrieve($persistentFileSpec)}; # Debug - print the hash values #print Dumper(\%vessel_hash); #open(my $fh, '>', 'report.txt'); #print $fh Dumper(\%vessel_hash); %countries = ( "201" => "Albania", #"Albania (Republic of)" "202" => "Andorra", # "Andorra (Principality of)" "203" => "Austria", "204" => "Azores", # "Azores - Portugal" "205" => "Belgium", "206" => "Belarus", # "Belarus (Republic of)" "207" => "Bulgaria", # "Bulgaria (Republic of)" "208" => "Vatican", # "Vatican City State" "209" => "Cyprus", # "Cyprus (Republic of)" "210" => "Cyprus", # "Cyprus (Republic of)" "211" => "Germany", # "Germany (Federal Republic of)" "212" => "Cyprus", # "Cyprus (Republic of)" "213" => "Georgia", "214" => "Moldova", # "Moldova (Republic of)" "215" => "Malta", "216" => "Armenia", # "Armenia (Republic of)" "218" => "Germany", # "Germany (Federal Republic of)" "219" => "Denmark", "220" => "Denmark", "224" => "Spain", "225" => "Spain", "226" => "France", "227" => "France", "228" => "France", "229" => "Malta", "230" => "Finland", "231" => "Faroe Is.", # "Faroe Islands - Denmark" "232" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "233" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "234" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "235" => "U.K.", # "United Kingdom of Great Britain and Northern Ireland" "236" => "Gibraltar", # "Gibraltar - United Kingdom of Great Britain and Northern Ireland" "237" => "Greece", "238" => "Croatia", # "Croatia (Republic of)" "239" => "Greece", "240" => "Greece", "241" => "Greece", "242" => "Morocco", # "Morocco (Kingdom of)" "243" => "Hungary", "244" => "Netherlands", # "Netherlands (Kingdom of the)" "245" => "Netherlands", # "Netherlands (Kingdom of the)" "246" => "Netherlands", # "Netherlands (Kingdom of the)" "247" => "Italy", "248" => "Malta", "249" => "Malta", "250" => "Ireland", "251" => "Iceland", "252" => "Liechtenstein", # "Liechtenstein (Principality of)" "253" => "Luxembourg", "254" => "Monaco", # "Monaco (Principality of)" "255" => "Madeira", # "Madeira - Portugal" "256" => "Malta", "257" => "Norway", "258" => "Norway", "259" => "Norway", "261" => "Poland", # "Poland (Republic of)" "262" => "Montenegro", "263" => "Portugal", "264" => "Romania", "265" => "Sweden", "266" => "Sweden", "267" => "Slovakia", # "Slovak Republic" "268" => "San Marino", # "San Marino (Republic of)" "269" => "Switzerland", # "Switzerland (Confederation of)" "270" => "Czech Rep.", # "Czech Republic" "271" => "Turkey", "272" => "Ukraine", "273" => "Russian Fed.", # "Russian Federation" "274" => "Macedonia", # "The Former Yugoslav Republic of Macedonia" "275" => "Latvia", # "Latvia (Republic of)" "276" => "Estonia", # "Estonia (Republic of)" "277" => "Lithuania", # "Lithuania (Republic of)" "278" => "Slovenia", # "Slovenia (Republic of)" "279" => "Serbia", # "Serbia (Republic of)" "301" => "Anguilla", # "Anguilla - United Kingdom of Great Britain and Northern Ireland" "303" => "Alaska - U.S.", # "Alaska (State of) - United States of America" "304" => "Antigua & Barbuda", # "Antigua and Barbuda" "305" => "Antigua & Barbuda", # "Antigua and Barbuda" "306" => "Sint Maarten", # "Sint Maarten (Dutch part) - Netherlands (Kingdom of the)" "306" => "Bonaire, Sint Eustatius & Saba", # "Bonaire, Sint Eustatius and Saba - Netherlands (Kingdom of the)" "306" => "Curaao", # "Curaao - Netherlands (Kingdom of the)" "307" => "Aruba", # "Aruba - Netherlands (Kingdom of the)" "308" => "Bahamas", # "Bahamas (Commonwealth of the)" "309" => "Bahamas", # "Bahamas (Commonwealth of the)" "310" => "Bermuda", # "Bermuda - United Kingdom of Great Britain and Northern Ireland" "311" => "Bahamas", # "Bahamas (Commonwealth of the)" "312" => "Belize", "314" => "Barbados", "316" => "Canada", "319" => "Cayman Is.", # "Cayman Islands - United Kingdom of Great Britain and Northern Ireland" "321" => "Costa Rica", "323" => "Cuba", "325" => "Dominica", # "Dominica (Commonwealth of)" "327" => "Dominican Rep.", # "Dominican Republic" "329" => "Guadeloupe", # "Guadeloupe (French Department of) - France" "330" => "Grenada", "331" => "Greenland", # "Greenland - Denmark" "332" => "Guatemala", # "Guatemala (Republic of)" "334" => "Honduras", # "Honduras (Republic of)" "336" => "Haiti", # "Haiti (Republic of)" "338" => "U.S.", # "United States of America" "339" => "Jamaica", "341" => "St. Kitts & Nevis", # "Saint Kitts and Nevis (Federation of)" "343" => "St. Lucia", "345" => "Mexico", "347" => "Martinique", # "Martinique (French Department of) - France" "348" => "Montserrat", # "Montserrat - United Kingdom of Great Britain and Northern Ireland" "350" => "Nicaragua", "351" => "Panama", # "Panama (Republic of)" "352" => "Panama", # "Panama (Republic of)" "353" => "Panama", # "Panama (Republic of)" "354" => "Panama", # "Panama (Republic of)" "355" => "Panama", # "Panama (Republic of)" "356" => "Panama", # "Panama (Republic of)" "357" => "Panama", # "Panama (Republic of)" "358" => "Puerto Rico - U.S.", # "Puerto Rico - United States of America" "359" => "El Salvador", # "El Salvador (Republic of)" "361" => "St. Pierre & Miquelon", # "Saint Pierre and Miquelon (Territorial Collectivity of) - France" "362" => "Trinidad & Tobago", # "Trinidad and Tobago" "364" => "Turks & Caicos Is.", # "Turks and Caicos Islands - United Kingdom of Great Britain and Northern Ireland" "366" => "U.S.", # "United States of America" "367" => "U.S.", # "United States of America" "368" => "U.S.", # "United States of America" "369" => "U.S.", # "United States of America" "370" => "Panama", # "Panama (Republic of)" "371" => "Panama", # "Panama (Republic of)" "372" => "Panama", # "Panama (Republic of)" "373" => "Panama", # "Panama (Republic of)" "374" => "Panama", # "Panama (Republic of)" "375" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "376" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "377" => "St. Vincent & the Grenadines", # "Saint Vincent and the Grenadines" "378" => "British Virgin Is.", # "British Virgin Islands - United Kingdom of Great Britain and Northern Ireland" "379" => "U.S. Virgin Is.", # "United States Virgin Islands - United States of America" "401" => "Afghanistan", "403" => "Saudi Arabia", # "Saudi Arabia (Kingdom of)" "405" => "Bangladesh", # "Bangladesh (People's Republic of)" "408" => "Bahrain", # "Bahrain (Kingdom of)" "410" => "Bhutan", # "Bhutan (Kingdom of)" "412" => "China", # "China (People's Republic of)" "413" => "China", # "China (People's Republic of)" "414" => "China", # "China (People's Republic of)" "416" => "Taiwan", # "Taiwan (Province of China) - China (People's Republic of)" "417" => "Sri Lanka", # "Sri Lanka (Democratic Socialist Republic of)" "419" => "India", # "India (Republic of)" "422" => "Iran", # "Iran (Islamic Republic of)" "423" => "Azerbaijan", # "Azerbaijan (Republic of)" "425" => "Iraq", # "Iraq (Republic of)" "428" => "Israel", # "Israel (State of)" "431" => "Japan", "432" => "Japan", "434" => "Turkmenistan", "436" => "Kazakhstan", # "Kazakhstan (Republic of)" "437" => "Uzbekistan", # "Uzbekistan (Republic of)" "438" => "Jordan", # "Jordan (Hashemite Kingdom of)" "440" => "Korea", # "Korea (Republic of)" "441" => "Korea", # "Korea (Republic of)" "443" => "Palestine", # "State of Palestine (In accordance with Resolution 99 Rev. Guadalajara, 2010)" "445" => "N. Korea", # "Democratic People's Republic of Korea" "447" => "Kuwait", # "Kuwait (State of)" "450" => "Lebanon", "451" => "Kyrgyzstan", # "Kyrgyz Republic" "453" => "Macao", # "Macao (Special Administrative Region of China) - China (People's Republic of)" "455" => "Maldives", # "Maldives (Republic of)" "457" => "Mongolia", "459" => "Nepal", # "Nepal (Federal Democratic Republic of)" "461" => "Oman", # "Oman (Sultanate of)" "463" => "Pakistan", # "Pakistan (Islamic Republic of)" "466" => "Qatar", # "Qatar (State of)" "468" => "Syria", # "Syrian Arab Republic" "470" => "United Arab Emirates", "471" => "United Arab Emirates", "472" => "Tajikistan", # "Tajikistan (Republic of)" "473" => "Yemen", # "Yemen (Republic of)" "475" => "Yemen", # "Yemen (Republic of)" "477" => "Hong Kong", # "Hong Kong (Special Administrative Region of China) - China (People's Republic of)" "478" => "Bosnia & Herzegovina", # "Bosnia and Herzegovina" "501" => "Adelie Land", # "Adelie Land - France" "503" => "Australia", "506" => "Myanmar", # "Myanmar (Union of)" "508" => "Brunei Darussalam", "510" => "Micronesia", # "Micronesia (Federated States of)" "511" => "Palau", # "Palau (Republic of)" "512" => "New Zealand", "514" => "Cambodia", # "Cambodia (Kingdom of)" "515" => "Cambodia", # "Cambodia (Kingdom of)" "516" => "Christmas Is.", # "Christmas Island (Indian Ocean) - Australia" "518" => "Cook Is.", # "Cook Islands - New Zealand" "520" => "Fiji", # "Fiji (Republic of)", "523" => "Cocos (Keeling) Is.", # "Cocos (Keeling) Islands - Australia" "525" => "Indonesia", # "Indonesia (Republic of)" "529" => "Kiribati", # "Kiribati (Republic of)" "531" => "Laos", # "Lao People's Democratic Republic" "533" => "Malaysia", "536" => "N. Mariana Is. - U.S.", # "Northern Mariana Islands (Commonwealth of the) - United States of America" "538" => "Marshall Is.", # "Marshall Islands (Republic of the)" "540" => "New Caledonia", # "New Caledonia - France" "542" => "Niue", # "Niue - New Zealand" "544" => "Nauru", # "Nauru (Republic of)" "546" => "French Polynesia", # "French Polynesia - France" "548" => "Philippines", # "Philippines (Republic of the)" "553" => "Papua New Guinea", "555" => "Pitcairn Is.", # "Pitcairn Island - United Kingdom of Great Britain and Northern Ireland" "557" => "Solomon Islands", "559" => "American Samoa - U.S.", # "American Samoa - United States of America" "561" => "Samoa", # "Samoa (Independent State of)" "563" => "Singapore", # "Singapore (Republic of)" "564" => "Singapore", # "Singapore (Republic of)" "565" => "Singapore", # "Singapore (Republic of)" "566" => "Singapore", # "Singapore (Republic of)" "567" => "Thailand", "570" => "Tonga", # "Tonga (Kingdom of)" "572" => "Tuvalu", "574" => "Viet Nam", # "Viet Nam (Socialist Republic of)" "576" => "Vanuatu", # "Vanuatu (Republic of)" "577" => "Vanuatu", # "Vanuatu (Republic of)" "578" => "Wallis & Futuna Is.", # "Wallis and Futuna Islands - France" "601" => "S. Africa", # "South Africa (Republic of)" "603" => "Angola", # "Angola (Republic of)" "605" => "Algeria", # "Algeria (People's Democratic Republic of)" "607" => "St. Paul & Amsterdam Is.", # "Saint Paul and Amsterdam Islands - France" "608" => "Ascension Is.", # "Ascension Island - United Kingdom of Great Britain and Northern Ireland" "609" => "Burundi", # "Burundi (Republic of)" "610" => "Benin", # "Benin (Republic of)" "611" => "Botswana", # "Botswana (Republic of)" "612" => "Central African Rep.", # "Central African Republic" "613" => "Cameroon", # "Cameroon (Republic of)" "615" => "Congo", # "Congo (Republic of the)" "616" => "Comoros", # "Comoros (Union of the)" "617" => "Cape Verde", # "Cabo Verde (Republic of)" "618" => "Crozet Archipelago", # "Crozet Archipelago - France" "619" => "Cte d'Ivoire", # "Cte d'Ivoire (Republic of)" "620" => "Comoros", # "Comoros (Union of the)" "621" => "Djibouti", # "Djibouti (Republic of)" "622" => "Egypt", # "Egypt (Arab Republic of)" "624" => "Ethiopia", # "Ethiopia (Federal Democratic Republic of)" "625" => "Eritrea", "626" => "Gabonese Rep.", # "Gabonese Republic" "627" => "Ghana", "629" => "Gambia", # "Gambia (Republic of the)" "630" => "Guinea-Bissau", # "Guinea-Bissau (Republic of)" "631" => "Equatorial Guinea", # "Equatorial Guinea (Republic of)" "632" => "Guinea", # "Guinea (Republic of)" "633" => "Burkina Faso", "634" => "Kenya", # "Kenya (Republic of)" "635" => "Kerguelen Is.", # "Kerguelen Islands - France" "636" => "Liberia", # "Liberia (Republic of)" "637" => "Liberia", # "Liberia (Republic of)" "638" => "S. Sudan", # "South Sudan (Republic of)" "642" => "Libya", "644" => "Lesotho", # "Lesotho (Kingdom of)" "645" => "Mauritius", # "Mauritius (Republic of)" "647" => "Madagascar", # "Madagascar (Republic of)" "649" => "Mali", # "Mali (Republic of)" "650" => "Mozambique", # "Mozambique (Republic of)" "654" => "Mauritania", # "Mauritania (Islamic Republic of)" "655" => "Malawi", "656" => "Niger", # "Niger (Republic of the)" "657" => "Nigeria", # "Nigeria (Federal Republic of)" "659" => "Namibia", # "Namibia (Republic of)" "660" => "Reunion", # "Reunion (French Department of) - France" "661" => "Rwanda", # "Rwanda (Republic of)" "662" => "Sudan", # "Sudan (Republic of the)" "663" => "Senegal", # "Senegal (Republic of)" "664" => "Seychelles", # "Seychelles (Republic of)" "665" => "St. Helena", # "Saint Helena - United Kingdom of Great Britain and Northern Ireland" "666" => "Somalia", # "Somalia (Federal Republic of)" "667" => "Sierra Leone", "668" => "Sao Tome & Principe", # "Sao Tome and Principe (Democratic Republic of)" "669" => "Swaziland", # "Swaziland (Kingdom of)" "670" => "Chad", # "Chad (Republic of)" "671" => "Togolese Rep.", # "Togolese Republic" "672" => "Tunisia", "674" => "Tanzania", # "Tanzania (United Republic of)" "675" => "Uganda", # "Uganda (Republic of)", "676" => "Dem. Rep. of the Congo", # "Democratic Republic of the Congo" "677" => "Tanzania", # "Tanzania (United Republic of)" "678" => "Zambia", # "Zambia (Republic of)" "679" => "Zimbabwe", # "Zimbabwe (Republic of)" "701" => "Argentine Rep.", # "Argentine Republic" "710" => "Brazil", # "Brazil (Federative Republic of)" "720" => "Bolivia", # "Bolivia (Plurinational State of)" "725" => "Chile", "730" => "Columbia", # "Colombia (Republic of)" "735" => "Ecuador", "740" => "Falkland Is.", # "Falkland Islands (Malvinas) - United Kingdom of Great Britain and Northern Ireland" "745" => "Guiana", # "Guiana (French Department of) - France" "750" => "Guyana", "755" => "Paraguay", # "Paraguay (Republic of)" "760" => "Peru", "765" => "Suriname", # "Suriname (Republic of)" "770" => "Uruguay", # "Uruguay (Eastern Republic of)" "775" => "Venezuela", # "Venezuela (Bolivarian Republic of)" ); # Main processing loop. Fetch lines from vessel_hash # and print them out on stdio # Format: MILLENIUM FALCON 366978720 U.S. while(my($userID, $vesselName) = each %vessel_hash) { my $country = &decode_MID($userID); printf "%-20s %-9d %s\n",$vesselName,$userID,$country; } exit; # Decode MID out of MMSI ($userID) too: # 8MIDXXXXX Diver's radio (not used in the U.S. in 2013) # MIDXXXXXX Ship # 0MIDXXXXX Group of ships; the U.S. Coast Guard, for example, is 03699999 # 00MIDXXXX Coastal stations # 111MIDXXX SAR (Search and Rescue) aircraft # 99MIDXXXX Aids to Navigation # 98MIDXXXX Auxiliary craft associated with a parent ship # 970MIDXXX AIS SART (Search and Rescue Transmitter) # 972XXXXXX MOB (Man Overboard) device # 974XXXXXX EPIRB (Emergency Position Indicating Radio Beacon) AIS # # NOTE: U.S. ships sometimes incorrectly send "669" for those first 3 digits. # http://www.itu.int/online/mms/glad/cga_mids.sh?lng=E # sub decode_MID { my $userID = shift; my $MID = $userID; if ($userID =~ m/^8.*/) { # Diver's radio $MID =~ s/^8(...).*/$1/; } elsif ($userID =~ m/^00.*/) { # Coastal station $MID =~ s/^00(...).*/$1/; } elsif ($userID =~ m/^0.*/) { # Group of ships $MID =~ s/^0(...).*/$1/; } elsif ($userID =~ m/^111.*/) { # SAR aircraft $MID =~ s/^111(...).*/$1/; } elsif ($userID =~ m/^99.*/) { # Navigation aid $MID =~ s/^99(...).*/$1/; } elsif ($userID =~ m/^98.*/) { # Auxiliary craft $MID =~ s/^98(...).*/$1/; } elsif ($userID =~ m/^970.*/) { # AIS SART $MID =~ s/^970(...).*/$1/; } elsif ($userID =~ m/^972.*/) { # Man overboard device $MID = "MOB"; } elsif ($userID =~ m/^974.*/) { # EPIRB $MID = "EPIRB"; } else { # Ship $MID =~ s/^(...).*/$1/; } my $country = ""; if (defined($countries{$MID})) { $country = $countries{$MID}; } else { $country = "Unknown"; } return $country; } Xastir-Release-2.2.4/scripts/coord-convert.pl0000775000175000017500000002023315151324131020134 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # Written by Paul Lutt, KE7XT. # Released to the public domain. # # # # # Converts between different lat/lon formats. Will also give UMS # position if the lat/lon resides somewhere inside the Seattle area # aeronautical map. # # UMS coordinates have been used in the past by King County, WA SAR. # It can be useful for plotting positions on Green Trails maps and # perhaps other maps. The maps must be 15' topo maps and marked in # tenths of miles along the edge in order to make use of this # coordinate system. # # Web pages which discuss UMS format: # http://www.impulse.net/~mlynch/land_nav.html # http://www.logicsouth.com/~lcoble/dir9/land_nav.htm # http://www.aasar.org/training/academy/navigation.pdf # use lib "${prefix}/lib"; use Coordinate; # WE7U's Coordinate.pm module # Create new Coordinate object my $position = Coordinate->new(); $position->datum("WGS 84"); # Datum print "\n"; print "Examples: 48.123N 122.123W\n"; print " 48 07.380N 122 07.380W\n"; print " 48 07 22.8N 122 07 22.8W\n"; print " 10U 0565264 5330343\n"; while (1) { print "\nEnter a Lat/Long value or UTM value:\n"; # Snag the input $_ = <>; print "\n"; # If the first item has 2 digits and one character and there are # three "words" in the input, we're starting with a UTM value. if (/^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { # printf("Found a UTM value\n"); # We'll convert it to the standard format first and then run # through the rest of the code. $zone = $_; $easting = $_; $northing = $_; $zone =~ s/^(\d\d[a-zA-Z])\s+\w+\s+\w+\s*$/$1/; $easting =~ s/^\d\d[a-zA-Z]\s+(\w+)\s+\w+\s*$/$1/; $northing =~ s/^\d\d[a-zA-Z]\s+\w+\s+(\w+)\s*$/$1/; if ($easting > 999999) { printf("Easting value is too high!\n"); next; } $position->zone($zone); $position->easting($easting); $position->northing($northing); # Convert to lat/lon values $position->utm_to_lat_lon(); # printf("Calculated Lat, Long position(Lat, Long): %f %f\n", # $position->latitude(), # $position->longitude() ); $latitude = $position->latitude(); $longitude = $position->longitude(); $lat_dir = "N"; $long_dir = "E"; if ($latitude < 0.0) { $latitude = abs($latitude); $lat_dir = "S" } if ($longitude < 0.0) { $longitude = abs($longitude); $long_dir = "W"; } # printf("%f%s %f%s\n", $latitude,$lat_dir,$longitude,$long_dir); $_ = sprintf("%f%s %f%s", $latitude,$lat_dir,$longitude,$long_dir); } # Look for lat/long value in the input # Add missing decimal points. s/^(\d+)([NSns])\s+(\d+)([EWew])\s*$/$1.$2 $3.$4/; # Check for N/S/E/W characters in the input. Set the # appropriate flags if found. $lat_dir = "N"; $long_dir = "E"; if (/S/ || /s/) { $lat_dir = "S"; } if (/W/ || /w/) { $long_dir = "W"; } # Filter out these characters from the input tr/nsewNSEW//d; # Convert to DD MM SS format ($lat_deg, $lat_min, $lat_sec, $long_deg, $long_min, $long_sec) = split(' '); # Decimal Degrees? if ($lat_deg =~ /\./) { $long_deg = $lat_min; # Save long_degrees in proper place $temp = $lat_deg; $lat_deg = int $temp; $lat_min = int ((abs($temp) * 60.0) % 60); # Modulus converts to integers, so we bump up by 10 and then # back down. $lat_sec = (abs($temp) * 36000.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_deg; $long_deg = int $temp; $long_min = int ((abs($temp) * 60.0) % 60); $long_sec = (abs($temp) * 36000.0) % 600; $long_sec = $long_sec / 10; } # Decimal Minutes? elsif ($lat_min =~ /\./) { $long_min = $long_deg; # Save long_minutes in proper place $long_deg = $lat_sec; # Save long_degrees in proper place $temp = $lat_min; $lat_min = int abs($temp); $lat_sec = (abs($temp) * 600.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_min; $long_min = int abs($temp); $long_sec = (abs($temp) * 600.0) % 600; $long_sec = $long_sec / 10; } # Decimal Seconds else { # Already in DD MM SS format, don't convert } # Print out the three lat/long formats printf(" Decimal Degrees: %8.5f%s %8.5f%s\n", $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0), $lat_dir, $long_deg + ($long_min/60.0) + ($long_sec/3600.0), $long_dir ); printf(" Degrees/Decimal Minutes: %02d %06.3f%s %02d %06.3f%s\n", $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); printf(" Degrees/Minutes/Dec. Seconds: %02d %02d %4.1f%s %02d %02d %4.1f%s\n", $lat_deg, $lat_min, $lat_sec, $lat_dir, $long_deg, $long_min, $long_sec, $long_dir); # Fill in the coordinate object with the current lat/lon. # Assuming WGS84 datum if ($lat_dir =~ /S/) { $position->latitude( -( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ) ); } else { $position->latitude( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ); } if ($long_dir =~ /W/) { $position->longitude( -( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ) ); } else { $position->longitude( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ); } #printf("%f %f\n",$position->latitude,$position->longitude); $position->lat_lon_to_utm(); printf(" Universal Transverse Mercator: %s %07.0f %07.0f\n", $position->zone(), $position->easting(), $position->northing() ); # Check whether the coordinates are within the SEA aeronautical # map area $lat_err = 0; if ($lat_dir =~ /S/ || $lat_deg < 44 || $lat_deg > 49 || ($lat_deg == 44 && ($lat_min < 30 || ($lat_min == 30 && $lat_sec == 0))) || ($lat_deg == 49 && ($lat_min > 0 || $lat_sec > 0))) { print " lat. out of range "; $lat_err = 1; } $long_err = 0; if ($long_dir =~ /E/ || $long_deg < 117 || $long_deg > 125 || ($long_deg == 117 && ($long_min == 0 && $long_sec == 0)) || ($long_deg == 125 && ($long_min > 0 || $long_sec > 0))) { print " long. out of range"; $long_err = 1; } next if ( $lat_err || $long_err); # Compute UMS coordinates $y_sec = 3600 * ($lat_deg - 44) + 60 * $lat_min + $lat_sec; $y_sec = 18000 - $y_sec; $x_sec = 3600 * ($long_deg - 117) + 60 * $long_min + $long_sec; $x_sec = 28800 - $x_sec; $quad = 32 * int($y_sec / 900) + int($x_sec / 900) + 1; # print "\tx_sec= $x_sec, y_sec= $y_sec, quad= $quad\n"; $y_subquad_offset = int($y_sec / 450); $x_subquad_offset = int($x_sec / 450); if (&even($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} A "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&odd($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} B "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&even($x_subquad_offset) && &odd($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} C "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } else { print " UMS (Green Trails Maps): SEA ${quad} D "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } } sub even { return (($_[0] & 1) == 0); } sub odd { return (($_[0] & 1) == 1); } sub s2m_y { return (int((0.1917966 * $_[0]) + 0.5)); } sub s2m_x { return (int((cos(($lat_deg + ($lat_min / 60.0) + ($lat_sec / 3600.0)) / 57.29578) * (0.1917966 * $_[0])) + 0.5)); } Xastir-Release-2.2.4/scripts/db_gis_mysql.sql0000775000175000017500000000444215151324131020214 0ustar hibbyhibby-- MYSQL SPATIAL (>4.1) -- Updated by Dan Zubey N7NMD dzubey@openincident.com 03Oct2010 -- -- See the last four lines to set permissions for a user -- to access this database. CREATE DATABASE IF NOT EXISTS xastir; USE xastir; CREATE TABLE version ( version_number INT, compatable_series INT ); INSERT INTO version (version_number,compatable_series) VALUES (1,1); -- MySQL spatial table using geometry POINT rather than lat/long -- CREATE TABLE simpleStationSpatial ( simpleStationId INT PRIMARY KEY NOT NULL AUTO_INCREMENT, station VARCHAR(9) NOT NULL, symbol VARCHAR(1), overlay VARCHAR(1), aprstype VARCHAR(1), transmit_time DATETIME, position POINT, origin VARCHAR(9) NOT NULL DEFAULT '', record_type VARCHAR(1), node_path VARCHAR(56) ); -- Note: Use the asText() function to retrieve data from the position field. -- In a shell, the return values from the raw position field will often -- change the character set in the shell, to avoid this, use asText(position). -- Example query returning the position in WKT format: -- select station, asText(position), transmit_time from simpleStationSpatial; -- MYSQL (default table) CREATE TABLE simpleStation ( simpleStationId INT PRIMARY KEY NOT NULL AUTO_INCREMENT, station VARCHAR(9) NOT NULL, symbol VARCHAR(1), overlay VARCHAR(1), aprstype VARCHAR(1), transmit_time DATETIME, latitude FLOAT, longitude FLOAT, origin VARCHAR(9) NOT NULL DEFAULT '', record_type VARCHAR(1), node_path VARCHAR(56) ); -- Example query to retrieve symbol as aprsworld icon filename. -- select count(*), concat(lpad(ascii(aprstype),3,'0'), '_', lpad(ascii(symbol),3,'0'), '.png') from simpleStationSpatial group by aprstype,symbol; -- *** Permissions *** -- Use the following grants to set up a user with minimal rights -- to the database. -- -- Change the password on the next line and uncomment the next four lines. -- GRANT USAGE ON xastir.* to 'xastir_user'@'localhost' identified by 'set_this_password'; -- GRANT SELECT ON xastir.version TO 'xastir_user'@'localhost'; -- GRANT SELECT, INSERT, UPDATE ON xastir.simpleStation to 'xastir_user'@'localhost'; -- GRANT SELECT, INSERT, UPDATE ON xastir.simpleStationSpatial TO 'xastir_user'@'localhost'; Xastir-Release-2.2.4/scripts/db_gis_postgis.sql0000775000175000017500000000623115151324131020535 0ustar hibbyhibby-- POSTGRES/POSTGIS create database xastir; --set the password and uncomment --create user xastir_user with encrypted password ''; -- edit pg_hba.conf to allow access from local host --local xastir xastir_user md5 --host xastir xastir_user 127.0.0.1/32 md5 -- run create lang to add plpgsql to xastir db --createlang --dbname=xastir plpgsql -- run lwpostgis script to enable postgis for xastir db --psql -d xastir -f lwpostgis.sql --run the following sql commands in psql --psql xastir create table version ( version_number int, compatable_series int ); grant select on version to xastir_user; insert into version (version_number,compatable_series) values (1,1); create table simpleStation ( simpleStationId serial primary key, station varchar(9) not null, symbol varchar(1), overlay varchar(1), aprstype varchar(1), transmit_time timestamptz not null default now(), origin varchar(9) not null default '', record_type varchar(1), node_path varchar(56), ); create index ssstation on simplestation(station); create index sssymbol on simplestation(symbol); create index sstype on simplestation(aprstype); create index sstransmittime on simplestation(transmit_time); create index ssstationtime on simplestation(station,transmit_time); --select AddGeometryColumn('','simpleStation','position',-1,'POINT',2); --alternately, set geometry explicitly as WGS84 Latitude/Longitude: insert into spatial_ref_sys (srid,auth_name,auth_srid,srtext,proj4text) values (1,'NAD83',4269,'+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs ','+proj=longlat +ellps=GRS80 +datum=NAD83 +no_defs '); --- EPSG 4326 : WGS 84 Lat/Long INSERT INTO spatial_ref_sys (srid,auth_name,auth_srid,srtext,proj4text) VALUES (4326,'EPSG',4326,'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '); select AddGeometryColumn('','simpleStation','position',4326,'POINT',2); grant select, insert, update on simpleStation to xastir_user; grant select, update on simpleStation_simpleStationId_seq to xastir_user; -- the next two grants allow xastir_user to be used in other applications -- such as qgis that need access to the spatial metadata tables grant select on geometry_columns to xastir_user; grant select on spatial_ref_sys to xastir_user; -- 0 update alter table simpleStation add column origin varchar(9) not null default ''; alter table simpleStation add column record_type varchar(1); alter table simpleStation add column node_path varchar(56); -- note - lat/long is transposed in version 0 and version 1 -- example query to list symbols by aprsworld icon filenames -- select count(*), lpad(ascii(aprstype),3,'0') || '_' || lpad(ascii(symbol),3,'0') || '.png' from simpleStation group by aprstype, symbol; -- view to add icon filenames create view simplestationicons as select *, lpad(ascii(aprstype),3,'0') || '_' || lpad(ascii(symbol),3,'0') || '.png' as icon from simpleStation; Xastir-Release-2.2.4/scripts/example_objects.log0000664000175000017500000002131715151324131020663 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # # Compare your results with the Area Object images here after # sucking this file in as a log file (They should appear in the # Pacific Ocean): # # http://www.xastir.org/wiki/index.php/HowTo:Scripts # #Corridors (Line with width in miles) #{1} means a corridor 1 mile on either side of the line N0CALL>APRS:)Corridor1!5012.00N\13033.00Wl130/200{1} N0CALL>APRS:)Corridor2!4955.00N\13000.00Wl630/400{1} N0CALL>APRS:)Corridor3!5012.00N\13000.00Wl130/330{2} N0CALL>APRS:)Corridor4!4957.00N\13033.00Wl630/130{2} N0CALL>APRS:)Corridor5!4800.00N\13000.00Wl100/599{20} #Shape 0, Open Circle N0CALL>APRS:)C-black !5000.00N\13000.00Wl004/004 N0CALL>APRS:)C-blue !5000.00N\13002.00Wl004/104 N0CALL>APRS:)C-green !5000.00N\13004.00Wl004/204 N0CALL>APRS:)C-cyan !5000.00N\13006.00Wl004/304 N0CALL>APRS:)C-red !5000.00N\13008.00Wl004/404 N0CALL>APRS:)C-violet !5000.00N\13010.00Wl004/504 N0CALL>APRS:)C-yellow !5000.00N\13012.00Wl004/604 N0CALL>APRS:)C-gray !5000.00N\13014.00Wl004/704 N0CALL>APRS:)CD-black !5000.00N\13016.00Wl004/804 N0CALL>APRS:)CD-blue !5000.00N\13018.00Wl004/904 N0CALL>APRS:)CD-green !5000.00N\13020.00Wl0041004 N0CALL>APRS:)CD-cyan !5000.00N\13022.00Wl0041104 N0CALL>APRS:)CD-red !5000.00N\13024.00Wl0041204 N0CALL>APRS:)CD-violet!5000.00N\13026.00Wl0041304 N0CALL>APRS:)CD-yellow!5000.00N\13028.00Wl0041404 N0CALL>APRS:)CD-gray !5000.00N\13030.00Wl0041504 #Shape 1, Line Right N0CALL>APRS:)L-black !5001.00N\13000.00Wl104/004 N0CALL>APRS:)L-blue !5001.00N\13002.00Wl104/104 N0CALL>APRS:)L-green !5001.00N\13004.00Wl104/204 N0CALL>APRS:)L-cyan !5001.00N\13006.00Wl104/304 N0CALL>APRS:)L-red !5001.00N\13008.00Wl104/404 N0CALL>APRS:)L-violet !5001.00N\13010.00Wl104/504 N0CALL>APRS:)L-yellow !5001.00N\13012.00Wl104/604 N0CALL>APRS:)L-gray !5001.00N\13014.00Wl104/704 N0CALL>APRS:)LD-black !5001.00N\13016.00Wl104/804 N0CALL>APRS:)LD-blue !5001.00N\13018.00Wl104/904 N0CALL>APRS:)LD-green !5001.00N\13020.00Wl1041004 N0CALL>APRS:)LD-cyan !5001.00N\13022.00Wl1041104 N0CALL>APRS:)LD-red !5001.00N\13024.00Wl1041204 N0CALL>APRS:)LD-violet!5001.00N\13026.00Wl1041304 N0CALL>APRS:)LD-yellow!5001.00N\13028.00Wl1041404 N0CALL>APRS:)LD-gray !5001.00N\13030.00Wl1041504 #Shape 2, Open Ellipse, not defined by Bob N0CALL>APRS:)E-black !5002.00N\13000.00Wl204/004 N0CALL>APRS:)E-blue !5002.00N\13002.00Wl204/104 N0CALL>APRS:)E-green !5002.00N\13004.00Wl204/204 N0CALL>APRS:)E-cyan !5002.00N\13006.00Wl204/304 N0CALL>APRS:)E-red !5002.00N\13008.00Wl204/404 N0CALL>APRS:)E-violet !5002.00N\13010.00Wl204/504 N0CALL>APRS:)E-yellow !5002.00N\13012.00Wl204/604 N0CALL>APRS:)E-gray !5002.00N\13014.00Wl204/704 N0CALL>APRS:)ED-black !5002.00N\13016.00Wl204/804 N0CALL>APRS:)ED-blue !5002.00N\13018.00Wl204/904 N0CALL>APRS:)ED-green !5002.00N\13020.00Wl2041004 N0CALL>APRS:)ED-cyan !5002.00N\13022.00Wl2041104 N0CALL>APRS:)ED-red !5002.00N\13024.00Wl2041204 N0CALL>APRS:)ED-violet!5002.00N\13026.00Wl2041304 N0CALL>APRS:)ED-yellow!5002.00N\13028.00Wl2041404 N0CALL>APRS:)ED-gray !5002.00N\13030.00Wl2041504 #Shape 3, Open Triangle N0CALL>APRS:)T-black !5003.00N\13000.00Wl304/004 N0CALL>APRS:)T-blue !5003.00N\13002.00Wl304/104 N0CALL>APRS:)T-green !5003.00N\13004.00Wl304/204 N0CALL>APRS:)T-cyan !5003.00N\13006.00Wl304/304 N0CALL>APRS:)T-red !5003.00N\13008.00Wl304/404 N0CALL>APRS:)T-violet !5003.00N\13010.00Wl304/504 N0CALL>APRS:)T-yellow !5003.00N\13012.00Wl304/604 N0CALL>APRS:)T-gray !5003.00N\13014.00Wl304/704 N0CALL>APRS:)TD-black !5003.00N\13016.00Wl304/804 N0CALL>APRS:)TD-blue !5003.00N\13018.00Wl304/904 N0CALL>APRS:)TD-green !5003.00N\13020.00Wl3041004 N0CALL>APRS:)TD-cyan !5003.00N\13022.00Wl3041104 N0CALL>APRS:)TD-red !5003.00N\13024.00Wl3041204 N0CALL>APRS:)TD-violet!5003.00N\13026.00Wl3041304 N0CALL>APRS:)TD-yellow!5003.00N\13028.00Wl3041404 N0CALL>APRS:)TD-gray !5003.00N\13030.00Wl3041504 #Shape 4, Open Box N0CALL>APRS:)B-black !5004.00N\13000.00Wl404/004 N0CALL>APRS:)B-blue !5004.00N\13002.00Wl404/104 N0CALL>APRS:)B-green !5004.00N\13004.00Wl404/204 N0CALL>APRS:)B-cyan !5004.00N\13006.00Wl404/304 N0CALL>APRS:)B-red !5004.00N\13008.00Wl404/404 N0CALL>APRS:)B-violet !5004.00N\13010.00Wl404/504 N0CALL>APRS:)B-yellow !5004.00N\13012.00Wl404/604 N0CALL>APRS:)B-gray !5004.00N\13014.00Wl404/704 N0CALL>APRS:)BD-black !5004.00N\13016.00Wl404/804 N0CALL>APRS:)BD-blue !5004.00N\13018.00Wl404/904 N0CALL>APRS:)BD-green !5004.00N\13020.00Wl4041004 N0CALL>APRS:)BD-cyan !5004.00N\13022.00Wl4041104 N0CALL>APRS:)BD-red !5004.00N\13024.00Wl4041204 N0CALL>APRS:)BD-violet!5004.00N\13026.00Wl4041304 N0CALL>APRS:)BD-yellow!5004.00N\13028.00Wl4041404 N0CALL>APRS:)BD-gray !5004.00N\13030.00Wl4041504 #Shape 5, Color-Filled Circle N0CALL>APRS:)CF-black !5005.00N\13000.00Wl504/004 N0CALL>APRS:)CF-blue !5005.00N\13002.00Wl504/104 N0CALL>APRS:)CF-green !5005.00N\13004.00Wl504/204 N0CALL>APRS:)CF-cyan !5005.00N\13006.00Wl504/304 N0CALL>APRS:)CF-red !5005.00N\13008.00Wl504/404 N0CALL>APRS:)CF-violet!5005.00N\13010.00Wl504/504 N0CALL>APRS:)CF-yellow!5005.00N\13012.00Wl504/604 N0CALL>APRS:)CF-gray !5005.00N\13014.00Wl504/704 N0CALL>APRS:)CFDblack !5005.00N\13016.00Wl504/804 N0CALL>APRS:)CFDblue !5005.00N\13018.00Wl504/904 N0CALL>APRS:)CFDgreen !5005.00N\13020.00Wl5041004 N0CALL>APRS:)CFDcyan !5005.00N\13022.00Wl5041104 N0CALL>APRS:)CFDred !5005.00N\13024.00Wl5041204 N0CALL>APRS:)CFDviolet!5005.00N\13026.00Wl5041304 N0CALL>APRS:)CFDyellow!5005.00N\13028.00Wl5041404 N0CALL>APRS:)CFDgray !5005.00N\13030.00Wl5041504 #Shape 6, Line Left N0CALL>APRS:)L2-black !5006.00N\13000.00Wl604/004 N0CALL>APRS:)L2-blue !5006.00N\13002.00Wl604/104 N0CALL>APRS:)L2-green !5006.00N\13004.00Wl604/204 N0CALL>APRS:)L2-cyan !5006.00N\13006.00Wl604/304 N0CALL>APRS:)L2-red !5006.00N\13008.00Wl604/404 N0CALL>APRS:)L2-violet!5006.00N\13010.00Wl604/504 N0CALL>APRS:)L2-yellow!5006.00N\13012.00Wl604/604 N0CALL>APRS:)L2-gray !5006.00N\13014.00Wl604/704 N0CALL>APRS:)L2Dblack !5006.00N\13016.00Wl604/804 N0CALL>APRS:)L2Dblue !5006.00N\13018.00Wl604/904 N0CALL>APRS:)L2Dgreen !5006.00N\13020.00Wl6041004 N0CALL>APRS:)L2Dcyan !5006.00N\13022.00Wl6041104 N0CALL>APRS:)L2Dred !5006.00N\13024.00Wl6041204 N0CALL>APRS:)L2Dviolet!5006.00N\13026.00Wl6041304 N0CALL>APRS:)L2Dyellow!5006.00N\13028.00Wl6041404 N0CALL>APRS:)L2Dgray !5006.00N\13030.00Wl6041504 #Shape 7, Color-Filled Ellipse, not defined by Bob N0CALL>APRS:)E2-black !5007.00N\13000.00Wl704/004 N0CALL>APRS:)E2-blue !5007.00N\13002.00Wl704/104 N0CALL>APRS:)E2-green !5007.00N\13004.00Wl704/204 N0CALL>APRS:)E2-cyan !5007.00N\13006.00Wl704/304 N0CALL>APRS:)E2-red !5007.00N\13008.00Wl704/404 N0CALL>APRS:)E2-violet!5007.00N\13010.00Wl704/504 N0CALL>APRS:)E2-yellow!5007.00N\13012.00Wl704/604 N0CALL>APRS:)E2-gray !5007.00N\13014.00Wl704/704 N0CALL>APRS:)E2Dblack !5007.00N\13016.00Wl704/804 N0CALL>APRS:)E2Dblue !5007.00N\13018.00Wl704/904 N0CALL>APRS:)E2Dgreen !5007.00N\13020.00Wl7041004 N0CALL>APRS:)E2Dcyan !5007.00N\13022.00Wl7041104 N0CALL>APRS:)E2Dred !5007.00N\13024.00Wl7041204 N0CALL>APRS:)E2Dviolet!5007.00N\13026.00Wl7041304 N0CALL>APRS:)E2Dyellow!5007.00N\13028.00Wl7041404 N0CALL>APRS:)E2Dgray !5007.00N\13030.00Wl7041504 #Shape 8, Color-Filled Triangle N0CALL>APRS:)T2-black !5008.00N\13000.00Wl804/004 N0CALL>APRS:)T2-blue !5008.00N\13002.00Wl804/104 N0CALL>APRS:)T2-green !5008.00N\13004.00Wl804/204 N0CALL>APRS:)T2-cyan !5008.00N\13006.00Wl804/304 N0CALL>APRS:)T2-red !5008.00N\13008.00Wl804/404 N0CALL>APRS:)T2-violet!5008.00N\13010.00Wl804/504 N0CALL>APRS:)T2-yellow!5008.00N\13012.00Wl804/604 N0CALL>APRS:)T2-gray !5008.00N\13014.00Wl804/704 N0CALL>APRS:)T2Dblack !5008.00N\13016.00Wl804/804 N0CALL>APRS:)T2Dblue !5008.00N\13018.00Wl804/904 N0CALL>APRS:)T2Dgreen !5008.00N\13020.00Wl8041004 N0CALL>APRS:)T2Dcyan !5008.00N\13022.00Wl8041104 N0CALL>APRS:)T2Dred !5008.00N\13024.00Wl8041204 N0CALL>APRS:)T2Dviolet!5008.00N\13026.00Wl8041304 N0CALL>APRS:)T2Dyellow!5008.00N\13028.00Wl8041404 N0CALL>APRS:)T2Dgray !5008.00N\13030.00Wl8041504 #Shape 9, Color-Filled Box N0CALL>APRS:)B2-black !5009.00N\13000.00Wl904/004 N0CALL>APRS:)B2-blue !5009.00N\13002.00Wl904/104 N0CALL>APRS:)B2-green !5009.00N\13004.00Wl904/204 N0CALL>APRS:)B2-cyan !5009.00N\13006.00Wl904/304 N0CALL>APRS:)B2-red !5009.00N\13008.00Wl904/404 N0CALL>APRS:)B2-violet!5009.00N\13010.00Wl904/504 N0CALL>APRS:)B2-yellow!5009.00N\13012.00Wl904/604 N0CALL>APRS:)B2-gray !5009.00N\13014.00Wl904/704 N0CALL>APRS:)B2Dblack !5009.00N\13016.00Wl904/804 N0CALL>APRS:)B2Dblue !5009.00N\13018.00Wl904/904 N0CALL>APRS:)B2Dgreen !5009.00N\13020.00Wl9041004 N0CALL>APRS:)B2Dcyan !5009.00N\13022.00Wl9041104 N0CALL>APRS:)B2Dred !5009.00N\13024.00Wl9041204 N0CALL>APRS:)B2Dviolet!5009.00N\13026.00Wl9041304 N0CALL>APRS:)B2Dyellow!5009.00N\13028.00Wl9041404 N0CALL>APRS:)B2Dgray !5009.00N\13030.00Wl9041504 Xastir-Release-2.2.4/scripts/geopdf2gtiff.pl0000775000175000017500000001640615151324131017725 0ustar hibbyhibby#!/usr/bin/env perl ############################################################################### # # Portions Copyright (C) 2000-2026 The Xastir Group # # Script to convert a GeoPDF file with included neatline into a collar-stripped # geotiff in EPSG:4326 projection (WGS84 equidistant cylindrical) in 8-bit # color. # # You must have installed GDAL/OGR, configured to use python in order to use # this script. This is because the script attempts to run rgb2pct.py, which # is only installed if you've built GDAL with python support. # # This also depends on the -cutline and -crop_to_cutline features of # gdalwarp, which are only present in versions of GDAL after 1.8.1. # # Last Edit:$Date$ # Revision:$Revision$ # Last Edited By: $Author$ ############################################################################### use Getopt::Long; my $fudgeNeatline; $result=GetOptions("fixneatline|f"=>\$fudgeNeatline); # Input file is a geopdf: if ($#ARGV<0) { print STDERR "Usage: $0 \n"; exit 1; } my $inputPDF=$ARGV[0]; if (! -e $inputPDF) { print STDERR "File $inputPDF does not exist.\n"; exit 1; } open GDALINFO, "gdalinfo $inputPDF |" or die "can't fork $!"; my $readingCoordSys=0; my $coordSys=""; my $readingMetadata=0; my $neatlinePoly=""; my $minLat=360,$maxLat=-360,$minLon=360,$maxLon=-360,$templat,$templon; while () { if (/^Driver: (.*)$/) { if ($1 ne "PDF/Geospatial PDF") { print STDERR "This script is intended to run only on GeoPDF input files.\n"; exit 1; } next; } if (/^Coordinate System is:/) { $readingCoordSys=1; next; } if ($readingCoordSys == 1) { # This is tricky --- finding the end of the coordinate system # means looking for the first line that starts in column 1 that isn't # the first line of the coordinate system. All lines of the coordinate # system other than the first start with space. if (/^[^ ]/ && $coordSys ne "") { $readingCoordSys=0; next; } else { chomp($_); $coordSys .= $_; next; } } if (/^Metadata:/) { $readingMetadata=1; next; } if ($readingMetadata==1) { if (/^Corner Coordinates:/) { $readingMetadata=0; next; } if (/^ *NEATLINE=(.*)$/) { $neatlinePoly=$1; next; } } if (/^Band ([0-9]+).*Type=([^,]*)/) { $bandinfo[$#bandinfo+1]=$2; next; } if (/^(Upper|Lower) (Left|Right)/) { s/(Upper|Lower) (Left|Right) *\([^)]*\) *//; /\(([^,]*), *([^\)]*)\)/; $templonstr=$1; $templatstr=$2; $templonstr =~ /([0-9]*)d( *[0-9]*)'( *[0-9.]*)"([EW])/; $deg=$1; $min=$2; $sec=$3; $hem=$4; $templon=$deg+$min/60+$sec/3600; $templon *= -1 if ($hem eq "W"); $minLon=$templon if ($templon<$minLon); $maxLon=$templon if ($templon>$maxLon); $templatstr =~ /([0-9]*)d( *[0-9]*)'( *[0-9.]*)"([NS])/; $deg=$1; $min=$2; $sec=$3; $hem=$4; $templat=$deg+$min/60+$sec/3600; $templat *= -1 if ($hem eq "S"); $minLat=$templat if ($templat<$minLat); $maxLat=$templat if ($templat>$maxLat); } } close GDALINFO; if (! $fudgeNeatline) { # Create a CSV for the neatline. OGR will recognize this geometry open CSVFILE, ">$inputPDF.csv"; print CSVFILE "foo,WKT\n"; print CSVFILE "bar,\"$neatlinePoly\"\n"; close CSVFILE; # Unfortunately, there's no easy way to attach a spatial reference system # (SRS) to the csv file so that gdalwarp will recognize it. So make a # virtual layer out of the CSV with the reference system in it. open VRTFILE, ">$inputPDF.vrt"; print VRTFILE "\n"; print VRTFILE " \n"; print VRTFILE " $coordSys\n"; print VRTFILE " $inputPDF.csv\n"; print VRTFILE " wkbPolygon\n"; print VRTFILE " WKT\n"; print VRTFILE " \n"; print VRTFILE "\n"; close VRTFILE; } else { print "User asked us to fudge the neatline, finding nearest 7.5 minute quad boundaries\n"; # Instead of using the neatline specified, round it to nearest 7.5' # quad boundary $left=(int((abs($minLon)-int(abs($minLon)))/.125+.5)*.125+int(abs($minLon)))*($minLon/abs($minLon)); $right=(int((abs($maxLon)-int(abs($maxLon)))/.125+.5)*.125+int(abs($maxLon)))*($maxLon/abs($maxLon)); if ($maxLon<0) { $temp=$left; $left=$right; $right=$temp; } $bottom=(int((abs($minLat)-int(abs($minLat)))/.125+.5)*.125+int(abs($minLat)))*($minLat/abs($minLat)); $top=(int((abs($maxLat)-int(abs($maxLat)))/.125+.5)*.125+int(abs($maxLat)))*($maxLat/abs($maxLat)); if ($maxLat<0) { $temp=$top; $top=$bottom; $bottom=$temp; } open CSVFILE, ">$inputPDF.csv"; print CSVFILE "foo,WKT\n"; print CSVFILE "bar,\"POLYGON(($left $top,$right $top, $right $bottom, $left $bottom, $left $top))\"\n"; close CSVFILE; # Unfortunately, there's no easy way to attach a spatial reference system # (SRS) to the csv file so that gdalwarp will recognize it. So make a # virtual layer out of the CSV with the reference system in it. open VRTFILE, ">$inputPDF.vrt"; print VRTFILE "\n"; print VRTFILE " \n"; print VRTFILE " EPSG:4326\n"; print VRTFILE " $inputPDF.csv\n"; print VRTFILE " wkbPolygon\n"; print VRTFILE " WKT\n"; print VRTFILE " \n"; print VRTFILE "\n"; close VRTFILE; } # The VRT virtual source will now appear to gdal warp as a complete # specification of the neatline, with both coordinates *AND* description of # the coordinate system. This will enable gdalwarp to do the clipping of the # neatline *AND* conversion to a different coordinate system in the same # operation. Had we not done the vrt, gdalwarp would have assumed the # neatline to be in the coordinates of the DESTINATION raster, not the # source raster. $outputTif=$inputPDF; $outputTif =~ s/pdf/tif/i; # We will warp from whatever the coordinate system is into EPSG:4326, the # coordinate system that requires the least work and involves the fewest # approximations from Xastir. #$theGdalWarp="gdalwarp -cutline $inputPDF.vrt -crop_to_cutline -t_srs EPSG:4326 -co \"COMPRESS=PACKBITS\" $inputPDF $outputTif"; $theGdalWarp="gdalwarp -cutline $inputPDF.vrt -crop_to_cutline -t_srs EPSG:4326 $inputPDF $outputTif"; system ($theGdalWarp) == 0 or die "System $theGdalWarp failed: $?"; if ($#bandinfo>0) { print "This is a multi-band raster, dithering...\n"; system ("mv $outputTif $$.tif"); # $theRGB2PCT="rgb2pct.py $$.tif $$-2.tif"; $theRGB2PCT="rgb2pct.py $$.tif $outputTif"; system ($theRGB2PCT) == 0 or die "Could not run rgb2pct: $?"; # system("gdal_translate -co \"COMPRESS=PACKBITS\" $$-2.tif $outputTif") == 0 or die "Could not gdal_translate: $?"; system("rm -f $$.tif $$-2.tif"); } # now clean up our mess: system ("rm $inputPDF.csv $inputPDF.vrt"); Xastir-Release-2.2.4/scripts/get-BOMdata.in0000775000175000017500000000551415151324131017374 0ustar hibbyhibby#!/bin/sh # # # Script to retrieve BOM data files. # # Originally written 2006/03/07 by Steven, WM5Z, and Curt, WE7U. # Modified from original get-NWSdata script by Geoff VK2XJG. # # Copyright (C) 2000-2026 The Xastir Group # # 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # See README.MAPS for a bit more information on the program. # # # NOTE: Run this script as root. # # MAINTAINERS: Go here to find out what the latest versions are: # FILE1="gfe_public_weather" # BOM Spatial: Public Warning Zone Boundaries FILE2="gfe_metro_areas" # BOM Spatial: Metropolitan Warning Area Boundaries FILE3="gfe_coastal_water" # BOM Spatial: Coastal Forecast Marine Zones FILE4="gfe_coastal_water_warning" # BOM Spatial: Coastal Warning Zones FILE5="gfe_local_effects" # BOM Spatial: Local Effects Areas FILE6="gfe_fire_weather" # BOM Spatial: Fire Weather Zone Boundaries FILE7="LGA08aAust" # Local Government Area Boundaries prefix=@prefix@ cd ${prefix}/share/xastir/Counties # Remove any old zip files hanging around in this directory # rm -f *.zip 2>&1 >/dev/null # Fetch new copies, unzip into place, delete archive. # # DIR=wsom for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6; do if [ -e $d.shp ] then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-30 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget ftp://ftp.bom.gov.au/anon/home/adfd/spatial/$d.zip unzip $d.zip rm -f *.zip mv $d*.shx $d.shx 2>&1 >/dev/null mv $d*.shp $d.shp 2>&1 >/dev/null mv $d*.dbf $d.dbf 2>&1 >/dev/null mv $d*.prj $d.prj 2>&1 >/dev/null mv $d*.sbx $d.sbx 2>&1 >/dev/null mv $d*.sbn $d.sbn 2>&1 >/dev/null fi done DIR=county for d in $FILE7; do if [ -e $d.shp ] then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget http://wxsvr.aprs.net.au/shapefiles/$d\_shape.zip unzip $d\_shape.zip rm -f *.zip fi done Xastir-Release-2.2.4/scripts/get-NWSdata.in0000775000175000017500000001061215151324131017421 0ustar hibbyhibby#!/bin/sh # # Script to retrieve NWS data files. # # Run this from the INSTALLED location of the script, i.e. # /usr/local/share/xastir/scripts # or /usr/share/xastir/scripts # # # Originally written 2006/03/07 by Steven, WM5Z, and Curt, WE7U. # # Copyright (C) 2000-2026 The Xastir Group # # 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # See README.MAPS for a bit more information on the program. # # # NOTE: Run this script as root. # # MAINTAINERS: Go here to find out what the latest versions are: # # # Please only have ONE of each variable listed here! Note that the "Valid # Date" listed on the NWS web pages is the date at which the Shapefile # should START to be used. Don't just blindly put the newest filename # here if that start-date hasn't arrived yet! # FILE1="w_03mr26" # GREEN: NWSM Library: County Warning Area Boundaries FILE2="z_03mr26" # GREEN: NWSM Library: Public Forecast Zone Boundaries FILE3="mz03mr26" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE4="oz03mr26" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE5="hz20fe25" # GREEN: NWSM Library: Coastal and Offshore Marine Zones FILE6="fz03mr26" # GREEN: NWSM Library: Fire Weather Zone Boundaries FILE7="c_03mr26" # RED: Counties, States, Provinces: U.S. Counties prefix=@prefix@ cd ${prefix}/share/xastir/Counties || exit 1 # Remove any old zip files hanging around in this directory # rm -f *.zip 2>&1 >/dev/null # Fetch new copies, unzip into place, delete archive. # # DIR=WSOM for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6; do if [ -e $d.shp ]; then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget https://www.weather.gov/source/gis/Shapefiles/$DIR/$d.zip unzip $d.zip rm -f *.zip fi done DIR=County for d in $FILE7; do if [ -e $d.shp ]; then echo "Already have $d shapefile, skipping..." else # Remove possible older copies cut=`echo $d|cut -c1-2 -` rm -f $cut*.shx $cut*.shp $cut*.dbf $cut*.prj $cut*.zip 2>&1 >/dev/null wget https://www.weather.gov/source/gis/Shapefiles/$DIR/$d.zip unzip $d.zip rm -f *.zip fi done #################### # After download/install of map files above, run commands such as these: # # cd /usr/local/share/xastir; testdbfawk -D config -d Counties/mz11au16.dbf 2>&1 | head -5 # cd /usr/local/share/xastir; testdbfawk -D config -d Counties/w_11au16.dbf 2>&1 | head -5 # # to determine whether there's dbfawk support for each of the NWS files. NWS # changes the signature on their files often so we need to create a new # dbfawk for each in xastir/config, test it, then add it into the # Makefile.am file there and commit, then do another "make install" to put # the dbfawk's into place. # Fixed the issue where there's an 'a' or 'b' after the filename root. NWS likes # to do that, but have non-a/b files extracted from the zip, which made the below # tests fail. #################### # exitcode=0 for d in $FILE1 $FILE2 $FILE3 $FILE4 $FILE5 $FILE6 $FILE7; do e=`echo $d | sed -e's/\(.*[0-9]\)[a-f]$/\1/'` if [ -e $e.dbf ]; then echo echo $e.dbf # Run in a separate shell so we don't mess up the current directory for the -e test above result=`cd ${prefix}/share/xastir; ${prefix}/bin/testdbfawk -D config -d Counties/$e.dbf 2>&1 | head -3 | tail -1` echo $result if [ "$result" = "No matching dbfawk signature found" ]; then echo "Fix dbfawk for $e!" exitcode=1 fi fi done echo if [ $exitcode -eq 1 ] ; then echo "One or more dbfawk files is out of date. Fix the problem." fi exit $exitcode Xastir-Release-2.2.4/scripts/get-fcc-rac.pl.in0000775000175000017500000000766215151324131020043 0ustar hibbyhibby#!/usr/bin/env perl # # # Copyright (C) 2000-2026 The Xastir Group # # 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # Updated on 7/5/03 to reflect the new directory structure # N0VH # # Note: Run this script as root in order to write the files into the # destination directory listed below, or change directory write access. use File::Basename; $prefix="@prefix@"; my $XASTIR_BASE="${prefix}/share/xastir"; # This script uses temporary storage space in /var/tmp to do its work. chdir "/var/tmp"; ##################################################################### # Get the RAC database, process it. # Download size: ~2MB # Final file size: ~13MB ##################################################################### # $file = "amateur.zip"; #$file2 = "amateur.rpt"; $file2 = "amateur.txt"; print STDERR "*********************************\n"; print STDERR "*** Fetching the RAC database ***\n"; print STDERR "*********************************\n"; #`wget -c http://205.236.99.41/%7Eindicatif/download/$file`; `wget -c http://apc-cap.ic.gc.ca/datafiles/$file`; if (-e $file && -r $file && -f $file) { print STDERR "***********************************\n"; print STDERR "*** Installing the RAC database ***\n"; print STDERR "***********************************\n"; `unzip $file $file2`; `mv $file2 $XASTIR_BASE/fcc/AMACALL.LST`; } # Remove the RAC download files unlink $file, $file2; ##################################################################### # Get the FCC database, process it. # Download size: ~84MB # Final file size: ~101MB ##################################################################### # my $file = "l_amat.zip"; my $file2 = "EN.dat"; print STDERR "*********************************\n"; print STDERR "*** Fetching the FCC database ***\n"; print STDERR "*********************************\n"; `wget -c ftp://wirelessftp.fcc.gov/pub/uls/complete/$file`; if (-e $file && -r $file && -f $file) { my $file_out = "$XASTIR_BASE/fcc/$file2"; # Get rid of characters "^M^M^J" which are sometimes present, sort # the file by callsign & remove old entries for vanity call access. print STDERR "*****************************************************\n"; print STDERR "*** Filtering/sorting/installing the FCC database ***\n"; print STDERR "*****************************************************\n"; my %from = (); open FILE, "unzip -p $file $file2|" or die "Can't open $file2 in $file : $!"; open FILE_OUT, '|-', "sort -k 5,5 -t \\| -o $file_out" or die "Can't sort $file_out : $!"; while( ) { if (/^EN\|(\d+)\|\|\|(\w+)\|.*/) { $x = $1; $z = $2; chop; chop; $y = $_; if (defined $from{$2}) { # check for vanity reassignment if ($from{$z} =~ /^EN\|(\d+)\|\|\|(\w+)\|.*/) { if ($1 < $x) { $replaced++; $from{$2} = $y; } } } else { $from{$2} = $_; } } } close FILE; for my $callsign ( keys %from ) { $total++; print FILE_OUT "$from{$callsign}\n"; } close FILE_OUT; print STDERR "Total callsigns: " . $total . ".\n"; print STDERR " Replaced callsigns: " . $replaced . ".\n"; } # Remove the FCC download files unlink $file; print STDERR "*************\n"; print STDERR "*** Done! ***\n"; print STDERR "*************\n"; Xastir-Release-2.2.4/scripts/gpx2shape0000775000175000017500000001376515151324131016653 0ustar hibbyhibby#!/usr/bin/env perl # # Copyright (C) 2006 James Washer # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # use strict; use XML::Simple; use Getopt::Std; use Geo::Shapelib qw/:all/; my $routenum=1; my @vertices; my $shp; my ($comment,$notes,$elevation)=("no comment", "no note",-9999); my %shapetype = ( wpt => 1, rte => 3, trk => 3 ); our ( $opt_v, $opt_t, $opt_w, $opt_r, $opt_d, $opt_s); getopts("vtwrds");#v=verbose t=tracks w=waypoints r=routes d=dbfawk s=shapefile_prefix print " args are \"@ARGV\"vals are $opt_t, $opt_w, $opt_r, $opt_d\n" if $opt_v; my $f = $ARGV[0]; $opt_s =$ARGV[0]; $opt_s =~ s/.gpx$//; print "shapename is $opt_s\n" if $opt_v; my $xml = XMLin($f,ForceArray => 1); process_rte() if $opt_r; process_trk() if $opt_t; process_wpt() if $opt_w; exit; sub dumpit{ use Data::Dumper; print Dumper($xml); exit; } ################################################################# ###################### SHAPEFILE SETUP ####################### ################################################################# sub init_shape{ my $type=shift; $shp = new Geo::Shapelib; $shp->{Name}=${opt_s}."-".$type; $shp->{Shapetype}= $shapetype{$type}; $shp->{FieldNames} = [ 'Name', 'Comment', 'Notes', 'Elevation' ]; $shp->{FieldTypes} = [ 'String:40','String:40','String:100','Integer:8' ]; } sub save_shape{ $shp->save(); } sub do_shape{ my($type,$name,$comment,$notes,$elevation)=@_; push @{$shp->{Shapes}}, { SHPType => $shapetype{$type}, ShapeID => $name, NVertices => scalar @vertices, Vertices => [ @vertices ] }; push @{$shp->{ShapeRecords}}, [ $name, $comment, $notes, $elevation]; print "\t\tdo_shape $name $type ",scalar @vertices,"\n" if $opt_v; } ################################################################# ###################### ROUTE PROCESSING ####################### ################################################################# sub process_rte{ print "Process Route called\n"; unless(exists $xml->{rte}){ print "\tNo Routes\n" if $opt_v; return; } my $aref=$xml->{rte}; return unless defined $aref; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('rte'); foreach my $rref ( @$aref ){ my $name="Route.$routenum++"; $name=$rref->{name}->[0] if defined $rref->{name}; print "\tProcessing route \"$name\"\n" if $opt_v; @vertices=(); do_route($rref->{rtept}); do_shape('rte',$name,"","",""); } save_shape(); } sub do_route{ my $rtept_ref=shift; die "do_route Unexpected reference $rtept_ref\n" unless ref($rtept_ref) eq "ARRAY"; foreach my $rtept ( @$rtept_ref ){ #print "\t\t$rtept->{lon} $rtept->{lat} $rtept->{name}->[0] $rtept->{sym}->[0]\n"; my $snell=get_snell($rtept); print_snell($snell) if $opt_v; push @vertices, [ $snell->{lon}, $snell->{lat} ]; } } ################################################################# ###################### TRACK PROCESSING ####################### ################################################################# sub process_trk{ print "Process Track called\n"; unless(exists $xml->{trk}){ print "\tNo Tracks\n" if $opt_v; return; } my $aref=$xml->{trk}; my $aref=$xml->{trk}; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('trk'); foreach my $tref( @$aref ){ print "Track $tref->{name}->[0]\n" if $opt_v; @vertices=(); foreach my $ele ( @{$tref->{trkseg}->[0]->{trkpt}}){ my $snell=get_snell($ele); print_snell($snell) if $opt_v; push @vertices, [ $snell->{lon}, $snell->{lat} ]; } do_shape('trk',$tref->{name}->[0],"","",""); } save_shape(); } sub do_trk{ my $trk_aref=shift; die "Unexpected reference $trk_aref\n" unless ref($trk_aref) eq "ARRAY"; } ################################################################# ##################### WAYPOINT PROCESSING ####################### ################################################################# sub process_wpt{ print "Process Waypoint called\n"; unless(exists $xml->{wpt}){ print "\tNo Waypoints\n" if $opt_v; return; } my $aref=$xml->{wpt}; die "Unexpected reference $aref\n" unless ref($aref) eq "ARRAY"; init_shape('wpt'); foreach my $wref ( @$aref ){ my $snell=get_snell($wref); print_snell($snell) if $opt_v; @vertices=[ $snell->{lon}, $snell->{lat} ]; do_shape('wpt',$snell->{name},$snell->{cmt},$snell->{ele}); } save_shape(); } ################################################################# ################################################################# ################################################################# #cute "SNELL" is Symbol Name Elevation Latitude Longitude sub get_snell { my $ref=shift; my %val=(lat => "0.0", lon => "0.0", ele => "0.0", name => "NoName", sym => "Waypoint", cmt => "NoComment"); $val{lon}=$ref->{lon} if exists $ref->{lon}; $val{lat}=$ref->{lat} if exists $ref->{lat}; $val{name}=$ref->{name}->[0] if exists $ref->{name} and exists $ref->{name}->[0]; $val{sym}=$ref->{sym}->[0] if exists $ref->{sym}; $val{ele}=$ref->{ele}->[0] if exists $ref->{ele}; $val{cmt}=$ref->{cmt}->[0] if exists $ref->{cmt}; return \%val; } sub print_snell { my $snell=shift; print "\t\t$snell->{lon} $snell->{lat} $snell->{ele} $snell->{name} $snell->{sym}\n"; } ################################################################# ################################################################# ################################################################# Xastir-Release-2.2.4/scripts/icontable.pl.in0000775000175000017500000001205315151324131017716 0ustar hibbyhibby#!/usr/bin/env perl # XASTIR icon table overview generator 20.02.01 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an overview graphics with all symbols used by Xastir # Output is as a XPM file to STDOUT # typical call: icontable.pl > symbols.xpm #-------------------------------------------------------------------------- use File::Basename; $prefix="@prefix@"; # symbols file from XASTIR V2.1, change the path for your environment $SYMBFILE = $prefix."/share/xastir/symbols/symbols.dat"; #-------------------------------------------------------------------------- %sympix = (); $lasttable = $table; $lastsymbol = $symbol; $tablist = "/\\"; @coltab = qw(#FFFF00 #CD6500 #A020F0 #CCCCCC #CD0000 #FF4040 #CD3333 #00008B #00BFFF #006400 #EE0000 #00CD00 #0000CD #FFFFFF #5A5A5A #878787 #454545 #000000 None); setuppics(); #storepics(); # store all icons as separate XPM files exit; #-------------------------------------------------------------------------- sub setuppics { my $table = ''; my $symbol = ''; my ($i,$j,$c); my $line; my $head; my $str; my $pix; my $pixstr; if (-f $SYMBFILE) { if (open(FH, "<$SYMBFILE")) { my %col = (); SYM: while() { last if (/DONE/); if (/TABLE (.)/) { $table = $1; if(length($_)>20) { $descr = 1 } next; } if (/APRS (.)/) { $symbol = $1; next if ($table ne '/' && $table ne '\\'); # ignore other $pixstr = ''; for ($i=0;$i<20;$i++) { $line = ; $line =~ s/\n//; $line =~ s/\r//; next SYM if (length($line) != 20); $pixstr .= $line; for ($j=0;$j<20;$j++) { $c = substr($line,$j,1); $col{$c} = $c; } } $sympix{$table.$symbol} = $pixstr; } } $str = ""; for ($i=0;$i<20;$i++) { $str .= "...................."; } $sympix{" "} = $str; $head = ''; $j = 0; foreach $c (keys %col) { $head .= colstr($c); $j++; } $head = "/* XPM */{\"337 258 $j 1 \",\n".$head; # 12 lines with 16 symbols each x 337 y $pix = ""; foreach $table ("/","\\") { for ($i=2;$i<8;$i++) { # symbol row $pix .= "\"".("q" x 337)."\",\n"; # black hor line for ($j=0;$j<20;$j++) { # scan line $pix .= "\""; # start of scan line for ($k=0;$k<16;$k++) { # symbol column $pix .= "q"; # vert line $symbol = chr($i*16+$k); $pix .= substr(getpic($table.$symbol),$j*20,20); } $pix .= "q\",\n"; # vert line } } if ($table eq "\\") { # { $pix .= "\"".("q" x 337)."\"};\n"; # black hor line } else { $pix .= "\"".("q" x 337)."\",\n"; # black hor line for ($i=0;$i<4;$i++) { $pix .= "\"".("." x 337)."\",\n"; # hor space } } } printf($head.$pix); close(FH); } } } #-------------------------------------------------------------------------- sub colstr { # setup string for color my ($c) = @_; if ($c eq '#') { # Yellow $cidx = 0; } elsif ($c ge 'a' && $c le 'q') { $cidx = ord($c)-ord('a')+1; } else { $cidx = @coltab-1; # Transparent } return("\"$c c $coltab[$cidx]\",\n"); } #-------------------------------------------------------------------------- sub getpic { my ($id) = @_; $str = $sympix{$id}; if (! $str) { $str = $sympix{" "}; # default } $str; } #-------------------------------------------------------------------------- sub storepics { # extract all icons to files foreach $cc (keys %sympix) { $fname = sprintf("Aprs%2.2X%2.2X.xpm",ord(substr($cc,0,1)),ord(substr($cc,1,1))); if (open(FH,">$fname")) { printf(FH "%s",getpic($cc)); close(FH); } } } #-------------------------------------------------------------------------- Xastir-Release-2.2.4/scripts/inf2geo.pl0000775000175000017500000001517215151324131016707 0ustar hibbyhibby#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # # # Invoke this script against one or more info files by typing: # # inf2geo.pl filename.inf # -or- # inf2geo.pl *.inf # # To process all .inf files in that directory. # # Note: This script requires GraphicsMagick or ImageMagick packages # to be installed before it will function properly. Install one of # these via your package manager. # # # What the script does for you: # Read in .inf file (from Ui-View) # Convert the lat/long coordinates into dd.dddd format # Get the image extents via "identify -ping filename" or # "gm identify -ping filename". # Write out the .geo file # Note that this program assumes (and converts to) # lower-case for the filename. # # Note: It appears that .INF files store the lat/lon # in DD.MM.MMMM format. Converting the script to this # format. # # 2003-08-15 ZL2UMF: add processing multiple files in one go (masks and whot-not) # so you can convert all your ui-view maps in one step #use strict; use IO::File; #go through every filename passed to this script #printf("ARGV:%d\n",$#ARGV); if ($#ARGV == -1) { # No filenames on the command line printf("\n\n\nNo filenames specified. Invoke this script against one\n"); printf("or more .inf files by typing:\n\n"); printf(" inf2geo.pl filename.inf\n"); printf("-or-\n"); printf(" inf2geo.pl *.inf\n\n"); printf("To process all .inf files in that directory.\n\n"); exit; } else { foreach my $file (@ARGV) { print "*** $file ***\n"; #make a geo of this file makeGeo ($file); } } exit; #just in case sub makeGeo { my $inf_filename = shift; my $filename = $inf_filename; $filename =~ s/\.inf$//i; my $geo_filename = $filename . ".geo"; # $inf = IO::File->new("< $ARGV[0].inf") # or $inf = IO::File->new("< $ARGV[0].INF") # or $inf = IO::File->new("< $ARGV[0].Inf") #skip this file if geo already exists return print "$filename.geo already exists, will not overwrite\n" if( -e "$filename.geo" ); #read the inf file my $inf = IO::File->new ( "< $inf_filename" ) or return print "\nCouldn't open $inf_filename for reading:\n$!\n\n"; #make the new geo file $geo = IO::File->new("> $geo_filename") or return print "Couldn't open $geo_filename for writing: $!\n"; $upper_left = $inf->getline(); my ($tp0_lon, $tp0_lat) = split(',', $upper_left); chomp($tp0_lat); # Reverse them if ( ($tp0_lat =~ /E/) || ($tp0_lat =~ /W/) ) { $temp = $tp0_lat; $tp0_lat = $tp0_lon; $tp0_lon = $temp; } $lower_right = $inf->getline(); ($tp1_lon, $tp1_lat) = split(',', $lower_right); chomp($tp1_lat); # Reverse them if ( ($tp1_lat =~ /E/) || ($tp1_lat =~ /W/) ) { $temp = $tp1_lat; $tp1_lat = $tp1_lon; $tp1_lon = $temp; } #do some maths $tp0_lat2 = &convert($tp0_lat) or return; $tp0_lon2 = &convert($tp0_lon) or return; $tp1_lat2 = &convert($tp1_lat) or return; $tp1_lon2 = &convert($tp1_lon) or return; my ($final_filename, $string) = &findImageFile($filename) or return; # The format returned by string changed from this: # test.gif 1148x830+0+0 PseudoClass 256c 48kb GIF 1s # to this: # test.gif GIF 1148x830+0+0 PseudoClass 256c Palette 8-bit 48kb 0.4u 0:01 # in later versions of ImageMagick. # # GraphicsMagick returns a string like this: # i4-mo.gif GIF 1020x581+0+0 PseudoClass 256c 8-bit 475.8k 0.050u 0:01 # chomp($string); $string =~ s/.*\s(\d+x\d+).*/$1/; # Grab the 1148x830 portion #print "String: $string\n"; $x = $y = $string; $x =~ s/(\d+)x\d+/$1/; $y =~ s/\d+x(\d+)/$1/; #print "X: $x\nY: $y\n"; $x1 = $x - 1; # We start numbering pixels at zero, not 1 $y1 = $y - 1; # We start numbering pixels at zero, not 1 #print "X: $x\nY: $y\n"; #print "X1: $x1\nY1: $y1\n"; #write to the geo file printf $geo "FILENAME $final_filename\n"; printf $geo "TIEPOINT 0\t\t0\t$tp0_lon2\t$tp0_lat2\n"; printf $geo "TIEPOINT $x1\t$y1\t$tp1_lon2\t$tp1_lat2\n"; printf $geo "IMAGESIZE $x\t$y\n"; printf $geo "#$string\n"; printf $geo "#\n# Converted from a .INF file by WE7U's inf2geo.pl script\n#\n"; $inf->close(); $geo->close(); } sub convert { #print "$_[0] -> "; ($dd,$mm,$mm2) = split('\.', $_[0]); $mm2 =~ s/(\d+).*/$1/; $mm = $mm . "\." . $mm2; $number = $dd + ($mm / 60.0); if ( ($_[0] =~ /S/) || ($_[0] =~ /s/) || ($_[0] =~ /W/) || ($_[0] =~ /w/) ) { $number = -$number; } # Latitude bound checking if ( ($_[0] =~ /S/) || ($_[0] =~ /s/) || ($_[0] =~ /N/) || ($_[0] =~ /n/) ) { if ($dd > 90) { print "Latitude degrees out-of-bounds: $dd. Must be <= 90\n"; return; } if ($mm >= 60) { print "Latitude minutes out-of-bounds: $mm. Must be < 60\n"; return; } if (abs($number) > 90.0) { print "Latitude out-of-bounds: $number. Must be between -90 and +90\n"; return; } } # Longitude bounds checking else { if ($dd > 180) { print "Longitude degrees out-of-bounds: $dd. Must be <= 180\n"; return; } if ($mm >= 60) { print "Longitude minutes out-of-bounds: $mm. Must be < 60\n"; return; } if (abs($number) > 180.0) { print "Longitude out-of-bounds: $number. Must be between -180 and +180\n"; return; } } #print "$number\n"; #print "Temp = $temp\n"; return($number); } sub findImageFile { $filename = shift; @extensions = ("gif", "bmp", "jpg", "png", "emf"); foreach $xtn (@extensions) { $try_filename = "$filename.$xtn"; # print "Looking for $try_filename\n"; # Try GraphicsMagick's 'gm' first $string = `gm identify -ping $try_filename 2>/dev/null`; if ($string eq "") { # Else try ImageMagick's 'identify' $string = `identify -ping $try_filename 2>/dev/null`; } if ($string ne "") { # Found the file and GM or IM $filename = $try_filename; $image_size = $string; } } if ($image_size eq "") { print "Image file not found for $filename, may be be a case problem\n" ; print "or a problem finding GraphicsMagick's 'gm' or ImageMagick's 'identify' program\n"; print "Make sure that either GraphicsMagick or ImageMagick is installed.\n"; return; } print "Found this image: $image_size\n"; return ($filename, $image_size); } Xastir-Release-2.2.4/scripts/kiss-off.pl0000775000175000017500000000235315151324131017074 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2004-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will send the proper characters to STDOUT to command a # KISS TNC out of KISS mode. Redirect it to the port that the TNC # is connected to. Turn off the port in Xastir first. # It is assumed that the baud rate on the port and the baud rate of # the TNC match, if not, this won't work. If you've just been using # the TNC in Xastir, they probably match. # Use the script like this: # # ./kiss-off.pl >/dev/ttyS1 # sleep 1; printf("%c%c%c", 192, 255, 192); sleep 1; Xastir-Release-2.2.4/scripts/kml_snapshot_feed.kml0000664000175000017500000000043715151324131021206 0ustar hibbyhibby http://www.example.com/tracks/screenshot.kml onExpire Xastir-Release-2.2.4/scripts/kml_snapshot_to_web.sh0000664000175000017500000000271015151324131021405 0ustar hibbyhibby#!/usr/bin/env bash # This shell script copies Xastir snapshots from the directory in which # they are created ~/.xastir/temp to a directory where a web server can deliver # them as a kml feed to overlay the current snapshot from on the terrain in a kml # capable application that is subscribed to the feed. # # You will need to set two parameters for this script: # 1. set DIR= to the directory into which you wish to copy the snapshot files. # This can be a directory on a remote webserver mounted using sshfs. # 2. change www.example.com to the address of your webserver. You will also # need to change the link specified in kml_snapshot_feed.kml # # You can copy the kml_snapshot_feed.kml into the web folder, and load the # http://www.example.com/tracks/kml_snapshot_feed.kml file into your KML # application instead of http://www.example.com/tracks/snapshot.kml, and run # this shell script with cron to periodically update the snapshot.kml file. # This should enable your KML application to refresh the snapshots in sync # with their creation by Xastir. # # Note: GE will load jpg files but not png files, so ImageMagick's # convert is used here to convert the snapshot.png produced by Xastir to # a snapshot.jpg file. # DIR=/var/www/htdocs/tracks cd ~/.xastir/tmp convert ./snapshot.png $DIR/snapshot.jpg cat snapshot.kml | gawk -- ' { gsub(//,"&http://www.example.com/tracks/") } { gsub(/snapshot.png/,"snapshot.jpg") } { print } ' > $DIR/snapshot.kml Xastir-Release-2.2.4/scripts/langElmerFudd.pl0000775000175000017500000000453215151324131020065 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langElmerFudd.pl -split language-ElmerFudd.sys # or # ../scripts/langElmerFudd.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://www.siafoo.net/snippet/133 # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-ElmerFudd.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/[rl]/w/g; s/[RL]/W/g; s/([Qq])u/$1w/g; s/th(\b)/f/g; s/TH(\b)/F/g; s/th/d/g; s/Th/D/g; s/([Nn])[.]/$1, uh-hah-hah-hah./g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.4/scripts/langMuppetsChef.pl0000775000175000017500000000627215151324131020444 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langMuppetsChef.pl -split language-MuppetsChef.sys # or # ../scripts/langMuppetsChef.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.siafoo.net/snippet/133 # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-MuppetsChef.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/An/Un/g; s/an/un/g; s/Au/Oo/g; s/au/oo/g; s/a\b/e/g; s/A\b/E/g; s/en\b/ee/g; s/\bew/oo/g; s/\be\b/e-a/g; s/\be/i/g; s/\bE/I/g; s/\bf/ff/g; s/\bir/ur/g; s/(\w*?)i(\w*?)$/$1ee$2/g; s/\bow/oo/g; s/\bo/oo/g; s/\bO/Oo/g; s/the/zee/g; s/The/Zee/g; s/th\b/t/g; s/\btion/shun/g; s/\bu/oo/g; s/\bU/Oo/g; s/v/f/g; s/V/F/g; s/w/w/g; s/W/W/g; s/([a-z])[.]/$&. Bork Bork Bork!/g; # From the text-filter-suite: s/(\w)ew/$1oo/g; s/(\w)ow/$1oo/g; s/(\W)o/$1oo/g; s/(\W)O/$1Oo/g; s/(\w)u/$1oo/g; s/(\w)U/$1Oo/g; s/a(\w)/e$1/g; s/A(\w)/E$1/g; s/en(\W)/ee$1/g; s/(\w)e(\W)/$1e-a$2/g; s/(\W)e/$1i/g; s/(\W)E/$1I/g; s/(\w)f/$1ff/g; s/(\w)ir/$1ur/g; s/([a-m])i/$1ee/g; s/([A-M])i/$1EE/g; s/(\w)o/$1u/g; s/the/zee/g; s/The/Zee/g; s/th(\W)/t$1/g; s/(\w)tion/$1shun/g; s/v/f/g; s/V/F/g; s/w/v/g; s/W/V/g; s/f{2,}/ff/g; s/o{2,}/oo/g; s/e{2,}/ee/g; # s/([\.!\?])\s*(]+>)?\s*$/$1 Bork Bork Bork!$2/g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.4/scripts/langOldeEnglish.pl0000775000175000017500000000601515151324131020411 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langOldeEnglish.pl -split language-OldeEnglish.sys # or # ../scripts/langOldeEnglish.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.faqs.org/docs/diveintopython/dialect_divein.html # http://www.siafoo.net/snippet/133 # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-OldeEnglish.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/i([bcdfghjklmnpqrstvwxyz])e\b/y$1/g; s/i([bcdfghjklmnpqrstvwxyz])e/y$1$1e/g; s/ick\b/yk/g; s/ia([bcdfghjklmnpqrstvwxyz])/e$1e/g; s/e[ea]([bcdfghjklmnpqrstvwxyz])/e$1e/g; s/([bcdfghjklmnpqrstvwxyz])y/$1ee/g; s/([bcdfghjklmnpqrstvwxyz])er/$1re/g; s/([aeiou])re\b/$1r/g; s/ia([bcdfghjklmnpqrstvwxyz])/i$1e/g; s/tion\b/cioun/g; s/ion\b/ioun/g; s/aid/ayde/g; s/ai/ey/g; s/ay\b/y/g; s/ay/ey/g; s/ant/aunt/g; s/ea/ee/g; s/oa/oo/g; s/ue/e/g; s/oe/o/g; s/ou/ow/g; s/ow/ou/g; s/\bhe/hi/g; s/ve\b/veth/g; s/se\b/e/g; s/\'s\b/es/g; s/ic\b/ick/g; s/ics\b/icc/g; s/ical\b/ick/g; s/tle\b/til/g; s/ll\b/l/g; s/ould\b/olde/g; s/own\b/oune/g; s/un\b/onne/g; s/rry\b/rye/g; s/est\b/este/g; s/pt\b/pte/g; s/th\b/the/g; s/ch\b/che/g; s/ss\b/sse/g; s/([wybdp])\b/$1e/g; s/([rnt])\b/$1$1e/g; s/from/fro/g; s/when/whan/g; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.4/scripts/langPigLatin.pl0000775000175000017500000000422515151324131017724 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # Run it like this: # # cd xastir/config # ../scripts/langPigLatin.pl -split language-PigLatin.sys # or # ../scripts/langPigLatin.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://www.perlmonks.org/?node_id=3586 # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show that we translated the file. print "# language-PigLatin.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } s/\b(qu|y(?=[^t])|[^\W\daeiouy]*)([a-z']+)/$2.($1||"w")."ay"/eg; if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } Xastir-Release-2.2.4/scripts/langPirateEnglish.pl0000775000175000017500000003357015151324131020760 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # Look at the README for more information on the program. # # Run it like this: # # cd xastir/config # ../scripts/langPirateEnglish.pl -split language-PirateEnglish.sys # or # ../scripts/langPirateEnglish.pl some-output-file # # "-split": Translate 2nd part of line only (Xastir language file). # Without it: Translate entire text. # Regex strings derived from: # http://userscripts.org/scripts/review/25998 # http://dougal.gunters.org/blog/2004/08/30/text-filter-suite # Check whether we're translating an Xastir language file or plain # text: # "-split" present: Translate the 2nd piece of each line. # "-split" absent: Translate the entire text. my $a; if ($#ARGV < 0) { $a = ""; } else { $a = shift; } $do_split = 0; if (length($a) > 0 && $a =~ m/-split/) { $do_split = 1; } # Add these two lines to show we translated the file. print "# language-PirateEnglish.sys, translated from language-English.sys\n"; print "# Please do not edit this derived file.\n"; while ( <> ) { # Skip other comment lines if (m/^#/) { next; } if ($do_split) { # Split each incoming line by the '|' character @pieces = split /\|/; # Translate the second portion of each line only $_ = $pieces[1]; } # Custom for Xastir: s/\bham\b/matey/g; s/\bhi hi\b/it be a joke, matey/g; s/\bk7gps\b/Th\' Good Cap\'n/g; s/\bDave Dobbins\b/Th\' Good Cap\'n/g; s/\bAPRS\'er\b/Fellow Pirate/g; s/\b[Aa]prs\'er\b/fellow pirate/g; s/\bHerb Gerhardt\b/scurvy dog/g; s/\bkb7uvc\b/scurvy dog/g; s/\bwa7nwp\b/cabin boy/g; s/\b[Mm]ap(s*)\b/Treasure Map/g; s/\bXastir\b/HMS Xastir/g; s/\bxastir\b/HMS xastir/g; s/\bXASTIR\b/HMS XASTIR/g; s/\bStation/Ship/g; s/\bstation/ship/g; s/\bView/Gander/g; s/\bview/gander/g; s/\bFile/Scroll/g; s/\bfile/scroll/g; #s/\bFile/Parchment/g; #s/\bfile/parchment/g; s/\bMessage/Dispatch/g; s/\bmessage/dispatch/g; s/\bLogging/Scribblin'/g; s/\blogging/scribblin'/g; s/\bLog/Scribble/g; s/\blog/scribble/g; s/\bPrint/Affix to parchment/g; s/\bprint/affix to parchment/g; s/\bCancel/Nay/g; s/\bcancel/nay/g; s/Close/Nay/g; s/close/nay/g; s/\bOK/Aye/g; s/\bOk/Aye/g; s/\bok/aye/g; s/\bQuit/Nay/g; s/\bquit/nay/g; s/\bExit/Run Away!/g; s/\bexit/run away!/g; s/\bSelect/Choose 'yer Weapon!/g; s/\bselect/choose 'yer weapon!/g; s/\bCompressed/Scrawny/g; s/\bcompressed/scrawny/g; s/\bAudio/Racket/g; s/\baudio/racket/g; s/\bFont/Scribble/g; s/\bfont/scribble/g; s/\bSatellite/Heavenly Body/g; s/\bsatellite/heavenly body/g; s/\bSnapshot/Etching/g; s/\bsnapshot/etching/g; #s/\bObject//g; #s/\bobject//g; #s/\bItem//g; #s/\bitem//g; s/\bInterface/Grapple/g; s/\binterface/grapple/g; s/\bConfigure/Provision me' ship/g; s/\bconfigure/provision me' ship/g; # From userscripts: s/About/\'bout/g; s/\babout\b/\'bout/g; s/\ba lot\b/mightily/g; s/\bam\b/be/g; s/\bamputee\b/peg leg/g; s/\bafraid\b/lily-livered/g; s/\band\b/an\'/g; s/\baround\b/\'round/g; s/\battack\b/pillage/g; s/\battacked\b/raped and pillaged/g; s/\barrest\b/keelhaul/g; s/\bAIDS\b/scurvy/g; s/\baids\b/scurvy/g; s/\bATTN\b/AVAST/g; s/\bbad\b/scurvy/g; s/\bbeer\b/grog/g; s/\bvodka\b/grog/g; s/\bban him\b/make him walk the plank/g; s/\bcar\b/ship/g; s/\bBAN HIM\b/Make him walk the plank!/g; s/\bBan him\b/Make him walk the plank/g; s/\bale\b/grog/g; s/\bbetween\b/betwixt/g; s/\bwhiskey\b/grog/g; s/\bbeauty\b/gov\'nor\'s daughter/g; s/\bbefore\b/\'ere/g; s/\bbanned\b/forced t\' walk the plank/g; s/\bbetween\b/\'tween/g; s/\bboy\b/jim lad/g; s/\bboys\b/jim lads/g; s/\bbought\b/pilfered/g; s/\b4chan\b/House o\' Bilge Rats/g; s/\bAsia\b/Th\' Mystic East/g; s/\bJapan\b/Th\' Mystic East/g; s/\bChina\b/Th\' Mystic East/g; s/\bKorea\b/Th\' Mystic East/g; s/\basia\b/Th\' Mystic East/g; s/\bjapan\b/Th\' Mystic East/g; s/\bchina\b/Th\' Mystic East/g; s/\bkorea\b/Th\' Mystic East/g; s/\bIndia\b/Hindustan/g; s/\bIsrael\b/Th\' Holy Lands/g; s/\bindia\b/Hindustan/g; s/\bisrael\b/Th\' Holy Lands/g; s/\bIraq\b/Th\' Ottoman Empire/g; s/\bIran\b/Th\' Ottoman Empire/g; s/\bPakistan\b/Th\' Ottoman Empire/g; s/\bAfghanistan\b/Th\' Ottoman Empire/g; s/\biraq\b/Th\' Ottoman Empire/g; s/\biran\b/Th\' Ottoman Empire/g; s/\bpakistan\b/Th\' Ottoman Empire/g; s/\bafghanistan\b/Th\' Ottoman Empire/g; s/\bAfrica\b/Th\' Dark Continent/g; s/\bafrica\b/Th\' Dark Continent/g; s/\bcheat\b/hornswaggle/g; s/\bchild\b/wee one/g; s/\bchildren\b/wee ones/g; s/\bcoffee\b/grog/g; s/\bcondemn\b/keelhaul/g; s/\bconference\b/parlay/g; s/\bcrazy\b/addled/g; s/\bjapanophile\b/scurvy mutt/g; s/\bweeaboo\b/scurvy mutt/g; s/\boh crap\b/shiver me timbers!/g; s/\bover\b/o\'er/g; s/\bThe Token Shop\b/Honest Jack\'s Swag Shop/g; s/\bToken Shop\b/Honest Jack\'s Swag Shop/g; s/\bdamn\b/damn\'ed/g; s/\bdevil\b/Davy Jones/g; s/\bdie\b/head to Davy Jones\' Locker/g; s/\bdead\b/\'n Davy Jones\' Locker/g; s/\bdoesn\'t\b/don\'t/g; s/\bdollars\b/pieces o\' eight/g; s/\beveryone\b/all hands/g; s/\beyewear\b/eye patch/g; s/\bglasses\b/eye patches/g; s/\bfight\b/duel/g; s/\bgreatly\b/mightily/g; s/\bgold\b/dubloons/g; s/\bha\b/har har/g; s/\bhaha\b/har har/g; s/\bbase\b/port/g; s/\bfort\b/port/g; s/\bhah\b/har har/g; s/\bheh\b/har har/g; s/\bHa\b/Har har/g; s/\bflag\b/Jolly Roger/g; s/\bhouse\b/shanty/g; s/\bidiot\b/bilge rat/g; s/\bhit\b/flog/g; s/\btorrents\b/Blackbeard\'s treasure /g; s/\btorrent\b/Blackbeard\'s treasure/g; s/\bn00b\b/landlubber/g; s/\bnoob\b/landlubber/g; s/\btroll\b/blowhard/g; s/\bdrive\b/sail/g; s/\bcoins\b/pieces o\' eight/g; s/\bcorrect\b/right an\' true/g; s/\bfly\b/sail/g; s/\bfool\b/squiffy/g; s/\bfoolish\b/addled/g; s/\bfor\b/fer/g; s/\bFor\b/Fer/g; s/\bfriend\b/matey/g; s/\bfriends\b/hearties/g; s/\bgirl\b/lass/g; s/\bex-girlfriend\b/festerin\' harlot/g; s/\bex girlfriend\b/festerin\' harlot/g; s/\bgood\b/worthy/g; s/\byou\'re\b/yer/g; s/\byour\b/yer/g; s/\bhello\b/ahoy/g; s/\bHello\b/Ahoy/g; s/\bhey\b/avast!/g; s/\bHey\b/Avast/g; s/\bhey\b/avast!/g; s/\bhi\b/ahoy/g; s/\bHi\b/Ahoy/g; s/\bHiya\b/Ahoy/g; s/\bhiya\b/ahoy/g; s/\bmoney\b/booty/g; s/\bguy\b/feller/g; s/\bfellow\b/feller/g; s/\bidiot\b/scalawag/g; s/ing\b/in\'/g; s/\bin\b/\'n/g; s/\bis\b/be/g; s/\bit\'s\b/\'tis/g; s/\bit is\b/\'tis/g; s/\bkid\b/wee one/g; s/\bkids\b/wee ones/g; s/\bkill\b/keelhaul/g; s/\bis not\b/be not/g; s/\baren\'t\b/be not/g; s/\bare\b/be/g; s/\bam\b/be/g; s/\bAre\b/Be/g; s/\blol\b/yo ho ho!/g; s/\blolol\b/Me sides be splittin\'!/g; s/\bodd\b/addled/g; s/\bof\b/o\'/g; s/\bohmigod\b/begad!/g; s/\bomigod\b/begad!/g; s/\bomg\b/begad!/g; s/\bOMG\b/BEGAD!/g; s/\bo rly\b/be that right, sailor?/g; s/\borly\b/be that right, sailor?/g; s/\bya rly\b/Sailor, \'tis true/g; s/\byarly\b/Sailor, \'tis true/g; s/\bwhoamg\b/shiver me timbers!/g; s/\bmoney\b/booty/g; s/\bmy\b/me/g; s/\bprosecute\b/keelhaul/g; s/\bpants\b/britches/g; s/\bHello\b/Ahoy!/g; s/\bquick\b/smart/g; s/\bquickly\b/smartly/g; s/\bthe rules\b/the Pirate\'s Code/g; s/\bnice\b/fine/g; s/\bthe Internet\b/The Seven Seas/g; s/\bThe Internet\b/The Seven Seas/g; s/\binternet\b/Seven Seas/g; s/\bInternet\b/Seven Seas/g; s/\bsilly\b/addled/g; s/\bsword\b/cutlass/g; s/\bshe\b/the lass/g; s/\bshut up\b/pipe down/g; #s/\bspeech/parlance/g; #s/\bSpeech/Parlance/g; s/\bspeech/parley/g; s/\bSpeech/Parley/g; s/\bsteal\b/commandeer/g; s/\bdownload\b/plunder/g; s/\bDownload\b/Plunder/g; s/\bsexy\b/saucy/g; s/\btelescope\b/spyglass/g; s/\bterrorist\b/scourge o\' the seven seas/g; s/\bterrorists\b/scalawags/g; s/tion\b/tin\'/g; s/\bthere\b/thar/g; s/tions\b/tin\'s/g; s/\bto\b/t\'/g; s/\btomorrow\b/the morrow/g; s/\btruck\b/vessel/g; s/\bwasn\'t\b/weren\'t/g; s/\bwant to\b/wish t\'/g; s/\bwanna\b/wish t\'/g; s/\bYep\b/Aye/g; s/\byep\b/aye/g; s/\bwoman\b/buxom beauty/g; s/\bwomen\b/wenches/g; s/\bwin\b/triumph/g; s/\bwins\b/triumphs/g; s/\bwork\b/deck swabbing/g; s/\bwine\b/grog/g; s/\byes\b/aye/g; s/\bYes\b/Aye/g; s/\bno\b/nay/g; s/\bNo\b/Nay/g; s/\bnah\b/nay/g; s/\bNah\b/Nay/g; s/\bYeah\b/Aye/g; s/\byeah\b/Aye/g; s/\byou\b/ye/g; s/\byour\b/yer/g; s/\bwtf\b/what devilry!/g; s/\bWTF\b/Begad, what devilry be is?!/g; s/\bFacebook\b/PirateBook/g; s/\bThis message was deleted at the request of the original poster\b/This here message be taken back by a yellow-bellied pirate/g; s/\bThis message has been deleted by a moderator\b/This poor soul had a run-in with the authorities/g; s/\bGood Tokens\b/Pieces o\' Eight/g; s/\bBad Tokens\b/Black Marks/g; s/\byou\'re\b/yer/g; s/\bYou\'re\b/Yer/g; s/\bwins\b/triumphs/g; s/\bHome\b/Haven/g; s/\bAdd a link\b/Add plunder/g; s/\bRandom link\b/Who needs maps?/g; s/\bTop rated links\b/Quality grog/g; s/\bLinks o\' the week\b/Modern fashions/g; s/\bWiki\b/Wikis/g; s/\bAll links\b/All th\' plunder/g; s/\bFavorites\b/Treasures/g; s/\bSearch\b/Scour/g; s/\bStats\b/Specs/g; s/\bBoards\b/Th\' Tavern/g; s/\bUser List\b/Roster/g; s/\bLogout\b/Retreat/g; s/\bHelp\b/Aid/g; s/\bBoard List\b/Port/g; s/\bCreate New Topic\b/Parley/g; s/\bPost New Message\b/Parley/g; s/\bNext Page\b/Next Map/g; s/\bTagged\b/X\'d/g; s/\bTag\b/X/g; # From text-filter-suite/ s/\bmy\b/me/g; s/\bboss\b/admiral/g; s/\bmanager\b/admiral/g; s/\b[Cc]aptain\b/Cap\'n/g; s/\bmyself\b/meself/g; s/\byour\b/yer/g; s/\byou\b/ye/g; s/\bfriend\b/matey/g; s/\bfriends\b/maties/g; s/\bco[-]?worker\b/shipmate/g; s/\bco[-]?workers\b/shipmates/g; s/\bpeople\b/scallywags/g; s/\bearlier\b/afore/g; s/\bold\b/auld/g; s/\bthe\b/th\'/g; s/\bof\b/o'/g; s/\bdon\'t\b/dern\'t/g; s/\bdo not\b/dern\'t/g; s/\bnever\b/ne\'er/g; s/\bever\b/e\'er/g; s/\bover\b/o\'er/g; s/\bYes\b/Aye/g; s/\bNo\b/Nay/g; s/\bYeah\b/Aye/g; s/\byeah\b/aye/g; s/\bdon\'t know\b/dinna/g; s/\bdidn\'t know\b/did nay know/g; s/\bhadn\'t\b/ha\'nae/g; s/\bdidn\'t\b/di\'nae/g; s/\bwasn\'t\b/weren\'t/g; s/\bhaven\'t\b/ha\'nae/g; s/\bfor\b/fer/g; s/\bbetween\b/betwixt/g; s/\baround\b/aroun\'/g; s/\bto\b/t\'/g; s/\bit\'s\b/\'tis/g; s/\bwoman\b/wench/g; s/\bwomen\b/wenches/g; s/\blady\b/wench/g; s/\bwife\b/lady/g; s/\bgirl\b/lass/g; s/\bgirls\b/lassies/g; s/\bguy\b/lubber/g; s/\bman\b/lubber/g; s/\bfellow\b/lubber/g; s/\bdude\b/lubber/g; s/\bboy\b/lad/g; s/\bboys\b/laddies/g; s/\bchildren\b/little sandcrabs/g; s/\bkids\b/minnows/g; s/\bhim\b/that scurvey dog/g; s/\bher\b/that comely wench/g; s/\bhim\.\b/that drunken sailor/g; s/\bHe\b/The ornery cuss/g; s/\bShe\b/The winsome lass/g; s/\bhe\'s\b/he be/g; s/\bshe\'s\b/she be/g; s/\bwas\b/were bein\'/g; s/\bHey\b/Avast/g; s/\bher\.\b/that lovely lass/g; s/\bfood\b/chow/g; s/\bmoney\b/dubloons/g; s/\bdollars\b/pieces of eight/g; s/\bcents\b/shillings/g; s/\broad\b/sea/g; s/\broads\b/seas/g; s/\bstreet\b/river/g; s/\bstreets\b/rivers/g; s/\bhighway\b/ocean/g; s/\bhighways\b/oceans/g; s/\binterstate\b/high sea/g; s/\bprobably\b/likely/g; s/\bidea\b/notion/g; s/\bcar\b/boat/g; s/\bcars\b/boats/g; s/\btruck\b/schooner/g; s/\btrucks\b/schooners/g; s/\bSUV\b/ship/g; s/\bairplane\b/flying machine/g; s/\bjet\b/flying machine/g; s/\bmachine\b/contraption/g; s/\bdriving\b/sailing/g; s/\bunderstand\b/reckon/g; s/\bdrive\b/sail/g; s/\bdied\b/snuffed it/g; s/ing\b/in\'/g; s/ings\b/in\'s/g; # These next two do cool random substitutions #s/(\.\s)/e/avast("$0",3)/g; #s/([!\?]\s)/e/avast("$0",2)/g; # Greater chance after exclamation # Add an opening phrase to each line randomly (see below)? if ($do_split) { # Combine the line again for output to STDOUT $pieces[1] = $_; print join '|', @pieces; } else { print; } } # Randomize use of this array, both in order and in frequency of # use. Not currently used at all. #my @shouts = ( # ", avast$stub", # "$stub Ahoy!", # ", and a bottle of rum!", # ", by Blackbeard's sword$stub", # ", by Davy Jones' locker$stub", # "$stub Walk the plank!", # "$stub Aarrr!", # "$stub Yaaarrrrr!", # ", pass the grog!", # ", and dinna spare the whip!", # ", with a chest full of booty$stub", # ", and a bucket o' chum$stub", # ", we'll keel-haul ye!", # "$stub Shiver me timbers!", # "$stub And hoist the mainsail!", # "$stub And swab the deck!", # ", ye scurvey dog$stub", # "$stub Fire the cannons!", # ", to be sure$stub", # ", I'll warrant ye$stub", # ", on a dead man's chest!", # "$stub Load the cannons!", # "$stub Prepare to be boarded!", # ", I'll warrant ye$stub", # "$stub Ye'll be sleepin' with the fishes!", # "$stub The sharks will eat well tonight!", # "$stub Oho!", # "$stub Fetch me spyglass!", # ); # Randomize use of this array both in order and frequency of use. # Not currently used at all. my @openings = ( 'Avast! ', 'Yarrr! ', 'Blimey! ', 'Ahoy! ', 'Harrr! ', 'Aye aye! ', 'Shiver me timbers! ', 'Arrrr! ' ); Xastir-Release-2.2.4/scripts/listen_and_display.pl0000775000175000017500000000164015151324131021216 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # listen_and_display.pl: Create a listener port which dumps anything received to STDOUT $server_port = 2024; $| = 1; use Socket; use IO::Handle; use POSIX qw(:errno_h); # Make the socket socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')); # So we can restart our server quickly setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1); # Build up my socket address $my_addr = sockaddr_in($server_port, INADDR_ANY); bind(SERVER, $my_addr) or die "Couldn't bind to port $server_port : $!\n"; # Establish a queue for incoming connections listen(SERVER, SOMAXCONN) or die "Couldn't listen on port $server_port : $!\n"; # Accept and process connections while (accept(CLIENT, SERVER)) { printf("\n*** A client connected on port $server_port ***\n"); CLIENT->autoflush(1); while () { print; } printf("\n*** The client disconnected ***\n"); } close(SERVER); Xastir-Release-2.2.4/scripts/mapblast2geo.pl0000775000175000017500000001615215151324131017735 0ustar hibbyhibby#!/usr/bin/env perl # XASTIR .geo file generator for mapblast pixel maps 16.10.2001 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- use POSIX; # provides acos() function # some default values: $width = 1280; # seems to be the maximum supported by mapblast $height = 1024; # seems to be the maximum supported by mapblast $pfx = "../../pixelmaps/"; # prefix for path $pfx = ""; # undefined values: $scale = 0; $lat = 9999; $lon = 9999; $help = 0; #-------------------------------------------------------------------------- while (@ARGV) { $arg = shift @ARGV; if ($arg =~ /^\-N(\d{1,2}(\.\d+)?)$/) { $lat = $1 } if ($arg =~ /^\-S(\d{1,2}(\.\d+)?)$/) { $lat = -$1 } if ($arg =~ /^\-E(\d{1,3}(\.\d+)?)$/) { $lon = $1 } if ($arg =~ /^\-W(\d{1,3}(\.\d+)?)$/) { $lon = -$1 } if ($arg =~ /^\-w(\d+)$/) { $width = $1 } if ($arg =~ /^\-h(\d+)$/) { $height= $1 } if ($arg =~ /^\-s(\d+)$/) { $scale = $1 } if ($arg =~ /^\-s(\d+)k$/) { $scale = $1 * 1000 } if ($arg =~ /^\-s(\d+)M$/) { $scale = $1 * 1000000 } if ($arg =~ /^\-p(.+)$/) { $pfx = $1 } if ($arg eq '-?') { $help = 1 } if ($arg eq '-h') { $help = 1 } if ($arg eq '--help') { $help = 1 } } if (!$help && $arg && $arg !~ /^\-/) { $file = $arg; # last arg is file name } else { print("ERROR: Map file name is missing\n"); $help = 1; } if (!$help) { if ($lat == 9999) { # we don't yet have a latitude if ($file =~ /N(\d{1,2}(\.\d+)?)/) { $lat = $1 } if ($file =~ /S(\d{1,2}(\.\d+)?)/) { $lat = -$1 } } if ($lon == 9999) { # we don't yet have a longitude if ($file =~ /E(\d{1,3}(\.\d+)?)/) { $lon = $1 } if ($file =~ /W(\d{1,3}(\.\d+)?)/) { $lon = -$1 } } if ($scale == 0) { # we don't yet have a map scale if ($file =~ /\-(\d+)/) { $scale = $1 } if ($file =~ /\-(\d+)k/) { $scale = $1 * 1000 } if ($file =~ /\-(\d+)M/) { $scale = $1 * 1000000 } } if ($lat == 9999) { # we need a latitude print("ERROR: Latitude is missing\n"); $help = 1; } if ($lon == 9999) { # we need a longitude print("ERROR: Longitude is missing\n"); $help = 1; } if ($scale == 0) { # we need a map scale print("ERROR: Map scale is missing\n"); $help = 1; } } if ($help) { usage(); exit 0; } if ($pfx && $pfx !~ /\/$/) { $pfx .= "/" } # add trailing '/' if missing #-------------------------------------------------------------------------- if ($scale >= 1000000) { printf("ERROR: Maps with scaling of 1M and above are not yet supported!\n"); printf(" They use a different projection...\n"); exit 1; } if (abs($lat) > 89) { printf("ERROR: Map center too near to the poles!\n"); exit 1; } # This scaling factor is just a wild guess! # But I need one, and this one is nice AND works quite well... ;-) $scale_y = 100.0 * pi(); # pixel/degree at 1M map scale $scale_x = $scale_y * calcScale($lat); # adjust horizontal scale for latitude $scale_y *= (1000000 / $scale); # adjust for current map scale $scale_x *= (1000000 / $scale); #-------------------------------------------------------------------------- # DK7IN: I'm not sure, if this formula is exact for what Xastir # is decoding, but in my region it works quite well # I need to do some further investigation for the best accuracy $latmin = $lat - ($height / 2.0 - 2.5) / $scale_y; $latmax = $lat + ($height / 2.0 - 0.5) / $scale_y; $lonmin = $lon - ($width / 2.0 - 0.5) / $scale_x; $lonmax = $lon + ($width / 2.0 - 2.5) / $scale_x; printf("FileName %s%s\n",$pfx,$file); printf("\n"); printf("ImageSize %4d %4d\n",$width,$height); printf("TiePoint %4d %4d %10.6f %11.6f\n",0,0,$lonmin,$latmax); printf("TiePoint %4d %4d %10.6f %11.6f\n",$width-1,$height-1,$lonmax,$latmin); printf("Datum WGS84\n"); printf("Projection LatLon\n"); printf("\n"); printf("# map from mapblast center %10.6f %11.6f, scale %d\n",$lat,$lon,$scale); printf("# created with mapblast2geo.pl (DK7IN)\n"); exit 0; #-------------------------------------------------------------------------- sub usage { my $name = $0; if ($name =~ /^.*\/(.+)$/) { $name = $1 } print("\n"); print("$name (c) 2001 Rolf Bleher \n"); print("create Xastir .geo files for mapblast pixel maps\n"); print("usage: $name [options] mapfile\n"); print(" -N52.5 -S10 define latitude\n"); print(" -E13.3 -W0.5 define longitude\n"); print(" -h1024 define map height in pixels (default 1024)\n"); print(" -w1280 define map width in pixels (default 1280)\n"); print(" -s50000 define map scale, 50k or 1M is ok\n"); print(" -p../pixmaps define prefix for path\n"); print(" -h -? --help print this help file\n"); print(" it tries to extract center Lat/Lon and map scale\n"); print(" from the filename like N52.5E13.3-50k.xpm\n"); print("\n"); } #-------------------------------------------------------------------------- sub pi { return(3.14159265358979323846); } #-------------------------------------------------------------------------- sub deg2rad { my ($deg) = @_; return($deg * pi()/180.0); } #-------------------------------------------------------------------------- # Calculate distance in meters between two locations sub dist { my ($lat1, $lon1, $lat2, $lon2) = @_; my $r_lat1 = deg2rad($lat1); my $r_lon1 = deg2rad($lon1); my $r_lat2 = deg2rad($lat2); my $r_lon2 = deg2rad($lon2); my $r_d = acos(sin($r_lat1) * sin($r_lat2) + cos($r_lat1) * cos($r_lat2) * cos($r_lon1-$r_lon2)); return($r_d*180.0*60.0/pi()*1852.0); } #-------------------------------------------------------------------------- sub calcScale { # EW / NS scaling my ($lat) = @_; return(dist($lat,-1.0/120.0,$lat,1.0/120.0) / 1852.0); } #-------------------------------------------------------------------------- Xastir-Release-2.2.4/scripts/mapfgd.pl0000775000175000017500000001553315151324131016615 0ustar hibbyhibby#!/usr/bin/env perl # -*- perl -*- # Written by Derrick J Brashear, KB3EGH # Released to the public domain. # Usage: mapfgd # Creates fake fgd files for all correctly USGS-named maps which don't # already have them local (@dirlist) = @ARGV; local ($mapdir); foreach $mapdir (@dirlist) { opendir (DIR, $mapdir) || die "mapini: couldn't open directory \`$mapdir': $!\n"; local ($file, $fullfile, $expr, $mlat, $mlon, $mlats, $mlons); local ($nlat, $nlon, $nlats, $nlons); local ($dlat, $dlon, $inifile); local ($imgwidth, $imglength, $imgres, $imgdepth, $imgphotometric); local ($imgtimestamp); foreach $file (sort grep (! /^\./, readdir (DIR))) { # Only examine .tif files. next unless $file =~ /\.tif$/; next unless $file =~ /^[iIoOcCfFkKlLpPjJgG]/; $fullfile = $mapdir . '/' . $file; $inifile = $mapdir . '/' . $file; $inifile =~ s/\.tif$/.fgd/; next if (-f $inifile); open (INI, ">$inifile"); $file =~ /^([iIoOcCfFkKlLpPjJgG])([0-9][0-9])([0-9][0-9][0-9])([a-hA-H])([1-8])/; $letter = $1; $mlat = $2; $mlon = $3; $mlats = $4; $mlons = $5; if ($letter eq 'c') { $dlon = 0-$mlon-2; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+1; printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat; printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if (($letter eq 'f') || ($letter eq 'g')){ $dlon = 0-$mlon-1; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+.375+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if ($letter eq 'k') { $dlon = 0-$mlon-(.125*$mlons)-.125; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { if ($letter eq 'i') { $dlon = 0-$mlon-(.125*$mlons)-.250; printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } else { $dlon = 0-$mlon-(.125*$mlons); printf INI "1.5.1.1 WEST BOUNDING COORDINATE: %.6f\n", $dlon; $dlon = 0-$mlon-(.125*$mlons)+.125; printf INI "1.5.1.2 EAST BOUNDING COORDINATE: %.6f\n", $dlon; $dlat = $mlat+(.125*(&lettonum ($mlats))); printf INI "1.5.1.3 NORTH BOUNDING COORDINATE: %.6f\n", $dlat; $dlat = $mlat-.125+(.125*(&lettonum ($mlats))); printf INI "1.5.1.4 SOUTH BOUNDING COORDINATE: %.6f\n", $dlat; } } } } close (INI); } closedir (DIR); } sub lettonum { local ($let) = @_; if ($let eq 'a') {return 1;} if ($let eq 'b') {return 2;} if ($let eq 'c') {return 3;} if ($let eq 'd') {return 4;} if ($let eq 'e') {return 5;} if ($let eq 'f') {return 6;} if ($let eq 'g') {return 7;} if ($let eq 'h') {return 8;} } sub nextlet { local ($let,$scale) = @_; if ($scale eq 'c') {$nlat++;return 'a';} if ($scale eq 'f') { if ($let eq 'a') {return 'e';} if ($let eq 'e') {$nlat++;return 'a';} } if ($let eq 'a') {return 'b';} if ($let eq 'b') {return 'c';} if ($let eq 'c') {return 'd';} if ($let eq 'd') {return 'e';} if ($let eq 'e') {return 'f';} if ($let eq 'f') {return 'g';} if ($let eq 'g') {return 'h';} if ($let eq 'h') {$nlat++;return 'a';} } sub nextnum { local ($let,$scale) = @_; if ($scale eq 'c') { $nlon+=2; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($scale eq 'f') { $nlon++; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($let eq '1') {return '2';} if ($let eq '2') {return '3';} if ($let eq '3') {return '4';} if ($let eq '4') {return '5';} if ($let eq '5') {return '6';} if ($let eq '6') {return '7';} if ($let eq '7') {return '8';} if ($let eq '8') {$nlon++; if ($nlon < 100) { $nlon="0$nlon"; } return '1';} } sub oldlastnum { local ($let,$scale) = @_; if ($let = 1) {print INI "let was 1\n";$let=9; $nlon--; $nlon="0$nlon";} $let--; return $let; } sub lastnum { local ($let,$scale) = @_; if ($scale eq 'c') { $nlon-=2; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($scale eq 'f') { $nlon--; if ($nlon < 100) { $nlon="0$nlon"; } return '1'; } if ($let eq '1') { $nlon--; if ($nlon < 100) { $nlon="0$nlon"; } return '8'; } if ($let eq '2') {return '1';} if ($let eq '3') {return '2';} if ($let eq '4') {return '3';} if ($let eq '5') {return '4';} if ($let eq '6') {return '5';} if ($let eq '7') {return '6';} if ($let eq '8') {return '7';} } sub lastlet { local ($let,$scale) = @_; if ($scale eq 'c') {$nlat--;return 'a';} if ($scale eq 'f') { if ($let eq 'a') {$nlat--;return 'e';} if ($let eq 'e') {return 'a';} } if ($let eq 'a') {$nlat--;return 'h';} if ($let eq 'b') {return 'a';} if ($let eq 'c') {return 'b';} if ($let eq 'd') {return 'c';} if ($let eq 'e') {return 'd';} if ($let eq 'f') {return 'e';} if ($let eq 'g') {return 'f';} if ($let eq 'h') {return 'g';} } Xastir-Release-2.2.4/scripts/object2shp.pl0000775000175000017500000000766615151324131017432 0ustar hibbyhibby#!/usr/bin/env perl # # Copyright (C) 2006-2012 Tom Russo # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an ESRI point shapefile from the object.log file, # according to the "Rolling your own shapefile maps" section of README.MAPS # The point file will display using the TIGER Landmark Point dbfawk file # # This enables fast generation of point maps by using xastir to plop down # objects, then this script to turn the object.log file into a shapefile # # Typical usage: # object2shp.pl object.log myshape # # Remember to exit xastir and delete "object.log", otherwise xastir will # never forget your objects. #-------------------------------------------------------------------------- if ($#ARGV != 1) { print "Usage: $0 \n"; exit 1; } open(INOBJ,"<$ARGV[0]") || die "Cannot open input object file $ARGV[0]\n"; $cmd[0]="shpcreate $ARGV[1] point"; $cmd[1]="dbfcreate $ARGV[1] -n ID 8 0 -s CFCC 4 -s NAME 30"; $outfile=$ARGV[1]; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } # We now have the shapefile and dbf file created, start populating from the # objects file: $i=0; while () { chomp($_); $semicolon=substr($_,0,1); $name=substr($_,1,9); $live_or_dead=substr($_,10,1); $timestamp=substr($_,11,7); $lat=substr($_,18,8); $symtab=substr($_,26,1); $long=substr($_,27,9); $sym=substr($_,36,1); #sanity check --- don't try to convert if the line doesn't conform to what # it should, or if it represents a killed object. Sometimes objects get # commented out with #, etc. next if ($semicolon ne ";"); next if ($live_or_dead eq "_"); $i++; # bump the ID number so every point has a unique one $lat_deg=substr($lat,0,2); $lat_min=substr($lat,2,5); $lat_hem=substr($lat,7,1); $long_deg=substr($long,0,3); $long_min=substr($long,3,5); $long_hem=substr($long,8,1); $lat=$lat_deg+$lat_min/60; $lat *= -1 if ($lat_hem eq "S"); $long=$long_deg+$long_min/60; $long *= -1 if ($long_hem eq "W"); # Construct symbol if ($symtab ne "/" && $symtab ne "\\") { print "overlay symbol, symtab is $symtab\n"; $overlay=$symtab; $symtab="\\"; print " reset values symtab is $symtab, overlay is $overlay\n"; } else { $overlay=" "; } $cmd[0]="shpadd $outfile $long $lat"; $cmd[1]="dbfadd $outfile $i \'X$symtab$sym$overlay\' $name"; print $cmd[1]."\n"; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } } Xastir-Release-2.2.4/scripts/overlay.pl0000775000175000017500000001415615151324131017040 0ustar hibbyhibby#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # # Script to create Xastir "Overlay" files from "CSV" files of the # proper format (comma-delimited files). # # 1) Creates files in Xastir "log" format if you enter a callsign # below. These files can then be put in your ~/.xastir/logs/ # directory and brought in via the File->Open Log File menu option. # If you start with the CSV files in the ~/.xastir/logs/ directory # and process them there with this script, the output files will be # placed into the proper place for Xastir to find them. # # 2) If no callsign is entered, this script will create files in # Xastir's "~/.xastir/config/object.log" format. You can then # replace or append the file to the object.log file, restart Xastir # or "Reload Object/Item History". # # NOTE: These APRS Items will become part of your locally # owned/transmitted objects, so if you don't want them transmitted, # turn of Object/Item transmit before bringing them in. # # Input: Directory name. If no directory name passed in, it will # operate on every CSV file in the current directory. # # Input format: # Name N/S lat E/W long // comment fields............. # SUPPLY,N,34.0000,W,78.0000,ICON,text1,text2,text3,text4,... # # # The name will have spaces removed if it is longer than nine # characters. If it is still too long, vowels will be removed, then # it will be truncated to nine characters if still needed. The full # name will be transmitted as a comment. All other text fields will # also be transmitted as comments, so that they will all appear in # the Station Info dialog. # # Icons will be a default small red circle unless '/' or '\' is the # leading character in that field and the next specifies the APRS # symbol. In that case the two-letter combination will get used as # the symbol for the Item. # Change this to match whatever callsign you're running Xastir as, # so that the APRS Items appear to have been generated locally. You # can then suck this file in as a "log" file from within Xastir. If # this field is empty, then instead write the packets out without a # header, as in Xastir's "object.log" format. $callsign = ""; if ($callsign ne "") { $callsign = uc($callsign) . '>APRS:'; } # Main program. Process every ".csv" file found in the directory. # $dirname = shift; if ($dirname == "") { $dirname = "."; } opendir(DIR, $dirname) or die "Can't opendir $dirname: %!"; while (defined($file = readdir(DIR))) { chomp $file; if ( $file =~ /\.csv$/ ) { # Do something with "$dirname/$file" &process_file($dirname, $file); } else { # printf("$dirname/$file\n"); } } # Process one file. Creates an output file that matches the # basename but changes the "csv" to "overlay". # sub process_file() { $output_file = $_[1]; $output_file =~ s/\.csv$/.overlay/; printf("$dirname/$file -> $output_file\n"); open(SOURCE, "< $_[1]") or die "Couldn't open $path for reading: $!\n"; open(OUTPUT, "> $output_file") or die "Couldn't open $output_file for writing: $!\n"; while () { &process_line($_); } close(SOURCE); close(OUTPUT); } # Process one line. Write the formatted data to the OUTPUT file. # sub process_line() { #printf("$_[0]"); # Parse the CSV line into an array @list = parse_csv($_[0]); if (!($list[0] =~ m/Location/i)) { #print OUTPUT @list; # As a temporary measure, create items out of each of the lines, # with a status line for each extra data object so that they # appear in the Station Info dialog. &create_items(@list); } } # Create an APRS Item out of each array. Create a status line for # each extra column associated with a line so that the info shows up # in the Station Info dialog. # # Examples. Name is 3-9 characters: # )AID #2!4903.50N/07201.75WA # )G/WB4APR!53 . N\002 . Wd # sub create_items { $name = $_[0]; if ($name eq "") { printf("Error, name column is empty\n"); } # If too long, try removing spaces first if (length($name) > 9) { $name =~ s/\s//ig; } # If still too long, remove vowels if (length($name) > 9) { $name =~ s/a//ig; $name =~ s/e//ig; $name =~ s/i//ig; $name =~ s/o//ig; $name =~ s/u//ig; } # Extend to three characters if short if (length($name) < 3) { $name = $name . " "; } $name = substr($name,0,9); $name[9] = "\0"; # Terminate name at 9 characters, minimum 3 $n_s = uc( substr($_[1],0,1) ); $latitude = $_[2]; $e_w = uc( substr($_[3],0,1) ); $longitude = $_[4]; if ($_[5] =~ /ICON/i) { $icon1 = "/"; $icon2 = "/"; } else { $icon1 = substr($_[5],0,1); $icon2 = substr($_[5],1,1); } # Convert lat/long to APRS format (or Base-91 Compressed format) $lat_deg = $latitude; $lat_deg =~ s/\.\d+$//; $lat_deg = sprintf("%02d", $lat_deg); $lat_min = $latitude; $lat_min =~ s/^\d+\./0./; $lat_min = $lat_min * 60.0; $lon_deg = $longitude; $lon_deg =~ s/\.\d+$//; $lon_deg = sprintf("%03d", $lon_deg); $lon_min = $longitude; $lon_min =~ s/^\d+\./0./; $lon_min = $lon_min * 60; # Create an APRS "Item" packet $line = sprintf("%s)%s!%s%05.2f%s%s%s%05.2f%s%s", $callsign, $name, $lat_deg, $lat_min, $n_s, $icon1, $lon_deg, $lon_min, $e_w, $icon2); # Go process the rest of the columns, if any. Create APRS Item # packets with comments from them. for ($i = 6; $i < 106; $i++) { chomp $_[$i]; if ($_[$i] ne "") { #printf("$_[$i]"); printf(OUTPUT "%s%s\n", $line, $_[$i]); } } # Write it out to the file, with the full name as a comment printf(OUTPUT "%s%s\n", $line, $_[0]); } # Parse CSV line into an array, removing double-quotes and such if # found. # sub parse_csv { my $text = shift; # Record containing comma-separated values my @new = (); push(@new, $+) while $text =~ m{ # The first part groups the phrase inside the quotes. # See explanation of this pattern in MRE "([^\"\\]*(?:\\.[^\"\\]*)*)",? | ([^,]+),? | , }gx; push(@new, undef) if substr($text, -1, 1) eq ','; return @new; # List of values that were comma-separated } Xastir-Release-2.2.4/scripts/ozi2geo.pl0000775000175000017500000001220115151324131016722 0ustar hibbyhibby#!/usr/bin/env perl # Written by Curt Mills, WE7U # Released to the public domain. # Modified from the earlier inf2geo.pl script. # # Read in .map file (an OziExplorer file in this case). # Check the version of the map format (1st line). My example is # version 2.2. # Get the filename from the 2nd line of the file. # Check that "WGS 84" or "NAD 83" are present in the file (5th # line?). # Check the "Map Projection". # Grab the first four points, which hopefully are the corners. # Snag the MMPXY lines and the MMPLL lines. These are the X/Y and # Lat/Long of the corners in the example I have. # Write out the .geo file # # 2003-08-15 ZL2UMF: add processing multiple files in one go (masks # and whot-not) so you can convert all your maps in one step. #use strict; use IO::File; #go through every filename passed to this script foreach my $file (@ARGV) { print "*** $file ***\n"; #make a geo of this file makeGeo ($file); } exit; #just in case sub makeGeo { my $ozimap_filename = shift; # Snag the filename out of the .map file instead? Here we # create it from the.map filename. # my $filename = $ozimap_filename; $filename =~ s/\.map$//i; my $geo_filename = $filename . ".geo"; # $ozimap = IO::File->new("< $ARGV[0].map") # or $ozimap = IO::File->new("< $ARGV[0].MAP") # or $ozimap = IO::File->new("< $ARGV[0].Map") #skip this file if geo already exists return print "$filename.geo already exists, will not overwrite\n" if( -e "$filename.geo" ); #read the map file my $ozimap = IO::File->new ( "< $ozimap_filename" ) or return print "\nCouldn't open $ozimap_filename for reading:\n$!\n\n"; #make the new geo file $geo = IO::File->new("> $geo_filename") or return print "Couldn't open $geo_filename for writing: $!\n"; # First line should be something like: # "OziExplorer Map Data File Version 2.2" # $tmp = $ozimap->getline(); print "\t$tmp"; $final_filename = $ozimap->getline(); chomp($final_filename); #print $final_filename; # Check that the filename we just read matches the filename we # created from the .map filename. $tmp = $ozimap->getline(); #print $tmp; $tmp = $ozimap->getline(); # Get the datum $tmp = $ozimap->getline(); #print $tmp; # Check that the datum is "WGS 84", "WGS84", "NAD 83", or "NAD83". if ($tmp =~ /WGS 84/i || $tmp =~ /WGS84/i || $tmp =~ /NAD 83/i || $tmp =~ /NAD83/i) { } else { print "***Datum is not WGS84 or NAD83: Results will be inaccurate***\n"; } # Read until we find "Map Projection" at the start of a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); #print $tmp; if ($tmp=~ /Map Projection/) { $done++; } } if ($tmp =~ /UTM/i) { print "***Found UTM projection: Results will be inaccurate***\n"; #print "$tmp"; } # We have the map projection. Check it. Issue a warning if it's # not what we can handle easily. # Read until we find "MMPXY" at the start of a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); if ($tmp=~ /MMPXY/) { $done++; } } $MMPXY1 = $tmp; #print $MMPXY1; $MMPXY2 = $ozimap->getline(); #print $MMPXY2; $MMPXY3 = $ozimap->getline(); #print $MMPXY3; $MMPXY4 = $ozimap->getline(); #print $MMPXY4; $MMPLL1 = $ozimap->getline(); #print $MMPLL1; $MMPLL2 = $ozimap->getline(); #print $MMPLL2; $MMPLL3 = $ozimap->getline(); #print $MMPLL3; $MMPLL4 = $ozimap->getline(); #print $MMPLL4; # If the corners are always listed in circular order, we can choose # to use corners 1 and 3 for our tiepoints. Try this. # Read until we find "Map Image Width" inside a line. # $done = 0; while (!$done) { $tmp = $ozimap->getline(); if ($tmp=~ /Map Image Width/) { $done++; } } #print $tmp; $image_size = $tmp; # That should be all that we need to read from the file. # Get the X/Y for the tiepoints my ($a, $b, $x0, $y0) = split(',', $MMPXY1); chomp($x0); chomp($y0); # Convert to numbers $x0 = $x0 * 1; $y0 = $y0 * 1; #print "$x0 $y0\n"; my ($a, $b, $x1, $y1) = split(',', $MMPXY3); chomp($x1); chomp($y1); # Convert to numbers $x1 = $x1 * 1; $y1 = $y1 * 1; #print "$x1 $y1\n"; # Get the lat/long for the tiepoints my ($a, $b, $tp0_lon, $tp0_lat) = split(',', $MMPLL1); chomp($tp0_lon); chomp($tp0_lat); #print "$tp0_lon $tp0_lat\n"; my ($a, $b, $tp1_lon, $tp1_lat) = split(',', $MMPLL3); chomp($tp1_lon); chomp($tp1_lat); #print "$tp1_lon $tp1_lat\n"; # Split out the imagesize string my ($a, $b, $width, $height) = split(',', $image_size); chomp($width); chomp($height); #write to the geo file printf $geo "FILENAME $final_filename\n"; printf $geo "TIEPOINT $x0\t\t$y0\t$tp0_lon\t$tp0_lat\n"; printf $geo "TIEPOINT $x1\t$y1\t$tp1_lon\t$tp1_lat\n"; printf $geo "IMAGESIZE $width\t$height\n"; printf $geo "#\n# Converted from an OziExplorer .MAP file by WE7U's ozi2geo.pl script\n#\n"; $ozimap->close(); $geo->close(); } Xastir-Release-2.2.4/scripts/permutations.pl0000775000175000017500000002575515151324131020120 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # Written by Paul Lutt, KE7XT & Curt Mills, WE7U. # Released to the public domain. # # # # Finds the different lat/long representations corresponding to the # input numbers. A space is required between the degrees portion # and the rest of the input. Writes out a log file containing APRS # objects suitable for importing into Xastir, to graphically plot # the locations of the objects. Now that Xastir has a server port # we could directly inject them into the program via that route as # well, but we currently don't do that. # # Converts between different lat/lon formats. Will also give UMS # position if the lat/lon resides somewhere inside the Seattle area # aeronautical map. # # UMS coordinates have been used in the past by King County, WA SAR. # It can be useful for plotting positions on Green Trails maps and # perhaps other maps. The maps must be 15' topo maps and marked in # tenths of miles along the edge in order to make use of this # coordinate system. # # Web pages which discuss UMS format: # http://www.impulse.net/~mlynch/land_nav.html # http://www.logicsouth.com/~lcoble/dir9/land_nav.htm # http://www.aasar.org/training/academy/navigation.pdf # use lib "/usr/local/lib"; use Coordinate; # WE7U's Coordinate.pm module # Get the username $user = getlogin; chomp $user; $filename = "/var/tmp/PERMUTATIONS-$user.log"; sub convert { # Snag the input $_ = $_[0]; print "\n"; # If the first item has 2 digits and one character and there are # three "words" in the input, we're starting with a UTM value. if (/^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { # printf("Found a UTM value\n"); # We'll convert it to the standard format first and then run # through the rest of the code. $zone = $_; $easting = $_; $northing = $_; $zone =~ s/^(\d\d[a-zA-Z])\s+\w+\s+\w+\s*$/$1/; $easting =~ s/^\d\d[a-zA-Z]\s+(\w+)\s+\w+\s*$/$1/; $northing =~ s/^\d\d[a-zA-Z]\s+\w+\s+(\w+)\s*$/$1/; if ($easting > 999999) { printf("Easting value is too high!\n"); return; } $position->zone($zone); $position->easting($easting); $position->northing($northing); # Convert to lat/lon values $position->utm_to_lat_lon(); # printf("Calculated Lat, Long position(Lat, Long): %f %f\n", # $position->latitude(), # $position->longitude() ); $latitude = $position->latitude(); $longitude = $position->longitude(); $lat_dir = "N"; $long_dir = "E"; if ($latitude < 0.0) { $latitude = abs($latitude); $lat_dir = "S" } if ($longitude < 0.0) { $longitude = abs($longitude); $long_dir = "W"; } # printf("%f%s %f%s\n", $latitude,$lat_dir,$longitude,$long_dir); $_ = sprintf("%f%s %f%s", $latitude,$lat_dir,$longitude,$long_dir); } # Look for lat/long value in the input # Check for N/S/E/W characters in the input. Set the # appropriate flags if found. $lat_dir = "N"; $long_dir = "E"; if (/S/ || /s/) { $lat_dir = "S"; } if (/W/ || /w/) { $long_dir = "W"; } # Filter out these characters from the input tr/nsewNSEW//d; # Convert to DD MM SS format ($lat_deg, $lat_min, $lat_sec, $long_deg, $long_min, $long_sec) = split(' '); # Decimal Degrees? if ($lat_deg =~ /\./) { $long_deg = $lat_min; # Save long_degrees in proper place $temp = $lat_deg; $lat_deg = int $temp; $lat_min = int ((abs($temp) * 60.0) % 60); # Modulus converts to integers, so we bump up by 10 and then # back down. $lat_sec = (abs($temp) * 36000.0) % 600; $lat_sec = $lat_sec / 10; $temp = $long_deg; $long_deg = int $temp; $long_min = int ((abs($temp) * 60.0) % 60); $long_sec = (abs($temp) * 36000.0) % 600; $long_sec = $long_sec / 10; } # Decimal Minutes? elsif ($lat_min =~ /\./) { $long_min = $long_deg; # Save long_minutes in proper place $long_deg = $lat_sec; # Save long_degrees in proper place $temp = $lat_min; $lat_min = int abs($temp); $lat_sec = (abs($temp) * 60.0) % 60; $lat_sec = $lat_sec / 10; $temp = $long_min; $long_min = int abs($temp); $long_sec = (abs($temp) * 600.0) % 600; $long_sec = $long_sec / 10; } # Decimal Seconds else { # Already in DD MM SS format, don't convert } # Print out the three lat/long formats printf(" Decimal Degrees: %8.5f%s %8.5f%s\n", $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0), $lat_dir, $long_deg + ($long_min/60.0) + ($long_sec/3600.0), $long_dir ); printf(" Degrees/Decimal Minutes: %02d %06.3f%s %02d %06.3f%s\n", $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); printf(" Degrees/Minutes/Dec. Seconds: %02d %02d %4.1f%s %02d %02d %4.1f%s\n", $lat_deg, $lat_min, $lat_sec, $lat_dir, $long_deg, $long_min, $long_sec, $long_dir); # Dump out the coordinate in APRS Item format: printf(FH "TEST>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s/\n", $_[1], $lat_deg, $lat_min + ($lat_sec/60.0), $lat_dir, $long_deg, $long_min + ($long_sec/60.0), $long_dir ); # Fill in the coordinate object with the current lat/lon. # Assuming WGS84 datum if ($lat_dir =~ /S/) { $position->latitude( -( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ) ); } else { $position->latitude( $lat_deg + ($lat_min/60.0) + ($lat_sec/3600.0) ); } if ($long_dir =~ /W/) { $position->longitude( -( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ) ); } else { $position->longitude( $long_deg + ($long_min/60.0) + ($long_sec/3600.0) ); } #printf("%f %f\n",$position->latitude,$position->longitude); $position->lat_lon_to_utm(); printf(" Universal Transverse Mercator: %s %07.0f %07.0f\n", $position->zone(), $position->easting(), $position->northing() ); # Check whether the coordinates are within the SEA aeronautical # map area $lat_err = 0; if ($lat_dir =~ /S/ || $lat_deg < 44 || $lat_deg > 49 || ($lat_deg == 44 && ($lat_min < 30 || ($lat_min == 30 && $lat_sec == 0))) || ($lat_deg == 49 && ($lat_min > 0 || $lat_sec > 0))) { print " lat. out of range "; $lat_err = 1; } $long_err = 0; if ($long_dir =~ /E/ || $long_deg < 117 || $long_deg > 125 || ($long_deg == 117 && ($long_min == 0 && $long_sec == 0)) || ($long_deg == 125 && ($long_min > 0 || $long_sec > 0))) { print " long. out of range"; $long_err = 1; } return if ( $lat_err || $long_err); # Compute UMS coordinates $y_sec = 3600 * ($lat_deg - 44) + 60 * $lat_min + $lat_sec; $y_sec = 18000 - $y_sec; $x_sec = 3600 * ($long_deg - 117) + 60 * $long_min + $long_sec; $x_sec = 28800 - $x_sec; $quad = 32 * int($y_sec / 900) + int($x_sec / 900) + 1; # print "\tx_sec= $x_sec, y_sec= $y_sec, quad= $quad\n"; $y_subquad_offset = int($y_sec / 450); $x_subquad_offset = int($x_sec / 450); if (&even($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} A "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&odd($x_subquad_offset) && &even($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} B "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y($y_sec - (450 * $y_subquad_offset)); } elsif (&even($x_subquad_offset) && &odd($y_subquad_offset)) { print " UMS (Green Trails Maps): SEA ${quad} C "; printf "%02d", &s2m_x($x_sec - (450 * $x_subquad_offset)); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } else { print " UMS (Green Trails Maps): SEA ${quad} D "; printf "%02d", &s2m_x(450 * ($x_subquad_offset + 1) - $x_sec); printf "%02d\n", &s2m_y(450 * ($y_subquad_offset + 1) - $y_sec); } } sub even { return (($_[0] & 1) == 0); } sub odd { return (($_[0] & 1) == 1); } sub s2m_y { return (int((0.1917966 * $_[0]) + 0.5)); } sub s2m_x { return (int((cos(($lat_deg + ($lat_min / 60.0) + ($lat_sec / 3600.0)) / 57.29578) * (0.1917966 * $_[0])) + 0.5)); } ############## # Main Program ############## open (FH, ">$filename") || die "Couldn't open file for writing:$!\n"; # Create new Coordinate object $position = Coordinate->new(); $position->datum("WGS 84"); # Datum print "\n"; print "Examples: 48 07228N 122 07228W\n"; print " 48 08N 122 07W\n"; print " 10U 0565264 5330343\n"; print "\nAPRS Items will be written to: $filename\n"; print "Enter a Lat/Long value or UTM value:\n"; # Snag the input $input = <>; # Get rid of whitespace at the beginning $input =~ s/\s*//; # UTM value? if ($input =~ /^\d\d[a-zA-Z]\s+\w+\s+\w+\s*$/) { $input2 = $input; &convert($input2, "UTM"); print "\n"; # Swap Easting/Northing values and convert again. Leave the # zone in it's original spot. $input2 = $input; $input2 =~ s/^(\d\d[a-zA-Z])\s+(\w+)\s+(\w+)\s*$/$1 $3 $2\n/; print $input2; &convert($input2, "UTM2"); } # else must be lat/lon value else { # Need to break up the input into several possible formats, # possibly including swapping lat/long pieces and plotting N/S # and E/W variants. # I'm going to assume that the user knows his/her approximate # lat/lon, so they can input it in roughly the proper format to # begin with. All that's left then is to determine which of the # three lat/lon formats it's in. # 48 07228N 122 07228W $input =~ s/^(\w+)\s+(\d)(\w)\s+(\w+)\s+(\d)(\w)\s*$/$1 0$2$3 $4 0$5$6\n/; # DD.DDD $input2 = $input; $input2 =~ s/^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s*$/$1.$2 $3.$4\n/; print $input2; &convert($input2, "DD.DDD"); print "\n"; # DD MM.MMM $input2 = $input; $input2 =~ s/^(\w+)\s+(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\w+)\s*$/$1 $2.$3 $4 $5.$6\n/; $input2 =~ s/(\.N)/.00N/; $input2 =~ s/(\.S)/.00S/; $input2 =~ s/(\.E)/.00E/; $input2 =~ s/(\.W)/.00W/; print $input2; &convert($input2, "DD MM.MM"); print "\n"; # DD MM SS.S $input2 = $input; $input2 =~ s/^(\w+)\s+(\d\d)(\w)\s+(\w+)\s+(\d\d)(\w)\s*$/$1 $2 00.$3 $4 $5 00.$6\n/; $input2 =~ s/^(\w+)\s+(\d\d)(\d)(\w)\s+(\w+)\s+(\d\d)(\d)(\w)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/; $input2 =~ s/^(\w+)\s+(\d\d)(\d\d)(\w+)\s+(\w+)\s+(\d\d)(\d\d)(\w+)\s*$/$1 $2 $3.$4 $5 $6 $7.$8\n/; $input2 =~ s/(\.N)/.0N/; $input2 =~ s/(\.S)/.0S/; $input2 =~ s/(\.E)/.0E/; $input2 =~ s/(\.W)/.0W/; $input2 =~ s/\s(\d)(\.\d)/ 0$1$2/g; print $input2; &convert($input2, "DD MM SS"); } close(FH); Xastir-Release-2.2.4/scripts/planesships.pl0000775000175000017500000000572015151324131017705 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # Enable various functions below. $start_xastir = 0; $enable_planes = 1; # Requires 1 SDR dongle $enable_plane_logging = 0; # Can fill up hard drive $enable_plane_alternate = 0; # Must also set $enable_planes. Requires another SDR dongle $enable_ships = 0; # Requires 1 SDR dongle $enable_ship_long_range = 0; # Requires 1 SDR dongle # Set RTL-SDR device numbers below (Starts at device 0). Set the numbers # based on how the SDR dongles get enumerated and how your antennas are # connected. You'll need a separate RTL-SDR dongle for each. $plane1090_SDR = 0; # Used with "enable_planes" above $plane978_SDR = 1; # Used with "enable_plane_alternate" above $ship_SDR = 2; # Used with "enable_ships" above $ship_long_range_SDR = 3; # Used with "enable_ship_long_range" above # Paths to executables: Set to match where things reside on your system. $XTERM = "/usr/bin/xterm"; $DUMP1090 = "~/src/dump1090/mutability/dump1090"; $ADSBPL = "/usr/local/share/xastir/scripts/ads-b.pl"; $RTLSDR = "/usr/local/bin/rtl_sdr"; $DUMP978 = "~/src/dump978/dump978"; $UAT2ESNT = "~/src/dump978/uat2esnt"; $NC = "/usr/bin/nc"; $XASTIR = "/usr/local/bin/xastir"; $RTLAIS = "~/src/rtl-ais/rtl-ais/rtl_ais"; $AISPL = "/usr/local/share/xastir/scripts/ais.pl"; #---------------------------------------------------- if ($start_xastir == 1) { system("$XASTIR &"); sleep(5); } if ($enable_planes == 1) { # SDR on main ADS-B frequency/protocol of 1.09 GHz: system("$XTERM -T ADS-B -e $DUMP1090 --interactive --net --interactive-ttl 86400 --net-sbs-port 30003 --phase-enhance --oversample --fix --ppm -1.2 --gain -10 --device-index $plane1090_SDR &"); if ($enable_plane_alternate == 1) { sleep(3); # Wait after starting dump1090 before dump978 connects to it # SDR on alternate ADS-B frequency of 978 MHz (and alternate ADS-B protocol): system("$XTERM -T ADS-B-Alternate -e $RTLSDR -f 978000000 -s 2083334 -g 0 -d $plane978_SDR - | $DUMP978 | $UAT2ESNT | $NC -q1 localhost 30001 &"); } sleep(3); # Give time to start programs above before Perl script connects if ($enable_plane_logging) { system("$XTERM -T ads-b.pl -geometry 175x25 -e $ADSBPL planes 10163 --logging &"); } else { system("$XTERM -T ads-b.pl -geometry 175x25 -e $ADSBPL planes 10163 &"); } } if ( ($enable_ships == 1) || ($enable_ship_long_range == 1) ) { if ($enable_ships == 1) { # SDR receiving the two normal AIS frequencies: system("$XTERM -T AIS -e $RTLAIS -h 127.0.0.1 -P 10110 -d $ship_SDR -l 161.975M -r 162.025M -n -p -2 &"); } if ($enable_ship_long_range == 1) { # SDR receiving the two long-range AIS frequencies: system("$XTERM -T AISLongRange -e $RTLAIS -h 127.0.0.1 -P 10110 -d $ship_long_range_SDR -l 156.775M -r 156.825M -n -p -2 &"); } sleep(3); # Give time to start programs above before Perl script connects system("$XTERM -T ais.pl -e $AISPL boats 9209 &"); } Xastir-Release-2.2.4/scripts/pos2shp.pl0000775000175000017500000001025315151324131016747 0ustar hibbyhibby#!/usr/bin/env perl # # # Copyright (C) 2006-2012 Tom Russo # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This script produces an ESRI point shapefile from an APRS overlay # file (*.pos), according to the "Rolling your own shapefile maps" # section of README.MAPS The point file will display using the TIGER # Landmark Point dbfawk file. # # This enables fast generation of point maps in Shapefile format # from APRS overlay files. # # Typical usage: # pos2shp.pl file.pos myshape #-------------------------------------------------------------------------- if ($#ARGV != 1) { print "Usage: $0 \n"; exit 1; } open(INOBJ,"<$ARGV[0]") || die "Cannot open input overlay file $ARGV[0]\n"; $cmd[0]="shpcreate $ARGV[1] point"; $cmd[1]="dbfcreate $ARGV[1] -n ID 8 0 -s CFCC 4 -s NAME 30"; $outfile=$ARGV[1]; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } # We now have the shapefile and dbf file created, start populating from the # overlay file: $i=0; $first_line = 1; while () { chomp($_); # Skip the first line if it starts with a '*' (comment line). next if ($first_line && (substr($_,0,1) eq '*') ); $first_line = 0; $temp = $_; @bits = split('!', $temp); # Sanity check --- don't try to convert if the line doesn't # conform to what we expect. We should have two items in the # array at this point. next if (length(@bits) < 1); $name2 = $bits[0]; $rest = $bits[1]; $name = substr($name2,0,9); # Chop at 9 chars $name =~ s/\w+\s+$//; # Remove trailing spaces $lat=substr($rest,0,8); $symtab=substr($rest,8,1); $long=substr($rest,9,9); $sym=substr($rest,18,1); # TODO: Do something with the comment field? It appears that if we # add too much here we get strange results when displayed in Xastir. $comment=substr($rest,19,100); # $name = $name . ":" . $comment; $i++; # bump the ID number so every point has a unique one $lat_deg=substr($lat,0,2); $lat_min=substr($lat,2,5); $lat_hem=substr($lat,7,1); $long_deg=substr($long,0,3); $long_min=substr($long,3,5); $long_hem=substr($long,8,1); $lat=$lat_deg+$lat_min/60; $lat *= -1 if ($lat_hem eq "S"); $long=$long_deg+$long_min/60; $long *= -1 if ($long_hem eq "W"); # Construct symbol if ($symtab ne "/" && $symtab ne "\\") { print "overlay symbol, symtab is $symtab\n"; $overlay=$symtab; $symtab="\\"; print " reset values symtab is $symtab, overlay is $overlay\n"; } else { $overlay=" "; } $cmd[0]="shpadd $outfile $long $lat"; $cmd[1]="dbfadd $outfile $i \'X$symtab$sym$overlay\' $name"; print $cmd[1]."\n"; foreach $command (@cmd) { system($command); if ($? == -1) { print "failed to execute: $!\n"; } elsif ($? & 127) { printf "child died with signal %d, %s coredump\n", ($? & 127), ($? & 128) ? 'with' : 'without'; } elsif ($?&0xF0) { printf "child exited with value %d\n", $? >> 8; } } } Xastir-Release-2.2.4/scripts/ridge_radar.pl0000775000175000017500000000331615151324131017616 0ustar hibbyhibby#!/usr/bin/env perl # # # Contributed to the public domain. Authored by Jeremy McDermond # (NH6Z). # # This script takes a single argument: The abbreviation of the # radar station off of the NWS site, and outputs to STDOUT a .geo # file that should be correct. # NOTE: You'll need to install "LWP::UserAgent" and "Image::Size" # from CPAN to make it work. # # Here's a typical invocation which creates a NYC Ridge Radar .geo # file called OKX_NOR.geo: # # ./ridge_radar.pl OKX > OKX_NOR.geo # # Of course you'd typically put the resulting file in your Xastir # maps directory and reindex maps to make it available for use. use strict; use LWP::UserAgent; use Image::Size; my $station = uc($ARGV[0]); my $gif_url = 'https://radar.weather.gov/ridge/RadarImg/N0R/' . $station . '_N0R_0.gif'; my $response = LWP::UserAgent->new->request( HTTP::Request->new( GET => $gif_url ) ); unless($response->is_success) { die "Couldn't get radar image: ", $response->status_line, "\n"; } my ($img_x, $img_y) = imgsize(\$response->content); my $response = LWP::UserAgent->new->request( HTTP::Request->new( GET => 'https://radar.weather.gov/ridge/RadarImg/N0R/' . $station . '_N0R_0.gfw' ) ); unless($response->is_success) { die "Couldn't get radar descriptor: ", $response->status_line, "\n"; } my ( $yscale, undef, undef, $xscale, $lon, $lat ) = split(/\r\n/, $response->content); my $tiepoint_lat = $lat - ($yscale * $img_y); my $tiepoint_lon = $lon - ($xscale * $img_x); print "URL\t\t$gif_url\n"; print "TIEPOINT\t0\t0\t$lon\t$lat\n"; print "TIEPOINT\t$img_x\t$img_y\t$tiepoint_lon\t$tiepoint_lat\n"; print "IMAGESIZE\t$img_x\t$img_y\n"; print "REFRESH\t\t60\n"; print "TRANSPARENT\t0x0\n"; print "PROJECTION\tLatLon\n"; Xastir-Release-2.2.4/scripts/slideshow.pl0000775000175000017500000000636715151324131017365 0ustar hibbyhibby#!/usr/bin/env perl # # Script to create a slideshow from Xastir snapshot images. Note # that this script is Unix/Linux-centric due to the use of the $HOME # variable and the use of the "cp" command. # # Written 20090415 by Curt Mills, WE7U # # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # # Copies/renames ~/.xastir/tmp/snapshot.png files so that a # slideshow can be created from the images at a later date. The # script monitors the input directory. Any new snapshot.png file # that appears is allowed to age for a few seconds to make sure that # Xastir is done writing the file, then the file is copied to the # ~/.xastir/tmp/slideshow/ directory as a numbered file. See below # for one method for turning these files into an animated GIF, or # else bring them up in some slideshow program and display them in # numerical order. The name of the file contains the Unix Epoch # timestamp (the exact second that the file was made). # # # A note from Carl Makin, vk1kcm, modified slightly by Curt, we7u, # regarding creation of an animated GIF from the slideshow images: # # ------------------------------------------------------------------- # This will create an animated gif that loops in your browser. # gm convert -delay 20 -loop snapshot*.png animation.gif # See: # http://www.graphicsmagick.org/FAQ.html#how-do-i-create-a-gif-animation-sequence-to-display-within-netscape # I think you can also great mpegs by changing the filename to "animation.mpg". # ------------------------------------------------------------------- # $home = $ENV{"HOME"}; $input_dir = "$home/.xastir/tmp"; $output_dir = "$input_dir/slideshow"; # Create the slideshow directory if it doesn't exist mkdir $output_dir; chdir $input_dir; while (1) { $current_time = time; # Snag the age of the existing snapshot.png file $number = (stat("snapshot.png"))[9]; $difference = $current_time - $number; # If the age of the file is more than 15 seconds but less than 31 # minutes, copy the file to the slideshow directory and rename it # along the way. Note that Xastir can produce snapshots at a rate # of between one per minute, and one per 30 minutes. # if ( ($difference > 15) && ($difference < (31 * 60)) ) { # Copy the snapshot image to the slideshow directory, renaming # it with the Unix Epoch time, something like: "1239897417.png". # Only copies the file if the source file is newer than the # destination, which prevents copying the file again and again # if it's the last file in your sequence. # `cp -u snapshot.png $output_dir/$number.png`; } sleep 30; } Xastir-Release-2.2.4/scripts/test_coord.pl0000775000175000017500000001224515151324131017521 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # test_coord.pl: Perl code to test out the Coordinate.pm # module. # # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # # TODO: # ----- # #------------------------------------------------------------------------------------------------ use lib "/usr/local/lib"; use Coordinate; # Snag WE7U's Coordinate module &test(); # # Routine for testing out the module. # # Need to add in tests for each method and object type. # sub test { my $to_WGS84 = 0; my $from_WGS84 = 1; my $position = Coordinate->new(); $position->latitude(48.125); $position->longitude(-122.500); $position->datum("NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri"); # Datum printf("Starting position(Lat, Long): %s %s\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS format printf("Starting position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); $position->lat_lon_to_utm(); printf("Calculated UTM position(Easting, Northing, Zone): %f %f %s\n", $position->easting(), $position->northing(), $position->zone() ); $position->utm_to_lat_lon(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "Changing from NAD27 to WGS84 datum...\n"; $position = $position->datum_shift_to_wgs84(); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); $position->degrees_minutes_seconds(); # Convert to DD MM SS printf("Calculated Lat, Long position(Lat, Long): %s %s\n", $position->formatted_latitude(), $position->formatted_longitude() ); print "Changing from WGS84 to NAD27 datum...\n"; $position = $position->datum_shift_from_wgs84_to( "NAD27 CONUS MEAN:W of Mississippi/Except Louisiana/Minnesota/Missouri" ); printf("Calculated Lat, Long position(Lat, Long): %f %f\n", $position->latitude(), $position->longitude() ); print "\n0\n"; my $temp = CoordinateFormat->new( "0" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( ) ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( ) ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds() ); print "180\n"; $temp->raw( "180" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180") ); print "180 30\n"; $temp->raw( "180 30" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30") ); print "180.50\n"; $temp->raw( "180.50" ); printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180.50") ); $temp->raw( "180 30.50" ); print "180 30.50\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30.50") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30.50") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30.50") ); $temp->raw( "180 30 30" ); print "180 30 30\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees( "180 30 30") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes( "180 30 30") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30 30") ); $temp->raw( "180 30 30.5" ); print "180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("180 30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("180 30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("180 30 30.5") ); $temp->raw( "-180 30 30.5" ); print "-180 30 30.5\n"; printf(" decimal_degrees: %s\n", $temp->decimal_degrees("-180 30 30.5") ); printf(" degrees_minutes: %s\n", $temp->degrees_minutes("-180 30 30.5") ); printf("degrees_minutes_seconds: %s\n\n", $temp->degrees_minutes_seconds("-180 30 30.5") ); EllipsoidTable->enumerate(); DatumTable->enumerate(); } Xastir-Release-2.2.4/scripts/toporama250k.pl0000775000175000017500000001725215151324131017603 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # Copyright (C) 2000-2026 The Xastir Group. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # This will retrieve the 1:250k map images from the "Department of # Natural Resources Geomatics Canada" site. These are topographic # map files for the whole of Canada! # # # - "cd /usr/local/share/xastir/maps" # # - Assure you have write privileges in the directory above either # by becoming root using the "su" command, using "sudo", or # temporarily changing ownership and/or privileges on the # "maps" directory. # # - "/usr/local/lib/xastir/toporama250k.pl" # # - The script will create/populate this directory hierarchy: # .../maps/toporama/images/ # .../maps/toporama/images/b250k/ # # - Move/rename directories/contents as you wish. # # - In Xastir: "Map->Configure->Index: Reindex ALL Maps!" # # # Note that the same map files are also available from Steve Dimse's # site: "http://mm.aprs.net/maps/geo/toporama" # # # Code for this script contributed by Adi Linden, VA3ADI. # Modifications for latitudes above 67 degrees north contributed by Tom Tessier, VE4TRT # Create the "toporama" directory mkdir "toporama"; chdir "toporama"; # Retrieve the 1:250,000 map images. Skipping those that we've # already downloaded. `wget -nv -np -nH -N -r -m -l 0 -T 10 http://toporama.cits.rncan.gc.ca/images/b250k/`; # Remove index.html files `rm -rf \`find ./images -type f -name index.html\*\``; # Remove *.asc files `rm -rf \`find ./images -type f -name \*.asc\``; # Define some stuff $base_dir = "images/b250k"; # This defines the top left corner of the 0 grid up to 67 degrees north latitude. $basex = '-56'; $basey = '44'; %offsetx = ( 'a' => 3, 'b' => 2, 'c' => 1, 'd' => 0, 'e' => 0, 'f' => 1, 'g' => 2, 'h' => 3, 'i' => 3, 'j' => 2, 'k' => 1, 'l' => 0, 'm' => 0, 'n' => 1, 'o' => 2, 'p' => 3, '1' => 3, '2' => 2, '3' => 1, '4' => 0, '5' => 0, '6' => 1, '7' => 2, '8' => 3, '9' => 3, '10' => 2, '11' => 1, '12' => 0, '13' => 0, '14' => 1, '15' => 2, '16' => 3 ); %offsety = ( 'a' => 3, 'b' => 3, 'c' => 3, 'd' => 3, 'e' => 2, 'f' => 2, 'g' => 2, 'h' => 2, 'i' => 1, 'j' => 1, 'k' => 1, 'l' => 1, 'm' => 0, 'n' => 0, 'o' => 0, 'p' => 0, '1' => 3, '2' => 3, '3' => 3, '4' => 3, '5' => 2, '6' => 2, '7' => 2, '8' => 2, '9' => 1, '10' => 1, '11' => 1, '12' => 1, '13' => 0, '14' => 0, '15' => 0, '16' => 0 ); # This defines the top left corner of the 0 grid between 68 and 84 degrees north latitude. %offsetx68 = ( 'a' => 4, 'b' => 0, 'c' => 0, 'd' => 4, 'e' => 4, 'f' => 0, 'g' => 0, 'h' => 4, '1' => 4, '2' => 0, '3' => 0, '4' => 4, '5' => 4, '6' => 0, '7' => 0, '8' => 4 ); %offsety68 = ( 'a' => 3, 'b' => 3, 'c' => 2, 'd' => 2, 'e' => 1, 'f' => 1, 'g' => 0, 'h' => 0, '1' => 3, '2' => 3, '3' => 2, '4' => 2, '5' => 1, '6' => 1, '7' => 0, '8' => 0 ); #def use File::Find; print "Writing .geo files\n"; find(\&process, $base_dir); print "\nDone.\n"; # Run for each file found sub process { # Only look for .gif files if ( /.gif$/ ) { # Get the map sheet designation from the file name $file = "$_"; $grida = substr($file, 0, 3); $gridb = substr($file, 3, 1); $hilat = substr($file, 2, 1); # .geo calculations for lattitudes greater than 78 degrees north latitude. if ( $grida > 119 ) { # Calculate top left coordinates of the map sheet use integer; $topx = $basex - ((($grida/10) +10 ) / 22 * 16) + $offsetx68{$gridb} * 2; $topy = 84 - $offsety68{$gridb} * 1; $botx = $topx + 8; $boty = $topy - 2; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t6399\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t6400\t1600\n"; close OUT; print "."; next; } # .geo calculations for lattitudes between 68 and 78 degrees north latitude. if ( $hilat > 6 ) { # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx68{$gridb} * 1; $topy = $basey + ($grida % 10) * 4 - $offsety68{$gridb} * 1; $botx = $topx + 4; $boty = $topy - 1; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t6399\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t6400\t1600\n"; close OUT; print "."; next; } # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx{$gridb} * 2; $topy = $basey + ($grida % 10) * 4 - $offsety{$gridb} * 1; $botx = $topx + 2; $boty = $topy - 1; # Create the output file $out = substr($file, 0, 4) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama250k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t3199\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t3200\t1600\n"; close OUT; print "."; } } Xastir-Release-2.2.4/scripts/toporama50k.pl0000775000175000017500000001204615151324131017515 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # Copyright (C) 2000-2026 The Xastir Group. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # Look at the README for more information on the program. # This will retrieve the 1:50k map images from the "Department of # Natural Resources Geomatics Canada" site. These are topographic # map files for the whole of Canada! # # # - "cd /usr/local/share/xastir/maps" # # - Assure you have write privileges in the directory above either # by becoming root using the "su" command, using "sudo", or # temporarily changing ownership and/or privileges on the # "maps" directory. # # - "/usr/local/lib/xastir/toporama50k.pl" # # - The script will create/populate this directory hierarchy: # .../maps/toporama/images/ # .../maps/toporama/images/b50k/ # # - Move/rename directories/contents as you see fit. # # - In Xastir: "Map->Configure->Index: Reindex ALL Maps!" # # # Note that the same map files are also available from Steve Dimse's # site: "http://mm.aprs.net/maps/geo/toporama" # # # Code for this script contributed by Adi Linden, VA3ADI. # Create the "toporama" directory mkdir "toporama"; chdir "toporama"; # Retrieve the 1:50,000 map images. Skipping those that we've # already downloaded. `wget -nv -np -nH -N -r -m -l 0 -T 10 http://toporama.cits.rncan.gc.ca/images/b50k/`; # Remove index.html files `rm -rf \`find ./images -type f -name index.html\*\``; # Remove *.asc files `rm -rf \`find ./images -type f -name \*.asc\``; # Define some stuff $base_dir = "images/b50k"; # This defines the top left corner of the 0 grid. $basex = '-56'; $basey = '44'; %offsetx = ( 'a' => 3, 'b' => 2, 'c' => 1, 'd' => 0, 'e' => 0, 'f' => 1, 'g' => 2, 'h' => 3, 'i' => 3, 'j' => 2, 'k' => 1, 'l' => 0, 'm' => 0, 'n' => 1, 'o' => 2, 'p' => 3, '01' => 3, '02' => 2, '03' => 1, '04' => 0, '05' => 0, '06' => 1, '07' => 2, '08' => 3, '09' => 3, '10' => 2, '11' => 1, '12' => 0, '13' => 0, '14' => 1, '15' => 2, '16' => 3 ); %offsety = ( 'a' => 3, 'b' => 3, 'c' => 3, 'd' => 3, 'e' => 2, 'f' => 2, 'g' => 2, 'h' => 2, 'i' => 1, 'j' => 1, 'k' => 1, 'l' => 1, 'm' => 0, 'n' => 0, 'o' => 0, 'p' => 0, '01' => 3, '02' => 3, '03' => 3, '04' => 3, '05' => 2, '06' => 2, '07' => 2, '08' => 2, '09' => 1, '10' => 1, '11' => 1, '12' => 1, '13' => 0, '14' => 0, '15' => 0, '16' => 0 ); use File::Find; print "Writing .geo files\n"; find(\&process, $base_dir); print "\nDone.\n"; # Run for each file found sub process { # Only look for .gif files if ( /.gif$/ ) { # Get the map sheet designation from the file name $file = "$_"; $grida = substr($file, 0, 3); $gridb = substr($file, 3, 1); $gridc = substr($file, 4, 2); if ( $grida > 119 ) { next; } # Calculate top left coordinates of the map sheet use integer; $topx = $basex - $grida / 10 * 8 + $offsetx{$gridb} * 2; $topy = $basey + ($grida % 10) * 4 - $offsety{$gridb} * 1; no integer; $topx = $topx + $offsetx{$gridc} * 0.5; $topy = $topy - $offsety{$gridc} * 0.25; $botx = $topx + 0.5; $boty = $topy - 0.25; # Create the output file $out = substr($file, 0, 6) . ".geo"; open (OUT, ">$out") or die "Can't open $OUT: $!\n"; print OUT "# Automatically created by toporama50k.pl\n"; print OUT "FILENAME\t$file\n"; print OUT "#\t\tx\ty\tlon\tlat\n"; print OUT "TIEPOINT\t0\t0\t$topx\t$topy\n"; print OUT "TIEPOINT\t3199\t1599\t$botx\t$boty\n"; print OUT "IMAGESIZE\t3200\t1600\n"; close OUT; print "."; } } Xastir-Release-2.2.4/scripts/track-get.pl0000775000175000017500000001060315151324131017231 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will ask for an item designator, then create a file # with that name + ".log" in the ~/.xastir/logs directory. The # file will contain APRS items created from the downloaded Garmin # tracklog. Reading that log file with Xastir will result in an # object with a track being displayed on the map screen. # You may wish to bump up MAX_TRACKS in db.h to 1024 in order to see # the entire log, but be careful with Xastir's memory image growing # too fast if you're connected to the 'net after making this change. # This script uses the GPS::Garmin module which can be obtained # from http://sourceforge.net/projects/perl-gps/ use GPS::Garmin; use IO::File; # Flush STDOUT $| = 1; # Hard-coded "from" callsign name. This becomes the "sending" # callsign for the APRS Items. $from = "SAR"; # Ask for the item name. This will turn into the 3-9 character APRS # item name. printf("\n\nEnter item designator: Length 1-9, all except '!' and '_' allowed, case respected:\n\n"); printf("\t123456789\n\t"); $name = <>; chomp $name; if (length($name) < 1) { die "Must be at least one character!\n"; } if (length($name) > 9) { $name =~ s/(.{9}).*/\1/; # Terminate it at 9 chars } if (length($name) < 3) { $name = $name . " "; # Pad the name with spaces $name =~ s/(.{3}).*/\1/; # Terminate it at 3 chars } # We need to enforce the naming restrictions for APRS Items. '!' # and '_' are not allowed, anything else that's printable ASCII is # ok. @j = split(//, $name); for ($i = 0; $i < length($name); $i++) { #printf("$i $j[$i]\n"); if ( ($j[$i] lt ' ') || ($j[$i] gt '~') || ($j[$i] eq '!') || ($j[$i] eq '_') ) { $j[$i] = ' '; } } $name = join("",@j); $filename = "~/.xastir/logs/$name.log"; # Get rid of spaces in the filename $filename =~ s/\s+//g; # Expand the tilde into the home directory $filename =~ s{ ^ ~ ( [^/]* ) } { $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7] ) }ex; printf("\nThe item designator will be: ($name)\n"); printf("The output filename will be: ($filename)\n\n"); printf("Connect Garmin GPS to /dev/ttyS0 (COM1), set it to Garmin/Garmin mode.\n"); printf("Press to proceed with download, Ctrl-C to abort\n"); <>; # Create a file to hold the data $output = IO::File->new("> $filename") or die "Couldn't open $filename for writing: $!\n"; $gps = new GPS::Garmin( 'Port' => '/dev/ttyS0', 'Baud' => 9600, ) or die "Unable to connect to receiver: $!"; # Transfer trackpoints: $i = 0; $gps->prepare_transfer("trk"); while ($gps->records) { ($lat,$lon,$time) = $gps->grab; # printf("%f %f %d\n",$lat,$lon,$time); if ($lon < 0) { $londeg = sprintf("%d",-$lon); $lonmin = (-$lon - $londeg) * 60; $lonchar = "W"; } else { $londeg = sprintf("%d",$lon); $lonchar = "E"; $lonmin = ($lon - $londeg) * 60; } if ($lat < 0) { $latdeg = sprintf("%d",-$lat); $latmin = (-$lat - $latdeg) * 60; $latchar = "S"; } else { $latdeg = sprintf("%d",$lat); $latmin = ($lat - $latdeg) * 60; $latchar = "N"; } # Write an APRS Item for each trackpoint printf($output "%s>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s%s\n", $from, $name, $latdeg, $latmin, $latchar, $londeg, $lonmin, $lonchar, "/"); if (! ($i % 10) ) { printf("$i "); } $i++; } printf("\n\nThe data has been saved in: ($filename)\n"); printf("Please open this logfile with Xastir to display the track\n"); printf("!!!Remember to set your GPS back to NMEA mode for APRS!!!\n"); Xastir-Release-2.2.4/scripts/update_langfile.pl0000775000175000017500000001120715151324131020474 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # Update utility for XASTIR language files 17.04.2001 # Copyright (C) 2001 Rolf Bleher http://www.dk7in.de # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # see file COPYING for details #-------------------------------------------------------------------------- # This program adds missing entries to the translated language files and # deletes obsolete entries. # If a translated comment before an entry block is found it will be preserved. # There might be problems with the comment with a changed block sequence. # I assume that you start it in the directory with the language files, # call it with the translated language file as parameter. # DK7IN: for now it assumes that the language files reside # in the current directory #-------------------------------------------------------------------------- $LF1 = "language-English.sys"; # original language file $LF2 = "language-German.sys"; # translated language file $LFOUT = "language-new.sys"; # modified translated language file if (@ARGV) { $LF2 = shift @ARGV; } #-------------------------------------------------------------------------- open(IN1,$LF1) or die "ERROR: could not open $LF1!\n"; open(IN2,$LF2) or die "ERROR: could not open $LF2!\n"; open(OUT,">$LFOUT") or die "ERROR: could not write to $LFOUT!\n"; #-------------------------------------------------------------------------- %token = (); # translated tokens @cmt1 = (); # original comment @cmt2 = (); # translated comment # collect all available translated tokens while () { next if (/^#/); # skip comment lines if (/^([A-Z]+[0-9]+)(|.+|.?|.*)$/) { $token{$1} = $2; # store translated text entry } } # process language file while () { # original language file if (/^#/) { # comment line push(@cmt1,$_); # store comment } else { if (/^([A-Z]+)([0-9]+)(|.+|.?|.*)$/) { # data line $name = $1; $numb = $2; $arg = $3; if (@cmt1) { # pending comment # try to find the translation seek IN2, 0, 0; # reposition to begin of file @cmt2 = (); # translated comment $match = 0; while () { $line = $_; if (/^([A-Z]+)([0-9]+)(|.+|.?|.*)$/) { $curr = $1; if ($name eq $curr) { # same block $match = 1; last; } else { @cmt2 = (); # clear wrong comment } } else { if (/^#/) { # store comment push(@cmt2,$_); } } } if ($match && @cmt2) { # found translated comment foreach $line (@cmt2) { print(OUT $line); # translated comment } } else { foreach $line (@cmt1) { print(OUT $line); # original comment } } @cmt1 = (); } if ($token{$name.$numb}) { # found translation $arg = $token{$name.$numb}; } printf(OUT "%s%s%s\n",$name,$numb,$arg); } else { print("ERROR: $_"); # bad line format } } } close(IN1); close(IN2); close(OUT); exit; #-------------------------------------------------------------------------- Xastir-Release-2.2.4/scripts/waypoint-get.pl0000775000175000017500000001041115151324131017774 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2012 Curt Mills, WE7U # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA. # # This script will ask for a name, then create a file # with that name + ".log" in the ~/.xastir/logs directory. The # file will contain APRS items created from the downloaded Garmin # waypoints. Reading that log file with Xastir will result in one # item appearing on the map screen for each waypoint, labeled with # the name of that waypoint. # This script uses the GPS::Garmin module which can be obtained # from http://sourceforge.net/projects/perl-gps/ use GPS::Garmin; use IO::File; # Flush STDOUT $| = 1; # Hard-coded "from" callsign name. This becomes the "sending" # callsign for the APRS Items. $from = "SAR"; # Ask for the name. This gets changed into the complete log file name. printf("\n\nEnter name for file: '.log' will get added to the end:\n\n"); $name = <>; chomp $name; if (length($name) < 1) { die "Must be at least one character!\n"; } $filename = "~/.xastir/logs/$name.log"; # Get rid of spaces in the filename $filename =~ s/\s+//g; # Expand the tilde into the home directory $filename =~ s{ ^ ~ ( [^/]* ) } { $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7] ) }ex; printf("\nThe output filename will be: ($filename)\n\n"); printf("Connect Garmin GPS to /dev/ttyS0 (COM1), set it to Garmin/Garmin mode.\n"); printf("Press to proceed with download, Ctrl-C to abort\n"); <>; # Create a file to hold the data $output = IO::File->new("> $filename") or die "Couldn't open $filename for writing: $!\n"; $gps = new GPS::Garmin( 'Port' => '/dev/ttyS0', 'Baud' => 9600, ) or die "Unable to connect to receiver: $!"; # Transfer waypoints: $i = 0; $gps->prepare_transfer("wpt"); while ($gps->records) { ($title,$lat,$lon,$desc) = $gps->grab; #printf("%f\t%f\t%s\t%s\n",$lat,$lon,$desc,$title); if ($lon < 0) { $londeg = sprintf("%d",-$lon); $lonmin = (-$lon - $londeg) * 60; $lonchar = "W"; } else { $londeg = sprintf("%d",$lon); $lonchar = "E"; $lonmin = ($lon - $londeg) * 60; } if ($lat < 0) { $latdeg = sprintf("%d",-$lat); $latmin = (-$lat - $latdeg) * 60; $latchar = "S"; } else { $latdeg = sprintf("%d",$lat); $latmin = ($lat - $latdeg) * 60; $latchar = "N"; } chomp $title; if (length($title) < 1) { die "Must be at least one character!\n"; } if (length($title) > 9) { $title =~ s/(.{9}).*/\1/; # Terminate it at 9 chars } if (length($title) < 3) { $title = $title . " "; # Pad the title with spaces $title =~ s/(.{3}).*/\1/; # Terminate it at 3 chars } # We need to enforce the naming restrictions for APRS Items. '!' # and '_' are not allowed, anything else that's printable ASCII is # ok. @j = split(//, $title); for ($k = 0; $k < length($title); $k++) { #printf("$k $j[$k]\n"); if ( ($j[$k] lt ' ') || ($j[$k] gt '~') || ($j[$k] eq '!') || ($j[$k] eq '_') ) { $j[$k] = ' '; } } $title = join("",@j); # Write an APRS Item for each waypoint printf($output "%s>APRS:)%s!%02d%05.2f%s/%03d%05.2f%s%s\n", $from, $title, $latdeg, $latmin, $latchar, $londeg, $lonmin, $lonchar, "/"); if (! ($i % 10) ) { printf("$i "); } $i++; } printf("\n\nThe data has been saved in: ($filename)\n"); printf("Please open this logfile with Xastir to display the waypoints.\n"); printf("!!!Remember to set your GPS back to NMEA mode for APRS!!!\n"); Xastir-Release-2.2.4/scripts/wms.pl0000775000175000017500000001025415151324131016160 0ustar hibbyhibby#!/usr/bin/env perl use warnings; # # Copyright (C) 2000-2026 The Xastir Group # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # # Run this as "./wms.pl URL", where URL = a "GetCapabilities" link, but # with a backslash added before each '&' character. The script will # download the XML file at that URL and parse it. It will then attempt # to find the map layer names and list them at the end of the run. #my $xml_text = `wget -O - "http://geogratis.gc.ca/maps/CBMT?service=wms\&version=1.1.1\&request\=GetCapabilities"`; #my $xml_text = `wget -O - "http://nowcoast.noaa.gov/arcgis/services/nowcoast/radar_meteo_imagery_nexrad_time/MapServer/WMSServer?request=GetCapabilities\&service=WMS\&version=1.3.0"`; # # Once you have the map layer names it is relatively easy to construct a # .geo file for Xastir that uses one of those map layers. Here's an example # from README.MAPS. Both lines are required in the .geo file: # ----------------------- # WMSSERVER # URL http://geogratis.gc.ca/maps/CBMT?VERSION=1.1.1&SERVICE=WMS&REQUEST=GetMap&SRS=EPSG:4326&LAYERS=Sub_regional&STYLES=&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=FALSE # ----------------------- # #Here's the info from Dumper that we're interested in (Name): #$VAR1 = { # 'Capability' => [ # { # 'Layer' => [ # { # 'Layer' => [ # { # 'Name' => [ # 'National' # # -or- # #$VAR1 = { # 'Capability' => { # 'Layer' => { # 'Layer' => { # 'Layer' => [ # { # 'Name' => '1', use strict; use XML::Simple; use Getopt::Std; use Data::Dumper; use Scalar::Util 'reftype'; my $url; $url = shift; if (!defined $url || $url eq "") { print "Please enter GetCapabilities URL with '\' before each '&' character.\n"; $url = <>; } my $xml_text= `wget -O - $url`; my $xml = XMLin( $xml_text ); print Dumper($xml); print "\n----------------------------------------------------------\n\n"; my $version = $url; $version =~ s/.*version=(\d+\.\d+\.\d+).*/$1/; if ($version =~ /\d+\.\d+\.\d+/) { } else { $version = "1.0.0"; } my $url_filtered = $url; $url_filtered =~ s/\\//g; # Get rid of backslashes $url_filtered =~ s/(.*\?).*/$1/; # Remove everything after '?' $url_filtered = "URL " . $url_filtered . "SERVICE=wms&VERSION=$version&REQUEST=GetMap&SRS=EPSG:4326&FORMAT=image/png&BGCOLOR=0xFFFFFF&TRANSPARENT=false&STYLES=&LAYERS="; print "POSSIBLE .GEO FILE CONTENTS:\n\n"; my $ii; my $reftype = reftype $xml->{Capability}->{Layer}->{Layer}; if ( (defined $reftype) && ($reftype eq 'ARRAY') ) { for ($ii = 0; $ii < 15; $ii++) { if ( defined($xml->{Capability}->{Layer}->{Layer}->[$ii]->{Name}) ) { print "-----\n"; print "WMSSERVER\n"; print $url_filtered; print "$xml->{Capability}->{Layer}->{Layer}->[$ii]->{Name}\n"; } } } if ( (defined $reftype) && ($reftype eq 'HASH') ) { for ($ii = 0; $ii < 15; $ii++) { if ( defined($xml->{Capability}->{Layer}->{Layer}->{Layer}->[$ii]->{Name}) ) { print "-----\n"; print "\nWMSSERVER\n"; print $url_filtered; print "$xml->{Capability}->{Layer}->{Layer}->{Layer}->[$ii]->{Name}\n"; } } } Xastir-Release-2.2.4/scripts/wxnowsrv.pl0000775000175000017500000001157415151324131017275 0ustar hibbyhibby#!/usr/bin/env perl # Copyright (C) 2000-2026 The Xastir Group # # 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., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # # This script is used to feed weather data from a "Wxnow.txt" file # into Xastir as if it were a networked weather station. Wxnow.txt is # a standard file format that is created by a number different types # of weather station control software, and Xastir is unable to read # this file directly. # # The command line arguments are the path to the Wxnow.txt file, and # a polling period in seconds (this should be chosen to be the same period # that the Wxnow.txt file is updated by whatever tool is creating it. # An optional third argument allows the user to specify an alternate # server port other than 5500. # The script works by polling the Wxnow.txt file each $POLLTIME, and if # anything changes, flagging the change. This is done in one thread. # For each client that connects to the port, a new thread is created for # communicating with that client over a socket. Each time the polling thread # flags that data has changed, a string of weather data is sent to all connected # clients. # This script leverages the "Davis METEO" code in Xastir that implements # the networked weather station interface. As such, all weather stations # connected in this way to Xastir are assumed to be Davis weather stations, # no matter what type of weather station is connected. # Once this script is running, add a "Networked WX" interface to your Xastir # config, and provide the IP address on which the script is running and the # port number (default 5500) in the interface properties. # Once Xastir connects to the script, "View->Own Weather Data" should show # the current weather data in Wxnow.txt, and be updated every time Wxnow.txt # changes. use threads; use threads::shared; use IO::Socket; use Net::hostent; # for OO version of gethostbyaddr sub read_wxnow { my ($pathname,$lastwxref,$wxchangedref,$POLLTIME) = @_; my $slash="/"; while ( -e $pathname) { open (WXNOWFILE, "<$pathname") || die "Cannot open wxnow file $pathname\n"; my $firstline=1; while () { if ($firstline==1) { $firstline=0; next; } else { $newwx=$_; chomp($newwx); $newwx =~ s/^([0-9]{3})$slash([0-9]{3})g/c$1s$2g/; $newwx = $newwx . "xDvs"; if ($newwx ne $$lastwxref) { $$lastwxref=$newwx; $$wxchangedref =1; } else { $$wxchangedref=0; } } } close (WXNOWFILE); sleep $POLLTIME; } } sub handle_connection { my ($socket,$lastwxref,$wxchangedref,$POLLTIME) = @_; my $disconn = 0; my $firsttime=1; $socket->autoflush(1); my $hostinfo = gethostbyaddr($socket->peeraddr); while (1) { $foobar=getpeername($socket) or $disconn=1; if ($socket->connected()) { $disconn=0; } else { $disconn=1; } if ($disconn==0) { if ($$wxchangedref==1 || $firsttime==1) { send($socket,"$$lastwxref\n",0); $firsttime=0; } sleep $POLLTIME/2; } last if $disconn==1; } } if ( $#ARGV < 1) { print STDERR "Usage: $0 wxnowpath pollsecs [port]\n"; print STDERR " where wxnowpath is the full path to your wxnow.txt file\n"; print STDERR " and pollsecs is how often we should check this file for changes (in seconds)\n"; print STDERR " If given, the third argument is the port number on which to listen. Default=5500"; exit(1); } $SERVER_PORT=5500; if ( $#ARGV >1) { $SERVER_PORT=$ARGV[2]; } my $listen = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $SERVER_PORT, ReuseAddr => 1, Listen => SOMAXCONN ); my $lastwx : shared =""; my $wxchanged : shared =0; my $POLLTIME =$ARGV[1]; $pathname=$ARGV[0]; async(\&read_wxnow, $pathname,\$lastwx,\$wxchanged,$POLLTIME)->detach; while (my $socket = $listen->accept) { async(\&handle_connection, $socket,\$lastwx,\$wxchanged,$POLLTIME)->detach; } Xastir-Release-2.2.4/src/0000775000175000017500000000000015151324131014110 5ustar hibbyhibbyXastir-Release-2.2.4/src/.vimrc0000664000175000017500000000143315151324131015232 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/src/LICENSE.geocoder0000664000175000017500000004762715151324131016723 0ustar hibbyhibby The enclosed material (the "Material") is copyrighted 2002 by me, Daniel Egnor. I certify that I am the sole copyright holder of the Material, excluding material derived from the original Google contest materials ("Contest Materials"). Contest materials are used under the terms of the license included below as "Original Google License". Google, Inc. is hereby granted a worldwide, perpetual, fully paid-up, non-exclusive license to make, sell, or use the technology related to the Material, including but not limited to the software, algorithms, techniques, concepts, etc. associated with the Material. The public is hereby granted rights to the Material under the terms of the GNU General Public License, also included below. Any necessary exemptions required to redistribute the Material along with the contest materials are hereby granted. ------------------------------------------------------------------------------- Original Google License (applies to all files "goo-*") follows: ------------------------------------------------------------------------------- This repository of web page information is being provided to you by Google Inc. solely for academic and research purposes related to the Google programming contest. You may not modify, distribute, or make any commercial use of the repository. This source code is copyrighted 2002 by Google Inc. All rights reserved. You are given a limited license to use this source code for purposes of participating in the Google programming contest. If you choose to use or distribute the source code for any other purpose, you must either (1) first obtain written approval from Google, or (2) prominently display the foregoing copyright notice and the following warranty and liability disclaimer on each copy used or distributed. The source code and repository (the "Software") is provided "AS IS", with no warranty, express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular use. In no event shall Google Inc. be liable for any damages, direct or indirect, even if advised of the possibility of such damages. ------------------------------------------------------------------------------- GNU General Public License (applies to all other files) follows: ------------------------------------------------------------------------------- GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 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. Xastir-Release-2.2.4/src/Makefile.am0000664000175000017500000000545515151324131016155 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # bin_PROGRAMS = xastir xastir_udp_client testdbfawk SUBDIRS = rtree DIST_SUBDIRS = rtree EXTRA_DIST=icon.xbm XASTIR_SRC = \ alert.c alert.h \ ambiguity_utils.c ambiguity_utils.h \ awk.c awk.h \ bulletin_gui.c bulletin_gui.h \ cad_objects.c cad_objects.h \ color.c color.h \ datum.c datum.h \ debug_utils.c debug_utils.h \ db.c db_funcs.h database.h \ db_gis.c db_gis.h \ db_gui.c db_gui.h \ dbfawk.c dbfawk.h \ dlm.c dlm.h \ dr_utils.c dr_utils.h \ draw_symbols.c draw_symbols.h \ fcc_data.c fcc_data.h \ festival.c festival.h \ fetch_remote.c fetch_remote.h \ forked_getaddrinfo.c forked_getaddrinfo.h \ geocoder.c geocoder.h \ geocoder_gui.c \ gps.c gps.h \ hashtable.c hashtable_private.h hashtable.h \ hashtable_itr.c hashtable_itr.h \ igate.c igate.h \ interface.c interface.h \ interface_gui.c \ lang.c lang.h \ leak_detection.h \ list_gui.c list_gui.h \ locate_gui.c \ location.c \ location_gui.c \ log_utils.c log_utils.h \ main.c main.h \ maps.c maps.h \ map_cache.c map_cache.h \ map_dos.c \ map_geo.c \ map_gnis.c \ map_OSM.c map_OSM.h \ map_pop.c \ map_shp.c map_shp_fwd.h \ map_tif.c \ map_WMS.c \ messages.c messages.h \ messages_gui.c \ mgrs_utils.c mgrs_utils.h \ mutex_utils.c mutex_utils.h \ objects.h objects.c \ objects_gui.c objects_gui.h \ object_utils.h object_utils.c \ popup.h \ popup_gui.c \ rac_data.c rac_data.h \ rotated.c rotated.h \ rpl_malloc.c rpl_malloc.h \ shp_hash.c shp_hash.h \ snprintf.c snprintf.h \ sound.c sound.h symbols.h \ tactical_call_utils.c tactical_call_utils.h \ tile_mgmnt.c tile_mgmnt.h \ timer_utils.c timer_utils.h \ track_gui.c track_gui.h \ util.c util.h \ view_message_gui.c \ wx.c wx.h \ wx_gui.c \ x_spider.c x_spider.h \ xa_config.c xa_config.h \ xastir.h # Conditionally compiled sources if HAVE_NOMINATIM NOMINATIM_SRC = nominatim.c nominatim.h else NOMINATIM_SRC = endif xastir_SOURCES = $(XASTIR_SRC) $(NOMINATIM_SRC) compiledate.c xastir_udp_client_SOURCES = \ xastir_udp_client.c testdbfawk_SOURCES = \ testdbfawk.c \ awk.c \ dbfawk.c \ rpl_malloc.c rpl_malloc.h .PHONY: compiledate.c compiledate.c: $(XASTIR_SRC) rm -f compiledate.c compiledate.o echo 'char gitstring[] = "'"`$(top_srcdir)/scripts/XastirGitStamp.sh $(top_srcdir)`"'";' >> compiledate.c remove_compiledate: rm -f compiledate.c compiledate.o xastir_LDADD=-Lrtree -lrtree xastir_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ xastir_udp_client_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ testdbfawk_LINK=$(CC) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ Xastir-Release-2.2.4/src/alert.c0000664000175000017500000023071515151324131015373 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // alert_redraw_on_update will cause refresh_image to get called. // alert_add_entry sets it. // In the alert structure, flags[] is size 16. Only the first two // positions in the array are currently used. // // alert_entry.flags[0] // on_screen // ? Initial state or ready-to-recompute state // - Expired between 1 sec and 1 hour // Y Active alert within viewport // N Active alert outside viewport // // alert_entry.flags[1] // source // DATA_VIA_TNC // DATA_VIA_LOCAL // // alert_entry.to alert_entry.alert_level // CANCL C // Colors of alerts????? // TEST T // Colors of alerts????? // WARN R // Colors of alerts????? // CIVIL R // Colors of alerts????? // WATCH Y // Colors of alerts????? // ADVIS B // Colors of alerts????? // Other G // Colors of alerts????? // Unset ? // // // Here's how Xastir breaks down an alert into an alert struct: // // SFONPW>APRS::NWS-ADVIS:191700z,WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // |----| |-------| |-----| |--| |-----| |-----| |-| // | | | | | | | // from to | | title title issue_date // | alert_tag // activity (expiration) // // // The code should also handle the case where the packet looks like // this (it's the same as the above packet except for no expiration // date): // // SFONPW>APRS::NWS-ADVIS:WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // // // Expiration is then computed from the activity field. Alert_level // is computed from "to" and/or "alert_tag". // // // Stuff from Dale, paraphrased by Curt: // // WATCH - weather of some type is possible or probable for a geographic // area- at present I cannot do watches because they can cover huge areas // with hundreds of counties across many states. I have a prototye of a // polygon generator - but that is a whole other can of worms // // WARN - warning - Severe or dangerous weather is occurring or is about to // occur in a geographical area. This we do a pretty good job on output. // // ADVIS - advisory - this can be trivial all the way to a tornado report. // If a tornado warning is issued and another tornado sighting happens in // the same county/zone during the valid time of the first- the info is // transmitted as an advisory. Most of the time is is updates for other // messages. // // CANCL - cancelation- discussed in earlier e-mail // // I would add CIVIL for terrorist earthquake catostrophic type stuff - // the D7 and D&)) have special alarms built in so that a message to // NWS-CIVIL would alert folks no matter what there filters are set for. // // // The clue to which shapefile to use is in the 4th char in the // title (which is the first following an '_') // // ICTSVS>APRS::NWS-ADVIS:120145z,SEVERE_WEATHER,KS_Z091, {C14AA // TSASVR>APRS::NWS-WARN :120230z,SVRTSM,OK_C113, OSAGE COUNTY {C16AA // // C = county file (c_mmddyy.dbf) // A = County Warning File (w_mmddyy.dbf) // Z = Zone File (z_mmddyy.dbf or mz_mmddyy.dbf) // F = Fire zone file (fz_mmddyy.dbf) // A = Canadian Area (a_mmddyy.dbf) // R = Canadian Region (r_mmddyy.dbf) // // Alerts are comma-delimited on the air s.t. after the // :NWS-?????: the first field is the time in zulu (or local // with no 'z'), the 2nd is the warning type // (severe_thunderstorm etc.), the 3rd and up to 7th are s.t. // the first 2 letters are the state or marine zone (1st field // in both the county and zone .dbf files) followed by an // underline char '_', the area type as above (C, Z, or A), // then a 3 digit numerical code derived from: // // Counties: the fips code (4th field in the .dbf) // // Zones: the zone number (2nd field in the .dbf) // // Marine Zones: have proper code in 1st field with addition of '_' in correct place. // // CWA: 2nd field has cwa-, these are always "CW_A" plus the cwa // // You must ignore anything after a space in the alert. // // We will probably want to add the "issue time" to the alert record // and parse that out if it's present. Change the view dialog to // show expiration time, issue time, who the alert is apparently // from, and the stuff after the curly brace. Some of that info // will be useful soon in a finger command to the weather server. // // New compressed-mode weather alert packets: // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ003>007-012>016-021>025-030>034-037>047-052>057-062>069{LLSAA // // The trick is to step thru the data base contained in the // shapefiles to determine what areas to light up. In the above // example read ">" as "thru" and "-" as "and". // // More from Dale: // It occurs to me you might need some insight into what shapefile to look // through for a zone/county. The current shape files are c_22mr02, // z_16mr02, and mz21fe02. // // ICTSVS>APRS::NWS-ADVIS:120145z,SEVERE_WEATHER,KS_Z091, {C14AA // would be in z_ file // // TSASVR>APRS::NWS-WARN :120230z,SVRTSM,OK_C113, OSAGE COUNTY {C16AA // would be in c_ file // // problem comes with marine warnings- // // AM,AN,GM,PZ,PK,PM,LS,LM,LH,LO,LE,SL will look like states, but will all // come from the mz file. // // so AM_Z686 looks like a state zone, but is a marine zone. // Aprs Plus requires the exact file name to be specified - winaprs just // looks for a file in the nwsshape folder starting c_ z_ and mz. Someone // in the middle of Kansas might not need the marine at all- but here I am // closer to marine zones than land. The fact there is an index file for // the shapes should help the speed in a lookup. // // More from Dale: // The CWA areas themselves were included for just one product- generally // called the "Hazardous Weather Outlook". The idea was to be able to // click on your region and get a synopsis as a Skywarn Heads-up. In // winaprs it turned out that you would get (unwanted) the CWA outline // instead of some other data about a specific station. It makes more // sense to have three or 4 "home CWA'S" that are defined in the config // file - and have a dialog box to view the Hazardous WX Outlook and // watches and warnings just for that CWA. One step futher- I assume there // is something that trips alarms when a warning is received for a county // or zone right around you - the cwa or cwa's of interest could be derived // from that if it already exists. A long way to say don't worry about CWA // maps as far as watches/warnings. // // I think the easy coding for determining which shapefile to use would // look like; // // char sevenCharStr[8]; // seven character string in warning or derived // // from compressed string i. e. AL_Z001 // // if the 4th char == 'C' then use "c_shapefile" // if the 4th char == 'Z'; // if the first two char == 'AN' || // if the first two char == 'AM' || // if the first two char == 'GM' || // If the first two char == 'PZ' || // if the first two char == 'LH' || // if the first two char == 'LO' || // if the first two char == 'LS' || // if the first two char == 'SL' || // if the first two char == 'LM' || // then use the "mzshapefile" // else use the "z_shapefile" // // I am running out of time but that should be all there is to it- I // will send you a complete list of marine zones later today- I // think there are no more than 13 or 14 to search through - better // that the 54 "states"- could be hard coded. // We now have fire weather alerts also. From Dale: // "Ok I think we can use this to solve a problem with the Fire // Watches and Warnings taking over the map of someone not // interested. Roger, I had to take Fire warnings off the regular // aprs-is feeds and send it to firenet.us server only because of // complaints of the maps getting cluttered-- with data most people // didn't want. Even though the NWS sends "AZZ148" just as if it // were to be found in the z_mmddyy.dbf (warning zone) type file, // wxsvr knows it is coming out of a "Fire Weather" type product and // can substitute "AZF148" . Client software (read xastir & // Ui-view) would know to look in the fireweather shapefile. If // someone doesn't have the fire shapefile loaded, it would just be // ignored (I think)." // Found on the AWIPS web pages so far: // AWIPS Counties C // County Warning Areas A // Zone Forecast Areas Z // Coastal Marine Zones Z // Offshore Marine Zones Z // High Seas Marine Zones Z (Says "Not for operational use") // Fire Weather Zones FZ // // Don't forget about the Canadian Areas and Regions, which are // created by Dale Huguley from Environment Canada data. // // // AWIPS Counties: // ----------------------------- // STATE character 2 // CWA character 9 // COUNTYNAME character 24 // FIPS character 5 // TIME_ZONE character 2 // FE_AREA character 2 // LON numeric 10,5 // LAT numeric 9,5 // // // County Warning Areas: // ----------------------------- // WFO character 3 // CWA character 3 // LON numeric 10,5 // LAT numeric 9,5 // // // Zone Forecast Areas: // ----------------------------- // STATE character 2 // ZONE character 3 // CWA character 3 // NAME character 254 // STATE_ZONE character 5 // TIME_ZONE character 2 // FE_AREA character 2 // LON numeric 10,5 // LAT numeric 9,5 // // // Coastal and Offshore Marine Zones: // ---------------------------------- // ID character 6 // WFO character 3 // NAME character 250 // LON numeric 10,5 // LAT numeric 9,5 // WFO_AREA character 200 // // // High Seas Marine Zones: // ----------------------------- // WFO character 3 // LON numeric 10,5 // LAT numeric 9,5 // HEADING character 250 #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "xastir.h" #include "globals.h" #include "alert.h" #include "util.h" #include "mutex_utils.h" #include "snprintf.h" #include "wx.h" #include "hashtable.h" #include "hashtable_itr.h" #include "database.h" #include "db_funcs.h" // Must be last include file #include "leak_detection.h" // New method for weather alerts, using a hash // #define ALERT_HASH_SIZE 4096 static struct hashtable *wx_alert_hash = NULL; int alert_redraw_on_update = 0; ///////////////////////////////////////////////////////////////////// // The following group of functions implement hash storage for // weather alerts. This makes the code very fast, which is good // because we run through these alerts often. ///////////////////////////////////////////////////////////////////// // Starting with an alert_entry, create a concatenated string // containing: // // *) "From" callsign // *) Zone // *) First four chars after the '{' char (the "issue date" field // plus one more character). // // These items should make the alert unique or nearly unique whether // it was received from the WXSVR software or from hand-entered // alerts. WXSVR is where all of the machine-readable alerts come // from and is run by Dale Huguley. // // This function takes a mostly filled-in alert_entry and fills in // the unique_string variable portion with values from other // variables in the record. // void alert_fill_unique_string(alert_entry *alert) { xastir_snprintf(alert->unique_string, sizeof(alert->unique_string), "%s%s%c%c%c%c", alert->from, alert->title, alert->seq[0], alert->seq[1], alert->seq[2], alert->seq[3]); //fprintf(stderr,"'%s'\t'%s'\t'%s'\n", alert->from, alert->title, alert->seq); //fprintf(stderr,"Unique string:'%s'\n", alert->unique_string); } // Add the chars (multiplied by a function of their index number to // weight them) then truncate the final number to ALERT_HASH_SIZE. // This should spread them nicely over the entire hash table. // unsigned int wx_alert_hash_from_key(void *key) { alert_entry *temp = key; char *jj = temp->unique_string; unsigned int hash = 1; int ii = 1; while (*jj != '\0') { hash = hash + ((unsigned int)*jj++ * ii); ii += 4; } hash = hash % ALERT_HASH_SIZE; //fprintf(stderr,"%d\n", hash); return ((unsigned int)hash); } // According to Dale Huguley the FROM callsign plus the first four // chars after the curly brace (at the end) should make the record // unique. Whether or not CANCEL messages get assigned to the // proper live record is another matter. They may, or may not match // using this scheme, but it's probably better than other schemes. // Multiple types of alerts can come out in the same message for the // same zone/county. In this case the fourth character will change // from an 'A' to a 'B' or other char to denote the different // messages with the same FROM and timestamp chars. This again // keeps each alert unique. // int wx_alert_keys_equal(void *key1, void *key2) { alert_entry *t1 = key1; alert_entry *t2 = key2; // These fprintf's allow us to see how many cache hits we get // and what the results were of the match. If different // unique_string's hash to the same value, we run through this // compare once for each already-inserted record that also has // the same hash value. // fprintf(stderr,"Comparing %s to %s\t",(char *)key1,(char *)key2); if (strlen((char *)t1->unique_string) == strlen((char *)t2->unique_string) && strncmp((char *)t1->unique_string, (char *)t2->unique_string, strlen((char *)t1->unique_string))==0) { //fprintf(stderr," match %s = %s\n", t1->unique_string, t2->unique_string); return(1); } else { //fprintf(stderr," no match\n"); return(0); } } // Creates the wx_alert_hash if it doesn't exist yet. If clobber is // non-zero, destroys any existing hash then creates a new one. // void init_wx_alert_hash(int clobber) { // fprintf(stderr," Initializing wx_alert_hash \n"); // make sure we don't leak //fprintf(stderr,"init_wx_alert_hash\n"); if (wx_alert_hash) { //fprintf(stderr,"Already have one!\n"); if (clobber) { //fprintf(stderr,"Clobbering hash table\n"); hashtable_destroy(wx_alert_hash, 1); wx_alert_hash = create_hashtable(ALERT_HASH_SIZE, wx_alert_hash_from_key, wx_alert_keys_equal); } } else { //fprintf(stderr,"Creating hash table from scratch\n"); wx_alert_hash = create_hashtable(ALERT_HASH_SIZE, wx_alert_hash_from_key, wx_alert_keys_equal); } } // Fetch an alert from the wx_alert_hash based on the from call // concatenated with the first four chars after the '{' character. // This concatenated string should be unique across weather alerts // if the alert came from the WXSVR. // // If it was a hand-entered alert, it won't have the '{' string at // the end. In that case use the from call and zone concatenated // together instead for matching purposes. // alert_entry *get_wx_alert_from_hash(char *unique_string) { alert_entry *result = NULL; if (unique_string == NULL || *unique_string == '\0') { fprintf(stderr,"Empty unique_string passed to get_wx_alert_from_hash()\n"); return(NULL); } if (!wx_alert_hash) { // no table to search //fprintf(stderr,"Creating hash table\n"); init_wx_alert_hash(1); // so create one return NULL; } //fprintf(stderr," searching for %s...",unique_string); result = hashtable_search(wx_alert_hash, unique_string); return (result); } // Add a wx alert to the hash. // This function checks whether there already is something in the // hash table that matches. If a match found, it skips the record, // else it inserts a new wx alert record into the hash. // // Unfortunately it appears that any unique_string that hashes to // the same value causes us to think it's a duplicate. // void add_wx_alert_to_hash(char *unique_string, alert_entry *alert_record) { alert_entry *temp; // alert_record alert_entry *new_record; char *new_unique_str; if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash start\n"); } if (unique_string == NULL || unique_string[0] == '\0' || alert_record == NULL) { if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash finish\n"); } return; } if (!wx_alert_hash) { // no table to add to //fprintf(stderr,"init_wx_alert_hash\n"); init_wx_alert_hash(1); // so create one } // Remove any matching entry to avoid duplicates temp = hashtable_remove(wx_alert_hash, unique_string); if (temp) { // If value found, free the storage space for it as // the hashtable_remove function doesn't. It does // however remove the key (callsign) ok. free(temp); } //fprintf(stderr, "\t\t\tAdding %s...\n", unique_string); // Allocate new space for the key and the record new_unique_str = (char *)malloc(50); CHECKMALLOC(new_unique_str); new_record = (alert_entry*)malloc(sizeof(alert_entry)); CHECKMALLOC(new_record); xastir_snprintf(new_unique_str, 50, "%s", unique_string); memcpy(new_record, alert_record, sizeof(alert_entry)); // hash title alert_record if (!hashtable_insert(wx_alert_hash, new_unique_str, new_record)) { fprintf(stderr,"Insert failed on wx alert hash --- fatal\n"); free(new_unique_str); free(new_record); // exit(1); } // Yet another check to see whether hash insert/update worked // properly temp = get_wx_alert_from_hash(unique_string); if (!temp) { fprintf(stderr,"***Failed wx alert hash insert/update***\n"); } else { //fprintf(stderr,"Current: %s -> %s\n", // unique_string, // temp); } if (debug_level & 2) { fprintf(stderr,"add_wx_alert_to_hash finish\n"); } } // Create the wx alert hash table iterator so that we can iterate // through the entire hash table and draw the alerts. // struct hashtable_itr *create_wx_alert_iterator(void) { if (wx_alert_hash && hashtable_count(wx_alert_hash) > 0) { return(hashtable_iterator(wx_alert_hash)); } else { return(NULL); } } // Get the wx alert entry that the iterator is pointing to. Advance // the iterator to the following wx alert. // alert_entry *get_next_wx_alert(struct hashtable_itr *iterator) { alert_entry *temp = NULL; if (wx_alert_hash && iterator && hashtable_count(wx_alert_hash) > 0) { // Get record temp = hashtable_iterator_value(iterator); // Advance to the next record hashtable_iterator_advance(iterator); } return(temp); } // alert_print_list() // // Debug routine. Currently attached to the Test() function in // main.c, but the button in the file menu is normally grey'ed out. // This function prints the current weather alert list out to the // xterm. // void alert_print_list(void) { } // Needed by alert_expire() below static time_t last_alert_expire = 0; // alert_expire() // // Function which iterates through the wx alert hash table, removing // expired alerts as it goes. Makes sure that the expired alert // doesn't get drawn or shown in the View->WX Alerts dialog. // // Returns the quantity of alerts that were just expired. // int alert_expire(int curr_sec) { // int ii; int expire_count = 0; struct hashtable_itr *iterator; alert_entry *temp; // Check only every 60 seconds if ( (last_alert_expire + 60) > curr_sec ) { return(0); } last_alert_expire = curr_sec; if (debug_level & 2) { fprintf(stderr,"Checking for expired alerts...\n"); } iterator = create_wx_alert_iterator(); while (iterator) { // Get current record temp = hashtable_iterator_value(iterator); if (!temp) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 1\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return(expire_count); } // If wx alert has expired, remove the record from the hash. if (temp->expiration < time(NULL)) { if (debug_level & 2) { fprintf(stderr, "alert_expire: Clearing %s, current: %lu, alert: %lu\n", temp->unique_string, (unsigned long)time(NULL), (unsigned long)temp->expiration); } // Free the storage space free(temp); // Delete the entry and advance to the next hashtable_iterator_remove(iterator); expire_count++; } else { if (temp && iterator) { // Else advance to the next entry hashtable_iterator_advance(iterator); } } } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 2\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC // Cause a screen redraw if we expired some alerts if (expire_count) { // Schedule a screen update 'cuz we have a new alert alert_redraw_on_update = redraw_on_new_data = 2; } return(expire_count); } // alert_add_entry() // // This function adds a new alert to our alert list. // // Returns address of new entry or NULL. // Called from alert_build_list() function. // /*@null@*/ static alert_entry *alert_add_entry(alert_entry *entry) { // alert_entry *ptr; // int i; set_dangerous("alert.c:alert_add_entry()"); if (debug_level & 2) { fprintf(stderr,"alert_add_entry\n"); } if (strlen(entry->title) == 0) { if (debug_level & 2) { fprintf(stderr,"alert_add_entry: Empty title!\n"); } clear_dangerous(); return(NULL); } // Skip NWS_SOLAR and -NoActivationExpected alerts, they don't // interest us. if ( (strcmp(entry->to, "NWS-SOLAR") == 0) || (strcmp(entry->to, "NWS_SOLAR") == 0) ) { if (debug_level & 2) { fprintf(stderr,"NWS-SOLAR, skipping\n"); } clear_dangerous(); return(NULL); } if (strcasecmp(entry->title, "-NoActivationExpected") == 0) { if (debug_level & 2) { fprintf(stderr,"NoActivationExpected, skipping\n"); } clear_dangerous(); return(NULL); } // Check whether this new alert has already expired. If so, // don't add it. if (entry->expiration < time(NULL)) { if (debug_level & 2) { fprintf(stderr, "Newest Alert Expired->Clearing, current: %lu, alert: %lu\n", (unsigned long)time(NULL), (unsigned long)entry->expiration ); } clear_dangerous(); return(NULL); } // Check for non-zero alert title, non-expired alert time in new // alert. if (entry->title[0] != '\0' && entry->expiration >= time(NULL)) { // Schedule a screen update 'cuz we have a new alert alert_redraw_on_update = redraw_on_new_data = 2; //WE7U set_dangerous("alert.c:add_wx_alert_to_hash()"); add_wx_alert_to_hash(entry->unique_string, entry); clear_dangerous(); return(entry); } // If we got to here, the title was empty or the alert has // already expired? Figure out why we might ever get here. if (debug_level & 2) { fprintf(stderr,"Exiting alert_add_entry() without actually adding the alert:\n"); fprintf(stderr,"%s %s %lu\n", entry->to, entry->title, (unsigned long)entry->expiration); } clear_dangerous(); return(NULL); } // alert_active() // // Here's where we get rid of expired alerts in the list. Called // from alert_display_request(), alert_on_screen(), // and alert_build_list() functions. Also called from // maps.c:load_alert_maps() function. // // Returns the alert level. // // Alert Match Levels: // 0 = ? // 1 = R // 2 = Y // 3 = B // 4 = T // 5 = G // 6 = C // int alert_active(alert_entry *alert, alert_match_level UNUSED (match_level) ) { alert_entry *a_ptr; char l_list[] = {"?RYBTGC"}; int level = 0; time_t now; if (strlen(alert->title) == 0) { if (debug_level & 2) { fprintf(stderr,"alert_active:NULL\n"); } return(0); } if (debug_level & 2) { fprintf(stderr,"alert_active:%s\n",alert->title); } (void)time(&now); // if ((a_ptr = alert_match(alert, match_level))) { if ((a_ptr = get_wx_alert_from_hash(alert->unique_string))) { if (a_ptr->expiration >= now) { for (level = 0; a_ptr->alert_level != l_list[level] && level < (int)sizeof(l_list); level++) { //do nothing } } else if (a_ptr->expiration < (now - 3600)) { // More than an hour past the expiration, a_ptr->title[0] = '\0'; // so delete it from list by clearing // out the title. //WE7U // Schedule an update 'cuz we need to delete an expired // alert from the list. alert_redraw_on_update = redraw_on_new_data = 2; } else if (a_ptr->flags[on_screen] == '?') { // Expired between 1sec and 1hr and found '?' a_ptr->flags[on_screen] = '-'; // Schedule a screen update 'cuz we have an expired alert alert_redraw_on_update = redraw_on_new_data = 2; } } return (level); } // alert_display_request() // // Function which checks whether an alert should be displayed. // Called from maps.c:load_alert_maps() function. // int alert_display_request(void) { // int i; int alert_count; static int last_alert_count; if (debug_level & 2) { fprintf(stderr,"alert_display_request\n"); } //WE7U if (wx_alert_hash) { alert_count = hashtable_count(wx_alert_hash); } else { return((int)FALSE); } // If we found any, return TRUE. if (alert_count != last_alert_count) { last_alert_count = alert_count; return ((int)TRUE); } return ((int)FALSE); } // alert_list_count int alert_list_count(void) { int count = 0; if (wx_alert_hash) { return(hashtable_count(wx_alert_hash)); } else { return count; } } // alert_on_screen() // // Returns a count of active weather alerts in the list which are // within our viewport. // Called from main.c:UpdateTime() function. Used for sounding // alarm if a new weather alert appears on screen. // int alert_on_screen(void) { // int i; int alert_count = 0; struct hashtable_itr *iterator; alert_entry *temp; if (debug_level & 2) { fprintf(stderr,"alert_on_screen\n"); } //WE7U iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { if (alert_active(temp, ALERT_ALL) && temp->flags[on_screen] == 'Y') { alert_count++; } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 3\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return (alert_count); } // alert_build_list() // // This function builds alert_entry structs from message entries that // contain NWS alert messages. // // Called from alert_data_add() function. // // // Here's how Xastir breaks down an alert into an alert struct: // // SFONPW>APRS::NWS-ADVIS:191700z,WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // |----| |-------| |-----| |--| |-----| |-----| |-| // | | | | | | | // from to | | title title issue_date // | alert_tag // activity (expiration) // // // The code should also handle the case where the packet looks like // this (same except no expiration date): // // SFONPW>APRS::NWS-ADVIS:WIND,CA_Z007,CA_Z065, ALAMEDA AND CON & NAPA COUNTY {JDIAA // // We also have compressed NWS alerts, signified by NWS_ADVIS // (underline instead of dash). Note that Pete Loveall, AE5PL, is // also sending out alerts and sending the "compressed" zone format // with "NWS-" which is different than how Dale Huguley was sending // them out. Pete's change is to support Kenwood radios. // // // Expiration is then computed from the activity field. Alert_level // is computed from "to" and/or "alert_tag". There can be up to // five titles in this original format. // // Here are some real examples captured over the 'net (may be quite old): // // TAEFFS>APRS::NWS-ADVIS:181830z,FLOOD,FL_C013,FL_C037,FL_C045,FL_C077, {HHEAA // ICTFFS>APRS::NWS-ADVIS:180200z,FLOOD,KS_C035, {HEtAA // JANFFS>APRS::NWS-ADVIS:180200z,FLOOD,MS_C049,MS_C079,MS_C089,MS_C099,MS_C121, {HEvAA // DSMFFS>APRS::NWS-ADVIS:180500z,FLOOD,IA_Z086, {HHGAA // EAXFFS>APRS::NWS-ADVIS:180500z,FLOOD,MO_Z023,MO_Z024,MO_Z028,MO_Z030,MO_Z031, {HHIAA // SECIND>APRS::NWS-SOLAR:Flx134 A004 BK0001232. PlnK0000232.Ep............Ee........ {HLaAA // SHVFFS>APRS::NWS-ADVIS:181800z,FLOOD,TX_C005,TX_C073,TX_C347,TX_C365,TX_C401, {HF2AA // FWDFFS>APRS::NWS-ADVIS:180200z,FLOOD,TX_C379,TX_C467, {HF5AA // LCHFFS>APRS::NWS-ADVIS:180400z,FLOOD,LA_C003,LA_C079, {HIdAA // GIDFFS>APRS::NWS-ADVIS:180200z,FLOOD,NE_C125, {H2uAA // FWDSWO>APRS::NWS-ADVIS:181100z,SKY,CW_AFWD, -NO Activation Expected {HLqAA // BGMWSW>APRS::NWS-ADVIS:180500z,WINTER_WEATHER,NY_Z015,NY_Z016,NY_Z017,NY_Z022,NY_Z023, {HKYAA // AMAWSW>APRS::NWS-WARN :180400z,WINTER_STORM,OK_Z001,OK_Z002,TX_Z001,TX_Z002,TX_Z003, {HLGBA // // New compressed-mode weather alert packets: // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ003>007-012>016-021>025-030>034-037>047-052>057-062>069{LLSAA // // or perhaps (leading zeroes removed): // // LZKNPW>APRS::NWS-ADVIS:221000z,WINTER_STORM,ARZ3>7-12>16-21>25-30>34-37>47-52>57-62>69{LLSAA // // This one's real: // DVNFFS>APRS,qAO,WXSVR::NWS_ADVIS:022300z,FLOOD,IAC57-95-103-111-115-163-171-ILC1-67-71-131-MOC45 {2FsAA // // The trick is to step thru the data base contained in the // shapefiles to determine what areas to light up. In the above // example read ">" as "thru" and "-" as "and". // // // RIWWSW>APRS::NWS-WARN :191800z,WINTER_STORM,WY_Z014, GREEN MOUNTAINS {JBNBA // RIWWSW>APRS::SKYRIW :WINTER STORM WARNING CONTINUING TODAY {JBNBB // RIWWSW>APRS::SKYRIW :THROUGH SATURDAY {JBNBC // // // We'll create and fill in "entry", then copy various "titles" into // is such as "ID_C001", then insert that alert into the system. // // // VK2XJG - November 2011: // Here are some examples of strings from the new WXSVR-AU for the Aussie Bureau of Meteorology (BOM) alerts: // // NECMWW>APRS::BOM_WARN :141300z,WIND,TAS_MW002>003-005>007-009 {D55AG // YKPMWW>APRS::BOM_ADVIS:131330z,WIND,SA_MW005 {D5aAA // // For the BOM alerts note that the STATE portion of the zone can be two or three characters - valid state // prefixes are "NSW,VIC,QLD,TAS,NT,WA,SA". The two characters following the underscore denote the shapefile to use // These will be one of "CW,MW,PW,FW or ME". // // WXSVR-AU also does NOT strip leading zeros from the zone strings, however the existing NWS code allows for this, so // it should be supported if WXSVR-AU strips the zeros in the future. // // // #define TITLE_SIZE 64 void alert_build_list(Message *fill) { alert_entry entry, *list_ptr; char title[5][TITLE_SIZE+1]; // Storage place for zone/county titles int ii, jj; char *ptr; DataRow *p_station; int compressed_wx_packet = 0; char uncompressed_wx[10000]; struct hashtable_itr *iterator; int tmp_size; //fprintf(stderr,"Message_line:%s\n",fill->message_line); if (debug_level & 2) { fprintf(stderr,"alert_build_list:%s>%s:%s\n", fill->from_call_sign, fill->call_sign, fill->message_line); } // Empty this string first uncompressed_wx[0] = uncompressed_wx[1] = '\0'; // Check for "SKY" text in the "call_sign" field. if (strncmp(fill->call_sign,"SKY",3) == 0) { // Special handling for SKY messages only. if (debug_level & 2) { fprintf(stderr,"Sky Message: %s\n",fill->message_line); } // Find a matching alert_record, check whether or not it is // expired. If not, add this additional text into the // "desc[0123]" fields, in order. Check that the // FROM callsign and the first four chars after the curly // brace match. The next character specifies which message // block to fill in. In order they should be: // // B = "desc0" // C = "desc1" // D = "desc2" // E = "desc3". // // A matching alert record would have the same "from" field // and the first four characters of the "seq" field would // match. // // Need to make this SKY data expire from the message list // somehow? // // Remember to blank out these fields when we expire an // alert. Check that all other fields are cleared in this // case as well. // // Run through the alert list looking for a match to the // FROM and first four chars of SEQ //WE7U iterator = create_wx_alert_iterator(); for (list_ptr = get_next_wx_alert(iterator); iterator != NULL && list_ptr; list_ptr = get_next_wx_alert(iterator)) { if ( (strcasecmp(list_ptr->from, fill->from_call_sign) == 0) && ( strncmp(list_ptr->seq,fill->seq,4) == 0 ) ) { if (debug_level & 2) { fprintf(stderr,"%s:Found a matching alert to a SKY message:\t",list_ptr->seq); } switch (fill->seq[4]) { case 'B': tmp_size = sizeof(list_ptr->desc0); memcpy(list_ptr->desc0, fill->message_line, tmp_size); list_ptr->desc0[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc0: %s\n",fill->message_line); } break; case 'C': tmp_size = sizeof(list_ptr->desc1); memcpy(list_ptr->desc1, fill->message_line, tmp_size); list_ptr->desc1[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc1: %s\n",fill->message_line); } break; case 'D': tmp_size = sizeof(list_ptr->desc2); memcpy(list_ptr->desc2, fill->message_line, tmp_size); list_ptr->desc2[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc2: %s\n",fill->message_line); } break; case 'E': default: tmp_size = sizeof(list_ptr->desc3); memcpy(list_ptr->desc3, fill->message_line, tmp_size); list_ptr->desc3[tmp_size-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"Wrote into desc3: %s\n",fill->message_line); } break; } } } if (debug_level & 2) { fprintf(stderr,"alert_build_list return 1\n"); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator a4\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } if (debug_level & 2) { fprintf(stderr,"1\n"); } if (fill->active == RECORD_ACTIVE) { int ignore_title = 0; #define MAX_SUB_ALERTS 5000 char *title_ptr[MAX_SUB_ALERTS]; int ret; if (debug_level & 2) { fprintf(stderr,"2\n"); } memset(&entry, 0, sizeof(entry)); // flags[0] specifies whether it's onscreen or not memset(entry.flags, (int)'?', sizeof(entry.flags)); // flags[source] specifies source of the alert DATA_VIA_TNC or // DATA_VIA_LOCAL entry.flags[source] = fill->heard_via_tnc; p_station = NULL; if (search_station_name(&p_station,fill->from_call_sign,1)) { entry.flags[source] = p_station->data_via; } // Zero the title strings. We can have up to five alerts in // a non-compressed weather alert. title[0][0] = '\0'; title[1][0] = '\0'; title[2][0] = '\0'; title[3][0] = '\0'; title[4][0] = '\0'; // This fills in the zone numbers (title) for uncompressed // alerts with up to five alerts per message. This doesn't // handle filling in the title for compressed alerts though. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%32[^,],%32[^,],%32[^,],%32[^,],%32[^,]", entry.activity, // 191700z entry.alert_tag, // WIND &title[0][0], // CA_Z007 &title[1][0], // ... &title[2][0], // ... &title[3][0], // ... &title[4][0]); // ... if (ret < 3) { fprintf(stderr,"sscanf parsed %d values in alert.c (3-7 ok) %s->%s: %s\n", ret, fill->from_call_sign, fill->call_sign, fill->message_line); } // Force a termination for each entry.activity[20] = '\0'; entry.alert_tag[20] = '\0'; title[0][TITLE_SIZE] = '\0'; title[1][TITLE_SIZE] = '\0'; title[2][TITLE_SIZE] = '\0'; title[3][TITLE_SIZE] = '\0'; title[4][TITLE_SIZE] = '\0'; // Check for "NWS_" in the call_sign field. Underline // signifies compressed alert format. Dash signifies // non-compressed format. // K2DLS 08/25/17 // Also check for NWS- where title[0] does not contain // an underscore. This is to identify AE5PL's compressed // alerts in uncompressed clothing. if ((strncmp(fill->call_sign,"NWS_",4) == 0) || ((strncmp(fill->call_sign,"NWS-",4) == 0) && (strstr(title[0], "_") == NULL))) { char compressed_wx[512]; char *ptr; ///////////////////////////////////////////////////////////////////// // Compressed weather alert special code ///////////////////////////////////////////////////////////////////// compressed_wx_packet++; // Set the flag //fprintf(stderr, "Found compressed alert packet via NWS_!\n"); //fprintf(stderr,"Compressed Weather Alert:%s\n",fill->message_line); //fprintf(stderr,"Compressed alerts are not fully implemented yet.\n"); // Create a new weather alert for each of these and then // call this function on each one? Seems like it might // work fine if we watch out for global variables. // Another method would be to create an incoming message // for each one and add it to the message queue, or just // a really long new message and add it to the queue, // in which case we'd exit from this routine as soon as // it was submitted. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%255[^, ]", entry.activity, entry.alert_tag, compressed_wx); // Stick the long string in here if (ret != 3) { fprintf(stderr,"sscanf parsed %d/3 values in alert.c\n", ret); compressed_wx[0] = '\0'; // Remove stale compressed alerts. compressed_wx_packet = 0; //Clear flag in error condition. } compressed_wx[255] = '\0'; //fprintf(stderr,"Line:%s\n",compressed_wx); // Snag alpha characters (should be three) at the start // of the string. Use those until we hit more alpha // characters. First two characters of each 3-letter // alpha group are the state, last character is the // zone/county/marine-zone indicator. // Need to be very careful here to validate the letters/numbers, and // to not run off the end of the string. Need more code here to do // this validation. // Scan through entire string ptr = compressed_wx; while (ptr < (compressed_wx + strlen(compressed_wx))) { char prefix[5]; char suffix[4]; char temp_suffix[4]; char ending[4]; int iterations = 0; // Snag the ALPHA portion xastir_snprintf(prefix, sizeof(prefix), "%s", ptr); ptr += 2; prefix[2] = '_'; prefix[3] = ptr[0]; prefix[4] = '\0'; // Terminate the string ptr += 1; // prefix should now contain something like "MN_Z" // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); temp_suffix[3] = '\0'; // Terminate the string if (temp_suffix[1] == '-' || temp_suffix[1] == '>') { temp_suffix[1] = '\0'; ptr += 1; } else if (temp_suffix[1] != '\0' && (temp_suffix[2] == '-' || temp_suffix[2] == '>')) { temp_suffix[2] = '\0'; ptr += 2; } else { ptr += 3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } // Make sure suffix is terminated properly suffix[3] = '\0'; // We have our first zone (of this loop) extracted! if (debug_level & 2) { fprintf(stderr,"1Zone:%s%s\n",prefix,suffix); } // Add it to our zone string. In this case we know // that the lengths of the strings we're working // with are quite short. Little danger of // overrunning our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; if (debug_level & 2) { fprintf(stderr,"uncompressed_wx:%s\n",uncompressed_wx); } // Here we keep looping until we hit another alpha // portion. We need to look at the field separator // to determine whether we have another separate // field coming up or a range to enumerate. while ( (ptr < (compressed_wx + strlen(compressed_wx))) && ( is_num_chr(ptr[1]) ) ) { iterations++; // Break out of this loop if we don't find an // alpha character fairly quickly. That way the // Xastir main thread can't hang in this loop // forever if the input string is malformed. if (iterations > 30) { break; } // Look for '>' or '-' character. If former, we // have a numeric sequence to ennumerate. If the // latter, we either have another zone number or // another prefix coming up. if (ptr[0] == '>' || ptr[0] == '<') { // Numeric zone sequence int start_number; int end_number; int kk; ptr++; // Skip past the '>' or '<' characters // Snag the NUMERIC portion. May be between // 1 and three digits long. xastir_snprintf(ending, sizeof(ending), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(ending[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(ending[1])) { ending[1] = '\0'; ptr++; } else if (!is_num_chr(ending[2])) { ending[2] = '\0'; ptr+=2; } else { ending[3] = '\0'; ptr+=3; } // ending should now contain something like // "046" or "35" or "2" if (debug_level & 2) { fprintf(stderr,"Ending:%s\n",ending); } start_number = (int)atoi(suffix); end_number = (int)atoi(ending); for ( kk=start_number+1; kk<=end_number; kk++) { xastir_snprintf(suffix,4,"%03d",kk); if (debug_level & 2) { fprintf(stderr,"2Zone:%s%s\n",prefix,suffix); } // And another zone... Ennumerate // through the sequence, adding each // new zone to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } } // Wasn't a '>' character, so check for a '-' else if (ptr[0] == '-') { // New zone number, not a numeric sequence. ptr++; // Skip past the '-' character if ( is_num_chr(ptr[0]) ) { // Found another number. Use the prefix // stored from last time. // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(temp_suffix[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(temp_suffix[1])) { temp_suffix[1] = '\0'; ptr++; } else if (!is_num_chr(temp_suffix[2])) { temp_suffix[2] = '\0'; ptr+=2; } else { temp_suffix[3] = '\0'; ptr+=3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } if (debug_level & 2) { fprintf(stderr,"3Zone:%s%s\n",prefix,suffix); } // And another zone... // Add it to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } else { // New prefix (not a number) // Start at the top of the outer loop again } } } // Skip past '-' character, if any, so that we can // get to the next prefix // RZG:Added the ptr check, so we don't read a byte off the end if ( (ptr < (compressed_wx + strlen(compressed_wx))) && (ptr[0] == '-') ) { ptr++; } } if (debug_level & 2) { fprintf(stderr,"Uncompressed: %s\n", uncompressed_wx); } } ///////////////////////////////////////////////////////////////////// // End of compressed weather alert special code ///////////////////////////////////////////////////////////////////// // Australian Buerau of Meeorology alerts (BOM) // Geoff VK2XJG // Check for "BOM_" in the call_sign field. // WXSVR-AU delivers messages in this format, keeping the protocol as close to // the NWS WXSVR as possible. // Underline signifies compressed alert format. Dash signifies // non-compressed format, although this has not been implemented on the server. if ( (strncmp(fill->call_sign,"BOM_",4) == 0) || (strncmp(fill->call_sign,"BOM-",4) == 0) ) { char compressed_wx[512]; char *ptr; ///////////////////////////////////////////////////////////////////// // Compressed weather alert (BOM) special code ///////////////////////////////////////////////////////////////////// compressed_wx_packet++; // Set the flag //fprintf(stderr, "Found compressed alert packet via BOM_!\n"); //fprintf(stderr,"Compressed Weather Alert:%s\n",fill->message_line); //fprintf(stderr,"Compressed alerts are not fully implemented yet.\n"); // Create a new weather alert for each of these and then // call this function on each one? Seems like it might // work fine if we watch out for global variables. // Another method would be to create an incoming message // for each one and add it to the message queue, or just // a really long new message and add it to the queue, // in which case we'd exit from this routine as soon as // it was submitted. ret = sscanf(fill->message_line, "%20[^,],%20[^,],%255[^, ]", entry.activity, entry.alert_tag, compressed_wx); // Stick the long string in here if (ret != 3) { fprintf(stderr,"sscanf parsed %d/3 values in alert.c\n", ret); compressed_wx[0] = '\0'; // Remove stale compressed alerts. compressed_wx_packet = 0; //Clear flag in error condition. } compressed_wx[255] = '\0'; //fprintf(stderr,"Line:%s\n",compressed_wx); // Snag alpha characters (should be five) at the start // of the string. Use those until we hit more alpha // characters. First two/three characters of each 5-letter // alpha group are the state, last two characters are the // zone/county/marine-zone indicator. // Need to be very careful here to validate the letters/numbers, and // to not run off the end of the string. Need more code here to do // this validation. // Scan through entire string ptr = compressed_wx; while (ptr < (compressed_wx + strlen(compressed_wx))) { char prefix[7]; char suffix[4]; char temp_suffix[4]; char ending[4]; int iterations = 0; // Snag the ALPHA portion xastir_snprintf(prefix, sizeof(prefix), "%s", ptr); ptr += 3; // Handle a 2 letter state abbreviation (SA/WA/NT) if (prefix[2] == '_' ) { prefix[3] = ptr[0]; prefix[5] = '\0'; // Terminate the string ptr += 3; } // All other cases are 3 letter states (NSW/VIC/TAS/QLD) else { prefix[3] = ptr[0]; prefix[6] = '\0'; // Terminate the string ptr += 3; } // prefix should now contain something like "TAS_CW" or "SA_PW" // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); temp_suffix[3] = '\0'; // Terminate the string if (temp_suffix[1] == '-' || temp_suffix[1] == '>') { temp_suffix[1] = '\0'; ptr += 1; } else if (temp_suffix[1] != '\0' && (temp_suffix[2] == '-' || temp_suffix[2] == '>')) { temp_suffix[2] = '\0'; ptr += 2; } else { ptr += 3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } // Make sure suffix is terminated properly suffix[3] = '\0'; // We have our first zone (of this loop) extracted! if (debug_level & 2) { fprintf(stderr,"1Zone:%s%s\n",prefix,suffix); } // Add it to our zone string. In this case we know // that the lengths of the strings we're working // with are quite short. Little danger of // overrunning our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; if (debug_level & 2) { fprintf(stderr,"uncompressed_wx:%s\n",uncompressed_wx); } // Here we keep looping until we hit another alpha // portion. We need to look at the field separator // to determine whether we have another separate // field coming up or a range to enumerate. while ( (ptr < (compressed_wx + strlen(compressed_wx))) && ( is_num_chr(ptr[1]) ) ) { iterations++; // Break out of this loop if we don't find an // alpha character fairly quickly. That way the // Xastir main thread can't hang in this loop // forever if the input string is malformed. if (iterations > 30) { break; } // Look for '>' or '-' character. If former, we // have a numeric sequence to ennumerate. If the // latter, we either have another zone number or // another prefix coming up. if (ptr[0] == '>' || ptr[0] == '<') { // Numeric zone sequence int start_number; int end_number; int kk; ptr++; // Skip past the '>' or '<' characters // Snag the NUMERIC portion. May be between // 1 and three digits long. xastir_snprintf(ending, sizeof(ending), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(ending[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(ending[1])) { ending[1] = '\0'; ptr++; } else if (!is_num_chr(ending[2])) { ending[2] = '\0'; ptr+=2; } else { ending[3] = '\0'; ptr+=3; } // ending should now contain something like // "046" or "35" or "2" if (debug_level & 2) { fprintf(stderr,"Ending:%s\n",ending); } start_number = (int)atoi(suffix); end_number = (int)atoi(ending); for ( kk=start_number+1; kk<=end_number; kk++) { xastir_snprintf(suffix,4,"%03d",kk); if (debug_level & 2) { fprintf(stderr,"2Zone:%s%s\n",prefix,suffix); } // And another zone... Ennumerate // through the sequence, adding each // new zone to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } } // Wasn't a '>' character, so check for a '-' else if (ptr[0] == '-') { // New zone number, not a numeric sequence. ptr++; // Skip past the '-' character if ( is_num_chr(ptr[0]) ) { // Found another number. Use the prefix // stored from last time. // Snag the NUMERIC portion. Note that the field // width can vary between 1 and 3. The leading // zeroes have been removed. xastir_snprintf(temp_suffix, sizeof(temp_suffix), "%s", ptr); // Terminate the string and advance the // pointer past it. if (!is_num_chr(temp_suffix[0])) { // We have a problem, 'cuz we didn't // find at least one number. Packet is // badly formatted. return; } else if (!is_num_chr(temp_suffix[1])) { temp_suffix[1] = '\0'; ptr++; } else if (!is_num_chr(temp_suffix[2])) { temp_suffix[2] = '\0'; ptr+=2; } else { temp_suffix[3] = '\0'; ptr+=3; } // temp_suffix should now contain something like // "039" or "45" or "2". Add leading zeroes to give // "suffix" a length of 3. xastir_snprintf(suffix, sizeof(suffix), "000"); switch (strlen(temp_suffix)) { case 1: // Copy one char across suffix[2] = temp_suffix[0]; break; case 2: // Copy two chars across suffix[1] = temp_suffix[0]; suffix[2] = temp_suffix[1]; break; case 3: // Copy all three chars across xastir_snprintf(suffix, sizeof(suffix), "%s", temp_suffix); break; } if (debug_level & 2) { fprintf(stderr,"3Zone:%s%s\n",prefix,suffix); } // And another zone... // Add it to our zone string. In this // case we know that the lengths of the // strings we're working with are quite // short. Little danger of overrunning // our destination string. strncat(uncompressed_wx, ",", sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, prefix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); strncat(uncompressed_wx, suffix, sizeof(uncompressed_wx) - 1 - strlen(uncompressed_wx)); // Terminate it every time uncompressed_wx[9999] = '\0'; } else { // New prefix (not a number) // Start at the top of the outer loop again } } } // Skip past '-' character, if any, so that we can // get to the next prefix // RZG:Added the ptr check, so we don't read a byte off the end if ( (ptr < (compressed_wx + strlen(compressed_wx))) && (ptr[0] == '-') ) { ptr++; } } if (debug_level & 2) { fprintf(stderr,"Uncompressed: %s\n", uncompressed_wx); } } ///////////////////////////////////////////////////////////////////// // End of compressed weather (BOM) alert special code ///////////////////////////////////////////////////////////////////// if (debug_level & 2) { fprintf(stderr,"3\n"); } // Terminate the strings entry.activity[20] = entry.alert_tag[20] = '\0'; // If the expire time is missing, shift fields to the right // by one field. Evidently we can have an alert come across // that doesn't have an expire time. The code shuffles the // titles to the next record before fixing up the title and // alert_tag for entry. if (!isdigit((int)entry.activity[0]) && entry.activity[0] != '-') { if (title[0][0] == '\0') { // No alerts in this message } // If it's a trashed packet, we may have entries here // that are too long. Assure that we don't overwrite // the strings. for (jj = 4; jj > 0; jj--) { xastir_snprintf(&title[jj][0], TITLE_SIZE, "%s", &title[jj-1][0]); } xastir_snprintf(&title[0][0], TITLE_SIZE, "%s", entry.alert_tag); xastir_snprintf(entry.alert_tag, sizeof(entry.alert_tag), "%s", entry.activity); entry.alert_tag[20] = '\0'; // Shouldn't we clear out entry.activity in this // case??? We've determined it's not a date/time value. xastir_snprintf(entry.activity,sizeof(entry.activity),"------z"); entry.expiration = sec_now() + (24 * 60 * 60); // Add a day } else { // Compute expiration time_t from zulu time entry.expiration = time_from_aprsstring(entry.activity); } if (debug_level & 2) { fprintf(stderr,"4\n"); } // Copy the sequence (which contains issue_date_time and // message sequence) into the record. memcpy(entry.seq, fill->seq, sizeof(entry.seq)); entry.seq[sizeof(entry.seq)-1] = '\0'; // Terminate string if (debug_level & 2) { fprintf(stderr,"5\n"); } // Now compute issue_date_time from the first three characters of // the sequence number: // 0-9 = 0-9 // 10-35 = A-Z // 36-61 = a-z // The 3 characters are Day/Hour/Minute of the issue date time in // zulu time. if (strlen(fill->seq) == 5) { // Looks ok so far // Could add another check to make sure that the first two // chars are a digit or a capital letter. char c; char date_time[10]; char temp[3]; date_time[0] = '\0'; for ( ii = 0; ii < 3; ii++ ) { c = fill->seq[ii]; // Snag one character if (is_num_chr(c)) { // Found numeric char temp[0] = '0'; temp[1] = c; temp[2] = '\0'; // Terminate the string } else if (c >= 'A' && c <= 'Z') { // Found upper-case letter // Need to take ord(c) - 55 to get the number char temp_string[5]; xastir_snprintf(temp_string, sizeof(temp_string), "%02d", (int)c - 55); memcpy(temp, temp_string, 2); temp[2] = '\0'; // Terminate the string } else if (c >= 'a' && c <= 'z') { // Found lower-case letter // Need to take ord(c) - 61 to get the number char temp_string[5]; xastir_snprintf(temp_string, sizeof(temp_string), "%02d", (int)c - 61); memcpy(temp, temp_string, 2); temp[2] = '\0'; // Terminate the string } strncat(date_time,temp,sizeof(date_time)-strlen(date_time)-1); // Concatenate the strings } strncat(date_time,"z",sizeof(date_time)-strlen(date_time)-1); // Add a 'z' on the end. if (debug_level & 2) { fprintf(stderr,"Seq: %s,\tIssue_time: %s\n",fill->seq,date_time); } xastir_snprintf(entry.issue_date_time, sizeof(entry.issue_date_time), "%s", date_time); //entry.issue_date_time = time_from_aprsstring(date_time); } else { xastir_snprintf(entry.issue_date_time, sizeof(entry.issue_date_time), "%s", "312359z"); } if (debug_level & 2) { fprintf(stderr,"6\n"); } /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////// // Iterate through up to five uncompressed alerts, or // through the string of now-uncompressed "compressed" // alerts, creating an alert out of each. // if (compressed_wx_packet) { // Handle compressed packet. // Skip the first character of our uncompressed_wx // string, as it's a leading comma. Snag out each // string in turn and use that as the title for a // weather alert. // Feed &uncompressed_wx[1] to split_string to fill in // an array with the various zone names. split_string(&uncompressed_wx[1], title_ptr, MAX_SUB_ALERTS, ','); } else { // Handle non-compressed packet // We have up to five alerts to process. // Set up an array of char pointers so that we can use // the same code for either compressed or uncompressed // weather alerts. title_ptr[0] = &title[0][0]; title_ptr[1] = &title[1][0]; title_ptr[2] = &title[2][0]; title_ptr[3] = &title[3][0]; title_ptr[4] = &title[4][0]; title_ptr[5] = NULL; // Make sure we terminate } // We now have all of our titles pointed to by the title_ptr[] // array. Either type of alert can be processed identically now. // Try to create alerts out of each one. for (ii = 0; ii < MAX_SUB_ALERTS && title_ptr[ii]; ii++) { // Copy into our entry.title variable xastir_snprintf(entry.title, sizeof(entry.title), "%s", title_ptr[ii]); // Terminate title string entry.title[sizeof(entry.title)-1] = '\0'; //fprintf(stderr,"Title: %s\n",entry.title); // This one removes spaces from the title. //while ((ptr = strpbrk(entry.title, " "))) // memmove(ptr, ptr+1, strlen(ptr)+1); // Instead we should blank out the title and any // following alert titles if a space is encountered, as // we're to disregard anything after a space in the // information field. if (ignore_title) // Blank out title if flag is set { entry.title[0] = '\0'; } // If we found a space in a title, this signifies that // we hit the end of the current list of zones. if ( (ptr = strpbrk(entry.title, " ")) ) { ignore_title++; // Set flag for following titles entry.title[0] = '\0'; // Blank out title } if ((ptr = strpbrk(entry.title, "}>=!:/*+;"))) { if (debug_level & 2) { fprintf(stderr, "Warning: Weird Weather Message: %ld:%s>%s:%s!\n", (long)fill->sec_heard, fill->from_call_sign, fill->call_sign, fill->message_line); } *ptr = '\0'; } // Skip loop iterations if we don't have a title for an // entry if (entry.title[0] == '\0') { continue; } xastir_snprintf(entry.from, sizeof(entry.from), "%s", fill->from_call_sign); xastir_snprintf(entry.to, sizeof(entry.to), "%s", fill->call_sign); memcpy(entry.seq, fill->seq, sizeof(entry.seq)); entry.seq[sizeof(entry.seq)-1] = '\0'; // Terminate string // NWS_ADVIS or NWS_CANCL normally appear in the "to" // field. ADVIS can appear in the alert_tag field on a // CANCL message though, and we want CANCL to have // priority. if (strstr(entry.alert_tag, "CANCL") || strstr(entry.to, "CANCL")) { entry.alert_level = 'C'; } else if (!strncmp(entry.alert_tag, "TEST", 4) || strstr(entry.to, "TEST")) { entry.alert_level = 'T'; } else if (strstr(entry.alert_tag, "WARN") || strstr(entry.to, "WARN")) { entry.alert_level = 'R'; } else if (strstr(entry.alert_tag, "CIVIL") || strstr(entry.to, "CIVIL")) { entry.alert_level = 'R'; } else if (strstr(entry.alert_tag, "WATCH") || strstr(entry.to, "WATCH")) { entry.alert_level = 'Y'; } else if (strstr(entry.alert_tag, "ADVIS") || strstr(entry.to, "ADVIS")) { entry.alert_level = 'B'; } else { entry.alert_level = 'G'; } // Kludge for fire zones if (!strncmp(entry.alert_tag,"RED_FLAG",8)) { // Replace "Z" in the zone field with "F" if (entry.title[3] == 'Z') { entry.title[3] = 'F'; } } // Look for a similar alert // We need some improvements here. We compare these fields: // // from SFONPW SFONPW // to NWS-ADVIS NWS-CANCL // alert_tag WIND WIND_ADVIS_CANCEL // title CA_Z007 CA_Z007 // // Of these, "from" and "title" should remain the same between an // alert and a cancelled alert. "to" and "alert_tag" change. Since // we're comparing all four fields, the cancels don't match any // existing alerts. //WE7U // Fill in the unique_string variable. We need this for // our hash code. alert_fill_unique_string(&entry); if ((list_ptr = get_wx_alert_from_hash(entry.unique_string))) { //fprintf(stderr,"alert_build_list: found match: %s\n",entry.unique_string); // We found a match! We probably need to copy some more data across // between the records: seq, alert_tag, alert_level, from, to, // issue_date_time, expiration? // If it's a CANCL or CANCEL, we need to make sure the cancel // packet's information is kept and the other's info is tossed, so // that the alert doesn't get drawn anymore. // If we're not trying to replace a cancelled alert with // a new non-cancelled alert, go ahead and copy the // fields across. if ( (list_ptr->alert_level != 'C') // Stored alert is _not_ a CANCEL || (entry.alert_level == 'C') ) { // Or new one _is_ a CANCEL list_ptr->expiration = entry.expiration; xastir_snprintf(list_ptr->activity, sizeof(list_ptr->activity), "%s", entry.activity); xastir_snprintf(list_ptr->alert_tag, sizeof(list_ptr->alert_tag), "%s", entry.alert_tag); list_ptr->alert_level = entry.alert_level; xastir_snprintf(list_ptr->seq, sizeof(list_ptr->seq), "%s", entry.seq); xastir_snprintf(list_ptr->from, sizeof(list_ptr->from), "%s", entry.from); xastir_snprintf(list_ptr->to, sizeof(list_ptr->to), "%s", entry.to); xastir_snprintf(list_ptr->issue_date_time, sizeof(list_ptr->issue_date_time), "%s", entry.issue_date_time); } else { // Don't copy the info across, as we'd be making a // cancelled alert active again if we did. } } else { // No similar alert, add a new one to the list entry.index = -1; // Haven't found it in a file yet (void)alert_add_entry(&entry); } if (alert_active(&entry, ALERT_ALL)) { // Empty "if" body here????? LCLINT caught this. } } // End of for loop // Signify that we're done processing the NWS message fill->active = RECORD_CLOSED; } if (debug_level & 2) { fprintf(stderr,"alert_build_list return 2\n"); } } Xastir-Release-2.2.4/src/alert.h0000664000175000017500000000500715151324131015372 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_ALERT_H #define __XASTIR_ALERT_H #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "database.h" //#include "maps.h" // How many alerts we add storage for each time we're short. #define ALERT_COUNT_INCREMENT 200 typedef enum { ALERT_TITLE, ALERT_TAG, ALERT_TO, ALERT_FROM } alert_match_level; #define ALERT_ALL ALERT_FROM enum flag_list { on_screen, source, max_flag=16 }; typedef struct { char unique_string[50]; double top_boundary, left_boundary, bottom_boundary, right_boundary; time_t expiration; // In local time (secs since epoch) char activity[21]; char alert_tag[21]; char title[33]; char alert_level; char from[10]; char to[10]; /* referenced flags 0 - on screen 1 - source */ char flags[max_flag]; char filename[64]; int index; // Index into shapefile char seq[10]; char issue_date_time[10]; char desc0[68]; // Space for additional text. char desc1[68]; // Spec allows 67 chars per char desc2[68]; // message. char desc3[68]; // } alert_entry; extern void alert_print_list(void); extern int alert_active(alert_entry *alert, alert_match_level match_level); extern int alert_display_request(void); extern int alert_on_screen(void); extern int alert_redraw_on_update; extern int alert_expire(int curr_sec); extern void alert_build_list(Message *fill); extern struct hashtable_itr *create_wx_alert_iterator(void); extern alert_entry *get_next_wx_alert(struct hashtable_itr *iterator); extern int alert_list_count(void); #endif /* __XASTIR_ALERT_H */ Xastir-Release-2.2.4/src/ambiguity_utils.c0000664000175000017500000000535015151324131017471 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include int position_amb_chars; /*************************************************************************/ /* output_lat - format position with position_amb_chars for transmission */ /*************************************************************************/ char *output_lat(char *in_lat, int comp_pos) { int i,j; //fprintf(stderr,"in_lat:%s\n", in_lat); if (!comp_pos) { // Don't do this as it results in truncation! //in_lat[7]=in_lat[8]; // Shift N/S down for transmission } else if (position_amb_chars>0) { in_lat[7]='0'; } j=0; if (position_amb_chars>0 && position_amb_chars<5) { for (i=6; i>(6-position_amb_chars-j); i--) { if (i==4) { i--; j=1; } if (!comp_pos) { in_lat[i]=' '; } else { in_lat[i]='0'; } } } if (!comp_pos) { in_lat[8] = '\0'; } return(in_lat); } /**************************************************************************/ /* output_long - format position with position_amb_chars for transmission */ /**************************************************************************/ char *output_long(char *in_long, int comp_pos) { int i,j; //fprintf(stderr,"in_long:%s\n", in_long); if (!comp_pos) { // Don't do this as it results in truncation! //in_long[8]=in_long[9]; // Shift e/w down for transmission } else if (position_amb_chars>0) { in_long[8]='0'; } j=0; if (position_amb_chars>0 && position_amb_chars<5) { for (i=7; i>(7-position_amb_chars-j); i--) { if (i==5) { i--; j=1; } if (!comp_pos) { in_long[i]=' '; } else { in_long[i]='0'; } } } if (!comp_pos) { in_long[9] = '\0'; } return(in_long); } Xastir-Release-2.2.4/src/ambiguity_utils.h0000664000175000017500000000221115151324131017467 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_AMBIGUITY_UTILS_H #define __XASTIR_AMBIGUITY_UTILS_H extern int position_amb_chars; extern char *output_lat(char *in_lat, int comp_pos); extern char *output_long(char *in_long, int comp_pos); #endif Xastir-Release-2.2.4/src/awk.c0000664000175000017500000007057015151324131015047 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ // // These functions allocate new memory: // ------------------------------------ // awk_new_symtab // awk_declare_sym // awk_compile_action // awk_new_rule // awk_new_program // awk_load_program_file // awk_load_program_array // // These functions free memory: // ---------------------------- // awk_free_symtab // awk_free_action // awk_free_rule // awk_free_program // awk_uncompile_program (indirectly) // /* * This is a library of Awk-like functions to facilitate, for example, * canonicalizing DBF attributes for shapefiles into internal Xastir * values when rendering shapefile maps, or rewriting labels * (e.g. callsigns into tactical calls), etc. * * Uses Philip Hazel's Perl-compatible regular expression library (pcre). * See www.pcre.org. * * Alan Crosswell, n2ygk@weca.org * * TODO * permit embedded ;#} inside string assignment (balance delims) * implement \t, \n, \0[x]nn etc. * instantiate new symbols instead of ignoring them? */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #include #include "awk.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" #define min(a,b) ((a)<(b)?(a):(b)) /* * Symbol table * * Symbols $0-$9 are set by the results of the pcre pattern match. * Other symbols are declared by the caller and bound to variables * in the caller's program. Make sure they are still in scope when * the pattern matcher is invoked! * * This assumes a very small symbol table, so it is searched linearly. * No fancy hash table lookups are needed. * XXX YES THEY ARE! */ #define MAXSUBS 10 /* $0 thru $9 should be plenty */ /* * awk_new_symtab: alloc a symbol table with $0-$9 pre-declared. */ awk_symtab *awk_new_symtab(void) { awk_symtab *n = calloc(1,sizeof(awk_symtab)); static char sym[MAXSUBS][2]; int i; if (!n) { fprintf(stderr, "Couldn't allocate memory in awk_new_symtab()\n"); return(NULL); } for (i = 0; i < MAXSUBS; i++) { sym[i][0] = i+'0'; sym[i][1] = '\0'; awk_declare_sym(n,sym[i],STRING,NULL,0); /* just reserve the name */ } return n; } void awk_free_symtab(awk_symtab *s) { int i; for (i = 0; i < AWK_SYMTAB_HASH_SIZE; i++) { awk_symbol *p,*x; for (x = s->hash[i]; x ; x = p) { p = x->next_sym; free(x); } } } /* * awk_declare_sym: declare a symbol and bind to storage for its value. */ int awk_declare_sym(awk_symtab *this, const char *name, enum awk_symtype type, const void *val, const int size) { awk_symbol *s = calloc(1,sizeof(awk_symbol)); awk_symbol *p; u_int i; if (!s) { fprintf(stderr, "Couldn't allocate memory in awk_declare_sym()\n"); return -1; } s->name = name; s->namelen = strlen(name); s->type = type; s->val = (void *)val; s->size = size; s->len = 0; i = AWK_SYM_HASH(s->name,s->namelen); if ((p = this->hash[i]) != NULL) { s->next_sym = p; /* insert at top of bucket */ } this->hash[i] = s; /* make (new) top of bucket */ return 0; } /* * awk_find_sym: search symtab for symbol */ awk_symbol *awk_find_sym(awk_symtab *this, const char *name, const int len) { awk_symbol *s; char c; // Create holding spot for first character in order to speed up // the loop below. Note that "toupper()" is very slow on some // systems so we took it out of this function to speed things // up. We evidently don't need case insensitive behavior here // anyway. // c = name[0]; // Check through the hash // for (s = this->hash[AWK_SYM_HASH(name,len)]; s; s = s->next_sym) { // Check length first (fast operation) if (s->namelen == len) { // Check first char next (fast operation) if (s->name[0] == c) { // Ok so far, test the entire string (slow // operation, case sensitive) if (len == 1) { return s; } if (len > 1 && strncmp(s->name+1,name+1,len-1) == 0) { return s; } } } } return NULL; } /* * awk_set_sym: set a symbol's value (writes into bound storage). * Returns -1 if it was unable to (symbol not found). */ /* int awk_set_sym(awk_symbol *s, const char *val, const int len) { int l = len + 1; int minlen = min(s->size-1,l); if (!s) { return -1; } switch(s->type) { case STRING: if (minlen > 0) { // Change this to an xastir_snprintf() function if we // need to use this awk_set_sym() function later. // strncpy won't null-terminate the string if there's no // '\0' in the first minlen bytes. strncpy(s->val,val,minlen); s->len = l - 1; } break; case INT: *((int *)s->val) = atoi(val); s->len = sizeof(int); break; case FLOAT: *((double *)s->val) = atof(val); s->len = sizeof(double); break; default: return -1; break; } return 0; } */ /* * awk_get_sym: copy (and cast) symbol's value into supplied string buffer */ int awk_get_sym(awk_symbol *s, /* symbol */ char *store, /* store result here */ int size, /* sizeof(*store) */ int *len) { /* store length here */ int minlen; char cbuf[128]; /* conversion buffer for int/float */ int cbl; if (!s) { return -1; } *store = '\0'; *len = 0; switch(s->type) { case STRING: if (s->len > 0) { minlen = min(s->len,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", (char *)(s->val)); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; case INT: if (s->len > 0) { sprintf(cbuf,"%d",*((int *)s->val)); cbl = strlen(cbuf); minlen = min(cbl,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", cbuf); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; case FLOAT: if (s->len > 0) { sprintf(cbuf,"%f",*((double *)s->val)); cbl = strlen(cbuf); minlen = min(cbl,size-1); if (minlen > 0) { xastir_snprintf(store, size, "%s", cbuf); *len = minlen; } else { *len = 0; } } else { *len = 0; } break; } return 0; } /* * Action compilation and interpretation. * * Action grammar is: * := "=" value * := "next" | "skip" (next skips to next field; skip skips to next * record.) * := | * := ";" | * := * * It's a trivial grammar so no need for yacc/bison. */ /* * awk_compile_stmt: "Compiles" a single action statement. */ int awk_compile_stmt(awk_symtab *this, awk_action *p, const char *stmt, int len) { const char *s = stmt, *op, *ep; while (isspace((int)*s)) { /* clean up leading white space */ ++s; --len; } ep = &s[len]; if ((op = strchr(s,'=')) != NULL) { /* it's either an assignment */ const char *val = op+1; while (isspace((int)*val)) { val++; len--; } --op; while (isspace((int)*op) && op>s) { op--; } p->opcode = ASSIGN; p->dest = awk_find_sym(this,s,(op-s+1)); if (!p->dest) { return -1; } p->expr = val; p->exprlen = (ep-val); } else { /* or the "next" keyword */ const char *r; for (r=&s[len-1]; isspace((int)*r); r--,len--) { /* trim trailing white space */ } if (len == 4 && strncmp(s,"next",4) == 0) { p->opcode = NEXT; } else if (len == 4 && strncmp(s,"skip",4) == 0) { p->opcode = SKIP; } else { /* failed to parse */ return -1; } } return 0; } /* * awk_compile_action: Break the action up into stmts and compile them * and link them together. */ awk_action *awk_compile_action(awk_symtab *this, const char *act) { awk_action *p, *first = calloc(1,sizeof(awk_action)); const char *cs,*ns; /* current, next stmt */ p = first; if (!p) { fprintf(stderr,"Couldn't allocate memory in awk_compile_action()\n"); return NULL; } for (cs = ns = act; ns && *ns; cs = (*ns==';')?ns+1:ns) { ns = strchr(cs,';'); if (!ns) /* end of string */ { ns = &cs[strlen(cs)]; } if (awk_compile_stmt(this,p,cs,(ns-cs)) >= 0) { p->next_act = calloc(1,sizeof(awk_action)); if (!p->next_act) { fprintf(stderr,"Couldn't allocate memoryin awk_compile_action (2)\n"); } p = p->next_act; } } return first; } /* * awk_free_action: Free the compiled action */ void awk_free_action(awk_action *a) { while (a) { awk_action *p = a; a = p->next_act; free(p); } } /* * awk_eval_expr: expand $vars into dest and do type conversions as * needed. For strings, just write directly into dest->val. For * ints/floats, write to a temp buffer and then atoi() or atof(). */ void awk_eval_expr(awk_symtab *this, awk_symbol *dest, const char *expr, int exprlen) { int i,dmax,dl,newlen; char c,delim; char *dp; const char *symname; int done; char tbuf[128]; awk_symbol *src; if (dest && expr) { if (dest->type == STRING) { dp = dest->val; /* just expand directly to result buffer */ dmax = dest->size; } else { dp = tbuf; /* use temp buffer */ dmax = sizeof(tbuf); } for (done = 0, i = 0, dl = 0; !done && i < dmax && exprlen > 0; i++) { switch (c = *expr) { case '"': case '\'': /* trim off string delims */ ++expr; --exprlen; if (expr[exprlen-1] == c) /* look for matching close delim */ { --exprlen; } break; case '$': /* $... look for variable substitution */ if (--exprlen < 0) { done = 1; break; } c = *++expr; /* what's after the $? */ switch (c) { case '{': /* ${var}... currently broken (see TODO) */ delim='}'; ++expr; /* skip the open delim */ --exprlen; break; case '(': /* $(var)... */ delim=')'; ++expr; --exprlen; break; default: /* $var ... */ delim='\0'; break; } /* now search for the var name using closing delim */ symname = expr; if (delim == '\0') { /* no close delim */ while (!isspace((int)*expr) && !ispunct((int)*expr) && exprlen > 0) { ++expr; --exprlen; } } else { /* search for close delim */ while (*expr != delim && exprlen > 0) { ++expr; --exprlen; } } src = awk_find_sym(this,symname,(expr-symname)); if (delim) { /* gotta skip over the close delim */ ++expr; --exprlen; } /* make sure src and dest of string copy don't overlap */ if (src && src->type == STRING && dp >= (char *)src->val && dp <= &((char *)src->val)[src->size]) { char *sp; int free_it = 0; if ((int)sizeof(tbuf) >= src->size) { /* tbuf big enuf */ sp = tbuf; } else { /* tbuf too small */ free_it++; sp = malloc(src->size); if (!sp) { /* oh well! */ fprintf(stderr,"Couldn't allocate memory in awk_eval_expr()\n"); break; } } awk_get_sym(src,sp,src->size,&newlen); bcopy(sp,dp,newlen); /* now copy it in */ // We only want to free it if we malloc'ed it. if (free_it) { free(sp); } } else { awk_get_sym(src,dp,(dmax-dl),&newlen); } dl += newlen; dp += newlen; break; case '\\': /* \... quote next char */ /* XXX TODO: implement \n,\t,\0[x].. etc. */ if (--exprlen < 0) { done = 1; } else { if (dl < dmax) { *dp++ = *expr++; /* copy the quoted char */ ++dl; } } break; default: /* just copy the character */ if (--exprlen < 0) { done = 1; } else { if (dl < dmax) { *dp++ = *expr++; /* copy the char */ ++dl; } } break; } /* end switch (*expr) */ } /* end for loop */ *dp = '\0'; /* null terminate the string */ switch(dest->type) { case INT: if (dest->size >= (int)sizeof(int)) { *((int *)dest->val) = atoi(tbuf); dest->len = sizeof(int); } break; case FLOAT: if (dest->size >= (int)sizeof(double)) { *((double *)dest->val) = atof(tbuf); dest->len = sizeof(double); } break; case STRING: /* already filled val in */ dest->len = dl; /* just update len */ break; default: break; } } } /* * awk_exec_action: interpret the compiled action. */ int awk_exec_action(awk_symtab *this, const awk_action *code) { const awk_action *p; int done = 0; for (p = code; p && !done; p = p->next_act) { switch (p->opcode) { case NEXT: done = 1; break; case SKIP: done = 2; break; case ASSIGN: awk_eval_expr(this,p->dest,p->expr,p->exprlen); break; case NOOP: break; default: break; } } return done; } /* * Rules consists of pcre patterns and actions. A program is * the collection of rules to apply as a group. */ /* * awk_new_rule: alloc a rule */ awk_rule *awk_new_rule(void) { awk_rule *n = calloc(1,sizeof(awk_rule)); if (!n) { fprintf(stderr,"Couldn't allocate memory in awk_new_rule()\n"); } return n; } void awk_free_rule(awk_rule *r) { if (r) { if (r->flags&AR_MALLOC) { if (r->act) { free((char *)r->act); } if (r->pattern) { free((char *)r->pattern); } if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } if (r->re) { #ifdef XASTIR_LEGACY_PCRE pcre_free(r->re); #else pcre2_code_free(r->re); #endif } #ifdef XASTIR_LEGACY_PCRE if (r->pe) { pcre_free(r->pe); } #endif } if (r->code) { awk_free_action(r->code); } free(r); } } /* * awk_new_program: alloc a program */ awk_program *awk_new_program(void) { awk_program *n = calloc(1,sizeof(awk_program)); if (!n) { fprintf(stderr,"Couldn't allocate memory in awk_new_program()\n"); } return n; } void awk_free_program(awk_program *rs) { awk_rule *r; if (rs) { for (r = rs->head; r; ) { awk_rule *x = r; r = r->next_rule; awk_free_rule(x); } free(rs); } } /* * awk_add_rule: add a rule to a program */ void awk_add_rule(awk_program *this, awk_rule *r) { if (!this) { return; } if (!this->last) { this->head = this->last = r; r->next_rule = NULL; } else { this->last->next_rule = r; this->last = r; } } /* * awk_load_program_array: load program from an array of rules. Use this * to load a program from a statically declared array (see test main * program for an example). */ awk_program *awk_load_program_array(awk_rule rules[], /* rules array */ int nrules) { /* size of array */ awk_program *n = awk_new_program(); awk_rule *r; if (!n) { return NULL; } for (r = rules; r < &rules[nrules]; r++) { awk_add_rule(n,r); } return n; } static void garbage(const char *file, int line, const char *buf, const char *cp) { fprintf(stderr,"%s:%d: parse error:\n",file,line); fputs(buf,stderr); fputc('\n',stderr); while (cp-- > buf) { fputc(' ',stderr); } fputs("^\n\n",stderr); } /* * awk_load_program_file: load program from a file. * * File syntax is a simplified version of awk: * * {action} * /pattern/ {action} * BEGIN {action} * BEGIN_RECORD {action} * END_RECORD {action} * END {action} * # comments... * (blank lines) * * Note that action can continue onto subsequent lines. */ awk_program *awk_load_program_file(const char *file) { /* rules filename */ awk_program *n = awk_new_program(); awk_rule *r; FILE *f = fopen(file,"r"); char in[2048]; int line = 0; if (!f) { if (n) { awk_free_program(n); } return NULL; } if (!n) { return NULL; } while (fgets(in,sizeof(in),f)) { char *cp = in, *p; int l = strlen(in); ++line; if (in[l-1] == '\n') { in[--l] = '\0'; } while (isspace((int)*cp)) { ++cp; } switch(*cp) { case '\0': /* empty line */ continue; case '#': /* comment line */ continue; case '/': /* begin regexp */ r = awk_new_rule(); r->ruletype = REGEXP; p = ++cp;; /* now points at pattern */ more: while (*cp && *cp != '/') { ++cp; /* find end of pattern */ } if (cp > in && cp[-1] == '\\') { /* '/' quoted */ ++cp; goto more; /* so keep going */ } if (*cp != '\0') /* zap end of pattern */ { *cp++ = '\0'; } r->pattern = strdup(p); break; case 'B': /* BEGIN? */ if (strncmp(cp,"BEGIN_RECORD",12) == 0) { r = awk_new_rule(); r->ruletype = BEGIN_REC; cp += 12; /* strlen("BEGIN_RECORD") */ } else if (strncmp(cp,"BEGIN",5) == 0) { r = awk_new_rule(); r->ruletype = BEGIN; cp += 5; /* strlen("BEGIN") */ } else { garbage(file,line,in,cp); continue; } break; case 'E': /* END? */ if (strncmp(cp,"END_RECORD",10) == 0) { r = awk_new_rule(); r->ruletype = END_REC; cp += 10; /* strlen("END_RECORD") */ } else if (strncmp(cp,"END",3) == 0) { r = awk_new_rule(); r->ruletype = END; cp += 3; /* strlen("END") */ } else { garbage(file,line,in,cp); continue; } break; default: garbage(file,line,in,cp); continue; } while (isspace((int)*cp)) { ++cp; /* skip whitespace */ } if (*cp == '{') { p = ++cp; loop: while (*cp && *cp != '}' && *cp != '#') { ++cp; } if (*cp == '\0' || *cp == '#') { /* continues on next line */ *cp++=' '; /* replace \n w/white space */ if (cp >= &in[sizeof(in)-1]) { garbage(file,line,"line too long",0); return n; } if (!fgets(cp,sizeof(in)-(cp-in),f)) { fprintf(stderr,"%s:%d: failed to parse\n",file,line); return n; } ++line; goto loop; /* keep looking for that close bracket */ } if (*cp != '\0') /* zap end of act */ { *cp++ = '\0'; } r->act = strdup(p); r->flags |= AR_MALLOC; /* make sure there's no extraneous junk on the line */ while (*cp && isspace((int)*cp)) { ++cp; } if (*cp == '#' || *cp == '\0') { awk_add_rule(n,r); } else { garbage(file,line,in,cp); continue; } } else { garbage(file,line,in,cp); continue; } } /* end while */ fclose(f); return n; } /* * awk_compile_program: Once loaded (from array or file), the program is compiled. Check for already compiled program. */ int awk_compile_program(awk_symtab *symtab, awk_program *rs) { awk_rule *r; #ifdef XASTIR_LEGACY_PCRE const char *error; int erroffset; #else int errornumber; PCRE2_SIZE erroffset; pcre2_compile_context *theCompileContext; #endif if (!rs) { return -1; } rs->symtbl = symtab; for (r = rs->head; r; r = r->next_rule) { if (r->ruletype == REGEXP) { if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } #ifdef XASTIR_LEGACY_PCRE r->tables = pcre_maketables(); /* NLS locale parse tables */ #else theCompileContext=pcre2_compile_context_create(NULL); r->tables = pcre2_maketables(NULL); /* NLS locale parse tables */ /* this always returns zero, so can ignore errornumber */ errornumber=pcre2_set_character_tables(theCompileContext,r->tables); #endif if (!r->re) { #ifdef XASTIR_LEGACY_PCRE r->re = pcre_compile(r->pattern, /* the pattern */ 0, /* default options */ &error, /* for error message */ &erroffset, /* for error offset */ r->tables); /* NLS locale character tables */ #else r->re = pcre2_compile((PCRE2_SPTR8)r->pattern, /* the pattern */ PCRE2_ZERO_TERMINATED, /* no length needed */ 0, /* default options */ &errornumber, /* for error message */ &erroffset, /* for error offset */ theCompileContext); #endif } if (!r->re) { int i; fprintf(stderr,"parse error: %s\n",r->pattern); fprintf(stderr," "); for (i = 0; i < erroffset; i++) { fputc(' ',stderr); } fprintf(stderr,"^\n"); return -1; } #ifdef XASTIR_LEGACY_PCRE if (!r->pe) { r->pe = pcre_study(r->re, 0, &error); /* optimize the regexp */ } #else pcre2_compile_context_free(theCompileContext); #endif } else if (r->ruletype == BEGIN) { rs->begin = r; } else if (r->ruletype == BEGIN_REC) { rs->begin_rec = r; } else if (r->ruletype == END_REC) { rs->end_rec = r; } else if (r->ruletype == END) { rs->end = r; } if (!r->code) { r->code = awk_compile_action(rs->symtbl,r->act); /* compile the action */ } } return 0; } /* * awk_uncompile_program: Frees the compiled program (patterns and stmts) * but keeps the program text loaded so it can be recompiled (e.g. with a * new symtbl). */ void awk_uncompile_program(awk_program *p) { awk_rule *r; if (!p) { return; } for (r = p->head; r; r = r->next_rule) { if (r->ruletype == REGEXP) { if (r->tables) { #ifdef XASTIR_LEGACY_PCRE pcre_free((void *)r->tables); #else pcre2_maketables_free(NULL,r->tables); #endif } r->tables = NULL; if (r->re) { #ifdef XASTIR_LEGACY_PCRE pcre_free(r->re); #else pcre2_code_free(r->re); #endif } r->re = NULL; #ifdef XASTIR_LEGACY_PCRE if (r->pe) { pcre_free(r->pe); } r->pe = NULL; #endif } if (r->code) { awk_free_action(r->code); /* free the action */ } r->code = NULL; } } /* * awk_exec_program: apply the program to the given buffer */ int awk_exec_program(awk_program *this, char *buf, int len) { int i,rc,done = 0; awk_rule *r; #ifdef XASTIR_LEGACY_PCRE int ovector[3*MAXSUBS]; #define OVECLEN (sizeof(ovector)/sizeof(ovector[0])) #else PCRE2_SIZE *ovector; #endif if (!this || !buf || len <= 0) { return 0; } for (r = this->head; r && !done ; r = r->next_rule) { if (r->ruletype == REGEXP) { #ifdef XASTIR_LEGACY_PCRE rc = pcre_exec(r->re,r->pe,buf,len,0,0,ovector,OVECLEN); #else pcre2_match_data *match_data; match_data=pcre2_match_data_create_from_pattern(r->re,NULL); rc=pcre2_match(r->re,(PCRE2_SPTR8)buf,len,0,0,match_data,NULL); if (rc >0 ) ovector=pcre2_get_ovector_pointer(match_data); #endif /* assign values to as many of $0 thru $9 as were set */ /* XXX - avoid calling awk_find_sym for these known values */ for (i = 0; rc > 0 && i < rc && i < MAXSUBS ; i++) { char symname[2]; awk_symbol *s; symname[0] = i + '0'; symname[1] = '\0'; s = awk_find_sym(this->symtbl,symname,1); s->val = &buf[ovector[2*i]]; s->len = ovector[2*i+1]-ovector[2*i]; } /* clobber the remaining $n thru $9 */ for (; i < MAXSUBS; i++) { char symname[10]; awk_symbol *s; symname[0] = i + '0'; symname[1] = '\0'; s = awk_find_sym(this->symtbl,symname,1); s->len = 0; } if (rc > 0) { done = awk_exec_action(this->symtbl,r->code); } #ifndef XASTIR_LEGACY_PCRE pcre2_match_data_free(match_data); #endif } } return done; } /* * awk_exec_begin_record: run the special BEGIN_RECORD rule, if any */ int awk_exec_begin_record(awk_program *this) { if (this && this->begin_rec) { return awk_exec_action(this->symtbl,this->begin_rec->code); } else { return 0; } } /* * awk_exec_begin: run the special BEGIN rule, if any */ int awk_exec_begin(awk_program *this) { if (this && this->begin) { return awk_exec_action(this->symtbl,this->begin->code); } else { return 0; } } /* * awk_exec_end_record: run the special END_RECORD rule, if any */ int awk_exec_end_record(awk_program *this) { if (this && this->end_rec) { return awk_exec_action(this->symtbl,this->end_rec->code); } else { return 0; } } /* * awk_exec_end: run the special END rule, if any */ int awk_exec_end(awk_program *this) { if (this && this->end) { return awk_exec_action(this->symtbl,this->end->code); } else { return 0; } } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.4/src/awk.h0000664000175000017500000001266215151324131015052 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef AWK_H #define AWK_H #ifdef XASTIR_LEGACY_PCRE #ifdef HAVE_PCRE_H #include #endif #ifdef HAVE_PCRE_PCRE_H #include #endif #else #define PCRE2_CODE_UNIT_WIDTH 8 #include #endif enum awk_symtype { STRING, INT, FLOAT }; /* the only data types */ typedef struct awk_symbol_ { /* symbol table entry */ struct awk_symbol_ *next_sym; /* linked list */ const char *name; /* name of the symbol */ int namelen; /* length of the name */ enum awk_symtype type; /* data type of symbol value */ void *val; /* storage for the value */ int size; /* size of *val */ int len; /* current length of *val */ } awk_symbol; #define AWK_SYMTAB_HASH_SIZE 0xff typedef struct awk_symtab_ { /* symbol table anchor */ awk_symbol *hash[AWK_SYMTAB_HASH_SIZE]; } awk_symtab; #define AWK_SYM_HASH(n,l) ((*n)&AWK_SYMTAB_HASH_SIZE) //#define AWK_SYM_HASH(n,l) ((n[0]+((l>1)?n[1]:0))&AWK_SYMTAB_HASH_SIZE) typedef struct awk_action_ { /* a program statement */ struct awk_action_ *next_act; enum {NOOP=0, NEXT, SKIP, ASSIGN} opcode; awk_symbol *dest; /* destination of assignment */ const char *expr; /* value setting expression */ int exprlen; /* length of expression */ } awk_action; typedef struct awk_rule_ { struct awk_rule_ *next_rule; /* linked list */ enum {BEGIN,BEGIN_REC,END_REC,END,REGEXP} ruletype; const char *pattern; /* pcre pattern string */ #ifdef XASTIR_LEGACY_PCRE const u_char *tables; /* pcre NLS tables */ pcre *re; /* pcre compiled pattern */ pcre_extra *pe; /* pcre optimized pattern */ #else const uint8_t *tables; /* pcre2 NLS tables */ pcre2_code *re; /* pcre2 compiled pattern */ void *pe; /* pcre2 doesn't use separate optimization */ #endif const char *act; /* the program string */ awk_action *code; /* compiled program */ int flags; /* some flags */ #define AR_MALLOC 0x01 /* pattern, act were malloc'd by me */ } awk_rule; typedef struct awk_program_ { /* anchor for the list of rules */ awk_symtab *symtbl; /* the symbol table for this program */ awk_rule *head; /* head of list */ awk_rule *last; /* last element */ awk_rule *begin; /* optional BEGIN rule */ awk_rule *begin_rec; /* optional BEGIN_RECORD rule */ awk_rule *end_rec; /* optional END_RECORD rule */ awk_rule *end; /* optional END rule */ } awk_program; extern awk_symtab *awk_new_symtab(void); extern void awk_free_symtab(awk_symtab *s); extern int awk_declare_sym(awk_symtab *this, const char *name, enum awk_symtype type, const void *val, const int size); extern awk_symbol *awk_find_sym(awk_symtab *this, const char *name, const int len); extern int awk_set_sym(awk_symbol *s, const char *val, const int len); extern int awk_get_sym(awk_symbol *s, char *store, int size, int *len); extern int awk_compile_stmt(awk_symtab *this, awk_action *p, const char *stmt, int len); extern awk_action *awk_compile_action(awk_symtab *this, const char *act); extern void awk_free_action(awk_action *a); extern void awk_eval_expr(awk_symtab *this, awk_symbol *dest, const char *expr, int exprlen); extern int awk_exec_action(awk_symtab *this, const awk_action *code); extern awk_rule *awk_new_rule(void); extern void awk_free_rule(awk_rule *r); extern awk_program *awk_new_program(void); extern void awk_free_program(awk_program *rs); void awk_add_rule(awk_program *this, awk_rule *r); extern awk_program *awk_load_program_array(awk_rule rules[],int nrules); extern awk_program *awk_load_program_file(const char *file); extern int awk_compile_program(awk_symtab *symtbl,awk_program *rs); extern void awk_uncompile_program(awk_program *rs); extern int awk_exec_program(awk_program *this, char *buf, int len); extern int awk_exec_begin_record(awk_program *this); extern int awk_exec_end_record(awk_program *this); extern int awk_exec_begin(awk_program *this); extern int awk_exec_end(awk_program *this); #endif /*!AWK_H*/ Xastir-Release-2.2.4/src/bulletin_gui.c0000664000175000017500000006567615151324131016762 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include #include #include "xastir.h" #include "main.h" #include "bulletin_gui.h" #include "interface.h" #include "util.h" #include "mutex_utils.h" #include "db_funcs.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget Display_bulletins_dialog = NULL; Widget Display_bulletins_text = NULL; Widget dist_data = NULL; Widget zero_bulletin_data = NULL; static xastir_mutex display_bulletins_dialog_lock; int bulletin_range; int new_bulletin_flag = 0; int new_bulletin_count = 0; static time_t first_new_bulletin_time = 0; static time_t last_new_bulletin_time = 0; void bulletin_gui_init(void) { init_critical_section(&display_bulletins_dialog_lock); } // Function called from check_for_new_bulletins() if a new bulletin // has come in that's within our range and we have // pop_up_new_bulletins enabled. This causes the Bulletins() dialog // to come up and rescan the message database for all bulletins that // are within the radius specified. By the time this gets called // we've already waited a few seconds to try to get the posit to // come in that matches the bulletin, and have then checked the // database to make sure that the new bulletins received are still // within our range. void popup_bulletins(void) { if ( Display_bulletins_dialog == NULL ) // Dialog not up { // Bring up the dialog Bulletins( (Widget)NULL, (XtPointer)NULL, (XtPointer)NULL ); } } void bulletin_message(char *call_sign, char *tag, char *packet_message, time_t sec_heard) { char temp[200]; char temp_my_course[10]; char temp_text[30]; double distance; XmTextPosition pos, eol, eod; struct tm *tmp; time_t timehd; char time_str[20]; char *temp_ptr; timehd=sec_heard; tmp = localtime(&timehd); if ( (packet_message != NULL) && (strlen(packet_message) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 1) { fprintf(stderr,"bulletin_message: Message length too long\n"); } return; } (void)strftime(time_str,sizeof(time_str),"%b %d %H:%M",tmp); distance = distance_from_my_station(call_sign,temp_my_course, english_units); xastir_snprintf(temp, sizeof(temp), "%-9s:%-4s (%s %6.1f %s) %s\n", call_sign, &tag[3], time_str, distance, english_units ? langcode("UNIOP00004"): langcode("UNIOP00005"), packet_message); // Operands of <= have incompatible types (double, int): if ( ( ((int)distance <= bulletin_range) && (distance > 0.0) ) || (view_zero_distance_bulletins && distance == 0.0) || ( (bulletin_range == 0) && (distance > 0.0) ) ) { begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:bulletin_message" ); if ((Display_bulletins_dialog != NULL) && Display_bulletins_text != NULL) // Dialog is up { eod = XmTextGetLastPosition(Display_bulletins_text); memcpy(temp_text, temp, 15); temp_text[14] = '\0'; // Terminate string // Look for this bulletin ID. "pos" will hold the first char position if found. if (XmTextFindString(Display_bulletins_text, 0, temp_text, XmTEXT_FORWARD, &pos)) { // Found it, so now find the end-of-line for it if (XmTextFindString(Display_bulletins_text, pos, "\n", XmTEXT_FORWARD, &eol)) { eol++; } else { eol = eod; } // And replace the old bulletin with a new copy if (eol == eod) { temp[strlen(temp)-1] = '\0'; } XmTextReplace(Display_bulletins_text, pos, eol, temp); } else { for (pos = 0; strlen(temp_text) > 12 && pos < eod;) { if (XmCOPY_SUCCEEDED == XmTextGetSubstring(Display_bulletins_text, pos, 14, 30, temp_text)) { if (temp_text[0] && strncmp(temp, temp_text, 14) < 0) { break; } } else { break; } if (XmTextFindString(Display_bulletins_text, pos, "\n", XmTEXT_FORWARD, &eol)) { pos = ++eol; } else { pos = eod; } } if (pos == eod) { temp[strlen(temp)-1] = '\0'; // End-of-Data remove trailing LF if (pos > 0) // Already have text. Need to insert LF between items { memmove(&temp[1], temp, strlen(temp)); temp[0] = '\n'; } } XmTextInsert(Display_bulletins_text,pos,temp); } temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); } end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:bulletin_message" ); } } static void bulletin_line(Message *fill) { bulletin_message(fill->from_call_sign, fill->call_sign, fill->message_line, fill->sec_heard); } static void scan_bulletin_file(void) { mscan_file(MESSAGE_BULLETIN, bulletin_line); } // bulletin_data_add // // Adds the bulletin to the message database. Updates the Bulletins // dialog if it is up. Causes Bulletins dialog to pop up if the // bulletin matches certain parameters. // long temp_bulletin_record; void bulletin_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from) { int distance = -1; // Add to the message database (void)msg_data_add(call_sign, from_call, data, " ", // Need something here. Empty string no good. MESSAGE_BULLETIN, from, &temp_bulletin_record); // If we received a NEW bulletin if (temp_bulletin_record == -1L) { char temp[10]; //fprintf(stderr,"We think it's a new bulletin!\n"); // We add to the distance in order to come up with 0.0 // if the distance is not known at all (no position // found yet). distance = (int)(distance_from_my_station(from_call,temp,english_units) + 0.9999); if ( (bulletin_range == 0) || (distance <= bulletin_range && distance > 0) || (view_zero_distance_bulletins && distance == 0.0) ) { // We have a _new_ bulletin that's within our // current range setting. Note that it's also possible // to have a zero distance for the bulletin (we haven't // heard a posit from the sending station yet), then get // a posit later. if (debug_level & 1) { fprintf(stderr,"New bulletin:"); fprintf(stderr,"%05d:%9s:%c:%c:%9s:%s:%s ", distance, call_sign, type, from, from_call, data, seq); fprintf(stderr," Distance ok:%d miles",distance); } if (pop_up_new_bulletins) { //fprintf(stderr,"bulletin_data_add: popping up bulletins\n"); popup_bulletins(); if (debug_level & 1) { fprintf(stderr,"\n"); } } else { if (debug_level & 1) { fprintf(stderr,", but popups disabled!\n"); } } } else { // fprintf(stderr,", but distance didn't work out!\n"); } } // Update the View->Bulletins dialog if it's up bulletin_message(from_call, call_sign, data, sec_now()); } // Find each bulletin that is within our range _and_ within our time // parameters for new bulletins. Count them only. Results returned // in the new_bulletin_count variable. void count_bulletin_messages(char *call_sign, char *packet_message, time_t sec_heard) { char temp_my_course[10]; double distance; if ( (packet_message != NULL) && (strlen(packet_message) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 1) { fprintf(stderr,"bulletin_message: Message length too long\n"); } return; } distance = distance_from_my_station(call_sign,temp_my_course,english_units); // Operands of <= have incompatible types (double, int): if ( ( ((int)distance <= bulletin_range) && (distance > 0.0) ) || (view_zero_distance_bulletins && distance == 0.0) || ( (bulletin_range == 0) && (distance > 0.0) ) ) { // Is it newer than our first new_bulletin timestamp? if (sec_heard >= first_new_bulletin_time) { new_bulletin_count++; } } } static void count_bulletin_line(Message *fill) { count_bulletin_messages(fill->from_call_sign, fill->message_line, fill->sec_heard); } static void count_new_bulletins(void) { mscan_file(MESSAGE_BULLETIN, count_bulletin_line); } // Function called by mscan_file for each bulletin with zero for the // position_known flag. See next function find_zero_position_bulletins() // static void zero_bulletin_processing(Message *fill) { DataRow *p_station; // Pointer to station data if (!fill->position_known) { //fprintf(stderr,"Position unknown: %s:%s\n", // fill->from_call_sign, // fill->message_line); // Check to see if we _now_ have a position for this non-new // bulletin. If so, change the position_known flag on that // record to a one, update the record, set the proper timers // and then schedule a popup if it fits within our current // parameters. if ( search_station_name(&p_station,fill->from_call_sign,1) ) { // Found a bulletin for which we get to fill in a new // position! if ( (p_station->coord_lon == 0l) && (p_station->coord_lat == 0l) ) { //fprintf(stderr,"Found it but still no valid position!\n"); } else // Found valid position for this bulletin { //fprintf(stderr,"Found it now! %s:%s\n", // fill->from_call_sign, // fill->message_line); // Mark it as found fill->position_known = 1; // Fake the timestamp so that we check messages back // to at least this one we just found. Allow for the // fact that we might find several older messages, so // we only want to keep taking the timestamp backwards // in time here. if (first_new_bulletin_time > (fill->sec_heard) ) { first_new_bulletin_time = fill->sec_heard; } // Check whether we really wish to pop them up if (pop_up_new_bulletins) { int distance; char temp_my_course[10]; distance = (int)(distance_from_my_station(fill->from_call_sign, temp_my_course, english_units) + 0.9999); if ( (bulletin_range == 0) || (distance <= bulletin_range && distance > 0) ) { if (debug_level & 1) { fprintf(stderr,"Filled in distance for earlier bulletin:%d miles\n", distance); } // If view_zero_distance_bulletins was not // turned on, then we probably haven't seen // this bulletin until now. Popup up the // Bulletin dialog. if (!view_zero_distance_bulletins) { //fprintf(stderr,"zero_bulletin_processing: popping up bulletins\n"); popup_bulletins(); } } } } } else { // No position known for the bulletin. Skip it for now. //fprintf(stderr,"Still not found\n"); } } } // Find all bulletins that have a zero for the position_known flag. // Calls the function above for each bulletin. // static void find_zero_position_bulletins(void) { mscan_file(MESSAGE_BULLETIN, zero_bulletin_processing); } // Function called by main.c:UpdateTime(). Checks whether enough // time has passed since the last new bulletin came in (so that the // posit for it might come in as well). If so, checks for bulletins // that are newer than first_new_bulletin_time and fit within our // range. If any found, it updates the Bulletins dialog. time_t last_bulletin_check = (time_t)0l; void check_for_new_bulletins(int curr_sec) { // Check every 15 seconds max if ( (last_bulletin_check + 15) > curr_sec ) { return; } last_bulletin_check = curr_sec; // Look first to see if we might be able to fill in positions on // any older bulletins, then cause a popup for those that fit // our parameters. The below function sets new_bulletin_flag if // it is able to fill in a distance for an older bulletin. // Note: This is time-consuming! find_zero_position_bulletins(); // Any new bulletins to check? If not, return if (!new_bulletin_flag) { return; } // Enough time passed since most recent bulletin? Need to have // enough time to perhaps fill in a distance for each bulletin. if ( (last_new_bulletin_time + 15) > curr_sec ) { //fprintf(stderr,"Not enough time has passed\n"); return; } // If we get to here, then we think we may have at least one new // bulletin, and the latest arrived more than XX seconds ago // (currently 15 seconds). Check for bulletins which have // timestamps equal to or newer than first_new_bulletin_time and // fit within our range. new_bulletin_count = 0; //fprintf(stderr,"Checking for new bulletins\n"); count_new_bulletins(); //fprintf(stderr,"%d new bulletins found\n",new_bulletin_count); if (new_bulletin_count) { //fprintf(stderr,"check_for_new_bulletins: popping up bulletins\n"); popup_bulletins(); if (debug_level & 1) { fprintf(stderr,"New bulletins (%d) caused popup!\n",new_bulletin_count); } } else { if (debug_level & 1) { fprintf(stderr,"No bulletin popup generated.\n"); } } // Reset so that we can do it all over again later. We need // mutex locks protecting these variables. first_new_bulletin_time = last_new_bulletin_time + 1; new_bulletin_flag = 0; } void Display_bulletins_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; // Keep this. It stores the range in a global variable when we destroy the dialog. temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Display_bulletins_destroy_shell" ); XtDestroyWidget(shell); Display_bulletins_dialog = (Widget)NULL; end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Display_bulletins_destroy_shell" ); } void Display_bulletins_change_range(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; // Keep this. It stores the range in a global variable when we destroy the dialog. temp_ptr = XmTextFieldGetString(dist_data); bulletin_range = atoi(temp_ptr); XtFree(temp_ptr); view_zero_distance_bulletins = (int)XmToggleButtonGetState(zero_bulletin_data); //fprintf(stderr,"%d\n",view_zero_distance_bulletins); Display_bulletins_destroy_shell( widget, clientData, callData); Bulletins( widget, clientData, callData); } void Zero_Bulletin_Data_toggle( Widget widget, XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { view_zero_distance_bulletins = atoi(which); } else { view_zero_distance_bulletins = 0; } Display_bulletins_destroy_shell( widget, Display_bulletins_dialog, callData); Bulletins( widget, clientData, callData); } void Bulletins(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, form, button_range, button_close, dist, dist_units; unsigned int n; Arg args[50]; Atom delw; char temp[10]; if(!Display_bulletins_dialog) { begin_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Bulletins" ); Display_bulletins_dialog = XtVaCreatePopupShell(langcode("BULMW00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Bulletins pane", xmPanedWindowWidgetClass, Display_bulletins_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Bulletins form", xmFormWidgetClass, pane, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); dist = XtVaCreateManagedWidget(langcode("BULMW00002"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); dist_data = XtVaCreateManagedWidget("dist_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*7)+2), XmNmaxLength, 8, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); dist_units = XtVaCreateManagedWidget((english_units?langcode("UNIOP00004"):langcode("UNIOP00005")), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_range = XtVaCreateManagedWidget(langcode("BULMW00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_units, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); zero_bulletin_data = XtVaCreateManagedWidget(langcode("WPUPCFD029"), xmToggleButtonWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_range, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(zero_bulletin_data,XmNvalueChangedCallback,Zero_Bulletin_Data_toggle,"1"); if (view_zero_distance_bulletins) { XmToggleButtonSetState(zero_bulletin_data,TRUE,FALSE); } else { XmToggleButtonSetState(zero_bulletin_data,FALSE,FALSE); } n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 108); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNscrollHorizontal, TRUE); n++; XtSetArg(args[n], XmNscrollVertical, TRUE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, dist); n++; XtSetArg(args[n], XmNtopOffset, 20); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, 30); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; Display_bulletins_text = XmCreateScrolledText(form, "Bulletins text", args, n); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_range, XmNactivateCallback, Display_bulletins_change_range, Display_bulletins_dialog); XtAddCallback(button_close, XmNactivateCallback, Display_bulletins_destroy_shell, Display_bulletins_dialog); pos_dialog(Display_bulletins_dialog); delw = XmInternAtom(XtDisplay(Display_bulletins_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(Display_bulletins_dialog, delw, Display_bulletins_destroy_shell, (XtPointer)Display_bulletins_dialog); xastir_snprintf(temp, sizeof(temp), "%d", bulletin_range); XmTextFieldSetString(dist_data, temp); XtManageChild(form); XtManageChild(Display_bulletins_text); XtVaSetValues(Display_bulletins_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); redraw_on_new_packet_data=1; XtPopup(Display_bulletins_dialog,XtGrabNone); end_critical_section(&display_bulletins_dialog_lock, "bulletin_gui.c:Bulletins" ); scan_bulletin_file(); // Move focus to the Close button. This appears to // highlight the button fine, but we're not able to hit the // key to have that default function happen. Note: // We _can_ hit the key, and that activates the // option. //XmUpdateDisplay(Display_bulletins_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(Display_bulletins_dialog), XtWindow(Display_bulletins_dialog)); } } Xastir-Release-2.2.4/src/bulletin_gui.h0000664000175000017500000000242315151324131016744 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_BULLETIN_GUI_H #define __XASTIR_BULLETIN_GUI_H extern int bulletin_range; // From bulletin_gui.c extern void bulletin_gui_init(void); extern void bulletin_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from); extern void check_for_new_bulletins(int current_sec); #endif // __XASTIR_BULLETIN_GUI_H Xastir-Release-2.2.4/src/cad_objects.c0000664000175000017500000026376015151324131016532 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include "xastir.h" #include "globals.h" #include "main.h" #include "xa_config.h" #include "db_funcs.h" #include "draw_symbols.h" #include "maps.h" // for draw_vector prototype #include #include // Must be last include file #include "leak_detection.h" // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX extern XmFontList fontlist1; // Menu/System fontlist extern void pos_dialog(Widget w); int polygon_last_x = -1; // Draw CAD Objects functions int polygon_last_y = -1; // Draw CAD Objects functions Widget draw_CAD_objects_dialog = (Widget)NULL; Widget cad_dialog = (Widget)NULL; Widget cad_label_data, cad_comment_data, cad_probability_data, cad_line_style_data; // Values entered in the cad_dialog int draw_CAD_objects_flag = 0; void Draw_All_CAD_Objects(Widget w); void Save_CAD_Objects_to_file(void); Widget cad_erase_dialog; Widget list_of_existing_CAD_objects = (Widget)NULL; Widget cad_list_dialog = (Widget)NULL; Widget list_of_existing_CAD_objects_edit = (Widget)NULL; void Draw_CAD_Objects_erase( Widget w, XtPointer clientData, XtPointer callData); void Update_CAD_objects_list_dialog(void); void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent); void Draw_CAD_Objects_erase_dialog( Widget w, XtPointer clientData, XtPointer callData ); void Draw_CAD_Objects_list_dialog( Widget w, XtPointer clientData, XtPointer callData ); void Draw_CAD_Objects_erase_dialog_close(Widget w, XtPointer clientData, XtPointer callData); void Draw_CAD_Objects_list_dialog_close(Widget w, XtPointer clientData, XtPointer callData); void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description); int CAD_draw_objects = TRUE; int CAD_show_label = TRUE; int CAD_show_raw_probability = TRUE; int CAD_show_comment = TRUE; int CAD_show_area = TRUE; #ifndef USE_COMBO_BOX int clsd_value; // replacement value for cad line type combo box #endif // !USE_COMBO_BOX //////////////////// Draw CAD Objects Functions //////////////////// //#define CAD_DEBUG // Allocate a new vertice along the polygon. If the vertice is very // close to the first vertice, ask the operator if they wish to // close the polygon. If closing, ask for a raw probability? // // As each vertice is allocated, write it out to file? We'd then // need to edit the file and comment vertices out if we're deleting // vertices in memory. We could also write out an entire object // when we select "Close Polygon". // void CAD_vertice_allocate(long latitude, long longitude) { #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new vertice\n"); #endif // Check whether a line segment will cross another? // We use the CAD_list_head variable, as it will be pointing to // the top of the list, where the current object we're working // on will be placed. Check whether that pointer is NULL // though, just in case. if (CAD_list_head) // We have at least one object defined { VerticeRow *p_new; // Allocate area to hold the vertice p_new = (VerticeRow *)malloc(sizeof(VerticeRow)); if (!p_new) { fprintf(stderr,"Couldn't allocate memory in CAD_vertice_allocate()\n"); return; } p_new->latitude = latitude; p_new->longitude = longitude; // Link it in at the top of the vertice chain. p_new->next = CAD_list_head->start; CAD_list_head->start = p_new; } // Call redraw_symbols outside this function, as // verticies may be allocated both when loading lots of them from a file // and when the user is drawing objects in the user interface // Reload symbols/tracks/CAD objects //redraw_symbols(da); } // Allocate a struct for a new object and add one vertice to it. // When do we name it and place the label? Assign probability to // it? We should keep a pointer to the current polygon we're // working on, so that we can modify it easily as we draw. // Actually, it'll be pointed to by CAD_list_head, so we already // have it! // // As each object is allocated, write it out to file? // // Compute a default label of date/time? // void CAD_object_allocate(long latitude, long longitude) { CADRow *p_new; #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new CAD object\n"); #endif // Allocate memory and link it to the top of the singly-linked // list of CADRow objects. p_new = (CADRow *)malloc(sizeof(CADRow)); if (!p_new) { fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate()\n"); return; } // Fill in default values p_new->creation_time = sec_now(); p_new->start = NULL; p_new->line_color = colors[0x27]; p_new->line_type = 2; // LineOnOffDash; p_new->line_width = 4; p_new->computed_area = 0; CAD_object_set_raw_probability(p_new,0.0,FALSE); p_new->label_latitude = 0l; p_new->label_longitude = 0l; p_new->label[0] = '\0'; p_new->comment[0] = '\0'; // Allocate area to hold the first vertice #ifdef CAD_DEBUG fprintf(stderr,"Allocating a new vertice\n"); #endif p_new->start = (VerticeRow *)malloc(sizeof(VerticeRow)); if (!p_new->start) { fprintf(stderr,"Couldn't allocate memory in CAD_object_allocate(2)\n"); free(p_new); return; } p_new->start->next = NULL; p_new->start->latitude = latitude; p_new->start->longitude = longitude; // Hook it into the linked list of objects p_new->next = CAD_list_head; CAD_list_head = p_new; /* // // Note: It was too confusing to have these two dialogs close and // get redrawn when we click on the first vertice. The net result // is that we may have two dialogs move on top of the drawing area // to the spot we're trying to draw. Commented out this section due // to that. We'll get the two dialogs updated when we click on // either the DONE or CANCEL button on the Close Polygon dialog. // // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(da, NULL, NULL); Draw_CAD_Objects_erase_dialog(da, NULL, NULL); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(da, NULL, NULL); Draw_CAD_Objects_list_dialog(da, NULL, NULL); } */ } // Delete all vertices associated with a CAD object and free the // memory. We really should pass a pointer to the object here // instead of a vertice, and set the start pointer to NULL when // done. // void CAD_vertice_delete_all(VerticeRow *v) { VerticeRow *tmp; // Call CAD_vertice_delete() for each vertice, then unlink this // CAD object from the linked list and free its memory. // Iterate through each vertice, deleting as we go while (v != NULL) { tmp = v; v = v->next; free(tmp); #ifdef CAD_DEBUG fprintf(stderr,"Free'ing a vertice\n"); #endif } } // Delete _all_ CAD objects and all associated vertices. Loop // through the entire list of CAD objects, calling // CAD_vertice_delete_all() and then free'ing the CAD object. When // done, set the start pointer to NULL. // // We also need to wipe the persistent CAD object file. // void CAD_object_delete_all(void) { CADRow *p = CAD_list_head; CADRow *tmp; while (p != NULL) { VerticeRow *v = p->start; // Remove all of the vertices if (v != NULL) { // Delete/free the vertices CAD_vertice_delete_all(v); } // Remove the object and free its memory tmp = p; p = p->next; free(tmp); #ifdef CAD_DEBUG fprintf(stderr,"Free'ing an object\n"); #endif } // Zero the CAD linked list head CAD_list_head = NULL; } // Remove a vertice, thereby joining two segments into one? // // Recompute the raw probability if need be, or make it an invalid // value so that we know we need to recompute it. // //void CAD_vertice_delete(CADrow *object) { // VerticeRow *v = object->start; // Unlink the vertice from the linked list and free its memory. // Allow removing a vertice in the middle or end of a chain. If // removing the vertice turns the polygon into an open polygon, // alert the user of that fact and ask if they wish to close it. //} /* Test to see if a CAD object of the name (label) provided exists. Parameter: label, the label text to be checked. Returns 0 if no CAD object with a name matching the provided name is found. Returns 1 if a CAD object with a name matching the provided name is found. */ int exists_CAD_object_by_label(char *label) { CADRow *object_pointer = CAD_list_head; int result = 0; // function return value int done = 0; // flag to stop loop when a match is found while (object_pointer != NULL && done==0) { if (strcmp(object_pointer->label,label)==0) { // a matching name was found result = 1; done = 1; } object_pointer = object_pointer->next; } return result; } /* Counts to see how many CAD objects of the name (label) provided exist. Parameter: label, the label text to be checked. Returns 0 if no CAD object with a name matching the provided name is found. Returns count of the number of CAD objects with a matching label if one or more is found. */ int count_CAD_object_with_matching_label(char *label) { CADRow *object_pointer = CAD_list_head; int result = 0; while (object_pointer != NULL) { // iterate through all CAD objects if (strcmp(object_pointer->label,label)==0) { // a matching name was found result++; object_pointer = object_pointer->next; } } return result; } /* Delete one CAD object and all of its vertices. */ void CAD_object_delete(CADRow *object) { CADRow *all_objects_ptr = CAD_list_head; CADRow *previous_object_ptr = CAD_list_head; VerticeRow *v = object->start; int done = 0; #ifdef CAD_DEBUG fprintf(stderr,"Deleting CAD object %s\n",object->label); #endif // check to see if the object we were given was the first object if (object==all_objects_ptr) { #ifdef CAD_DEBUG fprintf(stderr,"Deleting first CAD object %s\n",object->label); #endif CAD_vertice_delete_all(v); // Frees the memory also // Unlink the object from the chain and free the memory. CAD_list_head = object->next; // Unlink free(object); // Free the object memory } else { #ifdef CAD_DEBUG fprintf(stderr,"Deleting other than first CAD object %s\n",object->label); #endif // walk through the list and delete the object when found while (all_objects_ptr != NULL && done==0) { if (object==all_objects_ptr) { v = object->start; CAD_vertice_delete_all(v); previous_object_ptr->next = object->next; free(object); done = 1; } else { all_objects_ptr = all_objects_ptr->next; } } } } // Split an existing CAD object into two objects. Can we trigger // this by drawing a line across a closed polygon? void CAD_object_split_existing(void) { } // Join two existing polygons into one larger polygon. void CAD_object_join_two(void) { } // Move an entire CAD object, with all it's vertices, somewhere // else. Move the label along with it as well. void CAD_object_move(void) { } // Determine if a CAD object is a closed polygon. // // Takes a pointer to a CAD object as an argument. // Returns 1 if the object is closed. // Returns 0 if the object is not closed. // int is_CAD_object_open(CADRow *cad_object) { VerticeRow *vertex_pointer; int vertex_count = 0; int result = 1; int atleast_one_different = 0; long start_lat, start_long; long stop_lat, stop_long; vertex_pointer = cad_object->start; if (vertex_pointer!=NULL) { // greater than zero points, get first point. start_lat = vertex_pointer->latitude; start_long = vertex_pointer->longitude; stop_lat = vertex_pointer->latitude; stop_long = vertex_pointer->longitude; vertex_pointer = vertex_pointer->next; while (vertex_pointer != NULL) { //greater than one point, get current point. stop_lat = vertex_pointer->latitude; stop_long = vertex_pointer->longitude; if (stop_lat!=start_lat || stop_long!=start_long) { atleast_one_different = 1; } vertex_pointer = vertex_pointer->next; vertex_count++; } if (vertex_count>2 && start_lat==stop_lat && start_long==stop_long && atleast_one_different > 0) { // more than two points, and they aren't in the same place result = 0; } } return result; } // Compute the area enclosed by a CAD object. Check that it is a // closed, non-intersecting polygon first. // double CAD_object_compute_area(CADRow *CAD_list_head) { VerticeRow *tmp; double area; char temp_course[20]; // Walk the linked list, computing the area of the // polygon. Greene's Theorem is how we can compute the area of // a polygon using the vertices. We could also compute whether // we're going clockwise or counter-clockwise around the polygon // using Greene's Theorem. In fact I think we do that for // Shapefile hole polygons. Remember that here we're walking // around the vertices backwards due to the ordering of the // list. Shouldn't matter for our purposes though. // area = 0.0; tmp = CAD_list_head->start; if (is_CAD_object_open(CAD_list_head)==0) { // Only compute the area if CAD object is a closed polygon, // that is, not an open polygon. while (tmp->next != NULL) { double dx0, dy0, dx1, dy1; // Because lat/long units can vary drastically w.r.t. real // units, we need to multiply the terms by the real units in // order to get real area. // Compute real distances from a fixed point. Convert to // the current measurement units. We'll use the starting // vertice as our fixed point. // dx0 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, CAD_list_head->start->latitude, tmp->longitude, temp_course, sizeof(temp_course)); if (tmp->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } dy0 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, tmp->latitude, CAD_list_head->start->longitude, temp_course, sizeof(temp_course)); if (tmp->latitude < CAD_list_head->start->latitude) { dx0 = -dx0; } dx1 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, CAD_list_head->start->latitude, tmp->next->longitude, temp_course, sizeof(temp_course)); if (tmp->next->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } dy1 = calc_distance_course( CAD_list_head->start->latitude, CAD_list_head->start->longitude, tmp->next->latitude, CAD_list_head->start->longitude, temp_course, sizeof(temp_course)); // Add the minus signs back in, if any if (tmp->longitude < CAD_list_head->start->longitude) { dx0 = -dx0; } if (tmp->latitude < CAD_list_head->start->latitude) { dy0 = -dy0; } if (tmp->next->longitude < CAD_list_head->start->longitude) { dx1 = -dx1; } if (tmp->next->latitude < CAD_list_head->start->latitude) { dy1 = -dy1; } // Greene's Theorem: Summation of the following, then // divide by two: // // A = X Y - X Y // i i i+1 i+1 i // area += (dx0 * dy1) - (dx1 * dy0); tmp = tmp->next; } area = 0.5 * area; } if (area < 0.0) { area = -area; } //fprintf(stderr,"Square nautical miles: %f\n", area); return area; } // Allocate a label for an object, and place it according to the // user's requests. Keep track of where from the origin to place // the label, font to use, color, etc. void CAD_object_allocate_label(void) { } // Set the probability for an object. We should probably allocate // the raw probability to small "buckets" within the closed polygon. // This will allow us to split/join polygons later without messing // up the probablity assigned to each area originally. Check that // it is a closed polygon first. // if as_percent==TRUE, then probability is treated as a percent // (expected to be a value between 0 and 100). // otherwise, then probability is treated as a probability // (expected to be a value between 0 and 1). // void CAD_object_set_raw_probability(CADRow *object_ptr, float probability, int as_percent) { // initial implementation just assigns a single raw probability to the whole polygon. // internal storage is as a probability between 0 and 1 // users will usually want to manipulate this as a percent (between 0 and 100) // thus the get and set functions are aware of both internal storage and // the user's request and return an appropriately scaled value. if (as_percent==TRUE) { // convert from a percent to a probability between 0 and 1 object_ptr->raw_probability = (probability/100.00); } else { // treat as in internal storage form object_ptr->raw_probability = probability; } } // Get the raw probability for an object. Sum up the raw // probability "buckets" contained within the closed polygon. Check // that it _is_ a closed polygon first. // float CAD_object_get_raw_probability(CADRow *object_ptr, int as_percent) { float result = 0.0; // not checking yet for closure if (object_ptr != NULL) { // initial implementation returns just the single raw probability result = object_ptr->raw_probability; if (as_percent > 0) { // raw probability is a probability between 0 an 1, // this may be desired as a percent. result = result * 100; } } #ifdef CAD_DEBUG fprintf(stderr,"Getting Probability: %01.5f\n",result); #endif return result; } void CAD_object_set_line_width(void) { } void CAD_object_set_color(void) { } void CAD_object_set_linetype(void) { } // Used to break a line segment into two. Can then move the vertice // if needed. Recompute the raw probability if need be, or make it // an invalid value so that we know we need to recompute it. void CAD_vertice_insert_new(void) { // Check whether a line segment will cross another? } // Move an existing vertice. Recompute the raw probability if need // be, or make it an invalid value so that we know we need to // recompute it. void CAD_vertice_move(void) { // Check whether a line segment will cross another? } // Set the location for drawing the label of an area to the center // of the area. Takes a pointer to a CAD object as a parameter. // Sets the label_latitude and label_longitude attributes of the CAD // object to the center of the region described by the vertices of // the object. // void CAD_object_set_label_at_centroid(CADRow *CAD_object) { // *** current implementation approximates the center as the // average of the largest and smallest of each of latitude // and longitude rather than correctly computing the centroid, // that is, it places the label at the centroid of a bounding // box for the area. *** // We can't use a simple x=sum(x)/n, y=sum(y)/n as the // points on the outline shouldn't be weighted equally. // Ideal would be to place the label at the central point within // the area itslef, apparently this is a hard prbolem. // alternative would be to use the centroid, which like the // average of maximum and minimum values may lie outside of // the area. VerticeRow *vertex_pointer; long min_lat, min_long; long max_lat, max_long; // Walk the linked list and compute the centroid of the bounding box. vertex_pointer = CAD_object->start; min_lat = 0.0; min_long = 0.0; // Set the latitude and longitude of the label to the // centroid of the bounding box. // Start by setting lat and long of label to first point. CAD_object->label_latitude = vertex_pointer->latitude; CAD_object->label_longitude = vertex_pointer->longitude; if (vertex_pointer != NULL) { // Iterate through the vertices and calculate the center x and y position // based on an average of the largest and smallest latitudes and longitudes. min_lat = vertex_pointer->latitude; min_long = vertex_pointer->longitude; max_lat = vertex_pointer->latitude; max_long = vertex_pointer->longitude; while (vertex_pointer != NULL) { if (vertex_pointer->next != NULL) { if (vertex_pointer->longitude < min_long ) { min_long = vertex_pointer->longitude; } if (vertex_pointer->latitude < min_lat ) { min_lat = vertex_pointer->latitude; } if (vertex_pointer->longitude > max_long ) { max_long = vertex_pointer->longitude; } if (vertex_pointer->latitude > max_lat ) { max_lat = vertex_pointer->latitude; } } vertex_pointer = vertex_pointer->next; } CAD_object->label_latitude = (max_lat + min_lat)/2.0; CAD_object->label_longitude = (max_long + min_long)/2.0; } } // This is the callback for the CAD objects parameters dialog. It // takes the values entered in the dialog and stores them in the // most recently created object. // void Set_CAD_object_parameters (Widget widget, XtPointer clientData, XtPointer calldata) { float probability = 0.0; CADRow *target_object = NULL; int cb_selected; // need to find out object to edit from clientData rather than // using the first object in list as the one to edit. //target_object = CAD_list_head; target_object = (CADRow *)clientData; // set label, comment, and probability for area xastir_snprintf(target_object->label, sizeof(target_object->label), "%s", XmTextGetString(cad_label_data) ); xastir_snprintf(target_object->comment, sizeof(target_object->comment), "%s", XmTextGetString(cad_comment_data) ); // Is more error checking needed? atof appears to correctly handle // empty input, reasonable probability values, and text (0.00). // User side probabilities are expressed as percent. probability = atof(XmTextGetString(cad_probability_data)); CAD_object_set_raw_probability(target_object, probability, TRUE); // Use the selected line type, default is dashed cb_selected = FALSE; #ifdef USE_COMBO_BOX XtVaGetValues(cad_line_style_data, XmNselectedPosition, &cb_selected, NULL); #else cb_selected = clsd_value; #endif // USE_COMBO_BOX if (cb_selected) { target_object->line_type = cb_selected; } else { target_object->line_type = 2; // LineOnOffDash } if (cad_list_dialog) { Update_CAD_objects_list_dialog(); } // close object_parameters dialog XtPopdown(cad_dialog); XtDestroyWidget(cad_dialog); cad_dialog = (Widget)NULL; Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects so that object name will show on map. redraw_symbols(da); // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata); Draw_CAD_Objects_erase_dialog(widget,clientData,calldata); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata); Draw_CAD_Objects_list_dialog(widget, clientData, calldata); } } // Update the list of existing CAD objects on the cad list dialog to // reflect the current list of objects. // void Update_CAD_objects_list_dialog(void) { CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (list_of_existing_CAD_objects_edit!=NULL && cad_list_dialog) { XmListDeleteAllItems(list_of_existing_CAD_objects_edit); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects_edit, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } } } void close_object_params_dialog(Widget widget, XtPointer clientData, XtPointer calldata) { XtPopdown(cad_dialog); XtDestroyWidget(cad_dialog); cad_dialog = (Widget)NULL; // Here we update the erase cad objects dialog if it is up on // the screen. We get rid of it and re-establish it, which will // usually make the dialog move, but this is better than having // it be out-of-date. // if (cad_erase_dialog != NULL) { Draw_CAD_Objects_erase_dialog_close(widget,clientData,calldata); Draw_CAD_Objects_erase_dialog(widget,clientData,calldata); } // Here we update the edit cad objects dialog by getting rid of // it and then re-establishing it if it is active when we start. // This will usually make the dialog move, but it's better than // having it be out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(widget, clientData, calldata); Draw_CAD_Objects_list_dialog(widget, clientData, calldata); } } #ifndef USE_COMBO_BOX void clsd_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { //XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)callData; XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //clsd_menu is zero based, cad_line_style_data constants are one based. clsd_value = (int)userData + 1; if (debug_level & 1) { fprintf(stderr,"Selected value on cad line type pulldown: %d\n",clsd_value); } } #endif // !USE_COMBO_BOX // Create a dialog to obtain information about a newly created CAD // object from the user. Values of probability, name, and comment // are initially blank. Takes as a parameter a string describing // the area of the object. There is a single button with a callback // to Set_CAD_object_parameters, which stores values from the dialog // in the object's struct. Should be generalized to allow editing // of a pre-existing CAD object (except for the name). Parameter // should be a pointer to the object. // void Set_CAD_object_parameters_dialog(char *area_description, CADRow *CAD_object) { Widget cad_pane, cad_form, cad_label, cad_comment, cad_probability, cad_line_style, button_done, button_cancel; char probability_string[5]; int i; // loop counters //XmString cb_item; // used to create picklist of line styles XmString cb_items[3]; #ifndef USE_COMBO_BOX Widget clsd_menuPane; Widget clsd_button; Widget clsd_buttons[3]; Widget clsd_menu; char buf[18]; int x; Arg args[12]; // available for XtSetArguments #endif // !USE_COMBO_BOX Widget clsd_widget; if (cad_dialog) { (void)XRaiseWindow(XtDisplay(cad_dialog), XtWindow(cad_dialog)); } else { // Area Object" cad_dialog = XtVaCreatePopupShell(langcode("CADPUD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_pane = XtVaCreateWidget("Set_Del_Object pane", xmPanedWindowWidgetClass, cad_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); cad_form = XtVaCreateWidget("Set_Del_Object ob_form", xmFormWidgetClass, cad_pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Area of polygon, already scaled and internationalized. cad_label = XtVaCreateManagedWidget(area_description, xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Area Label:" cad_label = XtVaCreateManagedWidget(langcode("CADPUD002"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 50, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // label text field cad_label_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, CAD_LABEL_MAX_SIZE - 1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 50, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_label, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "Comment" cad_comment = XtVaCreateManagedWidget(langcode("CADPUD003"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 90, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // comment text field cad_comment_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNmaxLength, CAD_COMMENT_MAX_SIZE - 1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 90, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_comment, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "Probability (as %)" cad_probability = XtVaCreateManagedWidget(langcode("CADPUD004"), xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 130, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // probability field cad_probability_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, cad_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 130, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_probability, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // Boundary Line Type cad_line_style = XtVaCreateManagedWidget("Line Type:", xmLabelWidgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_probability_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lesstif as of 0.95 in 2008 doesn't fully support combo boxes // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. //cb_items = (XmString *) XtMalloc ( sizeof (XmString) * 4 ); // Solid cb_items[0] = XmStringCreateLtoR( langcode("CADPUD012"), XmFONTLIST_DEFAULT_TAG); // Dashed cb_items[1] = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); // Double Dash cb_items[2] = XmStringCreateLtoR( langcode("CADPUD014"), XmFONTLIST_DEFAULT_TAG); clsd_widget = cad_line_style_data; #ifdef USE_COMBO_BOX // Combo box to pick line style cad_line_style_data = XtVaCreateManagedWidget("select line style", xmComboBoxWidgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_probability_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_line_style, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmComboBoxAddItem(cad_line_style_data,cb_items[0],1,1); XmComboBoxAddItem(cad_line_style_data,cb_items[1],2,1); XmComboBoxAddItem(cad_line_style_data,cb_items[2],3,1); clsd_widget = cad_line_style_data; #else // menu replacement for combo box when using lesstif x = 0; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNfontList, fontlist1); ++x; clsd_menuPane = XmCreatePulldownMenu(cad_form,"sddd_menuPane", args, x); //sddd_menu is zero based, constants for database types are one based. //sddd_value is set to match constants in callback. for (i=0; i<3; i++) { x = 0; XtSetArg(args[x], XmNlabelString, cb_items[i]); x++; XtSetArg(args[x], XmNuserData, (XtPointer)i); x++; XtSetArg(args[x], XmNfontList, fontlist1); ++x; sprintf(buf,"button%d",i); clsd_button = XmCreatePushButton(clsd_menuPane, buf, args, x); XtManageChild(clsd_button); XtAddCallback(clsd_button, XmNactivateCallback, clsd_menuCallback, Set_CAD_object_parameters_dialog); clsd_buttons[i] = clsd_button; } x = 0; XtSetArg(args[x], XmNleftAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNleftWidget, cad_line_style); ++x; XtSetArg(args[x], XmNtopAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNtopWidget, cad_probability_data); ++x; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNtopOffset, 5); ++x; XtSetArg(args[x], XmNleftOffset, 10); ++x; XtSetArg(args[x], XmNsubMenuId, clsd_menuPane); ++x; XtSetArg(args[x], XmNfontList, fontlist1); ++x; clsd_menu = XmCreateOptionMenu(cad_form, "sddd_Menu", args, x); XtManageChild(clsd_menu); clsd_value = 2; // set a default value (line on off dash) clsd_widget = clsd_menu; #endif // USE_COMBO_BOX // free up space from combo box strings for (i=0; i<3; i++) { XmStringFree(cb_items[i]); } // "OK" button_done = XtVaCreateManagedWidget(langcode("CADPUD005"), xmPushButtonGadgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, clsd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Cancel" button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, cad_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, clsd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // callback depends on whether this is a new or old object //XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, Set_CAD_object_parameters_dialog); if (CAD_object!=NULL) { XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, (XtPointer *)CAD_object); } else { // called to get information for a newly created cad object // pass pointer to the head of the list, which contains // the most recently created cad object. XtAddCallback(button_done, XmNactivateCallback, Set_CAD_object_parameters, CAD_list_head); } XtAddCallback(button_cancel, XmNactivateCallback, close_object_params_dialog, NULL); pos_dialog(cad_dialog); XmInternAtom(XtDisplay(cad_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_form); XtManageChild(cad_pane); XtPopup(cad_dialog,XtGrabNone); } // end if ! caddialog if (CAD_object!=NULL) { XmString tempSelection; // given an existing object, fill form with its information XmTextFieldSetString(cad_label_data,CAD_object->label); XmTextFieldSetString(cad_comment_data,CAD_object->comment); xastir_snprintf(probability_string, sizeof(probability_string), "%01.2f", CAD_object_get_raw_probability(CAD_object,1)); XmTextFieldSetString(cad_probability_data,probability_string); switch(CAD_object->line_type) { case 1: // Solid #ifndef USE_COMBO_BOX i = 0; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD012"), XmFONTLIST_DEFAULT_TAG); break; case 2: // Dashed #ifndef USE_COMBO_BOX i = 1; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); break; case 3: // Double Dash #ifndef USE_COMBO_BOX i = 2; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD014"), XmFONTLIST_DEFAULT_TAG); break; default: #ifndef USE_COMBO_BOX i = 1; #endif // !USE_COMBO_BOX tempSelection = XmStringCreateLtoR( langcode("CADPUD013"), XmFONTLIST_DEFAULT_TAG); break; } #ifdef USE_COMBO_BOX XmComboBoxSelectItem(cad_line_style_data, tempSelection); #else clsd_value = i+1; //clsd_menu is zero based, line types are one based. //clsd_value matches line types (1-3). XtVaSetValues(clsd_menu, XmNmenuHistory, clsd_buttons[i], NULL); #endif // USE_COMBO_BOX XmStringFree(tempSelection); } } static Cursor cs_CAD = (Cursor)NULL; void free_cs_CAD(void) { XFreeCursor(XtDisplay(da), cs_CAD); cs_CAD = (Cursor)NULL; } // This is the callback for the Draw togglebutton // void Draw_CAD_Objects_mode( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { draw_CAD_objects_flag = 1; // Create the "pencil" cursor so we know what mode we're in. // if(!cs_CAD) { cs_CAD=XCreateFontCursor(XtDisplay(da),XC_pencil); atexit(free_cs_CAD); } // enable the close polygon button on an open CAD menu if (CAD_close_polygon_menu_item) { XtSetSensitive(CAD_close_polygon_menu_item,TRUE); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_CAD); (void)XFlush(XtDisplay(da)); draw_CAD_objects_flag = 1; polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position } else { draw_CAD_objects_flag = 0; polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position Save_CAD_Objects_to_file(); // Remove the special "pencil" cursor. (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); // disable the close polygon button on an open CAD menu. if (CAD_close_polygon_menu_item) { XtSetSensitive(CAD_close_polygon_menu_item,FALSE); } } } // Called when we complete a new CAD object. Save the object to // disk so that we can recover in the case of a crash or power // failure. Save any old file to a backup file. Perhaps write them // to numbered backup files so that we keep several on-hand? // void Save_CAD_Objects_to_file(void) { FILE *f; char *file; CADRow *object_ptr = CAD_list_head; char temp_file_path[MAX_VALUE]; fprintf(stderr,"Saving CAD objects to file\n"); // Save in ~/.xastir/config/CAD_object.log file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path)); f = fopen(file,"w+"); if (f == NULL) { fprintf(stderr, "Couldn't open config/CAD_object.log file for writing!\n"); return; } while (object_ptr != NULL) { VerticeRow *vertice = object_ptr->start; // Write out the main object info: fprintf(f,"\nCAD_Object\n"); fprintf(f,"creation_time: %lu\n",(unsigned long)object_ptr->creation_time); fprintf(f,"line_color: %d\n",object_ptr->line_color); fprintf(f,"line_type: %d\n",object_ptr->line_type); fprintf(f,"line_width: %d\n",object_ptr->line_width); fprintf(f,"computed_area: %f\n",object_ptr->computed_area); fprintf(f,"raw_probability: %f\n",CAD_object_get_raw_probability(object_ptr,TRUE)); fprintf(f,"label_latitude: %lu\n",object_ptr->label_latitude); fprintf(f,"label_longitude: %lu\n",object_ptr->label_longitude); fprintf(f,"label: %s\n",object_ptr->label); if (strlen(object_ptr->comment)>1) { fprintf(f,"comment: %s\n",object_ptr->comment); } else { fprintf(f,"comment: NULL\n"); } // Iterate through the vertices: while (vertice != NULL) { fprintf(f,"Vertice: %lu %lu\n", vertice->latitude, vertice->longitude); vertice = vertice->next; } object_ptr = object_ptr->next; } (void)fclose(f); } // Called by main() when we start Xastir. Restores CAD objects // created in earlier Xastir sessions. // void Restore_CAD_Objects_from_file(void) { FILE *f; char *file; char line[MAX_FILENAME]; char temp_file_path[MAX_VALUE]; #ifdef CAD_DEBUG fprintf(stderr,"Restoring CAD objects from file\n"); #endif // Restore from ~/.xastir/config/CAD_object.log file = get_user_base_dir("config/CAD_object.log", temp_file_path, sizeof(temp_file_path)); f = fopen(file,"r"); if (f == NULL) { #ifdef CAD_DEBUG fprintf(stderr, "Couldn't open config/CAD_object.log file for reading!\n"); #endif return; } while (!feof (f)) { (void)get_line(f, line, MAX_FILENAME); if (strncasecmp(line,"CAD_Object",10) == 0) { // Found a new CAD Object declaration! //fprintf(stderr,"Found CAD_Object\n"); // Malloc a new object, add it to the linked list, start // filling in the fields. // // This gives us a default object with one vertice. We // can replace all of the fields in it as we parse them. CAD_object_allocate(0l, 0l); // Remove the one vertice from the newly allocated // object so that we don't end up with one too many // vertices when all done. CAD_vertice_delete_all(CAD_list_head->start); CAD_list_head->start = NULL; } else if (strncasecmp(line,"creation_time:",14) == 0) { //fprintf(stderr,"Found creation_time:\n"); unsigned long temp_time; if (1 != sscanf(line+15, "%lu",&temp_time)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [creation_time]\n"); } CAD_list_head->creation_time=(time_t)temp_time; } else if (strncasecmp(line,"line_color:",11) == 0) { //fprintf(stderr,"Found line_color:\n"); if (1 != sscanf(line+12,"%d", &CAD_list_head->line_color)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_color]\n"); } } else if (strncasecmp(line,"line_type:",10) == 0) { //fprintf(stderr,"Found line_type:\n"); if (1 != sscanf(line+11,"%d", &CAD_list_head->line_type)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_type]\n"); } } else if (strncasecmp(line,"line_width:",11) == 0) { //fprintf(stderr,"Found line_width:\n"); if (1 != sscanf(line+12,"%d", &CAD_list_head->line_width)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [line_width]\n"); } } else if (strncasecmp(line,"computed_area:",14) == 0) { //fprintf(stderr,"Found computed_area:\n"); if (1 != sscanf(line+15,"%f", &CAD_list_head->computed_area)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [computed_area]\n"); } } else if (strncasecmp(line,"raw_probability:",16) == 0) { //fprintf(stderr,"Found raw_probability:\n"); if (1 != sscanf(line+17,"%f", &CAD_list_head->raw_probability)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [raw_probability]\n"); } else { // External storage is as percent, need to make sure that this // fits the expected internal storage format. // Thus take given value and store using method that knows // how to handle percents CAD_object_set_raw_probability(CAD_list_head,CAD_list_head->raw_probability,TRUE); } } else if (strncasecmp(line,"label_latitude:",15) == 0) { //fprintf(stderr,"Found label_latitude:\n"); if (1 != sscanf(line+16,"%lu", (unsigned long *)&CAD_list_head->label_latitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_latitude]\n"); } } else if (strncasecmp(line,"label_longitude:",16) == 0) { //fprintf(stderr,"Found label_longitude:\n"); if (1 != sscanf(line+17,"%lu", (unsigned long *)&CAD_list_head->label_longitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [label_longitude]\n"); } } else if (strncasecmp(line,"label:",6) == 0) { //fprintf(stderr,"Found label:\n"); xastir_snprintf(CAD_list_head->label, sizeof(CAD_list_head->label), "%s", line+7); } else if (strncasecmp(line,"comment:",8) == 0) { //fprintf(stderr,"Found comment:\n"); xastir_snprintf(CAD_list_head->comment, sizeof(CAD_list_head->comment), "%s", line+9); if (strcmp(CAD_list_head->comment,"NULL")==0) { xastir_snprintf(CAD_list_head->comment, sizeof(CAD_list_head->comment), "%c", '\0' ); } } else if (strncasecmp(line,"Vertice:",8) == 0) { long latitude, longitude; //fprintf(stderr,"Found Vertice:\n"); if (2 != sscanf(line+9,"%lu %lu", (unsigned long *)&latitude, (unsigned long *)&longitude)) { fprintf(stderr,"Restore_CAD_Objects_from_file:sscanf parsing error [vertex]\n"); } CAD_vertice_allocate(latitude,longitude); } else { // Else not recognized, do nothing with it! //fprintf(stderr,"Found unrecognized line\n"); } } (void)fclose(f); // Reload symbols/tracks/CAD objects to draw the loaded objects redraw_symbols(da); } // popdown and destroy the cad_erase_dialog. // void Draw_CAD_Objects_erase_dialog_close ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (cad_erase_dialog!=NULL) { // close cad_erase_dialog XtPopdown(cad_erase_dialog); XtDestroyWidget(cad_erase_dialog); cad_erase_dialog = (Widget)NULL; } } // Call back for delete selected button on // Draw_CAD_Objects_erase_dialog. Iterates through the list of // selected CAD objects and deletes them. // void Draw_CAD_Objects_erase_selected ( Widget w, XtPointer clientData, XtPointer callData) { int itemCount; // number of items in list of CAD objects. XmString *listItems; // names of CAD objects on list char *cadName; // the text name of a CAD object Position x; // position on list char *selectedName; // the text name of a selected CAD object CADRow *object_ptr = CAD_list_head; // pointer to the linked list of CAD objects int done = 0; // has a cad object with a name matching the current selection been found // For more than a few objects this loop/save/redraw will need to move // off to a separate thread. XtVaGetValues(list_of_existing_CAD_objects, XmNitemCount,&itemCount, XmNitems,&listItems, NULL); // iterate through list and delete each first object with a name matching // those that are selected on the list. // // *** Note: If names are not unique the results may not be what the user expects. // The first match to a selection will be deleted, not necessarily the selection. // for (x=1; x<=itemCount; x++) { if (done) { break; } if (XmListPosSelected(list_of_existing_CAD_objects,x)) { int no_label = 0; XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName); // Check for our own definition of no label for the CAD // objects, which is "" if (strcmp(selectedName,"") == 0) { no_label++; } object_ptr = CAD_list_head; done = 0; while (object_ptr != NULL && done == 0) { cadName = object_ptr->label; if (strcmp(cadName,selectedName)==0 || ( (cadName == NULL || cadName[0] == '\0') && no_label) ) { // delete CAD object matching the selected name CAD_object_delete(object_ptr); done = 1; } else { object_ptr = object_ptr->next; } } } } Draw_CAD_Objects_erase_dialog_close(w,clientData,callData); // Save the altered list to file. Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects redraw_symbols(da); // Here we update the edit cad objects dialog by getting rid of it and // then re-establishing it if it is active when we start. This will // usually make the dialog move, but it's better than having it be // out-of-date. // if (cad_list_dialog!=NULL) { // Update the Edit CAD Objects list Draw_CAD_Objects_list_dialog_close(w, clientData, callData); Draw_CAD_Objects_list_dialog(w, clientData, callData); } } // Callback for delete CAD objects menu option. Dialog to allow // users to delete all CAD objects or select individual CAD objects // to delete. // void Draw_CAD_Objects_erase_dialog( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget cad_erase_pane, cad_erase_form, cad_erase_label, button_delete_all, button_delete_selected, button_cancel; Arg al[100]; /* Arg List */ unsigned int ac; /* Arg Count */ CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (cad_erase_dialog) { (void)XRaiseWindow(XtDisplay(cad_erase_dialog), XtWindow(cad_erase_dialog)); } else { // Delete CAD Objects cad_erase_dialog = XtVaCreatePopupShell("Delete CAD Objects", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_erase_pane = XtVaCreateWidget("CAD erase Object pane", xmPanedWindowWidgetClass, cad_erase_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); cad_erase_form = XtVaCreateWidget("Cad erase Object form", xmFormWidgetClass, cad_erase_pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // heading: Delete CAD Objects cad_erase_label = XtVaCreateManagedWidget(langcode("CADPUD009"), xmLabelWidgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to handle the special case of no CAD objects ? *** // scrolled pick list to allow selection of current objects /*set args for list */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmEXTENDED_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, cad_erase_label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; list_of_existing_CAD_objects = XmCreateScrolledList(cad_erase_form, "CAD objects for deletion scrolled list", al, ac); // make sure list is empty XmListDeleteAllItems(list_of_existing_CAD_objects); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } // "Delete All" button_delete_all = XtVaCreateManagedWidget(langcode("CADPUD010"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_delete_all, XmNactivateCallback, Draw_CAD_Objects_erase, Draw_CAD_Objects_erase_dialog); // "Delete Selected" button_delete_selected = XtVaCreateManagedWidget(langcode("CADPUD011"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_delete_all, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_delete_selected, XmNactivateCallback, Draw_CAD_Objects_erase_selected, Draw_CAD_Objects_erase_dialog); // "Cancel" button_cancel = XtVaCreateManagedWidget(langcode("CADPUD008"), xmPushButtonGadgetClass, cad_erase_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_delete_selected, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Draw_CAD_Objects_erase_dialog_close, Draw_CAD_Objects_erase_dialog); pos_dialog(cad_erase_dialog); XmInternAtom(XtDisplay(cad_erase_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_erase_form); XtManageChild(list_of_existing_CAD_objects); XtManageChild(cad_erase_pane); XtPopup(cad_erase_dialog,XtGrabNone); } } // popdown and destroy the cad_list_dialog // void Draw_CAD_Objects_list_dialog_close ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (cad_list_dialog!=NULL) { // close cad_list_dialog XtPopdown(cad_list_dialog); XtDestroyWidget(cad_list_dialog); cad_list_dialog = (Widget)NULL; } } // Show details for selected CAD object. Callback for the show/edit // details button on the Draw_CAD_Objects_list dialog. // void Show_selected_CAD_object_details ( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static int sizeof_area_description = 200; int itemCount; // number of items in list of CAD objects. XmString *listItems; // names of CAD objects on list char *cadName; // the text name of a CAD object Position x; // position on list char *selectedName; // the text name of a selected CAD object CADRow *object_ptr = CAD_list_head; // pointer to the linked list of CAD objects int done = 0; // has a cad object with a name matching the current selection been found double area; char area_description[sizeof_area_description]; xastir_snprintf(area_description, sizeof_area_description, "Area"); if (cad_list_dialog!=NULL) { // get the selected object XtVaGetValues(list_of_existing_CAD_objects_edit, XmNitemCount,&itemCount, XmNitems,&listItems, NULL); // iterate through list and find each object with a name // matching one selected on the list. // // *** Note: If names are not unique the results may not be what the user expects. // The first match to a selection will be used, not necessarily the selection. // for (x=1; x<=itemCount; x++) { if (XmListPosSelected(list_of_existing_CAD_objects_edit,x)) { int no_label = 0; XmStringGetLtoR(listItems[(x-1)],XmFONTLIST_DEFAULT_TAG,&selectedName); // Check for our own definition of no label for the CAD // objects, which is "" if (strcmp(selectedName,"") == 0) { no_label++; } object_ptr = CAD_list_head; done = 0; while (object_ptr != NULL && done == 0) { cadName = object_ptr->label; if (strcmp(cadName,selectedName)==0 || ( (cadName == NULL || cadName[0] == '\0') && no_label) ) { // get the area for the CAD object matching the selected name // and format it as a localized string. area = object_ptr->computed_area; Format_area_for_output(&area, area_description,sizeof_area_description); // open the CAD object details dialog for the matching CAD object Set_CAD_object_parameters_dialog(area_description,object_ptr); done = 1; } else { object_ptr = object_ptr->next; } } } } // leave the list dialog open } } // Callback for edit CAD objects menu option. Dialog to allow users // to select individual CAD objects in order to edit their metadata. // void Draw_CAD_Objects_list_dialog( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget cad_list_pane, cad_list_form, cad_list_label, button_list_selected, button_close; Arg al[100]; /* Arg List */ unsigned int ac; /* Arg Count */ CADRow *object_ptr = CAD_list_head; int counter = 1; XmString cb_item; if (cad_list_dialog) { (void)XRaiseWindow(XtDisplay(cad_list_dialog), XtWindow(cad_list_dialog)); } else { // List CAD Objects cad_list_dialog = XtVaCreatePopupShell("List CAD Objects", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); cad_list_pane = XtVaCreateWidget("CAD list Object pane", xmPanedWindowWidgetClass, cad_list_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); cad_list_form = XtVaCreateWidget("Cad list Object form", xmFormWidgetClass, cad_list_pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // heading: CAD Objects cad_list_label = XtVaCreateManagedWidget(langcode("CADPUD006"), xmLabelWidgetClass, cad_list_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to handle the special case of no CAD objects ? *** // scrolled pick list to allow selection of current objects /*set args for list */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, cad_list_label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; //XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; list_of_existing_CAD_objects_edit = XmCreateScrolledList(cad_list_form, "CAD objects for deletion scrolled list", al, ac); // make sure list is empty XmListDeleteAllItems(list_of_existing_CAD_objects_edit); // iterate through list of objects to populate scrolled list while (object_ptr != NULL) { // If no label, use the string "" instead if (object_ptr->label[0] == '\0') { cb_item = XmStringCreateLtoR("", XmFONTLIST_DEFAULT_TAG); } else { cb_item = XmStringCreateLtoR(object_ptr->label, XmFONTLIST_DEFAULT_TAG); } XmListAddItem(list_of_existing_CAD_objects_edit, cb_item, counter); counter++; XmStringFree(cb_item); object_ptr = object_ptr->next; } // "Show/edit details" button_list_selected = XtVaCreateManagedWidget(langcode("CADPUD007"), xmPushButtonGadgetClass, cad_list_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects_edit, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_list_selected, XmNactivateCallback, Show_selected_CAD_object_details, Draw_CAD_Objects_list_dialog); // "Close" button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, cad_list_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, list_of_existing_CAD_objects_edit, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_list_selected, XmNleftOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, Draw_CAD_Objects_list_dialog_close, Draw_CAD_Objects_erase_dialog); pos_dialog(cad_list_dialog); XmInternAtom(XtDisplay(cad_list_dialog),"WM_DELETE_WINDOW", FALSE); XtManageChild(cad_list_form); XtManageChild(list_of_existing_CAD_objects_edit); XtManageChild(cad_list_pane); XtPopup(cad_list_dialog,XtGrabNone); } } // Free the object and vertice lists then do a screen update. // callback from delete all button on cad_erase_dialog. // void Draw_CAD_Objects_erase( Widget w, XtPointer clientData, XtPointer callData) { // if we were called from the cad_erase_dialog, make sure it is closed properly if (cad_erase_dialog) { Draw_CAD_Objects_erase_dialog_close(w,clientData,callData); } CAD_object_delete_all(); polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position // Save the empty list out to file Save_CAD_Objects_to_file(); // Reload symbols/tracks/CAD objects redraw_symbols(da); } // Add an ending vertice that is the same as the starting vertice. // Best not to use the screen coordinates we captured first, as the // user may have zoomed or panned since then. Better to copy the // first vertice that we recorded in our linked list. // // Compute the area of the closed polygon. Write it out to STDERR, // the computed_area field in the Object, and to a dialog that pops // up on the screen. // void Draw_CAD_Objects_close_polygon( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static int sizeof_area_description = 200; VerticeRow *tmp; double area; int n; //char temp_course[20]; char area_description[sizeof_area_description]; xastir_snprintf(area_description, sizeof_area_description, "Area"); // Check whether we're currently working on a polygon. If not, // get out of here. if (polygon_last_x == -1 || polygon_last_y == -1) { // Tell the code that we're starting a new polygon by wiping // out the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position return; } // Find the last vertice in the linked list. That will be the // first vertice we recorded for the object. // Check for at least three vertices. We don't need to check // that the first/last point are equal: We force it below by // copying the first vertice to the last. // n = 0; if (CAD_list_head != NULL) { // Walk the linked list. Stop at the last record. tmp = CAD_list_head->start; if (tmp != NULL) { n++; while (tmp->next != NULL) { tmp = tmp->next; n++; } if (n > 2) { // We have more than a point or a line, therefore // can copy the first point to the last, closing the // polygon. CAD_vertice_allocate(tmp->latitude, tmp->longitude); } } } // Reload symbols/tracks/CAD objects and redraw the polygon redraw_symbols(da); #ifdef CAD_DEBUG fprintf(stderr,"Points in closed polygon: n = %d\n",n); #endif if (n < 3) { // Not enough points to compute an area. // Tell the code that we're starting a new polygon by wiping // out the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position return; } area = CAD_object_compute_area(CAD_list_head); // Save it in the object. Convert nautical square miles to // square kilometers because that's what "Format_area_for_output" // requires. area = area * 3.429903999977917; // Now in km squared //fprintf(stderr,"SQUARE KM: %f\n", area); CAD_list_head->computed_area = area; Format_area_for_output(&area, area_description, sizeof_area_description); #ifdef CAD_DEBUG // Also write the area to stderr fprintf(stderr,"New CAD object %s\n",area_description); #endif // Tell the code that we're starting a new polygon by wiping out // the first position. polygon_last_x = -1; // Invalid position polygon_last_y = -1; // Invalid position CAD_object_set_label_at_centroid(CAD_list_head); // CAD object vertices are ready, needs associated data // obtain label, comment, and probability for this polygon // from user through a dialog. Set_CAD_object_parameters_dialog(area_description,NULL); } // Function called by UpdateTime when doing screen refresh. Draws // all CAD objects onto the screen again. // void Draw_All_CAD_Objects(Widget w) { CADRow *object_ptr = CAD_list_head; long x_long, y_lat; long x_offset, y_offset; float probability; char probability_string[8]; VerticeRow *vertice; double area; int actual_line_type = LineOnOffDash; static int sizeof_area_description = 50; // define here as local static to limit size of display on map // independent of size as shown on form char area_description[sizeof_area_description]; char dash[2]; // Start at CAD_list_head, iterate through entire linked list, // drawing as we go. Respect the line // width/line_color/line_type variables for each object. //fprintf(stderr,"Drawing CAD objects\n"); if (CAD_draw_objects==TRUE) { while (object_ptr != NULL) { probability = CAD_object_get_raw_probability(object_ptr,1); xastir_snprintf(probability_string, sizeof(probability_string), "%01.1f%%", probability); // find point at which to draw label and other descriptive text x_long = object_ptr->label_longitude; y_lat = object_ptr->label_latitude; #ifdef CAD_DEBUG fprintf(stderr,"Drawing object %s\n", (object_ptr->label) ? object_ptr->label : "NULL" ); #endif //fprintf(stderr,"Lat: %d\n", y_lat); //fprintf(stderr,"Long: %d\n", x_long); // if ((x_long+10>=0) && (x_long-10<=129600000l)) { // 360 deg // if ((y_lat+10>=0) && (y_lat-10<=64800000l)) { // 180 deg if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_latlabel)>0) & (CAD_show_label==TRUE)) { // Draw Label // 0x08 is background color // 0x40 is foreground color (yellow) draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->label,0x08,0x40,strlen(object_ptr->label)); x_offset=x_offset+12; y_offset=y_offset+15; } if (CAD_show_raw_probability==TRUE) { // draw probability draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,probability_string,0x08,0x40,strlen(probability_string)); y_offset=y_offset+15; } if ((CAD_show_comment==TRUE) & ((int)strlen(object_ptr->comment)>0)) { // draw comment draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,object_ptr->comment,0x08,0x40,strlen(object_ptr->comment)); y_offset=y_offset+15; } if (CAD_show_area==TRUE) { area = object_ptr->computed_area; Format_area_for_output(&area, area_description, sizeof_area_description); draw_nice_string(w,pixmap_final,letter_style,x_offset,y_offset,area_description,0x08,0x40,strlen(area_description)); y_offset=y_offset+15; } } } // } // } // Iterate through the vertices and draw the lines vertice = object_ptr->start; switch (object_ptr->line_type) { case 1: actual_line_type = LineSolid; break; case 2: actual_line_type = LineOnOffDash; dash[0] = dash[1] = 8; break; case 3: actual_line_type = LineDoubleDash; dash[0] = dash[1] = 16; break; default: actual_line_type = LineOnOffDash; dash[0] = dash[1] = 8; break; } // Set up line color/width/type here (void)XSetLineAttributes (XtDisplay (da), gc_tint, object_ptr->line_width, actual_line_type, CapButt, JoinMiter); if (object_ptr->line_type != 1) { (void)XSetDashes (XtDisplay (da), gc_tint, 0, // dash offset dash, // dash list[] 2); // elements in dash lista } (void)XSetForeground (XtDisplay (da), gc_tint, object_ptr->line_color); (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); while (vertice != NULL) { if (vertice->next != NULL) { // Use the draw_vector function from maps.c draw_vector(w, vertice->longitude, vertice->latitude, vertice->next->longitude, vertice->next->latitude, gc_tint, pixmap_final, 0); } vertice = vertice->next; } object_ptr = object_ptr->next; } } } // Formats an area as a string in english (square miles) or metric units // (square kilometers). Switches to square feet or square meters if the // area is less than 0.1 of the units. // // Parameters: // area: an area in square kilometers. // area_description: area reformatted as a localized text string. // sizeof_area_description: array length of area_description. // void Format_area_for_output(double *area_km2, char *area_description, int sizeof_area_description) { double area; // Format it for output and dump it out. We're using square terms, so // apply the conversion factor twice to convert from square kilometers // to the units of interest. The result here is squared meters or // squared feet. //fprintf(stderr,"Square km: %f\n", *area_km2); area = *area_km2 * 1000.0 * 1000.0 * cvt_m2len * cvt_m2len; // We could be measuring a very small or a very large object. // In the case of very small, convert it to square feet or // square meters. if (english_units) // Square feet { //fprintf(stderr,"Square feet: %f\n", area); if (area < 2787840.0) // Switch at 0.5 miles squared { // Smaller area: Output in feet squared xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA053") ); // ft //popup_message_always(langcode("POPUPMA020"),area_description); } else { // Larger area: Output in miles squared area = area / 27878400.0; xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA055") ); // mi //popup_message_always(langcode("POPUPMA020"),area_description); } } else // Square meters { //fprintf(stderr,"Square meters: %f\n", area); if (area < 100000.0) // Switch at 0.1 km squared { // Smaller area: Output in meters squared xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("POPUPMA054") ); // meters //popup_message_always(langcode("POPUPMA020"),area_description); } else { // Larger ara: Output in kilometers squared area = area / 1000000.0; xastir_snprintf(area_description, sizeof_area_description, "A:%0.2f %s %s", area, langcode("POPUPMA052"), // sq langcode("UNIOP00005") ); // km //popup_message_always(langcode("POPUPMA020"),area_description); } } } Xastir-Release-2.2.4/src/cad_objects.h0000664000175000017500000000361615151324131016527 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_CAD_OBJECTS_H #define XASTIR_CAD_OBJECTS_H extern void Draw_All_CAD_Objects(Widget w); extern void Draw_CAD_Objects_erase_dialog(Widget w, XtPointer clientData, XtPointer callData); extern void Draw_CAD_Objects_list_dialog(Widget w, XtPointer clientData, XtPointer callData); extern int draw_CAD_objects_flag; extern int polygon_last_x; extern int polygon_last_y; extern int CAD_draw_objects; extern int CAD_show_label; extern int CAD_show_raw_probability; extern int CAD_show_comment; extern int CAD_show_area; extern void Draw_CAD_Objects_mode( Widget widget, XtPointer clientData, XtPointer callData); extern void Draw_CAD_Objects_close_polygon(Widget w, XtPointer clientData, XtPointer calldata); extern void Draw_CAD_Objects_erase(Widget w, XtPointer clientData, XtPointer calldata); extern void CAD_vertice_allocate(long latitude, long longitude); extern void CAD_object_allocate(long latitude, long longitude); extern void Restore_CAD_Objects_from_file(void); #endif Xastir-Release-2.2.4/src/color.c0000664000175000017500000002245215151324131015377 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include "xastir.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" static color_load color_choice[MAX_COLORS]; static int colors_loaded; static int rm, gm, bm; // rgb masks static int rs, gs, bs; // rgb shifts int visual_depth; /**********************************************************************************/ /* load color file */ /* load the colors to be used with Xastir */ /* Return 1 if good 0 if not found or error */ /**********************************************************************************/ int load_color_file(void) { FILE *f; char temp[40]; int r,g,b; char colorname[50]; int ok,x; xastir_snprintf(temp, sizeof(temp), "config/xastir.rgb"); colors_loaded=0; ok=1; f=fopen(get_data_base_dir(temp),"r"); if (f!=NULL) { while (!feof(f) && ok) { if (fscanf(f,"%d %d %d %49s",&r,&g,&b,colorname)==4) { if (colors_loaded < MAX_COLORS) { for (x=0; x= 0) { // XFreeColors() here generates an error. Why? // "BadAccess (attempt to access private resource denied)" // XFreeColors(dpy, cmap, &(color_choice[found].color.pixel),1,0); if (XAllocColor(dpy,cmap,&color_choice[found].color)) { return(color_choice[found].color.pixel); } else { xastir_snprintf(warning, sizeof(warning), "Couldn't allocate color %s", colorname); XtWarning(warning); return(BlackPixel(dpy,scr)); } } else { xastir_snprintf(warning, sizeof(warning), "Couldn't find color %s", colorname); XtWarning(warning); return(BlackPixel(dpy,scr)); } } void setup_visual_info(Display* dpy, int scr) { int visuals_matched, i, j; XVisualInfo *visual_list, *vp; XVisualInfo visual_template; rm = gm = bm = rs = gs = bs = 0; visual_list = XGetVisualInfo(dpy, VisualNoMask, &visual_template, &visuals_matched); if (visuals_matched) { if (debug_level & 16) { fprintf(stderr,"Found %d visuals\n", visuals_matched); } for (i = 0; i < visuals_matched; i++) { vp = &visual_list[i]; if (vp->visualid == XVisualIDFromVisual(DefaultVisual(dpy, scr))) { if (vp->class == TrueColor || vp->class == DirectColor) { if (vp->red_mask == 0xf800 && vp->green_mask == 0x07e0 && vp->blue_mask == 0x001f) { visual_type = RGB_565; } else if (vp->red_mask == 0x7c00 && vp->green_mask == 0x03e0 && vp->blue_mask == 0x001f) { visual_type = RGB_555; } else if (vp->red_mask == 0xff0000 && vp->green_mask == 0x00ff00 && vp->blue_mask == 0x0000ff) { visual_type = RGB_888; } else { rm = vp->red_mask; gm = vp->green_mask; bm = vp->blue_mask; for (j = 31; j >= 0; j--) { if (rm >= (1 << j)) { rs = j - 15; break; } } for (j = 31; j >= 0; j--) { if (gm >= (1 << j)) { gs = j - 15; break; } } for (j = 31; j >= 0; j--) { if (bm >= (1 << j)) { bs = j - 15; break; } } visual_type = RGB_OTHER; } } else { visual_type = NOT_TRUE_NOR_DIRECT; } if (debug_level & 16) { fprintf(stderr,"\tID: 0x%lx, Default\n", vp->visualid); } } else if (debug_level & 16) { fprintf(stderr,"\tID: 0x%lx\n", vp->visualid); } // Store color depth for use by other routines. visual_depth = vp->depth; if (debug_level & 16) { fprintf(stderr,"\tScreen: %d\n", vp->screen); fprintf(stderr,"\tDepth: %d\n", vp->depth); fprintf(stderr,"\tClass: %d", vp->class); switch (vp->class) { case StaticGray: fprintf(stderr,", StaticGray\n"); break; case GrayScale: fprintf(stderr,", GrayScale\n"); break; case StaticColor: fprintf(stderr,", StaticColor\n"); break; case PseudoColor: fprintf(stderr,", PseudoColor\n"); break; case TrueColor: fprintf(stderr,", TrueColor\n"); break; case DirectColor: fprintf(stderr,", DirectColor\n"); break; default: fprintf(stderr,", ??\n"); break; } fprintf(stderr,"\tClrmap Size: %d\n", vp->colormap_size); fprintf(stderr,"\tBits per RGB: %d\n", vp->bits_per_rgb); fprintf(stderr,"\tRed Mask: 0x%lx\n", vp->red_mask); fprintf(stderr,"\tGreen Mask: 0x%lx\n", vp->green_mask); fprintf(stderr,"\tBlue Mask: 0x%lx\n\n", vp->blue_mask); } } } XFree(visual_list); } void pack_pixel_bits(unsigned short r, unsigned short g, unsigned short b, unsigned long* pixel) { switch (visual_type) { case RGB_565: *pixel = (( r & 0xf800) | ((g >> 5) & 0x07e0) | (b >> 11)); break; case RGB_555: *pixel = (((r >> 1) & 0x7c00) | ((g >> 6) & 0x03e0) | (b >> 11)); break; case RGB_888: *pixel = (((r << 8) & 0xff0000) | ( g & 0x00ff00) | (b >> 8)); break; case RGB_OTHER: if (rs >= 0) { *pixel = ((r << rs) & rm); } else { *pixel = ((r >> (-rs)) & rm); } if (gs >= 0) { *pixel |= ((g << gs) & gm); } else { *pixel |= ((g >> (-gs)) & gm); } if (bs >= 0) { *pixel |= ((b << bs) & bm); } else { *pixel |= ((b >> (-bs)) & bm); } break; case NOT_TRUE_NOR_DIRECT: default: break; } } Xastir-Release-2.2.4/src/color.h0000664000175000017500000000305015151324131015375 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_COLOR_H #define XASTIR_COLOR_H #define MAX_COLORS 256 #define MAX_COLORNAME 40 typedef struct { char colorname[MAX_COLORNAME]; XColor color; } color_load; typedef enum { NOT_TRUE_NOR_DIRECT, RGB_565, RGB_555, RGB_888, RGB_OTHER } Pixel_Format; extern Pixel_Format visual_type; extern int visual_depth; /* from color.c */ extern int load_color_file(void); extern Pixel GetPixelByName(Widget w, char *colorname); extern void setup_visual_info(Display* dpy, int scr); extern void pack_pixel_bits(unsigned short r, unsigned short g, unsigned short b, unsigned long* pixel); #endif /* XASTIR_COLOR_H */ Xastir-Release-2.2.4/src/database.h0000664000175000017500000004263015151324131016032 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Note: this file should be called db.h, but was renamed to database.h * to avoid conflicts with the Berkeley DB package. */ /* * Database structures * */ #ifndef XASTIR_DATABASE_H #define XASTIR_DATABASE_H #include #include "globals.h" #define MSG_INCREMENT 200 #define MAX_TACTICAL_CALL 57 // Up to XX chars for tactical calls #define MAX_COMMENT_LINES 20 // Save XX unique comment strings per station #define MAX_STATUS_LINES 20 // Save XX unique status strings per station /* define max size of info field */ #define MAX_INFO_FIELD_SIZE 256 // Number of times to send killed objects/items before ceasing to // transmit them. #define MAX_KILLED_OBJECT_RETRANSMIT 20 // Check entire station list at this rate for objects/items that // might need to be transmitted via the decaying algorithm. This is // the start rate, which gets doubled on each transmit. #define OBJECT_CHECK_RATE 20 // We should probably be using APRS_DF in extract_bearing_NRQ() // and extract_omnidf() functions. We aren't currently. /* Define APRS Types */ enum APRS_Types { APRS_NULL, APRS_MSGCAP, APRS_FIXED, APRS_DOWN, // Not used anymore APRS_MOBILE, APRS_DF, APRS_OBJECT, APRS_ITEM, APRS_STATUS, APRS_WX1, APRS_WX2, APRS_WX3, APRS_WX4, APRS_WX5, APRS_WX6, QM_WX, PEET_COMPLETE, RSWX200, GPS_RMC, GPS_GGA, GPS_GLL, STATION_CALL_DATA, OTHER_DATA, APRS_MICE, APRS_GRID, DALLAS_ONE_WIRE, DAVISMETEO, DAVISAPRSDL }; /* Define Record Types */ #define NORMAL_APRS 'N' #define MOBILE_APRS 'M' #define DF_APRS 'D' #define DOWN_APRS 'Q' #define NORMAL_GPS_RMC 'C' #define NORMAL_GPS_GGA 'A' #define NORMAL_GPS_GLL 'L' #define APRS_WX1 '1' #define APRS_WX2 '2' #define APRS_WX3 '3' #define APRS_WX4 '4' #define APRS_WX5 '5' #define APRS_WX6 '6' /* define RECORD ACTIVES */ #define RECORD_ACTIVE 'A' #define RECORD_NOTACTIVE 'N' #define RECORD_CLOSED 'C' /* define data from info type */ #define DATA_VIA_LOCAL 'L' #define DATA_VIA_TNC 'T' #define DATA_VIA_NET 'I' #define DATA_VIA_FILE 'F' #define DATA_VIA_DATABASE 'D' /* define Heard info type */ #define VIA_TNC 'Y' #define NOT_VIA_TNC 'N' /* define Message types */ #define MESSAGE_MESSAGE 'M' #define MESSAGE_BULLETIN 'B' #define MESSAGE_NWS 'W' // Define file info, string length are without trailing '\0' #define MAX_TIME 20 #define MAX_ALTITUDE 10 //-32808.4 to 300000.0? feet #define MAX_SPEED 9 /* ?? 3 in knots */ #define MAX_COURSE 7 /* ?? */ #define MAX_POWERGAIN 7 #define MAX_STATION_TIME 10 /* 6+1 */ #define MAX_SAT 4 #define MAX_DISTANCE 10 #define MAX_WXSTATION 50 #define MAX_TEMP 100 #define MAX_MESSAGE_LENGTH 100 #define MAX_MESSAGE_ORDER 10 // track export file formats #define EXPORT_XASTIR_TRACK 0 #define EXPORT_KML_TRACK 1 // Used for messages and bulletins typedef struct { char active; char data_via; char type; char heard_via_tnc; time_t sec_heard; time_t last_ack_sent; char packet_time[MAX_TIME]; char call_sign[MAX_CALLSIGN+1]; char from_call_sign[MAX_CALLSIGN+1]; char message_line[MAX_MESSAGE_LENGTH+1]; char seq[MAX_MESSAGE_ORDER+1]; char acked; char position_known; time_t interval; int tries; } Message; // Struct used to create linked list of most recent ack's typedef struct _ack_record { char callsign[MAX_CALLSIGN+1]; char ack[5+1]; struct _ack_record *next; } ack_record; #ifdef MSG_DEBUG extern void msg_clear_data(Message *clear); extern void msg_copy_data(Message *to, Message *from); #else // MSG_DEBUG #define msg_clear_data(clear) memset((Message *)clear, 0, sizeof(Message)) #define msg_copy_data(to, from) memmove((Message *)to, (Message *)from, \ sizeof(Message)) #endif /* MSG_DEBUG */ enum AreaObjectTypes { AREA_OPEN_CIRCLE = 0x0, AREA_LINE_LEFT = 0x1, AREA_OPEN_ELLIPSE = 0x2, AREA_OPEN_TRIANGLE = 0x3, AREA_OPEN_BOX = 0x4, AREA_FILLED_CIRCLE = 0x5, AREA_LINE_RIGHT = 0x6, AREA_FILLED_ELLIPSE = 0x7, AREA_FILLED_TRIANGLE = 0x8, AREA_FILLED_BOX = 0x9, AREA_MAX = 0x9, AREA_NONE = 0xF }; enum AreaObjectColors { AREA_BLACK_HI = 0x0, AREA_BLUE_HI = 0x1, AREA_GREEN_HI = 0x2, AREA_CYAN_HI = 0x3, AREA_RED_HI = 0x4, AREA_VIOLET_HI = 0x5, AREA_YELLOW_HI = 0x6, AREA_GRAY_HI = 0x7, AREA_BLACK_LO = 0x8, AREA_BLUE_LO = 0x9, AREA_GREEN_LO = 0xA, AREA_CYAN_LO = 0xB, AREA_RED_LO = 0xC, AREA_VIOLET_LO = 0xD, AREA_YELLOW_LO = 0xE, AREA_GRAY_LO = 0xF }; typedef struct { unsigned type : 4; unsigned color : 4; unsigned sqrt_lat_off : 8; unsigned sqrt_lon_off : 8; unsigned corridor_width : 16; } AreaObject; typedef struct { char aprs_type; char aprs_symbol; char special_overlay; AreaObject area_object; } APRS_Symbol; // Struct for holding current weather data. // This struct is pointed to by the DataRow structure. // An empty string indicates undefined data. typedef struct // strlen { time_t wx_sec_time; int wx_storm; // Set to one if severe storm char wx_time[MAX_TIME]; char wx_course[4]; // in ° 3 char wx_speed[4]; // in mph 3 time_t wx_speed_sec_time; char wx_gust[4]; // in mph 3 char wx_hurricane_radius[4]; //nautical miles 3 char wx_trop_storm_radius[4]; //nautical miles 3 char wx_whole_gale_radius[4]; // nautical miles 3 char wx_temp[5]; // in °F 3 char wx_rain[10]; // in hundredths inch/h 3 char wx_rain_total[10]; // in hundredths inch char wx_snow[6]; // in inches/24h 3 char wx_prec_24[10]; // in hundredths inch/day 3 char wx_prec_00[10]; // in hundredths inch 3 char wx_hum[5]; // in % 3 char wx_baro[10]; // in hPa 6 char wx_fuel_temp[5]; // in °F 3 char wx_fuel_moisture[5];// in % 2 char wx_type; char wx_station[MAX_WXSTATION]; int wx_compute_rain_rates; // Some stations provide rain rates // directly, others require Xastir to // compute from total rain. Flag this, // so we don't clobber useful info from // a station. } WeatherRow; // Struct for holding track data. Keeps a dynamically allocated // doubly-linked list of track points. The first record should have its // "prev" pointer set to NULL and the last record should have its "next" // pointer set to NULL. If no track storage exists then the pointers to // these structs in the DataRow struct should be NULL. typedef struct _TrackRow { long trail_long_pos; // coordinate of trail point long trail_lat_pos; // coordinate of trail point time_t sec; // date/time of position long speed; // in 0.1 km/h undefined: -1 int course; // in degrees undefined: -1 long altitude; // in 0.1 m undefined: -99999 char flag; // several flags, see below struct _TrackRow *prev; // pointer to previous record in list struct _TrackRow *next; // pointer to next record in list } TrackRow; // trail flag definitions #define TR_LOCAL 0x01 // heard direct (not via digis) #define TR_NEWTRK 0x02 // start new track // Struct for holding comment/status data. Will keep a dynamically // allocated list of text. Every different comment field will be // stored in a separate line. typedef struct _CommentRow { char *text_ptr; // Ptr to the comment text time_t sec_heard; // Latest timestamp for this comment/status struct _CommentRow *next; // Ptr to next record or NULL } CommentRow; #define MAX_MULTIPOINTS 35 // Struct for holding multipoint data. typedef struct _MultipointRow { long multipoints[MAX_MULTIPOINTS][2]; } MultipointRow; // Break DataRow into several structures. DataRow will contain the // parameters that are common across all types of stations. DataRow // will contain a pointer to TrackRow if it is a moving station, and // contain a pointer to WeatherRow if it is a weather station. If no // weather or track data existed, the pointers will be NULL. This new // way of storing station data will save a LOT of memory. If a // station suddenly starts moving or spitting out weather data the new // structures will be allocated, filled in, and pointers to them // installed in DataRow. // // Station storage now is organized as an ordered linked list. We have // both sorting by name and by time last heard // // todo: check the string length! // typedef struct _DataRow { struct _DataRow *n_next; // pointer to next element in name ordered list struct _DataRow *n_prev; // pointer to previous element in name ordered // list struct _DataRow *t_newer; // pointer to next element in time ordered // list (newer) struct _DataRow *t_older; // pointer to previous element in time ordered // list (older) char call_sign[MAX_CALLSIGN+1]; // call sign or name index or object/item // name char *tactical_call_sign; // Tactical callsign. NULL if not assigned APRS_Symbol aprs_symbol; long coord_lon; // Xastir coordinates 1/100 sec, 0 = 180°W long coord_lat; // Xastir coordinates 1/100 sec, 0 = 90°N int time_sn; // serial number for making time index unique time_t sec_heard; // time last heard, used also for time index time_t heard_via_tnc_last_time; time_t direct_heard; // KC2ELS - time last heard direct // Change into time_t structs? It'd save us a bunch of space. char packet_time[MAX_TIME]; char pos_time[MAX_TIME]; // char altitude_time[MAX_TIME]; // char speed_time[MAX_TIME]; // char station_time[MAX_STATION_TIME]; // char station_time_type; short flag; // several flags, see below char pos_amb; // Position ambiguity, 0 = none, // 1 = 0.1 minute... unsigned int error_ellipse_radius; // Degrades precision for this // station, from 0 to 65535 cm or // 655.35 meters. Assigned when we // decode each type of packet. // Default is 6.0 meters (600 cm) // unless we know the GPS position // is augmented, or is degraded by // less precision in the packet. unsigned int lat_precision; // In 100ths of a second latitude unsigned int lon_precision; // In 100ths of a second longitude int trail_color; // trail color (when assigned) char record_type; char data_via; // L local, T TNC, I internet, F file // Change to char's to save space? int heard_via_tnc_port; int last_port_heard; unsigned int num_packets; char *node_path_ptr; // Pointer to path string char altitude[MAX_ALTITUDE]; // in meters (feet gives better resolution ??) char speed[MAX_SPEED+1]; // in knots (same as nautical miles/hour) char course[MAX_COURSE+1]; char bearing[MAX_COURSE+1]; char NRQ[MAX_COURSE+1]; char power_gain[MAX_POWERGAIN+1]; // Holds the phgd values char signal_gain[MAX_POWERGAIN+1]; // Holds the shgd values (for DF'ing) WeatherRow *weather_data; // Pointer to weather data or NULL CommentRow *status_data; // Ptr to status records or NULL CommentRow *comment_data; // Ptr to comment records or NULL // Below two pointers are NULL if only one position has been received TrackRow *oldest_trackpoint; // Pointer to oldest track point in // doubly-linked list TrackRow *newest_trackpoint; // Pointer to newest track point in // doubly-linked list // When the station is an object, it can include coordinates // of related points. Currently these are being used to draw // outlines of NWS severe weather watches and warnings, and // storm regions. The coordinates are stored here in Xastir // coordinate form. Element [x][0] is the latitude, and // element [x][1] is the longitude. --KG4NBB // // Is there anything preventing a multipoint string from being // in other types of packets, in the comment field? --WE7U // int num_multipoints; char type; // from '0' to '9' char style; // from 'a' to 'z' MultipointRow *multipoint_data; /////////////////////////////////////////////////////////////////////// // Optional stuff for Objects/Items only (I think, needs to be // checked). These could be moved into an ObjectRow structure, with // only a NULL pointer here if not an object/item. /////////////////////////////////////////////////////////////////////// char origin[MAX_CALLSIGN+1]; // call sign originating an object short object_retransmit; // Number of times to retransmit object. // -1 = forever // Used currently to stop sending killed // objects. time_t last_transmit_time; // Time we last transmitted an object/item. // Used to implement decaying transmit time // algorithm short transmit_time_increment; // Seconds to add to transmit next time // around. Used to implement decaying // transmit time algorithm // time_t last_modified_time; // Seconds since the object/item // was last modified. We'll // eventually use this for // dead-reckoning. char signpost[5+1]; // Holds signpost data int df_color; char sats_visible[MAX_SAT]; char probability_min[10+1]; // Holds prob_min (miles) char probability_max[10+1]; // Holds prob_max (miles) } DataRow; // Used to store one vertice in CADRow object typedef struct _VerticeRow { long latitude; // Xastir coordinates 1/100sec, 0 = 180W long longitude; // Xastir coordinates 1/100sec, 0 = 90N struct _VerticeRow *next; // Pointer to next record in list } VerticeRow; #define CAD_LABEL_MAX_SIZE 40 #define CAD_COMMENT_MAX_SIZE 256 // CAD Objects typedef struct _CADRow { struct _CADRow *next; // Pointer to next element in list time_t creation_time; // Time at which object was first created VerticeRow *start; // Pointer to first VerticeRow int line_color; // Border color int line_type; // Border linetype int line_width; // Border line width float computed_area; // Area in square kilometers float raw_probability; // Probability of area (POA) or probability of // detection (POD) stored as probability // with a value between 0 and 1. // Set and get with CAD_object_get_raw_probability() // and CAD_object_set_raw_probability(), rather // than by a direct request for CADRow->raw_probability. long label_latitude; // Latitude for label placement long label_longitude; // Longitude for label placement char label[CAD_LABEL_MAX_SIZE]; // Name of polygon char comment[CAD_COMMENT_MAX_SIZE]; // Comments associated with polygon } CADRow; // station flag definitions. We have 16 bits available here as // "flag" in "DataRow" is defined as a short. // #define ST_OBJECT 0x01 // station is an object #define ST_ITEM 0x02 // station is an item #define ST_ACTIVE 0x04 // station is active (deleted objects are // inactive) #define ST_MOVING 0x08 // station is moving #define ST_DIRECT 0x10 // heard direct (not via digis) #define ST_VIATNC 0x20 // station heard via TNC #define ST_3RD_PT 0x40 // third party traffic #define ST_MSGCAP 0x80 // message capable (not used yet) #define ST_STATUS 0x100 // got real status message #define ST_INVIEW 0x200 // station is in current screen view #define ST_MYSTATION 0x400 // station is owned by my call-SSID #define ST_MYOBJITEM 0x800 // object/item owned by me // just used for aloha calcs typedef struct { double distance; char call_sign[MAX_CALLSIGN+1]; // call sign or name index or object/item // name char is_mobile; char is_other_mobile; char is_wx; char is_digi; // can only tell this if using a digi icon! char is_home; // stationary stations that are not digis } aloha_entry; typedef struct { int digis; int wxs; int other_mobiles; int mobiles_in_motion; int homes; int total; } aloha_stats; #ifdef HAVE_DB extern int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time, char *timeformat); #endif /* HAVE_DB */ #endif /* XASTIR_DATABASE_H */ Xastir-Release-2.2.4/src/datum.c0000664000175000017500000013456015151324131015377 0ustar hibbyhibby/* See the top of datum.h for information on this code. N7TAP Portions Copyright (C) 2000-2026 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include "xastir.h" #include "datum.h" #include "main.h" #include "util.h" // Must be last include file #include "leak_detection.h" // ellipsoid: index into the gEllipsoid[] array, in which // a is the ellipsoid semimajor axis // invf is the inverse of the ellipsoid flattening f // dx, dy, dz: ellipsoid center with respect to WGS84 ellipsoid center // x axis is the prime meridian // y axis is 90 degrees east longitude // z axis is the axis of rotation of the ellipsoid // The following values for dx, dy and dz were extracted from the output of // the GARMIN PCX5 program. The output also includes values for da and df, the // difference between the reference ellipsoid and the WGS84 ellipsoid semi- // major axis and flattening, respectively. These are replaced by the // data contained in the structure array gEllipsoid[], which was obtained from // the Defence Mapping Agency document number TR8350.2, "Department of Defense // World Geodetic System 1984." /* The above are the original comments by John Waers. Curt Mills, WE7U wrote a perl version of this code and added more datums from Peter H. Dana's website. Reference Ellipsoids: http://www.Colorado.EDU/geography/gcraft/notes/datum/elist.html Reference Ellipsoids and Datums: http://www.Colorado.EDU/geography/gcraft/notes/datum/edlist.html I've loaded the numbers from that second, newer web page. N7TAP */ /* Keep the enum in datum.h up to date with the order of this array */ const Ellipsoid gEllipsoid[] = { // name a 1/f { "Airy 1830", 6377563.396, 299.3249646 }, { "Modified Airy", 6377340.189, 299.3249646 }, { "Australian National", 6378160.0, 298.25 }, { "Bessel 1841", 6377397.155, 299.1528128 }, { "Bessel 1841 (Namibia)", 6377483.865, 299.1528128 }, { "Clarke 1866", 6378206.4, 294.9786982 }, { "Clarke 1880", 6378249.145, 293.465 }, { "Everest (India 1830)", 6377276.345, 300.8017 }, { "Everest (India 1956)", 6377301.243, 300.8017 }, { "Everest (Sabah Sarawak)", 6377298.556, 300.8017 }, { "Everest (Malaysia 1969)", 6377295.664, 300.8017 }, { "Everest (Malay. & Sing)", 6377304.063, 300.8017 }, { "Everest (Pakistan)", 6377309.613, 300.8017 }, { "Fischer 1960 (Mercury)", 6378166.0, 298.3 }, { "Modified Fischer 1960", 6378155.0, 298.3 }, { "Fischer 1968", 6378150.0, 298.3 }, { "Helmert 1906", 6378200.0, 298.3 }, { "Hough 1960", 6378270.0, 297.0 }, { "Indonesian 1974", 6378160.0, 298.247 }, { "International 1924", 6378388.0, 297.0 }, { "Krassovsky 1940", 6378245.0, 298.3 }, { "GRS 67", 6378160.0, 298.247167427 }, { "GRS 80", 6378137.0, 298.257222101 }, { "South American 1969", 6378160.0, 298.25 }, { "WGS 60", 6378165.0, 298.3 }, { "WGS 66", 6378145.0, 298.25 }, { "WGS 72", 6378135.0, 298.26 }, { "WGS 84", 6378137.0, 298.257223563 } }; /* Keep correct indices to commonly used datums in the enum in datum.h */ /* Feel free to add mnemonic indices for datums that you use */ const Datum gDatum[] = { // name ellipsoid dx dy dz { "Adindan (Burkina Faso)", E_CLARKE_80, -118, -14, 218 }, // 0 { "Adindan (Cameroon)", E_CLARKE_80, -134, -2, 210 }, // 1 { "Adindan (Ethiopia)", E_CLARKE_80, -165, -11, 206 }, // 2 { "Adindan (Mali)", E_CLARKE_80, -123, -20, 220 }, // 3 { "Adindan (MEAN FOR Ethiopia; Sudan)", E_CLARKE_80, -166, -15, 204 }, // 4 { "Adindan (Senegal)", E_CLARKE_80, -128, -18, 224 }, // 5 { "Adindan (Sudan)", E_CLARKE_80, -161, -14, 205 }, // 6 { "Afgooye (Somalia)", E_KRASS_40, -43, -163, 45 }, // 7 { "Ain el Abd 1970 (Bahrain)", E_INT_24, -150, -250, -1 }, // 8 { "Ain el Abd 1970 (Saudi Arabia)", E_INT_24, -143, -236, 7 }, // 9 { "American Samoa 1962 (American Samoa Islands)", E_CLARKE_66, -115, 118, 426 }, // 10 { "Anna 1 Astro 1965 (Cocos Islands)", E_AUS_NAT, -491, -22, 435 }, // 11 { "Antigua Island Astro 1943 (Antigua (Leeward Islands))", E_CLARKE_80, -270, 13, 62 }, // 12 { "Arc 1950 (Botswana)", E_CLARKE_80, -138, -105, -289 }, // 13 { "Arc 1950 (Burundi)", E_CLARKE_80, -153, -5, -292 }, // 14 { "Arc 1950 (Lesotho)", E_CLARKE_80, -125, -108, -295 }, // 15 { "Arc 1950 (Malawi)", E_CLARKE_80, -161, -73, -317 }, // 16 { "Arc 1950 (MEAN FOR Botswana; Lesotho; Malawi; Swaziland; Zaire; Zambia; Zimbabwe)", E_CLARKE_80, -143, -90, -294 }, // 17 { "Arc 1950 (Swaziland)", E_CLARKE_80, -134, -105, -295 }, // 18 { "Arc 1950 (Zaire)", E_CLARKE_80, -169, -19, -278 }, // 19 { "Arc 1950 (Zambia)", E_CLARKE_80, -147, -74, -283 }, // 20 { "Arc 1950 (Zimbabwe)", E_CLARKE_80, -142, -96, -293 }, // 21 { "Arc 1960 (MEAN FOR Kenya; Tanzania)", E_CLARKE_80, -160, -6, -302 }, // 22 { "Arc 1960 (Kenya)", E_CLARKE_80, -157, -2, -299 }, // 23 { "Arc 1960 (Taanzania)", E_CLARKE_80, -175, -23, -303 }, // 24 { "Ascension Island 1958 (Ascension Island)", E_INT_24, -205, 107, 53 }, // 25 { "Astro Beacon E 1945 (Iwo Jima)", E_INT_24, 145, 75, -272 }, // 26 { "Astro DOS 71/4 (St Helena Island)", E_INT_24, -320, 550, -494 }, // 27 { "Astro Tern Island (FRIG) 1961 (Tern Island)", E_INT_24, 114, -116, -333 }, // 28 { "Astronomical Station 1952 (Marcus Island)", E_INT_24, 124, -234, -25 }, // 29 { "Australian Geodetic 1966 (Australia; Tasmania)", E_AUS_NAT, -133, -48, 148 }, // 30 { "Australian Geodetic 1984 (Australia; Tasmania)", E_AUS_NAT, -134, -48, 149 }, // 31 { "Ayabelle Lighthouse (Djibouti)", E_CLARKE_80, -79, -129, 145 }, // 32 { "Bellevue (IGN) (Efate & Erromango Islands)", E_INT_24, -127, -769, 472 }, // 33 { "Bermuda 1957 (Bermuda)", E_CLARKE_66, -73, 213, 296 }, // 34 { "Bissau (Guinea-Bissau)", E_INT_24, -173, 253, 27 }, // 35 { "Bogota Observatory (Colombia)", E_INT_24, 307, 304, -318 }, // 36 { "Bukit Rimpah (Indonesia (Bangka & Belitung Ids))", E_BESS_41, -384, 664, -48 }, // 37 { "Camp Area Astro (Antarctica (McMurdo Camp Area))", E_INT_24, -104, -129, 239 }, // 38 { "Campo Inchauspe (Argentina)", E_INT_24, -148, 136, 90 }, // 39 { "Canton Astro 1966 (Phoenix Islands)", E_INT_24, 298, -304, -375 }, // 40 { "Cape (South Africa)", E_CLARKE_80, -136, -108, -292 }, // 41 { "Cape Canaveral (Bahamas; Florida)", E_CLARKE_66, -2, 151, 181 }, // 42 { "Carthage (Tunisia)", E_CLARKE_80, -263, 6, 431 }, // 43 { "Chatham Island Astro 1971 (New Zealand (Chatham Island))", E_INT_24, 175, -38, 113 }, // 44 { "Chua Astro (Paraguay)", E_INT_24, -134, 229, -29 }, // 45 { "Corrego Alegre (Brazil)", E_INT_24, -206, 172, -6 }, // 46 { "Dabola (Guinea)", E_CLARKE_80, -83, 37, 124 }, // 47 { "Deception Island (Deception Island; Antarctia)", E_CLARKE_80, 260, 12, -147 }, // 48 { "Djakarta (Batavia) (Indonesia (Sumatra))", E_BESS_41, -377, 681, -50 }, // 49 { "DOS 1968 (New Georgia Islands (Gizo Island))", E_INT_24, 230, -199, -752 }, // 50 { "Easter Island 1967 (Easter Island)", E_INT_24, 211, 147, 111 }, // 51 { "Estonia; Coordinate System 1937 (Estonia)", E_BESS_41, 374, 150, 588 }, // 52 { "European 1950 (Cyprus)", E_INT_24, -104, -101, -140 }, // 53 { "European 1950 (Egypt)", E_INT_24, -130, -117, -151 }, // 54 { "European 1950 (England; Channel Islands; Scotland; Shetland Islands)", E_INT_24, -86, -96, -120 }, // 55 { "European 1950 (England; Ireland; Scotland; Shetland Islands)", E_INT_24, -86, -96, -120 }, // 56 { "European 1950 (Finland; Norway)", E_INT_24, -87, -95, -120 }, // 57 { "European 1950 (Greece)", E_INT_24, -84, -95, -130 }, // 58 { "European 1950 (Iran)", E_INT_24, -117, -132, -164 }, // 59 { "European 1950 (Italy (Sardinia))", E_INT_24, -97, -103, -120 }, // 60 { "European 1950 (Italy (Sicily))", E_INT_24, -97, -88, -135 }, // 61 { "European 1950 (Malta)", E_INT_24, -107, -88, -149 }, // 62 { "European 1950 (MEAN FOR Austria; Belgium; Denmark; Finland; France; W Germany; Gibraltar; Greece; Italy; Luxembourg; Netherlands; Norway; Portugal; Spain; Sweden; Switzerland)", E_INT_24, -87, -98, -121 }, // 63 { "European 1950 (MEAN FOR Austria; Denmark; France; W Germany; Netherlands; Switzerland)", E_INT_24, -87, -96, -120 }, // 64 { "European 1950 (MEAN FOR Iraq; Israel; Jordan; Lebanon; Kuwait; Saudi Arabia; Syria)", E_INT_24, -103, -106, -141 }, // 65 { "European 1950 (Portugal; Spain)", E_INT_24, -84, -107, -120 }, // 66 { "European 1950 (Tunisia)", E_INT_24, -112, -77, -145 }, // 67 { "European 1979 (MEAN FOR Austria; Finland; Netherlands; Norway; Spain; Sweden; Switzerland)", E_INT_24, -86, -98, -119 }, // 68 { "Fort Thomas 1955 (Nevis; St. Kitts (Leeward Islands))", E_CLARKE_80, -7, 215, 225 }, // 69 { "Gan 1970 (Republic of Maldives)", E_INT_24, -133, -321, 50 }, // 70 { "Geodetic Datum 1949 (New Zealand)", E_INT_24, 84, -22, 209 }, // 71 { "Graciosa Base SW 1948 (Azores (Faial; Graciosa; Pico; Sao Jorge; Terceira))", E_INT_24, -104, 167, -38 }, // 72 { "Guam 1963 (Guam)", E_CLARKE_66, -100, -248, 259 }, // 73 { "Gunung Segara (Indonesia (Kalimantan))", E_BESS_41, -403, 684, 41 }, // 74 { "GUX 1 Astro (Guadalcanal Island)", E_INT_24, 252, -209, -751 }, // 75 { "Herat North (Afghanistan)", E_INT_24, -333, -222, 114 }, // 76 { "Hermannskogel Datum (Croatia -Serbia, Bosnia-Herzegovina)", E_BESS_41_NAM, 653, -212, 449 }, // 77 { "Hjorsey 1955 (Iceland)", E_INT_24, -73, 46, -86 }, // 78 { "Hong Kong 1963 (Hong Kong)", E_INT_24, -156, -271, -189 }, // 79 { "Hu-Tzu-Shan (Taiwan)", E_INT_24, -637, -549, -203 }, // 80 { "Indian (Bangladesh)", E_EVR_IND_30, 282, 726, 254 }, // 81 { "Indian (India; Nepal)", E_EVR_IND_56, 295, 736, 257 }, // 82 { "Indian (Pakistan)", E_EVR_PAK, 283, 682, 231 }, // 83 { "Indian 1954 (Thailand)", E_EVR_IND_30, 217, 823, 299 }, // 84 { "Indian 1960 (Vietnam (Con Son Island))", E_EVR_IND_30, 182, 915, 344 }, // 85 { "Indian 1960 (Vietnam (Near 16N))", E_EVR_IND_30, 198, 881, 317 }, // 86 { "Indian 1975 (Thailand)", E_EVR_IND_30, 210, 814, 289 }, // 87 { "Indonesian 1974 (Indonesia)", E_IND_74, -24, -15, 5 }, // 88 { "Ireland 1965 (Ireland)", E_MOD_AIRY, 506, -122, 611 }, // 89 { "ISTS 061 Astro 1968 (South Georgia Islands)", E_INT_24, -794, 119, -298 }, // 90 { "ISTS 073 Astro 1969 (Diego Garcia)", E_INT_24, 208, -435, -229 }, // 91 { "Johnston Island 1961 (Johnston Island)", E_INT_24, 189, -79, -202 }, // 92 { "Kandawala (Sri Lanka)", E_EVR_IND_30, -97, 787, 86 }, // 93 { "Kerguelen Island 1949 (Kerguelen Island)", E_INT_24, 145, -187, 103 }, // 94 { "Kertau 1948 (West Malaysia & Singapore)", E_EVR_MAL_SING, -11, 851, 5 }, // 95 { "Kusaie Astro 1951 (Caroline Islands)", E_INT_24, 647, 1777, -1124 }, // 96 { "Korean Geodetic System (South Korea)", E_GRS_80, 0, 0, 0 }, // 97 { "L. C. 5 Astro 1961 (Cayman Brac Island)", E_CLARKE_66, 42, 124, 147 }, // 98 { "Leigon (Ghana)", E_CLARKE_80, -130, 29, 364 }, // 99 { "Liberia 1964 (Liberia)", E_CLARKE_80, -90, 40, 88 }, // 100 { "Luzon (Philippines (Excluding Mindanao))", E_CLARKE_66, -133, -77, -51 }, // 101 { "Luzon (Philippines (Mindanao))", E_CLARKE_66, -133, -79, -72 }, // 102 { "M'Poraloko (Gabon)", E_CLARKE_80, -74, -130, 42 }, // 103 { "Mahe 1971 (Mahe Island)", E_CLARKE_80, 41, -220, -134 }, // 104 { "Massawa (Ethiopia (Eritrea))", E_BESS_41, 639, 405, 60 }, // 105 { "Merchich (Morocco)", E_CLARKE_80, 31, 146, 47 }, // 106 { "Midway Astro 1961 (Midway Islands)", E_INT_24, 912, -58, 1227 }, // 107 { "Minna (Cameroon)", E_CLARKE_80, -81, -84, 115 }, // 108 { "Minna (Nigeria)", E_CLARKE_80, -92, -93, 122 }, // 109 { "Montserrat Island Astro 1958 (Montserrat (Leeward Islands))", E_CLARKE_80, 174, 359, 365 }, // 110 { "Nahrwan (Oman (Masirah Island))", E_CLARKE_80, -247, -148, 369 }, // 111 { "Nahrwan (Saudi Arabia)", E_CLARKE_80, -243, -192, 477 }, // 112 { "Nahrwan (United Arab Emirates)", E_CLARKE_80, -249, -156, 381 }, // 113 { "Naparima BWI (Trinidad & Tobago)", E_INT_24, -10, 375, 165 }, // 114 { "North American 1927 (Alaska (Excluding Aleutian Ids))", E_CLARKE_66, -5, 135, 172 }, // 115 { "North American 1927 (Alaska (Aleutian Ids East of 180W))", E_CLARKE_66, -2, 152, 149 }, // 116 { "North American 1927 (Alaska (Aleutian Ids West of 180W))", E_CLARKE_66, 2, 204, 105 }, // 117 { "North American 1927 (Bahamas (Except San Salvador Id))", E_CLARKE_66, -4, 154, 178 }, // 118 { "North American 1927 (Bahamas (San Salvador Island))", E_CLARKE_66, 1, 140, 165 }, // 119 { "North American 1927 (Canada (Alberta; British Columbia))", E_CLARKE_66, -7, 162, 188 }, // 120 { "North American 1927 (Canada (Manitoba; Ontario))", E_CLARKE_66, -9, 157, 184 }, // 121 { "North American 1927 (Canada (New Brunswick; Newfoundland; Nova Scotia; Quebec))", E_CLARKE_66, -22, 160, 190 }, // 122 { "North American 1927 (Canada (Northwest Territories; Saskatchewan))", E_CLARKE_66, 4, 159, 188 }, // 123 { "North American 1927 (Canada (Yukon))", E_CLARKE_66, -7, 139, 181 }, // 124 { "North American 1927 (Canal Zone)", E_CLARKE_66, 0, 125, 201 }, // 125 { "North American 1927 (Cuba)", E_CLARKE_66, -9, 152, 178 }, // 126 { "North American 1927 (Greenland (Hayes Peninsula))", E_CLARKE_66, 11, 114, 195 }, // 127 { "North American 1927 (MEAN FOR Antigua; Barbados; Barbuda; Caicos Islands; Cuba; Dominican Republic; Grand Cayman; Jamaica; Turks Islands)", E_CLARKE_66, -3, 142, 183 }, // 128 { "North American 1927 (MEAN FOR Belize; Costa Rica; El Salvador; Guatemala; Honduras; Nicaragua)", E_CLARKE_66, 0, 125, 194 }, // 129 { "North American 1927 (MEAN FOR Canada)", E_CLARKE_66, -10, 158, 187 }, // 130 { "North American 1927 (MEAN FOR CONUS)", E_CLARKE_66, -8, 160, 176 }, // 131 { "North American 1927 (MEAN FOR CONUS (East of Mississippi; River Including Louisiana; Missouri; Minnesota))", E_CLARKE_66, -9, 161, 179 }, // 132 { "North American 1927 (MEAN FOR CONUS (West of Mississippi; River Excluding Louisiana; Minnesota; Missouri))", E_CLARKE_66, -8, 159, 175 }, // 133 { "North American 1927 (Mexico)", E_CLARKE_66, -12, 130, 190 }, // 134 { "North American 1983 (Alaska (Excluding Aleutian Ids))", E_GRS_80, 0, 0, 0 }, // 135 { "North American 1983 (Aleutian Ids)", E_GRS_80, -2, 0, 4 }, // 136 { "North American 1983 (Canada)", E_GRS_80, 0, 0, 0 }, // 137 { "North American 1983 (CONUS)", E_GRS_80, 0, 0, 0 }, // 138 { "North American 1983 (Hawaii)", E_GRS_80, 1, 1, -1 }, // 139 { "North American 1983 (Mexico; Central America)", E_GRS_80, 0, 0, 0 }, // 140 { "North Sahara 1959 (Algeria)", E_CLARKE_80, -186, -93, 310 }, // 141 { "Observatorio Meteorologico 1939 (Azores (Corvo & Flores Islands))", E_INT_24, -425, -169, 81 }, // 142 { "Old Egyptian 1907 (Egypt)", E_HELM_06, -130, 110, -13 }, // 143 { "Old Hawaiian (Hawaii)", E_CLARKE_66, 89, -279, -183 }, // 144 { "Old Hawaiian (Kauai)", E_CLARKE_66, 45, -290, -172 }, // 145 { "Old Hawaiian (Maui)", E_CLARKE_66, 65, -290, -190 }, // 146 { "Old Hawaiian (MEAN FOR Hawaii; Kauai; Maui; Oahu)", E_CLARKE_66, 61, -285, -181 }, // 147 { "Old Hawaiian (Oahu)", E_CLARKE_66, 58, -283, -182 }, // 148 { "Oman (Oman)", E_CLARKE_80, -346, -1, 224 }, // 149 { "Ordnance Survey Great Britain 1936 (England)", E_AIRY_30, 371, -112, 434 }, // 150 { "Ordnance Survey Great Britain 1936 (England; Isle of Man; Wales)", E_AIRY_30, 371, -111, 434 }, // 151 { "Ordnance Survey Great Britain 1936 (MEAN FOR England; Isle of Man; Scotland; Shetland Islands; Wales)", E_AIRY_30, 375, -111, 431 }, // 152 { "Ordnance Survey Great Britain 1936 (Scotland; Shetland Islands)", E_AIRY_30, 384, -111, 425 }, // 153 { "Ordnance Survey Great Britain 1936 (Wales)", E_AIRY_30, 370, -108, 434 }, // 154 { "Pico de las Nieves (Canary Islands)", E_INT_24, -307, -92, 127 }, // 155 { "Pitcairn Astro 1967 (Pitcairn Island)", E_INT_24, 185, 165, 42 }, // 156 { "Point 58 (MEAN FOR Burkina Faso & Niger)", E_CLARKE_80, -106, -129, 165 }, // 157 { "Pointe Noire 1948 (Congo)", E_CLARKE_80, -148, 51, -291 }, // 158 { "Porto Santo 1936 (Porto Santo; Madeira Islands)", E_INT_24, -499, -249, 314 }, // 159 { "Provisional South American 1956 (Bolivia)", E_INT_24, -270, 188, -388 }, // 160 { "Provisional South American 1956 (Chile (Northern; Near 19S))", E_INT_24, -270, 183, -390 }, // 161 { "Provisional South American 1956 (Chile (Southern; Near 43S))", E_INT_24, -305, 243, -442 }, // 162 { "Provisional South American 1956 (Colombia)", E_INT_24, -282, 169, -371 }, // 163 { "Provisional South American 1956 (Ecuador)", E_INT_24, -278, 171, -367 }, // 164 { "Provisional South American 1956 (Guyana)", E_INT_24, -298, 159, -369 }, // 165 { "Provisional South American 1956 (MEAN FOR Bolivia; Chile; Colombia; Ecuador; Guyana; Peru; Venezuela)", E_INT_24, -288, 175, -376 }, // 166 { "Provisional South American 1956 (Peru)", E_INT_24, -279, 175, -379 }, // 167 { "Provisional South American 1956 (Venezuela)", E_INT_24, -295, 173, -371 }, // 168 { "Provisional South Chilean 1963 (Chile (Near 53S) (Hito XVIII))", E_INT_24, 16, 196, 93 }, // 169 { "Puerto Rico (Puerto Rico; Virgin Islands)", E_CLARKE_66, 11, 72, -101 }, // 170 { "Pulkovo 1942 (Russia)", E_KRASS_40, 28, -130, -95 }, // 171 { "Qatar National (Qatar)", E_INT_24, -128, -283, 22 }, // 172 { "Qornoq (Greenland (South))", E_INT_24, 164, 138, -189 }, // 173 { "Reunion (Mascarene Islands)", E_INT_24, 94, -948, -1262 }, // 174 { "Rome 1940 (Italy (Sardinia))", E_INT_24, -225, -65, 9 }, // 175 { "S-42 (Pulkovo 1942) (Hungary)", E_KRASS_40, 28, -121, -77 }, // 176 { "S-42 (Pulkovo 1942) (Poland)", E_KRASS_40, 23, -124, -82 }, // 177 { "S-42 (Pulkovo 1942) (Czechoslavakia)", E_KRASS_40, 26, -121, -78 }, // 178 { "S-42 (Pulkovo 1942) (Latvia)", E_KRASS_40, 24, -124, -82 }, // 179 { "S-42 (Pulkovo 1942) (Kazakhstan)", E_KRASS_40, 15, -130, -84 }, // 180 { "S-42 (Pulkovo 1942) (Albania)", E_KRASS_40, 24, -130, -92 }, // 181 { "S-42 (Pulkovo 1942) (Romania)", E_KRASS_40, 28, -121, -77 }, // 182 { "S-JTSK (Czechoslavakia (Prior 1 JAN 1993))", E_BESS_41, 589, 76, 480 }, // 183 { "Santo (DOS) 1965 (Espirito Santo Island)", E_INT_24, 170, 42, 84 }, // 184 { "Sao Braz (Azores (Sao Miguel; Santa Maria Ids))", E_INT_24, -203, 141, 53 }, // 185 { "Sapper Hill 1943 (East Falkland Island)", E_INT_24, -355, 21, 72 }, // 186 { "Schwarzeck (Namibia)", E_BESS_41_NAM, 616, 97, -251 }, // 187 { "Selvagem Grande 1938 (Salvage Islands)", E_INT_24, -289, -124, 60 }, // 188 { "Sierra Leone 1960 (Sierra Leone)", E_CLARKE_80, -88, 4, 101 }, // 189 { "South American 1969 (Argentina)", E_S_AMER_69, -62, -1, -37 }, // 190 { "South American 1969 (Bolivia)", E_S_AMER_69, -61, 2, -48 }, // 191 { "South American 1969 (Brazil)", E_S_AMER_69, -60, -2, -41 }, // 192 { "South American 1969 (Chile)", E_S_AMER_69, -75, -1, -44 }, // 193 { "South American 1969 (Colombia)", E_S_AMER_69, -44, 6, -36 }, // 194 { "South American 1969 (Ecuador)", E_S_AMER_69, -48, 3, -44 }, // 195 { "South American 1969 (Ecuador (Baltra; Galapagos))", E_S_AMER_69, -47, 26, -42 }, // 196 { "South American 1969 (Guyana)", E_S_AMER_69, -53, 3, -47 }, // 197 { "South American 1969 (MEAN FOR Argentina; Bolivia; Brazil; Chile; Colombia; Ecuador; Guyana; Paraguay; Peru; Trinidad & Tobago; Venezuela)", E_S_AMER_69, -57, 1, -41 }, // 198 { "South American 1969 (Paraguay)", E_S_AMER_69, -61, 2, -33 }, // 199 { "South American 1969 (Peru)", E_S_AMER_69, -58, 0, -44 }, // 200 { "South American 1969 (Trinidad & Tobago)", E_S_AMER_69, -45, 12, -33 }, // 201 { "South American 1969 (Venezuela)", E_S_AMER_69, -45, 8, -33 }, // 202 { "South Asia (Singapore)", E_MOD_FISCH_60, 7, -10, -26 }, // 203 { "Tananarive Observatory 1925 (Madagascar)", E_INT_24, -189, -242, -91 }, // 204 { "Timbalai 1948 (Brunei; E. Malaysia (Sabah Sarawak))", E_EVR_SAB_SAR, -679, 669, -48 }, // 205 { "Tokyo (Japan)", E_BESS_41, -148, 507, 685 }, // 206 { "Tokyo (MEAN FOR Japan; South Korea; Okinawa)", E_BESS_41, -148, 507, 685 }, // 207 { "Tokyo (Okinawa)", E_BESS_41, -158, 507, 676 }, // 208 { "Tokyo (South Korea)", E_BESS_41, -147, 506, 687 }, // 209 { "Tristan Astro 1968 (Tristan da Cunha)", E_INT_24, -632, 438, -609 }, // 210 { "Viti Levu 1916 (Fiji (Viti Levu Island))", E_CLARKE_80, 51, 391, -36 }, // 211 { "Voirol 1960 (Algeria)", E_CLARKE_80, -123, -206, 219 }, // 212 { "Wake Island Astro 1952 (Wake Atoll)", E_INT_24, 276, -57, 149 }, // 213 { "Wake-Eniwetok 1960 (Marshall Islands)", E_HOUGH_60, 102, 52, -38 }, // 214 { "WGS 1972 (Global Definition)", E_WGS_72, 0, 0, 0 }, // 215 { "WGS 1984 (Global Definition)", E_WGS_84, 0, 0, 0 }, // 216 { "Yacare (Uruguay)", E_INT_24, -155, 171, 37 }, // 217 { "Zanderij (Suriname)", E_INT_24, -265, 120, -358 } // 218 }; static const double PI = 3.14159265358979323846; /* As you can see this little function is just a 2 step datum shift, going through WGS84. */ void datum_shift(double *latitude, double *longitude, short fromDatumID, short toDatumID) { wgs84_datum_shift(TO_WGS_84, latitude, longitude, fromDatumID); wgs84_datum_shift(FROM_WGS_84, latitude, longitude, toDatumID); } /* Function to convert latitude and longitude in decimal degrees from WGS84 to another datum or from another datum to WGS84. The arguments to this function include a direction flag 'fromWGS84', pointers to double precision latitude and longitude, and an index to the gDatum[] array. */ void wgs84_datum_shift(short fromWGS84, double *latitude, double *longitude, short datumID) { double dx = gDatum[datumID].dx; double dy = gDatum[datumID].dy; double dz = gDatum[datumID].dz; double phi = *latitude * PI / 180.0; double lambda = *longitude * PI / 180.0; double a0, b0, es0, f0; /* Reference ellipsoid of input data */ // a1 and b1 are never actually used, so don't declare them and set // them (gcc warns about set-but-unused vars) //double a1, b1, es1, f1; /* Reference ellipsoid of output data */ double es1, f1; /* Reference ellipsoid of output data */ double psi; /* geocentric latitude */ double x, y, z; /* 3D coordinates with respect to original datum */ double psi1; /* transformed geocentric latitude */ if (datumID == D_WGS_84) // do nothing if current datum is WGS84 { return; } if (fromWGS84) /* convert from WGS84 to new datum */ { a0 = gEllipsoid[E_WGS_84].a; /* WGS84 semimajor axis */ f0 = 1.0 / gEllipsoid[E_WGS_84].invf; /* WGS84 flattening */ // a1 is never used except to set b1, which itself is never used // a1 = gEllipsoid[gDatum[datumID].ellipsoid].a; f1 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf; } else /* convert from datum to WGS84 */ { a0 = gEllipsoid[gDatum[datumID].ellipsoid].a; /* semimajor axis */ f0 = 1.0 / gEllipsoid[gDatum[datumID].ellipsoid].invf; /* flattening */ // a1 is never used except to set b1, which is never used. // a1 = gEllipsoid[E_WGS_84].a; /* WGS84 semimajor axis */ f1 = 1.0 / gEllipsoid[E_WGS_84].invf; /* WGS84 flattening */ dx = -dx; dy = -dy; dz = -dz; } b0 = a0 * (1 - f0); /* semiminor axis for input datum */ es0 = 2 * f0 - f0*f0; /* eccentricity^2 */ // b1 is never used // b1 = a1 * (1 - f1); /* semiminor axis for output datum */ es1 = 2 * f1 - f1*f1; /* eccentricity^2 */ /* Convert geodedic latitude to geocentric latitude, psi */ if (*latitude == 0.0 || *latitude == 90.0 || *latitude == -90.0) { psi = phi; } else { psi = atan((1 - es0) * tan(phi)); } /* Calculate x and y axis coordinates with respect to the original ellipsoid */ if (*longitude == 90.0 || *longitude == -90.0) { x = 0.0; y = fabs(a0 * b0 / sqrt(b0*b0 + a0*a0*pow(tan(psi), 2.0))); } else { x = fabs((a0 * b0) / sqrt((1 + pow(tan(lambda), 2.0)) * (b0*b0 + a0*a0 * pow(tan(psi), 2.0)))); y = fabs(x * tan(lambda)); } if (*longitude < -90.0 || *longitude > 90.0) { x = -x; } if (*longitude < 0.0) { y = -y; } /* Calculate z axis coordinate with respect to the original ellipsoid */ if (*latitude == 90.0) { z = b0; } else if (*latitude == -90.0) { z = -b0; } else { z = tan(psi) * sqrt((a0*a0 * b0*b0) / (b0*b0 + a0*a0 * pow(tan(psi), 2.0))); } /* Calculate the geocentric latitude with respect to the new ellipsoid */ psi1 = atan((z - dz) / sqrt((x - dx)*(x - dx) + (y - dy)*(y - dy))); /* Convert to geocentric latitude and save return value */ *latitude = atan(tan(psi1) / (1 - es1)) * 180.0 / PI; /* Calculate the longitude with respect to the new ellipsoid */ *longitude = atan((y - dy) / (x - dx)) * 180.0 / PI; /* Correct the resultant for negative x values */ if (x-dx < 0.0) { if (y-dy > 0.0) { *longitude = 180.0 + *longitude; } else { *longitude = -180.0 + *longitude; } } } #define deg2rad (PI / 180) #define rad2deg (180.0 / PI) /* Source Defense Mapping Agency. 1987b. DMA Technical Report: Supplement to Department of Defense World Geodetic System 1984 Technical Report. Part I and II. Washington, DC: Defense Mapping Agency */ // // Convert lat/long to UTM/UPS coordinates void ll_to_utm_ups(short ellipsoidID, const double lat, const double lon, double *utmNorthing, double *utmEasting, char* utmZone, int utmZoneLength) { //converts lat/long to UTM coords. Equations from USGS Bulletin 1532 //East Longitudes are positive, West longitudes are negative. //North latitudes are positive, South latitudes are negative //Lat and Long are in decimal degrees //Written by Chuck Gantz- chuck.gantz@globalstar.com double a = gEllipsoid[ellipsoidID].a; double f = 1.0 / gEllipsoid[ellipsoidID].invf; double eccSquared = (2 * f) - (f * f); double k0 = 0.9996; double LongOrigin; double eccPrimeSquared; double N, T, C, A, M; //Make sure the longitude is between -180.00 .. 179.9 double LongTemp = (lon+180)-(int)((lon+180)/360)*360-180; // -180.00 .. 179.9; double LatRad = lat*deg2rad; double LongRad = LongTemp*deg2rad; double LongOriginRad; int ZoneNumber; ZoneNumber = (int)((LongTemp + 180)/6) + 1; if (coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { // Special zone for southern Norway. Used for military // version of UTM (MGRS) only. if ( lat >= 56.0 && lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 ) { ZoneNumber = 32; } // Handle the special zones for Svalbard. Used for military // version of UTM (MGRS) only. if (lat >= 72.0 && lat < 84.0) { if (LongTemp >= 0.0 && LongTemp < 9.0) { ZoneNumber = 31; } else if (LongTemp >= 9.0 && LongTemp < 21.0) { ZoneNumber = 33; } else if (LongTemp >= 21.0 && LongTemp < 33.0) { ZoneNumber = 35; } else if (LongTemp >= 33.0 && LongTemp < 42.0) { ZoneNumber = 37; } } } LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone LongOriginRad = LongOrigin * deg2rad; if (lat > 84.0 || lat < -80.0) { // We're in the UPS areas (near the poles). ZoneNumber // should not be printed in this case. xastir_snprintf(utmZone, utmZoneLength, "%c", utm_letter_designator(lat, lon)); } else // We're in the UTM areas (not near the poles). { //compute the UTM Zone from the latitude and longitude xastir_snprintf(utmZone, utmZoneLength, "%d%c", ZoneNumber, utm_letter_designator(lat, lon)); } eccPrimeSquared = (eccSquared)/(1-eccSquared); if (lat > 84.0 || lat < -80.0) { // // We're dealing with UPS coordinates (near the poles) // // The following piece of code which implements UPS // conversion is derived from code that John Waers // placed in the public domain. It's from // his program "MacGPS45". double t, e, rho; const double k0 = 0.994; double lambda = lon * (PI/180.0); double phi = fabs(lat * (PI/180.0) ); e = sqrt(eccSquared); t = tan(PI/4.0 - phi/2.0) / pow( (1.0 - e * sin(phi)) / (1.0 + e * sin(phi)), (e/2.0) ); rho = 2.0 * a * k0 * t / sqrt(pow(1.0+e, 1.0+e) * pow(1.0-e, 1.0-e)); *utmEasting = rho * sin(lambda); *utmNorthing = rho * cos(lambda); if (lat > 0.0) // Northern hemisphere { *utmNorthing = -(*utmNorthing); } *utmEasting += 2.0e6; // Add in false easting and northing *utmNorthing += 2.0e6; } else { // // We're dealing with UTM coordinates // N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad)); T = tan(LatRad)*tan(LatRad); C = eccPrimeSquared*cos(LatRad)*cos(LatRad); A = cos(LatRad)*(LongRad-LongOriginRad); M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256) * LatRad - (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024) * sin(2*LatRad) + (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024) * sin(4*LatRad) - (35*eccSquared*eccSquared*eccSquared/3072) * sin(6*LatRad)); *utmEasting = (double)(k0*N*(A+(1-T+C)*A*A*A/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120) + 500000.0); *utmNorthing = (double)(k0*(M+N*tan(LatRad)* (A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24 + (61-58*T+T*T+600*C-330*eccPrimeSquared)*A*A*A*A*A*A/720))); if (lat < 0) { *utmNorthing += 10000000.0; //10000000 meter offset for southern hemisphere } } } // Handles UPS/UTM coordinates equally well! // char utm_letter_designator(double lat, double lon) { // This routine determines the correct UTM/UPS letter designator // for the given latitude. Originally written by Chuck Gantz- // chuck.gantz@globalstar.com // Modified to handle UPS zones. --we7u char LetterDesignator; if ((84 >= lat) && (lat >= 72)) { LetterDesignator = 'X'; } else if ((72 > lat) && (lat >= 64)) { LetterDesignator = 'W'; } else if ((64 > lat) && (lat >= 56)) { LetterDesignator = 'V'; } else if ((56 > lat) && (lat >= 48)) { LetterDesignator = 'U'; } else if ((48 > lat) && (lat >= 40)) { LetterDesignator = 'T'; } else if ((40 > lat) && (lat >= 32)) { LetterDesignator = 'S'; } else if ((32 > lat) && (lat >= 24)) { LetterDesignator = 'R'; } else if ((24 > lat) && (lat >= 16)) { LetterDesignator = 'Q'; } else if ((16 > lat) && (lat >= 8)) { LetterDesignator = 'P'; } else if (( 8 > lat) && (lat >= 0)) { LetterDesignator = 'N'; } else if (( 0 > lat) && (lat >= -8)) { LetterDesignator = 'M'; } else if ((-8 > lat) && (lat >= -16)) { LetterDesignator = 'L'; } else if ((-16 > lat) && (lat >= -24)) { LetterDesignator = 'K'; } else if ((-24 > lat) && (lat >= -32)) { LetterDesignator = 'J'; } else if ((-32 > lat) && (lat >= -40)) { LetterDesignator = 'H'; } else if ((-40 > lat) && (lat >= -48)) { LetterDesignator = 'G'; } else if ((-48 > lat) && (lat >= -56)) { LetterDesignator = 'F'; } else if ((-56 > lat) && (lat >= -64)) { LetterDesignator = 'E'; } else if ((-64 > lat) && (lat >= -72)) { LetterDesignator = 'D'; } else if ((-72 > lat) && (lat >= -80)) { LetterDesignator = 'C'; } else { // // We're dealing with UPS (N/S Pole) coordinates, not UTM // if (lat > 84) // North Pole, Y/Z zones { if ((0 <= lon) && (lon <= 180)) { LetterDesignator = 'Z'; // E or + longitude } else { LetterDesignator = 'Y'; // W or - longitude } } else // Lat < 80S, South Pole, A/B zones { if ((0 <= lon) && (lon <= 180)) { LetterDesignator = 'B'; // E or + longitude } else { LetterDesignator = 'A'; // W or - longitude } } } return LetterDesignator; } // The following piece of code which implements UPS conversion is // derived from code that John Waers placed in // the public domain. It's from his program "MacGPS45". // static void calcPhi(double *phi, double e, double t) { double old = PI/2.0 - 2.0 * atan(t); short maxIterations = 20; while ( (fabs((*phi - old) / *phi) > 1.0e-8) && maxIterations-- ) { old = *phi; *phi = PI/ 2.0 - 2.0 * atan( t * pow((1.0 - e * sin(*phi)) / ((1.0 + e * sin(*phi))), (e / 2.0)) ); } } // Converts from UTM/UPS coordinates to Lat/Long coordinates. // void utm_ups_to_ll(short ellipsoidID, const double utmNorthing, const double utmEasting, const char* utmZone, double *lat, double *lon) { // Converts UTM coords to lat/long. Equations from USGS // Bulletin 1532. East Longitudes are positive, West longitudes // are negative. North latitudes are positive, South latitudes // are negative Lat and Long are in decimal degrees. // Written by Chuck Gantz- chuck.gantz@globalstar.com // Modified by WE7U to add UPS support. double k0 = 0.9996; double a = gEllipsoid[ellipsoidID].a; double f = 1.0 / gEllipsoid[ellipsoidID].invf; double eccSquared = (2 * f) - (f * f); double eccPrimeSquared; double e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared)); double N1, T1, C1, R1, D, M; double LongOrigin; // phi1 is never used, but is set. Don't make gcc warn us // double mu, phi1, phi1Rad; double mu, phi1Rad; double x, y; int ZoneNumber; char* ZoneLetter; // Unused variable // int NorthernHemisphere; // 1=northern hemisphere, 0=southern //fprintf(stderr,"%s %f %f\n", // utmZone, // utmEasting, // utmNorthing); x = utmEasting; y = utmNorthing; ZoneNumber = strtoul(utmZone, &ZoneLetter, 10); // Remove any possible leading spaces remove_leading_spaces(ZoneLetter); // Make sure the zone letter is upper-case *ZoneLetter = toupper(*ZoneLetter); //fprintf(stderr,"ZoneLetter: %s\n", ZoneLetter); if ( *ZoneLetter == 'Y' // North Pole || *ZoneLetter == 'Z' // North Pole || *ZoneLetter == 'A' // South Pole || *ZoneLetter == 'B') // South Pole { // The following piece of code which implements UPS // conversion is derived from code that John Waers // placed in the public domain. It's from // his program "MacGPS45". // // We're dealing with a UPS coordinate (near the poles) // instead of a UTM coordinate. We need to do entirely // different calculations for UPS. // double e, t, rho; const double k0 = 0.994; //fprintf(stderr,"UPS Coordinates\n"); e = sqrt(eccSquared); x -= 2.0e6; // Remove false easting and northing y -= 2.0e6; rho = sqrt(x*x + y*y); t = rho * sqrt(pow(1.0+e, 1.0+e) * pow(1.0-e, 1.0-e)) / (2.0 * a * k0); calcPhi(lat, e, t); *lat /= (PI/180.0); // This appears to be necessary in order to get proper // positions in the south polar region if (*ZoneLetter == 'A' || *ZoneLetter == 'B') { *lat = -*lat; } if (y != 0.0) { t = atan(fabs(x/y)); } else { t = PI / 2.0; if (x < 0.0) { t = -t; } } if (*ZoneLetter == 'Z' || *ZoneLetter == 'Y') { y = -y; // Northern hemisphere } if (y < 0.0) { t = PI - t; } if (x < 0.0) { t = -t; } *lon = t / (PI/180.0); /* fprintf(stderr,"datum.c:utm_ups_to_ll(): Found UPS Coordinate: %s %f %f\n", utmZone, utmEasting, utmNorthing); */ return; // Done computing UPS coordinates } // If we make it here, we're working on UTM coordinates (not // UPS coordinates). x = utmEasting - 500000.0; //remove 500,000 meter offset for longitude y = utmNorthing; if ((*ZoneLetter - 'N') >= 0) { // We never use this variable // NorthernHemisphere = 1;//point is in northern hemisphere } else { // we never use NorthernHemisphere // NorthernHemisphere = 0;//point is in southern hemisphere y -= 10000000.0;//remove 10,000,000 meter offset used for southern hemisphere } LongOrigin = (ZoneNumber - 1)*6 - 180 + 3; //+3 puts origin in middle of zone eccPrimeSquared = (eccSquared)/(1-eccSquared); M = y / k0; mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64-5*eccSquared*eccSquared*eccSquared/256)); phi1Rad = mu + (3*e1/2-27*e1*e1*e1/32)*sin(2*mu) + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu) + (151*e1*e1*e1/96)*sin(6*mu); // This variable is never used, it is just phi1Rad converted to degrees // phi1 = phi1Rad*rad2deg; N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad)); T1 = tan(phi1Rad)*tan(phi1Rad); C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad); R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5); D = x/(N1*k0); *lat = phi1Rad - (N1*tan(phi1Rad)/R1)*(D*D/2-(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24 +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared-3*C1*C1)*D*D*D*D*D*D/720); *lat *= rad2deg; *lon = (D-(1+2*T1+C1)*D*D*D/6+(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1) *D*D*D*D*D/120)/cos(phi1Rad); *lon = LongOrigin + (*lon) * rad2deg; } Xastir-Release-2.2.4/src/datum.h0000664000175000017500000000616415151324131015402 0ustar hibbyhibby/* Portions Copyright (C) 2000-2026 The Xastir Group The datum conversion code here and in datum.c is from MacGPS 45. According to the Read_Me file in the source archive of that program, the author says the following: "I've read the legalese statements that everyone attaches to works like this, but I can never remember what they say. Suffice it to say that I am releasing this source code to the public domain, and you are free to do with it what you like. If you find it of some use and include any of it in an application, credits (and perhaps a copy of your program, if your feel so inclined) would be appreciated. John F. Waers " If you ever read this, John, thanks for the code and feel free to try out Xastir, it's free. The UTM to/from Lat/Long translations were written by Chuck Gantz . Curt Mills received permission via e-mail to release the code under the GPL for a conversion he did to perl. I deduce from this that including it in Xastir, a GPL program is no problem. Thanks Chuck! N7TAP */ // Equatorial radius of the Earth. In our distance/angular/area // calculations (not here in datum.h/datum.c, but elsewhere in the // code) we currently ignore flattening as you go towards the poles. // // The datum translation code in datum.h/datum.c doesn't use these // three defines at all: That code uses ellipsoids and so // flattening is accounted for there. #define EARTH_RADIUS_METERS 6378138.0 #define EARTH_RADIUS_KILOMETERS 6378.138 #define EARTH_RADIUS_MILES 3963.1836 #define FROM_WGS_84 1 #define TO_WGS_84 0 void wgs84_datum_shift(short fromWGS84, double *latitude, double *longitude, short datumID); void datum_shift(double *latitude, double *longitude, short fromDatumID, short toDatumID); typedef struct { char *name; // name of ellipsoid double a; // semi-major axis, meters double invf; // 1/f } Ellipsoid; extern const Ellipsoid gEllipsoid[]; enum Ellipsoid_Names // Must match the order of the Ellipsoids defined in datum.c { E_AIRY_30, E_MOD_AIRY, E_AUS_NAT, E_BESS_41, E_BESS_41_NAM, E_CLARKE_66, E_CLARKE_80, E_EVR_IND_30, E_EVR_IND_56, E_EVR_SAB_SAR, E_EVR_MAL_69, E_EVR_MAL_SING, E_EVR_PAK, E_FISCH_60_MERC, E_MOD_FISCH_60, E_FISCH_68, E_HELM_06, E_HOUGH_60, E_IND_74, E_INT_24, E_KRASS_40, E_GRS_67, E_GRS_80, E_S_AMER_69, E_WGS_60, E_WGS_66, E_WGS_72, E_WGS_84 }; typedef struct { char *name; short ellipsoid; short dx; short dy; short dz; } Datum; extern const Datum gDatum[]; enum Common_Datum_Names // Must match the indices of the Datums defined in datum.c { D_NAD_27_CONUS = 131, D_NAD_83_CONUS = 138, D_WGS_72 = 215, D_WGS_84 = 216 }; void ll_to_utm_ups(short ellipsoidID, const double lat, const double lon, double *utmNorthing, double *utmEasting, char* utmZone, int utmZoneLength); void utm_ups_to_ll(short ellipsoidID, const double utmNorthing, const double utmEasting, const char* utmZone, double *lat, double *lon); char utm_letter_designator(double lat, double lon); Xastir-Release-2.2.4/src/db.c0000664000175000017500000176404415151324131014661 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Note: the header file for db.c should be called db.h, * but is named database.h to avoid conflicts with the * Berkeley DB package. */ // NOTE: decode_info_field() is a good place to start for decoding. // Used only for special debugging of message/station expiration. // Leave commented out for normal operation. //#define EXPIRE_DEBUG #define DEBUG_MESSAGE_REMOVE_CYCLE 15 #define DEBUG_STATION_REMOVE_CYCLE 15 #define DEBUG_MESSAGE_REMOVE 600 #define DEBUG_STATION_REMOVE 600 #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include "xastir.h" #include "globals.h" #include "main.h" #include "draw_symbols.h" #include "alert.h" #include "util.h" #include "tactical_call_utils.h" #include "bulletin_gui.h" #include "fcc_data.h" #include "gps.h" #include "rac_data.h" #include "interface.h" #include "maps.h" #include "wx.h" #include "igate.h" #include "list_gui.h" #include "objects.h" #include "objects_gui.h" #include "track_gui.h" #include "xa_config.h" #include "x_spider.h" #include "db_gis.h" #include "db_gui.h" #include "db_funcs.h" #include "sound.h" #include "log_utils.h" // Must be last include file #include "leak_detection.h" #define STATION_REMOVE_CYCLE 300 /* check station remove in seconds (every 5 minutes) */ #define MESSAGE_REMOVE_CYCLE 600 /* check message remove in seconds (every 10 minutes) */ #define IN_VIEW_MIN 600l /* margin for off-screen stations, with possible trails on screen, in minutes */ #define TRAIL_POINT_MARGIN 30l /* margin for off-screen trails points, for segment to be drawn, in minutes */ #define TRAIL_MAX_SPEED 900 /* max. acceptable speed for drawing trails, in mph */ #define TRAIL_ECHO_TIME 30 /* check for delayed echos during last 30 minutes */ /* MY_TRAIL_DIFF_COLOR changed to user configurable my_trail_diff_color */ ///////////////////////////////////// #define GUARD_SIZE 10 char GUARD_BAND_THREE[GUARD_SIZE]; ///////////////////////////////////// int station_data_auto_update = 0; // Used to store all the calls we might "relay" digipeat by. // Separated by commas. Up to 50 callsigns of 9 chars each plus // comma delimiters. char relay_digipeater_calls[10*MAX_RELAY_DIGIPEATER_CALLS]; void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char speedu, char *alt, char *sats); void station_shortcuts_update_function(int hash_key, DataRow *p_rem); int position_on_extd_screen(long lat, long lon); int extract_speed_course(char *info, char *speed, char *course); int extract_bearing_NRQ(char *info, char *bearing, char *nrq); int skip_dupe_checking; int tracked_stations = 0; // A count variable used in debug code only void track_station(Widget w, char *call_tracked, DataRow *p_station); int new_message_data; time_t last_message_remove; // last time we did a check for message removing //////////////////////////////////// char GUARD_BAND_FOUR[GUARD_SIZE]; //////////////////////////////////// //// Save most recent 100 packets in an array called packet_data_string[] #define MAX_PACKET_DATA_DISPLAY 100 int redraw_on_new_packet_data; char packet_data_string[MAX_PACKET_DATA_DISPLAY][MAX_LINE_SIZE+1]; int first_line=-1; int next_line=0; int ncharsdel=0; int nlinesadd=0; /////////////////////////////////// char GUARD_BAND_ONE[GUARD_SIZE]; /////////////////////////////////// int station_count; // number of stored stations int station_count_save = 0; // old copy of above DataRow *n_first; // pointer to first element in name sorted station list DataRow *n_last; // pointer to last element in name sorted station list DataRow *t_oldest; // pointer to first element in time sorted station list (oldest) DataRow *t_newest; // pointer to last element in time sorted station list (newest) time_t last_station_remove; // last time we did a check for station removing time_t last_sec,curr_sec; // for comparing if seconds in time have changed int next_time_sn; // time serial number for unique time index /////////////////////////////////// char GUARD_BAND_TWO[GUARD_SIZE]; /////////////////////////////////// int emergency_distance_check = 1; float emergency_range = 280.0; // Default is 4hrs @ 70mph distance CADRow *CAD_list_head = NULL; // pointer to first element in CAD objects list void draw_trail(Widget w, DataRow *fill, int solid); void export_trail(DataRow *p_station); // export trail of one or all stations to xastir export file //void export_trail_as_kml(DataRow *p_station); // export trail of one or all stations to kml file int fcc_lookup_pushed = 0; int rac_lookup_pushed = 0; time_t last_object_check = 0; // Used to determine when to re-transmit objects/items time_t last_emergency_time = 0; char last_emergency_callsign[MAX_CALLSIGN+1]; int st_direct_timeout = 60 * 60; // 60 minutes. // Used in search_station_name() function. Shortcuts into the // station list based on the least-significant 7 bits of the first // two letters of the callsign/object name. DataRow *station_shortcuts[16384]; // used to time aloha calculations time_t aloha_time = 0; time_t aloha_status_time = 0; double aloha_radius=-1; // in miles aloha_stats the_aloha_stats; int process_emergency_packet_again = 0; char echo_digis[6][MAX_CALLSIGN+1]; void db_init(void) { int ii; // Set up guard bands around important global pointers for (ii = 0; ii < GUARD_SIZE; ii++) { GUARD_BAND_ONE[ii] = 0x00; GUARD_BAND_TWO[ii] = 0x00; GUARD_BAND_THREE[ii] = 0x00; GUARD_BAND_FOUR[ii] = 0x00; } last_emergency_callsign[0] = '\0'; // Seed the random number generator srand(1); } /////////////////////////////////// Utilities //////////////////////////////////////////////////// // Variable used for below test code //int we7u_count = 50; // Check guard bands around important global pointers. // // These guard bands are initialized in db.c:db_init() // // Returns: 0 if ok // 1 if guard band has been tampered with // int check_guard_band(void) { int ii; for (ii = 0; ii < GUARD_SIZE; ii++) { if (GUARD_BAND_ONE[ii] != 0x00 || GUARD_BAND_TWO[ii] != 0x00 || GUARD_BAND_THREE[ii] != 0x00 || GUARD_BAND_FOUR[ii] != 0x00) { if (GUARD_BAND_ONE[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_ONE was corrupted!\n"); } if (GUARD_BAND_TWO[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_TWO was corrupted!\n"); } if (GUARD_BAND_THREE[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_THREE was corrupted!\n"); } if (GUARD_BAND_FOUR[ii] != 0x00) { fprintf(stderr, "WARNING: GUARD_BAND_FOUR was corrupted!\n"); } fprintf(stderr, "Previous incoming line was: %s\n", incoming_data_copy_previous); fprintf(stderr, " Last incoming line was: %s\n", incoming_data_copy); abort(); // Cause immediate exit to aid in debugging return(1); } } // Test code /* if (we7u_count-- <= 0) { GUARD_BAND_ONE[0] = 0x01; GUARD_BAND_TWO[0] = 0x01; GUARD_BAND_THREE[0] = 0x01; GUARD_BAND_FOUR[0] = 0x01; } */ return(0); } /* * Check whether callsign is mine. "exact == 1" checks the SSID * for a match as well. "exact == 0" checks only the base * callsign. */ int is_my_call(char *call, int exact) { char *p_del; int ok; // U.S. special-event callsigns can be as short as three // characters, any less and we don't have a valid callsign. We // don't check for that restriction here though. if (exact) { // We're looking for an exact match ok = (int)( !strcmp(call,my_callsign) ); //fprintf(stderr,"My exact call found: %s\n",call); } else { // We're looking for a similar match. Compare only up to // the '-' in each (if present). int len1,len2; p_del = index(call,'-'); if (p_del == NULL) { len1 = (int)strlen(call); } else { len1 = p_del - call; } p_del = index(my_callsign,'-'); if (p_del == NULL) { len2 = (int)strlen(my_callsign); } else { len2 = p_del - my_callsign; } ok = (int)(len1 == len2 && !strncmp(call,my_callsign,(size_t)len1)); //fprintf(stderr,"My base call found: %s\n",call); } return(ok); } int is_my_station(DataRow *p_station) { // if station is owned by me (including SSID) return(p_station->flag & ST_MYSTATION); } int is_my_object_item(DataRow *p_station) { // If object/item is owned by me (including SSID) return(p_station->flag & ST_MYOBJITEM); } /* * Change map position if necessary while tracking a station * we call it with defined station call and position */ int is_tracked_station(char *call_sign) { int found; char call_find[MAX_CALLSIGN+1]; int ii; int call_len; if (!track_station_on) { return(0); } call_len = 0; found = 0; if (!track_case) { for ( ii = 0; ii < (int)strlen(tracking_station_call); ii++ ) { if (isalpha((int)tracking_station_call[ii])) { call_find[ii] = toupper((int)tracking_station_call[ii]); } else { call_find[ii] = tracking_station_call[ii]; } } call_find[ii] = '\0'; } else { memcpy(call_find, tracking_station_call, sizeof(call_find)); call_find[sizeof(call_find)-1] = '\0'; // Terminate string } if (debug_level & 256) { fprintf(stderr,"is_tracked_station(): CALL %s %s %s\n", tracking_station_call, call_find, call_sign); } if (track_match) { if (strcmp(call_find,call_sign) == 0) // we want an exact match { found = 1; } } else { found = 0; call_len = (int)(strlen(call_sign) - strlen(call_find)); if (strlen(call_find) <= strlen(call_sign)) { found = 1; for ( ii = 0; ii <= call_len; ii++ ) { if (!track_case) { if (strncasecmp(call_find,call_sign+ii,strlen(call_find)) != 0) { found = 0; // Found a mis-match } } else { if (strncmp(call_find,call_sign+ii,strlen(call_find)) != 0) { found = 0; } } } } } return(found); } /////////////////////////////////////////// Messages /////////////////////////////////////////// static long *msg_index; static long msg_index_end; static long msg_index_max; static Message *msg_data; // Array containing all messages, // including ones we've transmitted (via // loopback in the code) time_t last_message_update = 0; ack_record *ack_list_head = NULL; // Head of linked list storing most recent ack's int satellite_ack_mode; // How often update_messages() will run, in seconds. // This is necessary because routines like UpdateTime() // call update_messages() VERY OFTEN. // // Actually, we just changed the code around so that we only call // update_messages() with the force option, and only when we receive a // message. message_update_delay is no longer used, and we don't call // update_messages() from UpdateTime() anymore. static int message_update_delay = 300; // Saves latest ack in a linked list. We need this value in order // to use Reply/Ack protocol when sending out messages. void store_most_recent_ack(char *callsign, char *ack) { ack_record *p; int done = 0; char call[MAX_CALLSIGN+1]; char new_ack[5+1]; xastir_snprintf(call, sizeof(call), "%s", callsign); remove_trailing_spaces(call); // Get a copy of "ack". We might need to change it. xastir_snprintf(new_ack, sizeof(new_ack), "%s", ack); // If it's more than 2 characters long, we can't use it for // Reply/Ack protocol as there's only space enough for two. // In this case we need to make sure that we blank out any // former ack that was 1 or 2 characters, so that communications // doesn't stop. if ( strlen(new_ack) > 2 ) { // It's too long, blank it out so that gets saved as "", // which will overwrite any previously saved ack's that were // short enough to use. new_ack[0] = '\0'; } // Search for matching callsign through linked list p = ack_list_head; while ( !done && (p != NULL) ) { if (strcasecmp(call,p->callsign) == 0) { done++; } else { p = p->next; } } if (done) // Found it. Update the ack field. { //fprintf(stderr,"Found callsign %s on recent ack list, Old:%s, New:%s\n",call,p->ack,new_ack); xastir_snprintf(p->ack,sizeof(p->ack),"%s",new_ack); } else // Not found. Add a new record to the beginning of the { // list. //fprintf(stderr,"New callsign %s, adding to list. Ack: %s\n",call,new_ack); p = (ack_record *)malloc(sizeof(ack_record)); CHECKMALLOC(p); xastir_snprintf(p->callsign,sizeof(p->callsign),"%s",call); xastir_snprintf(p->ack,sizeof(p->ack),"%s",new_ack); p->next = ack_list_head; ack_list_head = p; } } // Gets latest ack by callsign char *get_most_recent_ack(char *callsign) { ack_record *p; int done = 0; char call[MAX_CALLSIGN+1]; xastir_snprintf(call, sizeof(call), "%s", callsign); remove_trailing_spaces(call); // Search for matching callsign through linked list p = ack_list_head; while ( !done && (p != NULL) ) { if (strcasecmp(call,p->callsign) == 0) { done++; } else { p = p->next; } } if (done) // Found it. Return pointer to ack string. { //fprintf(stderr,"Found callsign %s on linked list, returning ack: %s\n",call,p->ack); return(&p->ack[0]); } else { //fprintf(stderr,"Callsign %s not found\n",call); return(NULL); } } void init_message_data(void) // called at start of main { new_message_data = 0; last_message_remove = sec_now(); } #ifdef MSG_DEBUG void msg_clear_data(Message *clear) { int size; int i; unsigned char *data_ptr; data_ptr = (unsigned char *)clear; size=sizeof(Message); for(i=0; i (last_message_update + message_update_delay) ) { return(1); } else { return(0); } } int msg_comp_active(const void *a, const void *b) { char temp_a[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+2]; char temp_b[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+2]; xastir_snprintf(temp_a, sizeof(temp_a), "%c%s%s%s", ((Message*)a)->active, ((Message*)a)->call_sign, ((Message*)a)->from_call_sign, ((Message*)a)->seq); xastir_snprintf(temp_b, sizeof(temp_b), "%c%s%s%s", ((Message*)b)->active, ((Message*)b)->call_sign, ((Message*)b)->from_call_sign, ((Message*)b)->seq); return(strcmp(temp_a, temp_b)); } int msg_comp_data(const void *a, const void *b) { char temp_a[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; char temp_b[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; xastir_snprintf(temp_a, sizeof(temp_a), "%s%s%s", msg_data[*(long*)a].call_sign, msg_data[*(long *)a].from_call_sign, msg_data[*(long *)a].seq); xastir_snprintf(temp_b, sizeof(temp_b), "%s%s%s", msg_data[*(long*)b].call_sign, msg_data[*(long *)b].from_call_sign, msg_data[*(long *)b].seq); return(strcmp(temp_a, temp_b)); } void msg_input_database(Message *m_fill) { void *m_ptr; long i; if (msg_index_end == msg_index_max) { for (i = 0; i < msg_index_end; i++) { // Check for a record that is marked RECORD_NOTACTIVE. // If found, use that record instead of malloc'ing a new // one. if (msg_data[msg_index[i]].active == RECORD_NOTACTIVE) { // Found an unused record. Fill it in. memcpy(&msg_data[msg_index[i]], m_fill, sizeof(Message)); // Sort msg_data qsort(msg_data, (size_t)msg_index_end, sizeof(Message), msg_comp_active); for (i = 0; i < msg_index_end; i++) { msg_index[i] = i; if (msg_data[i].active == RECORD_NOTACTIVE) { msg_index_end = i; break; } } // Sort msg_index qsort(msg_index, (size_t)msg_index_end, sizeof(long *), msg_comp_data); // All done with this message. return; } } // Didn't find free message record. Fetch some more space. // Get more msg_data space. m_ptr = realloc(msg_data, (msg_index_max+MSG_INCREMENT)*sizeof(Message)); if (m_ptr) { msg_data = m_ptr; // Get more msg_index space m_ptr = realloc(msg_index, (msg_index_max+MSG_INCREMENT)*sizeof(Message *)); if (m_ptr) { msg_index = m_ptr; msg_index_max += MSG_INCREMENT; //fprintf(stderr, "Max Message Array: %ld\n", msg_index_max); } else { XtWarning("Unable to allocate more space for message index.\n"); } } else { XtWarning("Unable to allocate more space for message database.\n"); } } if (msg_index_end < msg_index_max) { msg_index[msg_index_end] = msg_index_end; // Copy message data into new message record. memcpy(&msg_data[msg_index_end++], m_fill, sizeof(Message)); // Sort msg_index qsort(msg_index, (size_t)msg_index_end, sizeof(long *), msg_comp_data); } } // Does a binary search through a sorted message database looking // for a string match. // // If two or more messages match, this routine _should_ return the // message with the latest timestamp. This will ensure that earlier // messages don't get mistaken for current messages, for the case // where the remote station did a restart and is using the same // sequence numbers over again. // long msg_find_data(Message *m_fill) { long record_start, record_mid, record_end, return_record, done; char tempfile[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; char tempfill[MAX_CALLSIGN+MAX_CALLSIGN+MAX_MESSAGE_ORDER+1]; xastir_snprintf(tempfill, sizeof(tempfill), "%s%s%s", m_fill->call_sign, m_fill->from_call_sign, m_fill->seq); return_record = -1L; if (msg_index && msg_index_end >= 1) { /* more than one record */ record_start=0L; record_end = (msg_index_end - 1); record_mid=(record_end-record_start)/2; done=0; while (!done) { /* get data for record start */ xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_start]].call_sign, msg_data[msg_index[record_start]].from_call_sign, msg_data[msg_index[record_start]].seq); if (strcmp(tempfill, tempfile) < 0) { /* filename comes before */ /*fprintf(stderr,"Before No data found!!\n");*/ done=1; break; } else /* get data for record end */ { xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_end]].call_sign, msg_data[msg_index[record_end]].from_call_sign, msg_data[msg_index[record_end]].seq); if (strcmp(tempfill,tempfile)>=0) /* at end or beyond */ { if (strcmp(tempfill, tempfile) == 0) { return_record = record_end; //fprintf(stderr,"record %ld",return_record); } done=1; break; } else if ((record_mid == record_start) || (record_mid == record_end)) { /* no mid for compare check to see if in the middle */ done=1; xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_mid]].call_sign, msg_data[msg_index[record_mid]].from_call_sign, msg_data[msg_index[record_mid]].seq); if (strcmp(tempfill,tempfile)==0) { return_record = record_mid; //fprintf(stderr,"record: %ld",return_record); } } } if (!done) /* get data for record mid */ { xastir_snprintf(tempfile, sizeof(tempfile), "%s%s%s", msg_data[msg_index[record_mid]].call_sign, msg_data[msg_index[record_mid]].from_call_sign, msg_data[msg_index[record_mid]].seq); if (strcmp(tempfill, tempfile) == 0) { return_record = record_mid; //fprintf(stderr,"record %ld",return_record); done = 1; break; } if(strcmp(tempfill, tempfile)<0) { record_end = record_mid; } else { record_start = record_mid; } record_mid = record_start+(record_end-record_start)/2; } } } return(return_record); } void msg_replace_data(Message *m_fill, long record_num) { memcpy(&msg_data[msg_index[record_num]], m_fill, sizeof(Message)); } void msg_get_data(Message *m_fill, long record_num) { memcpy(m_fill, &msg_data[msg_index[record_num]], sizeof(Message)); } void msg_update_ack_stamp(long record_num) { //fprintf(stderr,"Attempting to update ack stamp: %ld\n",record_num); if ( (record_num >= 0) && (record_num < msg_index_end) ) { msg_data[msg_index[record_num]].last_ack_sent = sec_now(); //fprintf(stderr,"Ack stamp: %ld\n",msg_data[msg_index[record_num]].last_ack_sent); } //fprintf(stderr,"\n\n\n*** Record: %ld ***\n\n\n",record_num); } // Called when we receive an ACK. Sets the "acked" field in a // Message which gets rid of the highlighting in the Send Message // dialog for that message line. This lets us know which messages // have been acked and which have not. If timeout is non-zero, then // set acked to 2: We use this in update_messages() to flag that // "*TIMEOUT*" should prefix the string. If cancelled is non-zero, // set acked to 3: We use this in update_messages() to flag that // "*CANCELLED*" should prefix the string. // void msg_record_ack(char *to_call_sign, char *my_call, char *seq, int timeout, int cancel) { Message m_fill; long record; int do_update = 0; if (debug_level & 1) { fprintf(stderr,"Recording ack for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i], set the // "acked" field to one. substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if (record == -1L) // No match yet, try another tactic. { if (seq[2] == '}' && strlen(seq) == 3) { // Try it again without the trailing '}' character m_fill.from_call_sign[2] = '\0'; // Look for a message with the same to_call_sign, // my_call, and seq number (minus the trailing '}') record = msg_find_data(&m_fill); } } if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 1, seq %s, record %ld\n", msg_data[msg_index[record]].acked, seq, record); } // Only cause an update if this is the first ack. This // reduces dialog "flashing" a great deal if ( msg_data[msg_index[record]].acked == 0 ) { // Check for my callsign (including SSID). If found, // update any open message dialogs if (is_my_call(msg_data[msg_index[record]].from_call_sign, 1) ) { //fprintf(stderr,"From: %s\tTo: %s\n", // msg_data[msg_index[record]].from_call_sign, // msg_data[msg_index[record]].call_sign); do_update++; } } else // This message has already been acked. { } if (cancel) { msg_data[msg_index[record]].acked = (char)3; } else if (timeout) { msg_data[msg_index[record]].acked = (char)2; } else { msg_data[msg_index[record]].acked = (char)1; } // Set the interval to zero so that we don't display it // anymore in the dialog. Same for tries. msg_data[msg_index[record]].interval = 0; msg_data[msg_index[record]].tries = 0; if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 1, seq %s, record %ld\n\n", msg_data[msg_index[record]].acked, seq, record); } } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } if (do_update) { update_messages(1); // Force an update // Call check_popup_messages() here in order to pop up any // closed Send Message dialogs. For first ack's or // CANCELLED messages it is less important, but for TIMEOUT // messages it is very important. // (void)check_popup_window(m_fill.call_sign, 2); // Calls update_messages() } } // Called when we receive a REJ packet (reject). Sets the "acked" // field in a Message to 4 to indicate that the message has been // rejected by the remote station. This gets rid of the // highlighting in the Send Message dialog for that message line. // This lets us know which messages have been rejected and which // have not. We use this in update_messages() to flag that // "*REJECTED*" should prefix the string. // // The most common source of REJ packets would be from sending to a // D700A who's buffers are full, so that it can't take another // message. // void msg_record_rej(char *to_call_sign, char *my_call, char *seq) { Message m_fill; long record; int do_update = 0; if (debug_level & 1) { fprintf(stderr,"Recording rej for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i], set the // "acked" field to four. substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if (record == -1L) // No match yet, try another tactic. { if (seq[2] == '}' && strlen(seq) == 3) { // Try it again without the trailing '}' character m_fill.from_call_sign[2] = '\0'; // Look for a message with the same to_call_sign, // my_call, and seq number (minus the trailing '}') record = msg_find_data(&m_fill); } } if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 4, seq %s, record %ld\n", msg_data[msg_index[record]].acked, seq, record); } // Only cause an update if this is the first rej. This // reduces dialog "flashing" a great deal if ( msg_data[msg_index[record]].acked == 0 ) { // Check for my callsign (including SSID). If found, // update any open message dialogs if (is_my_call(msg_data[msg_index[record]].from_call_sign, 1) ) { //fprintf(stderr,"From: %s\tTo: %s\n", // msg_data[msg_index[record]].from_call_sign, // msg_data[msg_index[record]].call_sign); do_update++; } } else // This message has already been acked. { } // Actually record the REJ here msg_data[msg_index[record]].acked = (char)4; // Set the interval to zero so that we don't display it // anymore in the dialog. Same for tries. msg_data[msg_index[record]].interval = 0; msg_data[msg_index[record]].tries = 0; if (debug_level & 1) { fprintf(stderr,"Found in msg db, updating acked field %d -> 4, seq %s, record %ld\n\n", msg_data[msg_index[record]].acked, seq, record); } } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } if (do_update) { update_messages(1); // Force an update // Call check_popup_messages() here in order to pop up any // closed Send Message dialogs. For first ack's or // CANCELLED messages it is less important, but for TIMEOUT // messages it is very important. // (void)check_popup_window(m_fill.call_sign, 2); // Calls update_messages() } } // Called from check_and_transmit_messages(). Updates the interval // field in our message record for the message currently being // transmitted. We'll use this in the Send Message dialog to // display the current message interval. // void msg_record_interval_tries(char *to_call_sign, char *my_call, char *seq, time_t interval, int tries) { Message m_fill; long record; if (debug_level & 1) { fprintf(stderr,"Recording interval for message to: %s, seq: %s\n", to_call_sign, seq); } // Find the corresponding message in msg_data[i] substr(m_fill.call_sign, to_call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, my_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Look for a message with the same to_call_sign, my_call, // and seq number record = msg_find_data(&m_fill); if(record != -1L) // Found a match! { if (debug_level & 1) { fprintf(stderr, "Found in msg db, updating interval field %ld -> 1, seq %s, record %ld\n", (long)msg_data[msg_index[record]].interval, seq, record); } msg_data[msg_index[record]].interval = interval; msg_data[msg_index[record]].tries = tries; } else { if (debug_level & 1) { fprintf(stderr,"Matching message not found\n"); } } update_messages(1); // Force an update } // Returns: time_t for last_ack_sent // -1 if the message doesn't pass our tests // 0 if it is a new message. // // Also returns the record number found if not passed a NULL pointer // in record_out or -1L if it's a new record. // time_t msg_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from, long *record_out) { Message m_fill; long record; char time_data[MAX_TIME]; int do_msg_update = 0; time_t last_ack_sent; int distance = -1; char temp[10]; int group_message = 0; if (debug_level & 1) { fprintf(stderr,"msg_data_add start\n"); } //fprintf(stderr,"from:%s, to:%s, seq:%s\n", from_call, call_sign, seq); // Set the default output condition. We'll change this later if // we need to. if (record_out != NULL) { *record_out = -1l; } // Check for some reasonable string in call_sign parameter if (call_sign == NULL || strlen(call_sign) == 0) { if (debug_level & 1) { fprintf(stderr,"msg_data_add():call_sign was NULL or empty, exiting\n"); } return((time_t)-1l); } //else //fprintf(stderr,"msg_data_add():call_sign: %s\n", call_sign); if ( (data != NULL) && (strlen(data) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 2) { fprintf(stderr,"msg_data_add: Message length too long\n"); } return((time_t)-1l); } substr(m_fill.call_sign, call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, from_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // If the sequence number is blank, then it may have been a query, // directed query, or group message. Assume it is a new message in // each case and add it. if (seq[0] != '\0') // Normal station->station messaging or { // bulletins // Look for a message with the same call_sign, // from_call_sign, and seq number record = msg_find_data(&m_fill); //fprintf(stderr,"RECORD %ld \n",record); //fprintf(stderr,"Normal station->station message\n"); } else // Group message/query/etc. { record = -1L; group_message++; // Flag it as a group message //fprintf(stderr,"Group message/query/etc\n"); } msg_clear_data(&m_fill); if(record != -1L) /* fill old data */ { msg_get_data(&m_fill, record); last_ack_sent = m_fill.last_ack_sent; //fprintf(stderr,"Found: last_ack_sent: %ld\n",m_fill.last_ack_sent); //fprintf(stderr,"Found a duplicate message. Updating fields, seq %s\n",seq); // If message is different this time, do an update to the // send message window and update the sec_heard field. The // remote station must have restarted and is re-using the // sequence numbers. What a pain! if (strcmp(m_fill.message_line,data) != 0) { m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"Message is different this time: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { do_msg_update++; } } // If message is the same, but the sec_heard field is quite // old (more than 8 hours), the remote station must have // restarted, is re-using the sequence numbers, and just // happened to send the same message with the same sequence // number. Again, what a pain! Either that, or we // connected to a spigot with a _really_ long queue! if (m_fill.sec_heard < (sec_now() - (8 * 60 * 60) )) { m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"Found >8hrs old: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { do_msg_update++; } } // Check for zero time if (m_fill.sec_heard == (time_t)0) { m_fill.sec_heard = sec_now(); fprintf(stderr,"Zero time on a previous message.\n"); } } else { // Only do this if it's a new message. This keeps things // more in sequence by not updating the time stamps // constantly on old messages that don't get ack'ed. m_fill.sec_heard = sec_now(); last_ack_sent = (time_t)0; //fprintf(stderr,"New msg: Setting last_ack_sent to 0\n"); if (type != MESSAGE_BULLETIN) // Not a bulletin { //fprintf(stderr,"Found new message\n"); do_msg_update++; // Always do an update to the // message window for new messages } } /* FROM */ m_fill.data_via=from; m_fill.active=RECORD_ACTIVE; m_fill.type=type; if (m_fill.heard_via_tnc != VIA_TNC) { m_fill.heard_via_tnc = (from == 'T') ? VIA_TNC : NOT_VIA_TNC; } distance = (int)(distance_from_my_station(from_call,temp,english_units) + 0.9999); if (distance != 0) // Have a posit from the sending station { m_fill.position_known = 1; //fprintf(stderr,"Position known: %s\n",from_call); } else { //fprintf(stderr,"Position not known: %s\n",from_call); } substr(m_fill.call_sign,call_sign,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign,from_call,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); // Update the message field substr(m_fill.message_line,data,MAX_MESSAGE_LENGTH); substr(m_fill.seq,seq,MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Create a timestamp from the current time xastir_snprintf(m_fill.packet_time, sizeof(m_fill.packet_time), "%s", get_time(time_data)); if(record == -1L) // No old record found { if (group_message) { m_fill.acked = 1; // Group msgs/queries need no ack } else { m_fill.acked = 0; // We can't have been acked yet } m_fill.interval = 0; m_fill.tries = 0; // We'll be sending an ack right away if this is a new // message, so might as well set the time now so that we // don't care about failing to set it in // msg_update_ack_stamp due to the record number being -1. m_fill.last_ack_sent = sec_now(); msg_input_database(&m_fill); // Create a new entry //fprintf(stderr,"No record found: Setting last_ack_sent to sec_now()00\n"); } else // Old record found { //fprintf(stderr,"Replacing the message in the database, seq %s\n",seq); msg_replace_data(&m_fill, record); // Copy fields from m_fill to record } /* display messages */ if (type == MESSAGE_MESSAGE) { all_messages(from,call_sign,from_call,data); } // Check for my callsign (including SSID). If found, update any // open message dialogs if ( is_my_call(m_fill.from_call_sign, 1) || is_my_call(m_fill.call_sign, 1) ) { if (do_msg_update) { update_messages(1); // Force an update } } if (debug_level & 1) { fprintf(stderr,"msg_data_add end\n"); } // Return the important variables we'll need if (record_out != NULL) { *record_out = record; } //fprintf(stderr,"\nrecord_out:%ld record %ld\n",*record_out,record); return(last_ack_sent); } // End of msg_data_add() // alert_data_add: Function which adds NWS weather alerts to the // alert hash. // // This function adds alerts directly to the alert hash, bypassing // the message list and associated message-scan functions. // void alert_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from) { Message m_fill; char time_data[MAX_TIME]; char user_base_dir[MAX_VALUE]; if (debug_level & 2) { fprintf(stderr,"alert_data_add start\n"); } if (log_wx_alert_data && from != DATA_VIA_FILE) { char temp_msg[MAX_MESSAGE_LENGTH+1]; // Attempt to reconstruct the original weather alert packet // here, minus the path. xastir_snprintf(temp_msg, sizeof(temp_msg), "%s>APRS::%-9s:%s{%s", from_call, call_sign, data, seq); log_data( get_user_base_dir(LOGFILE_WX_ALERT, user_base_dir, sizeof(user_base_dir)), temp_msg); // fprintf(stderr, "%s\n", temp_msg); } if ( (data != NULL) && (strlen(data) > MAX_MESSAGE_LENGTH) ) { if (debug_level & 2) { fprintf(stderr,"alert_data_add: Message length too long\n"); } return; } substr(m_fill.call_sign, call_sign, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign, from_call, MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.seq, seq, MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); m_fill.sec_heard = sec_now(); /* FROM */ m_fill.data_via=from; m_fill.active=RECORD_ACTIVE; m_fill.type=type; // We don't have a value filled in yet here! //if (m_fill.heard_via_tnc != VIA_TNC) m_fill.heard_via_tnc = (from == 'T') ? VIA_TNC : NOT_VIA_TNC; substr(m_fill.call_sign,call_sign,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.call_sign); substr(m_fill.from_call_sign,from_call,MAX_CALLSIGN); (void)remove_trailing_asterisk(m_fill.from_call_sign); // Update the message field substr(m_fill.message_line,data,MAX_MESSAGE_LENGTH); substr(m_fill.seq,seq,MAX_MESSAGE_ORDER); (void)remove_trailing_spaces(m_fill.seq); (void)remove_leading_spaces(m_fill.seq); // Create a timestamp from the current time xastir_snprintf(m_fill.packet_time, sizeof(m_fill.packet_time), "%s", get_time(time_data)); // Go try to add it to our alert hash. alert_build_list() will // check for duplicates before adding it. alert_build_list(&m_fill); // This function fills in the Shapefile filename and index // so that we can later draw it. fill_in_new_alert_entries(); if (debug_level & 2) { fprintf(stderr,"alert_data_add end\n"); } } // End of alert_data_add() // What I'd like to do for the following routine: Use // XmTextGetInsertionPosition() or XmTextGetCursorPosition() to // find the last of the text. Could also save the position for // each SendMessage window. Compare the timestamps of messages // found with the last update time. If newer, then add them to // the end. This should stop the incessant scrolling. // Another idea, easier method: Create a buffer. Snag out the // messages from the array and sort by time. Put them into a // buffer. Figure out the length of the text widget, and append // the extra length of the buffer onto the end of the text widget. // Once the message data is turned into a linked list, it might // be sorted already by time, so this window will look better // anyway. // Calling update_messages with force == 1 will cause an update // no matter what message_update_time() says. void update_messages(int force) { static XmTextPosition pos; char temp1[MAX_CALLSIGN+1]; char temp2[500]; char stemp[20]; long i; int mw_p; char *temp_ptr; if ( message_update_time() || force) { //fprintf(stderr,"update_messages()\n"); //fprintf(stderr,"Um %d\n",(int)sec_now() ); /* go through all mw_p's! */ // Perform this for each message window for (mw_p=0; msg_index && mw_p < MAX_MESSAGE_WINDOWS; mw_p++) { //pos=0; begin_critical_section(&send_message_dialog_lock, "db.c:update_messages" ); if (mw[mw_p].send_message_dialog!=NULL/* && mw[mw_p].message_group==1*/) { //fprintf(stderr,"\n"); //fprintf(stderr,"found send_message_dialog\n"); // Clear the text from message window XmTextReplace(mw[mw_p].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[mw_p].send_message_text), ""); // Snag the callsign you're dealing with from the message dialogue if (mw[mw_p].send_message_call_data != NULL) { temp_ptr = XmTextFieldGetString(mw[mw_p].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); new_message_data--; if (new_message_data<0) { new_message_data=0; } if(strlen(temp1)>0) // We got a callsign from the dialog so { // create a linked list of the message indexes in time-sorted order typedef struct _index_record { int index; time_t sec_heard; struct _index_record *next; } index_record; index_record *head = NULL; index_record *p_prev = NULL; index_record *p_next = NULL; // Allocate the first record (a dummy record) head = (index_record *)malloc(sizeof(index_record)); CHECKMALLOC(head); head->index = -1; head->sec_heard = (time_t)0; head->next = NULL; (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); pos = 0; // Loop through looking for messages to/from // that callsign (including SSID) for (i = 0; i < msg_index_end; i++) { if (msg_data[msg_index[i]].active == RECORD_ACTIVE && (strcmp(temp1, msg_data[msg_index[i]].from_call_sign) == 0 || strcmp(temp1,msg_data[msg_index[i]].call_sign) == 0) && (is_my_call(msg_data[msg_index[i]].from_call_sign, 1) || is_my_call(msg_data[msg_index[i]].call_sign, 1) || mw[mw_p].message_group ) ) { int done = 0; // Message matches our parameters so // save the relevant data about the // message in our linked list. Compare // the sec_heard field to see whether // we're higher or lower, and insert the // record at the correct spot in the // list. We end up with a time-sorted // list. p_prev = head; p_next = p_prev->next; while (!done && (p_next != NULL)) // Loop until end of list or record inserted { //fprintf(stderr,"Looping, looking for insertion spot\n"); if (p_next->sec_heard <= msg_data[msg_index[i]].sec_heard) { // Advance one record p_prev = p_next; p_next = p_prev->next; } else // We found the correct insertion spot { done++; } } //fprintf(stderr,"Inserting\n"); // Add the record in between p_prev and // p_next, even if we're at the end of // the list (in that case p_next will be // NULL. p_prev->next = (index_record *)malloc(sizeof(index_record)); CHECKMALLOC(p_prev->next); p_prev->next->next = p_next; // Link to rest of records or NULL p_prev->next->index = i; p_prev->next->sec_heard = msg_data[msg_index[i]].sec_heard; // Remember to free this entire linked list before exiting the loop for // this message window! } } // Done processing the entire list for this // message window. //fprintf(stderr,"Done inserting/looping\n"); if (head->next != NULL) // We have messages to display { int done = 0; //fprintf(stderr,"We have messages to display\n"); // Run through the linked list and dump the // info out. It's now in time-sorted order. // Another optimization would be to keep a count of records added, then // later when we were dumping it out to the window, only dump the last // XX records out. p_prev = head->next; // Skip the first dummy record p_next = p_prev->next; while (!done && (p_prev != NULL)) // Loop until end of list { int j = p_prev->index; // Snag the index out of the record char prefix[50]; char interval_str[50]; int offset = 22; // Offset for highlighting //fprintf(stderr,"\nLooping through, reading messages\n"); //fprintf(stderr,"acked: %d\n",msg_data[msg_index[j]].acked); // Message matches so snag the important pieces into a string xastir_snprintf(stemp, sizeof(stemp), "%c%c/%c%c %c%c:%c%c", msg_data[msg_index[j]].packet_time[0], msg_data[msg_index[j]].packet_time[1], msg_data[msg_index[j]].packet_time[2], msg_data[msg_index[j]].packet_time[3], msg_data[msg_index[j]].packet_time[8], msg_data[msg_index[j]].packet_time[9], msg_data[msg_index[j]].packet_time[10], msg_data[msg_index[j]].packet_time[11] ); // Somewhere in here we appear to be losing the first message. It // doesn't get written to the window later in the QSO. Same for // closing the window and re-opening it, putting the same callsign // in and pressing "New Call" button. First message is missing. // Label the message line with who sent it. // If acked = 2 a timeout has occurred // If acked = 3 a cancel has occurred if (msg_data[msg_index[j]].acked == 2) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB016") ); // "*TIMEOUT*" } else if (msg_data[msg_index[j]].acked == 3) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB017") ); // "*CANCELLED*" } else if (msg_data[msg_index[j]].acked == 4) { xastir_snprintf(prefix, sizeof(prefix), "%s ", langcode("WPUPMSB018") ); // "*REJECTED*" } else { prefix[0] = '\0'; } if (msg_data[msg_index[j]].interval) { xastir_snprintf(interval_str, sizeof(interval_str), ">%d/%lds", msg_data[msg_index[j]].tries + 1, (long)msg_data[msg_index[j]].interval); // Don't highlight the interval // value offset = offset + strlen(interval_str); } else { interval_str[0] = '\0'; } xastir_snprintf(temp2, sizeof(temp2), "%s %-9s%s>%s%s\n", // Debug code. Trying to find sorting error //"%ld %s %-9s>%s\n", //msg_data[msg_index[j]].sec_heard, stemp, msg_data[msg_index[j]].from_call_sign, interval_str, prefix, msg_data[msg_index[j]].message_line); //fprintf(stderr,"message: %s\n", msg_data[msg_index[j]].message_line); //fprintf(stderr,"update_messages: %s|%s", temp1, temp2); if (debug_level & 2) { fprintf(stderr,"update_messages: %s|%s\n", temp1, temp2); } // Replace the text from pos to pos+strlen(temp2) by the string "temp2" if (mw[mw_p].send_message_text != NULL) { // Insert the text at the end // XmTextReplace(mw[mw_p].send_message_text, // pos, // pos+strlen(temp2), // temp2); XmTextInsert(mw[mw_p].send_message_text, pos, temp2); // Set highlighting based on the // "acked" field. Callsign // match here includes SSID. //fprintf(stderr,"acked: %d\t",msg_data[msg_index[j]].acked); if ( (msg_data[msg_index[j]].acked == 0) // Not acked yet && ( is_my_call(msg_data[msg_index[j]].from_call_sign, 1)) ) { //fprintf(stderr,"Setting underline\t"); XmTextSetHighlight(mw[mw_p].send_message_text, pos+offset, pos+strlen(temp2), //XmHIGHLIGHT_SECONDARY_SELECTED); // Underlining XmHIGHLIGHT_SELECTED); // Reverse Video } else // Message was acked, get rid of highlighting { //fprintf(stderr,"Setting normal\t"); XmTextSetHighlight(mw[mw_p].send_message_text, pos+offset, pos+strlen(temp2), XmHIGHLIGHT_NORMAL); } //fprintf(stderr,"Text: %s\n",temp2); pos += strlen(temp2); } // Advance to the next record in the list p_prev = p_next; if (p_next != NULL) { p_next = p_prev->next; } } // End of while } // End of if else // No messages matched, list is empty { } // What does this do? Move all of the text? // if (pos > 0) { // if (mw[mw_p].send_message_text != NULL) { // XmTextReplace(mw[mw_p].send_message_text, // --pos, // XmTextGetLastPosition(mw[mw_p].send_message_text), // ""); // } // } //fprintf(stderr,"Free'ing list\n"); // De-allocate the linked list p_prev = head; while (p_prev != NULL) { //fprintf(stderr,"You're free!\n"); p_next = p_prev->next; free(p_prev); p_prev = p_next; } // Show the last added message in the window XmTextShowPosition(mw[mw_p].send_message_text, pos); } } } end_critical_section(&send_message_dialog_lock, "db.c:update_messages" ); } last_message_update = sec_now(); //fprintf(stderr,"Message index end: %ld\n",msg_index_end); } } void mdelete_messages_from(char *from) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, my_callsign) == 0 && strcmp(msg_data[i].from_call_sign, from) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdelete_messages_to(char *to) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, to) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdelete_messages(char *to_from) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if (strcmp(msg_data[i].call_sign, to_from) == 0 || strcmp(msg_data[i].from_call_sign, to_from) == 0) { msg_data[i].active = RECORD_NOTACTIVE; } } void mdata_delete_type(const char msg_type, const time_t reference_time) { long i; // Mark message records with RECORD_NOTACTIVE. This will mark // them for re-use. for (i = 0; msg_index && i < msg_index_end; i++) if ((msg_type == '\0' || msg_type == msg_data[i].type) && msg_data[i].active == RECORD_ACTIVE && msg_data[i].sec_heard < reference_time) { msg_data[i].active = RECORD_NOTACTIVE; } } void check_message_remove(time_t curr_sec) // called in timing loop { // Time to check for old messages again? (Currently every ten // minutes) #ifdef EXPIRE_DEBUG if ( last_message_remove < (curr_sec - DEBUG_MESSAGE_REMOVE_CYCLE) ) #else // EXPIRE_DEBUG if ( last_message_remove < (curr_sec - MESSAGE_REMOVE_CYCLE) ) #endif { // Yes it is. Mark all messages that are older than // sec_remove with the RECORD_NOTACTIVE flag. This will // mark them for re-use. #ifdef EXPIRE_DEBUG mdata_delete_type('\0', curr_sec-DEBUG_MESSAGE_REMOVE); #else // EXPIRE_DEBUG mdata_delete_type('\0', curr_sec-sec_remove); #endif last_message_remove = curr_sec; } // Should we sort them at this point so that the unused ones are // near the end? It looks like the message input functions do // this, so I guess we don't need to do it here. } void mscan_file(char msg_type, void (*function)(Message *)) { long i; for (i = 0; msg_index && i < msg_index_end; i++) if ((msg_type == '\0' || msg_type == msg_data[msg_index[i]].type) && msg_data[msg_index[i]].active == RECORD_ACTIVE) { function(&msg_data[msg_index[i]]); } } void mprint_record(Message *m_fill) { fprintf(stderr, "%-9s>%-9s %s:%5s %s:%c :%s\n", m_fill->from_call_sign, m_fill->call_sign, langcode("WPUPMSB013"), // "seq" m_fill->seq, langcode("WPUPMSB014"), // "type" m_fill->type, m_fill->message_line); } void mdisplay_file(char msg_type) { fprintf(stderr,"\n\n"); mscan_file(msg_type, mprint_record); fprintf(stderr,"\tmsg_index_end %ld, msg_index_max %ld\n", msg_index_end, msg_index_max); } /////////////////////////////////////// Station Data /////////////////////////////////////////// void pad_callsign(char *callsignout, char *callsignin) { int i,l; l=(int)strlen(callsignin); for(i=0; i<9; i++) { if(i= 'a' && data <= 'j') { // Found a compressed posit numerical overlay data = data - 'a'+'0'; // Convert to a digit } if ( (data >= '0' && data <= '9') || (data >= 'A' && data <= 'Z') ) { // Found normal overlay character fill->aprs_symbol.aprs_type = '\\'; fill->aprs_symbol.special_overlay = data; } else { // Bad overlay character. Don't use it. Insert the // normal alternate table character instead. fill->aprs_symbol.aprs_type = '\\'; fill->aprs_symbol.special_overlay='\0'; } } else // No overlay character { fill->aprs_symbol.aprs_type = data; fill->aprs_symbol.special_overlay='\0'; } fill->aprs_symbol.aprs_symbol = symbol; } APRS_Symbol *id_callsign(char *call_sign, char * to_call) { char *ptr; char *id = "/aUfbYX's>,")) != NULL) { *ptr = '\0'; } if (strlen(hold) >= 2) { switch (hold[0]) { case 'A': symbol.aprs_type = '\\'; /* Falls through. */ case 'P': if (('0' <= hold[1] && hold[1] <= '9') || ('A' <= hold[1] && hold[1] <= 'Z')) { symbol.aprs_symbol = hold[1]; } break; case 'O': symbol.aprs_type = '\\'; /* Falls through. */ case 'B': switch (hold[1]) { case 'B': symbol.aprs_symbol = '!'; break; case 'C': symbol.aprs_symbol = '"'; break; case 'D': symbol.aprs_symbol = '#'; break; case 'E': symbol.aprs_symbol = '$'; break; case 'F': symbol.aprs_symbol = '%'; break; case 'G': symbol.aprs_symbol = '&'; break; case 'H': symbol.aprs_symbol = '\''; break; case 'I': symbol.aprs_symbol = '('; break; case 'J': symbol.aprs_symbol = ')'; break; case 'K': symbol.aprs_symbol = '*'; break; case 'L': symbol.aprs_symbol = '+'; break; case 'M': symbol.aprs_symbol = ','; break; case 'N': symbol.aprs_symbol = '-'; break; case 'O': symbol.aprs_symbol = '.'; break; case 'P': symbol.aprs_symbol = '/'; break; } break; case 'D': symbol.aprs_type = '\\'; /* Falls through. */ case 'H': switch (hold[1]) { case 'S': symbol.aprs_symbol = '['; break; case 'T': symbol.aprs_symbol = '\\'; break; case 'U': symbol.aprs_symbol = ']'; break; case 'V': symbol.aprs_symbol = '^'; break; case 'W': symbol.aprs_symbol = '_'; break; case 'X': symbol.aprs_symbol = '`'; break; } break; case 'N': symbol.aprs_type = '\\'; /* Falls through. */ case 'M': switch (hold[1]) { case 'R': symbol.aprs_symbol = ':'; break; case 'S': symbol.aprs_symbol = ';'; break; case 'T': symbol.aprs_symbol = '<'; break; case 'U': symbol.aprs_symbol = '='; break; case 'V': symbol.aprs_symbol = '>'; break; case 'W': symbol.aprs_symbol = '?'; break; case 'X': symbol.aprs_symbol = '@'; break; } break; case 'Q': symbol.aprs_type = '\\'; /* Falls through. */ case 'J': switch (hold[1]) { case '1': symbol.aprs_symbol = '{'; break; case '2': symbol.aprs_symbol = '|'; break; case '3': symbol.aprs_symbol = '}'; break; case '4': symbol.aprs_symbol = '~'; break; } break; case 'S': symbol.aprs_type = '\\'; /* Falls through. */ case 'L': if ('A' <= hold[1] && hold[1] <= 'Z') { symbol.aprs_symbol = tolower((int)hold[1]); } break; } if (hold[2]) { if (hold[2] >= 'a' && hold[2] <= 'j') { // Compressed mode numeric overlay symbol.special_overlay = hold[2] - 'a' + '0'; } else if ( (hold[2] >= '0' && hold[2] <= '9') || (hold[2] >= 'A' && hold[2] <= 'Z') ) { // Normal overlay character symbol.special_overlay = hold[2]; } else { // Bad overlay character found symbol.special_overlay = '\0'; } } else { // No overlay character found symbol.special_overlay = '\0'; } } } return(&symbol); } /******************************** Sort begin *************************** ****/ void clear_sort_file(char *filename) { char ptr_filename[400]; xastir_snprintf(ptr_filename, sizeof(ptr_filename), "%s-ptr", filename); (void)unlink(filename); (void)unlink(ptr_filename); } void sort_reset_pointers(FILE *pointer,long new_data_ptr,long records, int type, long start_ptr) { long temp[13000]; long buffn,start_buffn; long cp_records; long max_buffer; int my_size; my_size=(int)sizeof(new_data_ptr); max_buffer=13000l; if(type==0) { /* before start_ptr */ /* copy back pointers */ for(buffn=records; buffn > start_ptr; buffn-=max_buffer) { start_buffn=buffn-max_buffer; if(start_buffn0) { /* file name comes after */ /*fprintf(stderr,"END - After end\n");*/ done=1; /* now place pointer after end */ } else { if((record_mid==record_start) || (record_mid==record_end)) { /* no mid for compare check to see if in the middle */ /*fprintf(stderr,"END - NO Middle\n");*/ done=1; /* now place pointer before start*/ if (record_mid==record_start) { sort_reset_pointers(pointer,new_data_ptr,records,0,record_mid+1); } else { sort_reset_pointers(pointer,new_data_ptr,records,0,record_mid-1); } } else { /* get data for record mid */ (void)fseek(pointer,(ptr_size*record_mid),SEEK_SET); if (fread(&data_ptr,(size_t)ptr_size,1,pointer) != 0) { // we are explicitly // ignoring the return // value, but are doing it // this way to silence GCC // warnings } (void)fseek(my_data,data_ptr,SEEK_SET); if(fread(file_data,(size_t)size,1,my_data)==1) { /* COMPARE HERE */ if (1 != sscanf(file_data,"%1999s",tempfile)) { fprintf(stderr,"sort_input_database(4): sscanf failed to parse\n"); } if(strcasecmp(tempfill,tempfile)<0) { /* checking comes before */ /*record_start=0l;*/ record_end=record_mid; record_mid=record_start+(record_end-record_start)/2; /*fprintf(stderr,"TOP %ld, mid %ld\n",record_mid,record_end);*/ } else { /* checking comes after*/ record_start=record_mid; /*record_end=end*/ record_mid=record_start+(record_end-record_start)/2; /*fprintf(stderr,"BOTTOM start %ld, mid %ld\n",record_start,record_mid);*/ } } } } } } } } } } else { fprintf(stderr,"Could not open file %s\n",filename); } } else { fprintf(stderr,"Could not open file %s\n",filename); } if(my_data!=NULL) { (void)fclose(my_data); } if(pointer!=NULL) { (void)fclose(pointer); } return(return_records); } /******************** sort end **********************/ // is_altnet() // // Returns true if station fits the current altnet description. // int is_altnet(DataRow *p_station) { char temp_altnet_call[20+1]; char temp2[20+1]; char *net_ptr; int altnet_match; int result; // Snag a possible altnet call out of the record for later use if (p_station->node_path_ptr != NULL) { substr(temp_altnet_call, p_station->node_path_ptr, MAX_CALLSIGN); } else { temp_altnet_call[0] = '\0'; } // Save for later xastir_snprintf(temp2, sizeof(temp2), "%s", temp_altnet_call); if ((net_ptr = strchr(temp_altnet_call, ','))) { *net_ptr = '\0'; // Chop the string at the first ',' character } for (altnet_match = (int)strlen(altnet_call); altnet && altnet_call[altnet_match-1] == '*'; altnet_match--); result = (!strncmp(temp_altnet_call, altnet_call, (size_t)altnet_match) || !strcmp(temp_altnet_call, "local") || !strncmp(temp_altnet_call, "SPC", 3) || !strcmp(temp_altnet_call, "SPECL") // || is_my_call(p_station->call_sign,1)); // Check SSID as well || ( is_my_station(p_station) ) ) ; // It's my callsign/SSID if ( (debug_level & 1) && result ) { fprintf(stderr,"%s %-9s %s\n", altnet_call, temp_altnet_call, temp2 ); } return(result); } // Function which checks various filtering criteria (the Select struct) // and decides whether this station/object should be displayed. // // 0 = don't draw this station/object // 1 = ok to draw this station/object // int ok_to_draw_station(DataRow *p_station) { time_t secs_now = sec_now(); // Check overall flag if (Select_.none) { return 0; } // Check tactical flag if (Select_.tactical && (p_station->tactical_call_sign == NULL || p_station->tactical_call_sign[0] == '\0')) { return 0; } // Check for my station and my objects/items // if (strcmp(p_station->call_sign, my_callsign) == 0 // || (is_my_call(p_station->origin, 1) // If station is owned by me (including SSID) // && ( p_station->flag & ST_OBJECT // And it's an object // || p_station->flag & ST_ITEM) ) ) { // or an item // if ( is_my_station(p_station) || is_my_object_item(p_station) ) { if ( is_my_station(p_station) ) { if (!Select_.mine) { return 0; } } // Not mine, so check these next things else { // Check whether we wish to display TNC heard stations if (p_station->flag & ST_VIATNC) { if (!Select_.tnc) { return 0; } // Check whether we wish to display directly heard stations if (p_station->flag & ST_DIRECT && secs_now < (p_station->direct_heard + st_direct_timeout)) { if (!Select_.direct) { return 0; } } // Check whether we wish to display stations heard via a digi else { if (!Select_.via_digi) { return 0; } } } // Check whether we wish to display net stations else { if (!Select_.net) { return 0; } } //N7IPB - check for aircraft and if so check aircraft timeout // return 0 if timedout - else continue if ((aircraft_sec_clear != 0) && ((p_station->aprs_symbol.aprs_symbol == '^') || (p_station->aprs_symbol.aprs_symbol == '\'') || (p_station->aprs_symbol.aprs_symbol == 'X'))) { if ((p_station->sec_heard + (aircraft_sec_clear * 5)) < secs_now) { return 0; } } // Check if we want to display data past the clear time if (!Select_.old_data) { if ((p_station->sec_heard + sec_clear) < secs_now) { return 0; } } } // Check whether object or item if (p_station->flag & (ST_OBJECT | ST_ITEM)) { // Check whether we wish to display objects/items if (!Select_.objects || (!Select_.weather_objects && !Select_.gauge_objects && !Select_.aircraft_objects && !Select_.vessel_objects && !Select_.other_objects)) { return 0; } // Check if WX info and we wish to see it if (p_station->weather_data) { return Select_.weather_objects; } // Check if water gauge and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'w') { return Select_.gauge_objects; } // Check if aircraft and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && ((p_station->aprs_symbol.aprs_symbol == '^') || (p_station->aprs_symbol.aprs_symbol == '\'') || (p_station->aprs_symbol.aprs_symbol == 'X')) ) { return Select_.aircraft_objects; } // Check if vessel and we wish to see it else if (p_station->aprs_symbol.aprs_type == '/' && ((p_station->aprs_symbol.aprs_symbol == 's') || (p_station->aprs_symbol.aprs_symbol == 'Y')) ) { return Select_.vessel_objects; } // Check if we wish to see other objects/items else { return Select_.other_objects; } } else // Not an object or item { if (!Select_.stations || (!Select_.fixed_stations && !Select_.moving_stations && !Select_.weather_stations)) { return 0; } // Check if we wish to see weather stations if (p_station->weather_data) { // We have weather data // Check whether it is a citizen's weather station. // Note that there are quite a few countries with two-letter // prefixes whose second letter is W, so let's be careful how we // filter here. // All Citizen's weather stations seen to date have had // CW through GW and then four digits. There will undoubtedly be // more added in future years, so let's not be *too* restrictive, // but let's not be too aggressive, either. if (((p_station->call_sign[0] >= 'C' && p_station->call_sign[0] <= 'G') || (p_station->call_sign[0] >= 'c' && p_station->call_sign[0] <= 'g')) && (p_station->call_sign[1] == 'W' || p_station->call_sign[1] == 'w')) { if ( is_num_chr(p_station->call_sign[2]) && is_num_chr(p_station->call_sign[3]) && is_num_chr(p_station->call_sign[4]) && is_num_chr(p_station->call_sign[5]) ) { return(Select_.weather_stations && Select_.CWOP_wx_stations); } else { return Select_.weather_stations; } } else { return Select_.weather_stations; } } // Check if we wish to see other stations else { if (p_station->flag & ST_MOVING) { return Select_.moving_stations; } else { return Select_.fixed_stations; } } } } int heard_via_tnc_in_past_hour(char *call) { DataRow *p_station; int in_hour; in_hour=0; if (search_station_name(&p_station,call,1)) // find call { // Check the heard_via_tnc_last_time timestamp. This is a // timestamp that is saved each time a station is heard via // RF. It is initially set to 0. It does not get reset // when a packet comes in via a non-TNC interface. // if (p_station->heard_via_tnc_last_time) // non-zero entry { // Should we check to see if the last packet was message // capable? // Decide whether it was heard on a TNC interface within // the hour in_hour = (int)((p_station->heard_via_tnc_last_time+3600l) > sec_now()); if(debug_level & 2) fprintf(stderr, "Call %s: %ld %ld ok %d\n", call, (long)(p_station->heard_via_tnc_last_time), (long)sec_now(), in_hour); } else { if (debug_level & 2) { fprintf(stderr,"Call %s Not heard via tnc\n",call); } } } else { if (debug_level & 2) { fprintf(stderr,"IG:station not found\n"); } } return(in_hour); } //////////////////////////////////// Weather Data ////////////////////////////////////////////////// /* valid characters for APRS weather data fields */ int is_aprs_chr(char ch) { if (isdigit((int)ch) || ch==' ' || ch=='.' || ch=='-') { return(1); } else { return(0); } } int count_filler_chars(char ch) { if (isdigit((int)ch) || ch==' ' || ch=='.' || ch=='-') { return(1); } else { return(0); } } /* check data format 123 ___ ... */ // We wish to count how many ' ' or '.' characters we find. If it // equals zero or the field width, it might be a weather field. If // not, then it might be part of a comment field or something else. // int is_weather_data(char *data, int len) { int ok = 1; int i; int count = 0; for (i=0; ok && i= 8 && data[0] =='g' && is_weather_data(&data[1],3) && data[4] =='t' && is_weather_data(&data[5],3)) { // Snag WX course/speed from compressed position data. // This speed is in knots. This assumes that we've // already extracted speed/course from the compressed // packet. extract_comp_position() extracts // course/speed as well. memcpy(speed, p_station->speed, sizeof(speed)); speed[sizeof(speed)-1] = '\0'; // Terminate string memcpy(course, p_station->course, sizeof(course)); course[sizeof(course)-1] = '\0'; // Terminate string in_knots = 1; //fprintf(stderr,"Found compressed wx\n"); } // Look for weather data in non-fixed locations (RAWS WX // Stations?) else if ( strlen(data) >= 8 && test_extract_weather_item(data,'g',3) && test_extract_weather_item(data,'t',3) ) { // Snag WX course/speed from compressed position data. // This speed is in knots. This assumes that we've // already extracted speed/course from the compressed // packet. extract_comp_position() extracts // course/speed as well. memcpy(speed, p_station->speed, sizeof(speed)); speed[sizeof(speed)-1] = '\0'; // Terminate string memcpy(course, p_station->course, sizeof(course)); course[sizeof(course)-1] = '\0'; // Terminate string in_knots = 1; //fprintf(stderr,"Found compressed WX in non-fixed locations! %s:%s\n", // p_station->call_sign,data); } else // No weather data found { ok = 0; //fprintf(stderr,"No compressed wx\n"); } } else // Look for non-compressed weather data { // Look for weather data in defined locations first if (strlen(data)>=15 && data[3]=='/' && is_weather_data(data,3) && is_weather_data(&data[4],3) && data[7] =='g' && is_weather_data(&data[8], 3) && data[11]=='t' && is_weather_data(&data[12],3)) // Complete Weather Report { // Get speed/course. Speed is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { // Try to get speed/course from 's' and 'c' fields // (another wx format). Speed is in mph. (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found Complete Weather Report\n"); } // Look for date/time and weather in fixed locations first else if (strlen(data)>=16 && data[0] =='c' && is_weather_data(&data[1], 3) && data[4] =='s' && is_weather_data(&data[5], 3) && data[8] =='g' && is_weather_data(&data[9], 3) && data[12]=='t' && is_weather_data(&data[13],3)) // Positionless Weather Data { //fprintf(stderr,"Found positionless wx data\n"); // Try to snag speed/course out of first 7 bytes. Speed // is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { //fprintf(stderr,"Trying again for course/speed\n"); // Also try to get speed/course from 's' and 'c' fields // (another wx format) (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found weather\n"); } // Look for weather data in non-fixed locations (RAWS WX // Stations?) else if (strlen (data) >= 16 && test_extract_weather_item(data,'h',2) && test_extract_weather_item(data,'g',3) && test_extract_weather_item(data,'t',3) ) { // Try to snag speed/course out of first 7 bytes. Speed // is in knots. (void)extract_speed_course(data,speed,course); in_knots = 1; // Either one not found? Try again. if ( (speed[0] == '\0') || (course[0] == '\0') ) { // Also try to get speed/course from 's' and 'c' fields // (another wx format) (void)extract_weather_item(data,'c',3,course); // wind direction (in degrees) (void)extract_weather_item(data,'s',3,speed); // sustained one-minute wind speed (in mph) in_knots = 0; } //fprintf(stderr,"Found WX in non-fixed locations! %s:%s\n", // p_station->call_sign,data); } else // No weather data found { ok = 0; //fprintf(stderr,"No wx found\n"); } } if (ok) { ok = get_weather_record(p_station); // get existing or create new weather record } if (ok) { weather = p_station->weather_data; // Copy into weather speed variable. Convert knots to mph // if necessary. if (in_knots) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", atoi(speed) * 1.1508); // Convert knots to mph } else { // Already in mph. Copy w/no conversion. xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%s", speed); } xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%s", course); if (compr) // course/speed was taken from normal data, delete that { // fix me: we delete a potential real speed/course now // we should differentiate between normal and weather data in compressed position decoding... // p_station->speed_time[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; } (void)extract_weather_item(data,'g',3,weather->wx_gust); // gust (peak wind speed in mph in the last 5 minutes) (void)extract_weather_item(data,'t',3,weather->wx_temp); // temperature (in deg Fahrenheit), could be negative (void)extract_weather_item(data,'r',3,weather->wx_rain); // rainfall (1/100 inch) in the last hour (void)extract_weather_item(data,'p',3,weather->wx_prec_24); // rainfall (1/100 inch) in the last 24 hours (void)extract_weather_item(data,'P',3,weather->wx_prec_00); // rainfall (1/100 inch) since midnight if (extract_weather_item(data,'h',2,weather->wx_hum)) // humidity (in %, 00 = 100%) { xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d",(atoi(weather->wx_hum)+99)%100+1); } if (extract_weather_item(data,'b',5,weather->wx_baro)) // barometric pressure (1/10 mbar / 1/10 hPascal) xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", (float)(atoi(weather->wx_baro)/10.0)); // If we parsed a speed/course, a second 's' parameter means // snowfall. Try to parse it, but only in the case where // we've parsed speed out of this packet already. if ( (speed[0] != '\0') && (course[0] != '\0') ) { (void)extract_weather_item(data,'s',3,weather->wx_snow); // snowfall, inches in the last 24 hours } (void)extract_weather_item(data,'L',3,temp); // luminosity (in watts per square meter) 999 and below (void)extract_weather_item(data,'l',3,temp); // luminosity (in watts per square meter) 1000 and above (void)extract_weather_item(data,'#',3,temp); // raw rain counter (void)extract_weather_item(data,'F',3,weather->wx_fuel_temp); // Fuel Temperature in °F (RAWS) if (extract_weather_item(data,'f',2,weather->wx_fuel_moisture))// Fuel Moisture (RAWS) (in %, 00 = 100%) xastir_snprintf(weather->wx_fuel_moisture, sizeof(weather->wx_fuel_moisture), "%03d", (atoi(weather->wx_fuel_moisture)+99)%100+1); // extract_weather_item(data,'w',3,temp); // ?? text wUII // now there should be the name of the weather station... // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); // Set the timestamp in the weather record so that we can // decide whether or not to "ghost" the weather data later. weather->wx_sec_time=sec_now(); // weather->wx_data=1; // we don't need this // case ('.'):/* skip */ // wx_strpos+=4; // break; // default: // wx_done=1; // weather->wx_type=data[wx_strpos]; // if(strlen(data)>wx_strpos+1) // xastir_snprintf(weather->wx_station, // sizeof(weather->wx_station), // "%s", // data+wx_strpos+1); // break; } return(ok); } // Initial attempt at decoding tropical storm, tropical depression, // and hurricane data. // // This data can be in an Object report, but can also be in an Item // or position report. // "/TS" = Tropical Storm // "/HC" = Hurricane // "/TD" = Tropical Depression // "/TY" = Typhoon // "/ST" = Super Typhoon // "/SC" = Severe Cyclone // The symbol will be either "\@" for current position, or "/@" for // predicted position. // int extract_storm(DataRow *p_station, char *data, int UNUSED(compr) ) { char time_data[MAX_TIME]; int ok = 1; WeatherRow *weather; char course[4]; char speed[4]; // Speed in knots char *p, *p2; // Should probably encode the storm type in the weather object and // print it out in plain text in the Station Info dialog. if ((p = strstr(data, "/TS")) != NULL) { // We have a Tropical Storm //fprintf(stderr,"Tropical Storm! %s\n",data); } else if ((p = strstr(data, "/TD")) != NULL) { // We have a Tropical Depression //fprintf(stderr,"Tropical Depression! %s\n",data); } else if ((p = strstr(data, "/HC")) != NULL) { // We have a Hurricane //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/TY")) != NULL) { // We have a Typhoon //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/ST")) != NULL) { // We have a Super Typhoon //fprintf(stderr,"Hurricane! %s\n",data); } else if ((p = strstr(data, "/SC")) != NULL) { // We have a Severe Cyclone //fprintf(stderr,"Hurricane! %s\n",data); } else // Not one of the three we're trying to decode { ok = 0; return(ok); } //fprintf(stderr,"\n%s\n",data); // Back up 7 spots to try to extract the next items p2 = p - 7; if (p2 >= data) { // Attempt to extract course/speed. Speed in knots. if (!extract_speed_course(p2,speed,course)) { // No speed/course to extract //fprintf(stderr,"No speed/course found\n"); ok = 0; return(ok); } } else // Not enough characters for speed/course. Must have { // guessed wrong on what type of data it is. //fprintf(stderr,"No speed/course found 2\n"); ok = 0; return(ok); } //fprintf(stderr,"%s\n",data); if (ok) { // If we got this far, we have speed/course and know what type // of storm it is. //fprintf(stderr,"Speed: %s, Course: %s\n",speed,course); ok = get_weather_record(p_station); // get existing or create new weather record } if (ok) { // p_station->speed_time[0] = '\0'; p_station->weather_data->wx_storm = 1; // We found a storm // Note that speed is in knots. If we were stuffing it into // "wx_speed" we'd have to convert it to MPH. if (strcmp(speed," ") != 0 && strcmp(speed,"...") != 0) { xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%s", speed); } else { p_station->speed[0] = '\0'; } if (strcmp(course," ") != 0 && strcmp(course,"...") != 0) xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", course); else { p_station->course[0] = '\0'; } weather = p_station->weather_data; p2++; // Skip the description text, "/TS", "/HC", "/TD", "/TY", "/ST", or "/SC" // Extract the sustained wind speed in knots if(extract_weather_item(p2,'/',3,weather->wx_speed)) // Convert from knots to MPH xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%0.1f", atof(weather->wx_speed) * 1.1508); //fprintf(stderr,"%s\n",data); // Extract gust speed in knots if (extract_weather_item(p2,'^',3,weather->wx_gust)) // gust (peak wind speed in knots) // Convert from knots to MPH xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%0.1f", atof(weather->wx_gust) * 1.1508); //fprintf(stderr,"%s\n",data); // Pressure is already in millibars/hPa. No conversion // needed. if (extract_weather_item(p2,'/',4,weather->wx_baro)) // barometric pressure (1/10 mbar / 1/10 hPascal) xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", atof(weather->wx_baro)); //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'>',3,weather->wx_hurricane_radius); // Nautical miles //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'&',3,weather->wx_trop_storm_radius); // Nautical miles //fprintf(stderr,"%s\n",data); (void)extract_weather_item(p2,'%',3,weather->wx_whole_gale_radius); // Nautical miles //fprintf(stderr,"%s\n",data); // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); // Set the timestamp in the weather record so that we can // decide whether or not to "ghost" the weather data later. weather->wx_sec_time=sec_now(); } return(ok); } /* * Look for information about other points associated with this station. * If found, compute the coordinates and save the information in the * station structure. * KG4NBB */ // If remove_string == 0, don't remove the string from the comment // field. Useful for objects/items where we need to retransmit the // string unchanged. #define MULTI_DEBUG 2048 #define LBRACE '{' #define RBRACE '}' #define START_STR " }" static void extract_multipoints(DataRow *p_station, char *data, int UNUSED(type), int remove_string) { // If they're in there, the multipoints start with the // sequence and end with a . // In addition, there must be no spaces in there, and there // must be an even number of characters (after the lead-in). char *p, *p2; int found = 0; char *end; int data_size; if (debug_level & MULTI_DEBUG) fprintf(stderr,"extract_multipoints: start processing %s\n", p_station->call_sign); if (data == NULL) { if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: No Data, returning\n"); } return; } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"Data: %s\t\t\n", data); } data_size = strlen(data); end = data + (strlen(data) - 7); // 7 == 3 lead-in chars, plus 2 points p_station->num_multipoints = 0; /* for (p = data; !found && p <= end; ++p) { if (*p == ' ' && *(p+1) == RBRACE && islower((int)*(p+2)) && isdigit((int)*(p+3)) && (p2 = strchr(p+4, LBRACE)) != NULL && ((p2 - p) % 2) == 1) { found = 1; } } */ // Start looking at the beginning of the data. p = data; if (debug_level & MULTI_DEBUG) { if (strstr(p,START_STR) == NULL) { fprintf(stderr," Data does not start with space-brace, it starts with %c%c\n", p[0],p[1]); } else { fprintf(stderr," Data starts with space-brace\n"); } } // Look for the opening string. while (!found && p < end && (p = strstr(p, START_STR)) != NULL) { // The opening string was found. Check the following information. if (debug_level & MULTI_DEBUG) fprintf(stderr," Found opening brace, next chars are %c %c %c\n", *(p+2),*(p+3),*(p+4)); if (islower((int)*(p+2)) && isdigit((int)*(p+3)) && (p2 = strchr(p+4, LBRACE)) != NULL && ((p2 - p) % 2) == 1) { // It all looks good! found = 1; } else { // The following characters are not right. Advance and // look again. if (debug_level & MULTI_DEBUG) { fprintf(stderr," Found opening string (}) but next characters are not right: %c %c %c\n",*(p+2),*(p+3),*(p+4)); } ++p; } } if (found) { long multiplier; double d; char *m_start = p; // Start of multipoint string char ok = 1; if (debug_level & MULTI_DEBUG) { fprintf(stderr,"station %s contains \"%s\"\n", p_station->call_sign, p); } // The second character (the lowercase) indicates additional style information, // such as color, line type, etc. p_station->style = *(p+2); // The third character (the digit) indicates the way the points should be // used. They may be used to draw a closed polygon, a series of line segments, // etc. p_station->type = *(p+3); // The fourth character indicates the scale of the coordinates that // follow. It may range from '!' to '|' (124). The value represents the // unit of measure (1, 0.1, 0.001, etc., in degrees) used in the offsets. // // Use the following formula to convert the char to the value: // (10 ^ ((c - 33) / 20)) / 10000 degrees // // Finally we have to convert to Xastir units. Xastir stores coordinates // as hudredths of seconds. There are 360,000 of those per degree, so we // need to multiply by that factor so our numbers will be converted to // Xastir units. p = p + 4; if (*p < '!' || *p > '|') { fprintf(stderr,"extract_multipoints: invalid scale character %d\n", *p); ok = 0; // Failure } else { d = (double)(*p); d = pow(10.0, ((d - 33) / 20)) / 10000.0 * 360000.0; multiplier = (long)d; if (debug_level & MULTI_DEBUG) { fprintf(stderr," multiplier factor is: %c %d %f (%ld)\n", *p, *p, d, multiplier); } ++p; // The remaining characters are in pairs. Each pair is the // offset lat and lon for one of the points. (The offset is // from the actual location of the object.) Convert each // character to its numeric value and save it. while (*p != LBRACE && p_station->num_multipoints < MAX_MULTIPOINTS) { // The characters are in the range '"' (34 decimal) to 'z' (122). They // encode values in the range -44 to +44. To convert to the correct // value 78 is subtracted from the character's value. int lat_val = *p - 78; int lon_val = *(p+1) - 78; // Check for correct values. if (lon_val < -44 || lon_val > 44 || lat_val < -44 || lat_val > 44) { char temp[MAX_LINE_SIZE+1]; int i; // Filter the string so we don't send strange // chars to the xterm for (i = 0; i < (int)strlen(data); i++) { temp[i] = data[i] & 0x7f; if ( (temp[i] < 0x20) || (temp[i] > 0x7e) ) { temp[i] = ' '; } } temp[strlen(data)] = '\0'; fprintf(stderr,"extract_multipoints: invalid value in (filtered) \"%s\": %d,%d\n", temp, lat_val, lon_val); p_station->num_multipoints = 0; // forget any points we already set ok = 0; // Failure to decode break; } // Malloc the storage area for this if we don't have // it yet. if (p_station->multipoint_data == NULL) { //fprintf(stderr, "Malloc'ing MultipointRow record, %s\n", p_station->call_sign); p_station->multipoint_data = malloc(sizeof(MultipointRow)); if (p_station->multipoint_data == NULL) { p_station->num_multipoints = 0; fprintf(stderr,"Couldn't malloc MultipointRow'\n"); if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: Malloc failure, returning\n"); } return; } } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"computed offset %d,%d\n", lat_val, lon_val); } // Add the offset to the object's position to obtain the position of the point. // Note that we're working in Xastir coordinates, and in North America they // are exactly opposite to lat/lon (larger numbers are farther east and south). // An offset with a positive value means that the point should be north and/or // west of the object, so we have to *subtract* the offset to get the correct // placement in Xastir coordinates. // TODO: Consider what we should do in the other geographic quadrants. Should we // check here for the correct sign of the offset? Or should the program that // creates the offsets take that into account? p_station->multipoint_data->multipoints[p_station->num_multipoints][0] = p_station->coord_lon - (lon_val * multiplier); p_station->multipoint_data->multipoints[p_station->num_multipoints][1] = p_station->coord_lat - (lat_val * multiplier); if (debug_level & MULTI_DEBUG) fprintf(stderr, "computed point %ld, %ld\n", p_station->multipoint_data->multipoints[p_station->num_multipoints][0], p_station->multipoint_data->multipoints[p_station->num_multipoints][1]); p += 2; ++p_station->num_multipoints; } // End of while loop } if (ok && remove_string) { // We've successfully decoded a multipoint object? // Remove the multipoint strings (and the sequence // number at the end if present) from the data string. // m_start points to the first character (a space). 'p' // should be pointing at the LBRACE character. // Make 'p' point to just after the end of the chars while ( (p < data+strlen(data)) && (*p != ' ') ) { p++; } // The string that 'p' points to now may be empty // Truncate "data" at the starting brace - 1 *m_start = '\0'; // Now we have two strings inside "data". Copy the 2nd // string directly onto the end of the first. strncat(data, p, data_size+1); // The multipoint string and sequence number should be // erased now from "data". //fprintf(stderr,"New Data: %s\n", data); } if (debug_level & MULTI_DEBUG) { fprintf(stderr," station has %d points\n", p_station->num_multipoints); } } if (debug_level & MULTI_DEBUG) { fprintf(stderr,"extract_multipoints: Normal Return\n"); } } #undef MULTI_DEBUG //////////////////////////////////////////////////////////////////////////////////////////////////// void init_weather(WeatherRow *weather) // clear weather data { weather->wx_sec_time = (time_t)0; weather->wx_storm = 0; weather->wx_time[0] = '\0'; weather->wx_course[0] = '\0'; weather->wx_speed[0] = '\0'; weather->wx_speed_sec_time = 0; // ?? weather->wx_gust[0] = '\0'; weather->wx_hurricane_radius[0] = '\0'; weather->wx_trop_storm_radius[0] = '\0'; weather->wx_whole_gale_radius[0] = '\0'; weather->wx_temp[0] = '\0'; weather->wx_rain[0] = '\0'; weather->wx_rain_total[0] = '\0'; weather->wx_snow[0] = '\0'; weather->wx_prec_24[0] = '\0'; weather->wx_prec_00[0] = '\0'; weather->wx_hum[0] = '\0'; weather->wx_baro[0] = '\0'; weather->wx_fuel_temp[0] = '\0'; weather->wx_fuel_moisture[0] = '\0'; weather->wx_type = '\0'; weather->wx_station[0] = '\0'; } int get_weather_record(DataRow *fill) // get or create weather storage { int ok=1; if (fill->weather_data == NULL) // new weather data, allocate storage and init { fill->weather_data = malloc(sizeof(WeatherRow)); if (fill->weather_data == NULL) { fprintf(stderr,"Couldn't allocate memory in get_weather_record()\n"); ok = 0; } else { init_weather(fill->weather_data); } } return(ok); } int delete_weather(DataRow *fill) // delete weather storage, if allocated { if (fill->weather_data != NULL) { free(fill->weather_data); fill->weather_data = NULL; return(1); } return(0); } int delete_multipoints(DataRow *fill) // delete multipoint storage, if allocated { if (fill->multipoint_data != NULL) { //fprintf(stderr,"Removing multipoint data, %s\n", fill->call_sign); free(fill->multipoint_data); fill->multipoint_data = NULL; fill->num_multipoints = 0; return(1); } return(0); } ////////////////////////////////////////// Trails ////////////////////////////////////////////////// /* * See if current color is defined as active trail color */ int trail_color_active(int UNUSED(color_index)) { // this should be made configurable... // to select trail colors to use return(1); // accept this color } /* * Get new trail color for a call */ int new_trail_color(char *call) { int color, found, i; // If my_trail_diff_color is set a 0, then we'll // assign one color to every SSID from our callsign. If // 1, they get the next color available (round-robin style) just // like all the other stations. // // 0 for last parameter in is_my_call() means skip SSID in // callsign check. Non-zero means the callsign + SSID must be // an exact match. if (is_my_call(call,my_trail_diff_color)) { color = MY_TRAIL_COLOR; // It's my call, so use special color } else { // all other callsigns get some other color out of the color table color = current_trail_color; for(i=0,found=0; !found && icall_sign); if (debug_level & 256) { fprintf(stderr,"store_trail_point: for %s\n", p_station->call_sign); } // Allocate storage for the new track point ptr = malloc(sizeof(TrackRow)); if (ptr == NULL) { if (debug_level & 256) { fprintf(stderr,"store_trail_point: MALLOC failed for trail.\n"); } return(0); // Failed due to malloc } // Check whether we have any track data saved if (p_station->newest_trackpoint == NULL) { // new trail, do initialization if (debug_level & 256) { fprintf(stderr,"Creating new trail.\n"); } tracked_stations++; // Assign a new trail color 'cuz it's a new trail p_station->trail_color = new_trail_color(p_station->call_sign); } // Start linking the record to the new end of the chain ptr->prev = p_station->newest_trackpoint; // Link to record or NULL ptr->next = NULL; // Newest end of chain // Have an older record already? if (p_station->newest_trackpoint != NULL) // Yes { p_station->newest_trackpoint->next = ptr; } else // No, this is our first record { p_station->oldest_trackpoint = ptr; } // Link it in as our newest record p_station->newest_trackpoint = ptr; if (debug_level & 256) { fprintf(stderr,"store_trail_point: Storing data for %s\n", p_station->call_sign); } ptr->trail_long_pos = lon; ptr->trail_lat_pos = lat; ptr->sec = sec; if (alt[0] != '\0') { ptr->altitude = atoi(alt)*10; } else { ptr->altitude = -99999l; } if (speed[0] != '\0') { ptr->speed = (long)(atof(speed)*18.52); } else { ptr->speed = -1; } if (course[0] != '\0') { ptr->course = (int)(atof(course) + 0.5); // Poor man's rounding } else { ptr->course = -1; } flag = '\0'; // init flags if ((stn_flag & ST_DIRECT) != 0) { flag |= TR_LOCAL; // set "local" flag } if (ptr->prev != NULL) // we have at least two points... { // Check whether distance between points is too far. We // must convert from degrees to the Xastir coordinate system // units, which are 100th of a second. if ( labs(lon - ptr->prev->trail_long_pos) > (trail_segment_distance * 60*60*100) || labs(lat - ptr->prev->trail_lat_pos) > (trail_segment_distance * 60*60*100) ) { // Set "new track" flag if there's // "trail_segment_distance" degrees or more between // points. Originally was hard-coded to one degree, now // set by a slider in the timing dialog. flag |= TR_NEWTRK; } else { // Check whether trail went above our maximum time // between points. If so, don't draw segment. if (labs(sec - ptr->prev->sec) > (trail_segment_time *60)) { // Set "new track" flag if long delay between // reception of two points. Time is set by a slider // in the timing dialog. flag |= TR_NEWTRK; } } } else { // Set "new track" flag for first point received. flag |= TR_NEWTRK; } ptr->flag = flag; return(1); // We succeeded } /* * Check if current packet is a delayed echo */ int is_trailpoint_echo(DataRow *p_station) { int packets = 1; time_t checktime; char temp[50]; TrackRow *ptr; // Check whether we're to skip checking for dupes (reading in // objects/items from file is one such case). // if (skip_dupe_checking) { return(0); // Say that it isn't an echo } // Start at newest end of linked list and compare. Return if we're // beyond the checktime. ptr = p_station->newest_trackpoint; if (ptr == NULL) { return(0); // first point couldn't be an echo } checktime = p_station->sec_heard - TRAIL_ECHO_TIME*60; while (ptr != NULL) { if (ptr->sec < checktime) { return(0); // outside time frame, no echo found } if ((p_station->coord_lon == ptr->trail_long_pos) && (p_station->coord_lat == ptr->trail_lat_pos) && (p_station->speed[0] == '\0' || ptr->speed < 0 || (long)(atof(p_station->speed)*18.52) == ptr->speed) // current: char knots, trail: long 0.1m (-1 is undef) && (p_station->course[0] == '\0' || ptr->course <= 0 || atoi(p_station->course) == ptr->course) // current: char, trail: int (-1 is undef) && (p_station->altitude[0] == '\0' || ptr->altitude <= -99999l || atoi(p_station->altitude)*10 == ptr->altitude)) { // current: char, trail: int (-99999l is undef) if (debug_level & 1) { fprintf(stderr,"delayed echo for %s",p_station->call_sign); convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_HP_NORMAL); fprintf(stderr," at %s",temp); convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_HP_NORMAL); fprintf(stderr," %s, already heard %d packets ago\n",temp,packets); } return(1); // we found a delayed echo } ptr = ptr->prev; packets++; } return(0); // no echo found } // // Expire trail points. // // We now store track data in a doubly-linked list. Each record has a // pointer to the previous and the next record in the list. The main // station record has a pointer to the oldest and the newest end of the // chain, and the chain can be traversed in either order. We use // this to advantage by adding records at one end of the list and // expiring them at the other. // void expire_trail_points(DataRow *p_station, time_t sec) { int ii = 0; int done = 0; TrackRow *ptr; //fprintf(stderr,"expire_trail_points: %s\n",p_station->call_sign); if (debug_level & 256) { fprintf(stderr,"expire_trail_points: %s\n",p_station->call_sign); } // Check whether we have any track data saved if (p_station->oldest_trackpoint == NULL) { return; // Nothing to expire } // Iterate from oldest->newest trackpoints while (!done && p_station->oldest_trackpoint != NULL) { ptr = p_station->oldest_trackpoint; if ( (ptr->sec + sec) >= sec_now() ) { // New trackpoint, within expire time. Quit checking // the rest of the trackpoints for this station. done++; } else { //fprintf(stderr,"Found old trackpoint\n"); // Track too old. Unlink this trackpoint and free it. p_station->oldest_trackpoint = ptr->next; // End of chain in this direction if (p_station->oldest_trackpoint != NULL) { p_station->oldest_trackpoint->prev = NULL; } else { p_station->newest_trackpoint = NULL; } // Free up the space used by the expired trackpoint free(ptr); //fprintf(stderr,"Free'ing a trackpoint\n"); ii++; // Reduce our count of mobile stations if the size of // the track just went to zero. if (p_station->oldest_trackpoint == NULL) { tracked_stations--; } } } if ( (debug_level & 256) && ii ) { fprintf(stderr,"expire_trail_points: %d trackpoints free'd for %s\n", ii, p_station->call_sign); } } /* * Delete comment records and free memory */ int delete_comments_and_status(DataRow *fill) { // If the pointers are empty, we're done if ( (fill->comment_data == NULL) && (fill->status_data == NULL) ) { return(0); } if (fill->comment_data != NULL) // We have comment records { CommentRow *ptr; CommentRow *ptr_next; ptr = fill->comment_data; ptr_next = ptr->next; while (ptr != NULL) { // Free the actual text string that we malloc'ed if (ptr->text_ptr != NULL) { free(ptr->text_ptr); } free(ptr); ptr = ptr_next; // Advance to next record if (ptr != NULL) { ptr_next = ptr->next; } else { ptr_next = NULL; } } } if (fill->status_data != NULL) // We have status records { CommentRow *ptr; CommentRow *ptr_next; ptr = fill->status_data; ptr_next = ptr->next; while (ptr != NULL) { // Free the actual text string that we malloc'ed if (ptr->text_ptr != NULL) { free(ptr->text_ptr); } free(ptr); ptr = ptr_next; // Advance to next record if (ptr != NULL) { ptr_next = ptr->next; } else { ptr_next = NULL; } } } return(1); } /* * Delete trail and free memory */ int delete_trail(DataRow *fill) { if (fill->newest_trackpoint != NULL) { TrackRow *current; TrackRow *next; // Free the TrackRow records current = fill->oldest_trackpoint; while (current != NULL) { next = current->next; free(current); current = next; } fill->oldest_trackpoint = NULL; fill->newest_trackpoint = NULL; tracked_stations--; return(1); } return(0); } // DK7IN: there should be some library functions for the next two, // but I don't have any documentation while being in holidays... void month2str(int month, char *str, int str_size) { switch (month) { case 0: xastir_snprintf(str,str_size,"Jan"); break; case 1: xastir_snprintf(str,str_size,"Feb"); break; case 2: xastir_snprintf(str,str_size,"Mar"); break; case 3: xastir_snprintf(str,str_size,"Apr"); break; case 4: xastir_snprintf(str,str_size,"May"); break; case 5: xastir_snprintf(str,str_size,"Jun"); break; case 6: xastir_snprintf(str,str_size,"Jul"); break; case 7: xastir_snprintf(str,str_size,"Aug"); break; case 8: xastir_snprintf(str,str_size,"Sep"); break; case 9: xastir_snprintf(str,str_size,"Oct"); break; case 10: xastir_snprintf(str,str_size,"Nov"); break; case 11: xastir_snprintf(str,str_size,"Dec"); break; default: xastir_snprintf(str,str_size," "); break; } } void wday2str(int wday, char *str, int str_size) { switch (wday) { case 0: xastir_snprintf(str,str_size,"Sun"); break; case 1: xastir_snprintf(str,str_size,"Mon"); break; case 2: xastir_snprintf(str,str_size,"Tue"); break; case 3: xastir_snprintf(str,str_size,"Wed"); break; case 4: xastir_snprintf(str,str_size,"Thu"); break; case 5: xastir_snprintf(str,str_size,"Fri"); break; case 6: xastir_snprintf(str,str_size,"Sat"); break; default: xastir_snprintf(str,str_size," "); break; } } /* * Export trail point to file * * Don't call directly, call export_trail() or export_trail_as_kml() instead * as they need to open the file, set appropriate headers, and call export_trailstation() * to set the context for the position. */ void exp_trailpos(FILE *f,long lat,long lon,time_t sec,long speed,int course,long alt,int newtrk, int export_format) { struct tm *time; char lat_string[12+1]; char lon_string[12+1]; char month[3+1]; char wday[3+1]; float deg; time = gmtime(&sec); month2str(time->tm_mon, month, sizeof(month)); wday2str(time->tm_wday, wday, sizeof(wday)); switch (export_format) { case EXPORT_KML_TRACK: // kml format is longitude,latitude,altitude triplets with // a comma and no spaces separating elements of the triplet // and a single space separating sets of triplets in a // coordinates element. Latitude and longitude are // both in decimal degrees. deg = (float)(lon - 64800000l) / 360000.0; fprintf(f,"%09.5f,",deg); deg = -(float)(lat - 32400000l) / 360000.0; fprintf(f,"%08.5f,",deg); if (alt > -99999l) { fprintf(f,"%05.0f ",(float)(alt/10.0)); } else // undefined { fprintf(f,"0 "); } break; case EXPORT_XASTIR_TRACK: default: if (newtrk) { fprintf(f,"\nN New Track Start\n"); } // DK7IN: The format may change in the near future ! // Are there any standards? I want to be able to be compatible to // GPS data formats (e.g. G7TO) for easy interchange from/to GPS // How should we present undefined data? (speed/course/altitude) convert_lat_l2s(lat, lat_string, sizeof(lat_string), CONVERT_UP_TRK); convert_lon_l2s(lon, lon_string, sizeof(lon_string), CONVERT_UP_TRK); fprintf(f,"T %s",lat_string); fprintf(f," %s",lon_string); fprintf(f," %s %s %02d %02d:%02d:%02d %04d",wday,month,time->tm_mday,time->tm_hour,time->tm_min,time->tm_sec,time->tm_year+1900); if (alt > -99999l) { fprintf(f," %5.0fm",(float)(alt/10.0)); } else // undefined { fprintf(f," "); } if (speed >= 0) { fprintf(f," %4.0fkm/h",(float)(speed/10.0)); } else // undefined { fprintf(f," "); } if (course >= 0) // DK7IN: is 0 undefined ?? 1..360 ? { fprintf(f," %3d\xB0\n",course); } else // undefined { fprintf(f," \n"); } } } /* * Export trail for one station to file. * Don't call directly, call export_trail() or export_trail_as_kml() instead * as they need to open the file and set appropriate headers. * * @param f handle of file to write to * @param p_station pointer to station to write * @param export_format file format to use (xastir tracklog or kml). */ void exp_trailstation(FILE *f, DataRow *p_station, int export_format) { char timestring[101]; // string representation of the time heard or the current time long lat0, lon0; int newtrk; time_t sec; long speed; // 0.1km/h int course; // degrees long alt; // 0.1m TrackRow *current; newtrk = 1; current = p_station->oldest_trackpoint; switch (export_format) { case EXPORT_KML_TRACK: // This placemark is for a single position // or for the most recent position of a trail // in either case represented as a // and will show up as a labeled pushpin point. fprintf(f,""); get_iso_datetime(p_station->sec_heard,timestring,True,True); if (p_station->origin[0] == '\0') { fprintf(f,"%s\n",p_station->call_sign); fprintf(f,""); } else { fprintf(f,"%s\nObject from %s. \n",p_station->call_sign,p_station->origin); } // packets received %d last heard %s fprintf(f,langcode("WPUPSTI005"),p_station->num_packets, timestring); if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { // tactical call %s fprintf(f, langcode("WPUPSTI065"), p_station->tactical_call_sign); } fprintf(f,"\n"); // kml specifies w3c's date time format for timestamps if (get_w3cdtf_datetime(p_station->sec_heard, timestring, False, False)) if (strlen(timestring) > 0) { fprintf(f,"%s",timestring); } if (current != NULL) { // We have trail points, create both a set of time stamp labled point placemarks // and a linestring placemark to draw the trail. fprintf(f,"\n"); if (p_station->altitude[0] != '\0') { alt = atoi(p_station->altitude)*10; } else { alt = -99999l; } if (p_station->speed[0] != '\0') { speed = (long)(atof(p_station->speed)*18.52); } else { speed = -1; } if (p_station->course[0] != '\0') { course = atoi(p_station->course); } else { course = -1; } exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); fprintf(f,""); fprintf(f,"\n"); // follow with a set of timestamped placemarks for each point on trail while (current != NULL) { lon0 = current->trail_long_pos; // Trail segment start lat0 = current->trail_lat_pos; sec = current->sec; speed = current->speed; course = current->course; alt = current->altitude; // kml specifies w3c's date time format for timestamps if (get_w3cdtf_datetime(sec,timestring,False,False) && (int)sec>0) { // point has valid timestamp, write it fprintf(f,""); fprintf(f,"%s at %s\n",p_station->call_sign, timestring); fprintf(f,"%s",timestring); fprintf(f,""); exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); fprintf(f,""); fprintf(f,"\n"); } // Advance to the next point current = current->next; } // Prepare to follow with a trail (as a ). fprintf(f,""); if (p_station->origin[0] == '\0') { fprintf(f,"%s (trail)\n",p_station->call_sign); } else { fprintf(f,"%s (trail)\nObject from %s\n",p_station->call_sign,p_station->origin); } } break; case EXPORT_XASTIR_TRACK: default: if (p_station->origin[0] == '\0') { fprintf(f,"\n#C %s\n",p_station->call_sign); } else { fprintf(f,"\n#O %s %s\n",p_station->call_sign,p_station->origin); } } // A trail must have at least two points: One in the struct, // and one in the tracklog. If the station only has one point, // there won't be a tracklog. If the station has moved, then // it'll have both. // reset current, as we may have moved it past the last trackpoint // while generating kml above. current = p_station->oldest_trackpoint; if (current != NULL) // We have trail points, loop through { // them. Skip the most current position // because it is included in the // tracklog (if we have a tracklog!). switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n"); break; //default: // no heading for set of points } while (current != NULL) { lon0 = current->trail_long_pos; // Trail segment start lat0 = current->trail_lat_pos; sec = current->sec; speed = current->speed; course = current->course; alt = current->altitude; if ((current->flag & TR_NEWTRK) != '\0') { newtrk = 1; } // identical for kml and xastir tracks, but could be different for other formats switch (export_format) { case EXPORT_KML_TRACK: exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); break; case EXPORT_XASTIR_TRACK: default: exp_trailpos(f,lat0,lon0,sec,speed,course,alt,newtrk, export_format); } newtrk = 0; // Advance to the next point current = current->next; } switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n\n"); break; //default: // no close for set of points } } else // We don't have any tracklog, so write out the most { // current position only. if (p_station->altitude[0] != '\0') { alt = atoi(p_station->altitude)*10; } else { alt = -99999l; } if (p_station->speed[0] != '\0') { speed = (long)(atof(p_station->speed)*18.52); } else { speed = -1; } if (p_station->course[0] != '\0') { course = atoi(p_station->course); } else { course = -1; } switch (export_format) { case EXPORT_KML_TRACK: fprintf(f,"\n\t"); exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); fprintf(f,"\n\t\n"); break; case EXPORT_XASTIR_TRACK: default: exp_trailpos(f,p_station->coord_lat,p_station->coord_lon,p_station->sec_heard,speed,course,alt,newtrk, export_format); } } switch (export_format) { case (EXPORT_KML_TRACK): fprintf(f,"\n"); break; case (EXPORT_XASTIR_TRACK): default: fprintf(f,"\n"); } } // // Export trail data for one or all stations to file // // If p_station == NULL, store all stations, else store only one // station. // void export_trail(DataRow *p_station) { char file[420]; FILE *f; time_t sec; struct tm *time; int storeall; char user_base_dir[MAX_VALUE]; sec = sec_now(); time = gmtime(&sec); if (p_station == NULL) { storeall = 1; } else { storeall = 0; } if (storeall) { // define filename for storing all station xastir_snprintf(file, sizeof(file), "%s/%04d%02d%02d-%02d%02d%02d.trk", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } else { // define filename for current station xastir_snprintf(file, sizeof(file), "%s/%s.trk", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), p_station->call_sign); } // create or open file (void)filecreate(file); // create empty file if it doesn't exist // DK7IN: owner should better be set to user, it is now root with kernel AX.25! f=fopen(file,"a"); // open file for append if (f != NULL) { fprintf(f, "# WGS-84 tracklog created by Xastir %04d/%02d/%02d %02d:%02d\n", time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min); if (storeall) { p_station = n_first; while (p_station != NULL) { exp_trailstation(f,p_station, EXPORT_XASTIR_TRACK); p_station = p_station->n_next; } } else { exp_trailstation(f,p_station, EXPORT_XASTIR_TRACK); } (void)fclose(f); } else { fprintf(stderr,"Couldn't create or open tracklog file %s\n",file); } } // // Export trail data for one or all stations to a klm file suitable for // loading into google earth/google maps/NASA worldwind etc. // For documentation of the KML (Keyhole Markup Language) format, // see: http:// // // @param p_station pointer to datarow containing station to export // If p_station == NULL, store all stations, else store only one // station. // void export_trail_as_kml(DataRow *p_station) { char file[420]; FILE *f; time_t sec; struct tm *time; int storeall; char user_base_dir[MAX_VALUE]; sec = sec_now(); time = gmtime(&sec); if (p_station == NULL) { storeall = 1; } else { storeall = 0; } if (storeall) { // define filename for storing all station xastir_snprintf(file, sizeof(file), "%s/%04d%02d%02d-%02d%02d%02d.kml", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } else { // define filename for current station, call + current time. xastir_snprintf(file, sizeof(file), "%s/%s_%04d%02d%02d-%02d%02d%02d.kml", get_user_base_dir("tracklogs", user_base_dir, sizeof(user_base_dir)), p_station->call_sign, time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } // create or open file (void)filecreate(file); // create empty file if it doesn't exist // DK7IN: owner should better be set to user, it is now root with kernel AX.25! f=fopen(file,"w+"); // open file for writing if (f != NULL) { fprintf(f,"\n\n\nAPRS Data\n1\n"); fprintf(f, "WGS-84 tracklog created by Xastir %04d/%02d/%02d %02d:%02d\n", time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min); if (storeall) { p_station = n_first; while (p_station != NULL) { exp_trailstation(f,p_station,EXPORT_KML_TRACK); p_station = p_station->n_next; } } else { exp_trailstation(f,p_station,EXPORT_KML_TRACK); } fprintf(f,"\n"); (void)fclose(f); } else { fprintf(stderr,"Couldn't create or open tracklog file %s\n",file); } } ////////////////////////////////////// Station storage /////////////////////////////////////////// // Station storage is done in a double-linked list. In fact there are two such // pointer structures, one for sorting by name and one for sorting by time. // We store both the pointers to the next and to the previous elements. DK7IN /* * Setup station storage structure */ void init_station_data(void) { station_count = 0; // empty station list n_first = NULL; // pointer to next element in name sorted list n_last = NULL; // pointer to previous element in name sorted list t_oldest = NULL; // pointer to oldest element in time sorted list t_newest = NULL; // pointer to newest element in time sorted list last_sec = sec_now(); // check value for detecting changed seconds in time next_time_sn = 0; // serial number for unique time index current_trail_color = 0x00; // first trail color used will be 0x01 last_station_remove = sec_now(); // last time we checked for stations to remove } /* * Initialize station data */ void init_station(DataRow *p_station) { // the list pointers should already be set p_station->oldest_trackpoint = NULL; // no trail p_station->newest_trackpoint = NULL; // no trail p_station->trail_color = 0; p_station->weather_data = NULL; // no weather p_station->coord_lat = 0l; // 90°N \ undefined p_station->coord_lon = 0l; // 180°W / position p_station->pos_amb = 0; // No ambiguity p_station->error_ellipse_radius = 600; // In cm, default 6 meters p_station->lat_precision = 60; // In 100ths of seconds latitude (60 = 0.01 minutes) p_station->lon_precision = 60; // In 100ths of seconds longitude (60 = 0.01 minutes) p_station->call_sign[0] = '\0'; // ????? p_station->tactical_call_sign = NULL; p_station->sec_heard = 0; p_station->time_sn = 0; p_station->flag = 0; // set all flags to inactive p_station->object_retransmit = -1; // transmit forever p_station->last_transmit_time = sec_now(); // Used for object/item decaying algorithm p_station->transmit_time_increment = 0; // Used in data_add() // p_station->last_modified_time = 0; // Used for object/item dead-reckoning p_station->record_type = '\0'; p_station->data_via = '\0'; // L local, T TNC, I internet, F file p_station->heard_via_tnc_port = 0; p_station->heard_via_tnc_last_time = 0; p_station->last_port_heard = 0; p_station->num_packets = 0; p_station->aprs_symbol.aprs_type = '\0'; p_station->aprs_symbol.aprs_symbol = '\0'; p_station->aprs_symbol.special_overlay = '\0'; p_station->aprs_symbol.area_object.type = AREA_NONE; p_station->aprs_symbol.area_object.color = AREA_GRAY_LO; p_station->aprs_symbol.area_object.sqrt_lat_off = 0; p_station->aprs_symbol.area_object.sqrt_lon_off = 0; p_station->aprs_symbol.area_object.corridor_width = 0; // p_station->station_time_type = '\0'; p_station->origin[0] = '\0'; // no object p_station->packet_time[0] = '\0'; p_station->node_path_ptr = NULL; p_station->pos_time[0] = '\0'; // p_station->altitude_time[0] = '\0'; p_station->altitude[0] = '\0'; // p_station->speed_time[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; p_station->bearing[0] = '\0'; p_station->NRQ[0] = '\0'; p_station->power_gain[0] = '\0'; p_station->signal_gain[0] = '\0'; p_station->signpost[0] = '\0'; p_station->probability_min[0] = '\0'; p_station->probability_max[0] = '\0'; // p_station->station_time[0] = '\0'; p_station->sats_visible[0] = '\0'; p_station->status_data = NULL; p_station->comment_data = NULL; p_station->df_color = -1; // Show that there are no other points associated with this // station. We could also zero all the entries of the // multipoints[][] array, but nobody should be looking there // unless this is non-zero. // KG4NBB p_station->num_multipoints = 0; p_station->multipoint_data = NULL; } /* * Remove element from name ordered list */ void remove_name(DataRow *p_rem) // todo: return pointer to next element { int update_shortcuts = 0; int hash_key; // We use a 14-bit hash key // Do a quick check to see if we're removing a station record // that is pointed to by our pointer shortcuts array. // If so, update our pointer shortcuts after we're done. // // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((p_rem->call_sign[0] & 0x7f) << 7); hash_key = hash_key | (int)(p_rem->call_sign[1] & 0x7f); if (station_shortcuts[hash_key] == p_rem) { // Yes, we're trying to remove a record that a hash key // directly points to. We'll need to redo that hash key // after we remove the record. update_shortcuts++; } // Proceed to the station record removal // if (p_rem->n_prev == NULL) // Appears to be first element in list { if (n_first == p_rem) // Yes, head of list { // Make list head point to 2nd element in list (or NULL) // so that we can delete the current record. n_first = p_rem->n_next; } else // No, not first element in list. Problem! The { // list pointers are inconsistent for some reason. // The chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_name(): ERROR: p->n_prev == NULL but p != n_first\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up n_first to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the first element in the list. Fix up pointers { // to skip the current record. p_rem->n_prev->n_next = p_rem->n_next; } if (p_rem->n_next == NULL) // Appears to be last element in list { if (n_last == p_rem) // Yes, tail of list { // Make list tail point to previous element in list (or // NULL) so that we can delete the current record. n_last = p_rem->n_prev; } else // No, not last element in list. Problem! The list { // pointers are inconsistent for some reason. The // chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_name(): ERROR: p->n_next == NULL but p != n_last\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up n_last to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the last element in the list. Fix up pointers to { // skip the current record. p_rem->n_next->n_prev = p_rem->n_prev; } // Update our pointer shortcuts. Pass the removed hash_key to // the function so that we can try to redo just that hash_key // pointer. if (update_shortcuts) { //fprintf(stderr,"\t\t\t\t\t\tRemoval of hash key: %i\n", hash_key); // The -1 tells the function to redo all of the hash table // pointers because we deleted one of them. Later we could // optimize this so that only the specific pointer is fixed // up. station_shortcuts_update_function(-1, NULL); } } /* * Remove element from time ordered list */ void remove_time(DataRow *p_rem) // todo: return pointer to next element { if (p_rem->t_older == NULL) // Appears to be first element in list { if (t_oldest == p_rem) // Yes, head of list (oldest) { // Make oldest list head point to 2nd element in list (or NULL) // so that we can delete the current record. t_oldest = p_rem->t_newer; } else // No, not first (oldest) element in list. Problem! { // The list pointers are inconsistent for some // reason. The chain has been broken and we have // dangling pointers. fprintf(stderr, "remove_time(): ERROR: p->t_older == NULL but p != t_oldest\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up t_oldest to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the first (oldest) element in the list. Fix up { // pointers to skip the current record. p_rem->t_older->t_newer = p_rem->t_newer; } if (p_rem->t_newer == NULL) // Appears to be last (newest) element in list { if (t_newest == p_rem) // Yes, head of list (newest) { // Make newest list head point to previous element in // list (or NULL) so that we can delete the current // record. t_newest = p_rem->t_older; } else // No, not newest element in list. Problem! The { // list pointers are inconsistent for some reason. // The chain has been broken and we have dangling // pointers. fprintf(stderr, "remove_time(): ERROR: p->t_newer == NULL but p != t_newest\n"); abort(); // Cause a core dump at this point // Perhaps we could do some repair to the list pointers here? Start // at the other end of the chain and navigate back to this end, then // fix up t_newest to point to it? This is at the risk of a memory // leak, but at least Xastir might continue to run. } } else // Not the newest element in the list. Fix up pointers { // to skip the current record. p_rem->t_newer->t_older = p_rem->t_older; } } /* * Insert existing element into name ordered list before p_name. * If p_name is NULL then we add it to the end instead. */ void insert_name(DataRow *p_new, DataRow *p_name) { // Set up pointer to next record (or NULL), sorted by name p_new->n_next = p_name; if (p_name == NULL) // Add to end of list { p_new->n_prev = n_last; if (n_last == NULL) // If we have an empty list { n_first = p_new; // Add it to the head of the list } else // List wasn't empty, add to the end of the list. { n_last->n_next = p_new; } n_last = p_new; } else // Insert new record ahead of p_name record { p_new->n_prev = p_name->n_prev; if (p_name->n_prev == NULL) // add to begin of list { n_first = p_new; } else { p_name->n_prev->n_next = p_new; } p_name->n_prev = p_new; } } /* * Insert existing element into time ordered list before p_time * The p_new record ends up being on the "older" side of p_time when * all done inserting (closer in the list to the t_oldest pointer). * If p_time == NULL, insert at newest end of list. */ void insert_time(DataRow *p_new, DataRow *p_time) { // Set up pointer to next record (or NULL), sorted by time p_new->t_newer = p_time; if (p_time == NULL) // add to end of list (becomes newest station) { p_new->t_older = t_newest; // connect to previous end of list if (t_newest == NULL) // if list empty, create list { t_oldest = p_new; // it's now our only station on the list } else { t_newest->t_newer = p_new; // list not empty, link original last record to our new one } t_newest = p_new; // end of list (newest record pointer) points to our new record } else // Else we're inserting into the middle of the list somewhere { p_new->t_older = p_time->t_older; if (p_time->t_older == NULL) // add to end of list (new record becomes oldest station) { t_oldest = p_new; } else { p_time->t_older->t_newer = p_new; // else } p_time->t_older = p_new; } } /* * Free station memory for one entry */ void delete_station_memory(DataRow *p_del) { if (p_del == NULL) { return; } remove_name(p_del); remove_time(p_del); free(p_del); station_count--; } /* * Create new uninitialized element in station list * and insert it before p_name after p_time entries. * * Returns NULL if malloc error. */ /*@null@*/ DataRow *insert_new_station(DataRow *p_name, DataRow *p_time) { DataRow *p_new; p_new = (DataRow *)calloc(1, sizeof(DataRow)); if (p_new != NULL) // we really got the memory { insert_name(p_new,p_name); // insert element into name ordered list insert_time(p_new,p_time); // insert element into time ordered list } else // p_new == NULL { fprintf(stderr,"ERROR: we got no memory for station storage\n"); } return(p_new); // return pointer to new element } /* * Create new initialized element for call in station list * and insert it before p_name after p_time entries. * * Returns NULL if mallc error. */ /*@null@*/ DataRow *add_new_station(DataRow *p_name, DataRow *p_time, char *call) { DataRow *p_new; int hash_key; // We use a 14-bit hash key char *tactical_call; if (call[0] == '\0') { // Do nothing. No update needed. Callsign is empty. return(NULL); } //fprintf(stderr,"Adding new station: %s\n",call); p_new = insert_new_station(p_name,p_time); // allocate memory if (p_new == NULL) { // Couldn't allocate space for the station return(NULL); } init_station(p_new); // initialize new station record xastir_snprintf(p_new->call_sign, sizeof(p_new->call_sign), "%s", call); station_count++; // Do some quick checks to see if we just inserted a new hash // key or inserted at the beginning of a hash key (making the // old pointer incorrect). If so, update our pointers to match. // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((call[0] & 0x7f) << 7); hash_key = hash_key | (int)(call[1] & 0x7f); if (station_shortcuts[hash_key] == NULL) { // New hash key entry point found. Fill in the pointer. //fprintf(stderr,"New hash key: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } else if (p_new->n_prev == NULL) { // We just inserted at the beginning of the list. Assume // that we inserted at the beginning of our hash_key // segment. //fprintf(stderr,"Start of list hash_key: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } else { // Check whether either of the first two chars of the new // callsign and the previous callsign are different. If so, // we need to update the hash table entry for our new record // 'cuz we're at the start of a new hash table entry. if (p_new->n_prev->call_sign[0] != call[0] || p_new->n_prev->call_sign[1] != call[1]) { //fprintf(stderr,"Hash segment start: %i, call: %s\n", // hash_key, // call); station_shortcuts_update_function(hash_key, p_new); } } //if (p_new->n_prev != NULL) { // fprintf(stderr,"\tprev: %s", // p_new->n_prev->call_sign); //} //if (p_new->n_next != NULL) { // fprintf(stderr,"\t\tnext: %s", // p_new->n_next->call_sign); //} // //fprintf(stderr,"\n"); // Check whether we have a tactical call to assign to this // station in our tactical hash table. //fprintf(stderr,"Call:'%s'\n", call); tactical_call = get_tactical_from_hash(call); // If tactical call found and not blank if (tactical_call && tactical_call[0] != '\0') { // Malloc some memory to hold it in the station record. p_new->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); CHECKMALLOC(p_new->tactical_call_sign); //fprintf(stderr,"***Assigning tactical call to new record***\n"); xastir_snprintf(p_new->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", tactical_call); //if (tactical_call[0] == '\0') // fprintf(stderr,"Blank tactical call\n"); } else { //fprintf(stderr,"."); } return(p_new); // return pointer to new element } #ifdef HAVE_DB /* function add_simple_station() * adds an xastir DataRow using station and additional data from a simpleStation * record in a SQL database. * @param p_new_station Pointer to a DataRow for the new station, probably initialized as DataRow p_new_station = NULL * @param station String pointer for the callsign or object name * @param origin String pointer for the callsign for an object * @param symbol String pointer to an aprs symbol, will take the first character * @param overlay String pointer to an aprs overlay, will take the first character * @param aprs_type String pointer to an aprs type, will take the first character * @param latitude in decimal degrees * @param longitude in decimal degrees * @param record_type * @param node_path * @param transmit_time Time at which the station position was transmitted in a string pointer with format described by timeformat * @param timeformat Format for the transmit_time, e.g. "%Y-%M-%D %h:%d:%m" see documentation for strptime * * @returns 0 if unable to add new station (p_new_station should be null) * otherwise returns 1 (and p_new_station should be a pointer to the DataRow * for the new station record. */ int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time, char *timeformat) { int returnvalue = 0; unsigned long x; // xastir coordinate for longitude unsigned long y; // xastir coordinate for latitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string DataRow *p_time; // pointer to new station record //DataRow *p_new_station_unused; struct tm time; time_t sec; char timestring[100+1]; char empty[MAX_ALTITUDE]; // for storing trailpoint data (altitude, course, speed) we don't know here. empty[0]='\0'; // Add a datarow using the retrieved station record from the postgis/mysql database. p_time = NULL; p_new_station = NULL; if (debug_level & 4096) { fprintf(stderr,"add_simple_station(%s)\n",station); } if (search_station_name(&p_new_station,station,1)) { // A datarow for this station exists, find out if the new record // is older or younger than the existing DataRow for this station strptime(transmit_time,timeformat,&time); p_new_station->sec_heard = mktime(&time); if(p_new_station->sec_heard > mktime(&time)) { // Add the new record as a trailpoint. if (strlen(transmit_time) > 0) { strptime(transmit_time, timeformat, &time); sec = mktime(&time); lat = strtof(latitude,NULL); lon = strtof(longitude,NULL); if (convert_to_xastir_coordinates (&x, &y, lon, lat)) { (void)store_trail_point(p_new_station, x, y, sec, empty, empty, empty, 0); } } // all done returnvalue = 1; } else { // Append the position of the existing record as a trailpoint // and set the station DataRow to the new values. (void)store_trail_point(p_new_station, p_new_station->coord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } } else { // add a new station p_new_station = add_new_station(p_new_station,p_time,station); } if(returnvalue==0) { // Set the values for the p_new_station DataRow based on the // supplied parameters. At this point p_new_station might // be either a brand new station record, or an existing // station record for the callsign that we were passed. if (!(p_new_station==NULL)) { // set values for new station based on the database row xastir_snprintf(p_new_station->origin,58,"%s",origin); p_new_station->aprs_symbol.aprs_symbol = symbol[0]; p_new_station->aprs_symbol.special_overlay = overlay[0]; p_new_station->aprs_symbol.aprs_type = aprs_type[0]; lat = strtof(latitude,NULL); lon = strtof(longitude,NULL); if (convert_to_xastir_coordinates (&x, &y, lon, lat)) { p_new_station->coord_lon = x; p_new_station->coord_lat = y; } p_new_station->record_type = record_type[0]; // free node path, Malloc, and store the new path if (p_new_station->node_path_ptr != NULL) { free(p_new_station->node_path_ptr); } p_new_station->node_path_ptr = (char *)malloc(strlen(node_path) + 1); CHECKMALLOC(p_new_station->node_path_ptr); substr(p_new_station->node_path_ptr,node_path,strlen(node_path)); // also set flags for the station p_new_station->flag |= ST_ACTIVE; if (position_on_extd_screen(p_new_station->coord_lat,p_new_station->coord_lon)) { p_new_station->flag |= (ST_INVIEW); // set "In View" flag } else { p_new_station->flag &= (~ST_INVIEW); // clear "In View" flag } p_new_station->data_via = DATA_VIA_DATABASE; // treat as data from a file. if (strlen(transmit_time) > 0) { //strptime(transmit_time,"%Y-%m-%d %H:%M:%S",&time); strptime(transmit_time,timeformat,&time); p_new_station->sec_heard = mktime(&time); if (debug_level & 4096) { get_iso_datetime(p_new_station->sec_heard,timestring,False,False); fprintf(stderr,"time %s to [%s] using [%s]\n",transmit_time,timestring,timeformat); } if (p_new_station->sec_heard > sec_now()) { p_new_station->sec_heard = sec_now(); } (void)strftime(timestring,MAX_TIME,"%m%d%Y%H%M%S",&time); xastir_snprintf(p_new_station->pos_time, sizeof(p_new_station->pos_time), "%s", timestring); } returnvalue = 1; } } return returnvalue; } #endif /* HAVE_DB */ /* * Move station record before p_time in time ordered list */ void move_station_time(DataRow *p_curr, DataRow *p_time) { if (p_curr != NULL) // need a valid record { remove_time(p_curr); insert_time(p_curr,p_time); } } /* * Move station record before p_name in name ordered list */ void move_station_name(DataRow *p_curr, DataRow *p_name) { if (p_curr != NULL) // need a valid record { remove_name(p_curr); insert_name(p_curr,p_name); } } // Update all of the pointers so that they accurately reflect the // current state of the station database. // // NOTE: This part of the code could be made smarter so that the // pointers are updated whenever they are found to be out of whack, // instead of zeroing all of them and starting from scratch each // time. Alternate: Follow the current pointer if non-NULL then go // up/down the list to find the current switchover point between // letters. // // Better: Tie into the station insert function. If a new letter // is inserted, or a new station at the beginning of a letter group, // run this function to keep things up to date. That way we won't // have to traverse in both directions to find a callsign in the // search_station_name() function. // // If hash_key_in is -1, we need to redo all of the hash keys. If // it is between 0 and 16383, then we need to redo just that one // hash key. The 2nd parameter is either NULL for a removed record, // or a pointer to a new station record in the case of an addition. // void station_shortcuts_update_function(int hash_key_in, DataRow *p_rem) { int ii; DataRow *ptr; int prev_hash_key = 0x0000; int hash_key; // I just changed the function so that we can pass in the hash_key // that we wish to update: We should be able to speed things up by // updating one hash key instead of all 16384 pointers. if ( (hash_key_in != -1) && (hash_key_in >= 0) && (hash_key_in < 16384) ) { // We're adding/changing a hash key entry station_shortcuts[hash_key_in] = p_rem; //fprintf(stderr,"%i ",hash_key_in); } else // We're removing a hash key entry. { // Clear and rebuild the entire hash table. //?????????????????????????????????????????????????? // Clear all of the pointers before we begin???? //?????????????????????????????????????????????????? for (ii = 0; ii < 16384; ii++) { station_shortcuts[ii] = NULL; } ptr = n_first; // Start of list // Loop through entire list, writing the pointer into the // station_shortcuts array whenever a new character is // encountered. Do this until the end of the array or the end // of the list. // while ( (ptr != NULL) && (prev_hash_key < 16384) ) { // We create the hash key out of the lower 7 bits of the // first two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((ptr->call_sign[0] & 0x7f) << 7); hash_key = hash_key | (int)(ptr->call_sign[1] & 0x7f); if (hash_key > prev_hash_key) { // We found the next hash_key. Store the pointer at the // correct location. if (hash_key < 16384) { station_shortcuts[hash_key] = ptr; //fprintf(stderr,"%i ", hash_key); } prev_hash_key = hash_key; } ptr = ptr->n_next; } //fprintf(stderr,"\n"); } } // // Search station record by callsign // Returns a station with a call equal or after the searched one // // We use a doubly-linked list for the stations, so we can traverse // in either direction. We also use a 14-bit hash table created // from the first two letters of the call to dump us into the // beginning of the correct area that may hold the callsign, which // reduces search time quite a bit. We end up doing a linear search // only through a small area of the linked list. // // DK7IN: I don't look at case, objects and internet names could // have lower case. // int search_station_name(DataRow **p_name, char *call, int exact) { int kk; int hash_key; int result; int ok = 1; (*p_name) = n_first; // start of alphabet if (call[0] == '\0') { // If call we're searching for is empty, return n_first as // the pointer. return(0); } // We create the hash key out of the lower 7 bits of the first // two characters, creating a 14-bit key (1 of 16384) // hash_key = (int)((call[0] & 0x7f) << 7); hash_key = hash_key | (int)(call[1] & 0x7f); // Look for a match using hash table lookup // (*p_name) = station_shortcuts[hash_key]; if ((*p_name) == NULL) // No hash-table entry found. { int mm; //fprintf(stderr,"No hash-table entry found: call:%s\n",call); // No index found for that letter. Walk the array until // we find an entry that is filled. That'll be our // potential insertion point (insertion into the list will // occur just ahead of the hash entry). for (mm = hash_key; mm < 16384; mm++) { if (station_shortcuts[mm] != NULL) { (*p_name) = station_shortcuts[mm]; break; } } } // else { //fprintf(stderr,"Hash key %d=%s, searching for call: %s\n", // hash_key, // (*p_name)->call_sign, // call); // } // If we got to this point, we either have a NULL pointer or a // real hash-table pointer entry. A non-NULL pointer means that // we have a match for the lower seven bits of the first two // characters of the callsign. Check the rest of the callsign, // and jump out of the loop if we get outside the linear search // area (if first two chars are different). kk = (int)strlen(call); // Search linearly through list. Stop at end of list or break. while ( (*p_name) != NULL) { if (exact) { // Check entire string for exact match result = strcmp( call, (*p_name)->call_sign ); } else { // Check first part of string for match result = strncmp( call, (*p_name)->call_sign, kk ); } if (result < 0) // We went past the right location. { // We're done. ok = 0; //fprintf(stderr,"Went past possible entry point, searching for call: %s\n",call); break; } else if (result == 0) // Found a possible match { //fprintf(stderr,"Found possible match: list:%s call:%s\n", // (*p_name)->call_sign, // call); break; } else // Result > 0. We haven't found it yet. { (*p_name) = (*p_name)->n_next; // Next element in list } } // Did we find anything? if ( (*p_name) == NULL) { ok = 0; //fprintf(stderr,"End of list reached, call: %s\n",call); return(ok); // Nope. No match found. } // If "exact" is set, check that the string lengths match as // well. If not, we didn't find it. if (exact && ok && strlen((*p_name)->call_sign) != strlen(call)) { ok = 0; } return(ok); // if not ok: p_name points to correct insert position in name list } /* * Search station record by time and time serial number, serial ignored if -1 * Returns a station that is equal or older than the search criterium */ int search_station_time(DataRow **p_time, time_t heard, int serial) { int ok = 1; (*p_time) = t_newest; // newest station if (heard == 0) // we want the newest station { if (t_newest == NULL) { ok = 0; // empty list } } else { while((*p_time) != NULL) // check time { if ((*p_time)->sec_heard <= heard) // compare { break; // found time or earlier } (*p_time) = (*p_time)->t_older; // next element } // we now probably have found the entry if ((*p_time) != NULL && (*p_time)->sec_heard == heard) { // we got a match, but there may be more of them if (serial >= 0) // check serial number, ignored if -1 { while((*p_time) != NULL) // for unique time index { if ((*p_time)->sec_heard == heard && (*p_time)->time_sn <= serial) // compare { break; // found it (same time, maybe earlier SN) } if ((*p_time)->sec_heard < heard) // compare { break; // found it (earlier time) } (*p_time) = (*p_time)->t_older; // consider next element } if ((*p_time) == NULL || (*p_time)->sec_heard != heard || (*p_time)->time_sn != serial) { ok = 0; // no perfect match } } } else { ok = 0; // no perfect match } } return(ok); } /* * Get pointer to next station in name sorted list */ int next_station_name(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = n_first; } else { (*p_curr) = (*p_curr)->n_next; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to previous station in name sorted list */ int prev_station_name(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = n_last; } else { (*p_curr) = (*p_curr)->n_prev; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to newer station in time sorted list */ int next_station_time(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = t_oldest; // Grab oldest station if NULL passed to us??? } else { (*p_curr) = (*p_curr)->t_newer; // Else grab newer station } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Get pointer to older station in time sorted list */ int prev_station_time(DataRow **p_curr) { if ((*p_curr) == NULL) { (*p_curr) = t_newest; // Grab newest station if NULL passed to us??? } else { (*p_curr) = (*p_curr)->t_older; } if ((*p_curr) != NULL) { return(1); } else { return(0); } } /* * Set flag for all stations in current view area or a margin area around it * That are the stations we look at if we want to draw symbols or trails */ void setup_in_view(void) { DataRow *p_station; long min_lat, max_lat; // screen borders plus space long min_lon, max_lon; // for trails from off-screen stations long marg_lat, marg_lon; // margin around screen marg_lat = (long)(3 * screen_height * scale_y/2); marg_lon = (long)(3 * screen_width * scale_x/2); if (marg_lat < IN_VIEW_MIN*60*100) // allow a minimum area, { marg_lat = IN_VIEW_MIN*60*100; // there could be outside stations } if (marg_lon < IN_VIEW_MIN*60*100) // with trail parts on screen { marg_lon = IN_VIEW_MIN*60*100; } // Only screen view // min_lat = SE_corner_latitude // max_lat = NW_corner_latitude; // min_lon = NW_corner_longitude; // max_lon = SE_corner_longitude; // Screen view plus one screen wide margin // There could be stations off screen with on screen trails // See also the use of position_on_extd_screen() min_lat = center_latitude - marg_lat; max_lat = center_latitude + marg_lat; min_lon = center_longitude - marg_lon; max_lon = center_longitude + marg_lon; p_station = n_first; while (p_station != NULL) { if ((p_station->flag & ST_ACTIVE) == 0 // ignore deleted objects || p_station->coord_lon < min_lon || p_station->coord_lon > max_lon || p_station->coord_lat < min_lat || p_station->coord_lat > max_lat || (p_station->coord_lat == 0 && p_station->coord_lon == 0)) { // outside view and undefined stations: p_station->flag &= (~ST_INVIEW); // clear "In View" flag } else { p_station->flag |= ST_INVIEW; // set "In View" flag } p_station = p_station->n_next; } } /* * Check if position is inside screen borders */ int position_on_screen(long lat, long lon) { if ( lon > NW_corner_longitude && lon < SE_corner_longitude && lat > NW_corner_latitude && lat < SE_corner_latitude && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the screen } else { return(0); } } /* * Check if position is inside extended screen borders * (real screen + one screen margin for trails) * used for station "In View" flag */ int position_on_extd_screen(long lat, long lon) { long marg_lat, marg_lon; // margin around screen marg_lat = (long)(3 * screen_height * scale_y/2); marg_lon = (long)(3 * screen_width * scale_x/2); if (marg_lat < IN_VIEW_MIN*60*100) // allow a minimum area, { marg_lat = IN_VIEW_MIN*60*100; // there could be outside stations } if (marg_lon < IN_VIEW_MIN*60*100) // with trail parts on screen { marg_lon = IN_VIEW_MIN*60*100; } if ( labs(lon - center_longitude) < marg_lon && labs(lat - center_latitude) < marg_lat && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the area } else { return(0); } } /* * Delete single station with all its data ?? delete messages ?? * This function is called with a callsign parameter. Only used for * my callsign, not for any other. */ void station_del(char *call) { DataRow *p_name; // DK7IN: do it with move... ? if (search_station_name(&p_name, call, 1)) { (void)delete_trail(p_name); // Free track storage if it exists. (void)delete_weather(p_name); // Free weather memory, if allocated (void)delete_multipoints(p_name); // Free multipoint memory, if allocated (void)delete_comments_and_status(p_name); // Free comment storage if it exists if (p_name->node_path_ptr != NULL)// Free malloc'ed path { free(p_name->node_path_ptr); } if (p_name->tactical_call_sign != NULL) { free(p_name->tactical_call_sign); } delete_station_memory(p_name); // Free memory } } /* * Delete single station with all its data ?? delete messages ?? * This function is called with a pointer instead of a callsign. */ void station_del_ptr(DataRow *p_name) { //fprintf(stderr,"db.c:station_del_ptr(): %s\n",p_name->call_sign); if (p_name != NULL) { // A bit of debug code: Attempting to find out if we're // deleting our own objects from time to time. Leave this // in until we're sure the problem has been fixed. //// if (is_my_call(p_name->origin,1)) { // Check SSID as well // if ( is_my_object_item(p_name) ) { // Check SSID as well // fprintf(stderr,"station_del_ptr: Removing my own object: %s\n", // p_name->call_sign); // } #ifdef EXPIRE_DEBUG fprintf(stderr,"Removing: %s heard %d seconds ago\n",p_name->call_sign, (int)(sec_now() - p_name->sec_heard)); #endif (void)delete_trail(p_name); // Free track storage if it exists. (void)delete_weather(p_name); // free weather memory, if allocated (void)delete_multipoints(p_name); // Free multipoint memory, if allocated (void)delete_comments_and_status(p_name); // Free comment storage if it exists if (p_name->node_path_ptr != NULL) // Free malloc'ed path { free(p_name->node_path_ptr); } if (p_name->tactical_call_sign != NULL) { free(p_name->tactical_call_sign); } delete_station_memory(p_name); // free memory, update // linked lists, update // station_count //fprintf(stderr,"db.c:station_del_ptr(): Deleted station\n"); } } /* * Delete all stations ?? delete messages ?? */ void delete_all_stations(void) { DataRow *p_name; DataRow *p_curr; int ii; // Clear all of the pointers before we begin for (ii = 0; ii < 16384; ii++) { station_shortcuts[ii] = NULL; } p_name = n_first; while (p_name != NULL) { p_curr = p_name; p_name = p_name->n_next; station_del_ptr(p_curr); //(void)delete_trail(p_curr); // free trail memory, if allocated //(void)delete_weather(p_curr); // free weather memory, if allocated //(void)delete_multipoints(p_curr);// Free multipoint memory, if allocated //delete_station_memory(p_curr); // free station memory } if (station_count != 0) { fprintf(stderr, "ERROR: station_count should be 0 after stations delete, is %d\n", station_count); station_count = 0; } } /* * Check if we have to delete old stations. * * Called from main.c:UpdateTime() on a periodic basis. * */ void check_station_remove(time_t curr_sec) { DataRow *p_station, *p_station_t_newer; time_t t_rem; int done; // Run through this routine every STATION_REMOVE_CYCLE // seconds (currently every five minutes) #ifdef EXPIRE_DEBUG // Check every 15 seconds, useful for debug only. if (last_station_remove < (curr_sec - DEBUG_STATION_REMOVE_CYCLE)) // DEBUG #else if (last_station_remove < (curr_sec - STATION_REMOVE_CYCLE)) #endif { //fprintf(stderr,"db.c:check_station_remove() is running\n"); // Compute the cutoff time. Any stations older than t_rem // will be removed, unless they have a tactical call or // belong to us. t_rem = curr_sec - sec_remove; #ifdef EXPIRE_DEBUG // Expire every 15 seconds, useful for debug only. t_rem = curr_sec - (1 * DEBUG_STATION_REMOVE); #endif for (done = 0, p_station = t_oldest; p_station != NULL && !done; p_station = p_station_t_newer) { // Save a pointer to the next record in time-order // before we delete a record and lose it. p_station_t_newer = p_station->t_newer; if (p_station->sec_heard < t_rem) { // if ( (is_my_call(p_station->call_sign,1)) // It's my station (including SSID) or // || ( (is_my_call(p_station->origin,1)) // Station is owned by me (including SSID) // && ( ((p_station->flag & ST_OBJECT) != 0) // and it's an object // || ((p_station->flag & ST_ITEM ) != 0) ) ) ) { // or an item if ( is_my_station(p_station) || is_my_object_item(p_station)) { // It's one of mine, leave it alone! #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"mine\n"); #endif } /* else if (p_station->tactical_call_sign) { // Station has a tactical callsign assigned, // don't delete it. #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"tactical\n"); #endif } */ else // Not one of mine, doesn't have a tactical { // callsign assigned, so start deleting //The debug output needs to be before the delete, as // we're freeing the data pointed to by p_station! #ifdef EXPIRE_DEBUG fprintf(stderr,"found old station: %s\t\t",p_station->call_sign); fprintf(stderr,"deleting\n"); fprintf(stderr,"Last heard time: %ld\n",p_station->sec_heard); fprintf(stderr," t_rem: %ld\n",t_rem); fprintf(stderr," next older record has time %ld\n",p_station_t_newer->sec_heard); #endif mdelete_messages(p_station->call_sign); // Delete messages station_del_ptr(p_station); //(void)delete_trail(p_station); // Free track storage if it exists. //(void)delete_weather(p_station); // Free weather memory, if allocated //(void)delete_multipoints(p_station); // Free multipoint memory, if allocated //delete_station_memory(p_station); // Free memory } } else { #ifdef EXPIRE_DEBUG DataRow *testPtr = sanity_check_time_list(t_rem); if (testPtr) { fprintf(stderr,"TIME-SORTED LIST SANITY CHECK FAILED!\n"); fprintf(stderr," At least one station left after expire with time older than %ld\n",t_rem); fprintf(stderr," Station name: %s\n", testPtr->call_sign); fprintf(stderr," Last heard time %ld\n",testPtr->sec_heard); fprintf(stderr," Seconds ago: %ld\n",curr_sec-testPtr->sec_heard); fprintf(stderr," Seconds older than expire time: %ld\n",t_rem-testPtr->sec_heard); fprintf(stderr,"--------\n"); dump_time_sorted_list(); } #endif done++; // all other stations are newer... } } last_station_remove = curr_sec; } } /* * Delete an object (mark it as deleted) */ void delete_object(char *name) { DataRow *p_station; //fprintf(stderr,"delete_object\n"); p_station = NULL; if (search_station_name(&p_station,name,1)) // find object name { p_station->flag &= (~ST_ACTIVE); // clear flag p_station->flag &= (~ST_INVIEW); // clear "In View" flag if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { redraw_on_new_data = 2; // redraw now } // there is some problem... it is not redrawn immediately! ???? // but deleted from list immediatetly redo_list = (int)TRUE; // and update lists } } /////////////////////////////////////// APRS Decoding //////////////////////////////////////////// /* * Try to find a !DAO! format datum and extra precision string from the * comment field of an APRS location packet (incl. objects and items). * If !DAO! is found, it is removed from the comment. * See http://web.ew.usna.edu/~bruninga/aprs/datum.txt * * lat and lon will contain the thousandth and ten thousandth * minute digits of the location, if valid (see below). * For example, if the final location is 70 deg 12.3456 minutes, * lat or lon will contain 56. If the final location is * 50 deg 56.2104 minutes, lat or lon will contain 4. So remember * to zero pad! The range for lat/lon, when valid, is 0-99. * datumch will contain the datum character, if found. * * daocomment must be null-terminated and must contain the comment field * * returns 3 if dao was found and contained a base-91 position * (= datumch, lat, and lon contents are all valid) * returns 2 if dao was found and contained a human readable position * (= datumch, lat, and lon contents are all valid) * returns 1 if dao was found but only included datum information * (= only datumch is valid) * returns 0 if no valid dao was found * (= datumch, lat, and lon contents are all invalid, daocomment is unmodified) * * Tapio Sokura OH2KKU 2007-11-15 */ int decode_dao (int *lat, int *lon, char *datumch, char *daocomment) { char *searchval, *rval; size_t slen; // Loop around searching for !DAO!, return the first valid match. // The first '!' is found using strchr, the rest of the // string is validated more manually. searchval = daocomment; rval = strchr(searchval, '!'); while (rval != NULL) { // Check the remaining string length so we don't // run past string end slen = strlen(rval); if (slen < 5) { break; } if (rval[4] == '!' && rval[1] >= '!' && rval[1] <= '{') { // found the !DAO! terminator and datum char is // within the allowable range if (rval[1] >= 'A' && rval[1] <= 'Z') { // looks like human readable format if (rval[2] == ' ' && rval[3] == ' ') { // only datum information present *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 1; } else if (rval[2] >= '0' && rval[2] <= '9' && rval[3] >= '0' && rval[3] <= '9') { // human readable format 0-9 lat/lon ok // ASCII - 48 = the integer digit we want. // Multiply by 10, because we only get // thousandths of a minute with human // readable format. *lat = ((int)rval[2] - 48) * 10; *lon = ((int)rval[3] - 48) * 10; *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 2; } // not ok for human readable format, continue searching } else if (rval[1] >= 'a' && rval[1] <= 'z') { // looks like base-91 format if (rval[2] == ' ' && rval[3] == ' ') { // only datum information present *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 1; } else if (rval[2] >= '!' && rval[2] <= '{' && rval[3] >= '!' && rval[3] <= '{') { // base-91 lat/lon ok unsigned int lats, lons; float latval, lonval; lats = rval[2] - 33; // get base91 values lons = rval[3] - 33; latval = lats / 91.0 * 100; // do proper scaling lonval = lons / 91.0 * 100; *lat = (int)(latval + 0.5); // round and store *lon = (int)(lonval + 0.5); *datumch = rval[1]; memmove(rval, rval + 5, slen - 4); return 3; } // not ok for base91 format, continue searching } // Datum chars outside A-Z and a-z are not // handled (here at least). } // If we end up here, we didn't find a match. // Search for the next '!' char. searchval = rval + 1; rval = strchr(searchval, '!'); } // No more string left to search and no match. return 0; } /* * Extract Uncompressed Position Report from begin of line * * If a position is found, it is deleted from the data. */ int extract_position(DataRow *p_station, char **info, int type) { int ok, dao_lat, dao_lon, dao_rval; char temp_lat[10+1]; char temp_lon[11+1]; char temp_grid[8+1]; char *my_data; char dao_datumch; float gridlat; float gridlon; my_data = (*info); if (type != APRS_GRID) // Not a grid { ok = (int)(strlen(my_data) >= 19); ok = (int)(ok && my_data[4]=='.' && my_data[14]=='.' && (toupper(my_data[7]) =='N' || toupper(my_data[7]) =='S') && (toupper(my_data[17])=='E' || toupper(my_data[17])=='W')); // errors found: [4]: X [7]: n s [17]: w e if (ok) { ok = is_num_chr(my_data[0]); // 5230.31N/01316.88E> ok = (int)(ok && is_num_chr(my_data[1])); // 0123456789012345678 ok = (int)(ok && is_num_or_sp(my_data[2])); ok = (int)(ok && is_num_or_sp(my_data[3])); ok = (int)(ok && is_num_or_sp(my_data[5])); ok = (int)(ok && is_num_or_sp(my_data[6])); ok = (int)(ok && is_num_chr(my_data[9])); ok = (int)(ok && is_num_chr(my_data[10])); ok = (int)(ok && is_num_chr(my_data[11])); ok = (int)(ok && is_num_or_sp(my_data[12])); ok = (int)(ok && is_num_or_sp(my_data[13])); ok = (int)(ok && is_num_or_sp(my_data[15])); ok = (int)(ok && is_num_or_sp(my_data[16])); } if (ok) { overlay_symbol(my_data[18], my_data[8], p_station); p_station->pos_amb = 0; // spaces in latitude set position ambiguity, spaces in longitude do not matter // we will adjust the lat/long to the center of the rectangle of ambiguity if (my_data[2] == ' ') // nearest degree { p_station->pos_amb = 4; my_data[2] = my_data[12] = '3'; my_data[3] = my_data[5] = my_data[6] = '0'; my_data[13] = my_data[15] = my_data[16] = '0'; } else if (my_data[3] == ' ') // nearest 10 minutes { p_station->pos_amb = 3; my_data[3] = my_data[13] = '5'; my_data[5] = my_data[6] = '0'; my_data[15] = my_data[16] = '0'; } else if (my_data[5] == ' ') // nearest minute { p_station->pos_amb = 2; my_data[5] = my_data[15] = '5'; my_data[6] = '0'; my_data[16] = '0'; } else if (my_data[6] == ' ') // nearest 1/10th minute { p_station->pos_amb = 1; my_data[6] = my_data[16] = '5'; } xastir_snprintf(temp_lat, sizeof(temp_lat), "%s", my_data); temp_lat[9] = toupper(my_data[7]); temp_lat[10] = '\0'; xastir_snprintf(temp_lon, sizeof(temp_lon), "%s", my_data+9); temp_lon[10] = toupper(my_data[17]); temp_lon[11] = '\0'; // Check for !DAO!, beginning from the comment field. // Datum is not used for the time being. // Note: error/precision information (the white box on the map) is // not updated here, because changes to p_station->lat/lon_precision // are overridden in the calling function. dao_rval = decode_dao(&dao_lat, &dao_lon, &dao_datumch, my_data + 19); if (dao_rval == 2 || dao_rval == 3) { // 48 is the magic number to add to a single digit integer to // get the same digit in ASCII. temp_lat[7] = (char)(dao_lat / 10 + 48); temp_lat[8] = (char)(dao_lat % 10 + 48); temp_lon[8] = (char)(dao_lon / 10 + 48); temp_lon[9] = (char)(dao_lon % 10 + 48); // Signal that this is an accuracy-enhanced !DAO! position, // so the calling function can set the error boxes accordingly // (once somebody implements it). ok = dao_rval; } else { // no valid !DAO! _location_ found, pad with zeroes instead temp_lat[7] = '0'; temp_lat[8] = '0'; temp_lon[8] = '0'; temp_lon[9] = '0'; } // Callsign check here also checks SSID for an exact // match // if (!is_my_call(p_station->call_sign,1)) { // don't change my position, I know it better... if ( !(is_my_station(p_station)) ) // don't change my position, I know it better... { p_station->coord_lat = convert_lat_s2l(temp_lat); // ...in case of position ambiguity p_station->coord_lon = convert_lon_s2l(temp_lon); } (*info) += 19; // delete position from comment } } else // It is a grid { // first sanity checks, need more ok = (int)(is_num_chr(my_data[2])); ok = (int)(ok && is_num_chr(my_data[3])); ok = (int)(ok && ((my_data[0]>='A')&&(my_data[0]<='R'))); ok = (int)(ok && ((my_data[1]>='A')&&(my_data[1]<='R'))); if (ok) { xastir_snprintf(temp_grid, sizeof(temp_grid), "%s", my_data); // this test treats >6 digit grids as 4 digit grids; >6 are uncommon. // the spec mentioned 4 or 6, I'm not sure >6 is even allowed. if ( (temp_grid[6] != ']') || (temp_grid[4] == 0) || (temp_grid[5] == 0)) { p_station->pos_amb = 6; // 1deg lat x 2deg lon temp_grid[4] = 'L'; temp_grid[5] = 'L'; } else { p_station->pos_amb = 5; // 2.5min lat x 5min lon temp_grid[4] = toupper(temp_grid[4]); temp_grid[5] = toupper(temp_grid[5]); } // These equations came from what I read in the qgrid source code and // various mailing list archives. gridlon= (20.*((float)temp_grid[0]-65.) + 2.*((float)temp_grid[2]-48.) + 5.*((float)temp_grid[4]-65.)/60.) - 180.; gridlat= (10.*((float)temp_grid[1]-65.) + ((float)temp_grid[3]-48.) + 5.*(temp_grid[5]-65.)/120.) - 90.; // could check for my callsign here, and avoid changing it... p_station->coord_lat = (unsigned long)(32400000l + (360000.0 * (-gridlat))); p_station->coord_lon = (unsigned long)(64800000l + (360000.0 * gridlon)); p_station->aprs_symbol.aprs_type = '/'; p_station->aprs_symbol.aprs_symbol = 'G'; } // is it valid grid or not - "ok" // could cut off the grid square from the comment here, but why bother? } // is it grid or not return(ok); } // DK7IN 99 /* * Extract Compressed Position Report Data Formats from begin of line * [APRS Reference, chapter 9] * * If a position is found, it is deleted from the data. If a * compressed position is found, delete the three csT bytes as well, * even if all spaces. * Returns 0 if the packet is NOT a properly compressed position * packet, returns 1 if ok. */ int extract_comp_position(DataRow *p_station, char **info, int UNUSED(type) ) { int ok; int x1, x2, x3, x4, y1, y2, y3, y4; int c = 0; int s = 0; int T = 0; int len; char *my_data; float lon = 0; float lat = 0; // We were extracting the range from the posit, but never using it. // GCC 6.x whines // float range; int skip = 0; char L; if (debug_level & 1) { fprintf(stderr,"extract_comp_position: Start\n"); } //fprintf(stderr,"extract_comp_position start: %s\n",*info); // compressed data format /YYYYXXXX$csT is a fixed 13-character field // used for ! / @ = data IDs // / Symbol Table ID or overlay: '/' '\' A-Z a-j // YYYY compressed latitude // XXXX compressed longitude // $ Symbol Code // cs compressed // course/speed // radio range // altitude // T compression type ID my_data = (*info); // Check leading char. Must be one of these: // '/' // '\' // A-Z // a-j // L = my_data[0]; if ( L == '/' || L == '\\' || ( L >= 'A' && L <= 'Z' ) || ( L >= 'a' && L <= 'j' ) ) { // We're good so far } else { // Note one of the symbol table or overlay characters, so // there's something funky about this packet. It's not a // properly formatted compressed position. return(0); } //fprintf(stderr,"my_data: %s\n",my_data); // If c = space, csT bytes are ignored. Minimum length: 8 // bytes for lat/lon, 2 for symbol, 3 for csT for a total of 13. len = strlen(my_data); ok = (int)(len >= 13); if (ok) { y1 = (int)my_data[1] - '!'; y2 = (int)my_data[2] - '!'; y3 = (int)my_data[3] - '!'; y4 = (int)my_data[4] - '!'; x1 = (int)my_data[5] - '!'; x2 = (int)my_data[6] - '!'; x3 = (int)my_data[7] - '!'; x4 = (int)my_data[8] - '!'; // csT bytes if (my_data[10] == ' ') // Space { c = -1; // This causes us to ignore csT } else { c = (int)my_data[10] - '!'; s = (int)my_data[11] - '!'; T = (int)my_data[12] - '!'; } skip = 13; // Convert ' ' to '0'. Not specified in APRS Reference! Do // we need it? if (x1 == -1) { x1 = '\0'; } if (x2 == -1) { x2 = '\0'; } if (x3 == -1) { x3 = '\0'; } if (x4 == -1) { x4 = '\0'; } if (y1 == -1) { y1 = '\0'; } if (y2 == -1) { y2 = '\0'; } if (y3 == -1) { y3 = '\0'; } if (y4 == -1) { y4 = '\0'; } ok = (int)(ok && (x1 >= '\0' && x1 < 91)); // /YYYYXXXX$csT ok = (int)(ok && (x2 >= '\0' && x2 < 91)); // 0123456789012 ok = (int)(ok && (x3 >= '\0' && x3 < 91)); ok = (int)(ok && (x4 >= '\0' && x4 < 91)); ok = (int)(ok && (y1 >= '\0' && y1 < 91)); ok = (int)(ok && (y2 >= '\0' && y2 < 91)); ok = (int)(ok && (y3 >= '\0' && y3 < 91)); ok = (int)(ok && (y4 >= '\0' && y4 < 91)); T &= 0x3F; // DK7IN: force Compression Byte to valid format // mask off upper two unused bits, they should be zero!? ok = (int)(ok && (c == -1 || ((c >=0 && c < 91) && (s >= 0 && s < 91) && (T >= 0 && T < 64)))); if (ok) { lat = (((y1 * 91 + y2) * 91 + y3) * 91 + y4 ) / 380926.0; // in deg, 0: 90°N lon = (((x1 * 91 + x2) * 91 + x3) * 91 + x4 ) / 190463.0; // in deg, 0: 180°W lat *= 60 * 60 * 100; // in 1/100 sec lon *= 60 * 60 * 100; // in 1/100 sec // The below check should _not_ be done. Compressed // format can resolve down to about 1 foot worldwide // (0.3 meters). //if ((((long)(lat+4) % 60) > 8) || (((long)(lon+4) % 60) > 8)) // ok = 0; // check max resolution 0.01 min to // catch even more errors } } if (ok) { overlay_symbol(my_data[9], my_data[0], p_station); // Symbol / Table // Callsign check here includes checking SSID for an exact // match // if (!is_my_call(p_station->call_sign,1)) { // don't change my position, I know it better... if ( !(is_my_station(p_station)) ) // don't change my position, I know it better... { // Record the uncompressed lat/long that we just // computed. p_station->coord_lat = (long)((lat)); // in 1/100 sec p_station->coord_lon = (long)((lon)); // in 1/100 sec } if (c >= 0) // ignore csT if c = ' ' { if (c < 90) // Found course/speed or altitude bytes { if ((T & 0x18) == 0x10) // check for GGA (with altitude) { xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%06.0f",pow(1.002,(double)(c*91+s))*0.3048); } else // Found compressed course/speed bytes { // Convert 0 degrees to 360 degrees so that // Xastir will see it as a valid course and do // dead-reckoning properly on this station if (c == 0) { c = 90; } // Compute course in degrees xastir_snprintf(p_station->course, sizeof(p_station->course), "%03d", c*4); // Compute speed in knots xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%03.0f", pow( 1.08,(double)s ) - 1.0); //fprintf(stderr,"Decoded speed:%s, course:%s\n",p_station->speed,p_station->course); } } else // Found pre-calculated radio range bytes { if (c == 90) { // pre-calculated radio range // Commented out to silence GCC 6.x warning about // "set but unused" variables. // range = 2 * pow(1.08,(double)s); // miles // DK7IN: dirty hack... but better than nothing if (s <= 5) // 2.9387 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "000"); } else if (s <= 17) // 7.40 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "111"); } else if (s <= 36) // 31.936 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "222"); } else if (s <= 75) // 642.41 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "333"); } else // max 90: 2037.8 mi { xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "PHG%s0", "444"); } } } } (*info) += skip; // delete position from comment } if (debug_level & 1) { if (ok) { fprintf(stderr,"*** extract_comp_position: Succeeded: %ld\t%ld\n", p_station->coord_lat, p_station->coord_lon); } else { fprintf(stderr,"*** extract_comp_position: Failed!\n"); } } //fprintf(stderr," extract_comp_position end: %s\n",*info); return(ok); } // // Extract speed and/or course from beginning of info field // // Returns course in degrees, speed in KNOTS. // int extract_speed_course(char *info, char *speed, char *course) { int i,found,len; len = (int)strlen(info); found = 0; speed[0] = course[0] = '\0'; if (len >= 7) { found = 1; for(i=0; found && i<7; i++) // check data format { if (i==3) // check separator { if (info[i]!='/') { found = 0; } } else { if( !( isdigit((int)info[i]) || (info[i] == ' ') // Spaces and periods are allowed. Need these || (info[i] == '.') ) ) // here so that we can get the field deleted { found = 0; } } } } if (found) { substr(course,info,3); substr(speed,info+4,3); for (i=0; i<=len-7; i++) // delete speed/course from info field { info[i] = info[i+7]; } } if (!found || atoi(course) < 1) // course 0 means undefined { // speed[0] ='\0'; // Don't do this! We can have a valid // speed without a valid course. course[0]='\0'; } else // recheck data format looking for undefined fields { for(i=0; i<2; i++) { if( !(isdigit((int)speed[i]) ) ) { speed[0] = '\0'; } if( !(isdigit((int)course[i]) ) ) { course[0] = '\0'; } } } return(found); } /* * Extract bearing and number/range/quality from beginning of info field */ int extract_bearing_NRQ(char *info, char *bearing, char *nrq) { int i,found,len; len = (int)strlen(info); found = 0; if (len >= 8) { found = 1; for(i=1; found && i<8; i++) // check data format if(!(isdigit((int)info[i]) || (i==4 && info[i]=='/'))) { found=0; } } if (found) { substr(bearing,info+1,3); substr(nrq,info+5,3); //fprintf(stderr,"Bearing: %s\tNRQ: %s\n", bearing, nrq); for (i=0; i<=len-8; i++) // delete bearing/nrq from info field { info[i] = info[i+8]; } } // if (!found || nrq[2] == '0') { // Q of 0 means useless bearing if (!found) { bearing[0] ='\0'; nrq[0]='\0'; } return(found); } /* * Extract altitude from APRS info field "/A=012345" in feet */ int extract_altitude(char *info, char *altitude) { int i,ofs,found,len; found=0; len = (int)strlen(info); for(ofs=0; !found && ofs= 9 && strncmp(info2,"PHG",3)==0 && info2[7]=='/' && info2[8]!='A' // trailing '/' not defined in Reference... && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-8; i++) // delete powergain from data extension field { info2[i] = info2[i+8]; } } else { if (len >= 7 && strncmp(info2,"PHG",3)==0 && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-7; i++) // delete powergain from data extension field { info2[i] = info2[i+7]; } } else if (len >= 7 && strncmp(info2,"RNG",3)==0 && isdigit((int)info2[3]) && isdigit((int)info2[4]) && isdigit((int)info2[5]) && isdigit((int)info2[6])) { substr(phgd,info2,7); found = 1; for (i=0; i<=len-7; i++) // delete powergain from data extension field { info2[i] = info2[i+7]; } } else { phgd[0] = '\0'; } } return(found); } /* * Extract omnidf from APRS info field "DFS1234/" from APRS data extension */ int extract_omnidf(char *info, char *phgd) { int i,len; len = (int)strlen(info); if (len >= 8 && strncmp(info,"DFS",3)==0 && info[7]=='/' // trailing '/' not defined in Reference... && isdigit((int)info[3]) && isdigit((int)info[5]) && isdigit((int)info[6])) { substr(phgd,info,7); for (i=0; i<=len-8; i++) // delete omnidf from data extension field { info[i] = info[i+8]; } return(1); } else { phgd[0] = '\0'; return(0); } } /* * Extract signpost data from APRS info field: "{123}", an APRS data extension * Format can be {1}, {12}, or {123}. Letters or digits are ok. */ int extract_signpost(char *info, char *signpost) { int i,found,len,done; //0123456 //{1} //{12} //{121} found=0; len = (int)strlen(info); if ( (len > 2) && (info[0] == '{') && ( (info[2] == '}' ) || (info[3] == '}' ) || (info[4] == '}' ) ) ) { i = 1; done = 0; while (!done) // Snag up to three digits { if (info[i] == '}') // We're done { found = i; // found = position of '}' character done++; } else { signpost[i-1] = info[i]; } i++; if ( (i > 4) && !done) // Something is wrong, we should be done by now { done++; signpost[0] = '\0'; return(0); } } substr(signpost,info+1,found-1); found++; for (i=0; i<=len-found; i++) // delete omnidf from data extension field { info[i] = info[i+found]; } return(1); } else { signpost[0] = '\0'; return(0); } } /* * Extract probability_min data from APRS info field: "Pmin1.23," * Please note the ending comma. We use it to delimit the field. */ int extract_probability_min(char *info, char *prob_min, int prob_min_size) { int len,done; char *c; char *d; //fprintf(stderr,"%s\n",info); len = (int)strlen(info); if (len < 6) // Too short { //fprintf(stderr,"Pmin too short: %s\n",info); prob_min[0] = '\0'; return(0); } c = strstr(info,"Pmin"); if (c == NULL) // Pmin not found { //fprintf(stderr,"Pmin not found: %s\n",info); prob_min[0] = '\0'; return(0); } c = c+4; // Skip the Pmin part // Find the ending comma d = c; done = 0; while (!done) { if (*d == ',') // We're done { done++; } else { d++; } // Check for string too long if ( ((d-c) > 10) && !done) // Something is wrong, we should be done by now { //fprintf(stderr,"Pmin too long: %d,%s\n",d-c,info); prob_min[0] = '\0'; return(0); } } // Copy the substring across xastir_snprintf(prob_min, prob_min_size, "%s", c); prob_min[d-c] = '\0'; prob_min[10] = '\0'; // Just to make sure // Delete data from data extension field d++; // Skip the comma done = 0; while (!done) { *(c-4) = *d; if (*d == '\0') { done++; } c++; d++; } return(1); } /* * Extract probability_max data from APRS info field: "Pmax1.23," * Please note the ending comma. We use it to delimit the field. */ int extract_probability_max(char *info, char *prob_max, int prob_max_size) { int len,done; char *c; char *d; //fprintf(stderr,"%s\n",info); len = (int)strlen(info); if (len < 6) // Too short { //fprintf(stderr,"Pmax too short: %s\n",info); prob_max[0] = '\0'; return(0); } c = strstr(info,"Pmax"); if (c == NULL) // Pmax not found { //fprintf(stderr,"Pmax not found: %s\n",info); prob_max[0] = '\0'; return(0); } c = c+4; // Skip the Pmax part // Find the ending comma d = c; done = 0; while (!done) { if (*d == ',') // We're done { done++; } else { d++; } // Check for string too long if ( ((d-c) > 10) && !done) // Something is wrong, we should be done by now { //fprintf(stderr,"Pmax too long: %d,%s\n",d-c,info); prob_max[0] = '\0'; return(0); } } // Copy the substring across xastir_snprintf(prob_max, prob_max_size, "%s", c); prob_max[d-c] = '\0'; prob_max[10] = '\0'; // Just to make sure // Delete data from data extension field d++; // Skip the comma done = 0; while (!done) { *(c-4) = *d; if (*d == '\0') { done++; } c++; d++; } return(1); } static void clear_area(DataRow *p_station) { p_station->aprs_symbol.area_object.type = AREA_NONE; p_station->aprs_symbol.area_object.color = AREA_GRAY_LO; p_station->aprs_symbol.area_object.sqrt_lat_off = 0; p_station->aprs_symbol.area_object.sqrt_lon_off = 0; p_station->aprs_symbol.area_object.corridor_width = 0; } /* * Extract Area Object */ void extract_area(DataRow *p_station, char *data) { int i, val, len; unsigned int uval; AreaObject temp_area; /* NOTE: If we are here, the symbol was the area symbol. But if this is a slightly corrupted packet, we shouldn't blow away the area info for this station, since it could be from a previously received good packet. So we will work on temp_area and only copy to p_station at the end, returning on any error as we parse. N7TAP */ //fprintf(stderr,"Area Data: %s\n", data); len = (int)strlen(data); val = data[0] - '0'; if (val >= 0 && val <= AREA_MAX) { temp_area.type = val; val = data[4] - '0'; temp_area.color = AREA_BLACK_HI; // Initial value if (data[3] == '/') { if (val >=0 && val <= 9) { temp_area.color = val; } else { if (debug_level & 2) { fprintf(stderr,"Bad area color (/)"); } return; } } else if (data[3] == '1') { if (val >=0 && val <= 5) { temp_area.color = 10 + val; } else { if (debug_level & 2) { fprintf(stderr,"Bad area color (1)"); } return; } } val = 0; if (isdigit((int)data[1]) && isdigit((int)data[2])) { val = (10 * (data[1] - '0')) + (data[2] - '0'); } else { if (debug_level & 2) { fprintf(stderr,"Bad area sqrt_lat_off"); } return; } temp_area.sqrt_lat_off = val; val = 0; if (isdigit((int)data[5]) && isdigit((int)data[6])) { val = (10 * (data[5] - '0')) + (data[6] - '0'); } else { if (debug_level & 2) { fprintf(stderr,"Bad area sqrt_lon_off"); } return; } temp_area.sqrt_lon_off = val; for (i = 0; i <= len-7; i++) // delete area object from data extension field { data[i] = data[i+7]; } len -= 7; if (temp_area.type == AREA_LINE_RIGHT || temp_area.type == AREA_LINE_LEFT) { if (data[0] == '{') { if (sscanf(data, "{%u}", &uval) == 1) { temp_area.corridor_width = uval & 0xffff; for (i = 0; i <= len; i++) if (data[i] == '}') { break; } uval = i+1; for (i = 0; i <= (int)(len-uval); i++) { data[i] = data[i+uval]; // delete corridor width } } else { if (debug_level & 2) { fprintf(stderr,"Bad corridor width identifier"); } temp_area.corridor_width = 0; return; } } else { if (debug_level & 2) { fprintf(stderr,"No corridor width specified"); } temp_area.corridor_width = 0; } } else { temp_area.corridor_width = 0; } } else { if (debug_level & 2) { fprintf(stderr,"Bad area type: %c\n", data[0]); } return; } memcpy(&(p_station->aprs_symbol.area_object), &temp_area, sizeof(AreaObject)); if (debug_level & 2) { fprintf(stderr,"AreaObject: type=%d color=%d sqrt_lat_off=%d sqrt_lon_off=%d corridor_width=%d\n", p_station->aprs_symbol.area_object.type, p_station->aprs_symbol.area_object.color, p_station->aprs_symbol.area_object.sqrt_lat_off, p_station->aprs_symbol.area_object.sqrt_lon_off, p_station->aprs_symbol.area_object.corridor_width); } } /* * Extract Time from begin of line [APRS Reference, chapter 6] * * If a time string is found in "data", it is deleted from the * beginning of the string. */ int extract_time(DataRow * UNUSED(p_station), char *data, int type) { int len, i; int ok = 0; // todo: better check of time data ranges len = (int)strlen(data); if (type == APRS_WX2) { // 8 digit time from stand-alone positionless weather stations... if (len > 8) { // MMDDHHMM zulu time // MM 01-12 todo: better check of time data ranges // DD 01-31 // HH 01-23 // MM 01-59 ok = 1; for (i=0; ok && i<8; i++) if (!isdigit((int)data[i])) { ok = 0; } if (ok) { // substr(p_station->station_time,data+2,6); // p_station->station_time_type = 'z'; for (i=0; i<=len-8; i++) // delete time from data { data[i] = data[i+8]; } } } } else { if (len > 6) { // Status messages only with optional zulu format // DK7IN: APRS ref says one of 'z' '/' 'h', but I found 'c' at HB9TJM-8 ??? if (toupper(data[6])=='Z' || data[6]=='/' || toupper(data[6])=='H') { ok = 1; } for (i=0; ok && i<6; i++) if (!isdigit((int)data[i])) { ok = 0; } if (ok) { // substr(p_station->station_time,data,6); // p_station->station_time_type = data[6]; for (i=0; i<=len-7; i++) // delete time from data { data[i] = data[i+7]; } } } } return(ok); } // APRS Data Extensions [APRS Reference p.27] // .../... Course & Speed, may be followed by others (see p.27) // .../... Wind Dir and Speed // PHG.... Station Power and Effective Antenna Height/Gain // RNG.... Pre-Calculated Radio Range // DFS.... DF Signal Strength and Effective Antenna Height/Gain // T../C.. Area Object Descriptor /* Extract one of several possible APRS Data Extensions */ void process_data_extension(DataRow *p_station, char *data, int UNUSED(type) ) { char temp1[7+1]; char temp2[3+1]; char temp3[10+1]; char bearing[3+1]; char nrq[3+1]; if (p_station->aprs_symbol.aprs_type == '\\' && p_station->aprs_symbol.aprs_symbol == 'l') { /* This check needs to come first because the area object extension can look exactly like what extract_speed_course will attempt to decode. */ extract_area(p_station, data); } else { clear_area(p_station); // we got a packet with a non area symbol, so clear the data if (extract_speed_course(data,temp1,temp2)) // ... from Mic-E, etc. { //fprintf(stderr,"extracted speed/course\n"); if (atof(temp2) > 0) { //fprintf(stderr,"course is non-zero\n"); xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%06.2f", atof(temp1)); xastir_snprintf(p_station->course, // in degrees sizeof(p_station->course), "%s", temp2); } if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } // Don't try to extract speed & course if a compressed // object. Test for beam headings for compressed packets // here else if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } else { if (extract_powergain_range(data,temp1)) { //fprintf(stderr,"Found power_gain: %s\n", temp1); xastir_snprintf(p_station->power_gain, sizeof(p_station->power_gain), "%s", temp1); if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } else { if (extract_omnidf(data,temp1)) { xastir_snprintf(p_station->signal_gain, sizeof(p_station->signal_gain), "%s", temp1); // Grab the SHGD values p_station->bearing[0] = '\0'; // And blank out the bearing/NRQ values p_station->NRQ[0] = '\0'; // The spec shows speed/course before DFS, but example packets that // come with DOSaprs show DFSxxxx/speed/course. We'll take care of // that possibility by trying to decode speed/course again. if (extract_speed_course(data,temp1,temp2)) // ... from Mic-E, etc. { //fprintf(stderr,"extracted speed/course\n"); if (atof(temp2) > 0) { //fprintf(stderr,"course is non-zero\n"); xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%06.2f", atof(temp1)); xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", temp2); // in degrees } } // The spec shows that omnidf and bearing/NRQ can be in the same // packet, which makes no sense, but we'll try to decode it that // way anyway. if (extract_bearing_NRQ(data, bearing, nrq)) // Beam headings from DF'ing { //fprintf(stderr,"extracted bearing and NRQ\n"); xastir_snprintf(p_station->bearing, sizeof(p_station->bearing), "%s", bearing); xastir_snprintf(p_station->NRQ, sizeof(p_station->NRQ), "%s", nrq); //p_station->signal_gain[0] = '\0'; // And blank out the shgd values } } } } if (extract_signpost(data, temp2)) { //fprintf(stderr,"extracted signpost data\n"); xastir_snprintf(p_station->signpost, sizeof(p_station->signpost), "%s", temp2); } if (extract_probability_min(data, temp3, sizeof(temp3))) { if (strncasecmp(temp3, "0.0", sizeof(temp3)) == 0) { p_station->probability_min[0] = '\0'; // Clear it out } else if (strncasecmp(temp3, "0", sizeof(temp3)) == 0) { p_station->probability_min[0] = '\0'; // Clear it out } else { //fprintf(stderr,"extracted probability_min data: %s\n",temp3); xastir_snprintf(p_station->probability_min, sizeof(p_station->probability_min), "%s", temp3); } } else { p_station->probability_min[0] = '\0'; // Clear it out } if (extract_probability_max(data, temp3, sizeof(temp3))) { if (strncasecmp(temp3, "0.0", sizeof(temp3)) == 0) { p_station->probability_max[0] = '\0'; // Clear it out } else if (strncasecmp(temp3, "0", sizeof(temp3)) == 0) { p_station->probability_max[0] = '\0'; // Clear it out } else { //fprintf(stderr,"extracted probability_max data: %s\n",temp3); xastir_snprintf(p_station->probability_max, sizeof(p_station->probability_max), "%s", temp3); } } else { p_station->probability_max[0] = '\0'; // Clear it out } } } /* extract all available information from info field */ void process_info_field(DataRow *p_station, char *info, int UNUSED(type) ) { char temp_data[6+1]; // char time_data[MAX_TIME]; if (extract_altitude(info,temp_data)) // get altitude { xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%.2f",atof(temp_data)*0.3048); //fprintf(stderr,"%.2f\n",atof(temp_data)*0.3048); } // do other things... } //////////////////////////////////////////////////////////////////////////////////////////////////// // type: 18 // call_sign: VE6GRR-15 // path: GPSLV,TCPIP,VE7DIE* // data: GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0, // from: T // port: 0 // origin: // third_party: 1 // // Extract data for $GPRMC, it fails if there is no position!! // // GPRMC,UTC-Time,status(A/V),lat,N/S,lon,E/W,SOG,COG,UTC-Date,Mag-Var,E/W,Fix-Quality[*CHK] // GPRMC,hhmmss[.sss],{A|V},ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},[dd]d.d[ddddd],[dd]d.d[d],ddmmyy,[ddd.d],[{E|W}][,A|D|E|N|S][*CHK] // // The last field before the checksum is entirely optional, and in // fact first appeared in NMEA 2.3 (fairly recently). Most GPS's do // not currently put out that field. The field may be null or // nonexistent including the comma. Only "A" or "D" are considered // to be active and reliable fixes if this field is present. // Fix-Quality: // A: Autonomous // D: Differential // E: Estimated // N: Not Valid // S: Simulator // // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 // $GPRMC,104748.821,A,4301.1492,N,08803.0374,W,0.085048,102.36,010605,,*1A // $GPRMC,104749.821,A,4301.1492,N,08803.0377,W,0.054215,74.60,010605,,*2D // int extract_RMC(DataRow *p_station, char *data, char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[12]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; if (debug_level & 256) { fprintf(stderr,"extract_RMC\n"); } // should we copy it before processing? it changes data: ',' gets substituted by '\0' !! ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 34) ) // Not enough data to parse position from. { if (debug_level & 256) { fprintf(stderr,"Invalid RMC string: Too short\n"); } return(ok); } p_station->record_type = NORMAL_GPS_RMC; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 12, ','); // The Substring[] array contains pointers to each substring in // the original data string. // GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0,E*7D // 0 1 2 3 4 5 6 7 8 9 10 11 if (Substring[0] == NULL) // No GPRMC string { return(ok); } if (Substring[1] == NULL) // No time string { return(ok); } if (Substring[2] == NULL) // No valid fix char { return(ok); } if (Substring[2][0] != 'A' && Substring[2][0] != 'V') { return(ok); } // V is a warning but we can get good data still ? // DK7IN: got no position with 'V' ! if (Substring[3] == NULL) // No latitude string { return(ok); } if (Substring[4] == NULL) // No latitude N/S { return(ok); } // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234) or leave one out (4801.12). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[3],'.')) { *num_digits = strlen(Substring[3]) - (int)(strchr(Substring[3],'.') - Substring[3]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[4][0]); if (temp_char != 'N' && temp_char != 'S') // Bad N/S { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[3], temp_char); if (Substring[5] == NULL) // No longitude string { return(ok); } if (Substring[6] == NULL) // No longitude E/W { return(ok); } // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' temp_char = toupper((int)Substring[6][0]); if (temp_char != 'E' && temp_char != 'W') // Bad E/W { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[5], temp_char); p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); // If we've made it this far, We have enough for a position now! ok = 1; // Now that we have a basic position, let's see what other data // can be parsed from the packet. The rest of it can still be // corrupt, so we're proceeding carefully under yellow alert on // impulse engines only. // GPRMC,034728,A,5101.016,N,11359.464,W,000.0,284.9,110701,018.0,E*7D // 0 1 2 3 4 5 6 7 8 9 10 11 if (Substring[7] == NULL) // No speed string { p_station->speed[0] = '\0'; // No speed available return(ok); } else { xastir_snprintf(p_station->speed, MAX_SPEED, "%s", Substring[7]); // Is it always knots, otherwise we need a conversion! } if (Substring[8] == NULL) // No course string { xastir_snprintf(p_station->course, sizeof(p_station->course), "000.0"); // No course available return(ok); } else { xastir_snprintf(p_station->course, MAX_COURSE, "%s", Substring[8]); } if (debug_level & 256) { if (ok) { fprintf(stderr,"extract_RMC succeeded: %s\n",data); } else { fprintf(stderr,"extract_RMC failed: %s\n",data); } } return(ok); } // // Extract data for $GPGGA // // GPGGA,UTC-Time,lat,N/S,long,E/W,GPS-Quality,nsat,HDOP,MSL-Meters,M,Geoidal-Meters,M,DGPS-Data-Age(seconds),DGPS-Ref-Station-ID[*CHK] // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // // GPS-Quality: // 0: Invalid Fix // 1: GPS Fix // 2: DGPS Fix // 3: PPS Fix // 4: RTK Fix // 5: Float RTK Fix // 6: Estimated (dead-reckoning) Fix // 7: Manual Input Mode // 8: Simulation Mode // // $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75 // $GPGGA,104438.833,4301.1439,N,08803.0338,W,1,05,1.8,185.8,M,-34.2,M,0.0,0000*40 // // nsat=Number of Satellites being tracked // // int extract_GGA(DataRow *p_station,char *data,char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[15]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; int temp_num; if (debug_level & 256) { fprintf(stderr, "extract_GGA\n"); } ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 32) ) // Not enough data to parse position from. { return(ok); } p_station->record_type = NORMAL_GPS_GGA; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 15, ','); // The Substring[] array contains pointers to each substring in // the original data string. // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // 0 1 2 3 4 5 6 7 8 9 1 1 1 1 1 // 0 1 2 3 4 if (Substring[0] == NULL) // No GPGGA string { return(ok); } if (Substring[1] == NULL) // No time string { return(ok); } if (Substring[2] == NULL) // No latitude string { return(ok); } if (Substring[3] == NULL) // No latitude N/S { return(ok); } // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[2],'.')) { *num_digits = strlen(Substring[2]) - (int)(strchr(Substring[2],'.') - Substring[2]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[3][0]); if (temp_char != 'N' && temp_char != 'S') // Bad N/S { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[2], temp_char); if (Substring[4] == NULL) // No longitude string { return(ok); } if (Substring[5] == NULL) // No longitude E/W { return(ok); } // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' temp_char = toupper((int)Substring[5][0]); if (temp_char != 'E' && temp_char != 'W') // Bad E/W { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[4], temp_char); p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); // If we've made it this far, We have enough for a position now! ok = 1; // Now that we have a basic position, let's see what other data // can be parsed from the packet. The rest of it can still be // corrupt, so we're proceeding carefully under yellow alert on // impulse engines only. // Check for valid fix { if (Substring[6] == NULL || Substring[6][0] == '0' // Fix quality || Substring[7] == NULL // Sat number || Substring[8] == NULL // hdop || Substring[9] == NULL) // Altitude in meters { p_station->sats_visible[0] = '\0'; // Store empty sats visible p_station->altitude[0] = '\0';; // Store empty altitude return(ok); // A field between fix quality and altitude is missing } // Need to check for validity of this number. Should be 0-12? Perhaps a few more with WAAS, GLONASS, etc? temp_num = atoi(Substring[7]); if (temp_num < 0 || temp_num > 30) { return(ok); // Number of satellites not valid } else { // Store xastir_snprintf(p_station->sats_visible, sizeof(p_station->sats_visible), "%d", temp_num); } // Check for valid number for HDOP instead of just throwing it away? xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%s", Substring[9]); // Get altitude // Need to check for valid altitude before conversion // unit is in meters, if not adjust value ??? if (Substring[10] == NULL) // No units for altitude { return(ok); } if (Substring[10][0] != 'M') { //fprintf(stderr,"ERROR: should adjust altitude for meters\n"); //} else { // Altitude units wrong. Assume altitude bad p_station->altitude[0] = '\0'; } if (debug_level & 256) { if (ok) { fprintf(stderr,"extract_GGA succeeded: %s\n",data); } else { fprintf(stderr,"extract_GGA failed: %s\n",data); } } return(ok); } // // Extract data for $GPGLL // // $GPGLL,4748.811,N,12219.564,W,033850,A*3C // lat, long, UTCtime in hhmmss, A=Valid, checksum // // GPGLL,4748.811,N,12219.564,W,033850,A*3C // 0 1 2 3 4 5 6 // int extract_GLL(DataRow *p_station,char *data,char *call_sign, char *path, int *num_digits) { char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... ??? char lat_s[20]; char long_s[20]; int ok; char *Substring[7]; // Pointers to substrings parsed by split_string() char temp_string[MAX_MESSAGE_LENGTH+1]; char temp_char; if (debug_level & 256) { fprintf(stderr, "extract_GLL\n"); } ok = 0; // Start out as invalid. If we get enough info, we change this to a 1. if ( (data == NULL) || (strlen(data) < 28) ) // Not enough data to parse position from. { return(ok); } p_station->record_type = NORMAL_GPS_GLL; // Create a timestamp from the current time // get_time saves the time in temp_data xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag /* check aprs type on call sign */ p_station->aprs_symbol = *id_callsign(call_sign, path); // Make a copy of the incoming data. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", data); split_string(temp_string, Substring, 7, ','); // The Substring[] array contains pointers to each substring in // the original data string. if (Substring[0] == NULL) // No GPGGA string { return(ok); } if (Substring[1] == NULL) // No latitude string { return(ok); } if (Substring[2] == NULL) // No N/S string { return(ok); } if (Substring[3] == NULL) // No longitude string { return(ok); } if (Substring[4] == NULL) // No E/W string { return(ok); } temp_char = toupper((int)Substring[2][0]); if (temp_char != 'N' && temp_char != 'S') { return(ok); } xastir_snprintf(lat_s, sizeof(lat_s), "%s%c", Substring[1], temp_char); // Need to check lat_s for validity here. Note that some GPS's put out another digit of precision // (4801.1234). Next character after digits should be a ',' // Count digits after the decimal point for latitude if (strchr(Substring[1],'.')) { *num_digits = strlen(Substring[1]) - (int)(strchr(Substring[1],'.') - Substring[1]) - 1; } else { *num_digits = 0; } temp_char = toupper((int)Substring[4][0]); if (temp_char != 'E' && temp_char != 'W') { return(ok); } xastir_snprintf(long_s, sizeof(long_s), "%s%c", Substring[3], temp_char); // Need to check long_s for validity here. Should be all digits. Note that some GPS's put out another // digit of precision. (12201.1234). Next character after digits should be a ',' p_station->coord_lat = convert_lat_s2l(lat_s); p_station->coord_lon = convert_lon_s2l(long_s); ok = 1; // We have enough for a position now xastir_snprintf(p_station->course, sizeof(p_station->course), "000.0"); // Fill in with dummy values p_station->speed[0] = '\0'; // Fill in with dummy values // A is valid, V is a warning but we can get good data still? // We don't currently check the data valid flag. return(ok); } // Add a status line to the linked-list of status records // associated with a station. Note that a blank status line is // allowed, but we don't store that unless we have seen a non-blank // status line previously. // void add_status(DataRow *p_station, char *status_string) { CommentRow *ptr; int add_it = 0; int len; len = strlen(status_string); // Eliminate line-end chars if (len > 1) { if ( (status_string[len-1] == '\n') || (status_string[len-1] == '\r') ) { status_string[len-1] = '\0'; } } // Shorten it //fprintf(stderr,"1Status: (%s)\n",status_string); (void)remove_trailing_spaces(status_string); //fprintf(stderr,"2Status: (%s)\n",status_string); (void)remove_leading_spaces(status_string); //fprintf(stderr,"3Status: (%s)\n",status_string); len = strlen(status_string); // Check for valid pointer if (p_station != NULL) { // We should probably create a new station record for this station // if there isn't one. This allows us to collect as much info about // a station as we can until a posit comes in for it. Right now we // don't do this. If we decide to do this in the future, we also // need a method to find out the info about that station without // having to click on an icon, 'cuz the symbol won't be on our map // until we have a posit. //fprintf(stderr,"Station:%s\tStatus:%s\n",p_station->call_sign,status_string); // Check whether we have any data stored for this station if (p_station->status_data == NULL) { if (len > 0) { // No status stored yet and new status is non-NULL, // so add it to the list. add_it++; } } else // We have status data stored already { // Check for an identical string CommentRow *ptr2; int ii = 0; ptr = p_station->status_data; ptr2 = ptr; while (ptr != NULL) { // Note that both text_ptr and comment_string can be // empty strings. if (strcasecmp(ptr->text_ptr, status_string) == 0) { // Found a matching string //fprintf(stderr,"Found match: //%s:%s\n",p_station->call_sign,status_string); // Instead of updating the timestamp, we'll delete the record from // the list and add it to the top in the code below. Make sure to // tweak the "ii" pointer so that we don't end up shortening the // list unnecessarily. if (ptr == p_station->status_data) { // Only update the timestamp: We're at the // beginning of the list already. ptr->sec_heard = sec_now(); return; // No need to add a new record } else // Delete the record { CommentRow *ptr3; // Keep a pointer to the record ptr3 = ptr; // Close the chain, skipping this record ptr2->next = ptr3->next; // Skip "ptr" over the record we wish to // delete ptr = ptr3->next; // Free the record free(ptr3->text_ptr); free(ptr3); // Muck with the counter 'cuz we just // deleted one record ii--; } } ptr2 = ptr; // Back one record if (ptr != NULL) { ptr = ptr->next; } ii++; } // No matching string found, or new timestamp found for // old record. Add it to the top of the list. add_it++; //fprintf(stderr,"No match: //%s:%s\n",p_station->call_sign,status_string); // We counted the records. If we have more than // MAX_STATUS_LINES records we'll delete/free the last // one to make room for the next. This keeps us from // storing unique status records ad infinitum for active // stations, limiting the total space used. // if (ii >= MAX_STATUS_LINES) { // We know we didn't get a match, and that our list // is full (as full as we want it to be). Traverse // the list again, looking for ptr2->next->next == // NULL. If found, free last record and set the // ptr2->next pointer to NULL. ptr2 = p_station->status_data; while (ptr2->next->next != NULL) { ptr2 = ptr2->next; } // At this point, we have a pointer to the last // record in ptr2->next. Free it and the text // string in it. free(ptr2->next->text_ptr); free(ptr2->next); ptr2->next = NULL; } } if (add_it) // We add to the beginning so we don't have { // to traverse the linked list. This also // puts new records at the beginning of the // list to keep them in sorted order. ptr = p_station->status_data; // Save old pointer to records p_station->status_data = (CommentRow *)malloc(sizeof(CommentRow)); CHECKMALLOC(p_station->status_data); p_station->status_data->next = ptr; // Link in old records or NULL // Malloc the string space we'll need, attach it to our // new record p_station->status_data->text_ptr = (char *)malloc(sizeof(char) * (len+1)); CHECKMALLOC(p_station->status_data->text_ptr); // Fill in the string xastir_snprintf(p_station->status_data->text_ptr, len+1, "%s", status_string); // Fill in the timestamp p_station->status_data->sec_heard = sec_now(); //fprintf(stderr,"Station:%s\tStatus:%s\n\n",p_station->call_sign,p_station->status_data->text_ptr); } } } // Add a comment line to the linked-list of comment records // associated with a station. Note that a blank comment is allowed // and necessary for the times when we wish to blank out the comment // on an object/item, but we don't store that unless we have seen a // non-blank comment line previously. // void add_comment(DataRow *p_station, char *comment_string) { CommentRow *ptr; int add_it = 0; int len; len = strlen(comment_string); // Eliminate line-end chars if (len > 1) { if ( (comment_string[len-1] == '\n') || (comment_string[len-1] == '\r') ) { comment_string[len-1] = '\0'; } } // Shorten it //fprintf(stderr,"1Comment: (%s)\n",comment_string); (void)remove_trailing_spaces(comment_string); //fprintf(stderr,"2Comment: (%s)\n",comment_string); ///////TVR DEBUGGING RESULTS 28 March 2007: //NO! DON'T DO THIS --- it breaks multipoint objects! // (void)remove_leading_spaces(comment_string); /////////////////////////////////////////// //fprintf(stderr,"3Comment: (%s)\n",comment_string); len = strlen(comment_string); // Check for valid pointer if (p_station != NULL) { // Check whether we have any data stored for this station if (p_station->comment_data == NULL) { if (len > 0) { // No comments stored yet and new comment is // non-NULL, so add it to the list. add_it++; } } else // We have comment data stored already { // Check for an identical string CommentRow *ptr2; int ii = 0; ptr = p_station->comment_data; ptr2 = ptr; while (ptr != NULL) { // Note that both text_ptr and comment_string can be // empty strings. if (strcasecmp(ptr->text_ptr, comment_string) == 0) { // Found a matching string //fprintf(stderr,"Found match: %s:%s\n",p_station->call_sign,comment_string); // Instead of updating the timestamp, we'll delete the record from // the list and add it to the top in the code below. Make sure to // tweak the "ii" pointer so that we don't end up shortening the // list unnecessarily. if (ptr == p_station->comment_data) { // Only update the timestamp: We're at the // beginning of the list already. ptr->sec_heard = sec_now(); return; // No need to add a new record } else // Delete the record { CommentRow *ptr3; // Keep a pointer to the record ptr3 = ptr; // Close the chain, skipping this record ptr2->next = ptr3->next; // Skip "ptr" over the record we with to // delete ptr = ptr3->next; // Free the record free(ptr3->text_ptr); free(ptr3); // Muck with the counter 'cuz we just // deleted one record ii--; } } ptr2 = ptr; // Keep this pointer one record back as // we progress. if (ptr != NULL) { ptr = ptr->next; } ii++; } // No matching string found, or new timestamp found for // old record. Add it to the top of the list. add_it++; //fprintf(stderr,"No match: %s:%s\n",p_station->call_sign,comment_string); // We counted the records. If we have more than // MAX_COMMENT_LINES records we'll delete/free the last // one to make room for the next. This keeps us from // storing unique comment records ad infinitum for // active stations, limiting the total space used. // if (ii >= MAX_COMMENT_LINES) { // We know we didn't get a match, and that our list // is full (as we want it to be). Traverse the list // again, looking for ptr2->next->next == NULL. If // found, free that last record and set the // ptr2->next pointer to NULL. ptr2 = p_station->comment_data; while (ptr2->next->next != NULL) { ptr2 = ptr2->next; } // At this point, we have a pointer to the last // record in ptr2->next. Free it and the text // string in it. free(ptr2->next->text_ptr); free(ptr2->next); ptr2->next = NULL; } } if (add_it) // We add to the beginning so we don't have { // to traverse the linked list. This also // puts new records at the beginning of the // list to keep them in sorted order. ptr = p_station->comment_data; // Save old pointer to records p_station->comment_data = (CommentRow *)malloc(sizeof(CommentRow)); CHECKMALLOC(p_station->comment_data); p_station->comment_data->next = ptr; // Link in old records or NULL // Malloc the string space we'll need, attach it to our // new record p_station->comment_data->text_ptr = (char *)malloc(sizeof(char) * (len+1)); CHECKMALLOC(p_station->comment_data->text_ptr); // Fill in the string xastir_snprintf(p_station->comment_data->text_ptr, len+1, "%s", comment_string); // Fill in the timestamp p_station->comment_data->sec_heard = sec_now(); } } } /* * Add data from APRS information field to station database * Returns a 1 if successful */ int data_add(int type, char *call_sign, char *path, char *data, char from, int port, char *origin, int third_party, int station_is_mine, int object_is_mine) { DataRow *p_station; DataRow *p_time; char call[MAX_CALLSIGN+1]; char new_station; long last_lat, last_lon; char last_alt[MAX_ALTITUDE]; char last_speed[MAX_SPEED+1]; char last_course[MAX_COURSE+1]; time_t last_stn_sec; short last_flag; char temp_data[40]; // short term string storage, MAX_CALLSIGN, ... long l_lat, l_lon; double distance; char station_id[600]; int found_pos; float value; WeatherRow *weather; int moving; int changed_pos; int screen_update; int ok, store; int ok_to_display; int compr_pos; char *p = NULL; // KC2ELS - used for WIDEn-N int direct = 0; int new_origin_is_mine = 0; int num_digits = 0; // Number of digits after decimal point in NMEA string #ifdef HAVE_DB int ii; // loop counter for interfaces list #endif /* HAVE_DB */ // call and path had been validated before // Check "data" against the max APRS length, and dump the packet if too long. if ( (data != NULL) && (strlen(data) > MAX_INFO_FIELD_SIZE) ) // Overly long packet. Throw it away. { if (debug_level & 1) { fprintf(stderr,"data_add: Overly long packet. Throwing it away.\n"); } return(0); // Not an ok packet } // Check for some reasonable string in call_sign parameter if (call_sign == NULL || strlen(call_sign) == 0) { if (debug_level & 1) { fprintf(stderr,"data_add():call_sign was NULL or empty, exiting\n"); } return(0); } if (debug_level & 1) fprintf(stderr,"data_add:\n\ttype: %d\n\tcall_sign: %s\n\tpath: %s\n\tdata: %s\n\tfrom: %c\n\tport: %d\n\torigin: %s\n\tthird_party: %d\n", type, call_sign, path, data ? data : "NULL", // This parameter may be NULL, if exp1 then exp2 else exp3 from, port, origin ? origin : "NULL", // This parameter may be NULL third_party); if (origin && is_my_call(origin, 1)) { new_origin_is_mine++; // The new object/item is owned by me } weather = NULL; // only to make the compiler happy... found_pos = 1; xastir_snprintf(call, sizeof(call), "%s", call_sign); p_station = NULL; new_station = (char)FALSE; // to make the compiler happy... last_lat = 0L; last_lon = 0L; last_stn_sec = sec_now(); last_alt[0] = '\0'; last_speed[0] = '\0'; last_course[0] = '\0'; last_flag = 0; ok = 0; store = 0; p_time = NULL; // add to end of time sorted list (newest) compr_pos = 0; if (search_station_name(&p_station,call,1)) // If we found the station in our list { if (debug_level & 1) { fprintf(stderr,"data_add: Found existing station record.\n"); } move_station_time(p_station,p_time); // update time, change position in time sorted list new_station = (char)FALSE; // we have seen this one before if (is_my_station(p_station)) { station_is_mine++; // Station is me } //fprintf(stderr,"checks ok\n"); } else { //fprintf(stderr,"data_add()\n"); if (debug_level & 1) { fprintf(stderr,"data_add: No existing station record found.\n"); } p_station = add_new_station(p_station,p_time,call); // create storage new_station = (char)TRUE; // for new station } if (p_station != NULL) { last_lat = p_station->coord_lat; // remember last position last_lon = p_station->coord_lon; last_stn_sec = p_station->sec_heard; xastir_snprintf(last_alt, sizeof(last_alt), "%s", p_station->altitude); xastir_snprintf(last_speed, sizeof(last_speed), "%s", p_station->speed); xastir_snprintf(last_course, sizeof(last_course), "%s", p_station->course); last_flag = p_station->flag; // Wipe out old data so that it doesn't hang around forever p_station->altitude[0] = '\0'; p_station->speed[0] = '\0'; p_station->course[0] = '\0'; ok = 1; // succeed as default switch (type) { case (APRS_MICE): // Mic-E format case (APRS_FIXED): // '!' case (APRS_MSGCAP): // '=' if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } if (ok) { // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for weather data first process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); p_station->record_type = NORMAL_APRS; if (type == APRS_MSGCAP) { p_station->flag |= ST_MSGCAP; // set "message capable" flag } else { p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag } // Assign a non-default value for the error // ellipse? if (type == APRS_MICE || !compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; /* case (APRS_DOWN): // '/' ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) { // uncompressed lat/lon compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon ok = 0; else p_station->pos_amb = 0; // No ambiguity in compressed posits } } if (ok) { // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) extract_multipoints(p_station, data, type, 1); add_comment(p_station,data); p_station->record_type = DOWN_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; */ case (APRS_DF): // '@' case (APRS_MOBILE): // '@' ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } if (ok) { process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); if(type == APRS_MOBILE) { p_station->record_type = MOBILE_APRS; } else { p_station->record_type = DF_APRS; } //@ stations have messaging per spec p_station->flag |= (ST_MSGCAP); // set "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_GRID): ok = extract_position(p_station, &data, type); if (ok) { if (debug_level & 1) { fprintf(stderr,"data_add: Got grid data for %s\n", call); } process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); // Assign a non-default value for the error // ellipse? // p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution // WE7U // This needs to change based on the number of grid letters/digits specified // p_station->lat_precision = 60; // p_station->lon_precision = 60; } else { if (debug_level & 1) { fprintf(stderr,"data_add: Bad grid data for %s : %s\n", call, data); } } break; case (STATION_CALL_DATA): p_station->record_type = NORMAL_APRS; found_pos = 0; break; case (APRS_STATUS): // '>' Status Reports [APRS Reference, chapter 16] (void)extract_time(p_station, data, type); // we need a time // todo: could contain Maidenhead or beam heading+power if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_status(p_station,data); p_station->flag |= (ST_STATUS); // set "Status" flag p_station->record_type = NORMAL_APRS; // ??? found_pos = 0; break; case (OTHER_DATA): // Other Packets [APRS Reference, chapter 19] // non-APRS beacons, treated as status reports until we get a real one if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } if ((p_station->flag & (~ST_STATUS)) == 0) // only store if no status yet { add_status(p_station,data); p_station->record_type = NORMAL_APRS; // ??? } found_pos = 0; break; case (APRS_OBJECT): if (debug_level & 2048) { fprintf (stderr," Object: before any extractions at all, data is \"%s\"\n",data); } // If old match is a killed Object (owner doesn't // matter), new one is an active Object and owned by // us, remove the old record and create a new one // for storing this Object. Do the same for Items // in the next section below. // // The easiest implementation might be to remove the // old record and then call this routine again with // the same parameters, which will cause a brand-new // record to be created. // // The new record we're processing is an active // object, as data_add() won't be called on a killed // object. // // if ( is_my_call(origin,1) // If new Object is owned by me (including SSID) if (new_origin_is_mine && !(p_station->flag & ST_ACTIVE) && (p_station->flag & ST_OBJECT) ) // Old record was a killed Object { station_del_ptr(p_station); // Remove old killed Object // *completely* redo_list = (int)TRUE; return( data_add(type, call_sign, path, data, from, port, origin, third_party, 0, 1) ); } ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } p_station->flag |= ST_OBJECT; // Set "Object" flag if (ok) { // If object was owned by me but another station // is transmitting it now, write entries into // the object.log file showing that we don't own // this object anymore. // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) // If station was owned by me (include SSID) && !new_origin_is_mine) // But isn't now { disown_object_item(call_sign, origin); } // If station is owned by me (including SSID) // but it's a new object/item // if ( (is_my_call(p_station->origin,1)) if (new_origin_is_mine && (p_station->transmit_time_increment == 0) ) { // This will get us transmitting this object // on the decaying algorithm schedule. // We've transmitted it once if we've just // gotten to this code. p_station->transmit_time_increment = OBJECT_CHECK_RATE; //fprintf(stderr,"data_add(): Setting transmit_time_increment to %d\n", OBJECT_CHECK_RATE); } // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // define it as object if (debug_level & 2048) { fprintf (stderr," Object: before any extractions, data is \"%s\"\n",data); } (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for wx info process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if (debug_level & 2048) { fprintf (stderr," Object: calling extract_multipoints with data \"%s\"\n",data); } if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 0); } add_comment(p_station,data); // the last char always was missing... //p_station->comments[ strlen(p_station->comments) - 1 ] = '\0'; // Wipe out '\n' // moved that to decode_ax25_line // and don't added a '\n' in interface.c p_station->record_type = NORMAL_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_ITEM): // If old match is a killed Item (owner doesn't // matter), new one is an active Item and owned by // us, remove the old record and create a new one // for storing this Item. Do the same for Objects // in the previous section above. // // The easiest implementation might be to remove the // old record and then call this routine again with // the same parameters, which will cause a brand-new // record to be created. // // The new record we're processing is an active // Item, as data_add() won't be called on a killed // Item. // // if ( is_my_call(origin,1) // If new Item is owned by me (including SSID) if (new_origin_is_mine && !(p_station->flag & ST_ACTIVE) && (p_station->flag & ST_ITEM) ) // Old record was a killed Item { station_del_ptr(p_station); // Remove old killed Item // *completely* redo_list = (int)TRUE; return( data_add(type, call_sign, path, data, from, port, origin, third_party, 0, 1) ); } if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } p_station->flag |= ST_ITEM; // Set "Item" flag if (ok) { // If item was owned by me but another station // is transmitting it now, write entries into // the object.log file showing that we don't own // this item anymore. // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) && !new_origin_is_mine) // But isn't now { disown_object_item(call_sign,origin); } // If station is owned by me (including SSID) // but it's a new object/item // if ( (is_my_call(p_station->origin,1)) if (is_my_object_item(p_station) && (p_station->transmit_time_increment == 0) ) { // This will get us transmitting this object // on the decaying algorithm schedule. // We've transmitted it once if we've just // gotten to this code. p_station->transmit_time_increment = OBJECT_CHECK_RATE; //fprintf(stderr,"data_add(): Setting transmit_time_increment to %d\n", OBJECT_CHECK_RATE); } // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // define it as item (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); // look for wx info process_data_extension(p_station,data,type); // PHG, speed, etc. process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 0); } add_comment(p_station,data); // the last char always was missing... //p_station->comments[ strlen(p_station->comments) - 1 ] = '\0'; // Wipe out '\n' // moved that to decode_ax25_line // and don't added a '\n' in interface.c p_station->record_type = NORMAL_APRS; p_station->flag &= (~ST_MSGCAP); // clear "message capable" flag // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_WX1): // weather in '@' or '/' packet ok = extract_time(p_station, data, type); // we need a time if (ok) { if (!extract_position(p_station,&data,type)) // uncompressed lat/lon { compr_pos = 1; if (!extract_comp_position(p_station,&data,type)) // compressed lat/lon { ok = 0; } else { p_station->pos_amb = 0; // No ambiguity in compressed posits } } } if (ok) { (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,compr_pos); p_station->record_type = (char)APRS_WX1; process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } add_comment(p_station,data); // Assign a non-default value for the error // ellipse? if (!compr_pos) { p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } else { p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } } break; case (APRS_WX2): // '_' ok = extract_time(p_station, data, type); // we need a time if (ok) { (void)extract_storm(p_station,data,compr_pos); (void)extract_weather(p_station,data,0); // look for weather data first p_station->record_type = (char)APRS_WX2; found_pos = 0; process_info_field(p_station,data,type); // altitude if ( (p_station->coord_lat > 0) && (p_station->coord_lon > 0) ) { extract_multipoints(p_station, data, type, 1); } } break; case (APRS_WX4): // '#' Peet Bros U-II (km/h) case (APRS_WX6): // '*' Peet Bros U-II (mph) case (APRS_WX3): // '!' Peet Bros Ultimeter 2000 (data logging mode) case (APRS_WX5): // '$ULTW' Peet Bros Ultimeter 2000 (packet mode) if (get_weather_record(p_station)) // get existing or create new weather record { weather = p_station->weather_data; if (type == APRS_WX3) // Peet Bros Ultimeter 2000 data logging mode { decode_U2000_L(1,(unsigned char *)data,weather); } else if (type == APRS_WX5) // Peet Bros Ultimeter 2000 packet mode { decode_U2000_P(1,(unsigned char *)data,weather); } else // Peet Bros Ultimeter-II { decode_Peet_Bros(1,(unsigned char *)data,weather,type); } p_station->record_type = (char)type; // Create a timestamp from the current time xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(temp_data)); weather->wx_sec_time = sec_now(); found_pos = 0; } break; // GPRMC, digits after decimal point // --------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse // 4+ = 6.0 meter error ellipse case (GPS_RMC): // $GPRMC // WE7U // Change this function to return HDOP and the number of characters // after the decimal point. ok = extract_RMC(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius (25.5m). // Best (smallest) circle should be 600 as we have no augmentation // flag to check here for anything better. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; // GPGGA, digits after decimal point, w/o augmentation // --------------------------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse unless HDOP>4, then 10.0 meters // 4+ = 6.0 meter error ellipse unless HDOP>4, then 10.0 meters // // // GPGGA, digits after decimal point, w/augmentation // -------------------------------------------------- // 2 = 25.5 meter error ellipse // 3 = 2.5 meter error ellipse unless HDOP>4, then 10.0 meters // 4+ = 0.6 meter error ellipse unless HDOP>4, then 10.0 meters case (GPS_GGA): // $GPGGA // WE7U // Change this function to return HDOP and the number of characters // after the decimal point. ok = extract_GGA(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius (25.5m). // 3 digits: 6m w/o augmentation unless HDOP >4 = 10m, 2.5m w/augmentation. // 4+ digits: 6m w/o augmentation unless HDOP >4 = 10m, 0.6m w/augmentation. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; // GPGLL, digits after decimal point // --------------------------------- // 2 = 25.5 meter error ellipse // 3 = 6.0 meter error ellipse // 4+ = 6.0 meter error ellipse case (GPS_GLL): // $GPGLL ok = extract_GLL(p_station,data,call_sign,path,&num_digits); if (ok) { // Assign a non-default value for the error // ellipse? // // WE7U // Degrade based on the precision provided in the sentence. If only // 2 digits after decimal point, give it 2550 as a radius, otherwise // give it 600. // switch (num_digits) { case 0: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 6000; p_station->lon_precision = 6000; break; case 1: p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 600; p_station->lon_precision = 600; break; case 2: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; case 3: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; break; case 4: case 5: case 6: case 7: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 0; p_station->lon_precision = 0; break; default: p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 60; p_station->lon_precision = 60; break; } } break; default: fprintf(stderr,"ERROR: UNKNOWN TYPE in data_add\n"); ok = 0; break; } // Left this one in, just in case. Perhaps somebody might // attach a multipoint string onto the end of a packet we // might not expect. For this case we need to check whether // we have multipoints first, as we don't want to erase the // work we might have done with a previous call to // extract_multipoints(). if (ok && (p_station->coord_lat > 0) && (p_station->coord_lon > 0) && (p_station->num_multipoints == 0) ) // No multipoints found yet { extract_multipoints(p_station, data, type, 0); } } if (!ok) // non-APRS beacon, treat it as Other Packet [APRS Reference, chapter 19] { if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", data-1); makePrintable(filtered_data); fprintf(stderr,"store non-APRS data as status: %s: |%s|\n",call,filtered_data); } // GPRMC etc. without a position is here too, but it should not be stored as status! // store it as status report until we get a real one if ((p_station->flag & (~ST_STATUS)) == 0) // only store it if no status yet { add_status(p_station,data-1); p_station->record_type = NORMAL_APRS; // ??? } ok = 1; found_pos = 0; } curr_sec = sec_now(); if (ok) { // data packet is valid // announce own echo, we soon discard that packet... // if (!new_station && is_my_call(p_station->call_sign,1) // Check SSID as well if (!new_station && is_my_station(p_station) // Check SSID as well && strchr(path,'*') != NULL) { upd_echo(path); // store digi that echoes my signal... statusline(langcode("BBARSTA033"),0); // Echo from digipeater } // check if data is just a secondary echo from another digi if ((last_flag & ST_VIATNC) == 0 || (curr_sec - last_stn_sec) > 15 || p_station->coord_lon != last_lon || p_station->coord_lat != last_lat) { store = 1; // don't store secondary echos } } if (!ok && new_station) { delete_station_memory(p_station); // remove unused record } if (store) { // we now have valid data to store into database // make time index unique by adding a serial number if (station_is_mine) { // This station is me. Set the // flag which shows that we own/control this // station. We use this flag later in lieu // of the is_my_call() function in order to speed things // up. // p_station->flag |= ST_MYSTATION; } // Check whether it's a locally-owned object/item if ( object_is_mine || ( new_origin_is_mine && (p_station->flag & ST_ACTIVE) && (p_station->flag & ST_OBJECT) ) ) { p_station->flag |= ST_MYOBJITEM; // Do nothing else. We don't want to update the // last-heard time so that it'll expire from the queue // normally, unless it is a new object/item. // if (new_station) { p_station->sec_heard = curr_sec; } // We need an exception later in this function for the // case where we've moved an object/item (by how much?). // We need to update the time in this case so that it'll // expire later (in fact it could already be expired // when we move it). We should be able to move expired // objects/items to make them active again. Perhaps // some other method as well?. } else { // Reset the "my object" flag p_station->flag &= ~ST_MYOBJITEM; p_station->sec_heard = curr_sec; // Give it a new timestamp } if (curr_sec != last_sec) // todo: if old time calculate time_sn from database { last_sec = curr_sec; next_time_sn = 0; // restart time serial number } p_station->time_sn = next_time_sn++; // todo: warning if serial number too high if (from == DATA_VIA_TNC) // heard via TNC { if (!third_party) // Not a third-party packet { p_station->flag |= ST_VIATNC; // set "via TNC" flag p_station->heard_via_tnc_last_time = curr_sec; p_station->heard_via_tnc_port = port; } else // Third-party packet { // Leave the previous setting of "flag" alone. // Specifically do NOT set the ST_VIATNC flag if it // was a third-party packet. } } else // heard other than TNC { if (new_station) // new station { p_station->flag &= (~ST_VIATNC); // clear "via TNC" flag //fprintf(stderr,"New_station: Cleared ST_VIATNC flag: %s\n", p_station->call_sign); p_station->heard_via_tnc_last_time = 0l; } } p_station->last_port_heard = port; p_station->data_via = from; // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // get_time returns value in temp_data p_station->flag |= ST_ACTIVE; if (third_party) { p_station->flag |= ST_3RD_PT; // set "third party" flag } else { p_station->flag &= (~ST_3RD_PT); // clear "third party" flag } if (origin != NULL && strcmp(origin,"INET") == 0) // special treatment for inet names xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin != NULL && strcmp(origin,"INET-NWS") == 0) // special treatment for NWS xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin != NULL && strcmp(origin,"INET-BOM") == 0) // special treatment for BOM (AU) xastir_snprintf(p_station->origin, sizeof(p_station->origin), "%s", origin); // to keep them separated from calls if (origin == NULL || origin[0] == '\0') // normal call { p_station->origin[0] = '\0'; // undefine possible former object with same name } //-------------------------------------------------------------------- // KC2ELS // Okay, here are the standards for ST_DIRECT: // 1. The packet must have been received via TNC. // 2. The packet must not have any * flags. // 3. If present, the first WIDEn-N (or TRACEn-N) must have n=N. // A station retains the ST_DIRECT setting. If // "st_direct_timeout" seconds have passed since we set // that bit then APRSD queries and displays based on the // ST_DIRECT bit will skip that station. // In order to make this scheme work for stations that straddle both // RF and INET, we need to make sure that node_path_ptr doesn't get // overwritten with an INET path if there's an RF path already in // there and it has been less than st_direct_timeout seconds since // the station was last heard on RF. if ((from == DATA_VIA_TNC) // Heard via TNC && !third_party // Not a 3RD-Party packet && path != NULL // Path is not NULL && strchr(path,'*') == NULL) // No asterisk found { // Look for WIDE or TRACE if ((((p = strstr(path,"WIDE")) != NULL) && (p+=4)) || (((p = strstr(path,"TRACE")) != NULL) && (p+=5))) { // Look for n=N on WIDEn-N/TRACEn-N digi field if ((*p != '\0') && isdigit((int)*p)) { if ((*(p+1) != '\0') && (*(p+1) == '-')) { if ((*(p+2) != '\0') && isdigit((int)*(p+2))) { if (*(p) == *(p+2)) { direct = 1; } else { direct = 0; } } else { direct = 0; } } else { direct = 0; } } else { direct = 1; } } else { direct = 1; } } else { direct = 0; } if (direct == 1) { // This packet was heard direct. Set the ST_DIRECT bit // and save the timestamp away. if (debug_level & 1) { fprintf(stderr,"Setting ST_DIRECT for station %s\n", p_station->call_sign); } p_station->direct_heard = curr_sec; p_station->flag |= (ST_DIRECT); } else { // This packet was NOT heard direct. Check whether we // need to expire the ST_DIRECT bit. A lot of fixed // stations transmit every 30 minutes. One hour gives // us time to receive a direct packet from them among // all the digipeated packets. if ((p_station->flag & ST_DIRECT) != 0 && curr_sec > (p_station->direct_heard + st_direct_timeout)) { if (debug_level & 1) fprintf(stderr,"Clearing ST_DIRECT for station %s\n", p_station->call_sign); p_station->flag &= (~ST_DIRECT); } } // If heard on TNC, overwrite node_path_ptr if any of these // conditions are met: // *) direct == 1 (packet was heard direct) // *) ST_DIRECT flag == 0 (packet hasn't been heard // direct recently) // *) ST_DIRECT is set, st_direct_timeout has expired // (packet hasn't been heard direct recently) // // These rules will allow us to keep directly heard paths // saved for at least an hour (st_direct_timeout), and not // get overwritten with digipeated paths during that time. // if ((from == DATA_VIA_TNC) // Heard via TNC && !third_party // Not a 3RD-Party packet && path != NULL) // Path is not NULL { // Heard on TNC interface and not third party. Check // the other conditions listed in the comments above to // decide whether we should overwrite the node_path_ptr // variable. // if ( direct // This packet was heard direct || (p_station->flag & ST_DIRECT) == 0 // Not heard direct lately || ( (p_station->flag & ST_DIRECT) != 0 // Not heard direct lately && (curr_sec > (p_station->direct_heard+st_direct_timeout) ) ) ) { // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); } } // If a 3rd-party packet heard on TNC, overwrite // node_path_ptr only if heard_via_tnc_last_time is older // than one hour (zero counts as well!), plus clear the // ST_DIRECT and ST_VIATNC bits in this case. This makes us // keep the RF path around for at least one hour after the // station is heard. // else if ((from == DATA_VIA_TNC) // Heard via TNC && third_party // It's a 3RD-Party packet && path != NULL) // Path is not NULL { // 3rd-party packet heard on TNC interface. Check if // heard_via_tnc_last_time is older than an hour. If // so, overwrite the path and clear a few bits to show // that it has timed out on RF and we're now receiving // that station from an igate. // if (curr_sec > (p_station->heard_via_tnc_last_time + 60*60)) { // Yep, more than one hour old or is a zero, // overwrite the node_path_ptr variable with the new // one. We're only hearing this station on INET // now. // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); // Clear the ST_VIATNC bit p_station->flag &= ~ST_VIATNC; } // If direct_heard is over an hour old, clear the // ST_DIRECT flag. We're only hearing this station on // INET now. // if (curr_sec > (p_station->direct_heard + st_direct_timeout)) { // Yep, more than one hour old or is a zero, clear // the ST_DIRECT flag. p_station->flag &= ~ST_DIRECT; } } // If heard on INET then overwrite node_path_ptr only if // heard_via_tnc_last_time is older than one hour (zero // counts as well!), plus clear the ST_DIRECT and ST_VIATNC // bits in this case. This makes us keep the RF path around // for at least one hour after the station is heard. // else if (from != DATA_VIA_TNC // From an INET interface && !third_party // Not a 3RD-Party packet && path != NULL) // Path is not NULL { // Heard on INET interface. Check if // heard_via_tnc_last_time is older than an hour. If // so, overwrite the path and clear a few bits to show // that it has timed out on RF and we're now receiving // that station from the INET feeds. // if (curr_sec > (p_station->heard_via_tnc_last_time + 60*60)) { // Yep, more than one hour old or is a zero, // overwrite the node_path_ptr variable with the new // one. We're only hearing this station on INET // now. // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen(path) + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,path,strlen(path)); // Clear the ST_VIATNC bit p_station->flag &= ~ST_VIATNC; /* fprintf(stderr, "\ntype:%d call:%s path:%s data:%s from:%c port:%d origin:%s 3rd:%d\n", type, call_sign, path, data, from, port, origin, third_party); fprintf(stderr,"Cleared ST_VIATNC flag (2): %s\n", p_station->call_sign); */ } // If direct_heard is over an hour old, clear the // ST_DIRECT flag. We're only hearing this station on // INET now. // if (curr_sec > (p_station->direct_heard + st_direct_timeout)) { // Yep, more than one hour old or is a zero, clear // the ST_DIRECT flag. p_station->flag &= ~ST_DIRECT; } } //--------------------------------------------------------------------- p_station->num_packets += 1; redo_list = (int)TRUE; // we may need to update the lists if (found_pos) // if station has a position with the data { if (position_on_extd_screen(p_station->coord_lat,p_station->coord_lon)) { p_station->flag |= (ST_INVIEW); // set "In View" flag if (debug_level & 256) { fprintf(stderr,"Setting ST_INVIEW flag\n"); } } else { p_station->flag &= (~ST_INVIEW); // clear "In View" flag if (debug_level & 256) { fprintf(stderr,"Clearing ST_INVIEW flag\n"); } } } screen_update = 0; if (new_station) { if (debug_level & 256) { fprintf(stderr,"New Station %s\n", p_station->call_sign); } if (strlen(p_station->speed) > 0 && atof(p_station->speed) > 0) { p_station->flag |= (ST_MOVING); // it has a speed, so it's moving moving = 1; } if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { if (p_station->coord_lat != 0 && p_station->coord_lon != 0) // discard undef positions from screen { if (!altnet || is_altnet(p_station) ) { display_station(da,p_station,1); screen_update = 1; // ??? } } } } else // we had seen this station before... { if (debug_level & 256) { fprintf(stderr,"New Data for %s %ld %ld\n", p_station->call_sign, p_station->coord_lat, p_station->coord_lon); } if (found_pos && position_defined(p_station->coord_lat,p_station->coord_lon,1)) // ignore undefined and 0N/0E { if (debug_level & 256) { fprintf(stderr," Valid position for %s\n", p_station->call_sign); } if (p_station->newest_trackpoint != NULL) { if (debug_level & 256) { fprintf(stderr,"Station has a trail: %s\n", p_station->call_sign); } moving = 1; // it's moving if it has a trail } else { if (strlen(p_station->speed) > 0 && atof(p_station->speed) > 0) { if (debug_level & 256) { fprintf(stderr,"Speed detected on %s\n", p_station->call_sign); } moving = 1; // declare it moving, if it has a speed } else { if (debug_level & 256) { fprintf(stderr,"Position defined: %d, Changed: %s\n", position_defined(last_lat, last_lon, 1), (p_station->coord_lat != last_lat || p_station->coord_lon != last_lon) ? "Yes" : "No"); } // Here's where we detect movement if (position_defined(last_lat,last_lon,1) && (p_station->coord_lat != last_lat || p_station->coord_lon != last_lon)) { if (debug_level & 256) { fprintf(stderr,"Position Change detected on %s\n", p_station->call_sign); } moving = 1; // it's moving if it has changed the position } else { if (debug_level & 256) { fprintf(stderr,"Station %s still appears stationary.\n", p_station->call_sign); fprintf(stderr," %s stationary at %ld %ld (%ld %ld)\n", p_station->call_sign, p_station->coord_lat, p_station->coord_lon, last_lat, last_lon); } moving = 0; } } } changed_pos = 0; if (moving == 1) { p_station->flag |= (ST_MOVING); // we have a moving station, process trails if (atoi(p_station->speed) < TRAIL_MAX_SPEED) // reject high speed data (undef gives 0) { // we now may already have the 2nd position, so store the old one first if (debug_level & 256) { fprintf(stderr,"Station %s valid speed %s\n", p_station->call_sign, p_station->speed); } if (p_station->newest_trackpoint == NULL) { if (debug_level & 256) { fprintf(stderr,"Station %s no trail history.\n", p_station->call_sign); } if (position_defined(last_lat,last_lon,1)) // ignore undefined and 0N/0E { if (debug_level & 256) { fprintf(stderr,"Storing old position for %s\n", p_station->call_sign); } (void)store_trail_point(p_station, last_lon, last_lat, last_stn_sec, last_alt, last_speed, last_course, last_flag); } } //if ( p_station->coord_lon != last_lon // || p_station->coord_lat != last_lat ) { // we don't store redundant points (may change this // later ?) // // There are often echoes delayed 15 minutes // or so it looks ugly on the trail, so I // want to discard them This also discards // immediate echoes. Duplicates back in time // up to TRAIL_ECHO_TIME minutes are // discarded. // if (!is_trailpoint_echo(p_station)) { (void)store_trail_point(p_station, p_station->coord_lon, p_station->coord_lat, p_station->sec_heard, p_station->altitude, p_station->speed, p_station->course, p_station->flag); changed_pos = 1; // Check whether it's a locally-owned object/item if (object_is_mine) { // Update time, change position in // time-sorted list to change // expiration time. move_station_time(p_station,p_time); // Give it a new timestamp p_station->sec_heard = curr_sec; //fprintf(stderr,"Updating last heard time\n"); } } else if (debug_level & 256) { fprintf(stderr,"Trailpoint echo detected for %s\n", p_station->call_sign); } } else { if (debug_level & 256 || debug_level & 1) { fprintf(stderr,"Speed over %d mph\n",TRAIL_MAX_SPEED); } } if (track_station_on == 1) // maybe we are tracking a station { track_station(da,tracking_station_call,p_station); } } // moving... // now do the drawing to the screen ok_to_display = !altnet || is_altnet(p_station); // Optimization step, needed twice below. screen_update = 0; if (changed_pos == 1 && Display_.trail && ((p_station->flag & ST_INVIEW) != 0)) { if (ok_to_display) { if (debug_level & 256) { fprintf(stderr,"Adding Solid Trail for %s\n", p_station->call_sign); } draw_trail(da,p_station,1); // update trail screen_update = 1; } else if (debug_level & 256) { fprintf(stderr,"Skipped trail for %s (altnet)\n", p_station->call_sign); } } if (position_on_screen(p_station->coord_lat,p_station->coord_lon)) { if (changed_pos == 1 || !position_defined(last_lat,last_lon,0)) { if (ok_to_display) { display_station(da,p_station,1);// update symbol screen_update = 1; } } } } // defined position } if (screen_update) { if (p_station->data_via == 'T') // Data from local TNC { //WE7U // or data_via == 'I' and last_port_heard == AGWPE interface redraw_on_new_data = 2; // Update all symbols NOW! } else if (p_station->data_via == 'F') // If data from file { redraw_on_new_data = 1; // Update each 2 secs } // else if (scale_y > 2048) { // Wider area of world else { redraw_on_new_data = 0; // Update each 60 secs } } // announce stations in the status line // if (!is_my_call(p_station->call_sign,1) // Check SSID as well // && !is_my_call(p_station->origin,1) // Check SSID as well if (!is_my_station(p_station) && !is_my_object_item(p_station) // Check SSID as well && !wait_to_redraw) { if (new_station) { if (p_station->origin[0] == '\0') // new station { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA001"),p_station->call_sign); } else // new object { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA000"),p_station->call_sign); } } else // updated data { xastir_snprintf(station_id, sizeof(station_id), langcode("BBARSTA002"),p_station->call_sign); } statusline(station_id,0); } // announce new station with sound file or speech synthesis if (new_station && !wait_to_redraw) // && !is_my_call(p_station->call_sign,1) // ??? { if (sound_play_new_station) { play_sound(sound_command,sound_new_station); } #ifdef HAVE_FESTIVAL if (festival_speak_new_station) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); xastir_snprintf(station_id, sizeof(station_id), "%s, %s", langcode("SPCHSTR010"), speech_callsign); SayText(station_id); } #endif // HAVE_FESTIVAL } // check for range and DX // if (found_pos && !is_my_call(p_station->call_sign,1)) { // Check SSID also if (found_pos && !is_my_station(p_station)) // Check SSID also { // if station has a position with the data /* Check Audio Alarms based on incoming packet */ /* FG don't care if this is on screen or off get position */ l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,temp_data,sizeof(temp_data)); // Convert to whatever measurement value we're currently using distance = value * cvt_kn2len; /* check ranges */ if ((distance > atof(prox_min)) && (distance < atof(prox_max))) { //fprintf(stderr,"Station within proximity circle, creating waypoint\n"); create_garmin_waypoint(p_station->coord_lat, p_station->coord_lon, p_station->call_sign); if (sound_play_prox_message) { xastir_snprintf(station_id, sizeof(station_id), "%s < %.3f %s",p_station->call_sign, distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005")); statusline(station_id,0); play_sound(sound_command,sound_prox_message); /*fprintf(stderr,"%s> PROX distance %f\n",p_station->call_sign, distance);*/ } } #ifdef HAVE_FESTIVAL if ((distance > atof(prox_min)) && (distance < atof(prox_max)) && festival_speak_proximity_alert) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); if (english_units) { if (distance < 1.0) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance * 1760), langcode("SPCHSTR004")); // say it in yards else if ((int)((distance * 10) + 0.5) % 10) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR006"), speech_callsign, distance, langcode("SPCHSTR003")); // say it in miles with one decimal else xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance + 0.5), langcode("SPCHSTR003")); // say it in miles with no decimal } else { if (distance < 1.0) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance * 1000), langcode("SPCHSTR002")); // say it in meters else if ((int)((distance * 10) + 0.5) % 10) xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR006"), speech_callsign, distance, langcode("SPCHSTR001")); // say it in kilometers with one decimal else xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR005"), speech_callsign, (int)(distance + 0.5), langcode("SPCHSTR001")); // say it in kilometers with no decimal } SayText(station_id); } #endif // HAVE_FESTIVAL /* FG really should check the path before we do this and add setup for these ranges */ if (sound_play_band_open_message && from == DATA_VIA_TNC && !(p_station->flag & ST_3RD_PT) && (distance > atof(bando_min)) && (distance < atof(bando_max))) { xastir_snprintf(station_id, sizeof(station_id), "%s %s %.1f %s",p_station->call_sign, langcode("UMBNDO0001"), distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005")); statusline(station_id,0); play_sound(sound_command,sound_band_open_message); /*fprintf(stderr,"%s> BO distance %f\n",p_station->call_sign, distance);*/ } #ifdef HAVE_FESTIVAL if (festival_speak_band_opening && from == DATA_VIA_TNC && !(p_station->flag & ST_3RD_PT) && (distance > atof(bando_min)) && (distance < atof(bando_max))) { char speech_callsign[50]; xastir_snprintf(speech_callsign, sizeof(speech_callsign), "%s", p_station->call_sign); spell_it_out(speech_callsign, 50); xastir_snprintf(station_id, sizeof(station_id), langcode("SPCHSTR011"), speech_callsign, distance, english_units?langcode("SPCHSTR003"):langcode("SPCHSTR001")); SayText(station_id); } #endif // HAVE_FESTIVAL } // end found_pos #ifdef HAVE_DB // Clumsy way of doing things - needs a more elegant approach // iterate through interfaces if (p_station->data_via != DATA_VIA_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"Trying to store station %s to database interfaces.\n",p_station->call_sign); } for (ii=0; ii 0 && connections[ii].type < 4) { if (debug_level & 4096) { fprintf(stderr,"type=[%d]\n",connections[ii].type); } if (port_data[ii].status == DEVICE_UP) { if (connections[ii].descriptor->device_type==DEVICE_SQL_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"Trying interface %d\n",ii); } // if interface is a sql server interface // write station data to sql database ok = storeStationSimpleToGisDb(&connections[ii], p_station); if (ok==1) { if (debug_level & 4096) { fprintf(stderr,"Stored station %s to database interface %d.\n",p_station->call_sign,ii); } } else { pingConnection(&connections[ii]); } } } } } } } #endif /* HAVE_DB */ } // valid data into database return(ok); } // End of data_add() function // Code to compute SmartBeaconing(tm) rates. // // SmartBeaconing(tm) was invented by Steve Bragg (KA9MVA) and Tony Arnerich // (KD7TA). Its main goal is to change the beacon rate based on speed // and cornering. It does speed-variant corner pegging and // speed-variant posit rate. // Some tweaks have been added to the generic SmartBeaconing(tm) algorithm, // but are current labeled as experimental and commented out: 1) We do // a posit as soon as we first cross below the sb_low_speed_limit, and // 2) We do a posit as soon as we cross above the sb_low_speed_limit if // we haven't done a posit for sb_turn_time seconds. These tweaks are // intended to help show that the mobile station has stopped (so that // dead-reckoning doesn't keep it moving across the map on other // people's displays) and to more quickly show that the station is // moving again (for the case where they're in stop-and-go traffic // perhaps). // // It's possible that these new tweaks won't work well for the case // where a station is traveling near the speed of sb_low_speed_limit. // In this case they'll generate a posit each time they go below it and // every time they go above it if they haven't done a posit in // sb_turn_time seconds. This could result in a lot of posits very // quickly. We may need to add yet another limit just above the // sb_low_speed_limit for hysteresis, and not posit until we cross above // that new limit. // // Several special SmartBeaconing(tm) parameters come into play here: // // sb_turn_min Minimum degrees at which corner pegging will // occur. The next parameter affects this for // lower speeds. // // sb_turn_slope Fudget factor for making turns less sensitive at // lower speeds. No real units on this one. // It ends up being non-linear over the speed // range the way the original SmartBeaconing(tm) // algorithm works. // // sb_turn_time Dead-time before/after a corner peg beacon. // Units are in seconds. // // sb_posit_fast Fast posit rate, used if >= sb_high_speed_limit. // Units are in seconds. // // sb_posit_slow Slow posit rate, used if <= sb_low_speed_limit. // Units are in minutes. // // sb_low_speed_limit Low speed limit, units are in Mph. // // sb_high_speed_limit High speed limit, units are in Mph. // // // Input: Course in degrees // Speed in knots // // Output: May force beacons by setting posit_next_time to various // values. // // Modify: sb_POSIT_rate // sb_current_heading // sb_last_heading // posit_next_time // // // With the defaults compiled into the code, here are the // turn_thresholds for a few speeds: // // Example: sb_turn_min = 20 // sb_turn_slope = 25 // sb_high_speed_limit = 60 // // > 60mph 20 degrees // 50mph 25 degrees // 40mph 26 degrees // 30mph 28 degrees // 20mph 33 degrees // 10mph 45 degrees // 3mph 103 degrees (we limit it to 80 now) // 2mph 145 degrees (we limit it to 80 now) // // I added a max threshold of 80 degrees into the code. 145 degrees // is unreasonable to expect except for perhaps switchback or 'U' // turns. // // It'd probably be better to do a linear interpolation of // turn_threshold based on min/max speed and min/max turns. That's // not how the SmartBeaconing(tm) algorithm coders implemented it in // the HamHud though. // void compute_smart_beacon(char *current_course, char *current_speed) { int course; int speed; int turn_threshold; time_t secs_since_beacon; int heading_change_since_beacon; int beacon_now = 0; int curr_sec = sec_now(); // Don't compute SmartBeaconing(tm) parameters or force any beacons // if we're not in that mode! if (!smart_beaconing) { return; } // Convert from knots to mph/kph (whichever is selected) speed = (int)(atof(current_speed) * cvt_kn2len + 0.5); // Poor man's rounding course = atoi(current_course); secs_since_beacon = curr_sec - posit_last_time; // Check for the low speed threshold, set to slow posit rate if // we're going slow. if (speed <= sb_low_speed_limit) { //fprintf(stderr,"Slow speed\n"); // EXPERIMENTAL!!! //////////////////////////////////////////////////////////////////// // Check to see if we're just crossing the threshold, if so, // beacon. This keeps dead-reckoning working properly on // other people's displays. Be careful for speeds near this // threshold though. We really need a slow-speed rate and a // stop rate, with some distance between them, in order to // have some hysteresis for these posits. // if (sb_POSIT_rate != (sb_posit_slow * 60) ) { // Previous rate was _not_ the slow rate // beacon_now++; // Force a posit right away // //fprintf(stderr,"Stopping, POSIT!\n"); // } //////////////////////////////////////////////////////////////////// // Set to slow posit rate sb_POSIT_rate = sb_posit_slow * 60; // Convert to seconds } else // We're moving faster than the low speed limit { // EXPERIMENTAL!!! //////////////////////////////////////////////////////////////////// // Check to see if we're just starting to move. Again, we // probably need yet-another-speed-limit here to provide // some hysteresis. // if ( (secs_since_beacon > sb_turn_time) // Haven't beaconed for a bit // && (sb_POSIT_rate == (sb_posit_slow * 60) ) ) { // Last rate was the slow rate // beacon_now++; // Force a posit right away // //fprintf(stderr,"Starting to move, POSIT!\n"); // } //////////////////////////////////////////////////////////////////// // Start with turn_min degrees as the threshold turn_threshold = sb_turn_min; // Adjust rate according to speed if (speed > sb_high_speed_limit) // We're above the high limit { sb_POSIT_rate = sb_posit_fast; //fprintf(stderr,"Setting fast rate\n"); } else // We're between the high/low limits. Set a between rate { sb_POSIT_rate = (sb_posit_fast * sb_high_speed_limit) / speed; //fprintf(stderr,"Setting medium rate\n"); // Adjust turn threshold according to speed turn_threshold += (int)( (sb_turn_slope * 10) / speed); } // Force a maximum turn threshold of 80 degrees (still too // high?) if (turn_threshold > 80) { turn_threshold = 80; } // Check to see if we've written anything into // sb_last_heading variable yet. If not, write the current // course into it. if (sb_last_heading == -1) { sb_last_heading = course; } // Corner-pegging. Note that we don't corner-peg if we're // below the low-speed threshold. heading_change_since_beacon = abs(course - sb_last_heading); if (heading_change_since_beacon > 180) { heading_change_since_beacon = 360 - heading_change_since_beacon; } //fprintf(stderr,"course change:%d\n",heading_change_since_beacon); if ( (heading_change_since_beacon > turn_threshold) && (secs_since_beacon > sb_turn_time) ) { beacon_now++; // Force a posit right away //fprintf(stderr,"Corner, POSIT!\tOld:%d\tNew:%d\tDifference:%d\tSpeed: %d\tTurn Threshold:%d\n", // sb_last_heading, // course, // heading_change_since_beacon, // speed, // turn_threshold); } // EXPERIMENTAL //////////////////////////////////////////////////////////////////// // If we haven't beaconed for a bit (3 * sb_turn_time?), and // just completed a turn, check to see if our heading has // stabilized yet. If so, beacon the latest heading. We'll // have to save another variable which says whether the last // beacon was caused by corner-pegging. The net effect is // that we'll get an extra posit coming out of a turn that // specifies our correct course and probably a more accurate // speed until the next posit. This should make // dead-reckoning work even better. if (0) { } //////////////////////////////////////////////////////////////////// } // Check to see whether we've sped up sufficiently for the // posit_next_time variable to be too far out. If so, shorten // that interval to match the current speed. if ( (posit_next_time - curr_sec) > sb_POSIT_rate) { posit_next_time = curr_sec + sb_POSIT_rate; } if (beacon_now) { posit_next_time = 0; // Force a posit right away } // Should we also check for a rate too fast for the current // speed? Probably not. It'll get modified at the next beacon // time, which will happen quickly. // Save course for use later. It gets put into sb_last_heading // in UpdateTime() if a beacon occurs. We then use it above to // determine the course deviation since the last time we // beaconed. sb_current_heading = course; } // Speed is in knots void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char UNUSED(speedu), char *alt, char *sats) { long pos_long_temp, pos_lat_temp; char temp_data[40]; // short term string storage char temp_lat[12]; char temp_long[12]; DataRow *p_station; DataRow *p_time; // Note that speed will be in knots 'cuz it was derived from a // GPRMC string without modification. // Recompute the SmartBeaconing(tm) parameters based on current/past // course & speed. Sending the speed in knots. //fprintf(stderr,"Speed: %s\n",speed); compute_smart_beacon(course, speed); p_station = NULL; if (!search_station_name(&p_station,my_callsign,1)) // find my data in the database { p_time = NULL; // add to end of time sorted list //fprintf(stderr,"my_station_gps_change()\n"); p_station = add_new_station(p_station,p_time,my_callsign); } p_station->flag |= ST_ACTIVE; p_station->data_via = 'L'; p_station->flag &= (~ST_3RD_PT); // clear "third party" flag p_station->record_type = NORMAL_APRS; // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen("local") + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,"local",strlen("local")); // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag |= ST_MSGCAP; // set "message capable" flag /* convert to long and weed out any odd data */ pos_long_temp = convert_lon_s2l(pos_long); pos_lat_temp = convert_lat_s2l(pos_lat); /* convert back to clean string for config data */ convert_lon_l2s(pos_long_temp, temp_data, sizeof(temp_data), CONVERT_HP_NORMAL); xastir_snprintf(temp_long, sizeof(temp_long), "%c%c%c%c%c.%c%c%c%c",temp_data[0],temp_data[1],temp_data[2], temp_data[4],temp_data[5], temp_data[7],temp_data[8], temp_data[9], temp_data[10]); convert_lat_l2s(pos_lat_temp, temp_data, sizeof(temp_data), CONVERT_HP_NORMAL); xastir_snprintf(temp_lat, sizeof(temp_lat), "%c%c%c%c.%c%c%c%c",temp_data[0],temp_data[1],temp_data[3],temp_data[4], temp_data[6], temp_data[7], temp_data[8],temp_data[9]); /* fill the data in */ // ??????????????? memcpy(my_lat, temp_lat, sizeof(my_lat)); my_lat[sizeof(my_lat)-1] = '\0'; // Terminate string memcpy(my_long, temp_long, sizeof(my_long)); my_long[sizeof(my_long)-1] = '\0'; // Terminate string p_station->coord_lat = convert_lat_s2l(my_lat); p_station->coord_lon = convert_lon_s2l(my_long); if ((p_station->coord_lon != pos_long_temp) || (p_station->coord_lat != pos_lat_temp)) { /* check to see if enough to change pos on screen */ if ((pos_long_temp>NW_corner_longitude) && (pos_long_tempNW_corner_latitude) && (pos_lat_tempcoord_lon+(scale_x/2))-pos_long_temp)/scale_x)>0 || (labs((p_station->coord_lat+(scale_y/2))-pos_lat_temp)/scale_y)>0) { //redraw_on_new_data = 1; // redraw next chance //redraw_on_new_data = 2; // better response? if (debug_level & 256) { fprintf(stderr,"Redraw on new gps data \n"); } statusline(langcode("BBARSTA038"),0); } else if (debug_level & 256) { fprintf(stderr,"New Position same pixel as old.\n"); } } else if (debug_level & 256) { fprintf(stderr,"New Position is off edge of screen.\n"); } } else if (debug_level & 256) { fprintf(stderr,"New position is off side of screen.\n"); } } p_station->coord_lat = pos_lat_temp; // DK7IN: we have it already !?? p_station->coord_lon = pos_long_temp; curr_sec = sec_now(); my_last_altitude_time = curr_sec; xastir_snprintf(p_station->speed, sizeof(p_station->speed), "%s", speed); // is speed always in knots, otherwise we need a conversion! xastir_snprintf(p_station->course, sizeof(p_station->course), "%s", course); xastir_snprintf(p_station->altitude, sizeof(p_station->altitude), "%s", alt); // altu; unit should always be meters ???? if(debug_level & 256) fprintf(stderr,"GPS MY_LAT <%s> MY_LONG <%s> MY_ALT <%s>\n", my_lat, my_long, alt); /* get my last altitude meters to feet */ my_last_altitude=(long)(atof(alt)*3.28084); /* get my last course in deg */ my_last_course=atoi(course); /* get my last speed in knots */ my_last_speed = atoi(speed); xastir_snprintf(p_station->sats_visible, sizeof(p_station->sats_visible), "%s", sats); // Update "heard" time for our new position p_station->sec_heard = curr_sec; //if ( p_station->coord_lon != last_lon // || p_station->coord_lat != last_lat ) { // we don't store redundant points (may change this later ?) // There are often echoes delayed 15 minutes or so it looks ugly // on the trail, so I want to discard them This also discards // immediate echoes. Duplicates back in time up to // TRAIL_ECHO_TIME minutes are discarded. // if (!is_trailpoint_echo(p_station)) { (void)store_trail_point(p_station, p_station->coord_lon, p_station->coord_lat, curr_sec, p_station->altitude, p_station->speed, p_station->course, p_station->flag); } if (debug_level & 256) { fprintf(stderr,"Adding Solid Trail for %s\n", p_station->call_sign); } draw_trail(da,p_station,1); // update trail display_station(da,p_station,1); // update symbol if (track_station_on == 1) // maybe we are tracking ourselves? { track_station(da,tracking_station_call,p_station); } // We parsed a good GPS string, so allow beaconing to proceed // normally for a while. my_position_valid = 3; //fprintf(stderr,"Valid GPS input: my_position_valid = 3\n"); //redraw_on_new_data = 1; // redraw next chance redraw_on_new_data = 2; // Immediate update of symbols/tracks } void my_station_add(char *my_callsign, char my_group, char my_symbol, char *my_long, char *my_lat, char *my_phg, char *my_comment, char my_amb) { DataRow *p_station; DataRow *p_time; char temp_data[40]; // short term string storage char *strp; p_station = NULL; if (!search_station_name(&p_station,my_callsign,1)) // find call { p_time = NULL; // add to end of time sorted list //fprintf(stderr,"my_station_add()\n"); p_station = add_new_station(p_station,p_time,my_callsign); } p_station->flag |= ST_ACTIVE; p_station->flag |= ST_MYSTATION; p_station->data_via = 'L'; p_station->flag &= (~ST_3RD_PT); // clear "third party" flag p_station->record_type = NORMAL_APRS; if (transmit_compressed_posit) { // Compressed posit p_station->error_ellipse_radius = 600; // Default of 6m p_station->lat_precision = 6; p_station->lon_precision = 6; } else { // Standard APRS posit p_station->error_ellipse_radius = 2550; // 25.5m, or about 60ft resolution p_station->lat_precision = 60; p_station->lon_precision = 60; } // Free any old path we might have if (p_station->node_path_ptr != NULL) { free(p_station->node_path_ptr); } // Malloc and store the new path p_station->node_path_ptr = (char *)malloc(strlen("local") + 1); CHECKMALLOC(p_station->node_path_ptr); substr(p_station->node_path_ptr,"local",strlen("local")); // Create a timestamp from the current time xastir_snprintf(p_station->packet_time, sizeof(p_station->packet_time), "%s", get_time(temp_data)); // Create a timestamp from the current time xastir_snprintf(p_station->pos_time, sizeof(p_station->pos_time), "%s", get_time(temp_data)); p_station->flag |= ST_MSGCAP; // set "message capable" flag /* Symbol overlay */ if(my_group != '/' && my_group != '\\') { // Found an overlay character. Check it. if ( (my_group >= '0' && my_group <= '9') || (my_group >= 'A' && my_group <= 'Z') ) { // Overlay character is good p_station->aprs_symbol.aprs_type = '\\'; p_station->aprs_symbol.special_overlay = my_group; } else { // Found a bad overlay character, just use normal alternate character p_station->aprs_symbol.aprs_type = '\\'; p_station->aprs_symbol.special_overlay = '\0'; } } else // Normal symbol, no overlay { p_station->aprs_symbol.aprs_type = my_group; p_station->aprs_symbol.special_overlay = '\0'; } p_station->aprs_symbol.aprs_symbol = my_symbol; p_station->pos_amb = my_amb; xastir_snprintf(temp_data, sizeof(temp_data), "%s", my_lat); //fprintf(stderr," my_lat:%s\n",temp_data); temp_data[9] = '\0'; strp = &temp_data[20]; xastir_snprintf(strp, // sizeof(strp), // No good, as strp is a pointer (int)(sizeof(temp_data) / 2), "%s", my_long); strp[10] = '\0'; //fprintf(stderr,"my_long:%s\n",my_long); //fprintf(stderr,"my_long:%s\n",strp); switch (my_amb) { case 1: // 1/10th minute temp_data[6] = strp[7] = '5'; break; case 2: // 1 minute temp_data[5] = strp[6] = '5'; temp_data[6] = '0'; strp[7] = '0'; break; case 3: // 10 minutes temp_data[3] = strp[4] = '5'; temp_data[5] = temp_data[6] = '0'; strp[6] = strp[7] = '0'; break; case 4: // 1 degree temp_data[2] = strp[3] = '3'; temp_data[3] = temp_data[5] = temp_data[6] = '0'; strp[4] = strp[6] = strp[7] = '0'; break; case 0: default: break; } p_station->coord_lat = convert_lat_s2l(temp_data); p_station->coord_lon = convert_lon_s2l(strp); if (position_on_extd_screen(p_station->coord_lat,p_station->coord_lon)) { p_station->flag |= (ST_INVIEW); // set "In View" flag } else { p_station->flag &= (~ST_INVIEW); // clear "In View" flag } substr(p_station->power_gain,my_phg,7); add_comment(p_station,my_comment); my_last_course = 0; // set my last course in deg to zero redo_list = (int)TRUE; // update active station lists } // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // data_port == -1 for x_spider port, normal interface number // otherwise. -99 should give a "**" display, meaning all ports. // void packet_data_add(char *from, char *line, int data_port) { int offset; char prefix[3] = ""; int local_tnc_interface = 0; int network_interface = 0; if (data_port == -1) // x_spider port (server port) { xastir_snprintf(prefix,sizeof(prefix),"sp"); } else if (data_port == -99) // All ports, used for transmitting { xastir_snprintf(prefix,sizeof(prefix),"**"); } else { xastir_snprintf(prefix,sizeof(prefix),"%2d",data_port); } offset=0; if (line[0]==(char)3) { offset=1; } // Check whether local or network interface if (is_local_interface(data_port) || data_port == -99) { local_tnc_interface++; } if (is_network_interface(data_port) || data_port == -1 || data_port == -99) { network_interface++; } // Compare Display_packet_data_type against the port type // associated with data_port to determine whether or not to // display it. // switch (Display_packet_data_type) { case 2: // Display NET data only if (!network_interface) { return; // Don't display it } break; case 1: // Display TNC data only if (!local_tnc_interface) { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // fprintf(stderr,"display:%d, port:%d\n", // Display_packet_data_type, // data_port); // Check the Capabilities toggle to see if we only want to show // Station Capability packets if (show_only_station_capabilities) { if (!strstr(line, ":<") // Not a capabilities response && !( strstr(line, my_callsign) && strstr(line, "?IGATE?") ) ) { // Not a capabilities response and not my ?IGATE? // request, don't display the packet. return; } } // Check the "Mine Only" toggle to see if we only want to show // our own packets if (Display_packet_data_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(line, short_call)) { return; } } redraw_on_new_packet_data++; // Now save the packet in the history: xastir_snprintf(packet_data_string[next_line],MAX_LINE_SIZE,"%s:%s-> %s\n", prefix,from,line+offset); next_line = (next_line+1)%MAX_PACKET_DATA_DISPLAY; nlinesadd++; if (first_line == -1) { first_line = 0; } else if (first_line == next_line) { ncharsdel += strlen(packet_data_string[first_line]); first_line = (first_line + 1) %MAX_PACKET_DATA_DISPLAY; } } // Write the text from the packet_data_string out to the dialog if // the dialog exists. The user can contract/expand the dialog and // always have it filled with the most current data out of the // string. // void display_packet_data(void) { if( (Display_data_dialog != NULL) && (redraw_on_new_packet_data !=0)) { int pos; int last_char; int i; // Find out the last character position in the dialog text // area. last_char = XmTextGetLastPosition(Display_data_text); //fprintf(stderr,"In display_packet_data: first_line=%d,next_line=%d,ncharsdel=%d,nlinesadd=%d\n",first_line,next_line,ncharsdel,nlinesadd); if (first_line != -1) // there is data in the array { if (last_char == 0 || ncharsdel>=last_char) { //fprintf(stderr," Starting from clean slate...\n"); // but there is no text in the dialog or more chars to delete than // there actually are in the dialog // Clear the dialog just in case: XmTextReplace(Display_data_text,0,last_char,""); // display all the data in the ring for (i=first_line; i != next_line; i=(i+1)%MAX_PACKET_DATA_DISPLAY) { XmTextReplace(Display_data_text,last_char,last_char, packet_data_string[i]); last_char=XmTextGetLastPosition(Display_data_text); pos=last_char; XtVaSetValues(Display_data_text,XmNcursorPosition, pos,NULL); } // Now clear counters so they're always the number of lines to // add or characters to delete *since last display* nlinesadd=0; ncharsdel=0; } else // there is stuff left over after we delete old stuff { if (ncharsdel) // we have something to delete off the top { //fprintf(stderr," Must delete %d characters\n",ncharsdel); XmTextReplace(Display_data_text,0,ncharsdel,""); ncharsdel=0; } if (nlinesadd) // and there's new stuff to add at end { //fprintf(stderr," Must add %d lines\n",nlinesadd); last_char=XmTextGetLastPosition(Display_data_text); for (i=(next_line+MAX_PACKET_DATA_DISPLAY -nlinesadd)%MAX_PACKET_DATA_DISPLAY; i != next_line; i=(i+1)%MAX_PACKET_DATA_DISPLAY) { //fprintf(stderr," Adding data from line %d\n",i); XmTextReplace(Display_data_text,last_char,last_char, packet_data_string[i]); last_char=XmTextGetLastPosition(Display_data_text); pos=last_char; XtVaSetValues(Display_data_text,XmNcursorPosition, pos,NULL); } nlinesadd=0; } } } } redraw_on_new_packet_data=0; } /* * Decode Mic-E encoded data */ int decode_Mic_E(char *call_sign,char *path,char *info,char from,int port,int third_party) { int ii; int offset; unsigned char s_b1; unsigned char s_b2; unsigned char s_b3; unsigned char s_b4; unsigned char s_b5; unsigned char s_b6; // unsigned char s_b7; int north,west,long_offset; int d,m,h; char temp[MAX_LINE_SIZE+1]; // Note: Must be big in case we get long concatenated packets char new_info[MAX_LINE_SIZE+1]; // Note: Must be big in case we get long concatenated packets int course; int speed; int msg1,msg2,msg3,msg; int info_size; long alt; int msgtyp; char rig_type[10]; int ok; // MIC-E Data Format [APRS Reference, chapter 10] // todo: error check // drop wrong positions from receive errors... // drop 0N/0E position (p.25) /* First 7 bytes of info[] contains the APRS data type ID, */ /* longitude, speed, course. */ /* The 6-byte destination field of path[] contains latitude, */ /* N/S bit, E/W bit, longitude offset, message code. */ /* MIC-E Destination Field Format: ------------------------------- Ar1DDDD0 Br1DDDD0 Cr1MMMM0 Nr1MMMM0 Lr1HHHH0 Wr1HHHH0 CrrSSID0 D = Latitude Degrees. M = Latitude Minutes. H = Latitude Hundredths of Minutes. ABC = Message bits, complemented. N = N/S latitude bit (N=1). W = E/W longitude bit (W=1). L = 100's of longitude degrees (L=1 means add 100 degrees to longitude in the Info field). C = Command/Response flag (see AX.25 specification). r = reserved for future use (currently 0). */ /**************************************************************************** * I still don't handle: * * Custom message bits * * SSID special routing * * Beta versions of the MIC-E (which use a slightly different format). * * * * DK7IN : lat/long with custom msg works, altitude/course/speed works * *****************************************************************************/ if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: FOUND MIC-E\n"); } // Note that the first MIC-E character was not passed to us, so we're // starting just past it. // Check for valid symbol table character. Should be '/' or '\' // or 0-9, A-Z. // if ( info[7] == '/' // Primary table || info[7] == '\\' // Alternate table || (info[7] >= '0' && info[7] <= '9') // Overlay char || (info[7] >= 'A' && info[7] <= 'Z') ) // Overlay char { // We're good, keep going } else // Symbol table or overlay char incorrect { if (info[6] == '/' || info[6] == '\\') // Found it back one char in string { // Don't print out the full info string here because it // can contain unprintable characters. In fact, we // should check the chars we do print out to make sure // they're printable, else print a space char. if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: Symbol table (%c), symbol (%c) swapped or corrupted packet? Call=%s, Path=%s\n", ((info[7] > 0x1f) && (info[7] < 0x7f)) ? info[7] : ' ', ((info[6] > 0x1f) && (info[6] < 0x7f)) ? info[6] : ' ', call_sign, path); fprintf(stderr,"Returned from data_add, invalid symbol table character: %c\n",info[7]); } } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for valid symbol. Should be between '!' and '~' only. if (info[6] < '!' || info[6] > '~') { if (debug_level & 1) { fprintf(stderr,"Returned from data_add, invalid symbol\n"); } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for minimum MIC-E size. if (strlen(info) < 8) { if (debug_level & 1) { fprintf(stderr,"Returned from data_add, packet too short\n"); } return(1); // No good, not MIC-E format or corrupted packet. Return 1 // so that it won't get added to the database at all. } // Check for 8-bit characters in the first eight slots. Not // allowed per Mic-E chapter of the spec. for (ii = 0; ii < 8; ii++) { if ((unsigned char)info[ii] > 0x7f) { // 8-bit data was found in the lat/long/course/speed // portion. Bad packet. Drop it. //fprintf(stderr, "%s: 8-bits found in Mic-E packet initial portion. Dropping it.\n", call_sign); return(1); } } // Check whether we have more data. If flag character is 0x1d // (8-bit telemetry flag) then don't do the 8-bit check below. if (strlen(info) > 8) { // Check for the 8-bit telemetry flag if ((unsigned char)info[8] == 0x1d) { // 8-bit telemetry found, skip the check loop below } else // 8-bit telemetry flag was not found. Check that { // we only have 7-bit characters through the rest of // the packet. for (ii = 8; ii < (int)strlen(info); ii++) { if ((unsigned char)info[ii] > 0x7f) { // 8-bit data was found. Bad packet. Drop it. //fprintf(stderr, "%s: 8-bits found in Mic-E packet final portion (not 8-bit telemetry). Dropping it.\n", call_sign); return(1); } } } } //fprintf(stderr,"Path1:%s\n",path); msg1 = (int)( ((unsigned char)path[0] & 0x40) >>4 ); msg2 = (int)( ((unsigned char)path[1] & 0x40) >>5 ); msg3 = (int)( ((unsigned char)path[2] & 0x40) >>6 ); msg = msg1 | msg2 | msg3; // We now have the complemented message number in one variable msg = msg ^ 0x07; // And this is now the normal message number msgtyp = 0; // DK7IN: Std message, I have to add custom msg decoding //fprintf(stderr,"Msg: %d\n",msg); /* Snag the latitude from the destination field, Assume TAPR-2 */ /* DK7IN: latitude now works with custom message */ s_b1 = (unsigned char)( (path[0] & 0x0f) + (char)0x2f ); //fprintf(stderr,"path0:%c\ts_b1:%c\n",path[0],s_b1); if (path[0] & 0x10) // A-J { s_b1 += (unsigned char)1; } if (s_b1 > (unsigned char)0x39) // K,L,Z { s_b1 = (unsigned char)0x20; } //fprintf(stderr,"s_b1:%c\n",s_b1); s_b2 = (unsigned char)( (path[1] & 0x0f) + (char)0x2f ); //fprintf(stderr,"path1:%c\ts_b2:%c\n",path[1],s_b2); if (path[1] & 0x10) // A-J { s_b2 += (unsigned char)1; } if (s_b2 > (unsigned char)0x39) // K,L,Z { s_b2 = (unsigned char)0x20; } //fprintf(stderr,"s_b2:%c\n",s_b2); s_b3 = (unsigned char)( (path[2] & (char)0x0f) + (char)0x2f ); //fprintf(stderr,"path2:%c\ts_b3:%c\n",path[2],s_b3); if (path[2] & 0x10) // A-J { s_b3 += (unsigned char)1; } if (s_b3 > (unsigned char)0x39) // K,L,Z { s_b3 = (unsigned char)0x20; } //fprintf(stderr,"s_b3:%c\n",s_b3); s_b4 = (unsigned char)( (path[3] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path3:%c\ts_b4:%c\n",path[3],s_b4); if (s_b4 > (unsigned char)0x39) // L,Z { s_b4 = (unsigned char)0x20; } //fprintf(stderr,"s_b4:%c\n",s_b4); s_b5 = (unsigned char)( (path[4] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path4:%c\ts_b5:%c\n",path[4],s_b5); if (s_b5 > (unsigned char)0x39) // L,Z { s_b5 = (unsigned char)0x20; } //fprintf(stderr,"s_b5:%c\n",s_b5); s_b6 = (unsigned char)( (path[5] & 0x0f) + (char)0x30 ); //fprintf(stderr,"path5:%c\ts_b6:%c\n",path[5],s_b6); if (s_b6 > (unsigned char)0x39) // L,Z { s_b6 = (unsigned char)0x20; } //fprintf(stderr,"s_b6:%c\n",s_b6); // s_b7 = (unsigned char)path[6]; // SSID, not used here //fprintf(stderr,"path6:%c\ts_b7:%c\n",path[6],s_b7); //fprintf(stderr,"\n"); // Special tests for 'L' due to position ambiguity deviances in // the APRS spec table. 'L' has the 0x40 bit set, but they // chose in the spec to have that represent position ambiguity // _without_ the North/West/Long Offset bit being set. Yuk! // Please also note that the tapr.org Mic-E document (not the // APRS spec) has the state of the bit wrong in columns 2 and 3 // of their table. Reverse them. if (path[3] == 'L') { north = 0; } else { north = (int)((path[3] & 0x40) == (char)0x40); // N/S Lat Indicator } if (path[4] == 'L') { long_offset = 0; } else { long_offset = (int)((path[4] & 0x40) == (char)0x40); // Longitude Offset } if (path[5] == 'L') { west = 0; } else { west = (int)((path[5] & 0x40) == (char)0x40); // W/E Long Indicator } //fprintf(stderr,"north:%c->%d\tlat:%c->%d\twest:%c->%d\n",path[3],north,path[4],long_offset,path[5],west); /* Put the latitude string into the temp variable */ xastir_snprintf(temp, sizeof(temp), "%c%c%c%c.%c%c%c%c",s_b1,s_b2,s_b3,s_b4,s_b5,s_b6, (north ? 'N': 'S'), info[7]); // info[7] = symbol table /* Compute degrees longitude */ xastir_snprintf(new_info, sizeof(new_info), "%s", temp); d = (int) info[0]-28; if (long_offset) { d += 100; } if ((180<=d)&&(d<=189)) // ?? { d -= 80; } if ((190<=d)&&(d<=199)) // ?? { d -= 190; } /* Compute minutes longitude */ m = (int) info[1]-28; if (m>=60) { m -= 60; } /* Compute hundredths of minutes longitude */ h = (int) info[2]-28; /* Add the longitude string into the temp variable */ xastir_snprintf(temp, sizeof(temp), "%03d%02d.%02d%c%c",d,m,h,(west ? 'W': 'E'), info[6]); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); /* Compute speed in knots */ speed = (int)( ( info[3] - (char)28 ) * (char)10 ); speed += ( (int)( (info[4] - (char)28) / (char)10) ); if (speed >= 800) { speed -= 800; // in knots } /* Compute course */ course = (int)( ( ( (info[4] - (char)28) % 10) * (char)100) + (info[5] - (char)28) ); if (course >= 400) { course -= 400; } /* ??? fprintf(stderr,"info[4]-28 mod 10 - 4 = %d\n",( ( (int)info[4]) - 28) % 10 - 4); fprintf(stderr,"info[5]-28 = %d\n", ( (int)info[5]) - 28 ); */ xastir_snprintf(temp, sizeof(temp), "%03d/%03d",course,speed); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); offset = 8; // start of rest of info /* search for rig type in Mic-E data */ rig_type[0] = '\0'; if (info[offset] != '\0' && (info[offset] == '>' || info[offset] == ']')) { /* detected type code: > TH-D7 ] TM-D700 */ if (info[offset] == '>') xastir_snprintf(rig_type, sizeof(rig_type), " TH-D7"); else xastir_snprintf(rig_type, sizeof(rig_type), " TM-D700"); offset++; } info_size = (int)strlen(info); /* search for compressed altitude in Mic-E data */ // { if (info_size >= offset+4 && info[offset+3] == '}') // { { /* detected altitude ___} */ alt = ((((long)info[offset] - (long)33) * (long)91 +(long)info[offset+1] - (long)33) * (long)91 + (long)info[offset+2] - (long)33) - 10000; // altitude in meters alt /= 0.3048; // altitude in feet, as in normal APRS //32808 is -10000 meters, or 10 km (deepest ocean), which is as low as a MIC-E //packet may go. Upper limit is mostly a guess. if ( (alt > 500000) || (alt < -32809) ) // Altitude is whacko. Skip it. { if (debug_level & 1) { fprintf(stderr,"decode_Mic_E: Altitude is whacko: %ld feet, skipping altitude...\n", alt); } offset += 4; } else // Altitude is ok { xastir_snprintf(temp, sizeof(temp), " /A=%06ld",alt); offset += 4; strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } } /* start of comment */ if (strlen(rig_type) > 0) { xastir_snprintf(temp, sizeof(temp), "%s",rig_type); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } strncat(new_info, " Mic-E ", sizeof(new_info) - 1 - strlen(new_info)); if (msgtyp == 0) { switch (msg) { case 1: strncat(new_info, "Enroute", sizeof(new_info) - 1 - strlen(new_info)); break; case 2: strncat(new_info, "In Service", sizeof(new_info) - 1 - strlen(new_info)); break; case 3: strncat(new_info, "Returning", sizeof(new_info) - 1 - strlen(new_info)); break; case 4: strncat(new_info, "Committed", sizeof(new_info) - 1 - strlen(new_info)); break; case 5: strncat(new_info, "Special", sizeof(new_info) - 1 - strlen(new_info)); break; case 6: strncat(new_info, "Priority", sizeof(new_info) - 1 - strlen(new_info)); break; case 7: strncat(new_info, "Emergency", sizeof(new_info) - 1 - strlen(new_info)); // Do a popup to alert the operator to this // condition. Make sure we haven't popped up an // emergency message for this station within the // last 30 minutes. If we pop these up constantly // it gets quite annoying. // EMERGENCY if (emergency_distance_check) { double distance; char course_deg[5]; distance = distance_from_my_station(call_sign, course_deg, english_units); // Because of the distance check we have to receive a valid position // from the station BEFORE we process the EMERGENCY portion and // check distance, doing the popups. We need to figure out a way to // throw the packet back into the queue if it was an emergency // packet so that we process these packets twice each. That way // only one packet from the emergency station is required to // generate the popups. if (distance == 0.0) { process_emergency_packet_again++; } // Check whether the station is near enough to // us to require that we alert on the packet. // // This may be slightly controversial, but if we // don't know WHERE a station is, we can't help // much in an emergency, can we? The // zero-distance check helps in the case where // we haven't yet or never get a position packet // for a station. As soon as we have a position // and it is within a reasonable range, we do // our emergency popups. // if ( distance != 0.0 && (float)distance <= emergency_range ) { if ( (strncmp(call_sign, last_emergency_callsign, strlen(call_sign)) != 0) || ((last_emergency_time + 60*30) < sec_now()) ) { char temp[50]; char temp2[150]; char temp3[300]; char timestring[101]; // Callsign is different or enough time has // passed last_emergency_time = sec_now(); xastir_snprintf(last_emergency_callsign, sizeof(last_emergency_callsign), "%s", call_sign); // Bring up the Find Station dialog so that the // operator can go to the location quickly xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", call_sign); Locate_station( (Widget)NULL, (XtPointer)NULL, (XtPointer)1 ); // Bring up another dialog with the // callsign plus distance/bearing to the // station. xastir_snprintf(temp, sizeof(temp), "%0.1f", distance); xastir_snprintf(temp2, sizeof(temp2), langcode("WPUPSTI022"), temp, course_deg); get_timestamp(timestring); xastir_snprintf(temp3, sizeof(temp3), "%s %s", timestring, temp2); popup_message_always(call_sign, temp3); } } } break; default: strncat(new_info, "Off Duty", sizeof(new_info) - 1 - strlen(new_info)); } } else { xastir_snprintf(temp, sizeof(temp), "Custom%d",msg); strncat(new_info, temp, sizeof(new_info) - 1 - strlen(new_info)); } if (info[offset] != '\0') { /* Append the rest of the message to the expanded MIC-E message */ for (ii=offset; ii278/007 /A=-05685 TM-D700 Mic-E Off Duty N0EST , // from: 70, // port: -1, // NULL, // third_party: 0 } // We don't transmit Mic-E protocol from Xastir, so we know it's // not our station's packets or our object/item packets, // therefore the last two parameters here are both zero. // ok = data_add(APRS_MICE,call_sign,path,new_info,from,port,NULL,third_party, 0, 0); if (debug_level & 1) { fprintf(stderr,"Returned from data_add, end of function\n"); } return(ok); } // End of decode_Mic_E() /* * Directed Station Query (query to my station) [APRS Reference, chapter 15] */ int process_directed_query(char *call,char *path,char *message,char from) { DataRow *p_station; char from_call[MAX_CALLSIGN+1]; char temp[100]; int ok = 0; if (debug_level & 1) { fprintf(stderr,"process_directed_query: %s\n",message); } // Check for proper usage of the APRSD query if (!ok && strncmp(message,"APRSD",5) == 0 && from != 'F') // stations heard direct { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:Directs=",from_call); p_station = n_first; while (p_station != NULL) { if ((p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { if ( ((p_station->flag & ST_VIATNC) != 0) // test "via TNC" flag && ((p_station->flag & ST_DIRECT) != 0) // And "direct" flag && sec_now() < (p_station->direct_heard + st_direct_timeout) // Within the last hour // && !is_my_call(p_station->call_sign,1) ) { // and not me (checks SSID too) && !(is_my_station(p_station)) ) // and not me (checks SSID too) { if (strlen(temp)+strlen(p_station->call_sign) < 65) { strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); strncat(temp, p_station->call_sign, sizeof(temp) - 1 - strlen(temp)); } else { // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); xastir_snprintf(temp, sizeof(temp), ":%s:Directs=",from_call); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); strncat(temp, p_station->call_sign, sizeof(temp) - 1 - strlen(temp)); } } } p_station = p_station->n_next; } // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); ok = 1; } // Check for illegal case for the APRSD query if (!ok && strncasecmp(message,"APRSD",5) == 0 && from != 'F') // stations heard direct { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSH query if (!ok && strncmp(message,"APRSH",5)==0) { ok = 1; } // Check for illegal case for the APRSH query if (!ok && strncasecmp(message,"APRSH",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSM query if (!ok && strncmp(message,"APRSM",5)==0) { ok = 1; } // Check for illegal case for the APRSM query if (!ok && strncasecmp(message,"APRSM",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSO query if (!ok && strncmp(message,"APRSO",5)==0) { ok = 1; } // Check for illegal case for the APRSO query if (!ok && strncasecmp(message,"APRSO",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the APRSP query if (!ok && strncmp(message,"APRSP",5) == 0 && from != 'F') { transmit_now = 1; //send position ok = 1; } // Check for illegal case for the APRSP query if (!ok && strncasecmp(message,"APRSP",5) == 0 && from != 'F') { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // NOT IMPLEMENTED YET // Check for proper usage of the APRSS query if (!ok && strncmp(message,"APRSS",5)==0) { ok = 1; } // Check for illegal case for the APRSS query if (!ok && strncasecmp(message,"APRSS",5)==0) { // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the APRST/PING? queries if (!ok && (strncmp(message,"APRST",5)==0 || strncmp(message,"PING?",5)==0) && from != 'F') { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:PATH= %s>%s",from_call,call,path); // correct format ????? // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); ok = 1; } // Check for illegal case for the APRST/PING? queries if (!ok && (strncasecmp(message,"APRST",5)==0 || strncasecmp(message,"PING?",5)==0) && from != 'F') { fprintf(stderr, "%s just queried us with an illegal query: %s\n", call, message), fprintf(stderr, "Consider sending a message, asking them to follow the spec\n"); ok = 1; } // Check for proper usage of the VER query (either case?) if (!ok && strncasecmp("VER",message,3) == 0 && from != 'F') // not in Reference !??? { pad_callsign(from_call,call); xastir_snprintf(temp, sizeof(temp), ":%s:%s",from_call,VERSIONLABEL); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,temp,NULL); if (debug_level & 1) { fprintf(stderr,"Sent to %s:%s\n",call,temp); } ok = 1; } return(ok); } /* * Station Capabilities, Queries and Responses [APRS Reference, chapter 15] */ // // According to Bob Bruninga we should wait a random time between 0 // and 120 seconds before responding to a general query. We use the // delayed-ack mechanism to add this randomness. // // NOTE: We may end up sending these to RF when the query came in // over the internet. We should check that. // int process_query( char *call_sign, char * UNUSED(path), char *message,char from,int port, int UNUSED(third_party) ) { char temp[100]; int ok = 0; float randomize; // Generate a random number between 0.0 and 1.0 randomize = rand() / (float)RAND_MAX; // Convert to between 0 and 120 seconds randomize = randomize * 120.0; //fprintf(stderr,"Randomize:%f\n", randomize); // Check for proper usage of the ?APRS? query // // NOTE: We need to add support in here for the radius circle as // listed in the spec for general queries. Right now we respond to // all queries, whether we're inside the circle or not. Spec says // this: // // ?Query?Lat,Long,Radius // 1 n 1 n 1 n 1 4 Bytes // // i.e. ?APRS? 34.02,-117.15,0200 // // Note leading space in latitude as its value is positive. // Lat/long are floating point degrees. N/E are positive, indicated // by a leading space. S/W are negative. Radius is in miles // expressed as a fixed 4-digit number in whole miles. All stations // inside the specified circle should respond with a position report // and a status report. // if (!ok && strncmp(message,"APRS?",5)==0) { // // Initiate a delayed transmit of our own posit. // UpdateTime() uses posit_next_time to decide when to // transmit, so we'll just muck with that. // if ( posit_next_time - sec_now() < randomize ) { // Skip setting it, as we'll transmit soon anyway } else { posit_next_time = (size_t)(sec_now() + randomize); } ok = 1; } // Check for illegal case for the ?APRS? query if (!ok && strncasecmp(message,"APRS?",5)==0) { ok = 1; // fprintf(stderr, // "%s just queried us with an illegal query: %s\n", // call_sign, // message), // fprintf(stderr, // "Consider sending a message, asking them to follow the spec\n"); } // Check for proper usage of the ?IGATE? query if (!ok && strncmp(message,"IGATE?",6)==0 && port != -1) // Not from a log file { if (operate_as_an_igate && from != 'F') { xastir_snprintf(temp, sizeof(temp), "= 1) ) { xastir_snprintf(short_path, short_path_size, "%s", path); // Terminate the path at the end of the last used digipeater // This is trickier than it seems due to WIDEn-N and TRACEn-N // digipeaters. // Take a run through the entire path string looking for unused // TRACE/WIDE paths. for ( i = (strlen(path)-1); i >= 0; i-- ) // Count backwards { // If we find ",WIDE3-3" or ",TRACE7-7" (numbers match), // jam '\0' in at the comma. These are unused digipeaters. if ( (strstr(&short_path[i],",WIDE7-7") != NULL) || (strstr(&short_path[i],",WIDE6-6") != NULL) || (strstr(&short_path[i],",WIDE5-5") != NULL) || (strstr(&short_path[i],",WIDE4-4") != NULL) || (strstr(&short_path[i],",WIDE3-3") != NULL) || (strstr(&short_path[i],",WIDE2-2") != NULL) || (strstr(&short_path[i],",WIDE1-1") != NULL) || (strstr(&short_path[i],",TRACE7-7") != NULL) || (strstr(&short_path[i],",TRACE6-6") != NULL) || (strstr(&short_path[i],",TRACE5-5") != NULL) || (strstr(&short_path[i],",TRACE4-4") != NULL) || (strstr(&short_path[i],",TRACE3-3") != NULL) || (strstr(&short_path[i],",TRACE2-2") != NULL) || (strstr(&short_path[i],",TRACE1-1") != NULL) ) { short_path[i] = '\0'; } } // Take another run through short_string looking for used // TRACE/WIDE paths. Also look for '*' characters and flag // if we see any. If no '*' found, but a used TRACE/WIDE // path found, chop the path after the used TRACE/WIDE. This // is to modify paths like this: // APRS,PY1AYH-15*,RELAY,WIDE3-2,PY1EU-1 // to this: // APRS,PY1AYH-15*,RELAY,WIDE3-2 j = 0; found_trace_wide = 0; found_asterisk = 0; for ( i = (strlen(short_path)-1); i >= 0; i-- ) // Count backwards { if (short_path[i] == '*') { found_asterisk++; } // Search for TRACEn/WIDEn. If found (N!=n is guaranteed // by the previous loop) set the lower increment for the next // loop just past the last TRACEn/WIDEn found. The used part // of the TRACEn/WIDEn will still remain in our shorter path. if ( (strstr(&short_path[i],"WIDE7") != NULL) || (strstr(&short_path[i],"WIDE6") != NULL) || (strstr(&short_path[i],"WIDE5") != NULL) || (strstr(&short_path[i],"WIDE4") != NULL) || (strstr(&short_path[i],"WIDE3") != NULL) || (strstr(&short_path[i],"WIDE2") != NULL) || (strstr(&short_path[i],"WIDE1") != NULL) || (strstr(&short_path[i],"TRACE7") != NULL) || (strstr(&short_path[i],"TRACE6") != NULL) || (strstr(&short_path[i],"TRACE5") != NULL) || (strstr(&short_path[i],"TRACE4") != NULL) || (strstr(&short_path[i],"TRACE3") != NULL) || (strstr(&short_path[i],"TRACE2") != NULL) || (strstr(&short_path[i],"TRACE1") != NULL) ) { j = i; found_trace_wide++; break; // We only want to find the right-most one. // We've found a used digipeater! } } // Chop off any unused digi's after a used TRACEn/WIDEn if (!found_asterisk && found_trace_wide) { for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == ',') { short_path[i] = '\0'; // Terminate the string } } } // At this point, if we found a TRACEn or WIDEn, the "j" // variable will be non-zero. If not then it'll be zero and // we'll run completely through the shorter path converting // '*' characters to '\0'. found_asterisk = 0; for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == '*') { short_path[i] = '\0'; // Terminate the string found_asterisk++; } } // Check for TCPIP or TCPXX as the last digipeater. If present, // remove them. TCPXX means that the packet came from an unregistered // user, and those packets will be rejected in igate.c before they're // sent to RF anyway. igate.c will check for its presence in path, // not in short_path, so we're ok here to get rid of it in short_path. if (strlen(short_path) >= 5) // Get rid of "TCPIP" & "TCPXX" { ptr = &short_path[strlen(short_path) - 5]; if ( (strcasecmp(ptr,"TCPIP") == 0) || (strcasecmp(ptr,"TCPXX") == 0) ) { *ptr = '\0'; } if ( (strlen(short_path) >= 1) // Get rid of possible ending comma && (short_path[strlen(short_path) - 1] == ',') ) { short_path[strlen(short_path) - 1] = '\0'; } } // We might have a string with zero used digipeaters. In this case // we will have no '*' characters and no WIDEn-N/TRACEn-N digis. // Get rid of everything except the destination call. These packets // must have been heard directly by an igate station. if (!found_trace_wide && !found_asterisk) { for ( i = (strlen(short_path)-1); i >= j; i-- ) // Count backwards { if (short_path[i] == ',') { short_path[i] = '\0'; // Terminate the string } } } // The final step: Remove any asterisks in the path. // We'll insert our own on the way out to RF again. for ( i = 0; i < (int)(strlen(short_path) - 1); i++ ) { if (short_path[i] == '*') { for (j = i; j <= (int)(strlen(short_path) - 1); j++ ) { short_path[j] = short_path[j+1]; // Shift left by one char } } } } else { short_path[0] = '\0'; // We were passed an empty string or a NULL. } if (debug_level & 1) { fprintf(stderr,"%s\n",path); fprintf(stderr,"%s\n\n",short_path); } } // TODO: // *) Use the valid_call(call) function here? // *) Add a "Tactical Call Disable" togglebutton. Default = // disabled. // *) Send out TAC assignments as they are created via an APRS // message? // *) Add "Send All Tactical Calls" menu entry. Another entry to // send them out repetitively? // *) Create a public/private distinction for TAC calls? // *) Add public/private toggle to the Tactical Callsign box, and // have it send an APRS Message if public when changed? // *) Add a method to list the public/private TAC calls we currently // have assigned. // *) Create an easier method to remove one or more TAC calls? // Currently we have to send a blank assignment ("we7u-12="). // *) Log TAC calls and date/time for each assignment, including // NULL assignments. // // From Bob: // *) Range filter - won't accept tactical assignments without a // position within X miles of source. // *) Change filter - won't accept changes from others for locally // created tac assignment. Kind of implies two tables - local // and remote Button/menu item to send local, or send all - each // a manual operation, as we discussed. // *) Perhaps repeat messages fewer times if sent to TACTICAL than // for a normal message? This is so that more than one // controller can manipulate them without having to wait for the // timeout of the first message. // // int fill_in_tactical_callsign(char *call, char *tactical_call) { DataRow *p_station; // Convert callsign to upper-case (void)to_upper(call); // Get rid of white space on either end (void)remove_leading_spaces(call); (void)remove_trailing_spaces(call); (void)remove_leading_spaces(tactical_call); (void)remove_trailing_spaces(tactical_call); // Find the station record. if (!search_station_name(&p_station, call, 1)) { // Station not found. // Add the TAC call to the tactical hash for future // application to a callsign via the log_tactical_call() // function call below... } else // Found it! Assign the new tactical call. Some code { // here borrowed from db.c:Change_tactical_change_data() // Check for blank incoming tactical call. if (tactical_call[0] == '\0') { // Blank tactical call string. Free space and null // pointer. free(p_station->tactical_call_sign); p_station->tactical_call_sign = NULL; } else // Non-blank incoming tactical call string { if (p_station->tactical_call_sign == NULL) { // Malloc some memory to hold it. p_station->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); } if (p_station->tactical_call_sign == NULL) { fprintf(stderr, "Couldn't malloc space for tactical callsign\n"); return -1; } xastir_snprintf(p_station->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", tactical_call); } redraw_on_new_data = 2; // redraw now } // Log the change in the tactical_calls.log file. Also adds it // to the tactical callsign hash. log_tactical_call(call, tactical_call); return(0); } // // Assign tactical callsigns based on messages sent to "TACTICAL" // // *) To set your own tactical callsign and send it to others, // send an APRS message to "TACTICAL" with your callsign in // the message text. // // *) To send multiple tactical calls to others, send an APRS // message to "TACTICAL" and enter: // "CALL1=TAC1;CALL2=TAC2;CALL3=TAC3" in the message text. // // '=' or ';' characters can not be in the TAC callsign. // int tactical_data_add(char *call, char *message, char UNUSED(from) ) { char *temp_ptr; if (strlen(message) <= 1) { return -1; } // Check whether we're dealing with one or multiple tactical // callsign assignments. Look for a '=' character. temp_ptr = strrchr(message,'='); if (temp_ptr == NULL) { // No '=' character was found. We're dealing with a single // tactical assignment for the "call" callsign. Extract the // tactical call and assign it to the station data record // for the station. if (debug_level & 2) { fprintf(stderr, "One tactical assignment.\n"); } fill_in_tactical_callsign(call, message); } else // We're dealing with multiple tactical assignments. { int ii; const int max = 50; char *Substring[max]; char *Call_Tac[2]; if (debug_level & 2) { fprintf(stderr, "Possibly multiple tactical assignments.\n"); } // Split the message first on ';' characters to get the // callsign=tactical pairs separated from each other. split_string( message, Substring, max, ';' ); // Check whether we found more than one pair. if (Substring[0] == NULL) // No ';' chars were found. { // We might still have a single tactical definition in // the message. Assign "message" to Substring[0] for // further processing below. if (debug_level & 2) { fprintf(stderr, "No semicolons found.\n"); } Substring[0] = message; } ii = 0; while (Substring[ii] != NULL) { // Split each string and process. The results of each // split will be in: // Call_Tac[0] (Callsign) // Call_Tac[1] (Tactical Callsign) // split_string( Substring[ii], Call_Tac, 2, '=' ); if (Call_Tac[0] != NULL) // Found '=' char. { if (debug_level & 2) { fprintf(stderr, "Found a tactical pair: %s->%s\n", Call_Tac[0], Call_Tac[1]); } fill_in_tactical_callsign(Call_Tac[0], Call_Tac[1]); } ii++; } } return 0; } // // Messages, Bulletins and Announcements [APRS Reference, chapter 14] // // // Returns 1 if successful // 0 if not successful // int decode_message(char *call,char *path,char *message,char from,int port,int third_party) { char *temp_ptr; char ipacket_message[300]; char message_plus_acks[MAX_MESSAGE_LENGTH + 10]; char from_call[MAX_CALLSIGN+1]; char ack[20]; int ok, len; char addr[9+1]; char addr9[9+1]; char msg_id[5+1]; char orig_msg_id[5+1]; char ack_string[6]; int done; int reply_ack = 0; int to_my_call = 0; int to_my_base_call = 0; int from_my_call = 0; // :xxxxxxxxx:____0-67____ message printable, except '|', '~', '{' // :TACTICAL :text Tactical definition for sending station // :TACTICAL :CALL1=TAC1;CALL2=TAC2 Tactical definitions for multiple stations // :BLNn :____0-67____ general bulletin printable, except '|', '~' // :BLNnxxxxx:____0-67____ + Group Bulletin // :BLNX :____0-67____ Announcement // :NWS-xxxxx:____0-67____ NWS Service Bulletin // :NWS_xxxxx:____0-67____ NWS Service Bulletin // :BOM-xxxxx:____0-67____ BOM Service Bulletin (AU Wx) // :BOM_xxxxx:____0-67____ BOM Service Bulletin (AU Wx) // :xxxxxxxxx:ackn1-5n + ack // :xxxxxxxxx:rejn1-5n + rej // :xxxxxxxxx:____0-67____{n1-5n + message // :NTS.... // 01234567890123456 // 01234567890123456 old // we get message with already extracted data ID if (debug_level & 1) { fprintf(stderr,"decode_message: start\n"); } if (debug_level & 1) { if ( (message != NULL) && (strlen(message) > (MAX_MESSAGE_LENGTH + 10) ) ) { // // Overly long message. Throw it away. We're done. // fprintf(stderr,"decode_message: LONG message. Dumping it.\n"); return(0); } } if (is_my_call(call, 1) ) // Check SSID also { from_my_call++; } ack_string[0] = '\0'; // Clear out the Reply/Ack result string len = (int)strlen(message); ok = (int)(len > 9 && message[9] == ':'); if (ok) { substr(addr9,message,9); // extract addressee xastir_snprintf(addr, sizeof(addr), "%s", addr9); (void)remove_trailing_spaces(addr); if (is_my_call(addr,1)) // Check includes SSID { to_my_call++; } if (is_my_call(addr,0)) // Check ignores SSID. We use { // this to catch messages to some // of our other SSID's to_my_base_call++; } message = message + 10; // pointer to message text // Save the message text and the acks/reply-acks before we // extract the acks below. xastir_snprintf(message_plus_acks, sizeof(message_plus_acks), "%s", message); temp_ptr = strrchr(message,'{'); // look for message ID after //*last* { in message. msg_id[0] = '\0'; if (temp_ptr != NULL) { substr(msg_id,temp_ptr+1,5); // extract message ID, could be non-digit temp_ptr[0] = '\0'; // adjust message end (chops off message ID) } // Save the original msg_id away. xastir_snprintf(orig_msg_id, sizeof(orig_msg_id), "%s", msg_id); // Check for Reply/Ack protocol in msg_id, which looks like // this: "{XX}BB", where XX is the sequence number for the // message, and BB is the ack for the previous message from // my station. I've also seen this from APRS+: "{XX}B", so // perhaps this is also possible "{X}B" or "{X}BB}". We can // also get auto-reply responses from APRS+ that just have // "}X" or "}XX" at the end. We decode those as well. // temp_ptr = strstr(msg_id,"}"); // look for Reply Ack in msg_id if (temp_ptr != NULL) // Found Reply/Ack protocol! { reply_ack++; // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"1Found Reply/Ack:%s\n",message); fprintf(stderr,"Orig_msg_id:%s\t",msg_id); } // Put this code into the UI message area as well (if applicable). // Separate out the extra ack so that we can deal with // it properly. xastir_snprintf(ack_string, sizeof(ack_string), "%s", temp_ptr+1); // After the '}' character! // Terminate it here so that rest of decode works // properly. We can get duplicate messages // otherwise. // // Note that we modify msg_id here. Use orig_msg_id if we need the // unmodified version (full REPLY-ACK version) later. // temp_ptr[0] = '\0'; // adjust msg_id end // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"New_msg_id:%s\tReply_ack:%s\n\n", msg_id,ack_string); } } else // Look for Reply Ack in message without sequence { // number temp_ptr = strstr(message,"}"); if (temp_ptr != NULL) { int yy = 0; reply_ack++; // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"2Found Reply/Ack:%s\n",message); } // Put this code into the UI message area as well (if applicable). xastir_snprintf(ack_string, sizeof(ack_string), "%s", temp_ptr+1); // After the '}' character! ack_string[yy] = '\0'; // Terminate the string // Terminate it here so that rest of decode works // properly. We can get duplicate messages // otherwise. temp_ptr[0] = '\0'; // adjust message end // if ( (debug_level & 1) && (is_my_call(addr,1)) ) { // Check SSID also if ( (debug_level & 1) && to_my_call) // Check SSID also { fprintf(stderr,"Reply_ack:%s\n\n",ack_string); } } } done = 0; } else { done = 1; // fall through... } if (debug_level & 1) { fprintf(stderr,"1\n"); } len = (int)strlen(message); //-------------------------------------------------------------------------- if (!done && len > 3 && strncmp(message,"ack",3) == 0) // ACK { // Received an ACK packet. Note that these can carry the // REPLY-ACK protocol or a single ACK sequence number plus // perhaps an extra '}' on the end. They should have one of // these formats: // ack1 Normal ACK // ackY Normal ACK // ack23 Normal ACK // ackfH Normal ACK // ack23{ REPLY-ACK Protocol // ack2Q}3d REPLY-ACK Protocol substr(msg_id,message+3,5); // fprintf(stderr,"ACK: %s: |%s| |%s|\n",call,addr,msg_id); // if (is_my_call(addr,1)) { // Check SSID also if (to_my_call) // Check SSID also { // Note: This function handles REPLY-ACK protocol just // fine, stripping off the 2nd ack if present. It uses // only the first sequence number. clear_acked_message(call,addr,msg_id); // got an ACK for me // This one also handles REPLY-ACK protocol just fine. msg_record_ack(call,addr,msg_id,0,0); // Record the ack for this message } else // ACK is for another station { // Now if I have Igate on and I allow to retransmit station data // check if this message is to a person I have heard on my TNC within an X // time frame. If if is a station I heard and all the conditions are ok // spit the ACK out on the TNC -FG if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); // Only send '}' and the ack_string if it's not // empty, else just end the packet with the message // string. This keeps us from appending a '}' when // it's not called for. xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s%s%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, // message, message_plus_acks); // (ack_string[0] == '\0') ? "" : "}", // ack_string); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send ACK to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } } done = 1; } if (debug_level & 1) { fprintf(stderr,"2\n"); } //-------------------------------------------------------------------------- if (!done && len > 3 && strncmp(message,"rej",3) == 0) // REJ { substr(msg_id,message+3,5); // if ( is_my_call(addr,1) ) { // Check SSID also if (to_my_call) // Check SSID also { // REJ is for me! // fprintf(stderr,"Received a REJ packet from %s: |%s| |%s|\n",call,addr,msg_id); // Note: This function handles REPLY-ACK protocol just // fine, stripping off the 2nd ack if present. It uses // only the first sequence number. clear_acked_message(call,addr,msg_id); // got an REJ for me // This one also handles REPLY-ACK protocol just fine. msg_record_rej(call,addr,msg_id); // Record the REJ for this message } else // REJ is for another station { /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the REJ out on the TNC */ if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); // Only send '}' and the rej_string if it's not // empty, else just end the packet with the message // string. This keeps us from appending a '}' when // it's not called for. xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s%s%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, // message, message_plus_acks); // (ack_string[0] == '\0') ? "" : "}", // ack_string); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send REJ to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } } done = 1; } if (debug_level & 1) { fprintf(stderr,"3\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"TACTICAL",8) == 0) // Tactical definition { if (debug_level & 2) { fprintf(stderr,"found TACTICAL: |%s| |%s|\n",call,message); } tactical_data_add(call,message,from); done = 1; } if (debug_level & 1) { fprintf(stderr,"TAC\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"BLN",3) == 0) // Bulletin { // fprintf(stderr,"found BLN: |%s| |%s|\n",addr,message); bulletin_data_add(addr,call,message,"",MESSAGE_BULLETIN,from); done = 1; } if (debug_level & 1) { fprintf(stderr,"4\n"); } //-------------------------------------------------------------------------- // if (!done && strlen(msg_id) > 0 && is_my_call(addr,1)) { // Message for me (including SSID check) if (!done && strlen(msg_id) > 0 && to_my_call) // Message for me (including SSID check) { // with msg_id (sequence number) time_t last_ack_sent; long record; // Remember to put this code into the UI message area as well (if // applicable). // Check for Reply/Ack if (reply_ack && strlen(ack_string) != 0) // Have a free-ride ack to deal with { //fprintf(stderr, "reply-ack: clear_acked_message()\n"); clear_acked_message(call,addr,ack_string); // got an ACK for me //fprintf(stderr, "reply-ack: msg_record_ack()\n"); msg_record_ack(call,addr,ack_string,0,0); // Record the ack for this message } // Save the ack 'cuz we might need it while talking to this // station. We need it to implement Reply/Ack protocol. // Note that msg_id has already been truncated by this point. // orig_msg_id contains the full REPLY-ACK text. //fprintf(stderr, "store_most_recent_ack()\n"); store_most_recent_ack(call,msg_id); // fprintf(stderr,"found Msg w line to me: |%s| |%s|\n",message,msg_id); last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); // id_fixed // Here we need to know if it is a new message or an old. // If we've already received it, we don't want to kick off // the alerts or pop up the Send Message dialog again. If // last_ack_sent == (time_t)0, then it is a new message. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist // for this QSO. Only call it for the first message // line or the first ack, not for any repeats. // //fprintf(stderr,"***check_popup_window 1\n"); (void)check_popup_window(call, 2); // Calls update_messages() //update_messages(1); // Force an update if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } #ifdef HAVE_FESTIVAL /* I re-use ipacket_message as my string buffer */ if (festival_speak_new_message_alert) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "You have a new message from %s.", call); SayText(ipacket_message); } if (festival_speak_new_message_body) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), " %s", message); SayText(ipacket_message); } #endif // HAVE_FESTIVAL } // Try to only send an ack out once per 30 seconds at the // fastest. //WE7U // Does this 30-second check work? // if ( from != 'F' // Not from a log file && (last_ack_sent != (time_t)-1l) // Not an error && (last_ack_sent + 30 ) < sec_now() && !satellite_ack_mode // Disable separate ack's for satellite work && port != -1 ) // Not from a log file { char path[MAX_LINE_SIZE+1]; //fprintf(stderr,"Sending ack: %ld %ld %ld\n",last_ack_sent,sec_now(),record); // Update the last_ack_sent field for the message msg_update_ack_stamp(record); pad_callsign(from_call,call); /* ack the message */ // Attempt to snag a custom path out of the Send Message // dialog, if set. If not set, path will contain '\0'; get_send_message_path(call, path, MAX_LINE_SIZE+1); //fprintf(stderr,"Path: %s\n", path); // In this case we want to send orig_msg_id back, not // the (possibly) truncated msg_id. This is per Bob B's // Reply/Ack spec, sent to xastir-dev on Nov 14, 2001. xastir_snprintf(ack, sizeof(ack), ":%s:ack%s",from_call,orig_msg_id); //WE7U // Need to figure out the reverse path for this one instead of // passing a NULL for the path? Probably not, as auto-calculation // of paths isn't a good idea. // // What we need to do here is check whether we have a custom path // set for this QSO. If so, pass that path along as the transmit // path. messages.h:Message_Window struct has the send_message_path // variable in it. If a Message_Window still exists for this QSO // then we can snag the user-entered path from there. If the struct // has already been destroyed then we have nowhere to snag the // custom path from and have to rely on the default paths in each // interface properties dialog instead. Then again, we _could_ snag // the path out of the last received message in the message database // for that case. Might be better to disable the Close button, or // warn the user that the custom path will be lost if they close the // Send Message dialog. // Send out the immediate ACK if (path[0] == '\0') { transmit_message_data(call,ack,NULL); } else { transmit_message_data(call,ack,path); } if (record != -1l) // Msg we've received before { // It's a message that we've received before, // consider sending an extra ACK in about 30 seconds // to try to get it to the remote station. Perhaps // another one in 60 seconds as well. // fprintf(stderr, // "We've received this message before.\n"); // fprintf(stderr, // "Sending a couple of delayed ack's.\n"); if (path[0] == '\0') { transmit_message_data_delayed(call,ack,NULL,sec_now()+30); transmit_message_data_delayed(call,ack,NULL,sec_now()+60); transmit_message_data_delayed(call,ack,NULL,sec_now()+120); } else { transmit_message_data_delayed(call,ack,path,sec_now()+30); transmit_message_data_delayed(call,ack,path,sec_now()+60); transmit_message_data_delayed(call,ack,path,sec_now()+120); } } if (auto_reply == 1) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "AA:%s", auto_reply_message); if (debug_level & 2) fprintf(stderr,"Send autoreply to <%s> from <%s> :%s\n", call, my_callsign, ipacket_message); // if (!is_my_call(call,1)) // Check SSID also if (!from_my_call) // Check SSID also { output_message(my_callsign, call, ipacket_message, ""); } } } else { //fprintf(stderr,"Skipping ack: %ld %ld\n",last_ack_sent,sec_now()); } done = 1; } if (debug_level & 1) { fprintf(stderr,"5a\n"); } //-------------------------------------------------------------------------- if (!done && strlen(msg_id) == 0 && to_my_call) // Message for me (including SSID check) { // but without message-ID. // These should appear in a Send Message dialog and should // NOT get ack'ed. Kenwood radios send this message type as // an auto-answer or a buffer-full message. They look // something like: // // :WE7U-13 :Not at keyboard. // time_t last_ack_sent; long record; if (len > 2 && message[0] == '?' && port != -1 // Not from a log file && to_my_call) // directed query (check SSID also) { // Smallest query known is "?WX". if (debug_level & 1) { fprintf(stderr,"Received a directed query\n"); } done = process_directed_query(call,path,message+1,from); } // fprintf(stderr,"found Msg w line to me: |%s| |%s|\n",message,msg_id); last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); // id_fixed // Here we need to know if it is a new message or an old. // If we've already received it, we don't want to kick off // the alerts or pop up the Send Message dialog again. If // last_ack_sent == (time_t)0, then it is a new message. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist // for this QSO. Only call it for the first message // line or the first ack, not for any repeats. // //fprintf(stderr,"***check_popup_window 1\n"); (void)check_popup_window(call, 2); // Calls update_messages() //update_messages(1); // Force an update if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } #ifdef HAVE_FESTIVAL /* I re-use ipacket_message as my string buffer */ if (festival_speak_new_message_alert) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), "You have a new message from %s.", call); SayText(ipacket_message); } if (festival_speak_new_message_body) { xastir_snprintf(ipacket_message, sizeof(ipacket_message), " %s", message); SayText(ipacket_message); } #endif // HAVE_FESTIVAL } // Update the last_ack_sent field for the message, even // though we won't be sending an ack in response. msg_update_ack_stamp(record); //fprintf(stderr,"Received msg for me w/o ack\n"); done = 1; } if (debug_level & 1) { fprintf(stderr,"5b\n"); } //-------------------------------------------------------------------------- if (!done && ( (strncmp(addr,"NWS-",4) == 0) // NWS weather alert || (strncmp(addr,"NWS_",4) == 0) // NWS weather alert compressed || (strncmp(addr,"BOM-",4) == 0) // BOM (AU) weather alert || (strncmp(addr,"BOM_",4) == 0) ) ) // BOM (AU) weather alert compressed { // could have sort of line number //fprintf(stderr,"found NWS: |%s| |%s| |%s|\n",addr,message,msg_id); (void)alert_data_add(addr, call, message, msg_id, MESSAGE_NWS, from); done = 1; if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message); output_nws_igate_rf(call, path, ipacket_message, port, third_party); } } if (debug_level & 1) { fprintf(stderr,"6a\n"); } //-------------------------------------------------------------------------- if (!done && strncmp(addr,"SKY",3) == 0) // NWS weather alert additional info { // could have sort of line number //fprintf(stderr,"found SKY: |%s| |%s| |%s|\n",addr,message,msg_id); /* (void)alert_data_add(addr, call, message, msg_id, MESSAGE_NWS, from); */ // We don't wish to record these in memory. They cause an infinite // loop in the current code and a massive memory leak. return(1); // Tell the calling program that the packet was ok so // that it doesn't add it with data_add() itself! done = 1; if (operate_as_an_igate>1 && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message); output_nws_igate_rf(call, path, ipacket_message, port, third_party); } } if (debug_level & 1) { fprintf(stderr,"6b\n"); } //-------------------------------------------------------------------------- if (!done && strlen(msg_id) > 0) // Other message with linenumber. This { // is either a message for someone else // or a message for another one of my // SSID's. long record_out; time_t last_ack_sent; char message_plus_note[MAX_MESSAGE_LENGTH + 30]; if (debug_level & 2) fprintf(stderr,"found Msg w/line: |%s| |%s| |%s|\n", addr, message, orig_msg_id); if (to_my_base_call && !from_my_call) { // Special case: We saw a message w/msg_id that was to // one of our other SSID's, but it was not from // ourselves. That last bit (!from_my_call) is // important in the case where we're working an event // with several stations using the same callsign. // // Store as if it came to my callsign, with a zeroed-out // msg_id so we can't try to ack it. We also need some // other indication in the "Send Message" dialog as to // what's happening. Perhaps add the original callsign // to the message itself in a note at the start? // xastir_snprintf(message_plus_note, sizeof(message_plus_note), "(Sent to:%s) %s", addr, message); last_ack_sent = msg_data_add(my_callsign, call, message_plus_note, "", MESSAGE_MESSAGE, from, &record_out); } else // Normal case, messaging between other people { last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record_out); } new_message_data += look_for_open_group_data(addr); // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record_out == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 2\n"); // Callsign check here also checks SSID for exact match // if ((is_my_call(call,1) && check_popup_window(addr, 2) != -1) // if ((from_my_call && check_popup_window(addr, 2) != -1) // We need to do an SSID-non-specific check here so that we can pick // up messages intended for other stations of ours. // if ((to_my_base_call && check_popup_window(addr, 2) != -1) if ((to_my_base_call && check_popup_window(call, 2) != -1) || check_popup_window(call, 0) != -1 || check_popup_window(addr, 1) != -1) { //fprintf(stderr,"Matches my base call\n"); update_messages(1); // Force an update } } /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the message out on the TNC -FG */ if (operate_as_an_igate>1 && last_ack_sent != (time_t)-1l && from==DATA_VIA_NET // && !is_my_call(call,1) // Check SSID also && !from_my_call // Check SSID also // && !is_my_call(addr,1) // Check SSID also && !to_my_call // Check SSID also && port != -1) // Not from a log file { char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n", // operate_as_an_igate, // from, // my_callsign, // call, // addr); shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), // "}%s>%s,TCPIP,%s*::%s:%s{%s", "}%s>%s,TCPIP,%s*::%s:%s", call, short_path, my_callsign, addr9, message_plus_acks); // message, // orig_msg_id); if (reply_ack) // For debugging, so we only have reply-ack { // messages and acks scrolling across the screen. // fprintf(stderr,"Attempting to send message to RF: %s\n", ipacket_message); } output_igate_rf(call, addr, path, ipacket_message, port, third_party, NULL); igate_msgs_tx++; } done = 1; } if (debug_level & 1) { fprintf(stderr,"7\n"); } //-------------------------------------------------------------------------- if (!done) // message without line number { long record_out; time_t last_ack_sent; if (debug_level & 4) { fprintf(stderr,"found Msg: |%s| |%s|\n",addr,message); } //found Msg: |WE7U-13| |?APRSD| //found Msg: |WE7U-14| |Directs=| last_ack_sent = msg_data_add(addr, call, message, "", MESSAGE_MESSAGE, from, &record_out); new_message_data++; // ?????? // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record_out == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 3\n"); if (check_popup_window(addr, 1) != -1) { //update_messages(1); // Force an update } } // Could be response to a query. Popup a message. // Check addr for my_call and !third_party, then check later in the // packet for my_call if it is a third_party message? Depends on // what the packet looks like by this point. if ( last_ack_sent != (time_t)-1l && (message[0] != '?') // && is_my_call(addr,1) ) { // Check SSID also && to_my_call ) // Check SSID also { // We no longer wish to have both popups and the Send // Group Message dialogs come up for every query // response, so we use popup_message() here instead of // popup_message_always() so that by default we'll see // the below message in STDERR. If --with-errorpopups // has been configured in, we'll get a popup as well. // Send Group Message dialogs work well for multi-line // query responses, so we'll leave it that way. // popup_message(langcode("POPEM00018"),message); // Check for Reply/Ack. APRS+ sends an AA: response back // for auto-reply, with an embedded free-ride Ack. if (strlen(ack_string) != 0) // Have an extra ack to deal with { clear_acked_message(call,addr,ack_string); // got an ACK for me msg_record_ack(call,addr,ack_string,0,0); // Record the ack for this message } } // done = 1; } if (debug_level & 1) { fprintf(stderr,"9\n"); } //-------------------------------------------------------------------------- if (ok) (void)data_add(STATION_CALL_DATA, call, path, message, from, port, NULL, third_party, 0, // Not a packet from my station 0); // Not my object/item if (debug_level & 1) { fprintf(stderr,"decode_message: finish\n"); } return(ok); } /* * UI-View format messages, not relevant for APRS, format is not specified in APRS Reference * * This function is not currently called anywhere in the code. */ int decode_UI_message(char *call,char *path,char *message,char from,int port,int third_party) { char *temp_ptr; char from_call[MAX_CALLSIGN+1]; char ack[20]; char addr[9+1]; int ok, len; char msg_id[5+1]; int done; int from_my_call = 0; int to_my_call = 0; if (is_my_call(call, 1) ) // Check SSID also { from_my_call++; } // I'm not sure, but I think they use 2 digit line numbers only // extract addr from path substr(addr,path,9); ok = (int)(strlen(addr) > 0); if (ok) { temp_ptr = strstr(addr,","); // look for end of first call if (temp_ptr != NULL) { temp_ptr[0] = '\0'; // adjust addr end } ok = (int)(strlen(addr) > 0); } if (is_my_call(addr, 1) ) // Check SSID also { to_my_call++; } len = (int)strlen(message); ok = (int)(len >= 2); if (ok) { temp_ptr = strstr(message,"~"); // look for message ID msg_id[0] = '\0'; if (temp_ptr != NULL) { substr(msg_id,temp_ptr+1,2); // extract message ID, could be non-digit temp_ptr[0] = '\0'; // adjust message end } done = 0; } else { done = 1; // fall through... } len = (int)strlen(message); //-------------------------------------------------------------------------- // Callsign check here checks SSID as well // if (!done && msg_id[0] != '\0' && is_my_call(addr,1)) { // message for me if (!done && msg_id[0] != '\0' && to_my_call) // message for me { time_t last_ack_sent; long record; last_ack_sent = msg_data_add(addr, call, message, msg_id, MESSAGE_MESSAGE, from, &record); new_message_data += 1; // Note that the check_popup_window() function will // re-create a Send Message dialog if one doesn't exist for // this QSO. Only call it for the first message line or the // first ack, not for any repeats. // if (last_ack_sent == (time_t)0l && record == -1l) // Msg we've never received before { //fprintf(stderr,"***check_popup_window 4\n"); (void)check_popup_window(call, 2); //update_messages(1); // Force an update } if (last_ack_sent != (time_t)-1l) { if (sound_play_new_message) { play_sound(sound_command,sound_new_message); } // Only send an ack or autoresponse once per 30 seconds if ( (from != 'F') && ( (last_ack_sent + 30) < sec_now()) ) { //fprintf(stderr,"Sending ack: %ld %ld %ld\n",last_ack_sent,sec_now(),record); // Record the fact that we're sending an ack now msg_update_ack_stamp(record); pad_callsign(from_call,call); /* ack the message */ xastir_snprintf(ack, sizeof(ack), ":%s:ack%s",from_call,msg_id); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(call,ack,NULL); if (auto_reply == 1) { char temp[300]; xastir_snprintf(temp, sizeof(temp), "AA:%s", auto_reply_message); if (debug_level & 2) fprintf(stderr,"Send autoreply to <%s> from <%s> :%s\n", call, my_callsign, temp); // if (!is_my_call(call,1)) // Check SSID also if (!from_my_call) // Check SSID also { output_message(my_callsign, call, temp, ""); } } } } done = 1; } //-------------------------------------------------------------------------- if (!done && len == 2 && msg_id[0] == '\0') // ACK { substr(msg_id,message,5); // if (is_my_call(addr,1)) { // Check SSID also if (to_my_call) // Check SSID also { clear_acked_message(call,addr,msg_id); // got an ACK for me msg_record_ack(call,addr,msg_id,0,0); // Record the ack for this message } // else { // ACK for other station /* Now if I have Igate on and I allow to retransmit station data */ /* check if this message is to a person I have heard on my TNC within an X */ /* time frame. If if is a station I heard and all the conditions are ok */ /* spit the ACK out on the TNC -FG */ //// if (operate_as_an_igate>1 && from==DATA_VIA_NET && !is_my_call(call,1)) { // if (operate_as_an_igate>1 && from==DATA_VIA_NET && !from_my_call) { // char short_path[100]; //fprintf(stderr,"Igate check o:%d f:%c myc:%s cf:%s ct:%s\n",operate_as_an_igate,from,my_callsign,call,addr); { // shorten_path(path,short_path,sizeof(short_path)); //sprintf(ipacket_message,"}%s>%s:%s:%s",call,path,addr9,message); // sprintf(ipacket_message,"}%s>%s,TCPIP,%s*::%s:%s",call,short_path,my_callsign,addr9,message); // output_igate_rf(call,addr,path,ipacket_message,port,third_party,NULL); // igate_msgs_tx++; // } // } done = 1; } //-------------------------------------------------------------------------- if (ok) { (void)data_add(STATION_CALL_DATA, call, path, message, from, port, NULL, third_party, 0, // Not a packet from my station 0); // Not my object/item } return(ok); } /* * Decode APRS Information Field and dispatch it depending on the Data Type ID * * call = Callsign or object/item name string * path = Path string * message = Info field (corrupted already if object/item packet) * origin = Originating callsign if object/item, otherwise NULL * from = DATA_VIA_LOCAL/DATA_VIA_TNC/DATA_VIA_NET/DATA_VIA_FILE * port = Port number * third_party = Set to one if third-party packet * orig_message = Unmodified info field * */ void decode_info_field(char *call, char *path, char *message, char *origin, char from, int port, int third_party, char *orig_message) { char line[MAX_LINE_SIZE+1]; int ok_igate_net; int ok_igate_rf; int done, ignore; char data_id; int station_is_mine = 0; int object_is_mine = 0; char user_base_dir[MAX_VALUE]; /* remember fixed format starts with ! and can be up to 24 chars in the message */ // ??? if (debug_level & 1) { fprintf(stderr,"decode_info_field: c:%s p:%s m:%s f:%c o:%s\n",call,path,message,from,origin); } if (debug_level & 1) { fprintf(stderr,"decode_info_field: Past check\n"); } done = 0; // if 1, packet was decoded ignore = 0; // if 1, don't treat undecoded packets as status text ok_igate_net = 0; // if 1, send packet to internet ok_igate_rf = 0; // if 1, igate packet to RF if "from" is in nws-stations.txt if ( is_my_call(call, 1) ) { station_is_mine++; // Station is controlled by me } if ( (message != NULL) && (strlen(message) > MAX_LINE_SIZE) ) // Overly long message, throw it away. { if (debug_level & 1) { fprintf(stderr,"decode_info_field: Overly long message. Throwing it away.\n"); } done = 1; } else if (message == NULL || strlen(message) == 0) // we could have an empty message { (void)data_add(STATION_CALL_DATA,call,path,NULL,from,port,origin,third_party, station_is_mine, 0); done = 1; // don't report it to internet } // special treatment for objects/items. if (!done && origin[0] != '\0') { // If station/object/item is owned by me (including SSID) if ( is_my_call(origin, 1) ) { object_is_mine++; } if (message[0] == '*') // set object { (void)data_add(APRS_OBJECT,call,path,message+1,from,port,origin,third_party, station_is_mine, object_is_mine); if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } else if (message[0] == '!') // set item { (void)data_add(APRS_ITEM,call,path,message+1,from,port,origin,third_party, station_is_mine, object_is_mine); if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } else if (message[0] == '_') // delete object/item { DataRow *p_station; delete_object(call); // ?? does not vanish from map immediately !!??? // If object was owned by me but another station is // transmitting it now, write entries into the // object.log file showing that we don't own this object // anymore. p_station = NULL; if (search_station_name(&p_station,call,1)) { // if ( (is_my_call(p_station->origin,1)) // If station was owned by me (including SSID) // && (!is_my_call(origin,1)) ) { // But isn't now if (is_my_object_item(p_station) // If station was owned by me (including SSID) && (!object_is_mine) ) // But isn't now { disown_object_item(call,origin); } } if (strlen(origin) > 0 && strncmp(origin,"INET",4)!=0) { ok_igate_net = 1; // report it to internet } ok_igate_rf = 1; done = 1; } } if (!done) { data_id = message[0]; // look at the APRS Data Type ID (first char in information field) message += 1; // extract data ID from information field ok_igate_net = 1; // as default report packet to internet if (debug_level & 1) { if (ok_igate_net) { fprintf(stderr,"decode_info_field: ok_igate_net can be read\n"); } } switch (data_id) { case '=': // Position without timestamp (with APRS messaging) if (debug_level & 1) { fprintf(stderr,"decode_info_field: = (position w/o timestamp)\n"); } //WE7U // Need to check for weather info in this packet type as well? done = data_add(APRS_MSGCAP,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '!': // Position without timestamp (no APRS messaging) or Ultimeter 2000 WX if (debug_level & 1) { fprintf(stderr,"decode_info_field: ! (position w/o timestamp or Ultimeter 2000 WX)\n"); } if (message[0] == '!' && is_xnum_or_dash(message+1,40)) // Ultimeter 2000 WX { done = data_add(APRS_WX3,call,path,message+1,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_FIXED,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '/': // Position with timestamp (no APRS messaging) if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (position w/timestamp)\n"); } //WE7U // Need weather decode in this section similar to the '@' section // below. if ((toupper(message[14]) == 'N' || toupper(message[14]) == 'S') && (toupper(message[24]) == 'W' || toupper(message[24]) == 'E')) // uncompressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (uncompressed position w/timestamp no messaging)\n"); } if (message[29] == '/') { if (message[33] == 'g' && message[37] == 't') { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else // compressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: / (compressed position w/timestamp no messaging)\n"); } if (message[16] >= '!' && message[16] <= 'z') // csT is speed/course { if (message[20] == 'g' && message[24] == 't') // Wx data { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } // done = data_add(APRS_DOWN,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '@': // Position with timestamp (with APRS messaging) // DK7IN: could we need to test the message length first? if ((toupper(message[14]) == 'N' || toupper(message[14]) == 'S') && (toupper(message[24]) == 'W' || toupper(message[24]) == 'E')) // uncompressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: @ (uncompressed position w/timestamp)\n"); } if (message[29] == '/') { if (message[33] == 'g' && message[37] == 't') { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else // compressed format { if (debug_level & 1) { fprintf(stderr,"decode_info_field: @ (compressed position w/timestamp)\n"); } if (message[16] >= '!' && message[16] <= 'z') // csT is speed/course { if (message[20] == 'g' && message[24] == 't') // Wx data { done = data_add(APRS_WX1,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { done = data_add(APRS_MOBILE,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } else { done = data_add(APRS_DF,call,path,message,from,port,origin,third_party, station_is_mine, 0); } } ok_igate_rf = done; break; case '[': // Maidenhead grid locator beacon (obsolete- but used for meteor scatter) done = data_add(APRS_GRID,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case 0x27: // Mic-E Old GPS data (or current GPS data in Kenwood TM-D700) case 0x60: // Mic-E Current GPS data (but not used in Kennwood TM-D700) //case 0x1c:// Mic-E Current GPS data (Rev. 0 beta units only) //case 0x1d:// Mic-E Old GPS data (Rev. 0 beta units only) if (debug_level & 1) { fprintf(stderr,"decode_info_field: 0x27 or 0x60 (Mic-E)\n"); } done = decode_Mic_E(call,path,message,from,port,third_party); ok_igate_rf = done; break; case '_': // Positionless weather data [APRS Reference, chapter 12] if (debug_level & 1) { fprintf(stderr,"decode_info_field: _ (positionless wx data)\n"); } done = data_add(APRS_WX2,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '#': // Peet Bros U-II Weather Station (km/h) [APRS Reference, chapter 12] if (debug_level & 1) { fprintf(stderr,"decode_info_field: # (peet bros u-II wx station)\n"); } if (is_xnum_or_dash(message,13)) { done = data_add(APRS_WX4,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '*': // Peet Bros U-II Weather Station (mph) if (debug_level & 1) { fprintf(stderr,"decode_info_field: * (peet bros u-II wx station)\n"); } if (is_xnum_or_dash(message,13)) { done = data_add(APRS_WX6,call,path,message,from,port,origin,third_party, station_is_mine, 0); } ok_igate_rf = done; break; case '$': // Raw GPS data or Ultimeter 2000 if (debug_level & 1) { fprintf(stderr,"decode_info_field: $ (raw gps or ultimeter 2000)\n"); } if (strncmp("ULTW",message,4) == 0 && is_xnum_or_dash(message+4,44)) { done = data_add(APRS_WX5,call,path,message+4,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPGGA",message,5) == 0) { done = data_add(GPS_GGA,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPRMC",message,5) == 0) { done = data_add(GPS_RMC,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else if (strncmp("GPGLL",message,5) == 0) { done = data_add(GPS_GLL,call,path,message,from,port,origin,third_party, station_is_mine, 0); } else { // handle VTG and WPT too (APRS Ref p.25) } ok_igate_rf = done; break; case ':': // Message if (debug_level & 1) { fprintf(stderr,"decode_info_field: : (message)\n"); } // Do message logging if that feature is enabled. if (log_message_data && from != DATA_VIA_FILE) { char temp_msg[MAX_MESSAGE_LENGTH+1]; xastir_snprintf(temp_msg, sizeof(temp_msg), "%s>%s:%s", call, path, orig_message); log_data( get_user_base_dir(LOGFILE_MESSAGE, user_base_dir, sizeof(user_base_dir)), temp_msg ); } //fprintf(stderr,"Calling decode_message\n"); done = decode_message(call,path,message,from,port,third_party); //fprintf(stderr,"Back from decode_message\n"); // there could be messages I should not retransmit to internet... ??? Queries to me... break; case '>': // Status [APRS Reference, chapter 16] if (debug_level & 1) { fprintf(stderr,"decode_info_field: > (status)\n"); } done = data_add(APRS_STATUS,call,path,message,from,port,origin,third_party, station_is_mine, 0); ok_igate_rf = done; break; case '?': // Query if (debug_level & 1) { fprintf(stderr,"decode_info_field: ? (query)\n"); } done = process_query(call,path,message,from,port,third_party); ignore = 1; // don't treat undecoded packets as status text break; case 'T': // Telemetry data [APRS Reference, chapter 13] // We treat these as status packets currently. ok_igate_rf = 1; if (debug_level & 1) { fprintf(stderr,"decode_info_field: T (telem)\n"); } done = data_add(APRS_STATUS,call,path,message,from,port,origin,third_party, station_is_mine, 0); break; case '{': // User-defined APRS packet format //} // We treat these as status packets currently. ok_igate_rf = 1; break; case '<': // Station capabilities [APRS Reference, chapter 15] if (debug_level & 1) { fprintf(stderr,"decode_info_field: ~,<\n"); } // // We could tweak the Incoming Data dialog to add // filter togglebuttons. One such toggle could be // "Station Capabilities". We'd then have a usable // dialog for displaying things like ?IGATE? // responses. In this case we wouldn't have to do // anything special with the packet for decoding, // just let it hit the default block below for // putting them into the status field of the record. // One downside is that we'd only be able to catch // new station capability records in that dialog. // The only way to look at past capability records // would be the Station Info dialog for each // station. // //fprintf(stderr,"%10s: %s\n", call, message); // Don't set "done" as we want these to appear in // the status text for the record. break; case '%': // Agrelo DFJr / MicroFinder Radio Direction Finding if (debug_level & 1) { fprintf(stderr,"decode_info_field: %%\n"); } // Here is where we'd add a call to an RDF decode // function so that we could display vectors on the // map for each RDF position. // // Agrelo format: "%XXX/Q" // // "XXX" is relative bearing to the signal (000-359). Careful here: // At least one unit reports in magnetic instead of relative // degrees. "000" means no direction info available, 360 means true // north. // // "Q" is bearing quality (0-9). 0 = unsuitable. 9 = manually // entered. 1-8 = varying quality with 8 being the best. // // I've also seen these formats, which may not be Agrelo compatible: // // "%136.0/9" // "%136.0/8/158.0" (That last number is magnetic bearing) // // These sentences may be sent MULTIPLE times per second, like 20 or // more! If we decide to average readings, we'll need to dump our // averages and start over if our course changes. // // Check for Agrelo format: if ( strlen(message) >= 5 && is_num_chr(message[0]) // "%136/9" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '/' && is_num_chr(message[4]) ) { fprintf(stderr, "Type 1 RDF packet from call: %s\tBearing: %c%c%c\tQuality: %c\n", call, message[0], message[1], message[2], message[4]); } // Check for extended formats (not // Agrelo-compatible): else if (strlen(message) >= 13 && is_num_chr(message[0]) // "%136.0/8/158.0" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '.' && is_num_chr(message[4]) && message[5] == '/' && is_num_chr(message[6]) && message[7] == '/' && is_num_chr(message[8]) && is_num_chr(message[9]) && is_num_chr(message[10]) && message[11] == '.' && is_num_chr(message[12]) ) { fprintf(stderr, "Type 3 RDF packet from call: %s\tBearing: %c%c%c%c%c\tQuality: %c\tMag Bearing: %c%c%c%c%c\n", call, message[0], message[1], message[2], message[3], message[4], message[6], message[8], message[9], message[10], message[11], message[12]); } // Check for extended formats (not // Agrelo-compatible): else if (strlen(message) >= 7 && is_num_chr(message[0]) // "%136.0/9" && is_num_chr(message[1]) && is_num_chr(message[2]) && message[3] == '.' && is_num_chr(message[4]) && message[5] == '/' && is_num_chr(message[6]) ) { fprintf(stderr, "Type 2 RDF packet from call: %s\tBearing: %c%c%c%c%c\tQuality: %c\n", call, message[0], message[1], message[2], message[3], message[4], message[6]); } // Don't set "done" as we want these to appear in // the status text for the record until we get the // full decoding for this type of packet coded up. break; case '~': // UI-format messages, not relevant for APRS ("Do not use" in Reference) case ',': // Invalid data or test packets [APRS Reference, chapter 19] case '&': // Reserved -- Map Feature if (debug_level & 1) { fprintf(stderr,"decode_info_field: ~,&\n"); } ignore = 1; // Don't treat undecoded packets as status text break; } if (debug_level & 1) { if (done) { fprintf(stderr,"decode_info_field: done = 1\n"); } else { fprintf(stderr,"decode_info_field: done = 0\n"); } if (ok_igate_net) { fprintf(stderr,"decode_info_field: ok_igate_net can be read 2\n"); } } if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with big switch\n"); } // Add most remaining data to the station record as status // info // if (!done && !ignore) // Other Packets [APRS Reference, chapter 19] { done = data_add(OTHER_DATA,call,path,message-1,from,port,origin,third_party, station_is_mine, 0); if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with data_add(OTHER_DATA)\n"); } } if (!done) // data that we do ignore... { //fprintf(stderr,"decode_info_field: not decoding info: Call:%s ID:%c Msg:|%s|\n",call,data_id,message); ok_igate_net = 0; // don't put data on internet if (debug_level & 1) { fprintf(stderr,"decode_info_field: done with ignored data\n"); } } } if (third_party) { ok_igate_net = 0; // don't put third party traffic on internet } // if (is_my_call(call,1)) // Check SSID as well if (station_is_mine) { ok_igate_net = 0; // don't put my data on internet ??? } if (ok_igate_net) { if (debug_level & 1) { fprintf(stderr,"decode_info_field: ok_igate_net start\n"); } if ( (from == DATA_VIA_TNC) // Came in via a TNC && (strlen(orig_message) > 0) ) // Not empty { // Here's where we inject our own callsign like this: // "WE7U-15,I" in order to provide injection ID for our // igate. xastir_snprintf(line, sizeof(line), "%s>%s,%s,I:%s", (strlen(origin)) ? origin : call, path, my_callsign, orig_message); //fprintf(stderr,"decode_info_field: IGATE>NET %s\n",line); output_igate_net(line, port, third_party); } } // Attempt to gate to RF only if the following conditions are // met: // // *) ok_igate_rf flag is set. // *) Not my exact callsign. // *) Packet was from the INET, not local RF // *) The "from" call matches a line in data/nws-stations.txt, // verified by igate.c:check_NWS_stations(). // // The output_igate_rf() function will also do some checks on // the packet before allowing it to be igated, including a // dupe-check. // // Callsign check here checks SSID as well // if (ok_igate_rf && !is_my_call(call,1) && from == DATA_VIA_NET) { if (ok_igate_rf && !station_is_mine && from == DATA_VIA_NET) { char ipacket_message[300]; char short_path[100]; shorten_path(path,short_path,sizeof(short_path)); xastir_snprintf(ipacket_message, sizeof(ipacket_message), "}%s>%s,TCPIP,%s*:%s", (strlen(origin)) ? origin : call, short_path, my_callsign, orig_message); // If origin, pass "call" to output_igate_rf() as the last // parameter. This would be the object/item name. output_igate_rf((strlen(origin)) ? origin : call, (strlen(origin)) ? origin : call, path, ipacket_message, port, third_party, (strlen(origin)) ? call : NULL); //fprintf(stderr,"decode_info_field: IGATE>RF %s\n",ipacket_message); } if (debug_level & 1) { fprintf(stderr,"decode_info_field: done\n"); } } /* * Extract object or item data from information field before processing * * Returns 1 if valid object found, else returns 0. * */ int extract_object(char *call, char **info, char *origin) { int ok, i; // Object and Item Reports [APRS Reference, chapter 11] ok = 0; // todo: add station originator to database if ((*info)[0] == ';') // object { // fixed 9 character object name with any printable ASCII character if (strlen((*info)) > 1+9) { substr(call,(*info)+1,9); // extract object name (*info) = (*info) + 10; // Remove leading spaces ? They look bad, but are allowed by the APRS Reference ??? (void)remove_trailing_spaces(call); if (valid_object(call)) { // info length is at least 1 ok = 1; } } } else if ((*info)[0] == ')') // item { // 3 - 9 character item name with any printable ASCII character if (strlen((*info)) > 1+3) { for (i = 1; i <= 9; i++) { if ((*info)[i] == '!' || (*info)[i] == '_') { call[i-1] = '\0'; break; } call[i-1] = (*info)[i]; } call[9] = '\0'; // In case we never saw '!' || '_' (*info) = &(*info)[i]; // Remove leading spaces ? They look bad, but are allowed by the APRS Reference ??? //(void)remove_trailing_spaces(call); // This statement messed up our searching!!! Don't use it! if (valid_object(call)) { // info length is at least 1 ok = 1; } } } else { fprintf(stderr,"Not an object, nor an item!!! call=%s, info=%s, origin=%s.\n", call, *info, origin); } return(ok); } /* * Extract third-party traffic from information field before processing */ int extract_third_party(char *call, char *path, int path_size, char **info, char *origin, int origin_size) { int ok; char *p_call; char *p_path; p_call = NULL; // to make the compiler happy... p_path = NULL; // to make the compiler happy... ok = 0; if (!is_my_call(call,1)) // Check SSID also { // todo: add reporting station call to database ?? // but only if not identical to reported call (*info) = (*info) +1; // strip '}' character p_call = strtok((*info),">"); // extract call if (p_call != NULL) { p_path = strtok(NULL,":"); // extract path if (p_path != NULL) { (*info) = strtok(NULL,""); // rest is information field if ((*info) != NULL) // the above looks dangerous, but works on same string if (strlen(p_path) < 100) { ok = 1; // we have found all three components } } } } if ((debug_level & 1) && !ok) { fprintf(stderr,"extract_third_party: invalid format from %s\n",call); } if (ok) { xastir_snprintf(path, path_size, "%s", p_path); ok = valid_path(path); // check the path and convert it to TAPR format // Note that valid_path() also removes igate injection identifiers if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", path); makePrintable(filtered_data); fprintf(stderr,"extract_third_party: invalid path: %s\n",filtered_data); } } if (ok) // check callsign { (void)remove_trailing_asterisk(p_call); // is an asterisk valid here ??? if (valid_inet_name(p_call,(*info),origin,origin_size)) // accept some of the names used in internet { // Treat it as object with special origin xastir_snprintf(call, MAX_CALLSIGN+1, "%s", p_call); } else if (valid_call(p_call)) // accept real AX.25 calls { xastir_snprintf(call, MAX_CALLSIGN+1, "%s", p_call); } else { ok = 0; if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", p_call); makePrintable(filtered_data); fprintf(stderr,"extract_third_party: invalid call: %s\n",filtered_data); } } } return(ok); } /* * Extract text inserted by TNC X-1J4 from start of info line */ void extract_TNC_text(char *info) { int i,j,len; if (strncasecmp(info,"thenet ",7) == 0) // 1st match { len = strlen(info)-1; for (i=7; i7 && info[i] == ')' && info[i+1] == ' ') // found { i += 2; for (j=0; i<=len; i++,j++) { info[j] = info[i]; } } } } //WE7U2 // We feed a raw 7-byte string into this routine. It decodes the // callsign-SSID and tells us whether there are more callsigns after // this. If the "asterisk" input parameter is nonzero it'll add an // asterisk to the callsign if it has been digipeated. This // function is called by the decode_ax25_header() function. // // Inputs: string Raw input string // asterisk 1 = add "digipeated" asterisk // // Outputs: callsign Processed string // returned int 1=more callsigns follow, 0=end of address field // int decode_ax25_address(char *string, char *callsign, int asterisk) { int i,j; char ssid; char t; int more = 0; int digipeated = 0; // Shift each of the six callsign characters right one bit to // convert to ASCII. We also get rid of the extra spaces here. j = 0; for (i = 0; i < 6; i++) { t = ((unsigned char)string[i] >> 1) & 0x7f; if (t != ' ') { callsign[j++] = t; } } // Snag out the SSID byte to play with. We need more than just // the 4 SSID bits out of it. ssid = (unsigned char)string[6]; // Check the digipeat bit if ( (ssid & 0x80) && asterisk) { digipeated++; // Has been digipeated } // Check whether it is the end of the address field if ( !(ssid & 0x01) ) { more++; // More callsigns to come after this one } // Snag the four SSID bits ssid = (ssid >> 1) & 0x0f; // Construct the SSID number and add it to the end of the // callsign if non-zero. If it's zero we don't add it. if (ssid) { callsign[j++] = '-'; if (ssid > 9) { callsign[j++] = '1'; } ssid = ssid % 10; callsign[j++] = '0' + ssid; } // Add an asterisk if the packet has been digipeated through // this callsign if (digipeated) { callsign[j++] = '*'; } // Terminate the string callsign[j] = '\0'; return(more); } // Function which receives raw AX.25 packets from a KISS interface and // converts them to a printable TAPR-2 (more or less) style string. // We receive the packet with a KISS Frame End character at the // beginning and a "\0" character at the end. We can end up with // multiple asterisks, one for each callsign that the packet was // digipeated through. A few other TNC's put out this same sort of // format. // // Note about KISS & CRC's: The TNC checks the CRC. If bad, it // drops the packet. If good, it sends it to the computer WITHOUT // the CRC bytes. There's no way at the computer end to check // whether the packet was corrupted over the serial channel between // the TNC and the computer. Upon sending a KISS packet to the TNC, // the TNC itself adds the CRC bytes back on before sending it over // the air. In Xastir we can just assume that we're getting // error-free packets from the TNC, ignoring possible corruption // over the serial line. // // Some versions of KISS can encode the radio channel (for // multi-port TNC's) in the command byte. How do we know we're // running those versions of KISS though? Here are the KISS // variants that I've been able to discover to date: // // KISS No CRC, one radio port // // SMACK 16-bit CRC, multiport TNC's // // KISS-CRC // // 6-PACK // // KISS Multi-drop (Kantronics) 8-bit XOR Checksum, multiport TNC's (AGWPE compatible) // BPQKISS (Multi-drop) 8-bit XOR Checksum, multiport TNC's // XKISS (Kantronics) 8-bit XOR Checksum, multiport TNC's // // JKISS (AGWPE and BPQ32 compatible) // // MKISS Linux driver which supports KISS/BPQ and // hardware handshaking? Also Paccomm command to // immediately enter KISS mode. // // FlexKISS -, // FlexCRC -|-- These are all the same! // RMNC-KISS -| // CRC-RMNC -' // // // It appears that none of the above protocols implement any form of // hardware flow control. // // // Compare this function with interface.c:process_ax25_packet() to // see if we're missing anything important. // // // Inputs: data_string Raw string (must be MAX_LINE_SIZE or bigger) // length Length of raw string (may get changed here) // // Outputs: int 0 if it is a bad packet, // 1 if it is good // data_string Processed string // int decode_ax25_header(unsigned char *data_string, int *length) { char temp[20]; char result[MAX_LINE_SIZE+100]; char dest[15]; int i, ptr; char callsign[15]; char more; char num_digis = 0; // Do we have a string at all? if (data_string == NULL) { return(0); } // Drop the packet if it is too long. Note that for KISS packets // we can't use strlen() as there can be 0x00 bytes in the // data itself. if (*length > 1024) { data_string[0] = '\0'; *length = 0; return(0); } // Start with an empty string for the result result[0] = '\0'; ptr = 0; // Process the destination address for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 0); // No asterisk xastir_snprintf(dest,sizeof(dest),"%s",callsign); // Process the source address for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 0); // No asterisk // Store the two callsigns we have into "result" in the correct // order xastir_snprintf(result,sizeof(result),"%s>%s",callsign,dest); // Process the digipeater addresses (if any) num_digis = 0; while (more && num_digis < 8) { for (i = 0; i < 7; i++) { temp[i] = data_string[ptr++]; } temp[7] = '\0'; more = decode_ax25_address(temp, callsign, 1); // Add asterisk strncat(result, ",", sizeof(result) - 1 - strlen(result)); strncat(result, callsign, sizeof(result) - 1 - strlen(result)); num_digis++; } strncat(result, ":", sizeof(result) - 1 - strlen(result)); // Check the Control and PID bytes and toss packets that are // AX.25 connect/disconnect or information packets. We only // want to process UI packets in Xastir. // Control byte should be 0x03 (UI Frame). Strip the poll-bit // from the PID byte before doing the comparison. if ( (data_string[ptr++] & (~0x10)) != 0x03) { return(0); } // PID byte should be 0xf0 (normal AX.25 text) if (data_string[ptr++] != 0xf0) { return(0); } // WE7U: We get multiple concatenated KISS packets sometimes. Look // for that here and flag when it happens (so we know about it and // can fix it someplace earlier in the process). Correct the // current packet so we don't get the extra garbage tacked onto the // end. for (i = ptr; i < *length; i++) { if (data_string[i] == KISS_FEND) { fprintf(stderr,"***Found concatenated KISS packets:***\n"); data_string[i] = '\0'; // Truncate the string break; } } // Add the Info field to the decoded header info strncat(result, (char *)(&data_string[ptr]), sizeof(result) - 1 - strlen(result)); // Copy the result onto the top of the input data. Note that // the length can sometimes be longer than the input string, so // we can't just use the "length" variable here or we'll // truncate our string. Make sure the data_string variable is // MAX_LINE_SIZE or bigger. // memcpy(data_string, result, MAX_LINE_SIZE); data_string[MAX_LINE_SIZE-1] = '\0'; // Terminate string // Write out the new length *length = strlen(result); //fprintf(stderr,"%s\n",data_string); return(1); } // RELAY the packet back out onto RF if received on a port with // digipeat enabled and the packet header has a non-digipeated RELAY // or my_callsign entry. This is for AX.25 kernel networking ports // or Serial KISS TNC ports only: Regular serial TNC's have these // features enabled/disabled through the startup/shutdown files. // // Adding asterisks: // Keep whatever digipeated fields have already been set. If // there's a "RELAY", "WIDE1-1", or "my_callsign" entry that hasn't // been digipeated yet, change it to "my_callsign*". // // This might be much easier to code into the routine that first // receives the packet (for Serial KISS TNC's). There we'd have // access to every digipeated bit directly instead of parsing // asterisks out of a string. // // NOTE: We don't handle this case properly: Multiple // RELAY's/WIDE1-1's or my_callsign's in the path, where one of the // earlier matching callsigns has been digipeated, but a later one // has not. We'll find the first matching callsign and the last // digi, and we won't relay the packet. This probably won't happen // much in the real world. // // We could also do preemptive digipeating here and skip over // callsigns that haven't been digipeated yet. Should we set the // digipeated bits on everything before it? Probably. Either that // or remove the callsigns ahead of it in the list that weren't // digipeated. // void relay_digipeat(char *call, char *path, char *info, int port) { char new_path[110+1]; char new_digi[MAX_CALLSIGN+2]; // Need extra for '*' storage int ii, jj; int done; char destination[MAX_CALLSIGN+1]; #define MAX_RELAY_SUBSTRINGS 10 char *Substring[MAX_RELAY_SUBSTRINGS]; // Pointers to substrings parsed by split_string() // Pointers to all of the possible calls we with to digipeat by char *Relay_Calls[MAX_RELAY_DIGIPEATER_CALLS]; char temp_string[MAX_LINE_SIZE+1]; // Check whether transmits are disabled globally if (transmit_disable) { return; } // Check whether relay_digipeat has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].relay_digipeat != 1) { return; } // Check whether transmit has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].transmit_data != 1) { return; } // Check for the only four types of interfaces where we might // want to do RELAY digipeating. If not one of these, go // bye-bye. if ( (devices[port].device_type != DEVICE_SERIAL_KISS_TNC) && (devices[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (devices[port].device_type != DEVICE_AX25_TNC) && (devices[port].device_type != DEVICE_NET_AGWPE) ) { return; } // Check to see if this is my own transmitted packet (in some // cases you get your own packets back from interfaces) if (!strcasecmp(call, my_callsign)) { //fprintf(stderr,"relay_digipeat: packet was mine, don't digipeat it!\n"); return; } // Make a copy of the incoming path. The string passed to // split_string() gets destroyed. xastir_snprintf(temp_string, sizeof(temp_string), "%s", path); split_string(temp_string, Substring, MAX_RELAY_SUBSTRINGS, ','); // Each element in the path is now pointed to by a char ptr in // the Substring array. If a NULL is found in the array, that's // the end of the path. if (Substring[0] == NULL) { // Something's wrong! Couldn't find anything in the path // string, not even a destination callsign? //fprintf(stderr, "\t\tNo path: %s\n", path); return; } else // Save the destination callsign away { xastir_snprintf(destination, sizeof(destination), "%s", Substring[0]); //fprintf(stderr,"Destination: %s\n",destination); } // We'll skip the first call in the path (pointed to by // Substring[0]) in the loops below. That's the destination // call and we don't want to look for RELAY or my_callsign // there. // Check to see if we just ran out of path if (Substring[1] == NULL) // No digipeaters listed { //fprintf(stderr,"relay_digipeat: ran out of path, don't digipeat it!\n"); //fprintf(stderr, "\t\tNo digi's listed: %s\n", path); return; } //fprintf(stderr," Path: %s\n",path); // We could also loop through the array and dump them out until // we hit a NULL if necessary. // Find the first digipeater callsign _after_ any digis that // have asterisks. Run through the array in reverse, looking // for the digi callsign with an asterisk after it that's // closest to the end of the path. ii = MAX_RELAY_SUBSTRINGS - 1; done = 0; while (!done && ii > 0) { if (Substring[ii] != NULL) { if (strstr(Substring[ii],"*")) { ii++; // Found an asterisk: Used digi. Point to // the digi _after_ this one. done++; // We found what we're looking for! } else // No asterisk found yet. { ii--; } } else // No filled-in digipeater field found yet. { ii--; } } if (ii == 0) // No asterisks found. Entire path unused? { // Set ii to first actual digi field instead of the // destination callsign. ii = 1; } else // ii points to first unused digi field. { } if (Substring[ii] == NULL) // No unused digi's found. { // We're done here. //fprintf(stderr, "\t\tPath used up: %s\n", path); return; } //fprintf(stderr,"\t\tUnused digi: %s\tPath: %s\n", Substring[ii], path); // Split the relay digipeater calls into separate substrings. // Split on comma delimiters. We get rid of extra spaces at the // point where we read the string in from the config file // (xa_config.c), so spaces between the calls are ok (but not // tabs). split_string(relay_digipeater_calls, Relay_Calls, MAX_RELAY_DIGIPEATER_CALLS, ','); // Check for match against my_callsign in this digipeater slot done = 0; if (strcmp(Substring[ii], my_callsign) == 0) { // It's our callsign. Digipeat using this call slot. done++; } else // Not my_callsign. Check every non-empty string in { // Relay_Calls[] for a match. jj = 0; while (!done && jj < MAX_RELAY_DIGIPEATER_CALLS) { // Check for ending conditions if (Relay_Calls[jj] == NULL || Relay_Calls[jj][0] == '\0') { // We hit the end of the array of possible // digipeater calls and had no match. Exit from // this routine as we're not going to digipeat on // this callsign slot. // Later we could add the option of "preemptive digipeating", where // we look further down the path for a possible match. We're not // doing that now. // fprintf(stderr,"End of Relay_Calls array: %d\n",jj); return; } // If we made it to here, we should have a valid // digipeater callsign in the Relay_Calls[jj] slot to // compare against. if (debug_level & 1) { fprintf(stderr,"\tComparing %s to %s\n", Substring[ii], Relay_Calls[jj]); } if (strcmp(Substring[ii], Relay_Calls[jj]) == 0) { done++; // fprintf(stderr,"match, done++\n"); } else { jj++; // fprintf(stderr,"incrementing jj: %d\n", jj); } } } if (!done) { // No valid digipeating callsign found in this slot, exit // this routine as we're not going to digipeat this packet. return; } /* OLD CODE: // Check for RELAY, WIDE1-1 (the new relay) or my_callsign in // this digipeater slot. If none of these found then exit this // routine. if ( (strcmp(Substring[ii], "RELAY") != 0) && (strcmp(Substring[ii], "WIDE1-1") != 0) && (strcmp(Substring[ii], my_callsign) != 0) ) { // Some other callsign found in this digi field. Don't // relay the packet. //fprintf(stderr,"Not relay, wide1-1, or %s, skipping\n", my_callsign); return; } */ // Ok, we made it! We have RELAY, WIDE1-1, or my_callsign that // hasn't been digipeated through, and we wish to change that // fact. Put in our callsign for all three cases and add an // asterisk to the end of the call. Also had to fix up the KISS // transmit routine so that it'll set the digipeated bit for // each callsign that has an asterisk. // Construct the new digi call, with the trailing asterisk xastir_snprintf(new_digi, sizeof(new_digi), "%s*", my_callsign); Substring[ii] = new_digi; // Point to new digi string instead of old //fprintf(stderr,"*** new_digi: %s\tSubstring: %s\n", // new_digi, // Substring[ii]); // Construct the new path, substituting the correct portion. // Start with the first digi and a comma: xastir_snprintf(new_path, sizeof(new_path), "%s,", Substring[1]); ii = 2; while ( (Substring[ii] != NULL) && (ii < MAX_RELAY_SUBSTRINGS) ) { strncat(new_path, Substring[ii], sizeof(new_path) - 1 - strlen(new_path)); ii++; if (Substring[ii] != NULL) // Add a comma if more to come strncat(new_path, ",", sizeof(new_path) - 1 - strlen(new_path)); } //fprintf(stderr,"*** New Path: %s,%s\n", destination, new_path); if ( (devices[port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { #ifdef SERIAL_KISS_RELAY_DIGI // fprintf(stderr,"KISS RELAY short_path: %s\n", short_path); // fprintf(stderr,"KISS RELAY new_path: %s\n", new_path); send_ax25_frame(port, call, destination, new_path, info); #endif } else if (devices[port].device_type == DEVICE_AX25_TNC) { char header_txt[MAX_LINE_SIZE+5]; //fprintf(stderr,"AX25 RELAY new_path: %s\n", new_path); // set from call xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s\r", '\3', "MYCALL", call); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // set path xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", destination, new_path); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // set converse mode xastir_snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', "CONV"); if (port_data[port].status == DEVICE_UP) { port_write_string(port, header_txt); } // send packet if (port_data[port].status == DEVICE_UP) { port_write_string(port, info); } } else if (devices[port].device_type == DEVICE_NET_AGWPE) { send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string), // AGWPE RadioPort '\0', // Type of frame (data) (unsigned char *)call, // source (unsigned char *)destination, // destination (unsigned char *)new_path, // Path, (unsigned char *)info, strlen(info)); } } /* * Decode AX.25 line * \r and \n should already be stripped from end of line * line should not be NULL * * If dbadd is set, add to database. Otherwise, just return true/false * to indicate whether input is valid AX25 line. */ // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // int decode_ax25_line(char *line, char from, int port, int dbadd) { char *call_sign; char *path0; char path[100+1]; // new one, we may add an '*' char *info; char info_copy[MAX_LINE_SIZE+1]; char call[MAX_CALLSIGN+1]; char origin[MAX_CALLSIGN+1]; int ok; int third_party; char backup[MAX_LINE_SIZE+1]; char tmp_line[MAX_LINE_SIZE+1]; char tmp_line2[630]; char tmp_path[100+1]; char *ViaCalls[10]; // Check guard band around pointers. Make sure it's pristine. if ( check_guard_band() ) { fprintf(stderr, "WARNING: Guard band around global pointers was corrupted!\n"); } xastir_snprintf(backup, sizeof(backup), "%s", line); // This is a good one to enable for debugging without getting too // many other types of messages to the xterm. It will enable the // block below. //#define WE7U_DEBUG #ifndef WE7U_DEBUG if (debug_level & 1) #endif { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", line); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: start parsing %s\n", filtered_data); } if (line == NULL) { fprintf(stderr,"decode_ax25_line: line == NULL.\n"); return(FALSE); } if ( (line != NULL) && (strlen(line) > MAX_LINE_SIZE) ) // Overly long message, throw it away. We're done. { if (debug_level & 1) { fprintf(stderr,"\ndecode_ax25_line: LONG packet. Dumping it:\n%s\n",line); } return(FALSE); } if (line[strlen(line)-1] == '\n') // better: look at other places, // so that we don't get it here... { line[strlen(line)-1] = '\0'; // Wipe out '\n', to be sure } if (line[strlen(line)-1] == '\r') { line[strlen(line)-1] = '\0'; // Wipe out '\r' } call_sign = NULL; path0 = NULL; info = NULL; origin[0] = '\0'; call[0] = '\0'; path[0] = '\0'; third_party = 0; // CALL>PATH:APRS-INFO-FIELD // split line into components // ^ ^ ok = 0; call_sign = strtok(line,">"); // extract call from AX.25 line if (call_sign != NULL) { path0 = strtok(NULL,":"); // extract path from AX.25 line if (path0 != NULL) { info = strtok(NULL,""); // rest is info_field if (info != NULL) { if ((info - path0) < 100) // check if path could be copied { ok = 1; // we have found all three components } } } } if (ok) { xastir_snprintf(path, sizeof(path), "%s", path0); memset(info_copy, '\0', sizeof(info_copy)); xastir_snprintf(info_copy, sizeof(info_copy), "%s", info); ok = valid_path(path); // check the path and convert it to TAPR format // Note that valid_path() also removes igate injection identifiers if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", path); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: invalid path: %s\n",filtered_data); } } if (ok) { // If it's not me transmitting it: if (strcmp(my_callsign,call_sign) != 0) { // Check for "EMERGENCY" anywhere in the line. // APRS+SA also supports any of these in the TO: field: // // EMERGENCY // ALARM // ALERT // WARNING // WXALARM // EM // // Snag just the TO: field from the path, used for most of the // comparisons below. It will be pointed to by ViaCalls[0]; xastir_snprintf(tmp_path, // Make a temporary backup sizeof(tmp_path), "%s", path); split_string(tmp_path, ViaCalls, 10, ','); if ( (strstr(backup, "EMERGENCY")) // Checks entire line || (strcmp(ViaCalls[0], "ALARM") == 0) // Checks to_field || (strcmp(ViaCalls[0], "ALERT") == 0) // Checks to_field || (strcmp(ViaCalls[0], "WARNING") == 0) // Checks to_field || (strcmp(ViaCalls[0], "WXALARM") == 0) // Checks to_field || (strcmp(ViaCalls[0], "EM") == 0) ) // Checks to_field { double distance; // miles or km char course_deg[5]; // EMERGENCY if (emergency_distance_check) { distance = distance_from_my_station(call_sign, course_deg, english_units); // Because of the distance check we have to receive a valid position // from the station BEFORE we process the EMERGENCY portion and // check distance, doing the popups. We need to figure out a way to // throw the packet back into the queue if it was an emergency // packet so that we process these packets twice each. That way // only one packet from the emergency station is required to // generate the popups. if (distance == 0.0) { process_emergency_packet_again++; } // Check whether the station is near enough to // us to require that we alert on the packet. // // This may be slightly controversial, but if we // don't know WHERE a station is, we can't help // much in an emergency, can we? The // zero-distance check helps in the case where // we haven't yet or never get a position packet // for a station. As soon as we have a position // and it is within a reasonable range, we do // our emergency popups. // if ( distance != 0.0 && (float)distance <= emergency_range ) { // Do the conversion for emergency_range to mi or km as needed. // if (english_units) { // } // else { // } // Do a popup to alert the operator to this // condition. Make sure we haven't popped // up an emergency message for this station // within the last 30 minutes. If we pop // these up constantly it gets quite // annoying. if ( (strncmp(call_sign, last_emergency_callsign, strlen(call_sign)) != 0) || ((last_emergency_time + 60*30) < sec_now()) ) { char temp[50]; char temp2[150]; char temp3[300]; char timestring[101]; // Callsign is different or enough time // has passed last_emergency_time = sec_now(); xastir_snprintf(last_emergency_callsign, sizeof(last_emergency_callsign), "%s", call_sign); // Bring up the Find Station dialog so // that the operator can go to the // location quickly. xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", call_sign); Locate_station( (Widget)NULL, (XtPointer)NULL, (XtPointer)1 ); // Bring up an additional popup dialog // that shows the entire packet, so the // user can make a determination as to // whether the packet is or is not a // real emergency. // popup_message_always(langcode("POPEM00036"), backup); // Bring up another dialog with the // callsign plus distance/bearing to the // station. xastir_snprintf(temp, sizeof(temp), "%0.1f", distance); xastir_snprintf(temp2, sizeof(temp2), langcode("WPUPSTI022"), temp, course_deg); get_timestamp(timestring); xastir_snprintf(temp3, sizeof(temp3), "%s %s", timestring, temp2); popup_message_always(call_sign, temp3); } } } } } } if (ok) { // Attempt to digipeat this packet if we should. If port=-2, // we received this packet from the x_spider server and we // should not attempt to digipeat it. If port=-1, it's from // a log file. Again, don't digipeat it. if (port >= 0) { relay_digipeat(call_sign, path, info, port); } extract_TNC_text(info); // extract leading text from TNC X-1J4 if (strlen(info) > 256) // first check if information field conforms to APRS specs { ok = 0; // drop packets too long } if ((debug_level & 1) && !ok) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", info); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: info field too long: %s\n",filtered_data); } } if (ok) // check callsign { (void)remove_trailing_asterisk(call_sign); // is an asterisk valid here ??? if (valid_inet_name(call_sign,info,origin,sizeof(origin))) // accept some of the names used in internet { xastir_snprintf(call, sizeof(call), "%s", call_sign); } else if (valid_call(call_sign)) // accept real AX.25 calls { xastir_snprintf(call, sizeof(call), "%s", call_sign); } else { ok = 0; if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE + 1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call_sign); makePrintable(filtered_data); fprintf(stderr,"decode_ax25_line: invalid call: %s\n",filtered_data); } } } if (!dbadd) { if (debug_level & 1) { fprintf(stderr,"decode_ax25_line: exiting\n"); } return(ok); } if (ok && info[0] == '}') // look for third-party traffic { ok = extract_third_party(call,path,sizeof(path),&info,origin,sizeof(origin)); // extract third-party data third_party = 1; // Add it to the HEARD queue for this interface. We use this // for igating purposes. If some other igate beat us to this // packet, we don't want to duplicate it over the air. If // port=-2, we received it from the x_spider server and we // should not save it in the queue. If port=-1, the packet // came from a log file and again we shouldn't save it to // the queue. if (port >= 0) { insert_into_heard_queue(port, backup); } } if (ok && (info[0] == ';' || info[0] == ')')) // look for objects or items { xastir_snprintf(origin, sizeof(origin), "%s", call); ok = extract_object(call,&info,origin); // extract object data } if (ok) { // decode APRS information field, always called with valid call and path // info is a string with 0 - 256 bytes // fprintf(stderr,"dec: %s (%s) %s\n",call,origin,info); if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+80]; sprintf(filtered_data, "Registering data %s %s %s %s %c %d %d", call, path, info, origin, from, port, third_party); makePrintable(filtered_data); fprintf(stderr,"c/p/i/o fr pt tp: %s\n", filtered_data); } decode_info_field(call, path, info, origin, from, port, third_party, info_copy); } if (port == -2) // We received this packet from an x_spider { // server. We need to dump it out all of our // transmit-enabled ports. // If the string starts with "user" or "pass", it's an // authentication string. We need to send those through as // well so that the user gets logged into the internet // server and can send/receive packets/messages. We also // dump it to our console so that we can see who logged in // to us. if (strncasecmp(line,"user",4) == 0 || strncasecmp(line,"pass",4) == 0 || strncasecmp(line,"filter",6) == 0) { fprintf(stderr,"\tLogged on: %s\n", line); // If the line has a "filter" parameter in it, we need to remove it, // else a client may change our filtering parameters. Perhaps we // should skip the authentication stuff as well, as the servers // might get confused if we pass two different authentications on // the same socket? } else if (strlen(line) > 0) // Not empty { // Send the packet unchanged out all of our // transmit-enabled ports. We should send it as // third-party igated packets if we're sending to // servers, send it unchanged if sending through TNC? //fprintf(stderr,"Retransmitting x_spider packet: %s\n", line); // Here's where we inject our own callsign like this: // "WE7U-15,I" in order to provide injection ID for our // igate. xastir_snprintf(tmp_line2, sizeof(tmp_line2), "%s>%s,%s,I:%s", call_sign, path, my_callsign, info_copy); memcpy(tmp_line, tmp_line2, sizeof(tmp_line)); tmp_line[sizeof(tmp_line)-1] = '\0'; // Terminate line //fprintf(stderr,"decode_ax25_line: IGATE>NET %s\n",tmp_line); //fprintf(stderr,"call: %s\tcall_sign: %s\n", call, call_sign); output_igate_net(tmp_line, port, 0); // 0="not third-party" } } // EMERGENCY // For emergency packets we need to process them twice, to try // to get a position before we do the distance check. // // This causes an infinite loop on packets that don't have a // distance! Disabling it for now. if (process_emergency_packet_again) { process_emergency_packet_again = 0; //fprintf(stderr,"Again: %s\n", backup); // decode_ax25_line(backup, from, port, dbadd); } if (debug_level & 1) { fprintf(stderr,"decode_ax25_line: exiting\n"); } return(ok); } /* * Read a line from file. We use this to read in log files and to * read in findu track files. For findu track files we need to get * rid of the
at the end of the lines, else it shows up in our * comment lines in Station_info. */ void read_file_line(FILE *f) { char line[MAX_LINE_SIZE+1]; char cin; int pos; pos = 0; line[0] = '\0'; while (!feof(f)) { if (fread(&cin,1,1,f) == 1) { if (cin != (char)10 && cin != (char)13) // normal characters { if (pos < MAX_LINE_SIZE) { line[pos++] = cin; } } else // CR or LF { if (cin == (char)10) // Found LF as EOL char { char *ptr; line[pos] = '\0'; // Always add a terminating zero after last char pos = 0; // start next line // Get rid of
HTML tag at end of line here. // Findu track files have them. ptr = strstr(line, "
"); if (ptr) // Found one of them { *ptr = '\0'; // Terminate the line at that point } // Save backup copies of this string and the // previous string. Used for debugging // purposes. If we get a segfault, we can print // out the last two messages received. memcpy(incoming_data_copy_previous, incoming_data_copy, MAX_LINE_SIZE); incoming_data_copy_previous[MAX_LINE_SIZE-1] = '\0'; // Terminate string memcpy(incoming_data_copy, line, MAX_LINE_SIZE); incoming_data_copy[MAX_LINE_SIZE-1] = '\0'; // Terminate string if (line[0] != '#') { decode_ax25_line(line,'F',-1, 1); // Decode the packet } return; // only read line by line } } } } if (feof(f)) // Close file if at the end { (void)fclose(f); read_file = 0; statusline(langcode("BBARSTA012"),0); // File done.. redraw_on_new_data = 2; // redraw immediately after finish } } /* * Look for other stations that the tracked one has gotten close to. * and speak a proximity warning. * TODO: * - sort matches by distance * - set upper bound on number of matches so we don't speak forever * - use different proximity distances for different station types? * - look for proximity to embedded map objects */ void search_tracked_station(DataRow **p_tracked) { DataRow *t = (*p_tracked); DataRow *curr = NULL; if (debug_level & 1) { char lat[20],lon[20]; convert_lat_l2s(t->coord_lat, lat, sizeof(lat), CONVERT_HP_NORMAL); convert_lon_l2s(t->coord_lon, lon, sizeof(lat), CONVERT_HP_NORMAL); fprintf(stderr,"Searching for stations close to tracked station %s at %s %s ...\n", t->call_sign,lat,lon); } while (next_station_time(&curr)) { if (curr != t && curr->flag&ST_ACTIVE) { float distance; // Distance in whatever measurement // units we're currently using. char bearing[10]; char station_id[600]; distance = (float)calc_distance_course(t->coord_lat, t->coord_lon, curr->coord_lat, curr->coord_lon, bearing, sizeof(bearing)) * cvt_kn2len; if (debug_level & 1) fprintf(stderr,"Looking at %s: distance %.3f bearing %s (%s)\n", curr->call_sign,distance,bearing,convert_bearing_to_name(bearing,1)); /* check ranges (copied from earlier prox alert code, above) */ if ((distance > atof(prox_min)) && (distance < atof(prox_max))) { if (debug_level & 1) { fprintf(stderr," tracked station is near %s!\n",curr->call_sign); } if (sound_play_prox_message) { sprintf(station_id,"%s < %.3f %s from %s",t->call_sign, distance, english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), curr->call_sign); statusline(station_id,0); play_sound(sound_command,sound_prox_message); } #ifdef HAVE_FESTIVAL if (festival_speak_tracked_proximity_alert) { if (english_units) { if (distance < 1.0) sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance * 1760), langcode("SPCHSTR004"), convert_bearing_to_name(bearing,1), curr->call_sign); else if ((int)((distance * 10) + 0.5) % 10) sprintf(station_id, langcode("SPCHSTR008"), t->call_sign, distance, langcode("SPCHSTR003"), convert_bearing_to_name(bearing,1), curr->call_sign); else sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance + 0.5), langcode("SPCHSTR003"), convert_bearing_to_name(bearing,1), curr->call_sign); } else /* metric */ { if (distance < 1.0) sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance * 1000), langcode("SPCHSTR002"), convert_bearing_to_name(bearing,1), curr->call_sign); else if ((int)((distance * 10) + 0.5) % 10) sprintf(station_id, langcode("SPCHSTR008"), t->call_sign, distance, langcode("SPCHSTR001"), convert_bearing_to_name(bearing,1), curr->call_sign); else sprintf(station_id, langcode("SPCHSTR007"), t->call_sign, (int)(distance + 0.5), langcode("SPCHSTR001"), convert_bearing_to_name(bearing,1), curr->call_sign); } if (debug_level & 1) { fprintf(stderr," %s\n",station_id); } SayText(station_id); } #endif /* HAVE_FESTIVAL */ } } } // end of while } // ******************************************************************** // calc aloha_distance() // calculate and return alhoa circle radius in current distance units // The ALOHA radius is computed according to the algorithm described by // Bob Bruninga at http://web.usna.navy.mil/~bruninga/aprs/ALOHAcir.txt // with some clarification provided py private email. // // The gist of it is that we grab a list of all stations heard via TNC // and sort it b distance from our station. We then accumulate a // count of how many theoretical packets would be introduced into the local // area in 30 minutes from these stations, and stop when we hit 1800 // (the supposed limit of the channel capacity). The distance to the last // station we counted is our ALOHA limit. Per Bob B., this should be plotted // on the map as a circle with no user-selectable way of turning it off. // double calc_aloha_distance(void) { DataRow *p_station = n_first; // walk in alphabetical order aloha_entry *aloha_array; aloha_entry *temp_aloha_array; int num_aloha_alloc=1000; int num_aloha_entries=0; int digi_copies=1; char temp[10]; // needed for course_deg argument of // distance_from_my_station int sum; double distance; int ii; // This should be enough, though we'll realloc if necessary aloha_array = (aloha_entry *)malloc (num_aloha_alloc*sizeof(aloha_entry)); CHECKMALLOC(aloha_array); // We need a list of all stations that were heard via tnc: while (p_station != NULL) { if (num_aloha_entries == num_aloha_alloc) { num_aloha_alloc *= 2; temp_aloha_array=realloc(aloha_array,num_aloha_alloc); if (temp_aloha_array) { aloha_array=temp_aloha_array; } else { fprintf(stderr,"***** Realloc failed *****\n"); exit(1); } } if ( (p_station->flag & ST_VIATNC) != 0 && (p_station->flag & ST_ACTIVE) != 0 ) { if (position_defined(p_station->coord_lat,p_station->coord_lon,1)) { xastir_snprintf(aloha_array[num_aloha_entries].call_sign, MAX_CALLSIGN+1, "%s", p_station->call_sign); aloha_array[num_aloha_entries].is_digi = aloha_array[num_aloha_entries].is_mobile = aloha_array[num_aloha_entries].is_other_mobile = aloha_array[num_aloha_entries].is_home = aloha_array[num_aloha_entries].is_wx = (char) FALSE; aloha_array[num_aloha_entries].distance = distance_from_my_station(p_station->call_sign,temp, english_units); if ( p_station->newest_trackpoint != NULL && strlen(p_station->speed) > 0) { // If the station has a track and a speed of any value // (even zero), it's a mobile. aloha_array[num_aloha_entries].is_mobile = (char) TRUE; } else if ( (p_station->aprs_symbol.aprs_type=='/' && (strchr("'<=>()*0COPRSUXY[^abefgjkpsuv", p_station->aprs_symbol.aprs_symbol) != NULL)) || (p_station->aprs_symbol.aprs_type=='\\' && (strchr("/0>AKOS^knsuv", p_station->aprs_symbol.aprs_symbol) != NULL))) { // // Per private email exchange with Bob Bruninga: // If the station has one of these symbols, // it's "other mobile" // these are also listed on // web.usna.navy.mil/~bruninga/aprs/aprs11.html // aloha_array[num_aloha_entries].is_other_mobile =(char)TRUE; } else if ( p_station-> record_type == APRS_WX1 || p_station-> record_type == APRS_WX2 || p_station-> record_type == APRS_WX3 || p_station-> record_type == APRS_WX4 || p_station-> record_type == APRS_WX5 || p_station-> record_type == APRS_WX6 || p_station-> aprs_symbol.aprs_symbol=='_') { // Bob B. uses the station symbol "_" to select this, but // agrees that if we do it this way it's probably better // -- this says if we've gotten any WX data, it's a WX // station aloha_array[num_aloha_entries].is_wx = (char) TRUE; } else if (p_station->aprs_symbol.aprs_symbol=='#') { // Per Bob B., if it has "#" as its symbol, it's // assumed to be a digi. aloha_array[num_aloha_entries].is_digi = (char) TRUE; } else { // Anything that hasn't gotten selected yet is just a home aloha_array[num_aloha_entries].is_home = (char) TRUE; } num_aloha_entries++; } } p_station = p_station-> n_next; } if (debug_level & 2048) { fprintf (stderr,"aloha_distance: Found %d local stations\n", num_aloha_entries); } // we now have all the stations heard via TNC. Now sort it by distance qsort((void *) aloha_array,num_aloha_entries,sizeof(aloha_entry), comp_by_dist); // Starting from the closest, working outward, accumulate sum=0; the_aloha_stats.digis=0; the_aloha_stats.wxs = 0; the_aloha_stats.other_mobiles = 0; the_aloha_stats.mobiles_in_motion = 0; the_aloha_stats.homes = 0; the_aloha_stats.total = 0; for (ii=0; (ii0 && ii < num_aloha_entries && sum >= 1800) // we hit the limit { distance = aloha_array[ii-1].distance; } else { distance = -1; // indeterminate, not enough data yet } free (aloha_array); // make sure we don't leak return distance; } // Used by qsort to sort the aloha entries int comp_by_dist(const void *av,const void *bv) { aloha_entry *a = (aloha_entry *) av; aloha_entry *b = (aloha_entry *) bv; if (a->distance < b->distance) { return -1; } if (a->distance > b->distance) { return 1; } return 0; } // Called periodically by UpdateTime, we calculate our aloha radius every // so often. (Bob B. recommends every 30 minutes) void calc_aloha(int secs_now) { char status_text[100]; if (aloha_time == 0) // first call { aloha_time = secs_now+ALOHA_CALC_INTERVAL; aloha_status_time = secs_now+ALOHA_STATUS_INTERVAL; aloha_radius = -1.0; // Debug: Let's us play with/display aloha circles right away: //aloha_radius = 40.0; // Miles the_aloha_stats.digis=0; the_aloha_stats.wxs = 0; the_aloha_stats.other_mobiles = 0; the_aloha_stats.mobiles_in_motion = 0; the_aloha_stats.homes = 0; the_aloha_stats.total = 0; //fprintf(stderr,"Initialized aloha radius time\n"); } else { if (secs_now > aloha_time) { aloha_radius = calc_aloha_distance(); aloha_time = secs_now + ALOHA_CALC_INTERVAL; if (debug_level & 2048) { if (aloha_radius < 0) { fprintf(stderr,"Aloha distance indeterminate\n"); } else { fprintf(stderr,"Aloha distance is %f",aloha_radius); if (english_units) { fprintf(stderr," miles.\n"); } else { fprintf(stderr," km.\n"); } } } } if (secs_now > aloha_status_time) { if ( aloha_radius != -1 ) { xastir_snprintf(status_text, sizeof(status_text), langcode("BBARSTA044"), (english_units) ? (int)aloha_radius : (int)(aloha_radius * cvt_mi2len), (english_units) ? " miles" : " km"); statusline(status_text,1); } aloha_status_time = secs_now + ALOHA_STATUS_INTERVAL; } } } // Debugging tool: // Check to see if time list contains any stations older than remove_time. // If the expire code did its job properly, there should be none. If there // are none, we return NULL. If there are any, we return the pointer to the // last one found (which should be the newest of them by virtue of how we // walk the list). DataRow * sanity_check_time_list(time_t remove_time) { DataRow *p_station, *p_station_t_newer, *retval; retval=NULL; for (p_station = t_oldest; p_station != NULL; p_station = p_station_t_newer) { p_station_t_newer = p_station->t_newer; // Don't count my station in this. if (!is_my_station(p_station) && p_station->sec_heard < remove_time) { retval=p_station; } } return (retval); } // Debugging tool // dump out the entire time-sorted list starting from oldest and proceeding // to newest void dump_time_sorted_list(void) { DataRow *p_station, *p_station_t_newer; struct tm *time; fprintf(stderr,"\tTime-sorted list dump \n"); fprintf(stderr, "\t Call Sign:\tsec_heard\tdate/time\n"); for (p_station = t_oldest; p_station != NULL; p_station = p_station_t_newer) { p_station_t_newer = p_station->t_newer; time = localtime(&p_station->sec_heard); fprintf(stderr,"\t%s\t%ld\t%02d/%02d %02d:%02d:%02d\n", p_station->call_sign, (long int) p_station->sec_heard, time->tm_mon+1,time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); } } /* * Keep track of last six digis that echo my transmission */ void upd_echo(char *path) { int i,j,len; if (echo_digis[5][0] != '\0') { for (i=0; i<5; i++) { xastir_snprintf(echo_digis[i], MAX_CALLSIGN+1, "%s", echo_digis[i+1]); } echo_digis[5][0] = '\0'; } for (i=0,j=0; i < (int)strlen(path); i++) { if (path[i] == '*') { break; } if (path[i] == ',') { j=i; } } if (j > 0) { j++; // first char of call } if (i > 0 && i-j <= 9) { len = i-j; for (i=0; i<5; i++) // look for free entry { if (echo_digis[i][0] == '\0') { break; } } substr(echo_digis[i],path+j,len); } } Xastir-Release-2.2.4/src/db_funcs.h0000664000175000017500000001441015151324131016044 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Note: this file should be called db.h, but was renamed to db_funcs.h * to avoid conflicts with the Berkeley DB package. */ #ifndef XASTIR_DB_FUNCS_H #define XASTIR_DB_FUNCS_H #include #include #include "database.h" // These don't seem to be used // extern void clean_data_file(void); //extern void mem_display(void); //extern void sort_display_file(char *filename, int size); //extern unsigned long max_stations; extern void db_init(void); extern int is_my_call(char *call, int exact); extern int is_my_station(DataRow *p_station); extern int is_my_object_item(DataRow *p_station); extern int is_tracked_station(char *call_sign); extern char *get_most_recent_ack(char *callsign); extern void init_message_data(void); extern int message_update_time(void); extern void msg_record_ack(char *to_call_sign, char *my_call, char *seq, int timeout, int cancel); extern void msg_record_interval_tries(char *to_call_sign, char *my_call, char *seq, time_t interval, int tries); extern time_t msg_data_add(char *call_sign, char *from_call, char *data, char *seq, char type, char from, long *record_out); extern void update_messages(int force); extern void mdelete_messages_from(char *from); extern void mdelete_messages_to(char *to); extern void check_message_remove(time_t curr_sec); void mscan_file(char msg_type, void (*function)(Message *fill)); extern void mdisplay_file(char msg_type); extern void pad_callsign(char *callsignout, char *callsignin); extern void clear_sort_file(char *filename); extern long sort_input_database(char *filename, char *fill, int size); int is_altnet(DataRow *p_station); int ok_to_draw_station(DataRow *p_station); extern int heard_via_tnc_in_past_hour(char *call); extern int get_weather_record(DataRow *fill); extern int store_trail_point(DataRow *p_station, long lon, long lat, time_t sec, char *alt, char *speed, char *course, short stn_flag); void expire_trail_points(DataRow *p_station, time_t sec); extern int delete_trail(DataRow *fill); void export_trail(DataRow *p_station); extern void export_trail_as_kml(DataRow *p_station); // export trail of one or all stations to kml file extern void init_station_data(void); extern int search_station_name(DataRow **p_name, char *call, int exact); extern int search_station_time(DataRow **p_time, time_t heard, int serial); extern int next_station_name(DataRow **p_curr); extern int prev_station_name(DataRow **p_curr); extern int next_station_time(DataRow **p_curr); extern int prev_station_time(DataRow **p_curr); extern void setup_in_view(void); extern void station_del(char *callsign); extern void delete_all_stations(void); extern void check_station_remove(time_t curr_sec); extern void my_station_add(char *my_call_sign, char my_group, char my_symbol, char *my_long, char *my_lat, char *my_phg, char *my_comment, char my_amb); extern void my_station_gps_change(char *pos_long, char *pos_lat, char *course, char *speed, char speedu, char *alt, char *sats); extern void packet_data_add(char *from, char *line, int data_port); extern void display_packet_data(void); extern int decode_ax25_header(unsigned char *data_string, int *length); extern int decode_ax25_line(char *line, char from, int port, int dbadd); extern void read_file_line(FILE *f); extern void search_tracked_station(DataRow **p_tracked); double calc_aloha_distance(void); //meat int comp_by_dist(const void *,const void *);// used only for qsort void calc_aloha(int curr_sec); // periodic function void dump_time_sorted_list(void); #ifdef DATA_DEBUG extern void clear_data(DataRow *clear); extern void copy_data(DataRow *to, DataRow *from); #else // DATA_DEBUG #define clear_data(clear) memset((DataRow *)clear, 0, sizeof(DataRow)) #define copy_data(to, from) memmove((DataRow *)to, (DataRow *)from, \ sizeof(DataRow)) #endif /* DATA_DEBUG */ DataRow * sanity_check_time_list(time_t); // used only for debugging ///////////////////////////////////////// Global variables extern int redraw_on_new_packet_data; extern int new_message_data; extern CADRow *CAD_list_head; extern int station_data_auto_update; extern int fcc_lookup_pushed; extern int rac_lookup_pushed; // calculate every half hour, display in status line every 5 minutes #define ALOHA_CALC_INTERVAL 1800 #define ALOHA_STATUS_INTERVAL 300 extern time_t aloha_time; extern time_t aloha_status_time; extern double aloha_radius; // in miles extern aloha_stats the_aloha_stats; // stations extern int st_direct_timeout; // Interval that ST_DIRECT flag stays set extern int station_count; // Count of stations in the database extern int station_count_save; // Old copy of the above extern DataRow *n_first; // pointer to first element in name ordered station // list extern DataRow *n_last; // pointer to last element in name ordered station // list extern DataRow *t_oldest; // pointer to first element in time ordered station // list extern DataRow *t_newest; // pointer to last element in time ordered station // objects/items extern time_t last_object_check; // array to hold the list of digipeaters that have echoed the station extern char echo_digis[6][MAX_CALLSIGN+1]; // function to update echo_digis extern void upd_echo(char *path); #endif Xastir-Release-2.2.4/src/db_gis.c0000664000175000017500000033612615151324131015516 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // include postgresql library for postgis support #ifdef HAVE_POSTGIS #include // pg_type.h contains constants for OID values to use in paramTypes arrays // in prepared queries. #include #endif // HAVE_POSTGIS // mysql error library for mysql error code constants #ifdef HAVE_MYSQL #include #include #include #include #include #endif // HAVE_MYSQL #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H // Some systems don't have strtof #ifndef HAVE_STRTOF #define strtof(a,b) atof(a) #endif #include "snprintf.h" #include #include #include #include #include #include #include "database.h" #include "main.h" #include "util.h" #include "xastir.h" #include "db_gis.h" #ifdef HAVE_DB /* db_gis.c * * Functions supporting connections to databases, including GIS enabled * databases that hold OpenGIS objects and can apply spatial indices. * * XASTIR GIS database code is separated into three layers * * 1) Supporting XASTIR logic (ui elements, cad integration, * map drawing, etc). * 2a) Generic db storage/retrieval code - wrappers for layer 3 * 2b) Connection management code * 3a) DBMS specific db storage/retrieval code for spatial databases * 3b) DBMS specific db storage/retrieval code for non-spatial databases * * Data structures in an underlying database can be considered as a fourth * level. * * Code for layers 2 and 3 is in this file. * * Layer 2 functions should be extern and called from elsewhere to * perform spatial database operations. Xastir shouldn't need to care * if an underlying database has spatial support or not for simple data. * Some functionality might require spatial object support and might be * included only if a spatial database is available. Thus 3b code may only * support a subset of the 2a functions, while 3a code should support all * 2a functions. * Layer 2a wrappers should take and return values in xastir coordinates, * and convert them to decimal degrees to pass on to layer 3. Likewise * return values from layer 3 to layer 2a should be in decimal degrees, * limiting the number of different places at which the xastir/decimal * degree conversion code needs to be invoked. This would not be true if * data are fed directly from decimal degree feeds into the database, so * there may also be a need for layer 2 functions that deal only with * latitude and longitude in decimal degrees. * * Layer 3 functions should not be extern and should only be called * by layer 2 functions from within this file. * Layer 3 functions should take and return values in decimal degrees. * Xastir objects should be passed down into layer 3, as doing * so should make code easier to maintain (but harder to extend) than using * generic structures for transport of data between layers 2 and 3. * Passing a station struct from layer 2 to 3 makes layer 2 a very simple * wrapper, but requires new layer 3 code to write station data to a map * layer rather than to a DataRow (to, for example, prepare a layer of * temperature data at points for analysis and generation of a temperature * grid.) [Using generic structures for transport would let the layer 3 * code remain unchanged while layer 2 functions are added or extended, but * requires added maintenance to synchronise xastir structs, the generic * structs, and database structures.] * * A spatially enabled database is expected to support OpenGIS spatial * objects and be able to apply spatial indices to the data. A * non-spatially enabled database is expected to hold coordinates using * separate fields for latitude and longitude. Layer 3 functions that * interact with a spatial database will need to convert decimal degrees * to well known text (WKT, and perhaps also well known binary, WKB) * representations. Layer 3 functions that interact with non-spatially * enabled databases can just pass raw latitudes and longitudes. * * All spatial data are expected to be in WGS84 projection EPSG:4326 * * Support for five sets of underlying database schema elements is envisioned * - a very simple station at point and time table * - schema elements to support CAD objects with arbitrary associated data * tables. * - a schema capable of holding the full range of aprs data using spatial * elements (Points, Polygons, etc). * - full support for APRSWorld tables (using latitude and longitude fields * rather than spatial elements). * - arbitrary tables with schema discovery for arbitrary GIS databases * such as Tiger data. * The first three of these will require schema version awareness and will * produce compatibility/database lifecycle issues. * * Descriptions of how to make connections to databases are stored in * connection descriptors. Connection descriptors describe the DBMS, whether * the database has/lacks spatial support, the schema type (simple, * simple+cad, xastir full, APRSWorld, etc for the database, and connection * parameters (server, user, database). The layer 2/3 separation is intended * to allow functions (layer 2) to be called from within xastir (layer 1) * without the need to test which function to call for which dbms. Some * functions may be schema specific, others may be able to use any of * several different schemas. Connections can be opened from a database * descriptor, and more than one descriptor can point to the same database. * (Thus a single MySQL database may contain simple xastir tables, xastir * CAD object tables, and APRSWorld tables, but two different descriptors * would be used to define connections to talk to the APRSWorld tables and * the simple+cad tables within what MySQL considers one schema. A given * version of xastir will expect a particular version or range of versions * for database schemas - an older version of xastir may expect fields that * no longer exist in a database created for a newer version of xastir and * vice versa. * * Data selected from a spatial database might be brought into xastir as * stations just like an internet feed or findu fetch trail query, as * editable CAD objects, or as map layers. */ /******************* DATABASE SUPPORT IS EXPERIMENTAL ***********************/ /**************** CODE IN THIS FILE MAY CHANGE AT ANY TIME ******************/ // Layer 3 declarations // xastir_dbms_type is used in interface_gui.c to set up cb_items to populate // database picklist. Define and internationalise here. char xastir_dbms_type[4][XASTIR_DB_DESCRIPTOR_MAX_SIZE+1] = {"","MySQL (lat/long)","Postgresql/Postgis","MySQL Spatial"} ; // xastir_schema_type is used in interface_gui.c to set up cb_item to populate // schema type picklist Sql_Database_schema_type_data. Define and internationalize here. char xastir_schema_type[5][XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE+1] = {"","Xastir Simple","Xastir CAD","Xastir Full","APRSWorld"} ; const char *POSTGIS_TIMEFORMAT = "%Y-%m-%d %H:%M:%S%z"; const char *MYSQL_TIMEFORMAT = "%Y-%m-%d %H:%M:%S"; /* // store integer values for picklist items, but use localized strings on picklists char xastir_dbms_type[3][XASTIR_DB_DESCRIPTOR_MAX_SIZE+1]; // array of xastir database type strings xastir_snprintf(&xastir_dbms_type[DB_MYSQL][0], XASTIR_DB_DESCRIPTOR_MAX_SIZE, "%s",langcode("XADBMST001")); xastir_snprintf(&xastir_dbms_type[DB_POSTGIS][0], sizeof(&xastir_dbms_type[DB_POSTGIS][0]), "%s", langcode("XADBMST002")); xastir_snprintf(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], sizeof(&xastir_dbms_type[DB_MYSQL_SPATIAL][0]), "%s",langcode("XADBMST003")); char xastir_schema_type[4][XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE+1]; // array of xastir schema type strings xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_SIMPLE], sizeof(xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0]), "%s",langcode ("XASCHEMA01")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_CAD][0], sizeof(xastir_schema_type[XASTIR_SCHEMA_CAD][0]), "%s", langcode("XASCHEMA02")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_COMPLEX][0], sizeof(xastir_schema_type[XASTIR_SCHEMA_COMPLEX][0]), "%s", langcode("XASCHEMA03")); xastir_snprintf(xastir_schema_type[XASTIR_SCHEMA_APRSWORLD], sizeof(xastir_schema_type[XASTIR_SCHEMA_APRSWORLD][0]), "%s", langcode("XASCHEMA04")); */ #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS int storeStationToGisDbPostgis(Connection *aDbConnection, DataRow *aStation); int storeCadToGisDbPostgis(Connection *aDbConnection, CADRow *aCadObject); int storeStationSimplePointToGisDbPostgis(Connection *aDbConnection, DataRow *aStation); int testXastirVersionPostgis(Connection *aDbConnection); int getAllSimplePositionsPostgis(Connection *aDbConnection); int getAllSimplePositionsPostgisInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat); //PGconn postgres_conn_struct[MAX_DB_CONNECTIONS]; #endif /* HAVE_POSTGIS*/ #ifdef HAVE_MYSQL_SPATIAL int storeStationToGisDbMysql(Connection *aDbConnection, DataRow *aStation); int storeCadToGisDbMysql(Connection *aDbConnection, CADRow *aCadObject); int storeStationSimplePointToGisDbMysql(Connection *aDbConnection, DataRow *aStation); int getAllSimplePositionsMysqlSpatial(Connection *aDbConnection); int getAllCadFromGisDbMysql(Connection *aDbConnection); int getAllSimplePositionsMysqlSpatialInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat); #endif /* HAVE_MYSQL_SPATIAL */ #endif /* HAVE_SPATIAL_DB */ //Connection connection_struc[MAX_DB_CONNECTIONS]; Connection connections[MAX_IFACE_DEVICES]; int connections_initialized = 0; #ifdef HAVE_MYSQL //MYSQL mysql_conn_struct, *mysql_connection = &mysql_conn_struct; //MYSQL mcs[MAX_DB_CONNECTIONS]; Connection dbc_struct, *dbc = &dbc_struct; int testXastirVersionMysql(Connection *aDbConnection); int storeStationSimplePointToDbMysql(Connection *aDbConnection, DataRow *aStation); int getAllSimplePositionsMysql(Connection *aDbConnection); int getAllSimplePositionsMysqlInBoundingBox(Connection *aDbConnection, char *str_e_long, char *str_w_long, char *str_n_lat, char *str_s_lat); int storeStationToDbMysql(Connection *aDbConnection, DataRow *aStation); void mysql_interpret_error(int errorcode, Connection *aDbConnection); #endif /* HAVE_MYSQL*/ // Layer 2a: Generic GIS db storage code. ************************************ // Wrapper functions for actual DBMS specific actions #ifdef HAVE_SPATIAL_DB // ******** Functions that require spatialy enabled database support ********* /* function storeStationToGisDb() * Stores the information about a station and its most recent position * to a spatial database. * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } // This function is dbms agnostic, and hands the call off to a // function for the relevant database type. That function picks the // relevant schema and either handles the query or passes it on to // a function to handle that schema. switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = storeStationToGisDbPostgis(aDbConnection, aStation); break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = storeStationToGisDbMysql(aDbConnection, aStation); break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = storeStationToDbMysql(aDbConnection, aStation); break; #endif /* HAVE_MYSQL*/ } return returnvalue; } /* function storeCadToGisDb() * Stores current data about objects (including CAD objects) and their * most recent positions to a spatial database. Objects are treated as * points */ int storeCadToGisDb(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; if (aDbConnection==NULL || aCadObject==NULL) { return returnvalue; } // check that connection has cad support in schema return returnvalue; } /* function storeStationTrackToGisDb() * Stores information about a station and track of all received positions from * that station (including weather information if present) to a spatial * database. * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationTrackToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } return returnvalue; } #endif /* HAVE_SPATIAL_DB */ // ***** Functions that do not require spatialy enabled database support ****** // Include "Simple" in these function names. They should only deal with point // data, not polygons or complex spatial objects. Station positions and times // demarking implicit tracks should be ok. /* function storeStationSimpleToGisDb() * Stores basic information about a station and its most recent position * to a spatial database. Stores only callsign, most recent position, * and time. Intended for testing and simple logging uses. * Underlying table should have structure: * create table simpleStation ( * simpleStationId int primary key not null auto_increment * station varchar(9) not null, // max_callsign * time date not null default now(), * position POINT // or latitude float, longitude float for simple db. * ); **** or perhaps it should be an APRSWorld table?? **** **** or perhaps it should be an APRSWorld table, but with POINT when supported?? **** * * ********* generalize to lat/lon fields or position POINT. ****** * @param aDbConnection generic database connection to the database in * which the station information is to be stored. * @param aStation the station to store. * @returns 0 on failure, 1 on success. On failure, stores error message * in connection. */ int storeStationSimpleToGisDb(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; int triedDatabase = 0; if (debug_level & 4096) { fprintf(stderr,"in storeStationSimpleToGisDb() "); } if (aDbConnection==NULL || aStation==NULL) { return returnvalue; } if (aStation->data_via == DATA_VIA_DATABASE) { if (debug_level & 4096) { fprintf(stderr,"skipping station heard from Database\n"); } returnvalue = 1; return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"with connection->type: %d\n",aDbConnection->type); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = storeStationSimplePointToGisDbPostgis(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = storeStationSimplePointToGisDbMysql(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = storeStationSimplePointToDbMysql(aDbConnection, aStation); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } /* function getAllSimplePositions() * Given a database connection, return all simple station positions stored in * that database. */ int getAllSimplePositions(Connection *aDbConnection) { int returnvalue = 0; int triedDatabase = 0; if (aDbConnection==NULL) { return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"in getAllSimplePositions "); fprintf(stderr,"with aDbConnection->type %d\n",aDbConnection->type); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : //fprintf(stderr,"connection [%p]\n",aDbConnection); //fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); returnvalue = getAllSimplePositionsPostgis(aDbConnection); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = getAllSimplePositionsMysqlSpatial(aDbConnection); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = getAllSimplePositionsMysql(aDbConnection); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } /* function getAllSimplePositionsInBoundingBox() * Given a database connection and a bounding box, return all simple station * positions stored in that database that fall within the bounds of the box. * Takes eastern, western, northern, and southern bounds of box in xastir * coordinates. */ int getAllSimplePositionsInBoundingBox(Connection *aDbConnection, int east, int west, int north, int south) { int returnvalue = 0; int triedDatabase = 0; char str_e_long[11]; char str_n_lat[10]; char str_w_long[11]; char str_s_lat[10]; if (aDbConnection==NULL) { return returnvalue; } // convert from xastir coordinates to decimal degrees convert_lon_l2s(east, str_e_long, sizeof(str_e_long), CONVERT_DEC_DEG); convert_lat_l2s(north, str_n_lat, sizeof(str_n_lat), CONVERT_DEC_DEG); convert_lon_l2s(west, str_w_long, sizeof(str_w_long), CONVERT_DEC_DEG); convert_lat_l2s(south, str_s_lat, sizeof(str_s_lat), CONVERT_DEC_DEG); switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : returnvalue = getAllSimplePositionsPostgisInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : returnvalue = getAllSimplePositionsMysqlSpatialInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : returnvalue = getAllSimplePositionsMysqlInBoundingBox(aDbConnection,str_e_long,str_w_long,str_n_lat,str_s_lat); triedDatabase++; break; #endif /* HAVE_MYSQL*/ } if (triedDatabase==0) { } return returnvalue; } // Layer 2b: Connection management. ******************************************* /* It should be possible to maintain a list of an arbitrary number of defined * data sources of different types, and to have an arbitrary number of * connections to these data sources open at the same time. * * Some issues: How to handle login credentials for databases? Request on * connection? How to perform multiple operations with the same datasource * (e.g. logging to the database from feeds while querying CAD objects). * Probably want to be able to store password, request password on connect, * or use configuration file (e.g. my.ini) for password) - let user tune * choices to environment. * * The existing interface code seems better suited to having a fixed number * of interfaces with zero or one database connection associated with each * interface than handing an arbitrary number of connections per interface. */ // simple testing hardcoded database connection testing function // remove this function and call in main.c when integration with // interfaces is working. // fill in password, uncomment, and uncomment code in main.c for // simple database write test - writes station in n_first to simple mysql db /* ioparam simpleDbTest(void) { ioparam test; Connection conn; int ok; xastir_snprintf(test.device_name, sizeof(test.device_name), "Test Connection"); test.database_type = DB_MYSQL; xastir_snprintf(test.device_host_name, sizeof(test.device_host_name), "localhost"); test.sp = 3306; xastir_snprintf(test.database_username, sizeof(test.database_username), "xastir_test"); // hardcode a test password here for simple test xastir_snprintf(test.device_host_pswd, sizeof(test.device_host_pswd), "hardcoded test password"); xastir_snprintf(test.database_schema, sizeof(test.database_schema), "xastir"); test.database_schema_type = XASTIR_SCHEMA_SIMPLE; xastir_snprintf(test.database_unix_socket, sizeof(test.database_unix_socket), "/var/lib/mysql/mysql.sock"); got_conn=openConnection(&test, conn); ok = storeStationSimpleToGisDb(&conn, n_first); return test; } */ int initConnections() { int x; if (debug_level & 4096) { fprintf(stderr,"initConnections()\n"); } for (x=0; xdescriptor = &devices[x]; connection->type = 0; // assign no type by default connection->interface_number = x; // so we can reference port_data[] from a connection // without knowing the connection's position in // connections[] // malloc for the PGconn will cause segfault on trying to // open the connection #ifdef HAVE_POSTGIS connection->phandle = (PGconn*)malloc(sizeof(PGconn*)); #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL //connection->mhandle = (MYSQL)malloc(sizeof(MYSQL)); mysql_init(&connection->mhandle); #endif /* HAVE_MYSQL */ for(y=0; yerrormessage[y]=' '; } connection->errormessage[MAX_CONNECTION_ERROR_MESSAGE-1]='\0'; if (debug_level & 4096) { fprintf(stderr,"initAConnection() [%d]\n",x); } return 1; } /* Function openConnection() * Opens the specified database connection. * @param anIface a database connection description (host username etc). * @param connection a generic database connection for which the * appropriate MySQL or Postgresql connection handle will be used * for the open connection on success. * @returns 0 on any error, 1 for successful connection * on connection failure, returns 0 and sets error message in * the connection descriptor. */ int openConnection(ioparam *anIface, Connection *connection) { int returnvalue = 0; int connection_made = 0; #ifdef HAVE_POSTGIS char connection_string[900]; int connected; // status of connection polling loop time_t start_time; PGconn *postgres_connection; PostgresPollingStatusType poll; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL unsigned long client_flag = 0; // parameter used for mysql connection, is normally 0. unsigned int port; // port to make connection on #endif /* HAVE_MYSQL */ if (anIface==NULL) { fprintf(stderr,"Null iface\n"); return returnvalue; } if (anIface==NULL || connection==NULL) { fprintf(stderr,"Null connection\n"); return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"opening connection [%p] \n",connection); } // #ifdef HAVE_MYSQL // switch (anIface->database_type) { // #ifdef HAVE_MYSQL_SPATIAL // case DB_MYSQL_SPATIAL : // #endif /* HAVE_MYSQL_SPATIAL */ // #ifdef HAVE_MYSQL // case DB_MYSQL : // #endif /* HAVE_MYSQL */ // // instantiate the MYSQL structure for the connection // //fprintf(stderr,"calling mysql_init\n"); // //connection->mhandle = mysql_init(&connection->mhandle); // //fprintf(stderr,"called mysql_init\n"); // } // #endif /* HAVE_MYSQL */ // clear any existing error message xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); if (debug_level & 4096) { fprintf(stderr,"Entering openConnection with anIface [%p] and conn [%p]\n",anIface,connection); } connection->type = anIface->database_type; //connection->descriptor = anIface; if (connections_initialized == 0) { connections_initialized = initConnections(); connections_initialized = 1; } // TODO: need some sort of connection listener to handle reconnection attempts when a connection fails... // try to open connection if (!(anIface==NULL)) { switch (anIface->database_type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : if (debug_level & 4096) { fprintf(stderr,"Opening Connection to a Postgresql/Postgis database.\n"); } // If type is postgis, connect to postgis database. // build connection string from parameters xastir_snprintf(connection_string, sizeof(connection_string), \ "host=%s user=%s password=%s dbname=%s port=%d", \ anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, anIface->sp); // Use nonblocking connection (connectStart and connectPoll) //connection->phandle = PQconnectStart(connection_string); postgres_connection = PQconnectStart(connection_string); //if (connection->phandle == NULL) { if (postgres_connection == NULL) { xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); } else { connected = 0; // can connect, run PQ_connect_poll loop // Note: xastir needs to decide when to time out start_time = sec_now(); statusline("Connecting to Postgresql database",1); while ((connected==0) & (sec_now()<(start_time+30))) { // need to add a timer to polling loop //poll = PQconnectPoll(connection->phandle); poll = PQconnectPoll(postgres_connection); if (poll == PGRES_POLLING_FAILED || poll == PGRES_POLLING_OK) { connected = 1; } // add connection status feedback here if desired } //if (PQstatus(connection->phandle)==CONNECTION_OK) { if (PQstatus(postgres_connection)==CONNECTION_OK) { if (debug_level & 4096) { fprintf(stderr,"Connected to Postgresql database on %s\n",anIface->device_host_name); } // connection successful connection->phandle = postgres_connection; connection->type=DB_POSTGIS; //connection->descriptor = anIface; xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); connection_made = 1; } else { // connection attempt failed fprintf(stderr,"Failed to connect to Postgresql database on %s\n",anIface->device_host_name); fprintf(stderr,"Postgres Error: %s\n", PQerrorMessage(postgres_connection)); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to make Postgresql connection %s. %s", PQerrorMessage(postgres_connection), connection_string); } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : // if type is mysql (=>4.1), connect to mysql database if (debug_level & 4096) { fprintf(stderr,"Opening connection to a MySQL (spatial) database.\n"); } if (&connection->mhandle == NULL) { // insufficient memory to initialize a new database handle xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); } else { port = anIface->sp; statusline("Connecting to MySQL database",1); if (debug_level & 4096) { fprintf(stderr,"Opening connection to %s.\n",anIface->device_host_name); } mysql_real_connect(&connection->mhandle, anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port, anIface->database_unix_socket, client_flag); //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) if (&connection->mhandle == NULL) { // unable to establish connection xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to establish connection: %s", mysql_error(&connection->mhandle)); fprintf(stderr,"Failed to connect to MySQL database on %s\n",anIface->device_host_name); fprintf(stderr, "MySQL Error: %s", mysql_error(&connection->mhandle)); } else { // mysql_real_connect is coming back with non-null failed connection. // connected to database // make sure error message for making connection is empty. xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); // ping the server if (mysql_ping(&connection->mhandle)==0) { fprintf(stderr,"mysql ping ok [0]\n"); connection_made = 1; // store connection information connection->type = DB_MYSQL_SPATIAL; //connection->descriptor = anIface; if (debug_level & 4096) { fprintf(stderr,"Connected to MySQL database, connection stored\n"); } } else { fprintf(stderr,"mysql ping failed [1]\n"); fprintf(stderr,"Can't connect to MySQL database: Can't ping server.\n"); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to ping MySQL server. Server may be down. Check connection parameters."); } } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : // if type is mysql (<4.1), connect to mysql database if (debug_level & 4096) { fprintf(stderr,"Opening connection to a MySQL database.\n"); } if (&connection->mhandle == NULL) { // insufficient memory to initialize a new database handle xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Insufficient memory to open connection."); fprintf(stderr,"Insufficient memory to open mysql connection [mysql_init(*MYSQL) returned null].\n"); } else { client_flag = CLIENT_COMPRESS; port = anIface->sp; // **** fails if database_unix_socket doesn't exist mysql_real_connect(&connection->mhandle, anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port, anIface->database_unix_socket, client_flag); if (&connection->mhandle == NULL) { fprintf(stderr,"Unable to establish connection to MySQL database\nHost: %s Schema: %s Username: %s\n",anIface->device_host_name, anIface->database_schema, anIface->database_username); // unable to establish connection xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to establish MySQL connection. Host: %s Username: %s Password: %s Schema %s Port: %d", anIface->device_host_name, anIface->database_username, anIface->device_host_pswd, anIface->database_schema, port); fprintf(stderr,"Failed to connect to MySQL database on %s\n",anIface->device_host_name); fprintf(stderr, "MySQL Error: %s", mysql_error(&connection->mhandle)); } else { fprintf(stderr,"Connected to MySQL database on %s\n",anIface->device_host_name); // connected to database // make sure error message for making connection is empty. xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), " "); xastir_snprintf(connection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, " "); // ping the server if (mysql_ping(&connection->mhandle)==0) { fprintf(stderr,"mysql ping ok [0]\n"); connection_made = 1; // store connection information connection->type = DB_MYSQL; //connection->descriptor = anIface; if (debug_level & 4096) { fprintf(stderr,"Connected to MySQL database, connection stored\n"); } } else { fprintf(stderr,"mysql ping failed [1]\n"); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "Unable to ping MySQL server. Server may be down. Check connection parameters."); fprintf(stderr,"Can't connect to MySQL database: Can't ping server.\n"); } } } break; #endif /* HAVE_MYSQL*/ } /* end switch */ } /* end test for null interface */ if (connection_made==1) { if (debug_level & 4096) { fprintf(stderr,"Connection made: "); fprintf(stderr,"connection->type [%d]\n",connection->type); } if (testConnection((Connection*)connection)==True) { returnvalue = 1; statusline("Connected to database",1); } else { statusline("Incompatible database schema",1); fprintf(stderr,"Connection OK, but incompatible schema. [%s]\n",connection->errormessage); xastir_snprintf(anIface->database_errormessage, sizeof(anIface->database_errormessage), "%s",connection->errormessage); closeConnection(connection,-1); //free(connection); } } else { // Detailed error message should have been returned above, but make sure // there is at least a minimal failure message regardless of the problem. statusline("Failed to connect to database",1); fprintf(stderr,"Failed to make database connection.\n"); //free(connection); // not pointing to the right thing ?? port_data[connection->interface_number].status = DEVICE_ERROR; } return returnvalue; } /* Function closeConnection() * Closes the specified database connection. * @param aDbConnection a generic database connection handle. */ int closeConnection(Connection *aDbConnection, int port_number) { //ioparam db = aDbConnection->descriptor; fprintf(stderr,"Closing connection on port %d\n",port_number); if (aDbConnection==NULL) { return 0; } // free up connection resources switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS : fprintf(stderr,"Connection type is postgis.\n"); // if type is postgis, close connection to postgis database if (aDbConnection->phandle!=NULL) { if (port_data[port_number].status==DEVICE_UP) { PQfinish(aDbConnection->phandle); } //free(aDbConnection->phandle); } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL : // if type is mysql, close connection to mysql database if (&aDbConnection->mhandle!=NULL) { if (debug_level & 4096) { fprintf(stderr,"Connection type to close is mysql spatial.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } mysql_close(&aDbConnection->mhandle); //free(aDbConnection->mhandle); } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL : fprintf(stderr,"Connection type is mysql.\n"); // if type is mysql, close connection to mysql database if (&aDbConnection->mhandle!=NULL) { mysql_close(&aDbConnection->mhandle); //free(aDbConnection->mhandle); } break; #endif /* HAVE_MYSQL*/ } return 1; } /* Tests a database connection to see if the server is responding. * @param aDbConnection pointer to a generic connection handle. * @returns 0 on any error, 1 for successful ping. */ int pingConnection(Connection *aDbConnection) { int returnvalue = True; int dbreturn; #ifdef HAVE_POSTGIS ConnStatusType psql_status; #endif /* HAVE_POSTGIS */ if (aDbConnection==NULL) { return 0; } if (debug_level & 4096) { fprintf(stderr,"Pinging database server type=[%d]\n",aDbConnection->type); //} else { //fprintf(stderr,"Pinging database server.\n"); } switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS: returnvalue = False; // is the connection open [required] if (aDbConnection->phandle!=NULL) { psql_status = PQstatus(aDbConnection->phandle); if (psql_status!=CONNECTION_OK) { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Postgresql connection failed"); fprintf(stderr, "PQstatus returned CONNECTION_BAD, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "PQstatus returned CONNECTION_OK.\n"); } returnvalue = True; } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL: returnvalue = False; // is the connection open [required] if (&aDbConnection->mhandle!=NULL) { // can we ping the server [required] dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr, "MySQL Ping failed, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "MySQL Ping OK.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } returnvalue = True; } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL: // is the connection open [required] if (&aDbConnection->mhandle != NULL) { dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr, "MySQL Ping failed, probably unable to connect to server.\n"); } else { if (debug_level & 4096) { fprintf(stderr, "MySQL Ping OK.\n"); fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } returnvalue = True; } } break; #endif /* HAVE_MYSQL*/ } if (returnvalue==0) { fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); statusline("Database Ping Failed",1); port_data[aDbConnection->interface_number].status = DEVICE_ERROR; } return returnvalue; } /* Tests a database connection and the underlying schema to see * if the connection is open, the schema version is supported by * this version of the code, and to see what permissions are * available */ int testConnection(Connection *aDbConnection) { int returnvalue = True; int dbreturn; int major_version; int minor_version; char warning[100]; #ifdef HAVE_POSTGIS ConnStatusType psql_status; PGresult *result; const char *postgis_sql = "SELECT COUNT(*) FROM geometry_columns"; // test to see if schema used in connection has postgis support added #endif /* HAVE_POSTGIS */ if (aDbConnection==NULL) { return 0; } xastir_snprintf(warning, 100, " "); // make sure warning is empty switch (aDbConnection->type) { #ifdef HAVE_POSTGIS case DB_POSTGIS: returnvalue = False; // is the connection open [required] if (aDbConnection->phandle!=NULL) { psql_status = PQstatus(aDbConnection->phandle); if (psql_status!=CONNECTION_OK) { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Postgresql connection failed"); fprintf(stderr, "PQstatus returned CONNECTION_BAD, probably unable to connect to server.\n"); } else { fprintf(stderr, "PQstatus returned CONNECTION_OK.\n"); // which version of postgresql are we running dbreturn = PQserverVersion(aDbConnection->phandle); major_version = dbreturn / 10000; minor_version = (dbreturn - (major_version*10000)) / 100; fprintf(stderr,"Postgresql version [%d] %d.%d\n",dbreturn,major_version,minor_version); // is the database spatially enabled [required] result = PQexec(aDbConnection->phandle,postgis_sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(aDbConnection->phandle)); fprintf(stderr, "testConnection() Null result\nPostgresql Error : %s\n",PQerrorMessage(aDbConnection->phandle)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { // PQexec returned a valid result set, meaning that a geometry_types table exists. // are the needed tables present [required] // check schema type (simple, simple+cad, full, aprsworld) // check version of database schema for compatibility if (testXastirVersionPostgis(aDbConnection)==1) { returnvalue = True; } // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have inesrt privileges [optional] // does the user have delete privileges [optional] } else { // schema lacks a geometry_columns table, either schema or database lacks postgis support xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "No geometry_columns table found. Is PostGIS installed and added to this schema?\n"); xastir_snprintf(warning, 100, "No geometry_columns table found. PostGIS may not be installed, or the schema may not have PostGIS support added."); fprintf(stderr, "No geometry_columns table found.\nPostGIS may not be installed, or the schema may not have PostGIS support added.\n"); fprintf(stderr, "Postgresql Error : %s\n",PQerrorMessage(aDbConnection->phandle)); } } } } break; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL case DB_MYSQL_SPATIAL: returnvalue = False; // is the connection open [required] if (&aDbConnection->mhandle!=NULL) { // can we ping the server [required] dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); fprintf(stderr,"Ping of mysql server failed.\n"); xastir_snprintf(warning, 100, "%s",aDbConnection->errormessage); } else { if (debug_level & 4096) { fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } // is the database spatially enabled [required] // determine from db version >= 4.2 // MySQL 4.1 is past end of life, 4.2 at end of life but still in widespread use, e.g. RHEL4 (in early 2008). // mysql_server_version is new to mysql 4.1, prepared queries stabilized in 4.2 dbreturn = mysql_get_server_version(&aDbConnection->mhandle); if (dbreturn>0) { major_version = dbreturn / 10000; minor_version = (dbreturn - (major_version*10000)) / 100; if (major_version>=5 || (major_version==4 && minor_version >=2)) { fprintf(stderr,"MySQL Server version %d.%d OK.\n",major_version,minor_version); // check version of database schema for compatibility dbreturn = testXastirVersionMysql(aDbConnection); if (dbreturn==1) { fprintf(stderr,"Compatible Xastir database version found on server.\n"); // are the needed tables present [required] // check schema type (simple, simple+cad, full, aprsworld) // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have insert privileges [optional] // does the user have delete privileges [optional] returnvalue = True; } else { fprintf(stderr,"Xastir database version on server is not compatible with this version of Xastir.\n"); // aDbConnection->errormessage should have been set in testXastirVersionMysql xastir_snprintf(warning, 100, "%s",aDbConnection->errormessage); } } else { // version too low fprintf(stderr,"MySQL Server version %d.%d is too low and is not supported in Xastir.\n",major_version,minor_version); xastir_snprintf(warning, 100, "MySQL Server version %d.%d is too low and is not supported in Xastir.",major_version,minor_version); } } else { // ? mysql<4.1 } } } break; #endif /* HAVE_MYSQL_SPATIAL */ #ifdef HAVE_MYSQL case DB_MYSQL: // is the connection open [required] if (&aDbConnection->mhandle != NULL) { dbreturn = mysql_ping(&aDbConnection->mhandle); if (dbreturn>0) { mysql_interpret_error(dbreturn, aDbConnection); } else { if (debug_level & 4096) { fprintf(stderr,"mysql_stat [%s]\n",mysql_stat(&aDbConnection->mhandle)); } // is the database spatially enabled [optional] // determine from db version >= 4.1 #ifdef HAVE_MYSQL_SPATIAL // mysql_server_version is new to mysql 4.1 dbreturn = mysql_get_server_version(&aDbConnection->mhandle); #endif /* HAVE_MYSQL_SPATIAL */ // are the needed tables present [required] // check schema type (simple, simple+cad, aprsworld) // full requires objects, not supported here. // check version of database schema for compatibility dbreturn = testXastirVersionMysql(aDbConnection); // does the user have select privileges [required] // does the user have update privileges [optional] // does the user have insert privileges [optional] // does the user have delete privileges [optional] } } break; #endif /* HAVE_MYSQL*/ } if (returnvalue==0) { fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Incompatible schema: %s",warning); fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); // Note: Don't close connection here, we haven't handed the error to the user yet. //closeConnection(aDbConnection,-1); fprintf(stderr,"\n[%s]\n",aDbConnection->errormessage); } return returnvalue; } // Layer 3: DBMS specific db storage code ************************************* // Functions in this section should be local to this file and not exported // Export functions in section 2a above. // // Layer 3a: DBMS specific GIS db storage code ******************************** // Functions supporting queries to specific types of GIS enabled databasesa // #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS // Postgis implementation of spatial database functions /* postgresql+postgis implementation of storeStationToGisDb(). */ int storeStationToGisDbPostgis(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToGisDbPostgis(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* postgresql+postgis implementation of storeCadToGisDb(). */ int storeCadToGisDbPostgis(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; return returnvalue; } /* function storeStationSimplePointToGisDbPostgis() * Postgresql/Postgis implementation of wrapper storeStationSimplePointToGisDb(). * Should only be called through wrapper function. Do not call directly. */ int storeStationSimplePointToGisDbPostgis(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; // Default return value is failure. int ok; // Holds results of tests when building query. char wkt[MAX_WKT]; // well know text representation of latitude and longitude of point char timestring[101]; // string representation of the time heard or the current time char call_sign[(MAX_CALLSIGN*2)+1]; // temporary holding for escaped callsign char aprs_symbol[2]; // temporary holding for escaped aprs symbol char aprs_type[2]; // temporary holding for escaped aprs type char special_overlay[2]; // temporary holding for escaped overlay char origin[(MAX_CALLSIGN*2)+1]; // temporary holding for escaped origin char node_path[(NODE_PATH_SIZE*2)+1]; // temporary holding for escaped node_path char record_type[2]; // temporary holding for escaped record_type //PGconn *conn = aDbConnection->phandle; PGresult *prepared = NULL; PGresult *result = NULL; int count; // returned value from count query const int PARAMETERS = 9; // parameter arrays for prepared query const char *paramValues[PARAMETERS]; // To use native Postgres POINT for position instead of postgis geometry point. //const Oid paramTypes[6] = { VARCHAROID, TIMESTAMPTZOID, POINTOID, VARCHAROID, VARCHAROID, VARCHAROID }; //const Oid paramTypes[6] = { 1043, 1184, 600, 1043, 1043, 1043 }; // Native postgres (8.2) geometries don't have spatial support as rich as Postgis extensions. // use postgis geometry Point instead: // lookup OID for geometry: select OID from pg_type where typname = 'geometry'; returns 19480 //const Oid paramTypes[6] = { VARCHAROID, TIMESTAMPTZOID, 19480, VARCHAROID, VARCHAROID, VARCHAROID }; //const Oid paramTypes[6] = { 1043, 1184, 19480, 1043, 1043, 1043 }; // Value 18480 is probably installation specific, use unknownOID instead: //const Oid paramTypes[9] = { VARCHAROID, TIMESTAMPTZOID, UNKNOWNOID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID, VARCHAROID }; const Oid paramTypes[9] = { 1043, 1184, 705, 1043, 1043, 1043, 1043, 1043, 1043 }; const char *sql = "insert into simpleStation (station, transmit_time, position, symbol, overlay, aprstype, origin, record_type, node_path) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)"; const char *StatementName = "InsertSimpleStation"; const char *StatementExists = "select count(*) from pg_prepared_statements where name = 'InsertSimpleStation'"; if (debug_level & 4096) { fprintf(stderr,"In postgres simple station insert\n"); fprintf(stderr,"with connection [%p] \n",aDbConnection); fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); } if (aDbConnection->phandle==NULL) { fprintf(stderr,"Trying to save station on null postgresql connection\n"); return returnvalue; } if (PQserverVersion(aDbConnection->phandle)==0) { // no connection to server fprintf(stderr,"Trying to save station on closed postgresql connection\n"); return returnvalue; } if (debug_level & 4096) { fprintf(stderr,"Postgresql version=%d\n",PQserverVersion(aDbConnection->phandle)); } // Check to see if this prepared statement exists in the current session // and create it if it does not. // Query adds connection overhead - should probably track with a global variable, // and query/recreate statement only on failure. ok = 0; // pg_prepared_statements system view added in postgresql 8.2 if (PQserverVersion(aDbConnection->phandle)>80199) { result = PQexec(aDbConnection->phandle, "select count(*) from pg_prepared_statements where name = 'InsertSimpleStation'"); result = PQexec(aDbConnection->phandle, StatementExists); if (result==NULL) { fprintf(stderr,"Postgres Check for Prepared Query exec Failed: %s\n", PQerrorMessage(aDbConnection->phandle)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQerrorMessage(aDbConnection->phandle)); } else { count = 0; if (PQresultStatus(result) == PGRES_TUPLES_OK) { count = atoi(PQgetvalue(result,0,0)); } if (count==0) { // Statement doesn't exist, so prepare it, let PQprepare report on any error that got us a NULL result. prepared = PQprepare(aDbConnection->phandle, StatementName, sql, PARAMETERS, paramTypes); if (PQresultStatus(prepared)==PGRES_COMMAND_OK) { ok = 1; } else { // error condition - can't prepare statement fprintf(stderr,"Postgres Prepare Query Failed: %s\n", PQerrorMessage(aDbConnection->phandle)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQerrorMessage(aDbConnection->phandle)); exit(1); } } else if (count==1) { // prepared statement exists, we can go ahead with query. ok = 1; } else { fprintf(stderr,"Postgres Check for Prepared Query getvalue (count=%d) failed: %s\n",count, PQresultErrorMessage(result)); xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQresultErrorMessage(result)); } } } else { prepared = PQprepare(aDbConnection->phandle, StatementName, sql, PARAMETERS, paramTypes); ok = 1; } if (ok==1) { // native postgis POINT is (99.999 099.999) instead of POINT (99.999 099.999) // ok = xastirCoordToLatLongPosgresPoint(aStation->coord_lon, aStation->coord_lat, wkt); // // Prepared query is ready, get and fill in the parameter values // from the station provided, then fire the query. ok = xastirCoordToLatLongWKT(aStation->coord_lon, aStation->coord_lat, wkt); if (ok==1) { // Postgresql 8 documentation indicates that escape string should not be performed // when calling PQexecParams or its sibling routines, not explicit, but implication // is that PQexecPrepared with passed parameters is a sibling routine and we // shouldn't be running PQescapeStringConn() on the parameters. // If used, form would be: // PQescapeStringConn(conn,call_sign,aStation->call_sign,(MAX_CALLSIGN*2)+1,escape_error); xastir_snprintf(call_sign,MAX_CALLSIGN+1,"%s",aStation->call_sign); if (strlen(aStation->origin) > 0) { xastir_snprintf(origin,sizeof(origin),"%s",aStation->origin); } else { xastir_snprintf(origin,1,"%c",'\0'); } xastir_snprintf(record_type,2,"%c",aStation->record_type); if (aStation->node_path_ptr==NULL) { xastir_snprintf(node_path,2," "); } else { xastir_snprintf(node_path,sizeof(node_path),"%s",aStation->node_path_ptr); } if (debug_level & 4096) { fprintf(stderr,"node_path (12345678901234567890123456789012345678901234567890123456)\n"); fprintf(stderr,"node_path = [%s]\n",node_path); } // Get time in seconds, adjust to datetime // If aStation is my station or another unset sec_heard is // encountered, use current time instead. Conversely, use time // provided in sec_heard if sec_heard is an invalid time. get_iso_datetime(aStation->sec_heard,timestring,True,False); // set parameter values to call, transmit_time, and position paramValues[0]=call_sign; paramValues[1]=timestring; paramValues[2]=wkt; if (aStation->aprs_symbol.aprs_symbol==NULL) { xastir_snprintf(aprs_symbol,2," "); paramValues[3]=&aprs_symbol; } else { xastir_snprintf(aprs_symbol,2,"%c",aStation->aprs_symbol.aprs_symbol); paramValues[3]=aprs_symbol; } if (aStation->aprs_symbol.special_overlay==NULL) { xastir_snprintf(special_overlay,2," "); paramValues[4]=&special_overlay; } else { xastir_snprintf(special_overlay,2,"%c",aStation->aprs_symbol.special_overlay); paramValues[4]=&special_overlay; } if (aStation->aprs_symbol.aprs_type==NULL) { xastir_snprintf(aprs_type,2," "); paramValues[5]=&aprs_type; } else { xastir_snprintf(aprs_type,2,"%c",aStation->aprs_symbol.aprs_type); paramValues[5]=aprs_type; } paramValues[6]=origin; paramValues[7]=record_type; paramValues[8]=node_path; if (debug_level & 4096) { fprintf(stderr,"Inserting: Call: %s, Time: %s, Position: %s, Symbol:%s,%s,%s Origin:%s, Node_path:%s, Record type:%s\n",paramValues[0],paramValues[1],paramValues[2],paramValues[3],paramValues[4],paramValues[5],paramValues[6],paramValues[8],paramValues[7]); } // send query result = PQexecPrepared(aDbConnection->phandle,StatementName,PARAMETERS,paramValues,NULL,NULL,POSTGRES_RESULTFORMAT_TEXT); if (PQresultStatus(result)!=PGRES_COMMAND_OK) { fprintf(stderr,"Postgres Insert query failed:%s\n",PQresultErrorMessage(result)); // error, get error message. xastir_snprintf(aDbConnection->errormessage,MAX_CONNECTION_ERROR_MESSAGE,PQresultErrorMessage(result)); } else { // query was successful returnvalue=1; } } else { // problem with coordinates of station fprintf(stderr,"Unable to save station to Postgres db, Error converting latitude or longitude from xastir coordinates\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } if (result!=NULL) { PQclear(result); } if (prepared!=NULL) { PQclear(prepared); } return returnvalue; } /* function testXastirVersionPostgis() * Postgresql/Postgis implementation of wrapper testXastirVersionPostgis(). * Should only be called through wrapper function. Do not call directly. */ int testXastirVersionPostgis(Connection *aDbConnection) { int returnvalue = 0; int version_number; int compatable_series; const char sql[100] = "select version_number, compatable_series from version order by version_number desc limit 1"; PGresult *result; PGconn *conn = aDbConnection->phandle; result = PQexec(conn,sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(conn)); fprintf(stderr, "testXastirVersionPostgis() Null result\nPostgresql Error : %s\n",PQerrorMessage(conn)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { if (PQntuples(result)!=1) { fprintf(stderr,"Version table doesn't appear to contain any rows.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version table doesn't appear to contain any rows."); } else { version_number = atoi(PQgetvalue(result,0,0)); compatable_series = atoi(PQgetvalue(result,0,1)); if (version_number == XASTIR_SPATIAL_DB_VERSION) { returnvalue = 1; } else { if (version_number < XASTIR_SPATIAL_DB_VERSION && compatable_series == XASTIR_SPATIAL_DB_COMPATABLE_SERIES) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { fprintf(stderr,"Version in schema (%d) is not compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version in schema (%d) is not compatible with this version of xastir (%d).",version_number,XASTIR_SPATIAL_DB_VERSION); fprintf(stderr,"%s",aDbConnection->errormessage); returnvalue = 0; } } } } PQclear(result); } return returnvalue; } /* function getAllSimplePositionsPostgis() * Postgresql/Postgis implementation of wrapper getAllSimplePositions(). * Should only be called through wrapper function. Do not call directly. */ int getAllSimplePositionsPostgis(Connection *aDbConnection) { int returnvalue = 0; // value to return from function, 1 for success, 0 for failure int row; // row counter for result set loop int station_count = 0; // number of new stations retrieved unsigned long x; // xastir coordinate for longitude unsigned long y; // xastir coordinate for latitude unsigned long u_long; unsigned long u_lat; char *s_lat[13]; // string latitude char *s_lon[13]; // string longitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string const char *sql = "select station, symbol, overlay, aprstype, transmit_time, AsText(position), origin, record_type, node_path, X(position), Y(position) from simpleStation order by station, transmit_time asc"; // station is column 0, symbol is column 1, etc. PGconn *conn = aDbConnection->phandle; char feedback[100]; char lastcall[MAX_CALLSIGN+1]; //holds last retrieved callsign int exists; //shortcut to skip db check if currently retrieved callsign equals last retrieved callsign DataRow *p_new_station; // pointer to new station record DataRow *p_time; // pointer to new station record int skip; int points_this_station; // number of times this station has been heard. char empty[MAX_ALTITUDE]; struct tm time; time_t sec; empty[0]='\0'; xastir_snprintf(feedback,100,"Retrieving Postgis records\n"); stderr_and_statusline(feedback); //fprintf(stderr,"connection->phandle [%p]\n",aDbConnection->phandle); // run query and retrieve result set PGresult *result = PQexec(conn,sql); if (result==NULL) { // PQexec probably couldn't allocate memory for the result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Null result: %s\n",PQerrorMessage(conn)); fprintf(stderr, "getAllSimplePositionsPostgis() Null result\nPostgresql Error : %s\n",PQerrorMessage(conn)); } else { // PQexec returned a result, but it may not be valid, check to see. if (PQresultStatus(result)==PGRES_COMMAND_OK || PQresultStatus(result)==PGRES_TUPLES_OK) { // PQexec returned a valid result set. xastir_snprintf(feedback,100,"Retrieving %i Postgis records\n",PQntuples(result)); stderr_and_statusline(feedback); xastir_snprintf(lastcall,MAX_CALLSIGN+1," "); points_this_station = 0; for (row=0; rowcoord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } // store this trail point lat = atof(PQgetvalue(result,row,10)); lon = atof(PQgetvalue(result,row,9)); if (strlen(PQgetvalue(result,row,4)) > 0) { strptime(PQgetvalue(result,row,4), "%Y-%m-%d %H:%M:%S%z", &time); sec = mktime(&time); } if(convert_to_xastir_coordinates( &u_long, &u_lat, lon, lat)) { (void)store_trail_point(p_new_station, u_long, u_lat, sec, empty, empty, empty, 0); } if (p_new_station->sec_heard < sec) { // update the station record to this position if(convert_to_xastir_coordinates(&u_long, &u_lat, lon, lat)) { p_new_station->coord_lat = u_lat; p_new_station->coord_lon = u_long; p_new_station->sec_heard = sec; } } } } } else { // This station isn't in the xastir db. //int add_simple_station(DataRow *p_new_station,char *station, char *origin, char *symbol, char *overlay, char *aprs_type, char *latitude, char *longitude, char *record_type, char *node_path, char *transmit_time) { //const char *sql = "select station, symbol, overlay, aprstype, transmit_time, AsText(position), origin, record_type, node_path, X(position), Y(position) from simpleStation order by station, transmit_time asc"; add_simple_station(p_new_station,PQgetvalue(result,row,0), PQgetvalue(result,row,6), PQgetvalue(result,row,1), PQgetvalue(result,row,2), PQgetvalue(result,row,3), PQgetvalue(result,row,10), PQgetvalue(result,row,9), PQgetvalue(result,row,7), PQgetvalue(result,row,8), PQgetvalue(result,row,4), POSTGIS_TIMEFORMAT); station_count ++; } // end else, new station } // end else, station is not null } // end for loop stepping through rows redo_list = (int)TRUE; // update active station lists xastir_snprintf(feedback,100,"Added %d stations from Postgis\n",station_count); stderr_and_statusline(feedback); } else { // sql query had a problem retrieving result set. xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "%s %s\n",PQresStatus(PQresultStatus(result)),PQerrorMessage(conn)); fprintf(stderr, "getAllSimplePositionsPostgis() %s\nPostgresql Error : %s\n",PQresStatus(PQresultStatus(result)),PQerrorMessage(conn)); } // done with result set, so free the resource. PQclear(result); } return returnvalue; } /* function getAllSimplePositionsPostgisInBoundingBox() * Postgresql/Postgis implementation of wrapper getAllSimplePositionsInBoundingBox(). * Should only be called through wrapper function. Do not call directly. */ int getAllSimplePositionsPostgisInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat) { int returnvalue = 0; // set up prepared query with bounding box // postgis simple table uses POINT char sql[100] = "select call, transmit_time, position from simpleStation where "; PGconn *conn = aDbConnection->phandle; return returnvalue; } #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL // Mysql 5 implementation of spatial database functions /* function storeStationToGisDbMysql * MySQL implementation of storeStationToGisDb * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an exastir database connection struct describing * the connection. * @param aStation * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeStationToGisDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToGisDbMysql(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* function storeCadToGisDbMysql * MySQL implementation of storeCadToGisDbMysql * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an exastir database connection struct describing * the connection. * @param aCadObject * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeCadToGisDbMysql(Connection *aDbConnection, CADRow *aCadObject) { int returnvalue = 0; return returnvalue; } /* support function for prepared statements int bind_mysql_string_parameter(MYSQL_BIND *bind, int bind_number, char* buffer, int provided_length, int buffer_length, my_bool is_null) { bind[bind_number]->buffer = buffer; bind[bind_number]->length = provided_length; bind[bind_number]->buffer_length = buffer_length; bind[bind_number]->buffer_type = MYSQL_TYPE_STRING bind[bind_number]->is_null = is_null; } */ /* function storeStationSimplePointToGisDbMysql() * MySQL implementation of wrapper storeStationSimplePointToGisDb(). * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * @param aDbConnection an xastir database connection struct describing * the connection. * @param aStation * Returns 0 for failure, 1 for success. * On failure sets error message in aDbConnection->errormessage. */ int storeStationSimplePointToGisDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; int mysqlreturn; // hold return value of mysql query int param_count; // check on the number of parameters present in the prepared statement int ok; // variable to store results of tests preparatory to firing query // temporary holding variables for bind buffers char wkt[MAX_WKT]; // well know text representation of latitude and longitude of point char aprs_symbol[2]; // temporary holding for escaped aprs symbol char aprs_type[2]; // temporary holding for escaped aprs type char special_overlay[2]; // temporary holding for escaped overlay char record_type[2]; // temporary holding for escaped record type char origin[MAX_CALLSIGN+1]; // temporary holding for escaped origin char node_path[NODE_PATH_SIZE+1]; // temporary holding for escaped node_path_ptr MYSQL_STMT *statement; // bind string lengths unsigned long call_sign_length; unsigned long wkt_length; unsigned long aprs_symbol_length; unsigned long aprs_type_length; unsigned long special_overlay_length; unsigned long origin_length; unsigned long record_type_length; unsigned long node_path_length; // time MYSQL_TIME timestamp; char timestring[100+1]; time_t secs_now; struct tm *ts; // to convert time to component parts for bind.buffer_type MYSQL_TYPE_DATETIME // define prepared statement and matching bind array #define SQL "INSERT INTO simpleStationSpatial (station, transmit_time, position, symbol, overlay, aprstype, origin, record_type, node_path) VALUES (?,?,PointFromText(?),?,?,?,?,?,?)" MYSQL_BIND bind[9]; // bind array for prepared query. int parameters = 9; // Note: // bind[9], SQL "?????????", and param_count must all match value of parameters // nine bound parameters, nine question marks in the statement, and param_count returned as nine. if (debug_level & 4096) { fprintf(stderr,"in storeStationSimplePointToGisDbMysql\n"); fprintf(stderr,"with connection [%p] \n",aDbConnection); } if (&aDbConnection->mhandle==NULL) { return returnvalue; } statement = mysql_stmt_init(&aDbConnection->mhandle); if (!statement) { fprintf(stderr,"Unable to create mysql prepared statement. May be out of memory.\n"); } mysql_stmt_prepare(statement, SQL, strlen(SQL)); if (!statement) { mysql_interpret_error(*mysql_error(&aDbConnection->mhandle),aDbConnection); } else { // test to make sure that statement has the correct number of parameters param_count=mysql_stmt_param_count(statement); if (param_count!=parameters) { fprintf(stderr,"Number of bound parameters %d does not match expected value %d\nFor query[%s]",param_count,parameters,SQL); fprintf(stderr, " %s\n", mysql_stmt_error(statement)); } else { // set up the buffers memset(bind, 0, sizeof(bind)); bind[0].buffer = (char *)&aStation->call_sign; bind[0].length = &call_sign_length; bind[0].buffer_length = MAX_CALLSIGN; bind[0].buffer_type = MYSQL_TYPE_STRING; bind[0].is_null = 0; bind[1].buffer = (char *)×tamp; bind[1].length = 0; bind[1].buffer_type = MYSQL_TYPE_DATETIME; bind[1].is_null = 0; bind[2].buffer = (char *)&wkt; bind[2].length = &wkt_length; bind[2].buffer_length = MAX_WKT; bind[2].buffer_type = MYSQL_TYPE_STRING; bind[2].is_null = 0; bind[3].buffer = (char *)&aprs_symbol; bind[3].length = &aprs_symbol_length; bind[3].buffer_length = 2; bind[3].buffer_type = MYSQL_TYPE_STRING; bind[3].is_null = 0; bind[4].buffer = (char *)&special_overlay; bind[4].length = &special_overlay_length; bind[4].buffer_length = 2; bind[4].buffer_type = MYSQL_TYPE_STRING; bind[4].is_null = 0; bind[5].buffer = (char *)&aprs_type; bind[5].length = &aprs_type_length; bind[5].buffer_length = 2; bind[5].buffer_type = MYSQL_TYPE_STRING; bind[5].is_null = 0; bind[6].buffer = (char *)&origin; // segfaults with origin of zero length, otherwise writes bad data bind[6].length = &origin_length; bind[6].buffer_length = MAX_CALLSIGN; bind[6].buffer_type = MYSQL_TYPE_STRING; bind[6].is_null = 0; bind[7].buffer = (char *)&record_type; bind[7].length = &record_type_length; bind[7].buffer_length = 2; bind[7].buffer_type = MYSQL_TYPE_STRING; bind[7].is_null = 0; bind[8].buffer = (char *)&node_path; bind[8].length = &node_path_length; bind[8].buffer_length = NODE_PATH_SIZE; bind[8].buffer_type = MYSQL_TYPE_STRING; bind[8].is_null = 0; ok = mysql_stmt_bind_param(statement,bind); if (ok!=0) { fprintf(stderr,"Error binding parameters to mysql prepared statement.\n"); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); fprintf(stderr,mysql_stmt_error(statement)); } else { // get call, time, and position // call is required if (aStation->call_sign!=NULL && strlen(aStation->call_sign)>0) { call_sign_length = strlen(aStation->call_sign); // get time in seconds, adjust to datetime // If my station or another unset sec_heard is // encountered, use current time instead, use time // provided if it was invalid. get_iso_datetime(aStation->sec_heard,timestring,True,False); if ((int)aStation->sec_heard==0 ) { secs_now = sec_now(); ts = localtime(&secs_now); } else { ts = localtime(&aStation->sec_heard); } timestamp.year = ts->tm_year + 1900; // tm_year is from 1900 timestamp.month = ts->tm_mon + 1; // tm_mon is from 0 timestamp.day = ts->tm_mday; // tm_mday is from 1 timestamp.hour = ts->tm_hour; timestamp.minute = ts->tm_min; timestamp.second = ts->tm_sec; ok = xastirCoordToLatLongWKT(aStation->coord_lon, aStation->coord_lat, wkt); if (ok==1) { wkt_length = strlen(wkt); if (aStation->aprs_symbol.aprs_symbol) { xastir_snprintf(aprs_symbol,2,"%c",aStation->aprs_symbol.aprs_symbol); } else { xastir_snprintf(aprs_symbol,2,"%c",'\0'); } aprs_symbol_length = strlen(aprs_symbol); if (aStation->aprs_symbol.aprs_type) { xastir_snprintf(aprs_type,2,"%c",aStation->aprs_symbol.aprs_type); } else { xastir_snprintf(aprs_type,2,"%c",'\0'); } aprs_type_length = strlen(aprs_type); if (aStation->aprs_symbol.special_overlay) { xastir_snprintf(special_overlay,2,"%c",aStation->aprs_symbol.special_overlay); } else { xastir_snprintf(special_overlay,2,"%c",'\0'); } special_overlay_length = strlen(special_overlay); if (aStation->origin) { xastir_snprintf(origin,MAX_CALLSIGN+1,"%s",aStation->origin); } else { //xastir_snprintf(origin,2,"%c",'\0'); origin[0]='\0'; } origin_length = strlen(origin); if (aStation->record_type) { xastir_snprintf(record_type,2,"%c",aStation->record_type); } else { //xastir_snprintf(record_type,2,"%c",'\0'); record_type[0]='\0'; } record_type_length = strlen(record_type); if (aStation->node_path_ptr) { if (debug_level & 4096) { fprintf(stderr,"node_path (12345678901234567890123456789012345678901234567890123456)\n"); fprintf(stderr,"node_path = [%s]\n",aStation->node_path_ptr); } xastir_snprintf(node_path,NODE_PATH_SIZE+1,"%s",aStation->node_path_ptr); } else { //xastir_snprintf(node_path,2,"%c",'\0'); node_path[0]='\0'; } node_path_length = strlen(node_path); // all the bound parameters should be available and correct if (debug_level & 4096) { fprintf(stderr,"saving station %s %d %d %d %d:%d:%d wkt=%s [%s][%s][%s] \n",aStation->call_sign,ts->tm_year,ts->tm_mon,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec,wkt,aprs_type,aprs_symbol,record_type); } // send query mysqlreturn = mysql_stmt_execute(statement); if (mysqlreturn!=0) { returnvalue=0; fprintf(stderr,"%s\n",mysql_stmt_error(statement)); mysql_interpret_error(mysqlreturn,aDbConnection); } else { returnvalue=1; } } else { fprintf(stderr,"Unable to save station to mysql db, Error converting latitude or longitude from xastir coordinates\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } else { // set call not null error message fprintf(stderr,"Unable to save station to mysql db, Station call sign was blank or null.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Station callsign is required and was blank or null."); } } // end of bind check } // end of parameter count check } mysql_stmt_free_result(statement); mysql_stmt_close(statement); if (returnvalue==0) { pingConnection(aDbConnection); } return returnvalue; } int getAllSimplePositionsMysqlSpatial(Connection *aDbConnection) { int returnvalue = 0; DataRow *p_new_station; int station_count = 0; // number of new stations retrieved char *s_lat[13]; // string latitude char *s_lon[13]; // string longitude float lat; // latitude converted from retrieved string float lon; // longitude converted from retrieved string unsigned long u_lat; unsigned long u_long; int points_this_station; char feedback[100]; struct tm time; time_t sec; int skip; // used in identifying mobile stations char sql[] = "select station, transmit_time, AsText(position), symbol, overlay, aprstype, origin, record_type, node_path from simpleStationSpatial order by station, transmit_time asc"; char lastcall[MAX_CALLSIGN+1]; //holds last retrieved callsign int exists; //shortcut to skip db check if currently retrieved callsign equals last retrieved callsign MYSQL_RES *result; MYSQL_ROW row; char empty[MAX_ALTITUDE]; int ok; // to hold mysql_query return value empty[0]='\0'; ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { xastir_snprintf(feedback,100,"Retrieving MySQL records\n"); stderr_and_statusline(feedback); // with mysql_use_result each call to mysql_fetch_row retrieves // a row of data from the server. Mysql_store_result might use // too much memory in retrieving a large result set all at once. xastir_snprintf(lastcall,MAX_CALLSIGN+1," "); points_this_station=0; while ((row = mysql_fetch_row(result))) { // retrieve data from the row // test to see if this is a valid station if (row[0]==NULL) { // station is null, skip } else { p_new_station = NULL; exists = 0; // Shortcut check to see if station has allready been heard // works as query is ordered by station. if (strcmp(lastcall,row[0])==1) { exists = 1; points_this_station++; } else { if (search_station_name(&p_new_station,row[0],1)) { exists = 1; points_this_station++; } else { points_this_station=1; } } xastir_snprintf(lastcall,MAX_CALLSIGN+1,row[0]); if (exists==1) { // This station is allready in present as a DataRow in the xastir db. // check to see if this is likely to be a mobile station // We can't easily identify mobile stations from position position // because of rounding errors, therefore exclude stations that are likely to be fixed. // _/ = wx skip = 0; if ((strcmp(row[3],"_")==0) & (strcmp(row[5],"/")==0)) { skip = 1; // wx } if ((strcmp(row[3],"-")==0) & (strcmp(row[5],"/")==0)) { skip = 1; // house } if (skip==0) { // add to track if (search_station_name(&p_new_station,row[0],1)) { if (points_this_station<3) { //existing station record needs to be added as a trailpoint (void)store_trail_point(p_new_station, p_new_station->coord_lon, p_new_station->coord_lat, p_new_station->sec_heard, empty, empty, empty, 0); } // store this trail point lat = xastirWKTPointToLatitude(row[2]); lon = xastirWKTPointToLongitude(row[2]); if (strlen(row[1]) > 0) { strptime(row[1], "%Y-%m-%d %H:%M:%S", &time); sec = mktime(&time); //fprintf(stderr,"trailpoint time: %ld [%s]\n", sec, row[1]); } if(convert_to_xastir_coordinates( &u_long, &u_lat, lon, lat)) { (void)store_trail_point(p_new_station, u_long, u_lat, sec, empty, empty, empty, 0); } if (p_new_station->sec_heard < sec) { // update the station record to this position if(convert_to_xastir_coordinates(&u_long, &u_lat, lon, lat)) { p_new_station->coord_lat = u_lat; p_new_station->coord_lon = u_long; p_new_station->sec_heard = sec; } } } // search_station_name } // !skip } else { // This station isn't in the xastir db. // Add a datarow using the retrieved station record from the postgis database. lat = xastirWKTPointToLatitude(row[2]); lon = xastirWKTPointToLongitude(row[2]); xastir_snprintf(s_lat,13,"%3.6f",lat); xastir_snprintf(s_lon,13,"%3.6f",lon); add_simple_station(p_new_station, row[0], row[6], row[3], row[4], row[5], s_lat, s_lon, row[7], row[8], row[1],(char*)MYSQL_TIMEFORMAT); station_count++; } } } } else { // error fetching the result set fprintf(stderr,"mysql error: %s\n",mysql_error(&aDbConnection->mhandle)); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); } xastir_snprintf(feedback,100,"Retrieved %d new stations from MySQL\n",station_count); stderr_and_statusline(feedback); mysql_free_result(result); } else { // query didn't execute correctly mysql_interpret_error(ok,aDbConnection); } return returnvalue; } int getAllCadFromGisDbMysql(Connection *aDbConnection) { int returnvalue = 0; int mysqlreturn; MYSQL *conn = &aDbConnection->mhandle; return returnvalue; } int getAllSimplePositionsMysqlSpatialInBoundingBox(Connection *aDbConnection, char* str_e_long, char* str_w_long, char* str_n_lat, char* str_s_lat) { int returnvalue = 0; int mysqlreturn; MYSQL *conn = &aDbConnection->mhandle; return returnvalue; } /* // some thoughts on database schema elements create database xastir; grant select on xastir to user xastir_user@localhost identified by encrypted password ''; create table version ( version_number int, compatable_series int ); grant select on version to xastir_user@localhost insert into version (version_number) values (XASTIR_SPATIAL_DB_VERSION); insert into version (version_number) values (XASTIR_SPATIAL_DB_COMPATIBLE_SERIES); # should be minimum fields needed to populate a DataRow and a related # APRS_Symbol in xastir create table simpleStation ( simpleStationId int primary key not null auto_increment station varchar(MAX_CALLSIGN) not null, # callsign of station, length up to max_callsign symbol varchar(1), # aprs symbol character overlay varchar(1), # aprs overlay table character aprstype varchar(1), # aprs type, required??? transmit_time datetime not null default now(), # transmission time, if available, otherwise storage time position POINT # position of station or null if latitude and longitude are not available ); grant select, insert on simpleStation to xastir_user@localhost; create table datarow ( datarow_id int not null primary key auto_increment, call_sign varchar(10) not null, tactical_call_sign varchar() not null default '', c_aprs_symbol_id int location POINT, time_sn int, sec_heard long, heard_via_tnc_last_time long, direct_heard long, packet_time varchar, pos_time varchar, flag int, pos_amb varchar(1), error_ellipse_radius int, lon_precision int, lat_precision int, trail_color int, record_type varchar(1), data_via varchar(1), heard_via_tnc_port int, last_port_heard int, num_packets int, altitude varchar([MAX_ALTITUDE]), speed varchar([MAX_SPEED+1]), course varchar([MAX_COURSE+1]), bearing varchar([MAX_COURSE+1]), NRQ varchar([MAX_COURSE+1]), power_gain varchar([MAX_POWERGAIN+1]), signal_gain varchar([MAX_POWERGAIN+1]) ); */ #endif /* HAVE_MYSQL_SPATIAL */ #endif /* HAVE_SPATIAL_DB */ // Layer 3b: DBMS specific db storage code for non spatial databases ********** // Functions supporting queries to specific types of databases that lack // spatial extensions. Limited to storing points using latitude and longitude // fields without spatial objects or spatial indexing. // #ifdef HAVE_MYSQL // functions for MySQL database version < 4.1, or MySQL schema objects that don't // include spatial indices. // //********* Support for MySQL < 4.1 is depreciated ***************************** //********* Expect MySQL support to be limited to MySQL 5+ ********************** // /* function storeStationSimplePointToDbMysql() * MySQL implementation of wrapper storeStationSimplePointToGisDb(). * Should be private to db_gis.c * Should only be called through wrapper function. Do not call directly. * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int storeStationSimplePointToDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; // default return value is failure. int mysqlreturn = 1; // result of sending mysql query. char sql[400]; // Next three variables are one character in two bytes plus one character for // filling by mysql_real_escape_string(). char aprs_symbol[3]; // temporary holding for escaped aprs symbol char aprs_type[3]; // temporary holding for escaped aprs type char special_overlay[3]; // temporary holding for escaped overlay char record_type[3]; // temporary holding for escaped record type char from[3]; // temporary holding for all of the above length 3 variables char call_sign[(MAX_CALLSIGN)*2+1]; // temporary holding for escaped callsign char origin[(MAX_CALLSIGN)*2+1]; // temporary holding for escaped origin char node_path[(NODE_PATH_SIZE*2)+1]; // temporary holding for escaped node_path_ptr float longitude; float latitude; int ok; char timestring[100+1]; if (debug_level & 4096) { fprintf(stderr,"In storestationsimpletodbmysql()\n"); } // prepared statements not present below MySQL version 4.1 // details of prepared statement support changed between versions 4.1 and 5.0. // char [] sql = "insert into simpleStation (call, transmit_time, latitude, longitude) values ('%1','%2','%3','%4'))"; // call is a required element for a simple station if (aStation!=NULL && aStation->call_sign!=NULL && strlen(aStation->call_sign)>0) { // get time in seconds, adjust to datetime // If my station or another unset sec_heard is // encountered, use current time instead, use time // provided if it was invalid. get_iso_datetime(aStation->sec_heard,timestring,True,False); // get coord_lat, coord_long in xastir coordinates and convert to decimal degrees ok = convert_from_xastir_coordinates (&longitude, &latitude, aStation->coord_lon, aStation->coord_lat); // latitude and longitude are required elements for a simple station record. if (ok==1) { // build insert query with call, time, and position // handle special cases of null, \ and ' characters in type, symbol, and overlay. if (aStation->aprs_symbol.aprs_symbol) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.aprs_symbol); mysql_real_escape_string(&aDbConnection->mhandle,aprs_symbol,from,1); } else { xastir_snprintf(aprs_symbol,2,"%c",'\0'); } if (aStation->aprs_symbol.aprs_type) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.aprs_type); mysql_real_escape_string(&aDbConnection->mhandle,aprs_type,from,1); } else { xastir_snprintf(aprs_type,2,"%c",'\0'); } if (aStation->aprs_symbol.special_overlay) { xastir_snprintf(from,2,"%c",aStation->aprs_symbol.special_overlay); mysql_real_escape_string(&aDbConnection->mhandle,special_overlay,from,1); } else { xastir_snprintf(special_overlay,2,"%c",'\0'); } // Need to escape call sign - may contain special characters: // insert into simpleStation (station, symbol, overlay, aprstype, transmit_time, latitude, longitude) // values ('Fry's','/\0\0',' ','//\0','2007-08-07 21:55:43 -0400','47.496834','-122.198166') mysql_real_escape_string(&aDbConnection->mhandle,call_sign,(aStation->call_sign),strlen(aStation->call_sign)); // just in case, set a default value for record_type and escape it. if (aStation->record_type) { fprintf(stderr,"record_type: %c\n",aStation->record_type); xastir_snprintf(from,2,"%c",aStation->record_type); mysql_real_escape_string(&aDbConnection->mhandle,record_type,from,1); } else { xastir_snprintf(record_type,2,"%c",NORMAL_APRS); } if (strlen(aStation->origin) > 0) { mysql_real_escape_string(&aDbConnection->mhandle,origin,(aStation->origin),strlen(aStation->origin)); } else { xastir_snprintf(origin,2,"%c",'\0'); } if (aStation->node_path_ptr) { //mysql_real_escape_string(conn,&node_path,aStation->node_path_ptr,((strlen(aStation->node_path_ptr)*2)+1)); xastir_snprintf(node_path,sizeof(node_path),"%s",aStation->node_path_ptr); } else { xastir_snprintf(node_path,2,"%c",'\0'); } xastir_snprintf(sql,sizeof(sql),"insert into simpleStation (station, symbol, overlay, aprstype, transmit_time, latitude, longitude, origin, record_type, node_path) values ('%s','%s','%s','%s','%s','%3.6f','%3.6f','%s','%s','%s')", call_sign, aprs_symbol, special_overlay, aprs_type,timestring,latitude,longitude,origin,record_type,node_path); if (debug_level & 4096) { fprintf(stderr,"MySQL Query:\n%s\n",sql); } // send query mysql_ping(&aDbConnection->mhandle); mysqlreturn = mysql_real_query(&aDbConnection->mhandle, sql, strlen(sql)+1); if (mysqlreturn!=0) { // get the mysql error message fprintf(stderr,mysql_error(&aDbConnection->mhandle)); fprintf(stderr,"\n"); mysql_interpret_error(mysqlreturn,aDbConnection); } else { // insert query was successful, return value is ok. returnvalue=1; } } else { xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Error converting latitude or longitude from xastir coordinates: %ld,%ld",aStation->coord_lat,aStation->coord_lon); } } else { // set call not null error message xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Station callsign is required and was blank or null."); } return returnvalue; } /* function testXastirVersionMysql() * checks the xastir database version number of a connected MySQL database against the * version range supported by the running copy of xastir. * @param aDbConnection pointer to a Connection struct describing the connection * @returns 0 if incompatible, 1 if compatible, -1 on connection failure. * * db program * v cs v cs compatible * 1 1 1 1 1 identical * 2 1 1 1 1 database newer than program (added fields, not queried) * 1 1 2 1 0 program newer than database (added fields, queries fail). * 3 2 2 1 0 different series * 2 1 3 2 0 different series * * TODO: Need function to test for available schemas with mysql_list_tables() */ int testXastirVersionMysql(Connection *aDbConnection) { int returnvalue = -1; MYSQL_RES *result; MYSQL_ROW row; int version_number; int compatible_series; char sql[] = "select version_number, compatable_series from version order by version_number desc limit 1"; int ok; // to hold mysql_query return value ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { if ((row = mysql_fetch_row(result))) { version_number = atoi((char *)row[0]); if (version_number == XASTIR_SPATIAL_DB_VERSION) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is the same as this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { compatible_series = atoi((char *)row[1]); if (version_number < XASTIR_SPATIAL_DB_VERSION && compatible_series == XASTIR_SPATIAL_DB_COMPATABLE_SERIES) { returnvalue = 1; fprintf(stderr,"Version in schema (%d) is compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); } else { fprintf(stderr,"Version in schema (%d) is not compatible with this version of xastir (%d).\n",version_number,XASTIR_SPATIAL_DB_VERSION); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version in schema (%d) is not compatible with this version of xastir (%d).",version_number,XASTIR_SPATIAL_DB_VERSION); fprintf(stderr,"%s",aDbConnection->errormessage); returnvalue = 0; } } } else { // result returned, but no rows = incompatible returnvalue = 0; fprintf(stderr,"Version table doesn't appear to contain any rows.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Version table doesn't appear to contain any rows."); } } else { fprintf(stderr,"Schema doesn't appear to contain a version table.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Schema doesn't appear to contain a version table."); } mysql_free_result(result); } else { fprintf(stderr,"Query failed, Schema doesn't appear to contain a version table.\n"); xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "Query for version table failed."); } return returnvalue; } /* function storeStationToDbMysql() */ int storeStationToDbMysql(Connection *aDbConnection, DataRow *aStation) { int returnvalue = 0; //ioparam *device = aDbConnection->descriptor; // check type of schema to use (XASTIR simple, full or APRSWorld) switch (devices[aDbConnection->interface_number].database_schema_type) { case XASTIR_SCHEMA_SIMPLE : returnvalue = storeStationSimplePointToDbMysql(aDbConnection,aStation); break; case XASTIR_SCHEMA_APRSWORLD : break; case XASTIR_SCHEMA_COMPLEX : break; // otherwise error message } return returnvalue; } /* function getAllSimplePositionsMysql() * MySQL implementation of getAllSimplePositions for a MySQL database that * does not include spatial support. * @param aDbConnection an exastir database connection struct describing * the connection. * Returns 0 for failure, 1 for success. * If failure, stores error message in aDbConnection->errormessage. */ int getAllSimplePositionsMysql(Connection *aDbConnection) { int returnvalue = 0; DataRow *p_new_station; //DataRow *p_time; int station_count = 0; // number of new stations retrieved //unsigned long x; // xastir coordinate for longitude //unsigned long y; // xastir coordinate for latitude //float lat; // latitude converted from retrieved string //float lon; // longitude converted from retrieved string char feedback[100]; //struct tm time; char sql[] = "select station, transmit_time, latitude, longitude, symbol, overlay, aprstype, origin, record_type, node_path from simpleStation order by station, transmit_time"; MYSQL_RES *result; MYSQL_ROW row; int ok; // to hold mysql_query return value ok = mysql_query(&aDbConnection->mhandle,sql); if (ok==0) { result = mysql_use_result(&aDbConnection->mhandle); if (result!=NULL) { xastir_snprintf(feedback,100,"Retrieving MySQL records\n"); stderr_and_statusline(feedback); // with mysql_use_result each call to mysql_fetch_row retrieves // a row of data from the server. Mysql_store_result might use // too much memory in retrieving a large result set all at once. while ((row = mysql_fetch_row(result))) { // retrieve data from the row // test to see if this is a valid station if (row[0]==NULL) { // station is null, skip } else { p_new_station = NULL; if (search_station_name(&p_new_station,row[0],1)) { // This station is allready in present as a DataRow in the xastir db. // Add data to the station's track. } else { // This station isn't in the xastir db. // Add a datarow using the retrieved station record from the postgis database. add_simple_station(p_new_station, row[0], row[7], row[4], row[5], row[6], row[2], row[3], row[8], row[9], row[1],(char*)MYSQL_TIMEFORMAT); station_count++; } } } } else { // error fetching the result set fprintf(stderr,"mysql error: %s\n",mysql_error(&aDbConnection->mhandle)); mysql_interpret_error(mysql_errno(&aDbConnection->mhandle),aDbConnection); } xastir_snprintf(feedback,100,"Retrieved %d new stations from MySQL\n",station_count); stderr_and_statusline(feedback); mysql_free_result(result); } else { // query didn't execute correctly mysql_interpret_error(ok,aDbConnection); } return returnvalue; } int getAllSimplePositionsMysqlInBoundingBox(Connection *aDbConnection, char *str_e_long, char *str_w_long, char *str_n_lat, char *str_s_lat) { int returnvalue = 0; return returnvalue; } /* function mysql_interpret_error() * given a mysql error code and an xastir connection, sets an appropriate * error message in the errormessage field of the connection. Interprets * numeric error codes returned by mysql functions. * @param errorcode A result returned by a mysql function that can be * interpreted as an error code. * @param aDbConnection an xastir database connection struct describing the * connection and its current state. * Note - it is possible to give this function a connection on which an * error has not occurred along with an error code. This function does * not check the connection or assess whether an error actually occurred * on it or not, it simply interprets an error code and writes the * interpretation into the connection that was passed to it. */ void mysql_interpret_error(int errorcode, Connection *aDbConnection) { fprintf(stderr,"Error communicating with MySQL database. Error code=%d\n",errorcode); switch (errorcode) { case CR_OUT_OF_MEMORY : // insufficient memory for query xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Out of Memory"); // notify the connection status listener break; // mysql_query errors case CR_COMMANDS_OUT_OF_SYNC : // commands in improper order xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Commands out of sync"); break; case CR_SERVER_GONE_ERROR : // mysql server has gone away xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Connection to server lost"); // notify the connection status listener break; case CR_SERVER_LOST : // server connection was lost during query xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Connection to server lost during query"); // notify the connection status listener break; case CR_UNKNOWN_ERROR : xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Unknown Error"); break; default: xastir_snprintf(aDbConnection->errormessage, MAX_CONNECTION_ERROR_MESSAGE, "MySQL: Unrecognized error Code [%d]", errorcode); } fprintf(stderr,"%s\n",aDbConnection->errormessage); } #endif /* HAVE_MYSQL*/ // add code for a lightweight database here #endif /* HAVE_DB*/ // Functions related to GIS, but not database specific ************************ /* Function xastirCoordToLatLongPostgresPoint * converts a point in xastir coordinates to a native postgres representation * of a point using latitude and longitude in decimal degrees in the WGS84 * projection EPSG:4326. Format is similar to WKT, but without leading POINT. * @param x longitude in xastir coordinates = decimal 100ths of a second. * @param y latitude in xastir coordinates = decimal 100ths of a second. * @param pointer to a char[ at least 24] string to hold point representation. * returns 1 on success, 0 on failure. */ int xastirCoordToLatLongPostgresPoint(long x, long y, char *wkt) { // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 360000 xastir coordinates = 1 degree // conversion to string decimal degrees handled by utility functions int returnvalue = 0; // defaults to failure float latitude; float longitude; int ok; ok = convert_from_xastir_coordinates (&longitude,&latitude, x, y); if (ok>0) { xastir_snprintf(wkt, MAX_WKT, "(%3.6f, %3.6f)", latitude, longitude); returnvalue = 1; } return returnvalue; } /* Function xastirCoordToLatLongWKT * converts a point in xastir coordinates to a well known text string (WKT) * representation of a point using latitude and longitude in decimal degrees * in the WGS84 projection EPSG:4326 * @param x longitude in xastir coordinates = decimal 100ths of a second. * @param y latitude in xastir coordinates = decimal 100ths of a second. * @param pointer to a char[29] string to hold well known text representation. * returns 1 on success, 0 on failure. */ int xastirCoordToLatLongWKT(long x, long y, char *wkt) { // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 360000 xastir coordinates = 1 degree // conversion to string decimal degrees handled by utility functions int returnvalue = 0; // defaults to failure float latitude; float longitude; int ok; ok = convert_from_xastir_coordinates (&longitude,&latitude, x, y); if (ok>0) { xastir_snprintf(wkt, MAX_WKT, "POINT(%3.6f %3.6f)", longitude, latitude); returnvalue = 1; } return returnvalue; } float xastirWKTPointToLongitude(char *wkt) { float returnvalue = 0.0; char temp[MAX_WKT]; char *space = NULL; int x; if (wkt[0]=='P' && wkt[1]=='O' && wkt[2]=='I' && wkt[3]=='N' && wkt[4]=='T' && wkt[5]=='(') { // this is a point xastir_snprintf(temp, MAX_WKT, "%s", wkt); // truncate at the space space = strchr(temp,' '); if (space != NULL) { *space = '\0'; } // remove the leading "POINT(" for (x=0; x<6; x++) { temp[x]=' '; } returnvalue = atof(temp); } return returnvalue; } float xastirWKTPointToLatitude(char *wkt) { float returnvalue = 0.0; char temp[MAX_WKT]; char *paren = NULL; int x; if (wkt[0]=='P' && wkt[1]=='O' && wkt[2]=='I' && wkt[3]=='N' && wkt[4]=='T' && wkt[5]=='(') { // this is a point xastir_snprintf(temp, MAX_WKT, "%s", wkt); // truncate at the trailing parenthesis paren = strchr(temp,')'); if (paren != NULL) { *paren = '\0'; } // convert all leading characters up to the space to spaces. for (x=0; x<(int)(strlen(temp)); x++) { if (temp[x]==' ') { x = (int)(strlen(temp)); } else { temp[x] = ' '; } } returnvalue = atof(temp); } return returnvalue; } Xastir-Release-2.2.4/src/db_gis.h0000664000175000017500000001627515151324131015523 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include "xastir.h" #include "interface.h" // ioparam struct is used to store descriptions of databases // to which to connect. extern int xastirCoordToLatLongWKT(long x, long y, char *wkt); extern int xastirCoordToLatLongPoint(long x, long y, char *wkt); extern float xastirWKTPointToLatitude(char *wkt); extern float xastirWKTPointToLongitude(char *wkt); // maximum size of a well known text representation of a geometry // 100 should be fine for points, will need to be longer for other geometries. #define MAX_WKT 100 #ifdef HAVE_DB // maximum number of open database connections #define MAX_DB_CONNECTIONS 20 // includes for database client libraries and // constants to identify database types // constants are used in interface_gui.c // where the specify order on picklist // *** Need to localize these and the schema types *** #ifdef HAVE_MYSQL // MySQL version 3.x and higher #include // mysql error message codes #include #define DB_MYSQL 1 #endif /* HAVE_MYSQL */ #ifdef HAVE_SPATIAL_DB #ifdef HAVE_POSTGIS // Postgresql with postgis #include #define DB_POSTGIS 2 #define POSTGRES_RESULTFORMAT_TEXT 0 #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL_SPATIAL // MySQL version 4.1 and higher #define DB_MYSQL_SPATIAL 3 #endif /* HAVE_MYSQL_SPATIAL */ #define MAX_DB_TYPE 3 // largest value for DB_ // used in load_data_or_default #define NODE_PATH_SIZE 56 // field size for node_path, for data_row.node_path_ptr // constants to control database schema versioning // Version of the mysql/postgresql table structures this version of xastir expects to find. // Any change or addition of database schema elements should trigger a version change. // Newer versions of xastir should require an older database to be upgraded to the // current version before allowing queries to run against that database. #define XASTIR_SPATIAL_DB_VERSION 1 // Allow grouping of forward compatible table structures allowing an older version of xastir to // interact with a database created by a newer version of xastir of the same compatble series // addition of new tables and fields shouldn't change comapatable series, but renamed, deleted, // or shortened schema elements should change compatible series (changes where a select or // or insert query run by an older version of xastir will fail against a newer database). #define XASTIR_SPATIAL_DB_COMPATABLE_SERIES 1 // constants to indicate schema to use in a database #define XASTIR_SCHEMA_SIMPLE 1 // simple station table only #define XASTIR_SCHEMA_CAD 2 // simple station table and cad objects #define XASTIR_SCHEMA_COMPLEX 3 // full aprs concept support #define XASTIR_SCHEMA_APRSWORLD 4 // aprs world implementation #define MAX_XASTIR_SCHEMA 4 // largest value for xastir_schema_ // used in load_data_or_default #define XASTIR_SCHEMA_DESCRIPTOR_MAX_SIZE 50 // largest allowed size of a localized schema descriptor string #define XASTIR_DB_DESCRIPTOR_MAX_SIZE 50 // largest allowed size of a localized dbms descriptor string // description of a database // replaced with extension of ioparam struct in interface.h /* typedef struct { char name[MAX_DEVICE_NAME+1]; // name of connection to display to user - ioparam device_name char host[255]; // hostname for database server - ioparam device_host_name int port; // port on which to connect to database server - ioparam sp char password[20]; // password to use to connect to database - ioparam device_host_password char username[20]; // username to use to connect to database int type; // type of dbms (posgresql, mysql, etc) char schema[20]; // name of database or schema to use char makeerrormessage[255]; // most recent error message from attempting to make a // connection with using this descriptor. int schema_type; // table structures to use in the database // A database schema could contain both APRSWorld // and XASTIR table structures, but a separate database // descriptor should be defined for each. char unix_socket[255]; // MySQL - unix socket parameter (path and filename) //connection_list open_connections // list of open connections to this database } DbDescriptor; */ #define MAX_CONNECTION_ERROR_MESSAGE 255 // a database connection typedef struct { int type; // type of dbms (postgresql, mysql, etc, redundant from descriptor->type) ioparam *descriptor; // connection parameters used to establish this connection // stored in ioparam struct defined in interface.h #ifdef HAVE_MYSQL MYSQL mhandle; // mysql connection #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS PGconn *phandle; // postgres connection #endif /* HAVE_POSTGIS */ char errormessage[MAX_CONNECTION_ERROR_MESSAGE]; // most recent error message on this connection. int interface_number; // number of the interface on which this connection is managed } Connection; // list of database connections //typedef struct{ // Connection *conn; // a database connection // ioparam *iface; // interface definition for the connection //} ConnectionList; //extern ConnectionList connections[MAX_IFACE_DEVICES]; extern Connection connections[MAX_IFACE_DEVICES]; extern int connections_initialized; // connection management extern int openConnection (ioparam *aioparm, Connection *conn); int initAConnection(Connection *connection, int x); extern int closeConnection (Connection *aDbConnection, int port_number); extern int testConnection(Connection *aDbConnection); int pingConnection(Connection *aDbConnection); extern char xastir_dbms_type[4][51]; extern char xastir_schema_type[5][51]; // storing and retrieving data from a database extern int storeStationToGisDb(Connection *aDbConnection, DataRow *aStation); extern int storeCadToGisDb(Connection *aDbConnection, CADRow *aCadObject); extern int storeStationSimpleToGisDb(Connection *aDbConnection, DataRow *aStation); extern int getAllSimplePositions(Connection *aDbConnection); extern int getAllSimplePositionsInBoundingBox(Connection *aDbConnection, int east, int west, int north, int south); extern ioparam simpleDbTest(void); #endif /* HAVE_SPATIAL_DB */ extern int initConnections(void); #endif /* HAVE_DB */ // structure to hold a latutude and longitude in decimal degrees typedef struct { float latitude; float longitude; } Point; Xastir-Release-2.2.4/src/db_gui.c0000664000175000017500000050010615151324131015507 0ustar hibbyhibby#include #include #include "database.h" #include "db_gis.h" #include "db_funcs.h" #include "db_gui.h" #include "snprintf.h" #include "xastir.h" #include "main.h" #include "draw_symbols.h" #include "alert.h" #include "util.h" #include "tactical_call_utils.h" #include "mutex_utils.h" #include "bulletin_gui.h" #include "fcc_data.h" #include "gps.h" #include "geocoder.h" #include "rac_data.h" #include "interface.h" #include "maps.h" #include "wx.h" #include "igate.h" #include "list_gui.h" #include "objects.h" #include "objects_gui.h" #include "track_gui.h" #include "xa_config.h" #include "x_spider.h" #include "sound.h" #include "mgrs_utils.h" // Must be last include file #include "leak_detection.h" // ======================================================================== // Global Variable Declarations // ======================================================================== // External declarations extern XmFontList fontlist1; // Menu/System fontlist // Widget globals Widget si_text; Widget db_station_info = (Widget)NULL; Widget db_station_popup = (Widget)NULL; Widget SiS_symb; Widget station_list; Widget button_store_track; Widget change_tactical_dialog = (Widget)NULL; Widget tactical_text = (Widget)NULL; // Pixmap globals Pixmap SiS_icon0, SiS_icon; // DataRow pointer DataRow *tactical_pointer = NULL; // Window decoration and position tracking int decoration_offset_x = 0; int decoration_offset_y = 0; int last_station_info_x = 0; int last_station_info_y = 0; // Station Info char *db_station_info_callsign = NULL; // Global parameter so that we can pass another value to the below // function from the Station_info() function. We need to be able to // pass this value off to the Station_data() function for special // operations like moves, where objects are on top of each other. XtPointer station_info_select_global = NULL; // Static mutex globals static xastir_mutex db_station_info_lock; static xastir_mutex db_station_popup_lock; // ======================================================================== // INITIALIZATION FUNCTIONS // ======================================================================== /* Initialize the GUI components for the database */ void db_gui_init(void) { init_critical_section( &db_station_info_lock ); init_critical_section( &db_station_popup_lock ); } // ======================================================================== // WINDOW DECORATION UTILITIES // ======================================================================== static void PosTestExpose(Widget parent, XtPointer UNUSED(clientData), XEvent * UNUSED(event), Boolean * UNUSED(continueToDispatch) ) { Position x, y; XtVaGetValues(parent, XmNx, &x, XmNy, &y, NULL); if (debug_level & 1) { fprintf(stderr,"Window Decoration Offsets: X:%d\tY:%d\n", x, y); } // Store the new-found offets in global variables decoration_offset_x = (int)x; decoration_offset_y = (int)y; // Get rid of the event handler and the test dialog XtRemoveEventHandler(parent, ExposureMask, True, (XtEventHandler) PosTestExpose, (XtPointer)NULL); // XtRemoveGrab(XtParent(parent)); // Not needed? XtDestroyWidget(XtParent(parent)); } // Here's a stupid trick that we have to do in order to find out how big // window decorations are. We need to know this information in order to // be able to kill/recreate dialogs in the same place each time. If we // were to just get and set the X/Y values of the dialog, we would creep // across the screen by the size of the decorations each time. // I've seen it. It's ugly. // void compute_decorations( void ) { Widget cdtest = (Widget)NULL; Widget cdform = (Widget)NULL; Cardinal n = 0; Arg args[50]; // We'll create a dummy dialog at 0,0, then query its // position. That'll give us back the position of the // widget. Subtract 0,0 from it (easy huh?) and we get // the size of the window decorations. Store these values // in global variables for later use. n = 0; XtSetArg(args[n], XmNx, 0); n++; XtSetArg(args[n], XmNy, 0); n++; cdtest = (Widget) XtVaCreatePopupShell("compute_decorations test", xmDialogShellWidgetClass, appshell, args, n, NULL); n = 0; XtSetArg(args[n], XmNwidth, 0); n++; // Make it tiny XtSetArg(args[n], XmNheight, 0); n++; // Make it tiny cdform = XmCreateForm(cdtest, "compute_decorations test form", args, n); XtAddEventHandler(cdform, ExposureMask, True, (XtEventHandler) PosTestExpose, (XtPointer)NULL); XtManageChild(cdform); XtManageChild(cdtest); } // ======================================================================== // STATION TRACKING FUNCTIONS // ======================================================================== /* * Change map position if necessary while tracking a station * we call it with defined station call and position */ void track_station(Widget w, char * UNUSED(call_tracked), DataRow *p_station) { long x_ofs, y_ofs; long new_lat, new_lon; if ( is_tracked_station(p_station->call_sign) ) // We want to track this station { new_lat = p_station->coord_lat; // center map to station position as default new_lon = p_station->coord_lon; x_ofs = new_lon - center_longitude; // current offset from screen center y_ofs = new_lat - center_latitude; if ((labs(x_ofs) > (screen_width*scale_x/3)) || (labs(y_ofs) > (screen_height*scale_y/3))) { // only redraw map if near border (margin 1/6 of screen at each side) if (labs(y_ofs) < (screen_height*scale_y/2)) { new_lat += y_ofs/2; // give more space in driving direction } if (labs(x_ofs) < (screen_width*scale_x/2)) { new_lon += x_ofs/2; } set_map_position(w, new_lat, new_lon); // center map to new position } search_tracked_station(&p_station); } } /* * Track from Station_data * * Called by Station_data function below from the Track Station * button in Station Info. */ void Track_from_Station_data(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; if (p_station->call_sign[0] != '\0') { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", p_station->call_sign); track_station_on = 1; } else { tracking_station_call[0] = '\0'; } } // ======================================================================== // DRAWING AND RENDERING FUNCTIONS // ======================================================================== /* * Draw trail on screen. If solid=1, draw type LineSolid, else * draw type LineOnOffDash. * * If label_all_trackpoints=1, add the callsign next to each * trackpoint. We may modify this and just add the callsign at the * start/end of each new track segment. * */ void draw_trail(Widget w, DataRow *fill, int solid) { char short_dashed[2] = {(char)1,(char)5}; char medium_dashed[2] = {(char)5,(char)5}; unsigned long lat0, lon0, lat1, lon1; // trail segment points int col_trail, col_dot; XColor rgb; long brightness; char flag1; TrackRow *ptr; if (!ok_to_draw_station(fill)) { return; } // Expire old trackpoints first. We use the // remove-station-from-display time as the expire time for // trackpoints. This can be set from the Configure->Defaults // dialog. expire_trail_points(fill, sec_clear); ptr = fill->newest_trackpoint; // Trail should have at least two points if ( (ptr != NULL) && (ptr->prev != NULL) ) { int skip_dupes = 0; // Don't skip points first time through if (debug_level & 256) { fprintf(stderr,"draw_trail called for %s with %s.\n", fill->call_sign, (solid? "Solid" : "Non-Solid")); } col_trail = trail_colors[fill->trail_color]; // define color of position dots in trail rgb.pixel = col_trail; XQueryColor(XtDisplay(w),cmap,&rgb); brightness = (long)(0.3*rgb.red + 0.55*rgb.green + 0.15*rgb.blue); if (brightness > 32000l) { col_dot = trail_colors[0x05]; // black dot on light trails } else { col_dot = trail_colors[0x06]; // white dot on dark trail } if (solid) // Used to be "JoinMiter" and "CapButt" below { (void)XSetLineAttributes(XtDisplay(w), gc, 3, LineSolid, CapRound, JoinRound); } else { // Another choice is LineDoubleDash (void)XSetLineAttributes(XtDisplay(w), gc, 3, LineOnOffDash, CapRound, JoinRound); (void)XSetDashes(XtDisplay(w), gc, 0, short_dashed, 2); } // Traverse linked list of trail points from newest to // oldest while ( (ptr != NULL) && (ptr->prev != NULL) ) { lon0 = ptr->trail_long_pos; // Trail segment start lat0 = ptr->trail_lat_pos; lon1 = ptr->prev->trail_long_pos; // Trail segment end lat1 = ptr->prev->trail_lat_pos; flag1 = ptr->flag; // Are we at the start of a new trail? if ((flag1 & TR_NEWTRK) == '\0') { int lon0_screen, lat0_screen, lon1_screen, lat1_screen; // draw trail segment // (void)XSetForeground(XtDisplay(w),gc,col_trail); draw_vector(da, lon0, lat0, lon1, lat1, gc, pixmap_final, skip_dupes); // draw position point itself // (void)XSetForeground(XtDisplay(w),gc,col_dot); draw_point(w, lon0, lat0, gc, pixmap_final, skip_dupes); // Draw the callsign to go with the point if // label_all_trackpoints=1 // if (Display_.callsign && Display_.label_all_trackpoints) { // Convert to screen coordinates lon0_screen = (lon0 - NW_corner_longitude) / scale_x; lat0_screen = (lat0 - NW_corner_latitude) / scale_y; // Convert to screen coordinates. lon1_screen = (lon1 - NW_corner_longitude) / scale_x; lat1_screen = (lat1 - NW_corner_latitude) / scale_y; // The last position already gets its callsign // string drawn, plus that gets shifted based on // other parameters. Draw both points of all // line segments except that one. This will // result in strings getting drawn twice at // times, but they overlay on top of each other // so no big deal. // if (ptr != fill->newest_trackpoint) { draw_nice_string(da, pixmap_final, letter_style, lon0_screen+10, lat0_screen, fill->call_sign, 0x08, 0x0f, strlen(fill->call_sign)); // If not same screen position as last drawn if (lon0_screen != lon1_screen && lat0_screen != lat1_screen) { draw_nice_string(da, pixmap_final, letter_style, lon1_screen+10, lat1_screen, fill->call_sign, 0x08, 0x0f, strlen(fill->call_sign)); } } } } ptr = ptr->prev; skip_dupes = 1; } (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); } else if (debug_level & 256) { fprintf(stderr,"Trail for %s does not contain 2 or more points.\n", fill->call_sign); } } // display_station // // single is 1 if the calling station wants to update only a // single station. If updating multiple stations in a row, then // "single" will be passed to us as a zero. // // If current course/speed/altitude are absent, we check the last // track point to try to snag those numbers. // void display_station(Widget w, DataRow *p_station, int single) { char temp_altitude[20]; char temp_course[20]; char temp_speed[20]; char dr_speed[20]; char temp_call[MAX_TACTICAL_CALL+1]; char wx_tm[50]; char temp_wx_temp[30]; char temp_wx_wind[40]; char temp_my_distance[20]; char temp_my_course[20]; char temp1_my_course[20]; char temp2_my_gauge_data[50]; time_t temp_sec_heard; int temp_show_last_heard; long l_lon, l_lat; char orient; float value; char tmp[7+1]; int speed_ok = 0; int course_ok = 0; int wx_ghost = 0; Pixmap drawing_target; WeatherRow *weather = p_station->weather_data; time_t secs_now = sec_now(); int ambiguity_flag; long ambiguity_coord_lon, ambiguity_coord_lat; size_t temp_len; if (debug_level & 128) { fprintf(stderr,"Display station (%s) called for Single=%d.\n", p_station->call_sign, single); } if (!ok_to_draw_station(p_station)) { return; } // Set up call string for display if (Display_.callsign) { if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { // Display tactical callsign instead if it has one // defined. xastir_snprintf(temp_call, sizeof(temp_call), "%s", p_station->tactical_call_sign); } else { // Display normal callsign. xastir_snprintf(temp_call, sizeof(temp_call), "%s", p_station->call_sign); } } else { temp_call[0] = '\0'; } // Set up altitude string for display temp_altitude[0] = '\0'; if (Display_.altitude) { // Check whether we have altitude in the current data if (strlen(p_station->altitude)>0) { // Found it in the current data xastir_snprintf(temp_altitude, sizeof(temp_altitude), "%.0f%s", atof(p_station->altitude) * cvt_m2len, un_alt); } // Else check whether the previous position had altitude. // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { if ( p_station->newest_trackpoint->prev->altitude > -99999l) { // Found it in the tracklog xastir_snprintf(temp_altitude, sizeof(temp_altitude), "%.0f%s", (float)(p_station->newest_trackpoint->prev->altitude * cvt_dm2len), un_alt); // fprintf(stderr,"Trail data with altitude: %s : %s\n", // p_station->call_sign, // temp_altitude); } else { //fprintf(stderr,"Trail data w/o altitude %s\n", // p_station->call_sign); } } } // Set up speed and course strings for display temp_speed[0] = '\0'; dr_speed[0] = '\0'; temp_course[0] = '\0'; if (Display_.speed || Display_.dr_data) { // don't display 'fixed' stations speed and course. // Check whether we have speed in the current data and it's // >= 0. if ( (strlen(p_station->speed)>0) && (atof(p_station->speed) >= 0) ) { speed_ok++; xastir_snprintf(tmp, sizeof(tmp), "%s", un_spd); if (Display_.speed_short) { tmp[0] = '\0'; // without unit } xastir_snprintf(temp_speed, sizeof(temp_speed), "%.0f%s", atof(p_station->speed)*cvt_kn2len,tmp); } // Else check whether the previous position had speed // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { xastir_snprintf(tmp, sizeof(tmp), "%s", un_spd); if (Display_.speed_short) { tmp[0] = '\0'; // without unit } if ( p_station->newest_trackpoint->prev->speed > 0) { speed_ok++; xastir_snprintf(temp_speed, sizeof(temp_speed), "%.0f%s", p_station->newest_trackpoint->prev->speed * cvt_hm2len, tmp); } } } if (Display_.course || Display_.dr_data) { // Check whether we have course in the current data if ( (strlen(p_station->course)>0) && (atof(p_station->course) > 0) ) { course_ok++; xastir_snprintf(temp_course, sizeof(temp_course), "%.0f\xB0", atof(p_station->course)); } // Else check whether the previous position had a course // Note that newest_trackpoint if it exists should be the // same as the current data, so we have to go back one // further trackpoint. else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) ) { if( p_station->newest_trackpoint->prev->course > 0 ) { course_ok++; xastir_snprintf(temp_course, sizeof(temp_course), "%.0f\xB0", (float)p_station->newest_trackpoint->prev->course); } } } // Save the speed into the dr string for later xastir_snprintf(dr_speed, sizeof(dr_speed), "%s", temp_speed); if (!speed_ok || !Display_.speed) { temp_speed[0] = '\0'; } if (!course_ok || !Display_.course) { temp_course[0] = '\0'; } // Set up distance and bearing strings for display temp_my_distance[0] = '\0'; temp_my_course[0] = '\0'; if (Display_.dist_bearing && strcmp(p_station->call_sign,my_callsign) != 0) { l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles, convert to current measurement standard value = cvt_kn2len * calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,temp1_my_course,sizeof(temp1_my_course)); if (value < 5.0) { sprintf(temp_my_distance,"%0.1f%s",value,un_dst); } else { sprintf(temp_my_distance,"%0.0f%s",value,un_dst); } xastir_snprintf(temp_my_course, sizeof(temp_my_course), "%.0f\xB0", atof(temp1_my_course)); } // Set up weather strings for display temp_wx_temp[0] = '\0'; temp_wx_wind[0] = '\0'; if (weather != NULL) { // wx_ghost = 1 if the weather data is too old to display wx_ghost = (int)(((sec_old + weather->wx_sec_time)) < secs_now); } if (Display_.weather && Display_.weather_text && weather != NULL // We have weather data && !wx_ghost) // Weather is current, display it { if (strlen(weather->wx_temp) > 0) { xastir_snprintf(tmp, sizeof(tmp), "T:"); if (Display_.temperature_only) { tmp[0] = '\0'; } if (english_units) xastir_snprintf(temp_wx_temp, sizeof(temp_wx_temp), "%s%.0f\xB0%s", tmp, atof(weather->wx_temp),"F "); else xastir_snprintf(temp_wx_temp, sizeof(temp_wx_temp), "%s%.0f\xB0%s", tmp,((atof(weather->wx_temp)-32.0)*5.0)/9.0,"C "); } if (!Display_.temperature_only) { if (strlen(weather->wx_hum) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "H:%.0f%%", atof(weather->wx_hum)); strncat(temp_wx_temp, wx_tm, sizeof(temp_wx_temp) - 1 - strlen(temp_wx_temp)); } if (strlen(weather->wx_speed) > 0) { xastir_snprintf(temp_wx_wind, sizeof(temp_wx_wind), "S:%.0f%s ", atof(weather->wx_speed)*cvt_mi2len,un_spd); } if (strlen(weather->wx_gust) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "G:%.0f%s ", atof(weather->wx_gust)*cvt_mi2len,un_spd); strncat(temp_wx_wind, wx_tm, sizeof(temp_wx_wind) - 1 - strlen(temp_wx_wind)); } if (strlen(weather->wx_course) > 0) { xastir_snprintf(wx_tm, sizeof(wx_tm), "C:%.0f\xB0", atof(weather->wx_course)); strncat(temp_wx_wind, wx_tm, sizeof(temp_wx_wind) - 1 - strlen(temp_wx_wind)); } temp_len = strlen(temp_wx_wind); if ((temp_len > 0) && (temp_wx_wind[temp_len-1] == ' ')) { temp_wx_wind[temp_len-1] = '\0'; // delete blank at EOL } } temp_len = strlen(temp_wx_temp); if ((temp_len > 0) && (temp_wx_temp[strlen(temp_wx_temp)-1] == ' ')) { temp_wx_temp[temp_len-1] = '\0'; // delete blank at EOL } } (void)remove_trailing_asterisk(p_station->call_sign); // DK7IN: is this needed here? if (Display_.symbol_rotate) { orient = symbol_orient(p_station->course); // rotate symbol } else { orient = ' '; } // Prevents my own call from "ghosting"? // temp_sec_heard = (strcmp(p_station->call_sign, my_callsign) == 0) ? secs_now: p_station->sec_heard; temp_sec_heard = (is_my_station(p_station)) ? secs_now : p_station->sec_heard; // Check whether it's a locally-owned object/item // if ( (is_my_call(p_station->origin,1)) // If station is owned by me (including SSID) // && ( (p_station->flag & ST_OBJECT) // And it's an object // || (p_station->flag & ST_ITEM) ) ) { // or an item // if ( is_my_object_item(p_station) ) { // temp_sec_heard = secs_now; // We don't want our own objects/items to "ghost" // } // Show last heard times only for others stations and their // objects/items. // temp_show_last_heard = (strcmp(p_station->call_sign, my_callsign) == 0) ? 0 : Display_.last_heard; temp_show_last_heard = (is_my_station(p_station)) ? 0 : Display_.last_heard; //------------------------------------------------------------------------------------------ // If we're only planning on updating a single station at this time, we go // through the drawing calls twice, the first time drawing directly onto // the screen. if (!pending_ID_message && single) { drawing_target = XtWindow(da); } else { drawing_target = pixmap_final; } //_do_the_drawing: // Check whether it's a locally-owned object/item // if ( (is_my_call(p_station->origin,1)) // If station is owned by me (including SSID) // && ( (p_station->flag & ST_OBJECT) // And it's an object // || (p_station->flag & ST_ITEM ) ) ) { // or an item // if ( is_my_object_item(p_station) ) { // temp_sec_heard = secs_now; // We don't want our own objects/items to "ghost" // This isn't quite right since if it's a moving object, passing an incorrect // sec_heard should give the wrong results. // } ambiguity_flag = 0; // Default if (Display_.ambiguity && p_station->pos_amb) { ambiguity_flag = 1; draw_ambiguity(p_station->coord_lon, p_station->coord_lat, p_station->pos_amb, &ambiguity_coord_lon, // New longitude may get passed back to us &ambiguity_coord_lat, // New latitude may get passed back to us temp_sec_heard, drawing_target); } // Check for DF'ing data, draw DF circles if present and enabled if (Display_.df_data && strlen(p_station->signal_gain) == 7) // There's an SHGD defined { //fprintf(stderr,"SHGD:%s\n",p_station->signal_gain); draw_DF_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->signal_gain, temp_sec_heard, drawing_target); } // Check for DF'ing beam heading/NRQ data if (Display_.df_data && (strlen(p_station->bearing) == 3) && (strlen(p_station->NRQ) == 3)) { //fprintf(stderr,"Bearing: %s\n",p_station->signal_gain,NRQ); if (p_station->df_color == -1) { p_station->df_color = rand() % MAX_TRAIL_COLORS; } draw_bearing( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->course, p_station->bearing, p_station->NRQ, trail_colors[p_station->df_color], Display_.df_beamwidth_data, Display_.df_bearing_data, temp_sec_heard, drawing_target); } // Check whether to draw dead-reckoning data by KJ5O if (Display_.dr_data && ( (p_station->flag & ST_MOVING) // && (p_station->newest_trackpoint!=0 && course_ok && speed_ok && scale_y < 8000 && atof(dr_speed) > 0) ) { // Does it make sense to try to do dead-reckoning on an // object that has position ambiguity enabled? I don't // think so! // if ( ! ambiguity_flag && ( (secs_now-temp_sec_heard) < dead_reckoning_timeout) ) { draw_deadreckoning_features(p_station, drawing_target, w); } } if (p_station->aprs_symbol.area_object.type != AREA_NONE) { draw_area( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->aprs_symbol.area_object.type, p_station->aprs_symbol.area_object.color, p_station->aprs_symbol.area_object.sqrt_lat_off, p_station->aprs_symbol.area_object.sqrt_lon_off, p_station->aprs_symbol.area_object.corridor_width, temp_sec_heard, drawing_target); } // Draw additional stuff if this is the tracked station if (is_tracked_station(p_station->call_sign)) { //WE7U draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0020 * scale_y, colors[0x0e], // Yellow drawing_target, temp_sec_heard); draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0023 * scale_y, colors[0x44], // Red drawing_target, temp_sec_heard); draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, 0.0026 * scale_y, colors[0x61], // Blue drawing_target, temp_sec_heard); } // Draw additional stuff if this is a storm and the weather data // is not too old to display. if ( (weather != NULL) && weather->wx_storm && !wx_ghost ) { char temp[4]; //fprintf(stderr,"Plotting a storm symbol:%s:%s:%s:\n", // weather->wx_hurricane_radius, // weather->wx_trop_storm_radius, // weather->wx_whole_gale_radius); // Still need to draw the circles in different colors for the // different ranges. Might be nice to tint it as well. xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_hurricane_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x44], // Red drawing_target, temp_sec_heard); } xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_trop_storm_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x0e], // Yellow drawing_target, temp_sec_heard); } xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_whole_gale_radius); if ( (temp[0] != '\0') && (strncmp(temp,"000",3) != 0) ) { draw_pod_circle( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, atof(temp) * 1.15078, // nautical miles to miles colors[0x0a], // Green drawing_target, temp_sec_heard); } } // Draw wind barb if selected and we have wind, but not a severe // storm (wind barbs just confuse the matter). if (Display_.weather && Display_.wind_barb && weather != NULL && atoi(weather->wx_speed) >= 5 && !weather->wx_storm && !wx_ghost ) { draw_wind_barb( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, weather->wx_speed, weather->wx_course, temp_sec_heard, drawing_target); } // WE7U // // Draw truncation/rounding rectangles plus error ellipses. // // // We need to keep track of ellipse northing/easting radii plus // rectangle northing/easting offsets. If both sets are present // we'll need to draw the summation of both geometric figures. // Check that the math works at/near the poles. We may need to keep // track of truncation/rounding rectangles separately if some // devices or software use one method, some the other. // if (!ambiguity_flag) { // Check whether we're at a close enough zoom level to have // the ellipses/rectangles be visible, else skip drawing for // efficiency. // //fprintf(stderr,"scale_y: %ld\t", scale_y); if (scale_y < 17) // 60' figures are good out to about zoom 16 { // Here we may have to check what type of device is being used (if // possible to determine) to decide whether to draw a truncation/ // rounding rectangles or GPS error ellipses. Truncation rectangles // have the symbol at one corner, rounding have it in the middle. // Based on the precision inherent in the packet we wish to draw a // GPS error ellipse instead, the decision point is when the packet // precision is adequate to show ~6 meters. // // OpenTracker APRS: Truncation, rectangle // OpenTracker Base91:Truncation, ellipse // OpenTracker OpenTrac: Truncation, ellipse // TinyTrak APRS: Truncation, rectangle // TinyTrak NMEA: Truncation, ellipse/rectangle based on precision // TinyTrak Mic-E: Truncation, rectangle // GPGGA: Truncation, ellipse/rectangle based on precision/HDOP/Augmentation // GPRMC: Truncation, ellipse/rectangle based on precision // GPGLL: Truncation, ellipse/rectangle based on precision // Xastir APRS: Truncation, rectangle // Xastir Base91: Truncation, ellipse // UI-View APRS: ??, rectangle // UI-View Base91: ??, ellipse // APRS+SA APRS: ??, rectangle // APRS+SA Base91: ??, ellipse // PocketAPRS: ??, rectangle // SmartAPRS: ??, rectangle // HamHUD: Truncation, ?? // HamHUD GPRMC: Truncation, ellipse/rectangle based on precision // Linksys NSLU2: ??, rectangle // AGW Tracker: ??, ?? // APRSPoint: ??, rectangle // APRSce: ??, rectangle // APRSdos APRS: ??, rectangle // APRSdos Base91: ??, ellipse // BalloonTrack: ??, ?? // DMapper: ??, ?? // JavAPRS APRS: ??, rectangle // JavAPRS Base91: ??, ellipse // WinAPRS APRS: ??, rectangle // WinAPRS Base91: ??, ellipse // MacAPRS APRS: ??, rectangle // MacAPRS Base91: ??, ellipse // MacAPRSOSX APRS: ??, rectangle // MacAPRSOSX Base91: ??, ellipse // X-APRS APRS: ??, rectangle // X-APRS Base91: ??, ellipse // OziAPRS: ??, rectangle // NetAPRS: ??, rectangle // APRS SCS: ??, ?? // RadioMobile: ??, rectangle // KPC-3: ??, rectangle // MicroTNC: ??, rectangle // TigerTrak: ??, rectangle // PicoPacket: ??, rectangle // MIM: ??, rectangle // Mic-Encoder: ??, rectangle // Pic-Encoder: ??, rectangle // Generic Mic-E: ??, rectangle // D7A/D7E: ??, rectangle // D700A: ??, rectangle // Alinco DR-135: ??, rectangle // Alinco DR-620: ??, rectangle // Alinco DR-635: ??, rectangle // Other: ??, ?? // Initial try at drawing the error_ellipse_radius // circles around the posit. error_ellipse_radius is in // centimeters. Convert from cm to miles for // draw_pod_circle(). // /* draw_pod_circle( p_station->coord_lon, p_station->coord_lat, p_station->error_ellipse_radius / 100000.0 * 0.62137, // cm to mi colors[0x0f], // White drawing_target, temp_sec_heard); */ draw_precision_rectangle( p_station->coord_lon, p_station->coord_lat, p_station->error_ellipse_radius, // centimeters (not implemented yet) p_station->lat_precision, // 100ths of seconds latitude p_station->lon_precision, // 100ths of seconds longitude colors[0x0f], // White drawing_target); // Perhaps draw vectors from the symbol out to the borders of these // odd figures? Draw an outline without vectors to the symbol? // Have the color match the track color assigned to that station so // the geometric figures can be kept separate from nearby stations? // // draw_truncation_rectangle + error_ellipse (symbol at corner) // draw_rounding_rectangle + error_ellipse (symbol in middle) } } // Zero out the variable in case we don't use it below. temp2_my_gauge_data[0] = '\0'; // If an H2O object, create a timestamp + last comment variable // (which should contain gage-height and/or water-flow numbers) // for use in the draw_symbol() function below. if (p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'w' && ( p_station->flag & ST_OBJECT // And it's an object || p_station->flag & ST_ITEM) ) // or an item { // NOTE: Also check whether it was sent by the Firenet GAGE // script?? "GAGE-*" // NOTE: Check most recent comment time against // p_station->sec_heard. If they don't match, don't display the // comment. This will make sure that older comment data doesn't get // displayed which can be quite misleading for stream gauges. // Check whether we have any comment data at all. If so, // the first one will be the most recent comment and the one // we wish to display. if (p_station->comment_data != NULL) { CommentRow *ptr; // time_t sec; // struct tm *time; ptr = p_station->comment_data; // Check most recent comment's sec_heard time against // the station record's sec_heard time. If they don't // match, don't display the comment. This will make // sure that older comment data doesn't get displayed // which can be quite misleading for stream gauges. if (p_station->sec_heard == ptr->sec_heard) { // Note that text_ptr can be an empty string. // That's ok. // Also print the sec_heard timestamp so we know // when this particular gauge data was received // (Very important!). // sec = ptr->sec_heard; // time = localtime(&sec); xastir_snprintf(temp2_my_gauge_data, sizeof(temp2_my_gauge_data), "%s", // "%02d/%02d %02d:%02d %s", // time->tm_mon + 1, // time->tm_mday, // time->tm_hour, // time->tm_min, ptr->text_ptr); //fprintf(stderr, "%s\n", temp2_my_gauge_data); } } } draw_symbol(w, p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay, (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, temp_call, temp_altitude, temp_course, // ?? temp_speed, // ?? temp_my_distance, temp_my_course, // Display only if wx temp is current (wx_ghost) ? "" : temp_wx_temp, // Display only if wind speed is current (wx_ghost) ? "" : temp_wx_wind, temp_sec_heard, temp_show_last_heard, drawing_target, orient, p_station->aprs_symbol.area_object.type, p_station->signpost, temp2_my_gauge_data, 1); // Increment "currently_selected_stations" // If it's a Waypoint symbol, draw a line from it to the // transmitting station. if (p_station->aprs_symbol.aprs_type == '\\' && p_station->aprs_symbol.aprs_symbol == '/') { draw_WP_line(p_station, ambiguity_flag, ambiguity_coord_lon, ambiguity_coord_lat, drawing_target, w); } // Draw other points associated with the station, if any. // KG4NBB if (debug_level & 128) { fprintf(stderr," Number of multipoints = %d\n",p_station->num_multipoints); } if (p_station->num_multipoints != 0) { draw_multipoints( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->num_multipoints, p_station->multipoint_data->multipoints, p_station->type, p_station->style, temp_sec_heard, drawing_target); } temp_sec_heard = p_station->sec_heard; // DK7IN: ??? if (Display_.phg && (!(p_station->flag & ST_MOVING) || Display_.phg_of_moving)) { // Check for Map View "eyeball" symbol if ( strncmp(p_station->power_gain,"RNG",3) == 0 && p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'E' ) { // Map View "eyeball" symbol. Don't draw the RNG ring // for it. } else if (strlen(p_station->power_gain) == 7) { // Station has PHG or RNG defined // draw_phg_rng( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, p_station->power_gain, temp_sec_heard, drawing_target); } else if (Display_.default_phg && !(p_station->flag & (ST_OBJECT | ST_ITEM))) { // No PHG defined and not an object/item. Display a PHG // of 3130 as default as specified in the spec: 9W, 3dB // omni at 20 feet = 6.2 mile PHG radius. // draw_phg_rng( (ambiguity_flag) ? ambiguity_coord_lon : p_station->coord_lon, (ambiguity_flag) ? ambiguity_coord_lat : p_station->coord_lat, "PHG3130", temp_sec_heard, drawing_target); } } // Draw minimum proximity circle? if (p_station->probability_min[0] != '\0') { double range = atof(p_station->probability_min); // Draw red circle draw_pod_circle(p_station->coord_lon, p_station->coord_lat, range, colors[0x44], drawing_target, temp_sec_heard); } // Draw maximum proximity circle? if (p_station->probability_max[0] != '\0') { double range = atof(p_station->probability_max); // Draw red circle draw_pod_circle(p_station->coord_lon, p_station->coord_lat, range, colors[0x44], drawing_target, temp_sec_heard); } // DEBUG STUFF // draw_pod_circle(x_long, y_lat, 1.5, colors[0x44], where); // draw_pod_circle(x_long, y_lat, 3.0, colors[0x44], where); // Now if we just did the single drawing, we want to go back and draw // the same things onto pixmap_final so that when we do update from it // to the screen all of the stuff will be there. // if (drawing_target == XtWindow(da)) { // drawing_target = pixmap_final; // goto _do_the_drawing; // } } // draw line relative void draw_test_line(Widget w, long x, long y, long dx, long dy, long ofs) { x += screen_width - 10 - ofs; y += screen_height - 10; (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(x), l16(y), l16(x+dx), l16(y+dy)); } // draw text void draw_ruler_text(Widget w, char * text, long ofs) { int x,y; int len; len = (int)strlen(text); x = screen_width - 10 - ofs / 2; y = screen_height - 10; x -= len * 3; y -= 3; if (draw_labeled_grid_border==TRUE) { // move text up a few pixels to leave space for labeled border y = y - 15; x = x - 10; } draw_nice_string(w,pixmap_final,letter_style,x,y,text,0x10,0x20,len); } // Compute Range Scale in miles or kilometers. // // For this we need to figure out x-distance and y-distance across // the screen. Take the smaller of the two, then figure out which // power of 2 miles fits from the center to the edge of the screen. // "For metric, use the nearest whole number kilometer in powers of // two of 1.5 km above the 1 mile scale. At 1 mile and below, do // the conversion to meters where 1 mi is equal to 1600m..." (Bob // Bruninga's words). void draw_range_scale(Widget w) { Dimension width, height; long x, x0, y, y0; double x_miles_km, y_miles_km, distance; char temp_course[10]; long temp; double temp2; long range; int small_flag = 0; int x_screen, y_screen; int len; char text[80]; int border_offset = 0; // number of pixels to offset the scale if a labeled map border is drawn // Find out the screen values XtVaGetValues(da,XmNwidth, &width, XmNheight, &height, NULL); // Convert points to Xastir coordinate system // X x = center_longitude - ((width *scale_x)/2); x0 = center_longitude; // Center of screen // Y y = center_latitude - ((height*scale_y)/2); y0 = center_latitude; // Center of screen // Compute distance from center to each edge // X distance. Keep Y constant. x_miles_km = cvt_kn2len * calc_distance_course(y0,x0,y0,x,temp_course,sizeof(temp_course)); // Y distance. Keep X constant. y_miles_km = cvt_kn2len * calc_distance_course(y0,x0,y,x0,temp_course,sizeof(temp_course)); // Choose the smaller distance if (x_miles_km < y_miles_km) { distance = x_miles_km; } else { distance = y_miles_km; } // Convert it to nearest power of two that fits inside if (english_units) // English units { if (distance >= 1.0) { // Shift it right until it is less than 2. temp = (long)distance; range = 1; while (temp >= 2) { temp = temp / 2; range = range * 2; } } else // Distance is less than one { // divide 1.0 by 2 until distance is greater small_flag++; temp2 = 1.0; range = 1; while (temp2 > distance) { //fprintf(stderr,"temp2: %f, distance: %f\n", temp2, distance); temp2 = temp2 / 2.0; range = range * 2; } } } else // Metric units { if (distance >= 12800.0) { range = 12800; } else if (distance >= 6400.0) { range = 6400; } else if (distance >= 3200.0) { range = 3200; } else if (distance >= 1600.0) { range = 1600; } else if (distance >= 800.0) { range = 800; } else if (distance >= 400.0) { range = 400; } else if (distance >= 200.0) { range = 200; } else if (distance >= 100.0) { range = 100; } else if (distance >= 50.0) { range = 50; } else if (distance >= 25.0) { range = 25; } else if (distance >= 12.0) { range = 12; } else if (distance >= 6.0) { range = 6; } else if (distance >= 3.0) { range = 3; } else { small_flag++; if (distance >= 1.6) { range = 1600; } else if (distance >= 0.8) { range = 800; } else if (distance >= 0.4) { range = 400; } else if (distance >= 0.2) { range = 200; } else if (distance >= 0.1) { range = 100; } else if (distance >= 0.05) { range = 50; } else if (distance >= 0.025) { range = 25; } else { range = 12; } } } //fprintf(stderr,"Distance: %f\t", distance); //fprintf(stderr,"Range: %ld\n", range); if (english_units) // English units { if (small_flag) { xastir_snprintf(text, sizeof(text), "%s 1/%ld mi", langcode("RANGE001"), // "RANGE SCALE" range); } else { xastir_snprintf(text, sizeof(text), "%s %ld mi", langcode("RANGE001"), // "RANGE SCALE" range); } } else // Metric units { if (small_flag) { xastir_snprintf(text, sizeof(text), "%s %ld m", langcode("RANGE001"), // "RANGE SCALE" range); } else { xastir_snprintf(text, sizeof(text), "%s %ld km", langcode("RANGE001"), // "RANGE SCALE" range); } } // Draw it on the screen len = (int)strlen(text); x_screen = 10; y_screen = screen_height - 5; if ((draw_labeled_grid_border==TRUE) && long_lat_grid) { border_offset = get_rotated_label_text_length_pixels(w, "0", FONT_BORDER) + 3; // don't draw range scale right on top of labeled border, move into map draw_nice_string(w,pixmap_final,letter_style,x_screen+border_offset,y_screen-border_offset-3,text,0x10,0x20,len); } else { // draw range scale in lower left corder of map draw_nice_string(w,pixmap_final,letter_style,x_screen,y_screen,text,0x10,0x20,len); } } /* * Calculate and draw ruler on right bottom of screen */ void draw_ruler(Widget w) { int ruler_pix; // min size of ruler in pixel char unit[5+1]; // units char text[20]; // ruler text double ruler_siz; // len of ruler in meters etc. int mag; int i; int dx, dy; int border_offset = 0; // number of pixels to offset the scale if a labeled map border is drawn ruler_pix = (int)(screen_width / 9); // ruler size (in pixels) ruler_siz = ruler_pix * scale_x * calc_dscale_x(center_longitude,center_latitude); // size in meter if(english_units) { if (ruler_siz > 1609.3/2) { xastir_snprintf(unit, sizeof(unit), "mi"); ruler_siz /= 1609.3; } else { xastir_snprintf(unit, sizeof(unit), "ft"); ruler_siz /= 0.3048; } } else { xastir_snprintf(unit, sizeof(unit), "m"); if (ruler_siz > 1000/2) { xastir_snprintf(unit, sizeof(unit), "km"); ruler_siz /= 1000.0; } } mag = 1; while (ruler_siz > 5.0) // get magnitude { ruler_siz /= 10.0; mag *= 10; } // select best value and adjust ruler length if (ruler_siz > 2.0) { ruler_pix = (int)(ruler_pix * 5.0 / ruler_siz +0.5); ruler_siz = 5.0 * mag; } else { if (ruler_siz > 1.0) { ruler_pix = (int)(ruler_pix * 2.0 / ruler_siz +0.5); ruler_siz = 2.0 * mag; } else { ruler_pix = (int)(ruler_pix * 1.0 / ruler_siz +0.5); ruler_siz = 1.0 * mag; } } xastir_snprintf(text, sizeof(text), "%.0f %s",ruler_siz,unit); // Set up string //fprintf(stderr,"Ruler: %s, %d\n",text,ruler_pix); (void)XSetLineAttributes(XtDisplay(w),gc,1,LineSolid,CapRound,JoinRound); (void)XSetForeground(XtDisplay(w),gc,colors[0x20]); // white for (i = 8; i >= 0; i--) { dx = (((i / 3)+1) % 3)-1; // looks complicated... dy = (((i % 3)+1) % 3)-1; // I want 0 / 0 as last entry if ((draw_labeled_grid_border==TRUE) && long_lat_grid) { // move ruler up a few pixels to leave space for labeled border border_offset = get_rotated_label_text_length_pixels(w, "0", FONT_BORDER) + 3; dy = dy - border_offset - 3; dx = dx - border_offset - 3; } // If text on black background style selected, draw a black // rectangle in that corner of the map first so that the // scale lines show up well. // // If first time through and text-on-black style if ( (i == 8) && (letter_style == 2) ) { XSetForeground(XtDisplay(w),gc,colors[0x10]); // black (void)XSetLineAttributes(XtDisplay(w),gc,20,LineSolid,CapProjecting,JoinMiter); draw_test_line(w, dx, dy+5, ruler_pix, 0, ruler_pix); // Reset to needed parameters for drawing the scale (void)XSetLineAttributes(XtDisplay(w),gc,1,LineSolid,CapRound,JoinRound); (void)XSetForeground(XtDisplay(w),gc,colors[0x20]); // white } if (i == 0) { (void)XSetForeground(XtDisplay(w),gc,colors[0x10]); // black } draw_test_line(w,dx,dy, ruler_pix,0,ruler_pix); // hor line draw_test_line(w,dx,dy, 0,5, ruler_pix); // ver left draw_test_line(w,dx+ruler_pix,dy, 0,5, ruler_pix); // ver right if (text[0] == '2') { draw_test_line(w,dx+0.5*ruler_pix,dy,0,3,ruler_pix); // ver middle } if (text[0] == '5') { draw_test_line(w,dx+0.2*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.4*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.6*ruler_pix,dy,0,3,ruler_pix); // ver middle draw_test_line(w,dx+0.8*ruler_pix,dy,0,3,ruler_pix); // ver middle } } draw_ruler_text(w,text,ruler_pix); draw_range_scale(w); } /* * Display all stations on screen (trail, symbol, info text) */ void display_file(Widget w) { DataRow *p_station; // pointer to station data time_t temp_sec_heard; // time last heard time_t t_clr, t_old, now; if(debug_level & 1) { fprintf(stderr,"Display File Start\n"); } // Keep track of how many station we are currently displaying on // the screen. We'll display this number and the total number // of objects in the database as displayed/total on the status // line. Each time we call display_station() we'll bump this // number. currently_selected_stations = 0; // Draw probability of detection circle, if enabled //draw_pod_circle(64000000l, 32400000l, 10, colors[0x44], pixmap_final); now = sec_now(); t_old = now - sec_old; // precalc compare times t_clr = now - sec_clear; temp_sec_heard = 0l; p_station = t_oldest; // start with oldest station, have newest on top at t_newest while (p_station != NULL) { if (debug_level & 64) { fprintf(stderr,"display_file: Examining %s\n", p_station->call_sign); } // Skip deleted stations if ( !(p_station->flag & ST_ACTIVE) ) { if (debug_level & 64) { fprintf(stderr,"display_file: ignored deleted %s\n", p_station->call_sign); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } // Check for my objects/items // if ( (is_my_call(p_station->origin, 1) // If station is owned by me (including SSID) // && ( p_station->flag & ST_OBJECT // And it's an object // || p_station->flag & ST_ITEM) ) ) { // or an item // // This case is covered by the is_my_station() call, so we // don't need it here. // if (is_my_object_item(p_station) ) { // temp_sec_heard = now; // } // else { // Callsign match here includes checking SSID // temp_sec_heard = (is_my_call(p_station->call_sign,1))? now: p_station->sec_heard; temp_sec_heard = (is_my_station(p_station)) ? now : p_station->sec_heard; // } // Skip far away station if ((p_station->flag & ST_INVIEW) == 0) { // we make better use of the In View flag in the future if (debug_level & 256) { fprintf(stderr,"display_file: Station outside viewport\n"); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } // Skip if we're running an altnet and this station's not in // it if ( altnet && !is_altnet(p_station) ) { if (debug_level & 64) { fprintf(stderr,"display_file: Station %s skipped altnet\n", p_station->call_sign); } // Skip to the next station in the list p_station = p_station->t_newer; // next station continue; } if (debug_level & 256) { fprintf(stderr,"display_file: Inview, check for trail\n"); } // Display trail if we should if (Display_.trail && p_station->newest_trackpoint != NULL) { // ???????????? what is the difference? : if (debug_level & 256) { fprintf(stderr,"%s: Trails on and have track data\n", "display_file"); } if (temp_sec_heard > t_clr) { // Not too old, so draw trail if (temp_sec_heard > t_old) { // New trail, so draw solid trail if (debug_level & 256) { fprintf(stderr,"Drawing Solid trail for %s, secs old: %ld\n", p_station->call_sign, (long)(now - temp_sec_heard) ); } draw_trail(w,p_station,1); } else { if (debug_level & 256) { fprintf(stderr,"Drawing trail for %s, secs old: %ld\n", p_station->call_sign, (long)(now - temp_sec_heard) ); } draw_trail(w,p_station,0); } } else { if (debug_level & 256) { fprintf(stderr,"Station too old\n"); } } } else { if (debug_level & 256) { fprintf(stderr,"Station trails %d, track data %lx\n", Display_.trail, (long int)p_station->newest_trackpoint); } } if (debug_level & 256) { fprintf(stderr,"calling display_station()\n"); } // This routine will also update the // currently_selected_stations variable, if we're // updating all of the stations at once. display_station(w,p_station,0); p_station = p_station->t_newer; // next station } draw_ruler(w); Draw_All_CAD_Objects(w); // Draw all CAD objects, duh. // Check if we should mark where we found an address if (mark_destination) { int offset; // Set the line width in the GC. Make it nice and fat. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 7, LineSolid, CapButt,JoinMiter); (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); (void)(void)XSetFunction (XtDisplay (da), gc_tint, GXxor); // Scale it so that the 'X' stays the same size at all zoom // levels. offset = 25 * scale_y; // Make a big 'X' draw_vector(w, destination_coord_lon-offset, // x1 destination_coord_lat-offset, // y1 destination_coord_lon+offset, // x2 destination_coord_lat+offset, // y2 gc_tint, pixmap_final, 0); draw_vector(w, destination_coord_lon+offset, // x1 destination_coord_lat-offset, // y1 destination_coord_lon-offset, // x2 destination_coord_lat+offset, // y2 gc_tint, pixmap_final, 0); } // And last, draw the ALOHA circle if (Display_.aloha_circle) { if (aloha_radius != -1) { // if we actually have an aloha radius calculated already long l_lat,l_lon; l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); draw_aloha_circle(l_lon, l_lat, aloha_radius, colors[0x0e], pixmap_final); } } // Check whether currently_selected_stations has changed. If // so, set station_count_save to 0 so that main.c will come // along and update the counts on the status line. if (currently_selected_stations != currently_selected_stations_save) { station_count_save = 0; // Cause an update to occur } currently_selected_stations_save = currently_selected_stations; if (debug_level & 1) { fprintf(stderr,"Display File Stop\n"); } } // ======================================================================== // STATION DATA DIALOG FUNCTIONS // ======================================================================== /* * Delete tracklog for current station */ void Station_data_destroy_track( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { DataRow *p_station = clientData; if (delete_trail(p_station)) { redraw_on_new_data = 2; // redraw immediately } } /* * Delete Station Info PopUp */ void Station_data_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&db_station_info_lock, "db.c:Station_data_destroy_shell" ); XtDestroyWidget(shell); db_station_info = (Widget)NULL; end_critical_section(&db_station_info_lock, "db.c:Station_data_destroy_shell" ); } /* * Store track data for current station */ void Station_data_store_track(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { DataRow *p_station = clientData; //busy_cursor(XtParent(w)); busy_cursor(appshell); // Grey-out button so it doesn't get pressed twice XtSetSensitive(button_store_track,FALSE); // Store trail to file export_trail(p_station); #ifdef HAVE_LIBSHP // Save trail as a Shapefile map create_map_from_trail(p_station->call_sign); #endif // HAVE_LIBSHP // store trail to kml file export_trail_as_kml(p_station); } // This function merely reformats the button callback in order to // call wx_alert_double_click_action, which expects the parameter in // calldata instead of in clientData. // void Station_data_wx_alert(Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { //fprintf(stderr, "Station_data_wx_alert start\n"); wx_alert_finger_output( w, clientData); //fprintf(stderr, "Station_data_wx_alert end\n"); } void Station_data_add_fcc(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char temp[500]; FccAppl my_data; char *station = (char *) clientData; (void)check_fcc_data(); //busy_cursor(XtParent(w)); busy_cursor(appshell); if (search_fcc_data_appl(station, &my_data)==1) { /*fprintf(stderr,"FCC call %s\n",station);*/ xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s %s %s\n%s %s, %s %s, %s %s\n\n", langcode("STIFCC0001"), langcode("STIFCC0003"),my_data.name_licensee, langcode("STIFCC0004"),my_data.text_street,my_data.text_pobox, langcode("STIFCC0005"),my_data.city, langcode("STIFCC0006"),my_data.state, langcode("STIFCC0007"),my_data.zipcode); XmTextInsert(si_text,0,temp); XmTextShowPosition(si_text,0); fcc_lookup_pushed = 1; } } void Station_data_add_rac(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char temp[512]; char club[512]; rac_record my_data; char *station = (char *) clientData; xastir_snprintf(temp, sizeof(temp), " "); (void)check_rac_data(); //busy_cursor(XtParent(w)); busy_cursor(appshell); if (search_rac_data(station, &my_data)==1) { /*fprintf(stderr,"IC call %s\n",station);*/ xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s\n%s, %s\n%s\n", langcode("STIFCC0002"),my_data.first_name,my_data.last_name,my_data.address, my_data.city,my_data.province,my_data.postal_code); if (my_data.qual_a[0] == 'A') strncat(temp, langcode("STIFCC0008"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_d[0] == 'D') strncat(temp, langcode("STIFCC0009"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_b[0] == 'B' && my_data.qual_c[0] != 'C') strncat(temp, langcode("STIFCC0010"), sizeof(temp) - 1 - strlen(temp)); if (my_data.qual_c[0] == 'C') strncat(temp, langcode("STIFCC0011"), sizeof(temp) - 1 - strlen(temp)); strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); if (strlen(my_data.club_name) > 1) { xastir_snprintf(club, sizeof(club), "%s\n%s\n%s, %s\n%s\n", my_data.club_name, my_data.club_address, my_data.club_city, my_data.club_province, my_data.club_postal_code); strncat(temp, club, sizeof(temp) - 1 - strlen(temp)); } strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); XmTextInsert(si_text,0,temp); XmTextShowPosition(si_text,0); rac_lookup_pushed = 1; } } // Enable/disable auto-update of Station_data dialog void station_data_auto_update_toggle ( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { station_data_auto_update = 1; } else { station_data_auto_update = 0; } } /* * Change the trail color for a station */ void Change_trail_color( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; int temp; temp = p_station->trail_color; // Increment to the next color, round-robin style temp = (temp + 1) % MAX_TRAIL_COLORS; // Test for and skip if my trail color if (temp == MY_TRAIL_COLOR) { temp = (temp + 1) % MAX_TRAIL_COLORS; } p_station->trail_color = temp; redraw_on_new_data = 2; // redraw symbols now } /* * Clear DF from Station_data * * Called by Station_data function below from the Clear DF Bearing * button in Station Info. */ void Clear_DF_from_Station_data(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; if (strlen(p_station->bearing) == 3) { // we have DF data to clear p_station->bearing[0]='\0'; p_station->NRQ[0]='\0'; } } // ======================================================================== // STATION QUERY FUNCTIONS // ======================================================================== void Station_query_trace(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRST", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_messages(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRSM", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_direct(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?APRSD", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void Station_query_version(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *station = (char *) clientData; char temp[50]; char call[25]; pad_callsign(call,station); xastir_snprintf(temp, sizeof(temp), ":%s:?VER", call); // Nice to return via the reverse path here? No! Better to use the // default paths instead of a calculated reverse path. transmit_message_data(station,temp,NULL); } void General_query(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { char *location = (char *) clientData; char temp[50]; xastir_snprintf(temp, sizeof(temp), "?APRS?%s", location); output_my_data(temp,-1,0,0,0,NULL); // Not igating } void IGate_query(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { output_my_data("?IGATE?",-1,0,0,0,NULL); // Not igating } void WX_query(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { output_my_data("?WX?",-1,0,0,0,NULL); // Not igating } // popup window on menu request void Show_Aloha_Stats(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp[2000]; char format[1000]; unsigned long time_since_aloha_update; int minutes, hours; char Hours[7]; char Minutes[9]; if (aloha_radius != -1) { // we've done at least one interval, and aloha_time is the time // for the *next* one. We want the time since the last one. time_since_aloha_update = sec_now()-(aloha_time-ALOHA_CALC_INTERVAL); hours = time_since_aloha_update/3600; time_since_aloha_update -= hours*3600; minutes = time_since_aloha_update/60; if (hours == 1) xastir_snprintf(Hours,sizeof(Hours),"%s", langcode("TIME003")); // Hour else xastir_snprintf(Hours,sizeof(Hours),"%s", langcode("TIME004")); // Hours if (minutes == 1) xastir_snprintf(Minutes,sizeof(Minutes),"%s", langcode("TIME005")); // Minute else xastir_snprintf(Minutes,sizeof(Minutes),"%s", langcode("TIME006")); // Minutes // Build up the whole format string // "Aloha radius %d" xastir_snprintf(format,sizeof(format),"%s",langcode("WPUPALO001")); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); // "Stations inside...: %d" strncat(format,langcode("WPUPALO002"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Digis: %d" strncat(format,langcode("WPUPALO003"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Mobiles (in motion): %d" strncat(format,langcode("WPUPALO004"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Mobiles (other): %d" strncat(format,langcode("WPUPALO005"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" WX stations: %d" strncat(format,langcode("WPUPALO006"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //" Home stations: %d" strncat(format,langcode("WPUPALO007"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); //"Last calculated %s ago." strncat(format,langcode("WPUPALO008"),sizeof(format) - 1 - strlen(format)); strncat(format,"\n",sizeof(format) - 1 - strlen(format)); // We now have the whole format string, now print using it: xastir_snprintf(temp,sizeof(temp),format, (english_units) ? (int)aloha_radius : (int)(aloha_radius * cvt_mi2len), (english_units)?" miles":" km", the_aloha_stats.total, the_aloha_stats.digis, the_aloha_stats.mobiles_in_motion, the_aloha_stats.other_mobiles, the_aloha_stats.wxs, the_aloha_stats.homes, hours, Hours, minutes, Minutes); popup_message_always(langcode("PULDNVI016"),temp); } else { // Not calculated yet popup_message_always(langcode("PULDNVI016"),langcode("WPUPALO666")); } } // ======================================================================== // STATION DATA FILL-IN AND DISPLAY // ======================================================================== // Fill in the station data window with real data void station_data_fill_in ( Widget w, XtPointer clientData, XtPointer calldata ) { DataRow *p_station; char *station = (char *) clientData; char temp[300]; int pos, last_pos; char temp_my_distance[20]; char temp_my_course[25]; char temp1_my_course[20]; float temp_out_C, e, humidex; long l_lat, l_lon; float value; WeatherRow *weather; time_t sec; struct tm *time; int i; int track_count = 0; // Maximum tracks listed in Station Info dialog. This prevents // lockups on extremely long tracks. #define MAX_TRACK_LIST 50 db_station_info_callsign = (char *) clientData; // Used for auto-updating this dialog temp_out_C=0; pos=0; begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); if (db_station_info == NULL) // We don't have a dialog to write to { end_critical_section(&db_station_info_lock, "db.c:Station_data" ); return; } if (!search_station_name(&p_station,station,1) // Can't find call, || (p_station->flag & ST_ACTIVE) == 0) // or found deleted objects { end_critical_section(&db_station_info_lock, "db.c:Station_data" ); return; } // Clear the text XmTextSetString(si_text,NULL); // Weather Data ... if (p_station->weather_data != NULL // Make sure the timestamp on the weather is current && (int)(((sec_old + p_station->weather_data->wx_sec_time)) >= sec_now()) ) { last_pos = pos; weather = p_station->weather_data; pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI024"),weather->wx_type,weather->wx_station); XmTextInsert(si_text,pos,temp); pos += strlen(temp); sprintf(temp, "\n"); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI026"),weather->wx_course,weather->wx_speed); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI025"),weather->wx_course,(int)(atof(weather->wx_speed)*1.6094)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (strlen(weather->wx_gust) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI028"),weather->wx_gust); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI027"),(int)(atof(weather->wx_gust)*1.6094)); } strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); } else { xastir_snprintf(temp, sizeof(temp), "\n"); } XmTextInsert(si_text, pos, temp); pos += strlen(temp); if (strlen(weather->wx_temp) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI030"),weather->wx_temp); } else { temp_out_C =(((atof(weather->wx_temp)-32)*5.0)/9.0); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI029"),temp_out_C); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_hum) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI031"),weather->wx_hum); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // NOTE: The below (Humidex) is not coded for english units, only for metric. // What is Humidex anyway? Heat Index? Wind Chill? --we7u // DK7IN: ??? english_units ??? if (strlen(weather->wx_hum) > 0 && strlen(weather->wx_temp) > 0 && (!english_units) && (atof(weather->wx_hum) > 0.0) ) { e = (float)(6.112 * pow(10,(7.5 * temp_out_C)/(237.7 + temp_out_C)) * atof(weather->wx_hum) / 100.0); humidex = (temp_out_C + ((5.0/9.0) * (e-10.0))); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI032"),humidex); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_baro) > 0) { if (!english_units) // hPa { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI033"), weather->wx_baro); } else // Inches Mercury { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI063"), atof(weather->wx_baro)*0.02953); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if(last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } } if (strlen(weather->wx_snow) > 0) { if(english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI035"),atof(weather->wx_snow)); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI034"),atof(weather->wx_snow)*2.54); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain) > 0 || strlen(weather->wx_prec_00) > 0 || strlen(weather->wx_prec_24) > 0) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI036")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI038"),atof(weather->wx_rain)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI037"),atof(weather->wx_rain)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_prec_24) > 0) { if(english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI040"),atof(weather->wx_prec_24)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI039"),atof(weather->wx_prec_24)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_prec_00) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI042"),atof(weather->wx_prec_00)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI041"),atof(weather->wx_prec_00)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_rain_total) > 0) { xastir_snprintf(temp, sizeof(temp), "\n%s",langcode("WPUPSTI046")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI048"),atof(weather->wx_rain_total)/100.0); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI047"),atof(weather->wx_rain_total)*.254); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Fuel temp/moisture for RAWS weather stations if (strlen(weather->wx_fuel_temp) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI061"),weather->wx_fuel_temp); } else { temp_out_C =(((atof(weather->wx_fuel_temp)-32)*5.0)/9.0); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI060"),temp_out_C); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(weather->wx_fuel_moisture) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI062"),weather->wx_fuel_moisture); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Packets received ... xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI005"),p_station->num_packets); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time); temp[2]='/'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+2); temp[2]='/'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+4); temp[4]=' '; temp[5]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+8); temp[2]=':'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+10); temp[2]=':'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "%s", p_station->packet_time+12); temp[2]='\n'; temp[3]='\0'; XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Object if (strlen(p_station->origin) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI000"),p_station->origin); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Print the tactical call, if any if (p_station->tactical_call_sign && p_station->tactical_call_sign[0] != '\0') { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI065"), p_station->tactical_call_sign); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Heard via TNC ... if ((p_station->flag & ST_VIATNC) != 0) // test "via TNC" flag { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI006"),p_station->heard_via_tnc_port); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI007")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } switch(p_station->data_via) { case('L'): xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI008")); break; case('T'): xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI009"),p_station->last_port_heard); break; case('I'): xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI010"),p_station->last_port_heard); break; case('F'): xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI011")); break; case(DATA_VIA_DATABASE): xastir_snprintf(temp, sizeof(temp), "last via db on interface %d",p_station->last_port_heard); break; default: xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI012")); break; } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->newest_trackpoint != NULL) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI013")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Echoed from: ... // Callsign check here includes checking SSID // if (is_my_call(p_station->call_sign,1)) { if ( is_my_station(p_station) ) { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI055")); XmTextInsert(si_text,pos,temp); pos += strlen(temp); for (i=0; i<6; i++) { if (echo_digis[i][0] == '\0') { break; } xastir_snprintf(temp, sizeof(temp), " %s",echo_digis[i]); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Data Path ... if (p_station->node_path_ptr != NULL) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI043"),p_station->node_path_ptr); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI043"), ""); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Status ... if(p_station->status_data != NULL) // Found at least one record { CommentRow *ptr; ptr = p_station->status_data; while (ptr != NULL) { // We don't care if the pointer is NULL. This will // succeed anyway. It'll just make an empty string. // Note that text_ptr may be an empty string. That's // ok. //Also print the sec_heard timestamp. sec = ptr->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI059"), time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, ptr->text_ptr); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); ptr = ptr->next; // Advance to next record (if any) } } // // Comments ... // if(strlen(p_station->comments)>0) { // xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI044"),p_station->comments); // XmTextInsert(si_text,pos,temp); // pos += strlen(temp); // xastir_snprintf(temp, sizeof(temp), "\n"); // XmTextInsert(si_text,pos,temp); // pos += strlen(temp); // } // Comments ... if(p_station->comment_data != NULL) // Found at least one record { CommentRow *ptr; ptr = p_station->comment_data; while (ptr != NULL) { // We don't care if the pointer is NULL. This will // succeed anyway. It'll just make an empty string. // Note that text_ptr can be an empty string. That's // ok. //Also print the sec_heard timestamp. sec = ptr->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI044"), time->tm_mon + 1, time->tm_mday, time->tm_hour, time->tm_min, ptr->text_ptr); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); ptr = ptr->next; // Advance to next record (if any) } } // Current Power Gain ... if (strlen(p_station->power_gain) == 7) { // Check for RNG instead of PHG if (p_station->power_gain[0] == 'R') { // Found a Range xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI067"), atoi(&p_station->power_gain[3])); } else { // Found PHG phg_decode(langcode("WPUPSTI014"), // "Current Power Gain" p_station->power_gain, temp, sizeof(temp), english_units ); } // Check for Map View symbol: Eyeball symbol with // RNG // extension. if ( strncmp(p_station->power_gain,"RNG",3) == 0 && p_station->aprs_symbol.aprs_type == '/' && p_station->aprs_symbol.aprs_symbol == 'E' ) { //fprintf(stderr,"Found a Map View 'eyeball' symbol!\n"); // Center_Zoom() normally fills in the values with the // current zoom/center for the map window. We want to // be able to override these with our own values in this // case, derived from the object info. center_zoom_override++; Center_Zoom(w,NULL,(XtPointer)p_station); } } else if (p_station->flag & (ST_OBJECT | ST_ITEM)) { xastir_snprintf(temp, sizeof(temp), "%s %s", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI068") ); // "none" } else if (english_units) { xastir_snprintf(temp, sizeof(temp), "%s %s (9W @ 20ft %s, 3dB %s, %s 6.2mi)", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI069"), // "default" langcode("WPUPSTI070"), // "HAAT" langcode("WPUPSTI071"), // "omni" langcode("WPUPSTI072") ); // "range" // "default (9W @ 20ft HAAT, 3dB omni, range 6.2mi)"); } else { xastir_snprintf(temp, sizeof(temp), "%s %s (9W @ 6.1m %s, 3dB %s, %s 10.0km)", langcode("WPUPSTI014"), // "Current Power Gain:" langcode("WPUPSTI069"), // "default" langcode("WPUPSTI070"), // "HAAT" langcode("WPUPSTI071"), // "omni" langcode("WPUPSTI072") ); // "range" // "default (9W @ 6.1m HAAT, 3dB omni, range 10.0km)"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Current DF Info ... if (strlen(p_station->signal_gain) == 7) { shg_decode(langcode("WPUPSTI057"), p_station->signal_gain, temp, sizeof(temp) , english_units); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (strlen(p_station->bearing) == 3) { bearing_decode(langcode("WPUPSTI058"), p_station->bearing, p_station->NRQ, temp, sizeof(temp), english_units ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Signpost Data if (strlen(p_station->signpost) > 0) { xastir_snprintf(temp, sizeof(temp), "%s: %s",langcode("POPUPOB029"), p_station->signpost); XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Altitude ... last_pos=pos; if (strlen(p_station->altitude) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI016"),atof(p_station->altitude)*3.28084,"ft"); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI016"),atof(p_station->altitude),"m"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Course ... if (strlen(p_station->course) > 0) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI017"),p_station->course); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Speed ... if (strlen(p_station->speed) > 0) { if (english_units) { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI019"),atof(p_station->speed)*1.1508); } else { xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI018"),atof(p_station->speed)*1.852); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Distance ... last_pos = pos; // do my course // if (!is_my_call(p_station->call_sign,1)) { // Checks SSID as well if ( !(is_my_station(p_station)) ) // Checks SSID as well { l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(l_lat,l_lon,p_station->coord_lat, p_station->coord_lon,temp1_my_course,sizeof(temp1_my_course)); // n7tap: This is a quick hack to get some more useful values for // distance to near objects. if (english_units) { if (value*1.15078 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.15078*1760), langcode("SPCHSTR004")); // yards } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI020"), // miles value*1.15078); } } else { if (value*1.852 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.852*1000), langcode("UNIOP00031")); // 'm' as in meters } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI021"), // km value*1.852); } } xastir_snprintf(temp_my_course, sizeof(temp_my_course), "%s\xB0",temp1_my_course); xastir_snprintf(temp, sizeof(temp), langcode("WPUPSTI022"),temp_my_distance,temp_my_course); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if(last_pos!=pos) { xastir_snprintf(temp, sizeof(temp), "\n"); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } // Last Position sec = p_station->sec_heard; time = localtime(&sec); xastir_snprintf(temp, sizeof(temp), "%s%02d/%02d %02d:%02d ",langcode("WPUPSTI023"), time->tm_mon + 1, time->tm_mday,time->tm_hour,time->tm_min); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { convert_xastir_to_UTM_str(temp, sizeof(temp), p_station->coord_lon, p_station->coord_lat); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str(temp, sizeof(temp), p_station->coord_lon, p_station->coord_lat, 0); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(p_station->coord_lat, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), " "); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_DDDDDD) { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lon_l2s(p_station->coord_lon, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (p_station->altitude[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %5.0f%s", atof(p_station->altitude)*cvt_m2len, un_alt); } else { substr(temp," ",1+5+strlen(un_alt)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->speed[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %4.0f%s",atof(p_station->speed)*cvt_kn2len,un_spd); } else { substr(temp," ",1+4+strlen(un_spd)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (p_station->course[0] != '\0') { xastir_snprintf(temp, sizeof(temp), " %3d\xB0",atoi(p_station->course)); } else { xastir_snprintf(temp, sizeof(temp), " "); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // dl9sau // Maidenhead Grid Locator xastir_snprintf(temp, sizeof(temp), " %s", sec_to_loc(p_station->coord_lon, p_station->coord_lat) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if ((p_station->flag & ST_DIRECT) != 0) { xastir_snprintf(temp, sizeof(temp), " *\n"); } else { xastir_snprintf(temp, sizeof(temp), " \n"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // list rest of trail data if (p_station->newest_trackpoint != NULL) { TrackRow *ptr; ptr = p_station->newest_trackpoint; // Skip the first (latest) trackpoint as if it exists, it'll // be the same as the data in the station record, which we // just printed out. if (ptr->prev != NULL) { ptr = ptr->prev; } while ( (ptr != NULL) && (track_count <= MAX_TRACK_LIST) ) { track_count++; sec = ptr->sec; time = localtime(&sec); if ((ptr->flag & TR_NEWTRK) != '\0') xastir_snprintf(temp, sizeof(temp), " + %02d/%02d %02d:%02d ", time->tm_mon + 1,time->tm_mday,time->tm_hour,time->tm_min); else xastir_snprintf(temp, sizeof(temp), " %02d/%02d %02d:%02d ", time->tm_mon + 1,time->tm_mday,time->tm_hour,time->tm_min); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { convert_xastir_to_UTM_str(temp, sizeof(temp), ptr->trail_long_pos, ptr->trail_lat_pos); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str(temp, sizeof(temp), ptr->trail_long_pos, ptr->trail_lat_pos, 0); XmTextInsert(si_text,pos,temp); pos += strlen(temp); } else { if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); xastir_snprintf(temp, sizeof(temp), " "); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (coordinate_system == USE_DDDDDD) { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_HP_NORMAL); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); } if (ptr->altitude > -99999l) xastir_snprintf(temp, sizeof(temp), " %5.0f%s", ptr->altitude * cvt_dm2len, un_alt); else { substr(temp," ",1+5+strlen(un_alt)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (ptr->speed >= 0) xastir_snprintf(temp, sizeof(temp), " %4.0f%s", ptr->speed * cvt_hm2len, un_spd); else { substr(temp," ",1+4+strlen(un_spd)); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); if (ptr->course >= 0) xastir_snprintf(temp, sizeof(temp), " %3d\xB0", ptr->course); else { xastir_snprintf(temp, sizeof(temp), " "); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // dl9sau xastir_snprintf(temp, sizeof(temp), " %s", sec_to_loc(ptr->trail_long_pos, ptr->trail_lat_pos) ); XmTextInsert(si_text,pos,temp); pos += strlen(temp); if ((ptr->flag & TR_LOCAL) != '\0') { xastir_snprintf(temp, sizeof(temp), " *\n"); } else { xastir_snprintf(temp, sizeof(temp), " \n"); } XmTextInsert(si_text,pos,temp); pos += strlen(temp); // Go back in time one trackpoint ptr = ptr->prev; } } if (fcc_lookup_pushed) { Station_data_add_fcc(w, clientData, calldata); } else if (rac_lookup_pushed) { Station_data_add_rac(w, clientData, calldata); } XmTextShowPosition(si_text,0); end_critical_section(&db_station_info_lock, "db.c:Station_data" ); } // ======================================================================== // TACTICAL CALL MANAGEMENT FUNCTIONS // ======================================================================== void Change_tactical_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); change_tactical_dialog = (Widget)NULL; } void Change_tactical_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; temp = XmTextGetString(tactical_text); if (tactical_pointer->tactical_call_sign == NULL) { // Malloc some memory to hold it. tactical_pointer->tactical_call_sign = (char *)malloc(MAX_TACTICAL_CALL+1); } if (tactical_pointer->tactical_call_sign != NULL) { // Check for blank tactical call. If so, free the space. if (temp[0] == '\0') { free(tactical_pointer->tactical_call_sign); tactical_pointer->tactical_call_sign = NULL; } else { xastir_snprintf(tactical_pointer->tactical_call_sign, MAX_TACTICAL_CALL+1, "%s", temp); } fprintf(stderr, "Assigned tactical call \"%s\" to %s\n", temp, tactical_pointer->call_sign); // Log the change in the tactical_calls.log file. // Also adds it to the tactical callsign hash here. log_tactical_call(tactical_pointer->call_sign, tactical_pointer->tactical_call_sign); } else { fprintf(stderr, "Couldn't malloc space for tactical callsign\n"); } XtFree(temp); redraw_on_new_data = 2; // redraw now Change_tactical_destroy_shell(widget,clientData,callData); } void Change_tactical(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close, label, scrollwindow; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count if (!change_tactical_dialog) { change_tactical_dialog = XtVaCreatePopupShell(langcode("WPUPSTI065"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Change Tactical pane", xmPanedWindowWidgetClass, change_tactical_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("Change Tactical scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Change Tactical my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // set args for color ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Display the callsign or object/item name we're working on // in a label at the top of the dialog. Otherwise we don't // know what station we're operating on. // label = XtVaCreateManagedWidget(tactical_pointer->call_sign, xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); tactical_text = XtVaCreateManagedWidget("Change_Tactical text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, MAX_TACTICAL_CALL, XmNwidth, ((MAX_TACTICAL_CALL*7)+2), XmNmaxLength, MAX_TACTICAL_CALL, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // Fill in the current value of tactical callsign XmTextSetString(tactical_text, tactical_pointer->tactical_call_sign); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tactical_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tactical_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Change_tactical_change_data, change_tactical_dialog); XtAddCallback(button_close, XmNactivateCallback, Change_tactical_destroy_shell, change_tactical_dialog); pos_dialog(change_tactical_dialog); delw = XmInternAtom(XtDisplay(change_tactical_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(change_tactical_dialog, delw, Change_tactical_destroy_shell, (XtPointer)change_tactical_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, change_tactical_dialog); XtPopup(change_tactical_dialog,XtGrabNone); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(change_tactical_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(change_tactical_dialog), XtWindow(change_tactical_dialog)); } } /* * Assign a tactical call to a station */ void Assign_Tactical_Call( Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station = clientData; //fprintf(stderr,"Object Name: %s\n", p_station->call_sign); tactical_pointer = p_station; Change_tactical(w, p_station, NULL); } // ======================================================================== // MAIN STATION DATA DIALOG // ======================================================================== /* * List station info and trail * If calldata is non-NULL, then we drop straight through to the * Modify->Object or Assign_Tactical_Call dialogs. * * Input parameters: * clientData: Station callsign * * calldata: NULL = Station Info * "1" = Object -> Modify * "2" = Move Object * "3" = Assign Tactical Call * "4" = Send Message To * */ void Station_data(Widget w, XtPointer clientData, XtPointer calldata) { DataRow *p_station; char *station = (char *) clientData; static char local_station[25]; char temp[300]; unsigned int n; Atom delw; static Widget pane, form, button_cancel, button_message, button_nws, button_fcc, button_rac, button_clear_track, button_trace, button_messages, button_object_modify, button_direct, button_version, station_icon, station_call, station_type, station_data_auto_update_w, button_tactical, button_change_trail_color, button_track_station,button_clear_df,scrollwindow; Arg args[50]; Pixmap icon; Position x,y; // For saving current dialog position //fprintf(stderr,"db.c:Station_data start\n"); busy_cursor(appshell); db_station_info_callsign = (char *) clientData; // Used for auto-updating this dialog // Make a copy of the name. xastir_snprintf(local_station,sizeof(local_station),"%s",station); if (search_station_name(&p_station,station,1) // find call && (p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { } else { fprintf(stderr,"Couldn't find station in database\n"); return; // Don't update current/create new dialog } if (calldata != NULL) // We were called from the { // Object->Modify, Assign Tactical Call, // or Send Message To menu items. if (strncmp(calldata,"1",1) == 0) { Modify_object(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"2",1) == 0) { Modify_object(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"3",1) == 0) { Assign_Tactical_Call(w, (XtPointer)p_station, calldata); } else if (strncmp(calldata,"4",1) == 0) { //fprintf(stderr,"Send Message To: %s\n", p_station->call_sign); Send_message_call(NULL, (XtPointer) p_station->call_sign, NULL); } return; } // If we haven't calculated our decoration offsets yet, do so now if ( (decoration_offset_x == 0) && (decoration_offset_y == 0) ) { compute_decorations(); } if (db_station_info != NULL) // We already have a dialog { // This is a pain. We can get the X/Y position, but when // we restore the new dialog to the same position we're // off by the width/height of our window decorations. Call // above was added to pre-compute the offsets that we'll need. XtVaGetValues(db_station_info, XmNx, &x, XmNy, &y, NULL); // This call doesn't work. It returns the widget location, // just like the XtVaGetValues call does. I need the window // decoration location instead. //XtTranslateCoords(db_station_info, 0, 0, &xnew, &ynew); //fprintf(stderr,"%d:%d\t%d:%d\n", x, xnew, y, ynew); if (last_station_info_x == 0) { last_station_info_x = x - decoration_offset_x; } if (last_station_info_y == 0) { last_station_info_y = y - decoration_offset_y; } // Now get rid of the old dialog Station_data_destroy_shell(db_station_info, db_station_info, NULL); } else { // Clear the global state variables fcc_lookup_pushed = 0; rac_lookup_pushed = 0; } begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); if (db_station_info == NULL) { // Start building the dialog from the bottom up. That way // we can keep the buttons attached to the bottom of the // form and the correct height, and let the text widget // grow/shrink as the dialog is resized. db_station_info = XtVaCreatePopupShell(langcode("WPUPSTI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station Data pane", xmPanedWindowWidgetClass, db_station_info, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("State Data scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Station Data form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 4, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Start with the bottom row, left button button_clear_track = NULL; // Need this later, don't delete! if (p_station->newest_trackpoint != NULL) { // [ Clear Track ] button_clear_track = XtVaCreateManagedWidget(langcode("WPUPSTI045"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear_track, XmNactivateCallback, Station_data_destroy_track,(XtPointer)p_station); } else { // DK7IN: I drop the version button for mobile stations // we just have too much buttons... // and should find another solution // [ Station Version Query ] button_version = XtVaCreateManagedWidget(langcode("WPUPSTI052"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_version, XmNactivateCallback, Station_query_version,(XtPointer)p_station->call_sign); } // [ Trace Query ] button_trace = XtVaCreateManagedWidget(langcode("WPUPSTI049"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_trace, XmNactivateCallback, Station_query_trace,(XtPointer)p_station->call_sign); // [ Un-Acked Messages Query ] button_messages = XtVaCreateManagedWidget(langcode("WPUPSTI050"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_messages, XmNactivateCallback, Station_query_messages,(XtPointer)p_station->call_sign); // [ Direct Stations Query ] button_direct = XtVaCreateManagedWidget(langcode("WPUPSTI051"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_direct, XmNactivateCallback, Station_query_direct,(XtPointer)p_station->call_sign); // Now proceed to the row above it, left button first // [ Store Track ] or single Position button_store_track = XtVaCreateManagedWidget(langcode("WPUPSTI054"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, //XmNtopWidget,XtParent(si_text), XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, (button_clear_track) ? button_clear_track : button_version, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_store_track, XmNactivateCallback, Station_data_store_track,(XtPointer)p_station); if ( ((p_station->flag & ST_OBJECT) == 0) && ((p_station->flag & ST_ITEM) == 0) ) // Not an object/ { // fprintf(stderr,"Not an object or item...\n"); // [Send Message] button_message = XtVaCreateManagedWidget(langcode("WPUPSTI002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_trace, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_message, XmNactivateCallback, Send_message_call,(XtPointer)p_station->call_sign); } else { // fprintf(stderr,"Found an object or item...\n"); button_object_modify = XtVaCreateManagedWidget(langcode("WPUPSTI053"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_trace, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_object_modify, XmNactivateCallback, Modify_object, (XtPointer)p_station); } // Check whether it is a non-weather alert object/item. If // so, try to use the origin callsign instead of the object // for FCC/RAC lookups. // if ( (p_station->flag & ST_OBJECT) || (p_station->flag & ST_ITEM) ) { // It turns out that objects transmitted by a station // called "WINLINK" are what mess up the RAC button for // Canadian stations. Xastir sees the 'W' of WINLINK // (the originating station) and assumes it is a U.S. // station. Here's a sample packet: // // WINLINK>APWL2K,TCPIP*,qAC,T2MIDWEST:;VE7SEP-10*240521z4826.2 NW12322.5 Wa145.690MHz 1200b R11m RMSPacket EMCOMM // // If match on "WINLINK": Don't copy origin callsign // into local_station. Use the object name instead // which should be a callsign. if (strncmp(p_station->origin,"WINLINK",7)) { xastir_snprintf(local_station,sizeof(local_station),"%s",p_station->origin); } } // Add "Fetch NWS Info" button if it is an object or item // and has "WXSVR" in its path somewhere. // // Note from Dale Huguley: // "I would say an object with 6 upper alpha chars for the // "from" call and " {AAAAA" (space curly 5 alphanumerics) // at the end is almost guaranteed to be from Wxsvr. // Fingering for the six alphas and the first three // characters after the curly brace should be a reliable // finger - as in SEWSVR>APRS::a_bunch_of_info_in_here_ // {H45AA finger SEWSVRH45@wxsvr.net" // // Note from Curt: I had to remove the space from the // search as well, 'cuz the multipoint objects don't have // the space before the final curly-brace. // if ( ( (p_station->flag & ST_OBJECT) || (p_station->flag & ST_ITEM) ) && (p_station->comment_data != NULL) && ( strstr(p_station->comment_data->text_ptr, "{") != NULL ) ) { static char temp[25]; char *ptr3; button_nws = XtVaCreateManagedWidget(langcode("WPUPSTI064"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // We need to construct the "special" finger address. // We'll use the FROM callsign and the first three chars // of the curly-brace portion of the comment field. // Callsign in this case is from the "origin" field. // The curly-brace text is at the end of one of the // "comment_data" records, hopefully the first one // checked (most recent). // xastir_snprintf(temp, sizeof(temp), "%s", p_station->origin); temp[6] = '\0'; ptr3 = strstr(p_station->comment_data->text_ptr,"{"); ptr3++; // Skip over the '{' character strncat(temp,ptr3,3); //fprintf(stderr,"New Handle: %s\n", temp); XtAddCallback(button_nws, XmNactivateCallback, Station_data_wx_alert, (XtPointer)temp); } // Add FCC button only if probable match. The U.S. has // these prefixes assigned but not all are used for amateur // stations: // // AAA-ALZ // KAA-KZZ // NAA-NZZ // WAA-WZZ // else if ((! strncmp(local_station,"A",1)) || (! strncmp(local_station,"K",1)) || (! strncmp(local_station,"N",1)) || (! strncmp(local_station,"W",1)) ) { button_fcc = XtVaCreateManagedWidget(langcode("WPUPSTI003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_fcc, XmNactivateCallback, Station_data_add_fcc, (XtPointer)local_station); if ( ! check_fcc_data()) { XtSetSensitive(button_fcc,FALSE); } } // Add RAC button only if probable match. Canada has these // prefixes assigned but not all are used for amateur // stations: // // CFA-CKZ // CYA-CZZ // VAA-VGZ // VOA-VOZ // VXA-VYZ // XJA-XOZ // else if (!strncmp(local_station,"VA",2) || !strncmp(local_station,"VE",2) || !strncmp(local_station,"VO",2) || !strncmp(local_station,"VY",2)) { button_rac = XtVaCreateManagedWidget(langcode("WPUPSTI004"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_messages, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_rac, XmNactivateCallback, Station_data_add_rac, (XtPointer)local_station); if ( ! check_rac_data()) { XtSetSensitive(button_rac,FALSE); } } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_direct, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Station_data_destroy_shell, db_station_info); // Button to clear DF bearing data if we actually have some. if (strlen(p_station->bearing) == 3) { button_clear_df = XtVaCreateManagedWidget(langcode("WPUPSTI092"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_cancel, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear_df, XmNactivateCallback,Clear_DF_from_Station_data, (XtPointer)p_station); } button_track_station = XtVaCreateManagedWidget(langcode("WPUPTSP001"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, button_store_track, XmNbottomOffset, 1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, // XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_track_station, XmNactivateCallback,Track_from_Station_data, (XtPointer)p_station); // Now build from the top of the dialog to the buttons. icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)), 20,20,DefaultDepthOfScreen(XtScreen(appshell))); symbol(db_station_info,0,p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay,icon,0,0,0,' '); station_icon = XtVaCreateManagedWidget("Station Data icon", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNlabelType, XmPIXMAP, XmNlabelPixmap,icon, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); station_type = XtVaCreateManagedWidget("Station Data type", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns,5, XmNwidth,((5*7)+2), XmNbackground, colors[0xff], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,station_icon, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%c%c%c", p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay); XmTextFieldSetString(station_type, temp); XtManageChild(station_type); station_call = XtVaCreateManagedWidget("Station Data call", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns,10, XmNwidth,((10*7)+2), XmNbackground, colors[0xff], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_type, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); XmTextFieldSetString(station_call,p_station->call_sign); XtManageChild(station_call); station_data_auto_update_w = XtVaCreateManagedWidget(langcode("WPUPSTI056"), xmToggleButtonGadgetClass, form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_call, XmNleftOffset,10, XmNrightAttachment,XmATTACH_NONE, XmNbackground,colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(station_data_auto_update_w,XmNvalueChangedCallback,station_data_auto_update_toggle,"1"); //Add tactical button at the top/right // "Assign Tactical Call" button_tactical = XtVaCreateManagedWidget(langcode("WPUPSTI066"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftOffset, 10, XmNleftWidget, station_data_auto_update_w, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_tactical, XmNactivateCallback, Assign_Tactical_Call, (XtPointer)p_station); if (p_station->flag & (ST_OBJECT | ST_ITEM)) { // We don't allow setting tac-calls for objects/items, // so make the button insensitive. XtSetSensitive(button_tactical,FALSE); } //Add change_trail_color button at the top/right // "Trail Color" button_change_trail_color = XtVaCreateManagedWidget(langcode("WPUPSTI091"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftOffset, 10, XmNleftWidget, button_tactical, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_change_trail_color, XmNactivateCallback, Change_trail_color, (XtPointer)p_station); n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 100); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNbackground, colors[0xff]); n++; XtSetArg(args[n], XmNscrollHorizontal, FALSE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, station_icon); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; // XtSetArg(args[n], XmNbottomWidget, button_store_track); n++; XtSetArg(args[n], XmNbottomWidget, button_track_station); n++; XtSetArg(args[n], XmNbottomOffset, 1); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; si_text = NULL; si_text = XmCreateScrolledText(form,"Station_data",args,n); end_critical_section(&db_station_info_lock, "db.c:Station_data" ); // Fill in the si_text widget with real data station_data_fill_in( w, (XtPointer)db_station_info_callsign, NULL); begin_critical_section(&db_station_info_lock, "db.c:Station_data" ); pos_dialog(db_station_info); delw = XmInternAtom(XtDisplay(db_station_info),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(db_station_info, delw, Station_data_destroy_shell, (XtPointer)db_station_info); XtManageChild(form); XtManageChild(si_text); XtVaSetValues(si_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(form, db_station_info); if (station_data_auto_update) { XmToggleButtonSetState(station_data_auto_update_w,TRUE,FALSE); } if (calldata == NULL) // We're not going straight to the Modify dialog { // and will actually use the dialog we just drew XtPopup(db_station_info,XtGrabNone); XmTextShowPosition(si_text,0); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } } end_critical_section(&db_station_info_lock, "db.c:Station_data" ); } // ======================================================================== // STATION INFO DIALOG FUNCTIONS // ======================================================================== /* * Station Info Selection PopUp window: Canceled */ void Station_info_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; // We used to close the detailed Station Info dialog here too, which // makes no sense. Commenting this out so that we can close the // Station Chooser but leave the Station Info dialog open. // // if (db_station_info!=NULL) // Station_data_destroy_shell(db_station_info, db_station_info, NULL); XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),SiS_icon0); (void)XFreePixmap(XtDisplay(appshell),SiS_icon); begin_critical_section(&db_station_popup_lock, "db.c:Station_info_destroy_shell" ); XtDestroyWidget(shell); db_station_popup = (Widget)NULL; end_critical_section(&db_station_popup_lock, "db.c:Station_info_destroy_shell" ); } // Used for auto-refreshing the Station_info dialog. Called from // main.c:UpdateTime() every 30 seconds. // void update_station_info(Widget w) { begin_critical_section(&db_station_info_lock, "db.c:update_station_info" ); // If we have a dialog to update and a callsign to pass to it if (( db_station_info != NULL) && (db_station_info_callsign != NULL) && (strlen(db_station_info_callsign) != 0) ) { end_critical_section(&db_station_info_lock, "db.c:update_station_info" ); // Fill in the si_text widget with real data station_data_fill_in( w, (XtPointer)db_station_info_callsign, NULL); } else { end_critical_section(&db_station_info_lock, "db.c:update_station_info" ); } } /* * Station Info Selection PopUp window: Quit with selected station */ void Station_info_select_destroy_shell(Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *temp; char temp2[50]; XmString *list; int found; //Widget shell = (Widget) clientData; found=0; begin_critical_section(&db_station_popup_lock, "db.c:Station_info_select_destroy_shell" ); if (db_station_popup) { XtVaGetValues(station_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(station_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } // DK7IN ?? should we not first close the PopUp, then call Station_data ?? if (found) { xastir_snprintf(temp2, sizeof(temp2), "%s", temp); // Only keep the station info, remove Tactical Call Sign temp2[strcspn(temp2, "(")] = '\0'; remove_trailing_spaces(temp2); // Call it with the global parameter at the last, so we // can pass special parameters down that we couldn't // directly pass to Station_info_select_destroy_shell(). Station_data(widget, temp2, station_info_select_global); // Clear the global variable so that nothing else calls // it with the wrong parameter station_info_select_global = NULL; XtFree(temp); } /* // This section of code gets rid of the Station Chooser. Frank wanted to // be able to leave the Station Chooser up after selection so that other // stations could be selected, therefore I commented this out. XtPopdown(shell); // Get rid of the station chooser popup here (void)XFreePixmap(XtDisplay(appshell),SiS_icon0); (void)XFreePixmap(XtDisplay(appshell),SiS_icon); XtDestroyWidget(shell); // and here db_station_popup = (Widget)NULL; // and here */ } end_critical_section(&db_station_popup_lock, "db.c:Station_info_select_destroy_shell" ); } /* * Station Info PopUp * if only one station in view it shows the data with Station_data() * otherwise we get a selection box * clientData will be non-null if we wish to drop through to the object->modify * or Assign Tactical Call dialogs. * * clientData: NULL = Station Info * "1" = Object -> Modify * "2" = Move Object * "3" = Assign Tactical Call * "4" = Send Message To */ void Station_info(Widget w, XtPointer clientData, XtPointer UNUSED(calldata) ) { DataRow *p_station; DataRow *p_found; int num_found = 0; unsigned long min_diff_x, diff_x, min_diff_y, diff_y; XmString str_ptr; unsigned int n; Atom delw; static Widget pane, form, button_ok, button_cancel; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ char tactical_string[50]; busy_cursor(appshell); min_diff_y = scale_y * 20; // Pixels each way in y-direction. min_diff_x = scale_x * 20; // Pixels each way in x-direction. p_found = NULL; p_station = n_first; // Here we just count them. We go through the same type of code // again later if we find more than one station. while (p_station != NULL) // search through database for nearby stations { if ( ( (p_station->flag & ST_INVIEW) != 0) && ok_to_draw_station(p_station) ) // only test stations in view { if (!altnet || is_altnet(p_station)) { // Here we calculate diff in terms of XX pixels, // changed into lat/long values. This keeps the // affected rectangle the same at any zoom level. // scale_y/scale_x is Xastir units/pixel. Xastir // units are in 1/100 of a second. If we want to go // 10 pixels in any direction (roughly, scale_x // varies by latitude), then we want (10 * scale_y), // and (10 * scale_x) if we want to make a very // accurate square. diff_y = (unsigned long)( labs((NW_corner_latitude+(menu_y*scale_y)) - p_station->coord_lat)); diff_x = (unsigned long)( labs((NW_corner_longitude+(menu_x*scale_x)) - p_station->coord_lon)); // If the station fits within our bounding box, // count it if ((diff_y < min_diff_y) && (diff_x < min_diff_x)) { p_found = p_station; num_found++; } } } p_station = p_station->n_next; } if (p_found != NULL) // We found at least one station { if (num_found == 1) { // We only found one station, so it's easy Station_data(w,p_found->call_sign,clientData); } else // We found more: create dialog to choose a station { // Set up this global variable so that we can pass it // off to Station_data from the // Station_info_select_destroy_shell() function above. // Without this global variable we don't have enough // parameters passed to the final routine, so we can't // move an object that is on top of another. With it, // we can. station_info_select_global = clientData; if (db_station_popup != NULL) { Station_info_destroy_shell(db_station_popup, db_station_popup, NULL); } begin_critical_section(&db_station_popup_lock, "db.c:Station_info" ); if (db_station_popup == NULL) { // Set up a selection box: db_station_popup = XtVaCreatePopupShell(langcode("STCHO00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station_info pane",xmPanedWindowWidgetClass, db_station_popup, XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Station_info form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Attach buttons first to the bottom of the form, // so that we'll be able to stretch this thing // vertically to see all the callsigns. // button_ok = XtVaCreateManagedWidget("Info",xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Station_info_destroy_shell, db_station_popup); XtAddCallback(button_ok, XmNactivateCallback, Station_info_select_destroy_shell, db_station_popup); /*set args for color */ ac = 0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 6); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNbottomWidget, button_ok); ac++; XtSetArg(al[ac], XmNbottomOffset, 5); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_list = XmCreateScrolledList(form,"Station_info list",al,ac); // DK7IN: I want to add the symbol in front of the call... // icon SiS_icon0 = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); SiS_icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); /* SiS_symb = XtVaCreateManagedWidget("Station_info icon", xmLabelWidgetClass, ob_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, SiS_icon, XmNbackground, colors[0xff], XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL); */ /*fprintf(stderr,"What station\n");*/ n = 1; p_station = n_first; while (p_station != NULL) // search through database for nearby stations { if ( ( (p_station->flag & ST_INVIEW) != 0) && ok_to_draw_station(p_station) ) // only test stations in view { if (!altnet || is_altnet(p_station)) { diff_y = (unsigned long)( labs((NW_corner_latitude+(menu_y*scale_y)) - p_station->coord_lat)); diff_x = (unsigned long)( labs((NW_corner_longitude+(menu_x*scale_x)) - p_station->coord_lon)); // If the station fits within our // bounding box, count it. if ((diff_y < min_diff_y) && (diff_x < min_diff_x)) { /*fprintf(stderr,"Station %s\n",p_station->call_sign);*/ if (p_station->tactical_call_sign) { xastir_snprintf(tactical_string, sizeof(tactical_string), "%s (%s)", p_station->call_sign, p_station->tactical_call_sign); XmListAddItem(station_list, str_ptr = XmStringCreateLtoR(tactical_string, XmFONTLIST_DEFAULT_TAG), (int)n++); } else { XmListAddItem(station_list, str_ptr = XmStringCreateLtoR(p_station->call_sign, XmFONTLIST_DEFAULT_TAG), (int)n++); } XmStringFree(str_ptr); } } } p_station = p_station->n_next; } pos_dialog(db_station_popup); delw = XmInternAtom(XtDisplay(db_station_popup),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(db_station_popup, delw, Station_info_destroy_shell, (XtPointer)db_station_popup); XtManageChild(form); XtManageChild(station_list); XtVaSetValues(station_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XtPopup(db_station_popup,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } end_critical_section(&db_station_popup_lock, "db.c:Station_info" ); } } } // ======================================================================== // MAP POSITION AND LOCATION UTILITIES // ======================================================================== /* * Center map to new position */ void set_map_position(Widget UNUSED(w), long lat, long lon) { // see also map_pos() in location.c // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; set_last_position(); center_latitude = lat; center_longitude = lon; setup_in_view(); // flag all stations in new screen view // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(w)) { // (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } /* * Check if position is inside inner screen area * (real screen + minus 1/6 screen margin) * used for station tracking */ int position_on_inner_screen(long lat, long lon) { if ( lon > center_longitude-(long)(screen_width *scale_x/3) && lon < center_longitude+(long)(screen_width *scale_x/3) && lat > center_latitude -(long)(screen_height*scale_y/3) && lat < center_latitude +(long)(screen_height*scale_y/3) && !(lat == 0 && lon == 0)) // discard undef positions from screen { return(1); // position is inside the area } else { return(0); } } /* * Search for a station to be located (for Tracking and Find Station) */ int locate_station(Widget w, char *call, int follow_case, int get_match, int center_map) { DataRow *p_station; char call_find[MAX_CALLSIGN+1]; char call_find1[MAX_CALLSIGN+1]; int ii; if (!follow_case) { for (ii=0; ii<(int)strlen(call); ii++) { if (isalpha((int)call[ii])) { call_find[ii] = toupper((int)call[ii]); // Problem with lowercase objects/names!! } else { call_find[ii] = call[ii]; } } call_find[ii] = '\0'; xastir_snprintf(call_find1, sizeof(call_find1), "%s", call_find); } else xastir_snprintf(call_find1, sizeof(call_find1), "%s", call); if (search_station_name(&p_station,call_find1,get_match)) { if (position_defined(p_station->coord_lat,p_station->coord_lon,0)) { if (center_map || !position_on_inner_screen(p_station->coord_lat,p_station->coord_lon)) // only change map if really necessary { set_map_position(w, p_station->coord_lat, p_station->coord_lon); } return(1); // we found it } } return(0); } Xastir-Release-2.2.4/src/db_gui.h0000664000175000017500000000572415151324131015522 0ustar hibbyhibby#ifndef XASTIR_DB_GUI_H #define XASTIR_DB_GUI_H #include #define MY_TRAIL_COLOR 0x16 /* trail color index reserved for my station */ // ------------------------------------------------------------------------ // INITIALIZATION FUNCTIONS // ------------------------------------------------------------------------ void db_gui_init(void); // ------------------------------------------------------------------------ // STATION TRACKING FUNCTIONS // ------------------------------------------------------------------------ void track_station(Widget w, char *call_tracked, DataRow *p_station); // ------------------------------------------------------------------------ // DRAWING AND RENDERING FUNCTIONS // ------------------------------------------------------------------------ void draw_trail(Widget w, DataRow *fill, int solid); void display_station(Widget w, DataRow *p_station, int single); void draw_test_line(Widget w, long x, long y, long dx, long dy, long ofs); void draw_ruler_text(Widget w, char * text, long ofs); void draw_range_scale(Widget w); void draw_ruler(Widget w); void display_file(Widget w); // ------------------------------------------------------------------------ // STATION DATA DIALOG FUNCTIONS // ------------------------------------------------------------------------ extern void Station_data_destroy_track(Widget widget, XtPointer clientData, XtPointer callData); // ------------------------------------------------------------------------ // STATION INFO DIALOG FUNCTIONS // ------------------------------------------------------------------------ extern void Station_info(Widget w, XtPointer clientData, XtPointer calldata); // ------------------------------------------------------------------------ // STATION QUERY FUNCTIONS // ------------------------------------------------------------------------ extern void General_query(Widget w, XtPointer clientData, XtPointer calldata); extern void IGate_query(Widget w, XtPointer clientData, XtPointer calldata); extern void WX_query(Widget w, XtPointer clientData, XtPointer calldata); void Show_Aloha_Stats(Widget w, XtPointer clientData, XtPointer callData); // ------------------------------------------------------------------------ // MAIN STATION DATA DIALOG // ------------------------------------------------------------------------ void Station_data(Widget w, XtPointer clientData, XtPointer calldata); // ------------------------------------------------------------------------ // STATION INFO DIALOG FUNCTIONS // ------------------------------------------------------------------------ extern void update_station_info(Widget w); // ------------------------------------------------------------------------ // MAP POSITION AND LOCATION UTILITIES // ------------------------------------------------------------------------ extern void set_map_position(Widget w, long lat, long lon); int locate_station(Widget w, char *call, int follow_case, int get_match, int center_map); #endif // XASTIR_DB_GUI_HXastir-Release-2.2.4/src/dbfawk.c0000664000175000017500000002375715151324131015530 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ /* * This library glues the Awk-like functions (see awk.c) to attributes * for shapefiles (contained in DBF files). * * Alan Crosswell, n2ygk@weca.org * */ // // Functions which allocate memory: // -------------------------------- // dbfawk_field_list // dbfawk_load_sigs // dbfawk_find_sig // dbfawk_parse_record (indirectly) // // Functions which free memory: // ---------------------------- // dbfawk_free_info // dbfawk_load_sigs // dbfawk_free_sig // dbfawk_free_sigs // dbfawk_find_sig // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #include #include #include "awk.h" #include "dbfawk.h" #include "snprintf.h" #include "globals.h" #include // Must be last include file #include "leak_detection.h" /* * dbfawk_sig: Generate a signature for a DBF file. * Fills in sig and returns number of fields. */ int dbfawk_sig(DBFHandle dbf, char *sig, int size) { int nf = 0; if (sig && size > 0 && dbf) { int i; char *sp; int width,prec; nf = DBFGetFieldCount(dbf); for (i = 0, sp=sig; sp < &sig[size-XBASE_FLDHDR_SZ] && i < nf ; i++) { DBFGetFieldInfo(dbf,i,sp,&width,&prec); sp += strlen(sp); *sp++ = ':'; /* field name separator */ } if (i) { *--sp = '\0'; /* clobber the trailing sep */ } } return nf; } /* Free a field list */ void dbfawk_free_info ( dbfawk_field_info *list) { dbfawk_field_info *x, *p; for ( p = list; p != NULL; ) { x = p; p = p->next; free(x); } } /* * dbfawk_field_list: Generate a list of info about fields to read for * a given DBFHandle and colon-separated list of fieldnames. */ dbfawk_field_info *dbfawk_field_list(DBFHandle dbf, char *dbffields) { dbfawk_field_info *fi = NULL, *head = NULL, *prev; char *sp; /* now build up the list of fields to read */ for (sp = dbffields, prev = NULL; *sp; ) { char *d,*p = sp; char junk[XBASE_FLDHDR_SZ]; int w,prec; fi = calloc(1,sizeof(dbfawk_field_info)); if (!fi) { fprintf(stderr,"dbfawk_field_list: first calloc failed\n"); return NULL; } if (prev) { prev->next = fi; } else /* no prev, must be first one */ { head = fi; } d = fi->name; while (*p && *p != ':') { *d++ = *p++; } if (*p == ':') { *p++ = '\0'; } *d='\0'; fi->num = DBFGetFieldIndex(dbf, fi->name); fi->type = DBFGetFieldInfo(dbf, fi->num, junk, &w, &prec); sp = p; prev = fi; } return head; } /* * dbfawk_load_sigs: Load up dbfawk signature mappings * Reads *.dbfawk and registers dbffields "signature". * Returns head of sig_info list. * * TODO - consider whether it makes sense to use a private symtbl, * compile and then free here or require the caller to pass in a * symtbl that has dbfinfo declared. */ // Malloc's dbfawk_sig_info and returns a filled-in list dbfawk_sig_info *dbfawk_load_sigs(const char *dir, /* directory path */ const char *ftype) /* filetype */ { DIR *d; struct dirent *e; struct stat nfile; char fullpath[MAX_FILENAME]; int ftlen; dbfawk_sig_info *i = NULL, *head = NULL; awk_symtab *symtbl; char dbfinfo[1024]; /* local copy of signature */ if (!dir || !ftype) { return NULL; } ftlen = strlen(ftype); d = opendir(dir); if (!d) { return NULL; } symtbl = awk_new_symtab(); if (!symtbl) { return NULL; } awk_declare_sym(symtbl,"dbfinfo",STRING,dbfinfo,sizeof(dbfinfo)); while ((e = readdir(d)) != NULL) { int len = strlen(e->d_name); char *path = calloc(1,len+strlen(dir)+2); // Check for hidden files or directories if (e->d_name[0] == '.') { // Hidden, skip it free(path); continue; } // Check for regular files xastir_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, e->d_name); if (stat(fullpath, &nfile) != 0) { // Couldn't stat file free(path); continue; } if ((nfile.st_mode & S_IFMT) != S_IFREG) { // Not a regular file free(path); continue; } if (!path) { if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } fprintf(stderr,"failed to malloc in dbfawk.c!\n"); closedir(d); return NULL; } *dbfinfo = '\0'; if (len > ftlen && (strcmp(&e->d_name[len-ftlen],ftype) == 0)) { if (!head) { i = head = calloc(1,sizeof(dbfawk_sig_info)); if (!i) { fprintf(stderr,"failed to malloc in dbfawk.c!\n"); free(path); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } closedir(d); return NULL; } } else { i->next = calloc(1,sizeof(dbfawk_sig_info)); if (!i->next) { fprintf(stderr,"failed to malloc in dbfawk.c!\n"); free(path); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } closedir(d); return head; // Return what we were able to gather. } i = i->next; } xastir_snprintf(path, len+strlen(dir)+2, "%s/%s", dir, e->d_name); i->prog = awk_load_program_file(path); if (awk_compile_program(symtbl,i->prog) < 0) { fprintf(stderr,"%s: failed to parse\n",e->d_name); } else { /* dbfinfo must be defined in BEGIN rule */ awk_exec_begin(i->prog); i->sig = strdup(dbfinfo); awk_uncompile_program(i->prog); } } free(path); } closedir(d); if (symtbl) { awk_free_symtab(symtbl); free(symtbl); symtbl=NULL; } return head; } void dbfawk_free_sig(dbfawk_sig_info *ptr) { if (ptr) { if (ptr->prog) { awk_free_program(ptr->prog); } if (ptr->sig) { free(ptr->sig); } free(ptr); } } void dbfawk_free_sigs(dbfawk_sig_info *list) { dbfawk_sig_info *x, *p; for (p = list; p; ) { x = p; p = p->next; dbfawk_free_sig(x); } } /* * dbfawk_find_sig: Given a DBF file's "signature", find the appropriate * awk program. If filename is not null, see if there's a per-file .dbfawk * and load it. */ dbfawk_sig_info *dbfawk_find_sig(dbfawk_sig_info *Dbf_sigs, const char *sig, const char *file) { dbfawk_sig_info *result = NULL; if (file) { int perfilesize=strlen(file)+8; char *dot, *perfile = calloc(1,perfilesize); dbfawk_sig_info *info; if (!perfile) { fprintf(stderr,"failed to malloc in dbfawk_find_sig!\n"); return NULL; } xastir_snprintf(perfile, perfilesize-1, "%s", file); dot = strrchr(perfile,'.'); if (dot) { *dot = '\0'; } strncat(perfile, ".dbfawk", perfilesize-1); info = calloc(1,sizeof(*info)); if (!info) { fprintf(stderr,"failed to malloc in dbfawk_find_sig!\n"); free(perfile); return NULL; } info->prog = awk_load_program_file(perfile); /* N.B. info->sig is left NULL since it won't be searched, and to flag that it's safe to free this memory when we're done with it */ info->sig = NULL; free(perfile); if (info->prog) { return info; } else { dbfawk_free_sigs(info); } /* fall through and do normal signature search */ } for (result = Dbf_sigs; result; result = result->next) { if (strcmp(result->sig,sig) == 0) { return result; } } return NULL; } /* * dbfawk_parse_record: Read a dbf record and parse only the fields * listed in 'fi' using the program, 'rs'. */ void dbfawk_parse_record(awk_program *rs, DBFHandle dbf, dbfawk_field_info *fi, int i) { dbfawk_field_info *finfo; awk_exec_begin_record(rs); /* execute a BEGIN_RECORD rule if any */ for (finfo = fi; finfo ; finfo = finfo->next) { char qbuf[1024]; switch (finfo->type) { case FTString: sprintf(qbuf,"%s=%s",finfo->name,DBFReadStringAttribute(dbf,i,finfo->num)); break; case FTInteger: sprintf(qbuf,"%s=%d",finfo->name,DBFReadIntegerAttribute(dbf,i,finfo->num)); break; case FTDouble: sprintf(qbuf,"%s=%f",finfo->name,DBFReadDoubleAttribute(dbf,i,finfo->num)); break; case FTInvalid: default: sprintf(qbuf,"%s=??",finfo->name); break; } if (awk_exec_program(rs,qbuf,strlen(qbuf)) == 2) { break; } } awk_exec_end_record(rs); /* execute an END_RECORD rule if any */ } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.4/src/dbfawk.h0000664000175000017500000000467415151324131015532 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef DBFAWK_H #define DBFAWK_H #ifndef _SHAPEFILE_H_INCLUDED #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #endif // _SHAPEFILE_H_INCLUDED typedef struct dbfawk_field_info_ { struct dbfawk_field_info_ *next; char name[XBASE_FLDHDR_SZ]; /* name of the field */ int num; /* column number */ DBFFieldType type; /* data type */ } dbfawk_field_info; typedef struct dbfawk_sig_info_ { struct dbfawk_sig_info_ *next; char *sig; /* dbfinfo signature */ awk_program *prog; /* the program for this signature */ } dbfawk_sig_info; extern int dbfawk_sig(DBFHandle dbf, char *sig, int size); extern dbfawk_field_info *dbfawk_field_list(DBFHandle dbf, char *dbffields); extern dbfawk_sig_info *dbfawk_load_sigs(const char *dir, const char *ftype); extern dbfawk_sig_info *dbfawk_find_sig(dbfawk_sig_info *info, const char *sig, const char *file); extern void dbfawk_free_sig(dbfawk_sig_info *sig); extern void dbfawk_free_sigs(dbfawk_sig_info *list); extern void dbfawk_free_info(dbfawk_field_info *list); extern void dbfawk_parse_record(awk_program *rs, DBFHandle dbf, dbfawk_field_info *fi, int i); #endif /* !DBFAWK_H*/ Xastir-Release-2.2.4/src/debug_utils.c0000664000175000017500000000263615151324131016571 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include #include "xastir.h" #include "main.h" // Prints string to STDERR only if "my_debug_level" bits are set in // the global "debug_level" variable. Used for getting extra debug // messages during various stages of debugging. // // As far as I can tell, this was defined in utils.c but never, ever called // anywhere in Xastir. void xastir_debug(int my_debug_level, char *debug_string) { if (debug_level & my_debug_level) { fprintf(stderr, "%s", debug_string); } } Xastir-Release-2.2.4/src/debug_utils.h0000664000175000017500000000207115151324131016567 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_DEBUG_UTILS_H #define __XASTIR_DEBUG_UTILS_H extern void xastir_debug(int my_debug_level, char *debug_string); #endif Xastir-Release-2.2.4/src/dlm.c0000664000175000017500000007300615151324131015036 0ustar hibbyhibby/* * * Copyright (C) 2018-2026 The Xastir Group * * This file was contributed by Mike Nix. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #ifdef HAVE_LIBCURL #include #endif #include "xastir.h" #include "globals.h" #include "main.h" #include "mutex_utils.h" #include "dlm.h" // Must be last include file #include "leak_detection.h" /********************************************************** * DLM - DownLoad Manager - manage a list of items to download **********************************************************/ /* Notes on curl_multi and the tile queue: We could have used a thread for each transfer, but that's messy and wasteful. We could have used the curl_multi list as the queue, but that would end up with us either waiting until the last few tiles were downloading before returning, or just adding all the tiles and letting curl go for it - which could end up with hundreds of simultaneous transfers, although curl is supposed to have a limiter of some kind, it delivers no control over what order to process the queue. Our approach is to queue all the tiles in our own queue, and return immediately while letting a download thread feed curl the most recently added tiles first. This way, if you scroll past an area, the tiles will all be queued for checking but we will always start downloading tiles in the current view (ie most recently added) first - without cancelling any tiles already started. Mini HowTo: in your drawing function, before reading tiles, do this: DLM_queue_tile(...) each map tile you want call DLM_do_transfers() - this only does anything if the DLM was compiled with threading disabled optionally call DLM_wait_done() if you want to wait for all downloads to finish Draw your maps using the tiles available in your cache. When each download completes, the global request_new_image is incremented which triggers a redraw from the top level. It is safe to repeat this whole sequence at each redraw as tiles are only added to the queue if they are not in the queue already and the file does not exist, or the file is older than 7 days. */ // Enable use of a separate download thread in the background #define DLM_QUEUE_THREADED // Enable using curl_multi_* to download more than one tile at a time // Define this to use the code, set the number to limit the // simultaneous transfers // WARNING: defining this less than 1 will allow starting an unlimited number // of transfers. You probably shouldn't do that! // Also, don't set this too high or slow internet connections will have to // wait too long before starting to download tiles in the current view // when the user scrolls around a bit #define USE_CURL_MULTI 8 #define DLM_Q_STOP 0 #define DLM_Q_STARTING 1 #define DLM_Q_RUN 5 #define DLM_Q_IDLE 8 #define DLM_Q_QUIT 9 #define MAX_DESCLEN 40 struct DLM_queue_entry { struct DLM_queue_entry *next; struct DLM_queue_entry *prev; // These are only used by DLM_queue_tile for // checking if a tile is already queued // osm_zl is also used as a type flag (>=0 for tile, <0 for file) unsigned long x; unsigned long y; int osm_zl; int state; xastir_mutex lock; char fileName[MAX_FILENAME]; char desc[MAX_DESCLEN]; char *tempName; char *url; #ifdef HAVE_LIBCURL FILE *stream; #ifdef USE_CURL_MULTI char *curlErrBuf; CURL *curlSession; #endif #endif }; /* DLM_queue_lock is held whenever reading or changing DLM_queue_entry or * the linkages of the items in the queue. Each item also has a lock * for changing data in that item. */ xastir_mutex DLM_queue_lock = { .threadID=0, .lock=PTHREAD_MUTEX_INITIALIZER }; pthread_t DLM_queue_thread; volatile int DLM_queue_progress_flag=0; /* DLM_queue_state is protected by a lock to ensure memory consistency * between threads. It is held for every read or write of DLM_queue_state */ xastir_mutex DLM_state_lock = { .threadID=0, .lock=PTHREAD_MUTEX_INITIALIZER }; volatile int DLM_queue_state=DLM_Q_STOP; struct DLM_queue_entry *DLM_queue=NULL; void (*DLM_progress_callback)(void)=NULL; /********************************************************** * DLM_get_queue_state - Read DLM_queue_state while * ensuring it is locked **********************************************************/ static int DLM_get_queue_state(void) { int state; begin_critical_section(&DLM_state_lock, "DLM_get_queue_state"); state = DLM_queue_state; end_critical_section(&DLM_state_lock, "DLM_get_queue_state"); return state; } /********************************************************** * DLM_wait_done - wait until the transfers are all complete * returns the number of items in the queue if it timed out **********************************************************/ int DLM_wait_done(time_t timeout) { #ifdef DLM_QUEUE_THREADED while ((timeout > 0) && (DLM_get_queue_state() == DLM_Q_RUN)) { sleep(1); timeout--; } #else if (DLM_queue_len()>0) { DLM_do_transfers(); } #endif return DLM_queue_len(); } /********************************************************** * DLM_check_progress - check if we have more tiles since last call **********************************************************/ int DLM_check_progress(void) { int p=DLM_queue_progress_flag; DLM_queue_progress_flag=0; return p; } /********************************************************** * DLM_queue_progress - called when new tiles are available **********************************************************/ static void DLM_queue_progress(int prog) { if (prog) { DLM_queue_progress_flag=1; // trigger a redraw of the screen request_new_image++; if (DLM_progress_callback!=NULL) { DLM_progress_callback(); } } } /********************************************************** * DLM_queue_len - return number of tiles queued for download/check **********************************************************/ int DLM_queue_len(void) { struct DLM_queue_entry *q=DLM_queue; int count=0; begin_critical_section(&DLM_queue_lock, "DLM_queue_len"); while (q) { count++; q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_len"); //fprintf(stderr,"DLM_queue_len is %d\n", count); return count; } /********************************************************** * abort_DLM_queue_abort() - stop the transfer thread **********************************************************/ void DLM_queue_abort(void) { begin_critical_section(&DLM_state_lock, "DLM_queue_abort"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_queue_abort"); //fprintf(stderr, "DLM_queue aborting\n"); } /********************************************************** * DLM_queue_entry_alloc() - allocate a queue entry **********************************************************/ static struct DLM_queue_entry *DLM_queue_entry_alloc(void) { return malloc(sizeof(struct DLM_queue_entry)); } /********************************************************** * DLM_queue_entry_free() - free memory used by a tile queue entry **********************************************************/ static void DLM_queue_entry_free(struct DLM_queue_entry *q) { if (q) { begin_critical_section(&DLM_queue_lock, "DLM_queue_entry_free:Queue Lock"); begin_critical_section(&(q->lock), "DLM_queue_entry_free:tile lock"); //fprintf(stderr, "DLM_queue_free %s, ishead=%d\n", q->desc, DLM_queue_entry == q); if ((q->state==DLM_Q_IDLE) || (q->state==DLM_Q_STOP)) { // mark as being freed, just in case q->state=-1; // if we are the head of the queue, it needs updating if (DLM_queue == q) { DLM_queue = q->next; } // remove this entry from whatever list it's in if (q->next) { q->next->prev = q->prev; } if (q->prev) { q->prev->next = q->next; } // free anything we point to if (q->url) { free(q->url); } if (q->tempName) { free(q->tempName); } // if (q->serverURL) free(q->serverURL); // if (q->baseDir) free(q->baseDir); // if (q->ext) free(q->ext); #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI if (q->curlErrBuf) { free(q->curlErrBuf); } if (q->curlSession) { curl_easy_cleanup(q->curlSession); } if (q->stream) { fclose(q->stream); } #endif #endif // free us end_critical_section(&(q->lock), "DLM_queue_entry_free:tile unlock"); free(q); } else { end_critical_section(&(q->lock), "DLM_queue_entry_free:tile_unlock"); } end_critical_section(&DLM_queue_lock, "DLM_queue_entry_free:Queue_unlock"); } } /********************************************************** * DLM_queue_destroy() - free all entries in the queue **********************************************************/ static void DLM_queue_destroy(void) { struct DLM_queue_entry *next, *q; q = DLM_queue; while (q) { next=q->next; if (q->state==DLM_Q_IDLE) { DLM_queue_entry_free(q); } q=next; } } /********************************************************** * DLM_queue_abort_tiles() - free all tiles in the queue **********************************************************/ void DLM_queue_abort_tiles(void) { struct DLM_queue_entry *next, *q; q = DLM_queue; while (q) { next=q->next; if ((q->state==DLM_Q_IDLE) && (q->osm_zl>=0)) { DLM_queue_entry_free(q); } q=next; } } /********************************************************** * DLM_queue_abort_files() - free all non-tiles in the queue **********************************************************/ void DLM_queue_abort_files(void) { struct DLM_queue_entry *next, *q; q = DLM_queue; while (q) { next=q->next; if ((q->state==DLM_Q_IDLE) && (q->osm_zl<0)) { DLM_queue_entry_free(q); } q=next; } } /********************************************************** * DLM_store_file() - move the temp file into place if we used one **********************************************************/ static int DLM_store_file(struct DLM_queue_entry *q) { int rc; if (!q->tempName) { return 0; } //unlink(t->fileName); // not needed on Linux (the other OS?) if ((rc=rename(q->tempName, q->fileName))) { fprintf(stderr, "DLM_transfer_thread: unable to rename %s->%s: errno=%d\n", q->tempName, q->fileName, errno); } else { free(q->tempName); q->tempName=NULL; } return rc; } /********************************************************** * DLM_get_next_tile() - find the next idle tile ready for download * also locks that tile **********************************************************/ static struct DLM_queue_entry *DLM_get_next_tile(int state) { struct DLM_queue_entry *q; begin_critical_section(&DLM_queue_lock, "DLM_transfer_thread: queue lock"); q = DLM_queue; while (q && (q->state!=state)) { q=q->next; } if (q) { begin_critical_section(&(q->lock), "DLM_transfer_thread: tile lock"); } end_critical_section(&DLM_queue_lock, "DLM_transfer_thread: queue unlock"); return q; } #ifdef HAVE_LIBCURL /********************************************************** * DLM_curl_fwrite_callback() - callback for curl_multi **********************************************************/ static size_t DLM_curl_fwrite_callback(void *buffer, size_t size, size_t nmemb, void *stream) { struct DLM_queue_entry *out = (struct DLM_queue_entry *)stream; if (out && !out->stream) { out->stream=fopen((out->tempName ? out->tempName : out->fileName), "wb"); //fprintf(stderr,"DLM_curl_fwrite_callback: Opening %s\n", out->fileName); if (!out->stream) { return -1; } } return fwrite(buffer, size, nmemb, out->stream); } /********************************************************** * DLM_curl_progress_callback() - callback for curl_multi **********************************************************/ static int DLM_curl_progress_callback(void *p, double UNUSED(dltotal), double UNUSED(dlnow), double UNUSED(ultotal), double UNUSED(ulnow) ) { struct DLM_queue_entry *tile = (struct DLM_queue_entry *)p; if (!tile) { return 0; } // possibly update some display somewhere? return 0; } /********************************************************** * DLM_curl_set_queue_entry() - curl session options we can't set * at initialization in some cases. **********************************************************/ static void DLM_curl_set_queue_entry(CURL *mySession, struct DLM_queue_entry *qentry) { curl_easy_setopt(mySession, CURLOPT_FILE, qentry); curl_easy_setopt(mySession, CURLOPT_PROGRESSDATA, qentry); curl_easy_setopt(mySession, CURLOPT_PRIVATE, qentry); #ifdef USE_CURL_MULTI qentry->curlSession = mySession; #endif } /********************************************************** * DLM_curl_init() - prep a curl handle our way * **********************************************************/ static CURL *DLM_curl_init(char *errBuf) { CURL *mySession; char agent_string[15]; mySession = curl_easy_init(); if (mySession != NULL) { if (debug_level & 8192) { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 1L); } else { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 0L); } curl_easy_setopt(mySession, CURLOPT_ERRORBUFFER, errBuf); xastir_snprintf(agent_string, sizeof(agent_string),"Xastir"); curl_easy_setopt(mySession, CURLOPT_USERAGENT, agent_string); // write and progress functions curl_easy_setopt(mySession, CURLOPT_WRITEFUNCTION, DLM_curl_fwrite_callback); curl_easy_setopt(mySession, CURLOPT_PROGRESSFUNCTION, DLM_curl_progress_callback); curl_easy_setopt(mySession, CURLOPT_TIMEOUT, (long)net_map_timeout); curl_easy_setopt(mySession, CURLOPT_CONNECTTIMEOUT, (long)(net_map_timeout/2)); // Added in libcurl 7.9.8 #if (LIBCURL_VERSION_NUM >= 0x070908) curl_easy_setopt(mySession, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.6 #if (LIBCURL_VERSION_NUM >= 0x071006) curl_easy_setopt(mySession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.7 #if (LIBCURL_VERSION_NUM >= 0x071007) curl_easy_setopt(mySession, CURLOPT_PROXYAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10 #if (LIBCURL_VERSION_NUM >= 0x070a00) // This prevents a segfault for the case where we get a timeout on // domain name lookup. It has to do with the ALARM signal // and siglongjmp(), which we use in hostname.c already. // This URL talks about it a bit more, plus see the libcurl // docs: // // http://curl.haxx.se/mail/lib-2002-12/0103.html // curl_easy_setopt(mySession, CURLOPT_NOSIGNAL, 1L); #endif // LIBCURL_VERSION_NUM // Respect and follow http redirects curl_easy_setopt(mySession, CURLOPT_FOLLOWLOCATION, 1L); } return(mySession); } // DLM_curl_init() #endif // HAVE_LIBCURL /********************************************************** * DLM_transfer_thread() - retrieve item queued for download **********************************************************/ static void *DLM_transfer_thread(void * UNUSED(arg) ) { struct DLM_queue_entry *tile; #ifdef DLM_QUEUE_THREADED int idleCnt; #endif #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI CURLM *multiSession; CURLMsg *msg; int msgsLeft; int runningTransfers; #else CURL *mySession; char errBuf[CURL_ERROR_SIZE]; int curl_result; #endif #endif // HAVE_LIBCURL // detach - we don't care about the result, and won't be calling pthread_join() pthread_detach(pthread_self()); begin_critical_section(&DLM_state_lock, "DLM_transfer_thread set to run"); DLM_queue_state = DLM_Q_RUN; end_critical_section(&DLM_state_lock, "DLM_transfer_thread set to run"); #ifdef DLM_QUEUE_THREADED idleCnt=0; #endif if (debug_level & 1) { fprintf(stderr, "DLM_transfer_thread started\n"); } #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI multiSession = curl_multi_init(); runningTransfers=0; #else mySession = DLM_curl_init(errBuf); #endif #endif // HAVE_LIBCURL // get the tiles while (DLM_get_queue_state() != DLM_Q_QUIT) { #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI curl_multi_perform(multiSession, &runningTransfers); // handle any "download complete" messages from curl while ((msg=curl_multi_info_read(multiSession, &msgsLeft))) { if (msg->msg==CURLMSG_DONE) { if (msg->easy_handle) { struct DLM_queue_entry *t; curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (void *)&t); t->state=DLM_Q_STOP; if (t->stream) { fclose(t->stream); t->stream=NULL; } if (msg->data.result != 0) { fprintf(stderr, "CURL error downloading %s: %d\nURL:%s\n%s\n", t->desc, msg->data.result, t->url, t->curlErrBuf); } if ((msg->data.result==0) && (!DLM_store_file(t))) { DLM_queue_progress(1); } else { unlink(t->tempName); } //fprintf(stderr,"DLM_transfer_queue: completed item %s\n",t->desc); curl_multi_remove_handle(multiSession, msg->easy_handle); curl_easy_cleanup(msg->easy_handle); t->curlSession=NULL; DLM_queue_entry_free(t); } } else { fprintf(stderr, "CURL Message: (%d)\n", msg->msg); } } #ifdef DLM_QUEUE_THREADED if (runningTransfers>0) { idleCnt=0; } #endif if ((USE_CURL_MULTI < 1) || (runningTransfers < USE_CURL_MULTI)) { #endif #endif // get the next tile that is idle. Tile is locked for us tile=DLM_get_next_tile(DLM_Q_IDLE); if (tile) { tile->state = DLM_Q_RUN; #ifdef DLM_QUEUE_THREADED idleCnt=0; #endif end_critical_section(&(tile->lock), "DLM_transfer_thread: tile unlock"); //fprintf(stderr,"DLM_transfer_queue: started item %s, qlen=%d\n",tile->desc,DLM_queue_len()); #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI if (!tile->curlErrBuf) { tile->curlErrBuf=malloc(CURL_ERROR_SIZE); } if (!tile->curlSession) { tile->curlSession=DLM_curl_init(tile->curlErrBuf); } DLM_curl_set_queue_entry(tile->curlSession, tile); curl_easy_setopt(tile->curlSession, CURLOPT_URL, tile->url); curl_easy_setopt(tile->curlSession, CURLOPT_FAILONERROR, 1); curl_multi_add_handle(multiSession, tile->curlSession); #else // USE_CURL_MULTI DLM_curl_set_queue_entry(mySession, tile); curl_easy_setopt(mySession, CURLOPT_URL, tile->url); curl_easy_setopt(mySession, CURLOPT_FAILONERROR, 1); curl_result = curl_easy_perform(mySession); if (tile->stream) { fclose(tile->stream); tile->stream=NULL; } if (curl_result != CURLE_OK) { fprintf(stderr, "Download error for %s: curl result %d\nURL:%s\ncurlerr:%s", tile->desc, curl_result, tile->url, errBuf); } else { if (!DLM_store_file(tile)) { DLM_queue_progress(1); } } #endif // USE_CURL_MULTI #else // HAVE_LIBCURL // We have no other option - use wget, one file at a time { char cmd[500]; xastir_snprintf(cmd, sizeof(cmd), "%s --server-response --user-agent=Xastir --tries=1 --timeout=%d --output-document=\'%s\' \'%s\' 2> /dev/null\n", "wget", net_map_timeout, (tile->tempName ? tile->tempName : tile->fileName), tile->url); if (system(cmd)) { fprintf(stderr, "Couldn't download the file with wget\n"); } else { if (!DLM_store_file(tile)) { DLM_queue_progress(1); } } } #endif // HAVE_LIBCURL #if defined(HAVE_LIBCURL) && defined(USE_CURL_MULTI) #else tile->state = DLM_Q_STOP; //fprintf(stderr,"DLM_transfer_queue: done item %s\n",tile->desc); DLM_queue_entry_free(tile); #endif #ifdef DLM_QUEUE_THREADED } else if (idleCnt < 10) { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread idle check"); DLM_queue_state = DLM_Q_IDLE; end_critical_section(&DLM_state_lock, "DLM_transfer_thread idle check"); //fprintf(stderr,"DLM_transfer_queue: idling\n"); sleep(1); idleCnt++; #endif } else { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread set quit"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_transfer_thread set quit"); } #ifndef DLM_QUEUE_THREADED HandlePendingEvents(app_context); if (interrupt_drawing_now) { begin_critical_section(&DLM_state_lock, "DLM_transfer_thread interrupt quit"); DLM_queue_state = DLM_Q_QUIT; end_critical_section(&DLM_state_lock, "DLM_transfer_thread interrupt quit"); } #endif #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI } usleep(100000); // 0.1 seconds - don't hog the CPU :) // also limits us to starting 10 downloads/second // and staggers the downloads a bit #endif #endif } #ifdef HAVE_LIBCURL #ifdef USE_CURL_MULTI curl_multi_cleanup(multiSession); #else curl_easy_cleanup(mySession); #endif #endif // HAVE_LIBCURL DLM_queue_destroy(); if (debug_level & 1) { fprintf(stderr,"DLM_transfer_thread stopped\n"); } begin_critical_section(&DLM_state_lock, "DLM_transfer_thread stop update"); DLM_queue_state = DLM_Q_STOP; end_critical_section(&DLM_state_lock, "DLM_transfer_thread stop update"); return NULL; } /********************************************************** * DLM_queue_start_if_needed() * Start the transfers if they need starting **********************************************************/ static void DLM_queue_start_if_needed(void) { #ifdef DLM_QUEUE_THREADED if (DLM_get_queue_state() == DLM_Q_STOP) { // start the thread // Queue state lock not needed as there is no other thread running here DLM_queue_state = DLM_Q_STARTING; if (pthread_create(&DLM_queue_thread, NULL, DLM_transfer_thread, NULL)) { //fprintf(stderr,"Error creating OSM transfer thread\n"); DLM_queue_state = DLM_Q_STOP; } } #endif } /********************************************************** * DLM_do_transfers() - download all tiles now * Does nothing if we are in threaded mode **********************************************************/ void DLM_do_transfers(void) { #ifdef DLM_QUEUE_THREADED if (DLM_queue_len()>0) { DLM_queue_start_if_needed(); } #else DLM_transfer_thread(NULL); #endif } /********************************************************** * DLM_queue_add() - Queue a prepared entry for download. * Internal use only - no checking is done! **********************************************************/ static void DLM_queue_add(struct DLM_queue_entry *ent) { if (ent->url && ent->tempName) { // if the thread is quitting, wait till it's done while (DLM_get_queue_state() == DLM_Q_QUIT); // queue this tile //fprintf(stderr,"OSM queueing %s, qlen=%d\n",tile->fileName,DLM_queue_len()); begin_critical_section(&DLM_queue_lock, "DLM_queue_add"); if (DLM_queue) { DLM_queue->prev=ent; } ent->next = DLM_queue; DLM_queue = ent; end_critical_section(&DLM_queue_lock, "DLM_queue_add"); DLM_queue_start_if_needed(); } else { DLM_queue_entry_free(ent); } } /********************************************************** * DLM_queue_tile() - queue map tiles for download * Written for OpenStreetMap but generic enough to live here. **********************************************************/ void DLM_queue_tile( char *serverURL, unsigned long x, unsigned long y, int osm_zl, char *baseDir, char *ext ) { struct DLM_queue_entry *tile, *q; struct stat sb; int len; // see if it's already queued begin_critical_section(&DLM_queue_lock, "DLM_queue_tile:check queue"); q=DLM_queue; while (q && ((q->x!=x) || (q->y!=y) || (q->osm_zl!=osm_zl) )) { q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_tile:check queue"); if (q) { //fprintf(stderr, "OSM %s already queued\n", q->desc); return; } tile=DLM_queue_entry_alloc(); if (!tile) { return; } tile->next = NULL; tile->prev = NULL; // tile->serverURL = strndup(serverURL, MAX_FILENAME); // tile->baseDir = strndup(baseDir, MAX_FILENAME); // tile->ext = strndup(ext, MAX_FILENAME); tile->x = x; tile->y = y; tile->osm_zl = osm_zl; tile->state = DLM_Q_IDLE; tile->url = NULL; tile->fileName[0]='\0'; init_critical_section(&(tile->lock)); #ifdef HAVE_LIBCURL tile->stream=NULL; #ifdef USE_CURL_MULTI tile->curlErrBuf=NULL; tile->curlSession=NULL; #endif #endif xastir_snprintf(tile->desc, sizeof(tile->desc), "Tile:%u/%lu/%lu", osm_zl, x, y); xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%u/%lu/%lu.%s", osm_zl, x, y, ext); len = strlen(serverURL) + strlen(tile->fileName) +2; tile->url = malloc(len); if (tile->url) { xastir_snprintf(tile->url, len, "%s/%s", serverURL, tile->fileName); } xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s/%u/%lu/%lu.%s.part", baseDir, osm_zl, x, y, ext); tile->tempName = strdup(tile->fileName); xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s/%u/%lu/%lu.%s", baseDir, osm_zl, x, y, ext); // if we have the file and it's < 7 days old, don't queue it if (stat(tile->fileName, &sb) != -1) { if ((sb.st_mtime + (7 * 24 * 60 * 60)) >= time(NULL)) { //fprintf(stderr,"%s is fresh in cache\n", tile->fileName); tile->state=DLM_Q_STOP; DLM_queue_entry_free(tile); return; } } DLM_queue_add(tile); } /********************************************************** * DLM_queue_file() - Queue a file for download. **********************************************************/ void DLM_queue_file( char *url, char *filename, time_t expiry ) { struct DLM_queue_entry *tile, *q; struct stat sb; char *p; // see if it's already queued begin_critical_section(&DLM_queue_lock, "DLM_queue_file:check queue"); q=DLM_queue; while (q && (q->osm_zl>=0) && strncmp(filename,q->fileName,sizeof(q->fileName))) { q=q->next; } end_critical_section(&DLM_queue_lock, "DLM_queue_file:check queue"); if (q) { //fprintf(stderr, "OSM %s already queued\n", filename); return; } tile=DLM_queue_entry_alloc(); if (!tile) { return; } tile->next = NULL; tile->prev = NULL; // tile->serverURL = strndup(serverURL, MAX_FILENAME); // tile->baseDir = strndup(baseDir, MAX_FILENAME); // tile->ext = strndup(ext, MAX_FILENAME); tile->x = 0; tile->y = 0; tile->osm_zl = -1; tile->state = DLM_Q_IDLE; tile->url = strdup(url); init_critical_section(&(tile->lock)); #ifdef HAVE_LIBCURL tile->stream=NULL; #ifdef USE_CURL_MULTI tile->curlErrBuf=NULL; tile->curlSession=NULL; #endif #endif p=filename; while (p && *p) { p++; } p-=sizeof(tile->desc)-6; if (pdesc, sizeof(tile->desc), "File:%s", filename); } else { xastir_snprintf(tile->desc, sizeof(tile->desc), "File:...%s", p+3); } xastir_snprintf(tile->fileName, sizeof(tile->fileName), "%s.part", filename); tile->tempName = strdup(tile->fileName); strncpy(tile->fileName, filename, sizeof(tile->fileName)); // if we have the file and it's < expiry seconds old or expiry<0, don't queue it if ((expiry!=0) && stat(tile->fileName, &sb) != -1) { time_t age = time(NULL) - sb.st_mtime; if ((expiry < 0) || (age < expiry)) { //fprintf(stderr,"%s is fresh\n", tile->fileName); tile->state=DLM_Q_STOP; DLM_queue_entry_free(tile); return; } } DLM_queue_add(tile); } ///////////////////////////////////////////// End of DownLoadManager code /////////////////////////////////////// Xastir-Release-2.2.4/src/dlm.h0000664000175000017500000000264215151324131015041 0ustar hibbyhibby/* * Copyright (C) 2018-2026 The Xastir Group * * This file was contributed by Mike Nix. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef DLM_H #define DLM_H #include // for KeySym int DLM_wait_done(time_t timeout); int DLM_check_progress(void); int DLM_queue_len(void); void DLM_queue_abort(void); void DLM_queue_abort_tiles(void); void DLM_queue_abort_files(void); void DLM_do_transfers(void); void DLM_queue_tile( char *serverURL, unsigned long x, unsigned long y, int osm_zl, char *baseDir, char *ext ); void DLM_queue_file( char *url, char *filename, time_t expiry ); #endif //DLM_H Xastir-Release-2.2.4/src/dr_utils.c0000664000175000017500000002453015151324131016105 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include "util.h" #include "main.h" #include "database.h" // Calculate new position based on distance and angle. // // Input: lat/long in Xastir coordinate system (100ths of seconds) // distance in nautical miles // angle in ° true // // Outputs: *x_long, *y_lat in Xastir coordinate system (100ths of // seconds) // // // From http://home.t-online.de/home/h.umland/Chapter12.pdf // // Dead-reckoning using distance in km, course C: // Lat_B° = Lat_A° + ( (360/40031.6) * distance * cos C ) // // Dead-reckoning using distance in nm, course C: // Lat_B° = Lat_A° + ( (distance/60) * cos C ) // // Average of two latitudes (required for next two equations) // Lat_M° = (Lat_A° + Lat_B°) / 2 // // Dead-reckoning using distance in km, course C: // Lon_B° = Lon_A° + ( (360/40031.6) * distance * (sin C / cos // Lat_M) ) // // Dead-reckoning using distance in nm, course C: // Lon_B° = Lon_A° + ( (distance/60) * (sin C / cos Lat_M) ) // // If resulting longitude exceeds +/- 180°, subtract/add 360°. // void compute_DR_position(long x_long, // input long y_lat, // input double range, // input in nautical miles double course, // input in ° true long *x_long2, // output long *y_lat2) // output { double bearing_radians, lat_M_radians; float lat_A, lat_B, lon_A, lon_B, lat_M; int ret; unsigned long x_u_long, y_u_lat; //fprintf(stderr,"Distance:%fnm, Course:%f, Time:%d\n", // range, // course, // (int)(sec_now() - p_station->sec_heard)); // Bearing in radians bearing_radians = (double)((course/360.0) * 2.0 * M_PI); // Convert lat/long to floats ret = convert_from_xastir_coordinates( &lon_A, &lat_A, x_long, y_lat); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long2 = x_long; *y_lat2 = y_lat; return; } // Compute new latitude lat_B = (float)((double)(lat_A) + (range/60.0) * cos(bearing_radians)); // Compute mid-range latitude lat_M = (lat_A + lat_B) / 2.0; // Convert lat_M to radians lat_M_radians = (double)((lat_M/360.0) * 2.0 * M_PI); // Compute new longitude lon_B = (float)((double)(lon_A) + (range/60.0) * ( sin(bearing_radians) / cos(lat_M_radians)) ); // Test for out-of-bounds longitude, correct if so. if (lon_B < -360.0) { lon_B = lon_B + 360.0; } if (lon_B > 360.0) { lon_B = lon_B - 360.0; } //fprintf(stderr,"Lat:%f, Lon:%f\n", lat_B, lon_B); ret = convert_to_xastir_coordinates(&x_u_long, &y_u_lat, lon_B, lat_B); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long2 = x_long; *y_lat2 = y_lat; return; } // Convert from unsigned long to long *x_long2 = (long)x_u_long; *y_lat2 = (long)y_u_lat; } // Calculate new position based on speed/course/modified-time. // We'll call it from Create_object_item_tx_string() and from the // modify object/item routines to calculate a new position and stuff // it into the record along with the modification time before we // start off in a new direction. // // Input: *p_station // // Outputs: *x_long, *y_lat in Xastir coordinate system (100ths of // seconds) // // // From http://home.t-online.de/home/h.umland/Chapter12.pdf // // Dead-reckoning using distance in km, course C: // Lat_B° = Lat_A° + ( (360/40031.6) * distance * cos C ) // // Dead-reckoning using distance in nm, course C: // Lat_B° = Lat_A° + ( (distance/60) * cos C ) // // Average of two latitudes (required for next two equations) // Lat_M° = (Lat_A° + Lat_B°) / 2 // // Dead-reckoning using distance in km, course C: // Lon_B° = Lon_A° + ( (360/40031.6) * distance * (sin C / cos // Lat_M) ) // // Dead-reckoning using distance in nm, course C: // Lon_B° = Lon_A° + ( (distance/60) * (sin C / cos Lat_M) ) // // If resulting longitude exceeds +/- 180°, subtract/add 360°. // // // Possible Problems/Changes: // -------------------------- // *) Change to using last_modified_time for DR. Also tweak the // code so that we don't do incremental DR and use our own // decoded objects to update everything. If we keep the // last_modified_time and the last_modified_position separate // DR'ed objects/items, we can always use those instead of the // other variables if we have a non-zero speed. // // *) Make sure not to corrupt our position of the object when we // receive the packet back via loopback/RF/internet. In // particular the position and the last_modified_time should stay // constant in this case so that dead-reckoning can continue to // move the object consistently, plus we won't compound errors as // we go. // // *) A server Xastir sees empty strings on it's server port when // these objects are transmitted to it. Investigate. It // sometimes does it when speed is 0, but it's not consistent. // // *) Get the last_modified_time embedded into the logfile so that // we don't "lose time" if we shut down for a bit. DR'ed objects // will be at the proper positions when we start back up. // void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat) { int my_course = 0; // In ° true double range = 0.0; double bearing_radians, lat_M_radians; float lat_A, lat_B, lon_A, lon_B, lat_M; int ret; unsigned long x_u_long, y_u_lat; time_t secs_now; secs_now=sec_now(); // Check whether we have course in the current data // if ( (strlen(p_station->course)>0) && (atof(p_station->course) > 0) ) { my_course = atoi(p_station->course); // In ° true } // // Else check whether the previous position had a course. Note // that newest_trackpoint if it exists should be the same as the // current data, so we have to go back one further trackpoint. // Make sure in this case that this trackpoint has occurred // within the dead-reckoning timeout period though, else ignore // it. // else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) && (p_station->newest_trackpoint->prev->course != -1) // Undefined && ( (secs_now-p_station->newest_trackpoint->prev->sec) < dead_reckoning_timeout) ) { // In ° true my_course = p_station->newest_trackpoint->prev->course; } // Get distance in nautical miles from the current data // if ( (strlen(p_station->speed)>0) && (atof(p_station->speed) >= 0) ) { // Speed is in knots (same as nautical miles/hour) range = (double)( (sec_now() - p_station->sec_heard) * ( atof(p_station->speed) / 3600.0 ) ); } // // Else check whether the previous position had speed. Note // that newest_trackpoint if it exists should be the same as the // current data, so we have to go back one further trackpoint. // else if ( (p_station->newest_trackpoint != NULL) && (p_station->newest_trackpoint->prev != NULL) && (p_station->newest_trackpoint->prev->speed != -1) // Undefined && ( (secs_now-p_station->newest_trackpoint->prev->sec) < dead_reckoning_timeout) ) { // Speed is in units of 0.1km/hour. Different than above! range = (double)( (sec_now() - p_station->sec_heard) * ( p_station->newest_trackpoint->prev->speed / 10 * 0.5399568 / 3600.0 ) ); } //fprintf(stderr,"Distance:%fnm, Course:%d, Time:%d\n", // range, // my_course, // (int)(sec_now() - p_station->sec_heard)); // Bearing in radians bearing_radians = (double)((my_course/360.0) * 2.0 * M_PI); // Convert lat/long to floats ret = convert_from_xastir_coordinates( &lon_A, &lat_A, p_station->coord_lon, p_station->coord_lat); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long = p_station->coord_lon; *y_lat = p_station->coord_lat; return; } // Compute new latitude lat_B = (float)((double)(lat_A) + (range/60.0) * cos(bearing_radians)); // Compute mid-range latitude lat_M = (lat_A + lat_B) / 2.0; // Convert lat_M to radians lat_M_radians = (double)((lat_M/360.0) * 2.0 * M_PI); // Compute new longitude lon_B = (float)((double)(lon_A) + (range/60.0) * ( sin(bearing_radians) / cos(lat_M_radians)) ); // Test for out-of-bounds longitude, correct if so. if (lon_B < -360.0) { lon_B = lon_B + 360.0; } if (lon_B > 360.0) { lon_B = lon_B - 360.0; } //fprintf(stderr,"Lat:%f, Lon:%f\n", lat_B, lon_B); ret = convert_to_xastir_coordinates(&x_u_long, &y_u_lat, lon_B, lat_B); // Check if conversion ok if (!ret) { // Problem during conversion. Exit without changes. *x_long = p_station->coord_lon; *y_lat = p_station->coord_lat; return; } // Convert from unsigned long to long *x_long = (long)x_u_long; *y_lat = (long)y_u_lat; } Xastir-Release-2.2.4/src/dr_utils.h0000664000175000017500000000227415151324131016113 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_DR_UTILS_H #define __XASTIR_DR_UTILS_H extern void compute_DR_position(long x_long, long y_lat, double range, double course, long *x_long2, long *y_lat2); extern void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat); #endif Xastir-Release-2.2.4/src/draw_symbols.c0000664000175000017500000035263115151324131016773 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include "xastir.h" #include "database.h" #include "db_funcs.h" #include "draw_symbols.h" #include "main.h" #include "util.h" #include "mutex_utils.h" #include "dr_utils.h" #include "color.h" #include "maps.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define ANGLE_UPDOWN 45 /* prefer horizontal cars if less than 45 degrees */ int symbols_loaded = 0; int symbols_cache[5] = {0,0,0,0,0}; Widget select_symbol_dialog = (Widget)NULL; static xastir_mutex select_symbol_dialog_lock; Pixmap select_icons[(126-32)*2]; //33 to 126 with both '/' and '\' symbols (94 * 2) or 188 int symbol_change_requested_from = 0; void draw_symbols_init(void) { init_critical_section( &select_symbol_dialog_lock ); } /*** symbol data ***/ void clear_symbol_data(void) { int my_size; int i; char *data_ptr; data_ptr = (char *)symbol_data; my_size = (int)sizeof(SymbolData); for (i=0; i screen_width) { return; } if (x < 0) { return; } if (y > screen_height) { return; } if (y < 0) { return; } // With a large font, the background rectangle is too small. Need // to include the font metrics in this drawing algorithm. gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); font_width = (int)((xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->min_bounds.width) / 4); font_height = xfs_ptr->max_bounds.ascent + xfs_ptr->max_bounds.descent; switch (style) { case 0: // make outline style (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); // draw an outline 1 pixel bigger than text (void)XDrawString(XtDisplay(w),where,gc,x+1,y-1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x+1,y,text,length); (void)XDrawString(XtDisplay(w),where,gc,x+1,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y-1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x-1,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x,y+1,text,length); (void)XDrawString(XtDisplay(w),where,gc,x,y-1,text,length); break; case 1: // draw text the old way in a gray box // Leave this next one hard-coded to 0xff. This keeps // the background as gray. (void)XSetForeground(XtDisplay(w),gc,colors[0xff]); (void)XFillRectangle( XtDisplay(w), where, gc, x, // X y-(font_height-(font_height/4)), // Y // Get the actual width of the text in pixels get_text_width(w,text), // width font_height); // height (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x+(font_height/10),y+(font_width/8),text,length); break; case 2: // draw white or colored text in a black box (void)XSetForeground( XtDisplay(w), gc, GetPixelByName(w,"black") ); (void)XFillRectangle( XtDisplay(w), where, gc, x, // X y-(font_height-(font_height/4)), // Y // Get the actual width of the text in pixels get_text_width(w,text), font_height); // height break; // Case three will be used in a future release with an additional // Station Text Style selection case 3: default: // Real Shadow text on a transparent background (void)XSetForeground(XtDisplay(w),gc,colors[bgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x+(font_height/10),y+(font_width/8),text,length); break; } // finally draw the text (void)XSetForeground(XtDisplay(w),gc,colors[fgcolor]); (void)XDrawString(XtDisplay(w),where,gc,x,y,text,length); // And free our font info if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } } /* symbol drawing routines */ // Function to draw a line between a WP symbol "\/" and the // transmitting station. We pass it the WP symbol. It does a // lookup for the transmitting station callsign to get those // coordinates, then draws a line between the two symbols if // possible (both on screen). // // If the symbol was a Waypoint symbol, "\/", we need to draw a line // from the transmitting station to the waypoint symbol according to // the spec. Take care to not draw the line any longer than needed // (don't exercise the X11 long-line drawing bug). According to the // spec we also need to change the symbol to just a red dot, but // it's nice having the "WP" above it so we can differentiate it // from the other red dot symbol. // // We should skip drawing the line if the object/item is not being drawn. // Should we skip it if the origination station isn't being drawn? // Do we need to add yet another togglebutton to enable/disable this line? // // Note that this type of operation, making a relation between two // symbols, breaks our paradism quite a bit. Until now all symbols // have been independent of each other. Perhaps we should store the // location of one symbol in the data of the other so that we won't // have to compare back and forth. This won't help much if either // or both symbols are moving. Probably better to just do a lookup // of the originating station by callsign through our lists and then // draw the line between the two coordinates each time. // void draw_WP_line(DataRow *p_station, int ambiguity_flag, long ambiguity_coord_lon, long ambiguity_coord_lat, Pixmap where, Widget UNUSED(w) ) { DataRow *transmitting_station = NULL; int my_course; long x_long, y_lat; long x_long2, y_lat2; double lat_m; long x, y; long x2, y2; double temp; int color = trail_colors[p_station->trail_color]; float temp_latitude, temp_latitude2; float temp_longitude, temp_longitude2; // Compute screen position of waypoint symbol if (ambiguity_flag) { x_long = ambiguity_coord_lon; y_lat = ambiguity_coord_lat; } else { x_long = p_station->coord_lon; y_lat = p_station->coord_lat; } // x & y are screen location of waypoint symbol x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; // Find transmitting station, get it's position. // p_station->origin contains the callsign for the transmitting // station. Do a lookup on that callsign through our database // to get the position of that station. if (!search_station_name(&transmitting_station,p_station->origin,1)) { // Can't find call, return; } x_long2 = transmitting_station->coord_lon; y_lat2 = transmitting_station->coord_lat; // x2 & y2 are screen location of transmitting station x2 = (x_long2 - NW_corner_longitude)/scale_x; y2 = (y_lat2 - NW_corner_latitude)/scale_y; /* if ((x2 - x) > 0) { my_course = (int)( 57.29578 * atan( (double)((y2-(y*1.0)) / (x2-(x*1.0) ) ) ) ); } else { my_course = (int)( 57.29578 * atan( (double)((y2-(y*1.0)) / (x-(x2*1.0) ) ) ) ); } */ // Use the mid-latitude formulas for calculating the rhumb line // course. Modified to minimize the number of conversions we // need to do. // lat_m = (double)( (y_lat + y_lat2) / 2.0 ); // Convert from Xastir coordinate system // lat_m = (double)( -((lat_m - 32400000l) / 360000.0) ); lat_m = -((y_lat - 32400000l) / 360000.0) + -((y_lat2 - 32400000l) / 360000.0); lat_m = lat_m / 2.0; convert_from_xastir_coordinates(&temp_longitude2, &temp_latitude2, x_long2, y_lat2); convert_from_xastir_coordinates(&temp_longitude, &temp_latitude, x_long, y_lat); temp = (double)( (temp_longitude2 - temp_longitude) / (temp_latitude2 - temp_latitude) ); // Check for divide-by-zero here???? // Calculate course and convert to degrees my_course = (int)( 57.29578 * atan( cos(lat_m) * temp) ); // The arctan function returns values between -90 and +90. To // obtain the true course we apply the following rules: if (temp_latitude2 > temp_latitude && temp_longitude2 > temp_longitude) { // Do nothing. } else if (temp_latitude2 < temp_latitude && temp_longitude2 > temp_longitude) { my_course = 180 - my_course; } else if (temp_latitude2 < temp_latitude && temp_longitude2 < temp_longitude) { my_course = 180 + my_course; } else if (temp_latitude2 > temp_latitude && temp_longitude2 < temp_longitude) { my_course = 360 - my_course; } else { // ?? // Do nothing. } //fprintf(stderr,"course:%d\n", my_course); // Convert to screen angle // my_course = my_course + 90; // Compute whether either of them are on-screen. If so, draw at // least part of the line between them. (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(x), // int l16(y), // int l16(x2), // int l16(y2)); // int } //draw_pod_circle(64000000l, 32400000l, 10, colors[0x44], pixmap_final); // // Probability of Detection circle: A circle around the point last // seen drawn at the distance that a person of that description // could travel since they were last seen. It helps to limit a // search to a reasonable area. // // It'd be nice to have some method of showing where the center of // the circle was as well, in case we don't have a PLS object placed // there also. Perhaps a small dot and/or four lines going from // that point to the edge of the circle? // // range is in miles // x_long/y_lat are in Xastir lat/lon units // void draw_pod_circle(long x_long, long y_lat, double range, int color, Pixmap where, int sec_heard) { double diameter; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's on the screen. // if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } //fprintf(stderr,"Range:%f\tDiameter:%f\n",range,diameter); (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2)), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int // We may need to check for the lat/long being way too far // off-screen, refusing to draw the circles if so, if and only if we // get into X11 drawing bugs as-is. // } // } } } // range is in centimeters (0 to 65535 representing 0 to 655.35 meters) // x_long/y_lat are in Xastir lat/lon units // lat_precision/lon-precision are in 100ths of seconds of lat/lon // void draw_precision_rectangle(long x_long, long y_lat, double UNUSED(range), // Not implemented yet unsigned int lat_precision, unsigned int lon_precision, int color, Pixmap where) { // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's on the screen. if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); if (x_long > 64800000L) { // Eastern hemisphere, add X's (go further east) x2 = x_long + lon_precision; } else { // Western hemisphere, subtract X's (go further west) x2 = x_long - lon_precision; } if (y_lat > 32400000L) { // Southern hemisphere, add Y's (go further north) y2 = y_lat + lat_precision; } else { // Northern hemisphere, subtract Y's (go further south) y2 = y_lat - lat_precision; } draw_vector(da, x_long, y_lat, x_long, y2, gc, where, 0); // x_long constant draw_vector(da, x_long, y2, x2, y2, gc, where, 0); // y2 constant draw_vector(da, x2, y2, x2, y_lat, gc, where, 0); // x2 constant draw_vector(da, x2, y_lat, x_long, y_lat, gc, where, 0); // y_lat constant } } } void draw_phg_rng(long x_long, long y_lat, char *phg, time_t sec_heard, Pixmap where) { double range, diameter; int offx,offy; double tilt; char is_rng; char *strp; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { tilt=0.0; is_rng=0; offx=0; offy=0; if (phg[0] == 'R' && phg[1] == 'N' && phg[2] == 'G') { is_rng = 1; } if (is_rng) { strp = &phg[3]; range = atof(strp); } else { range = phg_range(phg[3],phg[4],phg[5]); } // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } if (!is_rng) // Figure out the directivity, if outside range of 0-8 it's declared to be an omni { switch (phg[6]-'0') { case(0): offx=0; offy=0; break; case(1): // 45 offx=-1*(diameter/6); offy=diameter/6; tilt=5.49778; break; case(2): // 90 offx=-1*(diameter/6); offy=0; tilt=0; break; case(3): // 135 offx=-1*(diameter/6); offy=-1*(diameter/6); tilt=.78539; break; case(4): // 180 offx=0; offy=-1*(diameter/6); tilt=1.5707; break; case(5): // 225 offx=diameter/6; offy=-1*(diameter/6); tilt=2.3561; break; case(6): // 270 offx=diameter/6; offy=0; tilt=3.14159; break; case(7): // 315 offx=diameter/6; offy=diameter/6; tilt=3.92699; break; case(8): // 360 offx=0; offy=diameter/6; tilt=4.71238; break; default: offx=0; offy=0; break; } // End of switch } (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineSolid, CapButt,JoinMiter); if ((sec_old+sec_heard)>sec_now()) { (void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); } else { (void)XSetForeground(XtDisplay(da),gc,colors[0x52]); } if (is_rng || phg[6]=='0') // Draw circl { // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2)), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } else // Draw oval to depict beam heading { // If phg[6] != '0' we still draw a circle, but the center // is offset in the indicated direction by 1/3 the radius. // This debug statement will almost never wind // up selected, because 4095 means "all possible debugging" // It is being placed here SOLELY so that I can // leave the setting of "tilt" (which should determine // how an oval would be tilted to indicate directivity) // without having GCC 6.x whine about it not being used. if (debug_level == 4095) { fprintf(stderr,"If we had tilted ovals implemented, would have tilted one by %lf\n",tilt); } // Draw Circle // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } } } // Function to draw DF circles around objects/stations for DF'ing purposes. // // We change from filled circles to open circles at zoom level 128 for speed purposes. // void draw_DF_circle(long x_long, long y_lat, char *shgd, time_t sec_heard, Pixmap where) { double range, diameter; int offx,offy; double tilt; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { tilt=0.0; offx=0; offy=0; range = shg_range(shgd[3],shgd[4],shgd[5]); // Range is in miles. Bottom term is in meters before the 0.0006214 // multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) // diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } // Figure out the directivity, if outside range of 0-8 it's declared to be an omni switch (shgd[6]-'0') { case(0): offx=0; offy=0; break; case(1): // 45 offx=-1*(diameter/6); offy=diameter/6; tilt=5.49778; break; case(2): // 90 offx=-1*(diameter/6); offy=0; tilt=0; break; case(3): // 135 offx=-1*(diameter/6); offy=-1*(diameter/6); tilt=.78539; break; case(4): // 180 offx=0; offy=-1*(diameter/6); tilt=1.5707; break; case(5): // 225 offx=diameter/6; offy=-1*(diameter/6); tilt=2.3561; break; case(6): // 270 offx=diameter/6; offy=0; tilt=3.14159; break; case(7): // 315 offx=diameter/6; offy=diameter/6; tilt=3.92699; break; case(8): // 360 offx=0; offy=diameter/6; tilt=4.71238; break; default: offx=0; offy=0; break; } if (scale_y > 128) // Don't fill in circle if zoomed in too far (too slow!) { (void)XSetLineAttributes(XtDisplay(da), gc_stipple, 1, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes(XtDisplay(da), gc_stipple, 8, LineSolid, CapButt,JoinMiter); } // Stipple the area instead of obscuring the map underneath (void)XSetStipple(XtDisplay(da), gc_stipple, pixmap_50pct_stipple); (void)XSetFillStyle(XtDisplay(da), gc_stipple, FillStippled); // Choose the color for the DF'ing circle // We try to choose similar colors to those used in DOSaprs, // which are qbasic or gwbasic colors. switch (shgd[3]) { case '9': // Light Red if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x25]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x25]); } break; case '8': // Red if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2d]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2d]); } break; case '7': // Light Magenta if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x26]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x26]); } break; case '6': // Magenta if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2e]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2e]); } break; case '5': // Light Cyan if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x24]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x24]); } break; case '4': // Cyan if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2c]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2c]); } break; case '3': // White if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x0f]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x0f]); } break; case '2': // Light Blue if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x22]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x22]); } break; case '1': // Blue if ((sec_old+sec_heard)>sec_now()) // New { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2a]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x2a]); } break; case '0': // DarkGray (APRSdos) or Black (looks better). We use Black. default: if ((sec_old+sec_heard)>sec_now()) // New (was 0x30) { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x08]); } else // Old { (void)XSetForeground(XtDisplay(da),gc_stipple,colors[0x08]); } break; } // If shgd[6] != '0' we still draw a circle, but the center // is offset in the indicated direction by 1/3 the radius. // This debug statement will almost never wind // up selected, because 4095 means "all possible debugging" // It is being placed here SOLELY so that I can // leave the setting of "tilt" (which should determine // how an oval would be tilted to indicate directivity) // without having GCC 6.x whine about it not being used. if (debug_level & 4095) { fprintf(stderr,"If we had tilted ovals implemented, would have tilted one by %lf\n",tilt); } // Draw Circle // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc_stipple, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int if (scale_y > 128) // Don't fill in circle if zoomed in too far (too slow!) { while (diameter > 1.0) { diameter = diameter - 1.0; // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc_stipple, l16(((x_long-NW_corner_longitude)/scale_x)-(diameter/2) - offx), // int l16(((y_lat-NW_corner_latitude)/scale_y)-(diameter/2) - offy), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } } } // Change back to non-stipple for whatever drawing occurs after this (void)XSetFillStyle(XtDisplay(da), gc_stipple, FillSolid); } // Draw the ALOHA circle // Identical to draw_pod_circle when this was first written, but separated // just in case that POD functionality ever changes per the comments in it void draw_aloha_circle(long x_long, long y_lat, double range, int color, Pixmap where) { double diameter; long width, height; // Range is in miles. Bottom term is in meters before the // 0.0006214 multiplication factor which converts it to miles. // Equation is: 2 * ( range(mi) / x-distance across window(mi) ) diameter = 2.0 * ( range/ (scale_x * calc_dscale_x(center_longitude,center_latitude) * 0.0006214 ) ); // If less than 4 pixels across, skip drawing it. if (diameter <= 4.0) { return; } width = (((x_long-NW_corner_longitude)/scale_x)-(diameter/2)); height = (((y_lat-NW_corner_latitude)/scale_y)-(diameter/2)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(width), // int l16(height), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(0), // int l16(64*360)); // int } static int barb_len; static int barb_spacing; // Change barb parameters based on our current zoom level, so the // barbs don't get too long as we zoom out. void set_barb_parameters(void) { float factor = 1.0; // Initial settings barb_len = 16; barb_spacing = 16; // Scale factor if (scale_y > 80000) { factor = 3.0; } else if (scale_y > 40000) { factor = 2.5; } else if (scale_y > 20000) { factor = 2.0; } else if (scale_y > 10000) { factor = 1.5; } // Scale them, plus use poor man's rounding barb_len = (int)((barb_len / factor) + 0.5); barb_spacing = (int)((barb_spacing / factor) + 0.5);; } void draw_half_barbs(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Set off in the barb direction now off_y = (long)( (barb_len / 2) * sin(barb_radians) ); off_x = (long)( (barb_len / 2) * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(start_x), // int l16(start_y), // int l16(start_x + off_x), // int l16(start_y + off_y)); // int } } void draw_full_barbs(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(start_x), // int l16(start_y), // int l16(start_x + off_x), // int l16(start_y + off_y)); // int } } void draw_triangle_flags(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (45/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y, off_x2, off_y2; XPoint points[3]; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Calculate 2nd point along staff off_x2 = (barb_spacing/2) * cos(bearing_radians); off_y2 = (barb_spacing/2) * sin(bearing_radians); // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 points[0].x = start_x; points[0].y = start_y; points[1].x = start_x + off_x; points[1].y = start_y + off_y; points[2].x = start_x + off_x2; points[2].y = start_y + off_y2; // Number of points is always 3 here, so we don't need to // check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 3, Convex, CoordModeOrigin); } } void draw_square_flags(int *i, int quantity, float bearing_radians, long x, long y, char * UNUSED(course), Pixmap where) { float barb_radians = bearing_radians + ( (90/360.0) * 2.0 * M_PI); int j; long start_x, start_y, off_x, off_y, off_x2, off_y2; XPoint points[4]; for (j = 0; j < quantity; j++) { // Starting point for barb is (*i * barb_spacing) pixels // along bearing_radians vector *i = *i + barb_spacing; off_x = *i * cos(bearing_radians); off_y = *i * sin(bearing_radians); start_y = y + off_y; start_x = x + off_x; // Calculate 2nd point along staff off_x2 = (barb_spacing/2) * cos(bearing_radians); off_y2 = (barb_spacing/2) * sin(bearing_radians); // Set off in the barb direction now off_y = (long)( barb_len * sin(barb_radians) ); off_x = (long)( barb_len * cos(barb_radians) ); (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 points[0].x = start_x; points[0].y = start_y; points[1].x = start_x + off_x; points[1].y = start_y + off_y; points[2].x = start_x + off_x + off_x2; points[2].y = start_y + off_y + off_y2; points[3].x = start_x + off_x2; points[3].y = start_y + off_y2; // Number of points is always 4 here, so we don't need to // check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } // Function to draw wind barbs. Use speed in knots to determine the // flags and barbs to draw along the shaft. Course is in true // degrees, in the direction that the wind is coming from. // // Square flag = 100 knots // Triangle flag = 50 knots // Full barb = 10 knots // Half barb = 5 knots // void draw_wind_barb(long x_long, long y_lat, char *speed, char *course, time_t sec_heard, Pixmap where) { int square_flags = 0; int triangle_flags = 0; int full_barbs = 0; int half_barbs = 0; int shaft_length = 0; int my_speed = atoi(speed); // In mph (so far) int my_course = atoi(course); // In ° true float bearing_radians; long off_x,off_y; long x,y; int i; // Ghost the wind barb if sec_heard is too long. if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } // What to do if my_speed is zero? Blank out any wind barbs // that were written before? // Prevents it from being drawn when the symbol is off-screen. // It'd be better to check for lat/long +/- range to see if it's // on the screen. if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; // Ok to draw wind barb } else { return; } } else { return; } // Set up the constants for our zoom level set_barb_parameters(); // Convert from mph to knots for wind speed. my_speed = my_speed * 0.8689607; //fprintf(stderr,"mph:%s, knots:%d\n",speed,my_speed); // Adjust so that it fits our screen angles. We're off by // 90 degrees. my_course = (my_course - 90) % 360; square_flags = (int)(my_speed / 100); my_speed = my_speed % 100; triangle_flags = (int)(my_speed / 50); my_speed = my_speed % 50; full_barbs = (int)(my_speed / 10); my_speed = my_speed % 10; half_barbs = (int)(my_speed / 5); shaft_length = barb_spacing * (square_flags + triangle_flags + full_barbs + half_barbs + 1); // Set a minimum length for the shaft? if (shaft_length < 2) { shaft_length = 2; } if (debug_level & 128) { fprintf(stderr,"Course:%d,\tL:%d,\tsq:%d,\ttr:%d,\tfull:%d,\thalf:%d\n", atoi(course), shaft_length, square_flags, triangle_flags, full_barbs, half_barbs); } // Draw shaft at proper angle. bearing_radians = (my_course/360.0) * 2.0 * M_PI; off_y = (long)( shaft_length * sin(bearing_radians) ); off_x = (long)( shaft_length * cos(bearing_radians) ); x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da),where,gc, l16(x), // int l16(y), // int l16(x + off_x), // int l16(y + off_y)); // int // Increment along shaft and draw filled polygons at: // "(angle + 45) % 360" degrees to create flags. i = barb_spacing; // Draw half barbs if any if (half_barbs) draw_half_barbs(&i, half_barbs, bearing_radians, x, y, course, where); // Draw full barbs if any if (full_barbs) draw_full_barbs(&i, full_barbs, bearing_radians, x, y, course, where); // Draw triangle flags if any if (triangle_flags) draw_triangle_flags(&i, triangle_flags, bearing_radians, x, y, course, where); // Draw rectangle flags if any if (square_flags) draw_square_flags(&i, square_flags, bearing_radians, x, y, course, where); } // Function to draw beam headings for DF'ing purposes. Separates NRQ into its // components, which are Number/Range/Quality. // // If N is 0, then the NRQ value is meaningless. 1 through 8 are hits per period // of time (auto-DF'ing equipment). A value of 8 means all samples possible got // a hit. A value of 9 means that the report is manual. // // Range limits the length of the line to the original map's scale of the sending // station. The range is 2**R, so for R=4 the range would be 16 miles. // // Q is a single digit from 0-9 and provides indication of bearing accuracy: // 0 Useless // 1 <240 deg (worst) // 2 <120 deg // 3 <64 deg // 4 <32 deg // 5 <16 deg // 6 <8 deg // 7 <4 deg // 8 <2 deg // 9 <1 deg (best) // // // TODO: Should we draw with XOR for this function? Would appear on // most maps that way, and we wouldn't have to worry much about // color. // // TODO: If Q between 1 and 8, shade the entire area to show the // beam width? // // // Latest: We ignore the color parameter and draw everything using // red3. // // The distance calculations below use nautical miles. Here we // ignore the difference between nautical and statute miles as it // really doesn't make much difference how long we draw the vectors: // The angle is what is important here. // void draw_bearing(long x_long, long y_lat, char *course, char *bearing, char *NRQ, int UNUSED(color), int draw_beamwidth, int draw_bearing, time_t sec_heard, Pixmap where) { double range = 0; double real_bearing = 0.0; double real_bearing_min = 0.0; double real_bearing_max = 0.0; int width = 0; long x_long2, x_long3, x_long4, y_lat2, y_lat3, y_lat4; double screen_miles; if ( ((sec_old+sec_heard)>sec_now()) || Select_.old_data ) { // Check for a zero value for N. If found, the NRQ value is meaningless // and we need to assume some working default values. if (NRQ[0] != '0') { // "range" as used below is in nautical miles. range = (double)( pow(2.0,NRQ[1] - '0') ); switch (NRQ[2]) { case('1'): width = 240; // Degrees of beam width. What's the point? break; case('2'): width = 120; // Degrees of beam width. What's the point? break; case('3'): width = 64; // Degrees of beam width. What's the point? break; case('4'): width = 32; // Degrees of beam width. Starting to be usable. break; case('5'): width = 16; // Degrees of beam width. Usable. break; case('6'): width = 8; // Degrees of beam width. Usable. break; case('7'): width = 4; // Degrees of beam width. Nice! break; case('8'): width = 2; // Degrees of beam width. Nice! break; case('9'): width = 1; // Degrees of beam width. Very Nice! break; case('0'): // "Useless" beam width according to spec default: return; // Exit routine without drawing vectors break; } } else // Assume some default values. { range = 512.0; // Assume max range of 512 nautical miles width = 8; // Assume 8 degrees for beam width } // We have the course of the vehicle and the bearing from the // vehicle. Now we need the real bearing. // if (atoi(course) != 0) { real_bearing = atoi(course) + atoi(bearing); real_bearing_min = real_bearing + 360.0 - (width/2.0); real_bearing_max = real_bearing + (width/2.0); } else { real_bearing = atoi(bearing); real_bearing_min = real_bearing + 360.0 - (width/2.0); real_bearing_max = real_bearing + (width/2.0); } while (real_bearing > 360.0) { real_bearing -= 360.0; } while (real_bearing_min > 360.0) { real_bearing_min -= 360.0; } while (real_bearing_max > 360.0) { real_bearing_max -= 360.0; } // want this in nautical miles screen_miles = scale_x * calc_dscale_x(center_longitude,center_latitude) * .5400; // Shorten range to more closely fit the screen if ( range > (3.0 * screen_miles) ) { range = 3.0 * screen_miles; } // We now have a distance and a bearing for each vector. // Compute the end points via dead-reckoning here. It will give // us points between which we can draw a vector and makes the // rest of the code much easier. Need to skip adding 270 // degrees if we use that method. // if (draw_beamwidth) { compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing_min, // input in ° true (double) &x_long2, // output (*long) &y_lat2); // output (*long) compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing_max, // input in ° true (double) &x_long3, // output (*long) &y_lat3); // output (*long) } if (draw_bearing) { compute_DR_position(x_long, // input (long) y_lat, // input (long) range, // input in nautical miles (double) real_bearing, // input in ° true (double) &x_long4, // output (*long) &y_lat4); // output (*long) } (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); if (draw_beamwidth) { (void)XSetForeground(XtDisplay(da),gc,colors[0x4a]); // red2 draw_vector(da, x_long, y_lat, x_long2, y_lat2, gc, where, 0); draw_vector(da, x_long, y_lat, x_long3, y_lat3, gc, where, 0); } if (draw_bearing) { (void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 draw_vector(da, x_long, y_lat, x_long4, y_lat4, gc, where, 0); } } // Change back to non-stipple for whatever drawing occurs after this // (void)XSetFillStyle(XtDisplay(da), gc_tint, FillSolid); } // TODO: Pass back the modified x_long/y_lat to the calling routine // and use the new lat/long to place the symbol. This will knock // off the digits on the right that the ambiguity specifies. We // then add 1/2 the rectangle offsets in order to get the symbol // placed in the middle of the rectangle. // void draw_ambiguity(long x_long, long y_lat, char amb, long *amb_x_long, long *amb_y_lat, time_t sec_heard, Pixmap UNUSED(where) ) { unsigned long left, right, top, bottom; long offset_lat, offset_long; int scale_limit; // Assign these first in case we do a sudden return from the // function. *amb_x_long = x_long; *amb_y_lat = y_lat; // if ((x_long < 0) || (x_long > 129600000l)) // return; // if ((y_lat < 0) || (y_lat > 64800000l)) // return; switch (amb) { case 1: // +- 1/10th minute offset_lat = offset_long = 600; scale_limit = 256; // Truncate digits off the right x_long = (long)(x_long / 600); x_long = x_long * 600; y_lat = (long)(y_lat / 600); y_lat = y_lat * 600; break; case 2: // +- 1 minute offset_lat = offset_long = 6000; scale_limit = 2048; // Truncate digits off the right x_long = (long)(x_long / 6000); x_long = x_long * 6000; y_lat = (long)(y_lat / 6000); y_lat = y_lat * 6000; break; case 3: // +- 10 minutes offset_lat = offset_long = 60000; scale_limit = 16384; // Truncate digits off the right x_long = (long)(x_long / 60000); x_long = x_long * 60000; y_lat = (long)(y_lat / 60000); y_lat = y_lat * 60000; break; case 4: // +- 1 degree offset_lat = offset_long = 360000; scale_limit = 65536; // Truncate digits off the right x_long = (long)(x_long / 360000); x_long = x_long * 360000; y_lat = (long)(y_lat / 360000); y_lat = y_lat * 360000; break; // TODO: The last two cases need fixing up like the above case 5: // grid square: 2.5min lat x 5min lon offset_lat = 360000.0 * 1.25 / 60.0; offset_long = 360000.0 * 2.50 / 60.0; scale_limit = 1024; break; case 6: // grid square: 1deg lat x 2deg lon offset_lat = 360000.0 * 0.5; offset_long = 360000.0 * 1.0; scale_limit = 16384; break; case 0: default: return; // if no ambiguity, do nothing break; } // Re-assign them here as they should have been truncated on the // right by the above code. We'll use these new values // to draw the symbols and the other associated symbol data // (external to this function). // *amb_x_long = x_long + (offset_long/2); *amb_y_lat = y_lat + (offset_lat / 2); if (scale_y > scale_limit) { // Ambiguity box will be smaller than smallest symbol so // don't draw it. //fprintf(stderr,"scale_y > scale_limit\n"); return; } if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } left = x_long; top = y_lat; right = x_long + offset_long; bottom = y_lat + offset_lat; (void)XSetForeground(XtDisplay(da), gc, colors[0x08]); // Draw rectangle (unfilled) plus vectors from symbol to // corners. (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineOnOffDash, CapButt,JoinMiter); // Top line of rectangle draw_vector(da,left,top,right,top,gc,pixmap_final, 0); // Bottom line of rectangle draw_vector(da,left,bottom,right,bottom,gc,pixmap_final, 1); // Left line of rectangle draw_vector(da,left,top,left,bottom,gc,pixmap_final, 1); // Right line of rectangle draw_vector(da,right,top,right,bottom,gc,pixmap_final, 1); // Diagonal lines draw_vector(da,left,top,right,bottom,gc,pixmap_final, 1); draw_vector(da,right,top,left,bottom,gc,pixmap_final, 1); } // Function which specifies whether any part of a bounding box fits // on the screen, using screen coordinates as inputs. // static __inline__ int onscreen(long left, long right, long top, long bottom) { // This checks to see if any part of a box is on the screen. if (left > screen_width || right < 0 || top > screen_height || bottom < 0) { return 0; } else { return 1; } } // According to the spec, the lat/long point is the upper left // corner of the object, and the offsets are down and to the right // (except for one line type where it's down and to the left). This // doesn't appear to be the case in dos/winAPRS. Matching what they // do: // // Type 0 Circle: Tie = center, offsets = vert/horiz. sizes. // Type 1 Line: Tie = bottom right, offsets = left and up. // Type 2 Ellipse: Tie = center, offsets = vert/horiz. sizes. // Type 3 Triangle: Tie = bottom right, offsets = height/width. // Type 4 Rectangle: Tie = lower right, offsets = left and up. // Type 5 Circle: Tie = center, offsets = vert/horiz. sizes. // Type 6 Line: Tie = bottom left, offsets = right and up. // Type 7 Ellipse: Tie = center, offsets = vert/horiz. sizes. // Type 8 Triangle: Tie = bottom right, offsets = height/width. // Type 9 Rectangle: Tie = lower right, offsets = left and up. // // Exceptions to this are the triangle, ellipse, and circle. The // ellipse and circle have the lat/long as the center point. The // triangle is an isosceles triangle with the lat/long point being // the bottom right and the bottom of the triangle being horizontal. // void draw_area(long x_long, long y_lat, char type, char color, char sqrt_lat_off, char sqrt_lon_off, unsigned int width, time_t sec_heard, Pixmap where) { long left, top, right, bottom, xoff, yoff; int c; XPoint points[4]; // Ghost the area object if sec_heard is too long. if ( ((sec_old+sec_heard)<=sec_now()) && !Select_.old_data ) { return; } // if ((x_long < 0) || (x_long > 129600000l) || // (y_lat < 0) || (y_lat > 64800000l)) // return; xoff = 360000.0 / 1500.0 * (sqrt_lon_off * sqrt_lon_off) / scale_x; yoff = 360000.0 / 1500.0 * (sqrt_lat_off * sqrt_lat_off) / scale_y; right = (x_long - NW_corner_longitude) / scale_x; bottom = (y_lat - NW_corner_latitude) / scale_y; left = right - xoff; top = bottom - yoff; // colors[0x21] is the first in the list of area object colors in main.c c = colors[0x21 + color]; (void)XSetForeground(XtDisplay(da), gc, c); if (xoff < 20 || yoff < 20) { (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes(XtDisplay(da), gc, 2, LineSolid, CapButt,JoinMiter); } (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // just in case (void)XSetStipple(XtDisplay(da), gc, pixmap_50pct_stipple); switch (type) { case AREA_OPEN_BOX: if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawRectangle // Tricky 'cuz the XRectangle struct has short's and unsigned short's, // while XDrawRectangle man-page says int's/unsigned int's. We'll // stick to 16-bit just to make sure. (void)XDrawRectangle(XtDisplay(da), where, gc, l16(left), // int l16(top), // int lu16(xoff), // unsigned int lu16(yoff)); // unsigned int } break; case AREA_FILLED_BOX: if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); (void)XFillRectangle(XtDisplay(da), where, gc, l16(left), l16(top), l16(xoff), l16(yoff)); } break; /* For the rest of the objects, the l16 limiting of the values is inadequate because the shapes will still be draw wrong if the value actually was limited down. However, this is slightly better than passing long or int values that would just be used as 16bit by X (i.e.: truncated) until I/we come up with some sort of clipping algorithm. In real use, what I'm talking about will occur based on two things: the size of the area and the zoom level being used. The more the extents of the area go beyond the edges of the screen, the more this will happen. N7TAP */ case AREA_OPEN_CIRCLE: case AREA_OPEN_ELLIPSE: right += xoff; bottom += yoff; if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da), where, gc, l16(left), // int l16(top), // int lu16(2*xoff), // unsigned int lu16(2*yoff), // unsigned int l16(0), // int l16(64 * 360)); // int } break; case AREA_FILLED_CIRCLE: case AREA_FILLED_ELLIPSE: right += xoff; bottom += yoff; if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); (void)XFillArc(XtDisplay(da), where, gc, l16(left), l16(top), l16(2*xoff), l16(2*yoff), 0, 64 * 360); } break; case AREA_LINE_RIGHT: left += xoff; right += xoff; if (width > 0) { double angle = atan((float)xoff/(float)yoff); // Check for divide-by-zero here??? int conv_width = width/(scale_x*calc_dscale_x(center_longitude,center_latitude)*0.0006214); points[0].x = l16(left-(conv_width * cos(angle))+xoff); points[0].y = l16(top -(conv_width * sin(angle))); points[1].x = l16(left-(conv_width * cos(angle))); points[1].y = l16(top -(conv_width * sin(angle))+yoff); points[2].x = l16(left+(conv_width * cos(angle))); points[2].y = l16(top +(conv_width * sin(angle))+yoff); points[3].x = l16(left+(conv_width * cos(angle))+xoff); points[3].y = l16(top +(conv_width * sin(angle))); if (onscreen(points[1].x, points[3].x, points[0].y, points[2].y)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 4 here, so we don't // need to check first before calling // XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da), where, gc, l16(left), // int l16(bottom), // int l16(right), // int l16(top)); // int } break; case AREA_LINE_LEFT: if (width > 0) { double angle = atan((float)xoff/(float)yoff); // Check for divide-by-zero here??? int conv_width = width/(scale_x*calc_dscale_x(center_longitude,center_latitude)*0.0006214); points[0].x = l16(left+(conv_width * cos(angle))); points[0].y = l16(top -(conv_width * sin(angle))); points[1].x = l16(left+(conv_width * cos(angle))+xoff); points[1].y = l16(top -(conv_width * sin(angle))+yoff); points[2].x = l16(left-(conv_width * cos(angle))+xoff); points[2].y = l16(top +(conv_width * sin(angle))+yoff); points[3].x = l16(left-(conv_width * cos(angle))); points[3].y = l16(top +(conv_width * sin(angle))); if (onscreen(points[3].x, points[1].x, points[0].y, points[2].y)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 4 here, so we don't // need to check first before calling // XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 4, Convex, CoordModeOrigin); } } if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); // Check that our parameters are within spec for XDrawLine. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLine(XtDisplay(da), where, gc, l16(right), // int l16(bottom), // int l16(left), // int l16(top)); // int } break; case AREA_OPEN_TRIANGLE: left -= xoff; points[0].x = l16(right); points[0].y = l16(bottom); points[1].x = l16(left+xoff); points[1].y = l16(top); points[2].x = l16(left); points[2].y = l16(bottom); points[3].x = l16(right); points[3].y = l16(bottom); if (onscreen(left, right, top, bottom)) { // Check that our parameters are within spec for XDrawLines. We'll // stick to 16-bit values here due to warnings on the man-page // regarding XSegment structs and the protocol only handling // short's/unsigned short's, just in case. (void)XDrawLines(XtDisplay(da), where, gc, points, // XPoint * l16(4), // int CoordModeOrigin); // int } break; case AREA_FILLED_TRIANGLE: left -= xoff; points[0].x = l16(right); points[0].y = l16(bottom); points[1].x = l16(left+xoff); points[1].y = l16(top); points[2].x = l16(left); points[2].y = l16(bottom); if (onscreen(left, right, top, bottom)) { (void)XSetFillStyle(XtDisplay(da), gc, FillStippled); // Number of points is always 3 here, so we don't need // to check first before calling XFillPolygon(). (void)XFillPolygon(XtDisplay(da), where, gc, points, 3, Convex, CoordModeOrigin); } break; default: break; } (void)XSetFillStyle(XtDisplay(da), gc, FillSolid); } /* DK7IN: Statistics for colors in all symbols (as of 16.03.2001) 60167 . 6399 q 3686 m 3045 c 2034 j 1903 h 1726 l 1570 k 1063 g 1051 # 840 p 600 ~ 477 i 443 n 430 a 403 o 337 f 250 b 207 e 169 d */ // read pixels from file, speeding it up by smart ordering of switches void read_symbol_from_file(FILE *f, char *pixels, char table_char) { int x,y; int color; char line[100]; char pixels_copy[400]; char *p,*q; unsigned char a, b, c; for (y=0; y<20; y++) { (void)get_line(f,line,100); for (x=0; x<20; x++) { switch (line[x]) { case('.'): // transparent color=0xff; break; case('q'): // #000000 black 0% color=0x51; break; case('m'): // #FFFFFF white 100% color=0x4d; break; case('c'): // #CCCCCC gray80 80% color=0x43; break; case('j'): // #EE0000 red2 color=0x4a; break; case('h'): // #00BFFF Deep sky blue color=0x48; break; case('l'): // #0000CD mediumblue color=0x4c; break; case('k'): // #00CD00 green3 color=0x4b; break; case('g'): // #00008B blue4 color=0x47; break; case('#'): // #FFFF00 yellow color=0x40; break; case('p'): // #454545 gray27 27% color=0x50; break; case('~'): // used in the last two symbols in the file color=0xff; // what should it be? was transparent before... break; case('i'): // #006400 Dark Green color=0x49; break; case('n'): // #878787 gray53 52% color=0x4e; break; case('a'): // #CD6500 darkorange2 color=0x41; break; case('o'): // #5A5A5A gray59 35% color=0x4f; break; case('f'): // #CD3333 brown3 color=0x46; break; case('b'): // #A020F0 purple color=0x42; break; case('e'): // #FF4040 brown1 color=0x45; break; case('d'): // #CD0000 red3 color=0x44; break; case('r'): // LimeGreen DK7IN: saw this in the color definitions... color=0x52; // so we could use it break; default: color=0xff; break; } pixels[y*20+x] = (char)(color); } } // Create outline on icons, if needed // Do not change the overlays and "number" tables if((icon_outline_style != 0) && (table_char != '~') && (table_char != '#')) { switch(icon_outline_style) { case 1: color = 0x51; // Black break; //case 2: color = 0x43; // Grey 80% case 2: color = 0x4e; // Grey 52% break; case 3: color = 0x4d; // White break; default: color = 0xff; // Transparent break; } p = pixels; q = &pixels_copy[0]; for (y=0; y<20; y++) { for (x=0; x<20; x++) { *q = *p; // copy current color // If transparent see if the pixel is on the edge if(*q == (char) 0xff) { //check if left or right is none transparent b = c = 0xff; // left (left only possible if x > 0) if(x > 0) { b = p[-1]; } // right (right only possible if x < 19) if(x < 19) { c = p[+1]; } // if non-transparent color is found change pixel // to outline color if((b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } if((y > 0) && (*q == (char) 0xff)) { //check if left-up, up or right-up is none transparent //"up" only possible if y > 0 a = b = c = 0xff; // left-up (left only possible if x > 0) if(x > 0) { a = p[-21]; } // up b = p[-20]; // right-up (right only possible if x < 19) if(x < 19) { c = p[-19]; } // if non-transparent color is found change pixel // to outline color if((a != (unsigned char) 0xff) || (b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } } if((y < 19) && (*q == (char) 0xff)) { //check if left-down, down or right-down is none transparent //"down" only possible if y < 19 a = b = c = 0xff; // left-down (left only possible if x > 0) if(x > 0) { a = p[+19]; } // down b = p[+20]; // right-down (right only possible if x < 19) if(x < 19) { c = p[+21]; } // if non-transparent color is found change pixel // to outline color if((a != (unsigned char) 0xff) || (b != (unsigned char) 0xff) || (c != (unsigned char) 0xff)) { // change to icon outline color *q = color; } } } p++; q++; } } memcpy(pixels, pixels_copy, 400); } } /* read in symbol table */ void load_pixmap_symbol_file(char *filename, int reloading) { FILE *f; char filen[500]; char line[100]; char table_char; char symbol_char; int done; char pixels[400]; char orient; busy_cursor(appshell); symbols_loaded = 0; table_char = '\0'; symbol_char = '\0'; done = 0; xastir_snprintf(filen, sizeof(filen), "%s/%s", SYMBOLS_DIR, filename); f = fopen(filen,"r"); if (f!=NULL) { while (!feof(f) && !done) { (void)get_line(f,line,100); if (strncasecmp("TABLE ",line,6)==0) { table_char=line[6]; /*fprintf(stderr,"TABLE %c\n",table_char);*/ } else { if (strncasecmp("DONE",line,4)==0) { done=1; /*fprintf(stderr,"DONE\n");*/ } else { if (strncasecmp("APRS ",line,5)==0) { symbol_char=line[5]; if (strlen(line)>=20 && line[19] == 'l') // symbol with orientation ? { orient = 'l'; // should be 'l' for left } else { orient = ' '; } read_symbol_from_file(f, pixels, table_char); // read pixels for one symbol insert_symbol(table_char,symbol_char,pixels,270,orient,reloading); // always have normal orientation if (orient == 'l') { insert_symbol(table_char,symbol_char,pixels, 0,'u',reloading); // create other orientations insert_symbol(table_char,symbol_char,pixels, 90,'r',reloading); insert_symbol(table_char,symbol_char,pixels,180,'d',reloading); } } } } } } else { fprintf(stderr,"Error opening symbol file %s\n",filen); popup_message("Error opening symbol file","Error opening symbol file"); } if (f != NULL) { (void)fclose(f); } } // add a symbol to the end of the symbol table. // // Here we actually draw the pixels into the SymbolData struct, // which contains separate Pixmap's for the icon, the transparent // background, and the ghost image. // void insert_symbol(char table, char symbol, char *pixel, int deg, char orient, int reloading) { int x,y,idx,old_next,color,last_color,last_gc2; if (symbols_loaded < MAX_SYMBOLS) { // first time loading, -> create pixmap... // when reloading -> reuse already created pixmaps... if(reloading == 0) { symbol_data[symbols_loaded].pix=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); symbol_data[symbols_loaded].pix_mask=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, 1); symbol_data[symbols_loaded].pix_mask_old=XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, 1); } old_next=0; last_color = -1; // Something bogus last_gc2 = -1; // Also bogus for (y=0; y<20; y++) { for (x=0; x<20; x++) { switch (deg) { case(0): idx = 20* (19-x) + y; break; case(90): idx = 20* y + (19-x); break; case(180): idx = 20* (19-x) + (19-y); break; default: idx = 20* y + x; break; } color = (int)(pixel[idx]); if (color<0) { color = 0xff; } // Change to new color only when necessary. We use two different // GC's here, one for the main icon pixmap, and one for the symbol // mask and ghost layer. // DK7IN: is (da) correct or should this be (appshell) ? if (color != last_color) { (void)XSetForeground(XtDisplay(da),gc,colors[color]); last_color = color; } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(da), symbol_data[symbols_loaded].pix, gc, l16(x), // int l16(y)); // int // DK7IN // Create symbol mask if (color != 0xff) { if (last_gc2 != 1) { (void)XSetForeground(XtDisplay(appshell),gc2,1); // active bit last_gc2 = 1; } } else { if (last_gc2 != 0) { (void)XSetForeground(XtDisplay(appshell),gc2,0); // transparent. last_gc2 = 0; } } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(appshell), symbol_data[symbols_loaded].pix_mask, gc2, l16(x), // int l16(y)); // int // Create ghost symbol mask by setting every 2nd bit // to transparent old_next++; if (old_next>1) { old_next=0; if (last_gc2 != 0) { (void)XSetForeground(XtDisplay(appshell),gc2,0); last_gc2 = 0; } } // Check that our parameters are within spec for XDrawPoint. Tricky // 'cuz the XPoint struct uses short's, while XDrawPoint manpage // specifies int's. We'll stick to 16-bit numbers just to make // sure. (void)XDrawPoint(XtDisplay(appshell), symbol_data[symbols_loaded].pix_mask_old, gc2, l16(x), // int l16(y)); // int } old_next++; // shift one bit every scan line for ghost image if (old_next>1) { old_next=0; } } symbol_data[symbols_loaded].active = SYMBOL_ACTIVE; symbol_data[symbols_loaded].table = table; symbol_data[symbols_loaded].symbol = symbol; symbol_data[symbols_loaded].orient = orient; symbols_loaded++; } } // calculate symbol orientation from course // ' ' = left // 'd' = down // 'r' = right // 'u' = up char symbol_orient(char *course) { char orient; float mydir; orient = ' '; // Default = left if (strlen(course)) { mydir = (float)atof(course); if (mydir > 0) { while (mydir > 360.0) { mydir = mydir - 360.0; } while (mydir < 0.0) { mydir = mydir + 360.0; } if (mydir == 360.0) { mydir = 0.0; } orient = 'u'; // 000-045 = up if ( mydir > (float)( 0+ANGLE_UPDOWN ) ) // 046-135 = right { orient = 'r'; } if ( mydir > (float)( 90+ANGLE_UPDOWN ) ) // 136-225 = down { orient = 'd'; } if ( mydir > (float)( 180+ANGLE_UPDOWN) ) // 226-314 = left { orient = ' '; } if ( mydir >= (float)(270+ANGLE_UPDOWN) ) // 315-360 = up { orient = 'u'; } } } return(orient); } // Storage for an index into the symbol table that we may need // later. int nosym_index = -1; // Look through our symbol table for a match. // void symbol(Widget w, int ghost, char symbol_table, char symbol_id, char symbol_overlay, Pixmap where, int mask, long x_offset, long y_offset, char orient) { int i; int found; int alphanum_index = -1; if (x_offset > screen_width) { return; } if (x_offset < 0) { return; } if (y_offset > screen_height) { return; } if (y_offset < 0) { return; } /* DK7IN: orient is ' ','l','r','u','d' for left/right/up/down symbol orientation */ // if symbol could be rotated, normal symbol orientation in symbols.dat is to the left // Find the nosymbol index if we haven't filled it in by now. // This "for" loop should get run only once during Xastir's // entire runtime, so it shouldn't contribute much to CPU // loading. if (nosym_index == -1) { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == '!' && symbol_data[i].symbol == '#') { nosym_index = i; // index of special symbol (if none available) break; } } } } // Handle the overlay character. The "for" loop below gets run // once every time we encounter an overlay character, which // isn't all that often. if (symbol_overlay == '\0' || symbol_overlay == ' ') { alphanum_index = 0; // we don't want an overlay } else // Find the overlay character index { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == '#' && symbol_data[i].symbol == symbol_overlay) { alphanum_index = i; // index of symbol for character overlay break; } } } } found = -1; // Check last few symbols we used to see if we can shortcut // looking through the entire index. The symbols array really // should be turned into a hash to save time. Basically we've // implemented a very short cache here, but it keeps us from // looking through the entire symbol array sometimes. // for ( i = 0; i < 5; i++ ) { //fprintf(stderr,"Checking symbol cache\n"); if (symbol_data[symbols_cache[i]].table == symbol_table && symbol_data[symbols_cache[i]].symbol == symbol_id) { // We found the matching symbol in the cache found = symbols_cache[i]; // index of symbol //fprintf(stderr,"Symbol cache hit:%d\n",found); break; } } if (found == -1) // Not found in symbols cache { for ( i = 0; i < symbols_loaded; i++ ) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == symbol_table && symbol_data[i].symbol == symbol_id) { // We found the matching symbol found = i; // index of symbol // Save newly found symbol in cache, shift other // cache entries down by one so that newest is // at the beginning for the cache search. //fprintf(stderr,"Saving in cache\n"); symbols_cache[4] = symbols_cache[3]; symbols_cache[3] = symbols_cache[2]; symbols_cache[2] = symbols_cache[1]; symbols_cache[1] = symbols_cache[0]; symbols_cache[0] = i; break; } } } } if (found == -1) // Didn't find a matching symbol { found = nosym_index; if (symbol_table && symbol_id && debug_level & 128) { fprintf(stderr,"No Symbol Yet! %2x:%2x\n", (unsigned int)symbol_table, (unsigned int)symbol_id); } } else // maybe we want a rotated symbol { // It looks like we originally did not want to rotate the symbol if // it was ghosted? Why? For dead-reckoning we do want it to be // rotated when ghosted. // if (!(orient == ' ' || orient == 'l' || symbol_data[found].orient == ' ' || ghost)) { if (!(orient == ' ' || orient == 'l' || symbol_data[found].orient == ' ')) { for (i = found; i < symbols_loaded; i++) { if (symbol_data[i].active == SYMBOL_ACTIVE) { if (symbol_data[i].table == symbol_table && symbol_data[i].symbol == symbol_id && symbol_data[i].orient == orient) { found=i; // index of rotated symbol break; } } } } } if (mask) { if (ghost) { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[found].pix_mask_old); } else { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[found].pix_mask); } } (void)XSetClipOrigin(XtDisplay(w),gc,x_offset,y_offset); (void)XCopyArea(XtDisplay(w),symbol_data[found].pix,where,gc,0,0,20,20,x_offset,y_offset); if(alphanum_index > 0) { if (ghost) { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[alphanum_index].pix_mask_old); } else { (void)XSetClipMask(XtDisplay(w),gc,symbol_data[alphanum_index].pix_mask); } (void)XSetClipOrigin(XtDisplay(w),gc,x_offset,y_offset); (void)XCopyArea(XtDisplay(w),symbol_data[alphanum_index].pix,where,gc,0,0,20,20,x_offset,y_offset); // rot } (void)XSetClipMask(XtDisplay(w),gc,None); } // Calculate the width in pixels of the actual text // This helps us take into account proportional or non-proportional fonts long get_text_width(Widget w,char *text) { long width; GContext gcontext; XFontStruct *xfs_ptr; int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); XTextExtents(xfs_ptr, text, strlen(text), &dir, &asc, &desc, &overall); //printf("%s Width = %d\n",text,overall.width); width =overall.width; if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } return width; } // Speed is in converted units by this point (kph or mph) void draw_symbol(Widget w, char symbol_table, char symbol_id, char symbol_overlay, long x_long,long y_lat, char *callsign_text, char *alt_text, char *course_text, char *speed_text, char *my_distance, char *my_course, char *wx_temp, char* wx_wind, time_t sec_heard, int temp_show_last_heard, Pixmap where, char orient, char area_type, char *signpost, char *gauge_data, int bump_count) { long x_offset,y_offset; int length; int ghost; int posyl; int posyr; long txt_width; // Added to allow dynamic offsets for the text around a symbol // Originally it was hard coded offsets, this bases the offset on // the font height and width // N7IPB - 4/7/2016 // GContext gcontext; XFontStruct *xfs_ptr; int font_width, font_height; gcontext = XGContextFromGC(gc); xfs_ptr = XQueryFont(XtDisplay(w), gcontext); font_width = (int)((xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->max_bounds.width + xfs_ptr->min_bounds.width) / 4); // Get the font height and use it for the distance between lineis of text font_height = xfs_ptr->max_bounds.ascent; // Free the info to avoid a memory leak if (xfs_ptr) { // This leaks memory if the last parameter is a "0" XFreeFontInfo(NULL, xfs_ptr, 1); } if ((x_long>NW_corner_longitude) && (x_longNW_corner_latitude) && (y_lat0) { posyr -= font_height/2; } if (strlen(callsign_text)>0) { posyr -= font_height/2; } if ( (!ghost || Select_.old_data) && strlen(speed_text)>0) { posyr -= font_height/2 ; } if ( (!ghost || Select_.old_data) && strlen(course_text)>0) { posyr -= font_height/2; } if (area_type == AREA_LINE_RIGHT) { posyr += 9; } if (signpost[0] != '\0') // Signpost data? { posyr -=font_height/2; } // we may eventually have more adjustments for different types of areas length=(int)strlen(alt_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,alt_text,0x08,0x48,length); posyr += font_height; } length=(int)strlen(callsign_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,callsign_text,0x08,0x0f,length); posyr += font_height; } length=(int)strlen(speed_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,speed_text,0x08,0x4a,length); posyr += font_height; } length=(int)strlen(course_text); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,course_text,0x08,0x52,length); posyr += font_height; } length=(int)strlen(signpost); // Make it white like callsign? if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)+13; y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,signpost,0x08,0x0f,length); posyr += font_height; } posyl = font_height; // distance and direction goes to the left. // Also minutes last heard. if ( (!ghost || Select_.old_data) && strlen(my_distance)>0) { posyl -= font_height/2; } if ( (!ghost || Select_.old_data) && strlen(my_course)>0) { posyl -= font_height/2; } if ( (!ghost || Select_.old_data) && temp_show_last_heard) { posyl -= font_height/2; } length=(int)strlen(my_distance); txt_width=get_text_width(w,my_distance); if ( (!ghost || Select_.old_data) && length>0) { x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width+9)); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,my_distance,0x08,0x0f,length); posyl += font_height; } length=(int)strlen(my_course); txt_width=get_text_width(w,my_course); if ( (!ghost || Select_.old_data) && length>0) { x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width+9)); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,my_course,0x08,0x0f,length); posyl += font_height; } if ( (!ghost || Select_.old_data) && temp_show_last_heard) { char age[20]; float minutes; float hours; int fgcolor; // Color code the time string based on // time since last heard: // Green: 0-29 minutes // Yellow: 30-59 minutes // Red: 60 minutes to 1 day // White: 1 day or later minutes = (float)( (sec_now() - sec_heard) / 60.0); hours = minutes / 60.0; // Heard from this station within the // last 30 minutes? if (minutes < 30.0) { xastir_snprintf(age, sizeof(age), "%d%s", (int)minutes, langcode("UNIOP00034")); // min fgcolor = 0x52; // green } // 30 to 59 minutes? else if (minutes < 60.0) { xastir_snprintf(age, sizeof(age), "%d%s", (int)minutes, langcode("UNIOP00034")); // min fgcolor = 0x40; // yellow } // 1 hour to 1 day old? else if (hours <= 24.0) { xastir_snprintf(age, sizeof(age), "%.1f%s", hours, langcode("UNIOP00035")); // hr fgcolor = 0x4a; // red } // More than a day old else { xastir_snprintf(age, sizeof(age), "%.1f%s", hours / 24.0, langcode("UNIOP00036")); // day fgcolor = 0x0f; // white } length = strlen(age); txt_width = get_text_width(w,age); x_offset=(((x_long-NW_corner_longitude)/scale_x)-(txt_width)-9); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyl; draw_nice_string(w,where,letter_style,x_offset,y_offset,age,0x08,fgcolor,length); posyl += font_height; } // weather goes to the bottom, centered horizontally. // Start off making sure it's below the symbol posyr += 10; if (posyr < posyl) { posyr = posyl; } if (posyr < font_height) { posyr = font_height; } length=(int)strlen(wx_temp); txt_width = get_text_width(w,wx_temp); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,wx_temp,0x08,0x40,length); posyr += font_height; } length=(int)strlen(wx_wind); txt_width = get_text_width(w,wx_wind); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,wx_wind,0x08,0x40,length); } if (gauge_data != NULL) { // Gauge data goes on the bottom, centered // horizontally. White. if (posyr < posyl) { posyr = posyl; } if (posyr < font_width) { posyr = font_width; } length=(int)strlen(gauge_data); txt_width=get_text_width(w,gauge_data); if ( (!ghost || Select_.old_data) && length>0) { x_offset=((x_long-NW_corner_longitude)/scale_x)-(txt_width/2); y_offset=((y_lat -NW_corner_latitude) /scale_y)+posyr; draw_nice_string(w,where,letter_style,x_offset,y_offset,gauge_data,0x08,0x0f,length); } } } } } /* * Looks at the style to determine what color to use. * KG4NBB */ static int getLineColor(char styleChar) { int color; switch (styleChar) { case 'a': case 'b': case 'c': color = colors[0x0c]; // red break; case 'd': case 'e': case 'f': color = colors[0x0e]; // yellow break; case 'g': case 'h': case 'i': color = colors[0x09]; // blue break; case 'j': case 'k': case 'l': color = colors[0x0a]; // green break; default: color = colors[0x0a]; // green break; } return color; } /* * Looks at the style to determine what line type to use. * KG4NBB */ static int getLineStyle(char styleChar) { int style; switch (styleChar) { case 'a': case 'd': case 'g': case 'j': style = LineSolid; break; case 'b': case 'e': case 'h': case 'k': style = LineOnOffDash; break; case 'c': case 'f': case 'i': case 'l': style = LineDoubleDash; break; default: style = LineSolid; break; } return style; } /* * Draw the other points associated with the station. * KG4NBB */ void draw_multipoints(long UNUSED(x_long), long UNUSED(y_lat), int numpoints, long mypoints[][2], char type, char style, time_t sec_heard, Pixmap where) { int ghost; int skip_duplicates; // See if we should draw multipoints for this station. This only happens // if there are points to draw and the object has not been cleared (or // we're supposed to show old data). // Per Dale Huguley in e-mail 07/10/2003, a good interval for // the severe weather polygons to disappear is 10 minutes. We // hard-code it here so the user can't mess it up too badly with // the ghosting interval. // ghost = (int)(((sec_old+sec_heard)) < sec_now()); ghost = (int)( ( sec_heard + (10 * 60) ) < sec_now() ); // We don't want to draw them if the ghost interval is up, no // matter whether Include Expired Data is checked. //if ( (!ghost || Select_.old_data) && (numpoints > 0) ) { if ( !ghost && (numpoints > 0) ) { //long x_offset, y_offset; int i; // XPoint xpoints[MAX_MULTIPOINTS + 1]; #if 0 long mostNorth, mostSouth, mostWest, mostEast; // Check to see if the object is onscreen. // Look for the coordinates that are farthest north, farthest south, // farthest west, and farthest east. Then check to see if any of that // box is onscreen. If so, proceed with drawing. This is all done in // Xastir coordinates. mostNorth = mostSouth = y_lat; mostWest = mostEast = x_long; for (i = 0; i < numpoints; ++i) { if (mypoints[i][0] < mostNorth) { mostNorth = mypoints[i][0]; } if (mypoints[i][0] > mostSouth) { mostSouth = mypoints[i][0]; } if (mypoints[i][1] < mostWest) { mostWest = mypoints[i][1]; } if (mypoints[i][1] > mostEast) { mostEast = mypoints[i][1]; } } if (onscreen(mostWest, mostEast, mostNorth, mostSouth)) #else // 0 // See if the station icon is on the screen. If so, draw the associated // points. The drawback to this approach is that if the station icon is // scrolled off the edge of the display the points aren't drawn even if // one or more of them is on the display. // if( (x_long > NW_corner_longitude) && (x_long < SE_corner_longitude) // && (y_lat > NW_corner_latitude) && (y_lat < SE_corner_latitude) ) #endif // 0 { //x_offset = (x_long - NW_corner_longitude) / scale_x; //y_offset = (y_lat - NW_corner_latitude) / scale_y; // Convert each of the points from Xastir coordinates to // screen coordinates and fill in the xpoints array. // for (i = 0; i < numpoints; ++i) { // xpoints[i].x = (mypoints[i][0] - NW_corner_longitude) / scale_x; // xpoints[i].y = (mypoints[i][1] - NW_corner_latitude) / scale_y; // // fprintf(stderr," %d: %d,%d\n", i, xpoints[i].x, xpoints[i].y); // } // The type parameter determines how the points will be used. // After determining the type, use the style parameter to // get the color and line style. switch (type) { case '0': // closed polygon default: // Repeat the first point so the polygon will be closed. // xpoints[numpoints].x = xpoints[0].x; // xpoints[numpoints].y = xpoints[0].y; // First draw a wider black line. (void)XSetForeground(XtDisplay(da), gc, colors[0x08]); // black (void)XSetLineAttributes(XtDisplay(da), gc, 4, LineSolid, CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints+1, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } // Close the polygon draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[0][0], mypoints[0][1], gc, where, skip_duplicates); // Then draw the appropriate colored line on top of it. (void)XSetForeground(XtDisplay(da), gc, getLineColor(style)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, getLineStyle(style), CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints+1, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } // Close the polygon draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[0][0], mypoints[0][1], gc, where, skip_duplicates); break; case '1': // line segments (void)XSetForeground(XtDisplay(da), gc, getLineColor(style)); (void)XSetLineAttributes(XtDisplay(da), gc, 2, getLineStyle(style), CapButt, JoinMiter); skip_duplicates = 0; for (i = 0; i < numpoints-1; i++) { // (void)XDrawLines(XtDisplay(da), where, gc, xpoints, numpoints, CoordModeOrigin); draw_vector(da, mypoints[i][0], mypoints[i][1], mypoints[i+1][0], mypoints[i+1][1], gc, where, skip_duplicates); skip_duplicates = 1; } break; // Other types have yet to be implemented. } } } } void Select_symbol_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; int i; XtPopdown(shell); // Free all 188 symbol pixmaps for ( i = 0; i < (126-32)*2; i++ ) { (void)XFreePixmap(XtDisplay(appshell),select_icons[i]); } begin_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol_destroy_shell" ); XtDestroyWidget(shell); select_symbol_dialog = (Widget)NULL; end_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol_destroy_shell" ); } void Select_symbol_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char table[2]; char symbol[2]; int i = XTPOINTER_TO_INT(clientData); //fprintf(stderr,"Selected a symbol: %d\n", clientData); if ( i > 0) { //fprintf(stderr,"Symbol is from primary symbol table: /%c\n",(char)i); table[0] = '/'; symbol[0] = (char)i; } else { //fprintf(stderr,"Symbol is from secondary symbol table: \\%c\n",(char)(-i)); table[0] = '\\'; symbol[0] = (char)(-i); } table[1] = '\0'; symbol[1] = '\0'; if (symbol_change_requested_from == 1) // Configure->Station Dialog { symbol_change_requested_from = 0; //fprintf(stderr,"Updating Configure->Station Dialog\n"); XmTextFieldSetString(station_config_group_data,table); XmTextFieldSetString(station_config_symbol_data,symbol); updateSymbolPictureCallback(widget,clientData,callData); } else if (symbol_change_requested_from == 2) // Create->Object/Item Dialog { symbol_change_requested_from = 0; //fprintf(stderr,"Updating Create->Object/Item Dialog\n"); XmTextFieldSetString(object_group_data,table); XmTextFieldSetString(object_symbol_data,symbol); updateObjectPictureCallback(widget,clientData,callData); } else // Do nothing. We shouldn't be here. { symbol_change_requested_from = 0; } Select_symbol_destroy_shell(widget,select_symbol_dialog,callData); } void Select_symbol( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, my_form2, my_form3, button_cancel, frame, frame2, b1, scrollwindow; int i; Atom delw; if (!select_symbol_dialog) { begin_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol" ); select_symbol_dialog = XtVaCreatePopupShell(langcode("SYMSEL0001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Select_symbol pane", xmPanedWindowWidgetClass, select_symbol_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("Select_symbol scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Select_symbol my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); frame = XtVaCreateManagedWidget("Select_symbol frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Discard the return value of this function, we're not using it. // GCC 6.x *hates* when we assign to variables we never use. XtVaCreateManagedWidget(langcode("SYMSEL0002"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); frame2 = XtVaCreateManagedWidget("Select_symbol frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, frame, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Discard the return value of this function call, we're not using it. // GCC 6.x *hates* when we assign to variables we never use. XtVaCreateManagedWidget(langcode("SYMSEL0003"), xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); my_form2 = XtVaCreateWidget("Select_symbol my_form2", xmRowColumnWidgetClass, frame, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, XmNnumColumns, 10, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form3 = XtVaCreateWidget("Select_symbol my_form3", xmRowColumnWidgetClass, frame2, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_COLUMN, XmNnumColumns, 10, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Symbols: 33 to 126, for both '/' and '\' tables (94 * 2) // 33 = start of icons in ASCII table, 126 = end // Draw the primary symbol set for ( i = 33; i < 127; i++ ) { select_icons[i-33] = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); b1 = XtVaCreateManagedWidget("symbol button", xmPushButtonWidgetClass, my_form2, XmNlabelType, XmPIXMAP, XmNlabelPixmap, select_icons[i-33], XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); symbol(b1,0,'/',(char)i,' ',select_icons[i-33],0,0,0,' '); // create icon // Here we send back the ascii number of the symbol. We need to keep it within // the range of short int's. XtAddCallback(b1, XmNactivateCallback, Select_symbol_change_data, INT_TO_XTPOINTER(i) ); } // Draw the alternate symbol set for ( i = 33+94; i < 127+94; i++ ) { select_icons[i-33] = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); b1 = XtVaCreateManagedWidget("symbol button", xmPushButtonWidgetClass, my_form3, XmNlabelType, XmPIXMAP, XmNlabelPixmap, select_icons[i-33], XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); symbol(b1,0,'\\',(char)i-94,' ',select_icons[i-33],0,0,0,' '); // create icon // Here we send back the ascii number of the symbol negated. We need to keep it // within the range of short int's. XtAddCallback(b1, XmNactivateCallback, Select_symbol_change_data, INT_TO_XTPOINTER(-(i-94)) ); } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Select_symbol_destroy_shell, select_symbol_dialog); pos_dialog(select_symbol_dialog); delw = XmInternAtom(XtDisplay(select_symbol_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(select_symbol_dialog, delw, Select_symbol_destroy_shell, (XtPointer)select_symbol_dialog); XtManageChild(my_form3); XtManageChild(my_form2); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, select_symbol_dialog); XtPopup(select_symbol_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(select_symbol_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); end_critical_section(&select_symbol_dialog_lock, "draw_symbols.c:Select_symbol" ); } else { (void)XRaiseWindow(XtDisplay(select_symbol_dialog), XtWindow(select_symbol_dialog)); } } // Function to draw dead-reckoning symbols. // void draw_deadreckoning_features(DataRow *p_station, Pixmap where, Widget w) { double my_course; long x_long, y_lat; long x_long2, y_lat2; long x, y; long x2, y2; double diameter; int color = trail_colors[p_station->trail_color]; // int symbol_on_screen = 0; int ghosted_symbol_on_screen = 0; // This function takes a bit of CPU if we are zoomed out. It'd be // best to check first whether the zoom level and the speed make it // worth computing DR at all for this station. As a first // approximation, we could turn off DR if we're at zoom 8000 or // higher: // // if (scale_y > 8000) // return; x_long = p_station->coord_lon; y_lat = p_station->coord_lat; // x/y are screen locations for start position x = (x_long - NW_corner_longitude)/scale_x; y = (y_lat - NW_corner_latitude)/scale_y; y_lat2 = y_lat; x_long2 = x_long; // Compute the latest DR'ed position for the object compute_current_DR_position(p_station, &x_long2, &y_lat2); // x2/y2 are screen location for ghost symbol (DR'ed position) x2 = (x_long2 - NW_corner_longitude)/scale_x; y2 = (y_lat2 - NW_corner_latitude)/scale_y; // Check DR'ed symbol position if ( (x_long2>NW_corner_longitude) && (x_long2NW_corner_latitude) && (y_lat2=0) && (x_long<=129600000l)) && ((y_lat>=0) && (y_lat<=64800000l))) { ghosted_symbol_on_screen++; } // Draw the DR arc // if (Display_.dr_arc && ghosted_symbol_on_screen) { double xdiff, ydiff; xdiff = (x2-x) * 1.0; ydiff = (y2-y) * 1.0; // a squared + b squared = c squared diameter = 2.0 * sqrt( (double)( (ydiff*ydiff) + (xdiff*xdiff) ) ); //fprintf(stderr,"Range:%f\tDiameter:%f\n",range,diameter); if (diameter > 10.0) { int arc_degrees = (sec_now() - p_station->sec_heard) * 90 / (5*60); if (arc_degrees > 360) { arc_degrees = 360; } (void)XSetLineAttributes(XtDisplay(da), gc, 1, LineOnOffDash, CapButt,JoinMiter); //(void)XSetForeground(XtDisplay(da),gc,colors[0x0a]); //(void)XSetForeground(XtDisplay(da),gc,colors[0x44]); // red3 (void)XSetForeground(XtDisplay(da),gc,color); // Compute angle from the two screen positions. // if (xdiff != 0) { //We should guard against divide-by-zero here! my_course = 57.29578 * atan(xdiff/ ydiff); } else { if (ydiff >= 0) { my_course = 180.0; } else { my_course = 0.0; } } //fprintf(stderr,"my_course:%f\n", my_course); // The arctan function returns values between -90 and +90. To // obtain the true course we apply the following rules: if (ydiff > 0 && xdiff > 0) { //fprintf(stderr,"1\n"); // Lower-right quadrant my_course = 360.0 - my_course; } else if (ydiff < 0.0 && xdiff > 0.0) { //fprintf(stderr,"2\n"); // Upper-right quadrant my_course = 180.0 - my_course; } else if (ydiff < 0.0 && xdiff < 0.0) { //fprintf(stderr,"3\n"); // Upper-left quadrant my_course = 180.0 - my_course; } else if (ydiff > 0.0 && xdiff < 0.0) { //fprintf(stderr,"4\n"); // Lower-left quadrant my_course = 360.0 - my_course; } else // 0/90/180/270 { //fprintf(stderr,"5\n"); my_course = 180.0 + my_course; } // Convert to screen angle for XDrawArc routines: my_course = my_course + 90.0; if (my_course > 360.0) { my_course = my_course - 360.0; } //fprintf(stderr,"\tmy_course2:%f\n", my_course); // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(x-(diameter/2)), // int l16(y-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(-64*my_course), // int l16(64/2*arc_degrees)); // int // Check that our parameters are within spec for XDrawArc. Tricky // 'cuz the XArc struct has short's and unsigned short's, while // XDrawArc man-page says int's/unsigned int's. We'll stick to 16-bit // just to make sure. (void)XDrawArc(XtDisplay(da),where,gc, l16(x-(diameter/2)), // int l16(y-(diameter/2)), // int lu16(diameter), // unsigned int lu16(diameter), // unsigned int l16(-64*my_course), // int l16(-64/2*arc_degrees)); // int } } // Note that for the DR course, if we're in the middle of the symbol // and the DR'ed symbol (ghosted symbol), but neither of them are // on-screen, the DR'ed course won't display. // // Draw the DR'ed course if either the symbol or the DR'ed // symbol (ghosted symbol) are on-screen. // if (Display_.dr_course) { (void)XSetLineAttributes(XtDisplay(da), gc, 0, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da),gc,color); // red3 // This one changes the angle as the vector gets longer, by // about 10 degrees (A test at 133 degrees -> 143 degrees). // draw_vector() needs to truncate the line in this case, // maintaining the same slope. This behavior is _much_ // better than the XDrawLine above though! // draw_vector(w, x_long, y_lat, x_long2, y_lat2, gc, where, 0); } // Draw the DR'ed symbol (ghosted symbol) if enabled and if // on-screen. // if (Display_.dr_symbol && ghosted_symbol_on_screen) { draw_symbol(w, p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay, x_long2, y_lat2, "", "", "", "", "", "", "", "", p_station->sec_heard-sec_old, // Always draw it ghosted 0, where, symbol_orient(p_station->course), p_station->aprs_symbol.area_object.type, p_station->signpost, NULL, 0); // Don't bump the station count } } Xastir-Release-2.2.4/src/draw_symbols.h0000664000175000017500000001056315151324131016773 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_DRAW_SYMBOLS_H #define __XASTIR_DRAW_SYMBOLS_H #define SYMBOL_ACTIVE 'A' #define SYMBOL_NOTACTIVE 'N' #define MAX_SYMBOLS 400 typedef struct { char active; // ?? char table; // table character char symbol; // symbol character char orient; // orientation of the symbol, one of ' ', 'l','r','u','d' Pixmap pix; // icon picture Pixmap pix_mask; // mask for transparent background Pixmap pix_mask_old; // mask for ghost symbols, half transparent icons } SymbolData; extern SymbolData symbol_data[]; extern void draw_nice_string(Widget w, Pixmap where, int style, long x, long y, char *text, int bgcolor, int fgcolor, int length); extern void clear_symbol_data(void); extern void read_symbol_from_file(FILE *f, char *pixels, char table_char); extern void load_pixmap_symbol_file(char *filename, int reloading); extern void insert_symbol(char table, char symbol, char *pixel, int deg, char orient, int reloading); extern char symbol_orient(char *course); extern void symbol(Widget w, int ghost,char symbol_table, char symbol_id, char symbol_overlay, Pixmap where, int mask, long x_offset, long y_offset, char rotate); long get_text_width(Widget w,char *text); extern void draw_WP_line(DataRow *p_station, int ambiguity_flag, long ambiguity_coord_lon, long ambiguity_coord_lat, Pixmap where, Widget w); extern void draw_symbol(Widget w, char symbol_table, char symbol_id, char symbol_overlay, long x_lon, long y_lat,char *callsign_text, char *alt_text, char *course_text, char *speed_text, char *my_distance, char *my_course, char *wx_temp, char* wx_wind, time_t sec_heard, int temp_show_last_heard, Pixmap where, char rotate, char area_type, char *signpost, char *gauge_data, int bump_count ); extern void draw_pod_circle(long x_long, long y_lat, double range, int color, Pixmap where, int sec_heard); extern void draw_precision_rectangle(long x_long, long y_lat, double range, unsigned int lat_precision, unsigned int lon_precision, int color, Pixmap where); extern void draw_aloha_circle(long x_long, long y_lat, double range, int color, Pixmap where); extern void draw_phg_rng(long x_long, long y_lat, char *phg, time_t sec_heard, Pixmap where); extern void draw_DF_circle(long x_long, long y_lat, char *shgd, time_t sec_heard, Pixmap where); extern void draw_wind_barb(long x_long, long y_lat, char *speed, char *course, time_t sec_heard, Pixmap where); extern void draw_bearing(long x_long, long y_lat, char *course, char *bearing, char *NRQ, int color, int draw_beamwidth, int draw_bearing, time_t sec_heard, Pixmap where); extern void draw_ambiguity(long x_long, long y_lat, char amb, long *amb_x_long, long *amb_y_lat, time_t sec_heard, Pixmap where); extern void draw_area(long x_long, long y_lat, char type, char color, char sqrt_lat_off, char sqrt_lon_off, unsigned int width, time_t sec_heard, Pixmap where); extern void draw_multipoints(long x_long, long y_lat, int numpoints, long points[][2], char type, char style, time_t sec_heard, Pixmap where); // KG4NBB extern void Select_symbol( Widget w, XtPointer clientData, XtPointer callData); extern int symbol_change_requested_from; extern Widget select_symbol_dialog; extern void Select_symbol_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData); extern void draw_symbols_init(void); extern void draw_deadreckoning_features(DataRow *p_station, Pixmap where, Widget w); #endif // __XASTIR_DRAW_SYMBOLS_H Xastir-Release-2.2.4/src/fcc_data.c0000664000175000017500000004201015151324131015775 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include "xastir.h" #include "fcc_data.h" #include "xa_config.h" #include "main.h" // Must be last include file #include "leak_detection.h" char *call_only(char *callsign) { int i, len; len = strlen(callsign); for (i = 0; i < len; i++) { if (!isalnum((int)callsign[i])) { callsign[i]='\0'; i=len; } } return(callsign); } /* ==================================================================== */ /* build a new (or newer if I check the file date) index file */ /* check for current ic index file */ /* FG: added a date check in case the FCC file has been updated. */ /* appl.dat must have a time stamp newer than the index file time */ /* stamp. Use the touch command on the appl.dat file to make the */ /* time current if necessary. */ // How this works: The index file contains a few callsigns and their // offsets into the large database file. The code uses these as // jump-off points to look for a particular call, to speed things up. /* ******************************************************************** */ int build_fcc_index(int type) { FILE *fdb; FILE *fndx; unsigned long call_offset = 0; unsigned long x = 0; char fccdata[FCC_DATA_LEN+8]; char database_name[100]; int found,i,num; char appl_file_path[MAX_VALUE]; if (type==1) { xastir_snprintf(database_name, sizeof(database_name), "fcc/appl.dat"); } else { xastir_snprintf(database_name, sizeof(database_name), "fcc/EN.dat"); } /* ==================================================================== */ /* If the index file is there, exit */ /* */ get_user_base_dir("data/appl.ndx", appl_file_path, sizeof(appl_file_path)); if (filethere(appl_file_path)) { /* if file is there make sure the index date is newer */ if (file_time(get_data_base_dir(database_name))<=file_time(appl_file_path)) { return(1); } else { // FCC index old, rebuilding statusline(langcode("STIFCC0100"),1); fprintf(stderr,"FCC index is old. Rebuilding index.\n"); // XmTextFieldSetString(text,"FCC index old, rebuilding"); // XtManageChild(text); // XmUpdateDisplay(XtParent(text)); // DK7IN: do we need this ??? } } /* ==================================================================== */ /* Open the database and index file */ /* */ fdb=fopen(get_data_base_dir(database_name),"rb"); if (fdb==NULL) { fprintf(stderr,"Build:Could not open FCC data base: %s\n", get_data_base_dir(database_name) ); return(0); } fndx=fopen(appl_file_path,"w"); if (fndx==NULL) { fprintf(stderr,"Build:Could not open/create FCC data base index: %s\n", appl_file_path ); (void)fclose(fdb); return(0); } /* ==================================================================== */ /* write out the current callsign and RBA of the db file */ /* skip (index_skip) records and do it again until no more */ /* */ xastir_snprintf(fccdata,sizeof(fccdata)," "); while(!feof(fdb)) { call_offset = (unsigned long)ftell(fdb); if (fgets(fccdata, (int)sizeof(fccdata), fdb) == NULL) { // error occurred fprintf(stderr,"Build: Could not read fcc data base: %s \n", appl_file_path); (void)fclose(fdb); return(0); } found=0; num=0; if (type==2) { for(i=0; i<14 && !found; i++) { if(fccdata[i]=='|') { num++; if(num==4) { found=i+1; } } } } (void)call_only(fccdata+found); fprintf(fndx,"%-6.6s%li\n",fccdata+found,call_offset+found); for (x=0; x<=500 && !feof(fdb); x++) { if (fgets(fccdata, (int)sizeof(fccdata), fdb)==NULL) { break; } } } (void)fclose(fdb); (void)fclose(fndx); // XmTextFieldSetString(text,""); // XtManageChild(text); return(1); } /* ==================================================================== */ /* Check for ic data base file */ /* Check/build the index */ /* */ /* ******************************************************************** */ int check_fcc_data(void) { int fcc_data_available = 0; if (filethere(get_data_base_dir("fcc/EN.dat")) && filethere(get_data_base_dir("fcc/appl.dat"))) { if(file_time(get_data_base_dir("fcc/appl.dat"))<=file_time(get_data_base_dir("fcc/EN.dat"))) { /*fprintf(stderr,"NEW FORMAT FCC DATA FILE is NEWER THAN OLD FCC FORMAT\n");*/ if (build_fcc_index(2)) { fcc_data_available=2; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } else { /*fprintf(stderr,"OLD FORMAT FCC DATA FILE is NEWER THAN NEW FCC FORMAT\n");*/ if (build_fcc_index(1)) { fcc_data_available=1; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } } else { if (filethere(get_data_base_dir("fcc/EN.dat"))) { /*fprintf(stderr,"NO OLD FCC, BUT NEW FORMAT FCC DATA AVAILABLE\n");*/ if (build_fcc_index(2)) { fcc_data_available=2; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } else { if (filethere(get_data_base_dir("fcc/appl.dat"))) { /*fprintf(stderr,"NO NEW FCC, BUT OLD FORMAT FCC DATA AVAILABLE\n");*/ if (build_fcc_index(1)) { fcc_data_available=1; } else { fprintf(stderr,"Check:Could not build fcc data base index\n"); fcc_data_available=0; } } } } return(fcc_data_available); } int search_fcc_data_appl(char *callsign, FccAppl *data) { FILE *f; char line[200]; int line_pos; char data_in[16385]; int found, xx, bytes_read; char temp[15]; int len; int which; int i,ii; int pos_it; int llen; char calltemp[8]; int pos,ix,num; FILE *fndx; long call_offset = 0; char char_offset[16]; char index[32]; char appl_file_path[MAX_VALUE]; data->id_file_num[0] = '\0'; data->type_purpose[0] = '\0'; data->type_applicant=' '; data->name_licensee[0] = '\0'; data->text_street[0] = '\0'; data->text_pobox[0] = '\0'; data->city[0] = '\0'; data->state[0] = '\0'; data->zipcode[0] = '\0'; data->date_issue[0] = '\0'; data->date_expire[0] = '\0'; data->date_last_change[0] = '\0'; data->id_examiner[0] = '\0'; data->renewal_notice=' '; xastir_snprintf(temp, sizeof(temp), "%s", callsign); (void)call_only(temp); xastir_snprintf(calltemp, sizeof(calltemp), "%-6.6s", temp); // calltemp doesn't appear to get used anywhere... /* add end of field data */ strncat(temp, "|", sizeof(temp) - 1 - strlen(temp)); len=(int)strlen(temp); found=0; line_pos=0; /* check the database again */ which = check_fcc_data(); // Check for first letter of a U.S. callsign if (! (callsign[0] == 'A' || callsign[0] == 'K' || callsign[0] == 'N' || callsign[0] == 'W') ) { return(0); // Not found } // ==================================================================== // Search thru the index, get the RBA // // This gives us a jumping-off point to start looking in the right // neighborhood for the callsign of interest. // get_user_base_dir("data/appl.ndx", appl_file_path, sizeof(appl_file_path)); fndx=fopen(appl_file_path,"r"); if (fndx!=NULL) { if (fgets(index,(int)sizeof(index),fndx) == NULL) { // Error occurred fprintf(stderr,"Search:Could not read FCC database index(1): %s\n",appl_file_path); return(0); } memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string // Search through the indexes looking for a callsign which is // close to the callsign of interest. If callsign is later in // the alphabet than the current index, snag the next index. while (!feof(fndx) && strncmp(callsign,index,6) > 0) { memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string if (fgets(index,(int)sizeof(index),fndx) == NULL) { // Error occurred fprintf(stderr,"Search:Could not read FCC database index(2): %s\n", appl_file_path ); return(0); } } } else { fprintf(stderr,"Search:Could not open FCC data base index: %s\n", appl_file_path ); return (0); } call_offset = atol(char_offset); (void)fclose(fndx); /* ==================================================================== */ /* Continue with the original search */ /* */ f=NULL; switch (which) { case(1): f=fopen(get_data_base_dir("fcc/appl.dat"),"r"); break; case(2): f=fopen(get_data_base_dir("fcc/EN.dat"),"r"); break; default: break; } if (f!=NULL) { (void)fseek(f, call_offset,SEEK_SET); while (!feof(f) && !found) { bytes_read=(int)fread(data_in,1,16384,f); if (bytes_read>0) { for (xx=0; (xxid_file_num,sizeof(data->id_file_num),"%s",line+pos_it); break; case(1): xastir_snprintf(data->type_purpose,sizeof(data->type_purpose),"%s",line+pos_it); break; case(2): data->type_applicant=line[pos_it]; break; case(3): xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it); break; case(4): xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it); break; case(5): xastir_snprintf(data->text_pobox,sizeof(data->text_pobox),"%s",line+pos_it); break; case(6): xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it); break; case(7): xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it); break; case(8): xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it); break; case(9): xastir_snprintf(data->date_issue,sizeof(data->date_issue),"%s",line+pos_it); break; case(11): xastir_snprintf(data->date_expire,sizeof(data->date_expire),"%s",line+pos_it); break; case(12): xastir_snprintf(data->date_last_change,sizeof(data->date_last_change),"%s",line+pos_it); break; case(13): xastir_snprintf(data->id_examiner,sizeof(data->id_examiner),"%s",line+pos_it); break; case(14): data->renewal_notice=line[pos_it]; break; default: break; } break; case(2): switch (i) { case(0): xastir_snprintf(data->id_file_num,sizeof(data->id_file_num),"%s",line+pos_it); break; case(2): xastir_snprintf(data->name_licensee,sizeof(data->name_licensee),"%s",line+pos_it); break; case(10): xastir_snprintf(data->text_street,sizeof(data->text_street),"%s",line+pos_it); break; case(11): xastir_snprintf(data->city,sizeof(data->city),"%s",line+pos_it); break; case(12): xastir_snprintf(data->state,sizeof(data->state),"%s",line+pos_it); break; case(13): xastir_snprintf(data->zipcode,sizeof(data->zipcode),"%s",line+pos_it); break; default: break; } break; default: break; } } } } else { // IF we aren't some bogus record with a null next field // (in which we skip to the next), // Check whether we passed the alphabetic // location for the callsign. Return if so. if ( line[pos] != '|' && ((temp[0] < line[pos]) || ( (temp[0] == line[pos]) && (temp[1] < line[pos+1])))) { // "Callsign Search", "Callsign Not Found!" popup_message_always(langcode("STIFCC0101"), langcode("STIFCC0102") ); //fprintf(stderr,"%c%c\t%c%c\n",temp[0],temp[1],line[pos],line[pos+1]); (void)fclose(f); return(0); } } } } } } (void)fclose(f); } else { fprintf(stderr,"Could not open FCC appl data base at: %s\n", get_data_base_dir("fcc/") ); } return(found); } Xastir-Release-2.2.4/src/fcc_data.h0000664000175000017500000000444615151324131016015 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * FCC Database structures * */ /* type_purpose - Indicates the reason why the application was filed. Multiple codes may occur. Codes are: A New license B Change existing class C Change name D Change mailing address E Change callsign F Renewal on Form 610 G Add record (internal) H Duplicate license request I Change Issue/Expiration Date J Supersede K Internal correction code L Delete N Renewal on form 610R O Renewal on form 610B P Modification on form 610B Q Restore both database and pending R Restore database S Special callsign change type_applicant - Indicates type of application. Codes are: A Alien C Club I Individual M Military recreation R RACES */ #ifndef XASTIR_FCC_DATA_H #define XASTIR_FCC_DATA_H #define FCC_DATA_LEN 200 typedef struct { char id_callsign[11]; char id_file_num[11]; char type_purpose[9]; char type_applicant; char name_licensee[41]; char text_street[36]; char text_pobox[21]; char city[30]; char state[3]; char zipcode[10]; char filler; char date_issue[7]; char date_expire[7]; char date_last_change[7]; char id_examiner[4]; char renewal_notice; } FccAppl; extern int check_fcc_data(void); extern int search_fcc_data_appl(char *callsign, FccAppl *data); #endif /* XASTIR_FCC_DATA_H */ Xastir-Release-2.2.4/src/festival.c0000664000175000017500000003464715151324131016107 0ustar hibbyhibby// Modification for Xastir CVS purposes // // Portions Copyright (C) 2000-2026 The Xastir Group // // // End of modification /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS 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. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API in C designed specifically for */ /* Galaxy Communicator use though might be of use for other things */ /* */ /* This is a standalone C client, no other Festival or Speech Tools */ /* libraries need be link with this. Thus is very small. */ /* */ /* Compile with (plus socket libraries if required) */ /* cc -o festival_client -DSTANDALONE festival_client.c */ /* */ /* Run as */ /* festival_client -text "hello there" -o hello.snd */ /* */ /* */ /* This is provided as an example, it is quite limited in what it does */ /* but is functional compiling without -DSTANDALONE gives you a simple */ /* API */ /* */ /*************************************************************************/ /* */ /* Heavily modified and Hacked together to provide a general purpose */ /* interface for use in XASTIR by: */ /* */ /* Ken Koster N7IPB 03/24/2001 */ /* */ /* */ /* More comments added and 'do' loop that waited for 'ok' response */ /* removed. Also cleaned up escape processing */ /* */ /* N7IPB 04/04/2001 */ /* Test for errno result from 'read' operation and re-opening of */ /* connection if it gets closed. */ /* N7IPB 04/08/2001 */ /* */ /*=======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include "sound.h" #include "festival.h" #include "snprintf.h" #include "util.h" #include "xastir.h" // Must be last include file #include "leak_detection.h" FT_Info *info = NULL; static char last_speech_text[8000]; static time_t last_speech_time = (time_t)0; static time_t festival_connect_attempt_time = (time_t)0; // Set up default struct // void festival_default_info(void) { if (info == NULL) // First time through { // Malloc storage for the struct info = (FT_Info *)malloc(1 * sizeof(FT_Info)); // Fill in the struct if (info != NULL) { info->server_host = FESTIVAL_DEFAULT_SERVER_HOST; info->server_port = FESTIVAL_DEFAULT_SERVER_PORT; info->text_mode = FESTIVAL_DEFAULT_TEXT_MODE; info->server_fd = -1; } else // Couldn't allocate memory { fprintf(stderr,"festival_default_info: Couldn't malloc\n"); } } return; } // Returns a FD to a remote server // static int festival_socket_open(const char *host, int port) { struct sockaddr_in serv_addr; struct hostent *serverhost; int fd; // Delay at least 60 seconds between each socket attempt if ( (festival_connect_attempt_time + 60) > sec_now() ) { //fprintf(stderr,"Not time yet\n"); return(-1); } festival_connect_attempt_time = sec_now(); if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { fprintf(stderr,"festival_client: can't get socket\n"); return(-1); } memset(&serv_addr, 0, sizeof(serv_addr)); if ((int)(serv_addr.sin_addr.s_addr = inet_addr(host)) == -1) { /* its a name rather than an ipnum */ serverhost = gethostbyname(host); if (serverhost == (struct hostent *)0) { fprintf(stderr,"festival_client: gethostbyname failed\n"); return(-1); } memmove(&serv_addr.sin_addr,serverhost->h_addr, (size_t)serverhost->h_length); } serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { fprintf(stderr,"festival_client: connect to server failed\n"); (void)close(fd); // Close the socket return(-1); } return(fd); } /***********************************************************************/ /* Public Functions to this API */ /***********************************************************************/ // Close socket to server // int festivalClose(void) { //fprintf(stderr,"festivalClose()\n"); if (info != NULL) // We have a struct allocated { // Check whether we have a socket open if (info->server_fd != -1) { fprintf(stderr,"Closing Festival socket\n"); (void)close(info->server_fd); // Close the socket info->server_fd = -1; // Just to be safe } // Free the struct, zero the pointer. The struct will get // re-created/re-initialized later when we re-open the // festival connection. free(info); info = NULL; } return(0); } // Open socket to server. Close the connection if one is already // open. // int festivalOpen(void) { //fprintf(stderr,"festivalOpen()\n"); festival_default_info(); // Check whether we have a record to work with if (info == NULL) { return(-1); } // Check whether we already have a socket open (or think we do) if (info->server_fd != -1) // We have a socket open { (void)festivalClose(); // Close it, free struct usleep(50000); // 50ms wait } info->server_fd = festival_socket_open(info->server_host, info->server_port); if (info->server_fd == -1) // Error occurred opening socket { //fprintf(stderr,"festivalOpen: Error opening socket\n"); (void)festivalClose(); // Close, free struct usleep(50000); // 50ms wait return(-1); } return(0); } void festivalStringToSpeech(char *text) { FILE *fd; char *p; char ack[4]; int n; int tmp = 0; int ret; //fprintf(stderr,"festivalStringToSpeech()\n"); // If we don't have a struct allocated if (info == 0) { if (festivalOpen() == -1) // Allocate struct, open socket { //fprintf(stderr,"festivalStringToSpeech: Couldn't open socket to Festival\n"); return; } } if (info == 0) // If socket is still not open { return; } if (info->server_fd == -1) { fprintf(stderr,"festival_client: server connection unopened\n"); (void)festivalClose(); return; } fd = fdopen(dup(info->server_fd),"wb"); if (fd == NULL) { fprintf(stderr,"Couldn't create duplicate socket\n"); (void)festivalClose(); return; } /* ** Send the mode commands to festival */ ret = fprintf(fd,"(audio_mode `async)\n(SayText \"\n"); if (ret == 0 || ret == -1) { fprintf(stderr,"Couldn't send mode commands to festival\n"); (void)fclose(fd); (void)festivalClose(); return; } /* ** Copy text over to server, escaping any quotes */ for (p=text; p && (*p != '\0'); p++) { if ((*p == '"') || (*p == '\\')) { if (putc('\\',fd) == EOF) // Error writing to socket { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } else { /* ** Then convert any embedded '-' into the word 'dash' ** This could cause problems with spoken text from ** Weather alerts or messages. We'll deal with that ** later if necessary. Making this a separate function ** is probably the thing to do. */ if (*p == '-' ) { ret = fprintf(fd,",dash,"); if (ret == 0 || ret == -1) { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } else { if (putc(*p,fd) == EOF) // Error writing to socket { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } } } } /* ** Complete the command to xastir, close the quotes and ** set the mode to 'fundamental' */ ret = fprintf(fd,"\" \"%s\")\n",info->text_mode); if (ret == 0 || ret == -1) { fprintf(stderr,"Error writing to socket\n"); (void)fclose(fd); (void)festivalClose(); return; } /* ** Close the duplicate port we used for writing */ (void)fclose(fd); /* ** Read back info from server ** ** We don't really care what we get back. If it's an error ** We're just going to continue on anyway so I've removed the ** check here for the 'OK' response. We still check for an ERror ** but we just print the fact we got it and continue on ** ** This could probably use some work, I need to study the ** festival docs a bit more, this could block and it could ** also have more than 3bytes that need to be read. It doesn't ** appear to matter but should be checked into. */ for (n=0; n < 3; ) { if ( ( tmp = read(info->server_fd,ack+n,3-n)) != -1 ) { n = n + tmp; } else { if (debug_level & 2) { fprintf(stderr,"Error reading festival ACK - %s\n",strerror(errno)); } n = 3; if (errno == ECONNRESET) { fprintf(stderr,"Connection reset\n"); info = 0; (void)festivalClose(); if (festivalOpen() == -1) { fprintf(stderr,"festivalStringToSpeech2: Couldn't open socket to Festival\n"); return; } } } } /* ** Null terminate the string */ ack[3] = '\0'; if (strcmp(ack,"ER\n") == 0) /* server got an error */ { fprintf(stderr,"festival_client: server returned error\n"); } return; } int SayText(char *text) { if (debug_level & 2) { fprintf(stderr,"SayText: %s\n",text); } // Check whether the last text was the same and it hasn't been // enough time between them (30 seconds). We include our speech // system test string here so that we don't have to wait 30 // seconds between Test button-presses. if ( (strcmp(last_speech_text,text) == 0) // Strings match && (strcmp(text,SPEECH_TEST_STRING) != 0) && (last_speech_time + 30 > sec_now()) ) { /* fprintf(stderr, "Same text, skipping speech: %d seconds, %s\n", (int)(sec_now() - last_speech_time), text); */ return(1); } //fprintf(stderr,"Speaking: %s\n",text); xastir_snprintf(last_speech_text, sizeof(last_speech_text), "%s", text); last_speech_time = sec_now(); festivalStringToSpeech(text); return(0); } int SayTextInit(void) { if (festivalOpen() == -1) { fprintf(stderr,"SayText: Couldn't open socket to Festival\n"); } last_speech_text[0] = '\0'; last_speech_time = (time_t)0; return(0); } Xastir-Release-2.2.4/src/festival.h0000664000175000017500000001072215151324131016100 0ustar hibbyhibby// Modification for Xastir CVS purposes // // Portions Copyright (C) 2000-2026 The Xastir Group // // End of modification /*************************************************************************/ /* */ /* Centre for Speech Technology Research */ /* University of Edinburgh, UK */ /* Copyright (c) 1999 */ /* All Rights Reserved. */ /* */ /* Permission is hereby granted, free of charge, to use and distribute */ /* this software and its documentation without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of this work, and to */ /* permit persons to whom this work is furnished to do so, subject to */ /* the following conditions: */ /* 1. The code must retain the above copyright notice, this list of */ /* conditions and the following disclaimer. */ /* 2. Any modifications must be clearly marked as such. */ /* 3. Original authors' names are not deleted. */ /* 4. The authors' names are not used to endorse or promote products */ /* derived from this software without specific prior written */ /* permission. */ /* */ /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */ /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */ /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */ /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS 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. */ /* */ /*************************************************************************/ /* Author : Alan W Black (awb@cstr.ed.ac.uk) */ /* Date : March 1999 */ /*-----------------------------------------------------------------------*/ /* */ /* Client end of Festival server API (in C) designed specifically for */ /* Galaxy Communicator use, though might be of use for other things */ /* */ /*=======================================================================*/ #ifndef _FESTIVAL_CLIENT_H_ #define _FESTIVAL_CLIENT_H_ #define FESTIVAL_DEFAULT_SERVER_HOST "localhost" #define FESTIVAL_DEFAULT_SERVER_PORT 1314 #define FESTIVAL_DEFAULT_TEXT_MODE "fundamental" typedef struct FT_Info { int encoding; char *server_host; int server_port; char *text_mode; int server_fd; } FT_Info; typedef struct FT_Wave { int num_samples; int sample_rate; short *samples; } FT_Wave; void delete_FT_Wave(FT_Wave *wave); void delete_FT_Info(FT_Info *info); #define SWAPSHORT(x) ((((unsigned)x) & 0xff) << 8 | \ (((unsigned)x) & 0xff00) >> 8) #define SWAPINT(x) ((((unsigned)x) & 0xff) << 24 | \ (((unsigned)x) & 0xff00) << 8 | \ (((unsigned)x) & 0xff0000) >> 8 | \ (((unsigned)x) & 0xff000000) >> 24) /* Sun, HP, SGI Mips, M68000 */ #define FAPI_BIG_ENDIAN (((char *)&fapi_endian_loc)[0] == 0) /* Intel, Alpha, DEC Mips, Vax */ #define FAPI_LITTLE_ENDIAN (((char *)&fapi_endian_loc)[0] != 0) /*****************************************************************/ /* Public functions to interface */ /*****************************************************************/ /* If called with NULL will attempt to access using defaults */ int festivalOpen(void); void festivalStringToWave(char *text); int festivalClose(void); #endif // _FESTIVAL_CLIENT_H_ Xastir-Release-2.2.4/src/fetch_remote.c0000664000175000017500000001525215151324131016725 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL // Needed for size_t #include // Must be last include file #include "leak_detection.h" extern int debug_level; extern int net_map_timeout; /* curl routines */ #ifdef HAVE_LIBCURL struct FtpFile { char *filename; FILE *stream; }; size_t curl_fwrite(void *buffer, size_t size, size_t nmemb, void *stream) { struct FtpFile *out = (struct FtpFile *)stream; if (out && !out->stream) { out->stream=fopen(out->filename, "wb"); if (!out->stream) { return -1; } } return fwrite(buffer, size, nmemb, out->stream); } /* * xastir_curl_init - create curl session with common options */ CURL *xastir_curl_init(char *errBuf) { CURL *mySession; char agent_string[15]; mySession = curl_easy_init(); if (mySession != NULL) { if (debug_level & 8192) { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 1L); } else { curl_easy_setopt(mySession, CURLOPT_VERBOSE, 0L); } curl_easy_setopt(mySession, CURLOPT_ERRORBUFFER, errBuf); xastir_snprintf(agent_string, sizeof(agent_string),"Xastir"); curl_easy_setopt(mySession, CURLOPT_USERAGENT, agent_string); // write function curl_easy_setopt(mySession, CURLOPT_WRITEFUNCTION, curl_fwrite); curl_easy_setopt(mySession, CURLOPT_TIMEOUT, (long)net_map_timeout); curl_easy_setopt(mySession, CURLOPT_CONNECTTIMEOUT, (long)(net_map_timeout/2)); // Added in libcurl 7.9.8 #if (LIBCURL_VERSION_NUM >= 0x070908) curl_easy_setopt(mySession, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.6 #if (LIBCURL_VERSION_NUM >= 0x071006) curl_easy_setopt(mySession, CURLOPT_HTTPAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10.7 #if (LIBCURL_VERSION_NUM >= 0x071007) curl_easy_setopt(mySession, CURLOPT_PROXYAUTH, CURLAUTH_ANY); #endif // LIBCURL_VERSION_NUM // Added in libcurl 7.10 #if (LIBCURL_VERSION_NUM >= 0x070a00) // This prevents a segfault for the case where we get a timeout on // domain name lookup. It has to do with the ALARM signal // and siglongjmp(), which we use in hostname.c already. // This URL talks about it a bit more, plus see the libcurl // docs: // // http://curl.haxx.se/mail/lib-2002-12/0103.html // curl_easy_setopt(mySession, CURLOPT_NOSIGNAL, 1L); #endif // LIBCURL_VERSION_NUM // Respect and follow http redirects curl_easy_setopt(mySession, CURLOPT_FOLLOWLOCATION, 1L); } return(mySession); } // xastir_curl_init() /* * fetch_remote_tile - downloads file using an open curl session * Returns curl result code. */ int fetch_remote_tile(CURL *session, char *tileURL, char *tileFileName) { CURLcode res; struct FtpFile ftpfile; curl_easy_setopt(session, CURLOPT_URL, tileURL); ftpfile.filename = tileFileName; ftpfile.stream = NULL; curl_easy_setopt(session, CURLOPT_FILE, &ftpfile); res = curl_easy_perform(session); if (ftpfile.stream) { fclose(ftpfile.stream); } return(res); } // fetch_remote_tile() #endif // HAVE_LIBCURL /* * fetch_remote_file * Returns: 0 If file retrieved * 1 If there was a problem getting the file */ int fetch_remote_file(char *fileimg, char *local_filename) { #ifdef HAVE_LIBCURL CURL *curl; CURLcode res; char curlerr[CURL_ERROR_SIZE]; struct FtpFile ftpfile; //fprintf(stderr, "Fetching remote file: %s\n", fileimg); curl = xastir_curl_init(curlerr); if (curl) { // download from fileimg curl_easy_setopt(curl, CURLOPT_URL, fileimg); ftpfile.filename = local_filename; ftpfile.stream = NULL; curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile); res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (CURLE_OK != res) { fprintf(stderr, "curl told us %d\n", res); fprintf(stderr, "curlerr: %s\n", curlerr); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); fprintf(stderr,"Could also be malformed URL, '%s'",fileimg); } if (ftpfile.stream) { fclose(ftpfile.stream); } // Return error-code if we had trouble if (CURLE_OK != res) { return(1); } } else { fprintf(stderr,"Couldn't download the file %s\n", fileimg); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); return(1); } return(0); // Success! #else // HAVE_LIBCURL #ifdef HAVE_WGET char tempfile[500]; //"%s --server-response --timestamping --user-agent=Xastir --tries=1 --timeout=%d --output-document=%s \'%s\' 2> /dev/null\n", xastir_snprintf(tempfile, sizeof(tempfile), "%s --server-response --user-agent=Xastir --tries=1 --timeout=%d --output-document=%s \'%s\' 2> /dev/null\n", WGET_PATH, net_map_timeout, local_filename, fileimg); if (debug_level & 2) { fprintf(stderr,"%s",tempfile); } if ( system(tempfile) ) // Go get the file { fprintf(stderr,"Couldn't download the file\n"); fprintf(stderr, "Perhaps a timeout? Try increasing \"Internet Map Timeout\".\n"); return(1); } return(0); // Success! #else // HAVE_WGET fprintf(stderr,"libcurl or 'wget' not installed. Can't download file\n"); return(1); #endif // HAVE_WGET #endif // HAVE_LIBCURL } Xastir-Release-2.2.4/src/fetch_remote.h0000664000175000017500000000241415151324131016726 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_FETCH_REMOTE_H #define __XASTIR_FETCH_REMOTE_H #ifdef HAVE_LIBCURL #include CURL *xastir_curl_init(char *errBuf); int fetch_remote_tile(CURL *session, char *tileURL, char *tileFileName); #endif // HAVE_LIBCURL int fetch_remote_file(char *fileimg, char *local_filename); #endif // __XASTIR_FETCH_REMOTE_H Xastir-Release-2.2.4/src/forked_getaddrinfo.c0000664000175000017500000002455715151324131020111 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include //Needed for Solaris 2.5 #include #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "lang.h" // Must be last include file #include "leak_detection.h" #include "forked_getaddrinfo.h" #ifndef HAVE_SIGHANDLER_T #ifdef HAVE_SIG_T typedef sig_t sighandler_t; #else typedef void (*sighandler_t)(int); #endif #endif #ifndef __LCLINT__ #ifndef HAVE_SIGJMP_BUF jmp_buf ret_place; #else // HAVE_SIGJMP_BUF static sigjmp_buf ret_place; /* Jump address if alarm */ #endif // HAVE_SIGJMP_BUF #endif // __LCLINT__ /*************************************************************************/ /* Time out on connect */ /* In case there is a problem in getting the hostname or connecting */ /* (see setjmp below). */ /*************************************************************************/ static void host_time_out( int UNUSED(sig) ) { #ifndef __LCLINT__ siglongjmp(ret_place,0); #endif // __LCLINT__ } /*************************************************************************/ /* do a nice host lookup (don't thread!!) */ /* */ /* host: name to lookup */ /* ip: buffer for ip's must be 400 bytes at least */ /* time: time in seconds to wait */ /* */ /* return the ip or ip's of the host name */ /* or these strings: */ /* NOHOST for no host by that name found */ /* NOIP for host found but no ip address available */ /* TIMEOUT for time exceeded */ /*************************************************************************/ #define RETSIGTYPE void int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time) { RETSIGTYPE * previous_loc; pid_t host_pid; int status; int fp[2]; int tm; int i; int rc = EAI_FAIL; char ttemp[60]; int wait_host; struct addrinfo *res0; struct addrinfo *res; if (debug_level & 1024) { fprintf(stderr,"Start Host lookup\n"); } busy_cursor(appshell); if (debug_level & 1024) { fprintf(stderr,"Creating pipe\n"); } // Create a pipe for communication if (pipe(fp)!=0) { fprintf(stderr, "Error creating pipe for hostname lookup: %s\n", strerror(errno)); return rc; } host_pid = fork(); // Fork off a child process if (debug_level & 1024) { fprintf(stderr,"Host fork\n"); } if (host_pid!=-1) // If the fork was successful { //--------------------------------------------------------------------------------------- if (host_pid==0) // We're in the child process { // Go back to default signal handler instead of // calling restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So far // this only works for "ps" listings, not for "top". // This code only works on Linux. For BSD use // setproctitle(3), NetBSD can use setprogname(2). #ifdef __linux__ init_set_proc_title(my_argc, my_argv, my_envp); set_proc_title("%s", "hostname lookup (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); #endif // __linux__ // Close the end of the pipe we don't need here if (debug_level & 1024) { fprintf(stderr,"Child closing read end of pipe\n"); } close(fp[0]); // Read end of the pipe if (debug_level & 1024) { fprintf(stderr,"Set alarm \n"); } previous_loc = (RETSIGTYPE *)signal(SIGALRM, host_time_out); // Set up to jump here if we time out on SIGALRM if (sigsetjmp(ret_place,-1)!=0) { // Turn off the alarm (void)alarm(0); // Reset the SIGALRM handler to its previous value (void)signal(SIGALRM, (sighandler_t)previous_loc); // Return net connection time out rc = FAI_TIMEOUT; if (write(fp[1],&rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (debug_level & 1024) { fprintf(stderr,"Child closing write end of pipe\n"); } close(fp[1]); // All done writing to the pipe exit(EXIT_FAILURE); // Exit from child process } (void)alarm(time); // Start the timer // Make the call that may time out if no response from DNS /*hostinfo = gethostbyname2(host,AF_INET); some systems don't have this*/ rc = getaddrinfo(hostname, servname, hints, &res0); // If we get to here, we haven't timed out // and we have an answer to process. // Turn off the alarm (void)alarm(0); // Reset the SIGALRM handler to its previous value (void)signal(SIGALRM, (sighandler_t)previous_loc); if (write(fp[1], &rc, sizeof(int)) == -1) // Send status { // Write error. Do nothing as we did prior // to checking the return value. } for (res = res0; res; res = res->ai_next) { // Signal that an entry is coming. rc = 1; if (write(fp[1], &rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } // Send entry if (write(fp[1], res, sizeof(struct addrinfo)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (write(fp[1], res->ai_addr, res->ai_addrlen) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } } // Signal that there is nothing left rc = 0; if (write(fp[1], &rc, sizeof(int)) == -1) { // Write error. Do nothing as we did prior // to checking the return value. } if (debug_level & 1024) { fprintf(stderr,"Child closing write end of pipe\n"); } freeaddrinfo(res0); close(fp[1]); // All done writing to the pipe exit(EXIT_FAILURE); // Exit from child process } // End of child process //--------------------------------------------------------------------------------------- else { // We're in the parent process at this point // Close the end of the pipe we don't need here if (debug_level & 1024) { fprintf(stderr,"Parent closing write end of pipe\n"); } close(fp[1]); // Write end of the pipe tm=1; wait_host=1; while (wait_host!=-1) { xastir_snprintf(ttemp, sizeof(ttemp), langcode("BBARSTA031"), tm++); statusline(ttemp,1); // Looking up hostname... for (i=0; i < 60 && wait_host!=-1; i++) { wait_host=waitpid(host_pid,&status,WNOHANG); /* update display while waiting */ // XmUpdateDisplay(XtParent(da)); //usleep(500); sched_yield(); } } // Get the return code if (read(fp[0],&rc,sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } if(rc!=0) { close(fp[0]); return rc; } if (read(fp[0], &status, sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } while(status) { *resout = (struct addrinfo*) malloc(sizeof(struct addrinfo)); res = *resout; if (read(fp[0], res, sizeof(struct addrinfo)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } res->ai_addr = (struct sockaddr*) malloc(res->ai_addrlen); if (read(fp[0], res->ai_addr, res->ai_addrlen) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } res->ai_canonname = NULL; resout = &res->ai_next; // See if there is another if (read(fp[0], &status, sizeof(int)) == -1) { // Read error. Do nothing as we did prior // to checking the return value. } } *resout = NULL; if (debug_level & 1024) { fprintf(stderr,"Parent closing read end of pipe\n"); } close(fp[0]); // Close the read end of the pipe } } else // We didn't fork { // Close both ends of the pipe to make // sure we've cleaned up properly close(fp[0]); close(fp[1]); } return rc; } void forked_freeaddrinfo(struct addrinfo *ai) { struct addrinfo *next = ai; struct addrinfo *current = ai; while(next) { current = next; next = current->ai_next; free(current->ai_addr); free(current); } } Xastir-Release-2.2.4/src/forked_getaddrinfo.h0000664000175000017500000000234415151324131020104 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_GETAADDRINFO_H #define __XASTIR_GETAADDRINFO_H int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time); void forked_freeaddrinfo(struct addrinfo *ai); #define FAI_TIMEOUT -55 #endif // __XASTIR_GETAADDRINFO_H Xastir-Release-2.2.4/src/geocoder.c0000664000175000017500000001527515151324131016055 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include "xastir.h" #include "geocoder.h" #ifdef HAVE_NOMINATIM #include "nominatim.h" #endif // Must be last include file #include "leak_detection.h" // Destination marking long destination_coord_lat = 0; long destination_coord_lon = 0; int mark_destination = 0; // Error message storage static char last_error[256] = ""; /** * Initialize the geocoding subsystem */ void geocode_init(void) { #ifdef HAVE_NOMINATIM nominatim_init(); #endif last_error[0] = '\0'; } /** * Search for locations matching the query string */ int geocode_search(geocode_service_t service, const char *query, const char *country_codes, int limit, struct geocode_result_list *results) { int ret = -1; // Validate parameters if (!query || !results) { xastir_snprintf(last_error, sizeof(last_error), "Invalid parameters"); return -1; } if (limit <= 0) { limit = 10; // Default } // Initialize result list results->count = 0; results->capacity = 0; results->results = NULL; // Dispatch to appropriate service switch (service) { #ifdef HAVE_NOMINATIM case GEOCODE_SERVICE_NOMINATIM: ret = nominatim_search(query, country_codes, limit, results); if (ret < 0) { const char *err = nominatim_get_error(); if (err) { xastir_snprintf(last_error, sizeof(last_error), "%s", err); } } break; #endif case GEOCODE_SERVICE_NONE: xastir_snprintf(last_error, sizeof(last_error), "No geocoding service specified"); ret = -1; break; default: xastir_snprintf(last_error, sizeof(last_error), "Geocoding service not available (not compiled in)"); ret = -1; break; } return ret; } /** * Free memory allocated for result list */ void geocode_free_results(struct geocode_result_list *results) { if (results && results->results) { free(results->results); results->results = NULL; results->count = 0; results->capacity = 0; } } /** * Get last error message */ const char *geocode_get_error(void) { if (last_error[0]) { return last_error; } return NULL; } /** * Check if a geocoding service is available */ int geocode_service_available(geocode_service_t service) { switch (service) { #ifdef HAVE_NOMINATIM case GEOCODE_SERVICE_NOMINATIM: return 1; #endif default: return 0; } } /** * Get human-readable name of a geocoding service */ const char *geocode_service_name(geocode_service_t service) { switch (service) { case GEOCODE_SERVICE_NOMINATIM: return "Nominatim (OpenStreetMap)"; case GEOCODE_SERVICE_NONE: return "None"; default: return "Unknown"; } } /** * Build a human-readable subtitle from geocode_result address components * Uses intelligent fallback for missing fields */ void geocode_format_subtitle(const struct geocode_result *result, char *subtitle, size_t size) { char components[256] = ""; int added = 0; if (!result || !subtitle || size == 0) { return; } // Build hierarchy based on what's available // Typical patterns by region: // US: settlement, county, state // UK: settlement, county/state_district, state (England/Scotland/Wales) // Germany: settlement, state // France: settlement, county (département), state (région) // Japan: settlement, state (prefecture) // Add primary settlement if present if (result->settlement[0]) { xastir_snprintf(components, sizeof(components), "%s", result->settlement); added = 1; } // Add county if present and not redundant with settlement if (result->county[0] && (!result->settlement[0] || strcmp(result->county, result->settlement) != 0)) { if (added) { strncat(components, ", ", sizeof(components) - strlen(components) - 1); } strncat(components, result->county, sizeof(components) - strlen(components) - 1); added = 1; } // Add state_district if present (e.g., "Greater London") if (result->state_district[0]) { if (added) { strncat(components, ", ", sizeof(components) - strlen(components) - 1); } strncat(components, result->state_district, sizeof(components) - strlen(components) - 1); added = 1; } // Add state/province if different from previous components if (result->state[0] && (!result->settlement[0] || strcmp(result->state, result->settlement) != 0) && (!result->county[0] || strcmp(result->state, result->county) != 0)) { if (added) { strncat(components, ", ", sizeof(components) - strlen(components) - 1); } strncat(components, result->state, sizeof(components) - strlen(components) - 1); added = 1; } // Always add country if available (unless city-state like Singapore) if (result->country[0] && (!result->settlement[0] || strcmp(result->country, result->settlement) != 0) && (!result->state[0] || strcmp(result->country, result->state) != 0)) { if (added) { strncat(components, ", ", sizeof(components) - strlen(components) - 1); } strncat(components, result->country, sizeof(components) - strlen(components) - 1); } xastir_snprintf(subtitle, size, "%s", components); } Xastir-Release-2.2.4/src/geocoder.h0000664000175000017500000001246615151324131016061 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_GEOCODER_H #define XASTIR_GEOCODER_H // Destination marking extern long destination_coord_lat; extern long destination_coord_lon; extern int mark_destination; /* * Abstract Geocoding API * * This module provides a service-agnostic interface for geocoding operations. * Multiple geocoding services can be added by implementing the service-specific * interface and registering with the dispatcher. * * Initial implementation supports Nominatim (OpenStreetMap). */ // Geocoding service enumeration typedef enum { GEOCODE_SERVICE_NONE = 0, GEOCODE_SERVICE_NOMINATIM = 1, // Future services can be added here } geocode_service_t; // Generic geocoding result (service-agnostic) // Designed to support international addresses with flexible components struct geocode_result { // Core location data double lat; double lon; double bbox[4]; // Bounding box: [min_lat, max_lat, min_lon, max_lon] // Primary identification char display_name[512]; // Full formatted address char service_id[64]; // Service-specific ID (e.g., Nominatim place_id) double relevance; // Service-specific relevance/importance score (0.0-1.0) // Hierarchical address components (international-aware) // Not all fields will be populated for every result char house_number[32]; // Building/house number char road[128]; // Street/road name char neighbourhood[64]; // Neighbourhood/quarter/suburb // Primary settlement (mutually exclusive - only ONE is set by Nominatim) // Could be city, town, village, or hamlet - check place_type if needed char settlement[64]; // Name of primary settlement char county[64]; // County/district char state[64]; // State/province/region char state_district[64]; // State district (e.g., "Greater London") char postcode[32]; // Postal/ZIP code char country[64]; // Country name char country_code[3]; // ISO 3166-1 alpha-2 country code (lowercase) // Administrative hierarchy (for international addresses) char iso3166_2[16]; // ISO3166-2 code (e.g., "GB-ENG", "US-CA") // Place classification char place_type[32]; // Type of place (house, street, city, etc.) char place_class[32]; // OSM class (place, building, amenity, etc.) // Service metadata geocode_service_t service; // Which service provided this result }; // Result list container struct geocode_result_list { int count; int capacity; struct geocode_result *results; }; /* * Public API Functions */ /** * Initialize the geocoding subsystem * Must be called before any other geocoding functions */ void geocode_init(void); /** * Search for locations matching the query string * * @param service Which geocoding service to use * @param query Search query (freeform text) * @param country_codes Optional country filter (e.g., "us,ca"), NULL for no filter * @param limit Maximum number of results to return * @param results Output parameter - will be populated with results * @return Number of results found, or negative error code */ int geocode_search(geocode_service_t service, const char *query, const char *country_codes, int limit, struct geocode_result_list *results); /** * Free memory allocated for result list * * @param results Result list to free */ void geocode_free_results(struct geocode_result_list *results); /** * Get last error message * * @return Error message string, or NULL if no error */ const char *geocode_get_error(void); /** * Check if a geocoding service is available * * @param service Service to check * @return 1 if available, 0 if not compiled in or disabled */ int geocode_service_available(geocode_service_t service); /** * Get human-readable name of a geocoding service * * @param service Service identifier * @return Service name string */ const char *geocode_service_name(geocode_service_t service); /** * Build a human-readable subtitle from geocode_result address components * Uses intelligent fallback for missing fields * * @param result Geocoding result * @param subtitle Output buffer * @param size Size of output buffer */ void geocode_format_subtitle(const struct geocode_result *result, char *subtitle, size_t size); #endif // XASTIR_GEOCODER_H Xastir-Release-2.2.4/src/geocoder_gui.c0000664000175000017500000013056515151324131016721 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include "xastir.h" #include "main.h" #include "lang.h" #include "db_gui.h" #include "mutex_utils.h" #include "geocoder.h" #include "maps.h" #include "util.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" #ifndef HAVE_NOMINATIM // Configuration variables - defined here to avoid linker errors if Nominatim is not compiled in char nominatim_server_url[400]; int nominatim_cache_enabled = 1; int nominatim_cache_days = 30; char nominatim_user_email[100]; char nominatim_country_default[20]; #endif // HAVE_NOMINATIM extern XmFontList fontlist1; // Menu/System fontlist static Atom delw; // Dialog widgets static Widget geocoder_dialog = (Widget)NULL; static Widget query_text = (Widget)NULL; static Widget country_combo = (Widget)NULL; static Widget country_custom_text = (Widget)NULL; static Widget results_list = (Widget)NULL; static Widget status_label = (Widget)NULL; static Widget attribution_label = (Widget)NULL; static Widget goto_button = (Widget)NULL; static Widget mark_button = (Widget)NULL; // Dialog state static xastir_mutex geocoder_dialog_lock; static xastir_mutex geocoder_config_lock; static struct geocode_result_list current_results; // Country code mapping (ISO 3166-1 alpha-2) struct country_option { const char *label; const char *value; }; static const struct country_option country_options[] = { {"None (Worldwide)", ""}, {"Afghanistan", "af"}, {"Albania", "al"}, {"Algeria", "dz"}, {"American Samoa", "as"}, {"Andorra", "ad"}, {"Angola", "ao"}, {"Argentina", "ar"}, {"Armenia", "am"}, {"Australia", "au"}, {"Austria", "at"}, {"Azerbaijan", "az"}, {"Bahamas", "bs"}, {"Bahrain", "bh"}, {"Bangladesh", "bd"}, {"Barbados", "bb"}, {"Belarus", "by"}, {"Belgium", "be"}, {"Belize", "bz"}, {"Bolivia", "bo"}, {"Bosnia and Herzegovina", "ba"}, {"Botswana", "bw"}, {"Brazil", "br"}, {"Brunei", "bn"}, {"Bulgaria", "bg"}, {"Cambodia", "kh"}, {"Cameroon", "cm"}, {"Canada", "ca"}, {"Chile", "cl"}, {"China", "cn"}, {"Colombia", "co"}, {"Costa Rica", "cr"}, {"Croatia", "hr"}, {"Cuba", "cu"}, {"Cyprus", "cy"}, {"Czech Republic", "cz"}, {"Denmark", "dk"}, {"Dominican Republic", "do"}, {"Ecuador", "ec"}, {"Egypt", "eg"}, {"El Salvador", "sv"}, {"Estonia", "ee"}, {"Ethiopia", "et"}, {"Finland", "fi"}, {"France", "fr"}, {"Georgia", "ge"}, {"Germany", "de"}, {"Ghana", "gh"}, {"Greece", "gr"}, {"Greenland", "gl"}, {"Guatemala", "gt"}, {"Haiti", "ht"}, {"Honduras", "hn"}, {"Hong Kong", "hk"}, {"Hungary", "hu"}, {"Iceland", "is"}, {"India", "in"}, {"Indonesia", "id"}, {"Iran", "ir"}, {"Ireland", "ie"}, {"Israel", "il"}, {"Italy", "it"}, {"Jamaica", "jm"}, {"Japan", "jp"}, {"Jordan", "jo"}, {"Kazakhstan", "kz"}, {"Kenya", "ke"}, {"Kuwait", "kw"}, {"Latvia", "lv"}, {"Lebanon", "lb"}, {"Liechtenstein", "li"}, {"Lithuania", "lt"}, {"Luxembourg", "lu"}, {"Malaysia", "my"}, {"Malta", "mt"}, {"Mexico", "mx"}, {"Moldova", "md"}, {"Monaco", "mc"}, {"Mongolia", "mn"}, {"Morocco", "ma"}, {"Namibia", "na"}, {"Netherlands", "nl"}, {"New Zealand", "nz"}, {"Nigeria", "ng"}, {"North Macedonia", "mk"}, {"Norway", "no"}, {"Oman", "om"}, {"Pakistan", "pk"}, {"Panama", "pa"}, {"Paraguay", "py"}, {"Peru", "pe"}, {"Philippines", "ph"}, {"Poland", "pl"}, {"Portugal", "pt"}, {"Qatar", "qa"}, {"Romania", "ro"}, {"Russia", "ru"}, {"Saudi Arabia", "sa"}, {"Serbia", "rs"}, {"Singapore", "sg"}, {"Slovakia", "sk"}, {"Slovenia", "si"}, {"South Africa", "za"}, {"South Korea", "kr"}, {"Spain", "es"}, {"Sri Lanka", "lk"}, {"Sweden", "se"}, {"Switzerland", "ch"}, {"Taiwan", "tw"}, {"Thailand", "th"}, {"Trinidad and Tobago", "tt"}, {"Tunisia", "tn"}, {"Turkey", "tr"}, {"Ukraine", "ua"}, {"United Arab Emirates", "ae"}, {"United Kingdom", "gb"}, {"United States", "us"}, {"Uruguay", "uy"}, {"Venezuela", "ve"}, {"Vietnam", "vn"}, {"Zambia", "zm"}, {"Zimbabwe", "zw"}, {"--- Custom Code ---", "custom"}, {NULL, NULL} }; // Initialize the geocoder GUI module void geocoder_gui_init(void) { init_critical_section(&geocoder_dialog_lock); init_critical_section(&geocoder_config_lock); current_results.results = NULL; current_results.count = 0; current_results.capacity = 0; } // Helper function to populate a country combo box with the standard list // Returns the 1-based index of the default_value if found, or 0 if not found static int populate_country_list(Widget combo, const char *default_value) { XmString str; int i; int default_index = 0; for (i = 0; country_options[i].label != NULL; i++) { str = XmStringCreateLocalized((char *)country_options[i].label); XmListAddItem(combo, str, 0); XmStringFree(str); // Check if this matches the default value if (default_value && default_value[0] != '\0' && strcmp(country_options[i].value, default_value) == 0) { default_index = i + 1; // XmList is 1-indexed } } return default_index; } // Helper function to get the selected country code from a combo box // If custom_text_widget is provided and "custom" is selected, reads from that field // Returns a newly allocated string that must be freed by caller, or NULL if none selected // If return value is non-NULL and *is_custom is non-NULL, sets *is_custom to 1 if custom field was used static char *get_selected_country_code(Widget combo, Widget custom_text_widget, int *is_custom) { XmString *selected_items; int selected_count; char *result = NULL; if (is_custom) { *is_custom = 0; } XtVaGetValues(combo, XmNselectedItems, &selected_items, XmNselectedItemCount, &selected_count, NULL); if (selected_count > 0) { char *selected_text = NULL; XmStringGetLtoR(selected_items[0], XmFONTLIST_DEFAULT_TAG, &selected_text); if (selected_text) { // Find matching option in our array int i; for (i = 0; country_options[i].label != NULL; i++) { if (strcmp(selected_text, country_options[i].label) == 0) { const char *selected_value = country_options[i].value; if (strcmp(selected_value, "custom") == 0) { // Use custom text field if (custom_text_widget) { char *custom = XmTextFieldGetString(custom_text_widget); if (custom && custom[0]) { result = XtNewString(custom); if (is_custom) { *is_custom = 1; } } if (custom) { XtFree(custom); } } } else if (selected_value[0] != '\0') { // Non-empty value - use it result = XtNewString(selected_value); } break; } } XtFree(selected_text); } } return result; } // Free the current geocode search results static void free_current_results(void) { if (current_results.results) { geocode_free_results(¤t_results); current_results.results = NULL; current_results.count = 0; current_results.capacity = 0; } } // Update the status label in the geocoder dialog static void update_status(const char *message) { if (status_label) { XmString str = XmStringCreateLocalized((char *)message); XtVaSetValues(status_label, XmNlabelString, str, NULL); XmStringFree(str); } } // Populate the results list widget with current search results static void populate_results_list(void) { int i; XmString *items; char temp[512]; if (!results_list) return; // Clear existing items XmListDeleteAllItems(results_list); if (current_results.count == 0) { update_status(langcode("GEOCODE011")); // No results found XtSetSensitive(goto_button, False); XtSetSensitive(mark_button, False); return; } // Allocate array for XmStrings items = (XmString *)malloc(sizeof(XmString) * current_results.count); if (!items) { update_status("Out of memory"); return; } // Build list items for (i = 0; i < current_results.count; i++) { struct geocode_result *result = ¤t_results.results[i]; if (result->display_name[0]) { xastir_snprintf(temp, sizeof(temp), "%s", result->display_name); } else { char subtitle[512]; geocode_format_subtitle(result, subtitle, sizeof(subtitle)); xastir_snprintf(temp, sizeof(temp), "%s", subtitle); } items[i] = XmStringCreateLocalized(temp); } // Add items to list XmListAddItems(results_list, items, current_results.count, 0); // Free XmStrings for (i = 0; i < current_results.count; i++) { XmStringFree(items[i]); } free(items); // Update status xastir_snprintf(temp, sizeof(temp), langcode("GEOCODE013"), current_results.count); update_status(temp); // Enable buttons XtSetSensitive(goto_button, True); XtSetSensitive(mark_button, True); } // Callback for the search button, performs geocoding search static void search_callback(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { char *query; char *country_codes = NULL; int result; char error_msg[512]; if (!query_text) return; // Get query text query = XmTextFieldGetString(query_text); if (!query || !query[0]) { update_status(langcode("GEOCODE024")); // Enter a location to search if (query) XtFree(query); return; } // Check if service is available if (!geocode_service_available(GEOCODE_SERVICE_NOMINATIM)) { update_status(langcode("GEOCODE023")); // Service not available XtFree(query); return; } // Get selected country filter using helper function if (country_combo) { country_codes = get_selected_country_code(country_combo, country_custom_text, NULL); } // Clear previous results free_current_results(); // Update status update_status(langcode("GEOCODE010")); // Searching... XmUpdateDisplay(geocoder_dialog); // Perform search result = geocode_search(GEOCODE_SERVICE_NOMINATIM, query, country_codes, 10, // max results ¤t_results); XtFree(query); if (country_codes) { XtFree(country_codes); } if (result < 0) { // Error occurred const char *error = geocode_get_error(); if (error) { xastir_snprintf(error_msg, sizeof(error_msg), langcode("GEOCODE012"), error); } else { xastir_snprintf(error_msg, sizeof(error_msg), langcode("GEOCODE012"), "Unknown error"); } update_status(error_msg); return; } // Display results populate_results_list(); } // Callback for the clear button, clears query and results static void clear_callback(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { if (query_text) { XmTextFieldSetString(query_text, ""); } free_current_results(); if (results_list) { XmListDeleteAllItems(results_list); } update_status(langcode("GEOCODE024")); // Enter a location to search if (goto_button) XtSetSensitive(goto_button, False); if (mark_button) XtSetSensitive(mark_button, False); } // Navigate the map to the specified geocode result location static void goto_location(struct geocode_result *result, int mark_location) { unsigned long coord_lat, coord_lon; convert_to_xastir_coordinates(&coord_lon, &coord_lat, (float)result->lon, (float)result->lat); // If marking, store the coordinates for display mark_destination = mark_location; if (mark_location) { destination_coord_lat = coord_lat; destination_coord_lon = coord_lon; } // Set map position set_map_position(geocoder_dialog, coord_lat, coord_lon); } // Callback for the Go To button, navigates to selected result static void goto_callback(Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { int *position_list; int position_count; if (!results_list || current_results.count == 0) return; // Get selected item(s) if (XmListGetSelectedPos(results_list, &position_list, &position_count)) { if (position_count > 0) { int index = position_list[0] - 1; // XmList is 1-indexed if (index >= 0 && index < current_results.count) { goto_location(¤t_results.results[index], 0); } } XtFree((char *)position_list); } } // Callback for the Mark button, navigates to and marks selected result static void mark_callback(Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { int *position_list; int position_count; if (!results_list || current_results.count == 0) return; // Get selected item(s) if (XmListGetSelectedPos(results_list, &position_list, &position_count)) { if (position_count > 0) { int index = position_list[0] - 1; // XmList is 1-indexed if (index >= 0 && index < current_results.count) { struct geocode_result *result = ¤t_results.results[index]; // Go to the location and mark it goto_location(result, 1); } } XtFree((char *)position_list); } } // Callback for closing the geocoder dialog static void close_callback(Widget widget, XtPointer clientData, XtPointer UNUSED(callData)) { Widget shell = (Widget)clientData; begin_critical_section(&geocoder_dialog_lock, "geocoder_gui.c:close_callback"); free_current_results(); XtPopdown(shell); XtDestroyWidget(shell); geocoder_dialog = (Widget)NULL; end_critical_section(&geocoder_dialog_lock, "geocoder_gui.c:close_callback"); } // Create and display the main geocoder dialog void Geocoder_place(Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { Widget form, label, rowcol; Widget search_button, clear_button, close_button; Arg args[50]; int n; int default_country_index = 0; if (!geocode_service_available(GEOCODE_SERVICE_NOMINATIM)) { popup_message_always(langcode("POPEM00035"), (char *)langcode("GEOCODE023")); // Service not available return; } begin_critical_section(&geocoder_dialog_lock, "geocoder_gui.c:Geocoder_place"); if (geocoder_dialog) { end_critical_section(&geocoder_dialog_lock, "geocoder_gui.c:Geocoder_place"); (void)XRaiseWindow(XtDisplay(geocoder_dialog), XtWindow(geocoder_dialog)); return; } // Create dialog shell geocoder_dialog = XtVaCreatePopupShell(langcode("GEOCODE001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); // Create main form form = XtVaCreateWidget("geocoder_form", xmFormWidgetClass, geocoder_dialog, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Query input section label = XtVaCreateManagedWidget(langcode("GEOCODE002"), // Search Query: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); query_text = XtVaCreateManagedWidget("query_text", xmTextFieldWidgetClass, form, XmNcolumns, 50, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); // Country filter label = XtVaCreateManagedWidget(langcode("GEOCODE003"), // Country Filter: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, query_text, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, query_text); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNleftWidget, label); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNvisibleItemCount, 5); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; country_combo = XmCreateScrolledList(form, "country_combo", args, n); // Populate country filter using helper function default_country_index = populate_country_list(country_combo, nominatim_country_default); // Select configured default or "None" if not set if (default_country_index > 0) { XmListSelectPos(country_combo, default_country_index, False); XmListSetPos(country_combo, default_country_index); } else { XmListSelectPos(country_combo, 1, False); // Select "None" by default XmListSetPos(country_combo, 1); } XtManageChild(country_combo); // Custom country code text field (for entering ISO codes not in list) label = XtVaCreateManagedWidget("Custom Code:", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(country_combo), XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); country_custom_text = XtVaCreateManagedWidget("country_custom_text", xmTextFieldWidgetClass, form, XmNcolumns, 20, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(country_combo), XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // Help text for custom field label = XtVaCreateManagedWidget("(e.g., 'us' or 'us,ca,mx')", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(country_combo), XmNtopOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, country_custom_text, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); // Button row rowcol = XtVaCreateManagedWidget("button_row", xmRowColumnWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNentryAlignment, XmALIGNMENT_CENTER, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, country_custom_text, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); search_button = XtVaCreateManagedWidget(langcode("GEOCODE004"), // Search xmPushButtonWidgetClass, rowcol, XmNfontList, fontlist1, NULL); XtAddCallback(search_button, XmNactivateCallback, search_callback, NULL); clear_button = XtVaCreateManagedWidget(langcode("GEOCODE005"), // Clear xmPushButtonWidgetClass, rowcol, XmNfontList, fontlist1, NULL); XtAddCallback(clear_button, XmNactivateCallback, clear_callback, NULL); // Results section label = XtVaCreateManagedWidget(langcode("GEOCODE006"), // Results: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, rowcol, XmNtopOffset, 15, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, label); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 10); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 10); n++; XtSetArg(args[n], XmNvisibleItemCount, 10); n++; XtSetArg(args[n], XmNselectionPolicy, XmSINGLE_SELECT); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; results_list = XmCreateScrolledList(form, "results_list", args, n); XtManageChild(results_list); // Status label status_label = XtVaCreateManagedWidget("", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(results_list), XmNtopOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); // Set initial status message to prevent layout shift update_status(langcode("GEOCODE024")); // Enter a location to search // Attribution label (OSM credit) attribution_label = XtVaCreateManagedWidget(langcode("GEOCODE014"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, status_label, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); // Action buttons rowcol = XtVaCreateManagedWidget("action_buttons", xmRowColumnWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNentryAlignment, XmALIGNMENT_CENTER, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, attribution_label, XmNtopOffset, 15, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNfontList, fontlist1, NULL); goto_button = XtVaCreateManagedWidget(langcode("GEOCODE007"), // Go To xmPushButtonWidgetClass, rowcol, XmNsensitive, False, XmNfontList, fontlist1, NULL); XtAddCallback(goto_button, XmNactivateCallback, goto_callback, NULL); mark_button = XtVaCreateManagedWidget(langcode("GEOCODE008"), // Mark xmPushButtonWidgetClass, rowcol, XmNsensitive, False, XmNfontList, fontlist1, NULL); XtAddCallback(mark_button, XmNactivateCallback, mark_callback, NULL); close_button = XtVaCreateManagedWidget(langcode("GEOCODE009"), // Close xmPushButtonWidgetClass, rowcol, XmNfontList, fontlist1, NULL); XtAddCallback(close_button, XmNactivateCallback, close_callback, geocoder_dialog); // Set up Enter key in text field to trigger search XtAddCallback(query_text, XmNactivateCallback, search_callback, NULL); pos_dialog(geocoder_dialog); delw = XmInternAtom(XtDisplay(geocoder_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(geocoder_dialog, delw, close_callback, (XtPointer)geocoder_dialog); XtManageChild(form); end_critical_section(&geocoder_dialog_lock, "geocoder_gui.c:Geocoder_place"); XtPopup(geocoder_dialog, XtGrabNone); // Initialize geocoding service geocode_init(); } // Geocoder configuration dialog static Widget geocoder_config_dialog = (Widget)NULL; static Widget config_server_url_text = (Widget)NULL; static Widget config_email_text = (Widget)NULL; static Widget config_country_combo = (Widget)NULL; static Widget config_country_custom_text = (Widget)NULL; // Destroy the geocoder configuration dialog shell static void geocoder_config_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData)) { Widget shell = (Widget)clientData; XtPopdown(shell); begin_critical_section(&geocoder_config_lock, "geocoder_gui.c:geocoder_config_destroy_shell"); XtDestroyWidget(shell); geocoder_config_dialog = (Widget)NULL; end_critical_section(&geocoder_config_lock, "geocoder_gui.c:geocoder_config_destroy_shell"); } // Save the geocoder configuration settings from the dialog static void geocoder_config_save_callback(Widget widget, XtPointer clientData, XtPointer callData) { char *server_url; char *email; char *country_code; // Get server URL (save even if empty to allow clearing) if (config_server_url_text) { server_url = XmTextFieldGetString(config_server_url_text); if (server_url) { if (server_url[0] == '\0') { // User cleared the field - restore default xastir_snprintf(nominatim_server_url, sizeof(nominatim_server_url), "https://nominatim.openstreetmap.org"); } else { xastir_snprintf(nominatim_server_url, sizeof(nominatim_server_url), "%s", server_url); } XtFree(server_url); } } // Get email address (save even if empty to allow clearing) if (config_email_text) { email = XmTextFieldGetString(config_email_text); if (email) { // Empty string is valid - clears the email xastir_snprintf(nominatim_user_email, sizeof(nominatim_user_email), "%s", email); XtFree(email); } } // Get default country using helper function if (config_country_combo) { country_code = get_selected_country_code(config_country_combo, config_country_custom_text, NULL); if (country_code) { xastir_snprintf(nominatim_country_default, sizeof(nominatim_country_default), "%s", country_code); XtFree(country_code); } else { // No country selected - clear the default nominatim_country_default[0] = '\0'; } } // Save configuration save_data(); geocoder_config_destroy_shell(widget, clientData, callData); } // Create and display the geocoder configuration dialog void Configure_geocoder_settings(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData)) { Widget form, label, button_ok, button_cancel, rowcol; Arg args[50]; int n; int default_country_index = 0; begin_critical_section(&geocoder_config_lock, "geocoder_gui.c:Configure_geocoder_settings"); if (geocoder_config_dialog) { end_critical_section(&geocoder_config_lock, "geocoder_gui.c:Configure_geocoder_settings"); (void)XRaiseWindow(XtDisplay(geocoder_config_dialog), XtWindow(geocoder_config_dialog)); return; } // Create dialog shell geocoder_config_dialog = XtVaCreatePopupShell(langcode("GEOCFG001"), // Geocoding Settings xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); // Create main form form = XtVaCreateWidget("geocoder_config_form", xmFormWidgetClass, geocoder_config_dialog, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Server URL section label = XtVaCreateManagedWidget(langcode("GEOCFG002"), // Server URL: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); config_server_url_text = XtVaCreateManagedWidget("config_server_url_text", xmTextFieldWidgetClass, form, XmNcolumns, 50, XmNmaxLength, 399, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); // Set current value XmTextFieldSetString(config_server_url_text, nominatim_server_url); // Email address section label = XtVaCreateManagedWidget(langcode("GEOCFG003"), // Email Address: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, config_server_url_text, XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); config_email_text = XtVaCreateManagedWidget("config_email_text", xmTextFieldWidgetClass, form, XmNcolumns, 40, XmNmaxLength, 99, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, config_server_url_text, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); // Set current value XmTextFieldSetString(config_email_text, nominatim_user_email); // Help text for email label = XtVaCreateManagedWidget(langcode("GEOCFG004"), // (Optional but recommended) xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, config_email_text, XmNtopOffset, 2, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 150, XmNfontList, fontlist1, NULL); // Default country section label = XtVaCreateManagedWidget(langcode("GEOCFG005"), // Default Country: xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label, XmNtopOffset, 15, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, label); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 10); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 10); n++; XtSetArg(args[n], XmNvisibleItemCount, 8); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; config_country_combo = XmCreateScrolledList(form, "config_country_combo", args, n); // Populate country list using helper function default_country_index = populate_country_list(config_country_combo, nominatim_country_default); // Select current default or "None" if not set if (default_country_index > 0) { XmListSelectPos(config_country_combo, default_country_index, False); XmListSetPos(config_country_combo, default_country_index); } else { XmListSelectPos(config_country_combo, 1, False); // Select "None" by default XmListSetPos(config_country_combo, 1); } XtManageChild(config_country_combo); // Custom country code text field (for entering ISO codes not in list) label = XtVaCreateManagedWidget("Custom Code:", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(config_country_combo), XmNtopOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); config_country_custom_text = XtVaCreateManagedWidget("config_country_custom_text", xmTextFieldWidgetClass, form, XmNcolumns, 20, XmNmaxLength, 99, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(config_country_combo), XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // Help text for custom field label = XtVaCreateManagedWidget("(e.g., 'us' or 'us,ca,mx' when Custom selected)", xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(config_country_combo), XmNtopOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, config_country_custom_text, XmNleftOffset, 10, XmNfontList, fontlist1, NULL); // Button row rowcol = XtVaCreateManagedWidget("button_row", xmRowColumnWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNpacking, XmPACK_TIGHT, XmNentryAlignment, XmALIGNMENT_CENTER, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, config_country_custom_text, XmNtopOffset, 15, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), // OK xmPushButtonWidgetClass, rowcol, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, geocoder_config_save_callback, geocoder_config_dialog); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), // Cancel xmPushButtonWidgetClass, rowcol, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, geocoder_config_destroy_shell, geocoder_config_dialog); pos_dialog(geocoder_config_dialog); delw = XmInternAtom(XtDisplay(geocoder_config_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(geocoder_config_dialog, delw, geocoder_config_destroy_shell, (XtPointer)geocoder_config_dialog); XtManageChild(form); end_critical_section(&geocoder_config_lock, "geocoder_gui.c:Configure_geocoder_settings"); XtPopup(geocoder_config_dialog, XtGrabNone); } Xastir-Release-2.2.4/src/globals.h0000664000175000017500000000364715151324131015716 0ustar hibbyhibby /* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* Defines used throughout Xastir, mostly, but not exclusively, in maps. */ #define MAX_FILENAME 2000 #define MAX_CALLSIGN 9 // Objects are up to 9 chars #define MAX_LONG 12 #define MAX_LAT 11 /* Malloc sanity checking macros used in many files */ #define CHECKMALLOC(m) if (!m) { fprintf(stderr, "***** Malloc Failed *****\n"); exit(0); } #define CHECKREALLOC(m) if (!m) { fprintf(stderr, "***** Realloc Failed *****\n"); exit(0); } // Latitude and longitude string formats. #define CONVERT_HP_NORMAL 0 #define CONVERT_HP_NOSP 1 #define CONVERT_LP_NORMAL 2 #define CONVERT_LP_NOSP 3 #define CONVERT_DEC_DEG 4 #define CONVERT_UP_TRK 5 #define CONVERT_DMS_NORMAL 6 #define CONVERT_VHP_NOSP 7 #define CONVERT_DMS_NORMAL_FORMATED 8 #define CONVERT_HP_NORMAL_FORMATED 9 /* Global variables defined in main.c */ extern char my_callsign[MAX_CALLSIGN+1]; extern char my_lat[MAX_LAT]; extern char my_long[MAX_LONG]; Xastir-Release-2.2.4/src/gps.c0000664000175000017500000005624115151324131015055 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include "gps.h" #include "main.h" #include "globals.h" #include "interface.h" #include "db_funcs.h" #include "lang.h" #include "util.h" // Must be last include file #include "leak_detection.h" char gps_gprmc[MAX_GPS_STRING+1]; char gps_gpgga[MAX_GPS_STRING+1]; char gps_sats[4] = ""; char gps_alt[8] = ""; char gps_spd[10] = ""; char gps_sunit[2] = ""; char gps_cse[10] = ""; int gps_valid = 0; // 0=invalid, 1=valid, 2=2D Fix, 3=3D Fix int gps_stop_now; // This function is destructive to its first parameter // // GPRMC,UTC-Time,status(A/V),lat,N/S,lon,E/W,SOG,COG,UTC-Date,Mag-Var,E/W[*CHK] // GPRMC,hhmmss[.sss],{A|V},ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},[dd]d.d[ddddd],[dd]d.d[d],ddmmyy,[ddd.d],[{E|W}][,A|D|E|N|S][*CHK] // // The last field before the checksum is entirely optional, and in // fact first appeared in NMEA 2.3 (fairly recently). Most GPS's do // not currently put out that field. The field may be null or // nonexistent including the comma. Only "A" or "D" are considered // to be active and reliable fixes if this field is present. // Fix-Quality: // A: Autonomous // D: Differential // E: Estimated // N: Not Valid // S: Simulator // // $GPRMC,081836,A,3751.65,S,14507.36,E,000.0,360.0,130998,011.3,E*62 // $GPRMC,104748.821,A,4301.1492,N,08803.0374,W,0.085048,102.36,010605,,*1A // $GPRMC,104749.821,A,4301.1492,N,08803.0377,W,0.054215,74.60,010605,,*2D // int decode_gps_rmc( char *data, char *long_pos, int long_pos_length, char *lat_pos, int lat_pos_length, char *spd, char *unit, int unit_length, char *cse, time_t *stim, int *status) { char *temp_ptr; char *temp_ptr2; char temp_data[MAX_LINE_SIZE+1]; // Big in case we get concatenated packets (it happens!) char sampletime[7]; // We ignore fractional seconds char long_pos_x[11]; char long_ew; char lat_pos_y[10]; char lat_ns; char speed[10]; char speed_unit; char course[8]; char sampledate[7]; #ifdef HAVE_STRPTIME char sampledatime[15]; char *tzp; char tzn[512]; struct tm stm; #endif // HAVE_STRPTIME // We should check for a minimum line length before parsing, // and check for end of input while tokenizing. if ( (data == NULL) || (strlen(data) < 37) ) { return(0); // Not enough data to parse position from. } if (!(isRMC(data))) // No GxRMC found { return(0); } if(strchr(data,',') == NULL) // No comma found { return(0); } (void)strtok(data,","); // get GxRMC and skip it temp_ptr=strtok(NULL,","); // get time if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(sampletime, sizeof(sampletime), "%s", temp_ptr); temp_ptr=strtok(NULL,","); // get fix status if (temp_ptr == NULL) // No comma found { return(0); } if (temp_ptr[0] == 'A') { *status = 1; } else { *status = 0; } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[2] = '\0'; if (temp_data[0] != 'A') // V is a warning but we can get good data still ? { return(0); // Didn't find 'A' in the proper spot } temp_ptr=strtok(NULL,","); // get latitude if (temp_ptr == NULL) { return(0); // Doesn't look like latitude } // Newer GPS'es appear not to zero-fill on the left. Check for // the decimal point in all the possible places. if (temp_ptr[1] != '.' && temp_ptr[2] != '.' && temp_ptr[3] != '.' && temp_ptr[4] != '.') { return(0); // Doesn't look like latitude } // Note: Starlink Invicta shows "lllll.ll" format for latitude in // the GPRMC sentence, which would mean we'd need another term in // the above, and would need to terminate at [10] below (making sure // we extended the field another char as well to handle it). I'm // hoping it was a typo in the Starlink Invicta spec, as latitude // never requires three digits for degrees. xastir_snprintf(lat_pos_y, sizeof(lat_pos_y), "%s", temp_ptr); lat_pos_y[9] = '\0'; // Note that some GPS's put out latitude with extra precision, such as 4801.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(lat_pos_y, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr=strtok(NULL,","); // get N-S if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; lat_ns=toupper((int)temp_data[0]); if(lat_ns != 'N' && lat_ns != 'S') { return(0); // Doesn't look like latitude } temp_ptr=strtok(NULL,","); // get long if (temp_ptr == NULL) { return(0); // Doesn't look like longitude } // Newer GPS'es appear not to zero-fill on the left. Check for // the decimal point in all the possible places. if (temp_ptr[1] != '.' && temp_ptr[2] != '.' && temp_ptr[3] != '.' && temp_ptr[4] != '.' && temp_ptr[5] != '.') { return(0); // Doesn't look like longitude } xastir_snprintf(long_pos_x, sizeof(long_pos_x), "%s", temp_ptr); long_pos_x[10] = '\0'; // Note that some GPS's put out longitude with extra precision, such as 12201.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(long_pos_x, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr=strtok(NULL,","); // get E-W if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; long_ew=toupper((int)temp_data[0]); if (long_ew != 'E' && long_ew != 'W') { return(0); // Doesn't look like longitude } temp_ptr=strtok(NULL,","); // Get speed if (temp_ptr == 0) // No comma found { return(0); } xastir_snprintf(speed, sizeof(speed), "%s", temp_ptr); speed[9] = '\0'; speed_unit='K'; temp_ptr=strtok(NULL,","); // Get course if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(course, sizeof(course), "%s", temp_ptr); course[7] = '\0'; temp_ptr=strtok(NULL,","); // get date of fix if (temp_ptr == NULL) // No comma found { return(0); } xastir_snprintf(sampledate, sizeof(sampledate), "%s", temp_ptr); sampledate[6] = '\0'; // Data is good xastir_snprintf(long_pos, long_pos_length, "%s%c", long_pos_x,long_ew); xastir_snprintf(lat_pos, lat_pos_length, "%s%c", lat_pos_y, lat_ns); xastir_snprintf(spd, 10, "%s", speed); xastir_snprintf(unit, unit_length, "%c", speed_unit); xastir_snprintf(cse, 10, "%s", course); #ifdef HAVE_STRPTIME // Translate date/time into time_t GPS time is in UTC. First, // save existing TZ Then set conversion to UTC, then set back to // existing TZ. tzp=getenv("TZ"); if ( tzp == NULL ) { tzp = ""; } xastir_snprintf(tzn, sizeof(tzn), "TZ=%s", tzp); putenv("TZ=UTC"); tzset(); xastir_snprintf(sampledatime, sizeof(sampledatime), "%s%s", sampledate, sampletime); (void)strptime(sampledatime, "%d%m%y%H%M%S", &stm); *stim=mktime(&stm); putenv(tzn); tzset(); #endif // HAVE_STRPTIME //fprintf(stderr,"Speed %s\n",spd); return(1); } // This function is destructive to its first parameter // // GPGGA,UTC-Time,lat,N/S,long,E/W,GPS-Quality,nsat,HDOP,MSL-Meters,M,Geoidal-Meters,M,DGPS-Data-Age(seconds),DGPS-Ref-Station-ID[*CHK] // GPGGA,hhmmss[.sss],ddmm.mm[mm],{N|S},dddmm.mm[mm],{E|W},{0-8},dd,[d]d.d,[-dddd]d.d,M,[-ddd]d.d,M,[dddd.d],[dddd][*CHK] // // GPS-Quality: // 0: Invalid Fix // 1: GPS Fix // 2: DGPS Fix // 3: PPS Fix // 4: RTK Fix // 5: Float RTK Fix // 6: Estimated (dead-reckoning) Fix // 7: Manual Input Mode // 8: Simulation Mode // // $GPGGA,170834,4124.8963,N,08151.6838,W,1,05,1.5,280.2,M,-34.0,M,,,*75 // $GPGGA,104438.833,4301.1439,N,08803.0338,W,1,05,1.8,185.8,M,-34.2,M,0.0,0000*40 // NOTE: while the above specifically refers to $GP strings for the GPS // receivers, there are others such as GNSS, GLONASS, Beidou, and Gallileo // that differ only in the third character. We support those, too. // int decode_gps_gga( char *data, char *long_pos, int long_pos_length, char *lat_pos, int lat_pos_length, char *sats, char *alt, char *aunit, int *status ) { char *temp_ptr; char *temp_ptr2; char temp_data[MAX_LINE_SIZE+1]; // Big in case we get concatenated packets (it happens!) char long_pos_x[11]; char long_ew; char lat_pos_y[10]; char lat_ns; char sats_visible[4]; char altitude[8]; char alt_unit; // We should check for a minimum line length before parsing, // and check for end of input while tokenizing. if ( (data == NULL) || (strlen(data) < 35) ) // Not enough data to parse position from. { return(0); } if (!(isGGA(data))) { return(0); } if (strchr(data,',') == NULL) { return(0); } if (strtok(data,",") == NULL) // get GPGGA and skip it { return(0); } if(strtok(NULL,",") == NULL) // get time and skip it { return(0); } temp_ptr = strtok(NULL,","); // get latitude if (temp_ptr == NULL) { return(0); } xastir_snprintf(lat_pos_y, sizeof(lat_pos_y), "%s", temp_ptr); lat_pos_y[9] = '\0'; // Note that some GPS's put out latitude with extra precision, such as 4801.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(lat_pos_y, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr = strtok(NULL,","); // get N-S if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; lat_ns=toupper((int)temp_data[0]); if(lat_ns != 'N' && lat_ns != 'S') { return(0); } temp_ptr = strtok(NULL,","); // get long if(temp_ptr == NULL) { return(0); } xastir_snprintf(long_pos_x, sizeof(long_pos_x), "%s", temp_ptr); long_pos_x[10] = '\0'; // Note that some GPS's put out longitude with extra precision, such as 12201.1234 // Check for comma char, replace with '\0' temp_ptr2 = strstr(long_pos_x, ","); if (temp_ptr2) { temp_ptr2[0] = '\0'; } temp_ptr = strtok(NULL,","); // get E-W if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; long_ew=toupper((int)temp_data[0]); if (long_ew != 'E' && long_ew != 'W') { return(0); } temp_ptr = strtok(NULL,","); // get FIX Quality if (temp_ptr == NULL) { return(0); } xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; // '0' = bad fix, positive numbers = ok if(temp_data[0] == '0') { return(0); } // Save the fix quality in "status" *status = atoi(temp_data); temp_ptr=strtok(NULL,","); // Get sats vis if (temp_ptr == NULL) { return(0); } xastir_snprintf(sats_visible, sizeof(sats_visible), "%s", temp_ptr); sats_visible[2] = '\0'; temp_ptr=strtok(NULL,","); // get hoz dil if (temp_ptr == NULL) { return(0); } temp_ptr=strtok(NULL,","); // Get altitude if (temp_ptr == NULL) { return(0); } // Get altitude xastir_snprintf(altitude, sizeof(altitude), "%s", temp_ptr); altitude[7] = '\0'; temp_ptr=strtok(NULL,","); // get UNIT if (temp_ptr == NULL) { return(0); } // get UNIT xastir_snprintf(temp_data, sizeof(temp_data), "%s", temp_ptr); temp_data[1] = '\0'; alt_unit=temp_data[0]; // Data is good xastir_snprintf(long_pos, long_pos_length, "%s%c", long_pos_x, long_ew); xastir_snprintf(lat_pos, lat_pos_length, "%s%c", lat_pos_y, lat_ns); xastir_snprintf(sats, 4, "%s", sats_visible); xastir_snprintf(alt, 8, "%s", altitude); xastir_snprintf(aunit, 2, "%c", alt_unit); return(1); } // // Note that the length of "gps_line_data" can be up to // MAX_DEVICE_BUFFER, which is currently set to 4096. // int gps_data_find(char *gps_line_data, int port) { char long_pos[20],lat_pos[20],aunit[2]; time_t t; char temp_str[MAX_GPS_STRING+1]; int have_valid_string = 0; #ifndef __CYGWIN__ struct timeval tv; struct timezone tz; #endif // __CYGWIN__ if (isRMC(gps_line_data)) { if (debug_level & 128) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", gps_line_data); makePrintable(filtered_data); fprintf(stderr,"Got RMC %s\n", filtered_data); } if (debug_level & 128) { // Got GPS RMC String statusline(langcode("BBARSTA015"),0); } xastir_snprintf(gps_gprmc, sizeof(gps_gprmc), "%s", gps_line_data); xastir_snprintf(temp_str, sizeof(temp_str), "%s", gps_gprmc); // decode_gps_rmc is destructive to its first parameter if (decode_gps_rmc( temp_str, long_pos, sizeof(long_pos), lat_pos, sizeof(lat_pos), gps_spd, gps_sunit, sizeof(gps_sunit), gps_cse, &t, &gps_valid ) == 1) // mod station data { // got GPS data have_valid_string++; if (debug_level & 128) fprintf(stderr,"RMC <%s> <%s><%s> %c <%s>\n", long_pos,lat_pos,gps_spd,gps_sunit[0],gps_cse); if (debug_level & 128) { fprintf(stderr,"Checking for Time Set on %d (%d)\n", port, devices[port].set_time); } // Don't set the time if it's a Cygwin system. Causes problems with // date, plus time can be an hour off if daylight savings time is // enabled on Windows. // #ifndef __CYGWIN__ if (devices[port].set_time) { tv.tv_sec=t; tv.tv_usec=0; tz.tz_minuteswest=0; tz.tz_dsttime=0; if (debug_level & 128) { fprintf(stderr,"Setting Time %ld EUID: %d, RUID: %d\n", (long)t, (int)getuid(), (int)getuid()); } #ifdef HAVE_SETTIMEOFDAY ENABLE_SETUID_PRIVILEGE; settimeofday(&tv, &tz); DISABLE_SETUID_PRIVILEGE; #endif // HAVE_SETTIMEOFDAY } #endif // __CYGWIN__ } } else { if (debug_level & 128) { int i; fprintf(stderr,"Not $GxRMC: "); for (i = 0; i<7; i++) { fprintf(stderr,"%c", gps_line_data[i]); } fprintf(stderr,"\n"); } } if (isGGA(gps_line_data)) { if (debug_level & 128) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", gps_line_data); makePrintable(filtered_data); fprintf(stderr,"Got GGA %s\n", filtered_data); } if (debug_level & 128) { // Got GPS GGA String statusline(langcode("BBARSTA016"),0); } xastir_snprintf(gps_gpgga, sizeof(gps_gpgga), "%s", gps_line_data); xastir_snprintf(temp_str, sizeof(temp_str), "%s", gps_gpgga); // decode_gps_gga is destructive to its first parameter if ( decode_gps_gga( temp_str, long_pos, sizeof(long_pos), lat_pos, sizeof(lat_pos), gps_sats, gps_alt, aunit, &gps_valid ) == 1) // mod station data { // got GPS data have_valid_string++; if (debug_level & 128) fprintf(stderr,"GGA <%s> <%s> <%s> <%s> %c\n", long_pos,lat_pos,gps_sats,gps_alt,aunit[0]); } } else { if (debug_level & 128) { int i; fprintf(stderr,"Not $GPGGA: "); for (i = 0; i<7; i++) { fprintf(stderr,"%c",gps_line_data[i]); } fprintf(stderr,"\n"); } } if (have_valid_string) { if (debug_level & 128) { statusline(langcode("BBARSTA037"),0); } // Go update my screen position my_station_gps_change(long_pos,lat_pos,gps_cse,gps_spd, gps_sunit[0],gps_alt,gps_sats); // gps_stop_now is how we tell main.c that we've got a valid GPS string. // Only useful for HSP mode? if (!gps_stop_now) { gps_stop_now=1; } // If HSP port, shutdown gps for timed interval if (port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { // return dtr to normal port_dtr(port,0); } } return(have_valid_string); } static char checksum[3]; // Function to compute checksums for NMEA sentences // // Input: "$............*" // Output: Two character string containing the checksum // // Checksum is computed from the '$' to the '*', but not including // these two characters. It is an 8-bit Xor of the characters // specified, encoded in hexadecimal format. // char *nmea_checksum(char *nmea_sentence) { int i; int sum = 0; int right; int left; char convert[17] = "0123456789ABCDEF"; for (i = 1; i < ((int)strlen(nmea_sentence) - 1); i++) { sum = sum ^ nmea_sentence[i]; } right = sum % 16; left = (sum / 16) % 16; xastir_snprintf(checksum, sizeof(checksum), "%c%c", convert[left], convert[right]); return(checksum); } // Function which will send an NMEA sentence to a Garmin GPS which // will create a waypoint if the Garmin is set to NMEA-in/NMEA-out // mode. The sentence looks like this: // // $GPWPL,4807.038,N,01131.000,E,WPTNME*31 // // $GPWPL,4849.65,N,06428.53,W,0001*54 // $GPWPL,4849.70,N,06428.50,W,0002*50 // // 4807.038,N Latitude // 01131.000,E Longitude // WPTNME Waypoint Name (stick to 6 chars for compatibility?) // *31 Checksum, always begins with '*' // // // Future implementation ideas: // // Create linked list of waypoints/location. // Use the list to prevent multiple writes of the same waypoint if // nothing has changed. // // Use the list to check distance of previously-written waypoints. // If we're out of range, delete the waypoint and remove it from the // list. // // Perhaps write the list to disk also. As we shut down, delete the // waypoints (self-cleaning). As we come up, load them in again? // We could also just continue cleaning out waypoints that are // out-of-range since the last time we ran the program. That's // probably a better solution. // void create_garmin_waypoint(long latitude,long longitude,char *call_sign) { char short_callsign[10]; char lat_string[15]; char long_string[15]; char lat_char; char long_char; int i,j,len; char out_string[80]; char out_string2[80]; convert_lat_l2s(latitude, lat_string, sizeof(lat_string), CONVERT_HP_NOSP); lat_char = lat_string[strlen(lat_string) - 1]; lat_string[strlen(lat_string) - 1] = '\0'; convert_lon_l2s(longitude, long_string, sizeof(long_string), CONVERT_HP_NOSP); long_char = long_string[strlen(long_string) - 1]; long_string[strlen(long_string) - 1] = '\0'; len = strlen(call_sign); if (len > 9) { len = 9; } j = 0; for (i = 0; i <= len; i++) // Copy the '\0' as well { if (call_sign[i] != '-') // We don't want the dash { short_callsign[j++] = call_sign[i]; } } short_callsign[6] = '\0'; // Truncate at 6 chars // Convert to upper case. Garmin's don't seem to like lower // case waypoint names to_upper(short_callsign); //fprintf(stderr,"Creating waypoint for %s:%s\n",call_sign,short_callsign); xastir_snprintf(out_string, sizeof(out_string), "$GPWPL,%s,%c,%s,%c,%s*", lat_string, lat_char, long_string, long_char, short_callsign); nmea_checksum(out_string); strncpy(out_string2, out_string, sizeof(out_string2)); out_string2[sizeof(out_string2)-1] = '\0'; // Terminate string strcat(out_string2, checksum); output_waypoint_data(out_string2); //fprintf(stderr,"%s\n",out_string2); } // Test if this is a GGA string, irrespective of what talker produced // it. This should allow us to support GPS, GLONASS, Gallileo, // Beidou, or GNSS receivers, and multi-constellation receivers ($GP, // $GN, etc.), but also other talkers like Integrated Instrumentation // ($II). int isGGA(char *gps_line_data) { int retval; retval = (strncmp(gps_line_data,"$",1)==0); retval = retval && ((strlen(gps_line_data)>7) && strncmp(&(gps_line_data[3]),"GGA,",4)==0); return (retval); } // Test if this is an RMC string. See comments for isGGA. int isRMC(char *gps_line_data) { int retval; retval = (strncmp(gps_line_data,"$",1)==0); retval = retval && ((strlen(gps_line_data)>7) && strncmp(&(gps_line_data[3]),"RMC,",4)==0); return (retval); } Xastir-Release-2.2.4/src/gps.h0000664000175000017500000000250515151324131015054 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_GPS_H #define __XASTIR_GPS_H #include "xastir.h" #define MAX_GPS_STRING 300 extern char gps_sats[4]; extern int gps_valid; extern int gps_stop_now; extern int gps_data_find(char *gps_line_data, int port); extern void create_garmin_waypoint(long latitude,long longitude,char *call_sign); int isGGA(char *gps_line_data); int isRMC(char *gps_line_data); #endif // __XASTIR_GPS_H Xastir-Release-2.2.4/src/hashtable.c0000664000175000017500000002020415151324131016205 0ustar hibbyhibby /* Copyright (C) 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2026 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "hashtable.h" #include "hashtable_private.h" // Must be last include file #include "leak_detection.h" /* defines GC_MALLOC/GC_FREE */ /* Credit for primes table: Aaron Krowne http://br.endernet.org/~akrowne/ http://planetmath.org/encyclopedia/GoodHashTablePrimes.html */ static const unsigned int primes[] = { 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); const float max_load_factor = 0.65; /*****************************************************************************/ struct hashtable * create_hashtable(unsigned int minsize, unsigned int (*hashf) (void*), int (*eqf) (void*,void*)) { struct hashtable *h; unsigned int pindex, size = primes[0]; /* Check requested hashtable isn't too large */ if (minsize > (1u << 30)) { return NULL; } /* Enforce size as prime */ for (pindex=0; pindex < prime_table_length; pindex++) { if (primes[pindex] > minsize) { size = primes[pindex]; break; } } h = (struct hashtable *)malloc(sizeof(struct hashtable)); if (NULL == h) { return NULL; /*oom*/ } h->table = (struct entry **)malloc(sizeof(struct entry*) * size); if (NULL == h->table) { free(h); /*oom*/ return NULL; } memset(h->table, 0, size * sizeof(struct entry *)); h->tablelength = size; h->primeindex = pindex; h->entrycount = 0; h->hashfn = hashf; h->eqfn = eqf; h->loadlimit = ceil(size * max_load_factor); return h; } /*****************************************************************************/ unsigned int hash(struct hashtable *h, void *k) { /* Aim to protect against poor hash functions by adding logic here * - logic taken from java 1.4 hashtable source */ unsigned int i = h->hashfn(k); i += ~(i << 9); i ^= ((i >> 14) | (i << 18)); /* >>> */ i += (i << 4); i ^= ((i >> 10) | (i << 22)); /* >>> */ return i; } /*****************************************************************************/ static int hashtable_expand(struct hashtable *h) { /* Double the size of the table to accommodate more entries */ struct entry **newtable; struct entry *e; struct entry **pE; unsigned int newsize, i, index; /* Check we're not hitting max capacity */ if (h->primeindex == (prime_table_length - 1)) { return 0; } newsize = primes[++(h->primeindex)]; newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize); if (NULL != newtable) { memset(newtable, 0, newsize * sizeof(struct entry *)); /* This algorithm is not 'stable'. ie. it reverses the list * when it transfers entries between the tables */ for (i = 0; i < h->tablelength; i++) { while (NULL != (e = h->table[i])) { h->table[i] = e->next; index = indexFor(newsize,e->h); e->next = newtable[index]; newtable[index] = e; } } free(h->table); h->table = newtable; } /* Plan B: realloc instead */ else { newtable = (struct entry **) realloc(h->table, newsize * sizeof(struct entry *)); if (NULL == newtable) { (h->primeindex)--; return 0; } h->table = newtable; memset(newtable[h->tablelength], 0, newsize - h->tablelength); for (i = 0; i < h->tablelength; i++) { for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { index = indexFor(newsize,e->h); if (index == i) { pE = &(e->next); } else { *pE = e->next; e->next = newtable[index]; newtable[index] = e; } } } } h->tablelength = newsize; h->loadlimit = ceil(newsize * max_load_factor); return -1; } /*****************************************************************************/ unsigned int hashtable_count(struct hashtable *h) { return h->entrycount; } /*****************************************************************************/ int hashtable_insert(struct hashtable *h, void *k, void *v) { /* This method allows duplicate keys - but they shouldn't be used */ unsigned int index; struct entry *e; if (++(h->entrycount) > h->loadlimit) { /* Ignore the return value. If expand fails, we should * still try cramming just this value into the existing table * -- we may not have memory for a larger table, but one more * element may be ok. Next time we insert, we'll try expanding again.*/ hashtable_expand(h); } e = (struct entry *)malloc(sizeof(struct entry)); if (NULL == e) { --(h->entrycount); /*oom*/ return 0; } e->h = hash(h,k); index = indexFor(h->tablelength,e->h); e->k = k; e->v = v; e->next = h->table[index]; h->table[index] = e; return -1; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_search(struct hashtable *h, void *k) { struct entry *e; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { return e->v; } e = e->next; } return NULL; } /*****************************************************************************/ void * /* returns value associated with key */ hashtable_remove(struct hashtable *h, void *k) { /* TODO: consider compacting the table when the load factor drops enough, * or provide a 'compact' method. */ struct entry *e; struct entry **pE; void *v; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hash(h,k)); pE = &(h->table[index]); e = *pE; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { *pE = e->next; h->entrycount--; v = e->v; freekey(e->k); free(e); return v; } pE = &(e->next); e = e->next; } return NULL; } /*****************************************************************************/ /* destroy */ void hashtable_destroy(struct hashtable *h, int free_values) { unsigned int i; struct entry *e, *f; struct entry **table = h->table; if (free_values) { for (i = 0; i < h->tablelength; i++) { e = table[i]; while (NULL != e) { f = e; e = e->next; freekey(f->k); free(f->v); free(f); } } } else { for (i = 0; i < h->tablelength; i++) { e = table[i]; while (NULL != e) { f = e; e = e->next; freekey(f->k); free(f); } } } free(h->table); free(h); } /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.4/src/hashtable.h0000664000175000017500000001530715151324131016222 0ustar hibbyhibby /* Copyright (C) 2002 Christopher Clark */ // Portions Copyright (C) 2000-2026 The Xastir Group #ifndef __HASHTABLE_CWC22_H__ #define __HASHTABLE_CWC22_H__ struct hashtable; /* Example of use: * * struct hashtable *h; * struct some_key *k; * struct some_value *v; * * static unsigned int hash_from_key_fn( void *k ); * static int keys_equal_fn ( void *key1, void *key2 ); * * h = create_hashtable(16, hash_from_key_fn, keys_equal_fn); * k = (struct some_key *) malloc(sizeof(struct some_key)); * v = (struct some_value *) malloc(sizeof(struct some_value)); * * (initialise k and v to suitable values) * * if (! hashtable_insert(h,k,v) ) * { exit(-1); } * * if (NULL == (found = hashtable_search(h,k) )) * { printf("not found!"); } * * if (NULL == (found = hashtable_remove(h,k) )) * { printf("Not found\n"); } * */ /* Macros may be used to define type-safe(r) hashtable access functions, with * methods specialized to take known key and value types as parameters. * * Example: * * Insert this at the start of your file: * * DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value); * DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value); * * This defines the functions 'insert_some', 'search_some' and 'remove_some'. * These operate just like hashtable_insert etc., with the same parameters, * but their function signatures have 'struct some_key *' rather than * 'void *', and hence can generate compile time errors if your program is * supplying incorrect data as a key (and similarly for value). * * Note that the hash and key equality functions passed to create_hashtable * still take 'void *' parameters instead of 'some key *'. This shouldn't be * a difficult issue as they're only defined and passed once, and the other * functions will ensure that only valid keys are supplied to them. * * The cost for this checking is increased code size and runtime overhead * - if performance is important, it may be worth switching back to the * unsafe methods once your program has been debugged with the safe methods. * This just requires switching to some simple alternative defines - eg: * #define insert_some hashtable_insert * */ /***************************************************************************** * create_hashtable * @name create_hashtable * @param minsize minimum initial size of hashtable * @param hashfunction function for hashing keys * @param key_eq_fn function for determining key equality * @return newly created hashtable or NULL on failure */ struct hashtable * create_hashtable(unsigned int minsize, unsigned int (*hashfunction) (void*), int (*key_eq_fn) (void*,void*)); /***************************************************************************** * hashtable_insert * @name hashtable_insert * @param h the hashtable to insert into * @param k the key - hashtable claims ownership and will free on removal * @param v the value - does not claim ownership * @return non-zero for successful insertion * * This function will cause the table to expand if the insertion would take * the ratio of entries to table size over the maximum load factor. * * This function does not check for repeated insertions with a duplicate key. * The value returned when using a duplicate key is undefined -- when * the hashtable changes size, the order of retrieval of duplicate key * entries is reversed. * If in doubt, remove before insert. */ int hashtable_insert(struct hashtable *h, void *k, void *v); #define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \ int fnname (struct hashtable *h, keytype *k, valuetype *v) \ { \ return hashtable_insert(h,k,v); \ } /***************************************************************************** * hashtable_search * @name hashtable_search * @param h the hashtable to search * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * hashtable_search(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_search(h,k)); \ } /***************************************************************************** * hashtable_remove * @name hashtable_remove * @param h the hashtable to remove the item from * @param k the key to search for - does not claim ownership * @return the value associated with the key, or NULL if none found */ void * /* returns value */ hashtable_remove(struct hashtable *h, void *k); #define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \ valuetype * fnname (struct hashtable *h, keytype *k) \ { \ return (valuetype *) (hashtable_remove(h,k)); \ } /***************************************************************************** * hashtable_count * @name hashtable_count * @param h the hashtable * @return the number of items stored in the hashtable */ unsigned int hashtable_count(struct hashtable *h); /***************************************************************************** * hashtable_destroy * @name hashtable_destroy * @param h the hashtable * @param free_values whether to call 'free' on the remaining values */ void hashtable_destroy(struct hashtable *h, int free_values); #endif /* __HASHTABLE_CWC22_H__ */ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.4/src/hashtable_itr.c0000664000175000017500000001254215151324131017071 0ustar hibbyhibby /* Copyright (C) 2002, 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2026 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include /* defines NULL */ #include //#include //#include #include "hashtable.h" #include "hashtable_private.h" #include "hashtable_itr.h" // Must be last include file #include "leak_detection.h" /* defines GC_MALLOC/GC_FREE */ /*****************************************************************************/ /* hashtable_iterator - iterator constructor */ struct hashtable_itr * hashtable_iterator(struct hashtable *h) { unsigned int i, tablelength; struct hashtable_itr *itr = (struct hashtable_itr *) malloc(sizeof(struct hashtable_itr)); if (NULL == itr) { return NULL; } itr->h = h; itr->e = NULL; itr->parent = NULL; tablelength = h->tablelength; itr->index = tablelength; if (0 == h->entrycount) { return itr; } for (i = 0; i < tablelength; i++) { if (NULL != h->table[i]) { itr->e = h->table[i]; itr->index = i; break; } } return itr; } /*****************************************************************************/ /* key - return the key of the (key,value) pair at the current position */ /* value - return the value of the (key,value) pair at the current position */ void * hashtable_iterator_key(struct hashtable_itr *i) { if (!i) { return NULL; } if (i->e) { return i->e->k; } else { return NULL; } } void * hashtable_iterator_value(struct hashtable_itr *i) { if (!i) { return NULL; } if (i->e) { return i->e->v; } else { return NULL; } } /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr) { unsigned int j,tablelength; struct entry **table; struct entry *next; if (NULL == itr->e) { return 0; /* stupidity check */ } next = itr->e->next; if (NULL != next) { itr->parent = itr->e; itr->e = next; return -1; } tablelength = itr->h->tablelength; itr->parent = NULL; if (tablelength <= (j = ++(itr->index))) { itr->e = NULL; return 0; } table = itr->h->table; while (NULL == (next = table[j])) { if (++j >= tablelength) { itr->index = tablelength; itr->e = NULL; return 0; } } itr->index = j; itr->e = next; return -1; } /*****************************************************************************/ /* remove - remove the entry at the current iterator position * and advance the iterator, if there is a successive * element. * If you want the value, read it before you remove: * beware memory leaks if you don't. * Returns zero if end of iteration. */ int hashtable_iterator_remove(struct hashtable_itr *itr) { struct entry *remember_e, *remember_parent; int ret; /* Do the removal */ if (NULL == (itr->parent)) { /* element is head of a chain */ itr->h->table[itr->index] = itr->e->next; } else { /* element is mid-chain */ itr->parent->next = itr->e->next; } /* itr->e is now outside the hashtable */ remember_e = itr->e; itr->h->entrycount--; freekey(remember_e->k); /* Advance the iterator, correcting the parent */ remember_parent = itr->parent; ret = hashtable_iterator_advance(itr); if (itr->parent == remember_e) { itr->parent = remember_parent; } free(remember_e); return ret; } /*****************************************************************************/ int /* returns zero if not found */ hashtable_iterator_search(struct hashtable_itr *itr, struct hashtable *h, void *k) { struct entry *e, *parent; unsigned int hashvalue, index; hashvalue = hash(h,k); index = indexFor(h->tablelength,hashvalue); e = h->table[index]; parent = NULL; while (NULL != e) { /* Check hash value to short circuit heavier comparison */ if ((hashvalue == e->h) && (h->eqfn(k, e->k))) { itr->index = index; itr->e = e; itr->parent = parent; itr->h = h; return -1; } parent = e; e = e->next; } return 0; } /* * Copyright (C) 2002, 2004 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.4/src/hashtable_itr.h0000664000175000017500000001065515151324131017101 0ustar hibbyhibby /* Copyright (C) 2002, 2004 Christopher Clark */ // Portions Copyright (C) 2000-2026 The Xastir Group #ifndef __HASHTABLE_ITR_CWC22__ #define __HASHTABLE_ITR_CWC22__ #include "hashtable.h" #include "hashtable_private.h" /* needed to enable inlining */ /*****************************************************************************/ /* This struct is only concrete here to allow the inlining of two of the * accessor functions. */ struct hashtable_itr { struct hashtable *h; struct entry *e; struct entry *parent; unsigned int index; }; /*****************************************************************************/ /* hashtable_iterator */ struct hashtable_itr * hashtable_iterator(struct hashtable *h); #if 0 // BZZZZT! it is very, very wrong to be inlining this this way. // If one calls hashtable_iterator on a hash table from which everything // has been deleted, the iterator has a null for i->e. // It is not good to require the caller to check the internals of the iterator // structure just to be sure there are no null pointers inside. // For whatever reason, these are defined again in the hashtable_iterator.c // file, not inlined. I have modified the ones in hashtable_iterator so they // actually check for nulls and don't try to dereference them. /*****************************************************************************/ /* hashtable_iterator_key * - return the value of the (key,value) pair at the current position */ extern inline void * hashtable_iterator_key(struct hashtable_itr *i) { return i->e->k; } /*****************************************************************************/ /* value - return the value of the (key,value) pair at the current position */ extern inline void * hashtable_iterator_value(struct hashtable_itr *i) { return i->e->v; } #else // SO instead of inlining, just declare. No need to be "extern" // The ones in the .c file check their arguments and return nulls if they // can't comply with the request. Much nicer for the calling routine to // check a return value than to monkey with the internals of the struct. void * hashtable_iterator_key(struct hashtable_itr *i); void * hashtable_iterator_value(struct hashtable_itr *i); #endif /*****************************************************************************/ /* advance - advance the iterator to the next element * returns zero if advanced to end of table */ int hashtable_iterator_advance(struct hashtable_itr *itr); /*****************************************************************************/ /* remove - remove current element and advance the iterator to the next element * NB: if you need the value to free it, read it before * removing. ie: beware memory leaks! * returns zero if advanced to end of table */ int hashtable_iterator_remove(struct hashtable_itr *itr); /*****************************************************************************/ /* search - overwrite the supplied iterator, to point to the entry * matching the supplied key. h points to the hashtable to be searched. * returns zero if not found. */ int hashtable_iterator_search(struct hashtable_itr *itr, struct hashtable *h, void *k); #define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \ int fnname (struct hashtable_itr *i, struct hashtable *h, keytype *k) \ { \ return (hashtable_iterator_search(i,h,k)); \ } #endif /* __HASHTABLE_ITR_CWC22__*/ /* * Copyright (C) 2002, 2004 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.4/src/hashtable_private.h0000664000175000017500000000456015151324131017753 0ustar hibbyhibby /* Copyright (C) 2002, 2004 Christopher Clark */ /* Portions Copyright (C) 2000-2026 The Xastir Group */ #ifndef __HASHTABLE_PRIVATE_CWC22_H__ #define __HASHTABLE_PRIVATE_CWC22_H__ #include "hashtable.h" /*****************************************************************************/ struct entry { void *k, *v; unsigned int h; struct entry *next; }; struct hashtable { unsigned int tablelength; struct entry **table; unsigned int entrycount; unsigned int loadlimit; unsigned int primeindex; unsigned int (*hashfn) (void *k); int (*eqfn) (void *k1, void *k2); }; /*****************************************************************************/ unsigned int hash(struct hashtable *h, void *k); /*****************************************************************************/ /* indexFor */ static inline unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { return (hashvalue % tablelength); } /* Only works if tablelength == 2^N */ /*static inline unsigned int indexFor(unsigned int tablelength, unsigned int hashvalue) { return (hashvalue & (tablelength - 1u)); } */ /*****************************************************************************/ #define freekey(X) free(X) /*define freekey(X) ; */ /*****************************************************************************/ #endif /* __HASHTABLE_PRIVATE_CWC22_H__*/ /* * Copyright (C) 2002 Christopher Clark * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ Xastir-Release-2.2.4/src/icon.xbm0000664000175000017500000000246615151324131015560 0ustar hibbyhibby#define icon_width 40 #define icon_height 40 static unsigned char icon_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x80, 0x10, 0x02, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x1f, 0x00, 0x00, 0x20, 0x20, 0x10, 0x00, 0x00, 0x10, 0x20, 0x10, 0x00, 0x00, 0x08, 0x20, 0x20, 0x00, 0x00, 0x04, 0x20, 0x20, 0x00, 0x00, 0x02, 0x28, 0x60, 0x00, 0x00, 0x27, 0x28, 0x60, 0xfc, 0xff, 0x3f, 0x28, 0x60, 0xfe, 0xff, 0x3f, 0xe8, 0x7f, 0xfe, 0xff, 0x27, 0xef, 0x7f, 0xfe, 0xff, 0x07, 0xef, 0x7f, 0xfe, 0xff, 0x07, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x0f, 0x00, 0xfc, 0x0f, 0xfc, 0x0f, 0x00, 0xfc, 0x0f, 0xf8, 0x07, 0x00, 0xf8, 0x07, 0xf0, 0x03, 0x00, 0xf0, 0x03, 0xe0, 0x01, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; Xastir-Release-2.2.4/src/igate.c0000664000175000017500000012721615151324131015356 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "igate.h" #include "main.h" #include "db_funcs.h" #include "interface.h" #include "xa_config.h" #include "util.h" #include "log_utils.h" // Must be last include file #include "leak_detection.h" time_t last_nws_stations_file_time = 0; int NWS_stations = 0; int max_NWS_stations = 0; NWS_Data *NWS_station_data; void load_NWS_stations(char *file); int check_NWS_stations(char *call); // Struct for holding packet data. We use dynamically-allocated // singly-linked lists. The last record should have its "next" // pointer set to NULL. // typedef struct _DupeRecord { char data[MAX_LINE_SIZE+15]; // Packet data time_t time; // The time the record was inserted struct _DupeRecord *next; // pointer to next record in list } DupeRecord; // Sent and Heard queue pointers. These are used for the dupe-checking // we do in the below routines. We have one Sent and one Heard queue // for each interface device. These pointers will point to the head of // each queue. We really only need these queues for each TNC interface, // but the user might destroy a NET interface and create a TNC interface // during a single runtime, so we need to populate all of the pointers // just in case. If people switch types, the old queue will empty out // (effectively anyway) within XX seconds, so we don't have to worry // about cleaning out the queues in this case. // DupeRecord *heard_queue[MAX_IFACE_DEVICES]; DupeRecord *sent_queue[MAX_IFACE_DEVICES]; // Types of queues for each interface #define HEARD 0 #define SENT 1 // Insert mode for the queues #define NO_FORCED_INSERT 0 #define FORCED_INSERT 1 // Initialization routine for this module which sets up the queue // pointers when Xastir first starts. Called from main.c:main() // void igate_init(void) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { heard_queue[i] = NULL; sent_queue[i] = NULL; } } // // not_a_dupe: Function which checks for duplicate packets. // // Returns: 1 if it's _not_ a duplicate record or we have an error // 0 if it _is_ a duplicate record // // Since we need to run through every record checking for dupes anyway, // we check the timestamp on each one as we go through. If too old, we // delete it from the head of the chain. We add new records to the end. // This makes it easy to keep it as a singly-linked list, and only have // to deal with one record at a time. // // The way this is set up we keep a thirty second queue for each // interface. Any records older than this are at the head of the chain // and are deleted one by one whenever this routine is called again due // to a new packet coming through. It's ok if these records sit around // on the queue for a long time due to no igate activity. It doesn't // take long to delete them! // int not_a_dupe(int queue_type, int port, char *line, int insert_mode) { DupeRecord *ptr; DupeRecord *ptr_last; int insert_new; time_t time_cutoff; int found_dupe = 0; char match_line[MAX_LINE_SIZE*2]; char line2[MAX_LINE_SIZE+1]; char *c0, *c1, *c2; if ( (line == NULL) || (line[0] == '\0') ) { return(1); } // Figure out what's "old" time_cutoff = sec_now() - (time_t)29; // 29 seconds ago // Fill the destination string with zeroes. This is a nice // segfault-prevention technique. Whatever strings we throw in here // will be automatically terminated. memset(match_line, 0, MAX_LINE_SIZE*2); switch (queue_type) { case HEARD: ptr_last = ptr = heard_queue[port]; // May be NULL! // The insert_into_heard_queue() function below (called by // db.c decode routines in turn) will call this function // with FORCED_INSERT. Other routines in igate.c will call // it with NO_FORCED_INSERT. For the Heard queue we only // want the db.c decode routines inserting records. if (insert_mode == FORCED_INSERT) { insert_new = 1; // Insert new records. } else { insert_new = 0; // Don't insert new records. } // RF packets will have third-party headers and regular // headers that must be stripped off. We only want to store // 3rd party RF strings in the Heard queue as the others // aren't going to be igated anyway. For matching and // storage purposes the 3rd party packets should look // identical to how they were originally passed on the 'net, // so that we can try to find duplicates before transmitting // them again. // NOTE: Below is the parsing code for an internet packet for the Sent // queue. Modify it to parse 3rd party packets for the Heard queue. // VE7VFM-12>APD214,VE7VAN-3*,WIDE3*:}WA7JAK>APK002,TCPIP*,VE7VFM-12*::N7WGR-7 :does{2 // Changes needed before parsing code: Get rid of first // part of packet up to the '}' symbol. After this the // generic parsing code will work. // Note that the REPLY-ACK algorithm also uses the '}' symbol. c0 = strstr(line, ":}"); // Find start of 3rd party packet if (c0 == NULL) // Not 3rd party packet { if (debug_level & 1024) { fprintf(stderr," Not 3rd party HeardQ: %s\n",line); } return(1); } // Copy original packet into line2 for later parsing. We // want to keep the '}' character because our own // transmissions out RF have that character as well. // Note that the REPLY-ACK algorithm also uses the '}' symbol. if (debug_level & 1024) { fprintf(stderr,"3rd party HeardQ: %s\n",line); } xastir_snprintf(line2, sizeof(line2), "%s", c0+1); break; case SENT: // For this queue we always want to insert records. Only // igate.c functions call this. ptr_last = ptr = sent_queue[port]; // May be NULL! insert_new = 1; // Insert new records // No extra changes needed before parsing code, Example: // }VE7VFM-11>APW251,TCPIP,WE7U-14*::VE7VFM-9 :OK GOT EMAIL OK{058 xastir_snprintf(line2, sizeof(line2), "%s", line); if (debug_level & 1024) { fprintf(stderr," COMPLETE SENT PACKET: %s\n",line2); } break; default: // We shouldn't be here. return(1); break; } // Create the string we're going to compare against and that we // might store in the queue. Knock off the path info and just check // source/destination/info portions of the packet for a match. c1 = strstr(line2, ","); // Find comma after destination c2 = strstr(line2, ":"); // Find end of path if ( (c1 != NULL) && (c2 != NULL) ) // Found both separators { // Copy source/destination portion xastir_snprintf(match_line, sizeof(match_line), "%s", line2); match_line[(int)(c1-line2)] = '\0'; // Terminate the substring strncat(match_line, // Copy info portion c2+1, sizeof(match_line) - 1 - strlen(match_line)); } else // At least one separator was not found, copy entire string { xastir_snprintf(match_line, sizeof(match_line), "%s", line2); } // Run through the selected queue from beginning to end. If the // pointer is NULL, the queue is empty and we're already done. while (ptr != NULL && !found_dupe) { // Check the timestamp to determine whether to delete this // record if (ptr->time < time_cutoff) // Old record, delete it { DupeRecord *temp; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD Deleting record: %s\n",ptr->data); break; case SENT: fprintf(stderr," SENT Deleting record: %s\n",ptr->data); break; default: break; } } // Delete record and free up the space temp = ptr; ptr = ptr->next; // May be NULL! free(temp); // Point master queue pointer to new head of queue. // Make sure to carry along ptr_last as well, as this is // our possible insertion point later. switch (queue_type) { case HEARD: heard_queue[port] = ptr_last = ptr; // May be NULL! break; case SENT: sent_queue[port] = ptr_last = ptr; // May be NULL! default: break; } } else // Record is current. Check for a match. { //fprintf(stderr,"\n\t\t%s\n\t\t%s\n",ptr->data,match_line); if (strcmp(ptr->data,match_line) == 0) { // We found a dupe! We're done with the loop. found_dupe++; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD* Found dupe: %s\n",match_line); break; case SENT: fprintf(stderr,"SENT* Found dupe: %s\n",match_line); default: break; } } } else // Not a dupe, skip to the next record in the { // queue. Keep a pointer to the last record // compared so that we have a possible insertion // point later. Once we hit the end (NULL), we // can't back up one. ptr_last = ptr; // Save pointer to last record ptr = ptr->next; // Advance one. May be NULL! } } } // End of while loop if (found_dupe) { if (debug_level & 1024) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_NET_AGWPE: fprintf(stderr," Found RF dupe: %s\n",match_line); break; default: fprintf(stderr," Found NET dupe: %s\n",match_line); break; } } return(0); // Found a dupe, return } else { // If insert_new == 1, insert each non-dupe record into the // queue and give it a timestamp. ptr_next is currently // either NULL or points to the last record in the chain. if (insert_new) { DupeRecord *temp; if (debug_level & 1024) { switch (queue_type) { case HEARD: fprintf(stderr,"HEARD Adding record: %s\n",match_line); break; case SENT: fprintf(stderr," SENT Adding record: %s\n",match_line); break; default: break; } } // Allocate a new storage space for the record and fill // it in. temp = (DupeRecord *)malloc(sizeof(DupeRecord)); if (!temp) { fprintf(stderr,"Couldn't allocate memory in not_a_dupe()\n"); return(1); // Send back "not a dupe" } temp->time = (time_t)sec_now(); memcpy(temp->data, match_line, sizeof(temp->data)); temp->data[sizeof(temp->data)-1] = '\0'; // Terminate string temp->next = NULL; // Will be the end of the linked list if (ptr_last == NULL) // Queue is currently empty { // Add record to empty list. Point master queue pointer // to new head of queue. switch (queue_type) { case HEARD: heard_queue[port] = temp; break; case SENT: sent_queue[port] = temp; default: break; } } else // Queue is not empty, add the record to the end of { // the list. ptr_last->next = temp; } } } return(1); // Nope, not a dupe } // Function which the receive routines call to insert a received // packet into the HEARD queue for an interface. The packet will // get added to the end of the linked list if it's not a duplicate // record. // // Check to make sure it's an RF interface, else return // void insert_into_heard_queue(int port, char *line) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_NET_AGWPE: // We're not using the dupe check function, but merely the // expiration and insert functions of not_a_dupe() // Don't insert the "Tickle" lines that keep the internet // sockets alive if ( (strncasecmp(line,"# Tickle",8) != 0) && (strncasecmp(line,"#Tickle",7) != 0) ) { (void)not_a_dupe(HEARD, port, line, FORCED_INSERT); } break; default: // Get out if not an RF interface return; break; } } /****************************************************************/ /* output data to inet interfaces */ /* line: data to send out */ /* port: port data came from */ /****************************************************************/ void output_igate_net(char *line, int port, int third_party) { char data_txt[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char *call_sign; char *path; char *message; int len,i,x,first; int igate_options; char log_file_path[MAX_VALUE]; call_sign = NULL; path = NULL; message = NULL; first = 1; if (line == NULL) { return; } if (line[0] == '\0') { return; } // Don't igate packets read in from a log file (port -1). // Packets from x_spider (port -2) are ok to igate. if (port == -1) { return; } //fprintf(stderr,"Igating: %s\n", line); // Should we Igate from RF->NET? if (operate_as_an_igate <= 0) { return; } xastir_snprintf(temp, sizeof(temp), "%s", line); // Check for null call_sign field call_sign = strtok(temp,">"); if (call_sign == NULL) { return; } // Check for null path field path = strtok(NULL,":"); if (path == NULL) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); // Check for "TCPIP" or "TCPXX" in the path. If found, don't // gate this into the internet again, it's already been gated to // RF, which means it's already been on the 'net. No looping // allowed here... // // We also now support NOGATE and RFONLY options. If these are // seen in the path, do _not_ gate those packets into the // internet. // // Don't gate OpenTrac expanded packets to the 'net. // if ( (strstr(path,"TCPXX") != NULL) || (strstr(path,"TCPIP") != NULL && port >= 0) // x_spider ok || (strstr(path,"NOGATE") != NULL) || (strstr(path,"RFONLY") != NULL) || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Packet was gated before or shouldn't be gated!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Check for null message field message = strtok(NULL,""); if (message == NULL) { return; } // Check for third party messages. We don't want to gate these // back onto the internet feeds // Note that the REPLY-ACK algorithm also uses the '}' symbol. if (message[0] == '}') { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Third party traffic!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Check for "general" queries. We don't wish to gate these in // either direction. There are exactly three general query // types defined in the spec. // if ( ( strstr(message,"?APRS?" ) != NULL) || (strstr(message,"?IGATE?") != NULL) || (strstr(message,"?WX?" ) != NULL) ) { // We found a general query, don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: General Query!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } len = (int)strlen(call_sign); for (i=0; iNET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: From my call!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Should I filter out more here.. get rid of all data // or Look in the path for things line "AP" "GPS" "ID" etc..? begin_critical_section(&devices_lock, "igate.c:output_igate_net" ); // If received from x_spider port or it's our own tactical call. // Here are the special port numbers we might see: // -1: We're reading in from a log file // -2: Packet came from x_spider server port (therefore it's // already authenticated) // -3: We're reading in tactical calls from file // if (port == -1) // Packet came from a log file. { igate_options = 0; // Don't igate it. } else if (port == -2) // Packet came from x_spider server port { igate_options = 1; // Ok to igate. } else if (port == -3) // We're reading tactical call from file. { igate_options = 0; // Don't igate it. } else if (port < -2) // Errant port number. { igate_options = 0; // Don't igate it. } else // Port number is 0 or positive number. A real port. // Decide whether to igate it based on the port's // configuration. { igate_options = devices[port].igate_options; } end_critical_section(&devices_lock, "igate.c:output_igate_net" ); if (igate_options <= 0 ) { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No RF->NET from input port [%d]!\n", port); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } xastir_snprintf(data_txt, sizeof(data_txt), "%s%c%c", line, '\r', '\n'); // write data out to net interfaces for (x = 0; x < MAX_IFACE_DEVICES; x++) { // Find all internet interfaces that are "up" if (port_data[x].device_type == DEVICE_NET_STREAM && x!=port && port_data[x].status == DEVICE_UP) { int pcode; // Check whether we have a valid callsign/password // combination for this interface. If not, don't gate // packets to it. pcode = atoi(port_data[x].device_host_pswd); if (checkHash(my_callsign, pcode)) { // The pcode checks out. Allow sending the // packet out to the internet. // log traffic for the first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "IGATE RF->NET(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } // Now log the interface that each bit of traffic // goes out on. xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate RF->NET packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr,"%s\n",temp); } // Write this data out to the Inet port The "1" // means raw format, the last digit says to _not_ // use the unproto_igate path output_my_data(data_txt,x,1,0,0,NULL); //fprintf(stderr,"Sending: %s\n", data_txt); } } } } /****************************************************************/ /* output data to tnc interfaces */ /* from: type of port heard from (No! It's the source call!) */ /* call: call sign heard from (No! It's the destination call!) */ /* line: data to gate to rf */ /* port: port data came from */ /****************************************************************/ void output_igate_rf(char *from, char *call, char *path, char *line, int port, int third_party, char *object_name) { char temp[MAX_LINE_SIZE+20]; int x; int first = 1; int found_in_nws_file = 0; char log_file_path[MAX_VALUE]; char nws_file_path[MAX_VALUE]; if ( (from == NULL) || (call == NULL) || (path == NULL) || (line == NULL) ) { return; } if ( (from[0] == '\0') || (call[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') ) { return; } // Should we Igate from NET->RF? if (operate_as_an_igate <= 1) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); // Don't gate anything with NOGATE in it, in either direction. // Same for OpenTrac packets. if ( (strstr(path,"NOGATE") != NULL) || (strstr(path,"OPNTRK") != NULL) // OpenTrac Packet || (strstr(path,"OPNTRC") != NULL) ) // OpenTrac Packet { // "NOGATE" was found in the header. Don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NOGATE found in path or shouldn't be gated!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Don't gate "general" queries in any direction. There are // exactly three general query types defined in the spec. // if ( (strstr(line,"?APRS?" ) != NULL) || (strstr(line,"?IGATE?") != NULL) || (strstr(line,"?WX?" ) != NULL) ) { // We found a general query, don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: General Query!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // check to see if the nws-stations file is newer than last read get_user_base_dir("data/nws-stations.txt",nws_file_path, sizeof(nws_file_path)); if (last_nws_stations_file_time < file_time(nws_file_path)) { last_nws_stations_file_time = file_time(nws_file_path); load_NWS_stations(nws_file_path); //fprintf(stderr,"NWS Station file time is old\n"); } // Check whether gating of packets from this station/object/item // has been specifically authorized via the nws-stations.txt // mechanism. // if (object_name) // It's an object or item name { if ( check_NWS_stations( object_name ) || group_active(object_name)) { found_in_nws_file++; // Object/Item is in nws-stations.txt } } else // It's a station callsign { if ( check_NWS_stations( from ) || group_active(from)) { found_in_nws_file++; // Source callsign is in nws-stations.txt } } // The above is really the same as the following code, but less // confusing: // if (check_NWS_stations( (object_name) ? object_name : from ) ) { // found_in_nws_file++; // } // Check for TCPXX in string only if station wasn't found in the // nws-stations.txt file. If TCPXX found, we have an // unregistered net user and the packet shouldn't normally head // to RF. // // I removed the trailing asterisk -we7u // // Note that we CAN now gate stations to RF that have TCPXX in // the string if they are authorized via the nws-stations.txt // mechanism. // if (!found_in_nws_file) // Skip this check if they're always authorized via the file { if (strstr(path,"TCPXX") != NULL) { // "TCPXX" was found in the header. We have an // unregistered user. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Unregistered net user!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } } // If we made it to this point, the packet is from an authorized net // user (no TCPXX found in the path), or the callsign has been // authorized via the nws-stations.txt file (whether or not TCPXX // was found in the path). // // Found in file: Gate always // // Not found: Gate if TCPXX not in path -AND- if destination // station was heard in last hour on RF -AND- if // source station was NOT heard in last hour on RF. // Check whether the source and destination calls have been // heard on local RF. if ( !found_in_nws_file // Skip this check if they're always authorized via the file && ( !heard_via_tnc_in_past_hour(call) // Haven't heard destination call in previous hour || heard_via_tnc_in_past_hour(from)) ) // Have heard source call in previous hour { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); // heard(call), heard(from) : RF-to-RF talk // !heard(call), heard(from) : Destination not heard on TNC // !heard(call), !heard(from) : Destination/source not heard on TNC if (!heard_via_tnc_in_past_hour(call)) xastir_snprintf(temp, sizeof(temp), "REJECT: Destination not heard on TNC within an hour %s!\n", call ); else xastir_snprintf(temp, sizeof(temp), "REJECT: RF->RF talk!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // Station we are going to is heard via tnc but station sending // shouldn't be heard via TNC. Write data out to interfaces. for (x=0; x1 && port_data[x].status==DEVICE_UP) { // log traffic for first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate NET->RF packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr, "%s", temp); } // ok write this data out to the RF port end_critical_section(&devices_lock, "igate.c:output_igate_rf" ); // First "0" means "cooked" // format, last digit: use // unproto_igate path output_my_data(line,x,0,0,1,NULL); //fprintf(stderr, "Igating->RF: %s\n", line); begin_critical_section(&devices_lock, "igate.c:output_igate_rf" ); } else { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NET->RF on port [%d]!\n", x); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } } end_critical_section(&devices_lock, "igate.c:output_igate_rf" ); break; default: break; } // End of switch } // End of if } // End of for } void add_NWS_stations(void) { void *tmp_ptr; if (NWS_stations>=max_NWS_stations) { if ((tmp_ptr = realloc(NWS_station_data, sizeof(NWS_Data)*(max_NWS_stations+11)))) { NWS_station_data = tmp_ptr; max_NWS_stations += 10; } else { fprintf(stderr,"Unable to allocate more space for NWS_station_data\n"); } } } /****************************************************************/ /* Load NWS stations file */ /* file: file to read */ /****************************************************************/ void load_NWS_stations(char *file) { FILE *f; char line[40]; if (file == NULL) { return; } if (file[0] == '\0') { return; } if (NWS_station_data) { free(NWS_station_data); NWS_station_data = NULL; } NWS_stations = 0; max_NWS_stations = 0; f = fopen(file,"r"); if (f!=NULL) { while (!feof(f)) { if (strlen(get_line(f,line,40))>0) { // look for comment if (line[0] != '#' ) { NWS_stations++; add_NWS_stations(); if (NWS_station_data != NULL) { // add data // Note: Size of string variable is 12 // bytes, defined in igate.h if (1 != sscanf(line,"%11s",NWS_station_data[NWS_stations-1].call)) { fprintf(stderr,"load_NWS_stations: sscanf parsing error\n"); } if (debug_level & 1024) { fprintf(stderr,"LINE:%s\n",line); } } else { fprintf(stderr,"Can't allocate data space for NWS station\n"); } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open NWS stations file: %s\n", file); } } // check NWS stations file // // call: call to check // returns 1 for found // // Both the incoming call and the stored call we're matching against // have to be >= 3 characters long. This routine will match only up // to the length of the stored string, so we now allow partial // matches. // int check_NWS_stations(char *call) { int ok, i, length, length_incoming; if (call == NULL) { return(0); } if (call[0] == '\0') { return(0); } if (NWS_station_data == NULL) { return(0); } if (debug_level & 1024) { fprintf(stderr,"igate.c::check_NWS_stations %s\n", call); } // Make sure that the incoming call is longer than three // characters. If not, skip it. length_incoming = strlen(call); if (length_incoming < 3) { return(0); } ok=0; for (i=0; i= 3) { // Compare the incoming call only up to the length of the // stored call. This allows partial matches. The // stored call could be significantly shorter than the // incoming call, but at least three characters. if (strncasecmp(call, NWS_station_data[i].call, length)==0) { ok=1; // match found if (debug_level & 1024) { fprintf(stderr,"NWS-MATCH:(%s) (%s)\n",NWS_station_data[i].call,call); } } } else { // Do nothing. Stored call is too short. } } return(ok); } /****************************************************************/ /* output NWS data to tnc interfaces */ /* from: type of port heard from */ /* call: call sign heard from */ /* line: data to gate to rf */ /* port: port data came from */ /****************************************************************/ void output_nws_igate_rf(char *from, char *path, char *line, int port, int third_party) { char temp[MAX_LINE_SIZE+20]; int x; int first = 1; char log_file_path[MAX_VALUE]; char nws_file_path[MAX_VALUE]; if ( (from == NULL) || (path == NULL) || (line == NULL) ) { return; } if ( (from[0] == '\0') || (path[0] == '\0') || (line[0] == '\0') ) { return; } // Should we Igate from NET->RF? if (operate_as_an_igate <= 1) { return; } get_user_base_dir(LOGFILE_IGATE,log_file_path, sizeof(log_file_path)); get_user_base_dir("data/nws-stations.txt",nws_file_path, sizeof(nws_file_path)); // Check for TCPXX in string! If found, we have an // unregistered net user. // I removed the trailing asterisk --we7u if (strstr(path,"TCPXX") != NULL) { // "TCPXX" was found in the header. We have an // unregistered user. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: Unregistered net user!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // no unregistered net user found in string. Look for NOGATE // next. if ( strstr(path,"NOGATE") != NULL ) { // "NOGATE" was found in the header. Don't gate it. if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NOGATE found in path!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // see if we can gate NWS messages if (!filethere(nws_file_path)) { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No nws-stations.txt file!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; } // check to see if the nws-stations file is newer than last read if (last_nws_stations_file_time < file_time(nws_file_path)) { last_nws_stations_file_time = file_time(nws_file_path); load_NWS_stations(nws_file_path); //fprintf(stderr,"NWS Station file time is old\n"); } // Look for NWS station in file data if (!check_NWS_stations(from) || !group_active(from)) // Couldn't find the station { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: No matching station in nws-stations.txt file!\n"); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } return; // Match for station not found in file } //fprintf(stderr,"SENDING NWS VIA TNC!!!!\n"); // write data out to interfaces for (x=0; x1 && port_data[x].status==DEVICE_UP) { // log traffic for first "up" interface only if (log_igate && first) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); first = 0; } xastir_snprintf(temp, sizeof(temp), "TRANSMIT: IGate NET->RF packet on device:%d\n", x); // log output if (log_igate) { log_data( log_file_path, temp ); } if (debug_level & 1024) { fprintf(stderr, "%s", temp); } // ok write this data out to the RF port end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); // First "0" means "cooked" // format, last digit: use // unproto_igate path output_my_data(line,x,0,0,1,NULL); begin_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); } else { if (log_igate && (debug_level & 1024) ) { xastir_snprintf(temp, sizeof(temp), "NWS IGATE NET->RF(%c):%s\n", third_party ? 'T':'N', line); log_data( log_file_path, temp ); xastir_snprintf(temp, sizeof(temp), "REJECT: NET->RF on port [%d]!\n", x); log_data( log_file_path, temp ); fprintf(stderr, "%s", temp); } } end_critical_section(&devices_lock, "igate.c:output_nws_igate_rf" ); break; default: break; } } } } Xastir-Release-2.2.4/src/igate.h0000664000175000017500000000265215151324131015357 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_IGATE_H #define __XASTIR_IGATE_H typedef struct { char call[12]; } NWS_Data; extern void igate_init(void); extern void insert_into_heard_queue(int port, char *line); extern void output_igate_net(char *line, int port, int third_party); extern void output_igate_rf(char *from, char *call, char *path, char *line, int port, int third_party, char *object_name); extern void output_nws_igate_rf(char *from, char *path, char *line, int port, int third_party); #endif // __XASTIR_IGATE_H Xastir-Release-2.2.4/src/interface.c0000664000175000017500000077030715151324131016232 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* AX.25 Parts adopted from: aprs_tty.c by Henk de Groot - PE1DNN */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include #include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include "xastir.h" #include "symbols.h" #include "main.h" #include "db_funcs.h" #include "xa_config.h" //#include "maps.h" #include "interface.h" #include "util.h" #include "mutex_utils.h" #include "wx.h" #include "forked_getaddrinfo.h" #include "x_spider.h" #include "db_gis.h" #include "gps.h" #include "ambiguity_utils.h" #include "log_utils.h" #ifdef HAVE_LIBAX25 #include #include #include #include #endif // HAVE_LIBAX25 // Must be last include file #include "leak_detection.h" #ifndef SIGRET #define SIGRET void #endif // SIGRET // Older versions of glibc <= 2.3.0 and <= OS X 10.5 do not have this // constant defined #ifndef AI_NUMERICSERV #define AI_NUMERICSERV 0 #endif //extern pid_t getpgid(pid_t pid); extern void port_write_binary(int port, unsigned char *data, int length); iodevices dtype[MAX_IFACE_DEVICE_TYPES]; // device names iface port_data[MAX_IFACE_DEVICES]; // shared port data int port_id[MAX_IFACE_DEVICES]; // shared port id data xastir_mutex port_data_lock; // Protects the port_data[] array of structs xastir_mutex data_lock; // Protects incoming_data_queue xastir_mutex output_data_lock; // Protects interface.c:channel_data() function only xastir_mutex connect_lock; // Protects port_data[].thread_status and port_data[].connect_status void port_write_string(int port, char *data); int ax25_ports_loaded = 0; // Incoming data queue typedef struct _incoming_data_record { int length; // Used for binary strings such as KISS int port; unsigned char data[MAX_LINE_SIZE]; } incoming_data_record; #define MAX_INPUT_QUEUE 1000 static incoming_data_record incoming_data_queue[MAX_INPUT_QUEUE]; unsigned char incoming_data_copy[MAX_LINE_SIZE]; // Used for debug unsigned char incoming_data_copy_previous[MAX_LINE_SIZE]; // Used for debug // interface wait time out int NETWORK_WAITTIME; // Read/write pointers for the circular input queue static int incoming_read_ptr = 0; static int incoming_write_ptr = 0; static int queue_depth = 0; static int push_count = 0; static int pop_count = 0; /* prototype for function that is only used in this file, need not be in the associated header */ void output_fixed_position(char *data_txt_save, size_t data_txt_save_size, char *my_pos, char * output_phg, char * output_alt, char *my_comment_tx, char *data_txt, size_t data_txt_size, char *output_net); // Fetch a record from the circular queue. // Returns 0 if no records available // Else returns length of string, data_string and port // data_string variable should be of size MAX_LINE_SIZE // int pop_incoming_data(unsigned char *data_string, int *port) { int length; int jj; if (begin_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } // Check for queue empty if (incoming_read_ptr == incoming_write_ptr) { // Yep, it's empty queue_depth = 0; if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(0); } // Bump the read pointer incoming_read_ptr = (incoming_read_ptr + 1) % MAX_INPUT_QUEUE; *port = incoming_data_queue[incoming_read_ptr].port; length = incoming_data_queue[incoming_read_ptr].length; // Yes, this is a string, but it may have zeros embedded. We can't // use string manipulation functions because of that: for (jj = 0; jj < length; jj++) { data_string[jj] = incoming_data_queue[incoming_read_ptr].data[jj]; } // Add terminator, just in case data_string[length+1] = '\0'; queue_depth--; pop_count++; if (end_critical_section(&data_lock, "interface.c:pop_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(length); } // Add one record to the circular queue. Returns 1 if queue is // full, 0 if successful. // int push_incoming_data(unsigned char *data_string, int length, int port) { int next_write_ptr = (incoming_write_ptr + 1) % MAX_INPUT_QUEUE; int jj; if (begin_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } // Check whether queue is full if (incoming_read_ptr == next_write_ptr) { // Yep, it's full! if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(1); } // Advance the write pointer incoming_write_ptr = next_write_ptr; incoming_data_queue[incoming_write_ptr].length = length; incoming_data_queue[incoming_write_ptr].port = port; // Binary safe copy in case there are embedded zeros for (jj = 0; jj < length; jj++) { incoming_data_queue[incoming_write_ptr].data[jj] = data_string[jj]; } queue_depth++; push_count++; if (end_critical_section(&data_lock, "interface.c:push_incoming_data" ) > 0) { fprintf(stderr,"data_lock\n"); } return(0); } // Returns 1 if a local interface, 0 otherwise // int is_local_interface(int port) { switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: case DEVICE_AX25_TNC: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: return(1); // Found a local interface break; // Could be port -1 which signifies a spider port or port // -99 which signifies "All Ports" and is used for // transmitting out all ports at once. default: return(0); // Unknown or network interface break; } } // Returns 1 if a network interface, 0 otherwise // int is_network_interface(int port) { switch (port_data[port].device_type) { case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: return(1); // Found a network interface break; // Could be port -1 which signifies a spider port or port // -99 which signifies "All Ports" and is used for // transmitting out all ports at once. default: return(0); // Unknown or local interface break; } } // Create a packet and send to AGWPE for transmission. // Format is as follows: // // RadioPort 4 bytes (0-3) // DataType 4 bytes (4-7) // FromCall 10 bytes (8-17) // ToCall 10 bytes (18-27) // DataLength 4 bytes (28-31) // UserField 4 bytes (32-35) // Data DataLength bytes (36-?) // // Callsigns are null-terminated at end of string, but callsign // field width is specified to be 10 bytes in all cases. // // Path is split up into the various ViaCalls. Path may also be a // NULL pointer. // // If type != '\0', then we'll create the specified type of packet. // // Else if Path is not empty, we'll use packet format "V" with // Viacalls prepended to the Data portion of the packet, 10 chars // per digi, with the number of digis as the first character. The // packet data then follows after the last via callsign. // // Else if no Path, then put the Data directly into the Data // field and use "M" format packets. // // We currently use the base portion of my_callsign as the username // portion of the AGWPE login. This must be upper-case when you're // setting up the account in AGWPE, as that's what we send to // authenticate. // void send_agwpe_packet(int xastir_interface,// Xastir interface port int RadioPort, // AGWPE RadioPort unsigned char type, unsigned char *FromCall, unsigned char *ToCall, unsigned char *Path, unsigned char *Data, int length) { int ii; #define agwpe_header_size 36 unsigned char output_string[512+agwpe_header_size]; unsigned char path_string[200]; int full_length; int data_length; // Check size of data if (length > 512) { return; } // Clear the output_string (set to binary zeroes) for (ii = 0; ii < (int)sizeof(output_string); ii++) { output_string[ii] = '\0'; } if (type != 'P') { // Write the port number into the frame. Note that AGWPE // uses 1 for the first port in its GUI, but the programming // interface starts at 0. output_string[0] = (unsigned char)RadioPort; if (FromCall) // Write the FromCall string into the frame xastir_snprintf((char *)&output_string[8], sizeof(output_string) - 8, "%s", FromCall); if (ToCall) // Write the ToCall string into the frame xastir_snprintf((char *)&output_string[18], sizeof(output_string) - 18, "%s", ToCall); } if ( (type != '\0') && (type != 'P') ) { // Type was specified, not a data frame or login frame // Write the type character into the frame output_string[4] = type; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, agwpe_header_size); } else if (Path == NULL) // No ViaCalls, Data or login packet { if (type == 'P') { // Login/Password frame char callsign_base[15]; int new_length; // Write the type character into the frame output_string[4] = type; // Compute the callsign base string // (callsign minus SSID) xastir_snprintf(callsign_base, sizeof(callsign_base), "%s", my_callsign); // Change '-' into end of string strtok(callsign_base, "-"); // Length = length of each string plus the two // terminating zeroes. //new_length = strlen(callsign_base) + length + 2; new_length = 255+255; output_string[28] = (unsigned char)(new_length % APRS_MAX_PACKET_DATA_LEN); output_string[29] = (unsigned char)((new_length >> 8) % APRS_MAX_PACKET_DATA_LEN); // Write login/password out as 255-byte strings each // Put the login string into the buffer xastir_snprintf((char *)&output_string[agwpe_header_size], sizeof(output_string) - agwpe_header_size, "%s", callsign_base); // Put the password string into the buffer xastir_snprintf((char *)&output_string[agwpe_header_size+255], sizeof(output_string) - agwpe_header_size - 255, "%s", Data); // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, 255+255+agwpe_header_size); } else // Data frame { // Write the type character into the frame output_string[4] = 'M'; // Unproto, no via calls // Write the PID type into the frame output_string[6] = 0xF0; // UI Frame output_string[28] = (unsigned char)(length % APRS_MAX_PACKET_DATA_LEN); output_string[29] = (unsigned char)((length >> 8) % APRS_MAX_PACKET_DATA_LEN); // Copy Data onto the end of the string. This one // doesn't have to be null-terminated, so strncpy() is // ok to use here. strncpy stops at the first null byte // though. Proper for a binary output routine? NOPE! strncpy((char *)(&output_string[agwpe_header_size]),(char *)Data, length); full_length = length + agwpe_header_size; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, full_length); } } else // We have ViaCalls. Data packet. { char *ViaCall[10]; // Doesn't need to be null-terminated, so strncpy is ok to // use here. strncpy stops at the first null byte though. // Proper for a binary output routine? NOPE! strncpy((char *)path_string, (char *)Path, sizeof(path_string)); // Convert path_string to upper-case to_upper((char *)path_string); split_string((char *)path_string, ViaCall, 10, ','); // Write the type character into the frame output_string[4] = 'V'; // Unproto, via calls present // Write the PID type into the frame output_string[6] = 0xF0; // UI Frame // Write the number of ViaCalls into the first byte if (ViaCall[7]) { output_string[agwpe_header_size] = 0x08; } else if (ViaCall[6]) { output_string[agwpe_header_size] = 0x07; } else if (ViaCall[5]) { output_string[agwpe_header_size] = 0x06; } else if (ViaCall[4]) { output_string[agwpe_header_size] = 0x05; } else if (ViaCall[3]) { output_string[agwpe_header_size] = 0x04; } else if (ViaCall[2]) { output_string[agwpe_header_size] = 0x03; } else if (ViaCall[1]) { output_string[agwpe_header_size] = 0x02; } else { output_string[agwpe_header_size] = 0x01; } // Write the ViaCalls into the Data field switch (output_string[agwpe_header_size]) { case 8: if (ViaCall[7]) { strncpy((char *)(&output_string[agwpe_header_size+1+70]), ViaCall[7], 10); } else { return; } /* Falls through. */ case 7: if (ViaCall[6]) { strncpy((char *)(&output_string[agwpe_header_size+1+60]), ViaCall[6], 10); } else { return; } /* Falls through. */ case 6: if (ViaCall[5]) { strncpy((char *)(&output_string[agwpe_header_size+1+50]), ViaCall[5], 10); } else { return; } /* Falls through. */ case 5: if (ViaCall[4]) { strncpy((char *)(&output_string[agwpe_header_size+1+40]), ViaCall[4], 10); } else { return; } /* Falls through. */ case 4: if (ViaCall[3]) { strncpy((char *)(&output_string[agwpe_header_size+1+30]), ViaCall[3], 10); } else { return; } /* Falls through. */ case 3: if (ViaCall[2]) { strncpy((char *)(&output_string[agwpe_header_size+1+20]), ViaCall[2], 10); } else { return; } /* Falls through. */ case 2: if (ViaCall[1]) { strncpy((char *)(&output_string[agwpe_header_size+1+10]), ViaCall[1], 10); } else { return; } /* Falls through. */ case 1: default: if (ViaCall[0]) { strncpy((char *)(&output_string[agwpe_header_size+1+0]), ViaCall[0], 10); } else { return; } break; } // Write the Data onto the end. // Doesn't need to be null-terminated, so strncpy is ok to // use here. strncpy stops at the first null byte though. // Proper for a binary output routine? strncpy((char *)(&output_string[((int)(output_string[agwpe_header_size]) * 10) + agwpe_header_size + 1]), (char *)Data, length); //Fill in the data length field. We're assuming the total //is less than 512 + 37. data_length = length + ((int)(output_string[agwpe_header_size]) * 10) + 1; if ( data_length > 512 ) { return; } output_string[28] = (unsigned char)(data_length % APRS_MAX_PACKET_DATA_LEN); output_string[29] = (unsigned char)((data_length >> 8) % APRS_MAX_PACKET_DATA_LEN); full_length = data_length + agwpe_header_size; // Send the packet to AGWPE port_write_binary(xastir_interface, output_string, full_length); } } /* // Here is a "monitor" UI packet // Total Length = 150 HEX:00 00 00 00 55 00 00 00 4b 4b 31 57 00 ed 12 00 96 ed 41 50 54 57 30 31 00 00 00 00 72 00 00 00 00 00 00 00 20 31 3a 46 6d 20 4b 4b 31 57 20 54 6f 20 41 50 54 57 30 31 20 56 69 61 20 57 49 44 45 33 20 3c 55 49 20 70 69 64 3d 46 30 20 4c 65 6e 3d 35 30 20 3e 5b 31 30 3a 34 33 3a 34 33 5d 0d 5f 30 38 30 36 31 30 33 39 63 33 35 39 73 30 30 30 67 30 30 30 74 30 36 32 72 30 30 30 70 30 30 33 50 30 39 36 68 30 30 62 31 30 30 39 33 74 55 32 6b 0d 0d 00 ASC:....U...KK1W......APTW01....r....... 1:Fm KK1W To APTW01 Via WIDE3 [10:43:43]._08061039c359s000g000t062r000p003P096h00b10093tU2k... */ /* // And here are some "raw" UI packets // AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 135 HEX:00 00 00 00 4b 00 00 00 4e 32 4c 42 54 2d 37 00 01 00 41 50 58 31 33 33 00 00 00 00 63 00 00 00 00 00 00 00 c0 82 a0 b0 62 66 66 60 9c 64 98 84 a8 40 6e 96 82 64 a2 b2 8a f4 ae 92 88 8a 40 40 61 03 f0 40 30 37 30 30 32 37 7a 34 32 33 39 2e 30 34 4e 5c 30 37 33 34 38 2e 31 30 57 5f 30 30 30 2f 30 30 30 67 30 30 30 74 30 36 34 72 30 30 30 50 30 30 30 70 30 30 30 68 35 33 62 31 30 31 32 37 58 55 32 6b 0d ASC:....K...N2LBT-7...APX133....c...........bff`.d...@n..d........@@a..@070027z4239.04N\07348.10W_000/000g000t064r000P000p000h53b10127XU2k. AGWPE: Got raw frame packet 3:23 Bad KISS packet. Dropping it. Total Length = 104 HEX:00 00 00 00 4b 00 00 00 4e 31 45 44 5a 2d 37 00 01 00 54 52 31 55 37 58 00 00 00 00 44 00 00 00 00 00 00 00 c0 a8 a4 62 aa 6e b0 60 9c 62 8a 88 b4 40 ee 96 82 62 a2 8c 8a fe ae 62 a8 9e 9a 40 fe 96 82 64 a2 b2 8a f5 03 f0 60 64 2a 39 6c 23 22 3e 2f 3e 22 35 6b 7d 6e 31 65 64 7a 40 61 6d 73 61 74 2e 6f 72 67 0d ASC:....K...N1EDZ-7...TR1U7X....D..........b.n.`.b...@...b.....b...@...d......`d*9l#">/>"5k}n1edz@amsat.org. AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 ae 92 88 8a 40 40 61 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d........@@a..!4319.79N/07340.87W>268/020/A=000485 AGWPE: Got raw frame packet 3:74 Bad KISS packet. Dropping it. Total Length = 82 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 ae 82 64 aa 9a b0 e5 03 f0 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r.d...@...d......!4319.79N/07340.87W>268/020/A=000485 AGWPE: Got raw frame packet 3:74 Bad KISS packet. Dropping it. Total Length = 82 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 2e 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 64 8e ae b2 40 e4 96 82 64 a2 b2 8a f5 03 f0 3e 6e 32 79 71 74 40 61 72 72 6c 2e 6e 65 74 ASC:....K...K2RRT-9...APT311................fbb`.d...@r.d...@...d......>n2yqt@arrl.net AGWPE: Got raw frame packet 3:2e Bad KISS packet. Dropping it. Total Length = 103 HEX:00 00 00 00 4b 00 00 00 4b 32 52 52 54 2d 39 00 01 00 41 50 54 33 31 31 00 00 00 00 43 00 00 00 00 00 00 00 c0 82 a0 a8 66 62 62 60 96 64 a4 a4 a8 40 72 ae 82 64 aa 9a b0 e4 96 82 64 a2 b2 8a f5 03 f0 21 34 33 31 39 2e 37 39 4e 2f 30 37 33 34 30 2e 38 37 57 3e 32 36 38 2f 30 32 30 2f 41 3d 30 30 30 34 38 35 ASC:....K...K2RRT-9...APT311....C...........fbb`.d...@r..d......d......!4319.79N/07340.87W>268/020/A=000485 */ // Parse an AGWPE header. Create a TAPR-2 style header out of the // data for feeding into the Xastir parsing code. Input format is // as follows: // // RadioPort 4 bytes (0-3) // DataType 4 bytes (4-7) // FromCall 10 bytes (8-17) // ToCall 10 bytes (18-27) // DataLength 4 bytes (28-31) // UserField 4 bytes (32-35) // Data xx bytes (36-??) // // Callsigns are null-terminated at end of string, but field width // is specified to be 10 bytes in all cases. // // output_string variable should be quite long, perhaps 1000 // characters. // // Someday it would be nice to turn on raw packet format in AGWPE // which gives us the AX.25 packet format directly. We should be // able to use our normal KISS decoding functions to parse those // types of packets, instead of the mess we have below which is // parsing a few things out of the header, a few things out of the // text that AGWPE puts after the header, and then snagging the info // field of the packet from the tail-end. // unsigned char *parse_agwpe_packet(unsigned char *input_string, int output_string_length, unsigned char *output_string, int *new_length) { int ii, jj, kk; char *info_ptr; char *via_ptr; char temp_str[512]; int special_debug = 0; int data_length; // Fetch the length of the data portion of the packet data_length = (unsigned char)(input_string[31]); data_length = (data_length << 8) + (unsigned char)(input_string[30]); data_length = (data_length << 8) + (unsigned char)(input_string[29]); data_length = (data_length << 8) + (unsigned char)(input_string[28]); // Implementing some special debugging output for the case of // third-party NWS messages, which so far haven't been parsed // properly by this function. // // Check for NWS string past the header part of the AGWPE // packet. // // Make sure we have a terminating '\0' at the end. // Note that this doesn't help for binary packets (like OpenTrac), // but doesn't really hurt either. input_string[38+data_length] = '\0'; // Check what sort of AGWPE packet it is. switch (input_string[4]) { case 'R': if (data_length == 8) { fprintf(stderr, "\nConnected to AGWPE server, version: %d.%d\n", (input_string[37] << 8) + input_string[36], (input_string[41] << 8) + input_string[40]); } return(NULL); // All done! break; case 'G': // Print out the data, changing all ';' characters to // and a bunch of spaces to format it nicely. fprintf(stderr, " Port Info, total ports = "); ii = 36; while (ii < data_length + 36 && input_string[ii] != '\0') { if (input_string[ii] == ';') { fprintf(stderr, "\n "); } else { fprintf(stderr, "%c", input_string[ii]); } ii++; } fprintf(stderr,"\n"); return(NULL); // All done! break; case 'g': return(NULL); // All done! break; case 'X': return(NULL); // All done! break; case 'y': return(NULL); // All done! break; case 'Y': return(NULL); // All done! break; case 'H': return(NULL); // All done! break; case 'C': return(NULL); // All done! break; case 'v': return(NULL); // All done! break; case 'c': return(NULL); // All done! break; case 'D': return(NULL); // All done! break; case 'd': return(NULL); // All done! break; case 'U': // We can decode this one ok in the below code (after // this switch statement), but we no longer use // "monitor" mode packets in AGWPE, switching to the // "raw" mode instead. return(NULL); // All done! break; case 'I': return(NULL); // All done! break; case 'S': return(NULL); // All done! break; case 'T': // We should decode this one ok in the below code (after // this switch statement), but we no longer use // "monitor" mode packets in AGWPE, switching to the // "raw" mode instead. return(NULL); // All done! break; case 'K': // Code here processes the packet for handing to our // KISS decoding routines. Chop off the header, add // anything to the beginning/end that we need, then send // it to decode_ax25_header(). // Try to decode header and checksum. If bad, break, // else continue through to ASCII logging & decode // routines. We skip the first byte as it's not part of // the AX.25 packet. // // Note that the packet length often increases here in // decode_ax25_header, as we add '*' characters and such // to the header as it's decoded. // This string already has a terminator on the end, // added by the code in port_read(). If we didn't have // one here, we could end up with portions of strings // concatenated on the end of our string by the time // we're done processing the data here. // // input_string[data_length+36] = '\0'; // WE7U: // We may need to extend input_string by a few characters before it // is fed to us. Something like max_callsigns * 3 or 4 characters, // to account for '*' and SSID characters that we might add. This // keeps the string from getting truncated as we add bytes to the // header in decode_ax25_header. if ( !decode_ax25_header( (unsigned char *)&input_string[37], &data_length ) ) { // int zz; // Had a problem decoding it. Drop it on the floor. fprintf(stderr, "AGWPE: Bad KISS packet. Dropping it.\n"); special_debug++; // for (zz = 0; zz < data_length; zz++) { // fprintf(stderr, "%02x ", input_string[zz+36]); // } // fprintf(stderr,"\n"); return(NULL); } // Good header. Compute the new length, again skipping // the first byte. data_length = strlen((const char *)&input_string[37]); // The above strlen() requires it to be printable ascii in the KISS // packet, so won't work for OpenTrac protocol or other binary // protocols. The decode_ax25_header() function also looks for // PID=0xF0, which again won't work for OpenTrac. It would be // better to have the decode_ax25_header routine return the new // length of the packet so that decoding of binary packets is still // possible. // Check for OpenTrac packets. If found, dump them into // OpenTrac-specific decode and skip the other decode below. Must // tweak the above stuff to allow binary-format packets to get // through to this point. // Do more stuff with the packet here. The actual // packet itself starts at offset 37. We can end up // with 0x0d, 0x0d 0x0d, or 0x0d 0x00 0x0d on the end of // it (or none of the above). Best method should be to // just search for any 0x0d's or 0x0a's starting at the // beginning of the string and overwrite them with // 0x00's. That's what we do here. // for (ii = 0; ii < data_length; ii++) { if (input_string[ii+37] == 0x0d || input_string[ii+37] == 0x0a) { input_string[ii+37] = '\0'; } } // Compute data_length again. data_length = strlen((const char *)&input_string[37]); // Send the processed string back for decoding xastir_snprintf((char *)output_string, output_string_length, "%s", &input_string[37]); // Send back the new length. *new_length = data_length; return(output_string); break; default: fprintf(stderr,"AGWPE: Got unrecognized '%c' packet\n",input_string[4]); return(NULL); // All done! break; } // NOTE: All of the code below gets used in "monitor" mode, which // we no longer use. We might keep this code around for a bit and // then delete it, as we've probably switched to "raw" mode for // good. "raw" mode allows us to use our KISS processing routines, // plus allows us to support digipeating and OpenTrac (binary) // protocol in the future. if (special_debug) { // Dump the hex & ascii representation of the whole packet kk = data_length + 36; // Add the header length fprintf(stderr, "Total Length = %d\n", kk); fprintf(stderr, "HEX:"); for (ii = 0; ii < kk; ii++) { fprintf(stderr, "%02x ", input_string[ii]); } fprintf(stderr, "\n"); fprintf(stderr, "ASC:"); for (ii = 0; ii < kk; ii++) { if (input_string[ii] < ' ' || input_string[ii] > '~') { fprintf(stderr, "."); } else { fprintf(stderr, "%c", input_string[ii]); } } fprintf(stderr, "\n"); } // Clear the output_string (set to binary zeroes) for (ii = 0; ii < output_string_length; ii++) { output_string[ii] = '\0'; } jj = 0; // Copy the source callsign ii = 8; while (input_string[ii] != '\0') { output_string[jj++] = input_string[ii++]; } // Add a '>' character output_string[jj++] = '>'; // Copy the destination callsign ii = 18; while (input_string[ii] != '\0') { output_string[jj++] = input_string[ii++]; } // Search for "]" (0x5d) which is the end of the header string, // beginning of the AX.25 information field. info_ptr = strstr((const char *)&input_string[36], "]"); // If not found, we can't process anymore if (!info_ptr) { output_string[0] = '\0'; new_length = 0; return(NULL); } // Copy the first part of the string into a variable. We'll // look for Via calls in this string, if present. ii = 36; temp_str[0] = '\0'; while (input_string[ii] != ']') { strncat(temp_str, (char *)(&input_string[ii++]), 1); } // Make sure that the protocol ID is "F0". If not, return. if (strstr(temp_str, "pid=F0") == NULL) { char *pid_ptr; // Look for the "pid=" string and print out what we can // figure out about the protocol ID. pid_ptr = strstr(temp_str, "pid="); if (pid_ptr) { pid_ptr +=4; fprintf(stderr, "parse_agwpe_packet: Non-APRS protocol was seen: PID=%2s. Dropping the packet.\n", pid_ptr); } else { fprintf(stderr, "parse_agwpe_packet: Non-APRS protocol was seen. Dropping the packet.\n"); } output_string[0] = '\0'; new_length = 0; return(NULL); } // Search for "Via" in temp_str via_ptr = strstr(temp_str, "Via"); if (via_ptr) { // Found some Via calls. Copy them into our output string. // Add a comma first output_string[jj++] = ','; // Skip past "Via " portion of string via_ptr += 4; // Copy the string across until we hit a space while (via_ptr[0] != ' ') { output_string[jj++] = via_ptr[0]; via_ptr++; } } // Add a ':' character output_string[jj++] = ':'; // Move the pointer past the "]" to the real info part of the // packet. info_ptr++; info_ptr++; // Copy the info field to the output string while (info_ptr[0] != '\0') { strncat((char *)output_string, &info_ptr[0], 1); info_ptr++; } // We end up with 0x0d characters on the end. Get rid of them. // The strtok() function will overwrite the first one found with // a '\0' character. (void)strtok((char *)output_string, "\n"); (void)strtok((char *)output_string, "\r"); *new_length = strlen((const char *)output_string); if (special_debug) { // Print out the resulting string fprintf(stderr,"AGWPE RX: %s\n", output_string); fprintf(stderr,"new_length: %d\n",*new_length); for (ii = 0; ii < (int)strlen((const char *)output_string); ii++) { fprintf(stderr,"%02x ",output_string[ii]); } fprintf(stderr,"\n"); } return(output_string); } /* Found complete AGWPE packet, 93 bytes total in frame: 00 00 00 00 55 00 00 00 'U' Packet 57 45 37 55 2d 33 00 00 ff ff WE7U-3 41 50 52 53 00 20 ec e9 6c 00 APRS 39 00 00 00 Length 00 00 00 00 20 31 .1 (36-37) 3a 46 6d 20 :Fm (38-41) 57 45 37 55 2d 33 WE7U-3 (42-space) 20 54 6f .To 20 41 50 52 53 .APRS 20 3c 55 49 .[23:13:20]. 54 65 73 74 0d 0d 00 Test. ....U...WE7U-3....APRS. ..l.9....... 1:Fm WE7U-3 To APRS [23:13:20].Test... 1:Fm WE7U-3 To APRS Via RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1 [23:51:46].Testing this darned thing!... */ //**************************************************************** // get device name only (the portion at the end of the full path) // device_name current full name of device //**************************************************************** char *get_device_name_only(char *device_name) { int i,len,done; if (device_name == NULL) { return(NULL); } done = 0; len = (int)strlen(device_name); for(i = len; i > 0 && !done; i--) { if(device_name[i] == '/') { device_name += (i+1); done = 1; } } return(device_name); } //*********************************************************** // Get Open Device // // if device is available this will return the port # // otherwise a -1 will be returned in error. //*********************************************************** int get_open_device(void) { int i, found; begin_critical_section(&devices_lock, "interface.c:get_open_device" ); found = -1; for(i = 0; i < MAX_IFACE_DEVICES && found == -1; i++) { if (devices[i].device_type == DEVICE_NONE) { found = i; break; } } end_critical_section(&devices_lock, "interface.c:get_open_device" ); if (found == -1) { popup_message(langcode("POPEM00004"),langcode("POPEM00017")); } return(found); } //*********************************************************** // Get Device Status // // this will return the device status for the port specified //*********************************************************** int get_device_status(int port) { int stat; if (begin_critical_section(&port_data_lock, "interface.c:get_device_status(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } stat = port_data[port].status; if (end_critical_section(&port_data_lock, "interface.c:get_device_status(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(stat); } //*********************************************************** // channel_data() // // Takes data read in from a port and adds it to the // incoming_data_queue. If queue is full, waits for queue to have // space before continuing. // // port # // string is the string of data // length is the length of the string. If 0 then use strlen() // on the string itself to determine the length. // // Note that decode_ax25_header() and perhaps other routines may // increase the length of the string while processing. We need to // send a COPY of our input string off to the decoding routines for // this reason, and the size of the buffer must be MAX_LINE_SIZE // for this reason also. //*********************************************************** void channel_data(int port, unsigned char *string, volatile int length) { volatile int max; struct timeval tmv; // Some messiness necessary because we're using xastir_mutex's // instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex1; pthread_mutex_t *cleanup_mutex2; // This variable defined as volatile to quash a GCC warning on some // platforms that "process_it" might be "clobbered" by a longjmp or // vfork. There is a longjmp in forked_getaddrinfo, and somehow this // function gets involved somewhere. If the compiler optimizes this // function just right, putting process_it into a register, that fouls // things up. Declaring volatile silences the warning by removing // the possibility of clobbering by longjmp. volatile int process_it = 0; // Save backup copies of the incoming string and the previous // string. Used for debugging purposes. If we get a segfault, // we can print out the last two messages received. xastir_snprintf((char *)incoming_data_copy_previous, sizeof(incoming_data_copy_previous), "%s", incoming_data_copy); xastir_snprintf((char *)incoming_data_copy, sizeof(incoming_data_copy), "Port%d:%s", port, string); max = 0; if (string == NULL) { return; } if (string[0] == '\0') { return; } if (length == 0) { // Compute length of string including terminator length = strlen((const char *)string) + 1; } // Check for excessively long packets. These might be TCP/IP // packets or concatenated APRS packets. In any case it's some // kind of garbage that we don't want to try to parse. // Note that for binary data (WX stations and KISS packets), the // strlen() function may not work correctly. if (length > MAX_LINE_SIZE) // Too long! { if (debug_level & 1) { fprintf(stderr,"\nchannel_data: LONG packet:%d, Dumping it:\n%s\n", length, string); } string[0] = '\0'; // Truncate it to zero length return; } // Install the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. We must first get the pthread_mutex_t address: cleanup_mutex1 = &output_data_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex1); // pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex1); // This protects channel_data from being run by more than one // thread at the same time. if (begin_critical_section(&output_data_lock, "interface.c:channel_data(1)" ) > 0) { fprintf(stderr,"output_data_lock, Port = %d\n", port); } if (length > 0) { // Install the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for the // thread to have this work properly. We must first get the // pthread_mutex_t address. cleanup_mutex2 = &data_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex2); // pthread_cleanup_push(void (*pthread_mutex_unlock)(void *), (void *)cleanup_mutex2); // if (begin_critical_section(&data_lock, "interface.c:channel_data(2)" ) > 0) // fprintf(stderr,"data_lock, Port = %d\n", port); // If it's any of three types of GPS ports and is a GPRMC or // GPGGA string, just stick it in one of two global // variables for holding such strings. UpdateTime() can // come along and process/clear-out those strings at the // gps_time interval. // switch(port_data[port].device_type) { case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_NET_GPSD: // One of the three types of interfaces that might // send in a lot of GPS data constantly. Save only // GPRMC and GPGGA strings into global variables. // Drop other GPS strings on the floor. // if ( (length > 7) && (isRMC((char *)string))) { xastir_snprintf(gprmc_save_string, sizeof(gprmc_save_string), "%s", string); gps_port_save = port; process_it = 0; } else if ( (length > 7) && (isGGA((char *)string))) { xastir_snprintf(gpgga_save_string, sizeof(gpgga_save_string), "%s", string); gps_port_save = port; process_it = 0; } else { // It's not one of the GPS strings we're looking // for. It could be another GPS string, a // partial GPS string, or a full/partial TNC // string. Drop the string on the floor unless // it's an HSP interface. // if (port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { // Decode the string normally. process_it++; } } break; // We need to make sure that the variables stating that a string is // available are reset in any case. Look at how/where data_avail is // reset. We may not care if we just wait for data_avail to be // cleared before writing to the string again. default: // Not one of the above three types, decode // the string normally. process_it++; break; } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup // routine initiates an unlock before the thread dies. We // must be in deferred cancellation mode for the thread to // have this work properly. // pthread_cleanup_pop(0); if (debug_level & 1) { fprintf(stderr,"Channel data on Port %d [%s]\n",port,(char *)string); } if (process_it) { // Wait for empty space in queue while (push_incoming_data(string, length, port) && max < 5400) { sched_yield(); // Yield to other threads tmv.tv_sec = 0; tmv.tv_usec = 2; // 2 usec (void)select(0,NULL,NULL,NULL,&tmv); max++; } } } if (end_critical_section(&output_data_lock, "interface.c:channel_data(4)" ) > 0) { fprintf(stderr,"output_data_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. // pthread_cleanup_pop(0); } //********************************* START AX.25 ******************************** #ifdef HAVE_LIBAX25 // stolen from libax25-0.0.9 and modified to set digipeated bit based on '*' int my_ax25_aton_arglist(char *call[], struct full_sockaddr_ax25 *sax) { char *bp; char *addrp; int n = 0; int argp = 0; int len = 0; int star = 0; addrp = sax->fsa_ax25.sax25_call.ax25_call; do { /* Fetch one callsign token */ if ((bp = call[argp++]) == NULL) { break; } /* Check for the optional 'via' syntax */ if (n == 1 && (strcasecmp(bp, "V") == 0 || strcasecmp(bp, "VIA") == 0)) { continue; } /* Process the token (Removes the star before the ax25_aton_entry call because it would call it a bad callsign.) */ len = strlen(bp); if (len > 1 && bp[len-1] == '*') { star = 1; bp[len-1] = '\0'; } else { star = 0; } if (ax25_aton_entry(bp, addrp) == -1) { popup_message("Bad callsign!", bp); return -1; } if (n >= 1 && star) { addrp[6] |= 0x80; // set digipeated bit if we had found a star } n++; if (n == 1) { addrp = sax->fsa_digipeater[0].ax25_call; /* First digipeater address */ } else { addrp += sizeof(ax25_address); } } while (n < AX25_MAX_DIGIS && call[argp] != NULL); /* Tidy up */ sax->fsa_ax25.sax25_ndigis = n - 1; sax->fsa_ax25.sax25_family = AF_AX25; return sizeof(struct full_sockaddr_ax25); } #endif // HAVE_LIBAX25 //*********************************************************** // ui connect: change call and proto paths and reconnect net // port device to work with //*********************************************************** int ui_connect( int port, char *to[]) { int s = -1; #ifdef HAVE_LIBAX25 int sockopt; int addrlen = sizeof(struct full_sockaddr_ax25); struct full_sockaddr_ax25 axbind, axconnect; /* char *arg[2]; */ char *portcall; char temp[200]; if (to == NULL) { return(-1); } if (*to[0] == '\0') { return(-1); } /* * Handle incoming data * * Parse the passed values for correctness. */ axconnect.fsa_ax25.sax25_family = AF_AX25; axbind.fsa_ax25.sax25_family = AF_AX25; axbind.fsa_ax25.sax25_ndigis = 1; if ((portcall = ax25_config_get_addr(port_data[port].device_name)) == NULL) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00005"), port_data[port].device_name); popup_message(langcode("POPEM00004"),temp); return -1; } if (ax25_aton_entry(portcall, axbind.fsa_digipeater[0].ax25_call) == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00006"), port_data[port].device_name); popup_message(langcode("POPEM00004"), temp); return -1; } if (ax25_aton_entry(port_data[port].ui_call, axbind.fsa_ax25.sax25_call.ax25_call) == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00007"), port_data[port].ui_call); popup_message(langcode("POPEM00004"),temp); return -1; } if (my_ax25_aton_arglist(to, &axconnect) == -1) { popup_message(langcode("POPEM00004"),langcode("POPEM00008")); return -1; } /* * Open the socket into the kernel. */ if ((s = socket(AF_AX25, SOCK_DGRAM, 0)) < 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00009"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } /* * Set our AX.25 callsign and AX.25 port callsign accordingly. */ ENABLE_SETUID_PRIVILEGE; if (bind(s, (struct sockaddr *)&axbind, addrlen) != 0) { DISABLE_SETUID_PRIVILEGE; xastir_snprintf(temp, sizeof(temp), langcode("POPEM00010"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } DISABLE_SETUID_PRIVILEGE; if (devices[port].relay_digipeat) { sockopt = 1; } else { sockopt = 0; } if (setsockopt(s, SOL_AX25, AX25_IAMDIGI, &sockopt, sizeof(int))) { fprintf(stderr,"AX25 IAMDIGI setsockopt FAILED"); return -1; } if (debug_level & 2) { fprintf(stderr,"*** Connecting to UNPROTO port for transmission...\n"); } /* * Lets try and connect to the far end. */ if (connect(s, (struct sockaddr *)&axconnect, addrlen) != 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00011"), strerror(errno)); popup_message(langcode("POPEM00004"),temp); return -1; } /* * We got there. */ #endif /* HAVE_LIBAX25 */ return s; } //************************************************************ // data_out_ax25() // // Send string data out ax25 port //************************************************************ static void data_out_ax25(int port, unsigned char *string) { static char ui_mycall[10]; char *temp; char *to[10]; int quantity; if (string == NULL) { return; } if (string[0] == '\0') { return; } if (begin_critical_section(&port_data_lock, "interface.c:data_out_ax25(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // Check for commands (start with Control-C) if (string[0] == (unsigned char)3) // Yes, process TNC type commands { // Look for MYCALL command if (strncmp((char *)&string[1],"MYCALL", 6) == 0) { // Found MYCALL. Snag the callsign and put it into the // structure for the port // Look for whitespace/CR/LF (end of "MYCALL") temp = strtok((char *)&string[1]," \t\r\n"); if (temp != NULL) { // Look for whitespace/CR/LF (after callsign) temp = strtok(NULL," \t\r\n"); if (temp != NULL) { substr(ui_mycall, temp, APRS_MAX_CALLSIGN_LEN); xastir_snprintf(port_data[port].ui_call, sizeof(port_data[port].ui_call), "%s", ui_mycall); if (debug_level & 2) { fprintf(stderr,"*** MYCALL %s\n",port_data[port].ui_call); } } } } // Look for UNPROTO command else if (strncmp((char *)&string[1],"UNPROTO", 6) == 0) { quantity = 0; // Number of callsigns found // Look for whitespace/CR/LF (end of "UNPROTO") temp = strtok((char *)&string[1]," \t\r\n"); if (temp != NULL) // Found end of "UNPROTO" { // Find first callsign (destination call) temp = strtok(NULL," \t\r\n"); if (temp != NULL) { to[quantity++] = temp; // Store it // Look for "via" or "v" temp = strtok(NULL," \t\r\n"); while (temp != NULL) // Found it { // Look for the rest of the callsigns (up to // eight of them) temp = strtok(NULL," ,\t\r\n"); if (temp != NULL) { if (quantity < APRS_MAX_CALLSIGN_LEN) { to[quantity++] = temp; } } } to[quantity] = NULL; if (debug_level & 2) { int i = 1; fprintf(stderr,"UNPROTO %s VIA ",*to); while (to[i] != NULL) { fprintf(stderr,"%s,",to[i++]); } fprintf(stderr,"\n"); } if (port_data[port].channel2 != -1) { if (debug_level & 2) { fprintf(stderr,"Write DEVICE is UP! Taking it down to reconfigure UI path.\n"); } (void)close(port_data[port].channel2); port_data[port].channel2 = -1; } if ((port_data[port].channel2 = ui_connect(port,to)) < 0) { popup_message(langcode("POPEM00004"),langcode("POPEM00012")); port_data[port].errors++; } else // Port re-opened and re-configured { if (debug_level & 2) { fprintf(stderr,"WRITE port re-opened after UI path change\n"); } } } } } } // Else not a command, write the data directly out to the port else { if (debug_level & 2) { fprintf(stderr,"*** DATA: %s\n",(char *)string); } if (port_data[port].channel2 != -1) { if (write(port_data[port].channel2, string, strlen((char *)string)) != -1) { /* we don't actually care if this returns -1 or not but newer linux systems hate when we ignore the return value of write() */ } } else if (debug_level & 2) { fprintf(stderr,"\nPort down for writing!\n\n"); } } if (end_critical_section(&port_data_lock, "interface.c:data_out_ax25(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } // fetch16bits // // Modifies: Nothing. // int fetch16bits(unsigned char *str) { int i; i = *str++; i = i << 8; i = i | *str++; return(i); } // fetch32bits // // Modifies: Nothing. // int fetch32bits(unsigned char *str) { int i; i = *str++; i = i << 8; i = i | *str++; i = i << 8; i = i | *str++; i = i << 8; i = i | *str; return(i); } //*********************************************************** // process_ax25_packet() // // bp raw packet data // len length of raw packet data // buffer buffer to write readable packet data to // buffer_size max length of buffer // // Note that db.c:decode_ax25_header does much the same thing for // Serial KISS interface packets. Consider combining the two // functions. process_ax25_packet() would be the earlier and more // thought-out function. //*********************************************************** char *process_ax25_packet(unsigned char *bp, unsigned int len, char *buffer, int buffer_size) { int i,j; unsigned int l; unsigned int digis; unsigned char source[10]; unsigned char dest[10]; unsigned char digi[10][10]; unsigned char digi_h[10]; unsigned int ssid; unsigned char message[513]; if ( (bp == NULL) || (buffer == NULL) ) { return(NULL); } /* clear buffer */ buffer[0] = '\0'; if (*bp != (unsigned char)0) { return(NULL); /* not a DATA packet */ } // We have a KISS packet here, so we know that the first // character is a flag character. Skip over it. bp++; len--; // Check the length to make sure that we don't have an empty // packet. if (!bp || !len) { return(NULL); } // Check for minimum KISS frame bytes. if (len < 15) { return(NULL); } if (bp[1] & 1) /* Compressed FlexNet Header */ { return(NULL); } /* Destination of frame */ j = 0; for(i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { dest[j++] = bp[i] >> 1; } } ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { dest[j++] = '-'; if ((ssid / 10) != 0) { dest[j++] = '1'; } ssid = (ssid % 10); dest[j++] = (unsigned char)ssid + (unsigned char)'0'; } dest[j] = '\0'; bp += 7; len -= 7; /* Source of frame */ j = 0; for(i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { source[j++] = bp[i] >> 1; } } ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { source[j++] = '-'; if ((ssid / 10) != 0) { source[j++] = '1'; } source[j++] = (unsigned char)(ssid % 10) + (unsigned char)'0'; // source[j++] = (unsigned char)ssid + (unsigned char)'0'; } source[j] = '\0'; bp += 7; len -= 7; // by KJ5O - test for proper extraction of source call and ssid // fprintf(stderr, "|KJ5O-test| %s-%d\n", source, ssid); /* Digipeaters */ digis = 0; while ((!(bp[-1] & 1)) && (len >= 7)) { /* Digi of frame */ if (digis != 10) { j = 0; for (i = 0; i < 6; i++) { if ((bp[i] &0xfe) != (unsigned char)0x40) { digi[digis][j++] = bp[i] >> 1; } } digi_h[digis] = (bp[6] & 0x80); ssid = (unsigned int)( (bp[6] & 0x1e) >> 1 ); if (ssid != 0) { digi[digis][j++] = '-'; if ((ssid / 10) != 0) { digi[digis][j++] = '1'; } ssid = (ssid % 10); digi[digis][j++] = (unsigned char)ssid + (unsigned char)'0'; } digi[digis][j] = '\0'; digis++; } bp += 7; len -= 7; } if (!len) { return(NULL); } /* We are now at the primitive bit */ i = (int)(*bp++); len--; /* strip the poll-bit from the primitive */ i = i & (~0x10); /* return if this is not an UI frame (= 0x03) */ if(i != 0x03) { return(NULL); } /* no data left */ if (!len) { return(NULL); } if(*bp != (unsigned char)0xF0) // APRS PID { // We _don't_ have an APRS packet return(NULL); } // We have what looks like a valid KISS-frame containing APRS // protocol data. bp++; len--; l = 0; while (len) { i = (int)(*bp++); if ((i != (int)'\n') && (i != (int)'\r')) { if (l < 512) { message[l++] = (unsigned char)i; } } len--; } /* add terminating '\0' to allow handling as a string */ message[l] = '\0'; xastir_snprintf(buffer, buffer_size, "%s", source); /* * if there are no digis or the first digi has not handled the * packet then this is directly from the source, mark it with * a "*" in that case */ strncat(buffer, ">", buffer_size - 1 - strlen(buffer)); /* destination is at the beginning of the chain, because it is */ /* needed so MIC-E packets can be decoded correctly. */ /* this may be changed in the future but for now leave it here -FG */ strncat(buffer, (char *)dest, buffer_size - 1 - strlen(buffer)); for(i = 0; i < (int)digis; i++) { strncat(buffer, ",", buffer_size - 1 - strlen(buffer)); strncat(buffer, (char *)digi[i], buffer_size - 1 - strlen(buffer)); /* at the last digi always put a '*' when h_bit is set */ if (i == (int)(digis - 1)) { if (digi_h[i] == (unsigned char)0x80) { /* this digi must have transmitted the packet */ strncat(buffer, "*", buffer_size - 1 - strlen(buffer)); } } else { if (digi_h[i] == (unsigned char)0x80) { /* only put a '*' when the next digi has no h_bit */ if (digi_h[i + 1] != (unsigned char)0x80) { /* this digi must have transmitted the packet */ strncat(buffer, "*", buffer_size - 1 - strlen(buffer)); } } } } strncat(buffer, ":", buffer_size - 1 - strlen(buffer)); //Copy into only the free space in buffer. strncat( buffer, (char *)message, MAX_DEVICE_BUFFER - 1 - strlen(buffer)); // And null-terminate it to make sure. buffer[MAX_DEVICE_BUFFER - 1] = '\0'; return(buffer); } //********************************************************* // AX25 port INIT // // port is port# used //********************************************************* int ax25_init(int port) { /* COMMENT:tested this Seems to work fine as ETH_P_AX25 on newer linux kernels (and you see your own transmissions but it is not good for older linux kernels and FreeBSD -FG */ #ifdef HAVE_LIBAX25 int proto = PF_AX25; char temp[200]; char *dev = NULL; #endif // HAVE_LIBAX25 if (begin_critical_section(&port_data_lock, "interface.c:ax25_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } /* clear port active */ port_data[port].active = DEVICE_NOT_IN_USE; /* clear port status */ port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); #ifdef HAVE_LIBAX25 if (ax25_ports_loaded == 0) { /* port file has not been loaded before now */ if (ax25_config_load_ports() == 0) { fprintf(stderr, "ERROR: problem with axports file\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00013")); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } /* we can only load the port file once!!! so do not load again */ ax25_ports_loaded = 1; } if (port_data[port].device_name != NULL) { if ((dev = ax25_config_get_dev(port_data[port].device_name)) == NULL) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00014"), port_data[port].device_name); popup_message(langcode("POPEM00004"),temp); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } } /* COMMENT: tested this AF_INET is CORRECT -FG */ // We keep the old socket number // around now, so have to start a new socket in all cases to make it work. ENABLE_SETUID_PRIVILEGE; #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 port_data[port].channel = socket(PF_INET, SOCK_DGRAM, htons(proto)); // proto = AF_AX25 #else // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 port_data[port].channel = socket(PF_INET, SOCK_PACKET, htons(proto)); #endif // __GLIBC__ >= 2 && __GLIBC_MINOR >= 3 DISABLE_SETUID_PRIVILEGE; if (port_data[port].channel == -1) { perror("socket"); if (end_critical_section(&port_data_lock, "interface.c:ax25_init(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return -1; } /* port active */ port_data[port].active = DEVICE_IN_USE; /* port status */ port_data[port].status = DEVICE_UP; // Show the latest status in the interface control dialog update_interface_list(); #else /* HAVE_LIBAX25 */ fprintf(stderr,"AX.25 support not compiled into Xastir!\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00021")); #endif /* HAVE_LIBAX25 */ if (end_critical_section(&port_data_lock, "interface.c:ax25_init(5)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(1); } //********************************* STOP AX.25 ******************************** //*************************** START SERIAL PORT FUNCTIONS ******************************** //****************************************************** // command file to tnc port // port to send config data to // Filename containing the config data //****************************************************** int command_file_to_tnc_port(int port, char *filename) { FILE *f; char line[MAX_LINE_SIZE+1]; char command[MAX_LINE_SIZE+5]; int i; char cin; int error; struct stat file_status; if (filename == NULL) { return(-1); } // Check file status if (stat(filename, &file_status) < 0) { fprintf(stderr, "Couldn't stat file: %s\n", filename); fprintf(stderr, "Skipping send to TNC\n"); return(-1); } // Check that it is a regular file if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "File is not a regular file: %s\n", filename); fprintf(stderr, "Skipping send to TNC\n"); return(-1); } error = 0; i = 0; f = fopen(filename,"r"); if (f != NULL) { int send_ctrl_C = 1; line[0] = (char)0; while (!feof(f) && error != -1) { if (fread(&cin,1,1,f) == 1) { // Check for / if (cin != (char)10 && cin != (char)13) { // If NOT or if (i < MAX_LINE_SIZE) { // Add to buffer line[i++] = cin; line[i] = (char)0; } } else // Found a or , process line { i = 0; // Check whether comment or zero-length line if (line[0] != '#' && strlen(line) > 0) { // Line looks good. Send it to the TNC. if (send_ctrl_C) { // Control-C desired xastir_snprintf(command, sizeof(command), "%c%s\r", (char)03, // Control-C line); } else { // No Control-C desired xastir_snprintf(command, sizeof(command), "%s\r", line); } if (debug_level & 2) { fprintf(stderr,"CMD:%s\n",command); } port_write_string(port,command); line[0] = (char)0; // Set flag to default condition send_ctrl_C = 1; } else // Check comment to see if it is a META { // command // Should we make these ignore white-space? if (strncasecmp(line, "##META <", 8) == 0) { // Found a META command, process it if (strncasecmp(line+8, "delay", 5) == 0) { usleep(500000); // Sleep 500ms } else if (strncasecmp(line+8, "no-ctrl-c", 9) == 0) { // Reset the flag send_ctrl_C = 0; } else { fprintf(stderr, "Unrecognized ##META command: %s\n", line); } } } } } } (void)fclose(f); } else { if (debug_level & 2) { fprintf(stderr,"Could not open TNC command file: %s\n",filename); } } return(error); } //*********************************************************** // port_dtr INIT // port is port# used // dtr 1 is down, 0 is normal(up) //*********************************************************** void port_dtr(int port, int dtr) { // It looks like we have two methods of getting this to compile on // CYGWIN, getting rid of the entire procedure contents, and getting // rid of the TIO* code. One method or the other should work to get // it compiled. We shouldn't need both. int sg; /* check for 1 or 0 */ dtr = (dtr & 0x1); if (begin_critical_section(&port_data_lock, "interface.c:port_dtr(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP && port_data[port].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { port_data[port].dtr = dtr; if (debug_level & 2) { fprintf(stderr,"DTR %d\n",port_data[port].dtr); } #ifdef TIOCMGET ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMGET, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMGET sg &= 0xff; #ifdef TIOCM_DTR // ugly HPUX hack - n8ysz 20041206 #ifndef MDTR #define MDTR 99999 #if (TIOCM_DTR == 99999) #include #endif #endif // end ugly hack sg = TIOCM_DTR; #endif // TIOCM_DIR if (dtr) { dtr &= ~sg; #ifdef TIOCMBIC ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMBIC, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMBIC if (debug_level & 2) { fprintf(stderr,"Down\n"); } // statusline(langcode("BBARSTA026"),1); } else { dtr |= sg; #ifdef TIOCMBIS ENABLE_SETUID_PRIVILEGE; (void)ioctl(port_data[port].channel, TIOCMBIS, &sg); DISABLE_SETUID_PRIVILEGE; #endif // TIOCMBIS if (debug_level & 2) { fprintf(stderr,"UP\n"); } // statusline(langcode("BBARSTA027"),1); } } if (end_critical_section(&port_data_lock, "interface.c:port_dtr(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } //*********************************************************** // port_dtr INIT // port is port# used // dtr 1 is down, 0 is normal(up) //*********************************************************** void dtr_all_set(int dtr) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS && port_data[i].status == DEVICE_UP) { port_dtr(i,dtr); } } } //*********************************************************** // Serial port close. Remove the lockfile as well. // port is port# used //*********************************************************** int serial_detach(int port) { char fn[600]; int ok; ok = -1; if (begin_critical_section(&port_data_lock, "interface.c:serial_detach(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP) { // Close port first (void)tcsetattr(port_data[port].channel, TCSANOW, &port_data[port].t_old); if (close(port_data[port].channel) == 0) { port_data[port].status = DEVICE_DOWN; usleep(200); port_data[port].active = DEVICE_NOT_IN_USE; ok = 1; // Show the latest status in the interface control dialog update_interface_list(); } else { if (debug_level & 2) { fprintf(stderr,"Could not close port %s\n",port_data[port].device_name); } port_data[port].status = DEVICE_DOWN; usleep(200); port_data[port].active = DEVICE_NOT_IN_USE; // Show the latest status in the interface control dialog update_interface_list(); } // Delete lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (debug_level & 2) { fprintf(stderr,"Delete lock file %s\n",fn); } ENABLE_SETUID_PRIVILEGE; (void)unlink(fn); DISABLE_SETUID_PRIVILEGE; } else { // If we didn't have the port in use, for instance we // weren't able to open it, we should check whether a // lockfile exists for the port and see if another running // process owns the lockfile (the PID of the owner is inside // the lockfile). If not, remove the lockfile 'cuz it may // have been ours from this or a previous run. Note that we // can now run multiple Xastir sessions from a single user, // and the lockfiles must be kept straight between them. If // a lockfile doesn't contain a PID from a running process, // it's fair game to delete the lockfile and/or take over // the port with a new lockfile. // // if (lockfile exists) { // PID = read contents of lockfile // if (PID is running) { // Do nothing, leave the file alone // } // else { // Delete the lockfile // } // } } if (end_critical_section(&port_data_lock, "interface.c:serial_detach(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return(ok); } //*********************************************************** // Serial port INIT // port is port# used //*********************************************************** int serial_init (int port) { FILE *lock; int speed; pid_t mypid = 0; pid_t lockfile_pid = 0; int lockfile_intpid; char fn[600]; uid_t user_id; struct passwd *user_info; char temp[100]; char temp1[100]; pid_t status; int ii; int myerrno; status = -9999; if (begin_critical_section(&port_data_lock, "interface.c:serial_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // clear port_channel port_data[port].channel = -1; // clear port active port_data[port].active = DEVICE_NOT_IN_USE; // clear port status port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); // Check whether we have a port with the same device already // open. Check all ports except this one and check for // DEVICE_IN_USE. If found, check whether the device_name // matches. If a match, skip initializing this port. // for (ii = 0; ii < MAX_IFACE_DEVICES; ii++) { if (ii != port) { if (port_data[ii].active == DEVICE_IN_USE) { if (strcmp(port_data[ii].device_name, port_data[port].device_name) == 0) { // Found a port with the same device_name which // is already active. Skip bringing up another // interface on the same port. return(-1); } } } } // check for lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (filethere(fn) == 1) { // Also look for pid of other process and see if it is a valid lock fprintf(stderr,"Found an existing lockfile %s for this port!\n",fn); lock = fopen(fn,"r"); if (lock != NULL) // We could open it so it must have { // been created by this userid if (fscanf(lock,"%d %99s %99s",&lockfile_intpid,temp,temp1) == 3) { lockfile_pid = (pid_t)lockfile_intpid; #ifdef HAVE_GETPGRP #ifdef GETPGRP_VOID // Won't this one get our process group instead of // the process group for the lockfile? Not of that // much use to us here. status = getpgrp(); #else // GETPGRP_VOID status = getpgrp(lockfile_pid); #endif // GETPGRP_VOID #else // HAVE_GETPGRP status = getpgid(lockfile_pid); #endif // HAVE_GETPGRP } else { // fscanf parsed the wrong number of items. // lockfile is different, perhaps created by some // other program. } (void)fclose(lock); // See whether the existing lockfile is stale. Remove // the file if it belongs to our process group or if the // PID in the file is no longer running. // // The only time we _shouldn't_ delete the file and // claim the port for our own is when the process that // created the lockfile is still running. // Get my process id mypid = getpid(); // If status = -1, the process that created the lockfile // is no longer running and of course will not match // "lockfile_pid", so we can delete it. // // If "lockfile_pid == mypid", then this currently // running instance of Xastir was the one that created // the lockfile and it is again ok to delete it. // if (status != lockfile_pid || lockfile_pid == mypid) { fprintf(stderr,"Lock is stale! Removing it.\n"); ENABLE_SETUID_PRIVILEGE; (void)unlink(fn); DISABLE_SETUID_PRIVILEGE; } else { fprintf(stderr,"Cannot open port: Another program has the lock!\n"); if (end_critical_section(&port_data_lock, "interface.c:serial_init(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return (-1); } } else // Couldn't open it, so the lock must have been { // created by another userid fprintf(stderr,"Cannot open port: Lockfile cannot be opened!\n"); if (end_critical_section(&port_data_lock, "interface.c:serial_init(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } return (-1); } } // Try to open the serial port now ENABLE_SETUID_PRIVILEGE; port_data[port].channel = open(port_data[port].device_name, O_RDWR|O_NOCTTY); myerrno = errno; DISABLE_SETUID_PRIVILEGE; if (port_data[port].channel == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not open channel on port %d!\n",port); } switch (myerrno) { case EACCES: fprintf(stderr,"\tEACCESS ERROR\n"); break; case EEXIST: fprintf(stderr,"\tEEXIST ERROR\n"); break; case EFAULT: fprintf(stderr,"\tEFAULT ERROR\n"); break; case EISDIR: fprintf(stderr,"\tEISDIR ERROR\n"); break; case ELOOP: fprintf(stderr,"\tELOOP ERROR\n"); break; case EMFILE: fprintf(stderr,"\tEMFILE ERROR\n"); break; case ENAMETOOLONG: fprintf(stderr,"\tENAMETOOLONG ERROR\n"); break; case ENFILE: fprintf(stderr,"\tEMFILE ERROR\n"); break; case ENODEV: fprintf(stderr,"\tENODEV ERROR\n"); break; case ENOENT: fprintf(stderr,"\tENOENT ERROR\n"); break; case ENOMEM: fprintf(stderr,"\tENOMEM ERROR\n"); break; case ENOSPC: fprintf(stderr,"\tENOSPC ERROR\n"); break; case ENOTDIR: fprintf(stderr,"\tENOTDIR ERROR\n"); break; case ENXIO: fprintf(stderr,"\tENXIO ERROR\n"); break; case EOVERFLOW: fprintf(stderr,"\tEOVERFLOW ERROR\n"); break; case EPERM: fprintf(stderr,"\tEPERM ERROR\n"); break; case EROFS: fprintf(stderr,"\tEROFS ERROR\n"); break; case ETXTBSY: fprintf(stderr,"\tETXTBSY ERROR\n"); break; default: fprintf(stderr,"\tOTHER ERROR\n"); break; } return (-1); } // Attempt to create the lockfile xastir_snprintf(fn, sizeof(fn), "/var/lock/LCK..%s", get_device_name_only(port_data[port].device_name)); if (debug_level & 2) { fprintf(stderr,"Create lock file %s\n",fn); } ENABLE_SETUID_PRIVILEGE; lock = fopen(fn,"w"); DISABLE_SETUID_PRIVILEGE; if (lock != NULL) { // get my process id for lockfile mypid = getpid(); // get user info user_id = getuid(); user_info = getpwuid(user_id); xastir_snprintf(temp, sizeof(temp), "%s", user_info->pw_name); fprintf(lock,"%9d %s %s",(int)mypid,"xastir",temp); (void)fclose(lock); // We've successfully created our own lockfile } else { // lock failed if (debug_level & 2) { fprintf(stderr,"Warning: Failed opening LCK file! Continuing on...\n"); } /* if we can't create lockfile don't fail! if (end_critical_section(&port_data_lock, "interface.c:serial_init(5)" ) > 0) fprintf(stderr,"port_data_lock, Port = %d\n", port); return (-1);*/ } // get port attributes for new and old if (tcgetattr(port_data[port].channel, &port_data[port].t) != 0) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(6)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not get t port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcgetattr(port_data[port].channel, &port_data[port].t_old) != 0) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(7)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not get t_old port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } // set time outs port_data[port].t.c_cc[VMIN] = (cc_t)1; port_data[port].t.c_cc[VTIME] = (cc_t)2; // set port flags port_data[port].t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); port_data[port].t.c_iflag = (tcflag_t)(IGNBRK | IGNPAR); port_data[port].t.c_oflag = (0); port_data[port].t.c_lflag = (0); #ifdef CBAUD speed = (int)(port_data[port].t.c_cflag & CBAUD); #else // CBAUD speed = 0; #endif // CBAUD port_data[port].t.c_cflag = (tcflag_t)(HUPCL|CLOCAL|CREAD); port_data[port].t.c_cflag &= ~PARENB; switch (port_data[port].style) { case(0): // No parity (8N1) port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS8; break; case(1): // Even parity (7E1) port_data[port].t.c_cflag &= ~PARODD; port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS7; break; case(2): // Odd parity (7O1): port_data[port].t.c_cflag |= PARODD; port_data[port].t.c_cflag &= ~CSTOPB; port_data[port].t.c_cflag &= ~CSIZE; port_data[port].t.c_cflag |= CS7; break; default: break; } port_data[port].t.c_cflag |= speed; // set input and out put speed if (cfsetispeed(&port_data[port].t, port_data[port].sp) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(8)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port input speed for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (cfsetospeed(&port_data[port].t, port_data[port].sp) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(9)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port output speed for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcflush(port_data[port].channel, TCIFLUSH) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(10)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not flush data for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } if (tcsetattr(port_data[port].channel,TCSANOW, &port_data[port].t) == -1) { if (end_critical_section(&port_data_lock, "interface.c:serial_init(11)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Could not set port attributes for port %d!\n",port); } // Close the port and remove the lock. serial_detach(port); return (-1); } // clear port active port_data[port].active = DEVICE_IN_USE; // clear port status port_data[port].status = DEVICE_UP; // Show the latest status in the interface control dialog update_interface_list(); if (end_critical_section(&port_data_lock, "interface.c:serial_init(12)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } // return good condition return (1); } //*************************** STOP SERIAL PORT FUNCTIONS ******************************** //***************************** START NETWORK FUNCTIONS ********************************* //************************************************************** // net_connect_thread() // Temporary thread used to start up a socket. //************************************************************** static void* net_connect_thread(void *arg) { int port; volatile int ok = -1; int result=-1; int flag; //int stat; struct addrinfo *res; // Some messiness necessary because we're using // xastir_mutex's instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex; if (debug_level & 2) { fprintf(stderr,"net_connect_thread start\n"); } port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); for (res = port_data[port].addr_list; res; res = res->ai_next) { pthread_testcancel(); // Check for thread termination request port_data[port].channel = socket(res->ai_family, res->ai_socktype, res->ai_protocol); pthread_testcancel(); // Check for thread termination request if (port_data[port].channel == -1) { fprintf(stderr, "Socket creation for type (%d, %d, %d) failed: %s\n", res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) ); fprintf(stderr, "This may be OK if we have more to try.\n"); continue; } if (debug_level & 2) { fprintf(stderr,"We have a socket to use\n"); } flag = 1; // Turn on the socket keepalive option (void)setsockopt(port_data[port].channel, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)); // Disable the Nagle algorithm (speeds things up) (void)setsockopt(port_data[port].channel, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); if (debug_level & 2) { fprintf(stderr,"after setsockopt\n"); } pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"calling connect(), port: %d\n", port_data[port].socket_port); } result = connect(port_data[port].channel, res->ai_addr, res->ai_addrlen); if (debug_level & 2) { fprintf(stderr,"connect result was: %d\n", result); } if(result == 0 ) { break; } if(result == -1) { fprintf(stderr, "Socket connection for interface %d type (%d, %d, %d) failed: %s\n", port, res->ai_family, res->ai_socktype, res->ai_protocol, strerror(errno) ); if(res->ai_next) { fprintf(stderr, "This is OK since we have more to try.\n"); } close(port_data[port].channel); port_data[port].channel = -1; continue; } } ok = 0; pthread_testcancel(); // Check for thread termination request if (result != -1) { /* connection up */ if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net up, port %d\n",port); } port_data[port].status = DEVICE_UP; ok = 1; // Show the latest status in the interface control dialog update_interface_list(); } else /* net connection failed */ { ok = 0; if (debug_level & 2) { fprintf(stderr,"net_connect_thread():net connection failed, port %d, DEVICE_ERROR ***\n",port); } port_data[port].status = DEVICE_ERROR; // Show the latest status in the interface control dialog update_interface_list(); usleep(100000); // 100ms // Note: Old comments note that it is essential not to shut down // the socket here, because the connection didn't actually happen, // and multithreading could lead to the socket number having // already been reused elsewhere. } // Install the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. We must first get the pthread_mutex_t address: cleanup_mutex = &connect_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex); if (begin_critical_section(&connect_lock, "interface.c:net_connect_thread(2)" ) > 0) { fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port); } port_data[port].connect_status = ok; port_data[port].thread_status = 0; if (end_critical_section(&connect_lock, "interface.c:net_connect_thread(3)" ) > 0) { fprintf(stderr,"net_connect_thread():connect_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this thread // gets killed while the mutex is locked. The cleanup routine // initiates an unlock before the thread dies. We must be in // deferred cancellation mode for the thread to have this work // properly. // pthread_cleanup_pop(0); if (debug_level & 2) { fprintf(stderr,"net_connect_thread terminating itself\n"); } return(NULL); // This should kill the thread } //************************************************************** // net_init() // // This brings up a network connection // // returns -1 on hard error, 0 on time out, 1 if ok //************************************************************** int net_init(int port) { int ok; char st[200]; pthread_t connect_thread; int stat; int wait_on_connect; time_t wait_time; int gai_rc; // Return code from get address info char port_num[16]; struct addrinfo hints; if (begin_critical_section(&port_data_lock, "interface.c:net_init(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } /* set port active */ port_data[port].active = DEVICE_IN_USE; /* clear port status */ port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); ok = -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG; xastir_snprintf(port_num, sizeof(port_num), "%d", port_data[port].socket_port); xastir_snprintf(st, sizeof(st), langcode("BBARSTA019"), port_data[port].device_host_name); statusline(st,1); // Looking up host if(port_data[port].addr_list) { forked_freeaddrinfo(port_data[port].addr_list); port_data[port].addr_list = NULL; } gai_rc = forked_getaddrinfo(port_data[port].device_host_name, port_num, &hints, &port_data[port].addr_list, 13); if(gai_rc == 0) { /* ok try to connect */ if (begin_critical_section(&connect_lock, "interface.c:net_init(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].thread_status = 1; port_data[port].connect_status = -1; // If channel is != -1, we have a socket remaining from a previous // connect attempt. Shutdown and close that socket, then create // a new one. if (port_data[port].channel != -1) // We have a socket already { // Shut down and close the socket pthread_testcancel(); // Check for thread termination request stat = shutdown(port_data[port].channel,2); pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net Shutdown 1 Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms pthread_testcancel(); // Check for thread termination request stat = close(port_data[port].channel); pthread_testcancel(); // Check for thread termination request if (debug_level & 2) { fprintf(stderr,"net_connect_thread():Net Close 1 Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms port_data[port].channel = -1; } if (end_critical_section(&connect_lock, "interface.c:net_init(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Creating new thread\n"); } if (pthread_create(&connect_thread, NULL, net_connect_thread, &port)) { /* error starting thread*/ ok = -1; fprintf(stderr,"Error creating net_connect thread, port %d\n",port); } busy_cursor(appshell); wait_time = sec_now() + NETWORK_WAITTIME; // Set ending time for wait wait_on_connect = 1; while (wait_on_connect && (sec_now() < wait_time)) { if (begin_critical_section(&connect_lock, "interface.c:net_init(4)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } wait_on_connect = port_data[port].thread_status; if (end_critical_section(&connect_lock, "interface.c:net_init(5)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } xastir_snprintf(st, sizeof(st), langcode("BBARSTA025"), wait_time - sec_now() ); statusline(st,1); // Host found, connecting n if (debug_level & 2) { fprintf(stderr,"%d\n", (int)(wait_time - sec_now()) ); } usleep(250000); // 250mS } ok = port_data[port].connect_status; /* thread did not return! kill it */ if ( (sec_now() >= wait_time) // Timed out || (ok != 1) ) // or connection failure of another type { if (debug_level & 2) { fprintf(stderr,"Thread exceeded it's time limit or failed to connect! Port %d\n",port); } if (begin_critical_section(&connect_lock, "interface.c:net_init(6)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Killing thread\n"); } if (pthread_cancel(connect_thread)) { // The only error code we can get here is ESRCH, which means // that the thread number wasn't found. The thread is already // dead, so let's not print out an error code. } if (sec_now() >= wait_time) // Timed out { port_data[port].connect_status = -2; if (debug_level & 2) { fprintf(stderr,"It was a timeout.\n"); } } if (end_critical_section(&connect_lock, "interface.c:net_init(7)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Thread did not return, port %d, DEVICE_ERROR ***\n",port); } // Show the latest status in the interface control dialog update_interface_list(); } if (begin_critical_section(&connect_lock, "interface.c:net_init(8)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } ok = port_data[port].connect_status; if (end_critical_section(&connect_lock, "interface.c:net_init(9)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Net ok: %d, port %d\n", ok, port); } switch (ok) { case 1: /* connection up */ xastir_snprintf(st, sizeof(st), langcode("BBARSTA020"), port_data[port].device_host_name); statusline(st,1); // Connected to ... break; case 0: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA021")); statusline(st,1); // Net Connection Failed! ok = -1; break; case -1: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA022")); statusline(st,1); // Could not bind socket break; case -2: xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018")); statusline(st,1); // Net Connection timed out ok = 0; break; default: break; /*break;*/ } } else if (gai_rc == FAI_TIMEOUT) /* host lookup time out */ { xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA018")); statusline(st,1); // Net Connection timed out port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Host lookup timeout, port %d, DEVICE_ERROR ***\n",port); } // Show the latest status in the interface control dialog update_interface_list(); ok = 0; } else /* Host ip look up failure (no ip address for that host) */ { xastir_snprintf(st, sizeof(st), "%s", langcode("BBARSTA023")); statusline(st,1); // No IP for Host port_data[port].status = DEVICE_ERROR; if (debug_level & 2) { fprintf(stderr,"Host IP lookup failure, port %d, rc %d, DEVICE_ERROR ***\n",port, gai_rc); } // Show the latest status in the interface control dialog update_interface_list(); } if (end_critical_section(&port_data_lock, "interface.c:net_init(10)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"*** net_init is returning a %d ***\n",ok); } return(ok); } //************************************************************** // This shuts down a network connection // //************************************************************** int net_detach(int port) { int ok; int max; int stat; char quiti[2]; if (debug_level & 2) { fprintf(stderr,"Net detach Start, port %d\n",port); } ok = -1; max = 0; if (begin_critical_section(&port_data_lock, "interface.c:net_detach(1)" ) > 0) { fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port); } if (port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP && port_data[port].device_type == DEVICE_NET_STREAM) { if (debug_level & 2) { fprintf(stderr,"net_detach():Found port %d up, shutting it down\n",port); } quiti[0] = (char)4; quiti[1] = (char)0; if (port_data[port].status == DEVICE_UP) { port_write_string(port,quiti); usleep(100000); // 100ms } /* wait to write */ while (port_data[port].status == DEVICE_UP && port_data[port].write_in_pos != port_data[port].write_out_pos && max < 25) { if (debug_level & 2) { fprintf(stderr,"net_detach():Waiting to finish writing data to port %d\n",port); } usleep(100000); // 100ms max++; } } /* Shut down and Close were separated but this would cause sockets to just float around */ /* we don't need to do a shut down on AX_25 devices */ if ( (port_data[port].status == DEVICE_UP) && (port_data[port].device_type != DEVICE_AX25_TNC) ) { stat = shutdown(port_data[port].channel,2); if (debug_level & 2) { fprintf(stderr,"net_detach():Net Shutdown Returned %d, port %d\n",stat,port); } } usleep(100000); // 100ms // We wish to close down the socket (so both ends of the darn thing // go away), but we want to keep the number on those systems that // re-assign the same file descriptor again. This is to prevent // cross-connects from one interface to another in Xastir (big pain!). // Close it stat = close(port_data[port].channel); if (debug_level & 2) { fprintf(stderr,"net_detach():Net Close Returned %d, port %d\n",stat,port); } usleep(100000); // 100ms // Snag a socket again. We'll use it next time around. port_data[port].channel = socket(PF_INET, SOCK_STREAM, 0); ok = 1; } /* close down no matter what */ port_data[port].status = DEVICE_DOWN; //usleep(300); port_data[port].active = DEVICE_NOT_IN_USE; // Show the latest status in the interface control dialog update_interface_list(); if (end_critical_section(&port_data_lock, "interface.c:net_detach(2)" ) > 0) { fprintf(stderr,"net_detach():port_data_lock, Port = %d\n", port); } if (debug_level & 2) { fprintf(stderr,"Net detach stop, port %d\n",port); } return(ok); } //***************************** STOP NETWORK FUNCTIONS ********************************** // This routine changes callsign chars to proper uppercase chars or // numerals, fixes the callsign to six bytes, shifts the letters left by // one bit, and puts the SSID number into the proper bits in the seventh // byte. The callsign as processed is ready for inclusion in an // AX.25 header. // void fix_up_callsign(unsigned char *data, int data_size) { unsigned char new_call[8] = " "; // Start with seven spaces int ssid = 0; int i; int j = 0; int digipeated_flag = 0; // Check whether we've digipeated through this callsign yet. if (strstr((const char *)data,"*") != 0) { digipeated_flag++; } // Change callsign to upper-case and pad out to six places with // space characters. for (i = 0; i < (int)strlen((const char *)data); i++) { data[i] = toupper(data[i]); if (data[i] == '-') // Stop at '-' { break; } else if (data[i] == '*') { } else { new_call[j++] = data[i]; } } new_call[7] = '\0'; // Handle SSID. 'i' should now be pointing at a dash or at the // terminating zero character. if ( (i < (int)strlen((const char *)data)) && (data[i++] == '-') ) // We might have an SSID { if (data[i] != '\0') { ssid = atoi((const char *)&data[i]); } } if (ssid >= 0 && ssid <= 15) { new_call[6] = ssid | 0x30; // Set 2 reserved bits } else // Whacko SSID. Set it to zero { new_call[6] = 0x30; // Set 2 reserved bits } if (digipeated_flag) { new_call[6] = new_call[6] | 0x40; // Set the 'H' bit } // Shift each byte one bit to the left for (i = 0; i < 7; i++) { new_call[i] = new_call[i] << 1; new_call[i] = new_call[i] & 0xfe; } // Write over the top of the input string with the newly // formatted callsign xastir_snprintf((char *)data, data_size, "%s", new_call); } //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- // //WE7U // Modify the other routines that needed binary output so that they // use this routine. // void port_write_binary(int port, unsigned char *data, int length) { int ii,erd; int write_in_pos_hold; erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } // Save the current position, just in case we have trouble write_in_pos_hold = port_data[port].write_in_pos; for (ii = 0; ii < length && !erd; ii++) { // Put character into write buffer and advance pointer port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[ii]; // Check whether we need to wrap back to the start of the // circular buffer if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } // Check whether we just filled our buffer (read/write // pointers are equal). If so, exit gracefully, dumping // this string and resetting the write pointer. if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } // Restore original write_in pos and dump this string port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_binary(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } // Create an AX25 frame and then turn it into a KISS packet. Dump // it into the transmit queue. // void send_ax25_frame(int port, char *source, char *destination, char *path, char *data) { unsigned char temp_source[15]; unsigned char temp_dest[15]; unsigned char temp[15]; unsigned char control[2], pid[2]; unsigned char transmit_txt[MAX_LINE_SIZE*2]; unsigned char transmit_txt2[MAX_LINE_SIZE*2]; unsigned char c; int i, j; int erd; int write_in_pos_hold; // Check whether transmits are disabled globally if (transmit_disable) { return; } // Check whether transmit has been enabled for this interface. // If not, get out while the gettin's good. if (devices[port].transmit_data != 1) { return; } transmit_txt[0] = '\0'; // Format the destination callsign xastir_snprintf((char *)temp_dest, sizeof(temp_dest), "%s", destination); fix_up_callsign(temp_dest, sizeof(temp_dest)); xastir_snprintf((char *)transmit_txt, sizeof(transmit_txt), "%s", temp_dest); // Format the source callsign xastir_snprintf((char *)temp_source, sizeof(temp_source), "%s", source); fix_up_callsign(temp_source, sizeof(temp_source)); strncat((char *)transmit_txt, (char *)temp_source, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Break up the path into individual callsigns and send them one // by one to fix_up_callsign(). If we get passed an empty path, // we merely skip this section and no path gets added to // "transmit_txt". j = 0; temp[0] = '\0'; // Start with empty path if ( (path != NULL) && (strlen(path) != 0) ) { while (path[j] != '\0') { i = 0; while ( (path[j] != ',') && (path[j] != '\0') ) { temp[i++] = path[j++]; } temp[i] = '\0'; if (path[j] == ',') // Skip over comma { j++; } fix_up_callsign(temp, sizeof(temp)); strncat((char *)transmit_txt, (char *)temp, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); } } // Set the end-of-address bit on the last callsign in the // address field transmit_txt[strlen((const char *)transmit_txt) - 1] |= 0x01; // Add the Control byte control[0] = 0x03; control[1] = '\0'; strncat((char *)transmit_txt, (char *)control, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Add the PID byte pid[0] = 0xf0; pid[1] = '\0'; strncat((char *)transmit_txt, (char *)pid, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Append the information chars strncat((char *)transmit_txt, data, sizeof(transmit_txt) - 1 - strlen((char *)transmit_txt)); // Add the KISS framing characters and do the proper escapes. j = 0; transmit_txt2[j++] = KISS_FEND; // Note: This byte is where different interfaces would be // specified: transmit_txt2[j++] = 0x00; for (i = 0; i < (int)strlen((const char *)transmit_txt); i++) { c = transmit_txt[i]; if (c == KISS_FEND) { transmit_txt2[j++] = KISS_FESC; transmit_txt2[j++] = KISS_TFEND; } else if (c == KISS_FESC) { transmit_txt2[j++] = KISS_FESC; transmit_txt2[j++] = KISS_TFESC; } else { transmit_txt2[j++] = c; } } transmit_txt2[j++] = KISS_FEND; // Terminate the string, but don't increment the 'j' counter. // We don't want to send the NULL byte out the KISS interface, // just make sure the string is terminated in all cases. // transmit_txt2[j] = '\0'; //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; for (i = 0; i < j && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt2[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:send_ax25_frame(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } // Send a KISS configuration command to the selected port. // The KISS spec allows up to 16 devices to be configured. We // support that here with the "device" input, which should be // between 0 and 15. The commands accepted are integer values: // // 0x01 TXDELAY // 0x02 P-Persistence // 0x03 SlotTime // 0x04 TxTail // 0x05 FullDuplex // 0x06 SetHardware // 0xff Exit from KISS mode (not implemented yet) // void send_kiss_config(int port, int device, int command, int value) { unsigned char transmit_txt[MAX_LINE_SIZE+1]; int i, j; int erd; int write_in_pos_hold; if (device < 0 || device > 15) { fprintf(stderr,"send_kiss_config: out-of-range value for device\n"); return; } if (command < 1 || command > 6) { fprintf(stderr,"send_kiss_config: out-of-range value for command\n"); return; } if (value < 0 || value > 255) { fprintf(stderr,"send_kiss_config: out-of-range value for value\n"); return; } // Add the KISS framing characters and do the proper escapes. j = 0; transmit_txt[j++] = KISS_FEND; transmit_txt[j++] = (device << 4) | (command & 0x0f); transmit_txt[j++] = value & 0xff; transmit_txt[j++] = KISS_FEND; // Terminate the string, but don't increment the 'j' counter. // We don't want to send the NULL byte out the KISS interface, // just make sure the string is terminated in all cases. // transmit_txt[j] = '\0'; //------------------------------------------------------------------- // Had to snag code from port_write_string() below because our string // needs to have 0x00 chars inside it. port_write_string() can't // handle that case. It's a good thing the transmit queue stuff // could handle it. //------------------------------------------------------------------- erd = 0; if (begin_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; for (i = 0; i < j && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = transmit_txt[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:send_kiss_config(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } //*********************************************************** // port_write_string() // // port is port# used // data is the string to write //*********************************************************** void port_write_string(int port, char *data) { int i,erd; int write_in_pos_hold; if (data == NULL) { return; } if (data[0] == '\0') { return; } erd = 0; if (debug_level & 2) { fprintf(stderr,"CMD:%s\n",data); } if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } write_in_pos_hold = port_data[port].write_in_pos; // Normal Serial/Net output? if (port_data[port].device_type != DEVICE_AX25_TNC) { for (i = 0; i < (int)strlen(data) && !erd; i++) { port_data[port].device_write_buffer[port_data[port].write_in_pos++] = data[i]; if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } if (port_data[port].write_in_pos == port_data[port].write_out_pos) { if (debug_level & 2) { fprintf(stderr,"Port %d Buffer overrun\n",port); } /* clear this restore original write_in pos and dump this string */ port_data[port].write_in_pos = write_in_pos_hold; port_data[port].errors++; erd = 1; } } } // AX.25 port output else { port_data[port].bytes_output += strlen(data); data_out_ax25(port,(unsigned char *)data); /* do for interface indicators */ if (port_data[port].write_in_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_in_pos = 0; } } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write_string(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } } //*********************************************************** // port_read() // // port is port# used // // This function becomes the long-running thread that snags // characters from an interface and passes them off to the // decoding routines. One copy of this is run for each read // thread for each interface. //*********************************************************** void port_read(int port) { unsigned char cin; unsigned char buffer[MAX_DEVICE_BUFFER]; // Only used for AX.25 packets int i; struct timeval tmv; fd_set rd; int group; int binary_wx_data = 0; int max; /* * Some local variables used for checking AX.25 data - PE1DNN * * "from" is used to look up where the data comes from * "from_len" is used to keep the size of sockaddr structure * "dev" is used to keep the name of the interface that * belongs to our port/device_name */ struct sockaddr from; socklen_t from_len; #ifdef HAVE_LIBAX25 char *dev; #endif /* USE_AX25 */ if (debug_level & 2) { fprintf(stderr,"Port %d read start\n",port); } group = 0; max = MAX_DEVICE_BUFFER - 1; cin = (unsigned char)0; // We stay in this read loop until the port is shut down while(port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP) { port_data[port].read_in_pos = 0; port_data[port].scan = 1; while (port_data[port].scan && (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) && (port_data[port].status == DEVICE_UP) ) { int skip = 0; // Handle all EXCEPT AX25_TNC interfaces here if (port_data[port].device_type != DEVICE_AX25_TNC) { // Get one character port_data[port].scan = (int)read(port_data[port].channel,&cin,1); } else // Handle AX25_TNC interfaces { /* * Use recvfrom on a network socket to know from * which interface the packet came - PE1DNN */ #ifdef __solaris__ from_len = (unsigned int)sizeof(from); #else // __solaris__ from_len = (socklen_t)sizeof(from); #endif // __solaris__ port_data[port].scan = recvfrom(port_data[port].channel,buffer, sizeof(buffer) - 1, 0, &from, &from_len); } // Below is code for ALL types of interfaces if (port_data[port].scan > 0 && port_data[port].status == DEVICE_UP ) { if (port_data[port].device_type != DEVICE_AX25_TNC) { port_data[port].bytes_input += port_data[port].scan; // Add character to read buffer } // Handle all EXCEPT AX25_TNC interfaces here if (port_data[port].device_type != DEVICE_AX25_TNC) { // Do special KISS packet processing here. // We save the last character in // port_data[port].channel2, as it is // otherwise only used for AX.25 ports. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { if (port_data[port].channel2 == KISS_FESC) // Frame Escape char { if (cin == KISS_TFEND) // Transposed Frame End char { // Save this char for next time // around port_data[port].channel2 = cin; cin = KISS_FEND; } else if (cin == KISS_TFESC) // Transposed Frame Escape char { // Save this char for next time // around port_data[port].channel2 = cin; cin = KISS_FESC; } else { port_data[port].channel2 = cin; } } else if (port_data[port].channel2 == KISS_FEND) // Frame End char { // Frame start or frame end. Drop // the next character which should // either be another frame end or a // type byte. // Note this "type" byte is where it specifies which KISS interface // the packet came from. We may want to use this later for // multi-drop KISS or other types of KISS protocols. // Save this char for next time // around port_data[port].channel2 = cin; skip++; } else if (cin == KISS_FESC) // Frame Escape char { port_data[port].channel2 = cin; skip++; } else { port_data[port].channel2 = cin; } } // End of first special KISS processing // AGWPE // Process AGWPE packets here. Massage the frames so that they look // like normal serial packets to the Xastir decoding functions? // // We turn on monitoring of packets when we first connect. We now // need to throw away all but the "U" packets, which are unconnected // information packets. // // Check for enough bytes to complete a header (36 bytes). If // enough, check the datalength to see if an entire packet has been // read. If so, run that packet through a conversion routine to // convert it to a TAPR2-style packet. // // Right now we're not taking into account multiple radio ports that // AGWPE is capable of. Just assume that we'll receive from all // radio ports, but transmit out port 0. // if (port_data[port].device_type == DEVICE_NET_AGWPE) { int bytes_available = 0; long frame_length = 0; skip = 1; // Keeps next block of code from // trying to process this data. // Add it to the buffer if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (1) on %d\n",port); } port_data[port].read_in_pos = 0; } bytes_available = port_data[port].read_in_pos - port_data[port].read_out_pos; if (bytes_available < 0) { bytes_available = (bytes_available + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } if (bytes_available >= 36) { // We have a full AGWPE header, // which means we can compute the // frame length. unsigned char count[4]; int my_pointer; // Snag bytes 28-32 of the buffer and compute frame_length my_pointer = (port_data[port].read_out_pos + 28) % MAX_DEVICE_BUFFER; count[0] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[1] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[2] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; count[3] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; frame_length = 0; frame_length = frame_length | (count[0] ); frame_length = frame_length | (count[1] << 8); frame_length = frame_length | (count[2] << 16); frame_length = frame_length | (count[3] << 24); // Have a complete AGWPE packet? If // so, convert it to a more standard // packet format then feed it to our // decoding routines. // if (bytes_available >= (frame_length+36)) { char input_string[MAX_DEVICE_BUFFER]; char output_string[MAX_DEVICE_BUFFER]; int ii,jj,new_length; my_pointer = port_data[port].read_out_pos; jj = 0; for (ii = 0; ii < frame_length+36; ii++) { input_string[jj++] = (unsigned char)port_data[port].device_read_buffer[my_pointer]; my_pointer = (my_pointer + 1) % MAX_DEVICE_BUFFER; } // Add a terminator. We need // this for the raw packets so // that we don't end up getting // portions of strings // concatenated onto the end of // our current packet during // later processing. input_string[jj] = '\0'; my_pointer = port_data[port].read_out_pos; if ( parse_agwpe_packet((unsigned char *)input_string, frame_length+36, (unsigned char *)output_string, &new_length) ) { channel_data(port, (unsigned char *)output_string, new_length+1); // include terminator } for (i = 0; i <= port_data[port].read_in_pos; i++) { port_data[port].device_read_buffer[i] = (char)0; } port_data[port].read_in_pos = 0; } } else { // Not enough for a full header so // we can't compute frame length // yet. Do nothing until we have // more data. } } // End of new AGWPE code // We shouldn't see any AX.25 flag // characters on a KISS interface because // they are stripped out by the KISS code. // What we should see though are KISS_FEND // characters at the beginning of each // packet. These characters are where we // should break the data apart in order to // send strings to the decode routines. It // may be just fine to still break it on \r // or \n chars, as the KISS_FEND should // appear immediately afterwards in // properly formed packets. if ( (!skip) && (cin == (unsigned char)'\r' || cin == (unsigned char)'\n' || port_data[port].read_in_pos >= (MAX_DEVICE_BUFFER - 1) || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) ) || ( (cin == KISS_FEND) && (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) ) && port_data[port].data_type == 0) // If end-of-line { // End serial/net type data send it to the decoder Put a terminating // zero at the end of the read-in data port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; if (port_data[port].status == DEVICE_UP && port_data[port].read_in_pos > 0) { int length; // Compute length of string in // circular queue // KISS TNC sends binary data if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { length = port_data[port].read_in_pos - port_data[port].read_out_pos; if (length < 0) { length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } length++; } else // ASCII data { length = 0; } channel_data(port, (unsigned char *)port_data[port].device_read_buffer, length); // Length of string } for (i = 0; i <= port_data[port].read_in_pos; i++) { port_data[port].device_read_buffer[i] = (char)0; } port_data[port].read_in_pos = 0; } else if (!skip) { // Check for binary WX station data if (port_data[port].data_type == 1 && (port_data[port].device_type == DEVICE_NET_WX || port_data[port].device_type == DEVICE_SERIAL_WX)) { /* BINARY DATA input (WX data ?) */ /* check RS WX200 */ switch (cin) { case 0x8f: case 0x9f: case 0xaf: case 0xbf: case 0xcf: if (group == 0) { port_data[port].read_in_pos = 0; group = (int)cin; switch (cin) { case 0x8f: max = 35; binary_wx_data = 1; break; case 0x9f: max = 34; binary_wx_data = 1; break; case 0xaf: max = 31; binary_wx_data = 1; break; case 0xbf: max = 14; binary_wx_data = 1; break; case 0xcf: max = 27; binary_wx_data = 1; break; default: break; } } break; default: break; } if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (1) on %d\n",port); } port_data[port].read_in_pos = 0; } if (port_data[port].read_in_pos >= max) { if (group != 0) /* ok try to decode it */ { int length = 0; if (binary_wx_data) { length = port_data[port].read_in_pos - port_data[port].read_out_pos; if (length < 0) { length = (length + MAX_DEVICE_BUFFER) % MAX_DEVICE_BUFFER; } length++; } channel_data(port, (unsigned char *)port_data[port].device_read_buffer, length); } max = MAX_DEVICE_BUFFER - 1; group = 0; port_data[port].read_in_pos = 0; } } else /* Normal Data input */ { if (cin == '\0') // OWW WX daemon sends 0x00's! { cin = '\n'; } if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)cin; port_data[port].read_in_pos++; port_data[port].device_read_buffer[port_data[port].read_in_pos] = (char)0; } else { if (debug_level & 2) { fprintf(stderr,"Port read overrun (2) on %d\n",port); } port_data[port].read_in_pos = 0; } } } // Ascii WX station data but no line-ends? if (port_data[port].read_in_pos > MAX_DEVICE_BUFFER_UNTIL_BINARY_SWITCH && (port_data[port].device_type == DEVICE_NET_WX || port_data[port].device_type == DEVICE_SERIAL_WX)) { /* normal data on WX not found do look at data for binary WX */ port_data[port].data_type++; port_data[port].data_type &= 1; port_data[port].read_in_pos = 0; } } // End of non-AX.25 interface code block else // Process ax25 interface data and send to the decoder { /* * Only accept data from our own interface (recvfrom will get * data from all AX.25 interfaces!) - PE1DNN */ #ifdef HAVE_LIBAX25 if (port_data[port].device_name != NULL) { if ((dev = ax25_config_get_dev(port_data[port].device_name)) != NULL) { /* if the data is not from our interface, ignore it! PE1DNN */ if(strcmp(dev, from.sa_data) == 0) { /* Received data from our interface! - process data */ if (process_ax25_packet(buffer, port_data[port].scan, port_data[port].device_read_buffer, sizeof(port_data[port].device_read_buffer)) != NULL) { port_data[port].bytes_input += strlen(port_data[port].device_read_buffer); channel_data(port, (unsigned char *)port_data[port].device_read_buffer, 0); } /* do this for interface indicator in this case we only do it for, data from the correct AX.25 port */ if (port_data[port].read_in_pos < (MAX_DEVICE_BUFFER - 1) ) { port_data[port].read_in_pos += port_data[port].scan; } else { /* no buffer over runs writing a line at a time */ port_data[port].read_in_pos = 0; } } } } #endif /* HAVE_LIBAX25 */ } // End of AX.25 interface code block } else if (port_data[port].status == DEVICE_UP) /* error or close on read */ { port_data[port].errors++; if (port_data[port].scan == 0) { // Should not get this unless the device is down. NOT TRUE! // We seem to also be able to get here if we're closing/restarting // another interface. For that reason I commented out the below // statement so that this interface won't go down. The inactivity // timer solves that issue now anyway. --we7u. port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (debug_level & 2) { fprintf(stderr,"end of file on read, or signal interrupted the read, port %d\n",port); } // Show the latest status in the interface control dialog update_interface_list(); } else { if (port_data[port].scan == -1) { /* Should only get this if an real error occurs */ port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect // Show the latest status in the // interface control dialog update_interface_list(); if (debug_level & 2) { fprintf(stderr,"error on read with error no %d, or signal interrupted the read, port %d, DEVICE_ERROR ***\n", errno,port); switch (errno) { case EINTR: fprintf(stderr,"EINTR ERROR\n"); break; case EAGAIN: fprintf(stderr,"EAGAIN ERROR\n"); break; case EIO: fprintf(stderr,"EIO ERROR\n"); break; case EISDIR: fprintf(stderr,"EISDIR ERROR\n"); break; case EBADF: // Get this one when we terminate nearby threads fprintf(stderr,"EBADF ERROR\n"); break; case EINVAL: fprintf(stderr,"EINVAL ERROR\n"); break; case EFAULT: fprintf(stderr,"EFAULT ERROR\n"); break; default: fprintf(stderr,"OTHER ERROR\n"); break; } } } } } } } if (port_data[port].active == DEVICE_IN_USE) { // We need to delay here so that the thread doesn't use // high amounts of CPU doing nothing. // This select that waits on data and a timeout, so that if data // doesn't come in within a certain period of time, we wake up to // check whether the socket has gone down. Else, we go back into // the select to wait for more data or a timeout. FreeBSD has a // problem if this is less than 1ms. Linux works ok down to 100us. // We don't need it anywhere near that short though. We just need // to check whether the main thread has requested the interface be // closed, and so need to have this short enough to have reasonable // response time to the user. // Set up the select to block until data ready or 100ms // timeout, whichever occurs first. FD_ZERO(&rd); FD_SET(port_data[port].channel, &rd); tmv.tv_sec = 0; tmv.tv_usec = 100000; // 100 ms (void)select(0,&rd,NULL,NULL,&tmv); } } if (debug_level & 2) { fprintf(stderr,"Thread for port %d read down!\n",port); } } //*********************************************************** // port_write() // // port is port# used // // This function becomes the long-running thread that sends // characters to an interface. One copy of this is run for // each write thread for each interface. //*********************************************************** void port_write(int port) { int retval; struct timeval tmv; fd_set wd; int wait_max; unsigned long bytes_input; char write_buffer[MAX_DEVICE_BUFFER]; int quantity; if (debug_level & 2) { fprintf(stderr,"Port %d write start\n",port); } init_critical_section(&port_data[port].write_lock); while(port_data[port].active == DEVICE_IN_USE) { if (port_data[port].status == DEVICE_UP) { // Some messiness necessary because we're using // xastir_mutex's instead of pthread_mutex_t's. pthread_mutex_t *cleanup_mutex; // Install the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for // the thread to have this work properly. We must first // get the pthread_mutex_t address: cleanup_mutex = &port_data[port].write_lock.lock; // Then install the cleanup routine: pthread_cleanup_push((void *)pthread_mutex_unlock, (void *)cleanup_mutex); if (begin_critical_section(&port_data[port].write_lock, "interface.c:port_write(1)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } if ( (port_data[port].write_in_pos != port_data[port].write_out_pos) && port_data[port].status == DEVICE_UP) { // We have something in the buffer to transmit! // Handle control-C delay switch (port_data[port].device_type) { // Use this block for serial interfaces where we // need special delays for control-C character // processing in the TNC. case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_TNC: // Are we trying to send a control-C? If so, wait a // special amount of time _before_ we send // it out the serial port. if (port_data[port].device_write_buffer[port_data[port].write_out_pos] == (char)0x03) { // Sending control-C. if (debug_level & 128) { fprintf(stderr,"Writing command [%x] on port %d, at pos %d\n", *(port_data[port].device_write_buffer + port_data[port].write_out_pos), port, port_data[port].write_out_pos); } wait_max = 0; bytes_input = port_data[port].bytes_input + 40; while ( (port_data[port].bytes_input != bytes_input) && (port_data[port].status == DEVICE_UP) && (wait_max < 100) ) { bytes_input = port_data[port].bytes_input; /*wait*/ FD_ZERO(&wd); FD_SET(port_data[port].channel, &wd); tmv.tv_sec = 0; tmv.tv_usec = 80000l; // Delay 80ms (void)select(0,NULL,&wd,NULL,&tmv); wait_max++; } } // End of command byte wait break; // Use this block for all other interfaces. default: // Do nothing (no delays for control-C's) break; } // End of switch // End of control-C delay code pthread_testcancel(); // Check for thread termination request // Handle method of sending data (1 or multiple chars per TX) switch (port_data[port].device_type) { // Use this block for serial interfaces where we // need character pacing and so must send one // character per write. case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: // Do the actual write here, one character // at a time for these types of interfaces. retval = (int)write(port_data[port].channel, &port_data[port].device_write_buffer[port_data[port].write_out_pos], 1); pthread_testcancel(); // Check for thread termination request if (retval == 1) // We succeeded in writing one byte { port_data[port].bytes_output++; port_data[port].write_out_pos++; if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_out_pos = 0; } } else { /* error of some kind */ port_data[port].errors++; port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (retval == 0) { /* Should not get this unless the device is down */ if (debug_level & 2) { fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port); } } else { if (retval == -1) { /* Should only get this if an real error occurs */ if (debug_level & 2) { fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port); } } } // Show the latest status in the interface control dialog update_interface_list(); } if (serial_char_pacing > 0) { // Character pacing. Delay in between // each character in milliseconds. // Convert to microseconds for this // usleep() call . usleep(serial_char_pacing * 1000); } break; // Use this block for all other interfaces where // we don't need character pacing and we can // send blocks of data in one write. default: // Do the actual write here, one buffer's // worth at a time. // Copy the data to a linear write buffer so // that we can send it all in one shot. // Need to handle the case where only a portion of the data was // written by the write() function. Perhaps just write out an error // message? quantity = 0; while (port_data[port].write_in_pos != port_data[port].write_out_pos) { write_buffer[quantity] = port_data[port].device_write_buffer[port_data[port].write_out_pos]; port_data[port].write_out_pos++; if (port_data[port].write_out_pos >= MAX_DEVICE_BUFFER) { port_data[port].write_out_pos = 0; } quantity++; } retval = (int)write(port_data[port].channel, write_buffer, quantity); pthread_testcancel(); // Check for thread termination request if (retval == quantity) // We succeeded in writing one byte { port_data[port].bytes_output++; } else { /* error of some kind */ port_data[port].errors++; port_data[port].status = DEVICE_ERROR; // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[port].reconnects = -1; // Causes an immediate reconnect if (retval == 0) { /* Should not get this unless the device is down */ if (debug_level & 2) { fprintf(stderr,"no data written %d, DEVICE_ERROR ***\n",port); } } else { if (retval == -1) { /* Should only get this if an real error occurs */ if (debug_level & 2) { fprintf(stderr,"error on write with error no %d, or port %d\n",errno,port); } } } // Show the latest status in the interface control dialog update_interface_list(); } break; } // End of switch // End of handling method of sending data (1 or multiple char per TX) } if (end_critical_section(&port_data[port].write_lock, "interface.c:port_write(2)" ) > 0) { fprintf(stderr,"write_lock, Port = %d\n", port); } // Remove the cleanup routine for the case where this // thread gets killed while the mutex is locked. The // cleanup routine initiates an unlock before the thread // dies. We must be in deferred cancellation mode for // the thread to have this work properly. // pthread_cleanup_pop(0); } if (port_data[port].active == DEVICE_IN_USE) { // Delay here so that the thread doesn't use high // amounts of CPU doing _nothing_. Take this delay out // and the thread will take lots of CPU time. // Try to change this to a select that waits on data and a timeout, // so that if data doesn't come in within a certain period of time, // we wake up to check whether the socket has gone down. Else, we // go back into the select to wait for more data or a timeout. // FreeBSD has a problem if this is less than 1ms. Linux works ok // down to 100us. Theoretically we don't need it anywhere near that // short, we just need to check whether the main thread has // requested the interface be closed, and so need to have this short // enough to have reasonable response time to the user. // Unfortunately it has been reported that having this at 100ms // causes about 9 seconds of delay when transmitting to a KISS TNC, // so it's good to keep this short also. FD_ZERO(&wd); FD_SET(port_data[port].channel, &wd); tmv.tv_sec = 0; tmv.tv_usec = 2000; // Delay 2ms (void)select(0,NULL,&wd,NULL,&tmv); } } if (debug_level & 2) { fprintf(stderr,"Thread for port %d write down!\n",port); } } //*********************************************************** // read_access_port_thread() // // Port read thread. // port is port# used // // open threads for reading data from this port. //*********************************************************** static void* read_access_port_thread(void *arg) { int port; port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); port_read(port); return(NULL); } //*********************************************************** // write_access_port_thread() // // Port write thread. // port is port# used // // open threads for writing data to this port. //*********************************************************** static void* write_access_port_thread(void *arg) { int port; port = *((int *) arg); // This call means we don't care about the return code and won't // use pthread_join() later. Makes threading more efficient. (void)pthread_detach(pthread_self()); port_write(port); return(NULL); } //*********************************************************** // Start port read & write threads // port is port# used // // open threads for reading and writing data to and from this // port. //*********************************************************** int start_port_threads(int port) { int ok; port_id[port] = port; if (debug_level & 2) { fprintf(stderr,"Start port %d threads\n",port); } ok = 1; if (port_data[port].active == DEVICE_IN_USE && port_data[port].status == DEVICE_UP) { if (debug_level & 2) { fprintf(stderr,"*** Startup of read/write threads for port %d ***\n",port); } /* start the two threads */ if (pthread_create(&port_data[port].read_thread, NULL, read_access_port_thread, &port_id[port])) { /* error starting read thread*/ fprintf(stderr,"Error starting read thread, port %d\n",port); port_data[port].read_thread = 0; ok = -1; } else if (pthread_create(&port_data[port].write_thread, NULL, write_access_port_thread, &port_id[port])) { /* error starting write thread*/ fprintf(stderr,"Error starting write thread, port %d\n",port); port_data[port].write_thread = 0; ok = -1; } } else if (debug_level & 2) { fprintf(stderr,"*** Skipping startup of read/write threads for port %d ***\n",port); } if (debug_level & 2) { fprintf(stderr,"End port %d threads\n",port); } return(ok); } //*********************************************************** // Clear Port Data // int port to be cleared //*********************************************************** void clear_port_data(int port, int clear_more) { if (begin_critical_section(&port_data_lock, "interface.c:clear_port_data(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].device_type = -1; port_data[port].active = DEVICE_NOT_IN_USE; port_data[port].status = DEVICE_DOWN; // Show the latest status in the interface control dialog update_interface_list(); port_data[port].device_name[0] = '\0'; port_data[port].device_host_name[0] = '\0'; port_data[port].addr_list = NULL; if (begin_critical_section(&connect_lock, "interface.c:clear_port_data(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].thread_status = -1; port_data[port].connect_status = -1; port_data[port].read_thread = 0; port_data[port].write_thread = 0; if (end_critical_section(&connect_lock, "interface.c:clear_port_data(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } port_data[port].decode_errors = 0; port_data[port].data_type = 0; port_data[port].socket_port = -1; port_data[port].device_host_pswd[0] = '\0'; if (clear_more) { port_data[port].channel = -1; } port_data[port].channel2 = -1; port_data[port].ui_call[0] = '\0'; port_data[port].dtr = 0; port_data[port].sp = -1; port_data[port].style = -1; port_data[port].errors = 0; port_data[port].bytes_input = 0l; port_data[port].bytes_output = 0l; port_data[port].bytes_input_last = 0l; port_data[port].bytes_output_last = 0l; port_data[port].port_activity = 1; // First time-period is a freebie port_data[port].read_in_pos = 0; port_data[port].read_out_pos = 0; port_data[port].write_in_pos = 0; port_data[port].write_out_pos = 0; if (end_critical_section(&port_data_lock, "interface.c:clear_port_data(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } //*********************************************************** // Clear All Port Data //*********************************************************** void clear_all_port_data(void) { int i; for (i = 0; i < MAX_IFACE_DEVICES; i++) { clear_port_data(i,1); } } //*********************************************************** // INIT Device names Data //*********************************************************** void init_device_names(void) { xastir_snprintf(dtype[DEVICE_NONE].device_name, sizeof(dtype[DEVICE_NONE].device_name), "%s", langcode("IFDNL00000")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_TNC].device_name), "%s", langcode("IFDNL00001")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_TNC_HSP_GPS].device_name), "%s", langcode("IFDNL00002")); xastir_snprintf(dtype[DEVICE_SERIAL_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_GPS].device_name), "%s", langcode("IFDNL00003")); xastir_snprintf(dtype[DEVICE_SERIAL_WX].device_name, sizeof(dtype[DEVICE_SERIAL_WX].device_name), "%s", langcode("IFDNL00004")); xastir_snprintf(dtype[DEVICE_NET_STREAM].device_name, sizeof(dtype[DEVICE_NET_STREAM].device_name), "%s", langcode("IFDNL00005")); xastir_snprintf(dtype[DEVICE_AX25_TNC].device_name, sizeof(dtype[DEVICE_AX25_TNC].device_name), "%s", langcode("IFDNL00006")); xastir_snprintf(dtype[DEVICE_NET_GPSD].device_name, sizeof(dtype[DEVICE_NET_GPSD].device_name), "%s", langcode("IFDNL00007")); xastir_snprintf(dtype[DEVICE_NET_WX].device_name, sizeof(dtype[DEVICE_NET_WX].device_name), "%s", langcode("IFDNL00008")); xastir_snprintf(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name, sizeof(dtype[DEVICE_SERIAL_TNC_AUX_GPS].device_name), "%s", langcode("IFDNL00009")); xastir_snprintf(dtype[DEVICE_SERIAL_KISS_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_KISS_TNC].device_name), "%s", langcode("IFDNL00010")); xastir_snprintf(dtype[DEVICE_NET_DATABASE].device_name, sizeof(dtype[DEVICE_NET_DATABASE].device_name), "%s", langcode("IFDNL00011")); xastir_snprintf(dtype[DEVICE_NET_AGWPE].device_name, sizeof(dtype[DEVICE_NET_AGWPE].device_name), "%s", langcode("IFDNL00012")); xastir_snprintf(dtype[DEVICE_SERIAL_MKISS_TNC].device_name, sizeof(dtype[DEVICE_SERIAL_MKISS_TNC].device_name), "%s", langcode("IFDNL00013")); #ifdef HAVE_DB // SQL Database (experimental) xastir_snprintf(dtype[DEVICE_SQL_DATABASE].device_name, sizeof(dtype[DEVICE_SQL_DATABASE].device_name), "%s", langcode("IFDNL00014")); #endif /* HAVE_DB */ } //*********************************************************** // Delete Device. Shuts down active port/ports. //*********************************************************** int del_device(int port) { int ok; char temp[300]; long wait_time = 0; if (debug_level & 2) { fprintf(stderr,"Delete Device start\n"); } ok = -1; switch (port_data[port].device_type) { case(DEVICE_SERIAL_TNC): case(DEVICE_SERIAL_KISS_TNC): case(DEVICE_SERIAL_MKISS_TNC): case(DEVICE_SERIAL_GPS): case(DEVICE_SERIAL_WX): case(DEVICE_SERIAL_TNC_HSP_GPS): case(DEVICE_SERIAL_TNC_AUX_GPS): switch (port_data[port].device_type) { case DEVICE_SERIAL_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC device\n"); } begin_critical_section(&devices_lock, "interface.c:del_device" ); xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device" ); (void)command_file_to_tnc_port(port,get_data_base_dir(temp)); break; case DEVICE_SERIAL_KISS_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial KISS TNC device\n"); } break; case DEVICE_SERIAL_MKISS_TNC: if (debug_level & 2) { fprintf(stderr,"Close a Serial MKISS TNC device\n"); } break; case DEVICE_SERIAL_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial GPS device\n"); } if (using_gps_position) { using_gps_position--; } break; case DEVICE_SERIAL_WX: if (debug_level & 2) { fprintf(stderr,"Close a Serial WX device\n"); } break; case DEVICE_SERIAL_TNC_HSP_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC w/HSP GPS\n"); } if (using_gps_position) { using_gps_position--; } begin_critical_section(&devices_lock, "interface.c:del_device" ); xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device" ); (void)command_file_to_tnc_port(port,get_data_base_dir(temp)); break; case DEVICE_SERIAL_TNC_AUX_GPS: if (debug_level & 2) { fprintf(stderr,"Close a Serial TNC w/AUX GPS\n"); } if (using_gps_position) { using_gps_position--; } begin_critical_section(&devices_lock, "interface.c:del_device"); sprintf(temp, "config/%s", devices[port].tnc_down_file); end_critical_section(&devices_lock, "interface.c:del_device"); (void)command_file_to_tnc_port(port, get_data_base_dir(temp)); break; default: break; } // End of switch // Let the write queue empty before we return, to make // sure all of the data gets written out. while ( (port_data[port].write_in_pos != port_data[port].write_out_pos) && port_data[port].status == DEVICE_UP) { // Check whether we're hung waiting on the device if (wait_time > SERIAL_MAX_WAIT) { break; // Break out of the while loop } sched_yield(); usleep(25000); // 25ms wait_time = wait_time + 25000; } if (debug_level & 2) { fprintf(stderr,"Serial detach\n"); } ok = serial_detach(port); break; case(DEVICE_NET_STREAM): case(DEVICE_AX25_TNC): case(DEVICE_NET_GPSD): case(DEVICE_NET_WX): case(DEVICE_NET_DATABASE): case(DEVICE_NET_AGWPE): switch (port_data[port].device_type) { case DEVICE_NET_STREAM: if (debug_level & 2) { fprintf(stderr,"Close a Network stream\n"); } break; case DEVICE_AX25_TNC: if (debug_level & 2) { fprintf(stderr,"Close a AX25 TNC device\n"); } break; case DEVICE_NET_GPSD: if (debug_level & 2) { fprintf(stderr,"Close a Network GPSd stream\n"); } if (using_gps_position) { using_gps_position--; } break; case DEVICE_NET_WX: if (debug_level & 2) { fprintf(stderr,"Close a Network WX stream\n"); } break; case DEVICE_NET_DATABASE: if (debug_level & 2) { fprintf(stderr,"Close a Network Database stream\n"); } break; case DEVICE_NET_AGWPE: if (debug_level & 2) { fprintf(stderr,"Close a Network AGWPE stream\n"); } break; default: break; } if (debug_level & 2) { fprintf(stderr,"Net detach\n"); } ok = net_detach(port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: if (debug_level & 2) { fprintf(stderr,"Close connection to database on device %d\n",port); } if (port_data[port].status==DEVICE_UP) { ok = closeConnection(&connections[port],port); } // remove the connection from the list of open connections /* clear port active */ port_data[port].active = DEVICE_NOT_IN_USE; /* clear port status */ port_data[port].active = DEVICE_DOWN; update_interface_list(); fprintf(stderr,"Closed connection to database on device %d\n",port); break; #endif /* HAVE_DB */ default: break; } if (ok) { int retvalue; if (debug_level & 2) { fprintf(stderr,"port detach OK\n"); } usleep(100000); // 100ms if (debug_level & 2) { fprintf(stderr,"Cancel threads\n"); } if (begin_critical_section(&port_data_lock, "interface.c:del_device(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } if (begin_critical_section(&connect_lock, "interface.c:del_device(2)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (port_data[port].read_thread != 0) // If we have a thread defined { retvalue = pthread_cancel(port_data[port].read_thread); if (retvalue == ESRCH) { } } if (port_data[port].write_thread != 0) // If we have a thread defined { retvalue = pthread_cancel(port_data[port].write_thread); // we used to test retvalue against ESRCH and throw a // warning if this failed, but it got commented out a very // long time ago (around 2003). } if (end_critical_section(&connect_lock, "interface.c:del_device(3)" ) > 0) { fprintf(stderr,"connect_lock, Port = %d\n", port); } if (end_critical_section(&port_data_lock, "interface.c:del_device(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } usleep(100000); // 100ms } else { if (debug_level & 2) { fprintf(stderr,"Port %d could not be closed\n",port); } } usleep(10); // Cover the case where someone plays with a GPS interface or // three and then turns it/them off again: They won't send a // posit again until the next restart or whenever they enable a // GPS interface again that has good data, unless we set this // variable again for them. if (!using_gps_position) { my_position_valid = 1; } return(ok); } #ifdef HAVE_DB /* Add a device, passing it a pointer to the ioparam * that describes the interface to start up, rather than passing * an extracted list of elements * * temporary addition for testing sql_database_functionality * when working, needs to be integrated into add_device */ int add_device_by_ioparam(int port_avail, ioparam *device) { int ok; int got_conn; int done = 0; DataRow *dr; ok = -1; if (port_avail >= 0) { switch (device->device_type) { case DEVICE_SQL_DATABASE: if (debug_level & 4096) { fprintf(stderr,"Opening a sql db connection to %s\n",device->device_host_name); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_SQL_DATABASE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", device->device_host_name); if (connections_initialized==0) { if (debug_level & 4096) { fprintf(stderr,"Calling initConnections in add_device_by_ioparam\n"); } fprintf(stderr,"adddevice, initializing connections"); connections_initialized = initConnections(); } if (debug_level & 4096) { fprintf(stderr,"Opening (in interfaces) device on port [%d] with connection [%p]\n",port_avail,&connections[port_avail]); fprintf(stderr,"device [%p][%p] device_type=%d\n",device,&device,device->device_type); } got_conn = 0; got_conn=openConnection(device, &connections[port_avail]); if (debug_level & 4096) { fprintf(stderr,"got_conn connections[%d] [%p] result=%d\n",port_avail,&connections[port_avail],got_conn); if (got_conn==1) { fprintf(stderr,"got_conn connection type %d\n",connections[port_avail].type); } } if ((got_conn == 1) && (!(connections[port_avail].type==NULL))) { if (debug_level & 4096) { fprintf(stderr, "Opened connection [%d] type=[%d]\n",port_avail,connections[port_avail].type); } ok = 1; port_data[port_avail].active = DEVICE_IN_USE; port_data[port_avail].status = DEVICE_UP; } else { port_data[port_avail].active = DEVICE_IN_USE; port_data[port_avail].status = DEVICE_ERROR; } // Show the latest status in the interface control dialog update_interface_list(); if (ok == 1) { /* if connected save top of call list */ ok = storeStationSimpleToGisDb(&connections[port_avail], n_first); if (ok==1) { if (debug_level & 4096) { fprintf(stderr,"Stored station n_first\n"); } // iterate through station_pointers and write all stations currently known dr = n_first->n_next; if (dr!=NULL) { while (done==0) { if (debug_level & 4096) { fprintf(stderr,"storing additional stations\n"); } // Need to check that stations aren't from the database // preventing creation of duplicate round trip records. ok = storeStationSimpleToGisDb(&connections[port_avail], dr); if (ok==1) { dr = dr->n_next; if (dr==NULL) { done = 1; } } else { done = 1; } } } } } } } return ok; } #endif /* HAVE_DB */ //*********************************************************** // Add Device. Starts up ports (makes them active). // dev_type is the device type to add // dev_num is the device name // dev_hst is the host name to connect to (network only) // dev_sck_p is the socket port to connect to (network only) // dev_sp is the baud rate of the port (serial only) // dev_sty is the port style (serial only) // // this will return the port # if one is available // otherwise it will return -1 if there is an error //*********************************************************** int add_device(int port_avail,int dev_type,char *dev_nm,char *passwd,int dev_sck_p, int dev_sp,int dev_sty,int reconnect, char *filter_string) { char logon_txt[600]; char init_kiss_string[5]; // KISS-mode on startup int ok; char temp[300]; char verstr[15]; if ( (dev_nm == NULL) || (passwd == NULL) ) { return(-1); } if (dev_nm[0] == '\0') { return(-1); } xastir_snprintf(verstr, sizeof(verstr), "XASTIR %s", VERSION); ok = -1; if (port_avail >= 0) { if (debug_level & 2) { fprintf(stderr,"Port Available %d\n",port_avail); } switch(dev_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: switch (dev_type) { case DEVICE_SERIAL_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC device\n"); } break; case DEVICE_SERIAL_KISS_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial KISS TNC device\n"); } break; case DEVICE_SERIAL_MKISS_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a Serial MKISS TNC device\n"); } break; case DEVICE_SERIAL_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; case DEVICE_SERIAL_WX: if (debug_level & 2) { fprintf(stderr,"Opening a Serial WX device\n"); } break; case DEVICE_SERIAL_TNC_HSP_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC w/HSP GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; case DEVICE_SERIAL_TNC_AUX_GPS: if (debug_level & 2) { fprintf(stderr,"Opening a Serial TNC w/AUX GPS device\n"); } // Must wait for valid GPS parsing after // sending one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); break; default: break; } clear_port_data(port_avail,0); port_data[port_avail].device_type = dev_type; xastir_snprintf(port_data[port_avail].device_name, sizeof(port_data[port_avail].device_name), "%s", dev_nm); port_data[port_avail].sp = dev_sp; port_data[port_avail].style = dev_sty; if (dev_type == DEVICE_SERIAL_WX) { if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } } ok = serial_init(port_avail); break; case DEVICE_NET_STREAM: if (debug_level & 2) { fprintf(stderr,"Opening a Network stream\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_STREAM; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); xastir_snprintf(port_data[port_avail].device_host_pswd, sizeof(port_data[port_avail].device_host_pswd), "%s", passwd); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; ok = net_init(port_avail); if (ok == 1) { /* if connected now send password */ if (strlen(passwd)) { if (filter_string != NULL && strlen(filter_string) > 0) // Filter specified { // Please note that "filter" must be the 8th // parameter on the line in order to be // parsed properly by the servers. xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass %s vers %s filter %s%c%c", my_callsign, passwd, verstr, filter_string, '\r', '\n'); } else // No filter specified { xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass %s vers %s%c%c", my_callsign, passwd, verstr, '\r', '\n'); } } else { xastir_snprintf(logon_txt, sizeof(logon_txt), "user %s pass -1 vers %s %c%c", my_callsign, verstr, '\r', '\n'); } port_write_string(port_avail,logon_txt); } break; case DEVICE_AX25_TNC: if (debug_level & 2) { fprintf(stderr,"Opening a network AX25 TNC\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_AX25_TNC; xastir_snprintf(port_data[port_avail].device_name, sizeof(port_data[port_avail].device_name), "%s", dev_nm); ok = ax25_init(port_avail); break; case DEVICE_NET_GPSD: if (debug_level & 2) { fprintf(stderr,"Opening a network GPS using gpsd\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_GPSD; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; ok = net_init(port_avail); if (ok == 1) { // Pre-2.90 GPSD protocol xastir_snprintf(logon_txt, sizeof(logon_txt), "R\r\n"); port_write_string(port_avail,logon_txt); // Post-2.90 GPSD protocol is handled near the // bottom of this routine. // Must wait for valid GPS parsing after sending // one posit. my_position_valid = 1; using_gps_position++; statusline(langcode("BBARSTA041"),1); } break; case DEVICE_NET_WX: if (debug_level & 2) { fprintf(stderr,"Opening a network WX\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_WX; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { /* if connected now send call and program version */ xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n'); port_write_string(port_avail,logon_txt); } break; case DEVICE_NET_DATABASE: if (debug_level & 2) { fprintf(stderr,"Opening a network database stream\n"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_DATABASE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { /* if connected now send call and program version */ xastir_snprintf(logon_txt, sizeof(logon_txt), "%s %s%c%c", my_callsign, VERSIONTXT, '\r', '\n'); port_write_string(port_avail,logon_txt); } break; case DEVICE_NET_AGWPE: if (debug_level & 2) { fprintf(stderr,"Opening a network AGWPE stream"); } clear_port_data(port_avail,0); port_data[port_avail].device_type = DEVICE_NET_AGWPE; xastir_snprintf(port_data[port_avail].device_host_name, sizeof(port_data[port_avail].device_host_name), "%s", dev_nm); port_data[port_avail].socket_port = dev_sck_p; port_data[port_avail].reconnect = reconnect; if (strcmp("1",passwd) == 0) { port_data[port_avail].data_type = 1; } ok = net_init(port_avail); if (ok == 1) { // If password isn't empty, send login // information // if (strlen(passwd) != 0) { // Send the login packet send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'P', // Login/Password Frame NULL, // FromCall NULL, // ToCall NULL, // Path (unsigned char *)passwd, // Data strlen(passwd)); // Length } } break; default: break; } if (ok == 1) // If port is connected... { if (debug_level & 2) { fprintf(stderr,"*** add_device: ok: %d ***\n",ok); } /* if all is ok check and start read write threads */ (void)start_port_threads(port_avail); usleep(100000); // 100ms switch (dev_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (ok == 1) { xastir_snprintf(temp, sizeof(temp), "config/%s", devices[port_avail].tnc_up_file); (void)command_file_to_tnc_port(port_avail,get_data_base_dir(temp)); } break; case DEVICE_SERIAL_KISS_TNC: // Initialize KISS-Mode at startup if (devices[port_avail].init_kiss) { xastir_snprintf(init_kiss_string, sizeof(init_kiss_string), "\x1B@k\r"); // [ESC@K sets tnc from terminal- into kissmode port_write_string(port_avail,init_kiss_string); usleep(100000); // wait a little bit... } // Send the KISS parameters to the TNC send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay)); send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence)); send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime)); send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail)); send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex); break; //WE7U case DEVICE_SERIAL_MKISS_TNC: // Send the KISS parameters to the TNC. We'll // need to send them to the correct port for // this MKISS device. send_kiss_config(port_avail,0,0x01,atoi(devices[port_avail].txdelay)); send_kiss_config(port_avail,0,0x02,atoi(devices[port_avail].persistence)); send_kiss_config(port_avail,0,0x03,atoi(devices[port_avail].slottime)); send_kiss_config(port_avail,0,0x04,atoi(devices[port_avail].txtail)); send_kiss_config(port_avail,0,0x05,devices[port_avail].fullduplex); break; case DEVICE_NET_AGWPE: // Query for the AGWPE version // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'R', // Request SW Version Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length // Query for port information // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'G', // Request Port Info Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length // Ask to receive "raw" frames // send_agwpe_packet(port_avail, 0, // AGWPE RadioPort 'k', // Request Raw Packets Frame NULL, // FromCall NULL, // ToCall NULL, // Path NULL, // Data 0); // Length /* // Send a dummy UI frame for testing purposes. // send_agwpe_packet(port_avail, atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port '\0', // type "TEST-3", // FromCall "APRS", // ToCall NULL, // Path "Test", // Data 4); // length // Send another dummy UI frame. // send_agwpe_packet(port_avail, atoi(devices[port_avail].device_host_filter_string) - 1, // AGWPE radio port '\0', // type "TEST-3", // FromCall "APRS", // ToCall "RELAY,SAR1-1,SAR2-1,SAR3-1,SAR4-1,SAR5-1,SAR6-1,SAR7-1", // Path "Testing this darned thing!", // Data 26); // length */ break; case DEVICE_NET_GPSD: // Post-2.90 GPSD protocol // (Pre-2.90 protocol handled in a prior section of // this routine) xastir_snprintf(logon_txt, sizeof(logon_txt), "?WATCH={\"enable\":true,\"nmea\":true}\r\n"); port_write_string(port_avail,logon_txt); break; default: break; } } if (ok == -1) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00015"), port_avail); popup_message(langcode("POPEM00004"),temp); port_avail = -1; } else { if (ok == 0) { xastir_snprintf(temp, sizeof(temp), langcode("POPEM00016"), port_avail); popup_message(langcode("POPEM00004"),temp); port_avail = -1; } } } else { popup_message(langcode("POPEM00004"),langcode("POPEM00017")); } return(port_avail); } //*********************************************************** // port status // port is the port to get status on //*********************************************************** void port_stats(int port) { if (port >= 0) { fprintf(stderr,"Port %d %s Status\n\n",port,dtype[port_data[port].device_type].device_name); fprintf(stderr,"Errors %d\n",port_data[port].errors); fprintf(stderr,"Reconnects %d\n",port_data[port].reconnects); fprintf(stderr,"Bytes in: %ld out: %ld\n",(long)port_data[port].bytes_input,(long)port_data[port].bytes_output); fprintf(stderr,"\n"); } } //*********************************************************** // startup defined ports // // port = -2: Start all defined interfaces // port = -1: Start all interfaces with "Activate on Startup" // port = 0 - MAX: Start only the one port specified //*********************************************************** void startup_all_or_defined_port(int port) { int i, override; int start; override = 0; switch (port) { case -1: // Start if "Activate on Startup" enabled start = 0; break; case -2: // Start all interfaces, period! start = 0; override = 1; break; default: // Start only the interface specified in "port" start = port; override = 1; break; } begin_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" ); for (i = start; i < MAX_IFACE_DEVICES; i++) { // Only start ports that aren't already up if ( (port_data[i].active != DEVICE_IN_USE) || (port_data[i].status != DEVICE_UP) ) { switch (devices[i].device_type) { case DEVICE_NET_STREAM: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_STREAM, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_DATABASE: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_DATABASE, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_AGWPE: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_AGWPE, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, devices[i].device_host_filter_string); } break; case DEVICE_NET_GPSD: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_GPSD, devices[i].device_host_name, "", devices[i].sp, 0, 0, devices[i].reconnect, ""); } break; case DEVICE_SERIAL_WX: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_SERIAL_WX, devices[i].device_name, devices[i].device_host_pswd, -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_NET_WX: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_NET_WX, devices[i].device_host_name, devices[i].device_host_pswd, devices[i].sp, 0, 0, devices[i].reconnect, ""); } break; case DEVICE_SERIAL_GPS: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_SERIAL_GPS, devices[i].device_name, "", -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, devices[i].device_type, devices[i].device_name, "", -1, devices[i].sp, devices[i].style, 0, ""); } break; case DEVICE_AX25_TNC: if (devices[i].connect_on_startup == 1 || override) { (void)add_device(i, DEVICE_AX25_TNC, devices[i].device_name, "", -1, -1, -1, 0, ""); } break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: if (debug_level & 4096) { fprintf(stderr,"Device %d Connect_on_startup=%d\n",i,devices[i].connect_on_startup); } if (devices[i].connect_on_startup == 1 || override) { ioparam *d = &devices[i]; if (debug_level & 4096) { fprintf(stderr,"Opening a sql db with device type %d\n",d->device_type); } (void)add_device_by_ioparam(i, &devices[i]); if (debug_level & 4096) { fprintf(stderr, "added device by ioparam [%d] type=[%d]\n",i,connections[i].type); } } break; #endif /* HAVE_DB */ default: break; } // End of switch } else if (debug_level & 2) { fprintf(stderr,"Skipping port %d, it's already running\n",i); } if (port != -1 && port != -2) { // We're doing a specific port #, so stop the loop i = MAX_IFACE_DEVICES+1; } } end_critical_section(&devices_lock, "interface.c:startup_all_or_defined_port" ); } //*********************************************************** // shutdown active ports // // port = -1: Shut down all active ports // port = 0 to max: Shut down the specified port if active //*********************************************************** void shutdown_all_active_or_defined_port(int port) { int i; int start; if (debug_level & 2) { fprintf(stderr,"\nshutdown_all_active_or_defined_port: %d\n\n",port); } if (port == -1) { start = 0; } else { start = port; } for( i = start; i < MAX_IFACE_DEVICES; i++ ) { if ( (port_data[i].active == DEVICE_IN_USE) && ( (port_data[i].status == DEVICE_UP) || (port_data[i].status == DEVICE_ERROR) ) ) { if (debug_level & 2) { fprintf(stderr,"Shutting down port %d \n",i); } (void)del_device(i); } if (port != -1) // Stop after one iteration if port specified { i = MAX_IFACE_DEVICES+1; } } } //************************************************************* // check ports // // Called periodically by main.c:UpdateTime() function. // Attempts to reconnect interfaces that are down. //************************************************************* void check_ports(void) { int i; int temp; for (i = 0; i < MAX_IFACE_DEVICES; i++) { switch (port_data[i].device_type) { case(DEVICE_NET_STREAM): //case(DEVICE_AX25_TNC): case(DEVICE_NET_GPSD): case(DEVICE_NET_WX): if (port_data[i].port_activity == 0) { // We've seen no activity for one time period. This variable // is updated in interface_gui.c if (port_data[i].status == DEVICE_ERROR) { // We're already in the error state, so force a reconnect port_data[i].reconnects = -1; } else if (port_data[i].status == DEVICE_UP) { // No activity on a port that's being used. // Cause a reconnect at the next iteration if (debug_level & 2) { fprintf(stderr,"check_ports(): Inactivity on port %d, DEVICE_ERROR ***\n",i); } port_data[i].status = DEVICE_ERROR; // No activity, so force a shutdown // Show the latest status in the interface control dialog update_interface_list(); // If the below statement is enabled, it causes an immediate reconnect // after one time-period of inactivity, currently 7.5 minutes, as set in // main.c:UpdateTime(). This means the symbol will never change from green // to red on the status bar, so the operator might not know about a // connection that is being constantly reconnected. By leaving it commented // out we get one time period of red, and then it will reconnect at the 2nd // time period. This means we can reconnect within 15 minutes if a line // goes dead. // port_data[i].reconnects = -1; // Causes an immediate reconnect } } else // We saw activity on this port. { port_data[i].port_activity = 0; // Reset counter for next time } break; } if (port_data[i].active == DEVICE_IN_USE && port_data[i].status == DEVICE_ERROR) { if (debug_level & 2) { fprintf(stderr,"Found device error on port %d\n",i); } if (port_data[i].reconnect == 1) { port_data[i].reconnects++; temp = port_data[i].reconnects; if (temp < 1) { if (debug_level & 2) { fprintf(stderr,"Device asks for reconnect count now at %d\n",temp); } if (debug_level & 2) { fprintf(stderr,"Shutdown device %d\n",i); } shutdown_all_active_or_defined_port(i); if (debug_level & 2) { fprintf(stderr,"Starting device %d\n",i); } startup_all_or_defined_port(i); /* if error on startup */ if (port_data[i].status == DEVICE_ERROR) { port_data[i].reconnects = temp; } } else { if (debug_level & 2) { fprintf(stderr,"Device has either too many errors, or no activity at all!\n"); } port_data[i].reconnects = temp - 2; } } } } } static char unproto_path_txt[MAX_LINE_SIZE+5]; // Function which selects an unproto path in round-robin fashion. // Once we select a path, we save the number selected back to // devices[port].unprotonum so that the next time around we select // the next in the sequence. If we don't come up with a valid // unproto path, we use the unproto path: "WIDE2-2". // // Input: Port number // Output: String pointer containing unproto path // // WE7U: Should we check to make sure that there are printable // characters in the path? // unsigned char *select_unproto_path(int port) { int count; int done; int temp; int bump_up; // Set unproto path: // We look for a non-null path entry starting at the current // value of "unprotonum". The first non-null path wins. count = 0; done = 0; bump_up = 0; while (!done && (count < 3)) { temp = (devices[port].unprotonum + count) % 3; switch (temp) { case 0: if (strlen(devices[port].unproto1) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto1); done++; } else { // No path entered here. Skip this path in the // rotation for next time. bump_up++; } break; case 1: if (strlen(devices[port].unproto2) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto2); done++; } else { // No path entered here. Skip this path in // the rotation for next time. bump_up++; } break; case 2: if (strlen(devices[port].unproto3) > 0) { xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "%s", devices[port].unproto3); done++; } else { // No path entered here. Skip this path in // the rotation for next time. bump_up++; } break; } // End of switch count++; } // End of while loop if (done) { // We found an unproto path. Check it for accepted values. // Output a warning message if it is beyond normal ranges, // but still allow it to be used. // if(check_unproto_path(unproto_path_txt)) { popup_message_always(langcode("WPUPCFT045"), langcode("WPUPCFT043")); } } else { // We found no entries in the unproto fields for the // interface. Set a default path of "WIDE2-2". xastir_snprintf(unproto_path_txt, sizeof(unproto_path_txt), "WIDE2-2"); } // Increment the path number for the next round of // transmissions. This will round-robin the paths so that all // entered paths get used. devices[port].unprotonum = (devices[port].unprotonum + 1 + bump_up) % 3; // Make sure the path is in upper-case (void)to_upper(unproto_path_txt); return((unsigned char *)unproto_path_txt); } //*********************************************************** // output_my_aprs_data // This is the function responsible for sending out my own // posits. The next function below this one handles objects, // messages and the like (output_my_data). //*********************************************************** void output_my_aprs_data(void) { char header_txt[MAX_LINE_SIZE+5]; char header_txt_save[MAX_LINE_SIZE+5]; char data_txt[MAX_LINE_SIZE+5]; char data_txt_save[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char path_txt[MAX_LINE_SIZE+5]; char *unproto_path = ""; char data_txt2[5]; struct tm *day_time; time_t sec; char my_pos[APRS_MAX_PACKET_DATA_LEN]; char my_output_lat[MAX_LAT]; char my_output_long[MAX_LONG]; char output_net[APRS_MAX_PACKET_DATA_LEN]; char wx_data[200]; char output_phg[10]; char output_cs[10]; char output_alt[20]; int ok; int port; char my_comment_tx[MAX_COMMENT+1]; int interfaces_ok_for_transmit = 0; char logfile_tmp_path[MAX_VALUE]; // Check whether transmits are disabled globally if (transmit_disable) { if (emergency_beacon) { // Notify the operator because emergency_beacon mode is on but // nobody will know it 'cuz global transmit is disabled. // // "Warning" // "Global transmit is DISABLED. Emergency beacons are NOT going out!" popup_message_always( langcode("POPEM00035"), langcode("POPEM00047") ); } return; } header_txt_save[0] = '\0'; data_txt_save[0] = '\0'; sec = sec_now(); // Check whether we're in emergency beacon mode. If so, add // "EMERGENCY" at the beginning of the comment field we'll // transmit. if (emergency_beacon) { strncpy(my_comment_tx, "EMERGENCY", sizeof(my_comment_tx)); my_comment_tx[sizeof(my_comment_tx)-1] = '\0'; // Terminate string } else { xastir_snprintf(my_comment_tx, sizeof(my_comment_tx), "%s", my_comment); } // Format latitude string for transmit later if (transmit_compressed_posit) // High res version { xastir_snprintf(my_output_lat, sizeof(my_output_lat), "%s", my_lat); } else // Create a low-res version of the latitude string { long my_temp_lat; char temp_data[20]; // Convert to long my_temp_lat = convert_lat_s2l(my_lat); // Convert to low-res string convert_lat_l2s(my_temp_lat, temp_data, sizeof(temp_data), CONVERT_LP_NORMAL); xastir_snprintf(my_output_lat, sizeof(my_output_lat), "%c%c%c%c.%c%c%c", temp_data[0], temp_data[1], temp_data[3], temp_data[4], temp_data[6], temp_data[7], temp_data[8]); } (void)output_lat(my_output_lat,transmit_compressed_posit); if (debug_level & 128) { fprintf(stderr,"OUT LAT <%s>\n",my_output_lat); } // Format longitude string for transmit later if (transmit_compressed_posit) // High res version { xastir_snprintf(my_output_long, sizeof(my_output_long), "%s", my_long); } else // Create a low-res version of the longitude string { long my_temp_long; char temp_data[20]; // Convert to long my_temp_long = convert_lon_s2l(my_long); // Convert to low-res string convert_lon_l2s(my_temp_long, temp_data, sizeof(temp_data), CONVERT_LP_NORMAL); xastir_snprintf(my_output_long, sizeof(my_output_long), "%c%c%c%c%c.%c%c%c", temp_data[0], temp_data[1], temp_data[2], temp_data[4], temp_data[5], temp_data[7], temp_data[8], temp_data[9]); } (void)output_long(my_output_long,transmit_compressed_posit); if (debug_level & 128) { fprintf(stderr,"OUT LONG <%s>\n",my_output_long); } output_net[0]='\0'; // Make sure this array at least starts initialized. begin_critical_section(&devices_lock, "interface.c:output_my_aprs_data" ); // Iterate across the ports, set up each device's headers/paths/handshakes, // then transmit the posit if the port is open and tx is enabled. for (port = 0; port < MAX_IFACE_DEVICES; port++) { // First send any header/path info we might need out the port, // set up TNC's to the proper mode, etc. ok = 1; switch (port_data[port].device_type) { // case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: output_net[0]='\0'; // We don't need this header for AGWPE break; case DEVICE_NET_STREAM: xastir_snprintf(output_net, sizeof(output_net), "%s>%s,TCPIP*:", my_callsign, VERSIONFRM); break; case DEVICE_SERIAL_TNC_HSP_GPS: /* make dtr normal (talk to TNC) */ if (port_data[port].status == DEVICE_UP) { port_dtr(port,0); } /* Falls through. */ case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: /* clear this for a TNC */ output_net[0] = '\0'; /* Set my call sign */ xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s\r", '\3', "MYCALL", my_callsign); // Send the callsign out to the TNC only if the interface is up and tx is enabled??? // We don't set it this way for KISS TNC interfaces. if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(header_txt, sizeof(header_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, unproto_path); xastir_snprintf(header_txt_save, sizeof(header_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, unproto_path); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); // Send the header data to the TNC. This sets the // unproto path that'll be used by the next packet. // We don't set it this way for KISS TNC interfaces. if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Set converse mode according to device's configuration setting. // xastir_snprintf(header_txt, sizeof(header_txt), "%c%s\r", '\3', devices[port].device_converse_string); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { port_write_string(port,header_txt); } // Delay a bit if the user clicked on the "Add Delay" // togglebutton in the port's interface properties dialog. // This is primarily needed for KAM TNCs, which will fail to // go into converse mode if there is no delay here. if (devices[port].tnc_extra_delay != 0) { usleep(devices[port].tnc_extra_delay); } break; default: /* port has unknown device_type */ ok = 0; break; } // End of switch // Set up some more strings for later transmission /* send station info */ output_cs[0] = '\0'; output_phg[0] = '\0'; output_alt[0] = '\0'; if (transmit_compressed_posit) xastir_snprintf(my_pos, sizeof(my_pos), "%s", compress_posit(my_output_lat, my_group, my_output_long, my_symbol, my_last_course, my_last_speed, // In knots my_phg)); else /* standard non compressed mode */ { xastir_snprintf(my_pos, sizeof(my_pos), "%s%c%s%c", my_output_lat, my_group, my_output_long, my_symbol); /* get PHG, if used for output */ if (strlen(my_phg) >= 6) xastir_snprintf(output_phg, sizeof(output_phg), "%s", my_phg); /* get CSE/SPD, Always needed for output even if 0 */ xastir_snprintf(output_cs, sizeof(output_cs), "%03d/%03d", my_last_course, my_last_speed); // Speed in knots /* get altitude */ if (my_last_altitude_time > 0) xastir_snprintf(output_alt, sizeof(output_alt), "/A=%06ld", my_last_altitude); } // And set up still more strings for later transmission switch (output_station_type) { case(1): /* APRS_MOBILE LOCAL TIME */ day_time = localtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02d/%s%s%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(2): /* APRS_MOBILE ZULU DATE-TIME */ day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dz%s%s%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(3): /* APRS_MOBILE ZULU TIME w/SEC */ day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dh%s%s%s%s", day_time->tm_hour, day_time->tm_min, day_time->tm_sec, my_pos, output_cs, output_alt, my_comment_tx); //WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string break; case(4): /* APRS position with WX data, no timestamp */ sec = wx_tx_data1(wx_data, sizeof(wx_data)); if (sec != 0) { xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%c%s%s", aprs_station_message_type, my_pos, wx_data); // WE7U2: // There's no limit on the max size for this kind of packet except // for the AX.25 limit of 256 bytes! // // Truncate at max length for this type of APRS // packet. Left the compressed/uncompressed // "if" statement here in case we need to change // this in the future due to spec changes. // Consistent with the rest of the code in this // function which does similar things. // if (transmit_compressed_posit) { if (strlen(data_txt_save) > APRS_MAX_PACKET_DATA_LEN) { data_txt_save[APRS_MAX_PACKET_DATA_LEN] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > APRS_MAX_PACKET_DATA_LEN) { data_txt_save[APRS_MAX_PACKET_DATA_LEN] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string } else { /* default to APRS FIXED if no wx data. No timestamp */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt), output_net); } break; case(5): /* APRS position with ZULU DATE-TIME and WX data */ sec = wx_tx_data1(wx_data,sizeof(wx_data)); if (sec != 0) { day_time = gmtime(&sec); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "@%02d%02d%02dz%s%s", day_time->tm_mday, day_time->tm_hour, day_time->tm_min, my_pos, wx_data); // WE7U2: // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 61) { data_txt_save[61] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 70) { data_txt_save[70] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", sizeof(data_txt_save)-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string } else { /* default to APRS FIXED if no wx data */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt),output_net); } break; /* default to APRS FIXED if no wx data */ case(0): default: /* APRS_FIXED */ output_fixed_position(data_txt_save, sizeof(data_txt_save), my_pos, output_phg, output_alt, my_comment_tx, data_txt, sizeof(data_txt),output_net); break; } if (ok) { // Here's where the actual transmit of the posit occurs. The // transmit string has been set up in "data_txt" by this point. // If transmit or posits have been turned off, don't transmit posit if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !posit_tx_disable) { interfaces_ok_for_transmit++; // WE7U: Change so that path is passed as well for KISS TNC // interfaces: header_txt_save would probably be the one to pass, // or create a new string just for KISS TNC's. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { // Note: This one has callsign & destination in the string // Transmit the posit out the KISS interface send_ax25_frame(port, my_callsign, // source VERSIONFRM, // destination path_txt, // path data_txt); // data } //WE7U:AGWPE else if (port_data[port].device_type == DEVICE_NET_AGWPE) { // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); // We need to remove the complete AX.25 header from data_txt before // we call this routine! Instead put the digipeaters into the // ViaCall fields. We do this above by setting output_net to '\0' // before creating the data_txt string. send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort '\0', // Type of frame (unsigned char *)my_callsign, // source (unsigned char *)VERSIONFRM, // destination (unsigned char *)unproto_path, // Path, (unsigned char *)data_txt, // Data strlen(data_txt) - 1); // Skip \r } else { // Not a Serial KISS TNC interface port_write_string(port, data_txt); // Transmit the posit } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",port,data_txt); } /* add new line on network data */ if (port_data[port].device_type == DEVICE_NET_STREAM) { xastir_snprintf(data_txt2, sizeof(data_txt2), "\n"); // Transmit a newline port_write_string(port, data_txt2); } // Put our transmitted packet into the Incoming Data // window as well. This way we can see both sides of a // conversation. data_port == -1 for x_spider port, // normal interface number otherwise. -99 to get a "**" // display meaning all ports. // // For packets that we're igating we end up with a CR or // LF on the end of them. Remove that so the display // looks nice. strcpy(temp, my_callsign); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ">"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, VERSIONFRM); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ","); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, unproto_path); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ":"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data_txt); temp[sizeof(temp)-1] = '\0'; // Terminate string makePrintable(temp); packet_data_add("TX ", temp, port); } else { } } // End of posit transmit: "if (ok)" } // End of big loop end_critical_section(&devices_lock, "interface.c:output_my_aprs_data" ); // Check the interfaces_ok_for_transmit variable if we're in // emergency_beacon mode. If we didn't transmit out any interfaces, alert // the operator so that they can either enable interfaces or get emergency // help in some other manner. // if (emergency_beacon) { if (interfaces_ok_for_transmit) { // Beacons are going out in emergency beacon mode. Alert the // operator so that he/she knows they've enabled that mode. // // "Emergency Beacon Mode" // "EMERGENCY BEACON MODE, transmitting every 60 seconds!" popup_message_always( langcode("POPEM00048"), langcode("POPEM00049") ); } else // Emergency beacons are not going out for some reason { // Notify the operator because emergency_beacon mode is on but // nobody will know it 'cuz there are no interfaces enabled for // transmit. // // "Warning" // "Interfaces or posits/transmits DISABLED. Emergency beacons are NOT going out!" popup_message_always( langcode("POPEM00035"), langcode("POPEM00050") ); } } // This will log a posit in the general format for a network interface // whether or not any network interfaces are currently up. if (log_net_data) { strcpy(data_txt, my_callsign); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ">"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, VERSIONFRM); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ",TCPIP*:"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } if (enable_server_port && !transmit_disable && !posit_tx_disable) { // Send data to the x_spider server strcpy(data_txt, my_callsign); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ">"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, VERSIONFRM); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, ",TCPIP*:"); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string if (writen(pipe_xastir_to_tcp_server, data_txt, strlen(data_txt)) != (int)strlen(data_txt)) { fprintf(stderr, "my_aprs_data: Writen error: %d\n", errno); } // Terminate it with a linefeed if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1) { fprintf(stderr, "my_aprs_data: Writen error: %d\n", errno); } } // End of x_spider server send code // Note that this will only log one TNC line per transmission now matter // how many TNC's are defined. It's a representative sample of what we're // sending out. At least one TNC interface must be enabled in order to // have anything output to the log file here. if (log_tnc_data) { if (header_txt_save[0] != '\0') { strcpy(data_txt, header_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[sizeof(data_txt)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } } } //***************************************************************************** // output_my_data() // // 1) Used to send local messages/objects/items. Cooked mode. // 2) Used from output_igate_net(), igating from RF to the 'net. Raw mode. // 3) Used from output_igate_rf() to igate from the 'net to RF. Cooked mode. // 4) Used from output_nws_igate_rf() to send NWS packets out RF. Cooked mode. // 5) Used for queries and responses. Cooked mode. // // Parameters: // message: the message data to send // port: the port transmitting through, or -1 for all // type: 0 for my data, 1 for raw data (Cooked/Raw) // loopback_only: 0 for transmit/loopback, 1 for loopback only // use_igate_path: 0 for standard unproto paths, 1 for igate path // path: Set to non-NULL if special path selected for messaging // // This function sends out messages/objects/bulletins/etc. // This one currently tries to do local logging even if // transmit is disabled. //***************************************************************************** void output_my_data(char *message, int incoming_port, int type, int loopback_only, int use_igate_path, char *path) { char data_txt[MAX_LINE_SIZE+5]; char data_txt_save[MAX_LINE_SIZE+5]; char temp[MAX_LINE_SIZE+5]; char path_txt[MAX_LINE_SIZE+5]; char *unproto_path = ""; char output_net[APRS_MAX_PACKET_DATA_LEN]; int ok, start, finish, port; int done; char logfile_tmp_path[MAX_VALUE]; // Check whether transmits are disabled globally if (transmit_disable && !loopback_only) { return; } //// cbell- if path is null, strlen/printf segv in solaris if (path == NULL) { path = ""; } if (debug_level & 1) { fprintf(stderr, "Sending out port: %d, type: %d, path: %s\n", incoming_port, type, path); } if (message == NULL) { return; } if (message[0] == '\0') { return; } data_txt_save[0] = '\0'; if (incoming_port == -1) // Send out all of the interfaces { start = 0; finish = MAX_IFACE_DEVICES; } else // Only send out the chosen interface { start = incoming_port; finish = incoming_port + 1; } begin_critical_section(&devices_lock, "interface.c:output_my_data" ); for (port = start; port < finish; port++) { ok = 1; if (type == 0) // my data { switch (port_data[port].device_type) { // case DEVICE_NET_DATABASE: case DEVICE_NET_AGWPE: output_net[0] = '\0'; // Clear header break; case DEVICE_NET_STREAM: if (debug_level & 1) { fprintf(stderr,"%d Net\n",port); } xastir_snprintf(output_net, sizeof(output_net), "%s>%s,TCPIP*:", my_callsign, VERSIONFRM); break; case DEVICE_SERIAL_TNC_HSP_GPS: if (port_data[port].status == DEVICE_UP && !loopback_only && !transmit_disable) { port_dtr(port,0); // make DTR normal (talk to TNC) } /* Falls through. */ case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: case DEVICE_SERIAL_TNC: case DEVICE_AX25_TNC: if (debug_level & 1) { fprintf(stderr,"%d AX25 TNC\n",port); } output_net[0] = '\0'; // clear this for a TNC /* Set my call sign */ xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s\r", '\3', "MYCALL", my_callsign); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(10000); // 10ms } done = 0; // Set unproto path. First check whether we're // to use the igate path. If so and the path // isn't empty, skip the rest of the path selection: if ( (use_igate_path) && (strlen(devices[port].unproto_igate) > 0) ) { // WE7U: Should we check here and in the following path // selection code to make sure that there are printable characters // in the path? Also: Output_my_aprs_data() has nearly identical // path selection code. Fix it in one place, fix it in the other. // Check whether igate path is socially // acceptable. Output warning if not, but // still allow the transmit. if(check_unproto_path(devices[port].unproto_igate)) { popup_message_always(langcode("WPUPCFT046"), langcode("WPUPCFT043")); } xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, devices[port].unproto_igate); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, devices[port].unproto_igate); xastir_snprintf(path_txt, sizeof(path_txt), "%s", devices[port].unproto_igate); done++; } // Check whether a path was passed to us as a // parameter: if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s\r", '\3', "UNPROTO", VERSIONFRM); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s:", my_callsign, VERSIONFRM); } else { xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, path); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, path); } if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path path_txt[0] = '\0'; // Empty path } else { xastir_snprintf(path_txt, sizeof(path_txt), "%s", path); } done++; // If "DEFAULT PATH" was passed to us, then // we're not done yet. // if (strncmp(path, "DEFAULT PATH", 12) == 0) { done = 0; } } if (!done) { // Set unproto path: Get next unproto path // in sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(data_txt, sizeof(data_txt), "%c%s %s VIA %s\r", '\3', "UNPROTO", VERSIONFRM, unproto_path); xastir_snprintf(data_txt_save, sizeof(data_txt_save), "%s>%s,%s:", my_callsign, VERSIONFRM, unproto_path); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); done++; } if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(10000); // 10ms } // Set converse mode using approprate string from configuration. xastir_snprintf(data_txt, sizeof(data_txt), "%c%s\r", '\3', devices[port].device_converse_string); if ( (port_data[port].device_type != DEVICE_SERIAL_KISS_TNC) && (port_data[port].device_type != DEVICE_SERIAL_MKISS_TNC) && (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); usleep(20000); // 20ms } break; default: /* unknown */ ok = 0; break; } // End of switch } else // Type == 1, raw data. Probably igating something... { output_net[0] = '\0'; } if (ok) { /* send data */ xastir_snprintf(data_txt, sizeof(data_txt), "%s%s\r", output_net, message); if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { // WE7U: Change so that path is passed as well for KISS TNC // interfaces: data_txt_save would probably be the one to pass, // or create a new string just for KISS TNC's. if ( (port_data[port].device_type == DEVICE_SERIAL_KISS_TNC) || (port_data[port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { // Transmit send_ax25_frame(port, my_callsign, // source VERSIONFRM, // destination path_txt, // path data_txt); // data } //WE7U:AGWPE else if (port_data[port].device_type == DEVICE_NET_AGWPE) { // Set unproto path. First check whether we're // to use the igate path. If so and the path // isn't empty, skip the rest of the path selection: if ( (use_igate_path) && (strlen(devices[port].unproto_igate) > 0) ) { // Check whether igate path is socially // acceptable. Output warning if not, but // still allow the transmit. if(check_unproto_path(devices[port].unproto_igate)) { popup_message_always(langcode("WPUPCFT046"), langcode("WPUPCFT043")); } xastir_snprintf(path_txt, sizeof(path_txt), "%s", devices[port].unproto_igate); } // Check whether a path was passed to us as a // parameter: else if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DEFAULT PATH", 12) == 0) { unproto_path = (char *)select_unproto_path(port); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); } else if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path path_txt[0] = '\0'; // Empty string // WE7U // TEST THIS TO SEE IF IT WORKS ON AGWPE TO HAVE NO PATH } else { xastir_snprintf(path_txt, sizeof(path_txt), "%s", path); } } else { // Set unproto path: Get next unproto path in // sequence. unproto_path = (char *)select_unproto_path(port); xastir_snprintf(path_txt, sizeof(path_txt), "%s", unproto_path); } // We need to remove the complete AX.25 header from data_txt before // we call this routine! Instead put the digipeaters into the // ViaCall fields. We do this above by setting output_net to '\0' // before creating the data_txt string. send_agwpe_packet(port, // Xastir interface port atoi(devices[port].device_host_filter_string) - 1, // AGWPE RadioPort '\0', // Type of frame (unsigned char *)my_callsign, // source (unsigned char *)VERSIONFRM, // destination (unsigned char *)path_txt, // Path, (unsigned char *)data_txt, // Data strlen(data_txt) - 1); // Skip \r } else { // Not a Serial KISS TNC interface port_write_string(port, data_txt); // Transmit } if (debug_level & 1) fprintf(stderr,"Sending to interface:%d, %s\n", port, data_txt); // Put our transmitted packet into the Incoming Data // window as well. This way we can see both sides of a // conversation. data_port == -1 for x_spider port, // normal interface number otherwise. -99 to get a "**" // display meaning all ports. // // For packets that we're igating we end up with a CR or // LF on the end of them. Remove that so the display // looks nice. // // Check whether a path was passed to us as a // parameter: if ( (path != NULL) && (strlen(path) != 0) ) { if (strncmp(path, "DEFAULT PATH", 12) == 0) { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, unproto_path, message); } else if (strncmp(path, "DIRECT PATH", 11) == 0) { // The user has requested a direct path xastir_snprintf(temp, sizeof(temp), "%s>%s:%s", my_callsign, VERSIONFRM, message); } else { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, path, message); } } else { xastir_snprintf(temp, sizeof(temp), "%s>%s,%s:%s", my_callsign, VERSIONFRM, unproto_path, message); } makePrintable(temp); packet_data_add("TX ", temp, port); } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",port,data_txt); } /* add newline on network data */ if (port_data[port].device_type == DEVICE_NET_STREAM) { xastir_snprintf(data_txt, sizeof(data_txt), "\n"); if ( (port_data[port].status == DEVICE_UP) && (devices[port].transmit_data == 1) && !transmit_disable && !loopback_only) { port_write_string(port,data_txt); } } else { } } // if (incoming_port != -1) // port = MAX_IFACE_DEVICES+1; // process only one port } end_critical_section(&devices_lock, "interface.c:output_my_data" ); // This will log a posit in the general format for a network interface // whether or not any network interfaces are currently up. xastir_snprintf(data_txt, sizeof(data_txt), "%s>%s,TCPIP*:%s", my_callsign, VERSIONFRM, message); if (debug_level & 2) { fprintf(stderr,"output_my_data: Transmitting and decoding: %s\n", data_txt); } if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); // Note that this will only log one TNC line per transmission now matter // how many TNC's are defined. It's a representative sample of what we're // sending out. At least one TNC interface must be enabled in order to // have anything output to the log file here. if (data_txt_save[0] != '\0') { xastir_snprintf(data_txt, sizeof(data_txt), "%s%s", data_txt_save, message); if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, logfile_tmp_path, sizeof(logfile_tmp_path)), (char *)data_txt ); } if (enable_server_port && !loopback_only && !transmit_disable) { // Send data to the x_spider server if (type == 0) // My data, add a header { xastir_snprintf(data_txt, sizeof(data_txt), "%s>%s,TCPIP*:%s", my_callsign, VERSIONFRM, message); } else // Not my data, don't add a header { xastir_snprintf(data_txt, sizeof(data_txt), "%s", message); } if (writen(pipe_xastir_to_tcp_server, data_txt, strlen(data_txt)) != (int)strlen(data_txt)) { fprintf(stderr, "output_my_data: Writen error: %d\n", errno); } // Terminate it with a linefeed if (writen(pipe_xastir_to_tcp_server, "\n", 1) != 1) { fprintf(stderr, "output_my_data: Writen error: %d\n", errno); } } // End of x_spider server send code // Decode our own transmitted packets. // Note that this function call is destructive to the first parameter. // This is why we call it _after_ we call the log_data functions. // // This must be the "L" packet we see in the View->Messages // dialog. We don't see a "T" packet (for TNC) and we only see // "I" packets if we re-receive our own packet from the internet // feeds. if (incoming_port == -1) // We were sending to all ports { // Pretend we received it from port 1 decode_ax25_line( data_txt, DATA_VIA_LOCAL, 1, 1); } else // We were sending to a specific port { decode_ax25_line( data_txt, DATA_VIA_LOCAL, incoming_port, 1); } } //***************************************************************************** // output_waypoint_data() // // message: the message data to send // // This function sends out waypoint creation strings to GPS // interfaces capable of dealing with it. // //***************************************************************************** void output_waypoint_data(char *message) { char data_txt[MAX_LINE_SIZE+5]; int ok, start, finish, i; if (message == NULL) { return; } if (message[0] == '\0') { return; } if (debug_level & 1) { fprintf(stderr,"Sending to GPS interfaces: %s\n", message); } start = 0; finish = MAX_IFACE_DEVICES; begin_critical_section(&devices_lock, "interface.c:output_waypoint_data" ); for (i = start; i < finish; i++) { ok = 1; switch (port_data[i].device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: port_dtr(i,1); // make DTR active (select GPS) break; case DEVICE_SERIAL_GPS: break; default: /* unknown */ ok = 0; break; } // End of switch if (ok) // Found a GPS interface { /* send data */ xastir_snprintf(data_txt, sizeof(data_txt), "%s\r\n", message); if (port_data[i].status == DEVICE_UP) { port_write_string(i,data_txt); usleep(250000); // 0.25 secs if (debug_level & 1) { fprintf(stderr,"Sending to interface:%d, %s\n",i,data_txt); } } if (debug_level & 2) { fprintf(stderr,"TX:%d<%s>\n",i,data_txt); } if (port_data[i].device_type == DEVICE_SERIAL_TNC_HSP_GPS) { port_dtr(i,0); // make DTR inactive (select TNC data) } } } end_critical_section(&devices_lock, "interface.c:output_waypoint_data" ); } // Added by KB6MER for KAM XL(SERIAL_TNC_AUX_GPS) support // buf is a null terminated string // returns buf as a null terminated string after cleaning. // Currently: // removes leading 'cmd:' prompts from TNC if needed // Can be used to add any additional data cleaning functions desired. // Currently only called for SERIAL_TNC_AUX_GPS, but could be added // to other device routines to improve packet decode on other devices. // // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void tnc_data_clean(char *buf) { if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // strncpy is ok here as long as nulls not in data. We // null-terminate it ourselves to make sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_data_clean: called to clean %s\n", filtered_data); } while (!strncmp(buf,"cmd:",4)) { int ii; // We're _shortening_ the string here, so we don't need to // know the length of the buffer unless it has no '\0' // terminator to begin with! In that one case we could run // off the end of the string and get a segfault or cause // other problems. for (ii = 0; ; ii++) { buf[ii] = buf[ii+4]; if (buf[ii] == '\0') { break; } } } if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as long as nulls not // in data. We null-terminate it ourselves to make sure it // is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_data_clean: clean result %s\n", filtered_data); } } // Added by KB6MER for KAM XL (SERIAL_TNC_AUX_GPS) support // buf is a null terminated string. // port is integer offset into port_data[] array of iface data (see interface.h) // returns int 0=AX25, 1=GPS // Tries to guess from the contents of buf whether it represents data from // the GPS or data from an AX25 packet. // // Note that the length of "buf" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // int tnc_get_data_type(char *buf, int UNUSED(port) ) { register int i; int type=1; // Don't know what it is yet. Assume NMEA for now. if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as long as nulls not // in data. We null-terminate it ourselves to make sure it // is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: parsing %s\n", filtered_data); } // First, let's look for NMEA-ish things. if (buf[0]=='$') { //This looks kind of NMEA-ish, let's check for known message type //headers ($P[A-Z][A-Z][A-Z][A-Z] or $GP[A-Z][A-Z][A-Z]) if(buf[1]=='P') { for(i=2; i<=5; i++) { if (buf[i]<'A' || buf[i]>'Z') { type=0; // Disqualified, not valid NMEA-0183 if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as // long as nulls not in data. We // null-terminate it ourselves to make // sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n", filtered_data); } } } } else if(buf[1]=='G' && buf[2]=='P') { for(i=3; i<=5; i++) { if (buf[i]<'A' || buf[i]>'Z') { type=0; // Disqualified, not valid NMEA-0183 if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; // Binary routine. strncpy is ok here as // long as nulls not in data. We // null-terminate it ourselves to make // sure it is terminated. strncpy(filtered_data, buf, MAX_LINE_SIZE); filtered_data[MAX_LINE_SIZE] = '\0'; // Terminate it makePrintable(filtered_data); fprintf(stderr,"tnc_get_data_type: Not NMEA %s\n", filtered_data); } } } } } else // Must be APRS data { type = 0; } if (debug_level & 1) { if (type == 0) { fprintf(stderr,"APRS data\n"); } else { fprintf(stderr,"NMEA data\n"); } } return(type); } /* This function is reused several times in the output_my_aprs_data function to create a string for the fixed aprs station, no timestamp. It is created to do away with three instances of cut/pasted code that complicated maintenance and readability. */ void output_fixed_position(char *data_txt_save, size_t data_txt_save_size, char *my_pos, char * output_phg, char * output_alt, char *my_comment_tx, char *data_txt, size_t data_txt_size, char *output_net) { xastir_snprintf(data_txt_save, data_txt_save_size, "%c%s%s%s%s", aprs_station_message_type, my_pos, output_phg, output_alt, my_comment_tx); // Truncate at max length for this type of APRS // packet. if (transmit_compressed_posit) { if (strlen(data_txt_save) > 54) { data_txt_save[54] = '\0'; } } else // Uncompressed lat/long { if (strlen(data_txt_save) > 63) { data_txt_save[63] = '\0'; } } // Add '\r' onto end. strncat(data_txt_save, "\r", data_txt_save_size-strlen(data_txt_save)-1); strcpy(data_txt, output_net); data_txt[data_txt_size-1] = '\0'; // Terminate string strcat(data_txt, data_txt_save); data_txt[data_txt_size-1] = '\0'; // Terminate string } Xastir-Release-2.2.4/src/interface.h0000664000175000017500000003400715151324131016225 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_INTERFACE_H #define __XASTIR_INTERFACE_H #include #include #include "util.h" #include "xastir.h" #define MAX_DEVICE_NAME 128 #define MAX_DEVICE_BUFFER 4096 #define MAX_DEVICE_BUFFER_UNTIL_BINARY_SWITCH 700 #define MAX_DEVICE_HOSTNM 40 #define MAX_DEVICE_HOSTPW 40 #define MAX_IFACE_DEVICES 15 #define NET_CONNECT_TIMEOUT 20 #define DEFAULT_GPS_RETR 0x05 /* CTRL-E */ // Define a 60 second max wait on a serial port (in microseconds) #define SERIAL_MAX_WAIT 60000000 // KISS Protocol Special Characters & Commands: #define KISS_FEND 0xc0 // Frame End #define KISS_FESC 0xdb // Frame Escape #define KISS_TFEND 0xdc // Transposed Frame End #define KISS_TFESC 0xdd // Transposed Frame Escape #define KISS_DATA 0x00 #define KISS_TXDELAY 0x01 #define KISS_PERSISTENCE 0x02 #define KISS_SLOTTIME 0x03 #define KISS_TXTAIL 0x04 #define KISS_FULLDUPLEX 0x05 #define KISS_SETHARDWARE 0x06 #define KISS_RETURN 0xff #define MAX_IFACE_DEVICE_TYPES 15 /* Define Device Types */ enum Device_Types { DEVICE_NONE, DEVICE_SERIAL_TNC, DEVICE_SERIAL_TNC_HSP_GPS, DEVICE_SERIAL_GPS, DEVICE_SERIAL_WX, DEVICE_NET_STREAM, DEVICE_AX25_TNC, DEVICE_NET_GPSD, DEVICE_NET_WX, DEVICE_SERIAL_TNC_AUX_GPS, // KB6MER -> KAM XL or other TNC w/GPS on AUX port DEVICE_SERIAL_KISS_TNC, // KISS TNC on serial port (not ax.25 kernel device) DEVICE_NET_DATABASE, DEVICE_NET_AGWPE, DEVICE_SERIAL_MKISS_TNC, // Multi-port KISS TNC, like the Kantronics KAM DEVICE_SQL_DATABASE // SQL server (MySQL/Postgis) database }; enum Device_Active { DEVICE_NOT_IN_USE, DEVICE_IN_USE }; enum Device_Status { DEVICE_DOWN, DEVICE_UP, DEVICE_ERROR }; typedef struct { int device_type; /* device type */ int active; /* channel in use */ int status; /* current status (up or down) */ char device_name[MAX_DEVICE_NAME+1]; /* device name */ char device_host_name[MAX_DEVICE_HOSTNM+1]; /* device host name for network */ struct addrinfo *addr_list; /* possible network addresses */ unsigned long int address; /* XXX Delete this */ int thread_status; /* thread status for connect thread */ int connect_status; /* connect status for connect thread */ int decode_errors; /* decode error count, used for data type */ int data_type; /* 0=normal 1=wx_binary */ int socket_port; /* socket port# for network */ char device_host_pswd[MAX_DEVICE_HOSTPW+1]; /* host password */ int channel; /* for serial and net ports */ int channel2; /* for AX25 ports */ char ui_call[30]; /* current call for this port */ struct termios t,t_old; /* terminal struct for serial port */ int dtr; /* dtr signal for HSP cable (status) */ int sp; /* serial port speed */ int style; /* serial port style */ int scan; /* data read available */ int errors; /* errors for this port */ int reconnect; /* reconnect on net failure */ int reconnects; /* total number of reconnects by this port */ unsigned long bytes_input; /* total bytes read by this port */ unsigned long bytes_output; /* total bytes written by this port */ unsigned long bytes_input_last; /* total bytes read last check */ unsigned long bytes_output_last; /* total bytes read last check */ int port_activity; /* 0 if no activity between checks */ pthread_t read_thread; /* read thread */ int read_in_pos; /* current read buffer input pos */ int read_out_pos; /* current read buffer output pos */ char device_read_buffer[MAX_DEVICE_BUFFER]; /* read buffer for this port */ xastir_mutex read_lock; /* Lock for reading the port data */ pthread_t write_thread; /* write thread */ int write_in_pos; /* current write buffer input pos */ int write_out_pos; /* current write buffer output pos */ xastir_mutex write_lock; /* Lock for writing the port data */ char device_write_buffer[MAX_DEVICE_BUFFER];/* write buffer for this port */ } iface; typedef struct { char device_name[100]; } iodevices; typedef struct { int device_type; /* device type */ char device_name[MAX_DEVICE_NAME+1]; /* device name */ char radio_port[3]; /* port for multi-port TNC's */ char device_host_name[MAX_DEVICE_HOSTNM+1]; /* device host name for network */ char device_host_pswd[MAX_DEVICE_HOSTPW+1]; /* host password also WX device data type */ char device_host_filter_string[201]; /* host filter string */ char device_converse_string[10+1]; /* string used to enter converse mode */ char comment[50]; /* Local comment or name for port */ char unproto1[50]; /* unproto path 1 for this port */ char unproto2[50]; /* unproto path 2 for this port */ char unproto3[50]; /* unproto path 3 for this port */ char unproto_igate[50]; /* unproto igate path for this port */ int unprotonum; /* unproto path selection */ char tnc_up_file[100]; /* file for setting up TNC on this port */ char tnc_down_file[100]; /* file for shutting down TNC on this port */ int sp; /* serial port speed/Net port */ int style; /* serial port style */ int igate_options; /* Igate options (0=none,1=input,2=in/out) */ int transmit_data; /* Data transmit out of this port */ int reconnect; /* reconnect on net failure */ int connect_on_startup; /* connect to this device on startup */ int gps_retrieve; /* Character to cause SERIAL_TNC_AUX_GPS to spit out current GPS data */ int tnc_extra_delay; /* Introduces fixed delay when talking to TNC in command-mode */ int set_time; /* Set System Time from GPS on this port */ char txdelay[4]; /* KISS parameter */ char persistence[4]; /* KISS parameter */ char slottime[4]; /* KISS parameter */ char txtail[4]; /* KISS parameter */ int fullduplex; /* KISS parameter */ int relay_digipeat; /* If 1: interface should RELAY digipeat */ int init_kiss; /* Initialize KISS-Mode on startup */ #ifdef HAVE_DB // to support connections to sql server databases for db_gis.c char database_username[20]; /* Username to use to connect to database */ int database_type; /* Type of dbms (posgresql, mysql, etc) */ char database_schema[20]; /* Name of database or schema to use */ char database_errormessage[255]; /* Most recent error message from attempting to make a connection with using this descriptor. */ int database_schema_type; /* table structures to use in the database A database schema could contain both APRSWorld and XASTIR table structures, but a separate database descriptor needs to be defined for each. */ char database_unix_socket[255]; /* MySQL - unix socket parameter (path and filename) */ // Need a pointer here, and one in connection pointing back here. How to do???? //Connection *database_connection; /* Pointer to database connection that contains database handle (with type of handle being dependent on type of database. */ int query_on_startup; /* Load stations from this database on startup. */ // Use of other ioparam variables for sql server database connections: // device_host_name = hostname for database server // sp = port on which to connect to database server // device_host_pswd = password to use to connect to database -- security issue needs to be addressed #endif // HAVE_DB } ioparam; extern iodevices dtype[]; extern xastir_mutex port_data_lock; // Protects the port_data[] array of structs extern xastir_mutex devices_lock; // Protects the devices[] array extern iface port_data[]; extern int port_id[]; extern int get_device_status(int port); extern int del_device(int port); extern int get_open_device(void); extern int add_device(int port_avail,int dev_type, char *dev_nm, char *passwd, int dev_sck_p, int dev_sp, int dev_sty, int reconnect, char *filter_string); extern xastir_mutex data_lock; // Protects incoming_data_queue extern xastir_mutex output_data_lock; // Protects interface.c:channel_data() function only extern xastir_mutex connect_lock; // Protects port_data[].thread_status and port_data[].connect_status extern ioparam devices[]; #if !HAVE_SOCKLEN_T typedef unsigned int socklen_t; #endif /* APRS Packet Size Constants */ #define APRS_MAX_PATH_LEN 100 #define APRS_MAX_CALLSIGN_LEN 9 #define APRS_MAX_PACKET_DATA_LEN 256 /* from interface_gui.c */ extern void interface_gui_init(void); extern void Configure_interface_destroy_shell(Widget widget, XtPointer clientData, XtPointer callData); extern void Configure_interface(Widget w, XtPointer clientData, XtPointer callData); extern void output_my_aprs_data(void); extern void control_interface(Widget w, XtPointer clientData, XtPointer callData); extern void dtr_all_set(int dtr); extern void interface_status(Widget w); extern void update_interface_list(void); extern int WX_rain_gauge_type; /* interface.c */ extern int is_local_interface(int port); extern int is_network_interface(int port); extern void send_agwpe_packet(int xastir_interface, int RadioPort, unsigned char type, unsigned char *FromCall, unsigned char *ToCall, unsigned char *Path, unsigned char *Data, int length); extern int pop_incoming_data(unsigned char *data_string, int *port); extern int push_incoming_data(unsigned char *data_string, int length, int port); extern unsigned char incoming_data_copy[MAX_LINE_SIZE]; extern unsigned char incoming_data_copy_previous[MAX_LINE_SIZE]; extern int NETWORK_WAITTIME; extern void startup_all_or_defined_port(int port); extern void shutdown_all_active_or_defined_port(int port); extern void check_ports(void); extern void clear_all_port_data(void); extern char aprs_station_message_type; extern void port_dtr(int port, int dtr); extern void send_kiss_config(int port, int device, int command, int value); void port_write_string(int port, char *data); extern void init_device_names(void); extern void output_my_data(char *message, int port, int type, int loopback_only, int use_igate_path, char *path); int tnc_get_data_type(char *buf, int port); void tnc_data_clean(char *buf); extern void output_waypoint_data(char *message); extern void send_ax25_frame(int port, char *source, char *destination, char *path, char *data); extern pid_t getpgid(pid_t pid); #endif /* XASTIR_INTERFACE_H */ Xastir-Release-2.2.4/src/interface_gui.c0000664000175000017500000142622015151324131017067 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include "xastir.h" #include "main.h" #include "xa_config.h" #include "interface.h" #include "wx.h" #include "draw_symbols.h" #include "util.h" #include "db_gis.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX Widget configure_interface_dialog = NULL; Widget choose_interface_dialog = NULL; Widget interface_type_list = NULL; Widget control_interface_dialog = NULL; Widget control_iface_list = NULL; static xastir_mutex control_interface_dialog_lock; ioparam devices[MAX_IFACE_DEVICES]; xastir_mutex devices_lock; void Choose_interface_destroy_shell(Widget widget, XtPointer clientData, XtPointer callData); void modify_device_list(int option, int port); void interface_gui_init(void) { init_critical_section( &control_interface_dialog_lock ); init_critical_section( &devices_lock ); } /*****************************************************/ /* Universal Serial GUI */ /*****************************************************/ int device_speed; int device_style; int device_igate_options; int device_data_type; void speed_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_speed = atoi(which); } else { device_speed = 0; } } void style_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_style = atoi(which); } else { device_style = 0; } } void data_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_data_type = atoi(which); } else { device_data_type = 0; } } void rain_gauge_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { WX_rain_gauge_type = atoi(which); } else { WX_rain_gauge_type = 0; } } void igate_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { device_igate_options = atoi(which); } else { device_igate_options = 0; } } void set_port_speed(int port) { switch (device_speed) { case(1): devices[port].sp=B300; break; case(2): devices[port].sp=B1200; break; case(3): devices[port].sp=B2400; break; case(4): devices[port].sp=B4800; break; case(5): devices[port].sp=B9600; break; case(6): devices[port].sp=B19200; break; case(7): devices[port].sp=B38400; break; case(8): devices[port].sp=B57600; break; case(9): devices[port].sp=B115200; break; case(10): #ifndef B230400 devices[port].sp=B115200; #else // B230400 devices[port].sp=B230400; #endif // B230400 break; default: break; } } /*****************************************************/ /* Configure Serial TNC GUI */ /*****************************************************/ /**** TNC CONFIGURE ******/ int TNC_port; int TNC_device; Widget config_TNC_dialog = (Widget)NULL; Widget TNC_active_on_startup; Widget TNC_transmit_data; Widget TNC_device_name_data; Widget TNC_radio_port_data; // Used only for Multi-Port TNC's Widget TNC_converse_string; Widget TNC_comment; Widget TNC_unproto1_data; Widget TNC_unproto2_data; Widget TNC_unproto3_data; Widget TNC_igate_data; Widget TNC_up_file_data; Widget TNC_down_file_data; Widget TNC_txdelay; Widget TNC_persistence; Widget TNC_slottime; Widget TNC_txtail; Widget TNC_init_kiss; // Used to initialize KISS-Mode Widget TNC_fullduplex; Widget TNC_extra_delay; Widget TNC_GPS_set_time; Widget TNC_AUX_GPS_Retrieve_Needed; Widget TNC_relay_digipeat; void Config_TNC_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_TNC_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_TNC_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int type; int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(TNC_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ //WE7U: Modify for MKISS? (void)del_device(TNC_port); was_up=1; usleep(1000000); // Wait for one second } /* device type */ type=DEVICE_SERIAL_TNC; // Default in case not defined next if (TNC_device) { type=TNC_device; // Modified to support more than two types } begin_critical_section(&devices_lock, "interface_gui.c:Config_TNC_change_data" ); temp_ptr = XmTextFieldGetString(TNC_device_name_data); xastir_snprintf(devices[TNC_port].device_name, sizeof(devices[TNC_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].device_name); temp_ptr = XmTextFieldGetString(TNC_converse_string); xastir_snprintf(devices[TNC_port].device_converse_string, sizeof(devices[TNC_port].device_converse_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].device_converse_string); temp_ptr = XmTextFieldGetString(TNC_comment); xastir_snprintf(devices[TNC_port].comment, sizeof(devices[TNC_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].comment); if (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) { // If MKISS, fetch "radio_port". If empty, store a zero. temp_ptr = XmTextFieldGetString(TNC_radio_port_data); xastir_snprintf(devices[TNC_port].radio_port, sizeof(devices[TNC_port].radio_port), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].radio_port); if (strcmp(devices[TNC_port].radio_port,"") == 0) { xastir_snprintf(devices[TNC_port].radio_port, sizeof(devices[TNC_port].radio_port), "0"); } //fprintf(stderr,"Radio Port: %s\n",devices[TNC_port].radio_port); } if (XmToggleButtonGetState(TNC_active_on_startup)) { devices[TNC_port].connect_on_startup=1; } else { devices[TNC_port].connect_on_startup=0; } if(XmToggleButtonGetState(TNC_transmit_data)) { devices[TNC_port].transmit_data=1; if ( (devices[TNC_port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGI } } else { devices[TNC_port].transmit_data=0; if ( (devices[TNC_port].device_type == DEVICE_SERIAL_KISS_TNC) || (devices[TNC_port].device_type == DEVICE_SERIAL_MKISS_TNC) ) { XtSetSensitive(TNC_relay_digipeat, FALSE); } } if ( (type == DEVICE_SERIAL_KISS_TNC) || (type == DEVICE_SERIAL_MKISS_TNC) ) { if (XmToggleButtonGetState(TNC_relay_digipeat)) { devices[TNC_port].relay_digipeat=1; } else { devices[TNC_port].relay_digipeat=0; } } switch(type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (XmToggleButtonGetState(TNC_extra_delay)) { devices[TNC_port].tnc_extra_delay=1000000; // 1,000,000 us } else { devices[TNC_port].tnc_extra_delay=0; } break; default: break; } switch(type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (XmToggleButtonGetState(TNC_GPS_set_time)) { devices[TNC_port].set_time=1; } else { devices[TNC_port].set_time=0; } if (type == DEVICE_SERIAL_TNC_AUX_GPS) { if (XmToggleButtonGetState(TNC_AUX_GPS_Retrieve_Needed)) { devices[TNC_port].gps_retrieve=DEFAULT_GPS_RETR; } else { devices[TNC_port].gps_retrieve=0; } } break; case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: default: break; } set_port_speed(TNC_port); devices[TNC_port].style=device_style; devices[TNC_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(TNC_unproto1_data); xastir_snprintf(devices[TNC_port].unproto1, sizeof(devices[TNC_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto1); if(check_unproto_path(devices[TNC_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_unproto2_data); xastir_snprintf(devices[TNC_port].unproto2, sizeof(devices[TNC_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto2); if(check_unproto_path(devices[TNC_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_unproto3_data); xastir_snprintf(devices[TNC_port].unproto3, sizeof(devices[TNC_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto3); if(check_unproto_path(devices[TNC_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(TNC_igate_data); xastir_snprintf(devices[TNC_port].unproto_igate, sizeof(devices[TNC_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].unproto_igate); if(check_unproto_path(devices[TNC_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } if ( (type == DEVICE_SERIAL_KISS_TNC) || (type == DEVICE_SERIAL_MKISS_TNC) ) { // KISS TNC, no up/down files for this one! devices[TNC_port].tnc_up_file[0] = '\0'; devices[TNC_port].tnc_down_file[0] = '\0'; // Instead we have KISS parameters to set // We really should do some validation of these strings //WE7U: Modify for MKISS: Must send to the proper Radio Port. temp_ptr = XmTextFieldGetString(TNC_txdelay); xastir_snprintf(devices[TNC_port].txdelay, sizeof(devices[TNC_port].txdelay), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x01,atoi(devices[TNC_port].txdelay)); temp_ptr = XmTextFieldGetString(TNC_persistence); xastir_snprintf(devices[TNC_port].persistence, sizeof(devices[TNC_port].persistence), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x02,atoi(devices[TNC_port].persistence)); temp_ptr = XmTextFieldGetString(TNC_slottime); xastir_snprintf(devices[TNC_port].slottime, sizeof(devices[TNC_port].slottime), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x03,atoi(devices[TNC_port].slottime)); temp_ptr = XmTextFieldGetString(TNC_txtail); xastir_snprintf(devices[TNC_port].txtail, sizeof(devices[TNC_port].txtail), "%s", temp_ptr); XtFree(temp_ptr); send_kiss_config(TNC_port,0,0x04,atoi(devices[TNC_port].txtail)); if (XmToggleButtonGetState(TNC_fullduplex)) { devices[TNC_port].fullduplex=1; } else { devices[TNC_port].fullduplex=0; } send_kiss_config(TNC_port,0,0x05,devices[TNC_port].fullduplex); // For KISS-mode if (XmToggleButtonGetState(TNC_init_kiss)) { devices[TNC_port].init_kiss=1; } else { devices[TNC_port].init_kiss=0; } } else { temp_ptr = XmTextFieldGetString(TNC_up_file_data); xastir_snprintf(devices[TNC_port].tnc_up_file, sizeof(devices[TNC_port].tnc_up_file), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].tnc_up_file); temp_ptr = XmTextFieldGetString(TNC_down_file_data); xastir_snprintf(devices[TNC_port].tnc_down_file, sizeof(devices[TNC_port].tnc_down_file), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[TNC_port].tnc_down_file); } //WE7U: Modify for MKISS? /* reopen port*/ if (was_up) { (void)add_device(TNC_port, type, devices[TNC_port].device_name, "", -1, devices[TNC_port].sp, devices[TNC_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[TNC_port].device_type=type; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_TNC_change_data" ); // Rebuild the interface control list update_interface_list(); Config_TNC_destroy_shell(widget,clientData,callData); } void Config_TNC( Widget UNUSED(w), int device_type, int config_type, int port) { static Widget pane, scrollwindow, form, form2, button_ok, button_cancel, frame, frame2, frame3, frame4, setup1, setup3, setup4, device, converse, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget setup, setup2, speed; static Widget speed_57600, speed_115200, speed_230400; static Widget style_box, style_8n1, style_7e1, style_7o1, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, proto, proto1, proto2, proto3, radio_port_label; // static Widget style, igate; char temp[50]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ register char *tmp; tmp=(char *)NULL; char tmp_string[100]; if(!config_TNC_dialog) { TNC_port=port; TNC_device=device_type; /* config_TNC_dialog = XtVaCreatePopupShell(device_type ? langcode("WPUPCFT023"):langcode("WPUPCFT001"), -- replaced by KB6MER with the lines below for adding AUX GPS type TNC */ switch(device_type) { case DEVICE_SERIAL_TNC: tmp=langcode("WPUPCFT001"); break; case DEVICE_SERIAL_KISS_TNC: tmp=langcode("WPUPCFT030"); break; case DEVICE_SERIAL_MKISS_TNC: tmp=langcode("WPUPCFT040"); break; case DEVICE_SERIAL_TNC_HSP_GPS: tmp=langcode("WPUPCFT023"); break; case DEVICE_SERIAL_TNC_AUX_GPS: tmp=langcode("WPUPCFT028"); break; default: // "Configure TNC w/INVALID ENUM" sprintf(tmp_string, langcode("WPUPCFT029"), (int)device_type); tmp = tmp_string; break; } config_TNC_dialog = XtVaCreatePopupShell( tmp, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_TNC pane",xmPanedWindowWidgetClass, config_TNC_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_TNC form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); TNC_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: TNC_extra_delay = XtVaCreateManagedWidget(langcode("UNIOP00038"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: TNC_GPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_extra_delay, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(TNC_GPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(TNC_GPS_set_time,FALSE); #endif // __CYGWIN__ // Let the user turn off the Control-E thing // that only SOME "tnc-with-gps" devices actually // require, and that confuse the heck out of others. // D700 is among the confused, by the way. TVR -- 14 Aug 2012 if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) { TNC_AUX_GPS_Retrieve_Needed = XtVaCreateManagedWidget(langcode("UNIOP00037"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_GPS_set_time, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); } break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: // Add a "RELAY Digipeat?" button for KISS/MKISS TNC's TNC_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGIPEAT break; case DEVICE_SERIAL_TNC: default: break; } device = XtVaCreateManagedWidget(langcode("WPUPCFT003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_device_name_data = XtVaCreateManagedWidget("Config_TNC device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // converse = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, converse = XtVaCreateManagedWidget("Converse CMD:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_device_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_converse_string = XtVaCreateManagedWidget("Config_TNC comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, converse, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_converse_string, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_comment = XtVaCreateManagedWidget("Config_TNC comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); if (device_type == DEVICE_SERIAL_MKISS_TNC) { // "Radio Port" field for Multi-Port KISS TNC's. radio_port_label = XtVaCreateManagedWidget(langcode("WPUPCFT041"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_comment, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_radio_port_data = XtVaCreateManagedWidget("Config_TNC device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNwidth, ((5*7)+2), XmNmaxLength, 2, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, radio_port_label, XmNleftOffset, 12, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); } frame = XtVaCreateManagedWidget("Config_TNC frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset, 10, XmNtopWidget, device, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_TNC Speed_box",al,ac); XtVaSetValues(speed_box,XmNnumColumns,5,NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); switch(device_type) { case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: break; default: frame2 = XtVaCreateManagedWidget("Config_TNC frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_TNC Style box",al,ac); XtVaSetValues(style_box,XmNorientation, XmHORIZONTAL,NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); break; } frame4 = XtVaCreateManagedWidget("Config_TNC frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, (device_type == DEVICE_SERIAL_KISS_TNC || device_type == DEVICE_SERIAL_MKISS_TNC) ? frame : frame2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); //igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); igate_box = XmCreateRadioBox(frame4,"Config_TNC IGate box",al,ac); XtVaSetValues(igate_box,XmNorientation, XmVERTICAL,XmNnumColumns,2,NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto1_data = XtVaCreateManagedWidget("Config_TNC protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, TNC_unproto1_data, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto2_data = XtVaCreateManagedWidget("Config_TNC protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 15, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_unproto3_data = XtVaCreateManagedWidget("Config_TNC protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, TNC_unproto3_data, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_igate_data = XtVaCreateManagedWidget("Config_TNC igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, TNC_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Draw a different frame3 for Serial KISS/MKISS TNC interfaces switch(device_type) { case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: frame3 = XtVaCreateManagedWidget("Config_TNC frame3", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, TNC_igate_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // KISS Parameters //setup XtVaCreateManagedWidget(langcode("WPUPCFT034"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form2 = XtVaCreateWidget("Config_TNC form2",xmFormWidgetClass, frame3, XmNfractionBase, 6, XmNbackground, colors[0xff], NULL); // TXDelay (10 ms units) setup1 = XtVaCreateManagedWidget(langcode("WPUPCFT035"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_txdelay = XtVaCreateManagedWidget("Config_TNC TNC_txdelay", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Persistence (0 to 255) //setup2 XtVaCreateManagedWidget(langcode("WPUPCFT036"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_persistence = XtVaCreateManagedWidget("Config_TNC persistence", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // SlotTime (10 ms units) setup3 = XtVaCreateManagedWidget(langcode("WPUPCFT037"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_slottime = XtVaCreateManagedWidget("Config_TNC slottime", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // TxTail (10 ms units) setup4 = XtVaCreateManagedWidget(langcode("WPUPCFT038"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup3, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_txtail = XtVaCreateManagedWidget("Config_TNC TxTail", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup3, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Full Duplex TNC_fullduplex = XtVaCreateManagedWidget(langcode("WPUPCFT039"),xmToggleButtonWidgetClass,form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, setup4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Button to enable KISS-mode at startup TNC_init_kiss = XtVaCreateManagedWidget(langcode("WPUPCFT047"),xmToggleButtonWidgetClass,form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, setup4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 135, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); break; default: frame3 = XtVaCreateManagedWidget("Config_TNC frame3", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, TNC_igate_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //setup XtVaCreateManagedWidget(langcode("WPUPCFT031"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form2 = XtVaCreateWidget("Config_TNC form2",xmFormWidgetClass, frame3, XmNfractionBase, 5, XmNbackground, colors[0xff], NULL); setup1 = XtVaCreateManagedWidget(langcode("WPUPCFT032"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_up_file_data = XtVaCreateManagedWidget("Config_TNC up_file", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); //setup2 XtVaCreateManagedWidget(langcode("WPUPCFT033"), xmLabelWidgetClass, form2, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); TNC_down_file_data = XtVaCreateManagedWidget("Config_TNC down_file", xmTextFieldWidgetClass, form2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, setup1, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); break; } //------------------------------------------------------------ button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_TNC_change_data, config_TNC_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_TNC_destroy_shell, config_TNC_dialog); pos_dialog(config_TNC_dialog); delw = XmInternAtom(XtDisplay(config_TNC_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_TNC_dialog, delw, Config_TNC_destroy_shell, (XtPointer)config_TNC_dialog); if (config_type==0) { /* first time port */ devices[TNC_port].gps_retrieve=DEFAULT_GPS_RETR; if (debug_level & 128) { fprintf(stderr,"Storing %d to gps_retrieve for %d\n", DEFAULT_GPS_RETR, port); } XmTextFieldSetString(TNC_device_name_data,TNC_PORT); XmTextFieldSetString(TNC_converse_string,"k"); XmTextFieldSetString(TNC_comment,""); if (device_type == DEVICE_SERIAL_MKISS_TNC) { XmTextFieldSetString(TNC_radio_port_data,"0"); //fprintf(stderr,"Assigning default '0' to radio port\n"); } XmToggleButtonSetState(TNC_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(TNC_transmit_data,TRUE,FALSE); switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: XmToggleButtonSetState(TNC_extra_delay, FALSE, FALSE); break; default: break; } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: XmToggleButtonSetState(TNC_GPS_set_time, FALSE, FALSE); if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, TRUE, FALSE); break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: XmToggleButtonSetState(TNC_relay_digipeat, FALSE, FALSE); XmToggleButtonSetState(TNC_fullduplex, FALSE, FALSE); XmToggleButtonSetState(TNC_init_kiss, FALSE, FALSE); // For KISS-Mode break; case DEVICE_SERIAL_TNC: default: break; } XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; if ( (device_type != DEVICE_SERIAL_KISS_TNC) && (device_type != DEVICE_SERIAL_MKISS_TNC) ) { XmToggleButtonSetState(style_8n1,TRUE,FALSE); } device_style=0; device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(TNC_unproto1_data,"WIDE2-2"); XmTextFieldSetString(TNC_unproto2_data,""); XmTextFieldSetString(TNC_unproto3_data,""); XmTextFieldSetString(TNC_igate_data,""); //WE7U if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { // We don't allow changing the selection for KISS // TNC's, as they require 8N1 device_style = 0; XmTextFieldSetString(TNC_txdelay,"40"); XmTextFieldSetString(TNC_persistence,"63"); XmTextFieldSetString(TNC_slottime,"20"); XmTextFieldSetString(TNC_txtail,"30"); } else { XmTextFieldSetString(TNC_up_file_data,"tnc-startup.sys"); XmTextFieldSetString(TNC_down_file_data,"tnc-stop.sys"); } } else { /* reconfig */ if (debug_level & 128) { fprintf(stderr,"Reconfiguring interface\n"); } begin_critical_section(&devices_lock, "interface_gui.c:Config_TNC" ); XmTextFieldSetString(TNC_device_name_data,devices[TNC_port].device_name); XmTextFieldSetString(TNC_converse_string,devices[TNC_port].device_converse_string); XmTextFieldSetString(TNC_comment,devices[TNC_port].comment); if (device_type == DEVICE_SERIAL_MKISS_TNC) { XmTextFieldSetString(TNC_radio_port_data, devices[TNC_port].radio_port); //fprintf(stderr,"Reconfig: %s\n", devices[TNC_port].radio_port); } if (devices[TNC_port].connect_on_startup) { XmToggleButtonSetState(TNC_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(TNC_active_on_startup,FALSE,FALSE); } if (devices[TNC_port].transmit_data) { XmToggleButtonSetState(TNC_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(TNC_transmit_data,FALSE,FALSE); } switch(device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[TNC_port].tnc_extra_delay) { XmToggleButtonSetState(TNC_extra_delay, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_extra_delay, FALSE, FALSE); } break; default: break; } switch(device_type) { case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: if (devices[TNC_port].set_time) { XmToggleButtonSetState(TNC_GPS_set_time, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_GPS_set_time, FALSE, FALSE); } if (device_type == DEVICE_SERIAL_TNC_AUX_GPS) { if (devices[TNC_port].gps_retrieve != 0) XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, TRUE, FALSE); else XmToggleButtonSetState(TNC_AUX_GPS_Retrieve_Needed, FALSE, FALSE); } break; case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: if (devices[TNC_port].relay_digipeat) { XmToggleButtonSetState(TNC_relay_digipeat, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_relay_digipeat, FALSE, FALSE); } if (devices[TNC_port].fullduplex) { XmToggleButtonSetState(TNC_fullduplex, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_fullduplex, FALSE, FALSE); } // For KISS-Mode if (devices[TNC_port].init_kiss) { XmToggleButtonSetState(TNC_init_kiss, TRUE, FALSE); } else { XmToggleButtonSetState(TNC_init_kiss, FALSE, FALSE); } if (devices[TNC_port].transmit_data) { #ifdef SERIAL_KISS_RELAY_DIGI XtSetSensitive(TNC_relay_digipeat, TRUE); #else XtSetSensitive(TNC_relay_digipeat, FALSE); #endif // SERIAL_KISS_RELAY_DIGI } else { XtSetSensitive(TNC_relay_digipeat, FALSE); } break; case DEVICE_SERIAL_TNC: default: break; } switch (devices[TNC_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { // We don't allow changing the selection for KISS // TNC's, as they require 8N1 device_style = 0; } else { switch (devices[TNC_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } } switch (devices[TNC_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } XmTextFieldSetString(TNC_unproto1_data,devices[TNC_port].unproto1); XmTextFieldSetString(TNC_unproto2_data,devices[TNC_port].unproto2); XmTextFieldSetString(TNC_unproto3_data,devices[TNC_port].unproto3); XmTextFieldSetString(TNC_igate_data,devices[TNC_port].unproto_igate); if ( (device_type == DEVICE_SERIAL_KISS_TNC) || (device_type == DEVICE_SERIAL_MKISS_TNC) ) { XmTextFieldSetString(TNC_txdelay,devices[TNC_port].txdelay); XmTextFieldSetString(TNC_persistence,devices[TNC_port].persistence); XmTextFieldSetString(TNC_slottime,devices[TNC_port].slottime); XmTextFieldSetString(TNC_txtail,devices[TNC_port].txtail); } else { XmTextFieldSetString(TNC_up_file_data,devices[TNC_port].tnc_up_file); XmTextFieldSetString(TNC_down_file_data,devices[TNC_port].tnc_down_file); } end_critical_section(&devices_lock, "interface_gui.c:Config_TNC" ); } XtManageChild(form); XtManageChild(form2); XtManageChild(speed_box); if ( (device_type != DEVICE_SERIAL_KISS_TNC) && (device_type != DEVICE_SERIAL_MKISS_TNC) ) { XtManageChild(style_box); } XtManageChild(igate_box); XtManageChild(pane); resize_dialog(form, config_TNC_dialog); XtPopup(config_TNC_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_TNC_dialog), XtWindow(config_TNC_dialog)); } } /*****************************************************/ /* Configure Serial GPS GUI */ /*****************************************************/ /**** GPS CONFIGURE ******/ int GPS_port; Widget config_GPS_dialog = (Widget)NULL; Widget GPS_device_name_data; Widget GPS_comment; Widget GPS_active_on_startup; Widget GPS_set_time; void Config_GPS_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_GPS_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_GPS_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(GPS_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(GPS_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_GPS_change_data" ); temp_ptr = XmTextFieldGetString(GPS_device_name_data); xastir_snprintf(devices[GPS_port].device_name, sizeof(devices[GPS_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[GPS_port].device_name); temp_ptr = XmTextFieldGetString(GPS_comment); xastir_snprintf(devices[GPS_port].comment, sizeof(devices[GPS_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[GPS_port].comment); if(XmToggleButtonGetState(GPS_active_on_startup)) { devices[GPS_port].connect_on_startup=1; } else { devices[GPS_port].connect_on_startup=0; } if (XmToggleButtonGetState(GPS_set_time)) { devices[GPS_port].set_time=1; } else { devices[GPS_port].set_time=0; } set_port_speed(GPS_port); devices[GPS_port].style=device_style; /* reopen */ if ( was_up ) { (void)add_device(GPS_port, DEVICE_SERIAL_GPS, devices[GPS_port].device_name, "", -1, devices[GPS_port].sp, devices[GPS_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[GPS_port].device_type=DEVICE_SERIAL_GPS; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_GPS_change_data" ); // Rebuild the interface control list update_interface_list(); Config_GPS_destroy_shell(widget,clientData,callData); } void Config_GPS( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, frame2, device, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget speed; static Widget speed_57600, speed_115200, speed_230400; static Widget style_box, style_8n1, style_7e1, style_7o1, sep; // static Widget style; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_GPS_dialog) { GPS_port=port; config_GPS_dialog = XtVaCreatePopupShell(langcode("WPUPCFG001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_GPS pane",xmPanedWindowWidgetClass, config_GPS_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_GPS form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); device = XtVaCreateManagedWidget(langcode("WPUPCFG003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_device_name_data = XtVaCreateManagedWidget("Config_GPS device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_comment = XtVaCreateManagedWidget("Config_GPS comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); GPS_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); GPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, GPS_active_on_startup, XmNtopOffset, 7, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(GPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(GPS_set_time,FALSE); #endif // __CYGWIN__ frame = XtVaCreateManagedWidget("Config_GPS frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, GPS_set_time, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_GPS Speed_box",al,ac); XtVaSetValues(speed_box,XmNnumColumns,3,NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); frame2 = XtVaCreateManagedWidget("Config_GPS frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); //style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_GPS Style box",al,ac); XtVaSetValues(style_box, XmNorientation, XmHORIZONTAL, NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); sep = XtVaCreateManagedWidget("Config_GPS sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_GPS_change_data, config_GPS_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_GPS_destroy_shell, config_GPS_dialog); pos_dialog(config_GPS_dialog); delw = XmInternAtom(XtDisplay(config_GPS_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_GPS_dialog, delw, Config_GPS_destroy_shell, (XtPointer)config_GPS_dialog); if (config_type==0) { /* first time port */ XmTextFieldSetString(GPS_device_name_data,GPS_PORT); XmTextFieldSetString(GPS_comment,""); XmToggleButtonSetState(GPS_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(GPS_set_time, FALSE, FALSE); XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_GPS" ); XmTextFieldSetString(GPS_device_name_data,devices[GPS_port].device_name); XmTextFieldSetString(GPS_comment,devices[GPS_port].comment); if (devices[GPS_port].connect_on_startup) { XmToggleButtonSetState(GPS_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(GPS_active_on_startup,FALSE,FALSE); } if (devices[GPS_port].set_time) { XmToggleButtonSetState(GPS_set_time,TRUE,FALSE); } else { XmToggleButtonSetState(GPS_set_time,FALSE,FALSE); } switch (devices[GPS_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } switch (devices[GPS_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } end_critical_section(&devices_lock, "interface_gui.c:Config_GPS" ); } XtManageChild(form); XtManageChild(speed_box); XtManageChild(style_box); XtManageChild(pane); resize_dialog(form, config_GPS_dialog); XtPopup(config_GPS_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_GPS_dialog), XtWindow(config_GPS_dialog)); } } /*****************************************************/ /* Configure Serial WX GUI */ /*****************************************************/ /**** WX CONFIGURE ******/ int WX_port; int WX_rain_gauge_type; Widget config_WX_dialog = (Widget)NULL; Widget WX_transmit_data; Widget WX_device_name_data; Widget WX_comment; Widget WX_active_on_startup; Widget WX_tenths, WX_hundredths, WX_millimeters; void Config_WX_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_WX_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_WX_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(WX_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(WX_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_WX_change_data" ); temp_ptr = XmTextFieldGetString(WX_device_name_data); xastir_snprintf(devices[WX_port].device_name, sizeof(devices[WX_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[WX_port].device_name); temp_ptr = XmTextFieldGetString(WX_comment); xastir_snprintf(devices[WX_port].comment, sizeof(devices[WX_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[WX_port].comment); if(XmToggleButtonGetState(WX_active_on_startup)) { devices[WX_port].connect_on_startup=1; } else { devices[WX_port].connect_on_startup=0; } set_port_speed(WX_port); devices[WX_port].style=device_style; xastir_snprintf(devices[WX_port].device_host_pswd, sizeof( devices[WX_port].device_host_pswd), "%d", device_data_type); /* reopen */ if ( was_up) { (void)add_device(WX_port, DEVICE_SERIAL_WX, devices[WX_port].device_name, devices[WX_port].device_host_pswd, -1, devices[WX_port].sp, devices[WX_port].style, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[WX_port].device_type=DEVICE_SERIAL_WX; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_WX_change_data" ); // Rebuild the interface control list update_interface_list(); Config_WX_destroy_shell(widget,clientData,callData); } void Config_WX( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, frame2, frame3, frame4, WX_none, device, comment, speed_box, speed_300, speed_1200, speed_2400, speed_4800, speed_9600, speed_19200, speed_38400; // static Widget speed; static Widget speed_57600, speed_115200, speed_230400; static Widget style_box, style_8n1, style_7e1, style_7o1, data_box, data_auto, data_bin, data_ascii, gauge_box, sep; // static Widget data_type, gauge_type; // static Widget style; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_WX_dialog) { WX_port=port; config_WX_dialog = XtVaCreatePopupShell(langcode("WPUPCFWX01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_WX pane",xmPanedWindowWidgetClass, config_WX_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_WX form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); device = XtVaCreateManagedWidget(langcode("WPUPCFWX02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_device_name_data = XtVaCreateManagedWidget("Config_WX device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, device, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_comment = XtVaCreateManagedWidget("Config_WX comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, device, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); WX_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_WX frame", xmFrameWidgetClass, form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopOffset,10, XmNtopWidget, WX_active_on_startup, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // speed XtVaCreateManagedWidget(langcode("WPUPCFT004"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; speed_box = XmCreateRadioBox(frame,"Config_WX Speed_box",al,ac); XtVaSetValues(speed_box, XmNnumColumns,3, NULL); speed_300 = XtVaCreateManagedWidget(langcode("WPUPCFT005"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_300,XmNvalueChangedCallback,speed_toggle,"1"); speed_1200 = XtVaCreateManagedWidget(langcode("WPUPCFT006"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_1200,XmNvalueChangedCallback,speed_toggle,"2"); speed_2400 = XtVaCreateManagedWidget(langcode("WPUPCFT007"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_2400,XmNvalueChangedCallback,speed_toggle,"3"); speed_4800 = XtVaCreateManagedWidget(langcode("WPUPCFT008"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_4800,XmNvalueChangedCallback,speed_toggle,"4"); speed_9600 = XtVaCreateManagedWidget(langcode("WPUPCFT009"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_9600,XmNvalueChangedCallback,speed_toggle,"5"); speed_19200 = XtVaCreateManagedWidget(langcode("WPUPCFT010"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_19200,XmNvalueChangedCallback,speed_toggle,"6"); speed_38400 = XtVaCreateManagedWidget(langcode("WPUPCFT019"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_38400,XmNvalueChangedCallback,speed_toggle,"7"); speed_57600 = XtVaCreateManagedWidget(langcode("WPUPCFT020"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_57600,XmNvalueChangedCallback,speed_toggle,"8"); speed_115200 = XtVaCreateManagedWidget(langcode("WPUPCFT021"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_115200,XmNvalueChangedCallback,speed_toggle,"9"); speed_230400 = XtVaCreateManagedWidget(langcode("WPUPCFT022"),xmToggleButtonGadgetClass, speed_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(speed_230400,XmNvalueChangedCallback,speed_toggle,"10"); frame2 = XtVaCreateManagedWidget("Config_WX frame2", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // style XtVaCreateManagedWidget(langcode("WPUPCFT015"),xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); style_box = XmCreateRadioBox(frame2,"Config_WX Style box",al,ac); XtVaSetValues(style_box, XmNorientation, XmHORIZONTAL, NULL); style_8n1 = XtVaCreateManagedWidget(langcode("WPUPCFT016"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_8n1,XmNvalueChangedCallback,style_toggle,"0"); style_7e1 = XtVaCreateManagedWidget(langcode("WPUPCFT017"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7e1,XmNvalueChangedCallback,style_toggle,"1"); style_7o1 = XtVaCreateManagedWidget(langcode("WPUPCFT018"),xmToggleButtonGadgetClass, style_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(style_7o1,XmNvalueChangedCallback,style_toggle,"2"); frame3 = XtVaCreateManagedWidget("Config_WX frame3", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // data_type XtVaCreateManagedWidget(langcode("WPUPCFT024"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); data_box = XmCreateRadioBox(frame3,"Config_WX data box",al,ac); XtVaSetValues(data_box, XmNorientation, XmHORIZONTAL, NULL); data_auto = XtVaCreateManagedWidget(langcode("WPUPCFT025"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_auto,XmNvalueChangedCallback,data_toggle,"0"); data_bin = XtVaCreateManagedWidget(langcode("WPUPCFT026"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_bin,XmNvalueChangedCallback,data_toggle,"1"); data_ascii = XtVaCreateManagedWidget(langcode("WPUPCFT027"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_ascii,XmNvalueChangedCallback,data_toggle,"2"); frame4 = XtVaCreateManagedWidget("Config_WX frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // Rain Gauge Type // gauge_type XtVaCreateManagedWidget(langcode("WPUPCFWX03"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); gauge_box = XmCreateRadioBox(frame4,"Config_WX gauge box",al,ac); XtVaSetValues(gauge_box, XmNorientation, XmHORIZONTAL, NULL); WX_none = XtVaCreateManagedWidget(langcode("WPUPCFWX07"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_tenths = XtVaCreateManagedWidget(langcode("WPUPCFWX04"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hundredths = XtVaCreateManagedWidget(langcode("WPUPCFWX05"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_millimeters = XtVaCreateManagedWidget(langcode("WPUPCFWX06"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(WX_none,XmNvalueChangedCallback,rain_gauge_toggle,"0"); XtAddCallback(WX_tenths,XmNvalueChangedCallback,rain_gauge_toggle,"1"); XtAddCallback(WX_hundredths,XmNvalueChangedCallback,rain_gauge_toggle,"2"); XtAddCallback(WX_millimeters,XmNvalueChangedCallback,rain_gauge_toggle,"3"); sep = XtVaCreateManagedWidget("Config_WX sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_WX_change_data, config_WX_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_WX_destroy_shell, config_WX_dialog); pos_dialog(config_WX_dialog); delw = XmInternAtom(XtDisplay(config_WX_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_WX_dialog, delw, Config_WX_destroy_shell, (XtPointer)config_WX_dialog); begin_critical_section(&devices_lock, "interface_gui.c:Config_WX" ); if (config_type==0) { /* first time port */ XmTextFieldSetString(WX_device_name_data,GPS_PORT); XmTextFieldSetString(WX_comment,""); XmToggleButtonSetState(WX_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; device_data_type=0; XmToggleButtonSetState(data_auto,TRUE,FALSE); } else { /* reconfig */ XmTextFieldSetString(WX_device_name_data,devices[WX_port].device_name); XmTextFieldSetString(WX_comment,devices[WX_port].comment); if (devices[WX_port].connect_on_startup) { XmToggleButtonSetState(WX_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(WX_active_on_startup,FALSE,FALSE); } switch (devices[WX_port].sp) { case(B300): XmToggleButtonSetState(speed_300,TRUE,FALSE); device_speed=1; break; case(B1200): XmToggleButtonSetState(speed_1200,TRUE,FALSE); device_speed=2; break; case(B2400): XmToggleButtonSetState(speed_2400,TRUE,FALSE); device_speed=3; break; case(B4800): XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; case(B9600): XmToggleButtonSetState(speed_9600,TRUE,FALSE); device_speed=5; break; case(B19200): XmToggleButtonSetState(speed_19200,TRUE,FALSE); device_speed=6; break; case(B38400): XmToggleButtonSetState(speed_38400,TRUE,FALSE); device_speed=7; break; case(B57600): XmToggleButtonSetState(speed_57600,TRUE,FALSE); device_speed=8; break; case(B115200): XmToggleButtonSetState(speed_115200,TRUE,FALSE); device_speed=9; break; #ifdef B230400 case(B230400): XmToggleButtonSetState(speed_230400,TRUE,FALSE); device_speed=10; break; #endif // B230400 default: XmToggleButtonSetState(speed_4800,TRUE,FALSE); device_speed=4; break; } switch (devices[WX_port].style) { case(0): XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; case(1): XmToggleButtonSetState(style_7e1,TRUE,FALSE); device_style=1; break; case(2): XmToggleButtonSetState(style_7o1,TRUE,FALSE); device_style=2; break; default: XmToggleButtonSetState(style_8n1,TRUE,FALSE); device_style=0; break; } switch (atoi(devices[WX_port].device_host_pswd)) { case(0): XmToggleButtonSetState(data_auto,TRUE,FALSE); device_data_type=0; break; case(1): XmToggleButtonSetState(data_bin,TRUE,FALSE); device_data_type=1; break; case(2): XmToggleButtonSetState(data_ascii,TRUE,FALSE); device_data_type=2; break; default: device_data_type=0; break; } } end_critical_section(&devices_lock, "interface_gui.c:Config_WX" ); XmToggleButtonSetState(WX_none,FALSE,FALSE); XmToggleButtonSetState(WX_tenths,FALSE,FALSE); XmToggleButtonSetState(WX_hundredths,FALSE,FALSE); XmToggleButtonSetState(WX_millimeters,FALSE,FALSE); switch (WX_rain_gauge_type) { case(1): XmToggleButtonSetState(WX_tenths,TRUE,FALSE); break; case(2): XmToggleButtonSetState(WX_hundredths,TRUE,FALSE); break; case(3): XmToggleButtonSetState(WX_millimeters,TRUE,FALSE); break; default: XmToggleButtonSetState(WX_none,TRUE,FALSE); break; } XtManageChild(form); XtManageChild(speed_box); XtManageChild(style_box); XtManageChild(data_box); XtManageChild(gauge_box); XtManageChild(pane); resize_dialog(form, config_WX_dialog); XtPopup(config_WX_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_WX_dialog), XtWindow(config_WX_dialog)); } } /**** net WX CONFIGURE ******/ int NWX_port; Widget config_NWX_dialog = (Widget)NULL; Widget NWX_host_name_data; Widget NWX_host_port_data; Widget NWX_comment; Widget NWX_active_on_startup; Widget NWX_host_reconnect_data; void Config_NWX_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_NWX_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_NWX_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(NWX_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(NWX_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_NWX_change_data" ); temp_ptr = XmTextFieldGetString(NWX_host_name_data); xastir_snprintf(devices[NWX_port].device_host_name, sizeof(devices[NWX_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NWX_port].device_host_name); temp_ptr = XmTextFieldGetString(NWX_host_port_data); devices[NWX_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(NWX_comment); xastir_snprintf(devices[NWX_port].comment, sizeof(devices[NWX_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NWX_port].comment); if (XmToggleButtonGetState(NWX_active_on_startup)) { devices[NWX_port].connect_on_startup=1; } else { devices[NWX_port].connect_on_startup=0; } if(XmToggleButtonGetState(NWX_host_reconnect_data)) { devices[NWX_port].reconnect=1; } else { devices[NWX_port].reconnect=0; } xastir_snprintf(devices[NWX_port].device_host_pswd, sizeof(devices[NWX_port].device_host_pswd), "%d", device_data_type); /* reopen if was up*/ if ( was_up) { (void)add_device(NWX_port, DEVICE_NET_WX, devices[NWX_port].device_host_name, devices[NWX_port].device_host_pswd, devices[NWX_port].sp, 0, 0, devices[NWX_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[NWX_port].device_type=DEVICE_NET_WX; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_NWX_change_data" ); // Rebuild the interface control list update_interface_list(); Config_NWX_destroy_shell(widget,clientData,callData); } void Config_NWX( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, frame3, frame4, WX_none, button_ok, button_cancel, hostn, portn, comment, data_box, data_auto, data_bin, data_ascii, gauge_box, sep; // static Widget data_type, gauge_type; char temp[20]; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ Atom delw; if(!config_NWX_dialog) { NWX_port=port; config_NWX_dialog = XtVaCreatePopupShell(langcode("WPUPCFG021"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_NWX pane",xmPanedWindowWidgetClass, config_NWX_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_NWX form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); hostn = XtVaCreateManagedWidget(langcode("WPUPCFG022"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_name_data = XtVaCreateManagedWidget("Config_NWX host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, hostn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); portn = XtVaCreateManagedWidget(langcode("WPUPCFG023"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_port_data = XtVaCreateManagedWidget("Config_NWX port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, portn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_comment = XtVaCreateManagedWidget("Config_NWX comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); NWX_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NWX_host_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFG020"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NWX_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; frame3 = XtVaCreateManagedWidget("Config_NWX frame3", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NWX_host_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // data_type XtVaCreateManagedWidget(langcode("WPUPCFT024"),xmLabelWidgetClass, frame3, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); data_box = XmCreateRadioBox(frame3,"Config_NWX data box",al,ac); XtVaSetValues(data_box, XmNorientation, XmHORIZONTAL, NULL); data_auto = XtVaCreateManagedWidget(langcode("WPUPCFT025"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_auto,XmNvalueChangedCallback,data_toggle,"0"); data_bin = XtVaCreateManagedWidget(langcode("WPUPCFT026"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_bin,XmNvalueChangedCallback,data_toggle,"1"); data_ascii = XtVaCreateManagedWidget(langcode("WPUPCFT027"),xmToggleButtonGadgetClass, data_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(data_ascii,XmNvalueChangedCallback,data_toggle,"2"); frame4 = XtVaCreateManagedWidget("Config_WX frame4", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // Rain Gauge Type // gauge_type XtVaCreateManagedWidget(langcode("WPUPCFWX03"),xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); gauge_box = XmCreateRadioBox(frame4,"Config_WX gauge box",al,ac); XtVaSetValues(gauge_box, XmNorientation, XmHORIZONTAL, NULL); WX_none = XtVaCreateManagedWidget(langcode("WPUPCFWX07"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_tenths = XtVaCreateManagedWidget(langcode("WPUPCFWX04"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hundredths = XtVaCreateManagedWidget(langcode("WPUPCFWX05"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_millimeters = XtVaCreateManagedWidget(langcode("WPUPCFWX06"),xmToggleButtonGadgetClass, gauge_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(WX_none,XmNvalueChangedCallback,rain_gauge_toggle,"0"); XtAddCallback(WX_tenths,XmNvalueChangedCallback,rain_gauge_toggle,"1"); XtAddCallback(WX_hundredths,XmNvalueChangedCallback,rain_gauge_toggle,"2"); XtAddCallback(WX_millimeters,XmNvalueChangedCallback,rain_gauge_toggle,"3"); sep = XtVaCreateManagedWidget("Config_NWX sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_NWX_change_data, config_NWX_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_NWX_destroy_shell, config_NWX_dialog); pos_dialog(config_NWX_dialog); delw = XmInternAtom(XtDisplay(config_NWX_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_NWX_dialog, delw, Config_NWX_destroy_shell, (XtPointer)config_NWX_dialog); begin_critical_section(&devices_lock, "interface_gui.c:Config_NWX" ); if (config_type==0) { /* first time port */ XmTextFieldSetString(NWX_host_name_data,"localhost"); XmTextFieldSetString(NWX_host_port_data,"1234"); XmTextFieldSetString(NWX_comment,""); XmToggleButtonSetState(NWX_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(NWX_host_reconnect_data,TRUE,FALSE); device_data_type=0; XmToggleButtonSetState(data_auto,TRUE,FALSE); } else { /* reconfig */ XmTextFieldSetString(NWX_host_name_data,devices[NWX_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[NWX_port].sp); /* port number */ XmTextFieldSetString(NWX_host_port_data,temp); XmTextFieldSetString(NWX_comment,devices[NWX_port].comment); if (devices[NWX_port].connect_on_startup) { XmToggleButtonSetState(NWX_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(NWX_active_on_startup,FALSE,FALSE); } if (devices[NWX_port].reconnect) { XmToggleButtonSetState(NWX_host_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(NWX_host_reconnect_data,FALSE,FALSE); } switch (atoi(devices[NWX_port].device_host_pswd)) { case(0): XmToggleButtonSetState(data_auto,TRUE,FALSE); device_data_type=0; break; case(1): XmToggleButtonSetState(data_bin,TRUE,FALSE); device_data_type=1; break; case(2): XmToggleButtonSetState(data_ascii,TRUE,FALSE); device_data_type=2; break; default: device_data_type=0; break; } } XmToggleButtonSetState(WX_none,FALSE,FALSE); XmToggleButtonSetState(WX_tenths,FALSE,FALSE); XmToggleButtonSetState(WX_hundredths,FALSE,FALSE); XmToggleButtonSetState(WX_millimeters,FALSE,FALSE); switch (WX_rain_gauge_type) { case(1): XmToggleButtonSetState(WX_tenths,TRUE,FALSE); break; case(2): XmToggleButtonSetState(WX_hundredths,TRUE,FALSE); break; case(3): XmToggleButtonSetState(WX_millimeters,TRUE,FALSE); break; default: XmToggleButtonSetState(WX_none,TRUE,FALSE); break; } end_critical_section(&devices_lock, "interface_gui.c:Config_NWX" ); XtManageChild(form); XtManageChild(data_box); XtManageChild(frame3); XtManageChild(gauge_box); XtManageChild(pane); resize_dialog(form, config_NWX_dialog); XtPopup(config_NWX_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_NWX_dialog), XtWindow(config_NWX_dialog)); } } /*****************************************************/ /* Configure net GPS GUI */ /*****************************************************/ /**** net GPS CONFIGURE ******/ int NGPS_port; Widget config_NGPS_dialog = (Widget)NULL; Widget NGPS_host_name_data; Widget NGPS_host_port_data; Widget NGPS_comment; Widget NGPS_active_on_startup; Widget NGPS_host_reconnect_data; Widget NGPS_set_time; void Config_NGPS_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_NGPS_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_NGPS_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(NGPS_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(NGPS_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_NGPS_change_data" ); temp_ptr = XmTextFieldGetString(NGPS_host_name_data); xastir_snprintf(devices[NGPS_port].device_host_name, sizeof(devices[NGPS_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NGPS_port].device_host_name); temp_ptr = XmTextFieldGetString(NGPS_host_port_data); devices[NGPS_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(NGPS_comment); xastir_snprintf(devices[NGPS_port].comment, sizeof(devices[NGPS_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[NGPS_port].comment); if(XmToggleButtonGetState(NGPS_active_on_startup)) { devices[NGPS_port].connect_on_startup=1; } else { devices[NGPS_port].connect_on_startup=0; } if (XmToggleButtonGetState(NGPS_host_reconnect_data)) { devices[NGPS_port].reconnect=1; } else { devices[NGPS_port].reconnect=0; } if (XmToggleButtonGetState(NGPS_set_time)) { devices[NGPS_port].set_time=1; } else { devices[NGPS_port].set_time=0; } /* reopen */ if ( was_up ) { (void)add_device(NGPS_port, DEVICE_NET_GPSD, devices[NGPS_port].device_host_name, "", devices[NGPS_port].sp, 0, 0, devices[NGPS_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[NGPS_port].device_type=DEVICE_NET_GPSD; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_NGPS_change_data" ); // Rebuild the interface control list update_interface_list(); Config_NGPS_destroy_shell(widget,clientData,callData); } void Config_NGPS( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, hostn, portn, comment, sep; char temp[20]; Atom delw; if (!config_NGPS_dialog) { NGPS_port=port; config_NGPS_dialog = XtVaCreatePopupShell(langcode("WPUPCFG019"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_NGPS pane",xmPanedWindowWidgetClass, config_NGPS_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_NGPS form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); hostn = XtVaCreateManagedWidget(langcode("WPUPCFG017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_name_data = XtVaCreateManagedWidget("Config_NGPS host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, hostn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); portn = XtVaCreateManagedWidget(langcode("WPUPCFG018"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_port_data = XtVaCreateManagedWidget("Config_NGPS port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hostn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, portn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_comment = XtVaCreateManagedWidget("Config_NGPS comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, portn, XmNtopOffset, 8, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); NGPS_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_host_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFG020"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NGPS_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); NGPS_set_time = XtVaCreateManagedWidget(langcode("UNIOP00029"), xmToggleButtonWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, NGPS_host_reconnect_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // We can only set the time properly on Linux systems #ifndef HAVE_SETTIMEOFDAY XtSetSensitive(NGPS_set_time,FALSE); #endif // HAVE_SETTIMEOFDAY #ifdef __CYGWIN__ XtSetSensitive(NGPS_set_time,FALSE); #endif // __CYGWIN__ sep = XtVaCreateManagedWidget("Config_NGPS sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, NGPS_set_time, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Config_NGPS_change_data, config_NGPS_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Config_NGPS_destroy_shell, config_NGPS_dialog); pos_dialog(config_NGPS_dialog); delw = XmInternAtom(XtDisplay(config_NGPS_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_NGPS_dialog, delw, Config_NGPS_destroy_shell, (XtPointer)config_NGPS_dialog); if (config_type==0) { /* first time port */ XmTextFieldSetString(NGPS_host_name_data,"localhost"); XmTextFieldSetString(NGPS_host_port_data,"2947"); XmTextFieldSetString(NGPS_comment,""); XmToggleButtonSetState(NGPS_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(NGPS_host_reconnect_data,TRUE,FALSE); XmToggleButtonSetState(NGPS_set_time, FALSE, FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_NGPS" ); XmTextFieldSetString(NGPS_host_name_data,devices[NGPS_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[NGPS_port].sp); /* port number */ XmTextFieldSetString(NGPS_host_port_data,temp); XmTextFieldSetString(NGPS_comment,devices[NGPS_port].comment); if (devices[NGPS_port].connect_on_startup) { XmToggleButtonSetState(NGPS_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(NGPS_active_on_startup,FALSE,FALSE); } if (devices[NGPS_port].reconnect) { XmToggleButtonSetState(NGPS_host_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(NGPS_host_reconnect_data,FALSE,FALSE); } if (devices[NGPS_port].set_time) { XmToggleButtonSetState(NGPS_set_time, TRUE, FALSE); } else { XmToggleButtonSetState(NGPS_set_time, FALSE, FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_NGPS" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_NGPS_dialog); XtPopup(config_NGPS_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_NGPS_dialog), XtWindow(config_NGPS_dialog)); } } /*****************************************************/ /* Configure AX.25 TNC GUI */ /*****************************************************/ /**** AX.25 CONFIGURE ******/ int AX25_port; Widget config_AX25_dialog = (Widget)NULL; Widget AX25_device_name_data; Widget AX25_comment; Widget AX25_unproto1_data; Widget AX25_unproto2_data; Widget AX25_unproto3_data; Widget AX25_igate_data; Widget AX25_active_on_startup; Widget AX25_transmit_data; Widget AX25_relay_digipeat; void Config_AX25_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_AX25_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Config_AX25_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(AX25_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(AX25_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Config_AX25_change_data" ); temp_ptr = XmTextFieldGetString(AX25_device_name_data); xastir_snprintf(devices[AX25_port].device_name, sizeof(devices[AX25_port].device_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].device_name); temp_ptr = XmTextFieldGetString(AX25_comment); xastir_snprintf(devices[AX25_port].comment, sizeof(devices[AX25_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].comment); if(XmToggleButtonGetState(AX25_active_on_startup)) { devices[AX25_port].connect_on_startup=1; } else { devices[AX25_port].connect_on_startup=0; } if(XmToggleButtonGetState(AX25_transmit_data)) { devices[AX25_port].transmit_data=1; XtSetSensitive(AX25_relay_digipeat, TRUE); } else { devices[AX25_port].transmit_data=0; XtSetSensitive(AX25_relay_digipeat, FALSE); } if(XmToggleButtonGetState(AX25_relay_digipeat)) { devices[AX25_port].relay_digipeat=1; } else { devices[AX25_port].relay_digipeat=0; } devices[AX25_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(AX25_unproto1_data); xastir_snprintf(devices[AX25_port].unproto1, sizeof(devices[AX25_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto1); if(check_unproto_path(devices[AX25_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_unproto2_data); xastir_snprintf(devices[AX25_port].unproto2, sizeof(devices[AX25_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto2); if(check_unproto_path(devices[AX25_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_unproto3_data); xastir_snprintf(devices[AX25_port].unproto3, sizeof(devices[AX25_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto3); if(check_unproto_path(devices[AX25_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AX25_igate_data); xastir_snprintf(devices[AX25_port].unproto_igate, sizeof(devices[AX25_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AX25_port].unproto_igate); if(check_unproto_path(devices[AX25_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } devices[AX25_port].reconnect=1; // reopen if open before - n8ysz 20041213 // if (devices[AX25_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(AX25_port, DEVICE_AX25_TNC, devices[AX25_port].device_name, "", -1, -1, -1, 0, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[AX25_port].device_type=DEVICE_AX25_TNC; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Config_AX25_change_data" ); // Rebuild the interface control list update_interface_list(); Config_AX25_destroy_shell(widget,clientData,callData); } void Config_AX25( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, frame, devn, comment, proto, proto1, proto2, proto3, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, sep; // static Widget igate; char temp[50]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!config_AX25_dialog) { AX25_port=port; config_AX25_dialog = XtVaCreatePopupShell(langcode("WPUPCAX001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_AX25 pane",xmPanedWindowWidgetClass, config_AX25_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_AX25 form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); AX25_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); devn = XtVaCreateManagedWidget(langcode("WPUPCAX002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_device_name_data = XtVaCreateManagedWidget("Config_AX25 device_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, devn, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AX25_device_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_comment = XtVaCreateManagedWidget("Config_AX25 comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_active_on_startup, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_AX25 frame", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, devn, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; igate_box = XmCreateRadioBox(frame,"Config_AX25 IGate box",al,ac); XtVaSetValues(igate_box, XmNorientation, XmVERTICAL, XmNnumColumns,2, NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto1_data = XtVaCreateManagedWidget("Config_AX25 protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto2_data = XtVaCreateManagedWidget("Config_AX25 protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_unproto3_data = XtVaCreateManagedWidget("Config_AX25 protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto3, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 60, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AX25_igate_data = XtVaCreateManagedWidget("Config_TNC igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AX25_unproto3_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_AX25 sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, igate_label, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); #ifdef HAVE_LIBAX25 XtAddCallback(button_ok, XmNactivateCallback, Config_AX25_change_data, config_AX25_dialog); #else // Need code to use button_ok variable to quiet a compiler warning //when we don't have LIBAX25 linked-in. if (button_ok != button_cancel) { // Do nothing (to shut up a compiler warning) } #endif /* USE_AX25 */ XtAddCallback(button_cancel, XmNactivateCallback, Config_AX25_destroy_shell, config_AX25_dialog); pos_dialog(config_AX25_dialog); delw = XmInternAtom(XtDisplay(config_AX25_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_AX25_dialog, delw, Config_AX25_destroy_shell, (XtPointer)config_AX25_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(AX25_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(AX25_transmit_data,TRUE,FALSE); XmToggleButtonSetState(AX25_relay_digipeat,FALSE,FALSE); XmTextFieldSetString(AX25_device_name_data,""); XmTextFieldSetString(AX25_comment,""); device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(AX25_unproto1_data,"WIDE2-2"); XmTextFieldSetString(AX25_unproto2_data,""); XmTextFieldSetString(AX25_unproto3_data,""); XmTextFieldSetString(AX25_igate_data,""); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_AX25" ); if (devices[AX25_port].connect_on_startup) { XmToggleButtonSetState(AX25_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_active_on_startup,FALSE,FALSE); } switch (devices[AX25_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } if (devices[AX25_port].transmit_data) { XmToggleButtonSetState(AX25_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_transmit_data,FALSE,FALSE); } if (devices[AX25_port].relay_digipeat) { XmToggleButtonSetState(AX25_relay_digipeat,TRUE,FALSE); } else { XmToggleButtonSetState(AX25_relay_digipeat,FALSE,FALSE); } XmTextFieldSetString(AX25_device_name_data,devices[AX25_port].device_name); XmTextFieldSetString(AX25_comment,devices[AX25_port].comment); XmTextFieldSetString(AX25_unproto1_data,devices[AX25_port].unproto1); XmTextFieldSetString(AX25_unproto2_data,devices[AX25_port].unproto2); XmTextFieldSetString(AX25_unproto3_data,devices[AX25_port].unproto3); XmTextFieldSetString(AX25_igate_data,devices[AX25_port].unproto_igate); end_critical_section(&devices_lock, "interface_gui.c:Config_AX25" ); } XtManageChild(form); XtManageChild(igate_box); XtManageChild(pane); resize_dialog(form, config_AX25_dialog); XtPopup(config_AX25_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_AX25_dialog), XtWindow(config_AX25_dialog)); } } /*****************************************************/ /* Configure Network server GUI */ /*****************************************************/ /**** INTERNET CONFIGURE ******/ Widget config_Inet_dialog = (Widget)NULL; Widget Inet_active_on_startup; Widget Inet_host_data; Widget Inet_port_data; Widget Inet_comment; Widget Inet_password_data; Widget Inet_filter_data; Widget Inet_transmit_data; Widget Inet_reconnect_data; int Inet_port; void Inet_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Inet_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Inet_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(Inet_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(Inet_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Inet_change_data" ); temp_ptr = XmTextFieldGetString(Inet_host_data); xastir_snprintf(devices[Inet_port].device_host_name, sizeof(devices[Inet_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_name); temp_ptr = XmTextFieldGetString(Inet_password_data); xastir_snprintf(devices[Inet_port].device_host_pswd, sizeof(devices[Inet_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_pswd); temp_ptr = XmTextFieldGetString(Inet_filter_data); xastir_snprintf(devices[Inet_port].device_host_filter_string, sizeof(devices[Inet_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].device_host_filter_string); temp_ptr = XmTextFieldGetString(Inet_comment); xastir_snprintf(devices[Inet_port].comment, sizeof(devices[Inet_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Inet_port].comment); temp_ptr = XmTextFieldGetString(Inet_port_data); devices[Inet_port].sp=atoi(temp_ptr); XtFree(temp_ptr); if(XmToggleButtonGetState(Inet_active_on_startup)) { devices[Inet_port].connect_on_startup=1; } else { devices[Inet_port].connect_on_startup=0; } if(XmToggleButtonGetState(Inet_transmit_data)) { devices[Inet_port].transmit_data=1; } else { devices[Inet_port].transmit_data=0; } if(XmToggleButtonGetState(Inet_reconnect_data)) { devices[Inet_port].reconnect=1; } else { devices[Inet_port].reconnect=0; } // Changed 20041213 per emails with we7u - n8ysz // if (devices[Inet_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(Inet_port, DEVICE_NET_STREAM, devices[Inet_port].device_host_name, devices[Inet_port].device_host_pswd, devices[Inet_port].sp, 0, 0, devices[Inet_port].reconnect, devices[Inet_port].device_host_filter_string); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[Inet_port].device_type=DEVICE_NET_STREAM; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Inet_change_data" ); // Rebuild the interface control list update_interface_list(); Inet_destroy_shell(widget,clientData,callData); } void Config_Inet( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, filter, comment, sep; // static Widget password_fl; Atom delw; char temp[40]; if(!config_Inet_dialog) { Inet_port=port; config_Inet_dialog = XtVaCreatePopupShell(langcode("WPUPCFI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Inet pane",xmPanedWindowWidgetClass, config_Inet_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Inet form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); Inet_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFI002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_host_data = XtVaCreateManagedWidget("Config_Inet host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFI003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,Inet_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Inet_host_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_port_data = XtVaCreateManagedWidget("Config_Inet port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,10, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFI009"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_password_data = XtVaCreateManagedWidget("Config_Inet password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFI010"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Inet_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); filter = XtVaCreateManagedWidget(langcode("WPUPCFI015"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_filter_data = XtVaCreateManagedWidget("Config_Inet filter_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, filter, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Inet_filter_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Inet_comment = XtVaCreateManagedWidget("Config_Inet comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_filter_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); Inet_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFI011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_Inet sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Inet_reconnect_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Inet_change_data, config_Inet_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Inet_destroy_shell, config_Inet_dialog); pos_dialog(config_Inet_dialog); delw = XmInternAtom(XtDisplay(config_Inet_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Inet_dialog, delw, Inet_destroy_shell, (XtPointer)config_Inet_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(Inet_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Inet_transmit_data,TRUE,FALSE); // Core APRS-IS Servers XmTextFieldSetString(Inet_host_data,"rotate.aprs.net"); // Filtered port XmTextFieldSetString(Inet_port_data,"14580"); // Filter of 500 miles around my location. But only if I // enable transmit on that interface and globally! XmTextFieldSetString(Inet_filter_data,"m/500"); XmTextFieldSetString(Inet_comment,"Core INET Servers"); XmToggleButtonSetState(Inet_reconnect_data,TRUE,FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_Inet" ); if (devices[Inet_port].connect_on_startup) { XmToggleButtonSetState(Inet_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_active_on_startup,FALSE,FALSE); } if (devices[Inet_port].transmit_data) { XmToggleButtonSetState(Inet_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Inet_host_data,devices[Inet_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[Inet_port].sp); XmTextFieldSetString(Inet_port_data,temp); XmTextFieldSetString(Inet_password_data,devices[Inet_port].device_host_pswd); XmTextFieldSetString(Inet_filter_data,devices[Inet_port].device_host_filter_string); XmTextFieldSetString(Inet_comment,devices[Inet_port].comment); if (devices[Inet_port].reconnect) { XmToggleButtonSetState(Inet_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Inet_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_Inet" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Inet_dialog); XtPopup(config_Inet_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Inet_dialog), XtWindow(config_Inet_dialog)); } } //WE7U-DATABASE /*****************************************************/ /* Configure Database Server GUI */ /*****************************************************/ /**** DATABASE CONFIGURE ******/ Widget config_Database_dialog = (Widget)NULL; Widget Database_active_on_startup; Widget Database_host_data; Widget Database_port_data; Widget Database_comment; Widget Database_password_data; Widget Database_filter_data; Widget Database_transmit_data; Widget Database_reconnect_data; int Database_port; void Database_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Database_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void Database_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(Database_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(Database_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:Database_change_data" ); temp_ptr = XmTextFieldGetString(Database_host_data); xastir_snprintf(devices[Database_port].device_host_name, sizeof(devices[Database_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_name); temp_ptr = XmTextFieldGetString(Database_password_data); xastir_snprintf(devices[Database_port].device_host_pswd, sizeof(devices[Database_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_pswd); temp_ptr = XmTextFieldGetString(Database_filter_data); xastir_snprintf(devices[Database_port].device_host_filter_string, sizeof(devices[Database_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].device_host_filter_string); temp_ptr = XmTextFieldGetString(Database_comment); xastir_snprintf(devices[Database_port].comment, sizeof(devices[Database_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Database_port].comment); temp_ptr = XmTextFieldGetString(Database_port_data); devices[Database_port].sp=atoi(temp_ptr); XtFree(temp_ptr); if(XmToggleButtonGetState(Database_active_on_startup)) { devices[Database_port].connect_on_startup=1; } else { devices[Database_port].connect_on_startup=0; } if(XmToggleButtonGetState(Database_transmit_data)) { devices[Database_port].transmit_data=1; } else { devices[Database_port].transmit_data=0; } if(XmToggleButtonGetState(Database_reconnect_data)) { devices[Database_port].reconnect=1; } else { devices[Database_port].reconnect=0; } // n8ysz 20041213 // if (devices[Database_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(Database_port, DEVICE_NET_DATABASE, devices[Database_port].device_host_name, devices[Database_port].device_host_pswd, devices[Database_port].sp, 0, 0, devices[Database_port].reconnect, devices[Database_port].device_host_filter_string); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[Database_port].device_type=DEVICE_NET_DATABASE; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:Database_change_data" ); // Rebuild the interface control list update_interface_list(); Database_destroy_shell(widget,clientData,callData); } void Config_Database( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, filter, sep, comment; // static Widget password_fl; Atom delw; char temp[40]; if(!config_Database_dialog) { Database_port=port; config_Database_dialog = XtVaCreatePopupShell(langcode("WPUPCFID01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Database pane",xmPanedWindowWidgetClass, config_Database_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Database form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); Database_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_active_on_startup, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFID02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_host_data = XtVaCreateManagedWidget("Config_Database host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFID03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Database_host_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_port_data = XtVaCreateManagedWidget("Config_Database port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Database_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset,10, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFID09"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_password_data = XtVaCreateManagedWidget("Config_Database password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFID10"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,Database_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); filter = XtVaCreateManagedWidget(langcode("WPUPCFID15"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_filter_data = XtVaCreateManagedWidget("Config_Database filter_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, filter, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, filter, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Database_comment = XtVaCreateManagedWidget("Config_Database comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, filter, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); Database_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFID11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_Database sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, Database_reconnect_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Database_change_data, config_Database_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Database_destroy_shell, config_Database_dialog); pos_dialog(config_Database_dialog); delw = XmInternAtom(XtDisplay(config_Database_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Database_dialog, delw, Database_destroy_shell, (XtPointer)config_Database_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Database_transmit_data,TRUE,FALSE); //XmTextFieldSetString(Database_host_data,"first.aprs.net"); XmTextFieldSetString(Database_host_data,""); XmTextFieldSetString(Database_port_data,""); XmTextFieldSetString(Database_filter_data,""); XmTextFieldSetString(Database_comment,""); XmToggleButtonSetState(Database_reconnect_data,FALSE,FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_Database" ); if (devices[Database_port].connect_on_startup) { XmToggleButtonSetState(Database_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Database_active_on_startup,FALSE,FALSE); } if (devices[Database_port].transmit_data) { XmToggleButtonSetState(Database_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Database_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Database_host_data,devices[Database_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[Database_port].sp); XmTextFieldSetString(Database_port_data,temp); XmTextFieldSetString(Database_password_data,devices[Database_port].device_host_pswd); XmTextFieldSetString(Database_filter_data,devices[Database_port].device_host_filter_string); XmTextFieldSetString(Database_comment,devices[Database_port].comment); if (devices[Database_port].reconnect) { XmToggleButtonSetState(Database_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Database_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_Database" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Database_dialog); XtPopup(config_Database_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Database_dialog), XtWindow(config_Database_dialog)); } } #ifdef HAVE_DB //AA3SD-SQL SERVER DATABASE, for db_gis spatial databases /*****************************************************/ /* Configure SQL Database Server GUI */ /*****************************************************/ /**** DATABASE CONFIGURE ******/ Widget config_Sql_Database_dialog = (Widget)NULL; // dialog for sql server database connections used in db_gis.c Widget Sql_Database_active_on_startup; Widget Sql_Database_query_on_startup_data; Widget Sql_Database_host_data; Widget Sql_Database_iport_data; // = sp, tcp port number on which to connect to database server Widget Sql_Database_comment; Widget Sql_Database_password_data; Widget Sql_Database_transmit_data; Widget Sql_Database_reconnect_data; int Sql_Database_port; // xastir interface port number, not tcp/ip port Widget Sql_Database_username_data; Widget Sql_Database_schema_name_data; // lesstif combo boxes are not fully implemented. // replace combo box with a fake combo box made out of a menu when only lesstif is available #ifdef USE_COMBO_BOX Widget Sql_Database_dbms_data; #else int sddd_value; // integer value of the currently selected item (replicating ordinal position in picklist) Widget sddd_button; // button to bring up the picklist Widget sddd_buttons[3]; Widget sddd_menuPane; /// menu that acts as the picklist of dbms types Widget sddd_menu; /// menu top level #endif // USE_COMBO_BOX Widget sddd_widget; // widget used to bind next control in either use combo box or not cases. Widget Sql_Database_unix_socket_data; Widget Sql_Database_schema_type_data; Widget Sql_Database_errormessage_data; // display most recent error message on connection #ifdef HAVE_MYSQL // Set the values on the user interface to an appropriate set // of defaults for connecting to a mysql database. void Sql_Database_set_defaults_mysql(Widget widget, XtPointer clientData, XtPointer callData) { XmString cb_item; //cb_item = XmStringCreateLtoR("MySQL (lat/long)", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL][0], XmFONTLIST_DEFAULT_TAG); //cb_item = XmStringCreateLtoR("MySQL (spatial)", XmFONTLIST_DEFAULT_TAG); #ifdef HAVE_MYSQL_SPATIAL cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], XmFONTLIST_DEFAULT_TAG); #endif /* HAVE_MYSQL_SPATIAL */ #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); #else XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[DB_MYSQL_SPATIAL], NULL); sddd_value = DB_MYSQL_SPATIAL; #endif // USE_COMBO_BOX XmStringFree(cb_item); //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); XmTextFieldSetString(Sql_Database_host_data,"localhost"); XmTextFieldSetString(Sql_Database_iport_data,"3306"); XmTextFieldSetString(Sql_Database_username_data,"xastir_user"); XmTextFieldSetString(Sql_Database_schema_name_data,"xastir"); // ** get default from mysql_config at configure time XmTextFieldSetString(Sql_Database_unix_socket_data,"/var/lib/mysql/mysql.sock"); XmTextFieldSetString(Sql_Database_comment,""); XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); // don't set Sql_Database_errormessage_data - leave most recent error message visible } #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS // Set the values on the user interface to an appropriate set // of defaults for connecting to a postgresql database. void Sql_Database_set_defaults_postgis(Widget widget, XtPointer clientData, XtPointer callData) { XmString cb_item; //cb_item = XmStringCreateLtoR("Postgres/Postgis", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_POSTGIS][0], XmFONTLIST_DEFAULT_TAG); #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); #else XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[DB_POSTGIS], NULL); sddd_value = DB_POSTGIS; #endif // USE_COMBO_BOX XmStringFree(cb_item); //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); XmTextFieldSetString(Sql_Database_host_data,"localhost"); XmTextFieldSetString(Sql_Database_iport_data,"5432"); XmTextFieldSetString(Sql_Database_username_data,"xastir_user"); XmTextFieldSetString(Sql_Database_schema_name_data,"xastir"); // ** get default from mysql_config at configure time XmTextFieldSetString(Sql_Database_unix_socket_data,""); XmTextFieldSetString(Sql_Database_comment,""); XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); // don't set Sql_Database_errormessage_data - leave most recent error message visible } #endif /* HAVE_POSTGIS */ // Destroy the dialog used to set properties for a SQL database interface. void Sql_Database_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_Sql_Database_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } /* Callback for OK button on SQL database interface properties dialog. Creates a new interface with the parameters provided in the dialog, or alters the values of the selected interface that was displayed in the dialog. Differs from other interfaces in that an active database connection needs to be started from the interface parameters. */ void Sql_Database_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; // flag to restart connection with new parameters char *temp_ptr; // temporary variable for retrieving string data from XmTextFields int cb_selected; // temporary variable for retrieving combo box selections // change to use code from db_gis.c busy_cursor(appshell); was_up=0; if (debug_level & 2) { fprintf(stderr,"Storing SQL Database interface on port %d\n",Sql_Database_port); } // determine if there is an active connection based on this interface, // if so, stop it and restart after changes have been made. if (get_device_status(Sql_Database_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ fprintf(stderr,"Device is up, disconnecting from database \n"); was_up=1; // close connection } // This needs to be a unitary transaction for other interfaces as we don't // want to read/write data from an interface while its configuration is in an // inconsistent state. In this case (SQL databases, we still need this to be // a unitary transaction in case a new connection is created while the // configuration is in an inconsistent state. begin_critical_section(&devices_lock, "interface_gui.c:Sql_Database_change_data" ); // ** set the interface values needed to make a connection to a database ** // hostname temp_ptr = XmTextFieldGetString(Sql_Database_host_data); xastir_snprintf(devices[Sql_Database_port].device_host_name, sizeof(devices[Sql_Database_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_name); //port temp_ptr = XmTextFieldGetString(Sql_Database_iport_data); devices[Sql_Database_port].sp=atoi(temp_ptr); XtFree(temp_ptr); //username temp_ptr = XmTextFieldGetString(Sql_Database_username_data); xastir_snprintf(devices[Sql_Database_port].database_username, sizeof(devices[Sql_Database_port].database_username), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_pswd); //password temp_ptr = XmTextFieldGetString(Sql_Database_password_data); xastir_snprintf(devices[Sql_Database_port].device_host_pswd, sizeof(devices[Sql_Database_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].device_host_pswd); // schema name temp_ptr = XmTextFieldGetString(Sql_Database_schema_name_data); xastir_snprintf(devices[Sql_Database_port].database_schema, sizeof(devices[Sql_Database_port].database_schema), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].database_schema); // database type cb_selected = FALSE; #ifdef USE_COMBO_BOX XtVaGetValues(Sql_Database_dbms_data,XmNselectedPosition, &cb_selected, NULL); #else // find out the value of the latest selection from the Sql_Databas_dbms_data_menu cb_selected = sddd_value; #endif if (cb_selected) { devices[Sql_Database_port].database_type = cb_selected; } else { // If no selection, // default to mysql non-spatial, unless postgis is available. #ifdef HAVE_POSTGIS devices[Sql_Database_port].database_type = DB_POSTGIS; #endif /* HAVE_POSTGIS */ #ifdef HAVE_MYSQL devices[Sql_Database_port].database_type = DB_MYSQL; #endif /* HAVE_MYSQL */ } // schema type cb_selected = FALSE; XtVaGetValues(Sql_Database_schema_type_data,XmNselectedPosition, &cb_selected, NULL); if (cb_selected) { devices[Sql_Database_port].database_schema_type = cb_selected; } else { // If no selection, default to simple schema. devices[Sql_Database_port].database_schema_type = XASTIR_SCHEMA_SIMPLE; } // unix socket temp_ptr = XmTextFieldGetString(Sql_Database_unix_socket_data); xastir_snprintf(devices[Sql_Database_port].database_unix_socket, sizeof(devices[Sql_Database_port].database_unix_socket), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].database_unix_socket); // reset the error message to a blank xastir_snprintf(devices[Sql_Database_port].database_errormessage, sizeof(devices[Sql_Database_port].database_errormessage), " "); // ** set additional interface values ** // comment to display on interface list temp_ptr = XmTextFieldGetString(Sql_Database_comment); xastir_snprintf(devices[Sql_Database_port].comment, sizeof(devices[Sql_Database_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[Sql_Database_port].comment); // activate on startup if(XmToggleButtonGetState(Sql_Database_active_on_startup)) { devices[Sql_Database_port].connect_on_startup=1; } else { devices[Sql_Database_port].connect_on_startup=0; } // query on startup if(XmToggleButtonGetState(Sql_Database_query_on_startup_data)) { devices[Sql_Database_port].query_on_startup=1; } else { devices[Sql_Database_port].query_on_startup=0; } // allow saving data if(XmToggleButtonGetState(Sql_Database_transmit_data)) { devices[Sql_Database_port].transmit_data=1; } else { devices[Sql_Database_port].transmit_data=0; } // reconnect on database connection failure if(XmToggleButtonGetState(Sql_Database_reconnect_data)) { devices[Sql_Database_port].reconnect=1; } else { devices[Sql_Database_port].reconnect=0; } if (was_up) { // If the connection was allready open when we started then reconnect // and reopen the database connection with the new parameters. if (openConnection(&devices[Sql_Database_port],&connections[Sql_Database_port])==1) { port_data[Sql_Database_port].status = DEVICE_UP; } else { port_data[Sql_Database_port].status = DEVICE_ERROR; } } /* add device type */ devices[Sql_Database_port].device_type=DEVICE_SQL_DATABASE; end_critical_section(&devices_lock, "interface_gui.c:Sql_Database_change_data" ); // Rebuild the interface control list update_interface_list(); // close the dialog Sql_Database_destroy_shell(widget,clientData,callData); if (debug_level & 2) { fprintf(stderr,"Done storing sql interface parameters\n"); } } #ifndef USE_COMBO_BOX void sddd_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //sddd_menu is zero based, constants for database types are one based. sddd_value = (int)userData + 1; if (debug_level & 4096) { fprintf(stderr,"Selected value on dbms pulldown: %d\n",sddd_value); } } #endif // USE_COMBO_BOX /* dialog to obtain connection parameters for a SQL server (MySQL/Postgresql) * database for spatialy enabled database support */ void Config_sql_Database( Widget w, int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, label_dbms, label_schema_type, ihost, iport, password, unix_socket, error_message, sep, comment, username, schema_name; static Widget button_mysql_defaults; // set form values to defaults for mysql static Widget button_postgis_defaults; // set form values to defaults for postgresql/postgis Dimension width, height; int defaults_set; // Have defaults been set on form for new interface? // Used to make only a single set defaults call when // support for multiple types of dbms are available. Atom delw; char temp[40]; XmString cb_item; XmString *cb_items[2]; int x; #ifndef USE_COMBO_BOX int i; // loop counter Arg args[12]; // available for XtSetArguments char buf[18]; char *tmp; #endif // !USE_COMBO_BOX /* // configuration parameters for a sql server database char database_username[20]; // username to use to connect to database // default xastir int database_type; // type of dbms (posgresql, mysql, etc) // default mysql char database_schema[20]; // name of database or schema to use // default xastir char database_errormessage[255]; // most recent error message from attempting to make a connection with using this descriptor. int database_schema_type; // table structures to use in the database A database schema could contain both APRSWorld and XASTIR table structures, but a separate database descriptor should be defined for each. // default simple char database_unix_socket[255]; // MySQL - unix socket parameter (path and filename) // device_host_name = hostname for database server // sp = port on which to connect to database server (Not database_port) // device_host_password = password to use to connect to database -- security issue needs to be addressed */ if(!config_Sql_Database_dialog) { // port is position in xastir interface list, not tcp port on which to connect Sql_Database_port=port; // SQL Server Database config_Sql_Database_dialog = XtVaCreatePopupShell("SQL Server Database", xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_Database pane",xmPanedWindowWidgetClass, config_Sql_Database_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_Database form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 13, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Activate on startup Sql_Database_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // DMBS label_dbms = XtVaCreateManagedWidget("Database:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_active_on_startup, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Combo box to pick dbms cb_items [0] = (XmString *) XtMalloc ( sizeof (XmString) * 4 ); // Combo box items are defined by xastir_dbms_type, defined in db_gis.c cb_items[0][0] = XmStringCreateLtoR( &xastir_dbms_type[1][0], XmFONTLIST_DEFAULT_TAG); cb_items[0][1] = XmStringCreateLtoR( &xastir_dbms_type[2][0], XmFONTLIST_DEFAULT_TAG); cb_items[0][2] = XmStringCreateLtoR( &xastir_dbms_type[3][0], XmFONTLIST_DEFAULT_TAG); // mysql //cb_items[0][0] = XmStringCreateLtoR("MySQL (lat/long)", XmFONTLIST_DEFAULT_TAG); // postgresql //cb_items[0][1] = XmStringCreateLtoR("Postgres/Postgis", XmFONTLIST_DEFAULT_TAG); // mysql with spatial extensions //cb_items[0][2] = XmStringCreateLtoR("MySQL (spatial)", XmFONTLIST_DEFAULT_TAG); cb_items[0][3] = NULL; #ifdef USE_COMBO_BOX Sql_Database_dbms_data = XtVaCreateManagedWidget("select dbms", xmComboBoxWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label_dbms, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNitems, cb_items[0], XmNitemCount, 3, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNmatchBehavior, XmQUICK_NAVIGATE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sddd_widget = Sql_Database_dbms_data; #else // lesstif, at least as of version 0.95 in 2008, doesn't fully support combo boxes. // // lesstif 0.94 doesn't support adding items to the list on creation through XmNitems // lesstif 0.94 combo boxes don't have means to set currently selected value // or to retrieve currently selected value. // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. // // Fake a combo box with a menu, as done by xpdf in in XPDFViewer.cc // // create widgets and populate menu // sddd_ abbreviates name of single control that is being replaced: Sql_Database_dbms_data // sddd_value // numeric value for the database dbms type // sddd_button // picklist item // sddd_menu // menu that acts as the picklist of dbms types x = 0; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; sddd_menuPane = XmCreatePulldownMenu(form,"sddd_menuPane", args, x); //sddd_menu is zero based, constants for database types are one based. //sddd_value is set to match constants in callback. for (i=0; i<3; i++) { x = 0; XmStringGetLtoR(cb_items[0][i],XmFONTLIST_DEFAULT_TAG,&tmp); XtSetArg(args[x], XmNlabelString, cb_items[0][i]); x++; XtSetArg(args[x], XmNuserData, (XtPointer)i); x++; XtSetArg(args[x], XmNfontList, fontlist1); x++; sprintf(buf,"button%d",i); sddd_button = XmCreatePushButton(sddd_menuPane, buf, args, x); XtManageChild(sddd_button); XtAddCallback(sddd_button, XmNactivateCallback, sddd_menuCallback, config_Sql_Database_dialog); sddd_buttons[i] = sddd_button; } x = 0; XtSetArg(args[x], XmNleftAttachment, XmATTACH_WIDGET); ++x; XtSetArg(args[x], XmNleftWidget, label_dbms); ++x; XtSetArg(args[x], XmNtopAttachment, XmATTACH_FORM); ++x; XtSetArg(args[x], XmNmarginWidth, 0); ++x; XtSetArg(args[x], XmNmarginHeight, 0); ++x; XtSetArg(args[x], XmNtopOffset, 7); ++x; XtSetArg(args[x], XmNleftOffset, 1); ++x; XtSetArg(args[x], XmNsubMenuId, sddd_menuPane); ++x; sddd_menu = XmCreateOptionMenu(form, "sddd_Menu", args, x); XtManageChild(sddd_menu); sddd_widget = sddd_menu; #endif // free up the XmStrings used to create the picklist x=0; while ( cb_items[0][x] ) { XmStringFree ( cb_items[0][x++] ); } x=0; XtFree ( (char *) cb_items[0] ); // *** when localizing these strings propagate the localizations to // the set default functions above and to constants for picklist // selection recognition. *** //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,1,1); //XmStringFree(cb_item); //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_POSTGIS][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,2,1); //XmStringFree(cb_item); //cb_item = XmStringCreateLtoR(&xastir_dbms_type[DB_MYSQL_SPATIAL][0], XmFONTLIST_DEFAULT_TAG); //XmComboBoxAddItem(Sql_Database_dbms_data,cb_item,3,1); //XmStringFree(cb_item); // Schema Type label_schema_type = XtVaCreateManagedWidget("With Tables for",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, sddd_widget, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Combo box to pick schema Sql_Database_schema_type_data = XtVaCreateManagedWidget("Tables to use", xmComboBoxWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, label_schema_type, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // *** need to add constants for order and localization *** // ? use an array - schm_typ[XASTIR_SCHEMA_SIMPLE]=langcode("codeforxastirsimple").... ? // ?or some other form of key-value pairs? // simple //cb_item = XmStringCreateLtoR("Xastir - simple", XmFONTLIST_DEFAULT_TAG); cb_item = XmStringCreateLtoR(&xastir_schema_type[XASTIR_SCHEMA_SIMPLE][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(Sql_Database_schema_type_data,cb_item,1,1); XmStringFree(cb_item); /* not yet implemented // aprs world cb_item = XmStringCreateLtoR("APRSWorld", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); // full cb_item = XmStringCreateLtoR("Xastir - full", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); // cad cb_item = XmStringCreateLtoR("Xastir - CAD", XmFONTLIST_DEFAULT_TAG); XmComboBoxAddItem(cad_line_style_data,cb_item,2,1); XmStringFree(cb_item); */ // Store data Sql_Database_transmit_data = XtVaCreateManagedWidget("Store incoming data",xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sddd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Retrieve data on start Sql_Database_query_on_startup_data = XtVaCreateManagedWidget("Load data on start",xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sddd_widget, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_transmit_data, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // put retrieve now button here. // hostname ihost = XtVaCreateManagedWidget(langcode("WPUPCFID02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_host_data = XtVaCreateManagedWidget("Config_Database host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 55, XmNmaxLength, 255, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // tcp port for server, not xastir interface port // port iport = XtVaCreateManagedWidget(langcode("WPUPCFID03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_host_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_iport_data = XtVaCreateManagedWidget("Config_Database port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_transmit_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Username username = XtVaCreateManagedWidget("Username",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_username_data = XtVaCreateManagedWidget("Config_Database username_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNmaxLength, 25, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, username, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Password password = XtVaCreateManagedWidget("Password",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_username_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_password_data = XtVaCreateManagedWidget("Config_Database password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_host_data, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Schema/Database name schema_name = XtVaCreateManagedWidget("Schema/Database name",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_schema_name_data= XtVaCreateManagedWidget("Config_Database schema_name_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNmaxLength, 50, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, schema_name, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // MySQL unix socket unix_socket = XtVaCreateManagedWidget("MySQL unix socket",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, Sql_Database_schema_name_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_unix_socket_data = XtVaCreateManagedWidget("Config_Database unix_socket_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 30, XmNmaxLength, 190, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, unix_socket, XmNleftOffset, 1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_username_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // comment comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_schema_name_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); Sql_Database_comment = XtVaCreateManagedWidget("Config_Database comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_schema_name_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // reconnect on network failure Sql_Database_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFID11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_comment, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // most recent error error_message = XtVaCreateManagedWidget("Most Recent Error:",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // error message isn't editable and isn't saved Sql_Database_errormessage_data = XtVaCreateManagedWidget("Config_Database error_message", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, FALSE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 79, XmNwidth, ((79*7)+2), XmNmaxLength, 255, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_reconnect_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, error_message, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // separator line sep = XtVaCreateManagedWidget("Config_Database sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, Sql_Database_errormessage_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: MySQL Defaults button_mysql_defaults = XtVaCreateManagedWidget("MySQL Defaults",xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: Postgis Defaults button_postgis_defaults = XtVaCreateManagedWidget("Postgis Defaults",xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 6, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: OK button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 7, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 9, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button: Cancel button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 12, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(button_mysql_defaults,FALSE); #ifdef HAVE_MYSQL XtSetSensitive(button_mysql_defaults,TRUE); XtAddCallback(button_mysql_defaults, XmNactivateCallback, Sql_Database_set_defaults_mysql, config_Sql_Database_dialog); #endif /* HAVE_MYSQL */ XtSetSensitive(button_postgis_defaults,FALSE); #ifdef HAVE_POSTGIS XtSetSensitive(button_postgis_defaults,TRUE); XtAddCallback(button_postgis_defaults, XmNactivateCallback, Sql_Database_set_defaults_postgis, config_Sql_Database_dialog); #endif /* HAVE_POSTGIS */ XtAddCallback(button_ok, XmNactivateCallback, Sql_Database_change_data, config_Sql_Database_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Sql_Database_destroy_shell, config_Sql_Database_dialog); pos_dialog(config_Sql_Database_dialog); delw = XmInternAtom(XtDisplay(config_Sql_Database_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_Sql_Database_dialog, delw, Sql_Database_destroy_shell, (XtPointer)config_Sql_Database_dialog); if (config_type==0) { /* first time port */ // Default settings for a new interface. defaults_set = 0; #ifdef HAVE_MYSQL Sql_Database_set_defaults_mysql(config_Sql_Database_dialog,NULL,NULL); defaults_set = 1; #endif /* HAVE_MYSQL */ #ifdef HAVE_POSTGIS if (defaults_set==0) { // mysql support not available, use postgis Sql_Database_set_defaults_postgis(config_Sql_Database_dialog,NULL,NULL); } #endif /* HAVE_POSTGIS */ } else { /* reconfigure an existing interface */ // why critical section here? We are reading data from an existing configuration, // not changing the configuration while the interface might be in use. begin_critical_section(&devices_lock, "interface_gui.c:Config_sql_Database" ); // *** need to look up localized string for database_type *** cb_item = XmStringCreateLtoR(&xastir_dbms_type[devices[Sql_Database_port].database_type][0], XmFONTLIST_DEFAULT_TAG); #ifdef USE_COMBO_BOX XmComboBoxSelectItem(Sql_Database_dbms_data,cb_item); XmComboBoxSetItem(Sql_Database_dbms_data,cb_item); #else //sddd_menu is zero based, constants for database types are one based. //sddd_value matches constants. XtVaSetValues(sddd_menu, XmNmenuHistory, sddd_buttons[devices[Sql_Database_port].database_type - 1 ], NULL); sddd_value = devices[Sql_Database_port].database_type; #endif XmStringFree(cb_item); cb_item = XmStringCreateLtoR(&xastir_schema_type[devices[Sql_Database_port].database_schema_type][0], XmFONTLIST_DEFAULT_TAG); XmComboBoxSelectItem(Sql_Database_schema_type_data,cb_item); XmComboBoxSetItem(Sql_Database_schema_type_data,cb_item); XmStringFree(cb_item); if (devices[Sql_Database_port].connect_on_startup) { XmToggleButtonSetState(Sql_Database_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_active_on_startup,FALSE,FALSE); } if (devices[Sql_Database_port].query_on_startup) { XmToggleButtonSetState(Sql_Database_query_on_startup_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_query_on_startup_data,FALSE,FALSE); } if (devices[Sql_Database_port].transmit_data) { XmToggleButtonSetState(Sql_Database_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_transmit_data,FALSE,FALSE); } XmTextFieldSetString(Sql_Database_host_data,devices[Sql_Database_port].device_host_name); XmTextFieldSetString(Sql_Database_schema_name_data,devices[Sql_Database_port].database_schema); xastir_snprintf(temp, sizeof(temp), "%d", devices[Sql_Database_port].sp); XmTextFieldSetString(Sql_Database_iport_data,temp); XmTextFieldSetString(Sql_Database_username_data,devices[Sql_Database_port].database_username); XmTextFieldSetString(Sql_Database_password_data,devices[Sql_Database_port].device_host_pswd); XmTextFieldSetString(Sql_Database_unix_socket_data,devices[Sql_Database_port].database_unix_socket); XmTextFieldSetString(Sql_Database_comment,devices[Sql_Database_port].comment); // display most recent error message XmTextFieldSetString(Sql_Database_errormessage_data,devices[Sql_Database_port].database_errormessage); if (devices[Sql_Database_port].reconnect) { XmToggleButtonSetState(Sql_Database_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(Sql_Database_reconnect_data,FALSE,FALSE); } end_critical_section(&devices_lock, "interface_gui.c:Config_sql_Database" ); } XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_Sql_Database_dialog); XtPopup(config_Sql_Database_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_Sql_Database_dialog), XtWindow(config_Sql_Database_dialog)); } } #endif /* HAVE_DB */ /*****************************************************/ /* Configure AGWPE Server GUI */ /*****************************************************/ /**** AGWPE CONFIGURE ******/ Widget config_AGWPE_dialog = (Widget)NULL; Widget AGWPE_active_on_startup; Widget AGWPE_host_data; Widget AGWPE_port_data; Widget AGWPE_comment; Widget AGWPE_password_data; Widget AGWPE_transmit_data; Widget AGWPE_igate_data; Widget AGWPE_reconnect_data; Widget AGWPE_unproto1_data; Widget AGWPE_unproto2_data; Widget AGWPE_unproto3_data; Widget AGWPE_relay_digipeat; Widget AGWPE_radioport_data; int AGWPE_port; void AGWPE_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); config_AGWPE_dialog = (Widget)NULL; if (choose_interface_dialog != NULL) { Choose_interface_destroy_shell(choose_interface_dialog,choose_interface_dialog,NULL); } choose_interface_dialog = (Widget)NULL; } void AGWPE_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int was_up; char *temp_ptr; busy_cursor(appshell); was_up=0; if (get_device_status(AGWPE_port) == DEVICE_IN_USE) { /* if active shutdown before changes are made */ /*fprintf(stderr,"Device is up, shutting down\n");*/ (void)del_device(AGWPE_port); was_up=1; usleep(1000000); // Wait for one second } begin_critical_section(&devices_lock, "interface_gui.c:AGWPE_change_data" ); devices[AGWPE_port].igate_options=device_igate_options; temp_ptr = XmTextFieldGetString(AGWPE_host_data); xastir_snprintf(devices[AGWPE_port].device_host_name, sizeof(devices[AGWPE_port].device_host_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_name); temp_ptr = XmTextFieldGetString(AGWPE_password_data); xastir_snprintf(devices[AGWPE_port].device_host_pswd, sizeof(devices[AGWPE_port].device_host_pswd), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_pswd); temp_ptr = XmTextFieldGetString(AGWPE_comment); xastir_snprintf(devices[AGWPE_port].comment, sizeof(devices[AGWPE_port].comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].comment); temp_ptr = XmTextFieldGetString(AGWPE_port_data); devices[AGWPE_port].sp=atoi(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(AGWPE_unproto1_data); xastir_snprintf(devices[AGWPE_port].unproto1, sizeof(devices[AGWPE_port].unproto1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto1); if(check_unproto_path(devices[AGWPE_port].unproto1)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_unproto2_data); xastir_snprintf(devices[AGWPE_port].unproto2, sizeof(devices[AGWPE_port].unproto2), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto2); if(check_unproto_path(devices[AGWPE_port].unproto2)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_unproto3_data); xastir_snprintf(devices[AGWPE_port].unproto3, sizeof(devices[AGWPE_port].unproto3), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto3); if(check_unproto_path(devices[AGWPE_port].unproto3)) { popup_message_always(langcode("WPUPCFT042"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_igate_data); xastir_snprintf(devices[AGWPE_port].unproto_igate, sizeof(devices[AGWPE_port].unproto_igate), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].unproto_igate); if(check_unproto_path(devices[AGWPE_port].unproto_igate)) { popup_message_always(langcode("WPUPCFT044"), langcode("WPUPCFT043")); } temp_ptr = XmTextFieldGetString(AGWPE_radioport_data); xastir_snprintf(devices[AGWPE_port].device_host_filter_string, sizeof(devices[AGWPE_port].device_host_filter_string), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(devices[AGWPE_port].device_host_filter_string); if(XmToggleButtonGetState(AGWPE_active_on_startup)) { devices[AGWPE_port].connect_on_startup=1; } else { devices[AGWPE_port].connect_on_startup=0; } if(XmToggleButtonGetState(AGWPE_transmit_data)) { devices[AGWPE_port].transmit_data=1; } else { devices[AGWPE_port].transmit_data=0; } //WE7U // if(XmToggleButtonGetState(AGWPE_relay_digipeat)) // devices[AGWPE_port].relay_digipeat=1; // else devices[AGWPE_port].relay_digipeat=0; if(XmToggleButtonGetState(AGWPE_reconnect_data)) { devices[AGWPE_port].reconnect=1; } else { devices[AGWPE_port].reconnect=0; } // n8ysz 20041213 // if (devices[AGWPE_port].connect_on_startup==1 || was_up) { if ( was_up) { (void)add_device(AGWPE_port, DEVICE_NET_AGWPE, devices[AGWPE_port].device_host_name, devices[AGWPE_port].device_host_pswd, devices[AGWPE_port].sp, 0, 0, devices[AGWPE_port].reconnect, ""); } /* delete list */ // modify_device_list(4,0); /* add device type */ devices[AGWPE_port].device_type=DEVICE_NET_AGWPE; /* rebuild list */ // modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:AGWPE_change_data" ); // Rebuild the interface control list update_interface_list(); AGWPE_destroy_shell(widget,clientData,callData); } void Config_AGWPE( Widget UNUSED(w), int config_type, int port) { static Widget pane, scrollwindow, form, button_ok, button_cancel, ihost, iport, password, sep, igate_box, igate_o_0, igate_o_1, igate_o_2, igate_label, frame, proto, proto1, proto2, proto3, radioport_label, comment; // static Widget igate, password_fl; Atom delw; char temp[40]; Arg al[50]; // Arg list register unsigned int ac = 0; // Arg Count if(!config_AGWPE_dialog) { AGWPE_port=port; config_AGWPE_dialog = XtVaCreatePopupShell(langcode("WPUPCFIA01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Config_AGWPE pane",xmPanedWindowWidgetClass, config_AGWPE_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Config_AGWPE form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); AGWPE_active_on_startup = XtVaCreateManagedWidget(langcode("UNIOP00011"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_transmit_data = XtVaCreateManagedWidget(langcode("UNIOP00010"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_active_on_startup, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_relay_digipeat = XtVaCreateManagedWidget(langcode("UNIOP00030"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_transmit_data, XmNleftOffset,35, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); ihost = XtVaCreateManagedWidget(langcode("WPUPCFIA02"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_host_data = XtVaCreateManagedWidget("Config_AGWPE host_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, MAX_DEVICE_NAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ihost, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); iport = XtVaCreateManagedWidget(langcode("WPUPCFIA03"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,AGWPE_host_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_port_data = XtVaCreateManagedWidget("Config_AGWPE port_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 5, XmNwidth, ((5*7)+2), XmNmaxLength, 6, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, iport, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_port_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_comment = XtVaCreateManagedWidget("Config_AGWPE comment", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 49, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_transmit_data, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); password = XtVaCreateManagedWidget(langcode("WPUPCFIA09"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_password_data = XtVaCreateManagedWidget("Config_AGWPE password_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, password, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // password_fl XtVaCreateManagedWidget(langcode("WPUPCFIA10"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ihost, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,AGWPE_password_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], NULL); AGWPE_reconnect_data = XtVaCreateManagedWidget(langcode("WPUPCFIA11"),xmToggleButtonWidgetClass,form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); radioport_label = XtVaCreateManagedWidget(langcode("WPUPCFIA15"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, AGWPE_reconnect_data, XmNleftOffset, 50, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_radioport_data = XtVaCreateManagedWidget("Config_AGWPE radioport_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, radioport_label, XmNleftOffset, 10, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, password, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("Config_AGWPE frame", xmFrameWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, AGWPE_reconnect_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // igate XtVaCreateManagedWidget(langcode("IGPUPCF000"),xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // Set args for color ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; igate_box = XmCreateRadioBox(frame,"Config_AGWPE IGate box",al,ac); XtVaSetValues(igate_box,XmNorientation, XmVERTICAL,XmNnumColumns,2,NULL); igate_o_0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_0,XmNvalueChangedCallback,igate_toggle,"0"); igate_o_1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_1,XmNvalueChangedCallback,igate_toggle,"1"); igate_o_2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"),xmToggleButtonGadgetClass, igate_box, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(igate_o_2,XmNvalueChangedCallback,igate_toggle,"2"); proto = XtVaCreateManagedWidget(langcode("WPUPCFT011"), xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT012"), VERSIONFRM); proto1 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 12, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto1_data = XtVaCreateManagedWidget("Config_AGWPE protopath1", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto1, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT013"), VERSIONFRM); proto2 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto1, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto2_data = XtVaCreateManagedWidget("Config_AGWPE protopath2", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto1_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, proto2, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), langcode("WPUPCFT014"), VERSIONFRM); proto3 = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto2, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_unproto3_data = XtVaCreateManagedWidget("Config_AGWPE protopath3", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto2_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, proto3, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); xastir_snprintf(temp, sizeof(temp), "%s", langcode("IGPUPCF004")); igate_label = XtVaCreateManagedWidget(temp, xmLabelWidgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, proto3, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 45, XmNrightAttachment,XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); AGWPE_igate_data = XtVaCreateManagedWidget("Config_AGWPE igate_data", xmTextFieldWidgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 40, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_unproto3_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, igate_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Config_AGWPE sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, AGWPE_igate_data, XmNtopOffset, 14, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, AGWPE_change_data, config_AGWPE_dialog); XtAddCallback(button_cancel, XmNactivateCallback, AGWPE_destroy_shell, config_AGWPE_dialog); pos_dialog(config_AGWPE_dialog); delw = XmInternAtom(XtDisplay(config_AGWPE_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(config_AGWPE_dialog, delw, AGWPE_destroy_shell, (XtPointer)config_AGWPE_dialog); if (config_type==0) { /* first time port */ XmToggleButtonSetState(AGWPE_active_on_startup,TRUE,FALSE); XmToggleButtonSetState(AGWPE_transmit_data,TRUE,FALSE); //XmTextFieldSetString(AGWPE_host_data,"first.aprs.net"); XmTextFieldSetString(AGWPE_host_data,"localhost"); XmTextFieldSetString(AGWPE_port_data,"8000"); XmTextFieldSetString(AGWPE_comment,""); XmToggleButtonSetState(AGWPE_reconnect_data,FALSE,FALSE); XmToggleButtonSetState(AGWPE_relay_digipeat, FALSE, FALSE); device_igate_options=0; XmToggleButtonSetState(igate_o_0,TRUE,FALSE); XmTextFieldSetString(AGWPE_unproto1_data,"WIDE2-2"); XmTextFieldSetString(AGWPE_unproto2_data,""); XmTextFieldSetString(AGWPE_unproto3_data,""); XmTextFieldSetString(AGWPE_igate_data,""); XmTextFieldSetString(AGWPE_radioport_data,"1"); //WE7U // Keep this statement until we get relay digipeating functional for // this interface. XtSetSensitive(AGWPE_relay_digipeat, FALSE); } else { /* reconfig */ begin_critical_section(&devices_lock, "interface_gui.c:Config_AGWPE" ); if (devices[AGWPE_port].connect_on_startup) { XmToggleButtonSetState(AGWPE_active_on_startup,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_active_on_startup,FALSE,FALSE); } if (devices[AGWPE_port].transmit_data) { XmToggleButtonSetState(AGWPE_transmit_data,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_transmit_data,FALSE,FALSE); } // if (devices[AGWPE_port].relay_digipeat) // XmToggleButtonSetState(AGWPE_relay_digipeat, TRUE, FALSE); // else XmToggleButtonSetState(AGWPE_relay_digipeat, FALSE, FALSE); // if (devices[AGWPE_port].transmit_data) { // XtSetSensitive(AGWPE_relay_digipeat, TRUE); // } // else XtSetSensitive(AGWPE_relay_digipeat, FALSE); XmTextFieldSetString(AGWPE_host_data,devices[AGWPE_port].device_host_name); xastir_snprintf(temp, sizeof(temp), "%d", devices[AGWPE_port].sp); XmTextFieldSetString(AGWPE_port_data,temp); XmTextFieldSetString(AGWPE_password_data,devices[AGWPE_port].device_host_pswd); XmTextFieldSetString(AGWPE_comment,devices[AGWPE_port].comment); if (devices[AGWPE_port].reconnect) { XmToggleButtonSetState(AGWPE_reconnect_data,TRUE,FALSE); } else { XmToggleButtonSetState(AGWPE_reconnect_data,FALSE,FALSE); } XmTextFieldSetString(AGWPE_radioport_data,devices[AGWPE_port].device_host_filter_string); switch (devices[AGWPE_port].igate_options) { case(0): XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; case(1): XmToggleButtonSetState(igate_o_1,TRUE,FALSE); device_igate_options=1; break; case(2): XmToggleButtonSetState(igate_o_2,TRUE,FALSE); device_igate_options=2; break; default: XmToggleButtonSetState(igate_o_0,TRUE,FALSE); device_igate_options=0; break; } XmTextFieldSetString(AGWPE_unproto1_data,devices[AGWPE_port].unproto1); XmTextFieldSetString(AGWPE_unproto2_data,devices[AGWPE_port].unproto2); XmTextFieldSetString(AGWPE_unproto3_data,devices[AGWPE_port].unproto3); XmTextFieldSetString(AGWPE_igate_data,devices[AGWPE_port].unproto_igate); end_critical_section(&devices_lock, "interface_gui.c:Config_AGWPE" ); } XtManageChild(igate_box); XtManageChild(form); XtManageChild(pane); resize_dialog(form, config_AGWPE_dialog); XtPopup(config_AGWPE_dialog,XtGrabNone); } else { (void)XRaiseWindow(XtDisplay(config_AGWPE_dialog), XtWindow(config_AGWPE_dialog)); } } /*****************************************************/ /* Configure Interface GUI */ /*****************************************************/ int are_shells_up(void) { int up; up=1; if (config_TNC_dialog) { (void)XRaiseWindow(XtDisplay(config_TNC_dialog), XtWindow(config_TNC_dialog)); } else { if (config_GPS_dialog) { (void)XRaiseWindow(XtDisplay(config_GPS_dialog), XtWindow(config_GPS_dialog)); } else { if (config_WX_dialog) { (void)XRaiseWindow(XtDisplay(config_WX_dialog), XtWindow(config_WX_dialog)); } else { if (config_NGPS_dialog) { (void)XRaiseWindow(XtDisplay(config_NGPS_dialog), XtWindow(config_NGPS_dialog)); } else { if (config_AX25_dialog) { (void)XRaiseWindow(XtDisplay(config_AX25_dialog), XtWindow(config_AX25_dialog)); } else { if (config_Inet_dialog) { (void)XRaiseWindow(XtDisplay(config_Inet_dialog), XtWindow(config_Inet_dialog)); } else { if (config_NWX_dialog) { (void)XRaiseWindow(XtDisplay(config_NWX_dialog), XtWindow(config_NWX_dialog)); } else { if (config_Database_dialog) { (void)XRaiseWindow(XtDisplay(config_Database_dialog), XtWindow(config_Database_dialog)); } else { #ifdef HAVE_DB if (config_Sql_Database_dialog) { (void)XRaiseWindow(XtDisplay(config_Sql_Database_dialog), XtWindow(config_Sql_Database_dialog)); } else { #endif /* HAVE_DB */ if (config_AGWPE_dialog) { (void)XRaiseWindow(XtDisplay(config_AGWPE_dialog), XtWindow(config_AGWPE_dialog)); } else { up=0; } #ifdef HAVE_DB } #endif /* HAVE_DB */ } } } } } } } } return(up); } void Choose_interface_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (are_shells_up()==0) { XtPopdown(shell); XtDestroyWidget(shell); choose_interface_dialog = (Widget)NULL; } } void modify_device_list(int option, int port) { int i,n; char temp[150]; char temp2[150]; XmString str_ptr; n=1; for (i=0; i < MAX_IFACE_DEVICES; i++) { if (devices[i].device_type!=DEVICE_NONE) { switch (option) { case 0 : /* delete entire list available */ XmListDeleteAllItems(control_iface_list); return; // Exit routine break; case 1 : /* delete item pointed to by port */ if (i==port) { XmListDeletePos(control_iface_list,n); } n++; break; case 2 : /* create item list */ /* format list for device modify*/ switch (devices[i].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00000"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_SERIAL_MKISS_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00001"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, atoi(devices[i].radio_port), devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_NET_DATABASE: case DEVICE_SQL_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_AGWPE: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00001"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_host_name, devices[i].sp, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_AX25_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00002"), langcode("UNIOP00006"), i, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; default: break; } /* look at list data (Must be "Device" port#) */ XmListAddItem(control_iface_list, str_ptr = XmStringCreateLtoR(temp,XmFONTLIST_DEFAULT_TAG),n++); XmStringFree(str_ptr); break; case 3 : /* create item list */ /* format list for device control*/ if (port_data[i].active==DEVICE_IN_USE) { switch (port_data[i].status) { case DEVICE_DOWN: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00006")); break; case DEVICE_UP: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00007")); break; case DEVICE_ERROR: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00008")); break; default: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00009")); break; } } else { xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("IFDIN00006")); } switch (devices[i].device_type) { case DEVICE_SERIAL_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_TNC_HSP_GPS: case DEVICE_SERIAL_TNC_AUX_GPS: case DEVICE_SERIAL_GPS: case DEVICE_SERIAL_WX: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00003"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_SERIAL_MKISS_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00004"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, atoi(devices[i].radio_port), devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_NET_DATABASE: case DEVICE_SQL_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_GPSD: case DEVICE_NET_WX: case DEVICE_NET_AGWPE: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00004"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_host_name, devices[i].sp, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; case DEVICE_AX25_TNC: xastir_snprintf(temp, sizeof(temp), langcode("IFDIN00005"), langcode("UNIOP00006"), i, temp2, dtype[devices[i].device_type].device_name, devices[i].device_name, devices[i].comment); strncat(temp, " ", sizeof(temp) - 1 - strlen(temp)); break; default: break; } /* look at list data (Must be "Device" port#) */ XmListAddItem(control_iface_list, str_ptr = XmStringCreateLtoR(temp,XmFONTLIST_DEFAULT_TAG),n++); XmStringFree(str_ptr); break; case 4 : /* delete entire list available */ XmListDeleteAllItems(control_iface_list); return; // Exit routine break; default: break; } } } } // Rebuild the list in the interface control dialog so that the // current status of each interface is shown. // void update_interface_list(void) { // If the interface control dialog exists if (control_interface_dialog) { // Delete the entire list modify_device_list(4,0); // Create the list again with updated values modify_device_list(3,0); } } void interface_setup(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { char *what = (char *)clientData; int x,i,do_w; char *temp; /*char temp2[100];*/ XmString *list; int port; int found; port=-1; found=0; do_w=atoi(what); /* get option selected */ XtVaGetValues(interface_type_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(interface_type_list,x)) { found=x; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { if (do_w==0) // Add an interface { /* add */ /*fprintf(stderr,"ADD DEVICE\n");*/ /* delete list */ begin_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); modify_device_list(0,0); end_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); port=get_open_device(); // Find an unused port number /*fprintf(stderr,"Open_port %d\n",port);*/ if(port!=-1) { /*devices[port].device_type=found;*/ /*fprintf(stderr,"adding device %s on port %d\n",dtype[found].device_name,port);*/ switch (found) { //WE7U: Set up for new KISS device type case DEVICE_SERIAL_KISS_TNC: // configure this port if (debug_level & 1) { fprintf(stderr,"ADD SERIAL KISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_KISS_TNC, 0, port); break; case DEVICE_SERIAL_MKISS_TNC: // configure this port if (debug_level & 1) { fprintf(stderr,"ADD SERIAL MKISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_MKISS_TNC, 0, port); break; case DEVICE_SERIAL_TNC: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC\n"); } Config_TNC(w, DEVICE_SERIAL_TNC, 0, port); break; case DEVICE_SERIAL_TNC_HSP_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC w HSP GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_HSP_GPS, 0, port); break; case DEVICE_SERIAL_TNC_AUX_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL TNC w AUX GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_AUX_GPS, 0, port); break; case DEVICE_SERIAL_GPS: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL GPS\n"); } Config_GPS(w, 0, port); break; case DEVICE_SERIAL_WX: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SERIAL WX\n"); } Config_WX(w, 0, port); break; case DEVICE_NET_WX: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD Network WX\n"); } Config_NWX(w, 0, port); break; case DEVICE_NET_GPSD: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD Network GPS\n"); } Config_NGPS(w, 0, port); break; case DEVICE_AX25_TNC: /* configure this port */ if (debug_level & 1) #ifdef HAVE_LIBAX25 fprintf(stderr,"ADD AX.25 TNC\n"); Config_AX25(w, 0, port); #else // HAVE_LIBAX25 fprintf(stderr,"AX.25 support not compiled into Xastir!\n"); popup_message(langcode("POPEM00004"),langcode("POPEM00021")); #endif // HAVE_LIBAX25 break; case DEVICE_NET_STREAM: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET STREAM\n"); } Config_Inet(w, 0, port); break; case DEVICE_NET_DATABASE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET DATABASE\n"); } Config_Database(w, 0, port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD SQL DATABASE\n"); } Config_sql_Database(w, 0, port); break; #endif /* HAVE_DB */ case DEVICE_NET_AGWPE: /* configure this port */ if (debug_level & 1) { fprintf(stderr,"ADD NET AGWPE\n"); } Config_AGWPE(w, 0, port); break; default: break; } } /* rebuild list */ begin_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); modify_device_list(2,0); end_critical_section(&devices_lock, "interface_gui.c:interface_setup" ); } /*fprintf(stderr,"SELECTION is %s\n",temp);*/ XtFree(temp); } } // clientData: // 0 = Add // 1 = Delete // 2 = Properties // void interface_option(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, form, label, button_add, button_cancel; char *what = (char *)clientData; int i,x,n,do_w; char *temp; char temp2[50]; int port; XmString *list; // int data_on,pos; int found; Atom delw; XmString str_ptr; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ // data_on=0; // pos=0; found=0; do_w=atoi(what); switch (do_w) { case 0:/* add interface */ if (!choose_interface_dialog) { choose_interface_dialog = XtVaCreatePopupShell(langcode("WPUPCIF002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("interface_option pane",xmPanedWindowWidgetClass, choose_interface_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("interface_option form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); label = XtVaCreateManagedWidget(langcode("WPUPCIF002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, MAX_IFACE_DEVICE_TYPES); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, label); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; interface_type_list = XmCreateScrolledList(form,"interface_option list",al,ac); n=1; for (i=1; i key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(choose_interface_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(choose_interface_dialog), XtWindow(choose_interface_dialog)); } break; case 1:/* delete interface */ case 2:/* interface properties */ /* get option selected */ XtVaGetValues(control_iface_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if(XmListPosSelected(control_iface_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { /* look at list data (Must be "Device" port#) */ if (2 != sscanf(temp,"%49s %d",temp2,&port)) { fprintf(stderr,"interface_option:sscanf parsing error\n"); } if(do_w==1) { /* delete interface */ /*fprintf(stderr,"delete interface port %d\n",port);*/ if (port_data[port].active==DEVICE_IN_USE) { /* shut down and delete port */ /*fprintf(stderr,"Shutting down port %d\n",port);*/ (void)del_device(port); } begin_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* delete item at that port */ modify_device_list(1,port); /* Clear device */ devices[port].device_type=DEVICE_NONE; devices[port].device_name[0] = '\0'; devices[port].radio_port[0] = '\0'; devices[port].device_converse_string[0] = '\0'; devices[port].device_host_name[0] = '\0'; devices[port].device_host_pswd[0] = '\0'; devices[port].device_host_filter_string[0] = '\0'; devices[port].comment[0] = '\0'; devices[port].unproto1[0] = '\0'; devices[port].unproto2[0] = '\0'; devices[port].unproto3[0] = '\0'; devices[port].unproto_igate[0] = '\0'; devices[port].style=0; devices[port].igate_options=0; devices[port].transmit_data=0; devices[port].reconnect=0; devices[port].connect_on_startup=0; end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); } else { /* Properties */ begin_critical_section(&devices_lock, "interface_gui.c:interface_option" ); if (debug_level & 1) { fprintf(stderr,"Changing device %s on port %d\n", dtype[devices[port].device_type].device_name,port); } switch (devices[port].device_type) { case DEVICE_SERIAL_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC\n"); } Config_TNC(w, DEVICE_SERIAL_TNC, 1, port); break; case DEVICE_SERIAL_KISS_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL KISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_KISS_TNC, 1, port); break; case DEVICE_SERIAL_MKISS_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL MKISS TNC\n"); } Config_TNC(w, DEVICE_SERIAL_MKISS_TNC, 1, port); break; case DEVICE_SERIAL_TNC_HSP_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC with HSP GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_HSP_GPS, 1, port); break; case DEVICE_SERIAL_TNC_AUX_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL TNC with AUX GPS\n"); } Config_TNC(w, DEVICE_SERIAL_TNC_AUX_GPS, 1, port); break; case DEVICE_SERIAL_GPS: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL GPS\n"); } Config_GPS(w, 1, port); break; case DEVICE_SERIAL_WX: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SERIAL WX\n"); } Config_WX(w, 1, port); break; case DEVICE_NET_WX: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify Network WX\n"); } Config_NWX(w, 1, port); break; case DEVICE_NET_GPSD: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify Network GPS\n"); } Config_NGPS(w, 1, port); break; case DEVICE_AX25_TNC: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify AX.25 TNC\n"); } Config_AX25(w, 1, port); break; case DEVICE_NET_STREAM: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET STREAM\n"); } Config_Inet(w, 1, port); break; case DEVICE_NET_DATABASE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET DATABASE\n"); } Config_Database(w, 1, port); break; #ifdef HAVE_DB case DEVICE_SQL_DATABASE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify SQL DATABASE\n"); } Config_sql_Database(w, 1, port); break; #endif /* HAVE_DB */ case DEVICE_NET_AGWPE: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); /* configure this port */ if (debug_level & 1) { fprintf(stderr,"Modify NET AGWPE\n"); } Config_AGWPE(w, 1, port); break; default: end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); break; } } /*fprintf(stderr,"interface - %s\n",temp);*/ XtFree(temp); } break; default: break; } } /*****************************************************/ /* Control Interface GUI */ /*****************************************************/ extern void startup_all_or_defined_port(int port); extern void shutdown_all_active_or_defined_port(int port); void start_stop_interface( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *which = (char *)clientData; int do_w; char temp2[50]; int i,x; char *temp; int port; XmString *list; int found; busy_cursor(appshell); found=0; /* get option selected */ XtVaGetValues(control_iface_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(control_iface_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&temp)) { x=i+1; } } } /* if selection was made */ if (found) { /* delete list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // modify_device_list(4,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); /* look at list data (Must be "Device" port#) */ if (2 != sscanf(temp,"%49s %d",temp2,&port)) { fprintf(stderr,"start_stop_interface:sscanf parsing error\n"); } /*fprintf(stderr,"Port to change %d\n",port);*/ do_w = atoi(which); if (do_w) { shutdown_all_active_or_defined_port(port); } else { /*fprintf(stderr,"DO port up\n");*/ if (port_data[port].active==DEVICE_IN_USE) { /*fprintf(stderr,"Device was up, Shutting down\n");*/ shutdown_all_active_or_defined_port(port); } /* now start port */ startup_all_or_defined_port(port); } /* rebuild list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // modify_device_list(3,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_interface" ); // Rebuild the interface control list update_interface_list(); XtFree(temp); } } void start_stop_all_interfaces( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *which = (char *)clientData; // Whether to start or stop the interfaces int do_w; busy_cursor(appshell); //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // modify_device_list(4,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); do_w = atoi(which); if (do_w) // We wish to shut down all ports { shutdown_all_active_or_defined_port(-1); } else // We wish to start up all ports { startup_all_or_defined_port(-2); } /* rebuild list */ //begin_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // modify_device_list(3,0); //end_critical_section(&devices_lock, "interface_gui.c:start_stop_all_interfaces" ); // Rebuild the interface control list update_interface_list(); } void Control_interface_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&control_interface_dialog_lock, "interface_gui.c:Control_interface_destroy_shell" ); XtDestroyWidget(shell); control_interface_dialog = (Widget)NULL; end_critical_section(&control_interface_dialog_lock, "interface_gui.c:Control_interface_destroy_shell" ); } void control_interface( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget scrollwindow, rowcol, form, button_start, button_stop, button_start_all, button_stop_all, button_cancel; static Widget button_add, button_delete, button_properties; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!control_interface_dialog) { begin_critical_section(&control_interface_dialog_lock, "interface_gui.c:control_interface" ); control_interface_dialog = XtVaCreatePopupShell(langcode("IFPUPCT000"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, TRUE, XmNfontList, fontlist1, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, control_interface_dialog, XmNscrollingPolicy, XmAUTOMATIC, NULL); rowcol = XtVaCreateWidget("control_interface rowcol", xmRowColumnWidgetClass, scrollwindow, XmNorientation, XmVERTICAL, XmNnumColumns, 1, XmNpacking, XmPACK_TIGHT, XmNisAligned, TRUE, XmNentryAlignment, XmALIGNMENT_CENTER, XmNkeyboardFocusPolicy, XmEXPLICIT, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, MAX_IFACE_DEVICES); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; control_iface_list = XmCreateScrolledList(rowcol,"control_interface list",al,ac); /* build device list */ begin_critical_section(&devices_lock, "interface_gui.c:control_interface" ); modify_device_list(3,0); end_critical_section(&devices_lock, "interface_gui.c:control_interface" ); form = XtVaCreateWidget("control_interface form",xmFormWidgetClass, rowcol, XmNfractionBase, 4, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); button_start = XtVaCreateManagedWidget(langcode("IFPUPCT001"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbottomAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_start_all = XtVaCreateManagedWidget(langcode("IFPUPCT003"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbottomAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_add = XtVaCreateManagedWidget(langcode("UNIOP00007"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_delete = XtVaCreateManagedWidget(langcode("UNIOP00008"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_stop = XtVaCreateManagedWidget(langcode("IFPUPCT002"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_stop_all = XtVaCreateManagedWidget(langcode("IFPUPCT004"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_properties = XtVaCreateManagedWidget(langcode("UNIOP00009"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_start, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNbottomAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_add, XmNactivateCallback, interface_option, "0"); XtAddCallback(button_delete, XmNactivateCallback, interface_option, "1"); XtAddCallback(button_properties, XmNactivateCallback, interface_option, "2"); XtAddCallback(button_cancel, XmNactivateCallback, Control_interface_destroy_shell, control_interface_dialog); XtAddCallback(button_start, XmNactivateCallback, start_stop_interface, "0"); XtAddCallback(button_stop, XmNactivateCallback, start_stop_interface, "1"); XtAddCallback(button_start_all, XmNactivateCallback, start_stop_all_interfaces, "0"); XtAddCallback(button_stop_all, XmNactivateCallback, start_stop_all_interfaces, "1"); delw = XmInternAtom(XtDisplay(control_interface_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(control_interface_dialog, delw, Control_interface_destroy_shell, (XtPointer)control_interface_dialog); XtVaSetValues(control_iface_list, XmNbackground, colors[0x0f], NULL); pos_dialog(control_interface_dialog); XtManageChild(control_iface_list); XtManageChild(form); XtManageChild(rowcol); resize_dialog(rowcol, control_interface_dialog); end_critical_section(&control_interface_dialog_lock, "interface_gui.c:control_interface" ); XtPopup(control_interface_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(control_interface_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(control_interface_dialog), XtWindow(control_interface_dialog)); } } void interface_status(Widget w) { int i; char s; char opt; int read_data; int write_data; read_data=0; write_data=0; s='\0'; begin_critical_section(&devices_lock, "interface_gui.c:interface_status" ); for (i=0; i < MAX_IFACE_DEVICES; i++) { read_data=0; write_data=0; opt='\0'; if (devices[i].device_type!=DEVICE_NONE) { switch(devices[i].device_type) { case DEVICE_SERIAL_TNC: s='0'; // Select icon for status bar break; case DEVICE_SERIAL_TNC_HSP_GPS: s='1'; // Select icon for status bar break; case DEVICE_SERIAL_GPS: s='2'; // Select icon for status bar break; case DEVICE_SERIAL_WX: case DEVICE_NET_WX: s='3'; // Select icon for status bar break; case DEVICE_SQL_DATABASE: s='8'; // Select icon for status bar break; case DEVICE_NET_DATABASE: case DEVICE_NET_STREAM: case DEVICE_NET_AGWPE: s='4'; // Select icon for status bar break; case DEVICE_AX25_TNC: case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: s='5'; // Select icon for status bar break; case DEVICE_NET_GPSD: s='6'; // Select icon for status bar break; case DEVICE_SERIAL_TNC_AUX_GPS: s='7'; // Select icon for status bar break; default: break; } if (port_data[i].active==DEVICE_IN_USE) { if (port_data[i].status==DEVICE_UP) { if (port_data[i].bytes_input_last != port_data[i].bytes_input) { if (begin_critical_section(&port_data_lock, "interface_gui.c:interface_status(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } port_data[i].bytes_input_last = port_data[i].bytes_input; port_data[i].port_activity = 1; if (end_critical_section(&port_data_lock, "interface_gui.c:interface_status(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } read_data=1; } if (port_data[i].bytes_output_last != port_data[i].bytes_output) { if (begin_critical_section(&port_data_lock, "interface_gui.c:interface_status(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } port_data[i].bytes_output_last = port_data[i].bytes_output; port_data[i].port_activity = 1; if (end_critical_section(&port_data_lock, "interface_gui.c:interface_status(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", i); } write_data=1; } if (write_data) { opt='>'; } else { if (read_data) { opt='<'; } else { opt='^'; } } } else { opt='*'; } } else { opt='\0'; } symbol(w,0,'~',s,opt,XtWindow(iface_da),0,(i*10),0,' '); } else { symbol(w,0,'~','#','\0',XtWindow(iface_da),0,(i*10),0,' '); } } end_critical_section(&devices_lock, "interface_gui.c:interface_option" ); } Xastir-Release-2.2.4/src/io-common.c0000664000175000017500000000303415151324131016151 0ustar hibbyhibby /* Copyright 2002 Daniel Egnor. See LICENSE.geocoder file. * Portions Copyright (C) 2000-2026 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "io.h" #include // Must be last include file #include "leak_detection.h" int io_out_i4(struct io_file *f,int pos,int o) { unsigned char x[4]; x[0] = o >> 24; x[1] = o >> 16; x[2] = o >> 8; x[3] = o; return io_out(f,pos,x,sizeof x); } int io_out_i2(struct io_file *f,int pos,short int o) { unsigned char x[2]; x[0] = o >> 8; x[1] = o; return io_out(f,pos,x,sizeof x); } int io_out_i1(struct io_file *f,int pos,signed char o) { return io_out(f,pos,&o,sizeof o); } int io_in_i4(struct io_file *f,int pos,int *i) { unsigned char x[4]; const int r = io_in(f,pos,x,sizeof x); if (i) { *i = (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]; } return r; } int io_in_i2(struct io_file *f,int pos,short *i) { unsigned char x[2]; const int r = io_in(f,pos,x,sizeof x); if (i) { *i = (x[0] << 8) | x[1]; } return r; } int io_in_i1(struct io_file *f,int pos,signed char *i) { return io_in(f,pos,i,sizeof *i); } int io_strntoi(const char *str,int len) { int r = 0; int sign = 1; const char * const end = str + len; while (end != str && isspace((int)*str)) { ++str; } if (end != str && *str == '-') { (sign *= -1),++str; } if (end != str && *str == '+') { ++str; } while (end != str && isdigit((int)*str)) { r = *str++ - '0' + 10 * r; } return r * sign; } Xastir-Release-2.2.4/src/lang.c0000664000175000017500000002031715151324131015200 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "lang.h" // Must be last include file #include "leak_detection.h" char lang_code[MAX_LANG_ENTRIES][MAX_LANG_CODE+1]; char *lang_code_ptr[MAX_LANG_ENTRIES]; char lang_buffer[MAX_LANG_BUFFER]; char lang_hotkey[MAX_LANG_ENTRIES]; int lang_code_number; long buffer_len; char invalid_code[50]; char *langcode(char *code) { int i; // Create an invalid code string to return in case we can't find the proper string if (strlen(code) <= MAX_LANG_CODE) // Code is ok { xastir_snprintf(invalid_code, sizeof(invalid_code), "IC>%s", code); } else // Code is too long { xastir_snprintf(invalid_code, sizeof(invalid_code), "IC>TOO LONG:%s",code); fprintf(stderr,"IC>TOO LONG:%s\n",code); return(invalid_code); } if(lang_code_number>0) { for(i=0; i0) { for(i=0; i0) { /* data line */ if(lang_code_number < MAX_LANG_ENTRIES) { if(buffer_len < MAX_LANG_BUFFER) { if(strchr(line,'|')!=NULL) { temp_ptr=strtok(line,"|"); /* get code */ if (temp_ptr!=NULL) { if(strlen(temp_ptr)<=MAX_LANG_CODE) { lcok=1; for (lt=0; lt on line %d\n",temp_ptr,line_num); } } else { ok=0; fprintf(stderr,"Language code on line %d is too long\n",line_num); } } else { ok=0; fprintf(stderr,"Missing Language code data on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Language code parse error on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Language data buffer full error on line %d\n",line_num); } } else { ok=0; fprintf(stderr,"Too many Language codes error on line %d\n",line_num); } if (ok) { if (debug_level & 32) fprintf(stderr,"Code #%d <%s> data <%s> hotkey <%c>\n",lang_code_number, lang_code[lang_code_number],lang_code_ptr[lang_code_number], lang_hotkey[lang_code_number]); lang_code_number++; } line[0]='\0'; } line_num++; } } } (void)fclose(f); } else { ok=0; fprintf(stderr,"Could not read Language file: %s!\n",filename); } if (debug_level & 32) { fprintf(stderr,"LANG %d\n",lang_code_number); } return(ok); } Xastir-Release-2.2.4/src/lang.h0000664000175000017500000000235315151324131015205 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_LANG_H #define XASTIR_LANG_H #define MAX_LANG_LINE_SIZE 800 #define MAX_LANG_CODE 10 #define MAX_LANG_ENTRIES 3000 #define MAX_LANG_BUFFER 30000 extern int load_language_file(char *filename); extern char *langcode(char *code); extern char langcode_hotkey(char *code); #endif /* XASTIR_LANG_H */ Xastir-Release-2.2.4/src/lclint.script0000775000175000017500000001274515151324131016637 0ustar hibbyhibby#!/usr/bin/perl # # This is for use with lclint 2.5 or later. # # http://lclint.cs.virginia.edu/ # #$options = "+forcehints +gnuextensions -warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include +trytorecover"; $options = "+D__LCLINT__ +forcehints -warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include -I../devel +trytorecover"; #$options = "-warnposix -I/usr/X11/LessTif/Motif2.0/include -I/usr/local/include -I/usr/X11/include +trytorecover -boolops -predboolint"; #$options = "-unqualifiedtrans -branchstate -mayaliasunique -exportlocal -linelength 1000 -predboolothers -nullassign -warnposix -I/usr/X11/LessTif/Motif1.2/include -I/usr/local/include -I/usr/X11/include +trytorecover -boolops -predboolint"; $grep = " \\ | grep -v \"Only storage\" \\ | grep -v \"New fresh\" \\ | grep -v \"Immediate address\" \\ | grep -v \"Fresh storage\" \\ | grep -v \"exported but not used\" \\ | grep -v Boolean \\ | grep -v \"in function\" \\ | grep -v \"used before definition\" \\ | grep -v \"comment inside comment\" \\ | grep -v \"Start comment inside comment\" \\ | grep -v \"declared unique\" \\ | grep -v \"used after being released\" \\ | grep -v \"referencing released storage\" \\ | grep -v \"Dereference\" \\ | grep -v \"Passed storage\" \\ | grep -v \"ossibly null\" \\ | grep -v \"Clauses\" \\ | grep -v \"may become null\" \\ | grep -v \"reachable from\" \\ | grep -v \"null storage derivable\" \\ | grep -v \"Implicitly\" \\ | grep -v \"Unqualified\" \\ | grep -v \"kept in true\" \\ | grep -v \"released in true branch\" "; #$grep = ""; `(nice splint $options ../callpass/callpass.c 2>&1) $grep >callpass.lint`; `echo "\n\nalert.c" > xastir.lint`; `(nice splint $options alert.c 2>&1) $grep >> xastir.lint`; `echo "\n\nbulletin_gui.c" >> xastir.lint`; `(nice splint $options bulletin_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\ncolor.c" >> xastir.lint`; `(nice splint $options color.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndatum.c" >> xastir.lint`; `(nice splint $options datum.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndb.c" >> xastir.lint`; `(nice splint $options db.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndb_gis.c" >> xastir.lint`; `(nice splint $options db_gis.c 2>&1) $grep >> xastir.lint`; `echo "\n\ndraw_symbols.c" >> xastir.lint`; `(nice splint $options draw_symbols.c 2>&1) $grep >> xastir.lint`; `echo "\n\nfcc_data.c" >> xastir.lint`; `(nice splint $options fcc_data.c 2>&1) $grep >> xastir.lint`; `echo "\n\nfestival.c" >> xastir.lint`; `(nice splint $options festival.c 2>&1) $grep >> xastir.lint`; `echo "\n\ngps.c" >> xastir.lint`; `(nice splint $options gps.c 2>&1) $grep >> xastir.lint`; `echo "\n\nhostname.c" >> xastir.lint`; `(nice splint $options hostname.c 2>&1) $grep >> xastir.lint`; `echo "\n\nigate.c" >> xastir.lint`; `(nice splint $options igate.c 2>&1) $grep >> xastir.lint`; `echo "\n\ninterface.c" >> xastir.lint`; `(nice splint $options interface.c 2>&1) $grep >> xastir.lint`; `echo "\n\ninterface_gui.c" >> xastir.lint`; `(nice splint $options interface_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlang.c" >> xastir.lint`; `(nice splint $options lang.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlist_gui.c" >> xastir.lint`; `(nice splint $options list_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocate_gui.c" >> xastir.lint`; `(nice splint $options locate_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocation.c" >> xastir.lint`; `(nice splint $options location.c 2>&1) $grep >> xastir.lint`; `echo "\n\nlocation_gui.c" >> xastir.lint`; `(nice splint $options location_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmain.c" >> xastir.lint`; `(nice splint $options main.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmaps.c" >> xastir.lint`; `(nice splint $options maps.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmessages.c" >> xastir.lint`; `(nice splint $options messages.c 2>&1) $grep >> xastir.lint`; `echo "\n\nmessages_gui.c" >> xastir.lint`; `(nice splint $options messages_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\npopup_gui.c" >> xastir.lint`; `(nice splint $options popup_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nrac_data.c" >> xastir.lint`; `(nice splint $options rac_data.c 2>&1) $grep >> xastir.lint`; `echo "\n\nrotated.c" >> xastir.lint`; `(nice splint $options rotated.c 2>&1) $grep >> xastir.lint`; `echo "\n\nsnprintf.c" >> xastir.lint`; `(nice splint $options snprintf.c 2>&1) $grep >> xastir.lint`; `echo "\n\nsound.c" >> xastir.lint`; `(nice splint $options sound.c 2>&1) $grep >> xastir.lint`; `echo "\n\ntrack_gui.c" >> xastir.lint`; `(nice splint $options track_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nutil.c" >> xastir.lint`; `(nice splint $options util.c 2>&1) $grep >> xastir.lint`; `echo "\n\nview_message_gui.c" >> xastir.lint`; `(nice splint $options view_message_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nwx.c" >> xastir.lint`; `(nice splint $options wx.c 2>&1) $grep >> xastir.lint`; `echo "\n\nwx_gui.c" >> xastir.lint`; `(nice splint $options wx_gui.c 2>&1) $grep >> xastir.lint`; `echo "\n\nxa_config.c" >> xastir.lint`; `(nice splint $options xa_config.c 2>&1) $grep >> xastir.lint`; #'(nice splint $options alert.c bulletin_gui.c color.c datum.c db.c db_gis.c draw_symbols.c fcc_data.c festival.c gps.c hostname.c igate.c interface.c interface_gui.c lang.c list_gui.c locate_gui.c location.c location_gui.c main.c maps.c messages.c messages_gui.c popup_gui.c rac_data.c rotated.c snprintf.c sound.c track_gui.c util.c view_message_gui.c wx.c wx_gui.c xa_config.c 2>&1) $grep > xastir.lint`; Xastir-Release-2.2.4/src/leak_detection.h0000664000175000017500000000616215151324131017240 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* All of the misc entry points to be included for all packages */ #ifndef _LEAK_DETECTION_H #define _LEAK_DETECTION_H // If libgc is installed, uncomment this next line to enable memory // leak detection: #define DETECT_MEMORY_LEAKS // Defines for including the libgc garbage collection library. // This enables automatic garbage collection of unused memory, // very similar to the garbage collection in Java. Get libgc from // here: http://www.hpl.hp.com/personal/Hans_Boehm/gc/ // // This will cause stats to be printed every 60 seconds, 'cuz we // call GC_collect via a macro from UpdateTime() once per minute: // export GC_PRINT_STATS=1; xastir & // // Compile libgc with this option for more debugging output. I // didn't do so: --enable-full_debug // // If we enable these thread options, Xastir won't link with the // library. Since we don't allocate dynamic memory in the child // threads anyway, skip them. // --enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark // // Call GC_gcollect at appropriate points to check for leaks. We do // this via the CHECK_LEAKS macro called from main.c:UpdateTime. // // // Note: The thread includes must be done before the libgc includes // as libgc redefines some thread stuff so that it cooperates with // the garbage collector routines. Any code module that does // malloc's/free's or thread operations should include // leak_detection.h as the last include if at all possible, and // should not include pthread.h themselves. // #include #include /* Where malloc/free definitions reside */ #ifdef HAVE_DMALLOC #include #endif // HAVE_DMALLOC // #ifdef HAVE_GC_H #ifdef HAVE_LIBGC // We use this define to enable code in *.c files #define USING_LIBGC // Set up for threads #define GC_THREADS #ifdef __LINUX__ #define GC_LINUX_THREADS #endif // __LINUX__ // #define _REENTRANT // Ask for more debugging #define GC_DEBUG #include #define malloc(n) GC_MALLOC(n) #define calloc(m,n) GC_MALLOC((m)*(n)) #define free(p) GC_FREE(p) #define realloc(p,n) GC_REALLOC((p),(n)) #define CHECK_LEAKS() GC_gcollect() #endif // HAVE_LIBGC #endif // HAVE_GC_H #endif /* LEAK_DETECTION_H */ Xastir-Release-2.2.4/src/list_gui.c0000664000175000017500000035652615151324131016114 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include "xastir.h" #include "main.h" #include "mutex_utils.h" #include "messages.h" #include "draw_symbols.h" #include "list_gui.h" #include "database.h" #include "db_funcs.h" #include "db_gui.h" #include "mgrs_utils.h" #include #include // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define SL_MAX 20 #define ROWS 17 // List Numbers (defined in list_gui.h) // 0: LST_ALL - all stations list // 1: LST_MOB - mobile stations list // 2: LST_WX - WX stations list // 3: LST_TNC - local stations list // 4: LST_TIM - last stations // 5: LST_OBJ - Objects/Items // 6: LST_MYOBJ - My Objects/Items // 7: LST_NUM - Number of lists; for use in array definitions below Widget station_list_dialog[LST_NUM]; // store list definitions static xastir_mutex station_list_dialog_lock; // Mutex lock for above Widget SL_list[LST_NUM][SL_MAX]; Widget SL_da[LST_NUM][SL_MAX]; Widget SL_call[LST_NUM][SL_MAX]; char * SL_callback[LST_NUM][SL_MAX]; Pixmap SL_icon[LST_NUM][SL_MAX]; // icons for different lists and list rows Pixmap blank_icon; // holds an empty icon Widget SL_scroll[LST_NUM]; Widget SL_wx_wind_course[LST_NUM][SL_MAX]; Widget SL_wx_wind_speed[LST_NUM][SL_MAX]; Widget SL_wx_wind_gust[LST_NUM][SL_MAX]; Widget SL_wx_temp[LST_NUM][SL_MAX]; Widget SL_wx_hum[LST_NUM][SL_MAX]; Widget SL_wx_baro[LST_NUM][SL_MAX]; Widget SL_wx_rain_h[LST_NUM][SL_MAX]; Widget SL_wx_rain_00[LST_NUM][SL_MAX]; Widget SL_wx_rain_24[LST_NUM][SL_MAX]; Widget SL_course[LST_NUM][SL_MAX]; Widget SL_speed[LST_NUM][SL_MAX]; Widget SL_alt[LST_NUM][SL_MAX]; Widget SL_lat_long[LST_NUM][SL_MAX]; Widget SL_packets[LST_NUM][SL_MAX]; Widget SL_sats[LST_NUM][SL_MAX]; Widget SL_my_course[LST_NUM][SL_MAX]; Widget SL_my_distance[LST_NUM][SL_MAX]; Widget SL_pos_time[LST_NUM][SL_MAX]; Widget SL_node_path[LST_NUM][SL_MAX]; Widget SL_power_gain[LST_NUM][SL_MAX]; Widget SL_comments[LST_NUM][SL_MAX]; int station_list_first = 1; int list_size_h[LST_NUM]; // height of entire list widget int list_size_w[LST_NUM]; // width of entire list widget int list_size_i[LST_NUM]; // size initialized, dirty hack, but works... int last_offset[LST_NUM]; char top_call[LST_NUM][MAX_CALLSIGN+1]; // call of first list entry or empty string for always first call time_t top_time; // time of first list entry or 0 for always newest station int top_sn; // serial number for unique time index time_t last_list_upd; // time of last list update int units_last; #define LIST_UPDATE_CYCLE 2 /* Minimum time between list updates in seconds, we want */ /* immediate update, but not in high traffic situations */ void list_gui_init(void) { init_critical_section( &station_list_dialog_lock ); } // get a valid list member, starting from current station in the desired direction // returns pointer to found member or NULL void get_list_member(int type, DataRow **p_station, int skip, int forward) { char found; if ((*p_station) == NULL) // default start value { if (type == LST_TIM) { (*p_station) = t_newest; } else { (*p_station) = n_first; } } if (skip == 1) // skip before searching { if (type != LST_TIM) { if (forward == 1) { (void)next_station_name(p_station); } else { (void)prev_station_name(p_station); } } else { if (forward == 1) { (void)prev_station_time(p_station); } else { (void)next_station_time(p_station); } } } found = (char)FALSE; switch (type) // DK7IN: here I'm trading code size for speed... { case LST_ALL: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) // ignore deleted objects { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_MOB: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->newest_trackpoint != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->newest_trackpoint != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_WX: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->weather_data != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && (*p_station)->weather_data != NULL) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_TNC: if (forward == 1) while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ((*p_station)->flag & ST_VIATNC) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ((*p_station)->flag & ST_VIATNC) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_TIM: if (forward == 1) // forward in list, backward in time while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) // ignore deleted objects { found = (char)TRUE; } else { (*p_station) = (*p_station)->t_older; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0) { found = (char)TRUE; } else { (*p_station) = (*p_station)->t_newer; } } break; case LST_OBJ: if (forward == 1) while (!found && (*p_station) != NULL) { // Show deleted objects/items as well if ( ( (((*p_station)->flag & ST_OBJECT) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) ) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ( (((*p_station)->flag & ST_VIATNC) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) ) { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; case LST_MYOBJ: // We should really show the active AND inactive objects. This is // so that inactive ones can be resurrected. Probably should do // this for all objects, not just ones we own. if (forward == 1) while (!found && (*p_station) != NULL) { // Show deleted objects/items as well if ( ( (((*p_station)->flag & ST_OBJECT) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) // && ( is_my_call( (*p_station)->origin,1)) ) // Exact match include SSID && ( is_my_object_item(*p_station)) ) // Exact match include SSID { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_next; } } else while (!found && (*p_station) != NULL) { if (((*p_station)->flag & ST_ACTIVE) != 0 && ( (((*p_station)->flag & ST_VIATNC) != 0) || (((*p_station)->flag & ST_ITEM) != 0) ) // && ( is_my_call( (*p_station)->origin,1)) ) // Exact match includes SSID && ( is_my_object_item(*p_station)) ) // Exact match include SSID { found = (char)TRUE; } else { (*p_station) = (*p_station)->n_prev; } } break; default: break; } } // initialization of station list at very first Station List call void init_station_lists(void) { int type,i; blank_icon = XCreatePixmap(XtDisplay(appshell),RootWindowOfScreen(XtScreen(appshell)),20,20, DefaultDepthOfScreen(XtScreen(appshell))); begin_critical_section(&station_list_dialog_lock, "list_gui.c:init_station_lists" ); for (type=0; typen_next) { if ((p_station->flag & ST_ACTIVE) != 0) // ignore deleted objects { switch (type) { case 0: // all stations list case 4: // last stations st++; break; case 1: // mobile stations list if (p_station->newest_trackpoint != NULL) { st++; } break; case 2: // WX stations list if (p_station->weather_data != NULL) { st++; } break; case 3: // local stations list if ((p_station->flag & ST_VIATNC) != 0) { st++; } break; case 5: // Object/Item list if ( ((p_station->flag & ST_OBJECT) != 0) || ((p_station->flag & ST_ITEM) != 0) ) { st++; } break; default: break; } } } if (st==0) { st=1; } return(st); } void station_list_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { int type; int i; type = atoi((char *)clientData); XtPopdown(station_list_dialog[type]); begin_critical_section(&station_list_dialog_lock, "list_gui.c:station_list_destroy_shell" ); for (i = 0; i < ROWS; i++) { if (SL_callback[type][i]) { XtFree(SL_callback[type][i]); SL_callback[type][i] = NULL; } } XtDestroyWidget(station_list_dialog[type]); station_list_dialog[type] = (Widget)NULL; // clear list definition end_critical_section(&station_list_dialog_lock, "list_gui.c:station_list_destroy_shell" ); } /* * Callback for station icon in list. * Calls a function to center the map on the selected station from the list. */ void Call_locate_station(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { if (clientData != NULL && strlen(clientData) > 0) { locate_station(w, clientData, 1,1,1); } } /* * *** This callback is not linked to a control on list yet. *** * Invokes the station information dialog for the selected station from the list. */ void Call_Station_data(Widget w, XtPointer clientData, XtPointer UNUSED(callData) ) { if (clientData != NULL && strlen(clientData) > 0) { Station_data(w, clientData, NULL); } } /* * Fill list with new data */ void Station_List_fill(int type, int new_offset) { int row; char temp[11]; char *temp_ptr; Dimension w,h; // size of scrollbar in pixel Dimension ww,wh; // size of entire widget in pixel Dimension new_h; // overall height in pixel char stemp[400]; char stemp1[60]; char stemp2[60]; char temp_call[MAX_CALLSIGN+1]; long l_lat, l_lon; float value; WeatherRow *weather; DataRow *p_station; DataRow *p_name; int cur_offset; Dimension count, inview; int to_move, rows; int strwid; assert(ROWS <= SL_MAX); #define HGT 26 #define FUDGE 78 // type 0 all, 1: mobile, 2: WX, 3: local, 4: time, 5: Objects/Items // offset is the entry that should be displayed in the first line w = h = ww = wh = 0; if (station_list_dialog[type] != NULL) // if list is defined { // the list is first drawn very big then gets initialized to the correct size // I don't want the first wrong draw but don't know how to avoid it. DK7IN // there are wrong icons drawn on the first time... ???? if (list_size_i[type]) // we are initialized... { // ww, wh get width and height of entire widget: XtVaGetValues(station_list_dialog[type], XmNwidth, &ww, XmNheight, &wh, NULL); // w, h get width and height of scrollbar: XtVaGetValues(SL_scroll[type], XmNwidth, &w, XmNheight, &h, NULL); rows = (h+10) / HGT; // number of rows we can display, HGT pixel per row // fprintf(stderr,"fill: %d %d %d\n",wh, h, rows); } else { if (list_size_w[type] > 0 && list_size_h[type] > 0) { wh = list_size_h[type]; // restore size ww = list_size_w[type]; rows = (wh -FUDGE+10) / HGT; // Fudge Factor ??? // fprintf(stderr,"load: %d %d\n",wh, rows); } else { wh = 500; // start with this... ??? ww = 700; rows = (wh -FUDGE+10) / HGT; // Fudge Factor ??? // fprintf(stderr,"set: %d %d\n",wh, rows); } XtVaSetValues(station_list_dialog[type], XmNwidth, ww, NULL); // set widget width } if (rows > ROWS) // limit vertical size to data structure size for widgets { rows = ROWS; } if (rows < 1) { rows = 1; } // new_h = (rows*HGT) + (wh-h); // (rows + border) in pixel new_h = (rows*HGT) + FUDGE; // (rows + border) in pixel XtVaSetValues(station_list_dialog[type], XmNheight, new_h, NULL); // correct widget height list_size_h[type] = new_h; // remember current size list_size_w[type] = ww; list_size_i[type] = (int)TRUE; // don't init next time // look for the station to display on the first row... p_station = NULL; if (type == LST_TIM) { (void)search_station_time(&p_station,top_time,top_sn); // gives match or next station } else { (void)search_station_name(&p_station,top_call[type],1); // gives match or next station } get_list_member(type, &p_station, 0, 1); // get member in list for first row // get updated statistics, database may have changed since last call count = 0; cur_offset = 0; p_name = NULL; get_list_member(type, &p_name, 0, 1); // get first member in list while (p_name != NULL) { if (p_name == p_station) { cur_offset = count; // got offset of first row entry } count++; // count valid list member get_list_member(type, &p_name, 1, 1); // get next member in list } // check boundaries new_offset += cur_offset - last_offset[type]; // adjust for database changes if (count == 0) { count = 1; // empty } if (count - new_offset < rows) // bottom { new_offset = count - rows; // keep page filled, if possible } if (new_offset < 0) // top { new_offset = 0; } inview = rows; // number of stations in view if (inview > count) // partially filled { inview = count; } // update scrollbar parameters XtVaSetValues(SL_scroll[type], XmNmaximum, count, XmNpageIncrement, inview, XmNvalue, new_offset, XmNsliderSize, inview, NULL); if (new_offset == 0) // stay at first member { p_station = NULL; get_list_member(type, &p_station, 0, 1); // get first member in list } else { // if database changed, adjust first entry accordingly to_move = new_offset - cur_offset; while (to_move > 0) // move down, if necessary { if (p_station != 0) { get_list_member(type, &p_station, 1, 1); // gets next member in list } to_move--; } while (to_move < 0) // move up, if necessary { if (p_station != 0) { get_list_member(type, &p_station, 1, 0); // gets previous member in list } to_move++; } } // store current start position, we need a unique index for this to work (time?) if (new_offset == 0 || p_station == NULL) // keep it at top { if (type != LST_TIM) { top_call[type][0] = '\0'; } else { top_time = 0; top_sn = -1; } } else { if (type != LST_TIM) { xastir_snprintf(top_call[type], MAX_CALLSIGN+1, "%s", p_station->call_sign); // remember call at list top } else { top_time = p_station->sec_heard; // remember time station was heard top_sn = p_station->time_sn; // remember time serial number } } last_offset[type] = new_offset; // now fill the list rows xastir_snprintf(temp, sizeof(temp), "%d", (rows+new_offset)); // calculate needed string width strwid = (int)strlen(temp); // to keep it right justified begin_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List_fill" ); // Start filling in the rows of the widget for (row=0; rowflag & ST_ACTIVE) { ghost = 0; // Active object/item } else { ghost = 1; // Deleted object/item } } else { ghost = 0; // Not an object } // call (or object/item name) // Do this first as it is used for callback data later /* check to see if string changed and over write */ temp_ptr = XmTextFieldGetString(SL_call[type][row]); xastir_snprintf(temp_call, sizeof(temp_call), "%s", temp_ptr); XtFree(temp_ptr); if (strcmp(temp_call, p_station->call_sign) != 0) { XmTextFieldSetString(SL_call[type][row], p_station->call_sign); if (ghost) { XtSetSensitive(SL_call[type][row], FALSE); } else { XtSetSensitive(SL_call[type][row], TRUE); } XtManageChild(SL_call[type][row]); } // Blank out the icon first XtVaSetValues(SL_da[type][row],XmNlabelPixmap, blank_icon,NULL); XtManageChild(SL_da[type][row]); symbol(SL_da[type][row],0,'~','$','\0',SL_icon[type][row],0,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); // Now redraw it symbol(SL_da[type][row],ghost,p_station->aprs_symbol.aprs_type, p_station->aprs_symbol.aprs_symbol, p_station->aprs_symbol.special_overlay,SL_icon[type][row],ghost,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); if (SL_callback[type][row]) { XtRemoveCallback((XtPointer)SL_da[type][row], XmNactivateCallback, Call_locate_station, SL_callback[type][row]); XtFree(SL_callback[type][row]); } SL_callback[type][row] = XmTextFieldGetString(SL_call[type][row]); // Pressing the icon button centers the map on the station. XtAddCallback( (XtPointer)SL_da[type][row], XmNactivateCallback, Call_locate_station, SL_callback[type][row] ); // number in list xastir_snprintf(temp, sizeof(temp), "%*d", strwid, (row+1+new_offset)); XmTextFieldSetString(SL_list[type][row],temp); XtManageChild(SL_list[type][row]); switch (type) { case LST_TNC: // local stations list case LST_TIM: // last stations list case LST_ALL: // stations list case LST_OBJ: // objects/items case LST_MYOBJ: // my objects/items xastir_snprintf(stemp, sizeof(stemp), "%5d", (int)p_station->num_packets); XmTextFieldSetString(SL_packets[type][row],stemp); XtManageChild(SL_packets[type][row]); if (strlen(p_station->pos_time) > 13) { xastir_snprintf(stemp, sizeof(stemp), "%c%c/%c%c %c%c:%c%c", //sprintf(stemp,"%c%c/%c%c/%c%c%c%c %c%c:%c%c", p_station->pos_time[0], p_station->pos_time[1], p_station->pos_time[2], p_station->pos_time[3], //p_station->pos_time[4], //p_station->pos_time[5], //p_station->pos_time[6], //p_station->pos_time[7], p_station->pos_time[8], p_station->pos_time[9], p_station->pos_time[10], p_station->pos_time[11]); } else { xastir_snprintf(stemp, sizeof(stemp), " "); } XmTextFieldSetString(SL_pos_time[type][row],stemp); XtManageChild(SL_pos_time[type][row]); xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->node_path_ptr); XmTextFieldSetString(SL_node_path[type][row],stemp); XtManageChild(SL_node_path[type][row]); xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->power_gain); XmTextFieldSetString(SL_power_gain[type][row],stemp); XtManageChild(SL_power_gain[type][row]); // Should we display only the first comment field we have stored, or // concatenate all of them up to the limit of stemp? //xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->comments); if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->comment_data->text_ptr); } else { stemp[0] = '\0'; // Empty string } XmTextFieldSetString(SL_comments[type][row],stemp); XtManageChild(SL_comments[type][row]); break; case LST_MOB: // mobile stations list if (strlen(p_station->course)>0) { XmTextFieldSetString(SL_course[type][row],p_station->course); } else { XmTextFieldSetString(SL_course[type][row],""); } XtManageChild(SL_course[type][row]); if (strlen(p_station->speed)>0) { if (!english_units) xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->speed)*1.852); else xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->speed)*1.1508); XmTextFieldSetString(SL_speed[type][row],stemp); } else { XmTextFieldSetString(SL_speed[type][row],""); } XtManageChild(SL_speed[type][row]); if (strlen(p_station->altitude)>0) { if (!english_units) { xastir_snprintf(stemp, sizeof(stemp), "%s", p_station->altitude); } else { xastir_snprintf(stemp, sizeof(stemp), "%.1f", atof(p_station->altitude)*3.28084); } XmTextFieldSetString(SL_alt[type][row],stemp); } else { XmTextFieldSetString(SL_alt[type][row],""); } XtManageChild(SL_alt[type][row]); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { // Create a UTM string from coordinates // in Xastir coordinate system. convert_xastir_to_UTM_str(stemp, sizeof(stemp), p_station->coord_lon, p_station->coord_lat); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } else if (coordinate_system == USE_MGRS) { // Create an MGRS string from // coordinates in Xastir coordinate // system. convert_xastir_to_MGRS_str(stemp, sizeof(stemp), p_station->coord_lon, p_station->coord_lat, 0); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } else { // Create lat/lon strings from coordinates // in Xastir coordinate system. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_DEC_DEG); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_DMS_NORMAL); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(p_station->coord_lat, stemp1, sizeof(stemp1), CONVERT_HP_NORMAL); convert_lon_l2s(p_station->coord_lon, stemp2, sizeof(stemp2), CONVERT_HP_NORMAL); } xastir_snprintf(stemp, sizeof(stemp), "%s %s", stemp1, stemp2); XmTextFieldSetString(SL_lat_long[type][row],stemp); XtManageChild(SL_lat_long[type][row]); } xastir_snprintf(stemp, sizeof(stemp), "%d", (int)p_station->num_packets); XmTextFieldSetString(SL_packets[type][row],stemp); XtManageChild(SL_packets[type][row]); if (strlen(p_station->sats_visible)>0) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(p_station->sats_visible)); XmTextFieldSetString(SL_sats[type][row],stemp); } else { XmTextFieldSetString(SL_sats[type][row],""); } XtManageChild(SL_sats[type][row]); l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); // Get distance in nautical miles value = (float)calc_distance_course(l_lat,l_lon, p_station->coord_lat,p_station->coord_lon,stemp,sizeof(stemp)); if (english_units) { xastir_snprintf(stemp1, sizeof(stemp1), "%0.1f", (value * 1.15078)); } else { xastir_snprintf(stemp1, sizeof(stemp1), "%0.1f", (value * 1.852)); } XmTextFieldSetString(SL_my_course[type][row],stemp); XtManageChild(SL_my_course[type][row]); XmTextFieldSetString(SL_my_distance[type][row],stemp1); XtManageChild(SL_my_distance[type][row]); break; case LST_WX: // weather stations list weather = p_station->weather_data; if ((int)(((sec_old + weather->wx_sec_time)) < sec_now())) { break; // Weather data is too old } if (strlen(weather->wx_course) > 0) { XmTextFieldSetString(SL_wx_wind_course[type][row],weather->wx_course); } else { XmTextFieldSetString(SL_wx_wind_course[type][row],""); } XtManageChild(SL_wx_wind_course[type][row]); if (strlen(weather->wx_speed) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)atoi(weather->wx_speed)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(atof(weather->wx_speed)*1.6094)); } XmTextFieldSetString(SL_wx_wind_speed[type][row],stemp); } else { XmTextFieldSetString(SL_wx_wind_speed[type][row],""); } XtManageChild(SL_wx_wind_speed[type][row]); if (strlen(weather->wx_gust) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(weather->wx_gust)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(atof(weather->wx_gust)*1.6094)); } XmTextFieldSetString(SL_wx_wind_gust[type][row],stemp); } else { XmTextFieldSetString(SL_wx_wind_gust[type][row],""); } XtManageChild(SL_wx_wind_gust[type][row]); if (strlen(weather->wx_temp) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%d", atoi(weather->wx_temp)); } else { xastir_snprintf(stemp, sizeof(stemp), "%d", (int)(((atof(weather->wx_temp)-32)*5.0)/9.0)); } XmTextFieldSetString(SL_wx_temp[type][row],stemp); } else { XmTextFieldSetString(SL_wx_temp[type][row],""); } XtManageChild(SL_wx_temp[type][row]); if (strlen(weather->wx_hum) > 0) { XmTextFieldSetString(SL_wx_hum[type][row],weather->wx_hum); } else { XmTextFieldSetString(SL_wx_hum[type][row],""); } XtManageChild(SL_wx_hum[type][row]); //WE7U // Change this to inches mercury when English Units is selected if (strlen(weather->wx_baro) > 0) { if (!english_units) // hPa { XmTextFieldSetString(SL_wx_baro[type][row], weather->wx_baro); } else // Inches Mercury { float tempf; char temp2[15]; tempf = atof(weather->wx_baro)*0.02953; xastir_snprintf(temp2, sizeof(temp2), "%0.2f", tempf); XmTextFieldSetString(SL_wx_baro[type][row], temp2); } } else { XmTextFieldSetString(SL_wx_baro[type][row],""); } XtManageChild(SL_wx_baro[type][row]); if (strlen(weather->wx_rain) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_rain)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_rain)*.254); } XmTextFieldSetString(SL_wx_rain_h[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_h[type][row],""); } XtManageChild(SL_wx_rain_h[type][row]); if (strlen(weather->wx_prec_00) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_00)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_00)*.254); } XmTextFieldSetString(SL_wx_rain_00[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_00[type][row],""); } XtManageChild(SL_wx_rain_00[type][row]); if (strlen(weather->wx_prec_24) > 0) { if (english_units) { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_24)/100.0); } else { xastir_snprintf(stemp, sizeof(stemp), "%0.2f", atof(weather->wx_prec_24)*.254); } XmTextFieldSetString(SL_wx_rain_24[type][row],stemp); } else { XmTextFieldSetString(SL_wx_rain_24[type][row],""); } XtManageChild(SL_wx_rain_24[type][row]); break; default: break; } } else // no data, empty row { XtVaSetValues(SL_da[type][row],XmNlabelPixmap, blank_icon,NULL); XtManageChild(SL_da[type][row]); symbol(SL_da[type][row],0,'~','$','\0',SL_icon[type][row],0,0,0,' '); XtVaSetValues(SL_da[type][row],XmNlabelPixmap, SL_icon[type][row],NULL); XtManageChild(SL_da[type][row]); xastir_snprintf(temp, sizeof(temp), "%*d", strwid, (row+1+new_offset)); XmTextFieldSetString(SL_list[type][row],temp); XtManageChild(SL_list[type][row]); XmTextFieldSetString(SL_call[type][row],""); XtManageChild(SL_call[type][row]); switch (type) { case LST_TNC: // local stations list case LST_TIM: case LST_ALL: // stations list case LST_OBJ: // Objects/Items list case LST_MYOBJ: // My objects/Items XmTextFieldSetString(SL_packets[type][row],""); XtManageChild(SL_packets[type][row]); XmTextFieldSetString(SL_pos_time[type][row],""); XtManageChild(SL_pos_time[type][row]); XmTextFieldSetString(SL_node_path[type][row],""); XtManageChild(SL_node_path[type][row]); XmTextFieldSetString(SL_power_gain[type][row],""); XtManageChild(SL_power_gain[type][row]); XmTextFieldSetString(SL_comments[type][row],""); XtManageChild(SL_comments[type][row]); break; case LST_MOB: // mobile stations list XmTextFieldSetString(SL_course[type][row],""); XtManageChild(SL_course[type][row]); XmTextFieldSetString(SL_speed[type][row],""); XtManageChild(SL_speed[type][row]); XmTextFieldSetString(SL_alt[type][row],""); XtManageChild(SL_alt[type][row]); XmTextFieldSetString(SL_lat_long[type][row],""); XtManageChild(SL_lat_long[type][row]); XmTextFieldSetString(SL_packets[type][row],""); XtManageChild(SL_packets[type][row]); XmTextFieldSetString(SL_sats[type][row],""); XtManageChild(SL_sats[type][row]); XmTextFieldSetString(SL_my_course[type][row],""); XtManageChild(SL_my_course[type][row]); XmTextFieldSetString(SL_my_distance[type][row],""); XtManageChild(SL_my_distance[type][row]); break; case LST_WX: /*WX stations list */ XmTextFieldSetString(SL_wx_wind_course[type][row],""); XtManageChild(SL_wx_wind_course[type][row]); XmTextFieldSetString(SL_wx_wind_speed[type][row],""); XtManageChild(SL_wx_wind_speed[type][row]); XmTextFieldSetString(SL_wx_wind_gust[type][row],""); XtManageChild(SL_wx_wind_gust[type][row]); XmTextFieldSetString(SL_wx_temp[type][row],""); XtManageChild(SL_wx_temp[type][row]); XmTextFieldSetString(SL_wx_hum[type][row],""); XtManageChild(SL_wx_hum[type][row]); XmTextFieldSetString(SL_wx_baro[type][row],""); XtManageChild(SL_wx_baro[type][row]); XmTextFieldSetString(SL_wx_rain_h[type][row],""); XtManageChild(SL_wx_rain_h[type][row]); XmTextFieldSetString(SL_wx_rain_00[type][row],""); XtManageChild(SL_wx_rain_00[type][row]); XmTextFieldSetString(SL_wx_rain_24[type][row],""); XtManageChild(SL_wx_rain_24[type][row]); break; default: break; } } // empty line if (p_station != NULL) { get_list_member(type, &p_station, 1, 1); // get next member in list } } // loop over display lines end_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List_fill" ); } // if list is defined } /* * Check if we have to update an active list, do it if necessary */ void update_station_scroll_list(void) // called from UpdateTime() [main.c] in timing loop { int i; int pos; Dimension last_h, last_w; int last; int ok; last_h = last_w = 0; ok = 0; for (i=0; i LIST_UPDATE_CYCLE)) || (last_h!=list_size_h[i]) || (last_w!=list_size_w[i]) || units_last!=english_units) { Station_List_fill(i,pos); // update list contents ok = 1; } } } if (ok == 1) { last_list_upd = sec_now(); redo_list = FALSE; } units_last = english_units; } void dragCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); // DK7IN: // todo: We should only do the update if no other list navigation command is // waiting, otherwise we only should update the offset value. // Same with all other callbacks below... Station_List_fill(i,cbs->value); } void decrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void incrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void pageDecrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void pageIncrementCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } void mouseScrollHandler(Widget UNUSED(w), XtPointer clientData, XButtonEvent* event, Boolean * UNUSED(continueToDispatch)) { int i = atoi((char*)clientData); int lines = 2; // no modifier moves 2 lines // shift moves 1 line // control moves 10 lines if (event->type == ButtonRelease) { if (event->state & ControlMask) { lines = 10; } else if (event->state & ShiftMask) { lines = 1; } if (event->button == Button4) // Scroll up { if (last_offset[i] > 0) { if ((last_offset[i] - lines) < 0) { Station_List_fill(i, 0); } else { Station_List_fill(i, last_offset[i] - lines); } } } else if (event->button == Button5) // Scroll down { Station_List_fill(i, last_offset[i] + lines); } } } void valueChangedCallback(Widget UNUSED(w), XtPointer clientData, XtPointer callData) { int i; XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)callData; i = atoi((char *)clientData); Station_List_fill(i,cbs->value); } /* * Setup the various list layouts */ void Station_List(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int i; Widget pane, form, win_list, form2, button_close; Widget numl,call,sep,sep2; Widget it1, it2, it3, it4, it5, it6, it7, it8, it9; Widget seps[40]; Atom delw; int type; char temp[400]; if (station_list_first) { memset(&SL_scroll, 0, sizeof(SL_scroll)); init_station_lists(); // init icons at very first list call station_list_first=0; } type=atoi((char *)clientData); switch(type) { case LST_ALL: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI000")); // All Stations break; case LST_MOB: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI001")); // Mobile Stations break; case LST_WX: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI002")); // Weather Stations break; case LST_TNC: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI003")); // Local Stations break; case LST_TIM: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI004")); // Last Stations break; case LST_OBJ: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI005")); // Objects/Items break; case LST_MYOBJ: xastir_snprintf(temp, sizeof(temp), "%s", langcode("LHPUPNI006")); // My Objects/Items break; default: return; } if (!station_list_dialog[type]) // setup list area if not previously done { // DK7IN: we should destroy those Widgets to get the // memory back, and rebuild it on the next call. ???? // I don't exactly know what's going on, but we lose memory // every time we call it. begin_critical_section(&station_list_dialog_lock, "list_gui.c:Station_List" ); station_list_dialog[type]= XtVaCreatePopupShell(temp, xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 274, XmNmaxHeight, ROWS*HGT+FUDGE, XmNminHeight, 95, // XmNheight, 230, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Station_List pane",xmPanedWindowWidgetClass, station_list_dialog[type], XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Station_List form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNshadowType, XmSHADOW_OUT, XmNshadowThickness, 1, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // station number in list numl = XtVaCreateManagedWidget(langcode("LHPUPNI010"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(numl,langcode("LHPUPNI010")); // # // icon // call call = XtVaCreateManagedWidget(langcode("LHPUPNI011"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 9, // 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, numl, XmNleftOffset, 23, // 22, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(call,langcode("LHPUPNI011")); // Call Sign switch (type) { case LST_ALL: // All Stations case LST_TNC: // Local Stations [via TNC] case LST_TIM: // Last Stations case LST_OBJ: // Objects/Item case LST_MYOBJ: // My objects/items // number of packets heard it1 = XtVaCreateManagedWidget(langcode("LHPUPNI012"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI012")); // #Pack // Last time of position it2 = XtVaCreateManagedWidget(langcode("LHPUPNI013"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 11, //16, //17, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI013")); // Last Position Time // Path it3 = XtVaCreateManagedWidget(langcode("LHPUPNI014"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 30, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI014")); // Path // PHG it4 = XtVaCreateManagedWidget(langcode("LHPUPNI015"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 7, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI015")); // PHG // Comments it5 = XtVaCreateManagedWidget(langcode("LHPUPNI016"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 40, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 0, // 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it5,langcode("LHPUPNI016")); // Comments break; case LST_MOB: /*mobile list */ it1 = XtVaCreateManagedWidget(langcode("LHPUPNI100"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI100")); // CSE it2 = XtVaCreateManagedWidget(langcode("LHPUPNI101"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI101")); // SPD it3 = XtVaCreateManagedWidget(langcode("LHPUPNI102"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 8, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI102")); // ALT. it4 = XtVaCreateManagedWidget(langcode("LHPUPNI103"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 25, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI209")); // Lat/Lon or UTM it6 = XtVaCreateManagedWidget(langcode("LHPUPNI105"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it6,langcode("LHPUPNI105")); // #Pack it7 = XtVaCreateManagedWidget(langcode("LHPUPNI106"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it6, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it7,langcode("LHPUPNI106")); // LSV it8 = XtVaCreateManagedWidget(langcode("LHPUPNI107"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it7, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it8,langcode("LHPUPNI107")); // CFMS it9 = XtVaCreateManagedWidget(langcode("LHPUPNI108"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it8, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it9,langcode("LHPUPNI108")); // DFMS break; case LST_WX: /*wx list */ it1 = XtVaCreateManagedWidget(langcode("LHPUPNI200"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it1,langcode("LHPUPNI200")); // CSE it2 = XtVaCreateManagedWidget(langcode("LHPUPNI201"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it1, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it2,langcode("LHPUPNI201")); // SPD it3 = XtVaCreateManagedWidget(langcode("LHPUPNI202"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it2, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it3,langcode("LHPUPNI202")); // GST it4 = XtVaCreateManagedWidget(langcode("LHPUPNI203"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it3, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it4,langcode("LHPUPNI203")); // Temp it5 = XtVaCreateManagedWidget(langcode("LHPUPNI204"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 3, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it4, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it5,langcode("LHPUPNI204")); // Hum it6 = XtVaCreateManagedWidget(langcode("LHPUPNI205"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it5, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it6,langcode("LHPUPNI205")); // Baro it7 = XtVaCreateManagedWidget(langcode("LHPUPNI206"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it6, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it7,langcode("LHPUPNI206")); // RN-H it8 = XtVaCreateManagedWidget(langcode("LHPUPNI207"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNtraversalOn, FALSE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it7, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it8,langcode("LHPUPNI207")); // RNSM it9 = XtVaCreateManagedWidget(langcode("LHPUPNI208"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNtraversalOn, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset,2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, it8, XmNleftOffset, 1, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XmTextFieldSetString(it9,langcode("LHPUPNI208")); // RN24 break; default: break; } // if (!station_list_dialog[type])... from some kilometers above... ;-) sep = XtVaCreateManagedWidget("Station_List sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, numl, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, NULL); SL_scroll[type] = XtVaCreateManagedWidget("Station_List SL_scroll", xmScrollBarWidgetClass,form, XmNorientation, XmVERTICAL, XmNtraversalOn, TRUE, XmNmaximum, 10, // XmNmaximum, stations_types(type), // XmNsliderSize, rows, // // XmNpageIncrement, rows, // was 18 XmNheight, 145, // test XmNsliderSize, 10, // XmNpageIncrement, 10, // was 18 XmNprocessingDirection, XmMAX_ON_BOTTOM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 42, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddEventHandler(SL_scroll[type], ButtonReleaseMask, FALSE, (XtEventHandler)mouseScrollHandler, (char*)clientData); win_list = XtVaCreateWidget("Station_List win_list",xmFormWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 42, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 2, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, SL_scroll[type], XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddEventHandler(win_list, ButtonReleaseMask, FALSE, (XtEventHandler)mouseScrollHandler, (char*)clientData); for (i=0; i key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(station_list_dialog[type]); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); // Note: If adding new lists, make sure to tweak xa_config.c to // increment the number. If not, you'll get an X-Windows error at // this point when trying to resize the window: /* set last size if there was one */ // done in list_fill if (list_size_w[type] > 0 && list_size_h[type] > 0) XtVaSetValues(station_list_dialog[type], XmNwidth, list_size_w[type], XmNheight, list_size_h[type], NULL); if (type != LST_TIM) { top_call[type][0] = '\0'; // start at top } else { top_time = 0; top_sn = -1; } last_offset[type] = 0; last_list_upd = sec_now(); list_size_i[type] = FALSE; redo_list = (int)TRUE; Station_List_fill(type,0); // start with top of list } else // if (!station_list_dialog[type]) // we already have an initialized widget { (void)XRaiseWindow(XtDisplay(station_list_dialog[type]), XtWindow(station_list_dialog[type])); } } Xastir-Release-2.2.4/src/list_gui.h0000664000175000017500000000265715151324131016112 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_LIST_GUI_H #define __XASTIR_LIST_GUI_H // different list types: #define LST_ALL 0 #define LST_MOB 1 #define LST_WX 2 #define LST_TNC 3 #define LST_TIM 4 #define LST_OBJ 5 #define LST_MYOBJ 6 #define LST_NUM 7 extern int list_size_h[]; extern int list_size_w[]; /* from list_gui.c */ extern void list_gui_init(void); extern void update_station_scroll_list(void); extern int stations_types(int type); extern void Station_List_fill(int type, int new_offset); #endif // __XASTIR_LIST_GUI_H Xastir-Release-2.2.4/src/locate_gui.c0000664000175000017500000014441515151324131016400 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include "xastir.h" #include "main.h" #include "lang.h" #include "maps.h" #include "db_funcs.h" #include "db_gui.h" #include "mutex_utils.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget locate_station_dialog = (Widget)NULL; Widget locate_station_data = (Widget)NULL; char locate_station_call[30]; static xastir_mutex locate_station_dialog_lock; Widget locate_place_dialog = (Widget)NULL; Widget locate_place_data = (Widget)NULL; Widget locate_state_data = (Widget)NULL; Widget locate_county_data = (Widget)NULL; Widget locate_quad_data = (Widget)NULL; Widget locate_type_data = (Widget)NULL; Widget locate_gnis_file_data = (Widget)NULL; char locate_place_name[50]; char locate_state_name[50]; char locate_county_name[50]; char locate_quad_name[50]; char locate_type_name[50]; char locate_gnis_filename[200]; static xastir_mutex locate_place_dialog_lock; /* locate station values */ Widget locate_case_data, locate_match_data; /* locate place values */ Widget locate_place_case_data, locate_place_match_data; Widget locate_place_list; Widget locate_place_chooser = (Widget)NULL; static xastir_mutex locate_place_chooser_lock; char match_array_name[50][200]; long match_array_lat[50]; long match_array_long[50]; int match_quantity = 0; void locate_gui_init(void) { init_critical_section( &locate_station_dialog_lock ); init_critical_section( &locate_place_dialog_lock ); init_critical_section( &locate_place_chooser_lock ); locate_station_call[0] = '\0'; locate_place_name[0] = '\0'; locate_state_name[0] = '\0'; locate_county_name[0] = '\0'; locate_quad_name[0] = '\0'; locate_type_name[0] = '\0'; } /**** LOCATE STATION ******/ void Locate_station_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station_destroy_shell" ); XtDestroyWidget(shell); locate_station_dialog = (Widget)NULL; end_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station_destroy_shell" ); } /* * Look up detailed FCC/RAC info about the station */ // Determine whether it is a U.S. or Canadian callsign then search // through the appropriate database and present the results. void fcc_rac_lookup(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char station_call[200]; char temp[1000]; char temp2[300]; char *temp_ptr; FccAppl my_fcc_data; rac_record my_rac_data; // Snag station call temp_ptr = XmTextFieldGetString(locate_station_data); xastir_snprintf(station_call, sizeof(station_call), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(station_call); (void)remove_trailing_dash_zero(station_call); to_upper(station_call); switch (station_call[0]) { case 'A': case 'K': case 'N': case 'W': if (search_fcc_data_appl(station_call, &my_fcc_data) == 1) { xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s %s %s\n%s %s, %s %s, %s %s\n\n", langcode("STIFCC0001"), langcode("STIFCC0003"), my_fcc_data.name_licensee, langcode("STIFCC0004"), my_fcc_data.text_street, my_fcc_data.text_pobox, langcode("STIFCC0005"), my_fcc_data.city, langcode("STIFCC0006"), my_fcc_data.state, langcode("STIFCC0007"), my_fcc_data.zipcode); popup_message_always(langcode("WPUPLSP007"),temp); } else { xastir_snprintf(temp2, sizeof(temp2), "Callsign Not Found!\n"); popup_message_always(langcode("POPEM00001"),temp2); } break; case 'V': if (search_rac_data(station_call, &my_rac_data) == 1) { xastir_snprintf(temp, sizeof(temp), "%s\n%s %s\n%s\n%s, %s\n%s\n", langcode("STIFCC0002"), my_rac_data.first_name, my_rac_data.last_name, my_rac_data.address, my_rac_data.city, my_rac_data.province, my_rac_data.postal_code); if (my_rac_data.qual_a[0] == 'A') strncat(temp, langcode("STIFCC0008"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_d[0] == 'D') strncat(temp, langcode("STIFCC0009"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_b[0] == 'B' && my_rac_data.qual_c[0] != 'C') strncat(temp, langcode("STIFCC0010"), sizeof(temp) - 1 - strlen(temp)); if (my_rac_data.qual_c[0] == 'C') strncat(temp, langcode("STIFCC0011"), sizeof(temp) - 1 - strlen(temp)); strncat(temp, "\n", sizeof(temp) - 1 - strlen(temp)); if (strlen(my_rac_data.club_name) > 1) { xastir_snprintf(temp2, sizeof(temp2), "%s\n%s\n%s, %s\n%s\n", my_rac_data.club_name, my_rac_data.club_address, my_rac_data.club_city, my_rac_data.club_province, my_rac_data.club_postal_code); strncat(temp, temp2, sizeof(temp) - 1 - strlen(temp)); } popup_message_always(langcode("WPUPLSP007"),temp); } else { // RAC code does its own popup in this case? //fprintf(stderr, "Callsign not found\n"); } break; default: xastir_snprintf(temp2, sizeof(temp2), "Not an FCC or RAC callsign!\n"); popup_message_always(langcode("POPEM00001"),temp2); break; } // Don't enable this as then we can't click on the Locate button // later. //Locate_station_destroy_shell(w, clientData, callData); } /* * Locate a station by centering the map at its position */ void Locate_station_now(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp2[200]; char *temp_ptr; /* find station and go there */ temp_ptr = XmTextFieldGetString(locate_station_data); xastir_snprintf(locate_station_call, sizeof(locate_station_call), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(locate_station_call); (void)remove_trailing_dash_zero(locate_station_call); /*fprintf(stderr,"looking for %s\n",locate_station_call);*/ if (locate_station(da, locate_station_call, (int)XmToggleButtonGetState(locate_case_data), (int)XmToggleButtonGetState(locate_match_data),1) ==0) { xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00002"), locate_station_call); popup_message_always(langcode("POPEM00001"),temp2); } // Don't enable this as then we can't click on the FCC/RAC // button later, and we'll lose the callsign info if we want to // see it again. //Locate_station_destroy_shell(w, clientData, callData); } // Here we pass in a 1 in callData if it's an emergency locate, // for when we've received a Mic-E emergency packet. // void Locate_station(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { static Widget pane, scrollwindow, form, button_locate, button_cancel, call, button_lookup, sep; Atom delw; int emergency_flag = XTPOINTER_TO_INT(callData); if (!locate_station_dialog) { begin_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station" ); // Check whether it is an emergency locate function if (emergency_flag == 1) { locate_station_dialog = XtVaCreatePopupShell(langcode("WPUPLSP006"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); } else // Non-emergency locate { locate_station_dialog = XtVaCreatePopupShell(langcode("WPUPLSP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); } pane = XtVaCreateWidget("Locate_station pane",xmPanedWindowWidgetClass, locate_station_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Locate_station form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); call = XtVaCreateManagedWidget(langcode("WPUPLSP002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_station_data = XtVaCreateManagedWidget("Locate_station data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_case_data = XtVaCreateManagedWidget(langcode("WPUPLSP003"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_match_data = XtVaCreateManagedWidget(langcode("WPUPLSP004"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locate_case_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Locate_station sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,locate_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_lookup = XtVaCreateManagedWidget(langcode("WPUPLSP007"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_locate = XtVaCreateManagedWidget(langcode("WPUPLSP005"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_lookup, XmNactivateCallback, fcc_rac_lookup, locate_station_dialog); XtAddCallback(button_locate, XmNactivateCallback, Locate_station_now, locate_station_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Locate_station_destroy_shell, locate_station_dialog); XmToggleButtonSetState(locate_case_data,FALSE,FALSE); XmToggleButtonSetState(locate_match_data,TRUE,FALSE); XmTextFieldSetString(locate_station_data,locate_station_call); pos_dialog(locate_station_dialog); delw = XmInternAtom(XtDisplay(locate_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_station_dialog, delw, Locate_station_destroy_shell, (XtPointer)locate_station_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, locate_station_dialog); end_critical_section(&locate_station_dialog_lock, "locate_gui.c:Locate_station" ); XtPopup(locate_station_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(locate_station_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(locate_station_dialog), XtWindow(locate_station_dialog)); } } /*******************************************************************/ /* Locate Place Chooser routines */ /* * Locate Place Chooser PopUp window: Cancelled */ void Locate_place_chooser_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_destroy_shell" ); XtDestroyWidget(shell); locate_place_chooser = (Widget)NULL; end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_destroy_shell" ); } /* * Locate Place Selection PopUp window: Map selected place */ void Locate_place_chooser_select(Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int ii, xx; char *temp; XmString *list; int found = 0; int index = 0; begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_select" ); if (locate_place_chooser) { XtVaGetValues(locate_place_list, XmNitemCount, &ii, XmNitems, &list, NULL); for (xx=1; xx<=ii; xx++) { if (XmListPosSelected(locate_place_list, xx)) { found = 1; index = xx; if (XmStringGetLtoR(list[(xx-1)], XmFONTLIST_DEFAULT_TAG, &temp)) { xx=ii+1; } } } if (found) { // Center the map at the chosen location set_map_position(widget, match_array_lat[index-1], match_array_long[index-1]); XtFree(temp); } } end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser_select" ); } void Locate_place_chooser(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, form, button_ok, button_cancel; Arg al[50]; register unsigned int ac = 0; int ii, nn; XmString str_ptr; Atom delw; if (locate_place_chooser != NULL) { Locate_place_chooser_destroy_shell(locate_place_chooser, locate_place_chooser, NULL); } begin_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser"); if (locate_place_chooser == NULL) { // Set up a selection box: locate_place_chooser = XtVaCreatePopupShell(langcode("WPUPCFS028"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Locate_place_chooser pane",xmPanedWindowWidgetClass, locate_place_chooser, XmNbackground, colors[0xff], NULL); form = XtVaCreateWidget("Locate_place_chooser form",xmFormWidgetClass, pane, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // Attach buttons first to the bottom of the form, // so that we'll be able to stretch this thing // vertically to see all of the entries. // button_ok = XtVaCreateManagedWidget(langcode("WPUPCFS028"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Locate_place_chooser_select, locate_place_chooser); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Locate_place_chooser_destroy_shell, locate_place_chooser); // set args for color ac = 0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 6); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNbottomWidget, button_ok); ac++; XtSetArg(al[ac], XmNbottomOffset, 5); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; locate_place_list = XmCreateScrolledList(form,"Locate_place_chooser list",al,ac); nn = 1; for (ii = 0; ii < match_quantity; ii++) { XmListAddItem(locate_place_list, str_ptr = XmStringCreateLtoR(match_array_name[ii], XmFONTLIST_DEFAULT_TAG), (int)nn++); XmStringFree(str_ptr); } pos_dialog(locate_place_chooser); delw = XmInternAtom(XtDisplay(locate_place_chooser), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_place_chooser, delw, Locate_place_chooser_destroy_shell, (XtPointer)locate_place_chooser); XtManageChild(form); XtManageChild(locate_place_list); XtVaSetValues(locate_place_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XtPopup(locate_place_chooser,XtGrabNone); // Move focus to the Cancel button. This appears to // highlight t // button fine, but we're not able to hit the // key to // have that default function happen. Note: We // _can_ hit the // key, and that activates the option. XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } end_critical_section(&locate_place_chooser_lock, "locate_gui.c:Locate_place_chooser" ); } /*******************************************************************/ /**** LOCATE PLACE ******/ void Locate_place_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place_destroy_shell" ); XtDestroyWidget(shell); locate_place_dialog = (Widget)NULL; end_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place_destroy_shell" ); } /* * Locate a place by centering the map at its position */ void Locate_place_now(Widget w, XtPointer clientData, XtPointer callData) { char *temp_ptr; // int ii; /* find place and go there */ temp_ptr = XmTextFieldGetString(locate_place_data); xastir_snprintf(locate_place_name, sizeof(locate_place_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_state_data); xastir_snprintf(locate_state_name, sizeof(locate_state_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_county_data); xastir_snprintf(locate_county_name, sizeof(locate_county_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_quad_data); xastir_snprintf(locate_quad_name, sizeof(locate_quad_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_type_data); xastir_snprintf(locate_type_name, sizeof(locate_type_name), "%s", temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(locate_gnis_file_data); xastir_snprintf(locate_gnis_filename, sizeof(locate_gnis_filename), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(locate_place_name); (void)remove_trailing_spaces(locate_state_name); (void)remove_trailing_spaces(locate_county_name); (void)remove_trailing_spaces(locate_quad_name); (void)remove_trailing_spaces(locate_type_name); /*fprintf(stderr,"looking for %s\n",locate_place_name);*/ match_quantity = gnis_locate_place(da, locate_place_name, locate_state_name, locate_county_name, locate_quad_name, locate_type_name, locate_gnis_filename, (int)XmToggleButtonGetState(locate_place_case_data), (int)XmToggleButtonGetState(locate_place_match_data), match_array_name, match_array_lat, match_array_long); if (0 == match_quantity) // Try population centers. match_quantity = pop_locate_place(da, locate_place_name, locate_state_name, locate_county_name, locate_quad_name, locate_type_name, locate_gnis_filename, (int)XmToggleButtonGetState(locate_place_case_data), (int)XmToggleButtonGetState(locate_place_match_data), match_array_name, match_array_lat, match_array_long); if (match_quantity) { // Found some matches! // Have a Chooser dialog if more than one match is found, // plus the associated callbacks. Don't center the map // unless the user chooses one of the matches. Leave the // chooser dialog up so that the user can click on the // matches one at a time until the correct one is found, // then he/she can hit the Close button on that dialog to // make it go away. // Bring up a chooser dialog with the results from the // match_array and a close button. Allow the user to choose // which one to center the map to. Could also allow the // user to find out more about each match if we fill the // array with more data from the GNIS file. // Debug: Print out the contents of the match arrays. //fprintf(stderr,"Found %d matches!\n", match_quantity); /* set_dangerous("printing"); for (ii = 0; ii < match_quantity; ii++) { fprintf(stderr, "%d, %s, %ld, %ld\n", ii, match_array_name[ii], match_array_lat[ii], match_array_long[ii]); } clear_dangerous(); */ // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), match_array_name[0]); // Bring up the new Chooser dialog (void)Locate_place_chooser(w, clientData, callData); } else { // No matches found. popup_message_always(langcode("POPEM00025"),locate_place_name); } Locate_place_destroy_shell(w, clientData, callData); } void Locate_place(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_cancel, sep, place, state, county, quad, place_type, gnis_file; Atom delw; if (!locate_place_dialog) { begin_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place" ); locate_place_dialog = XtVaCreatePopupShell(langcode("PULDNMP014"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Locate_place pane",xmPanedWindowWidgetClass, locate_place_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Locate_place form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); place = XtVaCreateManagedWidget(langcode("FEATURE001"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_place_data = XtVaCreateManagedWidget("Locate_place_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, place, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); state = XtVaCreateManagedWidget(langcode("FEATURE002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, place, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_state_data = XtVaCreateManagedWidget("Locate_state_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((4*7)+2), XmNmaxLength, 2, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, place, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, state, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); county = XtVaCreateManagedWidget(langcode("FEATURE003"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_county_data = XtVaCreateManagedWidget("Locate_county_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, state, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, county, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); quad = XtVaCreateManagedWidget(langcode("FEATURE004"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, county, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_quad_data = XtVaCreateManagedWidget("Locate_quad_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, county, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, quad, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); place_type = XtVaCreateManagedWidget(langcode("FEATURE005"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, quad, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_type_data = XtVaCreateManagedWidget("Locate_type_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 32, XmNwidth, ((32*7)+2), XmNmaxLength, 30, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, quad, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, place_type, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); gnis_file = XtVaCreateManagedWidget(langcode("FEATURE006"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, place_type, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); locate_gnis_file_data = XtVaCreateManagedWidget("locate_gnis_file_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, place_type, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, gnis_file, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_place_case_data = XtVaCreateManagedWidget(langcode("WPUPLSP003"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gnis_file, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); locate_place_match_data = XtVaCreateManagedWidget(langcode("WPUPLSP004"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gnis_file, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locate_place_case_data, XmNleftOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Locate_place sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,locate_place_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPLSP005"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Locate_place_now, locate_place_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Locate_place_destroy_shell, locate_place_dialog); XmToggleButtonSetState(locate_place_case_data,FALSE,FALSE); XmToggleButtonSetState(locate_place_match_data,FALSE,FALSE); // XtSetSensitive(locate_place_match_data,FALSE); XmTextFieldSetString(locate_place_data,locate_place_name); XmTextFieldSetString(locate_state_data,locate_state_name); XmTextFieldSetString(locate_county_data,locate_county_name); XmTextFieldSetString(locate_quad_data,locate_quad_name); XmTextFieldSetString(locate_type_data,locate_type_name); XmTextFieldSetString(locate_gnis_file_data,locate_gnis_filename); pos_dialog(locate_place_dialog); delw = XmInternAtom(XtDisplay(locate_place_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(locate_place_dialog, delw, Locate_place_destroy_shell, (XtPointer)locate_place_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, locate_place_dialog); end_critical_section(&locate_place_dialog_lock, "locate_gui.c:Locate_place" ); XtPopup(locate_place_dialog,XtGrabNone); // Move focus to the Locate Now! button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(locate_place_dialog); XmProcessTraversal(button_ok, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(locate_place_dialog), XtWindow(locate_place_dialog)); } } Xastir-Release-2.2.4/src/location.c0000664000175000017500000000633715151324131016075 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "track_gui.h" // Must be last include file #include "leak_detection.h" static long last_center_longitude; // remember last screen settings static long last_center_latitude; static long last_scale_x; static long last_scale_y; /***********************************************************/ /* set last map position */ /* store lat long and zoom */ /***********************************************************/ void set_last_position(void) { last_center_longitude=center_longitude; last_center_latitude=center_latitude; last_scale_x = scale_x; // we don't restore this... last_scale_y = scale_y; } /***********************************************************/ /* reset map to last position */ /* */ /***********************************************************/ void map_pos_last_position(void) { map_pos(last_center_latitude,last_center_longitude,last_scale_y); } /***********************************************************/ /* Jump map to position */ /* */ /***********************************************************/ void map_pos(long mid_y, long mid_x, long sz) { // see also set_map_position() in db.c // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; set_last_position(); center_longitude = mid_x; center_latitude = mid_y; scale_y = sz; scale_x = get_x_scale(mid_x,mid_y,scale_y); setup_in_view(); // flag all stations in screen view // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // // We don't care whether or not this succeeds? // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // display_zoom_status(); // } } Xastir-Release-2.2.4/src/location_gui.c0000664000175000017500000005304215151324131016734 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "xastir.h" #include "main.h" #include "globals.h" #include "db_funcs.h" #include "xa_config.h" #include "util.h" #include "mutex_utils.h" #include "lang.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget location_dialog = (Widget)NULL; Widget location_list; static xastir_mutex location_dialog_lock; void location_gui_init(void) { init_critical_section( &location_dialog_lock ); } /************************************************/ /* button function for last location */ /************************************************/ void Last_location(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { map_pos_last_position(); } /************************************************/ /* manage jump locations */ /************************************************/ void location_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); XtDestroyWidget(shell); location_dialog = (Widget)NULL; end_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); } /************************************************/ /* jump to chosen location/zoom */ /************************************************/ void location_view(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *location; XmString *list; int found,done; FILE *f; char temp[200]; char name[100]; char pos[100]; char *temp_ptr; char s_lat[20]; char s_long[20]; char s_sz[10]; char location_file_path[MAX_VALUE]; found=0; XtVaGetValues(location_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(location_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&location)) { x=i+1; } } } get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); if (found) { f=fopen(location_file_path,"r"); if (f!=NULL) { done=0; while (!feof(f) & !done) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string temp_ptr=strtok(NULL,"|"); /* get the pos */ xastir_snprintf(pos, sizeof(pos), "%s", temp_ptr); if (strcmp(location,name)==0) { if (3 != sscanf(pos,"%19s %19s %9s", s_lat, s_long, s_sz)) { fprintf(stderr,"location_view:sscanf parsing error\n"); } map_pos(convert_lat_s2l(s_lat),convert_lon_s2l(s_long),atol(s_sz)); done=1; } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } XtFree(location); } } /************************************************/ /* sort and jump locations */ /************************************************/ void jump_sort(void) { char temp[200]; char name[100]; char *temp_ptr; FILE *f; char location_file_path[MAX_VALUE]; char location_db_file_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("data/locations_db.dat", location_db_file_path, sizeof(location_db_file_path)); f=fopen(location_file_path,"r"); if (f!=NULL) { while (!feof(f)) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string (void)sort_input_database(location_db_file_path,name,200); } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } } /************************************************/ /* delete location/zoom */ /************************************************/ void location_delete(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i,x; char *location; XmString *list; int found,ok; FILE *f,*fout; char temp[200]; char name[100]; char pos[100]; char *temp_ptr; char filen[400]; char filen_bak[400]; char location_file_path[MAX_VALUE]; char location_sys_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("config/locations.sys-tmp", location_sys_path, sizeof(location_sys_path)); found=0; ok=0; XtVaGetValues(location_list,XmNitemCount,&i,XmNitems,&list,NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(location_list,x)) { found=1; if (XmStringGetLtoR(list[(x-1)],XmFONTLIST_DEFAULT_TAG,&location)) { XmListDeletePos(location_list,x); x=i+1; } } } if(found) { f=fopen(location_file_path,"r"); if (f!=NULL) { fout=fopen(location_sys_path,"a"); if (fout!=NULL) { while (!feof(f)) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { memcpy(name, temp, sizeof(name)); name[sizeof(name)-1] = '\0'; // Terminate string temp_ptr=strtok(NULL,"|"); /* get the pos */ xastir_snprintf(pos, sizeof(pos), "%s", temp_ptr); if (strcmp(location,name)!=0) { fprintf(fout,"%s|%s\n",name,pos); } } } } (void)fclose(fout); ok=1; } else { fprintf(stderr,"Couldn't open file: %s\n", location_sys_path ); } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } XtFree(location); } if (ok==1) { xastir_snprintf(filen, sizeof(filen), "%s", location_file_path); xastir_snprintf(filen_bak, sizeof(filen_bak), "%s", location_sys_path); (void)unlink(filen); (void)rename(filen_bak,filen); } } /************************************************/ /* add location/zoom */ /************************************************/ void location_add(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char name[100]; char s_long[20]; char s_lat[20]; FILE *f, *fout; char temp[200]; char *temp_ptr; Widget my_text = (Widget) clientData; int len,n,found; char location_file_path[MAX_VALUE]; char location_db_path[MAX_VALUE]; get_user_base_dir("config/locations.sys", location_file_path, sizeof(location_file_path)); get_user_base_dir("data/locations_db.dat", location_db_path, sizeof(location_db_path)); temp_ptr = XmTextFieldGetString(my_text); xastir_snprintf(name, sizeof(name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(name); XmTextFieldSetString(my_text,""); /* should check for name used already */ found=0; f=fopen(location_file_path,"r"); if (f!=NULL) { while (!feof(f) && !found) { (void)get_line(f,temp,200); if (!feof(f) && strlen(temp)>8) { temp_ptr=strtok(temp,"|"); /* get the name */ if (temp_ptr!=NULL) { if (strcmp(name,temp)==0) { found=1; } } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } if (!found) { /* delete entire list available */ XmListDeleteAllItems(location_list); len = (int)strlen(name); if (len>0 && len<100) { fout = fopen(location_file_path,"a"); if (fout!=NULL) { convert_lat_l2s(center_latitude, s_lat, sizeof(s_lat), CONVERT_HP_NOSP); convert_lon_l2s(center_longitude, s_long, sizeof(s_long), CONVERT_HP_NOSP); fprintf(fout,"%s|%s %s %ld\n",name,s_lat,s_long,scale_y); (void)fclose(fout); } else { fprintf(stderr,"Couldn't open file: %s\n", location_file_path ); } } else { popup_message_always(langcode("POPEM00022"),langcode("POPEM00023")); } /* resort the list and put it back up */ n=1; clear_sort_file(location_db_path); jump_sort(); sort_list(location_db_path,200,location_list,&n); } else { popup_message_always(langcode("POPEM00022"),langcode("POPEM00024")); /* dupe name */ } } /************************************************/ /* manage jump locations */ /************************************************/ void Jump_location(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_add, button_delete, button_cancel, locdata, location_name; int n; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ Atom delw; char location_db_path[MAX_VALUE]; get_user_base_dir("data/locations_db.dat", location_db_path, sizeof(location_db_path)); if(!location_dialog) { begin_critical_section(&location_dialog_lock, "location_gui.c:Jump_location" ); location_dialog = XtVaCreatePopupShell(langcode("JMLPO00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, location_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0ff]); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; location_list = XmCreateScrolledList(form, "Jump_location list", al, ac); n=1; clear_sort_file(location_db_path); jump_sort(); sort_list(location_db_path,200,location_list,&n); locdata = XtVaCreateManagedWidget(langcode("JMLPO00003"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(location_list), XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); location_name = XtVaCreateManagedWidget("Jump_location Location_name", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, XtParent(location_list), XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,locdata, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_add = XtVaCreateManagedWidget(langcode("UNIOP00007"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_delete = XtVaCreateManagedWidget(langcode("UNIOP00008"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, locdata, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 5, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, location_destroy_shell, location_dialog); XtAddCallback(button_ok, XmNactivateCallback, location_view, NULL); XtAddCallback(button_add, XmNactivateCallback, location_add, location_name); XtAddCallback(button_delete, XmNactivateCallback, location_delete, NULL); pos_dialog(location_dialog); delw = XmInternAtom(XtDisplay(location_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(location_dialog, delw, location_destroy_shell, (XtPointer)location_dialog); XtManageChild(form); XtManageChild(location_list); XtVaSetValues(location_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(form, location_dialog); end_critical_section(&location_dialog_lock, "location_gui.c:location_destroy_shell" ); XtPopup(location_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(location_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(location_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(location_dialog), XtWindow(location_dialog)); } } Xastir-Release-2.2.4/src/log_utils.c0000664000175000017500000002416315151324131016263 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "globals.h" #include "util.h" #include "db_funcs.h" #include "xa_config.h" #include "snprintf.h" #include "maps.h" // for fill_in_new_alert_entries prototype #define MAX_LOGFILE_SIZE 2048000 char *fetch_file_line(FILE *f, char *line) { char cin; int pos; pos = 0; line[0] = '\0'; while (!feof(f)) { // Read one character at a time if (fread(&cin,1,1,f) == 1) { if (pos < MAX_LINE_SIZE) { if (cin != (char)13) // CR { line[pos++] = cin; } } if (cin == (char)10) // Found LF as EOL char { line[pos++] = '\0'; // Always add a terminating zero after last char pos = 0; // start next line return(line); } } } // Must be end of file line[pos] = '\0'; return(line); } // used by log_data void rotate_file(char *file, int max_keep ) { int i; char file_a[MAX_FILENAME]; char file_b[MAX_FILENAME]; struct stat file_status; if (debug_level & 1) { fprintf(stderr, "Rotating: %s. Will keep %d \n", file, max_keep); } for(i=max_keep; i>=1; i--) { if (debug_level & 1) { fprintf(stderr, "rotate: %s : %s\n", file_b, file_a); } xastir_snprintf(file_a,sizeof(file_a),"%s.%d",file,i); xastir_snprintf(file_b,sizeof(file_b),"%s.%d",file,i-1); unlink (file_a); if (stat(file_a, &file_status) == 0) { // We got good status. That means it didn't get deleted! fprintf(stderr, "Couldn't delete file '%s': %s", file_a,strerror(errno)); return; } // Rename previous to next // // Check whether file_b exists if (stat(file_b, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s\n", file_b); break; } if ( rename (file_b, file_a) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling log_rotate()\n", file_b, file_a); return; } } } if (debug_level & 1) { fprintf(stderr, "rotate: %s : %s\n", file, file_a); } if ( rename (file, file_a) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling log_rotate()\n", file, file_a); } return; } // Restore weather alerts so that we have a clear picture of the // current state. Check timestamps on the file. If relatively // current, read the file in. // void load_wx_alerts_from_log_working_sub(time_t time_now, char *filename) { time_t file_timestamp; int file_age; int expire_limit; // In seconds char line[MAX_LINE_SIZE+1]; FILE *f; expire_limit = 60 * 60 * 24 * 15; // 15 days // expire_limit = 60 * 60 * 24 * 1; // 1 day file_timestamp = file_time(filename); if (file_timestamp == -1) { // fprintf(stderr,"File %s doesn't exist\n", filename); return; } file_age = time_now - file_timestamp; if ( file_age > expire_limit) { // fprintf(stderr,"Old file: %s, skipping...\n", filename); return; } // fprintf(stderr,"File is current: %s\n", filename); // Read the file in, as it exists and is relatively new. // Check timestamps before each log line and skip those that are // old. Lines in the file should look about like this: // // # 1157027319 Thu Aug 31 05:28:39 PDT 2006 // OUNSWO>APRS::SKYOUN :OUN Check For Activation VCEAB // # 1157027319 Thu Aug 31 05:28:39 PDT 2006 // LZKFFS>APRS::NWS_ADVIS:311324z,FLOOD,ARC67-147 V1PAA // // We could try to use the regular read_file and read_file_ptr // scheme for reading in the log file, but we'd have to modify // it in two ways: We need to keep from bringing up the // interfaces so we'd need to set a flag when done reading and // then start them, plus we'd need to have it check the // timestamps and skip old ones. Instead we'll do it all on our // own here so that we can control everything ourselves. f = fopen(filename, "r"); if (!f) { fprintf(stderr,"Wx Alert log file could not be opened for reading\n"); return; } while (!feof(f)) // Read until end of file { (void)fetch_file_line(f, line); restart_sync: if (line[0] == '\0') { // Empty line found, skip } else if (line[0] == '#') // Timestamp line, check the date { time_t line_stamp; int line_age; if (strlen(line) < 3) // Line is too short, skip { goto restart_sync; } line_stamp = atoi(&line[2]); line_age = time_now - line_stamp; //fprintf(stderr, "Age: %d\t", line_age); if ( line_age < expire_limit) { // Age is good, read next line and process it (void)fetch_file_line(f, line); if (line[0] != '#') // It's a packet, not a timestamp line { //fprintf(stderr,"%s\n",line); decode_ax25_line(line,'F',-1, 1); // Decode the packet } else { goto restart_sync; } } } } if (feof(f)) // Close file if at the end { (void)fclose(f); } } // Restore weather alerts so that we have a clear picture of the // current state. Do this before we start the interfaces. Only // reload if the log files datestamps are relatively current. // // Check timestamps on each file in turn. If relatively // current, read them in the correct order: // wx_alert.log.3 // wx_alert.log.2 // wx_alert.log.1 // wx.alert.log // void load_wx_alerts_from_log(void) { time_t time_now; char filename[MAX_FILENAME]; char logfile_path[MAX_VALUE]; get_user_base_dir(LOGFILE_WX_ALERT,logfile_path, sizeof(logfile_path)); time_now = sec_now(); fprintf(stderr,"*** Reading WX Alert log files\n"); // wx_alert.log.3 xastir_snprintf(filename, sizeof(filename), "%s.3", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log.2 xastir_snprintf(filename, sizeof(filename), "%s.2", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log.1 xastir_snprintf(filename, sizeof(filename), "%s.1", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); // wx_alert.log xastir_snprintf(filename, sizeof(filename), "%s", logfile_path ); load_wx_alerts_from_log_working_sub(time_now, filename); fill_in_new_alert_entries(); fprintf(stderr,"*** Done with WX Alert log files\n"); } // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void log_data(char *file, char *line) { FILE *f; struct stat file_status; int reset_setuid = 0 ; // Check for "# Tickle" first, don't log it if found. // It's an idle string designed to keep the socket active. if ( (strncasecmp(line, "#Tickle", 7)==0) || (strncasecmp(line, "# Tickle", 8) == 0) ) { return; } else { char temp[200]; char timestring[100+1]; struct tm *time_now; time_t secs_now; // Fetch the current date/time string // get_timestamp(timestring); secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%a %b %d %H:%M:%S %Z %Y",time_now); xastir_snprintf(temp, sizeof(temp), "# %ld %s", (unsigned long)secs_now, timestring); // Change back to the base directory // This call corrupts the "file" variable. Commented it out as we // don't appear to need it anyway. The complete root-anchored // path/filename are passed to us in the "file" parameter. // // chdir(get_user_base_dir("")); // check size and rotate if too big if (stat(file, &file_status)==0) { // if (debug_level & 1) { // fprintf(stderr, "log_data(): logfile size: %ld \n",(long) file_status.st_size); // } if ((file_status.st_size + strlen(temp) + strlen(line) )> MAX_LOGFILE_SIZE) { if (debug_level & 1) { fprintf(stderr, "log_data(): calling rotate_file()\n"); } rotate_file(file,3); } } else { // ENOENT is ok -- we make the file below if (errno != ENOENT ) { fprintf(stderr,"Couldn't stat log file '%s': %s\n", file,strerror(errno)); return; } } if (getuid() != geteuid()) { reset_setuid=1; DISABLE_SETUID_PRIVILEGE; } f=fopen(file,"a"); if (f!=NULL) { fprintf(f,"%s\n", temp); // Write the timestamp line fprintf(f,"%s\n",line); // Write the data line (void)fclose(f); } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } if(reset_setuid) { ENABLE_SETUID_PRIVILEGE; } } } Xastir-Release-2.2.4/src/log_utils.h0000664000175000017500000000211215151324131016256 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_LOG_UTILS_H #define __XASTIR_LOG_UTILS_H extern void load_wx_alerts_from_log(void); extern void log_data(char *file, char *line); #endif Xastir-Release-2.2.4/src/macspeech.c0000664000175000017500000001013415151324131016203 0ustar hibbyhibby/* Copyright (C) 2000-2026 The Xastir Group */ /* */ /* */ /* First draft */ /* KB3EGH 03/24/2004 */ /* needs -I/Developer/Headers/FlatCarbon */ /*=======================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include #include #include /* can't include this or X11's Cursor conflicts */ /* #include "xastir.h"*/ #include "snprintf.h" // Must be last include file #include "leak_detection.h" static char last_speech_text[8000]; static time_t last_speech_time = (time_t)0; static SpeechChannel channel; int macspeech_processes = 0; int SayText(char *text) { OSErr err; pid_t child_pid; //if (debug_level & 2) //fprintf(stderr,"SayText: %s\n",text); // Check whether the last text was the same and it hasn't been // enough time between them (30 seconds). if ( (strcmp(last_speech_text,text) == 0) // Strings match && (last_speech_time + 30 > sec_now()) ) { //fprintf(stderr,"Same text, skipping speech: %d seconds, %s\n", // (int)(sec_now() - last_speech_time), // text); return(1); } //fprintf(stderr,"Speaking: %s\n",text); xastir_snprintf(last_speech_text, sizeof(last_speech_text), "%s", text); last_speech_time = sec_now(); // Check for the variable going out-of-bounds if (macspeech_processes < 0) { macspeech_processes = 0; } // Allow only so many processes to be queued up ready to send // text to the speech subsystem. // if (macspeech_processes > 10) // Too many processes queued up! { return(1); // Don't send this string, return to calling program } // Create a separate process to handle the speech so that our // main process can continue processing packets and displaying // maps. // child_pid = fork(); if (child_pid == -1) // The fork failed { return(1); } if (child_pid == 0) // Child process { macspeech_processes++; // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Wait for the speech system to be freed up. Note that if // we have multiple processes queued up we don't know in // which order they'll get access to the speech subsystem. // while (SpeechBusy() == true) { usleep(1000000); } // The speech system is free, so send it our text. Right // now we ignore any errors. // err = SpeakText(channel, text, strlen(text)); macspeech_processes--; // Exit this child process. We don't need it anymore. exit(0); } else // Parent process { // Drop through to the return } return(0); // Return to the calling program } int SayTextInit(void) { OSErr err; long response; long mask; VoiceSpec defaultVoiceSpec; VoiceDescription voiceDesc; err = Gestalt(gestaltSpeechAttr, &response); if (err != noErr) { fprintf(stderr,"can't init Mac Speech Synthesis\n"); return(1); } mask = 1 << gestaltSpeechMgrPresent; if ((response & mask) == 0) { fprintf(stderr,"Mac Speech not supported\n"); return(1); } err = GetVoiceDescription(nil, &voiceDesc, sizeof(voiceDesc)); defaultVoiceSpec = voiceDesc.voice; err = NewSpeechChannel( &defaultVoiceSpec, &channel ); if (err != noErr) { DisposeSpeechChannel(channel); fprintf(stderr,"Failed to open a speech channel\n"); return(1); } last_speech_text[0] = '\0'; last_speech_time = (time_t)0; return(0); } /* cleanup should err = DisposeSpeechChannel( channel ); */ Xastir-Release-2.2.4/src/main.c0000664000175000017500000407057215151324131015217 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // This is for debug. If defined to 1, Xastir will display // coordinates in the Xastir coordinate system inside the text2 // widget. // static int DISPLAY_XASTIR_COORDINATES = 0; #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR -- stupid, stupid ImageMagick char *xastir_package=PACKAGE; char *xastir_version=VERSION; #undef PACKAGE #undef VERSION #ifdef HAVE_MAGICK #include /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK //#ifdef HAVE_NETAX25_AXLIB_H //#include //#endif // HAVE_NETAX25_AXLIB_H #ifdef HAVE_LIBCURL #include #endif #include "xastir.h" #include "globals.h" #include "draw_symbols.h" #include "main.h" #include "xa_config.h" #include "maps.h" #include "alert.h" #include "interface.h" #include "wx.h" #include "popup.h" #include "track_gui.h" #include "list_gui.h" #include "util.h" #include "tactical_call_utils.h" #include "color.h" #include "gps.h" #include "bulletin_gui.h" #include "rotated.h" #include "datum.h" #include "igate.h" #include "objects.h" #include "objects_gui.h" #include "db_funcs.h" #include "db_gui.h" #include "db_gis.h" #include "sound.h" #include "ambiguity_utils.h" #include "mgrs_utils.h" #include "log_utils.h" #include "cad_objects.h" #include "map_OSM.h" #ifdef HAVE_LIBSHP #include "shp_hash.h" #endif // HAVE_LIBSHP #include "x_spider.h" #include "map_cache.h" #include #include #include // Must be last include file #include "leak_detection.h" // Copyright 2016. // Added the above "Copyright" just so that grep would find these // lines and we could update the years in the Help->About message // each time. Otherwise it often gets missed when we're updating // the years. #define ABOUT_MSG "X Amateur Station Tracking and Information Reporting\n\n http://www.xastir.org\n\nCopyright (C) 2000-2026 The Xastir Group\nSee the \"LICENSE\" file for other applicable copyrights" // OpenStreetMap attribution #define ABOUT_OSM "Maps, tiles, and data from the OpenStreetMap project are\nCopyright OpenStreetMap and contributors, CC-BY-SA.\nhttp://www.openstreetmap.org/\n http://creativecommons.org/licenses/by-sa/2.0/\n" // Define this if you want an xastir.pid file created in the // ~/.xastir directory and want to check that there's not another // copy of Xastir running before a new one starts up. You can also // use this to send SIGHUP or SIGUSR1 signals to a running Xastir // from scripts. #define USE_PID_FILE_CHECK 1 #define DOS_HDR_LINES 8 #define STATUSLINE_ACTIVE 10 /* status line is cleared after 10 seconds */ #define REPLAY_DELAY 0 /* delay between replayed packets in sec, 0 is ok */ //#define REDRAW_WAIT 3 /* delay between consecutive redraws in seconds (file load) */ #define REDRAW_WAIT 0 /* delay between consecutive redraws in seconds (file load) */ // FONTS FONTS FONTS FONTS FONTS // // NOTE: See the main() function at the bottom of this module for // the default font definition. xa_config.c is where fonts get // saved/restored for user-defined fonts. // This one is not used anymore: //#define XmFONTLIST_DEFAULT_MY "-misc-fixed-*-r-*-*-10-*-*-*-*-*-*-*" // This one goes right along with smaller system fonts on fixed-size // LCD screens. Fix new dialogs to the upper left of the main // window, don't have them cycle through multiple possible positions // as each new dialog is drawn. // //#define FIXED_DIALOG_STARTUP // Yet another useful item: Puts the mouse menu on button 1 instead // of button3. Useful for one-button devices like touchscreens. // //#define SWAP_MOUSE_BUTTONS // If next line uncommented, Xastir will display the status line // in 2 rows instead of the normal single row. Formatted especially // for 640 pixel wide screens. It also gives a little extra room for // the number of stations and the Zoom factor. // #define USE_TWO_STATUS_LINES // Enable this next line to set all flags properly for a 640x480 // touch-screen: Makes the main window smaller due to the reduced // font sizes, makes all dialogs come up at the upper-left of the // main Xastir screen, reverses buttons 1 and 3 so that the more // important mouse menus are accessible via the touch-screen, and // sets it for 2 status lines. Make sure to change the system font // size smaller than the default. // //#define LCD640x480TOUCH // #ifdef LCD640x480TOUCH #define FIXED_DIALOG_STARTUP #define SWAP_MOUSE_BUTTONS #define USE_TWO_STATUS_LINES #endif #define LINE_WIDTH 1 #define ARROWS 1 // Arrow buttons on menubar // TVR 26 July 2005 // Moved this magic number to a #define --- there were numerous places // where this constant was hard coded, making it difficult to change the // map properties line format without breaking something. Now it can live // in one place that needs to be updated when the properties line is changed. // At the time of writing, the properties line had the following format: // min max lyr fil drg amap name // %5d %5d %5d %5c %5c %5c %s // placing the name at offset 37 #define MPD_FILENAME_OFFSET 37 // Define the ICON, created with the "bitmap" editor: #include "icon.xbm" // lesstif (at least as of version 0.94 in 2008), doesn't // have full implementation of combo boxes. #ifndef USE_COMBO_BOX #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) #define USE_COMBO_BOX 1 #endif #endif // USE_COMBO_BOX int geometry_x, geometry_y; unsigned int geometry_width, geometry_height; int geometry_flags; static int initial_load = 1; int first_time_run = 0; /* JMT - works under FreeBSD */ uid_t euid; gid_t egid; int my_argc; char **my_argv; char **my_envp; int restart_xastir_now = 0; // A count of the stations currently on the screen. Counted by // db.c:display_file() routine. int currently_selected_stations = 0; int currently_selected_stations_save = 0; // If my_trail_diff_color is 0, all my calls (SSIDs) will use MY_TRAIL_COLOR. // If my_trail_diff_color = 1 then each different ssid for my callsign will use a different color. int my_trail_diff_color = 0; // Used in segfault handler char dangerous_operation[200]; FILE *file_wx_test; int tcp_server_pid = 0; int udp_server_pid = 0; int serial_char_pacing; // Inter-char delay in ms for serial ports. int dtr_on = 1; time_t sec_last_dtr = (time_t)0; time_t last_updatetime = (time_t)0; int time_went_backwards = 0; /* language in use */ char lang_to_use[30]; /* version info in main.h */ int altnet; char altnet_call[MAX_CALLSIGN+1]; static void Window_Quit(Widget w, XtPointer client, XtPointer call); static void save_state(Widget w, XtPointer client, XtPointer call); void da_input(Widget w, XtPointer client_data, XtPointer call_data); void da_resize(Widget w, XtPointer client_data, XtPointer call_data); void da_expose(Widget w, XtPointer client_data, XtPointer call_data); void BuildPredefinedSARMenu_UI(Widget *parent_menu); Widget *predefined_object_menu_parent; Widget sar_object_sub; Widget predefined_object_menu_items[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; int debug_level; //Widget hidden_shell; Widget appshell; Widget form; Widget da; Widget text; Widget text2; Widget text3; Widget text4; Widget log_indicator; Widget iface_da; Widget menubar; Widget toolbar; Widget configure_station_dialog = (Widget)NULL; Widget right_menu_popup = (Widget)NULL; // Button one or left mouse button //Widget middle_menu_popup=(Widget)NULL; // Button two or middle mouse button //Widget right_menu_popup=(Widget)NULL; // Button three or right mouse button Widget trackme_button; Widget measure_button; Widget move_button; Widget cad_draw_button; Widget CAD_close_polygon_menu_item; int Station_transmit_type; int Igate_type; Widget Display_data_dialog = (Widget)NULL; Widget Display_data_text; int Display_packet_data_type; int show_only_station_capabilities = 0; int Display_packet_data_mine_only = 0; Widget configure_defaults_dialog = (Widget)NULL; Widget configure_timing_dialog = (Widget)NULL; Widget configure_coordinates_dialog = (Widget)NULL; Widget coordinate_calc_button_ok = (Widget)NULL; Widget change_debug_level_dialog = (Widget)NULL; Widget coordinate_calc_dialog = (Widget)NULL; Widget coordinate_calc_zone = (Widget)NULL; Widget coordinate_calc_latitude_easting = (Widget)NULL; Widget coordinate_calc_longitude_northing = (Widget)NULL; Widget coordinate_calc_result_text = (Widget)NULL; static char coordinate_calc_lat_deg[5]; static char coordinate_calc_lat_min[15]; static char coordinate_calc_lat_dir[5]; static char coordinate_calc_lon_deg[5]; static char coordinate_calc_lon_min[15]; static char coordinate_calc_lon_dir[5]; coordinate_calc_array_type coordinate_calc_array; extern void fix_dialog_size(Widget w); // --------------------------- help menu ----------------------------- Widget help_list; Widget help_index_dialog = (Widget)NULL; Widget help_view_dialog = (Widget)NULL; Widget emergency_beacon_toggle; int emergency_beacon = 0; static void Help_About(Widget w, XtPointer clientData, XtPointer callData); static void Help_Index(Widget w, XtPointer clientData, XtPointer callData); void Emergency_beacon_toggle( Widget widget, XtPointer clientData, XtPointer callData); // ----------------------------- map --------------------------------- Widget map_list; Widget map_properties_list; void map_index_update_temp_select(char *filename, map_index_record **current); void map_index_temp_select_clear(void); void map_chooser_fill_in (void); int map_chooser_expand_dirs = 0; void map_chooser_init (void); Widget map_chooser_dialog = (Widget)NULL; Widget map_chooser_button_ok = (Widget)NULL; Widget map_chooser_button_cancel = (Widget)NULL; Widget map_properties_dialog = (Widget)NULL; static void Map_chooser(Widget w, XtPointer clientData, XtPointer callData); Widget map_chooser_maps_selected_data = (Widget)NULL; int re_sort_maps = 1; #ifdef HAVE_LIBGEOTIFF static void Config_DRG(Widget w, XtPointer clientData, XtPointer callData); #endif // HAVE_LIBGEOTIFF Widget grid_on, grid_off; static void Grid_toggle( Widget w, XtPointer clientData, XtPointer calldata); int long_lat_grid; // Switch for Map Lat and Long grid display void Map_border_toggle( Widget w, XtPointer clientData, XtPointer callData); int draw_labeled_grid_border = FALSE; // Toggle labeled border around map. static void CAD_draw_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_lock_pan_zoom = 0; static void Map_lock_pan_zoom_toggle( Widget w, XtPointer clientData, XtPointer calldata); int disable_all_maps = 0; static void Map_disable_toggle( Widget w, XtPointer clientData, XtPointer calldata); static void Map_auto_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_auto_maps; /* toggle use of auto_maps */ static void Map_auto_skip_raster_toggle( Widget w, XtPointer clientData, XtPointer calldata); int auto_maps_skip_raster; Widget map_auto_skip_raster_button; Widget map_border_button; Widget map_levels_on, map_levels_off; static void Map_levels_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_color_levels; /* toggle use of map_color_levels */ Widget map_labels_on, map_labels_off; static void Map_labels_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_labels; // toggle use of map_labels */ Widget map_fill_on, map_fill_off; static void Map_fill_toggle( Widget w, XtPointer clientData, XtPointer calldata); int map_color_fill; /* Whether or not to fill in map polygons with solid color */ int index_maps_on_startup; // Index maps on startup static void Index_maps_on_startup_toggle(Widget w, XtPointer clientData, XtPointer calldata); Widget map_bgcolor[12]; static void Map_background(Widget w, XtPointer clientData, XtPointer calldata); int map_background_color; /* Background color for maps */ #if !defined(NO_GRAPHICS) Widget raster_intensity[11]; static void Raster_intensity(Widget w, XtPointer clientData, XtPointer calldata); #if defined(HAVE_MAGICK) Widget gamma_adjust_dialog = (Widget)NULL; Widget gamma_adjust_text; #endif // HAVE_MAGICK #endif // NO_GRAPHICS Widget map_font_dialog = (Widget)NULL; Widget map_font_text[FONT_MAX]; Widget map_station_label0,map_station_label1,map_station_label2,map_station_label3; static void Map_station_label(Widget w, XtPointer clientData, XtPointer calldata); int letter_style; /* Station Letter style */ Widget map_icon_outline0,map_icon_outline1,map_icon_outline2,map_icon_outline3; static void Map_icon_outline(Widget w, XtPointer clientData, XtPointer calldata); int icon_outline_style; /* Icon Outline style */ Widget map_wx_alerts_0,map_wx_alerts_1; static void Map_wx_alerts_toggle(Widget w, XtPointer clientData, XtPointer calldata); int wx_alert_style; /* WX alert map style */ time_t map_refresh_interval = 0; /* how often to refresh maps, seconds */ time_t map_refresh_time = 0; /* when to refresh maps next, seconds */ // ------------------------ Filter and Display menus ----------------------------- Selections Select_ = { 0, // none 1, // mine 1, // tnc 1, // direct 1, // via_digi 1, // net 0, // tactical 1, // old_data 1, // stations 1, // fixed_stations 1, // moving_stations 1, // weather_stations 1, // CWOP_wx_stations 1, // objects 1, // weather_objects 1, // gauge_objects 1, // other_objects 1, // aircraft_objects 1, // vessel_objects }; What_to_display Display_ = { 1, // callsign 1, // label_all_trackpoints 1, // symbol 1, // symbol_rotate 1, // trail 1, // course 1, // speed 1, // speed_short 1, // altitude 1, // weather 1, // weather_text 1, // temperature_only 1, // wind_barb 1, // aloha_circle 1, // ambiguity 1, // phg 1, // default_phg 1, // phg_of_moving 1, // df_data 1, // df_beamwidth_data 1, // df_bearing_data 1, // dr_data 1, // dr_arc 1, // dr_course 1, // dr_symbol 1, // dist_bearing 1, // last_heard }; Widget select_none_button; Widget select_mine_button; Widget select_tnc_button; Widget select_direct_button; Widget select_via_digi_button; Widget select_net_button; Widget select_tactical_button; Widget select_old_data_button; Widget select_stations_button; Widget select_fixed_stations_button; Widget select_moving_stations_button; Widget select_weather_stations_button; Widget select_CWOP_wx_stations_button; Widget select_objects_button; Widget select_weather_objects_button; Widget select_gauge_objects_button; Widget select_other_objects_button; Widget select_aircraft_objects_button; Widget select_vessel_objects_button; Widget display_callsign_button; Widget display_label_all_trackpoints_button; Widget display_symbol_button; Widget display_symbol_rotate_button; Widget display_trail_button; Widget display_course_button; Widget display_speed_button; Widget display_speed_short_button; Widget display_altitude_button; Widget display_weather_button; Widget display_weather_text_button; Widget display_temperature_only_button; Widget display_wind_barb_button; Widget display_aloha_circle_button; Widget display_ambiguity_button; Widget display_phg_button; Widget display_default_phg_button; Widget display_phg_of_moving_button; Widget display_df_data_button; Widget display_df_beamwidth_data_button; Widget display_df_bearing_data_button; Widget display_dr_data_button; Widget display_dr_arc_button; Widget display_dr_course_button; Widget display_dr_symbol_button; Widget display_dist_bearing_button; Widget display_last_heard_button; static void Select_none_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_mine_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_tnc_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_direct_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_via_digi_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_net_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_tactical_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_old_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_fixed_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_moving_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_weather_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_CWOP_wx_stations_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_weather_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_other_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_gauge_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_aircraft_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Select_vessel_objects_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_callsign_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_label_all_trackpoints_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_symbol_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_symbol_rotate_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_trail_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_course_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_speed_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_speed_short_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_altitude_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_weather_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_weather_text_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_temperature_only_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_wind_barb_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_aloha_circle_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_ambiguity_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_phg_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_default_phg_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_phg_of_moving_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_beamwidth_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_df_bearing_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_data_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_arc_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_course_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dr_symbol_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_dist_bearing_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Display_last_heard_toggle(Widget w, XtPointer clientData, XtPointer calldata); // ------------------------ Interfaces -------------------------- static void Transmit_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Posit_tx_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Object_tx_disable_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Server_port_toggle( Widget widget, XtPointer clientData, XtPointer callData); int transmit_disable; int posit_tx_disable; int object_tx_disable; int enable_server_port = 0; Widget iface_transmit_now, posit_tx_disable_toggle, object_tx_disable_toggle; Widget server_port_toggle; #ifdef HAVE_GPSMAN Widget Fetch_gps_track, Fetch_gps_route, Fetch_gps_waypoints; Widget Fetch_RINO_waypoints; Widget Send_gps_track, Send_gps_route, Send_gps_waypoints; int gps_got_data_from = 0; // We got data from a GPS int gps_operation_pending = 0; // A GPS transfer is happening int gps_details_selected = 0; // Whether name/color have been selected yet Widget gpsfilename_text; // Short name of gps map (no color/type) char gps_map_filename[MAX_FILENAME];// Chosen name of gps map (including color) char gps_map_filename_base[MAX_FILENAME]; // Same minus ".shp" char gps_map_filename_base2[MAX_FILENAME]; // Same minus ".shp" and color char gps_temp_map_filename[MAX_FILENAME]; char gps_temp_map_filename_base[MAX_FILENAME]; // Same minus ".shp" char gps_dbfawk_format[]="BEGIN_RECORD {key=\"\"; lanes=3; color=%d; name=\"%s\"; filled=0; pattern=1; display_level=65536; label_level=128; label_color=8; symbol=\"\"}\n"; int gps_map_color = 0; // Chosen color of gps map int gps_map_color_offset; // offset into colors array of that color. char gps_map_type[30]; // Type of GPS download void check_for_new_gps_map(int curr_sec); Widget GPS_operations_dialog = (Widget)NULL; #endif // HAVE_GPSMAN // ------------------------ unit conversion -------------------------- static void Units_choice_toggle(Widget w, XtPointer clientData, XtPointer calldata); // 0: metric, 1: english, (2: nautical, not fully implemented) int english_units; char un_alt[2+1]; // m / ft char un_dst[2+1]; // mi / km (..nm) char un_spd[4+1]; // mph / km/h (..kn) double cvt_m2len; // from meter double cvt_kn2len; // from knots double cvt_mi2len; // from miles double cvt_dm2len; // from decimeter double cvt_hm2len; // from hectometer void update_units(void); // dist/bearing on status line static void Dbstatus_choice_toggle(Widget w, XtPointer clientData, XtPointer calldata); int do_dbstatus; // Coordinate System int coordinate_system = USE_DDMMMM; // Default, used for most APRS systems // ------------------------- audio alarms ---------------------------- Widget configure_audio_alarm_dialog = (Widget)NULL; Widget audio_alarm_config_play_data, audio_alarm_config_play_on_new_station, audio_alarm_config_play_ons_data, audio_alarm_config_play_on_new_message, audio_alarm_config_play_onm_data, audio_alarm_config_play_on_prox, audio_alarm_config_play_onpx_data, audio_alarm_config_play_on_bando, audio_alarm_config_play_onbo_data, prox_min_data, prox_max_data, bando_min_data, bando_max_data, audio_alarm_config_play_on_wx_alert, audio_alarm_config_wx_alert_data; static void Configure_audio_alarms(Widget w, XtPointer clientData, XtPointer callData); // ---------------------------- speech ------------------------------- Widget configure_speech_dialog = (Widget)NULL; Widget speech_config_play_on_new_station, speech_config_play_on_new_message_alert, speech_config_play_on_new_message_body, speech_config_play_on_prox, speech_config_play_on_trak, speech_config_play_on_bando, speech_config_play_on_new_wx_alert; static void Configure_speech(Widget w, XtPointer clientData, XtPointer callData); //#ifdef HAVE_FESTIVAL /* WARNING - new station is initialized to FALSE for a reason */ /* If you're tempted to make it something that can be saved and restored */ /* beware, Speech cannot keep up with the initial flow of data from an */ /* Internet connection that has buffered data. An unbuffered connection */ /* yes, but not a buffered one. Ken, N7IPB */ int festival_speak_new_station = FALSE; int festival_speak_proximity_alert; int festival_speak_tracked_proximity_alert; int festival_speak_band_opening; int festival_speak_new_message_alert; int festival_speak_new_message_body; int festival_speak_new_weather_alert; int festival_speak_ID; //#endif // HAVE_FESTIVAL int ATV_screen_ID; #ifdef HAVE_LIBGEOTIFF Widget configure_DRG_dialog = (Widget) NULL; Widget DRG_XOR, DRG_color0, DRG_color1, DRG_color2, DRG_color3, DRG_color4, DRG_color5, DRG_color6, DRG_color7, DRG_color8, DRG_color9, DRG_color10, DRG_color11, DRG_color12; int DRG_XOR_colors = 0; int DRG_show_colors[13]; #endif // HAVE_LIBGEOTIFF // ------------------------------------------------------------------- Widget read_selection_dialog = (Widget)NULL; // config station values Widget station_config_call_data, station_config_slat_data_deg, station_config_slat_data_min, station_config_slat_data_ns, station_config_slong_data_deg, station_config_slong_data_min, station_config_slong_data_ew, station_config_group_data, station_config_symbol_data, station_config_icon, station_config_comment_data; Pixmap CS_icon0, CS_icon; /* defaults*/ #ifdef TRANSMIT_RAW_WX Widget raw_wx_tx; #endif // TRANSMIT_RAW_WX Widget compressed_posit_tx; Widget compressed_objects_items_tx; Widget new_bulletin_popup_enable; Widget zero_bulletin_popup_enable; Widget warn_about_mouse_modifiers_enable; Widget my_trail_diff_color_enable; Widget load_predefined_objects_menu_from_file_enable; #ifdef USE_COMBO_BOX Widget load_predefined_objects_menu_from_file; // combo box widget #else int lpomff_value; // replacement value for predefined menu file combo box #endif // USE_COMBO_BOX int pop_up_new_bulletins = 0; int view_zero_distance_bulletins = 0; int warn_about_mouse_modifiers = 1; Widget altnet_active; Widget altnet_text; Widget disable_dupe_check; Widget new_map_layer_text = (Widget)NULL; Widget new_max_zoom_text = (Widget)NULL; Widget new_min_zoom_text = (Widget)NULL; Widget debug_level_text; static int sec_last_dr_update = 0; FILE *f_xfontsel_pipe[FONT_MAX]; int xfontsel_query = 0; // ------------------------------------------------------------------- static void UpdateTime( XtPointer clientData, XtIntervalId id ); void pos_dialog(Widget w); static void Zoom_in(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_in_no_pan(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_out(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_out_no_pan(Widget w, XtPointer clientData, XtPointer calldata); static void Zoom_level(Widget w, XtPointer clientData, XtPointer calldata); static void display_zoom_image(int recenter); static void Track_Me( Widget w, XtPointer clientData, XtPointer calldata); static void Measure_Distance( Widget w, XtPointer clientData, XtPointer calldata); static void SetMyPosition( Widget w, XtPointer clientData, XtPointer calldata); static void Pan_ctr(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_up(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_up_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_down(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_down_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_left(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_left_less(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_right(Widget w, XtPointer clientData, XtPointer calldata); static void Pan_right_less(Widget w, XtPointer clientData, XtPointer calldata); void Center_Zoom(Widget w, XtPointer clientData, XtPointer calldata); void Go_Home(Widget w, XtPointer clientData, XtPointer calldata); int center_zoom_override = 0; Widget center_zoom_dialog = (Widget)NULL; Widget custom_zoom_dialog = (Widget)NULL; static void Menu_Quit(Widget w, XtPointer clientData, XtPointer calldata); static void TNC_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void TNC_Transmit_now(Widget w, XtPointer clientData, XtPointer calldata); #ifdef HAVE_GPSMAN static void GPS_operations(Widget w, XtPointer clientData, XtPointer calldata); #endif // HAVE_GPSMAN static void Net_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void IGate_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void Message_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void WX_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); static void WX_Alert_Logging_toggle(Widget w, XtPointer clientData, XtPointer calldata); void on_off_switch(int switchpos, Widget first, Widget second); void sel3_switch(int switchpos, Widget first, Widget second, Widget third); void sel4_switch(int switchpos, Widget first, Widget second, Widget third, Widget fourth); static void Configure_station(Widget w, XtPointer clientData, XtPointer callData); static void Configure_defaults(Widget w, XtPointer clientData, XtPointer callData); static void Configure_timing(Widget w, XtPointer clientData, XtPointer callData); static void Configure_coordinates(Widget w, XtPointer clientData, XtPointer callData); static void Stations_Clear(Widget w, XtPointer clientData, XtPointer callData); static void Test(Widget w, XtPointer clientData, XtPointer callData); static void Save_Config(Widget w, XtPointer clientData, XtPointer callData); static void Read_File_Selection(Widget w, XtPointer clientData, XtPointer callData); static void Display_data(Widget w, XtPointer clientData, XtPointer callData); static void Auto_msg_toggle( Widget widget, XtPointer clientData, XtPointer callData); static void Satellite_msg_ack_toggle( Widget widget, XtPointer clientData, XtPointer callData); Widget auto_msg_toggle; Widget satellite_msg_ack_toggle; Widget posamb0,posamb1,posamb2,posamb3,posamb4; //////////////////////////////////////////////////////////////////////////////////////////////////// /* GLOBAL DEFINES */ GC gc=0; // Used for drawing maps GC gc2=0; // Used for drawing symbols GC gc_tint=0; // Used for tinting maps & symbols GC gc_stipple=0; // Used for drawing symbols GC gc_bigfont=0; Pixmap pixmap; Pixmap pixmap_alerts; Pixmap pixmap_final; // Global variable, so we can set it up once check it from then on, // preventing memory leaks from repeatedly setting up the same // XFontStruct. XFontStruct *station_font = NULL; // Station font XFontStruct *font1; // Menu/System font XmFontList fontlist1; // Menu/System fontlist Pixmap pixmap_50pct_stipple; // 50% pixels used for position ambiguity, DF circle, etc. Pixmap pixmap_25pct_stipple; // 25% pixels used for large position ambiguity Pixmap pixmap_13pct_stipple; // 12.5% pixels used for larger position ambiguity Pixmap pixmap_wx_stipple; // Used for weather alerts int interrupt_drawing_now = 0; // Flag used to interrupt map drawing int request_resize = 0; // Flag used to request a resize operation int request_new_image = 0; // Flag used to request a create_image operation //time_t last_input_event = (time_t)0; // Time of last mouse/keyboard event void new_image(Widget da); typedef struct XastirGlobal { Widget top; // top level shell } XastirGlobal; XastirGlobal Global; char *database_ptr; /* database pointers */ //--------------------------------------------------------------------------------------------- // // These describe the current map window. They must be kept // up-to-date when we zoom/pan/resize the window. // float f_center_longitude; // Floating point map center longitude, updated by new_image() float f_center_latitude; // Floating point map center latitude , updated by new_image() float f_NW_corner_longitude; // longitude of NW corner, updated by create_image(), refresh_image() float f_NW_corner_latitude; // latitude of NW corner, updated by create_image(), refresh_image() float f_SE_corner_longitude; // longitude of SE corner, updated by create_image(), refresh_image() float f_SE_corner_latitude; // latitude of SE corner, updated by create_image(), refresh_image() long center_longitude; // Longitude at center of map, updated by display_zoom_image() long center_latitude; // Latitude at center of map, updated by display_zoom_image() long NW_corner_longitude; // Longitude at NW corner, updated by create_image(), refresh_image() long NW_corner_latitude; // Latitude at NW corner, updated by create_image(), refresh_image() long SE_corner_longitude; // Longitude at SE corner, updated by create_image(), refresh_image() long SE_corner_latitude; // Latitude at SE corner, updated by create_image(), refresh_image() long scale_x; // x scaling in 1/100 sec per pixel, calculated from scale_y long scale_y; // y scaling in 1/100 sec per pixel long new_mid_x, new_mid_y; // Check values used before applying real change long new_scale_x; long new_scale_y; long screen_width; // Screen width, map area without border (in pixels) long screen_height; // Screen height, map area without border (in pixels) Position screen_x_offset; Position screen_y_offset; float d_screen_distance; // Diag screen distance float x_screen_distance; // x screen distance //--------------------------------------------------------------------------------------------- char user_dir[1000]; /* user directory file */ int delay_time; /* used to delay display data */ time_t last_weather_cycle; // Time of last call to cycle_weather() Pixel colors[256]; /* screen colors */ Pixel trail_colors[MAX_TRAIL_COLORS]; /* station trail colors, duh */ int current_trail_color; /* what color to draw station trails with */ Pixel_Format visual_type = NOT_TRUE_NOR_DIRECT; int install_colormap; /* if visual_type == NOT_TRUE..., should we install priv cmap */ Colormap cmap; /* current colormap */ int redo_list; // Station List update request int redraw_on_new_data; // Station redraw request int wait_to_redraw; /* wait to redraw until system is up */ int display_up = 0; /* display up? */ int display_up_first = 0; /* display up first */ time_t max_transmit_time; /* max time between transmits */ time_t last_alert_redraw; /* last time alert caused a redraw */ time_t sec_next_gps; /* next gps check */ time_t gps_time; /* gps delay time */ char gprmc_save_string[MAX_LINE_SIZE+1]; char gpgga_save_string[MAX_LINE_SIZE+1]; int gps_port_save; time_t POSIT_rate; // Posit TX rate timer time_t OBJECT_rate; // Object/Item TX rate timer time_t update_DR_rate; // How often to call draw_symbols if DR enabled time_t remove_ID_message_time; // Time to get rid of large msg on screen. int pending_ID_message = 0; // Variable turning on/off this function // SmartBeaconing(tm) stuff. If enabled, POSIT_rate won't be used // for timing posits. sb_POSIT_rate computed via SmartBeaconing(tm) // will be used instead. int smart_beaconing; // Master enable/disable for SmartBeaconing(tm) mode int sb_POSIT_rate = 30 * 60; // Computed SmartBeaconing(tm) posit rate (secs) int sb_last_heading = -1; // Heading at time of last posit int sb_current_heading = -1; // Most recent heading parsed from GPS sentence int sb_turn_min = 20; // Min threshold for corner pegging (degrees) int sb_turn_slope = 25; // Threshold slope for corner pegging (degrees/mph) int sb_turn_time = 5; // Time between other beacon & turn beacon (secs) int sb_posit_fast = 90; // Fast beacon rate (secs) int sb_posit_slow = 30; // Slow beacon rate (mins) int sb_low_speed_limit = 2; // Speed below which SmartBeaconing(tm) is disabled & // we'll beacon at the POSIT_slow rate (mph) int sb_high_speed_limit = 60; // Speed above which we'll beacon at the // POSIT_fast rate (mph) Widget smart_beacon_dialog = (Widget)NULL; Widget smart_beacon_enable = (Widget)NULL; Widget sb_hi_rate_data = (Widget)NULL; Widget sb_hi_mph_data = (Widget)NULL; Widget sb_lo_rate_data = (Widget)NULL; Widget sb_lo_mph_data = (Widget)NULL; Widget sb_min_turn_data = (Widget)NULL; Widget sb_turn_slope_data = (Widget)NULL; Widget sb_wait_time_data = (Widget)NULL; Widget ghosting_time = (Widget)NULL; Widget clearing_time = (Widget)NULL; Widget aircraft_clearing_time = (Widget)NULL; Widget removal_time = (Widget)NULL; Widget posit_interval = (Widget)NULL; Widget gps_interval = (Widget)NULL; Widget dead_reckoning_time = (Widget)NULL; Widget object_item_interval = (Widget)NULL; Widget serial_pacing_time = (Widget)NULL; Widget trail_segment_timeout = (Widget)NULL; Widget trail_segment_distance_max = (Widget)NULL; Widget RINO_download_timeout = (Widget)NULL; Widget net_map_slider = (Widget)NULL; Widget snapshot_interval_slider = (Widget)NULL; int net_map_timeout = 120; time_t GPS_time; /* gps time out */ time_t last_statusline; // last update of statusline or 0 if inactive time_t last_id_time; // Time of last ID message to statusline time_t sec_old; /* station old after */ time_t sec_clear; /* station cleared after */ time_t aircraft_sec_clear; /* aircraft cleared after */ time_t sec_remove; /* Station removed after */ int trail_segment_time; // Segment missing if above this time (mins) int trail_segment_distance; // Segment missing if greater distance int RINO_download_interval; // Interval at which to download RINO waypoints, // creating APRS Objects from them. time_t last_RINO_download = (time_t)0; time_t sec_next_raw_wx; /* raw wx transmit data */ int dead_reckoning_timeout = 60 * 10; // 10 minutes; #ifdef TRANSMIT_RAW_WX int transmit_raw_wx; /* transmit raw wx data? */ #endif // TRANSMIT_RAW_WX int transmit_compressed_posit; // transmit location in compressed format? int transmit_compressed_objects_items; // Same for objects & items int output_station_type; /* Broadcast station type */ int Configure_station_pos_amb; /* Broadcast station position ambiguity */ long max_vectors_allowed; /* max map vectors allowed */ long max_text_labels_allowed; /* max map text labels allowed */ long max_symbol_labels_allowed; /* max map symbol labels allowed */ time_t net_last_time; /* reconnect last time in seconds */ time_t net_next_time; /* reconnect Next update delay time */ #ifdef USING_LIBGC time_t gc_next_time = 0L; // Garbage collection next time #endif // USING_LIBGC time_t posit_last_time; time_t posit_next_time; /* time at which next posit TX will occur */ time_t last_time; /* last time in seconds */ time_t next_time; /* Next update delay time */ time_t next_redraw; /* Next update time */ time_t last_redraw; /* Time of last redraw */ char aprs_station_message_type = '='; // station message-capable or not int transmit_now; /* set to transmit now (push on moment) */ int my_position_valid = 1; /* Don't send posits if this is zero */ int using_gps_position = 0; /* Set to one if a GPS port is active */ int operate_as_an_igate; /* toggle igate operations for net connections */ unsigned igate_msgs_tx; /* current total of igate messages transmitted */ int log_tnc_data; /* log data */ int log_net_data; /* log data */ int log_igate; /* toggle to allow igate logging */ int log_wx; /* toggle to allow wx logging */ int log_message_data; /* toggle to allow message logging */ int log_wx_alert_data; /* toggle to allow wx alert logging */ int snapshots_enabled = 0; // toggle to allow creating .png snapshots on a regular basis int kmlsnapshots_enabled = 0; // toggle to allow creating .kml snapshots on a regular basis time_t WX_ALERTS_REFRESH_TIME; /* Minimum WX alert map refresh time in seconds */ /* button zoom */ int menu_x; int menu_y; int possible_zoom_function = 0; int zoom_box_x1 = -1; // Stores one corner of zoom box int zoom_box_y1 = -1; int zoom_box_x2 = -1; // Stores one corner of zoom box int zoom_box_y2 = -1; int mouse_zoom = 0; // log file replay int read_file; FILE *read_file_ptr; time_t next_file_read; // Data for own station char my_callsign[MAX_CALLSIGN+1]; char my_lat[MAX_LAT]; char my_long[MAX_LONG]; char my_group; char my_symbol; char my_phg[MAX_PHG+1]; char my_comment[MAX_COMMENT+1]; int my_last_course; int my_last_speed; long my_last_altitude; time_t my_last_altitude_time; /* Symbols */ SymbolData symbol_data[MAX_SYMBOLS]; /* sound run */ pid_t last_sound_pid; /* Default directories */ char AUTO_MAP_DIR[400]; char ALERT_MAP_DIR[400]; char SELECTED_MAP_DIR[400]; char SELECTED_MAP_DATA[400]; char MAP_INDEX_DATA[400]; char SYMBOLS_DIR[400]; char HELP_FILE[400]; char SOUND_DIR[400]; char LOGFILE_TNC[400]; char LOGFILE_NET[400]; char LOGFILE_IGATE[400]; char LOGFILE_MESSAGE[400]; char LOGFILE_WX[400]; char LOGFILE_WX_ALERT[400]; /* sound data */ char sound_command[90]; int sound_play_new_station; char sound_new_station[90]; int sound_play_new_message; char sound_new_message[90]; int sound_play_prox_message; char sound_prox_message[90]; char prox_min[30]; char prox_max[30]; int sound_play_band_open_message; char sound_band_open_message[90]; char bando_min[30]; char bando_max[30]; int sound_play_wx_alert_message; char sound_wx_alert_message[90]; int input_x = 0; int input_y = 0; XtAppContext app_context; Display *display; /* Display */ /* dialog popup last */ int last_popup_x; int last_popup_y; int disable_all_popups = 0; char temp_tracking_station_call[30] = ""; time_t program_start_time; int measuring_distance = 0; int moving_object = 0; ///////////////////////////////////////////////////////////////////////// void Smart_Beacon_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); smart_beacon_dialog = (Widget)NULL; } // Still need to do some bounds checking on the values here. // // If the user enters 0's or non-numeric data, this function sets the // values to reasonable defaults. // // Another thing that'd be good to do is to recalculate the next // beacon time if one of the posit rates is shortened. Otherwise we // might be waiting a while to get into the "right rhythm". // void Smart_Beacon_change_data(Widget widget, XtPointer clientData, XtPointer callData) { // Snag the XmTextString data and write it into the variables if (smart_beacon_dialog != NULL) { char *str_ptr1; int i; smart_beaconing = (int)XmToggleButtonGetState(smart_beacon_enable); str_ptr1 = XmTextGetString(sb_hi_rate_data); i = atoi(str_ptr1); if (i == 0) { i = 90; } sb_posit_fast = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_hi_mph_data); i = atoi(str_ptr1); switch (english_units) { case 0: // Metric: Convert from KPH to MPH for storage i = (int)((i * 0.62137) + 0.5); break; case 1: // English case 2: // Nautical default: // No conversion necessary break; } if (i == 0) { i = 60; } sb_high_speed_limit = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_lo_rate_data); i = atoi(str_ptr1); if (i == 0) { i = 30; } sb_posit_slow = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_lo_mph_data); i = atoi(str_ptr1); switch (english_units) { case 0: // Metric: Convert from KPH to MPH for storage i = (int)((i * 0.62137) + 0.5); break; case 1: // English case 2: // Nautical default: // No conversion necessary break; } if (i == 0) { i = 2; } sb_low_speed_limit = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_min_turn_data); i = atoi(str_ptr1); if (i == 0) { i = 20; } sb_turn_min = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_turn_slope_data); i = atoi(str_ptr1); if (i == 0) { i = 25; } sb_turn_slope = i; // Free the space. XtFree(str_ptr1); str_ptr1 = XmTextGetString(sb_wait_time_data); i = atoi(str_ptr1); if (i == 0) { i = 5; } sb_turn_time = i; // Free the space. XtFree(str_ptr1); Smart_Beacon_destroy_shell(widget,clientData,callData); } } void Smart_Beacon(Widget w, XtPointer UNUSED(clientData), XtPointer callData) { static Widget pane, scrollwindow, form, label1, label2, label3, label4, label5, label6, button_ok, button_cancel; // static Widget label7; Atom delw; char temp_string[10]; char temp_label_string[100]; // Destroy the dialog if it exists. This is to make sure the // title is correct based on the last dialog that called us. if (smart_beacon_dialog) { Smart_Beacon_destroy_shell( w, smart_beacon_dialog, callData); } if (!smart_beacon_dialog) { smart_beacon_dialog = XtVaCreatePopupShell(langcode("SMARTB001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Smart_Beacon pane", xmPanedWindowWidgetClass, smart_beacon_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Smart_Beacon form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); smart_beacon_enable = XtVaCreateManagedWidget(langcode("SMARTB011"), xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,5, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label1 = XtVaCreateManagedWidget(langcode("SMARTB002"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, smart_beacon_enable, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_hi_rate_data = XtVaCreateManagedWidget("Smart_Beacon hi_rate_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, smart_beacon_enable, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); switch (english_units) { case 0: // Metric xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB004") ); break; case 1: // English case 2: // Nautical default: xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB003") ); break; } // High Speed (mph) / (kph) label2 = XtVaCreateManagedWidget(temp_label_string, xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_hi_mph_data = XtVaCreateManagedWidget("Smart_Beacon hi_mph_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label1, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label3 = XtVaCreateManagedWidget(langcode("SMARTB005"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label2, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_lo_rate_data = XtVaCreateManagedWidget("Smart_Beacon lo_rate_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); switch (english_units) { case 0: // Metric xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB007") ); break; case 1: // English case 2: // Nautical default: xastir_snprintf(temp_label_string, sizeof(temp_label_string), "%s", langcode("SMARTB006") ); break; } // Low Speed (mph) / (kph) label4 = XtVaCreateManagedWidget(temp_label_string, xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label3, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_lo_mph_data = XtVaCreateManagedWidget("Smart_Beacon lo_mph_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label3, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label5 = XtVaCreateManagedWidget(langcode("SMARTB008"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label4, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_min_turn_data = XtVaCreateManagedWidget("Smart_Beacon min_turn_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); label6 = XtVaCreateManagedWidget(langcode("SMARTB009"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_turn_slope_data = XtVaCreateManagedWidget("Smart_Beacon turn_slope_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); //label7 XtVaCreateManagedWidget(langcode("SMARTB010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label6, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sb_wait_time_data = XtVaCreateManagedWidget("Smart_Beacon wait_time_data", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((6*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label6, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sb_wait_time_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Smart_Beacon_change_data, smart_beacon_dialog); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sb_wait_time_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Smart_Beacon_destroy_shell, smart_beacon_dialog); pos_dialog(smart_beacon_dialog); delw = XmInternAtom(XtDisplay(smart_beacon_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(smart_beacon_dialog, delw, Smart_Beacon_destroy_shell, (XtPointer)smart_beacon_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, smart_beacon_dialog); XtPopup(smart_beacon_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(smart_beacon_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(smart_beacon_dialog), XtWindow(smart_beacon_dialog)); } // Fill in the current values if (smart_beacon_dialog != NULL) { if(smart_beaconing) { XmToggleButtonSetState(smart_beacon_enable,TRUE,FALSE); } else { XmToggleButtonSetState(smart_beacon_enable,FALSE,FALSE); } xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_posit_fast); XmTextSetString(sb_hi_rate_data, temp_string); switch (english_units) { case 0: // Metric: Convert from MPH to KPH for display xastir_snprintf(temp_string, sizeof(temp_string), "%d", (int)((sb_high_speed_limit * 1.6094) + 0.5) ); break; case 1: // English case 2: // Nautical default: // No conversion necessary xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_high_speed_limit); break; } XmTextSetString(sb_hi_mph_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_posit_slow); XmTextSetString(sb_lo_rate_data, temp_string); switch (english_units) { case 0: // Metric: Convert from MPH to KPH for display xastir_snprintf(temp_string, sizeof(temp_string), "%d", (int)((sb_low_speed_limit * 1.6094) + 0.5) ); break; case 1: // English case 2: // Nautical default: // No conversion necessary xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_low_speed_limit); break; } XmTextSetString(sb_lo_mph_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_min); XmTextSetString(sb_min_turn_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_slope); XmTextSetString(sb_turn_slope_data, temp_string); xastir_snprintf(temp_string, sizeof(temp_string), "%d", sb_turn_time); XmTextSetString(sb_wait_time_data, temp_string); } } ///////////////////////////////////////////////////////////////////////// // Causes the current set of internet-based maps to be snagged from // the 'net instead of from cache. Once downloaded they get written // to the cache, overwriting possibly corrupted maps already in the // cache (why else would you invoke this function?). This is a // method of getting rid of corrupted maps without having to wipe // out the entire cache. // void Re_Download_Maps_Now(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef USE_MAP_CACHE // Disable reads from the map cache map_cache_fetch_disable = 1; #endif // Show a busy cursor while the map is being downloaded busy_cursor(appshell); // Cause maps to be refreshed new_image(da); #ifdef USE_MAP_CACHE //Enable reads from the map cache map_cache_fetch_disable = 0; #endif } // Removes all files in the ~/.xastir/map_cache directory. Does not // recurse down into subdirectories, but it shouldn't have to. // void Flush_Entire_Map_Queue(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { struct dirent *dl = NULL; DIR *dm; char fullpath[MAX_FILENAME]; char dir[MAX_FILENAME]; struct stat nfile; get_user_base_dir("map_cache", dir, sizeof(dir)); dm = opendir(dir); if (!dm) // Couldn't open directory { fprintf(stderr,"Flush_Entire_Map_Queue: Couldn't open directory\n"); return; } // Read the directory contents, delete each file found, skip // directories. // while ((dl = readdir(dm))) { //Construct the entire path/filename strcpy(fullpath, dir); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string strcat(fullpath, "/"); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string strcat(fullpath, dl->d_name); fullpath[sizeof(fullpath)-1] = '\0'; // Terminate string if (stat(fullpath, &nfile) == 0) { if ((nfile.st_mode & S_IFMT) == S_IFREG) { // It's a regular file // Remove the file if (debug_level & 512) { fprintf(stderr,"Deleting file: %s\n", fullpath); } unlink(fullpath); } } } (void)closedir(dm); } // Find the extents of every map we have. This is the callback for // the "Re-Index Maps" button. // // If passed a NULL in the callback, we do a smart reindexing: Only // reindex the files that are new or have changed. // If passed a "1" in the callback, we do a full reindexing: Delete // the in-memory index and start indexing from scratch. // void Index_Maps_Now(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int parameter = 0; // Default: Smart timestamp-checking indexing if (clientData != NULL) { parameter = atoi((char *)clientData); if (parameter != 1) // Our only option { parameter = 0; } } // Update the list and write it to file. map_indexer(parameter); } void check_weather_symbol(void) { // Check for weather station, if so, make sure symbol is proper type if ( (output_station_type == 4) || (output_station_type == 5) ) { // Need one of these symbols if a weather station: /_ \_ /W \W if ( ( (my_symbol != '_') && (my_symbol != 'W') ) || ( (my_group != '\\') && (my_group != '/') ) ) { // Force it to '/_' my_group = '/'; my_symbol = '_'; // Update my station data with the new symbol my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; // Notify the operator that the symbol has been changed // "Weather Station", "Changed to WX symbol '/_', other option is '\\_'" popup_message_always( langcode("POPEM00030"), langcode("POPEM00031") ); } } } void check_nws_weather_symbol(void) { if ( (my_symbol == 'W') && ( (my_group == '\\') || (my_group == '/') ) ) { // Notify the operator that they're trying to be an NWS // weather station. popup_message_always( langcode("POPEM00030"), langcode("POPEM00032") ); } } void Coordinate_calc_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); coordinate_calc_dialog = (Widget)NULL; } // Clears out the dialog's input textFields void Coordinate_calc_clear_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { XmTextSetString(coordinate_calc_zone, ""); XmTextSetString(coordinate_calc_latitude_easting, ""); XmTextSetString(coordinate_calc_longitude_northing, ""); XmTextSetString(coordinate_calc_result_text, ""); XtSetSensitive(coordinate_calc_button_ok,FALSE); } // Computes all five coordinate representations for displaying in // the "result" textField. Also fills in the global variables for // possible later use when passing results back to the calling // dialog. We can't use the util.c:*_l2s routines for the // conversions here because the util.c routines use Xastir // coordinate system as inputs instead of normal lat/lon. Had to // home-grow our solution here. // // Inputs: full_zone, northing, easting, latitude, longitude. UTM // inputs are output directly. Latitude/longitude are converted to // the various different lat/lon representations. // // Outputs: global variables and "result" textField, full_zone. // full_zone should be a string of at least size 4. // void Coordinate_calc_output(char *full_zone, long northing, long easting, double latitude, double longitude) { char temp_string[1024]; int south = 0; int west = 0; double lat_min,lon_min,lat_sec,lon_sec; int lat_deg_int,lat_min_int; int lon_deg_int,lon_min_int; char maidenhead_grid[50]; long temp; long xastir_lat; long xastir_lon; char MGRS_str[50]; double double_easting, double_northing; // Latitude: Switch to integer arithmetic to avoid // floating-point rounding errors. // We _do_ need to round it first though so that we don't lose // accuracy. xastir_snprintf(temp_string,sizeof(temp_string),"%8.0f",latitude * 100000.0); temp = atol(temp_string); if (temp < 0) { south++; temp = labs(temp); } lat_deg_int = (int)temp / 100000; lat_min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(lat_min * 1000); lat_min_int = (int)(temp / 1000); lat_sec = (temp % 1000) * 60.0 / 1000.0; // Longitude: Switch to integer arithmetic to avoid // floating-point rounding errors. // We _do_ need to round it first though so that we don't lose // accuracy. xastir_snprintf(temp_string,sizeof(temp_string),"%9.0f",longitude * 100000.0); temp = atol(temp_string); if (temp < 0) { west++; temp = labs(temp); } lon_deg_int = (int)temp / 100000; lon_min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(lon_min * 1000); lon_min_int = (int)(temp / 1000); lon_sec = (temp % 1000) * 60.0 / 1000.0; double_easting = (double)easting; double_northing = (double)northing; convert_UTM_to_xastir(double_easting, double_northing, full_zone, &xastir_lon, &xastir_lat); //fprintf(stderr,"%s %f %f\t\t%lu %lu\n", //full_zone, //double_easting, //double_northing, //xastir_lat, //xastir_lon); // Compute MGRS coordinates. convert_xastir_to_MGRS_str(MGRS_str, sizeof(MGRS_str), xastir_lon, xastir_lat, 1); // Format with leading spaces plus spaces between // easting and northing, so that it lines up with UTM // strings. // Compute Maidenhead Grid Locator. Note that the sec_to_loc() // function expects lat/lon in Xastir coordinate system. xastir_snprintf(maidenhead_grid, sizeof(maidenhead_grid), "%s", sec_to_loc( xastir_lon, xastir_lat ) ); if (strlen(full_zone) == 1) { xastir_snprintf(temp_string, sizeof(temp_string), " %s", full_zone); memcpy(full_zone, temp_string, sizeof(&full_zone)); full_zone[sizeof(full_zone)-1] = '\0'; // Terminate string } else if (strlen(full_zone) == 2) { xastir_snprintf(temp_string, sizeof(temp_string), " %s", full_zone); memcpy(full_zone, temp_string, sizeof(&full_zone)); full_zone[sizeof(full_zone)-1] = '\0'; // Terminate string } // Put the four different representations of the coordinate into // the "result" textField. xastir_snprintf(temp_string, sizeof(temp_string), "%s%8.5f%c %9.5f%c\n%s%02d %06.3f%c %03d %06.3f%c\n%s%02d %02d %04.1f%c %03d %02d %04.1f%c\n%s%3s %07lu %07lu\n%s%s\n%s%s", langcode("COORD011"), // "Decimal Degrees:", lat_deg_int+lat_min/60.0, (south) ? 'S':'N', lon_deg_int+lon_min/60.0, (west) ? 'W':'E', langcode("COORD012"), // "Degrees/Decimal Minutes:", lat_deg_int, lat_min, (south) ? 'S':'N', lon_deg_int, lon_min, (west) ? 'W':'E', langcode("COORD013"), // "Degrees/Minutes/Dec. Seconds:", lat_deg_int, lat_min_int, lat_sec, (south) ? 'S':'N', lon_deg_int, lon_min_int, lon_sec, (west) ? 'W':'E', langcode("COORD014"), // "Universal Transverse Mercator:", full_zone, easting, northing, langcode("COORD015"), // "Military Grid Reference System:", MGRS_str, langcode("COORD016"), // "Maidenhead Grid Locator:", maidenhead_grid); XmTextSetString(coordinate_calc_result_text, temp_string); // Fill in the global dd mm.mmm values in case we wish to write // the result back to the calling dialog. // Changing to double to make "%02.0f" formatting work / get rid of compiler warning xastir_snprintf(coordinate_calc_lat_deg, sizeof(coordinate_calc_lat_deg), "%02.0f", (double)lat_deg_int); xastir_snprintf(coordinate_calc_lat_min, sizeof(coordinate_calc_lat_min), "%06.3f", lat_min); xastir_snprintf(coordinate_calc_lat_dir, sizeof(coordinate_calc_lat_dir), "%c", (south) ? 'S':'N'); // Changing to double to make "%03.0f" formatting work / get rid of compiler warning xastir_snprintf(coordinate_calc_lon_deg, sizeof(coordinate_calc_lon_deg), "%03.0f", (double)lon_deg_int); xastir_snprintf(coordinate_calc_lon_min, sizeof(coordinate_calc_lon_min), "%06.3f", lon_min); xastir_snprintf(coordinate_calc_lon_dir, sizeof(coordinate_calc_lon_dir), "%c", (west) ? 'W':'E'); } // Coordinate_calc_compute // // Inputs: coordinate_calc_zone textField // coordinate_calc_latitude_easting textField // coordinate_calc_longitude_northing textField // // Output: coordinate_calc_result_text only if the inputs are not // recognized, then it outputs help text to the textField. If // inputs are good it calls Coordinate_calc_output() to format and // save/output the results. // void Coordinate_calc_compute(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *str_ptr; char zone_letter; int zone_number = 0; char full_zone[5]; int i; int have_utm; int have_lat_lon; long easting = 0; long northing = 0; double double_easting; double double_northing; double latitude; double longitude; char temp_string[1024]; // Goal is to suck in the format provided, figure out what // format it is, then convert to the four major formats we // support and put all four into the output window, each on a // different line. // These are the formats that I'd like to be able to // auto-recognize and support: // ddN dddW IMPLEMENTED // dd N ddd W IMPLEMENTED // -dd -ddd IMPLEMENTED // dd.ddddN ddd.ddddW IMPLEMENTED // dd.dddd N ddd.dddd W IMPLEMENTED // -dd.dddd -ddd.dddd IMPLEMENTED // dd mmN ddd mmW IMPLEMENTED // dd mm N ddd mm W IMPLEMENTED // -dd mm -ddd mm IMPLEMENTED // dd mm.mmmN ddd mm.mmmW IMPLEMENTED // dd mm.mmm N ddd mm.mmm W IMPLEMENTED // -dd mm.mmm -ddd mm.mmm IMPLEMENTED // dd mm ssN ddd mm ssW IMPLEMENTED // dd mm ss N ddd mm ss W IMPLEMENTED // -dd mm ss -ddd mm ss IMPLEMENTED // dd mm ss.sN ddd mm ss.sW IMPLEMENTED // dd mm ss.s N ddd mm ss.s W IMPLEMENTED // -dd mm ss.s -ddd mm ss.s IMPLEMENTED // 10T 0123456 1234567 IMPLEMENTED // 10T 123456 1234567 IMPLEMENTED // 10T 012 3456 123 4567 // 10T 12 3456 123 4567 // Once the four major formats are created and written to the // output test widget, the dd mm.mmmN/ddd mm.mmmW formatted // output should also be saved for later pasting into the // calling dialog's input fields. DONE! // // Must also make sure that the calling dialog is still up and // active before we try to write to it's widgets. DONE! // Check for something in the zone field that looks like a valid // UTM zone. str_ptr = XmTextGetString(coordinate_calc_zone); i = strlen(str_ptr); have_utm = 1; // Wishful thinking. We'll zero it later if not. if ( (i >= 1) && (i <= 3) ) { // String is the correct length. Can have just A/B/Y/Z, or // else one or two digits plus one letter. int j; for (j = 0; j < (i-1); j++) { if ( (str_ptr[j] < '0') && (str_ptr[j] > '9') ) { // Not UTM, need either one or two digits first if // we have 2 or 3 chars. have_utm = 0; } } if ( ( (str_ptr[i-1] < 'A') || (str_ptr[i-1] > 'Z') ) && ( (str_ptr[i-1] < 'a') || (str_ptr[i-1] > 'z') ) ) { // Not UTM, zone character isn't correct have_utm = 0; } } else // Not a valid UTM zone, wrong length. { have_utm = 0; } // If we've made it to this point and have_utm == 1, then zone looks // like a UTM zone. if (have_utm) { zone_letter = toupper(str_ptr[i-1]); zone_number = atoi(str_ptr); //fprintf(stderr,"Zone Number: %d, Zone Letter: %c\n", zone_number, zone_letter); // Save it away for later use if (zone_number == 0) // We're in a UPS area { xastir_snprintf(full_zone, sizeof(full_zone), " %c", zone_letter); } else // UTM area { xastir_snprintf(full_zone, sizeof(full_zone), "%02d%c", zone_number, zone_letter); } have_lat_lon = 0; } else { //fprintf(stderr,"Bad zone, not a UTM coordinate\n"); // Skip zone widget for lat/lon, it's not used. have_lat_lon = 1; // Wishful thinking. We'll zero it later if not. } // We're done with that variable. Free the space. XtFree(str_ptr); str_ptr = XmTextGetString(coordinate_calc_latitude_easting); i = strlen(str_ptr); // Check for exactly six or seven chars. If seven, first one must // be a zero (Not true! UPS coordinates have digits there!). if ( have_utm && (i != 6) && (i != 7) ) { have_utm = 0; //fprintf(stderr,"Bad Easting value: Not 6 or 7 chars\n"); } // if ( have_utm && (i == 7) && (str_ptr[0] != '0') ) { // have_utm = 0; // //fprintf(stderr,"Bad Easting value: 7 chars but first one not 0\n"); // } if (have_utm) { int j; // Might be good to get rid of spaces at this point as we think // it's a UTM number. Might have to put it in our own string // first though to do that. for (j = 0; j < i; j++) { if ( (str_ptr[j] < '0') || (str_ptr[j] > '9') ) { // Not UTM, found a non-number have_utm = 0; } } if (have_utm) // If we still think it's a valid UTM number { easting = atol(str_ptr); //fprintf(stderr,"Easting: %lu\n",easting); } else { //fprintf(stderr,"Bad Easting value\n"); } } else if (have_lat_lon) { // Process the string to see if it's a valid latitude value. // Convert it into a double if so and store it in // "latitude". int j, substring; int south = 0; int temp[10]; // indexes to substrings char *ptr; char temp_string[30]; int piece; // Copy the string so we can change it. xastir_snprintf(temp_string,sizeof(temp_string),"%s",str_ptr); for (j = 0; j < i; j++) { temp_string[j] = toupper(temp_string[j]); } // Search for 'N' or 'S'. ptr = rindex(temp_string, 'N'); if (ptr != NULL) // Found an 'N' { *ptr = ' '; // Convert it to a space //fprintf(stderr,"Found an 'N', converted to %s\n", temp_string); } ptr = rindex(temp_string, 'S'); if (ptr != NULL) // Found an 'S' { *ptr = ' '; // Convert it to a space south++; //fprintf(stderr,"Found an 'S', converted to %s\n", temp_string); } ptr = rindex(temp_string, '-'); if (ptr != NULL) // Found an '-' { *ptr = ' '; // Convert it to a space south++; //fprintf(stderr,"Found an '-', converted to %s\n", temp_string); } // Tokenize the string // Find the space characters temp[0] = 0; // First index is to start of entire string substring = 1; for (j = 1; j < i; j++) { if (temp_string[j] == ' ') // Found a space { temp_string[j] = '\0'; // Terminate the substring if ( (j + 1) < i) // If not at the end { temp[substring++] = j + 1; // Save an index to the new substring //fprintf(stderr,"%s",&temp_string[j+1]); } } } // temp[] array now contains indexes into all of the // substrings. Some may contain empty strings. //fprintf(stderr,"Substrings: %d\n", substring); //fprintf(stderr,"temp_string: %s\n",temp_string); //for (j = 0; j < substring; j++) { // if (strlen(&temp_string[temp[j]]) > 0) { // fprintf(stderr,"%s\n", &temp_string[temp[j]]); // } //} piece = 0; have_lat_lon = 0; for (j = 0; j < substring; j++) { if (strlen(&temp_string[temp[j]]) > 0) { double kk; piece++; // Found the next piece kk = atof(&temp_string[temp[j]]); switch (piece) { case (1) : // Degrees latitude = kk; have_lat_lon = 1; break; case (2) : // Minutes if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad latitude minutes value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { latitude = latitude + ( kk / 60.0 ); } break; case (3) : // Seconds if ( (kk < 0.0) || (kk >= 60.0)) { fprintf(stderr,"Warning: Bad latitude seconds value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { latitude = latitude + ( kk / 3600.0 ); } break; default : break; } } } if (south) { latitude = -latitude; } //fprintf(stderr,"%f\n", latitude); // Test for valid values of latitude if ( have_lat_lon && ((latitude < -90.0) || (latitude > 90.0)) ) { have_lat_lon = 0; } if (strlen(str_ptr) == 0) { have_lat_lon = 0; } } // We're done with that variable. Free the space. XtFree(str_ptr); str_ptr = XmTextGetString(coordinate_calc_longitude_northing); i = strlen(str_ptr); // Check for exactly seven chars. if (have_utm && (i != 7) ) { have_utm = 0; //fprintf(stderr,"Bad Northing value: Not 7 chars\n"); } if (have_utm) { int j; // Might be good to get rid of spaces at this point as we think // it's a UTM number. Might have to put it in our own string // first though to do that. for (j = 0; j< i; j++) { if ( (str_ptr[j] < '0') || (str_ptr[j] > '9') ) { // Not UTM, found a non-number have_utm = 0; } } if (have_utm) // If we still think it's a valid UTM number { northing = atol(str_ptr); //fprintf(stderr,"Northing: %lu\n",northing); } else { //fprintf(stderr,"Bad Northing value\n"); } } else if (have_lat_lon) { // Process the string to see if it's a valid longitude // value. Convert it into a double if so and store it in // "longitude". int j, substring; int west = 0; int temp[10]; // indexes to substrings char *ptr; char temp_string[30]; int piece; // Copy the string so we can change it. xastir_snprintf(temp_string,sizeof(temp_string),"%s",str_ptr); for (j = 0; j < i; j++) { temp_string[j] = toupper(temp_string[j]); } // Search for 'W' or 'E'. ptr = rindex(temp_string, 'W'); if (ptr != NULL) // Found an 'W' { *ptr = ' '; // Convert it to a space west++; //fprintf(stderr,"Found an 'W', converted to %s\n", temp_string); } ptr = rindex(temp_string, 'E'); if (ptr != NULL) // Found an 'E' { *ptr = ' '; // Convert it to a space //fprintf(stderr,"Found an 'E', converted to %s\n", temp_string); } ptr = index(temp_string, '-'); if (ptr != NULL) // Found an '-' { *ptr = ' '; // Convert it to a space west++; //fprintf(stderr,"Found an '-', converted to %s\n", temp_string); } // Tokenize the string // Find the space characters temp[0] = 0; // First index is to start of entire string substring = 1; for (j = 1; j < i; j++) { if (temp_string[j] == ' ') // Found a space { temp_string[j] = '\0'; // Terminate the substring if ( (j + 1) < i) // If not at the end { temp[substring++] = j + 1; // Save an index to the new substring //fprintf(stderr,"%s",&temp_string[j+1]); } } } // temp[] array now contains indexes into all of the // substrings. Some may contain empty strings. //fprintf(stderr,"Substrings: %d\n", substring); //fprintf(stderr,"temp_string: %s\n",temp_string); //for (j = 0; j < substring; j++) { // if (strlen(&temp_string[temp[j]]) > 0) { // fprintf(stderr,"%s\n", &temp_string[temp[j]]); // } //} piece = 0; have_lat_lon = 0; for (j = 0; j < substring; j++) { if (strlen(&temp_string[temp[j]]) > 0) { double kk; piece++; // Found the next piece kk = atof(&temp_string[temp[j]]); switch (piece) { case (1) : // Degrees longitude = kk; have_lat_lon = 1; break; case (2) : // Minutes if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad longitude minutes value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { longitude = longitude + ( kk / 60.0 ); } break; case (3) : // Seconds if ( (kk < 0.0) || (kk >= 60.0) ) { fprintf(stderr,"Warning: Bad longitude seconds value\n"); // Set variables so that we'll get error output. have_lat_lon = 0; have_utm = 0; } else { longitude = longitude + ( kk / 3600.0 ); } break; default : break; } } } if (west) { longitude = -longitude; } //fprintf(stderr,"%f\n", longitude); // Test for valid values of longitude if (have_lat_lon && ((longitude < -180.0) || (longitude > 180.0)) ) { have_lat_lon = 0; } if (strlen(str_ptr) == 0) { have_lat_lon = 0; } } // We're done with that variable. Free the space. XtFree(str_ptr); // If we get to this point and have_utm == 1, then we're fairly sure // we have a good value and can convert it to the other formats for // display. if (have_utm) { //fprintf(stderr,"Processing 'good' UTM values\n"); // Process UTM values utm_ups_to_ll(E_WGS_84, (double)northing, (double)easting, full_zone, &latitude, &longitude); if (debug_level & 1) { fprintf(stderr,"Latitude: %f, Longitude: %f\n",latitude,longitude); } Coordinate_calc_output(full_zone, northing, easting, latitude, longitude); XtSetSensitive(coordinate_calc_button_ok,TRUE); } else if (have_lat_lon) { // Process lat/lon values double_northing = (double)northing; double_easting = (double)easting; ll_to_utm_ups(E_WGS_84, (double)latitude, (double)longitude, &double_northing, &double_easting, full_zone, sizeof(full_zone)); if (debug_level & 1) { fprintf(stderr,"Zone: %s, Easting: %f, Northing: %f\n", full_zone, double_easting, double_northing); } // Round the UTM values as we convert them to longs xastir_snprintf(temp_string,sizeof(temp_string),"%7.0f",double_northing); northing = atof(temp_string); xastir_snprintf(temp_string,sizeof(temp_string),"%7.0f",double_easting); easting = atof(temp_string); Coordinate_calc_output(full_zone, (long)northing, (long)easting, latitude, longitude); XtSetSensitive(coordinate_calc_button_ok,TRUE); } else // Dump out some helpful text { xastir_snprintf(temp_string, sizeof(temp_string), "%s\n%s\n%s\n%s", // " ** Sorry, your input was not recognized! **", langcode("COORD017"), // " ** Please use one of the following input formats: **", langcode("COORD018"), " ** 47.99999N 121.99999W, 47 59.999N 121 59.999W **", " ** 10T 0574599 5316887, 47 59 59.9N 121 59 59.9W **"); XmTextSetString(coordinate_calc_result_text, temp_string); XtSetSensitive(coordinate_calc_button_ok,FALSE); } } // Input: Values from the coordinate_calc_array struct. // // Output: Writes data back to the calling dialog's input fields if // the calling dialog still exists at this point. // // Make sure that if an error occurs during computation we don't // write a bad value back to the calling widget. DONE. // void Coordinate_calc_change_data(Widget widget, XtPointer clientData, XtPointer callData) { // Write output directly to the XmTextStrings pointed to by our array if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_deg != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_deg, coordinate_calc_lat_deg); } //fprintf(stderr,"%s\n",coordinate_calc_lat_deg); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_min != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_min, coordinate_calc_lat_min); } //fprintf(stderr,"%s\n",coordinate_calc_lat_min); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_dir != NULL) ) { XmTextSetString(coordinate_calc_array.input_lat_dir, coordinate_calc_lat_dir); } //fprintf(stderr,"%s\n",coordinate_calc_lat_dir); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_deg != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_deg, coordinate_calc_lon_deg); } //fprintf(stderr,"%s\n",coordinate_calc_lon_deg); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_min != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_min, coordinate_calc_lon_min); } //fprintf(stderr,"%s\n",coordinate_calc_lon_min); if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_dir != NULL) ) { XmTextSetString(coordinate_calc_array.input_lon_dir, coordinate_calc_lon_dir); } //fprintf(stderr,"%s\n",coordinate_calc_lon_dir); Coordinate_calc_destroy_shell(widget,clientData,callData); } // Coordinate Calculator // // Change the title based on what dialog is calling us? // // We want all four possible coordinate formats displayed // simultaneously. DONE. // // Hitting enter or "Calculate" will cause all of the fields to be // updated. DONE (for Calculate button). // // The fields should be filled in when this is first called. // When done, this routine will pass back values via a static array // of Widget pointers to the calling dialog's fields. DONE. // // We could grey-out the OK button until we have a successful // calculation, and when the "Clear" button is pressed. This // would make sure that an invalid location doesn't // get written to the calling dialog. Would have to have a // successful conversion before we could write the value back. // void Coordinate_calc(Widget w, XtPointer clientData, XtPointer callData) { static Widget pane, scrollwindow, form, label1, label4, button_clear, button_calculate, button_cancel; // static Widget label2, label3, label5, label6; Atom delw; Arg args[50]; // Arg List register unsigned int n = 0; // Arg Count char temp_string[50]; // Destroy the dialog if it exists. This is to make sure the // title is correct based on the last dialog that called us. if (coordinate_calc_dialog) { Coordinate_calc_destroy_shell( w, coordinate_calc_dialog, callData); } if (!coordinate_calc_dialog) { // We change the title based on who's calling us. // clientData supplies the string we use for the label, and // is sent to us by the calling dialog. xastir_snprintf( temp_string, sizeof(temp_string), "%s %s", (char *)clientData, langcode("COORD001") ); coordinate_calc_dialog = XtVaCreatePopupShell(temp_string, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Coordinate_calc pane", xmPanedWindowWidgetClass, coordinate_calc_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Coordinate_calc form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 4, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); label1 = XtVaCreateManagedWidget(langcode("COORD005"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label2 XtVaCreateManagedWidget(langcode("COORD006"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 70, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label3 XtVaCreateManagedWidget(langcode("COORD007"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 200, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label4 = XtVaCreateManagedWidget(langcode("COORD008"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label5 XtVaCreateManagedWidget(langcode("COORD009"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 70, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //label6 XtVaCreateManagedWidget(langcode("COORD010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 200, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ n=0; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; coordinate_calc_zone = XtVaCreateManagedWidget("Coordinate_calc zone", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((5*7)+2), XmNmaxLength, 3, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); coordinate_calc_latitude_easting = XtVaCreateManagedWidget("Coordinate_calc lat", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 13, XmNwidth, ((13*7)+2), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 65, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); coordinate_calc_longitude_northing = XtVaCreateManagedWidget("Coordinate_calc lon", xmTextWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 13, XmNwidth, ((14*7)+2), XmNmaxLength, 13, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, label4, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 195, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // xastir_snprintf(temp_string, sizeof(temp_string), "%d", temp); // XmTextSetString(coordinate_calc_text, temp_string); coordinate_calc_result_text = NULL; coordinate_calc_result_text = XtVaCreateManagedWidget("Coordinate_calc results", xmTextWidgetClass, form, XmNrows, 6, XmNcolumns, 58, XmNeditable, FALSE, XmNtraversalOn, FALSE, XmNeditMode, XmMULTI_LINE_EDIT, XmNwordWrap, TRUE, // XmNscrollHorizontal, FALSE, XmNcursorPositionVisible, FALSE, XmNautoShowCursorPosition, True, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_zone, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_clear = XtVaCreateManagedWidget(langcode("COORD004"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_clear, XmNactivateCallback, Coordinate_calc_clear_data, coordinate_calc_dialog); button_calculate = XtVaCreateManagedWidget(langcode("COORD003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_calculate, XmNactivateCallback, Coordinate_calc_compute, coordinate_calc_dialog); coordinate_calc_button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coordinate_calc_button_ok, XmNactivateCallback, Coordinate_calc_change_data, coordinate_calc_dialog); XtSetSensitive(coordinate_calc_button_ok,FALSE); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, coordinate_calc_result_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Coordinate_calc_destroy_shell, coordinate_calc_dialog); pos_dialog(coordinate_calc_dialog); delw = XmInternAtom(XtDisplay(coordinate_calc_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(coordinate_calc_dialog, delw, Coordinate_calc_destroy_shell, (XtPointer)coordinate_calc_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, coordinate_calc_dialog); XtPopup(coordinate_calc_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(coordinate_calc_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(coordinate_calc_dialog), XtWindow(coordinate_calc_dialog)); } // Fill in the latitude values if they're available if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lat_deg != NULL) && (coordinate_calc_array.input_lat_min != NULL) && (coordinate_calc_array.input_lat_dir != NULL) ) { char *str_ptr1; char *str_ptr2; char *str_ptr3; str_ptr1 = XmTextGetString(coordinate_calc_array.input_lat_deg); str_ptr2 = XmTextGetString(coordinate_calc_array.input_lat_min); str_ptr3 = XmTextGetString(coordinate_calc_array.input_lat_dir); xastir_snprintf(temp_string, sizeof(temp_string), "%s %s%s", str_ptr1, str_ptr2, str_ptr3); XmTextSetString(coordinate_calc_latitude_easting, temp_string); //fprintf(stderr,"String: %s\n", temp_string); // We're done with these variables. Free the space. XtFree(str_ptr1); XtFree(str_ptr2); XtFree(str_ptr3); } // Fill in the longitude values if they're available if ( (coordinate_calc_array.calling_dialog != NULL) && (coordinate_calc_array.input_lon_deg != NULL) && (coordinate_calc_array.input_lon_min != NULL) && (coordinate_calc_array.input_lon_dir != NULL) ) { char *str_ptr1; char *str_ptr2; char *str_ptr3; str_ptr1 = XmTextGetString(coordinate_calc_array.input_lon_deg); str_ptr2 = XmTextGetString(coordinate_calc_array.input_lon_min); str_ptr3 = XmTextGetString(coordinate_calc_array.input_lon_dir); xastir_snprintf(temp_string, sizeof(temp_string), "%s %s%s", str_ptr1, str_ptr2, str_ptr3); XmTextSetString(coordinate_calc_longitude_northing, temp_string); //fprintf(stderr,"String: %s\n", temp_string); // We're done with these variables. Free the space. XtFree(str_ptr1); XtFree(str_ptr2); XtFree(str_ptr3); } } //////////////////////////////////////////////////////////////////////////////////////////////////// void HandlePendingEvents( XtAppContext app) { XEvent event; while(XtAppPending(app)) { XtAppNextEvent(app,&event); (void)XtDispatchEvent(&event); } } Boolean unbusy_cursor(XtPointer clientdata) { Widget w = (Widget)clientdata; (void)XUndefineCursor(XtDisplay(w),XtWindow(w)); return((Boolean)TRUE); } static Cursor cs = (Cursor)NULL; void busy_cursor(Widget w) { if(!cs) { cs=XCreateFontCursor(XtDisplay(w),XC_watch); } (void)XDefineCursor(XtDisplay(w),XtWindow(w),cs); (void)XFlush(XtDisplay(w)); // This X11 function gets invoked when X11 decides that it has // some free time. We use that to advantage in making the busy // cursor go away "magically" when we're not so busy. // (void)XtAppAddWorkProc(XtWidgetToApplicationContext(w),unbusy_cursor,(XtPointer)w); } // This function: // Draws the map data into "pixmap", copies "pixmap" to // "pixmap_alerts", draws alerts into "pixmap_alerts", copies // "pixmap_alerts" to "pixmap_final", draws symbols/tracks into // "pixmap_final" via a call to display_file(). // // Other functions which call this function are responsible for // copying the image from pixmap_final() to the screen's drawing // area. // // We check for interrupt_drawing_now flag being set, and exit // nicely if so. That flag means that some other drawing operation // needs to happen. // // Returns 0 if it gets interrupted, 1 if it completes. // int create_image(Widget w) { Dimension width, height, margin_width, margin_height; long lat_offset_temp; long long_offset_temp; char temp_course[20]; unsigned char unit_type; char medium_dashed[2] = {(char)5,(char)5}; long pos1_lat, pos1_lon, pos2_lat, pos2_lon; //busy_cursor(w); busy_cursor(appshell); if (debug_level & 4) { fprintf(stderr,"Create image start\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); screen_width = (long)width; screen_height = (long)height; long_offset_temp = NW_corner_longitude = center_longitude - (screen_width * scale_x / 2); // NW corner lat_offset_temp = NW_corner_latitude = center_latitude - (screen_height * scale_y / 2); SE_corner_longitude = center_longitude + (screen_width * scale_x / 2); SE_corner_latitude = center_latitude + (screen_height * scale_y / 2); // Set up floating point lat/long values to match Xastir // coordinates. convert_from_xastir_coordinates(&f_NW_corner_longitude, &f_NW_corner_latitude, NW_corner_longitude, NW_corner_latitude); convert_from_xastir_coordinates(&f_SE_corner_longitude, &f_SE_corner_latitude, SE_corner_longitude, SE_corner_latitude); /* map default background color */ switch (map_background_color) { case 0 : colors[0xfd] = GetPixelByName(appshell,"gray73"); break; case 1 : colors[0xfd] = GetPixelByName(w,"MistyRose"); break; case 2 : colors[0xfd] = GetPixelByName(w,"NavyBlue"); break; case 3 : colors[0xfd] = GetPixelByName(w,"SteelBlue"); break; case 4 : colors[0xfd] = GetPixelByName(w,"MediumSeaGreen"); break; case 5 : colors[0xfd] = GetPixelByName(w,"PaleGreen"); break; case 6 : colors[0xfd] = GetPixelByName(w,"PaleGoldenrod"); break; case 7 : colors[0xfd] = GetPixelByName(w,"LightGoldenrodYellow"); break; case 8 : colors[0xfd] = GetPixelByName(w,"RosyBrown"); break; case 9 : colors[0xfd] = GetPixelByName(w,"firebrick"); break; case 10 : colors[0xfd] = GetPixelByName(w,"white"); break; case 11 : colors[0xfd] = GetPixelByName(w, "black"); break; default: colors[0xfd] = GetPixelByName(appshell,"gray73"); map_background_color=0; break; } HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } (void)XSetForeground(XtDisplay(w),gc,colors[0xfd]); (void)XSetBackground(XtDisplay(w),gc,colors[0xfd]); (void)XFillRectangle(XtDisplay(w), pixmap, gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } statusline(langcode("BBARSTA003"),1); // Loading Maps HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } if (display_up_first != 0) { // clear the OSM function keys. If an OSM // map is selected they will get re-initialized when // the map is loaded. init_OSM_values(); if (map_auto_maps && !disable_all_maps) { load_auto_maps(w,AUTO_MAP_DIR); } else if (!disable_all_maps) { load_maps(w); } } if (!wx_alert_style) { statusline(langcode("BBARSTA034"),1); } // Update to screen // (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* copy map data to alert pixmap */ (void)XCopyArea(XtDisplay(w),pixmap,pixmap_alerts,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } if (!wx_alert_style && !disable_all_maps) { load_alert_maps(w, ALERT_MAP_DIR); // These write onto pixmap_alerts } // Update to screen // (void)XCopyArea(XtDisplay(da),pixmap_alerts,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } /* copy map and alert data to final pixmap */ (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } wx_alert_update_list(); /* Compute distance */ if (lat_offset_temp<0l) { lat_offset_temp=0l; // max 90°N } else if (lat_offset_temp>64800000l) { lat_offset_temp=64800000l; // max 90°S } if(long_offset_temp<0l) { long_offset_temp=0l; // max 180°W } else if (long_offset_temp>129600000l) { long_offset_temp=129600000l; // max 180°E } pos1_lat = lat_offset_temp; pos1_lon = long_offset_temp; pos2_lat = lat_offset_temp; // ?? pos2_lon = long_offset_temp+(50.0*scale_x); // long_offset_temp = long_offset_temp+(50*scale_x); // ?? if(pos2_lat < 0l) // ?? { pos2_lat = 0l; } else if (pos2_lat > 64799999l) { pos2_lat = 64799999l; } if (pos2_lon < 0l) { pos2_lon = 0l; } else if (pos2_lon > 129599999l) { pos2_lon = 129599999l; } // Get distance in nautical miles x_screen_distance = (float)calc_distance_course(pos1_lat, pos1_lon, pos2_lat, pos2_lon, temp_course, sizeof(temp_course) ); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } draw_grid(w); // Draw grid if enabled HandlePendingEvents(app_context); if (interrupt_drawing_now) { return(0); } display_file(w); // display stations (symbols, info, trails) last_alert_redraw=sec_now(); // set last time of screen redraw if (debug_level & 4) { fprintf(stderr,"Create image stop\n"); } return(1); } // Routine used to refresh image WITHOUT reading regular map files // from disk. It starts with the map data already in "pixmap", // copies "pixmap" to "pixmap_alerts", draws alerts into // "pixmap_alerts", copies "pixmap_alerts" to "pixmap_final", draws // symbols/tracks into "pixmap_final" via a call to display_file(). // // Other functions which call this function are responsible for // copying the image from pixmap_final() to the screen's drawing // area. // void refresh_image(Widget w) { Dimension width, height, margin_width, margin_height; long lat_offset_temp; long long_offset_temp; char temp_course[20]; unsigned char unit_type; char medium_dashed[2] = {(char)5,(char)5}; long pos1_lat, pos1_lon, pos2_lat, pos2_lon; //busy_cursor(w); busy_cursor(appshell); if (debug_level & 4) { fprintf(stderr,"Refresh image start\n"); } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XSetDashes(XtDisplay(w), gc, 0, medium_dashed, 2); screen_width = (long)width; screen_height = (long)height; long_offset_temp = NW_corner_longitude = center_longitude - (screen_width * scale_x / 2); NW_corner_latitude = center_latitude - (screen_height * scale_y / 2); lat_offset_temp = center_latitude; SE_corner_longitude = center_longitude + (screen_width * scale_x / 2); SE_corner_latitude = center_latitude + (screen_height * scale_y / 2); // Set up floating point lat/long values to match Xastir // coordinates. convert_from_xastir_coordinates(&f_NW_corner_longitude, &f_NW_corner_latitude, NW_corner_longitude, NW_corner_latitude); convert_from_xastir_coordinates(&f_SE_corner_longitude, &f_SE_corner_latitude, SE_corner_longitude, SE_corner_latitude); (void)XSetForeground(XtDisplay(w),gc,colors[0xfd]); (void)XSetBackground(XtDisplay(w),gc,colors[0xfd]); /* copy over map data to alert pixmap */ (void)XCopyArea(XtDisplay(w),pixmap,pixmap_alerts,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); if (!wx_alert_style && !disable_all_maps) { statusline(langcode("BBARSTA034"),1); load_alert_maps(w, ALERT_MAP_DIR); // These write onto pixmap_alerts } /* copy over map and alert data to final pixmap */ (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // statusline("Weather Alert Maps Loaded",1); wx_alert_update_list(); /* Compute distance */ if (lat_offset_temp<0l) { lat_offset_temp=0l; // max 90°N } else if (lat_offset_temp>64800000l) { lat_offset_temp=64800000l; // max 90°S } if(long_offset_temp<0l) { long_offset_temp=0l; // max 180°W } else if (long_offset_temp>129600000l) { long_offset_temp=129600000l; // max 180°E } pos1_lat = lat_offset_temp; pos1_lon = long_offset_temp; pos2_lat = lat_offset_temp; // ?? pos2_lon = long_offset_temp+(50.0*scale_x); // long_offset_temp = long_offset_temp+(50*scale_x); // ?? if(pos2_lat < 0l) // ?? { pos2_lat = 0l; } else if (pos2_lat > 64799999l) { pos2_lat = 64799999l; } if (pos2_lon < 0l) { pos2_lon = 0l; } else if (pos2_lon > 129599999l) { pos2_lon = 129599999l; } // Get distance in nautical miles x_screen_distance = (float)calc_distance_course(pos1_lat, pos1_lon, pos2_lat, pos2_lon, temp_course, sizeof(temp_course) ); // Draw grid if enabled draw_grid(w); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } /* display icons */ display_file(w); /* set last time of screen redraw*/ last_alert_redraw=sec_now(); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; if (debug_level & 4) { fprintf(stderr,"Refresh image stop\n"); } } // And this function is even faster yet. It snags "pixmap_alerts", // which already has map and alert data drawn into it, copies it to // pixmap_final, then draws symbols and tracks on top of it. When // done it copies the image to the drawing area, making it visible. void redraw_symbols(Widget w) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // If we're in the middle of ID'ing, wait a bit. if (ATV_screen_ID && pending_ID_message) { usleep(2000000); // 2 seconds } /* copy over map and alert data to final pixmap */ if(!wait_to_redraw) { (void)XCopyArea(XtDisplay(w),pixmap_alerts,pixmap_final,gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); draw_grid(w); // draw grid if enabled HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } display_file(w); // display stations (symbols, info, trails) (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); } else { fprintf(stderr,"wait_to_redraw\n"); } // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; } static void TrackMouse( Widget UNUSED(w), XtPointer clientData, XEvent *event, Boolean * UNUSED(flag) ) { char my_text[70]; char str_lat[20]; char str_long[20]; long x, y; //beg char temp_my_distance[20]; char temp_my_course[20]; char temp1_my_course[20]; long ml_lat, ml_lon; float value; //end Widget textarea = (Widget) clientData; x = (center_longitude - ((screen_width * scale_x)/2) + (event->xmotion.x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (event->xmotion.y * scale_y)); if (x < 0) // x = 0l; // 180°W { return; } if (x > 129600000l) // x = 129600000l; // 180°E { return; } if (y < 0) // y = 0l; // 90°N { return; } if (y > 64800000l) // y = 64800000l; // 90°S { return; } if (DISPLAY_XASTIR_COORDINATES) { xastir_snprintf(my_text, sizeof(my_text), "%ld %ld", y, x); } else if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL) { // Create a UTM string from coordinate in Xastir coordinate // system. convert_xastir_to_UTM_str(my_text, sizeof(my_text), x, y); } else if (coordinate_system == USE_MGRS) { // Create an MGRS string from coordinate in Xastir // coordinate system. convert_xastir_to_MGRS_str(my_text, sizeof(my_text), x, y, 0); } else { // Create a lat/lon string from coordinate in Xastir // coordinate system. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DEC_DEG); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DMS_NORMAL_FORMATED); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DMS_NORMAL_FORMATED); //str_lat[2]='\xB0'; str_long[3]='\xB0'; //str_lat[5]='\''; str_long[6]='\''; } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_HP_NORMAL_FORMATED); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_HP_NORMAL_FORMATED); //str_lat[2]='\xB0'; str_long[3]='\xB0'; } xastir_snprintf(my_text, sizeof(my_text), "%s %s", str_lat, str_long); } strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, sec_to_loc(x,y), sizeof(my_text) - 1 - strlen(my_text)); // begin dist/bearing if ( do_dbstatus ) { ml_lat = convert_lat_s2l(my_lat); ml_lon = convert_lon_s2l(my_long); // Get distance in nautical miles. value = (float)calc_distance_course(ml_lat,ml_lon,y,x, temp1_my_course,sizeof(temp1_my_course)); // n7tap: This is a quick hack to get some more useful values for // distance to near objects. // (copied from db.c:station_data_fill_in) if (english_units) { if (value*1.15078 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.15078*1760), langcode("SPCHSTR004")); // yards } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI020"), // miles value*1.15078); } } else { if (value*1.852 < 0.99) { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), "%d %s", (int)(value*1.852*1000), langcode("UNIOP00031")); // 'm' as in meters } else { xastir_snprintf(temp_my_distance, sizeof(temp_my_distance), langcode("WPUPSTI021"), // km value*1.852); } } strcpy(temp_my_course, temp1_my_course); temp_my_course[sizeof(temp_my_course)-1] = '\0'; // Terminate string strcat(temp_my_course, "\xB0"); temp_my_course[sizeof(temp_my_course)-1] = '\0'; // Terminate string strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, temp_my_distance, sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, " ", sizeof(my_text) - 1 - strlen(my_text)); strncat(my_text, temp_my_course, sizeof(my_text) - 1 - strlen(my_text)); } XmTextFieldSetString(textarea, my_text); XtManageChild(textarea); } static void ClearTrackMouse( Widget UNUSED(w), XtPointer UNUSED(clientData), XEvent * UNUSED(event), Boolean * UNUSED(flag) ) { // N7TAP: In my opinion, it is handy to have the cursor position still displayed // in the xastir window when I switch to another (like to write it down...) // Widget textarea = (Widget) clientData; // XmTextFieldSetString(textarea," "); // XtManageChild(textarea); } /* * Delete tracks of all stations */ void Tracks_All_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { DataRow *p_station; p_station = n_first; while (p_station != 0) { if (delete_trail(p_station)) { redraw_on_new_data=2; } p_station = p_station->n_next; } } // Get a pointer to the first station record. Loop through all // station records and clear out the tactical_call_sign fields in // each. // void clear_all_tactical(void) { DataRow *p_station = n_first; // Run through the name-ordered list of records while (p_station != 0) { if (p_station->tactical_call_sign) { // One found. Free it. free(p_station->tactical_call_sign); p_station->tactical_call_sign = NULL; } p_station = p_station->n_next; } fprintf(stderr,"Cleared all tactical calls\n"); } /* * Clear all tactical callsigns from the station records. Comment * out the active records in the log file. */ void Tactical_Callsign_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char file[200]; char file_temp[200]; FILE *f; FILE *f_temp; char line[300]; int ret; // Loop through all station records and clear out the // tactical_call_sign fields in each. clear_all_tactical(); // Get rid of the tactical callsign hash here destroy_tactical_hash(); get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); get_user_base_dir("config/tactical_calls-temp.log", file_temp, sizeof(file_temp)); // Our own internal function from util.c ret = copy_file(file, file_temp); if (ret) { fprintf(stderr,"\n\nCouldn't create temp file %s!\n\n\n", file_temp); return; } // Comment out all active lines in the log file via a '#' mark. // Read one line at a time from the temp file. Add a '#' // mark to the line if it doesn't already have it, then write // that line to the original file. f_temp=fopen(file_temp,"r"); f=fopen(file,"w"); if (f == NULL) { fprintf(stderr,"Couldn't open %s\n",file); return; } if (f_temp == NULL) { fprintf(stderr,"Couldn't open %s\n",file_temp); return; } // Read lines from the temp file and write them to the standard // file, modifying them as necessary. while (fgets(line, 300, f_temp) != NULL) { if (line[0] != '#') { fprintf(f,"#%s",line); } else { fprintf(f,"%s",line); } } fclose(f); fclose(f_temp); } /* * Clear out tactical callsign log file */ void Tactical_Callsign_History_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char file[MAX_VALUE]; FILE *f; // Loop through all station records and clear out the // tactical_call_sign fields in each. clear_all_tactical(); // Get rid of the tactical callsign hash here destroy_tactical_hash(); // Wipe out the log file. get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"w"); if (f!=NULL) { (void)fclose(f); if (debug_level & 1) { fprintf(stderr,"Clearing tactical callsign file...\n"); } } else { fprintf(stderr,"Couldn't open file for writing: %s\n", file); } fprintf(stderr,"Cleared tactical call history file\n"); } /* * Display text in the status line, text is removed after timeout */ void statusline(char *status_text,int UNUSED(update) ) { XmTextFieldSetString (text, status_text); last_statusline = sec_now(); // Used for auto-ID timeout // if (update != 0) // XmUpdateDisplay(text); // do an immediate update } /* print a message on standard error and display the same message * on the status line of the user interface. */ void stderr_and_statusline(char *message) { fprintf(stderr,"%s",message); if (message[strlen(message)-1]=='\n') { // if there is a terminal new line character remove it. message[strlen(message)-1]='\0'; } statusline(message,1); XmUpdateDisplay(text); // force an immediate update } // // Check for statusline timeout and replace statusline text with a // station identification message. // // ID was requested so that Xastir could be used for a live fast-scan // TV display over amateur radio without having to identify the // station in some other manner. As long as we guarantee that we'll // see this line for a few seconds each 10 minutes (30 minutes for // Canada), we should be within the ID rules. // void check_statusline_timeout(int curr_sec) { char status_text[100]; int id_interval = (int)(9.5 * 60); // int id_interval = (int)(1 * 5); // Debug if ( (last_statusline != 0 && (last_statusline < curr_sec - STATUSLINE_ACTIVE)) || (last_id_time < curr_sec - id_interval) ) { // We save last_id_time and identify for a few seconds if // we haven't identified for the last nine minutes or so. xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA040"), my_callsign); XmTextFieldSetString(text, status_text); if (last_id_time < curr_sec - id_interval) { popup_ID_message(langcode("BBARSTA040"),status_text); #ifdef HAVE_FESTIVAL if (festival_speak_ID) { char my_speech_callsign[100]; xastir_snprintf(my_speech_callsign, sizeof(my_speech_callsign), "%s", my_callsign); spell_it_out(my_speech_callsign, 100); xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA040"), my_speech_callsign); SayText(status_text); } #endif // HAVE_FESTIVAL } last_statusline = 0; // now inactive // Guarantee that the ID text will be viewable for a few // seconds if we haven't identified recently. Note that the // sleep statement puts the entire main thread to sleep for // that amount of time. The application will be unresponsive // during that time. if (last_id_time < (curr_sec - (9 * 60))) { //fprintf(stderr,"Identifying at nine minutes\n"); //sleep(1); } last_id_time = curr_sec; } } /* * Display current zoom factor * * DK7IN: we should find a new measure, we now have different x/y scaling! * I now only use the y value */ void display_zoom_status(void) { char zoom[30]; char siz_str[6]; if (scale_y < 9000) { xastir_snprintf(siz_str, sizeof(siz_str), "%5.0f", (float)scale_y); } else { char temp_scale[20]; xastir_snprintf(temp_scale, sizeof(temp_scale), "%ldk", scale_y/1024); memcpy(siz_str, temp_scale, sizeof(siz_str)); siz_str[sizeof(siz_str)-1] = '\0'; // Terminate string } if (track_station_on == 1) { xastir_snprintf(zoom, sizeof(zoom), langcode("BBARZM0002"), siz_str); } else { xastir_snprintf(zoom, sizeof(zoom), langcode("BBARZM0001"), siz_str); \ } XmTextFieldSetString(text4,zoom); } void Change_debug_level_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); change_debug_level_dialog = (Widget)NULL; } void Change_debug_level_reset(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { debug_level = 0; XmTextSetString(debug_level_text, "0"); // Change_debug_level_destroy_shell(widget,clientData,callData); } void Change_debug_level_change_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp; char temp_string[10]; temp = XmTextGetString(debug_level_text); debug_level = atoi(temp); if ( (debug_level < 0) || (debug_level > 32767) ) { debug_level = 0; } XtFree(temp); // Fill in the current value of debug_level xastir_snprintf(temp_string, sizeof(temp_string), "%d", debug_level); XmTextSetString(debug_level_text, temp_string); // Change_debug_level_destroy_shell(widget,clientData,callData); } void Change_Debug_Level(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close, button_reset; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ char temp_string[10]; if (!change_debug_level_dialog) { change_debug_level_dialog = XtVaCreatePopupShell(langcode("PULDNFI007"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Change Debug Level pane", xmPanedWindowWidgetClass, change_debug_level_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Change Debug Level my_form", xmFormWidgetClass, pane, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; debug_level_text = XtVaCreateManagedWidget("Change_Debug_Level debug text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, ((5*7)+2), XmNmaxLength, 4, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // Fill in the current value of debug_level xastir_snprintf(temp_string, sizeof(temp_string), "%d", debug_level); XmTextSetString(debug_level_text, temp_string); button_reset = XtVaCreateManagedWidget(langcode("UNIOP00033"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, debug_level_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_reset, XmNactivateCallback, Change_debug_level_reset, change_debug_level_dialog); XtAddCallback(button_ok, XmNactivateCallback, Change_debug_level_change_data, change_debug_level_dialog); XtAddCallback(button_close, XmNactivateCallback, Change_debug_level_destroy_shell, change_debug_level_dialog); pos_dialog(change_debug_level_dialog); delw = XmInternAtom(XtDisplay(change_debug_level_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(change_debug_level_dialog, delw, Change_debug_level_destroy_shell, (XtPointer)change_debug_level_dialog); XtManageChild(my_form); XtManageChild(pane); XtPopup(change_debug_level_dialog,XtGrabNone); fix_dialog_size(change_debug_level_dialog); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(change_debug_level_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(change_debug_level_dialog), XtWindow(change_debug_level_dialog)); } } #if !defined(NO_GRAPHICS) && defined(HAVE_MAGICK) void Gamma_adjust_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); gamma_adjust_dialog = (Widget)NULL; } void Gamma_adjust_change_data(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp; char temp_string[10]; temp = XmTextGetString(gamma_adjust_text); imagemagick_gamma_adjust = atof(temp); if (imagemagick_gamma_adjust < -9.9) { imagemagick_gamma_adjust = -9.9; } else if (imagemagick_gamma_adjust > 9.9) { imagemagick_gamma_adjust = 9.9; } XtFree(temp); xastir_snprintf(temp_string, sizeof(temp_string), "%+.1f", imagemagick_gamma_adjust); XmTextSetString(gamma_adjust_text, temp_string); // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Gamma_adjust(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, my_form, button_ok, button_close; Atom delw; char temp_string[10]; if (!gamma_adjust_dialog) { // Gamma Correction gamma_adjust_dialog = XtVaCreatePopupShell(langcode("GAMMA002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, NULL); pane = XtVaCreateWidget("Adjust Gamma pane", xmPanedWindowWidgetClass, gamma_adjust_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Adjust Gamma my_form", xmFormWidgetClass, pane, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gamma_adjust_text = XtVaCreateManagedWidget("Adjust Gamma text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNwidth, 4*10, XmNmaxLength, 4, XmNbackground, colors[0x0f], XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); xastir_snprintf(temp_string, sizeof(temp_string), "%+.1f", imagemagick_gamma_adjust); XmTextSetString(gamma_adjust_text, temp_string); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gamma_adjust_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gamma_adjust_text, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Gamma_adjust_change_data, gamma_adjust_dialog); XtAddCallback(button_close, XmNactivateCallback, Gamma_adjust_destroy_shell, gamma_adjust_dialog); pos_dialog(gamma_adjust_dialog); delw = XmInternAtom(XtDisplay(gamma_adjust_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(gamma_adjust_dialog, delw, Gamma_adjust_destroy_shell, (XtPointer)gamma_adjust_dialog); XtManageChild(my_form); XtManageChild(pane); XtPopup(gamma_adjust_dialog, XtGrabNone); fix_dialog_size(gamma_adjust_dialog); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(gamma_adjust_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(gamma_adjust_dialog), XtWindow(gamma_adjust_dialog)); } } #endif // NO_GRAPHICS && HAVE_MAGICK void Load_station_font(void) { // Assign a font (or a different font) to the GC // Free any old font first. If we fail to assign a new font in // the code here, can we get in a situation where we are trying // to draw without a font? if (station_font != NULL) { XFreeFont(XtDisplay(da), station_font); } // Load the new font from the FONT_STATION string station_font = (XFontStruct *)XLoadQueryFont(XtDisplay(da), rotated_label_fontname[FONT_STATION]); if (station_font == NULL) // Couldn't get the font!!! { char tempy[100]; fprintf(stderr,"Map_font_change_data: Couldn't load station font %s. ", rotated_label_fontname[FONT_STATION]); fprintf(stderr,"Loading default station font instead.\n"); strcpy(tempy, "Couldn't get font "); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, rotated_label_fontname[FONT_STATION]); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, ". Loading default font instead."); tempy[sizeof(tempy)-1] = '\0'; // Terminate string popup_message_always(langcode("POPEM00035"), tempy); station_font = (XFontStruct *)XLoadQueryFont(XtDisplay(da), "fixed"); if (station_font == NULL) // Couldn't get the font!!! { fprintf(stderr,"Map_font_change_data: Couldn't load default station font.\n"); popup_message_always(langcode("POPEM00035"), "Couldn't load default station font."); } } // Assign the font to the GC. if (station_font != NULL) { XSetFont(XtDisplay(da), gc, station_font->fid); } } // chose map label font void Map_font_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; xfontsel_query = 0; XtPopdown(shell); XtDestroyWidget(shell); map_font_dialog = (Widget)NULL; } // Function called by UpdateTime when xfontsel_query is non-zero. // Checks the pipe to see if xfontsel has sent anything to us yet. // If we get anything from the read, we should wait a small amount // of time and try another read, to make sure we don't get a partial // read the first time and quit. // void Query_xfontsel_pipe (void) { char xfontsel_font[FONT_MAX][sizeof(rotated_label_fontname[0])]; struct timeval tmv; fd_set rd; int retval; int fd; int i; for (i = 0; i < FONT_MAX; i++) { // if (fgets(xfontsel_font,sizeof(xfontsel_font),f_xfontsel_pipe)) { // Find out the file descriptor associated with our pipe. if (!f_xfontsel_pipe[i]) { continue; } fd = fileno(f_xfontsel_pipe[i]); FD_ZERO(&rd); FD_SET(fd, &rd); tmv.tv_sec = 0; tmv.tv_usec = 1; // 1 usec // Do a non-blocking check of the read end of the pipe. retval = select(fd+1,&rd,NULL,NULL,&tmv); //fprintf(stderr,"1\n"); if (retval) { int l = strlen(xfontsel_font[i]); // We have something to process. Wait a bit, then snag the // data. usleep(250000); // 250ms if (fgets(xfontsel_font[i],sizeof(xfontsel_font[0]),f_xfontsel_pipe[i]) == NULL) { // We hit end-of-file or there's an error reading // Do nothing here, which was the standard operation // prior to adding the check for the return value. } if (xfontsel_font[i][l-1] == '\n') { xfontsel_font[i][l-1] = '\0'; } if (map_font_text[i] != NULL) { XmTextSetString(map_font_text[i], xfontsel_font[i]); } pclose(f_xfontsel_pipe[i]); f_xfontsel_pipe[i] = 0; //fprintf(stderr,"Resetting xfontset_query\n"); xfontsel_query = 0; } else { // Read nothing. Let UpdateTime run this function again // shortly. } } } void Map_font_xfontsel(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { #if defined(HAVE_XFONTSEL) int fontsize = XTPOINTER_TO_INT(clientData); char xfontsel[70]; /* invoke xfontsel -print and stick into map_font_text */ sprintf(xfontsel, "%s -print -title \"xfontsel %d\"", XFONTSEL_PATH, fontsize); if ((f_xfontsel_pipe[fontsize] = popen(xfontsel,"r"))) { // Request UpdateTime to keep checking the pipe periodically // using non-blocking reads. //fprintf(stderr,"Setting xfontsel_query\n"); xfontsel_query++; } else { perror("xfontsel"); } #endif // HAVE_XFONTSEL } void Map_font_change_data(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp; Widget shell = (Widget) clientData; int i; xfontsel_query = 0; for (i = 0; i < FONT_MAX; i++) { temp = XmTextGetString(map_font_text[i]); xastir_snprintf(rotated_label_fontname[i], sizeof(rotated_label_fontname[i]), "%s", temp); XtFree(temp); XmTextSetString(map_font_text[i], rotated_label_fontname[i]); } // Load a new font into the GC for the station font Load_station_font(); // Set interrupt_drawing_now because conditions have changed // (new map center). interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; XtPopdown(shell); XtDestroyWidget(shell); map_font_dialog = (Widget)NULL; } void Map_font(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, fontname[FONT_MAX], button_ok, button_cancel,button_xfontsel[FONT_MAX]; Atom delw; int i; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if (!map_font_dialog) { map_font_dialog = XtVaCreatePopupShell(langcode("MAPFONT002"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Choose map labels font", xmPanedWindowWidgetClass, map_font_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Map font my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // ac=0; // XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; // XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; for (i = 0; i < FONT_MAX; i++) { char *fonttitle[FONT_MAX] = {"MAPFONT009","MAPFONT010","MAPFONT003", "MAPFONT004","MAPFONT005","MAPFONT006", "MAPFONT007","MAPFONT008","MAPFONT011" }; ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, fontname[i-1]); ac++; } XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNwidth, 150); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNforeground,colors[0x08]); ac++; XtSetArg(al[ac], XmNbackground,colors[0xff]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; fontname[i] = XtCreateManagedWidget(langcode(fonttitle[i]), xmLabelWidgetClass, my_form, al, ac); ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, map_font_text[i-1]); ac++; } XtSetArg(al[ac], XmNeditable, TRUE); ac++; XtSetArg(al[ac], XmNcursorPositionVisible, TRUE); ac++; XtSetArg(al[ac], XmNsensitive, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 1); ac++; XtSetArg(al[ac], XmNcolumns, 60); ac++; XtSetArg(al[ac], XmNwidth, (60*7)+2); ac++; XtSetArg(al[ac], XmNmaxLength, 128); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0f]); ac++; XtSetArg(al[ac], XmNbottomAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNleftWidget, fontname[i]); ac++; XtSetArg(al[ac], XmNleftOffset, 10); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNrightAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_font_text[i] = XtCreateManagedWidget("Map font text", xmTextFieldWidgetClass, my_form, al, ac); XmTextSetString(map_font_text[i], rotated_label_fontname[i]); // Xfontsel ac = 0; if (i == 0) { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 10); ac++; } else { XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, button_xfontsel[i-1]); ac++; } XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNleftWidget, map_font_text[i]); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 10); ac++; XtSetArg(al[ac], XmNheight, 40); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNforeground,colors[0x08]); ac++; XtSetArg(al[ac], XmNbackground,colors[0xff]); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; button_xfontsel[i] = XtCreateManagedWidget(langcode("PULDNMP015"), xmPushButtonGadgetClass, my_form, al,ac); #if defined(HAVE_XFONTSEL) XtSetSensitive(button_xfontsel[i],TRUE); #else // HAVE_FONTSEL XtSetSensitive(button_xfontsel[i],FALSE); #endif // HAVE_FONTSEL XtAddCallback(button_xfontsel[i], XmNactivateCallback, Map_font_xfontsel, INT_TO_XTPOINTER(i) ); } button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_font_text[FONT_MAX-1], XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_font_text[FONT_MAX-1], XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Map_font_change_data, map_font_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Map_font_destroy_shell, map_font_dialog); pos_dialog(map_font_dialog); delw = XmInternAtom(XtDisplay(map_font_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_font_dialog, delw, Map_font_destroy_shell, (XtPointer)map_font_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, map_font_dialog); XtPopup(map_font_dialog, XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_font_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_font_dialog), XtWindow(map_font_dialog)); } } // Used by view_gps_status() function below. We must either expire // this data or associate a time with it on the display. char gps_status_save[100]; time_t gps_status_save_time = 0; char *report_gps_status(void) { static char gps_temp[100]; char temp2[20]; switch (gps_valid) { case 8: // Simulation Mode xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS008") ); // "Simulation" break; case 7: // Manual Input Mode xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS009") ); // "Manual" break; case 6: // Estimated Fix (dead reckoning) xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS010") ); // "Estimated" break; case 5: // Float RTK xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS011") ); // "Float RTK" break; case 4: // RTK xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS012") ); // "RTK" break; case 3: // WAAS or PPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS001") ); // "WAAS or PPS" break; case 2: // DGPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS002") ); // "DGPS" break; case 1: // Valid SPS Fix xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS003") ); // "Valid SPS" break; case 0: // Invalid default: xastir_snprintf(temp2, sizeof(temp2), "%s", langcode("GPSS004") ); // "Invalid" break; } xastir_snprintf(gps_temp, sizeof(gps_temp), "%s:%s %s:%s", langcode("GPSS005"), // "Sats/View" gps_sats, langcode("GPSS006"), // "Fix" temp2); // Save it in global variable in case we request status via the // menus. xastir_snprintf(gps_status_save, sizeof(gps_status_save), "%s", gps_temp); gps_status_save_time = sec_now(); // Reset the variables. xastir_snprintf(gps_sats, sizeof(gps_sats), "00"); gps_valid = 0; return(gps_temp); } void view_gps_status(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // GPS status data too old? if ((gps_status_save_time + 30) >= sec_now()) { // Nope, within 30 seconds popup_message_always(langcode("PULDNVI015"), gps_status_save); } else { // Yes, GPS status data is old popup_message_always(langcode("PULDNVI015"), langcode("GPSS007") ); // "!GPS data is older than 30 seconds!" } } void Compute_Uptime(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char temp[200]; unsigned long runtime; int days, hours, minutes, seconds; char Days[6]; char Hours[7]; char Minutes[9]; char Seconds[9]; runtime = sec_now() - program_start_time; days = runtime / 86400; runtime = runtime - (days * 86400); hours = runtime / 3600; runtime = runtime - (hours * 3600); minutes = runtime / 60; seconds = runtime - (minutes * 60); if (days == 1) { xastir_snprintf(Days,sizeof(Days),"%s",langcode("TIME001")); // Day } else { xastir_snprintf(Days,sizeof(Days),"%s",langcode("TIME002")); // Days } if (hours == 1) { xastir_snprintf(Hours,sizeof(Hours),"%s",langcode("TIME003")); // Hour } else { xastir_snprintf(Hours,sizeof(Hours),"%s",langcode("TIME004")); // Hours } if (minutes == 1) { xastir_snprintf(Minutes,sizeof(Minutes),"%s",langcode("TIME005")); // Minute } else { xastir_snprintf(Minutes,sizeof(Minutes),"%s",langcode("TIME006")); // Minutes } if (seconds == 1) { xastir_snprintf(Seconds,sizeof(Seconds),"%s",langcode("TIME007")); // Second } else { xastir_snprintf(Seconds,sizeof(Seconds),"%s",langcode("TIME008")); // Seconds } if (days != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s, %d %s, %d %s", days, Days, hours, Hours, minutes, Minutes, seconds, Seconds); } else if (hours != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s, %d %s", hours, Hours, minutes, Minutes, seconds, Seconds); } else if (minutes != 0) { xastir_snprintf(temp, sizeof(temp), "%d %s, %d %s", minutes, Minutes, seconds, Seconds); } else { xastir_snprintf(temp, sizeof(temp), "%d %s", seconds, Seconds); } popup_message_always(langcode("PULDNVI014"),temp); } void Mouse_button_handler (Widget UNUSED(w), Widget UNUSED(popup), XButtonEvent *event, Boolean * UNUSED(dispatch) ) { // Snag the current pointer position input_x = event->x; input_y = event->y; if (event->type == ButtonPress) { //fprintf(stderr,"Mouse_button_handler, button pressed %d\n", event->button); } if (event->type == ButtonRelease) { //fprintf(stderr,"Mouse_button_handler, button released %d\n", event->button); return; } #ifdef SWAP_MOUSE_BUTTONS if (event->button != Button1) { //fprintf(stderr,"Pressed a mouse button, but not Button1: %x\n",event->button); #else // SWAP_MOUSE_BUTTONS if (event->button != Button3) { //fprintf(stderr,"Pressed a mouse button, but not Button3: %x\n",event->button); #endif // SWAP_MOUSE_BUTTONS return; } // Right mouse button press menu_x=input_x; menu_y=input_y; if (right_menu_popup != NULL) // If popup menu defined { #ifdef SWAP_MOUSE_BUTTONS // This gets the menus out of the way that are on pointer // button1 if SWAP_MOUSE_BUTTONS is enabled. If it's not // enabled, they don't interfere with each other anyway. if (!measuring_distance && !moving_object) { #else // SWAP_MOUSE_BUTTONS if (1) // Always bring up the menu if SWAP is disabled { #endif // SWAP_MOUSE_BUTTONS // Bring up the popup menu XmMenuPosition(right_menu_popup,(XButtonPressedEvent *)event); XtManageChild(right_menu_popup); // Check whether any modifiers are pressed. // If so, pop up a warning message. if ( (event->state != 0) && warn_about_mouse_modifiers) { popup_message_always(langcode("POPUPMA023"),langcode("POPUPMA024")); } } } } void menu_link_for_mouse_menu(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (right_menu_popup!=NULL) { //XmMenuPosition(right_menu_popup,(XButtonPressedEvent *)event); XtManageChild(right_menu_popup); } } void store_all_kml_callback(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { export_trail_as_kml(NULL); last_kmlsnapshot = sec_now(); } void KML_Snapshots_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // Whether we're setting or unsetting it, set the timer such // that a snapshot will occur immediately once the button is set // again. last_kmlsnapshot = 0; if(state->set) { kmlsnapshots_enabled = atoi(which); } else { kmlsnapshots_enabled = 0; } } void Snapshots_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // Whether we're setting or unsetting it, set the timer such // that a snapshot will occur immediately once the button is set // again. last_snapshot = 0; if(state->set) { snapshots_enabled = atoi(which); } else { snapshots_enabled = 0; } } static inline int no_data_selected(void) { return ( Select_.none || ( !Select_.mine && !Select_.net && ( !Select_.tnc || ( !Select_.direct && !Select_.via_digi ) ) ) ); } #ifdef ARROWS Widget pan_up_menu, pan_down_menu, pan_left_menu, pan_right_menu, zoom_in_menu, zoom_out_menu; #endif // ARROWS void create_appshell( Display *display, char * UNUSED(app_name), int UNUSED(app_argc), char ** UNUSED(app_argv) ) { Pixmap icon_pixmap; Atom WM_DELETE_WINDOW; Widget children[9]; /* Children to manage */ Arg al[100]; /* Arg List */ register unsigned int ac; /* Arg Count */ /*popup menu widgets */ Widget zoom_in, zoom_out, zoom_sub, zl1, zl2, zl3, zl4, zl5, zl6, zl7, zl8, zl9, zlC; // Widget zoom_level; // Widget sar_object_menu; Widget CAD_sub, CAD1, CAD3, CAD4; Widget pan_sub; // Widget pan_menu; Widget move_my_sub; // Widget move_my_menu; Widget pan_ctr, last_loc, station_info, send_message_to; Widget set_object, modify_object; Widget setmyposition, pan_up, pan_down, pan_left, pan_right; /*menu widgets */ Widget sep; Widget filepane, configpane, mappane, viewpane, stationspane, messagepane, ifacepane, helppane, filter_data_pane, filter_display_pane, map_config_pane, station_config_pane, help_emergency_pane; // Widget exitpane, // help_emergency_button, // display_button, // file_button, // view_button, // config_button, // map_button, // map_background_button, // map_config_button, // station_config_button, // raster_intensity_button, // map_station_label_button, // map_icon_outline_button, // iface_button, // message_button, // filter_data_button, // filter_display_button, // draw_CAD_objects_menu, // store_data_button; Widget track_button, download_trail_button, station_clear_button, tracks_clear_button, object_history_refresh_button, object_history_clear_button, tactical_clear_button, tactical_history_clear_button, uptime_button, aloha_button, save_button, open_file_button, exit_button, view_messages_button, gps_status_button, bullet_button, packet_data_button, mobile_button, stations_button, localstations_button, laststations_button, objectstations_button, objectmystations_button, weather_button, wx_station_button, locate_button, geocode_place_button, locate_place_button, jump_button, jump_button2, alert_button, defaults_button, timing_button, coordinates_button, station_button, map_lock_pan_zoom_button, map_disable_button, map_auto_button, map_chooser_button, map_grid_button, map_levels_button, map_labels_button, map_fill_button, coordinate_calculator_button, center_zoom_button, Map_background_color_Pane, map_pointer_menu_button, cad_draw_button, cad_show_label_button, cad_show_probability_button, cad_show_area_button, cad_show_comment_button, #if !defined(NO_GRAPHICS) Raster_intensity_Pane, #if defined(HAVE_MAGICK) gamma_adjust_button, #endif // HAVE_MAGICK #ifdef HAVE_LIBGEOTIFF drg_config_button, #endif // HAVE_LIBGEOTIFF #endif // NO_GRAPHICS font_button, Map_station_label_Pane, Map_icon_outline_Pane, map_wx_alerts_button, index_maps_on_startup_button, redownload_maps_button, flush_map_cache_button, units_choice_button, dbstatus_choice_button, iface_connect_button, tnc_logging, transmit_disable_toggle, net_logging, igate_logging, wx_logging, message_logging, wx_alert_logging, enable_snapshots, print_button, test_button, debug_level_button, aa_button, speech_button, smart_beacon_button, map_indexer_button, map_all_indexer_button, geocoder_config_button, auto_msg_set_button, send_message_to_button, show_pending_messages_button, enable_kmlsnapshots, open_messages_group_button, clear_messages_button, General_q_button, IGate_q_button, WX_q_button, store_data_pane, store_all_kml_button, #ifdef HAVE_DB store_all_db_button, #endif // HAVE_DB help_button, help_about, help_help; char *title, *t; int t_size; // XWMHints *wm_hints; // Used for window manager hints Dimension my_appshell_width, my_appshell_height; Dimension da_width, da_height; static XmFontListEntry font_entry; if(debug_level & 8) { fprintf(stderr,"Create appshell start\n"); } /* wm_hints = XAllocWMHints(); if (!wm_hints) { fprintf(stderr,"Failure allocating memory: wm_hints\n"); exit(0); } // Set up the wm_hints struct wm_hints->initial_state = NormalState; wm_hints->input = True; wm_hints->flags = StateHint | InputHint; */ t = "X Amateur Station Tracking and Information Reporting"; title = (char *)malloc(t_size = (strlen(t) + 42 + strlen(xastir_package))); if (!title) { fprintf(stderr,"Couldn't allocate memory for title\n"); } else { xastir_snprintf(title, t_size, "XASTIR"); strncat(title, " - ", t_size - 1 - strlen(title)); strncat(title, t, t_size - 1 - strlen(title)); strncat(title, " @ ", t_size - 1 - strlen(title)); (void)gethostname(&title[strlen(title)], 28); } // Allocate a couple of colors that we'll need before we get // around to calling create_gc(), which creates the rest. // colors[0x08] = GetPixelByName(appshell,"black"); colors[0x0c] = GetPixelByName(appshell,"red"); colors[0xff] = GetPixelByName(appshell,"gray73"); ac = 0; // Snag border widths so that we can use them in the calculations // below. If we fail to do this the size and offsets will be off by // the width of the borders added by the window manager. // // if (XGetGeometry(XtDisplay(da), // XtWindow(appshell), // &root_return, // &x_return, // &y_return, // &width_return, // &height_return, // &border_width_return, // &depth_return) ) == False) { // fprintf(stderr,"Couldn't get window attributes\n"); // } // // Another method: // // XWindowAttributes windowattr; // Defined in Xlib.h // Struct has x/y/width/height/border_width/depth fields. // if (XGetWindowAttributes(display,XtWindow(appshell),&windowattr) == 0) { // fprintf(stderr,"Couldn't get window attributes\n") // } // Set up the main window X/Y sizes and the minimum sizes // allowable. // if ( (WidthValue|HeightValue) & geometry_flags ) { // // Size of Xastir was specified with a -geometry setting. // Set up the window size. // my_appshell_width = (Dimension)geometry_width; // Used in offset equations below my_appshell_height = (Dimension)geometry_height; // Used in offset equations below //fprintf(stderr,"gW:%d gH:%d\n", geometry_width, geometry_height); //fprintf(stderr,"tW:%d tH:%d\n", (int)my_appshell_width, (int)my_appshell_height); if (my_appshell_width < 61) { my_appshell_width = 61; } if (my_appshell_height < 61) { my_appshell_height = 61; } //fprintf(stderr,"tW:%d tH:%d\n", (int)my_appshell_width, (int)my_appshell_height); XtSetArg(al[ac], XmNwidth, my_appshell_width); ac++; XtSetArg(al[ac], XmNheight, my_appshell_height); ac++; // XtSetArg(al[ac], XmNminWidth, 61); ac++; // XtSetArg(al[ac], XmNminHeight, 61); ac++; // Lock the min size to the specified initial size for now, release // later after creating initial window. Snagged this idea from the // Lincity project where they do similar things in "lcx11.c" // XtSetArg(al[ac], XmNminWidth, my_appshell_width); ac++; // XtSetArg(al[ac], XmNminHeight, my_appshell_height); ac++; } else { // Size was NOT specified in a -geometry string. Set to the // size specified in the config file instead. // my_appshell_width = (Dimension)screen_width; my_appshell_height = (Dimension)(screen_height + 60); XtSetArg(al[ac], XmNwidth, my_appshell_width); ac++; XtSetArg(al[ac], XmNheight, my_appshell_height); ac++; // XtSetArg(al[ac], XmNminWidth, 61); ac++; // XtSetArg(al[ac], XmNminHeight, 61); ac++; // Lock the min size to the specified initial size for now, release // later after creating initial window. Got this idea from the // Lincity project where they do the similar things in "lcx11.c" // XtSetArg(al[ac], XmNminWidth, my_appshell_width); ac++; // XtSetArg(al[ac], XmNminHeight, my_appshell_height); ac++; } // Set up default font font1 = XLoadQueryFont(display, rotated_label_fontname[FONT_SYSTEM]); if (font1 == NULL) // Couldn't get the font!!! { fprintf(stderr,"create_appshell: Couldn't load system font %s. ", rotated_label_fontname[FONT_SYSTEM]); fprintf(stderr,"Loading default system font instead.\n"); font1 = XLoadQueryFont(display, "fixed"); if (font1 == NULL) // Couldn't get the font!!! { fprintf(stderr,"create_appshell: Couldn't load default system font, exiting.\n"); exit(1); } else { // _Now_ we can do a popup message about the first error // as we have a font to work with! char tempy[100]; strcpy(tempy, "Couldn't get font "); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, rotated_label_fontname[FONT_SYSTEM]); tempy[sizeof(tempy)-1] = '\0'; // Terminate string strcat(tempy, ". Loading default font instead."); tempy[sizeof(tempy)-1] = '\0'; // Terminate string popup_message_always(langcode("POPEM00035"), tempy); } } font_entry = XmFontListEntryCreate(XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT, font1); fontlist1 = XmFontListAppendEntry(NULL, font_entry); XmFontListEntryFree(&font_entry); XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Set up the X/Y offsets for the main window // if ( (XValue|YValue) & geometry_flags ) { Position my_x, my_y; // // Position of Xastir was specified with a -geometry setting. // if (XNegative & geometry_flags) { geometry_x = DisplayWidth(display, DefaultScreen(display) ) + geometry_x - (int)my_appshell_width; } if (YNegative & geometry_flags) { geometry_y = DisplayHeight(display, DefaultScreen(display) ) + geometry_y - (int)my_appshell_height; } my_x = (Position)geometry_x; my_y = (Position)geometry_y; XtSetArg(al[ac], XmNx, my_x); ac++; XtSetArg(al[ac], XmNy, my_y); ac++; } else { // // Position of Xastir was not specified. Use the values // from the config file // /* // This doesn't position the widget in fvwm2. Would hate to go back // to XSizeHints in order to make this work. fprintf(stderr,"Setting up widget's X/Y position at X:%d Y:%d\n", (int)screen_x_offset, (int)screen_y_offset); XtSetArg(al[ac], XmNx, screen_x_offset); ac++; // Doesn't work here XtSetArg(al[ac], XmNy, screen_y_offset); ac++; // Doesn't work here */ } XtSetArg(al[ac], XmNallowShellResize, TRUE); ac++; if (title) { XtSetArg(al[ac], XmNtitle, title); } ac++; XtSetArg(al[ac], XmNdefaultPosition, FALSE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; // // Set the above values into the appshell widget // XtSetValues(appshell, al, ac); // Make at least one Motif call so that the next function won't // result in this problem: 'Error: atttempt to add non-widget // child "DropSiteManager" to parent "xastir"'. // (void) XmIsMotifWMRunning(appshell); form = XtVaCreateWidget("create_appshell form", xmFormWidgetClass, appshell, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Menu Bar */ ac = 0; XtSetArg(al[ac], XmNshadowThickness, 1); ac++; XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNbottomAttachment,XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; menubar = XmCreateMenuBar(form, "create_appshell menubar", al, ac); /*set args for color */ ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; /* menu bar */ filepane = XmCreatePulldownMenu(menubar,"filepane", al, ac); viewpane = XmCreatePulldownMenu(menubar,"viewpane", al, ac); mappane = XmCreatePulldownMenu(menubar,"mappane", al, ac); stationspane= XmCreatePulldownMenu(menubar,"stationspane",al, ac); messagepane = XmCreatePulldownMenu(menubar,"messagepane", al, ac); ifacepane = XmCreatePulldownMenu(menubar,"ifacepane", al, ac); helppane = XmCreatePulldownMenu(menubar,"helppane", al, ac); //file_button XtVaCreateManagedWidget(langcode("MENUTB0001"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId, filepane, XmNmnemonic,langcode_hotkey("MENUTB0001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //view_button XtVaCreateManagedWidget(langcode("MENUTB0002"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,viewpane, XmNmnemonic,langcode_hotkey("MENUTB0002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //map_button XtVaCreateManagedWidget(langcode("MENUTB0004"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,mappane, XmNmnemonic,langcode_hotkey("MENUTB0004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //display_button XtVaCreateManagedWidget(langcode("MENUTB0005"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,stationspane, XmNmnemonic,langcode_hotkey("MENUTB0005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //message_button XtVaCreateManagedWidget(langcode("MENUTB0006"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,messagepane, XmNmnemonic,langcode_hotkey("MENUTB0006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //iface_button XtVaCreateManagedWidget(langcode("MENUTB0010"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,ifacepane, XmNmnemonic,langcode_hotkey("MENUTB0010"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); help_button = XtVaCreateManagedWidget(langcode("MENUTB0009"), xmCascadeButtonGadgetClass, menubar, XmNsubMenuId,helppane, XmNmnemonic,langcode_hotkey("MENUTB0009"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtVaSetValues (menubar,XmNmenuHelpWidget,help_button,NULL); /* end bar */ /* File */ ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; configpane = XmCreatePulldownMenu(filepane, "configpane", al, ac); // Print button print_button = XtVaCreateManagedWidget(langcode("PULDNFI015"), xmPushButtonWidgetClass, filepane, XmNmnemonic, langcode_hotkey("PULDNFI015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback( print_button, XmNactivateCallback, Print_Postscript, NULL ); //config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, filepane, XmNsubMenuId,configpane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); open_file_button = XtVaCreateManagedWidget(langcode("PULDNFI002"), xmPushButtonGadgetClass, filepane, XmNmnemonic,langcode_hotkey("PULDNFI002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); tnc_logging = XtVaCreateManagedWidget(langcode("PULDNFI010"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(tnc_logging,XmNvalueChangedCallback,TNC_Logging_toggle,"1"); if (log_tnc_data) { XmToggleButtonSetState(tnc_logging,TRUE,FALSE); } net_logging = XtVaCreateManagedWidget(langcode("PULDNFI011"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(net_logging,XmNvalueChangedCallback,Net_Logging_toggle,"1"); if (log_net_data) { XmToggleButtonSetState(net_logging,TRUE,FALSE); } igate_logging = XtVaCreateManagedWidget(langcode("PULDNFI012"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(igate_logging,XmNvalueChangedCallback,IGate_Logging_toggle,"1"); if (log_igate) { XmToggleButtonSetState(igate_logging,TRUE,FALSE); } // message_logging = XtVaCreateManagedWidget(langcode("PULDNFI012"), message_logging = XtVaCreateManagedWidget("Message Logging", xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(message_logging,XmNvalueChangedCallback,Message_Logging_toggle,"1"); if (log_message_data) { XmToggleButtonSetState(message_logging,TRUE,FALSE); } wx_logging = XtVaCreateManagedWidget(langcode("PULDNFI013"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(wx_logging,XmNvalueChangedCallback,WX_Logging_toggle,"1"); if (log_wx) { XmToggleButtonSetState(wx_logging,TRUE,FALSE); } // wx_alert_logging = XtVaCreateManagedWidget(langcode("PULDNFI013"), wx_alert_logging = XtVaCreateManagedWidget("WX Alert Logging", xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(wx_alert_logging,XmNvalueChangedCallback,WX_Alert_Logging_toggle,"1"); if (log_wx_alert_data) { XmToggleButtonSetState(wx_alert_logging,TRUE,FALSE); } enable_snapshots = XtVaCreateManagedWidget(langcode("PULDNFI014"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(enable_snapshots,XmNvalueChangedCallback,Snapshots_toggle,"1"); if (snapshots_enabled) { XmToggleButtonSetState(enable_snapshots,TRUE,FALSE); } // enable kml snapshots enable_kmlsnapshots = XtVaCreateManagedWidget(langcode("PULDNFI016"), xmToggleButtonGadgetClass, filepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(enable_kmlsnapshots,XmNvalueChangedCallback,KML_Snapshots_toggle,"1"); if (kmlsnapshots_enabled) { XmToggleButtonSetState(enable_kmlsnapshots,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep1a", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1b", xmSeparatorGadgetClass, filepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //exitpane XmCreatePulldownMenu(filepane, "exitpane", al, ac); exit_button = XtVaCreateManagedWidget(langcode("PULDNFI004"), xmPushButtonWidgetClass, filepane, XmNmnemonic,langcode_hotkey("PULDNFI004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* View */ packet_data_button = XtVaCreateManagedWidget(langcode("PULDNVI002"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); view_messages_button = XtVaCreateManagedWidget(langcode("PULDNVI011"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI011"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); bullet_button = XtVaCreateManagedWidget(langcode("PULDNVI001"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); mobile_button = XtVaCreateManagedWidget(langcode("PULDNVI003"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); stations_button = XtVaCreateManagedWidget(langcode("PULDNVI004"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); localstations_button = XtVaCreateManagedWidget(langcode("PULDNVI009"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI009"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); laststations_button = XtVaCreateManagedWidget(langcode("PULDNVI012"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI012"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep1?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); objectstations_button = XtVaCreateManagedWidget(langcode("LHPUPNI005"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("LHPUPNI005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); objectmystations_button = XtVaCreateManagedWidget(langcode("LHPUPNI006"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("LHPUPNI006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "List All CAD Polygons" CAD1 = XtVaCreateManagedWidget(langcode("POPUPMA046"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("POPUPMA046"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); weather_button = XtVaCreateManagedWidget(langcode("PULDNVI005"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); wx_station_button = XtVaCreateManagedWidget(langcode("PULDNVI008"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); alert_button = XtVaCreateManagedWidget(langcode("PULDNVI007"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep3?", xmSeparatorGadgetClass, viewpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gps_status_button = XtVaCreateManagedWidget(langcode("PULDNVI015"), xmPushButtonGadgetClass, viewpane, XmNmnemonic,langcode_hotkey("PULDNVI015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); uptime_button = XtVaCreateManagedWidget(langcode("PULDNVI013"), xmPushButtonWidgetClass, viewpane, XmNmnemonic, langcode_hotkey("PULDNVI013"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); aloha_button = XtVaCreateManagedWidget(langcode("PULDNVI016"), xmPushButtonWidgetClass, viewpane, XmNmnemonic, langcode_hotkey("PULDNVI016"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Configure */ station_button = XtVaCreateManagedWidget(langcode("PULDNCF004"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); defaults_button = XtVaCreateManagedWidget(langcode("PULDNCF001"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); timing_button = XtVaCreateManagedWidget(langcode("PULDNCF003"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); coordinates_button = XtVaCreateManagedWidget(langcode("PULDNCF002"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); aa_button = XtVaCreateManagedWidget(langcode("PULDNCF006"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); speech_button = XtVaCreateManagedWidget(langcode("PULDNCF007"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNCF007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); smart_beacon_button = XtVaCreateManagedWidget(langcode("SMARTB001"), xmPushButtonGadgetClass, configpane, XmNmnemonic,langcode_hotkey("SMARTB001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // map label font select font_button = XtVaCreateManagedWidget(langcode("PULDNMP025"), xmPushButtonWidgetClass, configpane, XmNmnemonic,langcode_hotkey("PULDNMP025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(font_button, XmNactivateCallback, Map_font, NULL); test_button = XtVaCreateManagedWidget(langcode("PULDNFI003"), xmPushButtonWidgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNFI003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); debug_level_button = XtVaCreateManagedWidget(langcode("PULDNFI007"), xmPushButtonWidgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNFI007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); units_choice_button = XtVaCreateManagedWidget(langcode("PULDNUT001"), xmToggleButtonGadgetClass, configpane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(units_choice_button,XmNvalueChangedCallback,Units_choice_toggle,"1"); if (english_units) { XmToggleButtonSetState(units_choice_button,TRUE,FALSE); } dbstatus_choice_button = XtVaCreateManagedWidget(langcode("PULDNDB001"), xmToggleButtonGadgetClass, configpane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(dbstatus_choice_button,XmNvalueChangedCallback,Dbstatus_choice_toggle,"1"); if (do_dbstatus) { XmToggleButtonSetState(dbstatus_choice_button,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep1d", xmSeparatorGadgetClass, configpane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); save_button = XtVaCreateManagedWidget(langcode("PULDNCF008"), xmPushButtonGadgetClass, configpane, XmNmnemonic, langcode_hotkey("PULDNCF008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //- Maps ------------------------------------------------------------- map_chooser_button = XtVaCreateManagedWidget(langcode("PULDNMP001"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_chooser_button, XmNactivateCallback,Map_chooser,NULL); // Map Display Bookmarks jump_button = XtVaCreateManagedWidget(langcode("PULDNMP012"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP012"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); locate_place_button = XtVaCreateManagedWidget(langcode("PULDNMP014"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP014"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); geocode_place_button = XtVaCreateManagedWidget(langcode("PULDNMP029"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP029"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); coordinate_calculator_button = XtVaCreateManagedWidget(langcode("COORD001"), xmPushButtonGadgetClass,mappane, XmNmnemonic, langcode_hotkey("COORD001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); center_zoom_button=XtVaCreateManagedWidget(langcode("POPUPMA026"), xmPushButtonGadgetClass, mappane, XmNmnemonic, langcode_hotkey("POPUPMA026"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(center_zoom_button,XmNactivateCallback,Center_Zoom,NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; CAD_sub=XmCreatePulldownMenu(mappane, "create_appshell CAD sub", al, ac); // "Draw CAD Objects" //draw_CAD_objects_menu XtVaCreateManagedWidget(langcode("POPUPMA029"), xmCascadeButtonGadgetClass, mappane, XmNsubMenuId,CAD_sub, // XmNmnemonic,langcode_hotkey("POPUPMA029"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Draw Mode" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA031")); ac++; // "Close Polygon" CAD_close_polygon_menu_item=XtCreateManagedWidget(langcode("POPUPMA031"), xmPushButtonGadgetClass, CAD_sub, al, ac); XtAddCallback(CAD_close_polygon_menu_item,XmNactivateCallback,Draw_CAD_Objects_close_polygon,NULL); // disable the close polygon menu item if not in draw mode if (draw_CAD_objects_flag==1) { XtSetSensitive(CAD_close_polygon_menu_item,TRUE); } if (draw_CAD_objects_flag==0) { XtSetSensitive(CAD_close_polygon_menu_item,FALSE); } ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; // XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA032")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "Erase CAD Polygons" CAD3=XtCreateManagedWidget(langcode("POPUPMA032"), xmPushButtonGadgetClass, CAD_sub, al, ac); XtAddCallback(CAD3,XmNactivateCallback,Draw_CAD_Objects_erase_dialog,NULL); // "List All CAD Polygons" CAD4 = XtVaCreateManagedWidget(langcode("POPUPMA046"), xmPushButtonGadgetClass, CAD_sub, XmNmnemonic,langcode_hotkey("POPUPMA046"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(CAD4,XmNactivateCallback,Draw_CAD_Objects_list_dialog,NULL); // Toggles for CAD object information display on map // Draw CAD Objects cad_draw_button = XtVaCreateManagedWidget(langcode("POPUPMA047"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_draw_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_draw_objects"); if (CAD_draw_objects==TRUE) { XmToggleButtonSetState(cad_draw_button,TRUE,FALSE); } // Draw CAD Labels cad_show_label_button = XtVaCreateManagedWidget(langcode("POPUPMA048"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_label_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_label"); if (CAD_show_label==TRUE) { XmToggleButtonSetState(cad_show_label_button,TRUE,FALSE); } // Draw CAD Probability cad_show_probability_button = XtVaCreateManagedWidget(langcode("POPUPMA050"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_probability_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_raw_probability"); if (CAD_show_raw_probability==TRUE) { XmToggleButtonSetState(cad_show_probability_button,TRUE,FALSE); } // Draw CAD Comments cad_show_comment_button = XtVaCreateManagedWidget(langcode("POPUPMA049"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_comment_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_comment"); if (CAD_show_comment==TRUE) { XmToggleButtonSetState(cad_show_comment_button,TRUE,FALSE); } // Draw CAD Size of Area cad_show_area_button = XtVaCreateManagedWidget(langcode("POPUPMA051"), xmToggleButtonGadgetClass, CAD_sub, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_show_area_button,XmNvalueChangedCallback,CAD_draw_toggle,"CAD_show_area"); if (CAD_show_area==TRUE) { XmToggleButtonSetState(cad_show_area_button,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep2", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_lock_pan_zoom_button = XtVaCreateManagedWidget(langcode("PULDNMP016"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_lock_pan_zoom_button, XmNvalueChangedCallback, Map_lock_pan_zoom_toggle, "1"); if (map_lock_pan_zoom) { XmToggleButtonSetState(map_lock_pan_zoom_button, TRUE, FALSE); } map_disable_button = XtVaCreateManagedWidget(langcode("PULDNMP013"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_disable_button, XmNvalueChangedCallback, Map_disable_toggle, "1"); if (disable_all_maps) { XmToggleButtonSetState(map_disable_button, TRUE, FALSE); } map_auto_button = XtVaCreateManagedWidget(langcode("PULDNMP002"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_auto_button,XmNvalueChangedCallback,Map_auto_toggle,"1"); if (map_auto_maps) { XmToggleButtonSetState(map_auto_button,TRUE,FALSE); } map_auto_skip_raster_button = XtVaCreateManagedWidget(langcode("PULDNMP021"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_auto_skip_raster_button,XmNvalueChangedCallback,Map_auto_skip_raster_toggle,"1"); if (auto_maps_skip_raster) { XmToggleButtonSetState(map_auto_skip_raster_button,TRUE,FALSE); } if (!map_auto_maps) { XtSetSensitive(map_auto_skip_raster_button,FALSE); } map_grid_button = XtVaCreateManagedWidget(langcode("PULDNMP003"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_grid_button,XmNvalueChangedCallback,Grid_toggle,"1"); if (long_lat_grid) { XmToggleButtonSetState(map_grid_button,TRUE,FALSE); } // Enable Map Border map_border_button = XtVaCreateManagedWidget(langcode("PULDNMP031"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_border_button,XmNvalueChangedCallback,Map_border_toggle,"1"); if (draw_labeled_grid_border) { XmToggleButtonSetState(map_border_button,TRUE,FALSE); } if (!long_lat_grid) { XtSetSensitive(map_border_button,FALSE); } else { XtSetSensitive(map_border_button,TRUE); } map_levels_button = XtVaCreateManagedWidget(langcode("PULDNMP004"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_levels_button,XmNvalueChangedCallback,Map_levels_toggle,"1"); if (map_color_levels) { XmToggleButtonSetState(map_levels_button,TRUE,FALSE); } map_labels_button = XtVaCreateManagedWidget(langcode("PULDNMP010"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_labels_button,XmNvalueChangedCallback,Map_labels_toggle,"1"); if (map_labels) { XmToggleButtonSetState(map_labels_button,TRUE,FALSE); } map_fill_button = XtVaCreateManagedWidget(langcode("PULDNMP009"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_fill_button,XmNvalueChangedCallback,Map_fill_toggle,"1"); if (map_color_fill) { XmToggleButtonSetState(map_fill_button,TRUE,FALSE); } map_wx_alerts_button = XtVaCreateManagedWidget(langcode("PULDNMP007"), xmToggleButtonGadgetClass, mappane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(map_wx_alerts_button,XmNvalueChangedCallback,Map_wx_alerts_toggle,"1"); if (!wx_alert_style) { XmToggleButtonSetState(map_wx_alerts_button,TRUE,FALSE); } #ifndef HAVE_LIBSHP // If we don't have Shapelib compiled in, grey-out the weather // alerts button. XtSetSensitive(map_wx_alerts_button, FALSE); #endif // HAVE_LIBSHP (void)XtVaCreateManagedWidget("create_appshell sep2b", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2c", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_config_pane = XmCreatePulldownMenu(mappane, "map_config_pane", al, ac); //map_config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, mappane, XmNsubMenuId,map_config_pane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // These go into the map config submenu Map_background_color_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_background_color", al, ac); //map_background_button XtVaCreateManagedWidget(langcode("PULDNMP005"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_background_color_Pane, XmNmnemonic, langcode_hotkey("PULDNMP005"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[10] = XtVaCreateManagedWidget(langcode("PULDNMBC11"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC11"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[11] = XtVaCreateManagedWidget(langcode("PULDNMBC12"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC12"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[0] = XtVaCreateManagedWidget(langcode("PULDNMBC01"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[1] = XtVaCreateManagedWidget(langcode("PULDNMBC02"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[2] = XtVaCreateManagedWidget(langcode("PULDNMBC03"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[3] = XtVaCreateManagedWidget(langcode("PULDNMBC04"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[4] = XtVaCreateManagedWidget(langcode("PULDNMBC05"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC05"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[5] = XtVaCreateManagedWidget(langcode("PULDNMBC06"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC06"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[6] = XtVaCreateManagedWidget(langcode("PULDNMBC07"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC07"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[7] = XtVaCreateManagedWidget(langcode("PULDNMBC08"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC08"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[8] = XtVaCreateManagedWidget(langcode("PULDNMBC09"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC09"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_bgcolor[9] = XtVaCreateManagedWidget(langcode("PULDNMBC10"), xmPushButtonGadgetClass, Map_background_color_Pane, XmNmnemonic,langcode_hotkey("PULDNMBC10"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtSetSensitive(map_bgcolor[map_background_color],FALSE); XtAddCallback(map_bgcolor[10], XmNactivateCallback,Map_background,"10"); XtAddCallback(map_bgcolor[11], XmNactivateCallback,Map_background,"11"); XtAddCallback(map_bgcolor[0], XmNactivateCallback,Map_background,"0"); XtAddCallback(map_bgcolor[1], XmNactivateCallback,Map_background,"1"); XtAddCallback(map_bgcolor[2], XmNactivateCallback,Map_background,"2"); XtAddCallback(map_bgcolor[3], XmNactivateCallback,Map_background,"3"); XtAddCallback(map_bgcolor[4], XmNactivateCallback,Map_background,"4"); XtAddCallback(map_bgcolor[5], XmNactivateCallback,Map_background,"5"); XtAddCallback(map_bgcolor[6], XmNactivateCallback,Map_background,"6"); XtAddCallback(map_bgcolor[7], XmNactivateCallback,Map_background,"7"); XtAddCallback(map_bgcolor[8], XmNactivateCallback,Map_background,"8"); XtAddCallback(map_bgcolor[9], XmNactivateCallback,Map_background,"9"); #if !defined(NO_GRAPHICS) ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Raster_intensity_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell raster_intensity", al, ac); //raster_intensity_button XtVaCreateManagedWidget(langcode("PULDNMP008"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Raster_intensity_Pane, XmNmnemonic, langcode_hotkey("PULDNMP008"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[0] = XtVaCreateManagedWidget("0%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"0%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[1] = XtVaCreateManagedWidget("10%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"10%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[2] = XtVaCreateManagedWidget("20%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"20%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[3] = XtVaCreateManagedWidget("30%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"30%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[4] = XtVaCreateManagedWidget("40%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"40%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[5] = XtVaCreateManagedWidget("50%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"50%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[6] = XtVaCreateManagedWidget("60%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"60%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[7] = XtVaCreateManagedWidget("70%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"70%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[8] = XtVaCreateManagedWidget("80%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"80%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[9] = XtVaCreateManagedWidget("90%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"90%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); raster_intensity[10] = XtVaCreateManagedWidget("100%", xmPushButtonGadgetClass, Raster_intensity_Pane, XmNmnemonic,"100%", XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtSetSensitive(raster_intensity[(int)(raster_map_intensity * 10.0)],FALSE); //fprintf(stderr,"raster index = %d\n", // (int)(raster_map_intensity * 10.01) ); XtAddCallback(raster_intensity[0], XmNactivateCallback,Raster_intensity,"0.0"); XtAddCallback(raster_intensity[1], XmNactivateCallback,Raster_intensity,"0.1"); XtAddCallback(raster_intensity[2], XmNactivateCallback,Raster_intensity,"0.2"); XtAddCallback(raster_intensity[3], XmNactivateCallback,Raster_intensity,"0.3"); XtAddCallback(raster_intensity[4], XmNactivateCallback,Raster_intensity,"0.4"); XtAddCallback(raster_intensity[5], XmNactivateCallback,Raster_intensity,"0.5"); XtAddCallback(raster_intensity[6], XmNactivateCallback,Raster_intensity,"0.6"); XtAddCallback(raster_intensity[7], XmNactivateCallback,Raster_intensity,"0.7"); XtAddCallback(raster_intensity[8], XmNactivateCallback,Raster_intensity,"0.8"); XtAddCallback(raster_intensity[9], XmNactivateCallback,Raster_intensity,"0.9"); XtAddCallback(raster_intensity[10], XmNactivateCallback,Raster_intensity,"1.0"); #if defined(HAVE_MAGICK) // Adjust Gamma Correction gamma_adjust_button = XtVaCreateManagedWidget(langcode("GAMMA001"), xmPushButtonWidgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("GAMMA001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(gamma_adjust_button, XmNactivateCallback, Gamma_adjust, NULL); #endif // HAVE_MAGICK #endif // NO_GRAPHICS ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Map_station_label_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_station_label", al, ac); //map_station_label_button XtVaCreateManagedWidget(langcode("PULDNMP006"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMP006"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label0 = XtVaCreateManagedWidget(langcode("PULDNMSL01"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label1 = XtVaCreateManagedWidget(langcode("PULDNMSL02"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label2 = XtVaCreateManagedWidget(langcode("PULDNMSL03"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_station_label3 = XtVaCreateManagedWidget(langcode("PULDNMSL04"), xmPushButtonGadgetClass, Map_station_label_Pane, XmNmnemonic,langcode_hotkey("PULDNMSL04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); sel4_switch(letter_style,map_station_label3,map_station_label2,map_station_label1,map_station_label0); XtAddCallback(map_station_label0, XmNactivateCallback,Map_station_label,"0"); XtAddCallback(map_station_label1, XmNactivateCallback,Map_station_label,"1"); XtAddCallback(map_station_label2, XmNactivateCallback,Map_station_label,"2"); XtAddCallback(map_station_label3, XmNactivateCallback,Map_station_label,"3"); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; Map_icon_outline_Pane = XmCreatePulldownMenu(map_config_pane, "create_appshell map_icon_outline", al, ac); //map_icon_outline_button XtVaCreateManagedWidget(langcode("PULDNMP026"), xmCascadeButtonWidgetClass, map_config_pane, XmNsubMenuId, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMP026"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline0 = XtVaCreateManagedWidget(langcode("PULDNMIO01"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline1 = XtVaCreateManagedWidget(langcode("PULDNMIO02"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline2 = XtVaCreateManagedWidget(langcode("PULDNMIO03"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_icon_outline3 = XtVaCreateManagedWidget(langcode("PULDNMIO04"), xmPushButtonGadgetClass, Map_icon_outline_Pane, XmNmnemonic,langcode_hotkey("PULDNMIO04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); sel4_switch(icon_outline_style,map_icon_outline3,map_icon_outline2,map_icon_outline1,map_icon_outline0); XtAddCallback(map_icon_outline0, XmNactivateCallback,Map_icon_outline,"0"); XtAddCallback(map_icon_outline1, XmNactivateCallback,Map_icon_outline,"1"); XtAddCallback(map_icon_outline2, XmNactivateCallback,Map_icon_outline,"2"); XtAddCallback(map_icon_outline3, XmNactivateCallback,Map_icon_outline,"3"); #ifdef HAVE_LIBGEOTIFF drg_config_button= XtVaCreateManagedWidget(langcode("PULDNMP030"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP030"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(drg_config_button, XmNactivateCallback,Config_DRG,NULL); #endif // HAVE_LIBGEOTIFF // Geocoder Configuration geocoder_config_button = XtVaCreateManagedWidget(langcode("PULDNMP032"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP032"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2d", xmSeparatorGadgetClass, map_config_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Re-download Maps (Not from cache) redownload_maps_button = XtVaCreateManagedWidget(langcode("PULDNMP027"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP027"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(redownload_maps_button, XmNactivateCallback,Re_Download_Maps_Now,NULL); // Flush Entire Map Cache! flush_map_cache_button = XtVaCreateManagedWidget(langcode("PULDNMP028"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP028"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(flush_map_cache_button, XmNactivateCallback,Flush_Entire_Map_Queue,NULL); //Index Maps on startup index_maps_on_startup_button = XtVaCreateManagedWidget(langcode("PULDNMP022"), xmToggleButtonGadgetClass, map_config_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(index_maps_on_startup_button,XmNvalueChangedCallback,Index_maps_on_startup_toggle,"1"); if (index_maps_on_startup) { XmToggleButtonSetState(index_maps_on_startup_button,TRUE,FALSE); } map_indexer_button = XtVaCreateManagedWidget(langcode("PULDNMP023"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP023"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_all_indexer_button = XtVaCreateManagedWidget(langcode("PULDNMP024"), xmPushButtonGadgetClass, map_config_pane, XmNmnemonic,langcode_hotkey("PULDNMP024"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep2e", xmSeparatorGadgetClass, mappane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); map_pointer_menu_button = XtVaCreateManagedWidget(langcode("PULDNMP011"), xmPushButtonGadgetClass, mappane, XmNmnemonic,langcode_hotkey("PULDNMP011"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //- Stations Menu ----------------------------------------------------- locate_button = XtVaCreateManagedWidget(langcode("PULDNDP014"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP014"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); track_button = XtVaCreateManagedWidget(langcode("PULDNDP001"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(track_button, XmNactivateCallback,Track_station,NULL); download_trail_button = XtVaCreateManagedWidget(langcode("PULDNDP022"), xmPushButtonGadgetClass, stationspane, XmNmnemonic,langcode_hotkey("PULDNDP022"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(download_trail_button, XmNactivateCallback,Download_findu_trail,NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Store Data pulldown/tearoff store_data_pane = XmCreatePulldownMenu(stationspane, "store_data_pane", al, ac); // Export all > //store_data_button XtVaCreateManagedWidget(langcode("PULDNDP055"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, store_data_pane, XmNmnemonic, langcode_hotkey("PULDNDP055"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Export to KML file store_all_kml_button = XtVaCreateManagedWidget(langcode("PULDNDP056"), xmPushButtonGadgetClass, store_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(store_all_kml_button, XmNactivateCallback, store_all_kml_callback, NULL); #ifdef HAVE_DB // store to open databases store_all_db_button = XtVaCreateManagedWidget("Store to open databases", xmPushButtonGadgetClass, store_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //XtAddCallback(store_all_db_button, XmNvalueChangedCallback, store_all_db_button_callback, "1"); XtSetSensitive(store_all_db_button,FALSE); #endif // HAVE_DB (void)XtVaCreateManagedWidget("create_appshell sep3", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Filter Data pulldown/tearoff filter_data_pane = XmCreatePulldownMenu(stationspane, "filter_data_pane", al, ac); //filter_data_button XtVaCreateManagedWidget(langcode("PULDNDP032"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, filter_data_pane, XmNmnemonic, langcode_hotkey("PULDNDP032"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); select_none_button = XtVaCreateManagedWidget(langcode("PULDNDP040"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_none_button, XmNvalueChangedCallback, Select_none_toggle, "1"); if (Select_.none) { XmToggleButtonSetState(select_none_button, TRUE, FALSE); } select_mine_button = XtVaCreateManagedWidget(langcode("PULDNDP041"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_mine_button, XmNvalueChangedCallback, Select_mine_toggle, "1"); if (Select_.mine) { XmToggleButtonSetState(select_mine_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_mine_button, FALSE); } select_tnc_button = XtVaCreateManagedWidget(langcode("PULDNDP042"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_tnc_button, XmNvalueChangedCallback, Select_tnc_toggle, "1"); if (Select_.tnc) { XmToggleButtonSetState(select_tnc_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_tnc_button, FALSE); } select_direct_button = XtVaCreateManagedWidget(langcode("PULDNDP027"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_direct_button, XmNvalueChangedCallback, Select_direct_toggle, "1"); if (Select_.direct) { XmToggleButtonSetState(select_direct_button, TRUE, FALSE); } if (!Select_.tnc || Select_.none) { XtSetSensitive(select_direct_button, FALSE); } select_via_digi_button = XtVaCreateManagedWidget(langcode("PULDNDP043"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_via_digi_button, XmNvalueChangedCallback, Select_via_digi_toggle, "1"); if (Select_.via_digi) { XmToggleButtonSetState(select_via_digi_button, TRUE, FALSE); } if (!Select_.tnc || Select_.none) { XtSetSensitive(select_via_digi_button, FALSE); } select_net_button = XtVaCreateManagedWidget(langcode("PULDNDP034"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_net_button, XmNvalueChangedCallback, Select_net_toggle, "1"); if (Select_.net) { XmToggleButtonSetState(select_net_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_net_button, FALSE); } // "Select Tactical Calls Only" select_tactical_button = XtVaCreateManagedWidget(langcode("PULDNDP051"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_tactical_button, XmNvalueChangedCallback, Select_tactical_toggle, "1"); if (Select_.tactical) { XmToggleButtonSetState(select_tactical_button, TRUE, FALSE); } if (Select_.none) { XtSetSensitive(select_tactical_button, FALSE); } select_old_data_button = XtVaCreateManagedWidget(langcode("PULDNDP019"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_old_data_button, XmNvalueChangedCallback, Select_old_data_toggle, "1"); if (Select_.old_data) { XmToggleButtonSetState(select_old_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3a", xmSeparatorGadgetClass, filter_data_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); select_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP044"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_stations_button, XmNvalueChangedCallback, Select_stations_toggle, "1"); if (Select_.stations) { XmToggleButtonSetState(select_stations_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_stations_button, FALSE); } select_fixed_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP028"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_fixed_stations_button, XmNvalueChangedCallback, Select_fixed_stations_toggle, "1"); if (Select_.fixed_stations) { XmToggleButtonSetState(select_fixed_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_fixed_stations_button, FALSE); } select_moving_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP029"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_moving_stations_button, XmNvalueChangedCallback, Select_moving_stations_toggle, "1"); if (Select_.moving_stations) { XmToggleButtonSetState(select_moving_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_moving_stations_button, FALSE); } select_weather_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP030"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_weather_stations_button, XmNvalueChangedCallback, Select_weather_stations_toggle, "1"); if (Select_.weather_stations) { XmToggleButtonSetState(select_weather_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected()) { XtSetSensitive(select_weather_stations_button, FALSE); } select_CWOP_wx_stations_button = XtVaCreateManagedWidget(langcode("PULDNDP053"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_CWOP_wx_stations_button, XmNvalueChangedCallback, Select_CWOP_wx_stations_toggle, "1"); if (Select_.CWOP_wx_stations) { XmToggleButtonSetState(select_CWOP_wx_stations_button, TRUE, FALSE); } if (!Select_.stations || no_data_selected() || !Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } else { XtSetSensitive(select_CWOP_wx_stations_button, TRUE); } select_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP045"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_objects_button, XmNvalueChangedCallback, Select_objects_toggle, "1"); if (Select_.objects) { XmToggleButtonSetState(select_objects_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(select_objects_button, FALSE); } select_weather_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP026"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_weather_objects_button, XmNvalueChangedCallback, Select_weather_objects_toggle, "1"); if (Select_.weather_objects) { XmToggleButtonSetState(select_weather_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_weather_objects_button, FALSE); } select_gauge_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP039"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_gauge_objects_button, XmNvalueChangedCallback, Select_gauge_objects_toggle, "1"); if (Select_.gauge_objects) { XmToggleButtonSetState(select_gauge_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_gauge_objects_button, FALSE); } select_aircraft_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP057"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_aircraft_objects_button, XmNvalueChangedCallback, Select_aircraft_objects_toggle, "1"); if (Select_.aircraft_objects) { XmToggleButtonSetState(select_aircraft_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_aircraft_objects_button, FALSE); } select_vessel_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP058"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_vessel_objects_button, XmNvalueChangedCallback, Select_vessel_objects_toggle, "1"); if (Select_.vessel_objects) { XmToggleButtonSetState(select_vessel_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_vessel_objects_button, FALSE); } select_other_objects_button = XtVaCreateManagedWidget(langcode("PULDNDP031"), xmToggleButtonGadgetClass, filter_data_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(select_other_objects_button, XmNvalueChangedCallback, Select_other_objects_toggle, "1"); if (Select_.other_objects) { XmToggleButtonSetState(select_other_objects_button, TRUE, FALSE); } if (!Select_.objects || no_data_selected()) { XtSetSensitive(select_other_objects_button, FALSE); } // End of Data Filtering ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Displayed Info Filtering filter_display_pane = XmCreatePulldownMenu(stationspane, "filter_display_pane", al, ac); //filter_display_button XtVaCreateManagedWidget(langcode("PULDNDP033"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId, filter_display_pane, XmNmnemonic, langcode_hotkey("PULDNDP033"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_callsign_button = XtVaCreateManagedWidget(langcode("PULDNDP010"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_callsign_button, XmNvalueChangedCallback, Display_callsign_toggle, "1"); if (Display_.callsign) { XmToggleButtonSetState(display_callsign_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_callsign_button, FALSE); } display_label_all_trackpoints_button = XtVaCreateManagedWidget(langcode("PULDNDP052"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_label_all_trackpoints_button, XmNvalueChangedCallback, Display_label_all_trackpoints_toggle, "1"); if (Display_.label_all_trackpoints) { XmToggleButtonSetState(display_label_all_trackpoints_button, TRUE, FALSE); } if (!Display_.callsign || no_data_selected()) { XtSetSensitive(display_label_all_trackpoints_button, FALSE); } display_symbol_button = XtVaCreateManagedWidget(langcode("PULDNDP012"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_symbol_button, XmNvalueChangedCallback, Display_symbol_toggle, "1"); if (Display_.symbol) { XmToggleButtonSetState(display_symbol_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_symbol_button, FALSE); } display_symbol_rotate_button = XtVaCreateManagedWidget(langcode("PULDNDP011"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_symbol_rotate_button, XmNvalueChangedCallback, Display_symbol_rotate_toggle, "1"); if (Display_.symbol_rotate) { XmToggleButtonSetState(display_symbol_rotate_button, TRUE, FALSE); } if (!Display_.symbol || no_data_selected()) { XtSetSensitive(display_symbol_rotate_button, FALSE); } display_trail_button = XtVaCreateManagedWidget(langcode("PULDNDP007"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_trail_button, XmNvalueChangedCallback, Display_trail_toggle, "1"); if (Display_.trail) { XmToggleButtonSetState(display_trail_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_trail_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3b", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_course_button = XtVaCreateManagedWidget(langcode("PULDNDP003"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_course_button, XmNvalueChangedCallback, Display_course_toggle, "1"); if (Display_.course) { XmToggleButtonSetState(display_course_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_course_button, FALSE); } display_speed_button = XtVaCreateManagedWidget(langcode("PULDNDP004"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_speed_button, XmNvalueChangedCallback, Display_speed_toggle, "1"); if (Display_.speed) { XmToggleButtonSetState(display_speed_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_speed_button, FALSE); } display_speed_short_button = XtVaCreateManagedWidget(langcode("PULDNDP017"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_speed_short_button, XmNvalueChangedCallback, Display_speed_short_toggle, "1"); if (Display_.speed_short) { XmToggleButtonSetState(display_speed_short_button, TRUE, FALSE); } if (!Display_.speed || no_data_selected()) { XtSetSensitive(display_speed_short_button, FALSE); } display_altitude_button = XtVaCreateManagedWidget(langcode("PULDNDP002"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_altitude_button, XmNvalueChangedCallback, Display_altitude_toggle, "1"); if (Display_.altitude) { XmToggleButtonSetState(display_altitude_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_altitude_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3c", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_weather_button = XtVaCreateManagedWidget(langcode("PULDNDP009"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_weather_button, XmNvalueChangedCallback, Display_weather_toggle, "1"); if (Display_.weather) { XmToggleButtonSetState(display_weather_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_weather_button, FALSE); } display_weather_text_button = XtVaCreateManagedWidget(langcode("PULDNDP046"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_weather_text_button, XmNvalueChangedCallback, Display_weather_text_toggle, "1"); if (Display_.weather_text) { XmToggleButtonSetState(display_weather_text_button, TRUE, FALSE); } if (!Display_.weather || no_data_selected()) { XtSetSensitive(display_weather_text_button, FALSE); } display_temperature_only_button = XtVaCreateManagedWidget(langcode("PULDNDP018"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_temperature_only_button, XmNvalueChangedCallback, Display_temperature_only_toggle, "1"); if (Display_.temperature_only) { XmToggleButtonSetState(display_temperature_only_button, TRUE, FALSE); } if (!Display_.weather || !Display_.weather_text || no_data_selected()) { XtSetSensitive(display_temperature_only_button, FALSE); } display_wind_barb_button = XtVaCreateManagedWidget(langcode("PULDNDP047"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_wind_barb_button, XmNvalueChangedCallback, Display_wind_barb_toggle, "1"); if (Display_.wind_barb) { XmToggleButtonSetState(display_wind_barb_button, TRUE, FALSE); } if (!Display_.weather || no_data_selected()) { XtSetSensitive(display_wind_barb_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3d", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_aloha_circle_button = XtVaCreateManagedWidget(langcode("PULDNDP054"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_aloha_circle_button, XmNvalueChangedCallback, Display_aloha_circle_toggle, "1"); if (Display_.aloha_circle) { XmToggleButtonSetState(display_aloha_circle_button, TRUE, FALSE); } display_ambiguity_button = XtVaCreateManagedWidget(langcode("PULDNDP013"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_ambiguity_button, XmNvalueChangedCallback, Display_ambiguity_toggle, "1"); if (Display_.ambiguity) { XmToggleButtonSetState(display_ambiguity_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_ambiguity_button, FALSE); } display_phg_button = XtVaCreateManagedWidget(langcode("PULDNDP008"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_phg_button, XmNvalueChangedCallback, Display_phg_toggle, "1"); if (Display_.phg) { XmToggleButtonSetState(display_phg_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_phg_button, FALSE); } display_default_phg_button = XtVaCreateManagedWidget(langcode("PULDNDP021"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_default_phg_button, XmNvalueChangedCallback, Display_default_phg_toggle, "1"); if (Display_.default_phg) { XmToggleButtonSetState(display_default_phg_button, TRUE, FALSE); } if (!Display_.phg || no_data_selected()) { XtSetSensitive(display_default_phg_button, FALSE); } display_phg_of_moving_button = XtVaCreateManagedWidget(langcode("PULDNDP020"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_phg_of_moving_button, XmNvalueChangedCallback, Display_phg_of_moving_toggle, "1"); if (Display_.phg_of_moving) { XmToggleButtonSetState(display_phg_of_moving_button, TRUE, FALSE); } if (!Display_.phg || no_data_selected()) { XtSetSensitive(display_phg_of_moving_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3e", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_df_data_button = XtVaCreateManagedWidget(langcode("PULDNDP023"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_data_button, XmNvalueChangedCallback, Display_df_data_toggle, "1"); if (Display_.df_data) { XmToggleButtonSetState(display_df_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_df_data_button, FALSE); } display_df_beamwidth_data_button = XtVaCreateManagedWidget(langcode("PULDNDP123"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_beamwidth_data_button, XmNvalueChangedCallback, Display_df_beamwidth_data_toggle, "1"); if (Display_.df_beamwidth_data) { XmToggleButtonSetState(display_df_beamwidth_data_button, TRUE, FALSE); } if (!Display_.df_data || no_data_selected()) { XtSetSensitive(display_df_beamwidth_data_button, FALSE); } display_df_bearing_data_button = XtVaCreateManagedWidget(langcode("PULDNDP223"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_df_bearing_data_button, XmNvalueChangedCallback, Display_df_bearing_data_toggle, "1"); if (Display_.df_bearing_data) { XmToggleButtonSetState(display_df_bearing_data_button, TRUE, FALSE); } if (!Display_.df_data || no_data_selected()) { XtSetSensitive(display_df_bearing_data_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3e", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_dr_data_button = XtVaCreateManagedWidget(langcode("PULDNDP035"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_data_button, XmNvalueChangedCallback, Display_dr_data_toggle, "1"); if (Display_.dr_data) { XmToggleButtonSetState(display_dr_data_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_dr_data_button, FALSE); } display_dr_arc_button = XtVaCreateManagedWidget(langcode("PULDNDP036"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_arc_button, XmNvalueChangedCallback, Display_dr_arc_toggle, "1"); if (Display_.dr_arc) { XmToggleButtonSetState(display_dr_arc_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_arc_button, FALSE); } display_dr_course_button = XtVaCreateManagedWidget(langcode("PULDNDP037"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_course_button, XmNvalueChangedCallback, Display_dr_course_toggle, "1"); if (Display_.dr_course) { XmToggleButtonSetState(display_dr_course_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_course_button, FALSE); } display_dr_symbol_button = XtVaCreateManagedWidget(langcode("PULDNDP038"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dr_symbol_button, XmNvalueChangedCallback, Display_dr_symbol_toggle, "1"); if (Display_.dr_symbol) { XmToggleButtonSetState(display_dr_symbol_button, TRUE, FALSE); } if (!Display_.dr_data || no_data_selected()) { XtSetSensitive(display_dr_symbol_button, FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep3f", xmSeparatorGadgetClass, filter_display_pane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); display_dist_bearing_button = XtVaCreateManagedWidget(langcode("PULDNDP005"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_dist_bearing_button, XmNvalueChangedCallback, Display_dist_bearing_toggle, "1"); if (Display_.dist_bearing) { XmToggleButtonSetState(display_dist_bearing_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_dist_bearing_button, FALSE); } display_last_heard_button = XtVaCreateManagedWidget(langcode("PULDNDP024"), xmToggleButtonGadgetClass, filter_display_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(display_last_heard_button, XmNvalueChangedCallback, Display_last_heard_toggle, "1"); if (Display_.last_heard) { XmToggleButtonSetState(display_last_heard_button, TRUE, FALSE); } if (no_data_selected()) { XtSetSensitive(display_last_heard_button, FALSE); } // End of Displayed Info Filtering (void)XtVaCreateManagedWidget("create_appshell sep3g", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep3h", xmSeparatorGadgetClass, stationspane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_config_pane = XmCreatePulldownMenu(stationspane, "stations_config_pane", al, ac); //station_config_button XtVaCreateManagedWidget(langcode("PULDNFI001"), xmCascadeButtonGadgetClass, stationspane, XmNsubMenuId,station_config_pane, XmNmnemonic,langcode_hotkey("PULDNFI001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); object_history_refresh_button = XtVaCreateManagedWidget(langcode("PULDNDP048"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP048"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); object_history_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP025"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Clear All Tactical Calls" tactical_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP049"), xmPushButtonGadgetClass, station_config_pane, // XmNmnemonic,langcode_hotkey("PULDNDP049"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Clear Tactical Call History" tactical_history_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP050"), xmPushButtonGadgetClass, station_config_pane, // XmNmnemonic,langcode_hotkey("PULDNDP050"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); tracks_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP016"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP016"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); station_clear_button = XtVaCreateManagedWidget(langcode("PULDNDP015"), xmPushButtonGadgetClass, station_config_pane, XmNmnemonic,langcode_hotkey("PULDNDP015"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //-------------------------------------------------------------------- /* Messages */ send_message_to_button = XtVaCreateManagedWidget(langcode("PULDNMG001"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); show_pending_messages_button = XtVaCreateManagedWidget(langcode("PULDNMG007"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG007"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); open_messages_group_button = XtVaCreateManagedWidget(langcode("PULDNMG002"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); clear_messages_button= XtVaCreateManagedWidget(langcode("PULDNMG003"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep4", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); General_q_button = XtVaCreateManagedWidget(langcode("PULDQUS001"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS001"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); IGate_q_button = XtVaCreateManagedWidget(langcode("PULDQUS002"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS002"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); WX_q_button = XtVaCreateManagedWidget(langcode("PULDQUS003"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDQUS003"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep4a", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); auto_msg_set_button = XtVaCreateManagedWidget(langcode("PULDNMG004"), xmPushButtonGadgetClass, messagepane, XmNmnemonic,langcode_hotkey("PULDNMG004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); auto_msg_toggle = XtVaCreateManagedWidget(langcode("PULDNMG005"), xmToggleButtonGadgetClass, messagepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(auto_msg_toggle,XmNvalueChangedCallback,Auto_msg_toggle,"1"); (void)XtVaCreateManagedWidget("create_appshell sep5", xmSeparatorGadgetClass, messagepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); satellite_msg_ack_toggle = XtVaCreateManagedWidget(langcode("PULDNMG006"), xmToggleButtonGadgetClass, messagepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(satellite_msg_ack_toggle,XmNvalueChangedCallback,Satellite_msg_ack_toggle,"1"); /* Interface */ iface_connect_button = XtVaCreateManagedWidget(langcode("PULDNTNT04"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT04"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sep5a", xmSeparatorGadgetClass, ifacepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); transmit_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT03"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(transmit_disable_toggle,XmNvalueChangedCallback,Transmit_disable_toggle,"1"); if (transmit_disable) { XmToggleButtonSetState(transmit_disable_toggle,TRUE,FALSE); } posit_tx_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT05"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(posit_tx_disable_toggle,XmNvalueChangedCallback,Posit_tx_disable_toggle,"1"); if (posit_tx_disable) { XmToggleButtonSetState(posit_tx_disable_toggle,TRUE,FALSE); } if (transmit_disable) { XtSetSensitive(posit_tx_disable_toggle,FALSE); } object_tx_disable_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT06"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(object_tx_disable_toggle,XmNvalueChangedCallback,Object_tx_disable_toggle,"1"); if (object_tx_disable) { XmToggleButtonSetState(object_tx_disable_toggle,TRUE,FALSE); } if (transmit_disable) { XtSetSensitive(object_tx_disable_toggle,FALSE); } server_port_toggle = XtVaCreateManagedWidget(langcode("PULDNTNT11"), xmToggleButtonGadgetClass, ifacepane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(server_port_toggle,XmNvalueChangedCallback,Server_port_toggle,"1"); if (enable_server_port) { XmToggleButtonSetState(server_port_toggle,TRUE,FALSE); } (void)XtVaCreateManagedWidget("create_appshell sep5b", xmSeparatorGadgetClass, ifacepane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); iface_transmit_now = XtVaCreateManagedWidget(langcode("PULDNTNT01"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); if (transmit_disable) { XtSetSensitive(iface_transmit_now,FALSE); } #ifdef HAVE_GPSMAN Fetch_gps_track = XtVaCreateManagedWidget(langcode("PULDNTNT07"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT07"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Fetch_gps_route = XtVaCreateManagedWidget(langcode("PULDNTNT08"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT08"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Fetch_gps_waypoints = XtVaCreateManagedWidget(langcode("PULDNTNT09"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT09"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* Send_gps_track = XtVaCreateManagedWidget(langcode("Send_Tr"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Tr"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Send_gps_route = XtVaCreateManagedWidget(langcode("Send_Rt"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Rt"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); Send_gps_waypoints = XtVaCreateManagedWidget(langcode("Send_Wp"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("Send_Wp"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); */ Fetch_RINO_waypoints = XtVaCreateManagedWidget(langcode("PULDNTNT10"), xmPushButtonGadgetClass, ifacepane, XmNmnemonic,langcode_hotkey("PULDNTNT10"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #endif // HAVE_GPSMAN /* Help*/ help_about = XtVaCreateManagedWidget(langcode("PULDNHEL01"), xmPushButtonGadgetClass, helppane, XmNmnemonic,langcode_hotkey("PULDNHEL01"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); help_help = XtVaCreateManagedWidget(langcode("PULDNHEL02"), xmPushButtonGadgetClass, helppane, XmNmnemonic,langcode_hotkey("PULDNHEL02"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); (void)XtVaCreateManagedWidget("create_appshell sephelp", xmSeparatorGadgetClass, helppane, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; help_emergency_pane = XmCreatePulldownMenu(helppane, "help_emergency_pane", al, ac); //help_emergency_button XtVaCreateManagedWidget(langcode("PULDNHEL03"), xmCascadeButtonGadgetClass, helppane, XmNsubMenuId,help_emergency_pane, XmNmnemonic,langcode_hotkey("PULDNHEL03"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); emergency_beacon_toggle = XtVaCreateManagedWidget(langcode("PULDNHEL04"), xmToggleButtonGadgetClass, help_emergency_pane, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(emergency_beacon_toggle,XmNvalueChangedCallback,Emergency_beacon_toggle,"1"); if (emergency_beacon) { XmToggleButtonSetState(emergency_beacon_toggle,TRUE,FALSE); } /* view */ XtAddCallback(stations_button, XmNactivateCallback,Station_List,"0"); XtAddCallback(mobile_button, XmNactivateCallback,Station_List,"1"); XtAddCallback(weather_button, XmNactivateCallback,Station_List,"2"); XtAddCallback(localstations_button, XmNactivateCallback,Station_List,"3"); XtAddCallback(laststations_button, XmNactivateCallback,Station_List,"4"); XtAddCallback(objectstations_button,XmNactivateCallback,Station_List,"5"); XtAddCallback(objectmystations_button,XmNactivateCallback,Station_List,"6"); XtAddCallback(CAD1,XmNactivateCallback,Draw_CAD_Objects_list_dialog,NULL); /* button callbacks */ XtAddCallback(General_q_button, XmNactivateCallback,General_query,""); XtAddCallback(IGate_q_button, XmNactivateCallback,IGate_query,NULL); XtAddCallback(WX_q_button, XmNactivateCallback,WX_query,NULL); XtAddCallback(station_clear_button, XmNactivateCallback,Stations_Clear,NULL); XtAddCallback(tracks_clear_button, XmNactivateCallback,Tracks_All_Clear,NULL); XtAddCallback(object_history_refresh_button, XmNactivateCallback,Object_History_Refresh,NULL); XtAddCallback(object_history_clear_button, XmNactivateCallback,Object_History_Clear,NULL); XtAddCallback(tactical_clear_button, XmNactivateCallback,Tactical_Callsign_Clear,NULL); XtAddCallback(tactical_history_clear_button, XmNactivateCallback,Tactical_Callsign_History_Clear,NULL); XtAddCallback(exit_button, XmNactivateCallback,Menu_Quit,NULL); XtAddCallback(defaults_button, XmNactivateCallback,Configure_defaults,NULL); XtAddCallback(timing_button, XmNactivateCallback,Configure_timing,NULL); XtAddCallback(coordinates_button, XmNactivateCallback,Configure_coordinates,NULL); XtAddCallback(aa_button, XmNactivateCallback,Configure_audio_alarms,NULL); XtAddCallback(speech_button, XmNactivateCallback,Configure_speech,NULL); XtAddCallback(smart_beacon_button, XmNactivateCallback,Smart_Beacon,NULL); XtAddCallback(map_indexer_button, XmNactivateCallback,Index_Maps_Now,NULL); XtAddCallback(map_all_indexer_button,XmNactivateCallback,Index_Maps_Now,"1"); XtAddCallback(geocoder_config_button,XmNactivateCallback,Configure_geocoder_settings,NULL); XtAddCallback(station_button, XmNactivateCallback,Configure_station,NULL); XtAddCallback(help_about, XmNactivateCallback,Help_About,NULL); XtAddCallback(help_help, XmNactivateCallback,Help_Index,NULL); /* TNC */ XtAddCallback(iface_transmit_now, XmNactivateCallback,TNC_Transmit_now,NULL); #ifdef HAVE_GPSMAN XtAddCallback(Fetch_gps_track, XmNactivateCallback,GPS_operations,"1"); XtAddCallback(Fetch_gps_route, XmNactivateCallback,GPS_operations,"2"); XtAddCallback(Fetch_gps_waypoints, XmNactivateCallback,GPS_operations,"3"); // XtAddCallback(Send_gps_track, XmNactivateCallback,GPS_operations,"4"); // XtAddCallback(Send_gps_route, XmNactivateCallback,GPS_operations,"5"); // XtAddCallback(Send_gps_waypoints, XmNactivateCallback,GPS_operations,"6"); XtAddCallback(Fetch_RINO_waypoints, XmNactivateCallback,GPS_operations,"7"); #endif // HAVE_GPSMAN XtAddCallback(auto_msg_set_button,XmNactivateCallback,Auto_msg_set,NULL); XtAddCallback(iface_connect_button, XmNactivateCallback,control_interface,NULL); XtAddCallback(open_file_button, XmNactivateCallback,Read_File_Selection,NULL); XtAddCallback(bullet_button, XmNactivateCallback,Bulletins,NULL); XtAddCallback(packet_data_button, XmNactivateCallback,Display_data,NULL); XtAddCallback(locate_button, XmNactivateCallback,Locate_station,NULL); XtAddCallback(alert_button, XmNactivateCallback,Display_Wx_Alert,NULL); XtAddCallback(view_messages_button, XmNactivateCallback,view_all_messages,NULL); XtAddCallback(gps_status_button,XmNactivateCallback,view_gps_status,NULL); XtAddCallback(map_pointer_menu_button, XmNactivateCallback,menu_link_for_mouse_menu,NULL); XtAddCallback(wx_station_button, XmNactivateCallback,WX_station,NULL); XtAddCallback(jump_button, XmNactivateCallback, Jump_location, NULL); XtAddCallback(locate_place_button, XmNactivateCallback,Locate_place,NULL); XtAddCallback(geocode_place_button, XmNactivateCallback,Geocoder_place,NULL); XtAddCallback(coordinate_calculator_button, XmNactivateCallback,Coordinate_calc,""); XtAddCallback(send_message_to_button, XmNactivateCallback,Send_message,NULL); XtAddCallback(show_pending_messages_button, XmNactivateCallback,Show_pending_messages,NULL); XtAddCallback(open_messages_group_button, XmNactivateCallback,Send_message,"*"); XtAddCallback(clear_messages_button,XmNactivateCallback,Clear_messages,NULL); XtAddCallback(save_button, XmNactivateCallback,Save_Config,NULL); XtAddCallback(test_button, XmNactivateCallback,Test,NULL); if (!debug_level) { XtSetSensitive(test_button, False); } XtAddCallback(debug_level_button, XmNactivateCallback, Change_Debug_Level,NULL); // XtSetSensitive(debug_level_button, False); XtAddCallback(uptime_button, XmNactivateCallback, Compute_Uptime,NULL); XtAddCallback(aloha_button, XmNactivateCallback, Show_Aloha_Stats,NULL); //XtSetSensitive(uptime_button, False); // Toolbar toolbar = XtVaCreateWidget("Toolbar form", xmFormWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, menubar, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); trackme_button=XtVaCreateManagedWidget(langcode("POPUPMA022"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, -5, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(trackme_button,XmNvalueChangedCallback,Track_Me,"1"); measure_button=XtVaCreateManagedWidget(langcode("POPUPMA020"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trackme_button, XmNtopOffset, -7, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, -5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(measure_button,XmNvalueChangedCallback,Measure_Distance,"1"); cad_draw_button=XtVaCreateManagedWidget(langcode("POPUPMA030"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, -5, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, trackme_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(cad_draw_button,XmNvalueChangedCallback,Draw_CAD_Objects_mode,NULL); move_button=XtVaCreateManagedWidget(langcode("POPUPMA021"), xmToggleButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, cad_draw_button, XmNtopOffset, -7, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, -5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, trackme_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 0, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(move_button,XmNvalueChangedCallback,Move_Object,"1"); #ifdef ARROWS zoom_in_menu=XtVaCreateManagedWidget(langcode("POPUPMA002"), xmPushButtonWidgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, cad_draw_button, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(zoom_in_menu,XmNactivateCallback,Zoom_in_no_pan,NULL); if (map_lock_pan_zoom) { XtSetSensitive(zoom_in_menu, FALSE); } zoom_out_menu=XtVaCreateManagedWidget(langcode("POPUPMA003"), xmPushButtonWidgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_in_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); XtAddCallback(zoom_out_menu,XmNactivateCallback,Zoom_out_no_pan,NULL); if (map_lock_pan_zoom) { XtSetSensitive(zoom_out_menu, FALSE); } pan_left_menu=XtVaCreateManagedWidget("create_appshell arrow1_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_out_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_LEFT, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_left_menu,XmNactivateCallback,Pan_left,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_left_menu, FALSE); } pan_up_menu=XtVaCreateManagedWidget("create_appshell arrow2_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_left_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_UP, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_up_menu,XmNactivateCallback,Pan_up,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_up_menu, FALSE); } pan_down_menu=XtVaCreateManagedWidget("create_appshell arrow3_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_up_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_DOWN, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_down_menu,XmNactivateCallback,Pan_down,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_down_menu, FALSE); } pan_right_menu=XtVaCreateManagedWidget("create_appshell arrow4_menu", xmArrowButtonGadgetClass, toolbar, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, pan_down_menu, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNarrowDirection, XmARROW_RIGHT, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, NULL); XtAddCallback(pan_right_menu,XmNactivateCallback,Pan_right,NULL); if (map_lock_pan_zoom) { XtSetSensitive(pan_right_menu, FALSE); } #endif // ARROWS #define FONT_WIDTH 9 // Create bottom text area // #ifdef USE_TWO_STATUS_LINES // Quantity of stations box, Bottom left corner text3 = XtVaCreateWidget("create_appshell text_output3", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 14, XmNwidth, ((22*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom level box, Bottom second from left text4 = XtVaCreateWidget("create_appshell text_output4", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((15*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Log indicator box, Bottom second from right log_indicator = XtVaCreateWidget(langcode("BBARSTA043"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*FONT_WIDTH)), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text4, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interface status indicators, Bottom right corner iface_da = XtVaCreateWidget("create_appshell iface", xmDrawingAreaWidgetClass, form, XmNwidth, 22*(MAX_IFACE_DEVICES/2), XmNheight, 20, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, log_indicator, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Message box, on Top left text = XtVaCreateWidget("create_appshell text_output", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 30, XmNwidth, ((29*FONT_WIDTH)+2), XmNtopOffset, 4, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text3, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Coordinate display box, Top right text2 = XtVaCreateWidget("create_appshell text_output2", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 35, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text3, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #else // Message box, on left text = XtVaCreateWidget("create_appshell text_output", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 30, XmNwidth, ((29*FONT_WIDTH)+2), XmNtopOffset, 4, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Coordinate display box, 2nd from left text2 = XtVaCreateWidget("create_appshell text_output2", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 35, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Quantity of stations box, 3rd from left text3 = XtVaCreateWidget("create_appshell text_output3", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 14, XmNwidth, ((10*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text2, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom level box, 3rd from right text4 = XtVaCreateWidget("create_appshell text_output4", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((8*FONT_WIDTH)+2), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Log indicator box, 2nd from right log_indicator = XtVaCreateWidget(langcode("BBARSTA043"), xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*FONT_WIDTH)), XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, text4, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interface status indicators, on right iface_da = XtVaCreateWidget("create_appshell iface", xmDrawingAreaWidgetClass, form, XmNwidth, 22*(MAX_IFACE_DEVICES/2), XmNheight, 20, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, log_indicator, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); #endif // USE_TWO_STATUS_LINES // The separator goes on top of the text box no matter how // many lines the status bar is, so I'm putting if after the // endif statement - DCR sep = XtVaCreateManagedWidget("create_appshell sep6", xmSeparatorGadgetClass, form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, text, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Map drawing area da_width = (Dimension)screen_width; da_height = (Dimension)screen_height; da = XtVaCreateWidget("create_appshell da", xmDrawingAreaWidgetClass, form, XmNwidth, da_width, XmNheight, da_height, XmNunitType, XmPIXELS, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menubar, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, sep, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //------------------------------------------------------------------------- // Create the mouse menus here ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; #ifdef SWAP_MOUSE_BUTTONS // // Motif 2.2.2 (and perhaps earlier, back to version 2.0) has a // problem where the XmNmenuPost doesn't work properly for // modifiers (CapsLock/ScrollLock/NumLock/etc). We're reverting // back to the Motif 1.x method of doing things. It works! // //XtSetArg(al[ac], XmNmenuPost, ""); ac++; // Set for popup menu on button 1 XtSetArg(al[ac], XmNwhichButton, 1); ac++; // Enable popup menu on button 1 #else // SWAP_MOUSE_BUTTONS // // Motif 2.2.2 (and perhaps earlier, back to version 2.0) has a // problem where the XmNmenuPost doesn't work properly for // modifiers (CapsLock/ScrollLock/NumLock/etc). We're reverting // back to the Motif 1.x method of doing things. It works! // //XtSetArg(al[ac], XmNmenuPost, ""); ac++; // Set for popup menu on button 3 XtSetArg(al[ac], XmNwhichButton, 3); ac++; // Enable popup menu on button 3 #endif // SWAP_MOUSE_BUTTONS XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; // Right menu popup (right mouse button or button 3) right_menu_popup = XmCreatePopupMenu(da, "create_appshell Menu Popup", al, ac); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "Options" (void)XtCreateManagedWidget(langcode("POPUPMA001"), xmLabelWidgetClass, right_menu_popup, al, ac); (void)XtCreateManagedWidget("create_appshell sep7", xmSeparatorWidgetClass, right_menu_popup, al, ac); // "Center" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA00c")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_ctr=XtCreateManagedWidget(langcode("POPUPMA00c"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(pan_ctr,XmNactivateCallback,Pan_ctr,NULL); // "Station info" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA015")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; station_info=XtCreateManagedWidget(langcode("POPUPMA015"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(station_info,XmNactivateCallback,Station_info,NULL); // Send Message To ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("PULDNMG001")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; send_message_to=XtCreateManagedWidget(langcode("PULDNMG001"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(send_message_to,XmNactivateCallback,Station_info,"4"); // Map Bookmarks ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("PULDNMP012")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; jump_button2=XtCreateManagedWidget(langcode("PULDNMP012"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(jump_button2,XmNactivateCallback,Jump_location, NULL); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell zoom sub", al, ac); // "Zoom level" //zoom_level XtVaCreateManagedWidget(langcode("POPUPMA004"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,zoom_sub, XmNmnemonic,langcode_hotkey("POPUPMA004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Zoom in" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA002")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_in=XtCreateManagedWidget(langcode("POPUPMA002"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zoom_in,XmNactivateCallback,Zoom_in,NULL); // Zoom out" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA003")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zoom_out=XtCreateManagedWidget(langcode("POPUPMA003"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zoom_out,XmNactivateCallback,Zoom_out,NULL); // "1" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA005")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl1=XtCreateManagedWidget(langcode("POPUPMA005"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl1,XmNactivateCallback,Zoom_level,"1"); // "16" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA006")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl2=XtCreateManagedWidget(langcode("POPUPMA006"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl2,XmNactivateCallback,Zoom_level,"2"); // "64" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA007")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl3=XtCreateManagedWidget(langcode("POPUPMA007"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl3,XmNactivateCallback,Zoom_level,"3"); // "256" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA008")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl4=XtCreateManagedWidget(langcode("POPUPMA008"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl4,XmNactivateCallback,Zoom_level,"4"); // "1024" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA009")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl5=XtCreateManagedWidget(langcode("POPUPMA009"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl5,XmNactivateCallback,Zoom_level,"5"); // "8192" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA010")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl6=XtCreateManagedWidget(langcode("POPUPMA010"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl6,XmNactivateCallback,Zoom_level,"6"); // "Entire World" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA017")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl7=XtCreateManagedWidget(langcode("POPUPMA017"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl7,XmNactivateCallback,Zoom_level,"7"); // "10% out" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'o'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl8=XtCreateManagedWidget(langcode("POPUPMA035"), // 10% out xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl8,XmNactivateCallback,Zoom_level,"8"); // "10% in" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'i'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zl9=XtCreateManagedWidget(langcode("POPUPMA036"), // 10% in xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zl9,XmNactivateCallback,Zoom_level,"9"); // "Custom Zoom Level" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, 'i'); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; zlC=XtCreateManagedWidget(langcode("POPUPMA034"), xmPushButtonGadgetClass, zoom_sub, al, ac); XtAddCallback(zlC,XmNactivateCallback,Zoom_level,"10"); // "Last map pos/zoom" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA016")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; last_loc=XtCreateManagedWidget(langcode("POPUPMA016"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(last_loc,XmNactivateCallback,Last_location,NULL); (void)XtCreateManagedWidget("create_appshell sep7a", xmSeparatorWidgetClass, right_menu_popup, al, ac); // "Object -> Create" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA018")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; set_object=XtCreateManagedWidget(langcode("POPUPMA018"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(set_object,XmNactivateCallback,Set_Del_Object,NULL); // "Object -> Modify" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA019")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; modify_object=XtCreateManagedWidget(langcode("POPUPMA019"), xmPushButtonGadgetClass, right_menu_popup, al, ac); XtAddCallback(modify_object,XmNactivateCallback,Station_info,"1"); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Display a list of predefined SAR or Public service event objects. sar_object_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell sar_object_sub", al, ac); // "Predefined Objects" //sar_object_menu XtVaCreateManagedWidget(langcode("POPUPMA045"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,sar_object_sub, // XmNmnemonic,langcode_hotkey("POPUPMA045"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); BuildPredefinedSARMenu_UI(&sar_object_sub); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; XtCreateManagedWidget("create_appshell sep7b", xmSeparatorWidgetClass, right_menu_popup, al, ac); XtCreateManagedWidget("create_appshell sep7c", xmSeparatorWidgetClass, right_menu_popup, al, ac); ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNtearOffModel, XmTEAR_OFF_ENABLED); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell pan sub", al, ac); // "Pan" // pan_menu=XtVaCreateManagedWidget(langcode(""), //pan_menu XtVaCreateManagedWidget("Pan", xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,pan_sub, // XmNmnemonic,langcode_hotkey("POPUPMA004"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Pan Up" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA011")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_up=XtCreateManagedWidget(langcode("POPUPMA011"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_up=XtVaCreateManagedWidget("create_appshell arrow1", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_UP, // NULL); XtAddCallback(pan_up,XmNactivateCallback,Pan_up,NULL); // "Pan Left" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA013")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_left=XtCreateManagedWidget(langcode("POPUPMA013"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_left=XtVaCreateManagedWidget("create_appshell arrow3", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_LEFT, // NULL); XtAddCallback(pan_left,XmNactivateCallback,Pan_left,NULL); // "Pan Right" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA014")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_right=XtCreateManagedWidget(langcode("POPUPMA014"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_right=XtVaCreateManagedWidget("create_appshell arrow4", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_RIGHT, // NULL); XtAddCallback(pan_right,XmNactivateCallback,Pan_right,NULL); // "Pan Down" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA012")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; pan_down=XtCreateManagedWidget(langcode("POPUPMA012"), xmPushButtonGadgetClass, pan_sub, al, ac); //pan_down=XtVaCreateManagedWidget("create_appshell arrow2", // xmArrowButtonGadgetClass, // right_menu_popup, // XmNarrowDirection, XmARROW_DOWN, // NULL); XtAddCallback(pan_down,XmNactivateCallback,Pan_down,NULL); XtCreateManagedWidget("create_appshell sep7d", xmSeparatorWidgetClass, right_menu_popup, al, ac); move_my_sub=XmCreatePulldownMenu(right_menu_popup, "create_appshell move_my sub", al, ac); //move_my_menu XtVaCreateManagedWidget(langcode("POPUPMA025"), xmCascadeButtonGadgetClass, right_menu_popup, XmNsubMenuId,move_my_sub, XmNmnemonic,langcode_hotkey("POPUPMA025"), XmNfontList, fontlist1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Move my station here" ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNmnemonic, langcode_hotkey("POPUPMA025")); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; setmyposition=XtCreateManagedWidget(langcode("POPUPMA025"), xmPushButtonGadgetClass, move_my_sub, al, ac); XtAddCallback(setmyposition,XmNactivateCallback,SetMyPosition,"1"); //------------------------------------------------------------------------- /* mouse tracking */ XtAddEventHandler(da,LeaveWindowMask,FALSE,ClearTrackMouse,(XtPointer)text2); XtAddEventHandler(da,PointerMotionMask,FALSE,TrackMouse,(XtPointer)text2); // Popup menus XtAddEventHandler(da, ButtonPressMask, FALSE, (XtEventHandler)Mouse_button_handler, NULL); //XtAddEventHandler(da,ButtonReleaseMask,FALSE,(XtEventHandler)Mouse_button_handler,NULL); // If adding any more widgets here, increase the size of the // children[] array above. ac = 0; children[ac++] = text; children[ac++] = text2; children[ac++] = text3; children[ac++] = text4; children[ac++] = log_indicator; children[ac++] = iface_da; children[ac++] = menubar; children[ac++] = toolbar; children[ac++] = da; XtManageChildren(children, ac); ac = 0; // This one needs to be done after all of // the above 'cuz it contains all of them. XtManageChild(form); WM_DELETE_WINDOW = XmInternAtom(XtDisplay(appshell),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(appshell, WM_DELETE_WINDOW, Window_Quit, (XtPointer) NULL); XtAddCallback(appshell,XtNsaveCallback, save_state, (XtPointer) NULL); XtAddCallback(appshell,XtNdieCallback, Window_Quit, (XtPointer) NULL); XmTextFieldSetString(text,""); XtManageChild(text); display_zoom_status(); XtManageChild(text); // We get this error on some systems if XtRealizeWidget() is called // without setting width/height values first: // "Error: Shell widget xastir has zero width and/or height" XtRealizeWidget (appshell); // Flush all pending requests to the X server. XFlush(display); create_gc(da); // Fill the drawing area with the background color. (void)XSetForeground(XtDisplay(da),gc,MY_BG_COLOR); // Not a mistake! (void)XSetBackground(XtDisplay(da),gc,MY_BG_COLOR); (void)XFillRectangle(XtDisplay(appshell), XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height); XtAddCallback (da, XmNinputCallback, da_input,NULL); XtAddCallback (da, XmNresizeCallback, da_resize,NULL); XtAddCallback (da, XmNexposeCallback, da_expose,(XtPointer)text); // Don't discard events in X11 queue, but wait for the X11 // server to catch up. (void)XSync(XtDisplay(appshell), False); // Send the window manager hints // XSetWMHints(display, XtWindow(appshell), wm_hints); // Set up the icon icon_pixmap = XCreateBitmapFromData(display, XtWindow(appshell), (char *)icon_bits, icon_width, // icon_bitmap_width, icon_height); // icon_bitmap_height XSetStandardProperties(display, XtWindow(appshell), title ? title: "Xastir", // window name "Xastir", // icon name icon_pixmap, // pixmap for icon 0, 0, // argv and argc for restarting NULL); // size hints if (title) { free(title); title = NULL; } if (track_me) { XmToggleButtonSetState(trackme_button,TRUE,TRUE); } else { XmToggleButtonSetState(trackme_button,FALSE,TRUE); } // Flush all pending requests to the X server. XFlush(display); // Don't discard events in X11 queue, but wait for the X11 // server to catch up. (void)XSync(XtDisplay(appshell), False); // Reset the minimum window size so that we can adjust the // window downwards again, but only down to size 61. If we go // any smaller height-wise then we end up getting segfaults, // probably because we're trying to update some widgets that // aren't visible at that point. // XtVaSetValues(appshell, XmNminWidth, 61, XmNminHeight, 61, XmNwidth, my_appshell_width, XmNheight, my_appshell_height, // XmNx, screen_x_offset, // Doesn't work here // XmNy, screen_y_offset, // Doesn't work here NULL); // Lincity method of locking down the min_width/height when // instantiating the window, then releasing it later: // http://pingus.seul.org/~grumbel/tmp/lincity-source/lcx11_8c-source.html // Actually show the draw and show the window on the display XMapRaised(XtDisplay(appshell), XtWindow(appshell)); // Free the allocated struct. We won't need it again. // XFree(wm_hints); // We're not currently using this struct if(debug_level & 8) { fprintf(stderr,"Create appshell stop\n"); } } // end of create_appshell() void BuildPredefinedSARMenu_UI(Widget *parent_menu) { int i; // number of items in menu int ac; // number of arguments Arg al[100]; // arguments // Set standard menu item arguments to use with each widget. ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // Before building menu, make sure that any existing menu items are removed // this allows the menu to be changed on the fly while the program is running. // for (i = 0; i < MAX_NUMBER_OF_PREDEFINED_OBJECTS; i++) { if (predefined_object_menu_items[i] != NULL) { XtDestroyWidget(predefined_object_menu_items[i]); predefined_object_menu_items[i] = NULL; } } // Now build a menu item for each entry in the predefinedObjects array. for (i = 0; i < number_of_predefined_objects; i++) { // Walk through array of predefined objects and // build a menu item for each predefined object. // if (predefinedObjects[i].show_on_menu == 1) { // Some predefined objects are hidden to allow construction // of two predefined objects in the same place at the same // time with one menu item. if(debug_level & 1) fprintf(stderr, "Menu item with name: %s and index_of_child=%d\n", predefinedObjects[i].menu_call, predefinedObjects[i].index_of_child); predefined_object_menu_items[i]=XtCreateManagedWidget(predefinedObjects[i].menu_call, xmPushButtonGadgetClass, *parent_menu, al, ac); XtAddCallback(predefined_object_menu_items[i], XmNactivateCallback, Create_SAR_Object, (intptr_t *)predefinedObjects[i].index); if (predefinedObjects[i].index_of_child > -1) { // This second callback allows stacking of two // objects such as a PLS with 0.25 and 0.5 and a // PLS_ with 0.75 and 1.0 mile probability circles. // if (predefinedObjects[i].index_of_child < number_of_predefined_objects) { XtAddCallback(predefined_object_menu_items[i], XmNactivateCallback, Create_SAR_Object, (intptr_t *)predefinedObjects[predefinedObjects[i].index_of_child].index); } } } } } void create_gc(Widget w) { XGCValues values; Display *my_display = XtDisplay(w); int mask = 0; Pixmap pix; unsigned int _w, _h; int _xh, _yh; char xbm_path[500]; int ret_val; if (debug_level & 8) { fprintf(stderr,"Create gc start\n"); } if (gc != 0) { return; } memset(&values, 0, sizeof(values)); // Allocate colors // Note that the names here are the ones given in xastir.rgb colors[0x00] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) colors[0x01] = GetPixelByName(w,"purple"); colors[0x02] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) colors[0x03] = GetPixelByName(w,"cyan"); colors[0x04] = GetPixelByName(w,"brown"); colors[0x05] = GetPixelByName(w,"plum"); // light magenta colors[0x06] = GetPixelByName(w,"orange"); colors[0x07] = GetPixelByName(w,"darkgray"); colors[0x08] = GetPixelByName(w,"black"); // Foreground font color colors[0x09] = GetPixelByName(w,"blue"); colors[0x0a] = GetPixelByName(w,"green"); // PHG (old) colors[0x0b] = GetPixelByName(w,"mediumorchid"); // light purple colors[0x0c] = GetPixelByName(w,"red"); colors[0x0d] = GetPixelByName(w,"magenta"); colors[0x0e] = GetPixelByName(w,"yellow"); colors[0x0f] = GetPixelByName(w,"white"); // colors[0x10] = GetPixelByName(w,"black"); colors[0x11] = GetPixelByName(w,"black"); colors[0x12] = GetPixelByName(w,"black"); colors[0x13] = GetPixelByName(w,"black"); colors[0x14] = GetPixelByName(w,"lightgray"); colors[0x15] = GetPixelByName(w,"magenta"); colors[0x16] = GetPixelByName(w,"mediumorchid"); // light purple colors[0x17] = GetPixelByName(w,"lightblue"); colors[0x18] = GetPixelByName(w,"purple"); colors[0x19] = GetPixelByName(w,"orange2"); // light orange colors[0x1a] = GetPixelByName(w,"SteelBlue"); colors[0x20] = GetPixelByName(w,"white"); // Area object colors. Order must not be changed. If beginning moves, // update draw_area and draw_map. // High colors[0x21] = GetPixelByName(w,"black"); // AREA_BLACK_HI colors[0x22] = GetPixelByName(w,"blue"); // AREA_BLUE_HI colors[0x23] = GetPixelByName(w,"green"); // AREA_GREEN_HI colors[0x24] = GetPixelByName(w,"cyan3"); // AREA_CYAN_HI colors[0x25] = GetPixelByName(w,"red"); // AREA_RED_HI colors[0x26] = GetPixelByName(w,"magenta"); // AREA_VIOLET_HI colors[0x27] = GetPixelByName(w,"yellow"); // AREA_YELLOW_HI colors[0x28] = GetPixelByName(w,"gray35"); // AREA_GRAY_HI // Low colors[0x29] = GetPixelByName(w,"gray27"); // AREA_BLACK_LO colors[0x2a] = GetPixelByName(w,"blue4"); // AREA_BLUE_LO colors[0x2b] = GetPixelByName(w,"green4"); // AREA_GREEN_LO colors[0x2c] = GetPixelByName(w,"cyan4"); // AREA_CYAN_LO colors[0x2d] = GetPixelByName(w,"red4"); // AREA_RED_LO colors[0x2e] = GetPixelByName(w,"magenta4"); // AREA_VIOLET_LO colors[0x2f] = GetPixelByName(w,"yellow4"); // AREA_YELLOW_LO colors[0x30] = GetPixelByName(w,"gray53"); // AREA_GRAY_LO colors[0x40] = GetPixelByName(w,"yellow"); // symbols ... colors[0x41] = GetPixelByName(w,"DarkOrange3"); colors[0x42] = GetPixelByName(w,"purple"); colors[0x43] = GetPixelByName(w,"gray80"); colors[0x44] = GetPixelByName(w,"red3"); colors[0x45] = GetPixelByName(w,"brown1"); colors[0x46] = GetPixelByName(w,"brown3"); colors[0x47] = GetPixelByName(w,"blue4"); colors[0x48] = GetPixelByName(w,"DeepSkyBlue"); colors[0x49] = GetPixelByName(w,"DarkGreen"); colors[0x4a] = GetPixelByName(w,"red2"); colors[0x4b] = GetPixelByName(w,"green3"); colors[0x4c] = GetPixelByName(w,"MediumBlue"); colors[0x4d] = GetPixelByName(w,"white"); colors[0x4e] = GetPixelByName(w,"gray53"); colors[0x4f] = GetPixelByName(w,"gray35"); colors[0x50] = GetPixelByName(w,"gray27"); colors[0x51] = GetPixelByName(w,"black"); // ... symbols colors[0x52] = GetPixelByName(w,"LimeGreen"); // PHG, symbols // map solid colors colors[0x60] = GetPixelByName(w,"HotPink"); colors[0x61] = GetPixelByName(w,"RoyalBlue"); colors[0x62] = GetPixelByName(w,"orange3"); colors[0x63] = GetPixelByName(w,"yellow3"); colors[0x64] = GetPixelByName(w,"ForestGreen"); colors[0x65] = GetPixelByName(w,"DodgerBlue"); colors[0x66] = GetPixelByName(w,"cyan2"); colors[0x67] = GetPixelByName(w,"plum2"); colors[0x68] = GetPixelByName(w,"MediumBlue"); // was blue3 (the same!) colors[0x69] = GetPixelByName(w,"gray86"); // These colors added to make it possible to color local shapefile tiger // maps similar to on-line ones. colors[0x6a] = GetPixelByName(w,"tgr_prird_1"); colors[0x6b] = GetPixelByName(w,"tgr_secrd_1"); colors[0x70] = GetPixelByName(w,"RosyBrown2"); colors[0x71] = GetPixelByName(w,"gray81"); colors[0x72] = GetPixelByName(w,"tgr_park_1"); colors[0x73] = GetPixelByName(w,"tgr_city_1"); colors[0x74] = GetPixelByName(w,"tgr_forest_1"); colors[0x75] = GetPixelByName(w,"tgr_water_1"); // These colors match the "civdis" map color palette, a colorblind-friendly // palette actually mandated by EU for public sector maps colors[0x76] = GetPixelByName(w,"cividis_1"); colors[0x77] = GetPixelByName(w,"cividis_2"); colors[0x78] = GetPixelByName(w,"cividis_3"); colors[0x79] = GetPixelByName(w,"cividis_4"); colors[0x7a] = GetPixelByName(w,"cividis_5"); colors[0x7b] = GetPixelByName(w,"cividis_6"); colors[0x7c] = GetPixelByName(w,"cividis_7"); colors[0x7d] = GetPixelByName(w,"cividis_8"); colors[0x7e] = GetPixelByName(w,"cividis_9"); // These colors are the "Set1" color palette from ColorBrewer // https://colorbrewer2.org/#type=qualitative&scheme=Set1&n=9 colors[0x7f] = GetPixelByName(w,"set1_1"); colors[0x80] = GetPixelByName(w,"set1_2"); colors[0x81] = GetPixelByName(w,"set1_3"); colors[0x82] = GetPixelByName(w,"set1_4"); colors[0x83] = GetPixelByName(w,"set1_5"); colors[0x84] = GetPixelByName(w,"set1_6"); colors[0x85] = GetPixelByName(w,"set1_7"); colors[0x86] = GetPixelByName(w,"set1_8"); colors[0x87] = GetPixelByName(w,"set1_9"); colors[0xfe] = GetPixelByName(w,"pink"); // tracking trail colors // set color for your own station with #define MY_TRAIL_COLOR in db.c trail_colors[0x00] = GetPixelByName(w,"yellow"); trail_colors[0x01] = GetPixelByName(w,"blue"); trail_colors[0x02] = GetPixelByName(w,"green"); trail_colors[0x03] = GetPixelByName(w,"red"); trail_colors[0x04] = GetPixelByName(w,"magenta"); trail_colors[0x05] = GetPixelByName(w,"black"); trail_colors[0x06] = GetPixelByName(w,"white"); trail_colors[0x07] = GetPixelByName(w,"DarkOrchid"); trail_colors[0x08] = GetPixelByName(w,"purple"); // very similar to DarkOrchid... trail_colors[0x09] = GetPixelByName(w,"OrangeRed"); trail_colors[0x0a] = GetPixelByName(w,"brown"); trail_colors[0x0b] = GetPixelByName(w,"DarkGreen"); // was darkgreen (same) trail_colors[0x0c] = GetPixelByName(w,"MediumBlue"); trail_colors[0x0d] = GetPixelByName(w,"ForestGreen"); trail_colors[0x0e] = GetPixelByName(w,"chartreuse"); trail_colors[0x0f] = GetPixelByName(w,"cornsilk"); trail_colors[0x10] = GetPixelByName(w,"LightCyan"); trail_colors[0x11] = GetPixelByName(w,"cyan"); trail_colors[0x12] = GetPixelByName(w,"DarkSlateGray"); trail_colors[0x13] = GetPixelByName(w,"NavyBlue"); trail_colors[0x14] = GetPixelByName(w,"DarkOrange3"); trail_colors[0x15] = GetPixelByName(w,"gray27"); trail_colors[0x16] = GetPixelByName(w,"RoyalBlue"); trail_colors[0x17] = GetPixelByName(w,"yellow2"); trail_colors[0x18] = GetPixelByName(w,"DodgerBlue"); trail_colors[0x19] = GetPixelByName(w,"cyan2"); trail_colors[0x1a] = GetPixelByName(w,"MediumBlue"); // was blue3 (the same!) trail_colors[0x1b] = GetPixelByName(w,"gray86"); trail_colors[0x1c] = GetPixelByName(w,"SteelBlue"); trail_colors[0x1d] = GetPixelByName(w,"PaleGreen"); trail_colors[0x1e] = GetPixelByName(w,"RosyBrown"); trail_colors[0x1f] = GetPixelByName(w,"DeepSkyBlue"); values.background=GetPixelByName(w,"darkgray"); gc = XCreateGC(my_display, XtWindow(w), mask, &values); // Load a new font into the GC for the station font Load_station_font(); gc_tint = XCreateGC(my_display, XtWindow(w), mask, &values); gc_stipple = XCreateGC(my_display, XtWindow(w), mask, &values); gc_bigfont = XCreateGC(my_display, XtWindow(w), mask, &values); pix = XCreatePixmap(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), 20, 20, 1); values.function = GXcopy; gc2 = XCreateGC(XtDisplay(w), pix,GCForeground|GCBackground|GCFunction, &values); pixmap=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); pixmap_final=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); pixmap_alerts=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)screen_width,(unsigned int)screen_height, DefaultDepthOfScreen(XtScreen(w))); xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "2x2.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_50pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 2x2.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "25pct.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_25pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 25pct.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "13pct.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_13pct_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // 13pct.xbm couldn't be loaded } xastir_snprintf(xbm_path, sizeof(xbm_path), "%s/%s", SYMBOLS_DIR, "alert.xbm"); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_wx_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); exit(1); // alert.xbm couldn't be loaded } display_up=1; wait_to_redraw=0; if (debug_level & 8) { fprintf(stderr,"Create gc stop\n"); } } // create_gc() // This routine just copies an area from pixmap_final to the // display, so we won't go through all the trouble of making this // interruptible. Just get on with it, perform the operation, and // return to X. If it did any map drawing, we'd make it // interruptible. // void da_expose(Widget w, XtPointer UNUSED(client_data), XtPointer call_data) { Dimension width, height, margin_width, margin_height; XmDrawingAreaCallbackStruct *db = (XmDrawingAreaCallbackStruct *)call_data; XExposeEvent *event = (XExposeEvent *) db->event; unsigned char unit_type; //fprintf(stderr,"Expose event\n");*/ /* Call a routine to create a Graphics Context */ create_gc(w); /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, XmNmarginWidth, &margin_width, XmNmarginHeight, &margin_height, XmNunitType, &unit_type, NULL); (void)XCopyArea(XtDisplay(w), pixmap_final, XtWindow(w), gc, event->x, event->y, event->width, event->height, event->x, event->y); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; } // The work function for resizing. This one will be called by // UpdateTime if certain flags have been set my da_resize. This // function and the functions it calls that are CPU intensive should // be made interruptible: They should check interrupt_drawing_now // flag periodically and exit nicely if it is set. // void da_resize_execute(Widget w) { Dimension width, height; busy_cursor(appshell); // Reset the flags that may have brought us here. interrupt_drawing_now = 0; request_resize = 0; if (XtIsRealized(w)) { /* First get the various dimensions */ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); screen_width = (long)width; screen_height = (long)height; XtVaSetValues(w, XmNwidth, width, XmNheight, height, NULL); /* fprintf(stderr,"Size x:%ld, y:%ld\n",screen_width,screen_height);*/ if (pixmap) { (void)XFreePixmap(XtDisplay(w),pixmap); } if(pixmap_final) { (void)XFreePixmap(XtDisplay(w),pixmap_final); } if(pixmap_alerts) { (void)XFreePixmap(XtDisplay(w),pixmap_alerts); } pixmap=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); pixmap_final=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); pixmap_alerts=XCreatePixmap(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), (unsigned int)width,(unsigned int)height, DefaultDepthOfScreen(XtScreen(w))); HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } setup_in_view(); // flag stations that are in screen view HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(w)) { // (void)XCopyArea(XtDisplay(w),pixmap_final,XtWindow(w),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } // We got a resize callback. Set flags. UpdateTime will come // along in a bit and perform the resize. With this method, the // resize can be made interruptible. We merely need to check for // the interrupt_drawing_now flag periodically while doing the // resize drawing. // void da_resize(Widget UNUSED(w), XtPointer UNUSED(client_data), XtPointer UNUSED(call_data) ) { // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Set the request_resize flag request_resize++; // last_input_event = sec_now() + 2; } // We got a mouse or keyboard callback. Set flags. UpdateTime // will come along in a bit and perform the screen redraw. With // this method, the redraw can be made interruptible. We merely // need to check for the interrupt_drawing_now flag periodically // while doing the redraw. // void da_input(Widget w, XtPointer client_data, XtPointer call_data) { XEvent *event = ((XmDrawingAreaCallbackStruct *) call_data)->event; Dimension width, height; int redraw; char buffer[20]; int bufsize = 20; char temp[200]; char temp_course[20]; KeySym key; XComposeStatus compose; int x_center; int y_center; // int x_distance; // int y_distance; float x_distance_real; float y_distance_real; float full_distance; double area; float area_acres; // area in acres long a_x, a_y, b_x, b_y; char str_lat[20]; char str_long[20]; long x,y; int done = 0; long lat, lon; XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL); /*fprintf(stderr,"input event %d %d\n",event->type,ButtonPress);*/ redraw=0; // Snag the current pointer position input_x = event->xbutton.x; input_y = event->xbutton.y; ///////////////// // CAD OBJECTS // ///////////////// // Start of CAD Objects code. We have both ButtonPress and // ButtonRelease code handlers here, for this mode only. // Check whether we're in CAD Object draw mode first if (draw_CAD_objects_flag && event->xbutton.button == Button2) { if (event->type == ButtonRelease) { // We don't want to do anything for ButtonRelease. Most // of all, we don't want another point drawn for both // press and release, and we don't want other GUI // actions performed on release when in CAD Draw mode. done++; } else // ButtonPress for Button2 { // We need to check to see whether we're dragging the // pointer, and then need to save the points away (in // Xastir lat/long format), drawing lines between the // points whenever we do a pixmap_final refresh to the // screen. // Check whether we just did the first mouse button down // while in CAD draw mode. If so, save away the mouse // pointer and get out. We'll use that mouse pointer // the next time a mouse button gets pressed in order to // draw a line. // We're going to use gc_tint with an XOR bitblit here // to make sure that any lines we draw will be easily // seen, no matter what colors we're drawing on top of. // // If we have a valid saved position already from our // first click, then we must be on the 2nd or later // click. Draw a line. if (polygon_last_x != -1 && polygon_last_y != -1) { // Convert from screen coordinates to Xastir // coordinate system and save in the object->vertice // list. convert_screen_to_xastir_coordinates(input_x, input_y, &lat, &lon); CAD_vertice_allocate(lat, lon); // Reload symbols/tracks/CAD objects redraw_symbols(da); } else // First point of a polygon. Save it. { // Figure out the real lat/long from the screen // coordinates. Create a new object to hold the // point. convert_screen_to_xastir_coordinates(input_x, input_y, &lat, &lon); CAD_object_allocate(lat, lon); } // Save current point away for the next draw. polygon_last_x = input_x; polygon_last_y = input_y; done++; } } // End of CAD Objects code. ///////////////////////////////// // Start of ButtonRelease code // ///////////////////////////////// if (!done && event->type == ButtonRelease) { //fprintf(stderr,"ButtonRelease %d %d\n",event->xbutton.button,Button3); #ifdef SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button3) { // Right mouse button release #else // SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button1) { // Left mouse button release #endif // SWAP_MOUSE_BUTTONS // If no drag, Center the map on the mouse pointer // If drag, compute new zoom factor/center and redraw // -OR- measure distances. ///////////////////////// // CENTER MAP FUNCTION // ///////////////////////// // Check for "Center Map" function. Must be within 15 // pixels of where the button press occurred to qualify. if ( mouse_zoom && !measuring_distance && !moving_object && (abs(menu_x - input_x) < 15) && (abs(menu_y - input_y) < 15) ) { /* if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } */ // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; } // It's not the center function because the mouse moved more than 15 pixels. // It must be either the "Compute new zoom/center" -OR- the "Measure distance" // -OR- "Move distance" functions.. The "measuring_distance" or "moving_object" // variables will tell us. else { // At this stage we have menu_x/menu_y where the button press occurred, // and input_x/input_y where the button release occurred. ////////////////////// // MEASURE DISTANCE // ////////////////////// if (measuring_distance) // Measure distance function { double R = EARTH_RADIUS_METERS; // Check whether we already have a box on screen // that we need to erase. if (zoom_box_x1 != -1) { //fprintf(stderr,"erasing\n"); // Remove the last box drawn via the XOR // function. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x1), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y1), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y1)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x2), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x2), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y2), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y2)); } // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; // x_distance = abs(menu_x - input_x); // y_distance = abs(menu_y - input_y); // Here we need to convert to either English or Metric units of distance. //(temp,"Distance x:%d pixels, y:%d pixels\n",x_distance,y_distance); //popup_message_always(langcode("POPUPMA020"),temp); XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); a_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); a_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); b_x = center_longitude - ((width *scale_x)/2) + (input_x*scale_x); b_y = center_latitude - ((height*scale_y)/2) + (input_y*scale_y); // Keep y constant to get x distance. Convert // to the current measurement units for display. x_distance_real = cvt_kn2len * calc_distance_course(a_y,a_x,a_y,b_x,temp_course,sizeof(temp_course)); // Keep x constant to get y distance. Convert // to the current measurement units for display. y_distance_real = cvt_kn2len * calc_distance_course(a_y,a_x,b_y,a_x,temp_course,sizeof(temp_course)); // Compute the total distance and course. // Convert to the current measurement units for // display. full_distance = cvt_kn2len * calc_distance_course(a_y,a_x,b_y,b_x,temp_course,sizeof(temp_course)); if (full_distance < 1.0) { switch (english_units) { case 1: // English full_distance = full_distance * 5280; // convert from miles to feet x_distance_real = x_distance_real * 5280; // convert from miles to feet y_distance_real = y_distance_real * 5280; // convert from miles to feet break; case 2: // Nautical miles and knots full_distance = full_distance * 6076; // convert from miles to feet x_distance_real = x_distance_real * 6076; // convert from miles to feet y_distance_real = y_distance_real * 6076; // convert from miles to feet break; default: // Metric full_distance = full_distance * 1000; // convert from kilometers to meters x_distance_real = x_distance_real * 1000; // convert from kilometers to meters y_distance_real = y_distance_real * 1000; // convert from kilometers to meters break; } // See this URL for a method of calculating the area of a lat/long // rectangle on a sphere: // http://mathforum.org/library/drmath/view/63767.html // area = (pi/180)*R^2 * abs(sin(lat1)-sin(lat2)) * abs(lon1-lon2) // // Their formula is incorrect due to the mistake of mixing radians // and degrees. The correct formula is (WE7U): // area = R^2 * abs(sin(lat1)-sin(lat2)) * abs(lon1-lon2) // Compute correct units switch (english_units) { case 1: // English R = EARTH_RADIUS_MILES * 5280.0; // feet break; case 2: // Nautical miles and knots R = EARTH_RADIUS_MILES * 5280.0; // feet break; default: // Metric R = EARTH_RADIUS_METERS; // Meters break; } // Compute the total area in feet or meters // New method using area on a sphere: area = R*R * fabs( sin(convert_lat_l2r(a_y)) - sin(convert_lat_l2r(b_y)) ) * fabs( convert_lon_l2r(a_x) - convert_lon_l2r(b_x) ); // Old method using planar geometry: //area = x_distance_real * y_distance_real; // calculate area in acres switch (english_units) { case 1: case 2: area_acres = area * 2.2956749e-05; break; default: // Metric area_acres = area * 2.4710439e-04; break; } //if (area_acres<0.1) // area_acres = 0; //fprintf(stderr,"Old method: %f\nNew method: %f\n\n", // x_distance_real * y_distance_real, // area); // NOTE: Angles currently change at zoom==1, so we purposely don't // give an angle in that measurement instance below. // xastir_snprintf(temp, sizeof(temp), "%0.2f %s, x=%0.2f %s, y=%0.2f %s, %0.2f %s %s (%0.2f %s), %s: %s %s", full_distance, un_alt, // feet/meters x_distance_real, un_alt, // feet/meters y_distance_real, un_alt, // feet/meters area, langcode("POPUPMA038"), // square un_alt, area_acres, "acres", langcode("POPUPMA041"), // Bearing (scale_y == 1) ? "??" : temp_course, // Fix for zoom==1 langcode("POPUPMA042") ); // degrees } else { // Compute the total area in miles or // kilometers // Compute correct units switch (english_units) { case 1: // English R = EARTH_RADIUS_MILES; // Statute miles break; case 2: // Nautical miles and knots R = EARTH_RADIUS_KILOMETERS/1.852; // Nautical miles break; default: // Metric R = EARTH_RADIUS_KILOMETERS; // kilometers break; } // New method, area on a sphere: area = R*R * fabs(sin(convert_lat_l2r(a_y))-sin(convert_lat_l2r(b_y))) * fabs(convert_lon_l2r(a_x)-convert_lon_l2r(b_x)); // Old method using planar geometry: //area = x_distance_real * y_distance_real; //fprintf(stderr,"Old method: %f\nNew method: %f\n\n", // x_distance_real * y_distance_real, // area); xastir_snprintf(temp, sizeof(temp), "%0.2f %s, x=%0.2f %s, y=%0.2f %s, %0.2f %s %s, %s: %s %s", full_distance, un_dst, // miles/kilometers x_distance_real, un_dst, // miles/kilometers y_distance_real, un_dst, // miles/kilometers area, langcode("POPUPMA038"), // square un_dst, langcode("POPUPMA041"), // Bearing temp_course, langcode("POPUPMA042") ); // degrees } popup_message_always(langcode("POPUPMA020"),temp); } /////////////////// // MOVING OBJECT // /////////////////// else if (moving_object) // Move function { // For this function we need to: // Determine which icon is closest to the mouse pointer press position. // We'll use Station_info to select the icon for us. // Determine whether it is our object. If not, force // the user to "adopt" the object before moving it. // Compute the lat/lon of the mouse pointer release position. // Put the new value of lat/lon into the object data. // Cause symbols to get redrawn. // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; x = (center_longitude - ((screen_width * scale_x)/2) + (event->xmotion.x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (event->xmotion.y * scale_y)); if (x < 0) { x = 0l; // 180°W } if (x > 129600000l) { x = 129600000l; // 180°E } if (y < 0) { y = 0l; // 90°N } if (y > 64800000l) { y = 64800000l; // 90°S } if (debug_level & 1) { // This math is only used for the debug mode printf below. if (coordinate_system == USE_DDDDDD) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DEC_DEG); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DEC_DEG); } else if (coordinate_system == USE_DDMMSS) { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_DMS_NORMAL); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_DMS_NORMAL); } else // Assume coordinate_system == USE_DDMMMM { convert_lat_l2s(y, str_lat, sizeof(str_lat), CONVERT_HP_NORMAL); convert_lon_l2s(x, str_long, sizeof(str_long), CONVERT_HP_NORMAL); } //fprintf(stderr,"%s %s\n", str_lat, str_long); } // Effect the change in the object/item's // position. // doing_move_operation++; Station_info(w, "2", NULL); doing_move_operation = 0; } ///////////////////////////// // COMPUTE NEW CENTER/ZOOM // ///////////////////////////// else // Must be "Compute new center/zoom" function { float ratio; if (!map_lock_pan_zoom) { // We need to compute a new center and a new scale, then // cause the new image to be created. // Compute new center. It'll be the average of the two points x_center = (menu_x + input_x) /2; y_center = (menu_y + input_y) /2; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height,NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (x_center*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (y_center*scale_y); // // What Rolf had to say: // // Calculate center of mouse-marked area and get the scaling relation // between x and y for that position. This position will be the new // center, so that lattitude-dependent relation does not change with // a zoom-in. For both x and y calculate a new zoom factor necessary // to fit that screen direction. Select the one that allows both x // and y part to fall into the screen area. Draw the new screen with // new center and new zoom factor. // // Compute the new scale, or as close to it as we can get //new_scale_y = scale_y / 2; // Zoom in by a factor of 2 new_scale_y = (long)( (((1.0 * abs(menu_y - input_y)) / (float)height ) * (float)scale_y ) + 0.5); new_scale_x = (long)( (((1.0 * abs(menu_x - input_x)) / (float)width ) * (float)scale_x ) + 0.5); if (new_scale_y < 1) { new_scale_y = 1; // Don't go further in than zoom 1 } if (new_scale_x < 1) { new_scale_x = 1; // Don't go further in than zoom 1 } // We now know approximately the scales we need // in order to view all of the pixels just // selected in the drag operation. Now set // new_scale_y to the highest number of the two, // which will make sure the entire drag // selection will be seen at the new zoom level. // Use the new ratio between scales to compute // this, computed from the new midpoint. // //fprintf(stderr,"scale_x:%ld\tscale_y:%ld\n", get_x_scale(new_mid_x, new_mid_y, scale_y), scale_y ); ratio = ( (1.0 * get_x_scale(new_mid_x,new_mid_y,scale_y)) / (float)scale_y); //fprintf(stderr,"Ratio: %f\n", ratio); //fprintf(stderr,"x:%ld\ty:%ld\n", new_scale_x, new_scale_y); if ( new_scale_y < (long)((new_scale_x / ratio) + 0.5) ) { new_scale_y = (long)((new_scale_x / ratio) + 0.5); //fprintf(stderr,"Changed y\n"); } //fprintf(stderr,"x:%ld\ty:%ld\n", new_scale_x, new_scale_y); display_zoom_image(1); // Check range and do display, recenter menu_x = input_x; menu_y = input_y; //fprintf(stderr,"Drag/zoom/center happened\n"); // Reset the zoom-box variables possible_zoom_function = 0; zoom_box_x1 = -1; } } } mouse_zoom = 0; } // End of Button1 release code ////////////// // ZOOM OUT // ////////////// else if (event->xbutton.button == Button2 && !map_lock_pan_zoom) { // Middle mouse button release // Zoom out 2x with panning menu_x=input_x; menu_y=input_y; Zoom_out( w, client_data, call_data ); // Simple zoom out, keeping map center at current position //Zoom_out_no_pan( w, client_data, call_data ); mouse_zoom = 0; } // End of Button2 release code //////////////////////////////// // THIRD MOUSE BUTTON RELEASE // //////////////////////////////// #ifdef SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button1) { // Left mouse button release #else // SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button3) { // Right mouse button release #endif // SWAP_MOUSE_BUTTONS // Do nothing. We have a popup tied into the button press anyway. // (Mouse_button_handler & right_menu_popup). // Leave the button release alone in this case. mouse_zoom = 0; } // End of Button3 release code /////////////// // SCROLL UP // /////////////// else if (event->xbutton.button == Button4 && !map_lock_pan_zoom) { // Scroll up menu_x=input_x; menu_y=input_y; Pan_up(w, client_data, call_data); } // End of Button4 release code ///////////////// // SCROLL DOWN // ///////////////// else if (event->xbutton.button == Button5 && !map_lock_pan_zoom) { // Scroll down menu_x=input_x; menu_y=input_y; Pan_down(w, client_data, call_data); } // End of Button5 release code //////////////////////////////////// // YET MORE MOUSE BUTTON RELEASES // //////////////////////////////////// else if (event->xbutton.button == 6 && !map_lock_pan_zoom) { // Mouse button 6 release menu_x=input_x; menu_y=input_y; Zoom_out_no_pan(w, client_data, call_data); mouse_zoom = 0; } // End of Button6 code else if (event->xbutton.button == 7 && !map_lock_pan_zoom) { // Mouse button 7 release menu_x=input_x; menu_y=input_y; Zoom_in_no_pan(w, client_data, call_data); mouse_zoom = 0; } // End of Button7 release code } // End of ButtonRelease code /////////////////////////////// // Start of ButtonPress code // /////////////////////////////// else if (!done && event->type == ButtonPress) { //fprintf(stderr,"ButtonPress %d %d\n",event->xbutton.button,Button3); #ifdef SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button3) { // Right mouse button press #else // SWAP_MOUSE_BUTTONS if (event->xbutton.button == Button1) { // Left mouse button press #endif // SWAP_MOUSE_BUTTONS // Mark the position for possible drag function menu_x=input_x; menu_y=input_y; mouse_zoom = 1; if (!moving_object) // Can be "Measure" or "Zoom-in" { if (!map_lock_pan_zoom || (map_lock_pan_zoom && measuring_distance)) { // Not moving an object/item, so allow the // zoom-in box to display. possible_zoom_function++; } } } // End of Button1 Press code else if (event->xbutton.button == Button2) { // Middle mouse button or both right/left mouse buttons press // Nothing attached here. mouse_zoom = 0; } // End of Button2 Press code #ifdef SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button1) { // Left mouse button press #else // SWAP_MOUSE_BUTTONS else if (event->xbutton.button == Button3) { // Right mouse button press #endif // SWAP_MOUSE_BUTTONS // Nothing attached here. mouse_zoom = 0; } // End of Button3 Press code } // End of ButtonPress code //////////////////////////// // Start of KeyPress code // //////////////////////////// else if (!done && event->type == KeyPress) { // We want to branch from the keysym instead of the keycode (void)XLookupString( (XKeyEvent *)event, buffer, bufsize, &key, &compose ); //fprintf(stderr,"main.c:da_input():keycode %d\tkeysym %ld\t%s\n", event->xkey.keycode, key, buffer); // keycode ??, keysym 65360 is Home (0x???? on sun kbd) // if ((key == 65360) || (key == 0x????)) { if (key == 65360) { if (!map_lock_pan_zoom) { Go_Home(w, NULL, NULL); } } // keycode 99, keysym 65365 is PageUp (0xffda on sun kbd) if ((key == 65365) || (key == 0xffda)) { menu_x=input_x; menu_y=input_y; Zoom_out_no_pan( w, client_data, call_data ); TrackMouse(w, (XtPointer)text2, event, NULL); } // keycode 105, keysym 65366 is PageDown (0xffe0 on sun kbd) if ((key == 65366) || (key == 0xffe0)) { menu_x=input_x; menu_y=input_y; Zoom_in_no_pan( w, client_data, call_data ); TrackMouse(w, (XtPointer)text2, event, NULL); } // keycode 100, keysym 65361 is left-arrow if ( (key == 65361) || ( (key == 65361) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_left_less( w, client_data, call_data); } else { Pan_left( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 102, keysym 65363 is right-arrow if ( (key == 65363) || ( (key == 65363) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_right_less( w, client_data, call_data); } else { Pan_right( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 98, keysym 65362 is up-arrow if ( (key == 65362) || ( (key == 65362) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_up_less( w, client_data, call_data); } else { Pan_up( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 105, keysym 65364 is down-arrow if ( (key == 65364) || ( (key == 65364) && (event->xkey.state & ShiftMask) ) ) // Doesn't work yet. { if (!map_lock_pan_zoom) { menu_x=input_x; menu_y=input_y; if (event->xbutton.state & ShiftMask) // This doesn't work yet { Pan_down_less( w, client_data, call_data); } else { Pan_down( w, client_data, call_data ); } TrackMouse(w, (XtPointer)text2, event, NULL); } } // keycode 35, keysym 61 is Equals // keycode 35, keysim 43 is Plus // keycode 86, keysim 65451 is KP_Add if (key == 61 || key == 43 || key == 65451) { grid_size++; redraw = 1; } // keycode 48, keysym 45 is Minus // keycode 82, keysym 65453 is KP_Subtract if (key == 45 || key == 65453) { grid_size--; redraw = 1; } // Adjust map scale, execpt when pan/zoom locked if (!map_lock_pan_zoom && OSM_optimize_key(key)) { if (debug_level & 512) { fprintf(stderr, "Initial scale, before adjustment sx/sy = %li/%li\n", scale_x, scale_y); } adj_to_OSM_level(&scale_x, &scale_y); if (debug_level & 512) { fprintf(stderr, "Scale adjusted for OSM, sx/sy = %li/%li\n", scale_x, scale_y); } redraw = 1; } if ((debug_level & 512) && OSM_report_scale_key(key)) { fprintf(stderr, "scale_x = %li, scale_y = %li, OSM zoom = %i\n", scale_x, scale_y, osm_zoom_level(scale_x)); } } // End of KeyPress code ////////////////////////////////// // START OF SOMETHING ELSE CODE // ////////////////////////////////// else if (!done) // Something else { if (event->type == MotionNotify) { input_x = event->xmotion.x; input_y = event->xmotion.y; //fprintf(stderr,"da_input2 x %d y %d\n",input_x,input_y); } } // End of SomethingElse code if (redraw) { /*fprintf(stderr,"Current x %ld y * %ld\n",center_longitude,center_latitude);*/ // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // last_input_event = sec_now() + 2; } } // DK7IN: this function is unused... //void wait_sec(int dt) { // time_t ct; // // ct = sec_now() + dt; // while (ct < sec_now()) { // } //} // This function snags the current pointer information and tries to // determine whether we're doing some sort of draw or zoom function. // If so, draws the appropriate temporary squares or lines that the // operator expects. // void check_pointer_position(void) { Window root_return, child_return; int rootx_return, rooty_return; int win_x_return, win_y_return; unsigned int mask_return; Bool ret; int x_return; int y_return; unsigned int width_return; unsigned int height_return; unsigned int border_width_return; unsigned int depth_return; // If this variable has not been set, we should not display the // box. if (!possible_zoom_function) { return; } // Snag the current pointer info ret = XQueryPointer(XtDisplay(da), XtWindow(da), // Window we are interested in &root_return, // Root window that pointer is in &child_return, // Child windows that pointer is in, if any &rootx_return, // Pointer coord. relative to root window &rooty_return, // Pointer coord. relative to root window &win_x_return, // Pointer coord. relative to specified window &win_y_return, // Pointer coord. relative to specified window &mask_return); // State of modifier keys and pointer buttons switch (ret) { case True: // If we made it here, we're on the same screen as the // specified window. It's a good start anyway. //fprintf(stderr, "x:%d y:%d ", win_x_return, win_y_return); //fprintf(stderr, "root:%lx child:%lx ", root_return, child_return); //fprintf(stderr, "mask:%03x ret:%02x\n", mask_return, ret); // Check mask_return to see if button one is being // pressed down (a drag operation). If so, we're doing // a zoom-in operation and need to draw a box. 0x100 // Check if button two (middle button) is being pressed // down (a drag operation). If so, we're doing a CAD // Object draw and need to draw a line. 0x200 // Figure out how to erase previous lines/boxes so that // only the current object is shown. We might need to // keep track of earlier vectors and then redraw them // with an XOR function to erase. // Get the dimensions for the drawing area // XGetGeometry(Display *display, // Drawable d, // Window *root_return, // int *x_return, // int *y_return, // unsigned int *width_return, // unsigned int *height_return, // unsigned int *border_width_return, // unsigned int *depth_return); XGetGeometry(XtDisplay(da), XtWindow(da), &root_return, &x_return, &y_return, &width_return, &height_return, &border_width_return, &depth_return); // Check that X/Y are positive and below the max size of // the child window. if ( win_x_return >= (int)width_return || win_y_return >= (int)height_return) { /* fprintf(stderr, "Out of bounds: %d:%d %d:%d\n", win_x_return, width_return, win_y_return, height_return); */ return; } else { // Draw what we need to. // For CAD objects, polygon_last_x and // polygon_last_y contain the last position. // For the zoom-in function, menu_x and menu_y // contain the last position. if (draw_CAD_objects_flag) { // Check if button two (middle button) is being // pressed down (a drag operation). If so, // we're doing a CAD Object draw and need to // draw a line. 0x200 if ( (mask_return & 0x200) == 0) { return; } // Remove the last line drawn (if any). Draw a // line from polygon_last_x and polygon_last_y // to the current pointer position. /* (void)XSetLineAttributes(XtDisplay(da), gc_tint, 0, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da), gc_tint, colors[(int)0x0e]); // yellow XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(polygon_last_x), l16(polygon_last_y), l16(win_x_return), l16(win_y_return)); */ return; } else // Zoom-in function? { // Check mask_return to see if button one is // being pressed down (a drag operation). If // so, we're doing a zoom-in operation and need // to draw a box. 0x100 #ifdef SWAP_MOUSE_BUTTONS if ( (mask_return & 0x400) == 0) // Button3 { #else // SWAP_MOUSE_BUTTONS if ( (mask_return & 0x100) == 0) // Button1 { #endif // SWAP_MOUSE_BUTTONS return; } (void)XSetLineAttributes(XtDisplay(da), gc_tint, 1, LineSolid, CapButt,JoinMiter); (void)XSetForeground(XtDisplay(da), gc_tint, colors[(int)0x0e]); // yellow (void)XSetFunction(XtDisplay(da), gc_tint, GXxor); // Check whether we already have a box on screen // that we need to erase. if (zoom_box_x1 != -1) { //fprintf(stderr,"erasing\n"); // Remove the last box drawn via the XOR // function. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x1), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y1), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y1)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x2), // Keep x constant l16(zoom_box_y1), l16(zoom_box_x2), l16(zoom_box_y2)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(zoom_box_x1), l16(zoom_box_y2), // Keep y constant l16(zoom_box_x2), l16(zoom_box_y2)); } // Draw a box around the current zoom area. XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), // Keep x constant l16(menu_y), l16(menu_x), l16(win_y_return)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), l16(menu_y), // Keep y constant l16(win_x_return), l16(menu_y)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(win_x_return), // Keep x constant l16(menu_y), l16(win_x_return), l16(win_y_return)); XDrawLine(XtDisplay(da), XtWindow(da), gc_tint, l16(menu_x), l16(win_y_return), // Keep y constant l16(win_x_return), l16(win_y_return)); // Save the values away so that we can erase the // box later. zoom_box_x1 = menu_x; zoom_box_y1 = menu_y; zoom_box_x2 = win_x_return; zoom_box_y2 = win_y_return; return; } } break; case BadWindow: // A window passed to the function was no // good. fprintf(stderr, "check_pointer_position: BadWindow\n"); return; break; case False: // Pointer is not on the same screen as the // specified window. default: return; break; } } // End of check_pointer_position() // Release ApplicationContext when we are asked to leave // void clear_application_context(void) { if (app_context) { XtDestroyApplicationContext(app_context); } app_context = NULL; } time_t stations_status_time = 0; static int last_alert_on_screen = -1; // This is the periodic process that updates the maps/symbols/tracks. // At the end of the function it schedules itself to be run again. void UpdateTime( XtPointer clientData, XtIntervalId UNUSED(id) ) { Widget w = (Widget) clientData; time_t nexttime; // int do_time; int max; int i; char station_num[30]; char line[MAX_LINE_SIZE+1]; int line_offset = 0; int n; time_t current_time; int data_length; int data_port; unsigned char data_string[MAX_LINE_SIZE]; #ifdef HAVE_DB int got_conn; // holds result from openConnection() #endif // HAVE_DB char temp_file_name[MAX_VALUE]; // do_time = 0; // Start UpdateTime again 10 milliseconds after we've completed. // Note: Setting this too low can cause // some systems // (RedHat/FreeBSD) to spin their wheels a lot, using up great // amounts of CPU time. This is heavily dependent on the true // value of the "HZ" value, which is reported as "100" on some // systems even if the kernel is using another value. #ifdef __CYGWIN__ // Cygwin performance is abysmal if nexttime is lower than 50, almost // acceptable at 200. nexttime = 200; #else // Changed from 2 to 10 to fix high CPU usage problems on // FreeBSD. nexttime = 10; #endif // __CYGWIN__ if (restart_xastir_now) { char bin_path[250]; clear_application_context(); // Restart Xastir in this process space. This is triggered // by receiving a SIGHUP signal to the main process, which // causes the signal handler restart() to run. restart() // shuts down most things nicely and then sets the // restart_xastir_now global variable. // // We need to snag the path to the executable from somewhere // so that we can start up again on a variety of systems. // Trying to get it from argv[0] doesn't work as that ends // up as "xastir" with no path. We therefore get it from // XASTIR_BIN_PATH which we define in configure.ac // // execve("/usr/local/bin/xastir", my_argv, my_envp); xastir_snprintf(bin_path, sizeof(bin_path), "%s/bin/xastir", XASTIR_BIN_PATH); // Restart this Xastir instance execve(bin_path, my_argv, my_envp); } current_time = sec_now(); if (last_updatetime > current_time) { // Time just went in the wrong direction. Sleep for a bit // so that we don't use massive CPU until the time catches // up again. // if (time_went_backwards == 0) { char temp[110]; // This is our first time through UpdateTime() since the // time went in the wrong direction. Dump out a // message to the user. time_went_backwards++; get_timestamp(temp); fprintf(stderr,"\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); fprintf(stderr, "!! System time jumped backwards %d seconds!\n", (int)(last_updatetime - current_time) ); fprintf(stderr, "!! Xastir sleeping, else will use excessive CPU\n"); fprintf(stderr, "!! %s\n", temp); fprintf(stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n"); time_went_backwards++; } usleep(1); // Sleep for 1uS. } else { // Time is behaving normally. last_updatetime = current_time; if (time_went_backwards) { fprintf(stderr, "Xastir is done sleeping due to time reversal.\n\n"); } time_went_backwards = 0; } (void)sound_done(); if(display_up) { if(display_up_first == 0) // very first call, do initialization { display_up_first = 1; statusline(langcode("BBARSTA045"), 1); // Loading symbols... load_pixmap_symbol_file("symbols.dat", 0); statusline(langcode("BBARSTA047"), 1); // Initialize my station... my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); da_resize(w, NULL,NULL); // make sure the size is right after startup & create image set_last_position(); // init last map position #ifdef HAVE_DB //uncomment to enable hardcoded test of writing station to db //simpleDbTest(); #endif /* HAVE_DB */ // Restore weather alerts so that we have a clear // picture of the current state. Do this before we // start the interfaces. load_wx_alerts_from_log(); statusline(langcode("BBARSTA048"), 1); // Start interfaces... startup_all_or_defined_port(-1); // start interfaces } else // Not the first time UpdateTime was called. { // Perform the regular updates. if (first_time_run) { first_time_run = 0; Configure_station(NULL, NULL, NULL); } popup_time_out_check(current_time); // clear popup windows after timeout check_statusline_timeout(current_time); // clear statusline after timeout check_station_remove(current_time); // remove old stations check_message_remove(current_time); // remove old messages #ifdef HAVE_LIBSHP purge_shp_hash(current_time); // purge stale rtrees #endif // HAVE_LIBSHP // We need to always calculate the Aloha circle so that // if it is turned on by the user it will be accurate. calc_aloha(current_time); //if ( (new_message_data > 0) && ( (delay_time % 2) == 0) ) //update_messages(0); // Check Messages, no forced update // Check whether it's time to expire some weather // alerts. This function will set redraw_on_new_data // and alert_redraw_on_update if any alerts are expired // from the list. (void)alert_expire(current_time); #ifdef HAVE_GPSMAN // Check whether we've just completed a GPS transfer and // have new maps to draw because of it. This function // can cause a complete redraw of the maps. check_for_new_gps_map(current_time); // Check whether it is time to snag RINO waypoints // again, creating APRS Objects out of them. "0" for // the download interval disables this function. if (RINO_download_interval > 0) { int rino_time = RINO_download_interval * 60; if (last_RINO_download + rino_time < current_time) { last_RINO_download = current_time; GPS_operations(NULL, "7", NULL); } } #endif // HAVE_GPSMAN if (xfontsel_query) { Query_xfontsel_pipe(); } // Check on resize requests if (request_resize) { // if (last_input_event < current_time) { da_resize_execute(w); // } } if (request_new_image) { // if (last_input_event < current_time) { new_image(w); // } } // check on Redraw requests if ( ( (redraw_on_new_data > 1) || (redraw_on_new_data && (current_time > last_redraw + REDRAW_WAIT)) || (current_time > next_redraw) || (pending_ID_message && (current_time > remove_ID_message_time)) ) && !wait_to_redraw) { int temp_alert_count; //fprintf(stderr,"Redraw on new data\n"); // Cause refresh_image() to happen if no other // triggers occurred, but enough time has passed. if (current_time > next_redraw) { alert_redraw_on_update++; } // check if alert_redraw_on_update is set and it has been at least xx seconds since // last weather alert redraw. if ( (alert_redraw_on_update && !pending_ID_message && ( current_time > ( last_alert_redraw + WX_ALERTS_REFRESH_TIME ) )) || (pending_ID_message && (current_time > remove_ID_message_time)) ) { // If we got here because of the ID_message // stuff, clear the variable. if (pending_ID_message && (current_time > remove_ID_message_time)) { pending_ID_message = 0; } //if (alert_redraw_on_update) { //fprintf(stderr,"Alert redraw on update: %ld\t%ld\t%ld\n", // current_time, last_alert_redraw, WX_ALERTS_REFRESH_TIME); if (!pending_ID_message) { refresh_image(da); // Much faster than create_image. (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); // We just refreshed the screen, so don't // try to erase any zoom-in boxes via XOR. zoom_box_x1 = -1; } // Here we use temp_alert_count as a temp holding place for the // count of active alerts. Sound alarm if new alerts are displayed. if ((temp_alert_count = alert_on_screen()) > last_alert_on_screen) { if (sound_play_wx_alert_message) { play_sound(sound_command, sound_wx_alert_message); } #ifdef HAVE_FESTIVAL if (festival_speak_new_weather_alert) { char station_id[50]; xastir_snprintf(station_id, sizeof(station_id), "%s, %d", langcode("SPCHSTR009"), temp_alert_count); SayText(station_id); } #endif // HAVE_FESTIVAL } last_alert_on_screen = temp_alert_count; alert_redraw_on_update = 0; } else { if (!pending_ID_message) { redraw_symbols(w); } } redraw_on_new_data = 0; //next_redraw = current_time+60; // redraw every minute next_redraw = current_time+1; // redraw every 1 second last_redraw = current_time; // This assures that we periodically check for expired alerts // and schedule a screen update if we find any. if (alert_display_request()) // should nor be placed in redraw loop !!??? { alert_redraw_on_update = redraw_on_new_data = 1; // ???? } } if (initial_load) { // Reload saved objects and items from previous runs. // This implements persistent objects. reload_object_item(); #ifdef HAVE_DB // load data from SQL database connections // step through interface list for (i = 0; i < MAX_IFACE_DEVICES; i++) { // if interface is a database and is set to load on start then load if (connections_initialized==0) { fprintf(stderr,"main, initializing connections"); connections_initialized = initConnections(); } if (devices[i].device_type == DEVICE_SQL_DATABASE && devices[i].query_on_startup && port_data[i].status==DEVICE_UP) { // load data if (devices[i].connect_on_startup == 1) { // there should be an open connection already if (debug_level & 4096) { fprintf(stderr,"Opening (in main) connection [%d] with existing connection [%p]",i,&connections[i]); } if (pingConnection(&connections[i])==True) { got_conn = 1; } else { // if (debug_level & 4096) fprintf(stderr,"Ping failed opening new connection [%p]",&connections[i]); got_conn = openConnection(&devices[i],&connections[i]); } } else { if (debug_level & 4096) { fprintf(stderr,"Opening (in main) connection [%d] with new connection [%p]",i,&connections[i]); } got_conn = openConnection(&devices[i],&connections[i]); } if ((got_conn == 1) && (!(connections[i].type==0))) { getAllSimplePositions(&connections[i]); // if connection worked, it is a oneshot upload of data, so we don't // need to set port_data[].active and .status values here. } else { // report error on this port port_data[i].active = DEVICE_IN_USE; port_data[i].status = DEVICE_ERROR; update_interface_list(); } } } #endif /* HAVE_DB */ // Reload any CAD objects from file. This implements // persistent objects. Restore_CAD_Objects_from_file(); initial_load = 0; // All done! } if (Display_.dr_data && ((current_time - sec_last_dr_update) > update_DR_rate) ) { //WE7U: Possible slow-down here w.r.t. dead-reckoning? If //update_DR_rate is too quick, we end up looking through all of the //stations in station list much too often and using a lot of CPU. redraw_on_new_data = 1; sec_last_dr_update = current_time; } // Look for packet data and check port status display_packet_data(); if (delay_time > 15) { interface_status(w); delay_time = 0; // check station lists update_station_scroll_list(); // maybe update lists } delay_time++; // If active HSP ports, check whether we've been sitting // for longer than XX seconds waiting for GPS data. If // so, the GPS is powered-down, lost lock, or become // disconnected. Go back to listening on the TNC port. // if (current_time > (sec_last_dtr + 2)) // 2-3 secs { if (!gps_stop_now) // No GPS strings parsed { // GPS listen timeout! Pop us out of GPS listen // mode on all HSP ports. Listen to the TNC for // a while. //fprintf(stderr,"1:calling dtr_all_set(0)\n"); dtr_all_set(0); sec_last_dtr = current_time; } } // If we parsed valid GPS data, bring all DTR lines back // to normal for all HSP interfaces (set to receive from // TNC now). if (gps_stop_now) { //fprintf(stderr,"2:calling dtr_all_set(0)\n"); dtr_all_set(0); // Go back to TNC listen mode sec_last_dtr = current_time; } // Start the GPS listening process again // check gps start up, GPS on GPSPORT if(current_time > sec_next_gps) { // Reset the gps good-data flag if (gps_stop_now) { gps_stop_now = 0; } //fprintf(stderr,"Check GPS\n"); // Set dtr lines down // works for SERIAL_GPS and SERIAL_TNC_HSP_GPS? // HSP interfaces: Set DTR line for all. DTR will // get reset for each line as valid GPS data gets // parsed on that interface. //fprintf(stderr,"3:calling dtr_all_set(1)\n"); dtr_all_set(1); sec_last_dtr = current_time; // GPS listen timeout for(i=0; i net_next_time) { net_last_time = current_time; net_next_time = net_last_time + 300; // Check every five minutes //net_next_time = net_last_time + 30; // This statement is for debug //fprintf(stderr,"Checking for reconnects\n"); check_ports(); } #ifdef USING_LIBGC // Check for leaks? if(current_time > gc_next_time) { gc_next_time = current_time + 60; // Check every minute //fprintf(stderr,"Checking for leaks\n"); CHECK_LEAKS(); } #endif // USING_LIBGC // Check to see if it is time to spit out data if(!wait_to_redraw) { if (last_time == 0) { // first update next_time = 120; last_time = current_time; // do_time = 1; } else { // check for update //fprintf(stderr,"Checking --- time %ld time to update %ld\n",current_time,last_time+next_time); if(current_time >= (last_time + next_time)) { next_time += next_time; if (next_time > max_transmit_time) { next_time = max_transmit_time; } last_time = current_time; // do_time = 1; } } } // Time to spit out a posit? If emergency_beacon is enabled // change to a relatively fast fixed beacon rate. Should be // more than a 30-second interval though to avoid digipeater // dupe intervals of 30 seconds. // if ( my_position_valid && ( transmit_now || (emergency_beacon && (current_time > (posit_last_time + 60) ) ) || (current_time > posit_next_time && POSIT_rate) ) ) { //fprintf(stderr,"Transmitting posit\n"); // Check for proper symbol in case we're a weather station (void)check_weather_symbol(); posit_last_time = current_time; if (smart_beaconing) { // Schedule next computed posit time based on // speed/turns, etc. posit_next_time = posit_last_time + sb_POSIT_rate; sb_last_heading = sb_current_heading; //fprintf(stderr,"Sending Posit\n"); } else { // Schedule next fixed posit time, set in // Configure->Defaults dialog posit_next_time = posit_last_time + POSIT_rate; } transmit_now = 0; // Output to ALL net/tnc ports that are enabled & have tx enabled //fprintf(stderr,"Sending posit\n"); output_my_aprs_data(); // Decrement the my_position_valid variable if we're // using GPS. This will make sure that positions // are valid, as we'll only get four positions out // maximum per valid GPS position. If the GPS // position goes stale, we'll stop sending posits. // We initialize it to one if we turn on a GPS // interface, so we'll get at the very most one // posit sent out with a stale position, each time // we open a GPS interface. if (using_gps_position && my_position_valid) { my_position_valid--; //fprintf(stderr,"my_position_valid:%d\n",my_position_valid); if (!my_position_valid) // We just went to zero! { // Waiting for GPS data.. statusline(langcode("BBARSTA041"),1); // If the user intends to send posits, GPS // interface is enabled, and we're not // getting GPS data, warn the user that // posits are disabled. if (!transmit_disable && !posit_tx_disable) { popup_message_always(langcode("POPEM00033"), langcode("POPEM00034")); } //fprintf(stderr,"my_position_valid just went to zero!\n"); } } } // if (do_time || transmit_now) { // transmit_now = 0; // // output to ALL net/tnc ports // //fprintf(stderr,"Output data\n"); // output_my_aprs_data(); // } // Must compute rain on a periodic basis, as some // weather daemons don't put out data often enough // to rotate through our queues. // We also refresh the Station_info dialog here if // it is currently drawn. if (current_time >= (last_weather_cycle + 30)) // Every 30 seconds { // Note that we also write timestamps out to all of the log files // from this routine. It works out well with the 30 second update // rate of cycle_weather(). (void)cycle_weather(); last_weather_cycle = current_time; if (station_data_auto_update) { update_station_info(w); // Go refresh the Station Info display } // Time to put out raw WX data ? if (current_time > sec_next_raw_wx) { sec_next_raw_wx = current_time+600; #ifdef TRANSMIT_RAW_WX if (transmit_raw_wx) { tx_raw_wx_data(); } #endif // TRANSMIT_RAW_WX // check wx data last received wx_last_data_check(); } } // is it time to spit out messages? check_and_transmit_messages(current_time); // Is it time to spit out any delayed ack's? check_delayed_transmit_queue(current_time); // Is it time to spit out objects/items? check_and_transmit_objects_items(current_time); // Do we have any new bulletins to display? check_for_new_bulletins(current_time); // Is it time to create a JPG snapshot? if (snapshots_enabled) { (void)Snapshot(); } // Is it time to create a kml dump of all current stations if (kmlsnapshots_enabled) { if (sec_now() > (last_kmlsnapshot + (snapshot_interval * 60)) ) { last_kmlsnapshot = sec_now(); // Set up timer for next time export_trail_as_kml(NULL); } } // Is it time to refresh maps? if ( map_refresh_interval && (current_time > map_refresh_time) ) { // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls // create_image, XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } map_refresh_time = current_time + map_refresh_interval; } // get data from interfaces max=0; // Allow multiple packets to be processed inside this // loop. Well, it was a nice idea anyway. See the // below note. // CAREFUL HERE: If we try to send to the Spider pipes faster than // it's reading from the pipes we corrupt the data out our server // ports. Having too high of a number here or putting too small of // a delay down lower causes our server port to server up junk! while (max < 1 && !XtAppPending(app_context)) { struct timeval tmv; // Check the x_spider server for incoming data if (enable_server_port) { // Check whether the x_spider server pipes have // any data for us. Process if found. // Check the TCP pipe line[0] = '\0'; // Start with line empty n = readline(pipe_tcp_server_to_xastir, line, MAX_LINE_SIZE); if (n == 0) { // Do nothing, empty packet } else if (n < 0) { //fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); } } else // We have a good packet { // Knock off the linefeed at the end line[n-1] = '\0'; if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)line); //fprintf(stderr,"TCP server data:%d: %s\n", n, line); packet_data_add(langcode("WPUPDPD006"), (char *)line, -1); // data_port -1 signifies x_spider // Set port to -2 here to designate that it // came from x_spider. -1 = from a log // file, 0 - 14 = from normal interfaces. decode_ax25_line((char *)line, 'I', -2, // Port -2 signifies x_spider data 1); max++; // Count the number of packets processed } // Check the UDP pipe line[0] = '\0'; // Start with line empty n = readline(pipe_udp_server_to_xastir, line, MAX_LINE_SIZE); if (n == 0) { // Do nothing, empty packet } else if (n < 0) { //fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"UpdateTime: Readline error: %d\n",errno); } } else // We have a good packet { char temp_call[10]; int skip_decode = 0; // Knock off the linefeed at the end line[n-1] = '\0'; // Check for "TO_INET," prefix, then check // for "TO_RF," prefix. Set appropriate // flags and remove the prefixes if found. // x_spider.c will always put them in that // order if both flags are present, so we // don't need to check for the reverse // order. // Note that this is NOT the "-to_inet" that xastir_udp_client // uses!!! See xspider.c for how that gets parsed/changed. // Set appropriate flags and remove the prefixes if found. if (strncmp(line, "TO_INET,", 8) == 0) { line_offset += 8; // // "TO_INET," found. // This packet should be gated to the internet if and only if // igating is enabled. This may happen automatically as-is, due to // the decode_ax25_line() call below. Check whether that's true. // // We can always add "NOGATE" or "RFONLY" to the path before we dump // it to decode_ax25_line() in order to stop this igating... // } else { // The packet did NOT have "TO_INET," in the string. // Change the packet to add "NOGATE", to the path to // assure it doesn't get igated. // Find the first ':' in the string. Copy the // first part of the string to a new string, add ",NOGATE" // to the path, copy the 2nd part of the string after it. char path[100+1]; char info[100+1]; char *path0 = NULL; char *info0 = NULL; path0 = strtok(line,":"); // Pointer to start of path info0 = strtok(NULL,""); // Pointer to information field xastir_snprintf(path, sizeof(path), "%s", path0); xastir_snprintf(info, sizeof(info), "%s", info0); //fprintf(stderr, "path: %s\n", path); //fprintf(stderr, "info: %s\n", info); //fprintf(stderr, "line: %s\n", line); xastir_snprintf(line, sizeof(line), "%s%s%s", path, ",NOGATE:", info); //fprintf(stderr, "line: %s\n", line); } // Check for "TO_RF," string // Note that this is NOT the "-to_rf" that xastir_udp_client // uses!!! See xspider.c for how that gets parsed/changed. if (strncmp((char *)(line+line_offset), "TO_RF,", 6) == 0) { fprintf(stderr,"Xastir received UDP packet with \"TO_RF,\" prefix\n"); line_offset += 6; // // "TO_RF," found. // This packet should be sent out the local RF ports. If the // callsign matches Xastir's (without the SSID), then send it out // first-person format. If it doesn't, send it out third-party // format? // // Snag FROM callsign and do a non-exact // match on it against "my_callsign" xastir_snprintf(temp_call, sizeof(temp_call), "%s", (char *)(line+line_offset)); if (strchr(temp_call,'>')) { *strchr(temp_call,'>') = '\0'; } // if (is_my_call(temp_call, 0)) { // Match ignoring SSID // exact match // Send to RF as direct packet //fprintf(stderr,"\tBase callsigns Match! Send to RF as direct packet\n"); //fprintf(stderr,"\t%s\n", line); // Change this to go out only RF interfaces so we don't double-up on // the INET interfaces? This would require looping on the // interfaces and checking type and transmit_enable for each, as is // done in output_igate_rf(). If we change to that method, // re-enable the decode_ax25_line() call below. // // Change to a third-party packet. In this case we know we have a // line_offset, so backing up one to insert a char is ok. *(line + line_offset - 1) = '}'; output_my_data( (char *)(line + line_offset - 1), // Raw data line -1, // ports, -1=send out all interfaces 0, // type: 0=cooked, 1=raw 0, // loopback_only 0, // use_igate_path NULL); // path //skip_decode++; igate_msgs_tx++; // } // else { // Send to RF as 3rd party packet //fprintf(stderr, // "\tBase callsigns don't match. Could send to RF as 3rd party packet, but dropping packet for now...\n"); //fprintf(stderr,"\t%s\n", line); // Drop the packet for now, until we get more code added to turn it // into a 3rd party packet /* output_igate_rf(temp_call, addr, path, (char *)(line + line_offset), port, 1, NULL); igate_msgs_tx++; */ //continue; // } } if (log_net_data) log_data( get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)(line + line_offset)); //fprintf(stderr,"UDP server data: %s\n", line); //fprintf(stderr,"\tUDP server data2: %s\n\n", (char *)(line + line_offset)); packet_data_add(langcode("WPUPDPD006"), (char *)(line + line_offset), -1); // data_port -1 signifies x_spider // We don't need the below if we call output_my_data with -1 for the // port, as in that case it calls decode_ax25_line directly. if (!skip_decode) { // Set port to -2 here to designate that it // came from x_spider. -1 = from a log // file, 0 - 14 = from normal interfaces. decode_ax25_line((char *)(line + line_offset), 'I', -2, // Port -2 signifies x_spider data 1); max++; // Count the number of packets processed } } } // End of x_spider server check code //if (begin_critical_section(&data_lock, "main.c:UpdateTime(1)" ) > 0) // fprintf(stderr,"data_lock\n"); // Check the rest of the ports for incoming data. Process up to // 1000 packets here in a loop. data_length = pop_incoming_data(data_string, &data_port); if (data_length != 0) { int data_type; // 0=AX25, 1=GPS // Terminate the string data_string[data_length] = '\0'; //fprintf(stderr,"device_type: %d\n",port_data[data_port].device_type); switch (port_data[data_port].device_type) { // NET Data stream case DEVICE_NET_STREAM: if (log_net_data) log_data(get_user_base_dir(LOGFILE_NET, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD006"), (char *)data_string, data_port); //fprintf(stderr,"\n-1 %s", data_string); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, data_length+1, "%s\n", data_string); //fprintf(stderr,"\n-2 %s", new_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { if (errno != EPIPE) { fprintf(stderr, "UpdateTime: Writen error (Net send x_spider): %d\n", errno); } } //fprintf(stderr,"\n-3 %s", new_string); } // End of x_spider server send code decode_ax25_line((char *)data_string, 'I', data_port, 1); break; // TNC Devices case DEVICE_SERIAL_KISS_TNC: case DEVICE_SERIAL_MKISS_TNC: // Try to decode header and checksum. If // bad, break, else continue through to // ASCII logging & decode routines. // Note that the length of data_string // can increase within decode_ax25_header(). if ( !decode_ax25_header( (unsigned char *)data_string, &data_length ) ) { // Had a problem decoding it. Drop // it on the floor. break; } else { // Good decode. Drop through to the // next block to log and decode the // packet. } /* Falls through. */ case DEVICE_SERIAL_TNC: tnc_data_clean((char *)data_string); /* Falls through. */ case DEVICE_AX25_TNC: case DEVICE_NET_AGWPE: if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error (TNC Send x_spider): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); break; case DEVICE_SERIAL_TNC_HSP_GPS: if (port_data[data_port].dtr==1) // get GPS data { char temp[200]; (void)gps_data_find((char *)data_string, data_port); xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } else { // get TNC data if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error(HSP data): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); } break; case DEVICE_SERIAL_TNC_AUX_GPS: tnc_data_clean((char *)data_string); data_type=tnc_get_data_type((char *)data_string, data_port); if (data_type) // GPS Data { char temp[200]; (void)gps_data_find((char *)data_string, data_port); xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } else // APRS Data { if (log_tnc_data) log_data( get_user_base_dir(LOGFILE_TNC, temp_file_name, sizeof(temp_file_name)), (char *)data_string); packet_data_add(langcode("WPUPDPD005"), (char *)data_string, data_port); if (enable_server_port) { char new_string[MAX_LINE_SIZE+1]; // Terminate it with a linefeed xastir_snprintf(new_string, MAX_LINE_SIZE+1, "%s\n", data_string); // Send data to the x_spider server if (writen(pipe_xastir_to_tcp_server, new_string, data_length+1) != data_length+1) { fprintf(stderr, "UpdateTime: Writen error(TNC/GPS data): %d\n", errno); } } // End of x_spider server send code decode_ax25_line((char *)data_string, 'T', data_port, 1); } break; // GPS Devices case DEVICE_SERIAL_GPS: case DEVICE_NET_GPSD: //fprintf(stderr,"GPS Data <%s>\n",data_string); (void)gps_data_find((char *)data_string, data_port); { char temp[200]; xastir_snprintf(temp, sizeof(temp), "GPS: "); strncat(temp, report_gps_status(), sizeof(temp) - 1 - strlen(temp)); statusline(temp, 0); } break; // WX Devices case DEVICE_SERIAL_WX: case DEVICE_NET_WX: if (log_wx) // TODO: Probably only logs to the first 0x00 byte... Need another // logging function that accepts a size, perhaps converting it to // 0x00 or similar as it writes to file. log_data( get_user_base_dir(LOGFILE_WX, temp_file_name, sizeof(temp_file_name)), (char *)data_string); wx_decode(data_string, data_length, data_port); break; default: fprintf(stderr,"Data from unknown source\n"); break; } max++; // Count the number of packets processed } else { max=1000; // Go straight to "max": Exit loop } //if (end_critical_section(&data_lock, "main.c:UpdateTime(2)" ) > 0) // fprintf(stderr,"data_lock\n"); // Do a usleep() here to give the interface threads // time to put something in the queue if they still // have data to process. We also need a delay here // to allow the x_spider code to process packets // we've sent to it. // NOTE: There's a very delicate balance here between x_spider // server, sched_yield(), the delay below, and nexttime. If we feed // packets to the x_spider server faster than it gets to process // them, we end up with blank lines and corrupted lines going to the // connected clients. sched_yield(); // Yield to the other threads if (enable_server_port) { tmv.tv_sec = 0; tmv.tv_usec = 2000; // Delay 2ms (void)select(0,NULL,NULL,NULL,&tmv); } } // End of packet processing loop // END- get data from interface // READ FILE IF OPENED if (read_file) { if (current_time >= next_file_read) { read_file_line(read_file_ptr); next_file_read = current_time + REPLAY_DELAY; } } // END- READ FILE IF OPENED } // If number of stations has changed, update the status // line, but only once per second max. if (station_count != station_count_save && stations_status_time != current_time) { // show number of stations in status line xastir_snprintf(station_num, sizeof(station_num), langcode("BBARSTH001"), currently_selected_stations, station_count); XmTextFieldSetString(text3, station_num); // Set up for next time station_count_save = station_count; stations_status_time = current_time; } check_pointer_position(); } sched_yield(); // Yield the processor to another thread (void)XtAppAddTimeOut(XtWidgetToApplicationContext(w), nexttime, (XtPointer)UpdateTime, (XtPointer)w); } void shut_down_server(void) { // Shut down the server if it was enabled if (tcp_server_pid || udp_server_pid) { // Send a kill to the main server process if (tcp_server_pid) { kill(tcp_server_pid, SIGHUP); } if (udp_server_pid) { kill(udp_server_pid, SIGHUP); } wait(NULL); // Reap the status of the process // Send to all processes in our process group. This will // cause the server and all of its children to die. Also // causes Xastir to die! Don't do it! //kill(0, 1); sleep(1); // Send a more forceful kill signal in case the "nice" kill // signal didn't work. if (tcp_server_pid) { kill(tcp_server_pid, SIGKILL); } if (udp_server_pid) { kill(udp_server_pid, SIGKILL); } } } // This is the SIGHUP handler. We restart Xastir if we receive a // SIGHUP, hopefully with the same environment that the original // Xastir had. We set a global variable, then UpdateTime() is the // process that actually calls execve() in order to replace our // current process with the new one. This assures that the signal // handler gets reset. We can't call execve() from inside the // signal handler and have the restart work more than once. // // This function should be nearly identical to the quit() function // below. // // One strangeness is that this routine gets called when any of the // spawned processes get a SIGHUP also, which means when we shut // down the TCP/UDP servers or similar. For some reason it still // appears to work, even though restart() gets called multiple // times when we shut down Xastir or the servers. We probably need // to call signal() from outside any signal handlers to tell it to // ignore further SIGHUP's. // static void restart(int UNUSED(sig) ) { char temp_file_name[MAX_VALUE]; // if (debug_level & 1) fprintf(stderr,"Shutting down Xastir...\n"); save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); #ifdef USE_PID_FILE_CHECK // remove the PID file unlink(get_user_base_dir("xastir.pid", temp_file_name, sizeof(temp_file_name))); #endif #ifdef HAVE_LIBCURL curl_global_cleanup(); #endif #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC // if (debug_level & 1) fprintf(stderr,"Attempting to restart Xastir...\n"); // Set the global variable which tells UpdateTime() to do a // restart. // restart_xastir_now++; } static void quit(int sig) { char temp_file_name[MAX_VALUE]; if(debug_level & 15) { fprintf(stderr,"Caught %d\n",sig); } save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); #ifdef USE_PID_FILE_CHECK // remove the PID file unlink(get_user_base_dir("xastir.pid",temp_file_name, sizeof(temp_file_name))); #endif if (debug_level & 1) { fprintf(stderr,"Exiting Xastir...\n"); } #ifdef HAVE_LIBCURL curl_global_cleanup(); #endif clear_application_context(); #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC exit(sig); // Main exit from the program } #ifdef USE_PID_FILE_CHECK static int pid_file_check(int hold) { int killret=0; int other_pid=0; char temp[32] ; FILE * PIDFILE ; char temp_file_name[MAX_VALUE]; /* Save our PID */ char pidfile_name[MAX_FILENAME]; xastir_snprintf(pidfile_name, sizeof(pidfile_name), "%s", get_user_base_dir("xastir.pid", temp_file_name, sizeof(temp_file_name))); if (filethere(pidfile_name)) { fprintf(stderr,"Found pid file: %s\n",pidfile_name); PIDFILE=fopen(pidfile_name,"r"); if (PIDFILE!=NULL) { if(!feof(PIDFILE)) { (void)get_line(PIDFILE,temp,32); } (void)fclose(PIDFILE); other_pid=atoi(temp); } else { fprintf(stderr,"Couldn't open file: %s\n", pidfile_name); } // send a ping killret = kill(other_pid,0); #ifdef N8YSZ fprintf(stderr, "other_pid = <%d> killret == <%d> errno == <%d>\n", other_pid,killret,errno); #endif if ((killret == -1) && (errno == ESRCH ) && !hold) { fprintf(stderr, "Other Xastir process, pid: %d does not appear be running. \n", other_pid); // nuke from orbit if (unlink(pidfile_name)) { fprintf(stderr,"Error unlinking pid file: %s, %d\n", pidfile_name,errno); } } else { fprintf(stderr, "Other Xastir process, pid: %d may be running. Exiting..\n", other_pid); #ifdef USING_LIBGC CHECK_LEAKS(); #endif // USING LIBGC exit(-1); // Quick exit from the program } } else { // if we're here - ok to truncate & open pidfile. #ifdef N8YSZ fprintf(stderr, "other_pid = <%d> killret == <%d> errno == <%d>\n", other_pid,killret,errno); #endif PIDFILE = fopen(pidfile_name,"w"); if(PIDFILE != NULL) { fprintf(PIDFILE, "%d",getpid()); (void) fclose (PIDFILE); return(0); } else { fprintf(stderr, "Error opening pidfile: %s\n", strerror(errno) ); return(errno); } return(0); } return(0); } // end pid_file_check #endif /* handle segfault signal */ void segfault(int UNUSED(sig) ) { fprintf(stderr, "Caught Segfault! Xastir will terminate\n"); fprintf(stderr, "Previous incoming line was: %s\n", incoming_data_copy_previous); fprintf(stderr, " Last incoming line was: %s\n", incoming_data_copy); if (dangerous_operation[0] != '\0') { fprintf(stderr, "Possibly died at: %s\n", dangerous_operation); } fprintf(stderr, "%02d:%02d:%02d\n", get_hours(), get_minutes(), get_seconds() ); shut_down_server(); quit(-1); } /* Added by KB4AMA Handle USR1 signal. This will cause a snapshot to be generated. */ #ifndef OLD_PTHREADS void usr1sig(int sig) { if (debug_level & 512) { fprintf(stderr, "Caught Signal USR1, Doing a snapshot! Signal No %d\n", sig); } last_snapshot = 0; (void)Snapshot(); } void usr2sig(int sig) { if (debug_level & 512) { fprintf(stderr, "Caught Signal USR2, Transmitting now! Signal No %d\n", sig); } transmit_now = 1; } #endif // OLD_PTHREADS /********************* dialog position *************************/ void pos_dialog(Widget w) { static Position x,y; Dimension wd, ht; int max_x, max_y; XtVaGetValues(appshell, XmNx, &x, XmNy, &y, NULL); XtVaGetValues(appshell, XmNwidth, &wd, XmNheight, &ht, NULL); if (x > 1280) // We sometimes get strange values for X/Y { x = 300; } if (y > 1024) // We sometimes get strange values for X/Y { y = 200; } if (wd > 1280) // And for width and height { wd = 640; } if (ht > 1024) // And for width and height { ht = 480; } max_x = x + wd - (wd / 5); // max_y = y + ht - (ht / 5); max_y = y + ht/3; // Check for proper values for last stored position if ( (last_popup_x < x) || (last_popup_y < y) || (last_popup_x > max_x) || (last_popup_y > max_y) ) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } else { last_popup_x += 10; // Increment slightly for next dialog last_popup_y += 20; // Increment slightly for next dialog } if ((last_popup_y+50) > max_y) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } if ((last_popup_x+50) > max_x) { last_popup_x = x + 20; // Go to initial position again last_popup_y = y + 30; // Go to initial position again } #ifdef FIXED_DIALOG_STARTUP XtVaSetValues(w,XmNx,x,XmNy,y,NULL); #else XtVaSetValues(w,XmNx,last_popup_x,XmNy,last_popup_y,NULL); #endif // FIXED_DIALOG_STARTUP //fprintf(stderr,"max_x:%d max_y:%d x:%d y:%d wd:%d ht:%d last_x:%d last_y:%d\n", //max_x,max_y,x,y,wd,ht,last_popup_x,last_popup_y); } /********************* resize_dialog *************************/ // // Resize dialog to fit screen size or form, whichever is smaller. // If screen size is smaller, also position dialog at 0,0. // // Don't forget window decorations! Setting a dialog to 320x240 ends // up with a total dialog of 326x267 on one Linux w/xfwm4 window // manager and certain selected fonts. This is 6 more in the X and 27 // more in the Y direction. We need to either add in the size of the // window decorations or activate the full-screen button on the // dialog. // // Found this which talks about getting sizes from parent and // grandparent of window to compute decoration sizes: // https://ubuntuforums.org/showthread.php?t=2048596 // Tried the above, plus several other methods: Couldn't come up with // a general method for calculating the size of the title bar portion // of the decorations. In particular the parent numbers return full // screen size and can't get the grandparent window. // // NOTE: 6, 27, and 10 numbers below were determined experimentally // on one system. Your mileage may vary based on window manager and // fonts selected. // void resize_dialog( Widget form, Widget dialog) { Dimension form_width, form_height; Dimension final_width, final_height; Dimension screen_width, screen_height; int set_to_origin = 0; // Fetch form size. Note that this will NOT include // the sizes of window decorations and title bar. XtVaGetValues(form, XmNwidth, &form_width, XmNheight, &form_height, NULL); // Fetch screen size screen_height = DisplayHeight(XtDisplay(appshell), DefaultScreen(display)); screen_width = DisplayWidth(XtDisplay(appshell), DefaultScreen(display)); // Simulate a small screen for testing: //screen_width = 320; //screen_height = 240; // NOTE: 27 and 6 numbers below were discovered by capturing a // known window size with XV, then examining the image with (any // of) "xv" / "gimp" / "identify" to determine final size with // decorations. On one system it was 3 pixels each side plus 21 // more for the titlebar, adding up to +6 left/right and +27 // top/bottom. This will vary per window manager, WM settings, // and fonts selected. // Find smaller of the two heights: // If dialog height is larger than screen, make smaller which // also activates the scrollbars. if ( (form_height+27) > screen_height) { // Set form height to screen height minus decorations and move // to origin final_height = screen_height-27; set_to_origin++; } else { // Dialog fits within the screen. final_height = form_height+10; } // Find smaller of the two widths: // If dialog width is larger than screen, make smaller which // also activates the scrollbars. if ( (form_width+6) > screen_width) { // Set form width to screen width minus decorations // and move to origin final_width = screen_width-6; set_to_origin++; } else { // Dialog fits within the screen. final_width = form_width+10; } if (set_to_origin) { // Set dialog's origin to 0,0. // Set width/height to the smaller of the two sizes. // Set max width/height to size of original form. // 10 was determined experimentally. XtVaSetValues(dialog, XmNx, 0, XmNy, 0, XmNwidth, final_width, XmNheight, final_height, XmNmaxWidth,form_width+10, XmNmaxHeight,form_height+10, NULL); } else { // Set width/height to the smaller of the two sizes. // Set max width/height to size of original form. // 10 was determined experimentally. XtVaSetValues(dialog, XmNwidth, final_width, XmNheight, final_height, XmNmaxWidth,form_width+10, XmNmaxHeight,form_height+10, NULL); } if (debug_level & 1) { fprintf(stderr,"Form size: X:%d\tY:%d\n", form_width, form_height); fprintf(stderr,"Screen size: X:%i, Y:%i\n", screen_width, screen_height); fprintf(stderr,"Setting dialog to width:%i, height:%i\n", final_width, final_height); if (set_to_origin) { fprintf(stderr,"Setting dialog to position 0,0\n"); } } } /********************* fix dialog size *************************/ void fix_dialog_size(Widget w) { Dimension wd, ht; if (XtIsRealized(w)) { XtVaGetValues(w, XmNwidth, &wd, XmNheight, &ht, NULL); XtVaSetValues(w, XmNminWidth,wd, XmNminHeight,ht, XmNmaxWidth,wd, XmNmaxHeight,ht, NULL); } } /**************************************** Button CallBacks *************************************/ /***********************************************************************************************/ /* * Button callback for 1 out of 2 selection */ void on_off_switch(int switchpos, Widget first, Widget second) { if(switchpos) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); } } /* * Button callback for 1 out of 3 selection */ void sel3_switch(int switchpos, Widget first, Widget second, Widget third) { if(switchpos == 2) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); } else if(switchpos == 1) { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); XtSetSensitive(third, TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, FALSE); } } /* * Button callback for 1 out of 4 selection */ void sel4_switch(int switchpos, Widget first, Widget second, Widget third, Widget fourth) { if(switchpos == 3) { XtSetSensitive(first, FALSE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, TRUE); } else if(switchpos == 2) { XtSetSensitive(first, TRUE); XtSetSensitive(second,FALSE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, TRUE); } else if(switchpos == 1) { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, FALSE); XtSetSensitive(fourth, TRUE); } else { XtSetSensitive(first, TRUE); XtSetSensitive(second,TRUE); XtSetSensitive(third, TRUE); XtSetSensitive(fourth, FALSE); } } // Called by UpdateTime when request_new_image flag is set. void new_image(Widget da) { busy_cursor(appshell); // Reset flags interrupt_drawing_now = 0; request_new_image = 0; // Set up floating point lat/long values to match Xastir // coordinates (speeds things up when dealing with lat/long // values later). convert_from_xastir_coordinates(&f_center_longitude, &f_center_latitude, center_longitude, center_latitude); if (create_image(da)) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); // We just refreshed the screen, so don't try to erase any // zoom-in boxes via XOR. zoom_box_x1 = -1; HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } display_zoom_status(); } } /* * Keep map in real world space, readjust center and scaling if necessary */ void check_range(void) { Dimension width, height; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); // Check the window itself to see if our new y-scale fits it // if ((height*new_scale_y) > 64800000l) { // Center between 90°N and 90°S new_mid_y = 64800000l/2; // Adjust y-scaling so that we fit perfectly in the window new_scale_y = 64800000l / height; } if ((new_mid_y < (height*new_scale_y)/2)) { new_mid_y = (height*new_scale_y)/2; // upper border max 90°N } if ((new_mid_y + (height*new_scale_y)/2) > 64800000l) { new_mid_y = 64800000l-((height*new_scale_y)/2); // lower border max 90°S } // Adjust scaling based on latitude of new center new_scale_x = get_x_scale(new_mid_x,new_mid_y,new_scale_y); // recalc x scaling depending on position if (debug_level & 512) { fprintf(stderr,"checkrange- x:%ld\ty:%ld\n\n",new_scale_x,new_scale_y); } // // scale_x will always be bigger than scale_y, so no problem here... // if ((width*new_scale_x) > 129600000l) { // // Center between 180°W and 180°E // new_mid_x = 129600000l/2; // } // The below code causes the map image to snap to the left or right // of the display. I'd rather see the scale factor changed so that // the map fits perfectly left/right in the display, so that we // cannot go past the edges of the earth. Change the code to work // this way later. We'll have to compute new_y_scale from the // new_x_scale once we scale X appropriately, then will probably // have to test the y scaling again? /* // Check against left border if ((new_mid_x < (width*new_scale_x)/2)) { // This will cause the map image to snap to the left of the // display. new_mid_x = (width*new_scale_x)/2; // left border max 180°W } else { // Check against right border if ((new_mid_x + (width*new_scale_x)/2) > 129600000l) // This will cause the map image to snap to the right of // the display. new_mid_x = 129600000l-((width*new_scale_x)/2); // right border max 180°E } */ // long NW_corner_longitude; // Longitude at top NW corner of map screen // long NW_corner_latitude; // Latitude at top NW corner of map screen /* if (NW_corner_longitude < 0l) { // fprintf(stderr,"left\n"); NW_corner_longitude = 0l; // New left viewpoint edge new_mid_x = 0l + ((width*new_scale_x) / 2); // New midpoint } if ( (NW_corner_longitude + (width*new_scale_x) ) > 129600000l) { // fprintf(stderr,"right\n"); NW_corner_longitude = 129600000l - (width*new_scale_x); // New left viewpoint edge new_mid_x = 129600000l - ((width*new_scale_x) / 2); // New midpoint } */ // Find the four corners of the map in the new scale system. Make // sure they are on the display, but not well inside the borders of // the display. // We keep getting center_longitude out of range when zooming out // and having the edge of the world map to the right of the middle // of the window. This shows up in new_image() above during the // convert_from_xastir_coordinates() call. new_mid_x is the data of // interest in this routine. } /* * Display a new map view after checking the view and scaling */ void display_zoom_image(int recenter) { Dimension width, height; XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); //fprintf(stderr,"Before, x: %lu, y: %lu\n",new_scale_x,new_scale_y); check_range(); // keep map inside world and calc x scaling //fprintf(stderr,"After, x: %lu, y: %lu\n\n",new_scale_x,new_scale_y); if (new_mid_x != center_longitude || new_mid_y != center_latitude || new_scale_x != scale_x || new_scale_y != scale_y) // If there's been a change in zoom or center { set_last_position(); if (recenter) { center_longitude = new_mid_x; // new map center center_latitude = new_mid_y; } scale_x = new_scale_x; scale_y = new_scale_y; setup_in_view(); // update "in view" flag for all stations // Set the interrupt_drawing_now flag interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // last_input_event = sec_now() + 2; } else // No change in zoom or center. Don't update ANYTHING. { } } void Zoom_in( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y / 2; if (new_scale_y < 1) { new_scale_y = 1; // don't go further in } display_zoom_image(1); // check range and do display, recenter } } void Zoom_in_no_pan( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude; new_scale_y = scale_y / 2; if (new_scale_y < 1) { new_scale_y = 1; // don't go further in, scale_x always bigger than scale_y } display_zoom_image(0); // check range and do display, keep center } } void Zoom_out( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); if (width*scale_x < 129600000l || height*scale_y < 64800000l) { new_scale_y = scale_y * 2; } else { new_scale_y = scale_y; // don't zoom out if whole world could be shown } display_zoom_image(1); // check range and do display, recenter } } void Zoom_out_no_pan( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude; if (width*scale_x < 129600000l || height*scale_y < 64800000l) { new_scale_y = scale_y * 2; } else { new_scale_y = scale_y; // don't zoom out if whole world could be shown } display_zoom_image(0); // check range and do display, keep center } } void Custom_Zoom_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); custom_zoom_dialog = (Widget)NULL; } static Widget custom_zoom_zoom_level; void Custom_Zoom_do_it( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *temp_ptr; temp_ptr = XmTextFieldGetString(custom_zoom_zoom_level); scale_y = atoi(temp_ptr); XtFree(temp_ptr); new_scale_y = scale_y; display_zoom_image(1); } // Function to bring up a dialog. User can then select zoom for the // display directly. // void Custom_Zoom( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { static Widget pane, form, button_ok, button_cancel, zoom_label; // Arg al[50]; /* Arg List */ // unsigned int ac = 0; /* Arg Count */ Atom delw; char temp[50]; if(!custom_zoom_dialog) { // "Custom Zoom" custom_zoom_dialog = XtVaCreatePopupShell(langcode("POPUPMA034"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, custom_zoom_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Zoom Level" zoom_label = XtVaCreateManagedWidget(langcode("POPUPMA004"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); custom_zoom_zoom_level = XtVaCreateManagedWidget("Custom_Zoom zoom_level", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,6, XmNwidth,((6*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Custom_Zoom_destroy_shell, custom_zoom_dialog); XtAddCallback(button_ok, XmNactivateCallback, Custom_Zoom_do_it, NULL); pos_dialog(custom_zoom_dialog); delw = XmInternAtom(XtDisplay(custom_zoom_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(custom_zoom_dialog, delw, Custom_Zoom_destroy_shell, (XtPointer)custom_zoom_dialog); // Snag the current zoom value, convert them to // displayable values, and fill in the fields. xastir_snprintf(temp, sizeof(temp), "%ld", scale_y); XmTextFieldSetString(custom_zoom_zoom_level, temp); XtManageChild(form); XtManageChild(pane); XtPopup(custom_zoom_dialog,XtGrabNone); fix_dialog_size(custom_zoom_dialog); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(custom_zoom_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(custom_zoom_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(custom_zoom_dialog), XtWindow(custom_zoom_dialog)); } } void Zoom_level( Widget w, XtPointer clientData, XtPointer calldata) { Dimension width, height; int level; level=atoi((char *)clientData); if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); switch(level) { case(1): new_scale_y = 1; break; case(2): new_scale_y = 16; break; case(3): new_scale_y = 64; break; case(4): new_scale_y = 256; break; case(5): new_scale_y = 1024; break; case(6): new_scale_y = 8192; break; case(7): //WE7U // Here it'd be good to calculate what zoom level the entire world // would best fit in, instead of fixing the scale to a particular // amount. Figure out which zoom level would fit in the X and the Y // direction, and then pick the higher zoom level of the two (to // make sure the world fits in both). We should probably center at // 0.0N/0.0W as well. new_scale_y = 500000; // Center on Earth (0/0) // new_mid_x = 12900000l / 2; // new_mid_y = 6480000l / 2; break; case(8): // 10% out new_scale_y = (int)(scale_y * 1.1); if (new_scale_y == scale_y) { new_scale_y++; } break; case(9): // 10% in new_scale_y = (int)(scale_y * 0.9); // Don't allow the user to go in further than zoom 1 if (new_scale_y < 1) { new_scale_y = 1; } break; // Pop up a new dialog that allows the user to select // the zoom level, then causes that zoom level and the // right-click mouse location to take effect on the map // window. Similar to the Center_Zoom function but with // the mouse coordinates instead of the center of the // screen. case(10): // Custom Zoom Level // Pop up a new dialog that allows the user to // select the zoom level, then causes that zoom // level and the right-click mouse location to take // effect on the map window. Similar to the // Center_Zoom function but with the mouse // coordinates instead of the center of the screen. // Set up new_scale_y for whatever custom zoom level // the user has chosen, then call // display_zoom_image() from the callback there. // Custom_Zoom( w, clientData, calldata); return; break; default: break; } display_zoom_image(1); // check range and do display, recenter } } void Pan_ctr( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); new_mid_y = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_up( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude - (height*scale_y/4); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_up_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude - (height*scale_y/10); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_down( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude + (height*scale_y/4); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_down_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude; new_mid_y = center_latitude + (height*scale_y/10); new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_left( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - (width*scale_x/4); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_left_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude - (width*scale_x/10); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_right( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude + (width*scale_x/4); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Pan_right_less( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; if(display_up && !map_lock_pan_zoom) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); new_mid_x = center_longitude + (width*scale_x/10); new_mid_y = center_latitude; new_scale_y = scale_y; // keep size display_zoom_image(1); // check range and do display, recenter } } void Center_Zoom_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData)) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); center_zoom_dialog = (Widget)NULL; } static Widget center_zoom_latitude, center_zoom_longitude, center_zoom_zoom_level; void Center_Zoom_do_it( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { unsigned long x, y; char *temp_ptr; temp_ptr = XmTextFieldGetString(center_zoom_latitude); f_center_latitude = atof(temp_ptr); XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(center_zoom_longitude); f_center_longitude = atof(temp_ptr); XtFree(temp_ptr); //Convert to Xastir coordinate system for lat/long convert_to_xastir_coordinates(&x, &y, f_center_longitude, f_center_latitude); temp_ptr = XmTextFieldGetString(center_zoom_zoom_level); scale_y = atoi(temp_ptr); XtFree(temp_ptr); new_mid_x = x; new_mid_y = y; new_scale_y = scale_y; display_zoom_image(1); } void Go_Home( Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { DataRow *p_station; if (!map_lock_pan_zoom) { if (search_station_name(&p_station,my_callsign,1)) { set_map_position(w, p_station->coord_lat, p_station->coord_lon); } } } // Function to bring up a dialog. User can then select the center // and zoom for the display directly. // // Later it would be nice to have a "Calc" button so that the user // could input lat/long in any of the supported formats. Right now // it is DD.DDDD format only. // void Center_Zoom( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer calldata) { static Widget pane,form, button_ok, button_cancel, lat_label, lon_label, zoom_label; // Arg al[50]; /* Arg List */ // unsigned int ac = 0; /* Arg Count */ Atom delw; char temp[50]; if(!center_zoom_dialog) { // "Center & Zoom" center_zoom_dialog = XtVaCreatePopupShell(langcode("POPUPMA026"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Jump_location pane", xmPanedWindowWidgetClass, center_zoom_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Jump_location form", xmFormWidgetClass, pane, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Latitude" lat_label = XtVaCreateManagedWidget(langcode("POPUPMA027"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_latitude = XtVaCreateManagedWidget("Center_Zoom latitude", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, lat_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); // "Longitude" lon_label = XtVaCreateManagedWidget(langcode("POPUPMA028"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lat_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_longitude = XtVaCreateManagedWidget("Center_Zoom longitude", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, lat_label, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, lon_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); // "Zoom Level" zoom_label = XtVaCreateManagedWidget(langcode("POPUPMA004"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lon_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); center_zoom_zoom_level = XtVaCreateManagedWidget("Center_Zoom zoom_level", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns,21, XmNwidth,((21*7)+2), XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, lon_label, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zoom_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("JMLPO00002"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zoom_label, XmNtopOffset,15, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 3, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, Center_Zoom_destroy_shell, center_zoom_dialog); XtAddCallback(button_ok, XmNactivateCallback, Center_Zoom_do_it, NULL); pos_dialog(center_zoom_dialog); delw = XmInternAtom(XtDisplay(center_zoom_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(center_zoom_dialog, delw, Center_Zoom_destroy_shell, (XtPointer)center_zoom_dialog); if (center_zoom_override) // We've found a Map View { // "eyeball" object and are // doing a center/zoom based on // that object's info. Grab the // pointer to the object which // is in calldata. DataRow *p_station = (DataRow *)calldata; float f_latitude, f_longitude; int range; Dimension width, height; long x, x0, y, y0; double x_miles, y_miles, distance; char temp_course[10]; double scale_factor; long my_scale_y; //fprintf(stderr,"Map View Object: %s\n",p_station->call_sign); center_zoom_override = 0; // Snag the objects values, convert them to displayable // values, and fill in the fields. convert_from_xastir_coordinates(&f_longitude, &f_latitude, p_station->coord_lon, p_station->coord_lat); xastir_snprintf(temp, sizeof(temp), "%f", f_latitude); XmTextFieldSetString(center_zoom_latitude, temp); xastir_snprintf(temp, sizeof(temp), "%f", f_longitude); XmTextFieldSetString(center_zoom_longitude, temp); // Compute the approximate zoom level we need from the // range value in the object. Range is in miles. range = atoi(&p_station->power_gain[3]); // We should be able to compute the distance across the // screen that we currently have, then compute an // accurate zoom level that will give us the range we // want. // Find out the screen values XtVaGetValues(da,XmNwidth, &width, XmNheight, &height, NULL); // Convert points to Xastir coordinate system // X x = center_longitude - ((width *scale_x)/2); // Check for the edge of the earth if (x < 0) { x = 0; } x0 = center_longitude; // Center of screen // Y y = center_latitude - ((height*scale_y)/2); // Check for the edge of the earth if (y < 0) { y = 0; } y0 = center_latitude; // Center of screen // Compute distance from center to each edge // X distance. Keep Y constant. x_miles = cvt_kn2len * calc_distance_course(y0, x0, y0, x, temp_course, sizeof(temp_course)); // Y distance. Keep X constant. y_miles = cvt_kn2len * calc_distance_course(y0, x0, y, x0, temp_course, sizeof(temp_course)); // Choose the smaller distance if (x_miles < y_miles) { distance = x_miles; } else { distance = y_miles; } //fprintf(stderr,"Current screen range: %f\n", distance); //fprintf(stderr,"Desired screen range: %d\n", range); // Note that these numbers will be off if we're zoomed out way too // far (edges of the earth are inside the screen view). // Now we know the range of the current screen // (distance) in miles. Compute what we need from // "distance" (screen) and "range" (object) in order to // get a scale factor we can apply to our zoom numbers. if (distance < range) { //fprintf(stderr,"Zooming out\n"); scale_factor = (range * 1.0)/distance; // fprintf(stderr,"Scale Factor: %f\n", scale_factor); my_scale_y = (long)(scale_y * scale_factor); } else // distance > range { //fprintf(stderr,"Zooming in\n"); scale_factor = distance/(range * 1.0); //fprintf(stderr,"Scale Factor: %f\n", scale_factor); my_scale_y = (long)(scale_y / scale_factor); } if (my_scale_y < 1) { my_scale_y = 1; } //fprintf(stderr,"my_scale_y: %ld\n", my_scale_y); xastir_snprintf(temp, sizeof(temp), "%ld", my_scale_y); XmTextFieldSetString(center_zoom_zoom_level, temp); } else { // Normal user-initiated center/zoom function // Snag the current lat/long/center values, convert them to // displayable values, and fill in the fields. xastir_snprintf(temp, sizeof(temp), "%f", f_center_latitude); XmTextFieldSetString(center_zoom_latitude, temp); xastir_snprintf(temp, sizeof(temp), "%f", f_center_longitude); XmTextFieldSetString(center_zoom_longitude, temp); xastir_snprintf(temp, sizeof(temp), "%ld", scale_y); XmTextFieldSetString(center_zoom_zoom_level, temp); } XtManageChild(form); XtManageChild(pane); XtPopup(center_zoom_dialog,XtGrabNone); fix_dialog_size(center_zoom_dialog); // Move focus to the Close button. This appears to // highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit // the // key, and that activates the option. // XmUpdateDisplay(center_zoom_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(center_zoom_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(center_zoom_dialog), XtWindow(center_zoom_dialog)); } } void SetMyPosition( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { Dimension width, height; long my_new_latl, my_new_lonl; // check for fixed station //if ( (output_station_type == 0) || (output_station_type > 3)) { // popup_message( "Modify fixed position", "Are you sure you want to modify your position?"); //} // check for position ambiguity if ( position_amb_chars > 0 ) // popup warning that ambiguity is on { popup_message_always(langcode("POPUPMA043"), // "Modify ambiguous position" langcode("POPUPMA044") ); // "Position ambiguity is on, your new position may appear to jump." } if(display_up) { XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); my_new_lonl = (center_longitude - ((width *scale_x)/2) + (menu_x*scale_x)); my_new_latl = (center_latitude - ((height*scale_y)/2) + (menu_y*scale_y)); // Check if we are still on the planet... if ( my_new_latl > 64800000l ) { my_new_latl = 64800000l; } if ( my_new_latl < 0 ) { my_new_latl = 0; } if ( my_new_lonl > 129600000l ) { my_new_lonl = 129600000l; } if ( my_new_lonl < 0 ) { my_new_lonl = 0; } convert_lon_l2s( my_new_lonl, my_long, sizeof(my_long), CONVERT_HP_NOSP); convert_lat_l2s( my_new_latl, my_lat, sizeof(my_lat), CONVERT_HP_NOSP); // Update my station data with the new lat/lon my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; } } void Window_Quit( Widget UNUSED(w), XtPointer UNUSED(client), XtPointer UNUSED(calldata) ) { quit(0); } void Menu_Quit( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { quit(0); } void save_state( Widget UNUSED(w), XtPointer UNUSED(client), XtPointer calldata) { if (((XtCheckpointToken)calldata)->shutdown) { save_data(); // shutdown all interfaces shutdown_all_active_or_defined_port(-1); shut_down_server(); } } // Turn on or off map border, callback from map_border_button. void Map_border_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { draw_labeled_grid_border = TRUE; } else { draw_labeled_grid_border = FALSE; } redraw_symbols(da); } void Grid_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { long_lat_grid = atoi(which); } else { long_lat_grid = 0; } if (long_lat_grid) { statusline(langcode("BBARSTA005"),1); // Map Lat/Long Grid On XtSetSensitive(map_border_button,TRUE); } else { statusline(langcode("BBARSTA006"),2); // Map Lat/Long Grid Off XtSetSensitive(map_border_button,FALSE); } redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } // Callback from menu buttons that allow user to turn on or off the // global display of CAD objects and their metadata on the map. void CAD_draw_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; // turn on or off display of cad objects if (strcmp(which,"CAD_draw_objects")==0) { CAD_draw_objects = state->set; } // turn on or off display of standard metadata if (strcmp(which,"CAD_show_label")==0) { CAD_show_label = state->set; } if (strcmp(which,"CAD_show_raw_probability")==0) { CAD_show_raw_probability = state->set; } if (strcmp(which,"CAD_show_comment")==0) { CAD_show_comment = state->set; } if (strcmp(which,"CAD_show_area")==0) { CAD_show_area = state->set; } // redraw objects on the current base maps redraw_symbols(da); } void Map_lock_pan_zoom_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_lock_pan_zoom = atoi(which); XtSetSensitive(zoom_in_menu, FALSE); XtSetSensitive(zoom_out_menu, FALSE); XtSetSensitive(pan_left_menu, FALSE); XtSetSensitive(pan_up_menu, FALSE); XtSetSensitive(pan_down_menu, FALSE); XtSetSensitive(pan_right_menu, FALSE); } else { map_lock_pan_zoom = 0; XtSetSensitive(zoom_in_menu, TRUE); XtSetSensitive(zoom_out_menu, TRUE); XtSetSensitive(pan_left_menu, TRUE); XtSetSensitive(pan_up_menu, TRUE); XtSetSensitive(pan_down_menu, TRUE); XtSetSensitive(pan_right_menu, TRUE); } } void Map_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { disable_all_maps = atoi(which); } else { disable_all_maps = 0; } request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_auto_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_auto_maps = atoi(which); XtSetSensitive(map_auto_skip_raster_button,TRUE); } else { map_auto_maps = 0; XtSetSensitive(map_auto_skip_raster_button,FALSE); } re_sort_maps = 1; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } if (map_auto_maps) { statusline(langcode("BBARSTA007"),1); // The use of Auto Maps is now on } else { statusline(langcode("BBARSTA008"),2); // The use of Auto Maps is now off } } void Map_auto_skip_raster_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { auto_maps_skip_raster = atoi(which); } else { auto_maps_skip_raster = 0; } re_sort_maps = 1; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_levels_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_color_levels = atoi(which); } else { map_color_levels = 0; } if (map_color_levels) { statusline(langcode("BBARSTA009"),1); // The use of Auto Maps is now on } else { statusline(langcode("BBARSTA010"),2); // The use of Auto Maps is now off } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_labels_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_labels = atoi(which); } else { map_labels = 0; } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_fill_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_color_fill = atoi(which); } else { map_color_fill = 0; } if (map_color_fill) { statusline(langcode("BBARSTA009"),1); // The use of Map Color Fill is now On } else { statusline(langcode("BBARSTA010"),1); // The use of Map Color Fill is now Off } // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } void Map_background( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int bgcolor; int i; bgcolor=atoi((char *)clientData); if(display_up) { for (i=0; i<12; i++) { if (i == bgcolor) { XtSetSensitive(map_bgcolor[i],FALSE); } else { XtSetSensitive(map_bgcolor[i],TRUE); } } map_background_color=bgcolor; // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } #if !defined(NO_GRAPHICS) void Raster_intensity(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { float my_intensity; int i; my_intensity=atof((char *)clientData); if(display_up) { for (i=0; i<11; i++) { if (i == (int)((float)(my_intensity * 10.01)) ) { XtSetSensitive(raster_intensity[i],FALSE); } else { XtSetSensitive(raster_intensity[i],TRUE); } //fprintf(stderr,"Change to index: %d\n", (int)((float)(my_intensity * 10.01))); } raster_map_intensity=my_intensity; //fprintf(stderr,"raster_map_intensity = %f\n", raster_map_intensity); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } #endif // NO_GRAPHICS void Map_station_label( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int style; style=atoi((char *)clientData); if(display_up) { letter_style = style; sel4_switch(letter_style,map_station_label3,map_station_label2,map_station_label1,map_station_label0); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } } void Map_icon_outline( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int style; style=atoi((char *)clientData); if(display_up) { icon_outline_style = style; sel4_switch(icon_outline_style,map_icon_outline3,map_icon_outline2,map_icon_outline1,map_icon_outline0); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } statusline( langcode("BBARSTA046"), 1); // Reloading symbols... load_pixmap_symbol_file("symbols.dat", 1); redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } void Map_wx_alerts_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { wx_alert_style = !(atoi(which)); } else { wx_alert_style = 1; } if (display_up) { refresh_image(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } } void Index_maps_on_startup_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { index_maps_on_startup = 1; } else { index_maps_on_startup = 0; } } void TNC_Transmit_now( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(calldata) ) { transmit_now = 1; /* toggle transmission of station now*/ } ///////////////////////////////////////////////////////////////////// // GPS operations ///////////////////////////////////////////////////////////////////// #ifdef HAVE_GPSMAN // Function to process the RINO.gpstrans file. We'll create APRS // objects out of them as if our own callsign created them. Lines // in the file look like this (spaces removed): // // W N3EG3 20-JUN-02 17:55 07/08/2004 13:03:29 46.1141682 -122.9384817 // W N3JGI 20-JUN-02 18:29 07/08/2004 13:03:29 48.0021644 -116.0118324 // // Fields are: // W name Comment Date/Time Latitude Longitude // void process_RINO_waypoints(void) { FILE *f; char temp[MAX_FILENAME * 2]; char line[301]; // float UTC_Offset; char temp_file_name[MAX_VALUE]; // char datum[50]; // Just to be safe line[300] = '\0'; // Create the full path/filename xastir_snprintf(temp, sizeof(temp), "%s/RINO.gpstrans", get_user_base_dir("gps", temp_file_name, sizeof(temp_file_name))); f=fopen(temp,"r"); // Open for reading if (f == NULL) { fprintf(stderr, "Couldn't open %s file for reading\n", temp); return; } // Process the file line-by-line here. The format for gpstrans // files as written by GPSMan appears to be: // // "W" // Waypoint name // Comment field (Date/Time is default on Garmins) // Date/Time // Decimal latitude // Decimal longitude // while (fgets(line, 300, f) != NULL) { // Snag the "Format:" line at the top of the file: // Format: DDD UTC Offset: -8.00 hrs Datum[100]: WGS 84 // if (strncmp(line,"Format:",7) == 0) { int i = 7; char temp2[50]; // Find the ':' after "UTC Offset" while (line[i] != ':' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Skip white space while (line[i] == ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy UTC offset chars into temp2 temp2[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(temp2,&line[i],1); i++; } // UTC_Offset = atof(temp2); //fprintf(stderr,"UTC Offset: %f\n", UTC_Offset); // NOTE: This would be the place to snag the datum as well. } // Check for a waypoint entry else if (line[0] == 'W') { char name[50]; char datetime[50]; char lat_c[20]; char lon_c[20]; int i = 1; // NOTE: We should check for the end of the string, skipping this // iteration of the loop if we haven't parsed enough fields. // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into name until tab or whitespace char. We're // assuming that a waypoint name can't have spaces in // it. name[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(name,&line[i],1); i++; } // Find tab character at end of name field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // We skip the comment field, doing nothing with the // data. // // Find tab character at end of comment field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Snag date/time. Use it in the object date/time field. // Copy into datetime until tab char. Include the space // between the time and date portions. datetime[0] = '\0'; while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(datetime,&line[i],1); i++; } // Find tab character at end of date/time field while (line[i] != '\t' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } i++; // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into lat_c until white space char lat_c[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(lat_c,&line[i],1); i++; } // Find non-white-space character while ((line[i] == '\t' || line[i] == ' ') && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { i++; } // Copy into lon_c until tab character lon_c[0] = '\0'; while (line[i] != '\t' && line[i] != ' ' && line[i] != '\0' && line[i] != '\n' && line[i] != '\r') { strncat(lon_c,&line[i],1); i++; } i++; /* fprintf(stderr, "%s\t%f\t%f\n", name, atof(lat_c), atof(lon_c)); */ // For now we're hard-coding the RINO group to "APRS". Any RINO // waypoints that begin with these four characters will have those // four characters chopped and will be turned into our own APRS // object, which we will then attempt to transmit. if (strncmp(name,"APRS",4) == 0) { // We have a match. Turn this into an APRS Object char line2[100]; int lat_deg, lon_deg; float lat_min, lon_min; char lat_dir, lon_dir; char temp2[50]; int date; int hour; int minute; // Three variables used for Base-91 compressed strings. We have a // bug in this code at the moment so the Base-91 compressed code in // this routine is commented out. // char *compressed_string; // char lat_s[50]; // char lon_s[50]; // Strip off the "APRS" at the beginning of the // name. Add spaces to flush out the length of an // APRS object name. strcpy(temp2, &name[4]); temp2[sizeof(temp2)-1] = '\0'; // Terminate string strcat(temp2, " "); temp2[sizeof(temp2)-1] = '\0'; // Terminate string // Copy it back to the "name" variable. xastir_snprintf(name, sizeof(name), "%s", temp2); // Truncate the name at nine characters. name[9] = '\0'; // We can either snag the UTC Offset from the top of // the file, or we can put the date/time format into // local time. The spec suggests using zulu time // for all future implementations, so we snagged the // UTC Offset earlier in this routine. // 07/09/2004 09:22:28 //fprintf(stderr,"%s %s", name, datetime); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[3]); temp2[2] = '\0'; date = atoi(temp2); //fprintf(stderr, "%02d\n", date); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[11]); temp2[2] = '\0'; hour = atoi(temp2); xastir_snprintf(temp2, sizeof(temp2), "%s", &datetime[14]); temp2[2] = '\0'; minute = atoi(temp2); //fprintf(stderr,"\t\t%02d%02d%02d/\n", date, hour, minute); // We need to remember to bump the date up if we go // past midnight adding the UTC offset. In that // case we may need to bump the day as well if we're // near the end of the month. Use the Unix time // facilities for this? // Here we're assuming that the UTC offset is // divisible by one hour. Always correct? // hour = (int)(hour - UTC_Offset); lat_deg = atoi(lat_c); if (lat_deg < 0) { lat_deg = -lat_deg; } lon_deg = atoi(lon_c); if (lon_deg < 0) { lon_deg = -lon_deg; } lat_min = atof(lat_c); if (lat_min < 0.0) { lat_min = -lat_min; } lat_min = (lat_min - lat_deg) * 60.0; lon_min = atof(lon_c); if (lon_min < 0.0) { lon_min = -lon_min; } lon_min = (lon_min - lon_deg) * 60.0; if (lat_c[0] == '-') { lat_dir = 'S'; } else { lat_dir = 'N'; } if (lon_c[0] == '-') { lon_dir = 'W'; } else { lon_dir = 'E'; } // Non-Compressed version xastir_snprintf(line2, sizeof(line2), ";%-9s*%02d%02d%02d/%02d%05.2f%c%c%03d%05.2f%c%c", name, date, hour, minute, lat_deg, // Degrees lat_min, // Minutes lat_dir, // N/S '/', // Primary symbol table lon_deg, // Degrees lon_min, // Minutes lon_dir, // E/W '['); // Hiker symbol /* // Compressed version. Gives us more of the // resolution inherent in the RINO waypoints. // Doesn't have an affect on whether we transmit // compressed objects from Xastir over RF. That is // selected from the File->Configure->Defaults // dialog. // // compress_posit expects its lat/long in // // APRS-like format: // "%2d%lf%c", °, &minutes, &ext xastir_snprintf(lat_s, sizeof(lat_s), "%02d%8.5f%c", lat_deg, lat_min, lat_dir); xastir_snprintf(lon_s, sizeof(lon_s), "%02d%8.5f%c", lon_deg, lon_min, lon_dir); compressed_string = compress_posit(lat_s, '/', // group character lon_s, '[', // symbol, 0, // course, 0, // speed, ""); // phg //fprintf(stderr, "compressed: %s\n", compressed_string); xastir_snprintf(line2, sizeof(line2), ";%-9s*%02d%02d%02d/%s", name, date, hour, minute, compressed_string); */ /* fprintf(stderr, "%-9s\t%f\t%f\t\t\t\t\t\t", name, atof(lat_c), atof(lon_c)); fprintf(stderr,"%s\n",line2); */ // Update this object in our save file log_object_item(line2,0,name); if (object_tx_disable) { output_my_data(line2,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line2,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } } } //fprintf(stderr,"\n"); (void)fclose(f); } void GPS_operations_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); GPS_operations_dialog = (Widget)NULL; } // Set up gps_map_filename based on user preferences for filename // and map color. void GPS_operations_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; char short_filename[MAX_FILENAME]; char color_text[50]; temp = XmTextGetString(gpsfilename_text); xastir_snprintf(short_filename, sizeof(short_filename), "%s", temp); XtFree(temp); // Add date/time to filename if no filename is given if (strlen(short_filename) == 0) { int ii; // Compute the date/time and put in string get_timestamp(short_filename); // Change spaces to underlines // Wed Mar 5 15:24:48 PST 2003 for (ii = 0; ii < (int)strlen(short_filename); ii++) { if (short_filename[ii] == ' ') { short_filename[ii] = '_'; } } } (void)remove_trailing_spaces(short_filename); switch (gps_map_color) { case 0: { xastir_snprintf(color_text,sizeof(color_text),"Red"); gps_map_color_offset=0x0c; break; } case 1: { xastir_snprintf(color_text,sizeof(color_text),"Green"); gps_map_color_offset=0x23; break; } case 2: { xastir_snprintf(color_text,sizeof(color_text),"Black"); gps_map_color_offset=0x08; break; } case 3: { xastir_snprintf(color_text,sizeof(color_text),"White"); gps_map_color_offset=0x0f; break; } case 4: { xastir_snprintf(color_text,sizeof(color_text),"Orange"); gps_map_color_offset=0x62; break; } case 5: { xastir_snprintf(color_text,sizeof(color_text),"Blue"); gps_map_color_offset=0x03; break; } case 6: { xastir_snprintf(color_text,sizeof(color_text),"Yellow"); gps_map_color_offset=0x0e; break; } case 7: { xastir_snprintf(color_text,sizeof(color_text),"Purple"); gps_map_color_offset=0x0b; break; } default: { xastir_snprintf(color_text,sizeof(color_text),"Red"); gps_map_color_offset=0x0c; break; } } // If doing waypoints, don't add the color onto the end if (strcmp("Waypoints",gps_map_type) == 0) { strcpy(gps_map_filename, short_filename); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, gps_map_type); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, ".shp"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string // Same without ".shp" strcpy(gps_map_filename_base, short_filename); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, gps_map_type); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string } else // Doing Tracks/Routes { strcpy(gps_map_filename, short_filename); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, gps_map_type); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, "_"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, color_text); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string strcat(gps_map_filename, ".shp"); gps_map_filename[sizeof(gps_map_filename)-1] = '\0'; // Terminate string // Same without ".shp" strcpy(gps_map_filename_base, short_filename); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, gps_map_type); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, "_"); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string strcat(gps_map_filename_base, color_text); gps_map_filename_base[sizeof(gps_map_filename_base)-1] = '\0'; // Terminate string // Same without ".shp" *or* color strcpy(gps_map_filename_base2, short_filename); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string strcat(gps_map_filename_base2, "_"); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string strcat(gps_map_filename_base2, gps_map_type); gps_map_filename_base2[sizeof(gps_map_filename_base2)-1] = '\0'; // Terminate string } //fprintf(stderr,"%s\t%s\n",gps_map_filename,gps_map_filename_base); // Signify that the user has selected the filename and color for // the downloaded file. gps_details_selected++; GPS_operations_destroy_shell(widget,clientData,callData); } void GPS_operations_cancel(Widget widget, XtPointer clientData, XtPointer callData) { // Destroy the GPS selection dialog GPS_operations_destroy_shell(widget,clientData,callData); // Wait for the GPS operation to be finished, then clear out all // of the variables. while (!gps_got_data_from && gps_operation_pending) { usleep(1000000); // 1 second } gps_details_selected = 0; gps_got_data_from = 0; gps_operation_pending = 0; } void GPS_operations_color_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { gps_map_color = atoi(which); } else { gps_map_color = 0; } } // This routine should be called while the transfer is progressing, // or perhaps just after it ends. If we can do it while the // transfer is occurring we can save time overall. Here we'll select // the color and name for the resulting file, then cause it to be // selected and displayed on the map screen. // void GPS_transfer_select( void ) { static Widget pane, scrollwindow, my_form, button_select, button_cancel, frame, type_box, ctyp0, ctyp1, ctyp2, ctyp3, ctyp4, ctyp5, ctyp6, ctyp7, gpsfilename_label; // static Widget color_type; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count if (!GPS_operations_dialog) { // Set args for color ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; GPS_operations_dialog = XtVaCreatePopupShell( langcode("GPS001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget( "GPS_transfer_select pane", xmPanedWindowWidgetClass, GPS_operations_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget( "GPS_transfer_select my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); gpsfilename_label = XtVaCreateManagedWidget( // Filename langcode("GPS002"), xmLabelWidgetClass, my_form, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); gpsfilename_text = XtVaCreateManagedWidget( "GPS_transfer_select gpsfilename_text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 20, XmNwidth, ((20*7)+2), XmNmaxLength, 200, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, gpsfilename_label, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget( "GPS_transfer_select frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, gpsfilename_label, XmNtopOffset,15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //color_type XtVaCreateManagedWidget( // Select Color langcode("GPS003"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); type_box = XmCreateRadioBox( frame, "GPS_transfer_select Transmit Options box", al, ac); XtVaSetValues(type_box, XmNnumColumns,2, NULL); ctyp0 = XtVaCreateManagedWidget( // Red langcode("GPS004"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp0,XmNvalueChangedCallback,GPS_operations_color_toggle,"0"); ctyp1 = XtVaCreateManagedWidget( // Green langcode("GPS005"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp1,XmNvalueChangedCallback,GPS_operations_color_toggle,"1"); ctyp2 = XtVaCreateManagedWidget( // Black langcode("GPS006"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp2,XmNvalueChangedCallback,GPS_operations_color_toggle,"2"); ctyp3 = XtVaCreateManagedWidget( // White langcode("GPS007"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp3,XmNvalueChangedCallback,GPS_operations_color_toggle,"3"); ctyp4 = XtVaCreateManagedWidget( // Orange langcode("GPS008"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp4,XmNvalueChangedCallback,GPS_operations_color_toggle,"4"); ctyp5 = XtVaCreateManagedWidget( // Blue langcode("GPS009"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp5,XmNvalueChangedCallback,GPS_operations_color_toggle,"5"); ctyp6 = XtVaCreateManagedWidget( // Yellow langcode("GPS010"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp6,XmNvalueChangedCallback,GPS_operations_color_toggle,"6"); ctyp7 = XtVaCreateManagedWidget( // Violet langcode("GPS011"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ctyp7,XmNvalueChangedCallback,GPS_operations_color_toggle,"7"); button_select = XtVaCreateManagedWidget( langcode("WPUPCFS028"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget( langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_select, XmNactivateCallback, GPS_operations_change_data, GPS_operations_dialog); XtAddCallback(button_cancel, XmNactivateCallback, GPS_operations_cancel, GPS_operations_dialog); // Set default color to first selection XmToggleButtonSetState(ctyp0,TRUE,FALSE); gps_map_color = 0; // De-sensitize the color selections if we're doing // waypoints. if (strcmp("Waypoints",gps_map_type) == 0) { XtSetSensitive(frame, FALSE); } pos_dialog(GPS_operations_dialog); delw = XmInternAtom( XtDisplay(GPS_operations_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback( GPS_operations_dialog, delw, GPS_operations_destroy_shell, (XtPointer)GPS_operations_dialog); XtManageChild(my_form); XtManageChild(type_box); XtManageChild(pane); resize_dialog(my_form, GPS_operations_dialog); XtPopup(GPS_operations_dialog,XtGrabNone); // Move focus to the Select button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(GPS_operations_dialog); XmProcessTraversal(button_select, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow( XtDisplay(GPS_operations_dialog), XtWindow(GPS_operations_dialog)); } } time_t check_gps_map_time = (time_t)0; // Function called by UpdateTime periodically. Checks whether // we've just completed a GPS transfer and need to redraw maps as a // result. // void check_for_new_gps_map(int curr_sec) { // Only check once per second if (check_gps_map_time == curr_sec) { return; // Skip it, we already checked once this second. } check_gps_map_time = curr_sec; if ( (gps_operation_pending || gps_got_data_from) && !gps_details_selected) { // A transfer is underway or has just completed. The user // hasn't selected the filename/color yet. Bring up the // selection dialog so that the user can do so. GPS_transfer_select(); } else if (gps_details_selected && gps_got_data_from && !gps_operation_pending) { FILE *f; char temp[MAX_FILENAME * 2]; char gps_base_dir[MAX_VALUE]; char temp_file_name[MAX_VALUE]; get_user_base_dir("gps",gps_base_dir, sizeof(gps_base_dir)); //fprintf(stderr,"check_for_new_gps_map()\n"); // We have new data from a GPS! Add the file to the // selected maps file, cause a reload of the maps to occur, // and then re-index maps (so that map may be deselected by // the user). // // It would be good to verify that we're not duplicating entries. // Add code here to read through the file first looking for a // match before attempting to append any new lines. // // We don't rename if Garmin RINO waypoint file if (strcmp(gps_map_type,"RINO") != 0) { // Rename the temporary file to the new filename. We must // do this three times, once for each piece of the Shapefile // map. #if defined(HAVE_MV) strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } // Done for the ".shp" file. Now repeat for the ".shx" and // ".dbf" files. strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".shx "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".shx"); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } strcpy(temp, MV_PATH); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".dbf "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_map_filename_base); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, ".dbf"); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't rename the downloaded GPS map file\n"); fprintf(stderr,"%s\n",temp); gps_got_data_from = 0; gps_details_selected = 0; return; } #endif // HAVE_MV // Write out a WKT in a .prj file to go with this shapefile. xastir_snprintf(temp, sizeof(temp), "%s/%s.prj", gps_base_dir, gps_map_filename_base); xastirWriteWKT(temp); if (strcmp(gps_map_type,"Waypoints") != 0) { // KM5VY: Create a really, really simple dbfawk file to // go with the shapefile. This is a dbfawk file of the // "per file" type, with the color hardcoded into it. // This will enable downloaded gps shapefiles to have // the right color even when they're not placed in the // GPS directory. // We don't do this for waypoint files, because all we need to // do for those is associate the name with the waypoint, and // that can be done by a generic signature-based file. xastir_snprintf(temp, sizeof(temp), "%s/%s.dbfawk", gps_base_dir, gps_map_filename_base); f=fopen(temp,"w"); // open for write if (f != NULL) { fprintf(f,gps_dbfawk_format,gps_map_color_offset, gps_map_filename_base2); fclose(f); } } // Add the new gps map to the list of selected maps f=fopen( get_user_base_dir(SELECTED_MAP_DATA, temp_file_name, sizeof(temp_file_name)), "a" ); // Open for appending if (f!=NULL) { //WE7U: Change this: fprintf(f,"GPS/%s\n",gps_map_filename); (void)fclose(f); // Reindex maps. Use the smart timestamp-checking indexing. map_indexer(0); // Have to have the new map in the index first before we can select it map_chooser_init(); // Re-read the selected_maps.sys file re_sort_maps = 1; // Creates a new sorted list from the selected maps // // We should set some flags here instead of doing the map redraw // ourselves, so that multiple map reloads don't occur sometimes in // UpdateTime. // // Reload maps // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } else { fprintf(stderr,"Couldn't open file: %s\n", get_user_base_dir(SELECTED_MAP_DATA, temp_file_name, sizeof(temp_file_name)) ); } } else { // We're dealing with Garmin RINO waypoints. Go process // the RINO.gpstrans file, creating objects out of them. process_RINO_waypoints(); } // Set up for the next GPS run gps_got_data_from = 0; gps_details_selected = 0; } } // This is the separate execution thread that transfers the data // to/from the GPS. The thread is started up by the // GPS_operations() function below. // static void* gps_transfer_thread(void *arg) { int input_param; char temp[500]; char prefix[100]; char postfix[100]; char gps_base_dir[MAX_VALUE]; get_user_base_dir("gps", gps_base_dir, sizeof(gps_base_dir)); // Set up the prefix string. Note that we depend on the correct // setup of serial ports and such in GPSMan's configs. xastir_snprintf(prefix, sizeof(prefix), "%s", GPSMAN_PATH); // Set up the postfix string. The files will be created in the // "~/.xastir/gps/" directory. strcpy(postfix, "Shapefile dim=2 "); postfix[sizeof(postfix)-1] = '\0'; // Terminate string strcat(postfix, gps_base_dir); postfix[sizeof(postfix)-1] = '\0'; // Terminate string strcat(postfix, "/"); postfix[sizeof(postfix)-1] = '\0'; // Terminate string input_param = atoi((char *)arg); // The pthread_detach() call means we don't care about the // return code and won't use pthread_join() later. Makes // threading more efficient. (void)pthread_detach(pthread_self()); switch (input_param) { case 1: // Fetch track from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite TR Shapefile dim=2 track.date // fprintf(stderr,"Fetch track from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Track_Red.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Track_Red"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Track"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite TR "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps track\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 2: // Fetch route from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite RT Shapefile dim=2 routes.date // fprintf(stderr,"Fetch routes from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Routes_Red.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Routes_Red"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Routes"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite RT "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps routes\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 3: // Fetch waypoints from GPS // gpsman.tcl -dev /dev/ttyS0 getwrite WP Shapefile dim=2 waypoints.date // fprintf(stderr,"Fetch waypoints from GPS\n"); xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "Unnamed_Waypoints.shp"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "Unnamed_Waypoints"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "Waypoints"); strcpy(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite WP "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, postfix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string if ( system(temp) ) { fprintf(stderr,"Couldn't download the gps waypoints\n"); gps_operation_pending = 0; // We're done return(NULL); } // Set the got_data flag gps_got_data_from++; break; case 4: // Send track to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 track.date TR fprintf(stderr,"Send track to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 5: // Send route to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 routes.date RT fprintf(stderr,"Send route to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 6: // Send waypoints to GPS // gpsman.tcl -dev /dev/ttyS0 readput Shapefile dim=2 waypoints.date WP fprintf(stderr,"Send waypoints to GPS\n"); fprintf(stderr,"Not implemented yet\n"); gps_operation_pending = 0; // We're done return(NULL); break; case 7: // Fetch waypoints from GPS in GPSTrans format // gpsman.tcl -dev /dev/ttyS0 getwrite WP GPStrans waypoints.date // fprintf(stderr,"Fetch Garmin RINO waypoints\n"); // The files will be created in the "~/.xastir/gps/" // directory. xastir_snprintf(gps_temp_map_filename, sizeof(gps_temp_map_filename), "RINO.gpstrans"); xastir_snprintf(gps_temp_map_filename_base, sizeof(gps_temp_map_filename_base), "RINO"); xastir_snprintf(gps_map_type, sizeof(gps_map_type), "RINO"); strcpy(temp, "("); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, prefix); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " getwrite WP GPStrans "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_base_dir); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "/"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, gps_temp_map_filename); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " 2>&1) >/dev/null"); temp[sizeof(temp)-1] = '\0'; // Terminate string // Execute the command if (system(temp) != 0) { // Ignore the return value as we've always done prior, // in other words: No change to the operation. } // if ( system(temp) ) { // fprintf(stderr,"Couldn't download the gps waypoints\n"); // gps_operation_pending = 0; // We're done // return(NULL); // } // Set the got_data flag gps_got_data_from++; break; default: fprintf(stderr,"Illegal parameter %d passed to gps_transfer_thread!\n", input_param); gps_operation_pending = 0; // We're done break; } // End of switch // Signal to the main thread that we're all done with the // GPS operation. gps_operation_pending = 0; // We're done // End the thread return(NULL); } // GPSMan can't handle multiple '.'s in the filename. It chops at // the first one. // // Note that the permissions on the "~/.xastir/gps/" directory have to be // set so that this user (or the root user?) can create files in // that directory. The permissions on the resulting files may need // to be tweaked. // // When creating files, we should warn the user of a conflict if the // filename already exists, then if the user wishes to overwrite it, // delete the old set of files before downloading the new ones. We // should also make sure we're not adding the filename to the // selected_maps.sys more than once. // // Set up default filenames for each, with an autoincrementing // number at the end? That'd be one way of getting a maps // downloaded in a hurry. Could also ask for a filename after the // download is complete instead of at the start of the download. In // that case, download to a temporary filename and then rename it // later and reload maps. // // Dialog should ask the user to put the unit into Garmin-Garmin // mode before proceeding. // // We could de-sensitize the GPS transfer menu items during a // transfer operation, to make sure we're not called again until the // first operation is over. // void GPS_operations( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { pthread_t gps_operations_thread; int parameter; if (clientData != NULL) { // Check whether we're already doing a GPS operation. // Return if so. if (gps_operation_pending) { fprintf(stderr,"GPS Operation is already pending, can't start another one!\n"); return; } parameter = atoi((char *)clientData); if ( ((parameter < 1) || (parameter > 3)) && parameter != 7) { fprintf(stderr,"GPS_operations: Parameter out-of-range: %d",parameter); return; } gps_operation_pending++; gps_got_data_from = 0; // We don't need to select filename/color if option 7 if (parameter == 7) { gps_details_selected++; } //----- Start New Thread ----- // Here we start a new thread. We'll communicate with the // main thread via global variables. Use mutex locks if // there might be a conflict as to when/how we're updating // those variables. // if (pthread_create(&gps_operations_thread, NULL, gps_transfer_thread, clientData)) { fprintf(stderr,"Error creating gps transfer thread\n"); gps_got_data_from = 0; // No data to present gps_operation_pending = 0; // We're done } else { // We're off and running with the new thread! } } } #endif // HAVE_GPSMAN ///////////////////////////////////////////////////////////////////// // End of GPS operations ///////////////////////////////////////////////////////////////////// void Set_Log_Indicator(void) { if ( (1==log_tnc_data) || (1==log_net_data) || (1==log_wx) || (1==log_igate) || (1==log_wx_alert_data) || (1==log_message_data) ) { XmTextFieldSetString(log_indicator, langcode("BBARSTA043")); // Logging XtVaSetValues(log_indicator, XmNbackground, GetPixelByName(appshell,"RosyBrown"), NULL); } else { XmTextFieldSetString(log_indicator, NULL); XtVaSetValues(log_indicator, MY_BACKGROUND_COLOR, NULL); } } void TNC_Logging_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_tnc_data = atoi(which); } else { log_tnc_data = 0; } Set_Log_Indicator(); } void Net_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_net_data = atoi(which); } else { log_net_data = 0; } Set_Log_Indicator(); } void IGate_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_igate = atoi(which); } else { log_igate = 0; } Set_Log_Indicator(); } void Message_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_message_data = atoi(which); } else { log_message_data = 0; } Set_Log_Indicator(); } void WX_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_wx = atoi(which); } else { log_wx = 0; } Set_Log_Indicator(); } void WX_Alert_Logging_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { log_wx_alert_data = atoi(which); } else { log_wx_alert_data = 0; } Set_Log_Indicator(); } // Filter Data Menu button callbacks // support functions void set_sensitive_select_sources(int sensitive) { XtSetSensitive(select_mine_button, sensitive); XtSetSensitive(select_tnc_button, sensitive); if (!Select_.tnc) { XtSetSensitive(select_direct_button, FALSE); XtSetSensitive(select_via_digi_button, FALSE); } else { XtSetSensitive(select_direct_button, sensitive); XtSetSensitive(select_via_digi_button, sensitive); } XtSetSensitive(select_net_button, sensitive); if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); } else { XtSetSensitive(select_old_data_button, sensitive); } } void set_sensitive_select_types(int sensitive) { XtSetSensitive(select_stations_button, sensitive); if (!Select_.stations) { XtSetSensitive(select_fixed_stations_button, FALSE); XtSetSensitive(select_moving_stations_button, FALSE); XtSetSensitive(select_weather_stations_button, FALSE); XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } else { XtSetSensitive(select_fixed_stations_button, sensitive); XtSetSensitive(select_moving_stations_button, sensitive); XtSetSensitive(select_weather_stations_button, sensitive); if (Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, sensitive); } } XtSetSensitive(select_objects_button, sensitive); if (!Select_.objects) { XtSetSensitive(select_weather_objects_button, FALSE); XtSetSensitive(select_gauge_objects_button, FALSE); XtSetSensitive(select_aircraft_objects_button, FALSE); XtSetSensitive(select_vessel_objects_button, FALSE); XtSetSensitive(select_other_objects_button, FALSE); } else { XtSetSensitive(select_weather_objects_button, sensitive); XtSetSensitive(select_gauge_objects_button, sensitive); XtSetSensitive(select_aircraft_objects_button, sensitive); XtSetSensitive(select_vessel_objects_button, sensitive); XtSetSensitive(select_other_objects_button, sensitive); } } void set_sensitive_display(int sensitive) { XtSetSensitive(display_callsign_button, sensitive); if (!Display_.callsign) { XtSetSensitive(display_label_all_trackpoints_button, FALSE); } else { XtSetSensitive(display_label_all_trackpoints_button, sensitive); } XtSetSensitive(display_symbol_button, sensitive); if (!Display_.symbol) { XtSetSensitive(display_symbol_rotate_button, FALSE); } else { XtSetSensitive(display_symbol_rotate_button, sensitive); } XtSetSensitive(display_phg_button, sensitive); if (!Display_.phg) { XtSetSensitive(display_default_phg_button, FALSE); XtSetSensitive(display_phg_of_moving_button, FALSE); } else { XtSetSensitive(display_default_phg_button, sensitive); XtSetSensitive(display_phg_of_moving_button, sensitive); } XtSetSensitive(display_altitude_button, sensitive); XtSetSensitive(display_course_button, sensitive); XtSetSensitive(display_speed_button, sensitive); if (!Display_.speed) { XtSetSensitive(display_speed_short_button, FALSE); } else { XtSetSensitive(display_speed_short_button, sensitive); } XtSetSensitive(display_dist_bearing_button, sensitive); XtSetSensitive(display_weather_button, sensitive); if (!Display_.weather) { XtSetSensitive(display_weather_text_button, FALSE); XtSetSensitive(display_temperature_only_button, FALSE); XtSetSensitive(display_wind_barb_button, FALSE); } else { XtSetSensitive(display_weather_text_button, sensitive); if (!Display_.weather_text) { XtSetSensitive(display_temperature_only_button, FALSE); } else { XtSetSensitive(display_temperature_only_button, sensitive); } XtSetSensitive(display_wind_barb_button, sensitive); } XtSetSensitive(display_trail_button, sensitive); XtSetSensitive(display_last_heard_button, sensitive); XtSetSensitive(display_ambiguity_button, sensitive); XtSetSensitive(display_df_data_button, sensitive); if (!Display_.df_data) { XtSetSensitive(display_df_beamwidth_data_button, FALSE); XtSetSensitive(display_df_bearing_data_button, FALSE); } else { XtSetSensitive(display_df_beamwidth_data_button, sensitive); XtSetSensitive(display_df_bearing_data_button, sensitive); } XtSetSensitive(display_dr_data_button, sensitive); if (!Display_.dr_data) { XtSetSensitive(display_dr_arc_button, FALSE); XtSetSensitive(display_dr_course_button, FALSE); XtSetSensitive(display_dr_symbol_button, FALSE); } else { XtSetSensitive(display_dr_arc_button, sensitive); XtSetSensitive(display_dr_course_button, sensitive); XtSetSensitive(display_dr_symbol_button, sensitive); } } void Select_none_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.none = atoi(which); set_sensitive_select_sources(FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } else { Select_.none = 0; set_sensitive_select_sources(TRUE); if (no_data_selected()) { set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } else { set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_mine_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.mine = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.mine = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_tnc_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.tnc = atoi(which); XtSetSensitive(select_direct_button, TRUE); XtSetSensitive(select_via_digi_button, TRUE); if (!no_data_selected()) { XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } } else { Select_.tnc = 0; XtSetSensitive(select_direct_button, FALSE); XtSetSensitive(select_via_digi_button, FALSE); if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_direct_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.direct = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.direct = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_via_digi_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.via_digi = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.via_digi = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_net_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.net = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.net = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_tactical_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.tactical = atoi(which); XtSetSensitive(select_old_data_button, TRUE); set_sensitive_select_types(TRUE); set_sensitive_display(TRUE); } else { Select_.tactical = 0; if (no_data_selected()) { XtSetSensitive(select_old_data_button, FALSE); set_sensitive_select_types(FALSE); set_sensitive_display(FALSE); } } redraw_on_new_data = 2; // Immediate screen update } void Select_old_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.old_data = atoi(which); } else { Select_.old_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.stations = atoi(which); XtSetSensitive(select_fixed_stations_button, TRUE); XtSetSensitive(select_moving_stations_button, TRUE); XtSetSensitive(select_weather_stations_button, TRUE); if (Select_.weather_stations) { XtSetSensitive(select_CWOP_wx_stations_button, TRUE); } } else { Select_.stations = 0; XtSetSensitive(select_fixed_stations_button, FALSE); XtSetSensitive(select_moving_stations_button, FALSE); XtSetSensitive(select_weather_stations_button, FALSE); XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_fixed_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.fixed_stations = atoi(which); } else { Select_.fixed_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_moving_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.moving_stations = atoi(which); } else { Select_.moving_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_weather_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.weather_stations = atoi(which); XtSetSensitive(select_CWOP_wx_stations_button, atoi(which)); } else { Select_.weather_stations = 0; XtSetSensitive(select_CWOP_wx_stations_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_CWOP_wx_stations_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.CWOP_wx_stations = atoi(which); } else { Select_.CWOP_wx_stations = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.objects = atoi(which); XtSetSensitive(select_weather_objects_button, TRUE); XtSetSensitive(select_gauge_objects_button, TRUE); XtSetSensitive(select_aircraft_objects_button, TRUE); XtSetSensitive(select_vessel_objects_button, TRUE); XtSetSensitive(select_other_objects_button, TRUE); } else { Select_.objects = 0; XtSetSensitive(select_weather_objects_button, FALSE); XtSetSensitive(select_gauge_objects_button, FALSE); XtSetSensitive(select_aircraft_objects_button, FALSE); XtSetSensitive(select_vessel_objects_button, FALSE); XtSetSensitive(select_other_objects_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Select_weather_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.weather_objects = atoi(which); } else { Select_.weather_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_gauge_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.gauge_objects = atoi(which); } else { Select_.gauge_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_aircraft_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.aircraft_objects = atoi(which); } else { Select_.aircraft_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_vessel_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.vessel_objects = atoi(which); } else { Select_.vessel_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } void Select_other_objects_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Select_.other_objects = atoi(which); } else { Select_.other_objects = 0; } redraw_on_new_data = 2; // Immediate screen update } // Display Menu button callbacks void Display_callsign_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.callsign = atoi(which); XtSetSensitive(display_label_all_trackpoints_button, TRUE); } else { Display_.callsign = 0; XtSetSensitive(display_label_all_trackpoints_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_label_all_trackpoints_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.label_all_trackpoints = atoi(which); } else { Display_.label_all_trackpoints = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_symbol_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.symbol = atoi(which); XtSetSensitive(display_symbol_rotate_button, TRUE); } else { Display_.symbol = 0; XtSetSensitive(display_symbol_rotate_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_symbol_rotate_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.symbol_rotate = atoi(which); } else { Display_.symbol_rotate = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_trail_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.trail = atoi(which); } else { Display_.trail = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_course_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.course = atoi(which); } else { Display_.course = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_speed_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.speed = atoi(which); XtSetSensitive(display_speed_short_button, TRUE); } else { Display_.speed = 0; XtSetSensitive(display_speed_short_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_speed_short_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.speed_short = atoi(which); } else { Display_.speed_short = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_altitude_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.altitude = atoi(which); } else { Display_.altitude = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_weather_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.weather = atoi(which); XtSetSensitive(display_weather_text_button, TRUE); XtSetSensitive(display_temperature_only_button, TRUE); XtSetSensitive(display_wind_barb_button, TRUE); } else { Display_.weather = 0; XtSetSensitive(display_weather_text_button, FALSE); XtSetSensitive(display_temperature_only_button, FALSE); XtSetSensitive(display_wind_barb_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_weather_text_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.weather_text = atoi(which); XtSetSensitive(display_temperature_only_button, TRUE); } else { Display_.weather_text = 0; XtSetSensitive(display_temperature_only_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_temperature_only_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.temperature_only = atoi(which); } else { Display_.temperature_only = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_wind_barb_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.wind_barb = atoi(which); } else { Display_.wind_barb = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_aloha_circle_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.aloha_circle = atoi(which); } else { Display_.aloha_circle = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_ambiguity_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.ambiguity = atoi(which); } else { Display_.ambiguity = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_phg_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.phg = atoi(which); XtSetSensitive(display_default_phg_button, TRUE); XtSetSensitive(display_phg_of_moving_button, TRUE); } else { Display_.phg = 0; XtSetSensitive(display_default_phg_button, FALSE); XtSetSensitive(display_phg_of_moving_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_default_phg_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.default_phg = atoi(which); } else { Display_.default_phg = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_phg_of_moving_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.phg_of_moving = atoi(which); } else { Display_.phg_of_moving = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_df_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_data = atoi(which); XtSetSensitive(display_df_beamwidth_data_button, TRUE); XtSetSensitive(display_df_bearing_data_button, TRUE); } else { Display_.df_data = 0; XtSetSensitive(display_df_beamwidth_data_button, FALSE); XtSetSensitive(display_df_bearing_data_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_df_beamwidth_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_beamwidth_data = atoi(which); } else { Display_.df_beamwidth_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_df_bearing_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.df_bearing_data = atoi(which); } else { Display_.df_bearing_data = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_data_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_data = atoi(which); XtSetSensitive(display_dr_arc_button, TRUE); XtSetSensitive(display_dr_course_button, TRUE); XtSetSensitive(display_dr_symbol_button, TRUE); } else { Display_.dr_data = 0; XtSetSensitive(display_dr_arc_button, FALSE); XtSetSensitive(display_dr_course_button, FALSE); XtSetSensitive(display_dr_symbol_button, FALSE); } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_arc_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_arc = atoi(which); } else { Display_.dr_arc = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_course_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_course = atoi(which); } else { Display_.dr_course = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dr_symbol_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dr_symbol = atoi(which); } else { Display_.dr_symbol = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_dist_bearing_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.dist_bearing = atoi(which); } else { Display_.dist_bearing = 0; } redraw_on_new_data = 2; // Immediate screen update } void Display_last_heard_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { Display_.last_heard = atoi(which); } else { Display_.last_heard = 0; } redraw_on_new_data = 2; // Immediate screen update } /* * Toggle unit system (button callbacks) */ void Units_choice_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { english_units = atoi(which); } else { english_units = 0; } redraw_on_new_data=2; update_units(); // setup conversion fill_wx_data(); } /* * Toggle dist/bearing status (button callbacks) */ void Dbstatus_choice_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { do_dbstatus = atoi(which); } else { do_dbstatus = 0; } // we need to rebuild main window now??? XtVaSetValues(text2, XmNwidth, do_dbstatus?((37*FONT_WIDTH)+2):((24*FONT_WIDTH)+2), NULL); redraw_on_new_data=2; } /* * Update global variables for unit conversion * * Be careful using these, as they change based on the value of * english_units! These variable should only be used when * DISPLAYING data, not when converting numbers for use in internal * storage or equations. * */ void update_units(void) { switch (english_units) { case 1: // English xastir_snprintf(un_alt,sizeof(un_alt),"ft"); xastir_snprintf(un_dst,sizeof(un_dst),"mi"); xastir_snprintf(un_spd,sizeof(un_spd),"mph"); cvt_m2len = 3.28084; // m to ft cvt_dm2len = 0.328084; // dm to ft cvt_hm2len = 0.0621504; // hm to mi cvt_kn2len = 1.1508; // knots to mph cvt_mi2len = 1.0; // mph to mph break; case 2: // Nautical // add nautical miles and knots for future use xastir_snprintf(un_alt,sizeof(un_alt),"ft"); xastir_snprintf(un_dst,sizeof(un_dst),"nm"); xastir_snprintf(un_spd,sizeof(un_spd),"kn"); cvt_m2len = 3.28084; // m to ft cvt_dm2len = 0.328084; // dm to ft cvt_hm2len = 0.0539957; // hm to nm cvt_kn2len = 1.0; // knots to knots cvt_mi2len = 0.8689607; // mph to knots / mi to nm break; default: // Metric xastir_snprintf(un_alt,sizeof(un_alt),"m"); xastir_snprintf(un_dst,sizeof(un_dst),"km"); xastir_snprintf(un_spd,sizeof(un_spd),"km/h"); cvt_m2len = 1.0; // m to m cvt_dm2len = 0.1; // dm to m cvt_hm2len = 0.1; // hm to km cvt_kn2len = 1.852; // knots to km/h cvt_mi2len = 1.609; // mph to km/h break; } } void Auto_msg_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { auto_reply = atoi(which); } else { auto_reply = 0; } } void Satellite_msg_ack_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { satellite_ack_mode = atoi(which); } else { satellite_ack_mode = 0; } } void Transmit_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { transmit_disable = atoi(which); XtSetSensitive(iface_transmit_now,FALSE); XtSetSensitive(object_tx_disable_toggle,FALSE); XtSetSensitive(posit_tx_disable_toggle,FALSE); } else { transmit_disable = 0; XtSetSensitive(iface_transmit_now,TRUE); XtSetSensitive(object_tx_disable_toggle,TRUE); XtSetSensitive(posit_tx_disable_toggle,TRUE); } } void Posit_tx_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { posit_tx_disable = atoi(which); } else { posit_tx_disable = 0; } } void Object_tx_disable_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_tx_disable = atoi(which); } else { object_tx_disable = 0; } } void Emergency_beacon_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { emergency_beacon = atoi(which); //WE7U // We need to send a posit or two immediately, shorten the interval // between posits, and add the string "EMERGENCY" to the posit // before anything else in the comment field. transmit_now = 1; } else { emergency_beacon = 0; } } void Server_port_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { // Start the listening socket. If we fork it early we end // up with much smaller process memory allocated for it and // all its children. The server will authenticate each // client that connects. We'll share all of our data with // the server, which will send it to all // connected/authenticated clients. Anything transmitted by // the clients will come back to us and standard igating // rules should apply from there. // enable_server_port = atoi(which); tcp_server_pid = Fork_TCP_server(my_argc, my_argv, my_envp); udp_server_pid = Fork_UDP_server(my_argc, my_argv, my_envp); } else { enable_server_port = 0; shut_down_server(); } } void Help_About( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget about_dialog; Widget child; XmString xms, xa, xb; Arg al[400]; unsigned int ac; float version; char string1[200]; char string2[200]; extern char gitstring[]; char version_str[50]; xastir_snprintf(string2, sizeof(string2),"\nXastir V%s %s\n",xastir_version,gitstring); xms = XmStringCreateLocalized(string2); xa = XmStringCreateLocalized("\n\n" ABOUT_MSG "\n\nLibraries used: " XASTIR_INSTALLED_LIBS "\n\n" ABOUT_OSM); // Add some newlines xb = XmStringConcat(xms, xa); XmStringFree(xa); XmStringFree(xms); //xb is still defined xa = XmStringCreateLocalized("\n" XmVERSION_STRING); // Add the Motif version string xms = XmStringConcat(xb, xa); XmStringFree(xa); XmStringFree(xb); //xms is still defined xa = XmStringCreateLocalized("\n"); // Add a newline xb = XmStringConcat(xms, xa); XmStringFree(xa); XmStringFree(xms); //xb is still defined xms = XmStringCopy(xb); XmStringFree(xb); //xms is still defined #ifdef HAVE_NETAX25_AXLIB_H //if (libax25_version != NULL) { xb = XmStringCreateLocalized("\n"); xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); xb = XmStringCreateLocalized("@(#)LibAX25 (ax25lib_version is broken. Complain to the authors.)\n"); xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //} #endif // AVE_NETAX25_AXLIB_H #ifdef HAVE_MAGICK xb = XmStringCreateLocalized("\n"); // Add a newline xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); //xa is still defined xb = XmStringCreateLocalized( MagickVersion); // Add ImageMagick version string xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //xms is still defined #endif // HAVE_MAGICK xb = XmStringCreateLocalized("\n"); // Add a newline xa = XmStringConcat(xb, xms); XmStringFree(xb); XmStringFree(xms); //xa is still defined version = XRotVersion( string1, 99 ); xastir_snprintf(version_str, sizeof(version_str), "%0.2f", version); strcpy(string2, "\n"); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, string1); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, ", Version "); string2[sizeof(string2)-1] = '\0'; // Terminate string strcat(string2, version_str); string2[sizeof(string2)-1] = '\0'; // Terminate string xb = XmStringCreateLocalized( string2); // Add Xvertext version string xms = XmStringConcat(xa, xb); XmStringFree(xa); XmStringFree(xb); //xms is still defined ac = 0; XtSetArg(al[ac], XmNmessageString, xms); ac++; // "About Xastir" XtSetArg(al[ac], XmNtitle, langcode("PULDNHEL05") ); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; // "About Xastir" about_dialog = XmCreateInformationDialog(appshell, langcode("PULDNHEL05"), al, ac); XmStringFree(xms); XtDestroyWidget(XmMessageBoxGetChild(about_dialog, (unsigned char)XmDIALOG_CANCEL_BUTTON)); XtDestroyWidget(XmMessageBoxGetChild(about_dialog, (unsigned char)XmDIALOG_HELP_BUTTON)); child = XmMessageBoxGetChild(about_dialog, XmDIALOG_MESSAGE_LABEL); XtVaSetValues(child, XmNfontList, fontlist1, NULL); XtManageChild(about_dialog); pos_dialog(about_dialog); } Widget GetTopShell(Widget w) { while(w && !XtIsWMShell(w)) { w = XtParent(w); } return(w); } /*********************** Display incoming data*******************************/ /****************************************************************************/ void Display_data_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); Display_data_dialog = (Widget)NULL; } void Display_packet_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Display_packet_data_type = atoi(which); } else { Display_packet_data_type = 0; } redraw_on_new_packet_data=1; } // Turn on or off "Station Capabilities", callback for capabilities // button. // void Capabilities_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { show_only_station_capabilities = TRUE; } else { show_only_station_capabilities = FALSE; } } // Turn on or off "Mine Only" // void Display_packet_mine_only_toggle( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Display_packet_data_mine_only = TRUE; } else { Display_packet_data_mine_only = FALSE; } } void Display_data( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close, option_box, tnc_data, net_data, tnc_net_data, capabilities_button, mine_only_button; unsigned int n; Arg args[50]; Atom delw; if (!Display_data_dialog) { Display_data_dialog = XtVaCreatePopupShell(langcode("WPUPDPD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Display_data pane", xmPanedWindowWidgetClass, Display_data_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Display_data my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /* set colors */ n=0; XtSetArg(args[n],XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n],XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; option_box = XmCreateRadioBox(my_form, "Display_data option box", args, n); XtVaSetValues(option_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, NULL); tnc_data = XtVaCreateManagedWidget(langcode("WPUPDPD002"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_data,XmNvalueChangedCallback,Display_packet_toggle,"1"); net_data = XtVaCreateManagedWidget(langcode("WPUPDPD003"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(net_data,XmNvalueChangedCallback,Display_packet_toggle,"2"); tnc_net_data = XtVaCreateManagedWidget(langcode("WPUPDPD004"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_net_data,XmNvalueChangedCallback,Display_packet_toggle,"0"); capabilities_button = XtVaCreateManagedWidget(langcode("WPUPDPD007"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, option_box, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(capabilities_button, XmNvalueChangedCallback,Capabilities_toggle,"1"); mine_only_button = XtVaCreateManagedWidget(langcode("WPUPDPD008"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, capabilities_button, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(mine_only_button, XmNvalueChangedCallback,Display_packet_mine_only_toggle,"1"); n=0; XtSetArg(args[n], XmNrows, 15); n++; XtSetArg(args[n], XmNcolumns, 100); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNscrollHorizontal, TRUE); n++; XtSetArg(args[n], XmNscrollVertical, TRUE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtraversalOn, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, option_box); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, 30); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; // XtSetArg(args[n], XmNnavigationType, XmTAB_GROUP); n++; Display_data_text=NULL; Display_data_text = XmCreateScrolledText(my_form, "Display_data text", args, n); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, Display_data_destroy_shell, Display_data_dialog); // I haven't figured out how to get the scrollbars to allow keyboard traversal. // When the ScrolledText widget is in the tab group, once you get there you can't // get out and it beeps at you when you try. Frustrating. For this dialog it's // probably not important enough to worry about. // I now have it set to allow TAB'ing into the ScrolledText widget, but to get // out you must do a . This sucks. Even if you enable the // ScrolledText widget in the tab group, the scrollbars don't work with the // arrow keys. // ScrolledList works. I need to convert to ScrolledList if // possible for output-only windows. pos_dialog(Display_data_dialog); delw = XmInternAtom(XtDisplay(Display_data_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(Display_data_dialog, delw, Display_data_destroy_shell, (XtPointer)Display_data_dialog); switch (Display_packet_data_type) { case(0): XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; case(1): XmToggleButtonSetState(tnc_data,TRUE,FALSE); break; case(2): XmToggleButtonSetState(net_data,TRUE,FALSE); break; default: XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; } if (show_only_station_capabilities) { XmToggleButtonSetState(capabilities_button,TRUE,FALSE); } else { XmToggleButtonSetState(capabilities_button,FALSE,FALSE); } if (Display_packet_data_mine_only) { XmToggleButtonSetState(mine_only_button,TRUE,FALSE); } else { XmToggleButtonSetState(mine_only_button,FALSE,FALSE); } XtManageChild(option_box); XtManageChild(Display_data_text); XtVaSetValues(Display_data_text, XmNbackground, colors[0x0f], NULL); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, Display_data_dialog); redraw_on_new_packet_data=1; XtPopup(Display_data_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(Display_data_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(Display_data_dialog), XtWindow(Display_data_dialog)); } } /****************************** Help menu ***********************************/ /****************************************************************************/ void help_view_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); help_view_dialog = (Widget)NULL; } void help_index_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (help_view_dialog) { help_view_destroy_shell(help_view_dialog, help_view_dialog, NULL); } help_view_dialog = (Widget)NULL; XtPopdown(shell); XtDestroyWidget(shell); help_index_dialog = (Widget)NULL; } void help_view( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close,help_text; int i; Position x, y; unsigned int n; char *temp = NULL; char title[200]; char temp2[200]; char temp3[200]; FILE *f; XmString *list; int open; Arg args[50]; int data_on,pos; int found; Atom delw; char help_file_path[MAX_VALUE]; data_on=0; pos=0; found=0; XtVaGetValues(help_list, XmNitemCount,&i, XmNitems,&list, NULL); for (x=1; x<=i; x++) { if (XmListPosSelected(help_list,x)) { found=1; temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); x=i+1; } } open=0; if (found) { if (help_view_dialog) { XtVaGetValues(help_view_dialog, XmNx, &x, XmNy, &y, NULL); help_view_destroy_shell(help_view_dialog, help_view_dialog, NULL); help_view_dialog = (Widget)NULL; open=1; } if (!help_view_dialog) { xastir_snprintf(title, sizeof(title), "%s - %s", langcode("MENUTB0009"), temp); help_view_dialog = XtVaCreatePopupShell(title, xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("help_view pane", xmPanedWindowWidgetClass, help_view_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("help_view my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); n=0; XtSetArg(args[n], XmNrows, 20); n++; XtSetArg(args[n], XmNcolumns, 80); n++; XtSetArg(args[n], XmNeditable, FALSE); n++; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; XtSetArg(args[n], XmNwordWrap, TRUE); n++; XtSetArg(args[n], XmNscrollHorizontal, FALSE); n++; XtSetArg(args[n], XmNcursorPositionVisible, FALSE); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightOffset, 5); n++; XtSetArg(args[n], XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n], XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; help_text=NULL; help_text = XmCreateScrolledText(my_form, "help_view help text", args, n); get_user_base_dir(HELP_FILE, help_file_path, sizeof(help_file_path)); f=fopen( help_file_path, "r" ); if (f!=NULL) { while(!feof(f)) { (void)get_line(f,temp2,200); if (strncmp(temp2,"HELP-INDEX>",11)==0) { if(strcmp((temp2+11),temp)==0) { data_on=1; } else { data_on=0; } } else { if (data_on) { strcpy(temp3, temp2); temp3[sizeof(temp3)-1] = '\0'; // Terminate string strcat(temp3, "\n"); temp3[sizeof(temp3)-1] = '\0'; // Terminate string XmTextInsert(help_text,pos,temp3); pos += strlen(temp3); XmTextShowPosition(help_text,0); } } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", help_file_path); } button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_text), XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, help_view_destroy_shell, help_view_dialog); if (!open) { pos_dialog(help_view_dialog); } else { XtVaSetValues(help_view_dialog, XmNx, x, XmNy, y, NULL); } delw = XmInternAtom(XtDisplay(help_view_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(help_view_dialog, delw, help_view_destroy_shell, (XtPointer)help_view_dialog); XtManageChild(my_form); XtManageChild(help_text); XtVaSetValues(help_text, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, help_view_dialog); XtPopup(help_view_dialog,XtGrabNone); XmTextShowPosition(help_text,0); } XtFree(temp); // Free up the space allocated } } void Help_Index( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel; int n; char temp[600]; FILE *f; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ Atom delw; XmString str_ptr; char help_file_path[MAX_VALUE]; if(!help_index_dialog) { help_index_dialog = XtVaCreatePopupShell(langcode("WPUPHPI001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNresize, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Help_Index pane", xmPanedWindowWidgetClass, help_index_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Help_Index my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 11); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNbackground, colors[0x0ff]); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; help_list = XmCreateScrolledList(my_form, "Help_Index list", al, ac); n=1; get_user_base_dir(HELP_FILE, help_file_path, sizeof(help_file_path)); f=fopen( help_file_path, "r" ); if (f!=NULL) { while (!feof(f)) { (void)get_line(f,temp,600); if (strncmp(temp,"HELP-INDEX>",11)==0) { XmListAddItem(help_list, str_ptr = XmStringCreateLocalized((temp+11)),n++); XmStringFree(str_ptr); } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", help_file_path ); } button_ok = XtVaCreateManagedWidget(langcode("WPUPHPI002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_list), XmNtopOffset,5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(help_list), XmNtopOffset,5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, help_index_destroy_shell, help_index_dialog); XtAddCallback(button_ok, XmNactivateCallback, help_view, NULL); pos_dialog(help_index_dialog); delw = XmInternAtom(XtDisplay(help_index_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(help_index_dialog, delw, help_index_destroy_shell, (XtPointer)help_index_dialog); XtManageChild(my_form); XtManageChild(help_list); XtVaSetValues(help_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, help_index_dialog); XtPopup(help_index_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(help_index_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { XtPopup(help_index_dialog,XtGrabNone); (void)XRaiseWindow(XtDisplay(help_index_dialog), XtWindow(help_index_dialog)); } } /************************** Clear stations *******************************/ /*************************************************************************/ void Stations_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { delete_all_stations(); my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); current_trail_color = 0x00; // restart // Reload saved objects and items from previous runs. // This implements persistent objects. reload_object_item(); redraw_on_new_data=2; } /************************* Map Properties*********************************/ /*************************************************************************/ // Destroys the Map Properties dialog void map_properties_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); map_properties_dialog = (Widget)NULL; re_sort_maps = 1; if (map_chooser_dialog) { XtSetSensitive(map_chooser_button_ok, TRUE); XtSetSensitive(map_chooser_button_cancel, TRUE); } } //WE7U // Possible changes: // *) Save/restore the map selections while changing properties. // Malloc a char array the size of the map_properties_list and // fill it in based on the current highlighting. Free it when // we're done. // *) Change the labels at the top into buttons? Zoom/Layer buttons // would pop up a dialog asking for the number. Others would // just toggle the feature. // *) Change to a single "Apply" button. This won't allow us to // easily change only some parameters unless we skip input fields // that are blank. Run through highlighted items, fill in input // fields if the parameter is the same for all. If different for // some, leave input field blank. // *) Bring up an "Abandon Changes?" confirmation dialog if input // fields are filled in but "Cancel" was pressed instead of // "Apply". // Fills in the map properties file entries. // void map_properties_fill_in (void) { int n; // int i; XmString str_ptr; map_index_record *current = map_index_head; int top_position; busy_cursor(appshell); // i=0; if (map_properties_dialog) { char *current_selections = NULL; int kk, mm; // Save our current place in the dialog XtVaGetValues(map_properties_list, XmNtopItemPosition, &top_position, NULL); // Get the list count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&kk, NULL); if (kk) // If list is not empty { // Allocate enough chars to hold the highlighting info current_selections = (char *)malloc(sizeof(char) * kk); //fprintf(stderr,"List entries:%d\n", kk); // Iterate over the list, saving the highlighting values for (mm = 0; mm < kk; mm++) { if (XmListPosSelected(map_properties_list, mm)) { current_selections[mm] = 1; } else { current_selections[mm] = 0; } } } // fprintf(stderr,"Top Position: %d\n",top_position); // Empty the map_properties_list widget first XmListDeleteAllItems(map_properties_list); // Put all the map files/dirs in the map_index into the Map // Properties dialog list (map_properties_list). Include // the map_layer and draw_filled variables on the line. n=1; // // We wish to only show the files that are currently selected in the // map_chooser_dialog's map_list widget. We'll need to run down // that widget's entries, checking whether each line is selected, // and only display it in the map_properties_list widget if selected // and a match with our string. // // One method would be to make the Map Chooser selections set a bit // in the in-memory index, so that we can tell which ones are // selected without a bunch of string compares. The bit would need // to be tweaked on starting up the map chooser (setting the // selected entries that match the selected_maps.sys file), and when // the user tweaked a selection. // // What we don't want to get into is an n*n set of string compares // between two lists, which would be very slow. If they're both // ordered lists though, we'll end up with at most a 2n multiplier, // which is much better. If we can pass the info between the lists // with a special entry in the record, we don't slow down at all. // // Reasonably fast method: Create a new list that contains only the // selected items from map_list. Run through this list as we // populate map_properties_list from the big linked list. // // Actually, it's probably just as fast to run down through // map_list, looking up records for every line that's selected. // Just keep the pointers incrementing for each list instead of // running through the entire in-memory linked list for every // selected item in map_list. // // For selected directories, we need to add each file that has that // initial directory name. We should be able to do this with a // match that stops at the end of the directory name. // // We need to grey-out the buttons in the Map Chooser until the // Properties dialog closes. Otherwise we might not able to get to // to the map_list widget to re-do the Properties list when a button // is pressed in the Properties dialog (if the user closes the Map // Chooser). // // Set all of the temp_select bits to zero in the in-memory // map index. map_index_temp_select_clear(); if (map_chooser_dialog) { map_index_record *ptr = map_index_head; int jj, x; XmString *list; char *temp; // Get the list and list count from the Map Chooser // dialog. XtVaGetValues(map_list, XmNitemCount,&jj, XmNitems,&list, NULL); // Find all selected files/directories in the Map // Chooser. Set the "temp_select" bits in the in-memory // map index to correspond. // for(x=1; x<=jj; x++) { if (XmListPosSelected(map_list,x)) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory // map index, setting the "temp_select" field to 1. map_index_update_temp_select(temp, &ptr); XtFree(temp); } } } } // We should now have all of the files/directories marked in // the in-memory map index. Files underneath selected // directories should also be marked by this point, as the // map_index_update_temp_select() routine should assure // this. while (current != NULL) { if (current->temp_select) { //fprintf(stderr,"%s\n",current->filename); // Make sure it's a file and not a directory if (current->filename[strlen(current->filename)-1] != '/') { char temp[MAX_FILENAME+100]; char temp_layer[10]; char temp_max_zoom[10]; char temp_min_zoom[10]; char temp_filled[20]; char temp_drg[20]; char temp_auto[20]; int len, start; // We have a file. Construct the line that we wish // to place in the list // JMT - this is a guess if (current->max_zoom == 0) { xastir_snprintf(temp_max_zoom, sizeof(temp_max_zoom), " - "); } else { xastir_snprintf(temp_max_zoom, sizeof(temp_max_zoom), "%5d", current->max_zoom); } if (current->min_zoom == 0) { xastir_snprintf(temp_min_zoom, sizeof(temp_min_zoom), " - "); } else { xastir_snprintf(temp_min_zoom, sizeof(temp_min_zoom), "%5d", current->min_zoom); } if (current->map_layer == 0) { xastir_snprintf(temp_layer, sizeof(temp_layer), " - "); } else { xastir_snprintf(temp_layer, sizeof(temp_layer), "%5d", current->map_layer); } xastir_snprintf(temp_filled, sizeof(temp_filled), " "); switch (current->draw_filled) { case 0: // Global No-Fill (vector) // Center the string in the column len = strlen(langcode("MAPP007")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP007")); // "No" break; case 1: // Global Fill // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP006")); // "Yes" break; case 2: // Auto default: // Center the string in the column len = strlen(langcode("MAPP011")); start = (int)( (5 - len) / 2 + 1.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_filled[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP011")); // "Auto" break; } // End of switch // Truncate it so it fits our column width. temp_filled[5] = '\0'; xastir_snprintf(temp_drg, sizeof(temp_drg), " "); switch (current->usgs_drg) { case 0: // No // Center the string in the column len = strlen(langcode("MAPP007")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP007")); // "No" break; case 1: // Yes // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP006")); // "Yes" break; case 2: // Auto default: // Center the string in the column len = strlen(langcode("MAPP011")); start = (int)( (5 - len) / 2 + 1.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces // on the end. xastir_snprintf(&temp_drg[start], sizeof(temp_drg)-start, "%s ", langcode("MAPP011")); // "Auto" break; } // End of switch // Truncate it so it fits our column width. temp_drg[5] = '\0'; xastir_snprintf(temp_auto, sizeof(temp_auto), " "); if (current->auto_maps) { int len, start; // Center the string in the column len = strlen(langcode("MAPP006")); start = (int)( (5 - len) / 2 + 0.5); if (start < 0) { start = 0; } // Insert the string. Fill with spaces on the // end. xastir_snprintf(&temp_auto[start], sizeof(temp_filled)-start, "%s ", langcode("MAPP006")); // Truncate it so it fits our column width. temp_auto[5] = '\0'; } //WARNING WARNING WARNING --- changing this format string // REQUIRES changing the defined constant MPD_FILENAME_OFFSET // at the top of this file, or all the routines that try // to decode the string will be wrong! xastir_snprintf(temp, sizeof(temp), "%s %s %s %s %s %s %s", temp_max_zoom, temp_min_zoom, temp_layer, temp_filled, temp_drg, temp_auto, current->filename); str_ptr = XmStringCreateLocalized(temp); XmListAddItem(map_properties_list, str_ptr, n); n++; XmStringFree(str_ptr); } } current = current->next; } if (kk) // If list is not empty { // Restore the highlighting values for (mm = 0; mm < kk; mm++) { if (current_selections[mm]) { XmListSelectPos(map_properties_list,mm,TRUE); } } // Free the highlighting array we allocated free(current_selections); } // Restore our place in the dialog XtVaSetValues(map_properties_list, XmNtopItemPosition, top_position, NULL); } } // Removes the highlighting for maps in the current view of the map // properties list. // void map_properties_deselect_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, deselecting every line for(x=1; x<=i; x++) { if (XmListPosSelected(map_properties_list,x)) { XmListDeselectPos(map_properties_list,x); } } } // Selects all maps in the current view of the map properties list. // void map_properties_select_all_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, selecting every line for(x=1; x<=i; x++) { // Deselect each one first, in case already selected XmListDeselectPos(map_properties_list,x); // Select/highlight that position XmListSelectPos(map_properties_list,x,TRUE); } } // Change the "draw_filled" field in the in-memory map_index to a // two. void map_index_update_filled_auto(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 2; break; } current = current->next; } } // Change the "draw_filled" field in the in-memory map_index to a // one. void map_index_update_filled_yes(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 1; break; } current = current->next; } } // Change the "draw_filled" field in the in-memory map_index to a // zero. void map_index_update_filled_no(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->draw_filled = 0; break; } current = current->next; } } void map_properties_filled_auto(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 2. map_index_update_filled_auto(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_filled_yes(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 1. map_index_update_filled_yes(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_filled_no(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the filled field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "draw_filled" field to 0. map_index_update_filled_no(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Change the "usgs_drg" field in the in-memory map_index to a // specified value. void map_index_update_usgs_drg(char *filename, int drg_setting) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->usgs_drg = drg_setting; break; } current = current->next; } } // common functionality of all the callbacks. Probably don't even need // all the X data here, either void map_properties_usgs_drg(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData), int drg_setting) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the usgs_drg field on // every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "usgs_drg" field to drg_setting. map_index_update_usgs_drg(&temp[MPD_FILENAME_OFFSET],drg_setting); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // the real callbacks void map_properties_usgs_drg_auto(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 2); } void map_properties_usgs_drg_yes(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 1); } void map_properties_usgs_drg_no(Widget widget, XtPointer clientData, XtPointer callData) { map_properties_usgs_drg(widget, clientData, callData, 0); } // Change the "auto_maps" field in the in-memory map_index to a one. void map_index_update_auto_maps_yes(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->auto_maps = 1; return; } current = current->next; } } // Change the "auto_maps" field in the in-memory map_index to a // zero. void map_index_update_auto_maps_no(char *filename) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->auto_maps = 0; return; } current = current->next; } } void map_properties_auto_maps_yes(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the auto_maps field // on every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "auto_maps" field to 1. map_index_update_auto_maps_yes(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } void map_properties_auto_maps_no(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; char *temp; // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the auto_maps field // on every one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting the "auto_maps" field to 0. map_index_update_auto_maps_no(&temp[MPD_FILENAME_OFFSET]); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "map_layer" field in the in-memory map_index based on // the "map_layer" input parameter. void map_index_update_layer(char *filename, int map_layer) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->map_layer = map_layer; return; } current = current->next; } } void map_properties_layer_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_layer; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_map_layer_text); new_layer = atoi(temp); XtFree(temp); //fprintf(stderr,"New layer selected is: %d\n", new_layer); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_layer(&temp[MPD_FILENAME_OFFSET], new_layer); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "max_zoom" field in the in-memory map_index based on // the "max_zoom" input parameter. void map_index_update_max_zoom(char *filename, int max_zoom) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->max_zoom = max_zoom; return; } current = current->next; } } void map_properties_max_zoom_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_max_zoom; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_max_zoom_text); new_max_zoom = atoi(temp); XtFree(temp); // fprintf(stderr,"New max_zoom selected is: %d\n", new_max_zoom); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_max_zoom(&temp[MPD_FILENAME_OFFSET], new_max_zoom); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // Update the "min_zoom" field in the in-memory map_index based on // the "min_zoom" input parameter. void map_index_update_min_zoom(char *filename, int min_zoom) { map_index_record *current = map_index_head; while (current != NULL) { if (strcmp(current->filename,filename) == 0) { // Found a match. Update the field and return. current->min_zoom = min_zoom; return; } current = current->next; } } void map_properties_min_zoom_change(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, new_min_zoom; XmString *list; char *temp; // Get new layer selection in the form of an int temp = XmTextGetString(new_min_zoom_text); new_min_zoom = atoi(temp); XtFree(temp); //fprintf(stderr,"New layer selected is: %d\n", new_layer); // Get the list and the count from the dialog XtVaGetValues(map_properties_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, changing the layer on every // one that is selected. for(x=1; x<=i; x++) { // If the line was selected if ( XmListPosSelected(map_properties_list,x) ) { // Snag the filename portion from the line temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_END); if (temp) { // Update this file or directory in the in-memory // map index, setting/resetting the "selected" field // as appropriate. map_index_update_min_zoom(&temp[MPD_FILENAME_OFFSET], new_min_zoom); XtFree(temp); } } } // Delete all entries in the list and re-create anew. map_properties_fill_in(); // Save the updated index to the file index_save_to_file(); } // JMT -- now supports max and min zoom levels // Allows setting map layer and filled polygon properties for maps // selected in the map chooser. Show a warning or bring up a // confirmation dialog if more than one map is selected when this // function is entered. This is the callback function for the // Properties button in the Map Chooser. // // If the map_layer is a range of values, inform the user here // via a popup, so that they don't make a mistake and change too // many different types of maps to the same map layer. // // We could either show all maps here and allow changing each // one, or just show min/max map_layer draw_filled properties // for the maps selected in the Map Chooser. // // Create the properties dialog. Show the map_layer and // draw_filled properties for the maps. // // Could still create Cancel and OK buttons. Cancel would wipe the // in-memory list and fetch it from file again. OK would write the // in-memory list to disk. // void map_properties( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // int i; // int x; // char *temp; // XmString *list; static Widget pane, my_form, button_clear, button_close, rowcol1, rowcol2, rowcol3, label1, label2, button_filled_auto, button_filled_yes, button_filled_no, button_usgs_drg_auto, button_usgs_drg_yes, button_usgs_drg_no, button_layer_change, button_auto_maps_yes, button_auto_maps_no, button_max_zoom_change, button_min_zoom_change, button_select_all; // static Widget label3, label4, label5; Atom delw; Arg al[50]; // Arg List register unsigned int ac = 0; // Arg Count busy_cursor(appshell); if (map_chooser_dialog) { XtSetSensitive(map_chooser_button_ok, FALSE); XtSetSensitive(map_chooser_button_cancel, FALSE); } // i=0; if (!map_properties_dialog) { map_properties_dialog = XtVaCreatePopupShell(langcode("MAPP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Map_properties pane", xmPanedWindowWidgetClass, map_properties_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); my_form = XtVaCreateWidget("Map_properties my_form", xmFormWidgetClass, pane, XmNfractionBase, 7, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_properties_list = XmCreateScrolledList(my_form, "Map_properties list", al, ac); // Find the names of all the map files on disk and put them // into map_properties_list map_properties_fill_in(); // Attach a rowcolumn manager widget to my_form to handle // the third button row. Attach it to the bottom of the // form. rowcol3 = XtVaCreateManagedWidget("Map properties rowcol3", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Attach a rowcolumn manager widget to my_form to handle // the second button row. Attach it to the top of rowcol3. rowcol2 = XtVaCreateManagedWidget("Map properties rowcol2", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol3, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Attach a rowcolumn manager widget to my_form to handle // the first button row. rowcol1 = XtVaCreateManagedWidget("Map properties rowcol1", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol2, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label1 = XtVaCreateManagedWidget(langcode("MAPP002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); label2 = XtVaCreateManagedWidget(langcode("MAPP003"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label1, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtVaSetValues(XtParent(map_properties_list), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, label2, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol1, XmNbottomOffset, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // JMT -- this is a guess // "Max Zoom" stolen from "Change Layer" button_max_zoom_change = XtVaCreateManagedWidget(langcode("MAPP009"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_max_zoom_text = XtVaCreateManagedWidget("Map Properties max zoom number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // "Min Zoom" stolen from "Change Layer" button_min_zoom_change = XtVaCreateManagedWidget(langcode("MAPP010"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_min_zoom_text = XtVaCreateManagedWidget("Map Properties min zoom number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); // "Change Layer" button_layer_change = XtVaCreateManagedWidget(langcode("MAPP004"), xmPushButtonGadgetClass, rowcol1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_map_layer_text = XtVaCreateManagedWidget("Map Properties new layer number", xmTextWidgetClass, rowcol1, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNwidth, ((7*7)+2), XmNmaxLength, 5, XmNbackground, colors[0x0f], XmNrightOffset, 1, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); //label3 XtVaCreateManagedWidget(langcode("MAPP005"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-Auto" button_filled_auto = XtVaCreateManagedWidget(langcode("MAPP011"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-Yes" button_filled_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Filled-No" button_filled_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Automaps //label4 XtVaCreateManagedWidget(langcode("MAPP008"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Automaps-Yes" button_auto_maps_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Automaps-No" button_auto_maps_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // USGS DRG-> //label5 XtVaCreateManagedWidget(langcode("MAPP012"), xmLabelWidgetClass, rowcol2, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG Auto" button_usgs_drg_auto = XtVaCreateManagedWidget(langcode("MAPP011"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG Yes" button_usgs_drg_yes = XtVaCreateManagedWidget(langcode("MAPP006"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "USGS DRG No" button_usgs_drg_no = XtVaCreateManagedWidget(langcode("MAPP007"), xmPushButtonGadgetClass, rowcol2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Select All" button_select_all = XtVaCreateManagedWidget(langcode("PULDNMMC09"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Clear" button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC01"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Close" button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, rowcol3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, map_properties_destroy_shell, map_properties_dialog); XtAddCallback(button_clear, XmNactivateCallback, map_properties_deselect_maps, map_properties_dialog); XtAddCallback(button_select_all, XmNactivateCallback, map_properties_select_all_maps, map_properties_dialog); XtAddCallback(button_filled_auto, XmNactivateCallback, map_properties_filled_auto, map_properties_dialog); XtAddCallback(button_filled_yes, XmNactivateCallback, map_properties_filled_yes, map_properties_dialog); XtAddCallback(button_filled_no, XmNactivateCallback, map_properties_filled_no, map_properties_dialog); XtAddCallback(button_usgs_drg_auto, XmNactivateCallback, map_properties_usgs_drg_auto, map_properties_dialog); XtAddCallback(button_usgs_drg_yes, XmNactivateCallback, map_properties_usgs_drg_yes, map_properties_dialog); XtAddCallback(button_usgs_drg_no, XmNactivateCallback, map_properties_usgs_drg_no, map_properties_dialog); XtAddCallback(button_max_zoom_change, XmNactivateCallback, map_properties_max_zoom_change, map_properties_dialog); XtAddCallback(button_min_zoom_change, XmNactivateCallback, map_properties_min_zoom_change, map_properties_dialog); XtAddCallback(button_layer_change, XmNactivateCallback, map_properties_layer_change, map_properties_dialog); XtAddCallback(button_auto_maps_yes, XmNactivateCallback, map_properties_auto_maps_yes, map_properties_dialog); XtAddCallback(button_auto_maps_no, XmNactivateCallback, map_properties_auto_maps_no, map_properties_dialog); pos_dialog(map_properties_dialog); delw = XmInternAtom(XtDisplay(map_properties_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_properties_dialog, delw, map_properties_destroy_shell, (XtPointer)map_properties_dialog); XtManageChild(rowcol1); XtManageChild(rowcol2); XtManageChild(rowcol3); XtManageChild(my_form); XtManageChild(map_properties_list); XtVaSetValues(map_properties_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); XmTextSetString(new_map_layer_text, "0"); XtPopup(map_properties_dialog,XtGrabNone); // Move focus to the OK button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_properties_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_properties_dialog), XtWindow(map_properties_dialog)); } } /************************* Map Chooser ***********************************/ /*************************************************************************/ // Destroys the Map Chooser dialog void map_chooser_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); map_chooser_dialog = (Widget)NULL; } // Update the "selected" field in the in-memory map_index based on // the "selected" input parameter. void map_index_update_selected(char *filename, int selected, map_index_record **current) { // If we're passed a NULL pointer, start at the head of the // in-memory linked list. // if ( (*current) == NULL) { (*current) = map_index_head; } // Start searching through the list at the pointer we were // given. // while ( (*current) != NULL) { if (strcmp( (*current)->filename,filename) == 0) { // Found a match. Update the field and return. (*current)->selected = selected; return; } (*current) = (*current)->next; } } // Update the "temp_select" field in the in-memory map_index. void map_index_update_temp_select(char *filename, map_index_record **current) { int result; // If we're passed a NULL pointer, start at the head of the // in-memory linked list. // if ( (*current) == NULL) { (*current) = map_index_head; } // Start searching through the list at the pointer we were // given. We need to do a loose match here for directories. If // a selected directory is contained in a filepath, select that // file as well. For the directory case, once we find a match // in the file path, keep walking down the list until we get a // non-match. // while ( (*current) != NULL) { result = strncmp( (*current)->filename,filename,strlen(filename)); if (result == 0) { // Found a match. Update the field. (*current)->temp_select = 1; } else if (result > 0) // We passed the relevant area. { // All done for now. return; } (*current) = (*current)->next; } } // Clear all of the temp_select bits in the in-memory map index void map_index_temp_select_clear(void) { map_index_record *current; current = map_index_head; while (current != NULL) { current->temp_select = 0; current = current->next; } } // Gets the list of selected maps out of the dialog, writes them to // the selected maps disk file, destroys the dialog, then calls // create_image() with the newly selected map set in place. This // should be the _only_ routine in this set of functions that // actually changes the selected maps disk file. The others should // merely manipulate the list in the map chooser dialog. This // function is attached to the "OK" button in the Map Chooser dialog. // // What we'll do here is set/reset the "selected" field in the // in-memory map_index list, then write the info out to the // selected_maps.sys file. Only set the file entries if in file // mode, dir entries if in dir mode. When writing out to file, // write them both out. // // In order to make this fast, we'll send a start pointer to // map_index_update_selected() which is the "next" pointer from the // previous hit. We're relying on the fact that the Map Chooser // list and the in-memory linked list are in the same search order, // so this way we don't search through the entire linked list for // each update. With 30,000 maps, it ended up being up to 30,000 * // 30,000 for the loop iterations, which was unwieldy. // void map_chooser_select_maps(Widget widget, XtPointer clientData, XtPointer callData) { int i, x; char *temp; XmString *list; FILE *f; map_index_record *ptr = map_index_head; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // It'd be nice to turn off auto-maps here, or better perhaps would // be if any button were chosen other than "Cancel". // reset map_refresh in case we no longer have a refreshed map selected map_refresh_interval = 0; // Cause load_maps() and load_automaps() to re-sort the selected // maps by layer. re_sort_maps = 1; // Get the list and the list count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list, updating the equivalent entries in the // in-memory map index. If we're in "directory" mode we'll only // update the directory entries. In "Expanded dirs" mode, we'll // update both file and directory entries. // The end result is that both directories and files may be // selected, not either/or as the code was written earlier. // // Here we basically walk both lists together, the List widget // and the in-memory linked list, as they're both in the same // sort order. We do this by passing "ptr" back and forth, and // updating it to point to one after the last one found each // time. That turns and N*N search into an N search and is a // big speed improvement when you have 1000's of maps. // for(x=1; x<=i; x++) { temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory map // index, setting/resetting the "selected" field as // appropriate. map_index_update_selected(temp, XmListPosSelected(map_list,x), &ptr); XtFree(temp); } //fprintf(stderr,"Passed back: %s\n", ptr->filename); ptr = ptr->next; } // Now we have all of the updates done to the in-memory map // index. Write out the selected maps to disk, overwriting // whatever was there before. ptr = map_index_head; f=fopen( selected_map_path, "w+" ); if (f!=NULL) { while (ptr != NULL) { // Write only selected files/directories out to the disk // file. if (ptr->selected) { fprintf(f,"%s\n",ptr->filename); } ptr = ptr->next; } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } map_chooser_destroy_shell(widget,clientData,callData); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0; // } } // Same as map_chooser_select_maps, but doesn't destroy the Map // Chooser dialog. void map_chooser_apply_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; char *temp; XmString *list; FILE *f; map_index_record *ptr = map_index_head; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // It'd be nice to turn off auto-maps here, or better perhaps would // be if any button were chosen other than "Cancel". // reset map_refresh in case we no longer have a refreshed map selected map_refresh_interval = 0; // Cause load_maps() and load_automaps() to re-sort the selected // maps by layer. re_sort_maps = 1; // Get the list and the list count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list, updating the equivalent entries in the // in-memory map index. If we're in "directory" mode we'll only // update the directory entries. In "Expanded dirs" mode, we'll // update both file and directory entries. // The end result is that both directories and files may be // selected, not either/or as the code was written earlier. // // Here we basically walk both lists together, the List widget // and the in-memory linked list, as they're both in the same // sort order. We do this by passing "ptr" back and forth, and // updating it to point to one after the last one found each // time. That turns and N*N search into an N search and is a // big speed improvement when you have 1000's of maps. // for(x=1; x<=i; x++) { temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if (temp) { // Update this file or directory in the in-memory map // index, setting/resetting the "selected" field as // appropriate. map_index_update_selected(temp, XmListPosSelected(map_list,x), &ptr); XtFree(temp); } //fprintf(stderr,"Passed back: %s\n", ptr->filename); ptr = ptr->next; } // Now we have all of the updates done to the in-memory map // index. Write out the selected maps to disk, overwriting // whatever was there before. ptr = map_index_head; f=fopen( selected_map_path, "w+" ); if (f!=NULL) { while (ptr != NULL) { // Write only selected files/directories out to the disk // file. if (ptr->selected) { fprintf(f,"%s\n",ptr->filename); } ptr = ptr->next; } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } // map_chooser_destroy_shell(widget,clientData,callData); // Set interrupt_drawing_now because conditions have changed. interrupt_drawing_now++; // Request that a new image be created. Calls create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } // Counts the number of "selected" fields with a value of 1 in the // in-memory map index. Updates the "Dirs/Maps Selected" count in // the map chooser. void map_chooser_update_quantity(void) { int dir_quantity = 0; int map_quantity = 0; static char str_quantity[100]; map_index_record *current = map_index_head; XmString x_str; // Count the "selected" fields in the map index with value of 1 while (current != NULL) { if (current->selected) { if (current->filename[strlen(current->filename)-1] == '/') { // It's a directory dir_quantity++; } else { // It's a map map_quantity++; } } current = current->next; } // Update the "Dirs/Maps Selected" label in the Map Chooser xastir_snprintf(str_quantity, sizeof(str_quantity), "%d/%d", dir_quantity, map_quantity); x_str = XmStringCreateLocalized(str_quantity); XtVaSetValues(map_chooser_maps_selected_data, XmNlabelString, x_str, NULL); XmStringFree(x_str); } void map_chooser_select_vector_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); if ( (ext != NULL) && ( (strcasecmp(ext,"map") == 0) || (strcasecmp(ext,"shp") == 0) || (strcasecmp(ext,"gnis") == 0) || (strcasecmp(ext,"rt1") == 0) || (strcasecmp(ext,"rt2") == 0) || (strcasecmp(ext,"rt4") == 0) || (strcasecmp(ext,"rt5") == 0) || (strcasecmp(ext,"rt6") == 0) || (strcasecmp(ext,"rt7") == 0) || (strcasecmp(ext,"rt8") == 0) || (strcasecmp(ext,"rta") == 0) || (strcasecmp(ext,"rtc") == 0) || (strcasecmp(ext,"rth") == 0) || (strcasecmp(ext,"rti") == 0) || (strcasecmp(ext,"rtp") == 0) || (strcasecmp(ext,"rtr") == 0) || (strcasecmp(ext,"rts") == 0) || (strcasecmp(ext,"rtt") == 0) || (strcasecmp(ext,"rtz") == 0) || (strcasecmp(ext,"tab") == 0) ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_250k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'c') || (temp[length - 12] == 'C') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_100k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'f') || (temp[length - 12] == 'F') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } void map_chooser_select_24k_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x, length; char *temp; char *ext; XmString *list; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the list looking for matching file extensions for(x=1; x<=i; x++) { // // Deselect all currently selected maps // if (XmListPosSelected(map_list,x)) { // XmListDeselectPos(map_list,x); // } temp = XmStringUnparse(list[(x-1)], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(temp) { ext = get_map_ext (temp); length = (int)strlen(temp); if ( (ext != NULL) && (strcasecmp (ext, "tif") == 0) && (length >= 12) // "o48122h3.tif", we might have subdirectories also && ( (temp[length - 12] == 'o') || (temp[length - 12] == 'O') || (temp[length - 12] == 'k') || (temp[length - 12] == 'K') ) ) { XmListSelectPos(map_list,x,TRUE); } XtFree(temp); } } map_chooser_update_quantity(); } // Removes the highlighting for maps in the current view of the map // chooser. In order to de-select all maps, must flip through both // map chooser views and hit the "none" button each time, then hit // the "ok" button. // // Changed the code to clear all of the "selected" bits in the // in-memory map index as well. The "None" and "OK" buttons take // immediate effect, all others do not (until the "OK" button is // pressed). Decided that this was too inconsistent, so changed it // back and changed "None" to "Clear", which means to clear the // currently seen selections, but not the selections in the other // mode. // void map_chooser_deselect_maps(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { int i, x; XmString *list; // map_index_record *current = map_index_head; // Get the list and the count from the dialog XtVaGetValues(map_list, XmNitemCount,&i, XmNitems,&list, NULL); // Run through the widget's list, deselecting every line for(x=1; x<=i; x++) { if (XmListPosSelected(map_list,x)) { XmListDeselectPos(map_list,x); } } /* // Run through the in-memory map list, deselecting every line while (current != NULL) { current->selected = 0; // Not Selected current = current->next; } */ map_chooser_update_quantity(); } void sort_list(char *filename,int size, Widget list, int *item) { FILE *f_data; FILE *f_pointer; char fill[2000]; long file_ptr; // long ptr; char ptr_filename[400]; XmString str_ptr; // Clear the list widget first XmListDeleteAllItems(list); xastir_snprintf(ptr_filename, sizeof(ptr_filename), "%s-ptr", filename); f_pointer=fopen(ptr_filename,"r"); f_data=fopen(filename,"r"); if (f_pointer!=NULL && f_data !=NULL) { while (!feof(f_pointer)) { // ptr=ftell(f_pointer); if (fread(&file_ptr,sizeof(file_ptr),1,f_pointer)==1) { (void)fseek(f_data,file_ptr,SEEK_SET); if (fread(fill,(size_t)size,1,f_data)==1) { str_ptr = XmStringCreateLocalized(fill); XmListAddItem(list, str_ptr,*item); XmStringFree(str_ptr); (*item)++; } } } } if(f_pointer!=NULL) { (void)fclose(f_pointer); } else { fprintf(stderr,"Couldn't open file: %s\n", ptr_filename); } if(f_data!=NULL) { (void)fclose(f_data); } else { fprintf(stderr,"Couldn't open file: %s\n", filename); } } // Mark the "selected" field in the in-memory map index based on the // contents of the selected_maps.sys file. Called from main() right // after map_indexer() is called on startup. void map_chooser_init (void) { FILE *f; char temp[600]; map_index_record *current; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); busy_cursor(appshell); // First run through our in-memory map index, clearing all of // the selected bits. current = map_index_head; while (current != NULL) { current->selected = 0; current = current->next; } (void)filecreate( selected_map_path ); // Create empty file if it doesn't exist f=fopen( selected_map_path, "r" ); if (f!=NULL) { while(!feof(f)) { int done; (void)get_line(f,temp,600); // We have a line from the file. Find the matching line // in the in-memory map index. current = map_index_head; done = 0; while (current != NULL && !done) { //fprintf(stderr,"%s\n",current->filename); if (strcmp(temp,current->filename) == 0) { current->selected = 1; done++; } current = current->next; } } (void)fclose(f); } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } } // Fills in the map chooser file/directory entries based on the // current view and whether the "selected" field in the in-memory // map_index is set for each file/directory. // // We also check the XmStringPtr field in the map index records. If // NULL, then we call XmStringCreateLocalized() to allocate and fill in // the XmString value corresponding to the filename. We use that to // speed up Map Chooser later. // void map_chooser_fill_in (void) { int n,i; map_index_record *current = map_index_head; busy_cursor(appshell); i=0; if (map_chooser_dialog) { // Empty the map_list widget first XmListDeleteAllItems(map_list); // Put all the map files/dirs in the map_index into the Map // Chooser dialog list (map_list). n=1; while (current != NULL) { //fprintf(stderr,"%s\n",current->filename); // Check whether we're supposed to show dirs and files or // just dirs. Directories are always shown. if (map_chooser_expand_dirs // Show all || current->filename[strlen(current->filename)-1] == '/') { // Try XmListAddItems() here? Could also create XmString's for each // filename and keep them in the map index. Then we wouldn't have to // free that malloc/free that storage space all the time. // XmListAddItems() // XmListAddItemsUnselected() // XmListReplaceItems() // XmListReplaceItemsUnselected() // If pointer is NULL, malloc and create the // XmString corresponding to the filename, attach it // to the record. The 2nd and succeeding times we // bring up Map Chooser, things will be faster. if (current->XmStringPtr == NULL) { current->XmStringPtr = XmStringCreateLocalized(current->filename); } XmListAddItem(map_list, current->XmStringPtr, n); // If a selected map, highlight it in the list if (current->selected) { XmListSelectPos(map_list,i,TRUE); } n++; } current = current->next; } } } /////////////////////////////////////// Configure DRG Dialog ////////////////////////////////////////////// #if defined(HAVE_LIBGEOTIFF) void Configure_DRG_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (configure_DRG_dialog) { XtPopdown(shell); XtDestroyWidget(shell); configure_DRG_dialog = (Widget)NULL; } } void Configure_DRG_change_data(Widget widget, XtPointer clientData, XtPointer callData) { if (configure_DRG_dialog) { if(XmToggleButtonGetState(DRG_XOR)) { DRG_XOR_colors=TRUE; } else { DRG_XOR_colors=FALSE; } if(XmToggleButtonGetState(DRG_color0)) { DRG_show_colors[0]=TRUE; } else { DRG_show_colors[0]=FALSE; } if(XmToggleButtonGetState(DRG_color1)) { DRG_show_colors[1]=TRUE; } else { DRG_show_colors[1]=FALSE; } if(XmToggleButtonGetState(DRG_color2)) { DRG_show_colors[2]=TRUE; } else { DRG_show_colors[2]=FALSE; } if(XmToggleButtonGetState(DRG_color3)) { DRG_show_colors[3]=TRUE; } else { DRG_show_colors[3]=FALSE; } if(XmToggleButtonGetState(DRG_color4)) { DRG_show_colors[4]=TRUE; } else { DRG_show_colors[4]=FALSE; } if(XmToggleButtonGetState(DRG_color5)) { DRG_show_colors[5]=TRUE; } else { DRG_show_colors[5]=FALSE; } if(XmToggleButtonGetState(DRG_color6)) { DRG_show_colors[6]=TRUE; } else { DRG_show_colors[6]=FALSE; } if(XmToggleButtonGetState(DRG_color7)) { DRG_show_colors[7]=TRUE; } else { DRG_show_colors[7]=FALSE; } if(XmToggleButtonGetState(DRG_color8)) { DRG_show_colors[8]=TRUE; } else { DRG_show_colors[8]=FALSE; } if(XmToggleButtonGetState(DRG_color9)) { DRG_show_colors[9]=TRUE; } else { DRG_show_colors[9]=FALSE; } if(XmToggleButtonGetState(DRG_color10)) { DRG_show_colors[10]=TRUE; } else { DRG_show_colors[10]=FALSE; } if(XmToggleButtonGetState(DRG_color11)) { DRG_show_colors[11]=TRUE; } else { DRG_show_colors[11]=FALSE; } if(XmToggleButtonGetState(DRG_color12)) { DRG_show_colors[12]=TRUE; } else { DRG_show_colors[12]=FALSE; } Configure_DRG_destroy_shell(widget,clientData,callData); // Reload maps // Set interrupt_drawing_now because conditions have // changed. interrupt_drawing_now++; // Request that a new image be created. Calls // create_image, // XCopyArea, and display_zoom_status. request_new_image++; // if (create_image(da)) { // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); // } } } void Configure_DRG_all(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (configure_DRG_dialog) { XmToggleButtonSetState(DRG_color0,TRUE,FALSE); XmToggleButtonSetState(DRG_color1,TRUE,FALSE); XmToggleButtonSetState(DRG_color2,TRUE,FALSE); XmToggleButtonSetState(DRG_color3,TRUE,FALSE); XmToggleButtonSetState(DRG_color4,TRUE,FALSE); XmToggleButtonSetState(DRG_color5,TRUE,FALSE); XmToggleButtonSetState(DRG_color6,TRUE,FALSE); XmToggleButtonSetState(DRG_color7,TRUE,FALSE); XmToggleButtonSetState(DRG_color8,TRUE,FALSE); XmToggleButtonSetState(DRG_color9,TRUE,FALSE); XmToggleButtonSetState(DRG_color10,TRUE,FALSE); XmToggleButtonSetState(DRG_color11,TRUE,FALSE); XmToggleButtonSetState(DRG_color12,TRUE,FALSE); } } void Configure_DRG_none(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (configure_DRG_dialog) { XmToggleButtonSetState(DRG_color0,FALSE,FALSE); XmToggleButtonSetState(DRG_color1,FALSE,FALSE); XmToggleButtonSetState(DRG_color2,FALSE,FALSE); XmToggleButtonSetState(DRG_color3,FALSE,FALSE); XmToggleButtonSetState(DRG_color4,FALSE,FALSE); XmToggleButtonSetState(DRG_color5,FALSE,FALSE); XmToggleButtonSetState(DRG_color6,FALSE,FALSE); XmToggleButtonSetState(DRG_color7,FALSE,FALSE); XmToggleButtonSetState(DRG_color8,FALSE,FALSE); XmToggleButtonSetState(DRG_color9,FALSE,FALSE); XmToggleButtonSetState(DRG_color10,FALSE,FALSE); XmToggleButtonSetState(DRG_color11,FALSE,FALSE); XmToggleButtonSetState(DRG_color12,FALSE,FALSE); } } void Config_DRG( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget DRG_pane, scrollwindow, DRG_form, button_ok, button_cancel, DRG_label1, sep1, sep2, button_all, button_none; Atom delw; if (!configure_DRG_dialog) { configure_DRG_dialog = XtVaCreatePopupShell(langcode("PULDNMP030"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); DRG_pane = XtVaCreateWidget("Configure_DRG pane", xmPanedWindowWidgetClass, configure_DRG_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, DRG_pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); DRG_form = XtVaCreateWidget("Configure_DRG DRG_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); DRG_XOR = XtVaCreateManagedWidget(langcode("MPUPDRG002"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep1 = XtVaCreateManagedWidget("Config DRG sep1", xmSeparatorGadgetClass, DRG_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, DRG_XOR, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); DRG_label1 = XtVaCreateManagedWidget(langcode("MPUPDRG001"), xmLabelWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 1 // Black DRG_color0 = XtVaCreateManagedWidget(langcode("MPUPDRG003"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Blue DRG_color2 = XtVaCreateManagedWidget(langcode("MPUPDRG005"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color0, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Red DRG_color3 = XtVaCreateManagedWidget(langcode("MPUPDRG006"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Brown DRG_color4 = XtVaCreateManagedWidget(langcode("MPUPDRG007"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color3, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Purple DRG_color6 = XtVaCreateManagedWidget(langcode("MPUPDRG009"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color4, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 2 // Light Gray DRG_color11 = XtVaCreateManagedWidget(langcode("MPUPDRG014"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Blue DRG_color8 = XtVaCreateManagedWidget(langcode("MPUPDRG011"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color11, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Red DRG_color9 = XtVaCreateManagedWidget(langcode("MPUPDRG012"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color8, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Brown DRG_color12 = XtVaCreateManagedWidget(langcode("MPUPDRG015"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color9, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Light Purple DRG_color10 = XtVaCreateManagedWidget(langcode("MPUPDRG013"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color12, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Column 3 // White DRG_color1 = XtVaCreateManagedWidget(langcode("MPUPDRG004"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_label1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Green DRG_color5 = XtVaCreateManagedWidget(langcode("MPUPDRG008"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color1, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Yellow DRG_color7 = XtVaCreateManagedWidget(langcode("MPUPDRG010"), xmToggleButtonWidgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, DRG_color5, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep2 = XtVaCreateManagedWidget("Config DRG sep2", xmSeparatorGadgetClass, DRG_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, DRG_color6, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_all = XtVaCreateManagedWidget(langcode("PULDNMMC09"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_none = XtVaCreateManagedWidget(langcode("PULDNDP040"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_all, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_none, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, DRG_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep2, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_ok, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_all, XmNactivateCallback, Configure_DRG_all, configure_DRG_dialog); XtAddCallback(button_none, XmNactivateCallback, Configure_DRG_none, configure_DRG_dialog); XtAddCallback(button_ok, XmNactivateCallback, Configure_DRG_change_data, configure_DRG_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_DRG_destroy_shell, configure_DRG_dialog); pos_dialog(configure_DRG_dialog); delw = XmInternAtom(XtDisplay(configure_DRG_dialog), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_DRG_dialog, delw, Configure_DRG_destroy_shell, (XtPointer)configure_DRG_dialog); if(DRG_XOR_colors) { XmToggleButtonSetState(DRG_XOR,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_XOR,FALSE,FALSE); } if(DRG_show_colors[0]) { XmToggleButtonSetState(DRG_color0,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color0,FALSE,FALSE); } if(DRG_show_colors[1]) { XmToggleButtonSetState(DRG_color1,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color1,FALSE,FALSE); } if(DRG_show_colors[2]) { XmToggleButtonSetState(DRG_color2,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color2,FALSE,FALSE); } if(DRG_show_colors[3]) { XmToggleButtonSetState(DRG_color3,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color3,FALSE,FALSE); } if(DRG_show_colors[4]) { XmToggleButtonSetState(DRG_color4,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color4,FALSE,FALSE); } if(DRG_show_colors[5]) { XmToggleButtonSetState(DRG_color5,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color5,FALSE,FALSE); } if(DRG_show_colors[6]) { XmToggleButtonSetState(DRG_color6,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color6,FALSE,FALSE); } if(DRG_show_colors[7]) { XmToggleButtonSetState(DRG_color7,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color7,FALSE,FALSE); } if(DRG_show_colors[8]) { XmToggleButtonSetState(DRG_color8,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color8,FALSE,FALSE); } if(DRG_show_colors[9]) { XmToggleButtonSetState(DRG_color9,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color9,FALSE,FALSE); } if(DRG_show_colors[10]) { XmToggleButtonSetState(DRG_color10,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color10,FALSE,FALSE); } if(DRG_show_colors[11]) { XmToggleButtonSetState(DRG_color11,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color11,FALSE,FALSE); } if(DRG_show_colors[12]) { XmToggleButtonSetState(DRG_color12,TRUE,FALSE); } else { XmToggleButtonSetState(DRG_color12,FALSE,FALSE); } XtManageChild(DRG_form); XtManageChild(DRG_pane); resize_dialog(DRG_form, configure_DRG_dialog); XtPopup(configure_DRG_dialog,XtGrabNone); XmProcessTraversal(button_ok, XmTRAVERSE_CURRENT); } else (void)XRaiseWindow(XtDisplay(configure_DRG_dialog), XtWindow(configure_DRG_dialog)); } #endif // HAVE_LIBGEOTIFF ///////////////////////// End of Configure DRG code /////////////////////////////////// void Expand_Dirs_toggle( Widget w, XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { map_chooser_expand_dirs = atoi(which); } else { map_chooser_expand_dirs = 0; } // Kill/resurrect the Map Chooser so that the changes take // effect. map_chooser_destroy_shell( w, map_chooser_dialog, (XtPointer) NULL); Map_chooser( w, (XtPointer)NULL, (XtPointer) NULL); map_chooser_update_quantity(); } void Map_chooser( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_clear, button_V, button_C, button_F, button_O, rowcol, expand_dirs_button, button_properties, maps_selected_label, button_apply; Atom delw; // int i; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ busy_cursor(appshell); // i=0; if (!map_chooser_dialog) { map_chooser_dialog = XtVaCreatePopupShell(langcode("WPUPMCP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Map_chooser pane", xmPanedWindowWidgetClass, map_chooser_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Map_chooser my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 7, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; map_list = XmCreateScrolledList(my_form, "Map_chooser list", al, ac); // Find the names of all the map files on disk and put them into map_list map_chooser_fill_in(); expand_dirs_button = XtVaCreateManagedWidget(langcode("PULDNMMC06"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNsensitive, TRUE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(expand_dirs_button,XmNvalueChangedCallback,Expand_Dirs_toggle,"1"); if(map_chooser_expand_dirs) { XmToggleButtonSetState(expand_dirs_button,TRUE,FALSE); } else { XmToggleButtonSetState(expand_dirs_button,FALSE,FALSE); } maps_selected_label = XtVaCreateManagedWidget(langcode("PULDNMMC07"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, expand_dirs_button, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); map_chooser_maps_selected_data = XtVaCreateManagedWidget("0/0", xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, maps_selected_label, XmNleftOffset, 2, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Button for configuring properties button_properties = XtVaCreateManagedWidget(langcode("UNIOP00009"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_properties, XmNactivateCallback, map_properties, map_chooser_dialog); // Attach a rowcolumn manager widget to my_form to handle all of the buttons rowcol = XtVaCreateManagedWidget("Map Chooser rowcol", xmRowColumnWidgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNkeyboardFocusPolicy, XmEXPLICIT, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtVaSetValues(XtParent(map_list), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, expand_dirs_button, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, rowcol, XmNbottomOffset, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNfontList, fontlist1, NULL); // "Clear" if(map_chooser_expand_dirs) // "Clear" { button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC01"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } else // "Clear Dirs" { button_clear = XtVaCreateManagedWidget(langcode("PULDNMMC08"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } // "Vector Maps" button_V = XtVaCreateManagedWidget(langcode("PULDNMMC02"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "250k Topos" button_C = XtVaCreateManagedWidget(langcode("PULDNMMC03"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "100k Topos" button_F = XtVaCreateManagedWidget(langcode("PULDNMMC04"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "24k Topos" button_O = XtVaCreateManagedWidget(langcode("PULDNMMC05"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, #ifndef HAVE_LIBGEOTIFF XmNsensitive, FALSE, #endif /* HAVE_LIBGEOTIFF */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Apply" button_apply = XtVaCreateManagedWidget(langcode("UNIOP00032"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "OK" map_chooser_button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Cancel" map_chooser_button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, rowcol, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_apply, XmNactivateCallback, map_chooser_apply_maps, map_chooser_dialog); XtAddCallback(map_chooser_button_cancel, XmNactivateCallback, map_chooser_destroy_shell, map_chooser_dialog); XtAddCallback(map_chooser_button_ok, XmNactivateCallback, map_chooser_select_maps, map_chooser_dialog); XtAddCallback(button_clear, XmNactivateCallback, map_chooser_deselect_maps, map_chooser_dialog); XtAddCallback(button_V, XmNactivateCallback, map_chooser_select_vector_maps, map_chooser_dialog); #ifdef HAVE_LIBGEOTIFF XtAddCallback(button_C, XmNactivateCallback, map_chooser_select_250k_maps, map_chooser_dialog); XtAddCallback(button_F, XmNactivateCallback, map_chooser_select_100k_maps, map_chooser_dialog); XtAddCallback(button_O, XmNactivateCallback, map_chooser_select_24k_maps, map_chooser_dialog); #endif /* HAVE_LIBGEOTIFF */ if(!map_chooser_expand_dirs) { XtSetSensitive(button_V, FALSE); XtSetSensitive(button_C, FALSE); XtSetSensitive(button_F, FALSE); XtSetSensitive(button_O, FALSE); } pos_dialog(map_chooser_dialog); delw = XmInternAtom(XtDisplay(map_chooser_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(map_chooser_dialog, delw, map_chooser_destroy_shell, (XtPointer)map_chooser_dialog); XtManageChild(rowcol); XtManageChild(my_form); XtManageChild(map_list); XtVaSetValues(map_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, map_chooser_dialog); XtPopup(map_chooser_dialog,XtGrabNone); // Move focus to the OK button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(map_chooser_dialog); XmProcessTraversal(map_chooser_button_ok, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(map_chooser_dialog), XtWindow(map_chooser_dialog)); } map_chooser_update_quantity(); } /****** Read in file **********/ void read_file_selection_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtDestroyWidget(shell); read_selection_dialog = (Widget)NULL; } void read_file_selection_now(Widget w, XtPointer clientData, XtPointer callData) { char *file; XmFileSelectionBoxCallbackStruct *cbs =(XmFileSelectionBoxCallbackStruct*)callData; file = XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_BEGINNING); if(file) { // fprintf(stderr,"FILE is %s\n",file); // Make sure we're not already reading a file and the user actually // selected a file (if not, the last character will be a '/'). if ( (!read_file) && (file[strlen(file) - 1] != '/') ) { /* do read file start */ read_file_ptr = fopen(file,"r"); if (read_file_ptr != NULL) { read_file = 1; } else { fprintf(stderr,"Couldn't open file: %s\n", file); } } XtFree(file); } read_file_selection_destroy_shell(w, clientData, callData); // Note that we leave the file in the "open" state. UpdateTime // comes along shortly and reads the file. } void Read_File_Selection( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ Widget fs; Widget child; char temp_base_dir[MAX_VALUE]; if (read_selection_dialog!=NULL) { read_file_selection_destroy_shell(read_selection_dialog, read_selection_dialog, NULL); } if(read_selection_dialog==NULL) { // This is necessary because the resources for setting the // directory in the FileSelectionDialog aren't working in Lesstif. if (chdir( get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)) ) != 0) { fprintf(stderr,"Couldn't chdir to the file selection\n"); return; } /*set args for color */ ac=0; XtSetArg(al[ac], XmNtitle, langcode("PULDNFI002")); ac++; // Open Log File XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; //XtSetArg(al[ac], XmNdirMask, "/home/hacker/.xastir/logs/*"); ac++; //XtSetArg(al[ac], XmNdirectory, "/home/hacker/.xastir/logs/"); ac++; //XtSetArg(al[ac], XmNpattern, "*"); ac++; //XtSetArg(al[ac], XmNdirMask, ".xastir/logs/*"); ac++; read_selection_dialog = XmCreateFileSelectionDialog(appshell, "filesb", al, ac); // Change back to the base directory if (chdir( get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)) ) != 0) { fprintf(stderr,"Couldn't chdir back to the base directory\n"); return; } fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_TEXT); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_FILTER_TEXT); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_DIR_LIST); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); fs=XmFileSelectionBoxGetChild(read_selection_dialog,(unsigned char)XmDIALOG_LIST); XtVaSetValues(fs,XmNbackground, colors[0x0f],NULL); XtVaSetValues(fs,XmNfontList,fontlist1,NULL); //XtVaSetValues(read_selection_dialog, XmNdirMask, "/home/hacker/.xastir/logs/*", NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_FILTER_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_DIR_LIST_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_LIST_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_SELECTION_LABEL); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_OK_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_APPLY_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_CANCEL_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); child = XmFileSelectionBoxGetChild(read_selection_dialog, XmDIALOG_HELP_BUTTON); XtVaSetValues(child,XmNfontList,fontlist1,NULL); XtAddCallback(read_selection_dialog, XmNcancelCallback,read_file_selection_destroy_shell,read_selection_dialog); XtAddCallback(read_selection_dialog, XmNokCallback,read_file_selection_now,read_selection_dialog); XtAddCallback(read_selection_dialog, XmNhelpCallback, Help_Index, read_selection_dialog); XtManageChild(read_selection_dialog); pos_dialog(read_selection_dialog); } } void Test(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // static char temp[256]; // int port = 7; mdisplay_file(0); // mem_display(); alert_print_list(); /* draw_wind_barb(50000000l, // long x_long, 32000000l, // long y_lat, "169", // char *speed, "005", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(60000000l, // long x_long, 32000000l, // long y_lat, "009", // char *speed, "123", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(70000000l, // long x_long, 32000000l, // long y_lat, "109", // char *speed, "185", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); draw_wind_barb(80000000l, // long x_long, 32000000l, // long y_lat, "079", // char *speed, "275", // char *course, sec_now(), // time_t sec_heard, pixmap_final); // Pixmap where); */ // fprintf(stderr,"view_zero_distance_bulletins = %d\n", // view_zero_distance_bulletins); /* // Simulate data coming in from a TNC in order to test igating. // Port 7 in this case is a serial TNC port (in my current test // configuration). xastir_snprintf(temp, sizeof(temp), "WE7U-4>APOT01,SUMAS*,WIDE2-2:!4757.28N/12212.00Wv178/057/A=000208 14.0V 30C\r"); if (begin_critical_section(&data_lock, "main.c" ) > 0) fprintf(stderr,"data_lock, Port = %d\n", port); incoming_data=temp; incoming_data_length = strlen(temp); data_port = port; data_avail = 1; if (end_critical_section(&data_lock, "main.c" ) > 0) fprintf(stderr,"data_lock, Port = %d\n", port); fprintf(stderr, "Sent: %s\n", temp); */ // (void)XCopyArea(XtDisplay(da),pixmap_final,XtWindow(da),gc,0,0,(unsigned int)screen_width,(unsigned int)screen_height,0,0); } /****** Save Config data **********/ void Save_Config( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { save_data(); } /////////////////////////////////// Configure Defaults Dialog ////////////////////////////////// void Configure_defaults_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_defaults_dialog = (Widget)NULL; } void Configure_defaults_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp; int load_predefined_cb_selected; XmString load_predefined_cb_selection; output_station_type = Station_transmit_type; if ((output_station_type >= 1) && (output_station_type <= 3)) { next_time = 60; max_transmit_time = (time_t)120l; // shorter beacon interval for mobile stations } else { max_transmit_time = (time_t)900l; } // Check for proper symbol in case we're a weather station (void)check_weather_symbol(); // Check for NWS symbol and print warning if so (void)check_nws_weather_symbol(); #ifdef TRANSMIT_RAW_WX transmit_raw_wx = (int)XmToggleButtonGetState(raw_wx_tx); #endif // TRANSMIT_RAW_WX transmit_compressed_objects_items = (int)XmToggleButtonGetState(compressed_objects_items_tx); pop_up_new_bulletins = (int)XmToggleButtonGetState(new_bulletin_popup_enable); view_zero_distance_bulletins = (int)XmToggleButtonGetState(zero_bulletin_popup_enable); // user interface refers to all my trails in one color // my trail diff color as 0 means my trails in one color, so select // button when my trail diff color is 0 rather than 1. my_trail_diff_color = !(int)XmToggleButtonGetState(my_trail_diff_color_enable); // Predefined (SAR/EVENT) objects menu loading (default hardcoded SAR objects or objects from file) predefined_menu_from_file = (int)XmToggleButtonGetState(load_predefined_objects_menu_from_file_enable); // Use the file specified on the picklist if one is selected. load_predefined_cb_selected = 0; #ifdef USE_COMBO_BOX XtVaGetValues(load_predefined_objects_menu_from_file, XmNselectedPosition, &load_predefined_cb_selected, NULL); #else load_predefined_cb_selected = lpomff_value; #endif //USE_COMBO_BOX // Use the file specified on the picklist if one is selected. if (load_predefined_cb_selected > 0) { // XtVaGetValues() expects to be able to write into // allocated memory. // load_predefined_cb_selection = (XmString)malloc(MAX_FILENAME); #ifdef USE_COMBO_BOX XtVaGetValues(load_predefined_objects_menu_from_file, XmNselectedItem, &load_predefined_cb_selection, NULL); #else switch (load_predefined_cb_selected) { case 1: load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); break; case 2: load_predefined_cb_selection = XmStringCreateLocalized("predefined_EVENT.sys"); break; case 3: load_predefined_cb_selection = XmStringCreateLocalized("predefined_USER.sys"); break; case 4: load_predefined_cb_selection = XmStringCreateLocalized(predefined_object_definition_filename); break; default: load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); } #endif //USE_COMBO_BOX } else { load_predefined_cb_selection = XmStringCreateLocalized("predefined_SAR.sys"); } xastir_snprintf(predefined_object_definition_filename, sizeof(predefined_object_definition_filename), "%s", temp = XmStringUnparse(load_predefined_cb_selection, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL) ); XtFree(temp); XmStringFree(load_predefined_cb_selection); // Repopulate the predefined object (SAR/Public service) struct Populate_predefined_objects(predefinedObjects); // Rebuild the predefined objects SAR/Public service menu. BuildPredefinedSARMenu_UI(&sar_object_sub); warn_about_mouse_modifiers = (int)XmToggleButtonGetState(warn_about_mouse_modifiers_enable); altnet = (int)(XmToggleButtonGetState(altnet_active)); skip_dupe_checking = (int)(XmToggleButtonGetState(disable_dupe_check)); temp = XmTextGetString(altnet_text); xastir_snprintf(altnet_call, sizeof(altnet_call), "%s", temp); XtFree(temp); (void)remove_trailing_spaces(altnet_call); if (strlen(altnet_call)==0) { altnet = FALSE; xastir_snprintf(altnet_call, sizeof(altnet_call), "XASTIR"); } operate_as_an_igate=Igate_type; redraw_on_new_data=2; Configure_defaults_destroy_shell(widget,clientData,callData); } /* Station_transmit type radio buttons */ void station_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Station_transmit_type = atoi(which); } else { Station_transmit_type = 0; } } /* Igate type radio buttons */ void igate_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Igate_type = atoi(which); } else { Igate_type = 0; } } #ifndef USE_COMBO_BOX void lpomff_menuCallback(Widget widget, XtPointer ptr, XtPointer callData) { XtPointer userData; XtVaGetValues(widget, XmNuserData, &userData, NULL); //clsd_menu is zero based, cad_line_style_data constants are one based. lpomff_value = (int)userData + 1; if (debug_level & 1) { fprintf(stderr,"Selected value on cad line type pulldown: %d\n",lpomff_value); } } #endif // !USE_COMBO_BOX void Configure_defaults( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, frame4, frame5, type_box, styp1, styp2, styp3, styp4, styp5, styp6, igate_box, igtyp0, igtyp1, igtyp2, altnet_label; // static Widget station_type, igate_option; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ #ifndef USE_COMBO_BOX Widget lpomff_menuPane; Widget lpomff_button; Widget lpomff_buttons[4]; Widget lpomff_menu; char buf[18]; int x; #endif // !USE_COMBO_BOX Widget lpomff_widget; int i; XmString cb_items[4]; #ifdef OBJECT_DEF_FILE_USER_BASE char temp_base_dir[MAX_VALUE]; #endif if (!configure_defaults_dialog) { char loadfrom[300]; // Set args for color ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; configure_defaults_dialog = XtVaCreatePopupShell(langcode("WPUPCFD001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_defaults pane", xmPanedWindowWidgetClass, configure_defaults_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_defaults my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Transmit Station Options frame4 = XtVaCreateManagedWidget("Configure_defaults frame4", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //station_type XtVaCreateManagedWidget(langcode("WPUPCFD015"), xmLabelWidgetClass, frame4, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); type_box = XmCreateRadioBox(frame4, "Configure_defaults Transmit Options box", al, ac); XtVaSetValues(type_box, XmNnumColumns,2, NULL); styp1 = XtVaCreateManagedWidget(langcode("WPUPCFD016"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp1,XmNvalueChangedCallback,station_type_toggle,"0"); styp2 = XtVaCreateManagedWidget(langcode("WPUPCFD017"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp2,XmNvalueChangedCallback,station_type_toggle,"1"); styp3 = XtVaCreateManagedWidget(langcode("WPUPCFD018"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp3,XmNvalueChangedCallback,station_type_toggle,"2"); styp4 = XtVaCreateManagedWidget(langcode("WPUPCFD019"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp4,XmNvalueChangedCallback,station_type_toggle,"3"); styp5 = XtVaCreateManagedWidget(langcode("WPUPCFD021"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp5,XmNvalueChangedCallback,station_type_toggle,"4"); styp6 = XtVaCreateManagedWidget(langcode("WPUPCFD022"), xmToggleButtonGadgetClass, type_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(styp6,XmNvalueChangedCallback,station_type_toggle,"5"); // Igate Options frame5 = XtVaCreateManagedWidget("Configure_defaults frame5", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, frame4, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //igate_option XtVaCreateManagedWidget(langcode("IGPUPCF000"), xmLabelWidgetClass, frame5, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); igate_box = XmCreateRadioBox(frame5, "Configure_defaults Igate Options box", al, ac); XtVaSetValues(igate_box, XmNnumColumns,2, NULL); igtyp0 = XtVaCreateManagedWidget(langcode("IGPUPCF001"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp0,XmNvalueChangedCallback,igate_type_toggle,"0"); igtyp1 = XtVaCreateManagedWidget(langcode("IGPUPCF002"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp1,XmNvalueChangedCallback,igate_type_toggle,"1"); igtyp2 = XtVaCreateManagedWidget(langcode("IGPUPCF003"), xmToggleButtonGadgetClass, igate_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(igtyp2,XmNvalueChangedCallback,igate_type_toggle,"2"); // Miscellaneous Options compressed_objects_items_tx = XtVaCreateManagedWidget(langcode("WPUPCFD024"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); new_bulletin_popup_enable = XtVaCreateManagedWidget(langcode("WPUPCFD027"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, compressed_objects_items_tx, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); zero_bulletin_popup_enable = XtVaCreateManagedWidget(langcode("WPUPCFD029"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); warn_about_mouse_modifiers_enable = XtVaCreateManagedWidget(langcode("WPUPCFD028"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, zero_bulletin_popup_enable, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Show all My trails in one color my_trail_diff_color_enable = XtVaCreateManagedWidget(langcode("WPUPCFD032"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, new_bulletin_popup_enable, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, warn_about_mouse_modifiers_enable, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Check box to load predefined (SAR/Event) objects menu from a file or not. xastir_snprintf(loadfrom, sizeof(loadfrom), "%s %s", langcode("WPUPCFD031"), #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir))); #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config")); #endif // OBJECT_DEF_FILE_USER_BASE load_predefined_objects_menu_from_file_enable = XtVaCreateManagedWidget(loadfrom, xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zero_bulletin_popup_enable, XmNtopOffset,5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lesstif as of 0.95 in 2008 doesn't fully support combo boxes // // Need to replace combo boxes with a pull down menu when lesstif is used. // See xpdf's XPDFViewer.cc/XPDFViewer.h for an example. cb_items[0] = XmStringCreateLocalized("predefined_SAR.sys"); cb_items[1] = XmStringCreateLocalized("predefined_EVENT.sys"); cb_items[2] = XmStringCreateLocalized("predefined_USER.sys"); #ifdef USE_COMBO_BOX // Combo box to pick file from which to load predefined objects menu load_predefined_objects_menu_from_file = XtVaCreateManagedWidget("Load objects menu filename ComboBox", xmComboBoxWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, zero_bulletin_popup_enable, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, load_predefined_objects_menu_from_file_enable, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNpositionMode, XmONE_BASED, XmNvisibleItemCount, 3, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[0],1,1); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[1],2,1); XmComboBoxAddItem(load_predefined_objects_menu_from_file,cb_items[2],3,1); lpomff_widget = load_predefined_objects_menu_from_file; #else // Menu replacement for combo box when using lesstif. // Not a full replacement, as combo box in motif can have editable values, // not just selection from predefined list as is the case here. ac = 0; XtSetArg(al[ac], XmNmarginWidth, 0); ac++; XtSetArg(al[ac], XmNmarginHeight, 0); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; lpomff_menuPane = XmCreatePulldownMenu(my_form,"lpomff_menuPane", al, ac); //lpomff_menu is zero based, constants for filenames are one based //lpomff_value is set to match constants in callback. for (i=0; i<3; i++) { ac = 0; XtSetArg(al[ac], XmNlabelString, cb_items[i]); ac++; XtSetArg(al[ac], XmNuserData, (XtPointer)i); ac++; sprintf(buf,"button%d",i); lpomff_button = XmCreatePushButton(lpomff_menuPane, buf, al, ac); XtManageChild(lpomff_button); XtAddCallback(lpomff_button, XmNactivateCallback, lpomff_menuCallback, Configure_defaults); lpomff_buttons[i] = lpomff_button; } ac = 0; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ++ac; XtSetArg(al[ac], XmNleftWidget, load_predefined_objects_menu_from_file_enable); ++ac; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ++ac; XtSetArg(al[ac], XmNtopWidget, zero_bulletin_popup_enable); ++ac; XtSetArg(al[ac], XmNmarginWidth, 0); ++ac; XtSetArg(al[ac], XmNmarginHeight, 0); ++ac; XtSetArg(al[ac], XmNtopOffset, 5); ++ac; XtSetArg(al[ac], XmNleftOffset, 10); ++ac; XtSetArg(al[ac], XmNsubMenuId, lpomff_menuPane); ++ac; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; lpomff_menu = XmCreateOptionMenu(my_form, "sddd_Menu", al, ac); XtManageChild(lpomff_menu); lpomff_value = 2; // set a default value (line on off dash) lpomff_widget = lpomff_menu; #endif // USE_COMBO_BOX // free up space from combo box strings for (i=0; i<3; i++) { XmStringFree(cb_items[i]); } #ifdef TRANSMIT_RAW_WX raw_wx_tx = XtVaCreateManagedWidget(langcode("WPUPCFD023"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, lpomff_widget, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); #endif // TRANSMIT_RAW_WX altnet_active = XtVaCreateManagedWidget(langcode("WPUPCFD025"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, compressed_objects_items_tx, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "ALTNET:" altnet_label = XtVaCreateManagedWidget(langcode("WPUPCFD033"), xmLabelWidgetClass, my_form, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, altnet_active, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, compressed_objects_items_tx, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); altnet_text = XtVaCreateManagedWidget("Configure_defaults Altnet_text", xmTextWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNwidth, ((10*7)+2), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, altnet_active, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, altnet_label, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); disable_dupe_check = XtVaCreateManagedWidget(langcode("WPUPCFD030"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame5, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, altnet_active, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, #ifdef TRANSMIT_RAW_WX XmNtopWidget, raw_wx_tx, #else // TRANSMIT_RAW_WX XmNtopWidget, lpomff_widget, #endif // TRANSMIT_RAW_WX XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, #ifdef TRANSMIT_RAW_WX XmNtopWidget, raw_wx_tx, #else // TRANSMIT_RAW_WX XmNtopWidget, lpomff_widget, #endif // TRANSMIT_RAW_WX XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_defaults_change_data, configure_defaults_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_defaults_destroy_shell, configure_defaults_dialog); switch(output_station_type) { case(0): XmToggleButtonSetState(styp1,TRUE,FALSE); Station_transmit_type=0; break; case(1): XmToggleButtonSetState(styp2,TRUE,FALSE); Station_transmit_type=1; break; case(2): XmToggleButtonSetState(styp3,TRUE,FALSE); Station_transmit_type=2; break; case(3): XmToggleButtonSetState(styp4,TRUE,FALSE); Station_transmit_type=3; break; case(4): XmToggleButtonSetState(styp5,TRUE,FALSE); Station_transmit_type=4; break; case(5): XmToggleButtonSetState(styp6,TRUE,FALSE); Station_transmit_type=5; break; default: XmToggleButtonSetState(styp1,TRUE,FALSE); Station_transmit_type=0; break; } #ifdef TRANSMIT_RAW_WX if (transmit_raw_wx) { XmToggleButtonSetState(raw_wx_tx,TRUE,FALSE); } else { XmToggleButtonSetState(raw_wx_tx,FALSE,FALSE); } #endif // TRANSMIT_RAW_WX if(transmit_compressed_objects_items) { XmToggleButtonSetState(compressed_objects_items_tx,TRUE,FALSE); } else { XmToggleButtonSetState(compressed_objects_items_tx,FALSE,FALSE); } if(pop_up_new_bulletins) { XmToggleButtonSetState(new_bulletin_popup_enable,TRUE,FALSE); } else { XmToggleButtonSetState(new_bulletin_popup_enable,FALSE,FALSE); } if(view_zero_distance_bulletins) { XmToggleButtonSetState(zero_bulletin_popup_enable,TRUE,FALSE); } else { XmToggleButtonSetState(zero_bulletin_popup_enable,FALSE,FALSE); } if(warn_about_mouse_modifiers) { XmToggleButtonSetState(warn_about_mouse_modifiers_enable,TRUE,FALSE); } else { XmToggleButtonSetState(warn_about_mouse_modifiers_enable,FALSE,FALSE); } // user interface refers to all my trails in one color // my trail diff color as 0 means my trails in one color, so select // button when my trail diff color is 0 rather than 1. if(my_trail_diff_color) { XmToggleButtonSetState(my_trail_diff_color_enable,FALSE,FALSE); } else { XmToggleButtonSetState(my_trail_diff_color_enable,TRUE,FALSE); } if(predefined_menu_from_file) { // Option to load the predefined SAR objects menu items from a file. // Display the filename if one is currently selected and option is enabled. #ifdef USE_COMBO_BOX XmString tempSelection = XmStringCreateLocalized(predefined_object_definition_filename); XmComboBoxSelectItem(load_predefined_objects_menu_from_file, tempSelection); XmStringFree(tempSelection); #else x = -1; if (strncmp(predefined_object_definition_filename,"predefined_SAR.sys",strlen(predefined_object_definition_filename)) == 0) { x = 0; } if (strncmp(predefined_object_definition_filename,"predefined_EVENT.sys",strlen(predefined_object_definition_filename)) == 0) { x = 1; } if (strncmp(predefined_object_definition_filename,"predefined_USER.sys",strlen(predefined_object_definition_filename)) == 0) { x = 2; } i = 3; // allow display of another filename from the config file. // user won't be able to edit it, but they will see it. if (x==-1) { ac = 0; cb_items[i] = XmStringCreateLocalized(predefined_object_definition_filename); XtSetArg(al[ac], XmNlabelString, cb_items[i]); ac++; XtSetArg(al[ac], XmNuserData, (XtPointer)i); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; sprintf(buf,"button%d",i); lpomff_button = XmCreatePushButton(lpomff_menuPane, buf, al, ac); XtManageChild(lpomff_button); XtAddCallback(lpomff_button, XmNactivateCallback, lpomff_menuCallback, Configure_defaults); lpomff_buttons[i] = lpomff_button; XmStringFree(cb_items[i]); x = i; } XtVaSetValues(lpomff_menu, XmNmenuHistory, lpomff_buttons[x], NULL); lpomff_value = x+1; #endif // USE_COMBO_BOX XmToggleButtonSetState(load_predefined_objects_menu_from_file_enable,TRUE,FALSE); } else { // by default combo box is created with no selection // make sure that toggle button is unchecked XmToggleButtonSetState(load_predefined_objects_menu_from_file_enable,FALSE,FALSE); } XmToggleButtonSetState(altnet_active, altnet, FALSE); XmToggleButtonSetState(disable_dupe_check, skip_dupe_checking, FALSE); // Known to have memory leaks in some Motif versions: //XmTextSetString(altnet_text, altnet_call); XmTextReplace(altnet_text, (XmTextPosition) 0, XmTextGetLastPosition(altnet_text), altnet_call); switch(operate_as_an_igate) { case(0): XmToggleButtonSetState(igtyp0,TRUE,FALSE); Igate_type=0; break; case(1): XmToggleButtonSetState(igtyp1,TRUE,FALSE); Igate_type=1; break; case(2): XmToggleButtonSetState(igtyp2,TRUE,FALSE); Igate_type=2; break; default: XmToggleButtonSetState(igtyp0,TRUE,FALSE); Igate_type=0; break; } pos_dialog(configure_defaults_dialog); delw = XmInternAtom(XtDisplay(configure_defaults_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_defaults_dialog, delw, Configure_defaults_destroy_shell, (XtPointer)configure_defaults_dialog); XtManageChild(my_form); XtManageChild(type_box); XtManageChild(igate_box); XtManageChild(pane); resize_dialog(my_form, configure_defaults_dialog); XtPopup(configure_defaults_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_defaults_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_defaults_dialog), XtWindow(configure_defaults_dialog)); } } /////////////////////////////////// Configure Timing Dialog ////////////////////////////////// void Configure_timing_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_timing_dialog = (Widget)NULL; } void Configure_timing_change_data(Widget widget, XtPointer clientData, XtPointer callData) { int value; XmScaleGetValue(ghosting_time, &value); // Minutes sec_old = (time_t)(value * 60); // Convert to seconds XmScaleGetValue(clearing_time, &value); // Hours sec_clear = (time_t)(value * 60 * 60); // Convert to seconds XmScaleGetValue(posit_interval, &value); // Minutes * 10 POSIT_rate = (long)(value * 60 / 10); // Convert to seconds XmScaleGetValue(gps_interval, &value); // Seconds gps_time = (long)value; XmScaleGetValue(dead_reckoning_time, &value);// Minutes dead_reckoning_timeout = value * 60; // Convert to seconds XmScaleGetValue(object_item_interval, &value);// Minutes OBJECT_rate = value * 60; // Convert to seconds XmScaleGetValue(removal_time, &value); // Days sec_remove = (time_t)(value * 60 * 60 * 24);// Convert to seconds // Set the new posit rate into effect immediately posit_next_time = posit_last_time + POSIT_rate; // Set the new GPS rate into effect immediately sec_next_gps = sec_now() + gps_time; // Set the serial port inter-character delay XmScaleGetValue(serial_pacing_time, &serial_char_pacing); // Milliseconds XmScaleGetValue(trail_segment_timeout, &value); // Minutes trail_segment_time = (int)value; XmScaleGetValue(trail_segment_distance_max, &value); // Degrees trail_segment_distance = (int)value; #ifdef HAVE_GPSMAN XmScaleGetValue(RINO_download_timeout, &value); // Degrees RINO_download_interval = (int)value; #endif // HAVE_GPSMAN XmScaleGetValue(net_map_slider, &net_map_timeout); XmScaleGetValue(snapshot_interval_slider, &snapshot_interval); XmScaleGetValue(aircraft_clearing_time, &value); // Minutes aircraft_sec_clear = (time_t)(value * 60); // Convert to seconds redraw_on_new_data=2; Configure_timing_destroy_shell(widget,clientData,callData); } void Configure_timing( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel; Atom delw; XmString x_str; if (!configure_timing_dialog) { configure_timing_dialog = XtVaCreatePopupShell(langcode("WPUPCFTM01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_timing pane", xmPanedWindowWidgetClass, configure_timing_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_timing my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Posit Time x_str = XmStringCreateLocalized(langcode("WPUPCFTM02")); posit_interval = XtVaCreateManagedWidget("Posit Interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes (disables the function) XmNmaximum, 60*10, // 60 minutes XmNdecimalPoints, 1, // Move decimal point over one XmNscaleMultiple, 5, // Move 30 seconds per left mouse XmNshowValue, TRUE, XmNvalue, (int)((POSIT_rate * 10) / 60), // Minutes * 10 XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for stations being considered old (symbol ghosting) x_str = XmStringCreateLocalized(langcode("WPUPCFTM03")); ghosting_time = XtVaCreateManagedWidget("Station Ghosting Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One minute XmNmaximum, 3*60, // Three hours XmNshowValue, TRUE, XmNvalue, (int)(sec_old/60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Object Item Transmit Interval x_str = XmStringCreateLocalized(langcode("WPUPCFTM04")); object_item_interval = XtVaCreateManagedWidget("Object/Item Transmit Interval (min)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, posit_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 5, // Five minutes XmNmaximum, 120, // 120 minutes XmNscaleMultiple, 5, // Move 5 minutes per left mouse XmNshowValue, TRUE, XmNvalue, (int)(OBJECT_rate / 60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for station not being displayed x_str = XmStringCreateLocalized(langcode("WPUPCFTM05")); clearing_time = XtVaCreateManagedWidget("Station Clear Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, posit_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One hour XmNmaximum, 24*7, // One week XmNshowValue, TRUE, XmNvalue, (int)(sec_clear/(60*60)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // GPS Time x_str = XmStringCreateLocalized(langcode("WPUPCFTM06")); gps_interval = XtVaCreateManagedWidget("GPS Interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_item_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One second XmNmaximum, 60, // Sixty seconds XmNshowValue, TRUE, XmNvalue, (int)gps_time, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for station being removed from database x_str = XmStringCreateLocalized(langcode("WPUPCFTM07")); removal_time = XtVaCreateManagedWidget("Station Delete Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_item_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One Day XmNmaximum, 14, // Two weeks XmNshowValue, TRUE, XmNvalue, (int)(sec_remove/(60*60*24)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Dead Reckoning Timeout x_str = XmStringCreateLocalized(langcode("WPUPCFTM08")); dead_reckoning_time = XtVaCreateManagedWidget("DR Time (min)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, gps_interval, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // One minute XmNmaximum, 60, // Sixty minutes XmNshowValue, TRUE, XmNvalue, (int)(dead_reckoning_timeout / 60), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Serial Pacing Time (delay between each serial character) x_str = XmStringCreateLocalized(langcode("WPUPCFTM09")); serial_pacing_time = XtVaCreateManagedWidget("Serial Pacing Time (ms)", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, removal_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero XmNmaximum, 50, // Fifty milliseconds XmNshowValue, TRUE, XmNvalue, (int)(serial_char_pacing), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Time below which track segment will get drawn, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM10")); trail_segment_timeout = XtVaCreateManagedWidget("Trail segment timeout", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dead_reckoning_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes XmNmaximum, 12*60, // 12 hours XmNshowValue, TRUE, XmNvalue, trail_segment_time, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval at track segment will not get drawn, in degrees x_str = XmStringCreateLocalized(langcode("WPUPCFTM11")); trail_segment_distance_max = XtVaCreateManagedWidget("Trail segment interval degrees", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dead_reckoning_time, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero degrees XmNmaximum, 45, // 90 degrees XmNshowValue, TRUE, XmNvalue, trail_segment_distance, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Time below which track segment will get drawn, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM12")); RINO_download_timeout = XtVaCreateManagedWidget("RINO download interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trail_segment_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // Zero minutes (disables the function) XmNmaximum, 30, // 30 minutes XmNshowValue, TRUE, XmNvalue, RINO_download_interval, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); #ifndef HAVE_GPSMAN XtSetSensitive(RINO_download_timeout, FALSE); #endif // HAVE_GPSMAN x_str = XmStringCreateLocalized(langcode("MPUPTGR017")); net_map_slider = XtVaCreateManagedWidget("Net Map Timeout", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, trail_segment_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 10, XmNmaximum, 300, XmNshowValue, TRUE, XmNvalue, net_map_timeout, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval at which snapshots will be taken, in minutes x_str = XmStringCreateLocalized(langcode("WPUPCFTM13")); snapshot_interval_slider = XtVaCreateManagedWidget("Snapshot interval", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, RINO_download_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, // 0.5 minutes XmNmaximum, 30, // 30 minutes XmNshowValue, TRUE, XmNvalue, snapshot_interval, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); // Interval for aircraft not being displayed x_str = XmStringCreateLocalized(langcode("WPUPCFTM14")); aircraft_clearing_time = XtVaCreateManagedWidget("Aircraft Clear Time", xmScaleWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, clearing_time, XmNtopWidget, RINO_download_timeout, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 0, // zero disables - this is the default XmNmaximum, 60*8, // 8 hours XmNshowValue, TRUE, XmNvalue, (int)(aircraft_sec_clear/(60)), XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, snapshot_interval_slider, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, snapshot_interval_slider, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_timing_change_data, configure_timing_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_timing_destroy_shell, configure_timing_dialog); pos_dialog(configure_timing_dialog); delw = XmInternAtom(XtDisplay(configure_timing_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_timing_dialog, delw, Configure_timing_destroy_shell, (XtPointer)configure_timing_dialog); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_timing_dialog); XtPopup(configure_timing_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_timing_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_timing_dialog), XtWindow(configure_timing_dialog)); } } /////////////////////////////////// Configure Coordinates Dialog ////////////////////////////////// void coordinates_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if (state->set) { coordinate_system = atoi(which); } else { coordinate_system = USE_DDMMMM; } // Update any active view lists so their coordinates get updated Station_List_fill(1,0); // Update View->Mobile Station list (has lat/lon or UTM info on it) // Force redraw redraw_on_new_data = 2; } void Configure_coordinates_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_coordinates_dialog = (Widget)NULL; } void Configure_coordinates( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, frame, coord_box, coord_0, coord_1, coord_2, coord_3, coord_4, coord_5; // static Widget label; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if (!configure_coordinates_dialog) { configure_coordinates_dialog = XtVaCreatePopupShell(langcode("WPUPCFC001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_coordinates pane", xmPanedWindowWidgetClass, configure_coordinates_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_coordinates my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Interval for station being considered old frame = XtVaCreateManagedWidget("Configure_coordinates frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_FORM, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //label XtVaCreateManagedWidget(langcode("WPUPCFC002"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; coord_box = XmCreateRadioBox(frame,"Configure_coordinates coord_box", al, ac); XtVaSetValues(coord_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNnumColumns,5, NULL); coord_0 = XtVaCreateManagedWidget(langcode("WPUPCFC003"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_0,XmNvalueChangedCallback,coordinates_toggle,"0"); coord_1 = XtVaCreateManagedWidget(langcode("WPUPCFC004"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_1,XmNvalueChangedCallback,coordinates_toggle,"1"); coord_2 = XtVaCreateManagedWidget(langcode("WPUPCFC005"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_2,XmNvalueChangedCallback,coordinates_toggle,"2"); coord_3 = XtVaCreateManagedWidget(langcode("WPUPCFC006"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_3,XmNvalueChangedCallback,coordinates_toggle,"3"); coord_4 = XtVaCreateManagedWidget(langcode("WPUPCFC008"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_4,XmNvalueChangedCallback,coordinates_toggle,"4"); coord_5 = XtVaCreateManagedWidget(langcode("WPUPCFC007"), xmToggleButtonGadgetClass, coord_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coord_5,XmNvalueChangedCallback,coordinates_toggle,"5"); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_coordinates_destroy_shell, configure_coordinates_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_coordinates_destroy_shell, configure_coordinates_dialog); // Set the toggle buttons based on current data switch (coordinate_system) { case(USE_DDDDDD): XmToggleButtonSetState(coord_0,TRUE,FALSE); break; case(USE_DDMMSS): XmToggleButtonSetState(coord_2,TRUE,FALSE); break; case(USE_UTM): XmToggleButtonSetState(coord_3,TRUE,FALSE); break; case(USE_UTM_SPECIAL): XmToggleButtonSetState(coord_4,TRUE,FALSE); break; case(USE_MGRS): XmToggleButtonSetState(coord_5,TRUE,FALSE); break; case(USE_DDMMMM): default: XmToggleButtonSetState(coord_1,TRUE,FALSE); break; } pos_dialog(configure_coordinates_dialog); delw = XmInternAtom(XtDisplay(configure_coordinates_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_coordinates_dialog, delw, Configure_coordinates_destroy_shell, (XtPointer)configure_coordinates_dialog); XtManageChild(my_form); XtManageChild(coord_box); XtManageChild(pane); resize_dialog(my_form, configure_coordinates_dialog); XtPopup(configure_coordinates_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_coordinates_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_coordinates_dialog), XtWindow(configure_coordinates_dialog)); } } ///////////////////////////////// Configure Audio Alarms Dialog //////////////////////////////// void Configure_audio_alarm_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_audio_alarm_dialog = (Widget)NULL; } void Configure_audio_alarm_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; temp_ptr = XmTextFieldGetString(audio_alarm_config_play_data); xastir_snprintf(sound_command, sizeof(sound_command), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_command); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_ons_data); xastir_snprintf(sound_new_station, sizeof(sound_new_station), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_new_station); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onm_data); xastir_snprintf(sound_new_message, sizeof(sound_new_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_new_message); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onpx_data); xastir_snprintf(sound_prox_message, sizeof(sound_prox_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_prox_message); temp_ptr = XmTextFieldGetString(prox_min_data); xastir_snprintf(prox_min, sizeof(prox_min), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(prox_min); temp_ptr = XmTextFieldGetString(prox_max_data); xastir_snprintf(prox_max, sizeof(prox_max), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(prox_max); temp_ptr = XmTextFieldGetString(audio_alarm_config_play_onbo_data); xastir_snprintf(sound_band_open_message, sizeof(sound_band_open_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_band_open_message); temp_ptr = XmTextFieldGetString(bando_min_data); xastir_snprintf(bando_min, sizeof(bando_min), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(bando_min); temp_ptr = XmTextFieldGetString(bando_max_data); xastir_snprintf(bando_max, sizeof(bando_max), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(bando_max); temp_ptr = XmTextFieldGetString(audio_alarm_config_wx_alert_data); xastir_snprintf(sound_wx_alert_message, sizeof(sound_wx_alert_message), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(sound_wx_alert_message); if(XmToggleButtonGetState(audio_alarm_config_play_on_new_station)) { sound_play_new_station=1; } else { sound_play_new_station=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_new_message)) { sound_play_new_message=1; } else { sound_play_new_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_prox)) { sound_play_prox_message=1; } else { sound_play_prox_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_bando)) { sound_play_band_open_message=1; } else { sound_play_band_open_message=0; } if(XmToggleButtonGetState(audio_alarm_config_play_on_wx_alert)) { sound_play_wx_alert_message=1; } else { sound_play_wx_alert_message=0; } Configure_audio_alarm_destroy_shell(widget,clientData,callData); } void Configure_audio_alarms( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, audio_play, file1, file2, min1, max1, minb1, maxb2, sep; // static Widget min2, max2, minb2, maxb1; Atom delw; if (!configure_audio_alarm_dialog) { configure_audio_alarm_dialog = XtVaCreatePopupShell(langcode("WPUPCFA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_audio_alarms pane", xmPanedWindowWidgetClass, configure_audio_alarm_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_audio_alarms my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); audio_play = XtVaCreateManagedWidget(langcode("WPUPCFA002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); file1 = XtVaCreateManagedWidget(langcode("WPUPCFA003"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_play, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); file2 = XtVaCreateManagedWidget(langcode("WPUPCFA004"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_play, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_new_station = XtVaCreateManagedWidget(langcode("WPUPCFA005"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, file1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_ons_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command NS", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, file2, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftWidget, audio_alarm_config_play_on_new_station, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_new_message = XtVaCreateManagedWidget(langcode("WPUPCFA006"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_station, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onm_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command NM", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_station, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_prox = XtVaCreateManagedWidget(langcode("WPUPCFA007"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_message, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onpx_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command PROX", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_new_message, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); min1 = XtVaCreateManagedWidget(langcode("WPUPCFA009"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_prox, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); prox_min_data = XtVaCreateManagedWidget("Configure_audio_alarms prox min", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_onpx_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //min2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_prox, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); max1 = XtVaCreateManagedWidget(langcode("WPUPCFA010"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, min1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); prox_max_data = XtVaCreateManagedWidget("Configure_audio_alarms prox max", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, prox_min_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //max2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, min1, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_bando = XtVaCreateManagedWidget(langcode("WPUPCFA008"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, max1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_onbo_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command BAND", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, prox_max_data, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); minb1 = XtVaCreateManagedWidget(langcode("WPUPCFA009"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_bando, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); bando_min_data = XtVaCreateManagedWidget("Configure_audio_alarms bando min", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_onbo_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); //minb2 XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_bando, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //maxb1 XtVaCreateManagedWidget(langcode("WPUPCFA010"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, minb1, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); bando_max_data = XtVaCreateManagedWidget("Configure_audio_alarms bando max", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bando_min_data, XmNtopOffset, 2, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment,XmATTACH_POSITION, XmNrightPosition, 2, XmNfontList, fontlist1, NULL); maxb2 = XtVaCreateManagedWidget(english_units?langcode("UNIOP00004"):langcode("UNIOP00005"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, minb1, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_play_on_wx_alert = XtVaCreateManagedWidget(langcode("WPUPCFA011"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, maxb2, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); audio_alarm_config_wx_alert_data = XtVaCreateManagedWidget("Configure_audio_alarms Play Command WxAlert", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 25, XmNwidth, ((25*7)+2), XmNmaxLength, 80, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bando_max_data, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Configure_audio_alarms sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, audio_alarm_config_play_on_wx_alert, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_audio_alarm_change_data, configure_audio_alarm_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_audio_alarm_destroy_shell, configure_audio_alarm_dialog); pos_dialog(configure_audio_alarm_dialog); delw = XmInternAtom(XtDisplay(configure_audio_alarm_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_audio_alarm_dialog, delw, Configure_audio_alarm_destroy_shell, (XtPointer)configure_audio_alarm_dialog); XmTextFieldSetString(audio_alarm_config_play_data,sound_command); XmTextFieldSetString(audio_alarm_config_play_ons_data,sound_new_station); XmTextFieldSetString(audio_alarm_config_play_onm_data,sound_new_message); XmTextFieldSetString(audio_alarm_config_play_onpx_data,sound_prox_message); XmTextFieldSetString(prox_min_data,prox_min); XmTextFieldSetString(prox_max_data,prox_max); XmTextFieldSetString(audio_alarm_config_play_onbo_data,sound_band_open_message); XmTextFieldSetString(bando_min_data,bando_min); XmTextFieldSetString(bando_max_data,bando_max); XmTextFieldSetString(audio_alarm_config_wx_alert_data, sound_wx_alert_message); if(sound_play_new_station) { XmToggleButtonSetState(audio_alarm_config_play_on_new_station,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_new_station,FALSE,FALSE); } if(sound_play_new_message) { XmToggleButtonSetState(audio_alarm_config_play_on_new_message,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_new_message,FALSE,FALSE); } if(sound_play_prox_message) { XmToggleButtonSetState(audio_alarm_config_play_on_prox,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_prox,FALSE,FALSE); } if(sound_play_band_open_message) { XmToggleButtonSetState(audio_alarm_config_play_on_bando,TRUE,FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_bando,FALSE,FALSE); } if (sound_play_wx_alert_message) { XmToggleButtonSetState(audio_alarm_config_play_on_wx_alert, TRUE, FALSE); } else { XmToggleButtonSetState(audio_alarm_config_play_on_wx_alert, FALSE, FALSE); } XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_audio_alarm_dialog); XtPopup(configure_audio_alarm_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_audio_alarm_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_audio_alarm_dialog), XtWindow(configure_audio_alarm_dialog)); } } ///////////////////////////////////// Configure Speech Dialog ////////////////////////////////// void Configure_speech_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); XtDestroyWidget(shell); configure_speech_dialog = (Widget)NULL; } void Test_speech(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { SayText(SPEECH_TEST_STRING); } void Configure_speech_change_data(Widget widget, XtPointer clientData, XtPointer callData) { if(XmToggleButtonGetState(speech_config_play_on_new_station)) { festival_speak_new_station=1; } else { festival_speak_new_station=0; } if(XmToggleButtonGetState(speech_config_play_on_new_message_alert)) { festival_speak_new_message_alert=1; } else { festival_speak_new_message_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_new_message_body)) { festival_speak_new_message_body=1; } else { festival_speak_new_message_body=0; } if(XmToggleButtonGetState(speech_config_play_on_prox)) { festival_speak_proximity_alert=1; } else { festival_speak_proximity_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_trak)) { festival_speak_tracked_proximity_alert=1; } else { festival_speak_tracked_proximity_alert=0; } if(XmToggleButtonGetState(speech_config_play_on_bando)) { festival_speak_band_opening=1; } else { festival_speak_band_opening=0; } if(XmToggleButtonGetState(speech_config_play_on_new_wx_alert)) { festival_speak_new_weather_alert=1; } else { festival_speak_new_weather_alert=0; } Configure_speech_destroy_shell(widget,clientData,callData); } //Make it helpful - Gray the config selections, but add a choice //that basically pops up a box that says where to get Festival, have //it be ungrayed if Festival isn't installed. void Configure_speech( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, file1, sep, button_test; Atom delw; if (!configure_speech_dialog) { configure_speech_dialog = XtVaCreatePopupShell(langcode("WPUPCFSP01"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_speech pane", xmPanedWindowWidgetClass, configure_speech_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Configure_speech my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); file1 = XtVaCreateManagedWidget(langcode("WPUPCFSP02"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_station = XtVaCreateManagedWidget(langcode("WPUPCFSP03"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, file1, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_message_alert = XtVaCreateManagedWidget(langcode("WPUPCFSP04"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_station, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_message_body = XtVaCreateManagedWidget(langcode("WPUPCFSP05"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_message_alert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_prox = XtVaCreateManagedWidget(langcode("WPUPCFSP06"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_message_body, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_trak = XtVaCreateManagedWidget(langcode("WPUPCFSP09"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_prox, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_bando = XtVaCreateManagedWidget(langcode("WPUPCFSP07"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_trak, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); speech_config_play_on_new_wx_alert = XtVaCreateManagedWidget(langcode("WPUPCFSP08"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_bando, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, #ifndef HAVE_FESTIVAL XmNsensitive, FALSE, #endif /* HAVE_FESTIVAL */ MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Configure_speech sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, speech_config_play_on_new_wx_alert, XmNtopOffset, 20, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_test = XtVaCreateManagedWidget(langcode("PULDNFI003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_test, XmNactivateCallback, Test_speech, configure_speech_dialog); XtAddCallback(button_ok, XmNactivateCallback, Configure_speech_change_data, configure_speech_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_speech_destroy_shell, configure_speech_dialog); pos_dialog(configure_speech_dialog); delw = XmInternAtom(XtDisplay(configure_speech_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_speech_dialog, delw, Configure_speech_destroy_shell, (XtPointer)configure_speech_dialog); if(festival_speak_new_station) { XmToggleButtonSetState(speech_config_play_on_new_station,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_station,FALSE,FALSE); } if(festival_speak_new_message_alert) { XmToggleButtonSetState(speech_config_play_on_new_message_alert,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_message_alert,FALSE,FALSE); } if(festival_speak_new_message_body) { XmToggleButtonSetState(speech_config_play_on_new_message_body,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_message_body,FALSE,FALSE); } if(festival_speak_proximity_alert) { XmToggleButtonSetState(speech_config_play_on_prox,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_prox,FALSE,FALSE); } if(festival_speak_tracked_proximity_alert) { XmToggleButtonSetState(speech_config_play_on_trak,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_trak,FALSE,FALSE); } if(festival_speak_band_opening) { XmToggleButtonSetState(speech_config_play_on_bando,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_bando,FALSE,FALSE); } if(festival_speak_new_weather_alert) { XmToggleButtonSetState(speech_config_play_on_new_wx_alert,TRUE,FALSE); } else { XmToggleButtonSetState(speech_config_play_on_new_wx_alert,FALSE,FALSE); } XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, configure_speech_dialog); XtPopup(configure_speech_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_speech_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_speech_dialog), XtWindow(configure_speech_dialog)); } } /* * Track_Me * */ void Track_Me( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", my_callsign); track_me = atoi(which); track_station_on = atoi(which); display_zoom_status(); } else { track_me = 0; track_station_on = 0; display_zoom_status(); } } // Pointer to the Move/Measure cursor object static Cursor cs_move_measure = (Cursor)NULL; /* * Move_Object * */ void Move_Object( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { moving_object = atoi(which); XmToggleButtonSetState(measure_button, FALSE, FALSE); measuring_distance = 0; // Change the cursor if(!cs_move_measure) { cs_move_measure=XCreateFontCursor(XtDisplay(da),XC_crosshair); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_move_measure); (void)XFlush(XtDisplay(da)); } else { moving_object = 0; // Remove the special "crosshair" cursor (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); } } /* * Measure_Distance * */ void Measure_Distance( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { measuring_distance = atoi(which); XmToggleButtonSetState(move_button, FALSE, FALSE); moving_object = 0; // Change the cursor if(!cs_move_measure) { cs_move_measure=XCreateFontCursor(XtDisplay(da),XC_crosshair); } (void)XDefineCursor(XtDisplay(da),XtWindow(da),cs_move_measure); (void)XFlush(XtDisplay(da)); } else { measuring_distance = 0; // Remove the special "crosshair" cursor (void)XUndefineCursor(XtDisplay(da),XtWindow(da)); (void)XFlush(XtDisplay(da)); } } ///////////////////////////////////////////////////////////////////////// /* * Destroy Configure Station Dialog Popup Window */ void Configure_station_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),CS_icon0); // ???? DK7IN: avoid possible memory leak ? (void)XFreePixmap(XtDisplay(appshell),CS_icon); XtDestroyWidget(shell); configure_station_dialog = (Widget)NULL; // Take down the symbol selection dialog as well (if it's up) if (select_symbol_dialog) { Select_symbol_destroy_shell( widget, select_symbol_dialog, callData); } // NULL out the dialog field in the global struct used for // Coordinate Calculator. Prevents segfaults if the calculator is // still up and trying to write to us. coordinate_calc_array.calling_dialog = NULL; } void Configure_station_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Configure_station_pos_amb = atoi(which); } else { Configure_station_pos_amb = 0; } } /* * Process changes to station data */ void Configure_station_change_data(Widget widget, XtPointer clientData, XtPointer callData) { char temp[40]; char old_callsign[MAX_CALLSIGN+1]; int ok = 1; int temp2; int temp3; char *temp_ptr; char *temp_ptr2; transmit_compressed_posit = (int)XmToggleButtonGetState(compressed_posit_tx); xastir_snprintf(old_callsign, sizeof(old_callsign), "%s", my_callsign); /*fprintf(stderr,"Changing Configure station data\n");*/ temp_ptr = XmTextFieldGetString(station_config_call_data); xastir_snprintf(my_callsign, sizeof(my_callsign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(my_callsign); (void)to_upper(my_callsign); (void)remove_trailing_dash_zero(my_callsign); // Enter NOCALL if there's nothing left. if (my_callsign[0] == '\0') xastir_snprintf(my_callsign, sizeof(my_callsign), "NOCALL"); temp_ptr = XmTextFieldGetString(station_config_slat_data_ns); if((char)toupper((int)temp_ptr[0])=='S') { temp[0]='S'; } else { temp[0]='N'; } XtFree(temp_ptr); // Check latitude for out-of-bounds temp_ptr = XmTextFieldGetString(station_config_slat_data_deg); temp2 = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp2 > 90) || (temp2 < 0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slat_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { ok = 0; } if ( (temp2 == 90) && (temp3 != 0.0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slat_data_deg); temp_ptr2 = XmTextFieldGetString(station_config_slat_data_min); xastir_snprintf(my_lat, sizeof(my_lat), "%02d%06.3f%c", atoi(temp_ptr), atof(temp_ptr2),temp[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(station_config_slong_data_ew); if((char)toupper((int)temp_ptr[0])=='E') { temp[0]='E'; } else { temp[0]='W'; } XtFree(temp_ptr); // Check longitude for out-of-bounds temp_ptr = XmTextFieldGetString(station_config_slong_data_deg); temp2 = atoi(temp_ptr); XtFree(temp_ptr); if ( (temp2 > 180) || (temp2 < 0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slong_data_min); temp3 = atof(temp_ptr); XtFree(temp_ptr); if ( (temp3 >= 60.0) || (temp3 < 0.0) ) { ok = 0; } if ( (temp2 == 180) && (temp3 != 0.0) ) { ok = 0; } temp_ptr = XmTextFieldGetString(station_config_slong_data_deg); temp_ptr2 = XmTextFieldGetString(station_config_slong_data_min); xastir_snprintf(my_long, sizeof(my_long), "%03d%06.3f%c", atoi(temp_ptr), atof(temp_ptr2),temp[0]); XtFree(temp_ptr); XtFree(temp_ptr2); temp_ptr = XmTextFieldGetString(station_config_group_data); my_group=temp_ptr[0]; if(isalpha((int)my_group)) { my_group = toupper((int)temp_ptr[0]); } XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(station_config_symbol_data); my_symbol = temp_ptr[0]; XtFree(temp_ptr); if(isdigit((int)my_phg[3]) && isdigit((int)my_phg[4]) && isdigit((int)my_phg[5]) && isdigit((int)my_phg[6])) { my_phg[0] = 'P'; my_phg[1] = 'H'; my_phg[2] = 'G'; my_phg[7] = '\0'; } else { my_phg[0]='\0'; } /* set station ambiguity*/ position_amb_chars = Configure_station_pos_amb; if (transmit_compressed_posit) { position_amb_chars = 0; } temp_ptr = XmTextFieldGetString(station_config_comment_data); xastir_snprintf(my_comment, sizeof(my_comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(my_comment); /* TO DO: KILL only my station data? */ if (ok) // If entered data was valid { // Check whether we changed our callsign if (strcasecmp(old_callsign,my_callsign) != 0) { station_del(old_callsign); // move to new sort location... // If TrackMe is enabled, copy the new callsign into the // track_station_call variable. If we don't do this, we // will still be tracking our old callsign. if (track_me) { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", my_callsign); } } // Update our parameters my_station_add(my_callsign,my_group,my_symbol,my_long,my_lat,my_phg,my_comment,(char)position_amb_chars); redraw_on_new_data=2; Configure_station_destroy_shell(widget,clientData,callData); } // Check for proper weather symbols if a weather station (void)check_weather_symbol(); // Check for use of NWS symbols (void)check_nws_weather_symbol(); } /* * Update symbol picture for changed symbol or table */ void updateSymbolPictureCallback( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char table, overlay; char symb, group; char *temp_ptr; XtVaSetValues(station_config_icon, XmNlabelPixmap, CS_icon0, NULL); // clear old icon XtManageChild(station_config_icon); temp_ptr = XmTextFieldGetString(station_config_group_data); group = temp_ptr[0]; XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(station_config_symbol_data); symb = temp_ptr[0]; XtFree(temp_ptr); if (group == '/' || group == '\\') { table = group; overlay = ' '; } else { table = '\\'; overlay = group; } symbol(station_config_icon,0,table,symb,overlay,CS_icon,0,0,0,' '); // create icon XtVaSetValues(station_config_icon,XmNlabelPixmap,CS_icon,NULL); // draw new icon XtManageChild(station_config_icon); } /* Power radio buttons */ void Power_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[3] = which[0]; // Set to power desired if (which[0] == 'x') // Disable PHG field if 'x' found { my_phg[0] = '\0'; } } else { my_phg[3] = '3'; // 10 Watts (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Height radio buttons */ void Height_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[4] = which[0]; // Set to height desired } else { my_phg[4] = '1'; // 20 Feet above average terrain (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Gain radio buttons */ void Gain_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[5] = which[0]; // Set to gain desired } else { my_phg[5] = '3'; // 3dB gain antenna (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } /* Directivity radio buttons */ void Directivity_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { my_phg[6] = which[0]; // Set to directivity desired } else { my_phg[6] = '0'; // Omni-directional antenna (default in spec if none specified) } my_phg[8] = '\0'; //fprintf(stderr,"PHG: %s\n",my_phg); } void Posit_compressed_toggle( Widget UNUSED(w), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { transmit_compressed_posit = atoi(which); } else { transmit_compressed_posit = 0; } if(transmit_compressed_posit) { // Compressed posits don't allow position ambiguity position_amb_chars = 0; XtSetSensitive(posamb0,FALSE); XtSetSensitive(posamb1,FALSE); XtSetSensitive(posamb2,FALSE); XtSetSensitive(posamb3,FALSE); XtSetSensitive(posamb4,FALSE); } else // Position ambiguity ok for this mode { XtSetSensitive(posamb0,TRUE); XtSetSensitive(posamb1,TRUE); XtSetSensitive(posamb2,TRUE); XtSetSensitive(posamb3,TRUE); XtSetSensitive(posamb4,TRUE); } } /* * Select a symbol graphically */ void Configure_change_symbol(Widget widget, XtPointer clientData, XtPointer callData) { //fprintf(stderr,"Trying to change a symbol\n"); symbol_change_requested_from = 1; // Tell Select_symbol who to return the data to Select_symbol(widget, clientData, callData); } /* * Setup Configure Station dialog */ void Configure_station( Widget UNUSED(ww), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, cs_form, cs_form1, button_ok, button_cancel, call, frame, frame2, framephg, formphg, power_box,poption0,poption1,poption2,poption3,poption4,poption5,poption6,poption7,poption8,poption9,poption10, height_box,hoption1,hoption2,hoption3,hoption4,hoption5,hoption6,hoption7,hoption8,hoption9,hoption10, gain_box,goption1,goption2,goption3,goption4,goption5,goption6,goption7,goption8,goption9,goption10, directivity_box,doption1,doption2,doption3,doption4,doption5,doption6,doption7,doption8,doption9, slat, slat_deg, slat_min, slong_deg, slong_min, slong_ew, group, st_symbol, comment, option_box, sep, configure_button_symbol, compute_button; // static Widget pg2, slat_ns, slong, sts, posamb; char temp_data[40]; Atom delw; Arg al[50]; /* Arg List */ register unsigned int ac = 0; /* Arg Count */ if(!configure_station_dialog) { configure_station_dialog = XtVaCreatePopupShell(langcode("WPUPCFS001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Configure_station pane", xmPanedWindowWidgetClass, configure_station_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); cs_form = XtVaCreateWidget("Configure_station cs_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPCFS002"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_call_data = XtVaCreateManagedWidget("Configure_station call_data", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNwidth, ((10*7)+2), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); compressed_posit_tx = XtVaCreateManagedWidget(langcode("WPUPCFS029"), xmToggleButtonWidgetClass, cs_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(compressed_posit_tx,XmNvalueChangedCallback,Posit_compressed_toggle,"1"); slat = XtVaCreateManagedWidget(langcode("WPUPCFS003"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_deg = XtVaCreateManagedWidget("Configure_station lat_deg", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 2, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slat_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_min = XtVaCreateManagedWidget("Configure_station lat_min", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slat_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slat_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slat_data_ns = XtVaCreateManagedWidget("Configure_station lat_ns", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 20, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slat_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //slat_n XtVaCreateManagedWidget(langcode("WPUPCFS006"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 25, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slat_data_ns, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); //slong XtVaCreateManagedWidget(langcode("WPUPCFS007"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_deg = XtVaCreateManagedWidget("Configure_station long_deg", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_min = XtVaCreateManagedWidget("Configure_station long_min", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_slong_data_ew = XtVaCreateManagedWidget("Configure_station long_ew", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 14, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); slong_ew = XtVaCreateManagedWidget(langcode("WPUPCFS008"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_slong_data_ew, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); compute_button = XtVaCreateManagedWidget(langcode("COORD002"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, slong_ew, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Fill in the pointers to our input textfields so that the // coordinate calculator can fiddle with them. coordinate_calc_array.calling_dialog = configure_station_dialog; coordinate_calc_array.input_lat_deg = station_config_slat_data_deg; coordinate_calc_array.input_lat_min = station_config_slat_data_min; coordinate_calc_array.input_lat_dir = station_config_slat_data_ns; coordinate_calc_array.input_lon_deg = station_config_slong_data_deg; coordinate_calc_array.input_lon_min = station_config_slong_data_min; coordinate_calc_array.input_lon_dir = station_config_slong_data_ew; // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, configure_station_dialog); // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, "Configure_station"); XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, langcode("WPUPCFS001")); //----- Frame for table / symbol frame = XtVaCreateManagedWidget("Configure_station frame", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, slong_ew, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Station Symbol" //sts XtVaCreateManagedWidget(langcode("WPUPCFS009"), xmLabelWidgetClass, frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); cs_form1 = XtVaCreateWidget("Configure_station cs_form1", xmFormWidgetClass, frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Group/overlay" group = XtVaCreateManagedWidget(langcode("WPUPCFS010"), xmLabelWidgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 100, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // table station_config_group_data = XtVaCreateManagedWidget("Configure_station group", xmTextFieldWidgetClass, cs_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, group, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Symbol" st_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS011"), xmLabelWidgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_group_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // symbol station_config_symbol_data = XtVaCreateManagedWidget("Configure_station symbol", xmTextFieldWidgetClass, cs_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, st_symbol, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // icon CS_icon0 = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); CS_icon = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); station_config_icon = XtVaCreateManagedWidget("Configure_station icon", xmLabelWidgetClass, cs_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, CS_icon, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_symbol_data, XmNleftOffset, 15, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); configure_button_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS028"), xmPushButtonGadgetClass, cs_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 6, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, station_config_icon, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(configure_button_symbol, XmNactivateCallback, Configure_change_symbol, configure_station_dialog); //----- Frame for Power-Gain framephg = XtVaCreateManagedWidget("Configure_station framephg", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //pg2 XtVaCreateManagedWidget(langcode("WPUPCFS012"), xmLabelWidgetClass, framephg, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formphg = XtVaCreateWidget("Configure_station power_form", xmFormWidgetClass, framephg, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Power ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; power_box = XmCreateRadioBox(formphg, "Configure_station Power Radio Box", al, ac); XtVaSetValues(power_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,11, NULL); poption0 = XtVaCreateManagedWidget(langcode("WPUPCFS013"), xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption0,XmNvalueChangedCallback,Power_toggle,"x"); // 0 Watts poption1 = XtVaCreateManagedWidget("0W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption1,XmNvalueChangedCallback,Power_toggle,"0"); // 1 Watt poption2 = XtVaCreateManagedWidget("1W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption2,XmNvalueChangedCallback,Power_toggle,"1"); // 4 Watts poption3 = XtVaCreateManagedWidget("4W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption3,XmNvalueChangedCallback,Power_toggle,"2"); // 9 Watts poption4 = XtVaCreateManagedWidget("9W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption4,XmNvalueChangedCallback,Power_toggle,"3"); // 16 Watts poption5 = XtVaCreateManagedWidget("16W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption5,XmNvalueChangedCallback,Power_toggle,"4"); // 25 Watts poption6 = XtVaCreateManagedWidget("25W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption6,XmNvalueChangedCallback,Power_toggle,"5"); // 36 Watts poption7 = XtVaCreateManagedWidget("36W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption7,XmNvalueChangedCallback,Power_toggle,"6"); // 49 Watts poption8 = XtVaCreateManagedWidget("49W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption8,XmNvalueChangedCallback,Power_toggle,"7"); // 64 Watts poption9 = XtVaCreateManagedWidget("64W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption9,XmNvalueChangedCallback,Power_toggle,"8"); // 81 Watts poption10 = XtVaCreateManagedWidget("81W", xmToggleButtonGadgetClass, power_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(poption10,XmNvalueChangedCallback,Power_toggle,"9"); // Height height_box = XmCreateRadioBox(formphg, "Configure_station Height Radio Box", al, ac); XtVaSetValues(height_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,power_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 10 Feet hoption1 = XtVaCreateManagedWidget( (english_units) ? "10ft" : "3m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption1,XmNvalueChangedCallback,Height_toggle,"0"); // 20 Feet hoption2 = XtVaCreateManagedWidget( (english_units) ? "20ft" : "6m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption2,XmNvalueChangedCallback,Height_toggle,"1"); // 40 Feet hoption3 = XtVaCreateManagedWidget( (english_units) ? "40ft" : "12m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption3,XmNvalueChangedCallback,Height_toggle,"2"); // 80 Feet hoption4 = XtVaCreateManagedWidget( (english_units) ? "80ft" : "24m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption4,XmNvalueChangedCallback,Height_toggle,"3"); // 160 Feet hoption5 = XtVaCreateManagedWidget( (english_units) ? "160ft" : "49m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption5,XmNvalueChangedCallback,Height_toggle,"4"); // 320 Feet hoption6 = XtVaCreateManagedWidget( (english_units) ? "320ft" : "98m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption6,XmNvalueChangedCallback,Height_toggle,"5"); // 640 Feet hoption7 = XtVaCreateManagedWidget( (english_units) ? "640ft" : "195m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption7,XmNvalueChangedCallback,Height_toggle,"6"); // 1280 Feet hoption8 = XtVaCreateManagedWidget( (english_units) ? "1280ft" : "390m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption8,XmNvalueChangedCallback,Height_toggle,"7"); // 2560 Feet hoption9 = XtVaCreateManagedWidget( (english_units) ? "2560ft" : "780m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption9,XmNvalueChangedCallback,Height_toggle,"8"); // 5120 Feet hoption10 = XtVaCreateManagedWidget( (english_units) ? "5120ft" : "1561m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption10,XmNvalueChangedCallback,Height_toggle,"9"); // Gain gain_box = XmCreateRadioBox(formphg, "Configure_station Gain Radio Box", al, ac); XtVaSetValues(gain_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,height_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 0 dB goption1 = XtVaCreateManagedWidget("0dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption1,XmNvalueChangedCallback,Gain_toggle,"0"); // 1 dB goption2 = XtVaCreateManagedWidget("1dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption2,XmNvalueChangedCallback,Gain_toggle,"1"); // 2 dB goption3 = XtVaCreateManagedWidget("2dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption3,XmNvalueChangedCallback,Gain_toggle,"2"); // 3 dB goption4 = XtVaCreateManagedWidget("3dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption4,XmNvalueChangedCallback,Gain_toggle,"3"); // 4 dB goption5 = XtVaCreateManagedWidget("4dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption5,XmNvalueChangedCallback,Gain_toggle,"4"); // 5 dB goption6 = XtVaCreateManagedWidget("5dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption6,XmNvalueChangedCallback,Gain_toggle,"5"); // 6 dB goption7 = XtVaCreateManagedWidget("6dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption7,XmNvalueChangedCallback,Gain_toggle,"6"); // 7 dB goption8 = XtVaCreateManagedWidget("7dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption8,XmNvalueChangedCallback,Gain_toggle,"7"); // 8 dB goption9 = XtVaCreateManagedWidget("8dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption9,XmNvalueChangedCallback,Gain_toggle,"8"); // 9 dB goption10 = XtVaCreateManagedWidget("9dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption10,XmNvalueChangedCallback,Gain_toggle,"9"); // Gain directivity_box = XmCreateRadioBox(formphg, "Configure_station Directivity Radio Box", al, ac); XtVaSetValues(directivity_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,gain_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // Omni-directional doption1 = XtVaCreateManagedWidget(langcode("WPUPCFS016"), // Omni xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption1,XmNvalueChangedCallback,Directivity_toggle,"0"); // 45 NE doption2 = XtVaCreateManagedWidget("45\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption2,XmNvalueChangedCallback,Directivity_toggle,"1"); // 90 E doption3 = XtVaCreateManagedWidget("90\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption3,XmNvalueChangedCallback,Directivity_toggle,"2"); // 135 SE doption4 = XtVaCreateManagedWidget("135\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption4,XmNvalueChangedCallback,Directivity_toggle,"3"); // 180 S doption5 = XtVaCreateManagedWidget("180\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption5,XmNvalueChangedCallback,Directivity_toggle,"4"); // 225 SW doption6 = XtVaCreateManagedWidget("225\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption6,XmNvalueChangedCallback,Directivity_toggle,"5"); // 270 W doption7 = XtVaCreateManagedWidget("270\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption7,XmNvalueChangedCallback,Directivity_toggle,"6"); // 315 NW doption8 = XtVaCreateManagedWidget("315\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption8,XmNvalueChangedCallback,Directivity_toggle,"7"); // 360 N doption9 = XtVaCreateManagedWidget("360\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption9,XmNvalueChangedCallback,Directivity_toggle,"8"); //----------------------- comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"), xmLabelWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framephg, XmNtopOffset, 15, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); station_config_comment_data = XtVaCreateManagedWidget("Configure_station comment", xmTextFieldWidgetClass, cs_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 60, XmNwidth, ((60*7)+2), XmNmaxLength, MAX_COMMENT, XmNtopOffset, 11, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, comment, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framephg, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //Position Ambiguity Frame frame2 = XtVaCreateManagedWidget("Configure_station frame2", xmFrameWidgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, comment, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); //posamb XtVaCreateManagedWidget(langcode("WPUPCFS018"), xmLabelWidgetClass, frame2, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); /*set args for color */ ac=0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; option_box = XmCreateRadioBox(frame2, "Configure_station Option box", al, ac); XtVaSetValues(option_box, XmNnumColumns,5, NULL); posamb0 = XtVaCreateManagedWidget(langcode("WPUPCFS019"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb0,XmNvalueChangedCallback,Configure_station_toggle,"0"); posamb1 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS020"):langcode("WPUPCFS024"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb1,XmNvalueChangedCallback,Configure_station_toggle,"1"); posamb2 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS021"):langcode("WPUPCFS025"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb2,XmNvalueChangedCallback,Configure_station_toggle,"2"); posamb3 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS022"):langcode("WPUPCFS026"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb3,XmNvalueChangedCallback,Configure_station_toggle,"3"); posamb4 = XtVaCreateManagedWidget(english_units?langcode("WPUPCFS023"):langcode("WPUPCFS027"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(posamb4,XmNvalueChangedCallback,Configure_station_toggle,"4"); sep = XtVaCreateManagedWidget("Configure_station sep", xmSeparatorGadgetClass, cs_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame2, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, cs_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Configure_station_change_data, configure_station_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Configure_station_destroy_shell, configure_station_dialog); // fill in current data XmTextFieldSetString(station_config_call_data,my_callsign); substr(temp_data,my_lat,2); XmTextFieldSetString(station_config_slat_data_deg,temp_data); substr(temp_data,my_lat+2,6); XmTextFieldSetString(station_config_slat_data_min,temp_data); substr(temp_data,my_lat+8,1); XmTextFieldSetString(station_config_slat_data_ns,temp_data); substr(temp_data,my_long,3); XmTextFieldSetString(station_config_slong_data_deg,temp_data); substr(temp_data,my_long+3,6); XmTextFieldSetString(station_config_slong_data_min,temp_data); substr(temp_data,my_long+9,1); XmTextFieldSetString(station_config_slong_data_ew,temp_data); temp_data[0] = my_group; temp_data[1] = '\0'; XmTextFieldSetString(station_config_group_data,temp_data); XtAddCallback(station_config_group_data, XmNvalueChangedCallback, updateSymbolPictureCallback, configure_station_dialog); temp_data[0] = my_symbol; temp_data[1] = '\0'; XmTextFieldSetString(station_config_symbol_data,temp_data); XtAddCallback(station_config_symbol_data, XmNvalueChangedCallback, updateSymbolPictureCallback, configure_station_dialog); // update symbol picture (void)updateSymbolPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); if (my_phg[0]=='P') { switch (my_phg[3]) { case '0': XmToggleButtonGadgetSetState(poption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(poption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(poption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(poption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(poption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(poption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(poption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(poption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(poption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(poption10, TRUE, TRUE); break; case 'x': default: XmToggleButtonGadgetSetState(poption0, TRUE, TRUE); break; } switch (my_phg[4]) { case '0': XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(hoption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(hoption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(hoption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(hoption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(hoption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(hoption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(hoption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(hoption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(hoption10, TRUE, TRUE); break; default: break; } switch (my_phg[5]) { case '0': XmToggleButtonGadgetSetState(goption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(goption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(goption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(goption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(goption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(goption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(goption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(goption9, TRUE, TRUE); break; case '9': XmToggleButtonGadgetSetState(goption10, TRUE, TRUE); break; default: break; } switch (my_phg[6]) { case '0': XmToggleButtonGadgetSetState(doption1, TRUE, TRUE); break; case '1': XmToggleButtonGadgetSetState(doption2, TRUE, TRUE); break; case '2': XmToggleButtonGadgetSetState(doption3, TRUE, TRUE); break; case '3': XmToggleButtonGadgetSetState(doption4, TRUE, TRUE); break; case '4': XmToggleButtonGadgetSetState(doption5, TRUE, TRUE); break; case '5': XmToggleButtonGadgetSetState(doption6, TRUE, TRUE); break; case '6': XmToggleButtonGadgetSetState(doption7, TRUE, TRUE); break; case '7': XmToggleButtonGadgetSetState(doption8, TRUE, TRUE); break; case '8': XmToggleButtonGadgetSetState(doption9, TRUE, TRUE); break; default: break; } } else // PHG field disabled { XmToggleButtonGadgetSetState(poption0, TRUE, TRUE); } XmTextFieldSetString(station_config_comment_data,my_comment); if(transmit_compressed_posit) { // Compressed posits don't allow position ambiguity XmToggleButtonSetState(compressed_posit_tx,TRUE,FALSE); position_amb_chars = 0; XtSetSensitive(posamb0,FALSE); XtSetSensitive(posamb1,FALSE); XtSetSensitive(posamb2,FALSE); XtSetSensitive(posamb3,FALSE); XtSetSensitive(posamb4,FALSE); } else // Position ambiguity ok for this mode { XmToggleButtonSetState(compressed_posit_tx,FALSE,FALSE); XtSetSensitive(posamb0,TRUE); XtSetSensitive(posamb1,TRUE); XtSetSensitive(posamb2,TRUE); XtSetSensitive(posamb3,TRUE); XtSetSensitive(posamb4,TRUE); } Configure_station_pos_amb = position_amb_chars; switch (Configure_station_pos_amb) { case(0): XmToggleButtonSetState(posamb0,TRUE,FALSE); break; case(1): XmToggleButtonSetState(posamb1,TRUE,FALSE); break; case(2): XmToggleButtonSetState(posamb2,TRUE,FALSE); break; case(3): XmToggleButtonSetState(posamb3,TRUE,FALSE); break; case(4): XmToggleButtonSetState(posamb4,TRUE,FALSE); break; default: XmToggleButtonSetState(posamb0,TRUE,FALSE); break; } pos_dialog(configure_station_dialog); delw = XmInternAtom(XtDisplay(configure_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(configure_station_dialog, delw, Configure_station_destroy_shell, (XtPointer)configure_station_dialog); XtManageChild(cs_form); XtManageChild(cs_form1); XtManageChild(option_box); XtManageChild(power_box); XtManageChild(height_box); XtManageChild(gain_box); XtManageChild(directivity_box); XtManageChild(formphg); XtManageChild(pane); resize_dialog(cs_form, configure_station_dialog); XtPopup(configure_station_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(configure_station_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(configure_station_dialog), XtWindow(configure_station_dialog)); } } // Borrowed from the libiberty library, a GPL'ed program. // void freeargv (char **vector) { register char **scan; if (vector != NULL) { for (scan = vector; *scan != NULL; scan++) { free (*scan); } free (vector); } } // Borrowed from the libiberty library, a GPL'ed program. // char **dupargv (char **argv) { int argc; char **copy; if (argv == NULL) { return NULL; } /* the vector */ for (argc = 0; argv[argc] != NULL; argc++); copy = (char **) calloc ((argc + 1), sizeof (char *)); if (copy == NULL) { return NULL; } /* the strings */ for (argc = 0; argv[argc] != NULL; argc++) { int len = strlen (argv[argc]); copy[argc] = malloc (sizeof (char *) * (len + 1)); if (copy[argc] == NULL) { freeargv (copy); return NULL; } strcpy (copy[argc], argv[argc]); } copy[argc] = NULL; return copy; } ///////////////////////////////////////////// main ///////////////////////////////////////////// // Third argument is now deprecated //int main(int argc, char *argv[], char *envp[]) { int main(int argc, char *argv[], char *envp[]) { int ag, ag_error, trap_segfault, deselect_maps_on_startup; uid_t user_id; struct passwd *user_info; static char lang_to_use_or[30]; char temp[100]; static char *Geometry = NULL; static int xt = 0; char temp_base_dir[MAX_VALUE]; // Define some overriding resources for the widgets. // Look at files in /usr/X11/lib/X11/app-defaults for ideas. String fallback_resources[] = { // "Mwm*iconImageForeground: #000000000000\n", "*initialResourcesPersistent: False\n", // Default font if nothing else overrides it: "*.fontList: fixed\n", "*List.Translations: #override \n\ Return: Select(children)\n\ space: Select(children)\n", "*List.baseTranslations: #override \n\ Return: Select(children)\n\ space: Select(children)\n", "*XmTextField.translations: #override \ Return: activate()\n\ Enter: activate()\n", "*.Text.Translations: #override\n\ CtrlS: no-op(RingBell)\n\ CtrlR: no-op(RingBell)\n\ space: next-page()\n\ F: next-page()\n\ CtrlB: previous-page()\n\ B: previous-page()\n\ K: scroll-one-line-down()\n\ Y: scroll-one-line-down()\n\ J: scroll-one-line-up()\n\ E: scroll-one-line-up()\n\ Return: scroll-one-line-up()\n\ q: quit()\n", "*.Text.baseTranslations: #override\n\ space: next-page()\n\ F: next-page()\n\ CtrlB: previous-page()\n\ K: scroll-one-line-down()\n\ Y: scroll-one-line-down()\n\ J: scroll-one-line-up()\n\ E: scroll-one-line-up()\n\ Return: scroll-one-line-up()\n\ q: quit()\n", "*.vertical.Translations: #override\n\ space: StartScroll(Forward) NotifyScroll(FullLength) EndScroll() \n\ Delete: StartScroll(Backward) NotifyScroll(FullLength) EndScroll() \n\ CtrlUp: KbdScroll(up,50) EndScroll()\n\ CtrlDown: KbdScroll(down,50) EndScroll()\n\ Up: KbdScroll(up,10) EndScroll()\n\ Down: KbdScroll(down,10) EndScroll()\n\ Page_Up: KbdScroll(up,90) EndScroll()\n\ Page_Down: KbdScroll(down,90) EndScroll()\n", "*.horizontal.translations: #override \n\ CtrlLeft: KbdScroll(left,50) EndScroll()\n\ CtrlRight: KbdScroll(right,50) EndScroll()\n\ Left: KbdScroll(left,10) EndScroll()\n\ Right: KbdScroll(right,10) EndScroll()\n", "*.horizontal.accelerators: #override \n\ CtrlLeft: KbdScroll(left,50) EndScroll()\n\ CtrlRight: KbdScroll(right,50) EndScroll()\n\ Left: KbdScroll(left,10) EndScroll()\n\ Right: KbdScroll(right,10) EndScroll()\n", "*.vertical.accelerators: #override \n\ CtrlUp: KbdScroll(up,50) EndScroll()\n\ CtrlDown: KbdScroll(down,50) EndScroll()\n\ Up: KbdScroll(up,10) EndScroll()\n\ Down: KbdScroll(down,10) EndScroll()\n\ Page_Up: KbdScroll(up,90) EndScroll()\n\ Page_Down: KbdScroll(down,90) EndScroll()\n", "*.nodeText.Translations: #override \n\ Noneb: beginning-of-file() \n\ Home: beginning-of-file() \n\ Delete: previous-page() \n\ Prior: previous-page() \n\ Next: next-page() \n\ space: next-page() \n\ None: select-end() info_click() \n", "*.arg.translations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n", "*.pane.text.translations: #override \n\ Noneq: MenuPopdown(help) \n\ Noneb: beginning-of-file() \n\ Home: beginning-of-file() \n\ Delete: previous-page() \n\ Prior: previous-page() \n\ Next: next-page() \n\ space: next-page() \n", "*.dialog.value.translations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n\ Tab: Complete()\n", "*.dialog.value.baseTranslations: #override \n\ Return: confirm() \n\ CtrlG: abort() \n", "*.baseTranslations: #override \n\ Ctrlq: Quit()\n\ Ctrlc: Quit()\n\ Return: Accept()\n", "*Translations: #override \n\ q: Quit()\n\ c: Quit()\n\ Ctrl n: Next()\n\ Ctrl p: Prev()\n", "*minWidth: 200\n", "*minHeight: 100\n", NULL }; #ifndef optarg extern char *optarg; #endif // optarg extern char gitstring[]; #ifdef USING_LIBGC GC_find_leak = 1; GC_INIT(); #endif // USING_LIBGC // Make copies of argc/argv/envp so that we can start other // processes and know the environment we were started with. // my_argc = argc; // my_argv = argv; my_argv = dupargv(argv); my_envp = (void *)&envp[0]; euid = geteuid(); egid = getegid(); DISABLE_SETUID_PRIVILEGE; program_start_time = sec_now(); // For use by "Display Uptime" (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); #ifdef HAVE_LIBCURL curl_global_init(CURL_GLOBAL_ALL); #endif #ifdef HAVE_GRAPHICSMAGICK InitializeMagick(*argv); #else // HAVE_GRAPHICSMAGICK #ifdef HAVE_IMAGEMAGICK MagickCoreGenesis(*argv, MagickTrue); #endif // HAVE_IMAGEMAGICK #endif //HAVE_GRAPHICSMAGICK /* check fhs directories ?*/ /* setup values */ redo_list = FALSE; // init lists xa_config_dir[0]='\0'; delay_time = 0; last_weather_cycle = sec_now(); redraw_on_new_packet_data = 0; next_file_read = sec_now(); // init file replay timing redraw_on_new_data = 0; display_up = 0; display_up_first = 0; max_transmit_time = (time_t)900l; sec_next_gps = 0l; gprmc_save_string[0] = '\0'; gpgga_save_string[0] = '\0'; sec_next_raw_wx = 0l; auto_reply = 0; satellite_ack_mode = 0; last_time = 0l; next_time = (time_t)120l; net_last_time = 0l; net_next_time = (time_t)120l; posit_last_time = 0l; posit_next_time = 0l; wait_to_redraw=1; last_popup_x = 0; last_popup_y = 0; trap_segfault = 0; // Default is to dump core deselect_maps_on_startup = 0; debug_level = 0; install_colormap = 0; last_sound_pid = 0; my_last_course = 0; my_last_speed = 0; my_last_altitude = 0l; my_last_altitude_time = 0l; wx_station_type[0] = '\0'; last_alert_redraw = 0; igate_msgs_tx = 0; last_statusline = 0; // inactive statusline last_object[0] = '\0'; // initialize object dialog last_obj_grp = '\\'; last_obj_sym = '!'; clear_rain_data(); // init weather data clear_local_wx_data(); next_redraw = sec_now()+60; // init redraw timing last_redraw = sec_now(); lang_to_use_or[0] = '\0'; ag_error=0; // Reset the gps variables. xastir_snprintf(gps_sats, sizeof(gps_sats), "00"); gps_valid = 0; memset(&appshell, 0, sizeof(appshell)); // Here we had to add "g:" in order to allow -geometry to be // used and x: to allow xt arguments, which is actually parsed out // by the XtIntrinsics code, not directly in Xastir code. // while ((ag = getopt(argc, argv, "c:f:v:l:g:x:012346789timpV")) != EOF) { switch (ag) { case 'c': if (optarg) { xastir_snprintf(xa_config_dir,sizeof(xa_config_dir),"%s", optarg); fprintf(stderr,"Using config dir %s\n",xa_config_dir); } break; case 'f': // Track callsign if (optarg) { xastir_snprintf(temp_tracking_station_call, sizeof(temp_tracking_station_call), "%s", optarg); fprintf(stderr, "Tracking callsign %s\n", temp_tracking_station_call); (void)remove_leading_spaces(temp_tracking_station_call); (void)remove_trailing_spaces(temp_tracking_station_call); (void)remove_trailing_dash_zero(temp_tracking_station_call); (void)to_upper(temp_tracking_station_call); } break; case 't': fprintf(stderr,"Internal SIGSEGV handler enabled\n"); trap_segfault = 1; break; case 'v': fprintf(stderr,"debug"); if (optarg) { debug_level = atoi(optarg); fprintf(stderr," level %d", debug_level); } fprintf(stderr,"\n"); break; case 'V': printf("\nXastir V%s %s\n",xastir_version, gitstring); exit(0); break; case 'l': fprintf(stderr,"Language is"); if (optarg) { lang_to_use_or[0] = '\0'; if (strncasecmp(optarg,"ENGLISH", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "English"); } else if (strncasecmp(optarg,"DUTCH", 5) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Dutch"); } else if (strncasecmp(optarg,"FRENCH", 6) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "French"); } else if (strncasecmp(optarg,"GERMAN", 6) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "German"); } else if (strncasecmp(optarg,"SPANISH", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Spanish"); } else if (strncasecmp(optarg,"ITALIAN", 7) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Italian"); } else if (strncasecmp(optarg,"PORTUGUESE",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "Portuguese"); } else if (strncasecmp(optarg,"ELMERFUDD",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "ElmerFudd"); } else if (strncasecmp(optarg,"MUPPETSCHEF",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "MuppetsChef"); } else if (strncasecmp(optarg,"OLDEENGLISH",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "OldeEnglish"); } else if (strncasecmp(optarg,"PIGLATIN",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "PigLatin"); } else if (strncasecmp(optarg,"PIRATEENGLISH",10) == 0) { xastir_snprintf(lang_to_use_or, sizeof(lang_to_use_or), "PirateEnglish"); } else { ag_error++; fprintf(stderr," INVALID"); } if (!ag_error) { fprintf(stderr," %s", lang_to_use_or); } } fprintf(stderr,"\n"); break; case 'i': fprintf(stderr,"Install Colormap\n"); install_colormap = (int)TRUE; break; case 'm': fprintf(stderr,"De-select Maps\n"); deselect_maps_on_startup = (int)TRUE; break; case 'g': // -geometry Geometry = argv[optind++]; break; case 'x': // -xtsessionID optind++; // swallow argument, let XtIntrinsics deal with it. xt = 1; break; case 'p': // Disable popups disable_all_popups = 1; pop_up_new_bulletins = 0; warn_about_mouse_modifiers = 0; break; default: ag_error++; break; } } if (ag_error) { fprintf(stderr,"\nXastir Command line Options\n\n"); fprintf(stderr,"-c /path/dir Xastir config dir\n"); fprintf(stderr,"-f callsign Track callsign\n"); fprintf(stderr,"-i Install private Colormap\n"); fprintf(stderr,"-geometry WxH+X+Y Set Window Geometry\n"); fprintf(stderr,"-l Dutch Set the language to Dutch\n"); fprintf(stderr,"-l English Set the language to English\n"); fprintf(stderr,"-l French Set the language to French\n"); fprintf(stderr,"-l German Set the language to German\n"); fprintf(stderr,"-l Italian Set the language to Italian\n"); fprintf(stderr,"-l Portuguese Set the language to Portuguese\n"); fprintf(stderr,"-l Spanish Set the language to Spanish\n"); fprintf(stderr,"-l ElmerFudd Set the language to ElmerFudd\n"); fprintf(stderr,"-l MuppetsChef Set the language to MuppetsChef\n"); fprintf(stderr,"-l OldeEnglish Set the language to OldeEnglish\n"); fprintf(stderr,"-l PigLatin Set the language to PigLatin\n"); fprintf(stderr,"-l PirateEnglish Set the language to PirateEnglish\n"); fprintf(stderr,"-m Deselect Maps\n"); fprintf(stderr,"-p Disable popups\n"); fprintf(stderr,"-t Internal SIGSEGV handler enabled\n"); fprintf(stderr,"-v level Set the debug level\n"); fprintf(stderr,"-V Print version number and exit\n\n"); fprintf(stderr,"\n"); exit(0); // Exiting after dumping out command-line options } // If we don't make this call, we can't access Xt or // Xlib calls from multiple threads at the same time. // Note that Motif from the OSF (including OpenMotif) // still can't handle multiple threads talking to it at // the same time. See: // http://www.faqs.org/faqs/x-faq/part7/section-46.html // We'll probably have to add in a global mutex lock in // order to keep from accessing the widget set from more // than one thread. // XInitThreads(); // Set language attribs. Must be called prior to // XtVaOpenApplication(). (void)XtSetLanguageProc((XtAppContext) NULL, XtSetLanguageProc(NULL, NULL, NULL), (XtPointer) NULL ); if (Geometry) { // // Really we should be merging with the RDB database as well // and then parsing the final geometry (Xlib Programming // Manual section 14.4.3 and 14.4.4). // geometry_flags = XParseGeometry(Geometry, &geometry_x, &geometry_y, &geometry_width, &geometry_height); /* if ((WidthValue|HeightValue) & geometry_flags) { fprintf(stderr,"Found width/height\n"); } if (XValue & geometry_flags) { fprintf(stderr,"Found X-offset\n"); } if (YValue & geometry_flags) { fprintf(stderr,"Found Y-offset\n"); } fprintf(stderr, "appshell: Width:%4d Height:%4d X-offset:%4d Y-offset:%4d\n", (int)geometry_width, (int)geometry_height, (int)geometry_x, (int)geometry_y); */ } /* get User info */ user_id = getuid(); user_info = getpwuid(user_id); xastir_snprintf(user_dir, sizeof(user_dir), "%s", user_info->pw_dir); /* fprintf(stderr,"User %s, Dir %s\n",user_info->pw_name,user_dir); fprintf(stderr,"User dir %s\n",get_user_base_dir("")); fprintf(stderr,"Data dir %s\n",get_data_base_dir("")); */ /* check user directories */ if (filethere(get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user dir\n"); if (mkdir(get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); // Creature to feep later? // needs // fprintf(stderr,"Check to see if '%s' exists \n", // dirname(get_user_base_dir("")) ); exit(errno); } } if (filethere(get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user config dir\n"); if (mkdir(get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("config", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user data dir\n"); if (mkdir(get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("data", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user log dir\n"); if (mkdir(get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("logs", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user tracklogs dir\n"); if (mkdir(get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user tmp dir\n"); if (mkdir(get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making user gps dir\n"); if ( mkdir(get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("gps", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } if (filethere(get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir))) != 1) { fprintf(stderr,"Making map_cache dir\n"); if (mkdir(get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir)),S_IRWXU) !=0 ) { fprintf(stderr,"Fatal error making user dir '%s':\n\t%s \n", get_user_base_dir("map_cache", temp_base_dir, sizeof(temp_base_dir)), strerror(errno) ); exit(errno); } } /* done checking user dirs */ #ifdef USE_PID_FILE_CHECK if (pid_file_check(xt) !=0 ) { fprintf(stderr,"pid_file_check failed:\t%s \n", strerror(errno) ); exit(errno); } #endif // initialize interfaces init_critical_section(&port_data_lock); // Protects the port_data[] array of structs init_critical_section(&output_data_lock); // Protects interface.c:channel_data() function only init_critical_section(&data_lock); // Protects global incoming_data_queue init_critical_section(&connect_lock); // Protects port_data[].thread_status and port_data[].connect_status // We should probably protect redraw_on_new_data, alert_redraw_on_update, and // redraw_on_new_packet_data variables as well? // Also need to protect dialogs. #ifdef HAVE_DB connections_initialized = 0; #endif // HAVE_DB #ifdef USE_MAP_CACHE map_cache_init(); #endif // USE_MAP_CACHE (void)bulletin_gui_init(); (void)db_init(); (void)db_gui_init(); (void)draw_symbols_init(); (void)interface_gui_init(); (void)list_gui_init(); (void)locate_gui_init(); (void)geocoder_gui_init(); (void)location_gui_init(); (void)maps_init(); (void)messages_gui_init(); (void)popup_gui_init(); (void)track_gui_init(); (void)view_message_gui_init(); (void)wx_gui_init(); (void)igate_init(); clear_all_port_data(); // clear interface port data (void) signal(SIGINT,quit); // set signal on stop (void) signal(SIGQUIT,quit); (void) signal(SIGTERM,quit); // Make sure that we reset to SIG_DFL handler any time we spawn // a child process. This is so the child process doesn't call // restart() as well. Only the main process needs to call // restart() on receiving a SIGHUP. We can do this via the // following call: // // (void)signal(SIGHUP,SIG_DFL); // (void) signal(SIGHUP,restart); // Shut down/restart if SIGHUP received #ifndef OLD_PTHREADS (void) signal(SIGUSR1,usr1sig); // take a snapshot on demand (void) signal(SIGUSR2,usr2sig); // transmit now on demand #else // OLD_PTHREADS # warning ***** Old kernel detected: Disabling SIGUSR1 handler (snapshot on demand) ***** #endif // OLD_PTHREADS #ifdef HAVE_SIGIGNORE (void) sigignore(SIGPIPE); #else // HAVE_SIGIGNORE (void) signal(SIGPIPE,SIG_IGN); // set sigpipe signal to ignore #endif // HAVE_SIGIGNORE if (trap_segfault) { (void) signal(SIGSEGV,segfault); // set segfault signal to check } // Load program parameters or set to default values load_data_or_default(); // Start the listening socket. If we fork it early we end up // with much smaller process memory allocated for it and all its // children. The server will authenticate each client that // connects. We'll share all of our data with the server, which // will send it to all connected/authenticated clients. // Anything transmitted by the clients will come back to us and // standard igating rules should apply from there. if (enable_server_port) { tcp_server_pid = Fork_TCP_server(my_argc, my_argv, my_envp); udp_server_pid = Fork_UDP_server(my_argc, my_argv, my_envp); } if (deselect_maps_on_startup) { unlink( get_user_base_dir(SELECTED_MAP_DATA, temp_base_dir, sizeof(temp_base_dir)) ); // Remove the selected_maps.sys file } update_units(); // set up conversion factors and strings /* do language links */ if (strlen(lang_to_use_or) > 0) xastir_snprintf(lang_to_use, sizeof(lang_to_use), "%s", lang_to_use_or); xastir_snprintf(temp, sizeof(temp), "help/help-%s.dat", lang_to_use); (void)unlink(get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir))); // Note that this symlink will probably not fail. It's easy to // create a symlink that points to nowhere. if (symlink(get_data_base_dir(temp),get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir))) == -1) { fprintf(stderr,"Error creating database link for help.dat\n"); fprintf(stderr, "Couldn't create symlink: %s -> %s\n", get_user_base_dir("config/help.dat", temp_base_dir, sizeof(temp_base_dir)), get_data_base_dir(temp)); exit(0); // Exiting 'cuz online help won't work. } xastir_snprintf(temp, sizeof(temp), "config/language-%s.sys", lang_to_use); (void)unlink(get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir))); // Note that this symlink will probably not fail. It's easy to // create a symlink that points to nowhere. if (symlink(get_data_base_dir(temp),get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir))) == -1) { fprintf(stderr,"Error creating database link for language.sys\n"); fprintf(stderr, "Couldn't create symlink: %s -> %s\n", get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir)), get_data_base_dir(temp)); exit(0); // We can't set our language, so exit. } /* (NEW) set help file area */ xastir_snprintf(HELP_FILE, sizeof(HELP_FILE), "%s", "config/help.dat"); #ifdef HAVE_FESTIVAL /* Initialize the festival speech synthesis port */ if (SayTextInit()) { fprintf(stderr,"Error connecting to Festival speech server.\n"); //exit(0); // Not worth exiting just because we can't talk! } #endif // HAVE_FESTIVAL /* populate the predefined object (SAR/Public service) struct */ Populate_predefined_objects(predefinedObjects); if (load_color_file()) { if (load_language_file(get_user_base_dir("config/language.sys", temp_base_dir, sizeof(temp_base_dir)))) { init_device_names(); // set interface names clear_message_windows(); clear_popup_message_windows(); init_station_data(); // init station storage init_message_data(); // init messages reset_outgoing_messages(); // This convenience function calls (in turn): // XtToolkitInitialize() // XtCreateApplicationContext() // XtOpenDisplay() // XtAppCreateShell(). // appshell = XtVaOpenApplication( &app_context, "Xastir", NULL, 0, &argc, argv, fallback_resources, sessionShellWidgetClass, XmNmappedWhenManaged, FALSE, NULL); display = XtDisplay(appshell); if (!display) { fprintf(stderr,"%s: can't open display, exiting...\n", argv[0]); exit(-1); // Must exit here as we can't get our display. } XtSetValues(XmGetXmDisplay(display), NULL, 0); // DK7IN: now scanf and printf use "," instead of "." // that leads to several problems in the initialization. // // DK7IN: inserted next line here for avoiding scanf // errors during init! // // (void)setlocale(LC_NUMERIC, "C"); // DK7IN: It's now ok (void)setlocale(LC_CTYPE, "C"); // K4INT: Make sure strings work OK. setup_visual_info(display, DefaultScreen(display)); // Adjust default window size based on actual screen dimensions // if still using the hardcoded defaults // (DEFAULT_STARTUP_SCREEN_WIDTHxDEFAULT_STARTUP_SCREEN_HEIGHT). // This improves the experience for users with larger displays // while preserving existing user configurations. if (screen_width == DEFAULT_STARTUP_SCREEN_WIDTH && screen_height == DEFAULT_STARTUP_SCREEN_HEIGHT) { // Constants for screen sizing ratios const double DEFAULT_SCREEN_RATIO = 0.70; int screen_num = DefaultScreen(display); int display_width = DisplayWidth(display, screen_num); int display_height = DisplayHeight(display, screen_num); // Use DEFAULT_SCREEN_RATIO of screen width and height as default long new_width = (long)(display_width * DEFAULT_SCREEN_RATIO); long new_height = (long)(display_height * DEFAULT_SCREEN_RATIO); // Enforce minimum sizes (use the old defaults as minimum) if (new_width < 590l) { new_width = 590l; } if (new_height < 420l) { new_height = 420l; } // Enforce the upper bounds from the config system if (new_width > 10000l) { new_width = 10000l; } if (new_height > 10000l) { new_height = 10000l; } screen_width = new_width; screen_height = new_height; fprintf(stderr, "Auto-sizing window to %ldx%ld based on display size %dx%d\n", screen_width, screen_height, display_width, display_height); } // Get colormap (N7TAP: do we need this if the screen // visual is TRUE or DIRECT? // cmap = DefaultColormapOfScreen(XtScreen(appshell)); if (visual_type == NOT_TRUE_NOR_DIRECT) { if (install_colormap) { cmap = XCopyColormapAndFree(display, cmap); XtVaSetValues(appshell, XmNcolormap, cmap, NULL); } } //fprintf(stderr,"***index_restore_from_file\n"); // Read the current map index file into the index linked list index_restore_from_file(); // Reload tactical calls. This implements persistence // for this type. reload_tactical_calls(); //fprintf(stderr,"***create_appshell\n"); // This call fills in the top-level window and then // calls XtRealize. // create_appshell(display, argv[0], argc, argv); // reset language attribs for numeric, program needs // decimal in US for all data! (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); // DK7IN: now scanf and printf work as wanted... //fprintf(stderr,"***check_fcc_data\n"); /* check for ham databases */ (void)check_rac_data(); (void)check_fcc_data(); // Find the extents of every map we have. Use the smart // timestamp-checking reindexing (quicker). if ( index_maps_on_startup ) { map_indexer(0); } // Check whether we're running Xastir for the first time. // If so, my_callsign will be "NOCALL". In this case // write something appropriate into ~/.xastir/config/selected_maps.sys // so that we get the default map on startup. Also // request to bring up the Configure->Station dialog in // this case. // if (strncasecmp(my_callsign,"NOCALL",6) == 0) { FILE *ff; // fprintf(stderr,"***** First time run *****\n"); // Set the flag first_time_run = 1; // Write the default map into the selected map file ff = fopen( get_user_base_dir(SELECTED_MAP_DATA, temp_base_dir, sizeof(temp_base_dir)), "a"); if (ff != NULL) { #ifdef HAVE_LIBSHP fprintf(ff,"NaturalEarth/\n"); #else fprintf(ff,"worldhi.map\n"); #endif (void)fclose(ff); } } // Mark the "selected" field in the in-memory map index // to correspond to the selected_maps.sys file. map_chooser_init(); // Warn the user if altnet is enabled on startup. This // is so that the people who are button pushers/knob turners // will know what's wrong when they don't see stations on their // screen anymore. // if (altnet) { // "Warning" // "Altnet is enabled (File->Configure->Defaults dialog)"); popup_message_always( langcode("POPEM00035"), langcode("POPEM00051") ); } // Start UpdateTime. It schedules itself to be run // again each time. This is also the process that // starts up the interfaces. UpdateTime( (XtPointer) da, (XtIntervalId) NULL ); // Update the logging indicator Set_Log_Indicator(); XtAppMainLoop(app_context); } else { fprintf(stderr,"Error in language file! Exiting...\n"); } } else { fprintf(stderr,"Error in Color file! Exiting...\n"); } quit(0); return 0; } Xastir-Release-2.2.4/src/main.h0000664000175000017500000003560415151324131015215 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_MAIN_H #define XASTIR_MAIN_H #include // For mutex debugging with Linux threads only //#ifdef __linux__ // #define MUTEX_DEBUG 1 //#endif // __linux__ // This gets defined if pthreads implementation uses SIGUSR1/SIGUSR2 // signals. This disables our SIGUSR1 handler which disallows // creating snapshots on receipt of that signal. Old kernels (2.0 // and early 2.1) had only 32 signals available so only USR1/USR2 // were available for LinuxThreads use. Newer kernels have more // signals available, making USR1/USR2 available to programs again. // _NSIG is defined in /usr/include/bits/signum.h // #ifdef __linux__ #ifdef _NSIG #if (_NSIG <= 32) #define OLD_PTHREADS //# warning ***** OLD_PTHREADS DETECTED ***** #else //# warning ***** NEW_PTHREADS DETECTED ***** #endif // if (_NSIG...) #endif // _NSIG #endif // __linux__ // To enable the "Transmit Raw WX data" button in // Configure->Defaults dialog. Warning: If you enable this, enable // the button in Configure->Defaults, and are running a weather // station that puts out raw data that is NOT allowed by the APRS // spec, you'll be putting out garbage and trashing the channel. // //#define TRANSMIT_RAW_WX // To use predefined object configuration files from within the // user's base directory e.g. ~/.xastir/config/predefined_SAR.sys // rather than from the main base directory, enable this definition. //#define OBJECT_DEF_FILE_USER_BASE extern int enable_server_port; extern char altnet_call[MAX_CALLSIGN+1]; extern int altnet; extern Widget iface_da; extern FILE *read_file_ptr; extern int interrupt_drawing_now; #define VERSIONFRM (!altnet?XASTIR_TOCALL:altnet_call) /* Packet version info */ #ifdef __LCLINT__ #define PACKAGE "xastir" #define VERSION "lclint" #define VERSIONTXT "xastir lclint debug version" #else // __LCLINT__ #define VERSIONTXT PACKAGE " " VERSION #endif // __LCLINT__ #define VERSIONLABEL VERSIONTXT // NOTE: This is out of date and not used anymore anyway. #define VERSIONMESSAGE "XASTIR Version: " VERSION "\n\nAmateur Station Tracking and Information Reporting\nby Frank Giannandrea, KC2GJS was KC0DGE\n Code added by:\n Richard Hagemeyer - VE3UNW, Curt Mills - WE7U,\n Mike Sims - KA9KIM, Gerald Stueve - K4INT was KE4NFJ,\n Mark Grennan - KD5AMB, Henk de Groot - PE1DNN,\n Jim Sevilla - KD6VPE, Jose R. Marte A. - HI8GN,\n Michael G. Petry - N3NYN, Lloyd Miller - VE6LFM,\n Alessandro Frigeri - IK0YUP,\n Chuck Byam - KG4IJB, Rolf Bleher - DK7IN, Ken Koster - N7IPB" // NOTE: This is out of date and not used anymore anyway. #define ABOUTGNUL "XASTIR, Copyright (C) 1999, 2000 Frank Giannandrea\nXASTIR comes with ABSOLUTELY NO WARRANTY;\nThis is free software, and you are welcome\nto redistribute it under certain conditions;\nsee the GNU LICENSE for details.\n" #define MAX_PHG 8 #define MAX_COMMENT 80 ////////////////////////////////////////////////////////////////////// // These globals and prototypes are from: // http://lightconsulting.com/~thalakan/process-title-notes.html // They seems to work fine on Linux, but they only change the "ps" // listings, not the top listings. I don't know why yet. /* Globals */ //extern char **Argv = ((void *)0); //extern char *__progname, *__progname_full; //extern char *LastArgv = ((void *)0); /* Prototypes */ extern void set_proc_title(char *fmt,...); extern void init_set_proc_title(int argc, char *argv[], char *envp[]); // New stuff defined by Xastir project: extern int my_argc; extern char **my_argv; extern char **my_envp; ////////////////////////////////////////////////////////////////////// extern int input_x; extern int input_y; #define MAX_RELAY_DIGIPEATER_CALLS 50 extern char relay_digipeater_calls[10*MAX_RELAY_DIGIPEATER_CALLS]; extern int skip_dupe_checking; extern int serial_char_pacing; // Inter-character delay in ms. extern int disable_all_maps; extern int re_sort_maps; extern Widget trackme_button; extern Widget CAD_close_polygon_menu_item; extern int debug_level; extern int my_position_valid; extern int using_gps_position; extern int transmit_now; extern char DATABASE_FILE[]; extern char DATABASE_POINTER_FILE[]; extern char DATABASE_POINTER_TEMP[]; extern char ALERT_MAP_DIR[400]; extern char SELECTED_MAP_DIR[400]; extern char SELECTED_MAP_DATA[400]; extern char MAP_INDEX_DATA[400]; extern char AUTO_MAP_DIR[400]; extern char SYMBOLS_DIR[400]; extern char LOGFILE_IGATE[400]; extern char LOGFILE_TNC[400]; extern char LOGFILE_NET[400]; extern char LOGFILE_MESSAGE[400]; extern char LOGFILE_WX[400]; extern char LOGFILE_WX_ALERT[400]; extern char HELP_FILE[]; extern char SOUND_DIR[400]; extern time_t WX_ALERTS_REFRESH_TIME; extern time_t remove_ID_message_time; extern int pending_ID_message; extern time_t gps_time; extern time_t POSIT_rate; extern time_t OBJECT_rate; extern time_t update_DR_rate; extern time_t posit_last_time; extern time_t posit_next_time; extern int smart_beaconing; extern int sb_POSIT_rate; extern int sb_last_heading; extern int sb_current_heading; extern time_t sb_last_posit_time; extern int sb_turn_min; extern int sb_turn_slope; extern int sb_turn_time; extern int sb_posit_fast; extern int sb_posit_slow; extern int sb_low_speed_limit; extern int sb_high_speed_limit; extern int pop_up_new_bulletins; extern int view_zero_distance_bulletins; extern int warn_about_mouse_modifiers; extern int predefined_menu_from_file; extern int draw_labeled_grid_border; // used to turn on or off border on map extern int my_trail_diff_color; // trails for mycall with different ssids have the same or a different color extern int output_station_type; extern int emergency_beacon; typedef struct _selections { int none; int mine; int tnc; int direct; int via_digi; int net; int tactical; int old_data; int stations; int fixed_stations; int moving_stations; int weather_stations; int CWOP_wx_stations; int objects; int weather_objects; int gauge_objects; int other_objects; int aircraft_objects; int vessel_objects; } Selections; extern Selections Select_; typedef struct _what_to_display { int callsign; int label_all_trackpoints; int symbol; int symbol_rotate; int trail; int course; int speed; int speed_short; int altitude; int weather; int weather_text; int temperature_only; int wind_barb; int aloha_circle; int ambiguity; int phg; int default_phg; int phg_of_moving; int df_data; int df_beamwidth_data; int df_bearing_data; int dr_data; int dr_arc; int dr_course; int dr_symbol; int dist_bearing; int last_heard; } What_to_display; extern What_to_display Display_; extern int currently_selected_stations; extern int currently_selected_stations_save; extern Pixel colors[256]; #define MAX_TRAIL_COLORS 32 extern Pixel trail_colors[MAX_TRAIL_COLORS]; extern int current_trail_color; extern int english_units; extern int do_dbstatus; extern int redraw_on_new_data; extern int redo_list; extern int operate_as_an_igate; #ifdef TRANSMIT_RAW_WX extern int transmit_raw_wx; #endif // TRANSMIT_RAW_WX extern int transmit_compressed_posit; extern int transmit_compressed_objects_items; extern int log_igate; extern int log_tnc_data; extern int log_net_data; extern int log_message_data; extern int log_wx_alert_data; extern int log_wx; extern int snapshots_enabled; extern int kmlsnapshots_enabled; extern char user_dir[]; extern char lang_to_use[30]; extern char my_group; extern char my_symbol; extern char my_phg[MAX_PHG+1]; extern char my_comment[MAX_COMMENT+1]; extern int map_background_color; extern int map_color_fill; extern int letter_style; extern int icon_outline_style; extern int wx_alert_style; extern time_t map_refresh_interval; extern time_t map_refresh_time; extern char sound_command[90]; extern pid_t last_sound_pid; extern int sound_play_new_station; extern int sound_play_new_message; extern int sound_play_prox_message; extern int sound_play_band_open_message; extern int sound_play_wx_alert_message; extern char sound_new_station[90]; extern char sound_new_message[90]; extern char sound_prox_message[90]; extern char sound_band_open_message[90]; extern char sound_wx_alert_message[90]; extern int ATV_screen_ID; extern int festival_speak_ID; extern int festival_speak_new_station; extern int festival_speak_proximity_alert; extern int festival_speak_tracked_proximity_alert; extern int festival_speak_band_opening; extern int festival_speak_new_message_alert; extern int festival_speak_new_message_body; extern int festival_speak_new_weather_alert; extern char prox_min[30]; extern char prox_max[30]; extern time_t sec_old; extern time_t sec_clear; extern time_t aircraft_sec_clear; extern int trail_segment_time; extern int trail_segment_distance; extern int RINO_download_interval; extern int dead_reckoning_timeout; extern char bando_min[30]; extern char bando_max[30]; extern int Display_packet_data_type; extern int show_only_station_capabilities; extern int Display_packet_data_mine_only; extern int menu_x; extern int menu_y; extern long my_last_altitude; extern time_t my_last_altitude_time; extern int my_last_course; extern int my_last_speed; // in knots extern unsigned igate_msgs_tx; extern int symbols_loaded; extern GC gc2; extern GC gc_tint; extern GC gc_stipple; extern GC gc_bigfont; extern int read_file; extern float x_screen_distance; extern time_t max_transmit_time; extern int transmit_disable; extern int posit_tx_disable; extern int object_tx_disable; extern int map_chooser_expand_dirs; extern int request_new_image; extern int disable_all_popups; extern char temp_tracking_station_call[30]; extern int coordinate_system; #define USE_DDDDDD 0 #define USE_DDMMMM 1 #define USE_DDMMSS 2 #define USE_UTM 3 #define USE_UTM_SPECIAL 4 #define USE_MGRS 5 typedef struct { Widget calling_dialog; // NULL if the calling dialog has been closed. Widget input_lat_deg; // Pointers to calling dialog's widgets Widget input_lat_min; // (Where to get/put the data) Widget input_lat_dir; Widget input_lon_deg; Widget input_lon_min; Widget input_lon_dir; } coordinate_calc_array_type; extern coordinate_calc_array_type coordinate_calc_array; extern void Coordinate_calc(Widget w, XtPointer clientData, XtPointer callData); extern void HandlePendingEvents(XtAppContext app); extern void create_gc(Widget w); extern void Station_List(Widget w, XtPointer clientData, XtPointer calldata); extern void Tracks_All_Clear(Widget w, XtPointer clientData, XtPointer callData); extern void Locate_station(Widget w, XtPointer clientData, XtPointer callData); extern void Locate_place(Widget w, XtPointer clientData, XtPointer callData); extern void Geocoder_place(Widget w, XtPointer clientData, XtPointer callData); extern void Configure_geocoder_settings(Widget w, XtPointer clientData, XtPointer callData); extern void Display_Wx_Alert(Widget w, XtPointer clientData, XtPointer callData); extern void Auto_msg_option(Widget w, XtPointer clientData, XtPointer calldata); extern void Auto_msg_set(Widget w, XtPointer clientData, XtPointer calldata); extern void Bulletins(Widget w, XtPointer clientData, XtPointer callData); extern void on_off_switch(int switchpos, Widget first, Widget second); extern void busy_cursor(Widget w); extern void pos_dialog(Widget w); extern int create_image(Widget w); typedef struct _transparent_color_record { unsigned long trans_color; struct _transparent_color_record *next; } transparent_color_record; extern int check_trans (XColor c, transparent_color_record *c_trans_color_head); extern void draw_WMS_map (Widget w, char *filenm, int destination_pixmap, char *URL, transparent_color_record *c_trans_color_head, int nocache); extern void locate_gui_init(void); extern void geocoder_gui_init(void); extern void location_gui_init(void); extern void view_message_gui_init(void); extern void wx_gui_init(void); extern long get_x_scale(long x, long y, long ysc); extern Widget Display_data_dialog; extern Widget Display_data_text; extern Widget text3; extern Widget text4; extern Widget log_indicator; extern void display_zoom_status(void); extern void Center_Zoom(Widget w, XtPointer clientData, XtPointer calldata); extern int center_zoom_override; extern void statusline(char *status_text,int update); extern void stderr_and_statusline(char *message); extern int SayTextInit(void); extern int SayText(char *text); extern Widget auto_msg_toggle; // Symbol update stuff extern Widget configure_station_dialog; extern Widget station_config_group_data; extern Widget station_config_symbol_data; extern void updateSymbolPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern Widget object_dialog; extern Widget object_group_data; extern Widget object_symbol_data; extern void updateObjectPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern void Draw_All_CAD_Objects(Widget w); // Nominatim geocoding configuration extern char nominatim_server_url[400]; extern int nominatim_cache_enabled; extern int nominatim_cache_days; extern char nominatim_user_email[100]; extern char nominatim_country_default[20]; // unit conversion extern char un_alt[2+1]; extern char un_dst[2+1]; extern char un_spd[4+1]; extern double cvt_m2len; extern double cvt_dm2len; extern double cvt_hm2len; extern double cvt_kn2len; extern double cvt_mi2len; // euid and egid extern uid_t euid; extern gid_t egid; /* JMT - works in FreeBSD */ // Note: weird conditional thing is there just to shut up // "ignoring return value" warnings from GCC on newer Linux systems #define DISABLE_SETUID_PRIVILEGE do { \ if (seteuid(getuid())==0){/* all is well*/} \ if (setegid(getgid())==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)getuid(), (int)getgid()); } \ } while(0) #define ENABLE_SETUID_PRIVILEGE do { \ if (seteuid(euid)==0){/* all is well*/} \ if (setegid(egid)==0){/* all is well*/} \ if (debug_level & 4) { fprintf(stderr, "Changing euid to %d and egid to %d\n", (int)euid, (int)egid); } \ } while(0) #ifdef HAVE_LIBSHP extern void create_map_from_trail(char *call_sign); #endif // HAVE_LIBSHP #endif /* XASTIR_MAIN_H */ Xastir-Release-2.2.4/src/map_OSM.c0000664000175000017500000015551615151324131015564 0ustar hibbyhibby/* * * * Copyright (C) 2000-2026 The Xastir Group * * This file was contributed by Jerry Dunmire, KA6HLD. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * This file derived from map_tiger.c which has the following copyrights: * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "color.h" #include "xa_config.h" #include "map_cache.h" #include "tile_mgmnt.h" #include "dlm.h" #include "map_OSM.h" #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION // This matte color was chosen emphirically to work well with the // contours from topOSM. #if (QuantumDepth == 8) #define MATTE_RED (0xa7) #define MATTE_GREEN (0xa7) #define MATTE_BLUE (0xa7) #define MATTE_OPACITY (0x00) #define MATTE_COLOR_STRING "xc:#a7a7a7" //#define MATTE_COLOR_STRING "xc:#a7a7a700" //#define MATTE_OPACITY (0xff) //#define MATTE_COLOR_STRING "xc:#a7a7a7ff" #elif (QuantumDepth == 16) #define MATTE_RED (0xa700) #define MATTE_GREEN (0xa700) #define MATTE_BLUE (0xa700) #define MATTE_OPACITY (0x0000) #define MATTE_COLOR_STRING "xc:#a700a700a700" //#define MATTE_COLOR_STRING "xc:#a700a700a700ffff" #else #error "QuantumDepth != 16 or 8" #endif // QuantumDepth #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" #define xastirColorsMatch(p,q) (((p).red == (q).red) && ((p).blue == (q).blue) \ && ((p).green == (q).green)) // osm_scale_x - map Xastir scale_x value to an OSM binned value // // Note that the terms 'higher' and 'lower' are confusing because a // smaller Xastir scale number is a larger OSM zoom level. OSM zoom level // 0 would show the whole world in a 256x256 pixel tile, OSM zoom level // 18 (the max) would require 2^18 tiles to simple wrap the equator. // // On the equator, OSM zoom level 0 equates to ~97 miles/pixel // and OSM zoom level 18 equates to ~2 ft/pixel // // direction = -1, zoom in // direction = 1, zoom out // direction = 0, nearst level out from the xastir scale // #define MAX_OSM_ZOOM_LEVEL 18 #define OSM_ZOOM_LEVELS (MAX_OSM_ZOOM_LEVEL + 1) static long osm_scale_x(long xastir_scale_x) { long osm_level[OSM_ZOOM_LEVELS] = {1, 2, 4, 8, 15, 31, 62, 124, \ 247, 494, 989, 1978, 3955, 7910, 15820, 31641,\ 63281, 126563, 253125 }; long osm_scale_x = osm_level[0]; int i = 0; for (i=1; i <= MAX_OSM_ZOOM_LEVEL; i++) { if (xastir_scale_x > osm_level[i]) { continue; } else { if (labs(osm_level[i - 1] - xastir_scale_x) < labs(osm_level[i] - xastir_scale_x)) { osm_scale_x = osm_level[i - 1]; } else { osm_scale_x = osm_level[i]; } break; } } if (i > MAX_OSM_ZOOM_LEVEL) { i = MAX_OSM_ZOOM_LEVEL; osm_scale_x = osm_level[i]; } return(osm_scale_x); } // osm_scale_x() /* * adj_to_OSM_level - adjust scale_x and scale_y to approximate an OSM zoom level * * The OSM zoom level closest to the scale_x value will be chosen and scale_x is modified. * The scale_y value (pointed to by the second argument) is scaled proportionaly. Both * values pointed to by the arguments are modified. */ void adj_to_OSM_level( long *new_scale_x, long *new_scale_y) { long scale; scale = osm_scale_x(*new_scale_x); // the y scale must also be adjusted. *new_scale_y = (int)(((double)(*new_scale_y) * ((double)scale / (double)(*new_scale_x)) + 0.5)); *new_scale_x = scale; return; } // adj_to_OSM_level() /* * osm_zoom_level - translate the longitude scale to the nearest OSM zoom level * * OSM tile scaling is based on the number of tiles needed to wrap the earth at the equator. * A tile is 256x256 pixels. */ unsigned int osm_zoom_level(long scale_x) { double circumference = 360.0*3600.0*100.0; // Xastir Units = 1/100 second. double zf; int z; zf = (log(circumference / (double)scale_x) / log(2.0)) - 8.0; z = (int)(zf + 0.5); // OSM levels run from 0 to 18. Not all levels are available for all views. if (z < 0) { z = 0; } if (z > 18) { z = 18; } return((unsigned int)z); } // osm_zoom_level() static KeySym OptimizeKey = 0; static KeySym ReportScaleKey = 0; void init_OSM_values(void) { OptimizeKey = 0; ReportScaleKey = 0; return; } int OSM_optimize_key(KeySym key) { return (key == OptimizeKey ? TRUE : FALSE); } void set_OSM_optimize_key(KeySym key) { OptimizeKey = key; return; } int OSM_report_scale_key(KeySym key) { return (key == ReportScaleKey ? TRUE : FALSE); } void set_OSM_report_scale_key(KeySym key) { ReportScaleKey = key; return; } #ifdef HAVE_MAGICK static void get_OSM_local_file(char * local_filename, char * fileimg) { time_t query_start_time, query_end_time; #ifdef USE_MAP_CACHE int map_cache_return = 1; // Default = cache miss char *cache_file_id; #endif // USE_MAP_CACHE char temp_file_path[MAX_VALUE]; if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (!map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } set_dangerous("map_OSM: map_cache_get"); map_cache_return = map_cache_get(fileimg,local_filename); clear_dangerous(); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: <%d> bytes returned: %d\n", map_cache_return, (int) strlen(local_filename)); } if (map_cache_return != 0 ) { set_dangerous("map_OSM: map_cache_fileid"); cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, MAX_FILENAME, // hardcoded to avoid sizeof() "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, "png"); free(cache_file_id); clear_dangerous(); #else // USE_MAP_CACHE xastir_snprintf(local_filename, MAX_FILENAME, // hardcoded to avoid sizeof() "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same name. // This avoids the problem of having an old map image here and // the code trying to display it when the download fails. unlink( local_filename ); if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // For debugging the MagickError/MagickWarning segfaults. //system("cat /dev/null >/var/tmp/xastir_hacker_map.png"); #ifdef USE_MAP_CACHE set_dangerous("map_OSM: map_cache_put"); map_cache_put(fileimg,local_filename); clear_dangerous(); } // end if is cached DHBROWN #endif // MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); } // end get_OSM_local_file #endif //HAVE_MAGICK #ifdef HAVE_MAGICK static long xastirLat2pixelLat( long xlat, int osm_zoom ) { double lat; // in radians double projection, y; long pixelLat; lat = convert_lat_l2r(xlat); // xastir latitude values can exceed +/- 90.0 degrees because // the latitude is the extent of the display window. Limit the // OSM latitude to less than +/- 90.0 degrees so that the projection // calculation does not blow up or return unreasonable values. if (lat > ((89.0/180.0) * M_PI)) { lat = ((89.0/180.0) * M_PI); } else if (lat < ((-89.0/180.0) * M_PI)) { lat = ((-89.0/180.0) * M_PI); } projection = log(tan(lat) + (1.0 / cos(lat))); y = projection / M_PI; y = 1.0 - y; pixelLat = (long)((y * (double)(1<<(osm_zoom + 8))) / 2.0); return(pixelLat); } // xastirLat2pixelLat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static double pixelLat2Lat(long osm_lat, int osm_zoom) { double lat, projection, y; y = (double)osm_lat * 2.0 / (double)(1<<(osm_zoom + 8)); y = 1.0 - y; projection = y * M_PI; lat = 2.0 * atan(exp(projection)) - (M_PI / 2.0); lat = (lat * 180.0 ) / M_PI; return(lat); } // pixelLat2Lat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long pixelLat2xastirLat(long osm_lat, int osm_zoom) { double lat; long xastirLat; lat = pixelLat2Lat(osm_lat, osm_zoom); xastirLat = (long)((90.0 - lat) * 3600.0 * 100.0); return (xastirLat); } // pixelLat2xastirLat() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long xastirLon2pixelLon( long xlon, int osm_zoom) { double lon; long pixelLon; lon = xlon / (3600.0 * 100.0); lon = lon * (1<<(osm_zoom +8)); lon = lon / 360.0; pixelLon = lon; return(pixelLon); } // xastirLon2pixelLon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static double pixelLon2Lon(long osm_lon, int osm_zoom) { double lon; lon = osm_lon * 360.0 ; lon = lon / (1<<(osm_zoom + 8)); return(lon); } // pixelLon2Lon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK static long pixelLon2xastirLon(long osm_lon, int osm_zoom) { long xastirLon; xastirLon = (long)(pixelLon2Lon(osm_lon, osm_zoom) * 3600.0 * 100.0); return(xastirLon); } // pixelLon2xastirLon() #endif // HAVE_MAGICK #ifdef HAVE_MAGICK /********************************************************** * draw_image() - copy a image onto the display **********************************************************/ static void draw_image( Widget w, Image *image, ExceptionInfo *except_ptr, unsigned offsetx, unsigned offsety) { int l; XColor my_colors[256]; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; unsigned image_row; unsigned image_col; unsigned scr_x, scr_y; // screen pixel plot positions //if (debug_level & 512) // fprintf(stderr,"Color depth is %i \n", (int)image->depth); /* if (image->colorspace != RGBColorspace) { TransformImageColorspace(image, RGBColorspace); //fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); //return; } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, except_ptr) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, except_ptr); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as // ImageMagick can read in all sorts of image files temp_pack = image->colormap[l]; //if (debug_level & 512) // fprintf(stderr,"Colormap color is %i %i %i \n", // temp_pack.red, temp_pack.green, temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as // Quantum's. Quantum is defined in // /usr/include/magick/image.h as either an unsigned short // or an unsigned char, depending on what "configure" // decided when ImageMagick was installed. We can determine // which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } //if (debug_level & 512) // fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, // my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } // loop over image pixel rows for (image_row = 0; image_row < image->rows; image_row++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = image_row + offsety; // loop over image pixel columns for (image_col = 0; image_col < image->columns; image_col++) { scr_x = image_col + offsetx; // now copy a pixel from the image to the screen l = image_col + (image_row * image->columns); if (image->storage_class == PseudoClass) { // Make matte transparent if (xastirColorsMatch(pixel_pack[l],image->matte_color)) { continue; } XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); } else { // Skip transparent pixels if (pixel_pack[l].opacity == TransparentOpacity) { continue; } // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); } // write the pixel from the map image to the // screen. (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,1,1); } // loop over map pixel columns } // loop over map pixel rows return; } // end draw_image() /********************************************************** * draw_OSM_image() - copy map image to display **********************************************************/ static void draw_OSM_image( Widget w, Image *image, ExceptionInfo *except_ptr, tiepoint *tpNW, tiepoint *tpSE, int osm_zl) { int l; XColor my_colors[256]; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; long map_image_row; long map_image_col; long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; int map_seen = 0; int map_act; int map_done; long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions //if (debug_level & 512) // fprintf(stderr,"Color depth is %i \n", (int)image->depth); /* if (image->colorspace != RGBColorspace) { TransformImageColorspace(image, RGBColorspace); //fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); //return; } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, except_ptr) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, except_ptr); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as // ImageMagick can read in all sorts of image files temp_pack = image->colormap[l]; //if (debug_level & 512) // fprintf(stderr,"Colormap color is %i %i %i \n", // temp_pack.red, temp_pack.green, temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as // Quantum's. Quantum is defined in // /usr/include/magick/image.h as either an unsigned short // or an unsigned char, depending on what "configure" // decided when ImageMagick was installed. We can determine // which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { //if (debug_level & 512) // fprintf(stderr,"Color quantum is [0..65535]\n"); my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { //if (debug_level & 512) // fprintf(stderr,"Color quantum is [0..255]\n"); my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } //if (debug_level & 512) // fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, // my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our image were calculated and stored * above as tiepoints using OSM units (pixels/circle). They are: * * left edge of map = tp[0].x_long * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ scr_dx = 1; scr_dy = 1; // calculate map pixel range in y direction that falls into screen area map_y_min = map_y_max = 0l; for (map_image_row = 0; map_image_row < (long)image->rows; map_image_row++) { scr_y = (pixelLat2xastirLat(map_image_row + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y; if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_image_row; // update last map pixel in y } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_image_row; // update first map pixel in y } } // Calculate the position of the map image relative to the screen map_x_min = map_x_max = 0l; for (map_image_col = 0; map_image_col < (long)image->columns; map_image_col++) { scr_x = (pixelLon2xastirLon(map_image_col + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x; if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_image_col; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_image_col; // update first map pixel in x } } scr_yp = -1; map_done = 0; map_act = 0; map_seen = 0; // loop over map pixel rows for (map_image_row = map_y_min; (map_image_row <= map_y_max); map_image_row++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = (pixelLat2xastirLat(map_image_row + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y; // image rows do not match 1:1 with screen rows due to Mercator // scaling, so scr_dy will be passed to XFillRectangle to // handle that issue. // scr_dy is in rows and must be a minimum of 1 row. scr_dy = (( pixelLat2xastirLat(map_image_row + 1 + tpNW->y_lat, osm_zl) - NW_corner_latitude) / scale_y) - scr_y; if (scr_dy < 1) { scr_dy = 1; } if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y scr_xp = -1; // loop over map pixel columns map_act = 0; for (map_image_col = map_x_min; map_image_col <= map_x_max; map_image_col++) { scr_x = ( pixelLon2xastirLon(map_image_col + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x; // handle the case when here the horizontal resolution // of the image is less than the horizontal resolution // displayed. scr_dx is passed to XFillRectangle() below // and must be at least 1 column. scr_dx = ( (pixelLon2xastirLon(map_image_col + 1 + tpNW->x_long, osm_zl) - NW_corner_longitude) / scale_x) - scr_x; if (scr_dx < 1) { scr_dx = 1; } if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x // check map boundaries in y direction if (map_image_row >= 0 && map_image_row <= tpSE->img_y) { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // now copy a pixel from the map image to the screen l = map_image_col + map_image_row * image->columns; if (image->storage_class == PseudoClass) { // Make matte transparent by skipping pixels if (xastirColorsMatch(pixel_pack[l],image->matte_color)) { continue; } XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); } else { // Skip transparent pixels and make matte // colored pixels transparent (by skipping) if ((pixel_pack[l].opacity == TransparentOpacity) || (xastirColorsMatch(pixel_pack[l], image->matte_color))) { continue; } // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); } // write the pixel from the map image to the // screen. Stretch to a rectangle as needed // specified by scr_dx and scr_dy. (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } // check map boundaries in y direction } // don't do a screen pixel twice (in the same row) } // loop over map pixel columns if (map_seen && !map_act) { map_done = 1; } (void)map_done; // map_done is never used, but this takes away the compile warning. } // don't do a screen row twice. } // loop over map pixel rows } // end draw_OSM_image() /********************************************************** * draw_OSM_tiles() - retrieve enough map tiles to fill the display **********************************************************/ // MaxTextExtent is an ImageMagick/GraphicMagick constant #define MAX_TMPSTRING MaxTextExtent void draw_OSM_tiles (Widget w, char *filenm, // this is the name of the xastir map file int destination_pixmap, char *server_url, // if specified in xastir map file char *tileCacheDir, // if specified in xastir map file char *mapName, // if specified in xastir map file char *tileExt) // if specified in xastir map file { char serverURL[MAX_FILENAME]; char tileRootDir[MAX_FILENAME]; char map_it[MAX_FILENAME]; char short_filenm[MAX_FILENAME]; int osm_zl; tileArea_t tiles; coord_t corner; tiepoint NWcorner; tiepoint SEcorner; unsigned long tilex, tiley; unsigned long tileCnt = 0; unsigned long numTiles; int interrupted = 0; ExceptionInfo exception; Image *canvas = NULL; Image *tile = NULL; ImageInfo *canvas_info = NULL; ImageInfo *tile_info = NULL; unsigned int row, col; unsigned int offset_x, offset_y; char tmpString[MAX_TMPSTRING]; char temp_file_path[MAX_VALUE]; // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), // Indexing %s short_filenm); statusline(map_it,0); // Indexing return; // Done indexing this file } if (tileCacheDir[0] != '\0') { if (tileCacheDir[0] == '/') { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", tileCacheDir); } else { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", get_user_base_dir(tileCacheDir, temp_file_path, sizeof(temp_file_path))); } } else { xastir_snprintf(tileRootDir, sizeof(tileRootDir), "%s", get_user_base_dir("OSMtiles", temp_file_path, sizeof(temp_file_path))); } if (mapName[0] != '\0') { xastir_snprintf(tmpString, sizeof(tmpString), "/%s", mapName); strncat(tileRootDir, tmpString, sizeof(tileRootDir) - 1 - strlen(tileRootDir)); } if (server_url[0] != '\0') { xastir_snprintf(serverURL, sizeof(serverURL), "%s", server_url); } else { xastir_snprintf(serverURL, sizeof(serverURL), "%s", "http://tile.openstreetmap.org"); } if (server_url[strlen(serverURL) - 1] == '/') { serverURL[strlen(serverURL) - 1] = '\0'; } // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); GetExceptionInfo(&exception); if (debug_level & 512) { unsigned long lat, lon; (void)convert_to_xastir_coordinates(&lon, &lat, f_NW_corner_longitude, f_NW_corner_latitude); fprintf(stderr, "NW_corner_longitude = %f, %ld, %ld\n", f_NW_corner_longitude, NW_corner_longitude, lon); fprintf(stderr, "NW_corner_latitude = %f, %ld, %ld\n", f_NW_corner_latitude, NW_corner_latitude, lat); (void)convert_to_xastir_coordinates(&lon, &lat, f_SE_corner_longitude, f_SE_corner_latitude); fprintf(stderr, "SE_corner_longitude = %f, %ld, %ld\n", f_SE_corner_longitude, SE_corner_longitude, lon); fprintf(stderr, "SE_corner_latitude = %f, %ld, %ld\n", f_SE_corner_latitude, SE_corner_latitude, lat); } osm_zl = osm_zoom_level(scale_x); calcTileArea(f_NW_corner_longitude, f_NW_corner_latitude, f_SE_corner_longitude, f_SE_corner_latitude, osm_zl, &tiles); xastir_snprintf(map_it, sizeof(map_it), "%s", langcode ("BBARSTA050")); // Downloading tiles... statusline(map_it,0); XmUpdateDisplay(text); // make sure all the map directories exist mkOSMmapDirs(tileRootDir, tiles.startx, tiles.endx, osm_zl); // Check to see how many tiles need to be downloaded // A simple calculation doesn't work well here because some // (possibly all) of the tiles may exist in the cache. numTiles = tilesMissing(tiles.startx, tiles.endx, tiles.starty, tiles.endy, osm_zl, tileRootDir, tileExt[0] != '\0' ? tileExt : "png"); // get the tiles tileCnt = 1; for (tilex = tiles.startx; tilex <= tiles.endx; tilex++) { for (tiley = tiles.starty; tiley <= tiles.endy; tiley++) { if ((numTiles > 0) & (tileCnt <= numTiles)) { xastir_snprintf(map_it, sizeof(map_it), langcode("BBARSTA051"), tileCnt, numTiles); // Downloading tile %ls of %ls statusline(map_it,0); XmUpdateDisplay(text); } DLM_queue_tile(serverURL, tilex, tiley, osm_zl, tileRootDir, tileExt[0] != '\0' ? tileExt : "png"); } } // if the Download Manager is not using threaded (background) mode, // we need this to actually do the downloads. // In threaded mode, it does nothing DLM_do_transfers(); if (interrupt_drawing_now) { interrupted = 1; } if (interrupted != 1) { // calculate tie points NWcorner.img_x = 0; NWcorner.img_y = 0; NWcorner.x_long = tiles.startx * 256; NWcorner.y_lat = tiles.starty * 256; if (debug_level & 512) { fprintf(stderr, "scale = %ld, zoom = %d\n", scale_x, osm_zl); fprintf(stderr, "NW corner:\n"); fprintf(stderr, " img_x = %d, img_y = %d\n", NWcorner.img_x, NWcorner.img_y); fprintf(stderr, " x_long = %ld, y_lat = %ld\n", NWcorner.x_long, NWcorner.y_lat); fprintf(stderr, "req. lon = %f, lat = %f\n", f_NW_corner_longitude, f_NW_corner_latitude); tile2coord(tiles.startx, tiles.starty, osm_zl, &corner); fprintf(stderr, "ret. lon = %f, lat = %f\n", corner.lon, corner.lat); fprintf(stderr, "tile x = %li, y = %li\n", tiles.startx, tiles.starty); } // The NW corner of the next tile is the SE corner of the last tile // we fetched. So add one to the end tile numbers before calculating // the coordinates. SEcorner.img_x = (256 * ((tiles.endx + 1) - tiles.startx)) - 1; SEcorner.img_y = (256 * ((tiles.endy + 1) - tiles.starty)) - 1; SEcorner.x_long = (tiles.endx + 1) * 256; SEcorner.y_lat = (tiles.endy + 1) * 256; if (debug_level & 512) { fprintf(stderr, "SE corner:\n"); fprintf(stderr, " img_x = %d, img_y = %d\n", SEcorner.img_x, SEcorner.img_y); fprintf(stderr, " x_long = %ld, y_lat = %ld\n", SEcorner.x_long, SEcorner.y_lat); fprintf(stderr, "req. lon = %f, lat = %f\n", f_SE_corner_longitude, f_SE_corner_latitude); tile2coord(tiles.endx + 1, tiles.endy + 1, osm_zl, &corner); fprintf(stderr, "ret. lon = %f, lat = %f\n", corner.lon, corner.lat); fprintf(stderr, "tile x = %li, y = %li\n", tiles.endx, tiles.endy); } /* * Create a canvas upon which the tiles will be composited. */ canvas_info=CloneImageInfo((ImageInfo *)NULL); // Set canvas dimensions in pixels xastir_snprintf(tmpString, sizeof(tmpString), "%lix%li", ((tiles.endx + 1) - tiles.startx) * 256, ((tiles.endy + 1) - tiles.starty) * 256); (void)CloneString(&canvas_info->size, tmpString); /* * A file name based on a color creates an image filled * with that color. The matte color will be treated as * transparent when the completed OSM map gets copied to the X * display. */ xastir_snprintf(canvas_info->filename, sizeof(canvas_info->filename), "%s", MATTE_COLOR_STRING); canvas = ReadImage(canvas_info, &exception); if (exception.severity != UndefinedException) { CatchException(&exception); fprintf(stderr, "Could not allocate canvas to hold tiles.\n"); if (canvas_info != NULL) { DestroyImageInfo(canvas_info); } return; } // Make sure that the canvas is an image type that uses the // opacity channel for compositing. SetImageType(canvas, PaletteMatteType); // Fill the image with an opaque color. Ultimately pixels that // are this color will be skipped when the image is written to // the screen. canvas->background_color.red = MATTE_RED; canvas->background_color.green = MATTE_GREEN; canvas->background_color.blue = MATTE_BLUE; canvas->background_color.opacity = MATTE_OPACITY; #if defined(HAVE_GRAPHICSMAGICK) SetImage(canvas, MATTE_OPACITY); #else SetImageBackgroundColor(canvas); SetImageOpacity(canvas, MATTE_OPACITY); #endif xastir_snprintf(map_it, sizeof(map_it), "%s", langcode ("BBARSTA049")); // Reading tiles... statusline(map_it,0); XmUpdateDisplay(text); tile_info = CloneImageInfo((ImageInfo *)NULL); // Read the tile and composite them onto the canvas for (col = tiles.starty, offset_y = 0; col <= tiles.endy; col++, offset_y += 256) { for (row = tiles.startx, offset_x = 0; row <= tiles.endx; row++, offset_x += 256) { xastir_snprintf(tmpString, sizeof(tmpString), "%s/%d/%d/%d.%s", tileRootDir, osm_zl, row, col, tileExt[0] != '\0' ? tileExt : "png"); strncpy(tile_info->filename, tmpString, MaxTextExtent); tile = ReadImage(tile_info,&exception); if (exception.severity != UndefinedException) { //fprintf(stderr,"Exception severity:%d\n", exception.severity); if (exception.severity==FileOpenError) { //fprintf(stderr, "%s NOT available\n", tile_info->filename); #if !defined(HAVE_GRAPHICSMAGICK) ClearMagickException(&exception); #endif } else { xastir_snprintf(tmpString, sizeof(tmpString), "%s/%d/%d/%d.%s", tileRootDir, osm_zl, row, col, tileExt[0] != '\0' ? tileExt : "png"); if (debug_level & 512) { fprintf(stderr, "%s NOT removed.\n", tmpString); } else { fprintf(stderr, "Removing %s\n", tmpString); unlink(tmpString); } CatchException(&exception); } // clear exception so next iteration doesn't fail GetExceptionInfo(&exception); // replace the missing tile with a place holder //(void)strcpy(tile_info->filename, "xc:red"); //tile = ReadImage(tile_info, &exception); } if (tile) { (void)CompositeImage(canvas, OverCompositeOp, tile, offset_x, offset_y); DestroyImage(tile); } } } // Set the matte color for use in transparentency testing canvas->matte_color.red = MATTE_RED; canvas->matte_color.green = MATTE_GREEN; canvas->matte_color.blue = MATTE_BLUE; if (debug_level & 512) { #if defined(HAVE_GRAPHICSMAGICK) DescribeImage(canvas, stderr, 0); #else IdentifyImage(canvas, stderr, 0); #endif WriteImages(canvas_info, canvas, "/tmp/xastirOSMTiledMap.png", &exception); } draw_OSM_image(w, canvas, &exception, &NWcorner, &SEcorner, osm_zl); // Display the OpenStreetMap attribution // Just reuse the tile structure rather than creating another. xastir_snprintf(tmpString, sizeof(tmpString), "%s/CC_OpenStreetMap.png", get_data_base_dir("maps")); strncpy(tile_info->filename, tmpString, MaxTextExtent); tile = ReadImage(tile_info,&exception); if (exception.severity != UndefinedException) { CatchException(&exception); } else { draw_image(w, tile, &exception, 4, 4); DestroyImage(tile); } } else { // map draw was interrupted // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } /* * Release resources */ if (tile_info != NULL) { DestroyImageInfo(tile_info); } if (canvas_info != NULL) { DestroyImageInfo(canvas_info); } if (canvas != NULL) { DestroyImage(canvas); } DestroyExceptionInfo(&exception); return; } // draw_OSM_tiles() /********************************************************** * draw_OSM_map() - retrieve an image that is the size of the display **********************************************************/ void draw_OSM_map (Widget w, char *filenm, int destination_pixmap, char *url, char *style, int UNUSED(nocache) ) // For future implementation of a "refresh cached map" option { char file[MAX_FILENAME]; // Complete path/name of image file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of image file char fileimg[MAX_FILENAME]; // Ascii name of image file, read from GEO file char OSMtmp[MAX_FILENAME*2]; // Used for putting together the OSMmap query tiepoint tp[2]; // Calibration points for map char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; double left, right, top, bottom; double lat_center = 0; double long_center = 0; char map_it[MAX_FILENAME]; char tmpstr[1001]; int osm_zl = 18; // OSM zoom level, at 18, the whole // world fits in one 256x256 tile. unsigned map_image_width; // Image width unsigned map_image_height; // Image height // TODO: put the max_image_* limits in the .geo/.osm file because it could change on a by-server // basis and the server URL can be specified in the .geo/.osm file. unsigned max_image_width = 2000; // This value is for the default server unsigned max_image_height = 2000; // This value is for the default server // initialize this local_filename[0]='\0'; // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... XmUpdateDisplay(text); // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // calculate the OSM zoom level (osm_zl) that is nearest the xastir scale osm_zl = osm_zoom_level(scale_x); // Calculate the image size to request. The size will be saved as tiepoints // for the top-left and bottom-right of the image. tp[0].x_long = xastirLon2pixelLon(NW_corner_longitude, osm_zl); // OSM pixels tp[1].x_long = xastirLon2pixelLon(SE_corner_longitude, osm_zl); // OSM pixels tp[0].y_lat = xastirLat2pixelLat(NW_corner_latitude, osm_zl); // OSM pixels tp[1].y_lat = xastirLat2pixelLat(SE_corner_latitude, osm_zl); // OSM pixels map_image_height = tp[1].y_lat - tp[0].y_lat; map_image_width = tp[1].x_long - tp[0].x_long; // Limit dimensions to the max the server will allow. if (map_image_width > max_image_width) { int tmp = ((map_image_width - map_image_height) / 2) + 1; tp[0].x_long += tmp; tp[1].x_long -= tmp; map_image_width = tp[1].x_long - tp[0].x_long; } if (map_image_height > max_image_height) { int tmp = ((map_image_height - max_image_height) / 2) + 1; tp[0].y_lat += tmp; tp[1].y_lat -= tmp; map_image_height = tp[1].y_lat - tp[0].y_lat; } // Size and coordinates for the tiepoints in pixels tp[0].img_x = 0; tp[0].img_y = 0; tp[1].img_x = map_image_width - 1; tp[1].img_y = map_image_height - 1; // calculate the center coordinates for the image request left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates, degrees top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates, degrees right = (double)((SE_corner_longitude - 64800000l)/360000.0); //Lat/long Coordinates, degrees bottom = (double)(-((SE_corner_latitude - 32400000l)/360000.0));//Lat/long Coordinates, degrees long_center = (left + right)/2.0l; // degrees // The vertical center of the image must be calculated from the OSM image size to // compensate for latitude scaling (Mercator). This is particularly important for small image/screen // sizes and may not be apparent on large displays. lat_center = pixelLat2Lat((map_image_height / 2) + tp[0].y_lat, osm_zl); /* * Query format to the StaticMap * See: http://ojw.dev.openstreetmap.org/StaticMap/?mode=API& * * http://ojw.dev.openstreetmap.org/StaticMap/?lat=LL.LLLLLL&lon=-LLL.LLLLL&z=15& \ * w=WWW&h=HHH&layer=osmarender&mode=Export&att=none&show=1 */ if (url[0] != '\0') { xastir_snprintf(OSMtmp, sizeof(OSMtmp), "%s", url); } else { xastir_snprintf(OSMtmp, sizeof(OSMtmp), "http://ojw.dev.openstreetmap.org/StaticMap/"); } //xastir_snprintf(tmpstr, sizeof(tmpstr), "?mode=Export&att=text&show=1&"); xastir_snprintf(tmpstr, sizeof(tmpstr), "?mode=Export&show=1&"); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); if (style[0] != '\0') { xastir_snprintf(tmpstr, sizeof(tmpstr), "%s", style); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); } else { xastir_snprintf(tmpstr, sizeof(tmpstr), "layer=osmarender&"); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); } xastir_snprintf(tmpstr, sizeof(tmpstr), "&lat=%f\046lon=%f\046", lat_center, long_center); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "w=%i\046h=%i\046", map_image_width, map_image_height); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "z=%d", osm_zl); strncat (OSMtmp, tmpstr, sizeof(OSMtmp) - 1 - strlen(OSMtmp)); memcpy(fileimg, OSMtmp, sizeof(fileimg)); fileimg[sizeof(fileimg)-1] = '\0'; // Terminate string if (debug_level & 512) { fprintf(stderr,"left side is %f\n", left); fprintf(stderr,"right side is %f\n", right); fprintf(stderr,"top is %f\n", top); fprintf(stderr,"bottom is %f\n", bottom); fprintf(stderr,"lat center is %f\n", lat_center); fprintf(stderr,"long center is %f\n", long_center); fprintf(stderr,"screen width is %li\n", screen_width); fprintf(stderr,"screen height is %li\n", screen_height); fprintf(stderr,"OSM image width is %i\n", map_image_width); fprintf(stderr,"OSM image height is %i\n", map_image_height); fprintf(stderr,"scale_y = %li\n", scale_y); fprintf(stderr,"scale_x = %li\n", scale_x); fprintf(stderr,"OSM zoom level = %i\n", osm_zl); fprintf(stderr,"fileimg is %s\n", fileimg); fprintf(stderr,"ftp or http file: %s\n", fileimg); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } get_OSM_local_file(local_filename,fileimg); // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 512) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { if (debug_level & 512) { fprintf(stderr,"File could not be read\n"); } #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete unreadable map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } else if ( (image->columns != map_image_width) || (image->rows != map_image_height)) { fprintf(stderr, "Server returned an image size different than requested!\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 512) { fprintf(stderr,"Image: %s\n", file); fprintf(stderr,"Image size %d %d\n", map_image_width, map_image_height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"image matte is %i\n", image->matte); } // debug_level & 512 draw_OSM_image(w, image, &exception, &(tp[0]), &(tp[1]), osm_zl); DestroyImage(image); // Display the OpenStreetMap attribution xastir_snprintf(OSMtmp, sizeof(OSMtmp), "%s/CC_OpenStreetMap.png", get_data_base_dir("maps")); strncpy(image_info->filename, OSMtmp, MaxTextExtent); image = ReadImage(image_info,&exception); if (exception.severity != UndefinedException) { CatchException(&exception); } else { draw_image(w, image, &exception, 4, 4); } // Clean up if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); } // end draw_OSM_map() #endif //HAVE_MAGICK ///////////////////////////////////////////// End of OpenStreetMap code /////////////////////////////////////// Xastir-Release-2.2.4/src/map_OSM.h0000664000175000017500000000361415151324131015560 0ustar hibbyhibby/* * * Copyright (C) 2000-2026 The Xastir Group * * This file was contributed by Jerry Dunmire, KA6HLD. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * */ #ifndef OSM_H #define OSM_H #include // for KeySym #define MAX_OSMSTYLE 1000 // max characters in the a OSM style argument #define MAX_OSM_URL 1000 // max characters for a OSM URL #define MAX_OSMEXT 10 // max characters for a tilename extension void adj_to_OSM_level( long *new_scale_x, long *new_scale_y); void draw_OSM_map(Widget w, char *filenm, int destination_pixmap, char *url, char *style, int nocache); void draw_OSM_tiles(Widget w, char *filenm, int destination_pixmap, char *server_url, char *tileCacheDir, char *mapName, char *tileExt); unsigned int osm_zoom_level(long scale_x); void init_OSM_values(void); int OSM_optimize_key(KeySym key); void set_OSM_optimize_key(KeySym key); int OSM_report_scale_key(KeySym key); void set_OSM_report_scale_key(KeySym key); #endif //OSM_H Xastir-Release-2.2.4/src/map_WMS.c0000664000175000017500000010205615151324131015563 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #include "map_cache.h" #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" /********************************************************** * draw_WMS_map() **********************************************************/ #ifdef HAVE_MAGICK void draw_WMS_map (Widget w, char *filenm, int destination_pixmap, char *URL, transparent_color_record *c_trans_color_head, int nocache) // If non-zero, don't use cached version { char file[MAX_FILENAME]; // Complete path/name of image file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of image file char fileimg[MAX_FILENAME]; // Ascii name of image file, read from GEO file char WMStmp[MAX_FILENAME*2]; // Used for putting together the WMS map query int width, height; tiepoint tp[2]; // Calibration points for map, read in from .geo file long map_c_T, map_c_L; // map delta NW edge coordinates, DNN: these should be signed long tp_c_dx, tp_c_dy; // tiepoint coordinate differences unsigned long c_x_min, c_y_min;// top left coordinates of map inside screen // unsigned long c_y_max; // bottom right coordinates of map inside screen double c_x; // Xastir coordinates 1/100 sec, 0 = 180W double c_y; // Xastir coordinates 1/100 sec, 0 = 90N long map_y_0; // map pixel pointer prior to TM adjustment long map_x, map_y; // map pixel pointers, DNN: this was a float, chg to long long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; // // long map_x_ctr; // half map width in pixel // long map_y_ctr; // half map height in pixel int map_seen = 0; int map_act; // int map_done; // long map_c_yc; // map center, vert coordinate // long map_c_xc; // map center, hor coordinate double map_c_dx, map_c_dy; // map coordinates increment (pixel width) double c_dx; // adjusted map pixel width long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions // long scr_x_mc; // map center in screen units // long scr_c_xr; // long scale_xa; // adjusted for topo maps // double scale_x_nm; // nm per Xastir coordinate unit // long scale_x0; // at widest map area char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; int l; XColor my_colors[256]; int trans_skip = 0; // skip transparent pixel double left, right, top, bottom, map_width, map_height; double lat_center = 0; double long_center = 0; char map_it[MAX_FILENAME]; char tmpstr[100]; int geo_image_width; // Image width from GEO file int geo_image_height; // Image height from GEO file time_t query_start_time, query_end_time; #ifdef USE_MAP_CACHE int map_cache_return; char * cache_file_id; #endif // USE_MAP_CACHE char temp_file_path[MAX_VALUE]; if (debug_level & 512) { if (nocache) { fprintf(stderr,"draw_WMS_map: NOCACHE selected\n"); } else { fprintf(stderr,"draw_WMS_map: CACHING if enabled\n"); } } // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // Tiepoint for upper left screen corner // tp[0].img_x = 0; // Pixel Coordinates tp[0].img_y = 0; // Pixel Coordinates tp[0].x_long = NW_corner_longitude; // Xastir Coordinates tp[0].y_lat = NW_corner_latitude; // Xastir Coordinates // Tiepoint for lower right screen corner // // Here we must use scale_x for both directions because we have // square pixels returned by the WMS server. // Really what we want to do here is to change our bounding box for // our request to fit square pixels, using scale_x for both // dimensions, and to change our tiepoints to match. WMS servers // currently feed us back square pixels but the spec says that the // servers should be capable of sending back rectangular pixels, so // the images we get back may change if we don't request square // pixels each time. // // TODO: Change our imagesize, bounding rectangle requested, and // tiepoints to fit square pixels and to use scale_x for both // dimensions. // // Actually, looking at the changes that were made, it looks like we // _are_ using square pixels and requesting a bounding box based on // scale_x for both dimensions, so we might be good to go as-is. // tp[1].img_x = screen_width - 1; // Pixel Coordinates tp[1].img_y = screen_height - 1; // Pixel Coordinates tp[1].x_long = SE_corner_longitude; // Xastir Coordinates // Modified to use same scale (scale_x) for both dimensions, square // pixels. Don't use SE_corner_latitude here as it uses scale_y! // tp[1].y_lat = NW_corner_latitude + ((screen_height) * scale_y); // Xastir Coordinates tp[1].y_lat = NW_corner_latitude + ((screen_height) * scale_x); // Xastir Coordinates // Again, use scale_x for both directions due to the square // pixels returned from the WMS server. // left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates right = (double)((SE_corner_longitude - 64800000l)/360000.0);//Lat/long Coordinates // Modified to use same scale (scale_x) for both dimensions, square // pixels. Don't use SE_corner_latitude here as it uses scale_y! // bottom = (double)(-(((NW_corner_latitude + ((screen_height) * scale_y) ) - 32400000l)/360000.0));//Lat/long Coordinates bottom = (double)(-(((NW_corner_latitude + ((screen_height) * scale_x) ) - 32400000l)/360000.0));//Lat/long Coordinates map_width = right - left; // Lat/long Coordinates map_height = top - bottom; // Lat/long Coordinates geo_image_width = screen_width; geo_image_height = screen_height; long_center = (left + right)/2.0l; lat_center = (top + bottom)/2.0l; // Example query for a WMS map server.... // xastir_snprintf(fileimg, sizeof(fileimg), // "\'http://mesonet.tamu.edu/cgi-bin/p-warn?SERVICE=WMS&VERSION=1.1.1&REQUEST=getmap&layers=radar&BBOX=-129.000,52.500,-111.000,42.500&HEIGHT=1000&WIDTH=1800&FORMAT=image/png\'"); // xastir_snprintf(WMStmp, sizeof(WMStmp), // "http://mesonet.tamu.edu/cgi-bin/p-warn?SERVICE=WMS&VERSION=1.1.1&REQUEST=getmap"); xastir_snprintf(WMStmp, sizeof(WMStmp), "%s", URL); strncat(WMStmp, "&REQUEST=getmap", sizeof(WMStmp) - 1 - strlen(WMStmp)); strncat(WMStmp, "&EXCEPTIONS=INIMAGE", sizeof(WMStmp) - 1 - strlen(WMStmp)); // This specifies a bounding box based on square pixels. xastir_snprintf(tmpstr, sizeof(tmpstr), "&BBOX=%08.5f,%07.5f,%08.5f,%07.5f", left, // Lower left bottom, // Lower left right, // Upper right top); // Upper right strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "&HEIGHT=%d", geo_image_height); strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); xastir_snprintf(tmpstr, sizeof(tmpstr), "&WIDTH=%d", geo_image_width); strncat (WMStmp, tmpstr, sizeof(WMStmp) - 1 - strlen(WMStmp)); // These should be specified in the .geo file instead of hard-coded: // // strncat(WMStmp, "&VERSION=1.0.0", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&FORMAT=image/png", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&TRANSPARENT=TRUE", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&BGCOLOR=0xffffff", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&BGCOLOR=0x000000", sizeof(WMStmp) - 1 - strlen(WMStmp)); // strncat(WMStmp, "&CRS=CRS:84", sizeof(WMStmp) - 1 - strlen(WMStmp)); memcpy(fileimg, WMStmp, sizeof(fileimg)); fileimg[sizeof(fileimg)-1] = '\0'; // Terminate string if (debug_level & 512) { fprintf(stderr,"left side is %f\n", left); fprintf(stderr,"right side is %f\n", right); fprintf(stderr,"top is %f\n", top); fprintf(stderr,"bottom is %f\n", bottom); fprintf(stderr,"lat center is %f\n", lat_center); fprintf(stderr,"long center is %f\n", long_center); fprintf(stderr,"screen width is %li\n", screen_width); fprintf(stderr,"screen height is %li\n", screen_height); fprintf(stderr,"map width is %f\n", map_width); fprintf(stderr,"map height is %f\n", map_height); fprintf(stderr,"fileimg is %s\n", fileimg); fprintf(stderr,"ftp or http file: %s\n", fileimg); } if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (nocache || map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } // Simulate a cache miss map_cache_return = 1; } else { // Else look for the file in the cache map_cache_return = map_cache_get(fileimg,local_filename); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: %d\n", map_cache_return); } // Don't use cached version if "nocache" is non-zero // if (nocache || map_cache_return != 0 ) { // Caching has not been requested or cached file not found. // We must snag the remote file via libcurl or wget. if (nocache) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); } else { cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, sizeof(local_filename), "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, "png"); free(cache_file_id); } #else // USE_MAP_CACHE xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "png"); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same name. // This avoids the problem of having an old map image here and // the code trying to display it when the download fails. unlink( local_filename ); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // For debugging the MagickError/MagickWarning segfaults. //system("cat /dev/null >/var/tmp/xastir_hacker_map.png"); #ifdef USE_MAP_CACHE // Cache this map only if nocache is zero if (!nocache) { map_cache_put(fileimg,local_filename); } } // end if is cached DHBROWN #endif // USE_MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 512) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { if (debug_level & 512) { fprintf(stderr,"File could not be read\n"); } #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 512) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } /* if (image->colorspace != RGBColorspace) { fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); if (image) DestroyImage(image); if (image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); return; } */ width = image->columns; height = image->rows; // Code to mute the image so it's not as bright. /* if (raster_map_intensity < 1.0) { char tempstr[30]; if (debug_level & 512) fprintf(stderr,"level=%s\n", tempstr); xastir_snprintf(tempstr, sizeof(tempstr), "%d, 100, 100", (int)(raster_map_intensity * 100.0)); ModulateImage(image, tempstr); } */ // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, &exception) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows, &exception); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { // Need to check how to do this for ANY image, as ImageMagick can read in all sorts // of image files temp_pack = image->colormap[l]; if (debug_level & 512) fprintf(stderr,"Colormap color is %i %i %i \n", (int)temp_pack.red, (int)temp_pack.green, (int)temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as Quantum's. Quantum // is defined in /usr/include/magick/image.h as either an unsigned short or an // unsigned char, depending on what "configure" decided when ImageMagick was installed. // We can determine which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/image.h { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red * raster_map_intensity; my_colors[l].green = temp_pack.green * raster_map_intensity; my_colors[l].blue = temp_pack.blue * raster_map_intensity; } else // QuantumDepth = 8 { if (debug_level & 512) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = (temp_pack.red * 256) * raster_map_intensity; my_colors[l].green = (temp_pack.green * 256) * raster_map_intensity; my_colors[l].blue = (temp_pack.blue * 256) * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (debug_level & 512) fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our map will soon be (after translating the * tiepoints to the corners if they're not already there): * * left edge of map = tp[0].x_long in Xastir format * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ map_c_L = tp[0].x_long - NW_corner_longitude; // map left coordinate map_c_T = tp[0].y_lat - NW_corner_latitude; // map top coordinate tp_c_dx = (long)(tp[1].x_long - tp[0].x_long);// Width between tiepoints tp_c_dy = (long)(tp[1].y_lat - tp[0].y_lat); // Height between tiepoints // Check for tiepoints being in wrong relation to one another if (tp_c_dx < 0) { tp_c_dx = -tp_c_dx; // New width between tiepoints } if (tp_c_dy < 0) { tp_c_dy = -tp_c_dy; // New height between tiepoints } // Calculate step size per pixel map_c_dx = ((double) tp_c_dx / abs(tp[1].img_x - tp[0].img_x)); map_c_dy = ((double) tp_c_dy / abs(tp[1].img_y - tp[0].img_y)); // Scaled screen step size for use with XFillRectangle below scr_dx = (int) (map_c_dx / scale_x) + 1; scr_dy = (int) (map_c_dy / scale_y) + 1; // calculate top left map corner from tiepoints if (tp[0].img_x != 0) { tp[0].x_long -= (tp[0].img_x * map_c_dx); // map left edge longitude map_c_L = tp[0].x_long - NW_corner_longitude; // delta ?? tp[0].img_x = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 x: %d\t%lu\n", tp[0].img_x, tp[0].x_long); } } if (tp[0].img_y != 0) { tp[0].y_lat -= (tp[0].img_y * map_c_dy); // map top edge latitude map_c_T = tp[0].y_lat - NW_corner_latitude; tp[0].img_y = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 y: %d\t%lu\n", tp[0].img_y, tp[0].y_lat); } } // calculate bottom right map corner from tiepoints // map size is geo_image_width / geo_image_height if (tp[1].img_x != (geo_image_width - 1) ) { tp[1].img_x = geo_image_width - 1; tp[1].x_long = tp[0].x_long + (tp[1].img_x * map_c_dx); // right if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 x: %d\t%lu\n", tp[1].img_x, tp[1].x_long); } } if (tp[1].img_y != (geo_image_height - 1) ) { tp[1].img_y = geo_image_height - 1; tp[1].y_lat = tp[0].y_lat + (tp[1].img_y * map_c_dy); // bottom if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 y: %d\t%lu\n", tp[1].img_y, tp[1].y_lat); } } if (debug_level & 512) { fprintf(stderr,"X tiepoint width: %ld\n", tp_c_dx); fprintf(stderr,"Y tiepoint width: %ld\n", tp_c_dy); fprintf(stderr,"Loading imagemap: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"Image size %d %d\n", width, height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"image matte is %i\n", image->matte); } // debug_level & 512 // draw the image from the file out to the map screen // Get the border values for the X and Y for loops used // for the XFillRectangle call later. // map_c_yc = (tp[0].y_lat + tp[1].y_lat) / 2; // vert center of map as reference // map_y_ctr = (long)(height / 2 +0.499); // scale_x0 = get_x_scale(0,map_c_yc,scale_y); // reference scaling at vert map center // map_c_xc = (tp[0].x_long + tp[1].x_long) / 2; // hor center of map as reference // map_x_ctr = (long)(width / 2 +0.499); // scr_x_mc = (map_c_xc - NW_corner_longitude) / scale_x; // screen coordinates of map center // calculate map pixel range in y direction that falls into screen area // c_y_max = 0ul; map_y_min = map_y_max = 0l; for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_y_0; // update last map pixel in y // c_y_max = (unsigned long)c_y;// bottom map inside screen coordinate } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_y_0; // update first map pixel in y } } c_y_min = (unsigned long)(tp[0].y_lat + map_y_min * map_c_dy); // top map inside screen coordinate map_x_min = map_x_max = 0l; for (map_x = 0, c_x = tp[0].x_long; map_x < (long)width; map_x++, c_x += map_c_dx) { scr_x = (c_x - NW_corner_longitude)/ scale_x; // current screen position if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_x; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_x; // update first map pixel in x } } c_x_min = (unsigned long)(tp[0].x_long + map_x_min * map_c_dx); // left map inside screen coordinate scr_yp = -1; // scr_c_xr = SE_corner_longitude; c_dx = map_c_dx; // map pixel width // scale_xa = scale_x0; // the compiler likes it ;-) // map_done = 0; map_act = 0; map_seen = 0; scr_y = screen_height - 1; // loop over map pixel rows for (map_y_0 = map_y_min, c_y = (double)c_y_min; (map_y_0 <= map_y_max); map_y_0++, c_y += map_c_dy) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } scr_y = (c_y - NW_corner_latitude) / scale_y; if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y scr_xp = -1; // loop over map pixel columns map_act = 0; // scale_x_nm = calc_dscale_x(0,(long)c_y) / 1852.0; // nm per Xastir coordinate for (map_x = map_x_min, c_x = (double)c_x_min; map_x <= map_x_max; map_x++, c_x += c_dx) { scr_x = (c_x - NW_corner_longitude) / scale_x; if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x map_y = map_y_0; if (map_y >= 0 && map_y <= tp[1].img_y) // check map boundaries in y direction { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // now copy a pixel from the map image to the screen l = map_x + map_y * image->columns; trans_skip = 1; // possibly transparent if (image->storage_class == PseudoClass) { if ( c_trans_color_head && check_trans(my_colors[(int)index_pack[l]],c_trans_color_head)) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); trans_skip = 0; // draw it } } else { // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); if ( c_trans_color_head && check_trans(my_colors[0],c_trans_color_head)) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); trans_skip = 0; // draw it } } // Skip drawing if a transparent pixel if (!trans_skip) { (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } } // check map boundaries in y direction } } // loop over map pixel columns if (map_seen && !map_act) { // map_done = 1; } } } // loop over map pixel rows if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); } #endif //HAVE_MAGICK Xastir-Release-2.2.4/src/map_cache.c0000664000175000017500000006561715151324131016173 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ /* * The code in this file is used to cache maps downloaded * from tiger.census.gov, and to manage that cache. It was written * to use Berkeley DB version 4 or better. * * Dan Brown N8YSZ. * */ // Need this one before the #ifdef in order to get the definition of // USE_MAP_CACHE, if defined. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef USE_MAP_CACHE //#warning USE_MAP_CACHE Defined #include #include #include #include #include #include #include #include "snprintf.h" #include "xastir.h" #include "globals.h" #include "xa_config.h" #include "main.h" #include "maps.h" #include "map_cache.h" #include // Must be last include file #include "leak_detection.h" // This is used to temporarily disable fetching from the map cache. // Used for refreshing corrupted maps in the cache. int map_cache_fetch_disable = 0; // Used to disable map caching entirely if the header and dblib // versions don't match, in order to avoid segfaults when the map // caching is used. int map_cache_disabled = 0; // Here we do a run-time check to verify that the header file we // used to compile with is the same version as the shared library // we're currently linked with. To do otherwise often results in // segfaults. // void map_cache_init(void) { int warn_now = 0; if (strcmp( DB_VERSION_STRING, db_version(NULL,NULL,NULL) ) != 0) { fprintf(stderr, "\n\n***** WARNING *****\n"); fprintf(stderr, "Berkeley DB header files/shared library file do NOT match!\n"); fprintf(stderr, "Disabling use of the map cache.\n"); // Can't bring up a popup here 'cuz we don't have any GUI running // yet by this point. // popup_message_always(langcode("POPEM00034"),langcode("POPEM00046")); warn_now++; map_cache_disabled++; } if (debug_level & 5 || warn_now) { //fprintf(stderr, // "Berkeley DB Library Header File Version %d.%d.%d\n", // DB_VERSION_MAJOR, // DB_VERSION_MINOR, // DB_VERSION_PATCH); fprintf(stderr, " Header file: %s\n", DB_VERSION_STRING); fprintf(stderr, "Library file: %s\n", db_version(NULL,NULL,NULL) ); } if (warn_now) { fprintf(stderr, "***** WARNING *****\n"); } } // map_cache_put() // // Inputs: // // Outputs: // int map_cache_put( char * map_cache_url, char * map_cache_file ) { // Puts an entry into the url->filename database // Tracks space used in "CACHE_SPACE_USED" char mc_database_filename[MAX_FILENAME]; int mc_ret, mc_t_ret, mc_file_stat, mc_space_used ; DBT mc_key, mc_data ; DB *dbp; struct stat file_status; char mc_buf[128]; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } mc_space_used=0; xastir_snprintf(mc_database_filename, sizeof(mc_database_filename), "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); // check for reasonable filename // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // 1234567890123456789012345678901234567 mc_ret=strlen(map_cache_file); if ( mc_ret < 37 ) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_put: Unusable filename: %s. Skipping encaching\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } return (-1 * mc_ret); } // stat the file to see if we even need to bother if ((mc_file_stat=stat(map_cache_file, &file_status)) !=0) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_put: File Error: %s. Skipping encaching\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } return (mc_file_stat); } if ( debug_level & 512) { fprintf (stderr, "map_cache_put: file_status.st_size %d\n", (int) file_status.st_size); } // Create handle to db if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_put db_create:%s\n", db_strerror(mc_ret)); return(1); } // open the db #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); db_strerror(mc_ret); } #else if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); db_strerror(mc_ret); } #endif /** DB_VERSION Check **/ // Before we put something in we need to see if we got space // if mc_cache_size_limit // Setup for get memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data = "CACHE_SPACE_USED"; mc_key.size = sizeof("CACHE_SPACE_USED"); // check "CACHE_SPACE_USED" record in db // mc_ret is assigned here but not used. Commented it out for now. if (((/* mc_ret = */ dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) == 0) && ( mc_data.data != NULL ) ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } if (mc_data.data == NULL) { mc_space_used = 0; } else { mc_space_used = atoi( (char *)mc_data.data); } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: CACHE_SPACE_USED = %.2f mb\n", (mc_space_used/1024/1024.0)); } } else { if (mc_data.data == NULL) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: CACHE_SPACE_USED get returned null \n"); } } else { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: Unable to check CACHE_SPACE_USED: %s\n", db_strerror(mc_ret)); } } // for now let us assume this is the first map entry and we // just flag an error. Better procedure for later might be to // return(mc_ret) indicating a database error of some sort } // xastir_snprintf(map_cache_file, MAX_FILENAME, "%s",(char *)mc_data.data); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_space_used before = %d bytes file_status.st_size %d\n", mc_space_used, (int) file_status.st_size); } mc_space_used += (int) file_status.st_size; if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_space_used after = %d bytes \n", mc_space_used); } if ( mc_space_used > MAP_CACHE_SPACE_LIMIT) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: Warning cache space used: %.2f mb NOW OVER LIMIT: %.2f mb\n", (mc_space_used/1024/1024.0), (MAP_CACHE_SPACE_LIMIT/1024/1024.0)); } // Cache Cleanup // The warning is nice, but we should do something here // Needs LRU and or FIFO db structures } else { // else put cache_space_used // setup memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); // data mc_key.data = "CACHE_SPACE_USED"; mc_key.size = sizeof("CACHE_SPACE_USED"); xastir_snprintf(mc_buf, sizeof(mc_buf), "%d", mc_space_used); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_put: mc_buf: %s len %d\n", mc_buf,(int) sizeof(mc_buf)); } mc_data.data = mc_buf ; mc_data.size = sizeof(mc_buf); // put if ((mc_ret = dbp->put(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key stored.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put"); } // db_strerror(mc_ret); return(mc_ret); } } // Setup for put of data memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); // Real data at last mc_key.data = map_cache_url; mc_key.size = strlen(map_cache_url); mc_data.data = map_cache_file; mc_data.size = strlen(map_cache_file)+1; /* +1 includes \0 */ // do the actual put if ((mc_ret = dbp->put(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_put: %s: key stored.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put") ; } // db_strerror(mc_ret); return(mc_ret); } // Map now cached statusline(langcode("CACHE001"), 1); // close the db // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; db_strerror(mc_ret); } } /* end map_cache_put */ return (0) ; } // map_cache_get() // // Queries URL->Filename db // Calls map_cache_del to cleanup expired maps // // Inputs: // // Outputs: 0 if cached file is retrieved successfully // 1 if db can't be created // negative number if unusable filename or bad filestat // positive number if map has expired // return value from dbp->get if record not found // int map_cache_get( char * map_cache_url, char * map_cache_file ) { DBT mc_key, mc_data ; DB *dbp; int mc_ret, mc_t_ret, mc_file_stat ; char mc_database_filename[MAX_FILENAME]; struct stat file_status; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } set_dangerous("map_cache_get: xastir_snprintf 1"); xastir_snprintf(mc_database_filename, sizeof(mc_database_filename), // change to max_filename? "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); clear_dangerous(); set_dangerous("map_cache_get: db_create"); if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_get db_create:%s\n", db_strerror(mc_ret)); return(1); } clear_dangerous(); #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) set_dangerous("map_cache_get:dbp->open 1"); if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { ( debug_level & 512 ) ? dbp->err(dbp, mc_ret, "%s", mc_database_filename):0; // db_strerror(mc_ret); } clear_dangerous(); #else set_dangerous("map_cache_get:dbp->open 2"); if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { if (debug_level & 512) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); // db_strerror(mc_ret); } } clear_dangerous(); #endif /** DB_VERSION Check **/ memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data=map_cache_url ; mc_key.size=strlen(map_cache_url); statusline("Checking Map Cache",1); if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Checking Map Cache\n"); } set_dangerous("map_cache_get:dbp->get"); if ((mc_ret = dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } set_dangerous("map_cache_get: xastir_snprintf 2"); xastir_snprintf(map_cache_file, MAX_FILENAME, "%s",(char *)mc_data.data); clear_dangerous(); // check for reasonable filename // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // 1234567890123456789012345678901234567 mc_ret=strlen(map_cache_file); if ( mc_ret < 37 ) { if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Unusable filename: %s. Deleting key %s from cache\n", (map_cache_file == NULL) ? "(null)" : map_cache_file, (map_cache_url == NULL) ? "(null)" : map_cache_url); } set_dangerous("map_cache_get: map_cache_del 1"); map_cache_del(map_cache_url); if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (-1 * mc_ret); } // check age of file - based on name - delete if too old if (debug_level & 512 ) { fprintf(stderr, "map_cache_get: Checking age\n"); } set_dangerous("map_cache_get: map_cache_expired"); if ( (mc_ret=map_cache_expired(map_cache_file, (MC_MAX_FILE_AGE)))) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: deleting expired key: %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } set_dangerous("map_cache_get: map_cache_del 2"); map_cache_del(map_cache_url); if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (mc_ret); } clear_dangerous(); // check if the file exists if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: checking for existence of map_cache_file: %s.\n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } mc_file_stat=stat(map_cache_file, &file_status); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: map_cache_file %s stat returned:%d.\n", (map_cache_file == NULL) ? "(null)" : map_cache_file, mc_file_stat); } if ( mc_file_stat == -1 ) { // if ( debug_level & 512 ) { fprintf(stderr,"map_cache_get: attempting to delete map_cache_file %s \n", (map_cache_file == NULL) ? "(null)" : map_cache_file); } set_dangerous("map_cache_get: dbp->del"); if ((mc_ret = dbp->del(dbp, NULL, &mc_key, 0)) == 0) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: File stat failed %s: key was deleted.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } } else { if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); } clear_dangerous(); set_dangerous("map_cache_get: dbp->close 1"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); // db_strerror(mc_ret); // Return the file stat if there was a file problem return (mc_file_stat); } else { set_dangerous("map_cache_get: dbp->close 2"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); // If we made it here all is good // Loading Cached Map statusline(langcode("CACHE002"), 1); return (0); } } else { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_get: Get failed. Key was: %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } if (debug_level & 512) { dbp->err(dbp, mc_ret, "DB->get"); // db_strerror(mc_ret); } // there was some problem getting things from the db // return the return from the get // Map not found in cache... statusline(langcode("CACHE003"), 1); set_dangerous("map_cache_get: dbp->close 3"); // Only try the close if we have a valid handle if (dbp != NULL) { if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { mc_ret = mc_t_ret; // db_strerror(mc_ret); } } clear_dangerous(); return (mc_ret); } clear_dangerous(); /** end map_cache_get **/ } // map_cache_del() // // Delete entry from the cache and unlink associated file from disk // // Inputs: Map URL // // Outputs: 0 if successful deleting the item from the cache // 1 if error in creating/opening DB file // mc_ret if unlink failed or if error in DB->del // int map_cache_del( char * map_cache_url ) { DBT mc_key, mc_data, mc_size_key, mc_size_data ; DB *dbp; int mc_ret, mc_t_ret, mc_file_stat, mc_space_used; char mc_database_filename[MAX_FILENAME]; char mc_delete_file[MAX_FILENAME]; struct stat file_status; char mc_buf[128]; char temp_file_path[MAX_VALUE]; if (map_cache_disabled) { return(1); } mc_space_used = 0 ; xastir_snprintf(mc_database_filename, MAX_FILENAME, "%s/map_cache.db", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path))); if ((mc_ret = db_create(&dbp, NULL, 0)) != 0) { fprintf(stderr, "map_cache_del db_create:%s\n", db_strerror(mc_ret)); return(1); } #if (DB_VERSION_MAJOR<4) /** DB_VERSION Check **/ #error DB_VERSION_MAJOR < 4 #elif (DB_VERSION_MAJOR==4 && DB_VERSION_MINOR<=0 ) if ((mc_ret = dbp->open(dbp, mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { ( debug_level & 512 ) ? dbp->err(dbp, mc_ret, "%s", mc_database_filename):0; // db_strerror(mc_ret); return(1); } #else if ((mc_ret = dbp->open(dbp, NULL,mc_database_filename, NULL, DB_CREATE, DB_BTREE, 0664)) != 0) { if (debug_level & 512) { dbp->err(dbp, mc_ret, "%s", mc_database_filename); // db_strerror(mc_ret); } return(1); } #endif /** DB_VERSION Check **/ memset(&mc_key, 0, sizeof(mc_key)); memset(&mc_data, 0, sizeof(mc_data)); mc_key.data=map_cache_url ; mc_key.size=strlen(map_cache_url); // Try to get the key from the cache if ((mc_ret = dbp->get(dbp, NULL, &mc_key, &mc_data, 0)) != 0) { // Couldn't get the key from the cache if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); // Only try the close if we have a valid handle if (dbp != NULL) { set_dangerous("map_cache_del: dbp->close 1"); dbp->close(dbp, 0); clear_dangerous(); } return (mc_ret); } if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key retrieved: data was %s.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data, (mc_data.data == NULL) ? "(null)" : (char *)mc_data.data); } // stat the file xastir_snprintf(mc_delete_file, MAX_FILENAME, "%s", (char *) mc_data.data); set_dangerous("map_cache_del: stat"); mc_file_stat = stat(mc_delete_file, &file_status); clear_dangerous(); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: file %s stat returned:%d.\n", (mc_data.data == NULL) ? "(null)" : (char *) mc_data.data, mc_file_stat); } if (mc_file_stat != 0 ) { // file stat was not good - do something here // RETURN() HERE? } // Setup for get CACHE_SPACE_USED memset(&mc_size_key, 0, sizeof(mc_size_key)); memset(&mc_size_data, 0, sizeof(mc_size_data)); mc_size_key.data = "CACHE_SPACE_USED"; mc_size_key.size = sizeof("CACHE_SPACE_USED"); // check "CACHE_SPACE_USED" record in db if (((mc_ret = dbp->get(dbp, NULL, &mc_size_key, &mc_size_data, 0)) == 0) && ( mc_size_data.data != NULL ) && ( strlen(mc_size_data.data) != 0 ) ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key retrieved: data was %s.\n", (mc_size_key.data == NULL) ? "(null)" : (char *)mc_size_key.data, (mc_size_data.data == NULL) ? "(null)" : (char *)mc_size_data.data); } set_dangerous("map_cache_del: atoi"); if (mc_size_data.data == NULL) { mc_space_used = 0; } else { mc_space_used = atoi( (char *)mc_size_data.data); } clear_dangerous(); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: CACHE_SPACE_USED = %.2f mb\n", (mc_space_used/1024/1024.0)); } } else { // Failed the "dpb->get" operation if (mc_size_data.data == NULL) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: CACHE_SPACE_USED get returned null \n"); } } else { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: Unable to check CACHE_SPACE_USED: %s\n", db_strerror(mc_ret)); } } // RETURN() HERE? } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: mc_space_used before = %d bytes file_status.st_size %d\n", mc_space_used, (int) file_status.st_size); } mc_ret = unlink( mc_delete_file ); if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: file %s unlink returned:%d.\n", mc_delete_file, mc_ret); } if (mc_ret != 0 ) { if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: unlink failed mc_space_used = %d bytes \n", mc_space_used); } return(mc_ret); } // Update cache_space_used // setup mc_space_used -= (int) file_status.st_size; if (mc_space_used < 0) { mc_space_used = 0; } if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: unlink succeeded mc_space_used = %d bytes \n", mc_space_used); } memset(&mc_size_key, 0, sizeof(mc_size_key)); memset(&mc_size_data, 0, sizeof(mc_size_data)); // data mc_size_key.data = "CACHE_SPACE_USED"; mc_size_key.size = sizeof("CACHE_SPACE_USED"); xastir_snprintf(mc_buf, sizeof(mc_buf), "%d", mc_space_used); if ( debug_level & 512 ) { fprintf (stderr, "map_cache_del: mc_buf: %s len %d\n", mc_buf, (int)sizeof(mc_buf)); } mc_size_data.data = mc_buf ; mc_size_data.size = sizeof(mc_buf); // put if ((mc_ret = dbp->put(dbp, NULL, &mc_size_key, &mc_size_data, 0)) != 0) { // Failed the "dbp->put" operation if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->put"); } // db_strerror(mc_ret); // RETURN() HERE? } if ( debug_level & 512 ) { fprintf(stderr,"map_cache_del: %s: key stored.\n", (mc_size_key.data == NULL) ? "(null)" : (char *)mc_size_key.data); } // remove entry from cache url->filename database if ((mc_ret = dbp->del(dbp, NULL, &mc_key, 0)) != 0) { // Failed the "dbp->del" operation if ( debug_level & 512 ) { dbp->err(dbp, mc_ret, "DB->del"); } // db_strerror(mc_ret); // RETURN() HERE? } if ( debug_level & 512 ) { fprintf(stderr, "map_cache_del: %s: key was deleted.\n", (mc_key.data == NULL) ? "(null)" : (char *)mc_key.data); } // close the db. // Only try the close if we have a valid handle if (dbp != NULL) { set_dangerous("map_cache_del: dbp->close 2"); if ((mc_t_ret = dbp->close(dbp, 0)) != 0 && mc_ret == 0) { clear_dangerous(); mc_ret = mc_t_ret; // db_strerror(mc_ret); // RETURN() HERE? } } return (0); // All is well /** end map_cache_del **/ } char * map_cache_fileid(void) { // returns a unique identifier // used for generating filenames for cached files time_t t; char * mc_time_buf; mc_time_buf = malloc (16); sprintf( mc_time_buf, "%d",(int) time(&t)); return (mc_time_buf); } // check for files old enough to expire // this is lame but it should work for now. // expects file name like /home/brown/.xastir/map_cache/map_1100052372.gif // // writing this proved a good example of why pointer arithmetic is tricky // and a good example of why I should avoid it - n8ysz 20041110 // int map_cache_expired( char * mc_filename, time_t mc_max_age ) { time_t mc_t,mc_file_age; char *mc_filename_tmp, *mc_time_buf_tmp, *mc_time_buf; if (map_cache_disabled) { return(0); } mc_time_buf=malloc(MAX_FILENAME); mc_time_buf_tmp=mc_time_buf; // grab filename mc_filename_tmp=strrchr(mc_filename,'/'); // clean up map_ mc_filename_tmp=strchr(mc_filename_tmp,'_'); ++mc_filename_tmp; // save up to .gif while ((*mc_time_buf_tmp++ = *mc_filename_tmp++) != '.' ) ; *(--mc_time_buf_tmp) ='\0'; // if ( debug_level & 512 ) { // fprintf(stderr, "map_cache_expired: mc_filename is: %s mc_time_buf is: %s.\n", mc_filename, mc_time_buf); // } mc_file_age=(time(&mc_t) - ((time_t) atoi(mc_time_buf)) ); if ( mc_file_age < mc_max_age ) { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_expired: mc_filename %s is NOT expired. mc_time_buf is: %s.\n", (mc_filename == NULL) ? "(null)" : mc_filename, (mc_time_buf == NULL) ? "(null)" : mc_time_buf); } free(mc_time_buf); return (0); } else { if ( debug_level & 512 ) { fprintf(stderr, "map_cache_expired: mc_filename %s IS expired. mc_time_buf is: %s.\n", (mc_filename == NULL) ? "(null)" : mc_filename, (mc_time_buf == NULL) ? "(null)" : mc_time_buf); } free(mc_time_buf); return ((int)mc_file_age); } // sprintf( mc_time_buf, "%d",(int) return (0); } // Functions that need writing int mc_check_space_used (void) { if (map_cache_disabled) { return(0); } return(0); } int mc_update_space_used (void) { if (map_cache_disabled) { return(0); } return(0); } #endif // USE_MAP_CACHE Xastir-Release-2.2.4/src/map_cache.h0000664000175000017500000000433115151324131016162 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_MAP_CACHE_H #define XASTIR_MAP_CACHE_H // Global variable declarations extern int map_cache_fetch_disable; // External function declarations extern void map_cache_init(void); // Saves file and puts entries into cache db extern int map_cache_put( char * map_cache_url, char * map_cache_file ); // Retrieves entry from cache db - checks existence of file extern int map_cache_get( char * map_cache_url, char * map_cache_file ); // Deletes cached map file and the entry from cache extern int map_cache_del( char * map_cache_url ); // Checks to see if map is expired based on date embedded in filename extern int map_cache_expired( char * mc_filename, time_t mc_max_age ); // Generates filename based on current time extern char * map_cache_fileid(void); // Static variable definitions // These should probably be runtime options // Cache expiration times // about 6mo #define MC_MAX_FILE_AGE 6*30*24*60*60 // 1 hr //#define MC_MAX_FILE_AGE 60*60 // 5 seconds -- don't do this except for testing //#define MC_MAX_FILE_AGE 5 // Cache Space Limit in bytes // 1 megabytes == about ten 1024x768 map gifs n8ysz // MAP_CACHE_SPACE_LIMIT=1024*1024 // 16 megabytes // MAP_CACHE_SPACE_LIMIT=16*1024*1024 // 128 megabytes #define MAP_CACHE_SPACE_LIMIT 128*1024*1024 #endif /* XASTIR_MAP_CACHE_H */ Xastir-Release-2.2.4/src/map_dos.c0000664000175000017500000014211215151324131015677 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" #define DOS_HDR_LINES 8 #define GRID_MORE 5000 extern int npoints; /* tsk tsk tsk -- globals */ extern int mag; /* MAP pointers */ //static map_vectors *map_vectors_ptr; //static text_label *map_text_label_ptr; //static symbol_label *map_symbol_label_ptr; /* MAP counters */ //static long vectors_num; //static long text_label_num; //static long object_label_num; /********************************************************** * map_plot() * * Plots vectors on the map. If "color" is non-zero, * then it draws filled polygons in the color of * "object_behavior"? Weird. **********************************************************/ void map_plot (Widget w, long max_x, long max_y, long x_long_cord, long y_lat_cord, unsigned char color, long object_behavior, int destination_pixmap, int draw_filled) { static int redraw_check; static XPoint points[MAX_MAP_POINTS]; static unsigned char last_color = (unsigned char)0; static unsigned char last_behavior = (unsigned char)0, first_behavior = (unsigned char)0; long x, y; int draw_ok; unsigned char line_behavior, fill_color; char warning[200]; /* don't ever go over MAX_MAP_POINTS have a bad map not a crashed program */ if (npoints > MAX_MAP_POINTS) { xastir_snprintf(warning, sizeof(warning), "Warning line point count overflow: map_plot\b\n"); XtAppWarning (app_context, warning); npoints = MAX_MAP_POINTS; } /* if map_color_levels are on see if we should draw the line? */ draw_ok = 0; if (map_color_levels) // Decide which colors to display at this zoom level switch (color) { case (0x01): case (0x14): case (0x18): if (mag < 100) { draw_ok = 1; } break; case (0x15): case (0x19): if (mag < 600) { draw_ok = 1; } break; case (0x16): if (mag < 800) { draw_ok = 1; } break; default: draw_ok = 1; break; } // end of switch else // Display all colors { draw_ok = 1; } if (draw_ok) { x = ((x_long_cord - NW_corner_longitude) / scale_x); y = ((y_lat_cord - NW_corner_latitude) / scale_y); if (x < -MAX_OUTBOUND) { x = -MAX_OUTBOUND; } if (y < -MAX_OUTBOUND) { y = -MAX_OUTBOUND; } if (x > max_x) { x = max_x; } if (y > max_y) { y = max_y; } if (debug_level & 16) fprintf(stderr," MAP Plot - max_x: %ld, max_y: %ld, x: %ld, y: %ld, color: %d, behavior: %lx, points: %d\n", max_x, max_y, x, y, (int)color, (unsigned long)object_behavior, npoints); if ( (last_color != color) || (color == (unsigned char)0xff) ) { if (npoints && (last_color != (unsigned char)0xff) ) { line_behavior = last_behavior; if (last_behavior & 0x80) { if (color) { fill_color = (last_behavior & ~0x80) + (unsigned char)0x60; if (fill_color > (unsigned char)0x69) { fill_color = (unsigned char)0x60; } } else { fill_color = (unsigned char)object_behavior; } // Here's where we draw filled areas using fill_color. (void)XSetForeground (XtDisplay (w), gc, colors[(int)fill_color]); switch (destination_pixmap) { case DRAW_TO_PIXMAP: // We must be drawing maps 'cuz this is the pixmap we use for it. if (map_color_fill && draw_filled) { if (npoints >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap, gc, points, npoints, Nonconvex, CoordModeOrigin); } else { // fprintf(stderr, // "map_plot:Too few points:%d, Skipping XFillPolygon()", // npoints); } } break; case DRAW_TO_PIXMAP_ALERTS: fprintf(stderr,"You're calling the wrong routine to draw weather alerts!\n"); break; case DRAW_TO_PIXMAP_FINAL: // We must be drawing symbols/tracks 'cuz this is the pixmap we use for it. if (npoints >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap_final, gc, points, npoints, Nonconvex, CoordModeOrigin); } else { // fprintf(stderr, // "map_plot:Too few points:%d, Skipping XFillPolygon()", // npoints); } break; } // end of switch line_behavior = first_behavior; } if (line_behavior & 0x01) { (void)XSetLineAttributes (XtDisplay (w), gc, 2, LineSolid, CapButt,JoinMiter); } else { (void)XSetLineAttributes (XtDisplay (w), gc, 1, LineSolid, CapButt,JoinMiter); } if (color == (unsigned char)0x56) { (void)XSetLineAttributes (XtDisplay (w), gc, 10, LineSolid, CapButt,JoinMiter); } // Set the color for drawing lines/borders (void)XSetForeground (XtDisplay (w), gc, colors[(int)last_color]); switch (destination_pixmap) { case DRAW_TO_PIXMAP_FINAL: (void)XDrawLines (XtDisplay (w), pixmap_final, gc, points, l16(npoints), CoordModeOrigin); break; case DRAW_TO_PIXMAP: (void)XDrawLines (XtDisplay (w), pixmap, gc, points, l16(npoints), CoordModeOrigin); break; case DRAW_TO_PIXMAP_ALERTS: fprintf(stderr,"You're calling the wrong routine to draw weather alerts!\n"); break; } // end of switch npoints = 0; /* check to see if we have been away from the screen too long */ if (redraw_check > 1000) { redraw_check = 0; XmUpdateDisplay (XtParent (da)); } redraw_check++; } last_color = color; if (color == (unsigned char)0xff) { npoints = 0; first_behavior = (unsigned char)object_behavior; } points[npoints].x = l16(x); points[npoints].y = l16(y); if ( (points[npoints].x > (-MAX_OUTBOUND)) && (points[npoints].x < (short)max_x) && (points[npoints].y > (-MAX_OUTBOUND)) && (points[npoints].y < (short)max_y) && (color != (unsigned char)0) ) { npoints++; } last_behavior = (unsigned char)object_behavior; return; } points[npoints].x = l16(x); points[npoints].y = l16(y); last_behavior = (unsigned char)object_behavior; if (points[npoints].x != points[npoints - 1].x || points[npoints].y != points[npoints - 1].y) { if (last_behavior & 0x80) { npoints++; } else if (points[npoints].x > (-MAX_OUTBOUND) && points[npoints].x < (short)max_x && points[npoints].y > (-MAX_OUTBOUND) && points[npoints].y < (short)max_y) { npoints++; } } } else { npoints = 0; } } /* map_plot */ void draw_dos_map(Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { FILE *f; char file[MAX_FILENAME]; char short_filenm[MAX_FILENAME]; char map_it[MAX_FILENAME]; /* map header info */ char map_type[5]; char map_version[5]; char file_name[33]; // char *ext; char map_title[33]; char map_creator[9]; unsigned long creation_date; unsigned long left_boundary; unsigned long right_boundary; unsigned long top_boundary; unsigned long bottom_boundary; char map_reserved1[9]; long total_vector_points; long total_labels; char map_reserved2[141]; char Buffer[2049]; char *ptr; int dos_labels; int dos_flag; long temp; int points_per_degree; // int map_range; /* vector info */ unsigned char vector_start; unsigned char object_behavior; unsigned long x_long_cord; unsigned long y_lat_cord; /* label data */ char label_type[3]; unsigned long label_x_cord; unsigned long label_y_cord; int temp_mag; int label_mag; char label_symbol_del; char label_symbol_char; char label_text_color; char label_text[50]; unsigned long year; unsigned long days; long count; int label_length; int i; // int map_maxed_vectors; // int map_maxed_text_labels; // int map_maxed_symbol_labels; // map_vectors *vectors_ptr; // text_label *text_ptr; // symbol_label *symbol_ptr; int line_width; int x, y; int color; long max_x, max_y; int in_window = 0; char symbol_table; char symbol_id; char symbol_color; int embedded_object; int draw_filled; unsigned char last_behavior, special_fill = (unsigned char)FALSE; draw_filled=mdf->draw_filled; x = 0; y = 0; color = -1; line_width = 1; mag = (1 * scale_y) / 2; // determines if details are drawn /* MAP counters */ // vectors_ptr = map_vectors_ptr; // text_ptr = map_text_label_ptr; // symbol_ptr = map_symbol_label_ptr; // map_maxed_vectors = 0; // map_maxed_text_labels = 0; // map_maxed_symbol_labels = 0; npoints = 0; xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); f = fopen (file, "r"); if (f == NULL) { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (fread (map_type, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_type[4] = '\0'; dos_labels = FALSE; points_per_degree = 300; // DOS-type map header portion of the code. if (strtod (map_type, &ptr) > 0.01 && (*ptr == '\0' || *ptr == ' ' || *ptr == ',')) { int j; if (debug_level & 512) { fprintf(stderr,"\nDOS Map\n"); } top_boundary = left_boundary = bottom_boundary = right_boundary = 0; rewind (f); map_title[0] = map_creator[0] = Buffer[0] = '\0'; // set map_type for DOS ASCII maps xastir_snprintf(map_type,sizeof(map_type),"DOS "); map_type[4] = '\0'; xastir_snprintf(file_name,sizeof(file_name),"%s",filenm); total_vector_points = 200000; total_labels = 2000; for (j = 0; j < DOS_HDR_LINES; strlen(Buffer) ? 1 : j++) { if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } // if (!strlen(Buffer)) // j++; while ((ptr = strpbrk (Buffer, "\r\n")) != NULL && j < DOS_HDR_LINES) { *ptr = '\0'; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; switch (j) { case 0: //fprintf(stderr,"top_boundary: %s\n", Buffer); top_boundary = (unsigned long) (-atof (Buffer) * 360000 + 32400000); break; case 1: //fprintf(stderr,"left_boundary: %s\n", Buffer); left_boundary = (unsigned long) (-atof (Buffer) * 360000 + 64800000); break; case 2: //fprintf(stderr,"points_per_degree: %s\n", Buffer); points_per_degree = atoi (Buffer); break; case 3: //fprintf(stderr,"bottom_boundary: %s\n", Buffer); bottom_boundary = (unsigned long) (-atof (Buffer) * 360000 + 32400000); bottom_boundary = bottom_boundary + bottom_boundary - top_boundary; break; case 4: //fprintf(stderr,"right_boundary: %s\n", Buffer); right_boundary = (unsigned long) (-atof (Buffer) * 360000 + 64800000); right_boundary = right_boundary + right_boundary - left_boundary; break; case 5: //fprintf(stderr,"map_range: %s\n", Buffer); // map_range = (int) atof (Buffer); break; case 7: //fprintf(stderr,"Map Version: %s\n", Buffer); memcpy(map_version, Buffer, sizeof(map_version)); map_version[sizeof(map_version)-1] = '\0'; // Terminate string //fprintf(stderr,"MAP VERSION: %s\n", map_version); break; } // end of switch xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); // if (strlen (Buffer)) // j++; } } // End of DOS-type map header portion } else { // Windows-type map header portion if (debug_level & 512) { fprintf(stderr,"\nWindows map\n"); } if (fread (map_version, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_version[4] = '\0'; if (fread (file_name, 32, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } file_name[32] = '\0'; if (fread (map_title, 32, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_title[32] = '\0'; if (debug_level & 16) { fprintf(stderr,"Map Title %s\n", map_title); } if (fread (map_creator, 8, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } map_creator[8] = '\0'; if (debug_level & 16) { fprintf(stderr,"Map Creator %s\n", map_creator); } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } creation_date = ntohl (temp); if (debug_level & 16) { fprintf(stderr,"Creation Date %lX\n", creation_date); } year = creation_date / 31536000l; days = (creation_date - (year * 31536000l)) / 86400l; if (debug_level & 16) { fprintf(stderr,"year is %ld + days %ld\n", 1904l + year, (long)days); } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } left_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } right_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } top_boundary = ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } bottom_boundary = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { left_boundary *= 10; right_boundary *= 10; top_boundary *= 10; bottom_boundary *= 10; } if (fread (map_reserved1, 8, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } total_vector_points = (long)ntohl (temp); if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } total_labels = (long)ntohl (temp); if (fread (map_reserved2, 140, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } } // End of Windows-type map header portion // Done processing map header info. The rest of this // function performs the actual drawing of both DOS-type // and Windows-type maps to the screen. if (debug_level & 16) { fprintf(stderr,"Map Type: %s, Version: %s, Filename: %s\n", map_type, map_version, file_name); fprintf(stderr,"Left Boundary: %ld, Right Boundary: %ld\n", (long)left_boundary,(long)right_boundary); fprintf(stderr,"Top Boundary: %ld, Bottom Boundary: %ld\n", (long)top_boundary,(long)bottom_boundary); fprintf(stderr,"Total vector points: %ld, total labels: %ld\n",total_vector_points, total_labels); } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_boundary, // Bottom top_boundary, // Top left_boundary, // Left right_boundary, // Right 1000); // Default Map Level (void)fclose (f); // Update the statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check to see if we should draw the map in_window = map_onscreen(left_boundary, right_boundary, top_boundary, bottom_boundary, 1); if (!in_window) { (void)fclose (f); return; } // Update the statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading/Indexing ... object_behavior = '\0'; if (debug_level & 16) { fprintf(stderr,"in Boundary %s\n", map_it); } (void)XSetLineAttributes (XtDisplay (w), gc, line_width, LineSolid, CapButt,JoinMiter); /* read vectors */ max_x = screen_width + MAX_OUTBOUND; max_y = screen_height + MAX_OUTBOUND; x_long_cord = 0; y_lat_cord = 0; color = 0; dos_flag = 0; for (count = 0l; count < total_vector_points && !feof (f) && !dos_labels; count++) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // DOS type map if (strncmp ("DOS ", map_type, 4) == 0) { if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } while ((ptr = strpbrk (Buffer, "\r\n")) != NULL && !dos_labels) { long LatHld = 0, LongHld; char *trailer; *ptr = '\0'; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; process: if (strncasecmp ("Line", map_version, 4) == 0) { int k; color = (int)strtol (Buffer, &trailer, 0); if (trailer && (*trailer == ',' || *trailer == ' ')) { trailer++; if (color == -1) { dos_labels = (int)TRUE; xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); break; } for (k = strlen (trailer) - 1; k >= 0; k--) { trailer[k] = (char)( (int)trailer[k] - 27 ); } while (*trailer) { LongHld = (long)( (int)(*(unsigned char *)trailer) * 16); trailer++; LatHld = (long)( (int)(*(unsigned char *)trailer) * 8); trailer++; LongHld += (long)((*trailer >> 3) & 0xf); LatHld += (long)( (*trailer) & 0x7); trailer++; LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', 0, destination_pixmap, draw_filled); } } else if (strncasecmp ("ASCII", map_version, 4) == 0) { if (color == 0) { color = (int)strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; dos_flag = (int)strtol (trailer, &trailer, 0); if (dos_flag == -1) { dos_labels = (int)TRUE; } } } else { LongHld = strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; LatHld = strtol (trailer, &trailer, 0); } else if (LongHld == 0 && *trailer != '\0') { xastir_snprintf(map_version,sizeof(map_version),"Comp"); map_version[4] = '\0'; goto process; } if (LongHld == 0 && LatHld == 0) { color = 0; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } else if (LongHld == 0 && LatHld == -1) { dos_labels = (int)TRUE; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', 0, destination_pixmap, draw_filled); } else { LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } } } else if (strncasecmp ("Comp", map_version, 4) == 0) { char Tag[81]; int k; Tag[80] = '\0'; if (color == 0) { color = (int)strtol (Buffer, &trailer, 0); if (trailer && strpbrk (trailer, ", ")) { for (; *trailer == ',' || *trailer == ' '; trailer++) ; dos_flag = (int)strtol (trailer, &trailer, 0); xastir_snprintf(Tag,sizeof(Tag),"%s",trailer); Tag[79] = '\0'; if (dos_flag == -1) { dos_labels = (int)TRUE; } } } else { LongHld = strtol (Buffer, &trailer, 0); for (; *trailer == ',' || *trailer == ' '; trailer++) ; LatHld = strtol (trailer, &trailer, 0); if (LatHld == 0 && *trailer != '\0') { LatHld = 1; } if (LongHld == 0 && LatHld == 0) { color = 0; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } else if (LongHld == 0 && LatHld == -1) { dos_labels = (int)TRUE; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } if (color && !dos_labels) { trailer = Buffer; for (k = strlen (trailer) - 1; k >= 0; k--) { trailer[k] = (char)((int)trailer[k] - 27); } while (*trailer) { LongHld = (long)( (int)(*(unsigned char *)trailer) * 16); trailer++; LatHld = (long)( (int)(*(unsigned char *)trailer) * 8); trailer++; LongHld += (long)((*(unsigned char *)trailer >> 3) & 0xf); LatHld += (*trailer) & 7l; trailer++; LatHld = ((double)LatHld * 360000.0) / points_per_degree; LongHld = ((double)LongHld * 360000.0) / points_per_degree; x_long_cord = LongHld + left_boundary; y_lat_cord = LatHld + top_boundary; map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, (unsigned char)color, 0, destination_pixmap, draw_filled); } } } } else { LongHld = strtol (Buffer, &trailer, 0); if (trailer) { if (*trailer == ',' || *trailer == ' ') { if (LongHld == 0) { memcpy(map_version, "ASCII", sizeof(map_version)); map_version[sizeof(map_version)-1] = '\0'; // Terminate string } map_version[4] = '\0'; trailer++; dos_flag = (int)strtol (trailer, &trailer, 0); if (dos_flag == -1) { dos_labels = (int)TRUE; } if (dos_flag == 0 && *trailer != '\0') { xastir_snprintf(map_version,sizeof(map_version),"Line"); map_version[4] = '\0'; goto process; } color = (int)LongHld; } } else { xastir_snprintf(map_version,sizeof(map_version),"Comp"); } map_version[4] = '\0'; } xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr); } } else { // Windows type map... last_behavior = object_behavior; if (fread (&vector_start, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&object_behavior, 1, 1, f) == 0) // Fill Color? { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (strcmp (map_type, "COMP") == 0) { short temp_short; long LatOffset, LongOffset; LatOffset = (long)(top_boundary - top_boundary % 6000); LongOffset = (long)(left_boundary - left_boundary % 6000); if (fread (&temp_short, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } x_long_cord = (ntohs (temp_short) * 10 + LongOffset); if (fread (&temp_short, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } y_lat_cord = (ntohs (temp_short) * 10 + LatOffset); } else { if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } x_long_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { x_long_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } y_lat_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { y_lat_cord *= 10; } } if (alert_color && last_behavior & 0x80 && (int)vector_start == 0xff) { map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, '\0', (long)alert_color, destination_pixmap, draw_filled); //special_fill = TRUE; } map_plot (w, max_x, max_y, (long)x_long_cord, (long)y_lat_cord, vector_start, (long)object_behavior, destination_pixmap, draw_filled); } } if (alert_color) { map_plot (w, max_x, max_y, 0, 0, '\0', special_fill ? (long)0xfd : (long)alert_color, destination_pixmap, draw_filled); } else { map_plot (w, max_x, max_y, 0, 0, (unsigned char)0xff, 0, destination_pixmap, draw_filled); } (void)XSetForeground (XtDisplay (w), gc, colors[20]); line_width = 2; (void)XSetLineAttributes (XtDisplay (w), gc, line_width, LineSolid, CapButt,JoinMiter); // Here is the map label section of the code for both DOS & Windows-type maps if (map_labels) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose(f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* read labels */ for (count = 0l; count < total_labels && !feof (f); count++) { //DOS-Type Map Labels embedded_object = 0; if (strcmp (map_type, "DOS ") == 0) // Handle DOS-type map labels/embedded objects { char *trailer; if (fgets (&Buffer[strlen (Buffer)],(int)sizeof (Buffer) - (strlen (Buffer)), f) == 0) { // Ignoring fgets errors as we've done here since forever. // Would be good to take another look at this later. } for (; (ptr = strpbrk (Buffer, "\r\n")) != NULL; xastir_snprintf(Buffer,sizeof(Buffer),"%s",ptr)) { *ptr = '\0'; label_type[0] = (char)0x08; for (ptr++; *ptr == '\r' || *ptr == '\n'; ptr++) ; trailer = strchr (Buffer, ','); if (trailer && strncmp (Buffer, "0", 1) != 0) { *trailer = '\0'; trailer++; memcpy(label_text, Buffer, sizeof(label_text)); label_text[sizeof(label_text)-1] = '\0'; // Terminate string // Check for '#' or '$' as the first character of the label. // If found, we have an embedded symbol and colored text to display. symbol_table = ' '; symbol_id = ' '; symbol_color = '0'; if ( (label_text[0] == '$') || (label_text[0] == '#') ) { // We found an embedded map object embedded_object = 1; // Set the flag if (label_text[0] == '$') // Old format: $xC { symbol_table = '/'; symbol_id = label_text[1]; symbol_color = label_text[2]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+3); } else // Could be in new or old format with a leading '#' character { symbol_table = label_text[1]; if (symbol_table == '/' || symbol_table == '\\') // New format: #/xC { symbol_id = label_text[2]; symbol_color = label_text[3]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+4); } else // Old format: #xC { symbol_table = '\\'; symbol_id = label_text[1]; symbol_color = label_text[2]; // Take the object out of the label text xastir_snprintf(label_text,sizeof(label_text),"%s",Buffer+3); } } if (debug_level & 512) { fprintf(stderr,"Found embedded object: %c %c %c %s\n",symbol_table,symbol_id,symbol_color,label_text); } } label_length = (int)strlen (label_text); label_y_cord = (unsigned long) (-strtod (trailer, &trailer) * 360000) + 32400000; trailer++; label_x_cord = (unsigned long) (-strtod (trailer, &trailer) * 360000) + 64800000; trailer++; label_mag = (int)strtol (trailer, &trailer, 0) * 20; if ((label_type[0] & 0x80) == '\0') /* left of coords */ { x = ((label_x_cord - NW_corner_longitude) / scale_x) - (label_length * 6); } else /* right of coords */ { x = ((label_x_cord - NW_corner_longitude) / scale_x); } y = ((label_y_cord - NW_corner_latitude) / scale_y); if (x > (0) && (x < (int)screen_width)) { if (y > (0) && (y < (int)screen_height)) { /*fprintf(stderr,"Label mag %d mag %d\n",label_mag,(scale_x*2)-1); */ //if (label_mag > (int)((scale_x * 2) - 1) || label_mag == 0) if (label_mag > (int)((scale_x) - 1) || label_mag == 0) { if (embedded_object) { // NOTE: 0x21 is the first color for the area object or "DOS" colors draw_label_text (w, x+10, y+5, label_length,colors[0x21 + symbol_color],label_text); symbol(w,0,symbol_table,symbol_id,' ',pixmap,1,x-10,y-10,' '); } else { draw_label_text (w, x, y, label_length,colors[(int)(label_type[0] & 0x7f)],label_text); } } } } } } } else // Handle Windows-type map labels/embedded objects { int rotation = 0; char rotation_factor[5]; // Windows-Type Map Labels char label_type_1[2], label_type_2[2]; // Snag first two bytes of label if (fread (label_type_1, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (label_type_2, 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_type_2[0] == '\0') // Found a label { // Found text label if (fread (&temp, 4, 1, f) == 0) /* x */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_x_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_x_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) /* y */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_y_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_y_cord *= 10; } if (fread (&temp_mag, 2, 1, f) == 0) /* mag */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_mag = (int)ntohs (temp_mag); if (strcmp (map_version, "2.00") != 0) { label_mag *= 10; } if (strcmp (map_type, "COMP") == 0) { for (i = 0; i < 32; i++) { if (fread (&label_text[i], 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text[i] == '\0') { break; } } label_text[32] = '\0'; // Make sure we have a terminator } else { if (fread (label_text, 32, 1, f) == 0) /* text */ { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_text[32] = '\0'; // Make sure we have a terminator } // Special strings like: "#123" are rotation factors for labels // in degrees. This is not documented in the windows-type map // format documents that I could find. if (label_text[0] == '#') { int i,j; if (debug_level & 512) { fprintf(stderr,"%s\n",label_text); } // Save the rotation factor in "rotation" for ( i=1; i<4; i++ ) { rotation_factor[i-1] = label_text[i]; } rotation_factor[3] = '\0'; rotation = atoi(rotation_factor); // Take rotation factor out of label string for ( i=4, j=0; i < (int)(strlen(label_text)+1); i++,j++) { label_text[j] = label_text[i]; } //fprintf(stderr,"Windows label: %s, rotation factor: %d\n",label_text, rotation); } label_length = (int)strlen (label_text); for (i = (label_length - 1); i > 0; i--) { if (label_text[i] == ' ') { label_text[i] = '\0'; } else { break; } } label_length = (int)strlen (label_text); /*fprintf(stderr,"labelin:%s\n",label_text); */ if ((label_type_1[0] & 0x80) == '\0') { /* left of coords */ x = ((label_x_cord - NW_corner_longitude) / scale_x) - (label_length * 6); x = 0; // ?????? } else { /* right of coords */ x = ((label_x_cord - NW_corner_longitude) / scale_x); } y = ((label_y_cord - NW_corner_latitude) / scale_y); if (x > (0) && (x < (int)screen_width)) { if (y > (0) && (y < (int)screen_height)) { /*fprintf(stderr,"Label mag %d mag %d\n",label_mag,(scale_x*2)-1); */ //if (label_mag > (int)((scale_x * 2) - 1) || label_mag == 0) if (label_mag > (int)((scale_x) - 1) || label_mag == 0) { // Note: We're not drawing the labels in the right colors if (rotation == 0) // Non-rotated label { // draw_label_text (w, // x, // y, // label_length, // colors[(int)(label_type_1[0] & 0x7f)], // label_text); draw_rotated_label_text (w, -90.0, x, y, label_length, colors[(int)(label_type_1[0] & 0x7f)], label_text, FONT_DEFAULT); } else // Rotated label { draw_rotated_label_text (w, rotation, x, y, label_length, colors[(int)(label_type_1[0] & 0x7f)], label_text, FONT_DEFAULT); } } } } } else if (label_type_2[0] == '\1' && label_type_1[0] == '\0') // Found an embedded object { //fprintf(stderr,"Found windows embedded symbol\n"); /* label is an embedded symbol */ if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_x_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_x_cord *= 10; } if (fread (&temp, 4, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_y_cord = ntohl (temp); if (strcmp (map_version, "2.00") != 0) { label_y_cord *= 10; } if (fread (&temp_mag, 2, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } label_mag = (int)ntohs (temp_mag); if (strcmp (map_version, "2.00") != 0) { label_mag *= 10; } if (fread (&label_symbol_del, 1, 1, f) == 0) // Snag symbol table char { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&label_symbol_char, 1, 1, f) == 0) // Snag symbol char { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (fread (&label_text_color, 1, 1, f) == 0) // Snag text color (should be 1-9, others should default to black) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text_color < '1' && label_text_color > '9') { label_text_color = '0'; // Default to black } x = ((label_x_cord - NW_corner_longitude) / scale_x); y = ((label_y_cord - NW_corner_latitude) / scale_y); // Read the label text portion if (strcmp (map_type, "COMP") == 0) { for (i = 0; i < 32; i++) { if (fread (&label_text[i], 1, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } if (label_text[i] == '\0') { break; } } } else { if (fread (label_text, 29, 1, f) == 0) { // Ignoring fread errors as we've done here since forever. // Would be good to take another look at this later. } } // NOTE: 0x21 is the first color for the area object or "DOS" colors draw_label_text (w, x+10, y+5, strlen(label_text),colors[0x21 + label_text_color],label_text); symbol(w,0,label_symbol_del,label_symbol_char,' ',pixmap,1,x-10,y-10,' '); if (debug_level & 512) fprintf(stderr,"Windows map, embedded object: %c %c %c %s\n", label_symbol_del,label_symbol_char,label_text_color,label_text); } else { if (debug_level & 512) fprintf(stderr,"Weird label in Windows map, neither a plain label nor an object: %d %d\n", label_type_1[0],label_type_2[0]); } } } } // if (map_labels) (void)fclose (f); } Xastir-Release-2.2.4/src/map_geo.c0000664000175000017500000025565315151324131015703 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //#define FUZZYRASTER #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "map_cache.h" #include "alert.h" #include "fetch_remote.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #include "map_OSM.h" // Check for XPM and/or ImageMagick. We use "NO_GRAPHICS" // to disable some routines below if the support for them // is not compiled in. #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK)) #define NO_GRAPHICS 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK) #if defined(HAVE_MAGICK) || !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM)) #define NO_XPM 1 #endif // HAVE_MAGICK || !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM) #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK // Must be last include file #include "leak_detection.h" int check_interrupt( #ifdef HAVE_MAGICK Image *image, ImageInfo *image_info, ExceptionInfo *exception, #else // HAVE_MAGICK XImage *xi, #endif // HAVE_MAGICK Widget *da, Pixmap *pixmap, GC *gc, unsigned long screen_width, unsigned long screen_height) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { #ifdef HAVE_MAGICK if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } #else // HAVE_MAGICK if (xi) { XDestroyImage (xi); } #endif // HAVE_MAGICK // Update to screen (void)XCopyArea(XtDisplay(*da), *pixmap, XtWindow(*da), *gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); #ifdef HAVE_MAGICK DestroyExceptionInfo(exception); #endif // HAVE_MAGICK return(~0); } else { return(0); } } void draw_geo_image_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf); /* typedef struct _transparent_color_record{ unsigned long trans_color; struct _transparent_color_record *next; } transparent_color_record; */ // Pointer to head of transparent color linked list. transparent_color_record *trans_color_head = NULL; // Empty out the linked list containing transparent colors void empty_trans_color_list(void) { transparent_color_record *p; while (trans_color_head != NULL) { p = trans_color_head; trans_color_head = p->next; free(p); } } // Add a new transparent color to the linked list void new_trans_color(unsigned long trans_color) { transparent_color_record *p; //fprintf(stderr,"New transparent color: %lx\n", trans_color); p = (transparent_color_record *)malloc( sizeof(transparent_color_record) ); // Fill in value p->trans_color = trans_color; // Link it to transparent color list p->next = trans_color_head; trans_color_head = p; } /********************(********************************************** * check_trans() * * See if this pixel's color should be transparent * * We only call this from blocks where ImageMagick is used, so we're * ok to use IM calls. ******************************************(************************/ int check_trans (XColor c, transparent_color_record *c_trans_color_head) { transparent_color_record *p = c_trans_color_head; // fprintf (stderr, "pix = %li,%lx, chk = %li,%lx.\n",c.pixel,c.pixel,c_trans_color,c_trans_color); // A linked list from the geo file of colors to zap. // if ( c.pixel == (unsigned long) 0x000000 ) { // return 1; // black background //} while (p) { if ( c.pixel == p->trans_color ) { return 1; } p = p->next; } return 0; // everything else is OK to draw } // Regarding MAP CACHING for toporama maps: Here we are only // snagging a .geo file for toporama from findu.com: We send the // parameters off to findu.com, it computes the .geo file, we // download it, then we call draw_geo_image_map() with it. We would // have to cache the .geo files from findu, we'd have to modify them // to point to our local cached map file (maybe), and we'd of course // have to cache that map image as well. The image filename on // findu changes each time we call with the same parameters, so we'd // have to give the image file our own name based on the parameters // and write that same name into the cached .geo file. A bit of // work, but it _could_ be done. Actually, we should be able to map // between the original URL we use to request the .GEO file and the // final image we received. That way the name would stay the same // each time we made the request. There may be other things we need // from the generated .GEO file though. // // For this particular case we need to snag a remote .geo file and // then start the process all over again. The URL we'll need to use // looks something like this: // // http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1 // // Where the lat/lon are the center of our view, and the // width/height depend on our window size. The "set" parameter // decides whether we're fetching 50k or 250k maps. // void draw_toporama_map (Widget w, char * UNUSED(dir), char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf, int toporama_flag) // 50 or 250 { #ifdef HAVE_MAGICK char fileimg[MAX_FILENAME+1]; // Ascii name of image file, read from GEO file char map_it[MAX_FILENAME]; char local_filename[MAX_FILENAME]; char file[MAX_FILENAME+1]; // Complete path/name of image file char short_filenm[MAX_FILENAME+1]; FILE *f; // Filehandle of image file double lat_center = 0; double long_center = 0; double left, right, top, bottom; int my_screen_width, my_screen_height; float my_zoom = 1.0; char temp_file_path[MAX_VALUE]; // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); ; // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. // Force the extents to the edges of the earth for the index // file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } // Compute the parameters we'll need for the URL, fetch the .geo // file at that address, then pass that .geo file off to // draw_geo_image_map(). This will cause us to fetch the image // file corresponding to the .geo file and display it. We may // also need to tweak the zoom parameter for our current zoom // level so that things match up properly. // Compute the center of our view in decimal lat/long. left = (double)((NW_corner_longitude - 64800000l )/360000.0); // Lat/long Coordinates top = (double)(-((NW_corner_latitude - 32400000l )/360000.0)); // Lat/long Coordinates right = (double)((SE_corner_longitude - 64800000l)/360000.0);//Lat/long Coordinates bottom = (double)(-((SE_corner_latitude - 32400000l)/360000.0));//Lat/long Coordinates long_center = (left + right)/2.0l; lat_center = (top + bottom)/2.0l; // We now have the center in decimal lat/long. We also have the // screen width and height in pixels, which we can use in the // URL as well (depending on the zoom parameter and how to make // the finished display look nice). // Compute the size of the image we want to snag. It should be // easy to get darn near anything to work, although the size and // scale of the image will drastically affect how nicely the // finished map display will look. // Compute the zoom parameter for the URL. // A test URL that works, just to get things going. This URL // requests 1:50k scale maps ("set=50"). //xastir_snprintf(fileimg, sizeof(fileimg), // "\"http://mm.aprs.net/toporama.cgi?set=50|lat=44.59333|lon=-75.72933|width=800|height=600|zoom=1\""); // Compute our custom URL based on our map view and the // requested map scale. // my_screen_width = (int)screen_width; my_screen_height = (int)screen_height; if (toporama_flag == 50) // 1:50k { my_zoom = 32.0 / scale_y; if (scale_y <= 16) { my_zoom = 2.0; } } else // toporama_flag == 250 (1:250k) { my_zoom = 128.0 / scale_y; if (scale_y <= 64) { my_zoom = 2.0; } } // Set a max zoom limit so we don't tax the server too much. if (my_zoom < 0.02) { my_zoom = 0.02; } xastir_snprintf(fileimg, sizeof(fileimg), "http://mm.aprs.net/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f", // "http://www2.findu.com/toporama.cgi?set=%d|lat=%f|lon=%f|width=%d|height=%d|zoom=%0.3f", toporama_flag, // Scale, 50 or 250 lat_center, long_center, my_screen_width, my_screen_height, my_zoom); //fprintf(stderr,"%s\n", fileimg); // Create a local filename that we'll save to. xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.geo", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path))); // Erase any previously existing local file by the same // name. This avoids the problem of having an old map image // here and the code trying to display it when the download // fails. unlink( local_filename ); // Call wget or libcurl to fetch the .geo file. Best would be // to create a generic "fetch" routine which would fetch a // remote file, then go back and rework all of the various map // routines to use it. if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. // Tell ImageMagick where to find it xastir_snprintf(file,sizeof(file),"%s",local_filename); // Check whether we got a reasonable ~/.xastir/tmp/map.geo file from // the fetch. If so, pass it off to the routine which can draw it. // We also need to write a valid IMAGESIZE line into the .geo // file. We know these parameters because they should match // screen_width/screen_height. // xastir_snprintf(map_it, sizeof(map_it), "IMAGESIZE\t%d\t%d\n", my_screen_width, my_screen_height); // Another thing we might need is a TRANSPARENT line, for the grey // color we see crossing over the U.S. border and obscuring maps on // this side of the border. f = fopen (local_filename, "a"); if (f != NULL) { fprintf(f, "%s", map_it); (void)fclose (f); } else { fprintf(stderr,"Couldn't open file: %s to add IMAGESIZE tag\n", local_filename); return; } // Call draw_geo_image_map() with our newly-fetched .geo file, // passing it most of the parameters that we were originally // passed in order to effect the map draw. draw_geo_image_map (w, get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)), "map.geo", alert, alert_color, destination_pixmap, mdf); #endif // HAVE_MAGICK } /********************************************************** * draw_geo_image_map() * * If we have found a ".geo" file, we read it here and plot * the graphic image into the current viewport. * We check first to see whether the map should be plotted * and skip it if it's not in our viewport. These images * are expected to be aligned in the lat/lon directions * (not rotated) and rectangular. **********************************************************/ void draw_geo_image_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { #ifdef NO_GRAPHICS fprintf(stderr,"XPM and/or ImageMagick support have not been compiled in.\n"); #else // NO_GRAPHICS char file[MAX_FILENAME+1]; // Complete path/name of image file char short_filenm[MAX_FILENAME+1]; FILE *f; // Filehandle of image file char line[MAX_FILENAME]; // One line from GEO file char fileimg[MAX_FILENAME+1]; // Ascii name of image file, read from GEO file char tileCache[MAX_FILENAME+1]; // directory for the OSM tile cache, read from GEO file. char OSMstyle[MAX_OSMSTYLE]; char OSMtileExt[MAX_OSMEXT]; // Start with an empty fileimg[] string so that we can // tell if a URL has been specified in the file. Same for OSMstyle. fileimg[0] = '\0'; OSMstyle[0] = '\0'; tileCache[0] = '\0'; OSMtileExt[0] = '\0'; int width,height; #ifndef NO_XPM XpmAttributes atb; // Map attributes after map's read into an XImage #endif // NO_XPM tiepoint tp[2]; // Calibration points for map, read in from .geo file int n_tp; // Temp counter for number of tiepoints read float temp_long, temp_lat; long map_c_T, map_c_L; // map delta NW edge coordinates, DNN: these should be signed long tp_c_dx, tp_c_dy; // tiepoint coordinate differences // DK7IN-- // int test; // temporary debugging unsigned long c_x_min, c_y_min;// top left coordinates of map inside screen // unsigned long c_y_max; // bottom right coordinates of map inside screen double c_x; // Xastir coordinates 1/100 sec, 0 = 180W double c_y; // Xastir coordinates 1/100 sec, 0 = 90N double c_y_a; // coordinates correction for Transverse Mercator long map_y_0; // map pixel pointer prior to TM adjustment long map_x, map_y; // map pixel pointers, DNN: this was a float, chg to long long map_x_min, map_x_max; // map boundaries for in screen part of map long map_y_min, map_y_max; // long map_x_ctr; // half map width in pixel // long map_y_ctr; // half map height in pixel // long x; int map_seen, map_act, map_done; double corrfact; long map_c_yc; // map center, vert coordinate long map_c_xc; // map center, hor coordinate double map_c_dx, map_c_dy; // map coordinates increment (pixel width) double c_dx; // adjusted map pixel width long scr_x, scr_y; // screen pixel plot positions long scr_xp, scr_yp; // previous screen plot positions int scr_dx, scr_dy; // increments in screen plot positions // long scr_x_mc; // map center in screen units long scr_c_xr; double dist; // distance from equator in nm double ew_ofs; // distance from map center in nm long scale_xa; // adjusted for topo maps double scale_x_nm; // nm per Xastir coordinate unit long scale_x0; // at widest map area #ifdef HAVE_MAGICK char local_filename[MAX_FILENAME]; ExceptionInfo exception; Image *image; ImageInfo *image_info; PixelPacket *pixel_pack; PixelPacket temp_pack; IndexPacket *index_pack; int l; XColor my_colors[256]; time_t query_start_time, query_end_time; char gamma[16]; struct { float r_gamma; float g_gamma; float b_gamma; int gamma_flag; int contrast; int negate; int equalize; int normalize; char level[32]; char modulate[32]; } imagemagick_options = { 1.0, 1.0, 1.0, 0, 0, -1, 0, 0, "", "" }; double left, right, top, bottom; // double map_width, map_height; //N0VH // double lat_center = 0; // double long_center = 0; // Terraserver variables double top_n=0, left_e=0, bottom_n=0, right_e=0, map_top_n=0, map_left_e=0; int z, url_n=0, url_e=0, t_zoom=16, t_scale=12800; char zstr0[8]; char zstr1[8]; #else // HAVE_MAGICK XImage *xi; // Temp XImage used for reading in current image #endif // HAVE_MAGICK int terraserver_flag = 0; // U.S. satellite images/topo/reflectivity/urban // areas via terraserver int OSMserver_flag = 0; // OpenStreetMaps server, 1 = static maps, 2 = tiled unsigned tmp_zl = 0; int toporama_flag = 0; // Canadian topo's from mm.aprs.net (originally from Toporama) int WMSserver_flag = 0; // WMS server char map_it[MAX_FILENAME]; int geo_image_width = 0; // Image width from GEO file int geo_image_height = 0; // Image height from GEO file char geo_datum[8+1]; // WGS-84 etc. char geo_projection[256+1]; // TM, UTM, GK, LATLON etc. int map_proj=0; int map_refresh_interval_temp = 0; #ifdef HAVE_MAGICK int nocache = 0; // Don't cache the file if non-zero #endif // HAVE_MAGICK #ifdef FUZZYRASTER int rasterfuzz = 3; // ratio to skip #endif //FUZZYRASTER unsigned long temp_trans_color; // what color to zap int trans_skip = 0; // skip transparent pixel int crop_x1=0, crop_x2=0, crop_y1=0, crop_y2=0; // pixel crop box int do_crop = 0; // do we crop pixels //#define TIMING_DEBUG #ifdef TIMING_DEBUG time_mark(1); #endif // TIMING_DEBUG #ifdef HAVE_MAGICK #ifdef USE_MAP_CACHE int map_cache_return; char *cache_file_id; #endif // USE_MAP_CACHE #endif // HAVE_MAGICK #ifdef HAVE_MAGICK char temp_file_path[MAX_VALUE]; #endif // HAVE_MAGICK KeySym OSM_key = 0; xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); // Read the .geo file to find out map filename and tiepoint info // Empty the transparent color list before we start reading in a // new .geo file. empty_trans_color_list(); n_tp = 0; geo_datum[0] = '\0'; geo_projection[0] = '\0'; f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) { (void)get_line (f, line, MAX_FILENAME); if (strncasecmp (line, "FILENAME", 8) == 0) { if (1 != sscanf (line + 9, "%s", fileimg)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (fileimg[0] != '/' ) // not absolute path { // make it relative to the .geo file char temp[MAX_FILENAME]; // grab .geo file name strcpy(temp, file); temp[sizeof(temp)-1] = '\0'; // Terminate line (void)get_map_dir(temp); // leaves just the path and trailing / if (strlen(temp) < (MAX_FILENAME - 1 - strlen(fileimg))) strncat(temp, fileimg, sizeof(temp) - 1 - strlen(temp)); xastir_snprintf(fileimg,sizeof(fileimg),"%s",temp); } } if (strncasecmp (line, "URL", 3) == 0) if (1 != sscanf (line + 4, "%s", fileimg)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (n_tp < 2) // Only take the first two tiepoints { if (strncasecmp (line, "TIEPOINT", 8) == 0) { if (4 != sscanf (line + 9, "%d %d %f %f", &tp[n_tp].img_x, &tp[n_tp].img_y, &temp_long, &temp_lat)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } // Convert tiepoints from lat/lon to Xastir coordinates tp[n_tp].x_long = 64800000l + (360000.0 * temp_long); tp[n_tp].y_lat = 32400000l + (360000.0 * (-temp_lat)); n_tp++; } } if (strncasecmp (line, "IMAGESIZE", 9) == 0) if (2 != sscanf (line + 10, "%d %d",&geo_image_width,&geo_image_height)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "DATUM", 5) == 0) if (1 != sscanf (line + 6, "%8s",geo_datum)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "PROJECTION", 10) == 0) // Ignores leading and trailing space (nice!) if (1 != sscanf (line + 11, "%256s",geo_projection)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (strncasecmp (line, "TERRASERVER-URBAN", 17) == 0) { terraserver_flag = 4; } if (strncasecmp (line, "TERRASERVER-REFLECTIVITY", 24) == 0) { terraserver_flag = 3; } if (strncasecmp (line, "TERRASERVER-TOPO", 16) == 0) { // Set to max brightness as it looks weird when the // intensity variable comes into play. #ifdef HAVE_MAGICK // This one causes problems now. Not sure why. // xastir_snprintf(imagemagick_options.modulate,32,"100 100 100"); #endif // HAVE_MAGICK terraserver_flag = 2; } if (strncasecmp (line, "TERRASERVER-SATELLITE", 21) == 0) { terraserver_flag = 1; } if (strncasecmp (line, "OSMSTATICMAP", 12) == 0) { OSMserver_flag = 1; if (strlen(line) > 13) { if (1 != sscanf (line + 13, "%s", OSMstyle)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n"); } } } if (strncasecmp (line, "OSM_TILED_MAP", 13) == 0) { OSMserver_flag = 2; if (strlen(line) > 14) { if (1 != sscanf (line + 14, "%s", OSMstyle)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM style.\n"); } } } if (OSMserver_flag > 0) // the following keywords are only valid for OSM maps { if (strncasecmp (line, "OSM_OPTIMIZE_KEY", 16) == 0) { if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS)) { if (strlen(line) > 17) { if (1 != sscanf (line + 17, "%lu", &OSM_key)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n"); } else { set_OSM_optimize_key(OSM_key); } } } } if (strncasecmp (line, "OSM_REPORT_SCALE_KEY", 20) == 0) { if ((destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS)) { if (strlen(line) > 21) { if (1 != sscanf (line + 21, "%lu", &OSM_key)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for OSM_OPTIMIZE_KEY.\n"); } else { set_OSM_report_scale_key(OSM_key); } } } } if (strncasecmp (line, "TILE_DIR", 8) == 0) { if (strlen(line) > 9) { if (1 != sscanf (line + 9, "%s", tileCache)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_DIR\n"); } } } if (strncasecmp (line, "TILE_EXT", 8) == 0) { if (strlen(line) > 9) { if (1 != sscanf (line + 9, "%s", OSMtileExt)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error for TILE_EXT\n"); } } } if (strncasecmp(line, "ZOOM_LEVEL_MIN", 14) == 0) { if (strlen(line) > 15) { if (1 != sscanf(line + 15, "%u", &tmp_zl)) { fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MIN\n"); } else { if (!(osm_zoom_level(scale_x) >= tmp_zl)) { // skip this map because the zoom level // is not supported. if (debug_level & 512) { fprintf(stderr, "Skipping OSM map. zl = %u < %u\n", osm_zoom_level(scale_x), tmp_zl); } return; } } } } if (strncasecmp(line, "ZOOM_LEVEL_MAX", 14) == 0) { if (strlen(line) > 15) { if (1 != sscanf(line + 15, "%u", &tmp_zl)) { fprintf(stderr, "draw_geo_image_map:sscanf parsing error for ZOOM_LEVEL_MAX\n"); } else { if (!(tmp_zl >= osm_zoom_level(scale_x))) { // skip this map because the zoom level // is not supported. if (debug_level & 512) { fprintf(stderr, "Skipping OSM map. zl = %u > %u\n", osm_zoom_level(scale_x), tmp_zl); } return; } } } } } if (strncasecmp (line, "WMSSERVER", 9) == 0) { WMSserver_flag = 1; } // Check for Canadian topo map request if (strncasecmp (line, "TOPORAMA-50k", 12) == 0) { toporama_flag = 50; } if (strncasecmp (line, "TOPORAMA-250k", 13) == 0) { toporama_flag = 250; } // Check whether we're indexing or drawing the map. // Exclude setting the map refresh interval from // indexing. if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { if (strncasecmp (line, "REFRESH", 7) == 0) { if (1 != sscanf (line + 8, "%d", &map_refresh_interval_temp)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if ( map_refresh_interval_temp > 0 && ( map_refresh_interval == 0 || map_refresh_interval_temp < map_refresh_interval) ) { map_refresh_interval = (time_t) map_refresh_interval_temp; map_refresh_time = sec_now() + map_refresh_interval; if (debug_level & 512) { fprintf(stderr, "Map Refresh set to %d.\n", (int) map_refresh_interval); } } #ifdef HAVE_MAGICK nocache = map_refresh_interval_temp; #endif // HAVE_MAGICK } } if (strncasecmp(line, "TRANSPARENT", 11) == 0) { // need to make this read a list of colors to zap // out. Use 32-bit unsigned values, so we can // handle 32-bit color displays. if (1 != sscanf (line + 12, "%lx", &temp_trans_color)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } { unsigned short r,g,b; // We'll assume the temp_trans_color has been // specified as a 24-bit quantity r = (temp_trans_color&0xff0000) >> 16; g = (temp_trans_color&0x00ff00)>>8; b = temp_trans_color&0x0000ff; // Now this is an incredible kludge, but seems to be right // Apparently, if QuantumDepth is 16 bits, r, g, and b // values are duplicated in the high and low byte, which // is just bizarre #ifdef HAVE_MAGICK if (QuantumDepth == 16) { r=r|(r<<8); g=g|(g<<8); b=b|(b<<8); } #endif // HAVE_MAGICK //fprintf(stderr,"Original Transparent %lx\n",temp_trans_color); //fprintf(stderr,"Transparent r,g,b=%x,%x,%x\n",r,g,b); if (visual_type == NOT_TRUE_NOR_DIRECT) { XColor junk; #ifdef HAVE_MAGICK if (QuantumDepth == 16) { junk.red=r; junk.green=g; junk.blue=b; } else #endif // HAVE_MAGICK { junk.red= r<<8; junk.green = g<<8; junk.blue = b<<8; } XAllocColor(XtDisplay(w),cmap,&junk); temp_trans_color = junk.pixel; } else { pack_pixel_bits(r,g,b,&temp_trans_color); } //fprintf(stderr,"Packed Transparent %lx\n",temp_trans_color); } //fprintf(stderr,"New Transparent: %lx\n",temp_trans_color); // Link color to transparent color list new_trans_color(temp_trans_color); } if (strncasecmp(line, "CROP", 4) == 0) { if (4 != sscanf (line + 5, "%d %d %d %d", &crop_x1, &crop_y1, &crop_x2, &crop_y2 )) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } if (crop_x1 < 0 ) { crop_x1 = 0; } if (crop_y1 < 0 ) { crop_y1 = 0; } if (crop_x2 < 0 ) { crop_x2 = 0; } if (crop_y2 < 0 ) { crop_y2 = 0; } if (crop_x2 < crop_x1 ) { // swap do_crop = crop_x1; crop_x1=crop_x2; crop_x2=do_crop; } if (crop_y2 < crop_y1 ) { // swap do_crop = crop_y1; crop_y1=crop_y2; crop_y2=do_crop; } do_crop = 1; } #ifdef HAVE_MAGICK if (strncasecmp(line, "GAMMA", 5) == 0) imagemagick_options.gamma_flag = sscanf(line + 6, "%f,%f,%f", &imagemagick_options.r_gamma, &imagemagick_options.g_gamma, &imagemagick_options.b_gamma); if (strncasecmp(line, "CONTRAST", 8) == 0) { if (1 != sscanf(line + 9, "%d", &imagemagick_options.contrast)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } } if (strncasecmp(line, "NEGATE", 6) == 0) { if (1 != sscanf(line + 7, "%d", &imagemagick_options.negate)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } } if (strncasecmp(line, "EQUALIZE", 8) == 0) { imagemagick_options.equalize = 1; } if (strncasecmp(line, "NORMALIZE", 9) == 0) { imagemagick_options.normalize = 1; } if (strncasecmp(line, "LEVEL", 5) == 0) { xastir_snprintf(imagemagick_options.level, sizeof(imagemagick_options.level), "%s", line+6); } if (strncasecmp(line, "MODULATE", 8) == 0) { xastir_snprintf(imagemagick_options.modulate, sizeof(imagemagick_options.modulate), "%s", line+9); } #endif // HAVE_MAGICK } (void)fclose (f); } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } // // Check whether OpenStreetMap has been selected. If so, run off to // another routine to service this request. // if (OSMserver_flag == 1) { #ifdef HAVE_MAGICK // We need to send the "nocache" parameter to this function // for those instances when the received map is bad. // Later the GUI can implement a method for refreshing the // latest map and replacing the bad map in the cache. // // fileimg is the server URL, if specified. draw_OSM_map(w, filenm, destination_pixmap, fileimg, OSMstyle, nocache); #endif // HAVE_MAGICK return; } else if (OSMserver_flag == 2) { #ifdef HAVE_MAGICK // fileimg is the server URL, if specified. draw_OSM_tiles(w, filenm, destination_pixmap, fileimg, tileCache, OSMstyle, OSMtileExt); #endif // HAVE_MAGICK return; } // Check whether a WMS server has been selected. If so, run off // to another routine to service this request. // if (WMSserver_flag) { #ifdef HAVE_MAGICK // Pass the URL in "fileimg" draw_WMS_map(w, filenm, destination_pixmap, fileimg, trans_color_head, nocache); // Don't use cached version if non-zero #endif // HAVE_MAGICK return; } if (toporama_flag) { #ifdef HAVE_MAGICK // Pass all of the parameters to it. We'll need to use them // to call draw_geo_image_map() again shortly, after we // fetch the remote .geo file. // draw_toporama_map(w, dir, filenm, alert, alert_color, destination_pixmap, mdf, toporama_flag); #endif // HAVE_MAGICK return; } // DK7IN: I'm experimenting with the adjustment of topo maps with // Transverse Mercator projection. Those maps have equal scaling // in distance while we use equal scaling in degrees. // For now I use the map center as central meridian (I think that // is ok for mapblast), that will change with UTM and Gauss-Krueger // I have introduced new entries in the geo file for that... // I first adjust the x scaling depending on the latitude // Then I move points in y direction depending on the offset from // the central meridian. I hope I get that right with those // approximations. I have the correct formulas, but that will // be very computing intensive and result in slow map loading... // if (geo_datum[0] != '\0') // fprintf(stderr,"Map Datum: %s\n",geo_datum); // not used now... if (geo_projection[0] == '\0') // default xastir_snprintf(geo_projection, sizeof(geo_projection), "LatLon"); //fprintf(stderr,"Map Projection: %s\n",geo_projection); // (void)to_upper(geo_projection); if (strcasecmp(geo_projection,"TM") == 0) { map_proj = 1; // Transverse Mercator } else { map_proj = 0; // Lat/Lon, default } #ifdef HAVE_MAGICK if (terraserver_flag) { //http://terraservice.net/download.ashx?t=1&s=10&x=2742&y=26372&z=10&w=820&h=480 if (scale_y <= 4) { t_zoom = 10; // 1m/pixel t_scale = 200; } else if (scale_y <= 8) { t_zoom = 11; // 2m/pixel t_scale = 400; } else if (scale_y <= 16) { t_zoom = 12; // 4m/pixel t_scale = 800; } else if (scale_y <= 32) { t_zoom = 13; // 8m/pixel t_scale = 1600; } else if (scale_y <= 64) { t_zoom = 14; // 16m/pixel t_scale = 3200; } else if (scale_y <= 128) { t_zoom = 15; // 32m/pixel t_scale = 6400; } else { t_zoom = 16; // 64m/pixel t_scale = 12800; } top = -((NW_corner_latitude - 32400000l) / 360000.0); left = (NW_corner_longitude - 64800000l) / 360000.0; ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid, top, left, &top_n, &left_e, zstr0, sizeof(zstr0) ); if (1 != sscanf(zstr0, "%d", &z)) { fprintf(stderr,"draw_geo_image_map:sscanf parsing error\n"); } bottom = -((SE_corner_latitude - 32400000l) / 360000.0); right = (SE_corner_longitude - 64800000l) / 360000.0; ll_to_utm_ups(gDatum[D_NAD_83_CONUS].ellipsoid, bottom, right, &bottom_n, &right_e, zstr1, sizeof(zstr1) ); // // NOTE: // POSSIBLE FUTURE ENHANCEMENT: // If zstr0 != zstr1, we have a viewscreen that crosses a UTM zone // boundary. Terraserver/Toposerver will only feed us a map for one // side of it or the other. It'd be VERY nice if some day we could // check for this condition and do two map loads instead of the one. // We'd need to stop drawing right at the boundary for each map // also, so that they'd tile together nicely. // map_top_n = (int)((top_n / t_scale) + 1) * t_scale; map_left_e = (int)((left_e / t_scale) + 0) * t_scale; utm_ups_to_ll(gDatum[D_NAD_83_CONUS].ellipsoid, map_top_n, map_left_e, zstr0, &top, &left); // Below here things can get messed up. We can end up with very // large and/or negative values for geo_image_width and/or // geo_image_height. Usually happens around UTM zone boundaries. // // Terraserver uses UTM coordinates for specifying the maps instead // of lat/long. Note that we're also not supposed to cross UTM // zones in our requests. // // t = 1 - 4, theme. 1=DOQ (aerial photo) // 2=DRG (topo) // 3=shaded relief // 4=Color photos/Urban areas // s = 10 - 16, scale. 10=1 meter/pixel. 11=2 meters/pixel. // x = UTM easting, center of image // y = UTM northing, center of image // z = 1 - 60, UTM zone, center of image // w = 50 - 2000, width in pixels // h = 50 - 2000, height in pixels // logo = 0/1, USGS logo in image if 1 // // This number gets messed up if we cross zones. UTM lines // are slanted, so we _can_ cross zones vertically! geo_image_height = abs( (((int)map_top_n - (int)bottom_n) * 200 / t_scale) ); // This number gets messed up if we cross zones geo_image_width = abs( (((int)right_e - (int)map_left_e) * 200 / t_scale) ); //fprintf(stderr,"\ngeo_image_height:%d\tmap_top_n:%0.1f\tbottom_n:%0.1f\tt_scale:%d\n", //geo_image_height, //map_top_n, //bottom_n, //t_scale); // map_top_n is the one that goes whacko, throwing off the height. // Check whether this is because we're crossing a UTM zone. We // _can_ cross zones vertically because the UTM lines are slanted. //fprintf(stderr,"geo_image_width:%d\tright_e:%0.1f\tmap_left_e:%0.1f\tt_scale:%d\n", //geo_image_width, //right_e, //map_left_e, //t_scale); // right_e is the one that goes whacko, throwing off the width. // Check whether this is because we're crossing a UTM zone. if (geo_image_height < 50) { geo_image_height = 50; } if (geo_image_width < 50) { geo_image_width = 50; } if (geo_image_height > 2000) { geo_image_height = geo_image_width; } if (geo_image_width > 2000) { geo_image_width = geo_image_height; } if (geo_image_height > 2000) { geo_image_height = geo_image_width; } if (geo_image_width > 2000) { geo_image_width = geo_image_height; } // map_width = right - left; // map_height = top - bottom; tp[0].img_x = 0; tp[0].img_y = 0; tp[0].x_long = 64800000l + (360000.0 * left); tp[0].y_lat = 32400000l + (360000.0 * (-top)); tp[1].img_x = geo_image_width - 1; tp[1].img_y = geo_image_height - 1; tp[1].x_long = 64800000l + (360000.0 * right); tp[1].y_lat = 32400000l + (360000.0 * (-bottom)); url_n = (int)(top_n / t_scale); // The request URL does not use the url_e = (int)(left_e / t_scale); // N/E of the map corner xastir_snprintf(fileimg, sizeof(fileimg), "http://terraservice.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d", // "http://terraserver-usa.net/download.ashx?t=%d\046s=%d\046x=%d\046y=%d\046z=%d\046w=%d\046h=%d", terraserver_flag, // 1, 2, 3, or 4 t_zoom, url_e, // easting, center of map url_n, // northing, center of map z, geo_image_width, geo_image_height); //http://terraservice.net/download.ashx?t=1&s=11&x=1384&y=13274&z=10&w=1215&h=560 //fprintf(stderr,"%s\n",fileimg); if (debug_level & 16) { fprintf(stderr,"URL: %s\n", fileimg); } } #endif // HAVE_MAGICK // // DK7IN: we should check what we got from the geo file // we use geo_image_width, but it might not be initialised... // and it's wrong if the '\n' is missing at the end... /* * Here are the corners of our viewport, using the Xastir * coordinate system. Notice that Y is upside down: * * left edge of view = NW_corner_longitude * right edge of view = SE_corner_longitude * top edge of view = NW_corner_latitude * bottom edge of view = SE_corner_latitude * * The corners of our map will soon be (after translating the * tiepoints to the corners if they're not already there): * * left edge of map = tp[0].x_long in Xastir format * right edge of map = tp[1].x_long * top edge of map = tp[0].y_lat * bottom edge of map = tp[1].y_lat * */ map_c_L = tp[0].x_long - NW_corner_longitude; // map left coordinate map_c_T = tp[0].y_lat - NW_corner_latitude; // map top coordinate tp_c_dx = (long)(tp[1].x_long - tp[0].x_long);// Width between tiepoints tp_c_dy = (long)(tp[1].y_lat - tp[0].y_lat); // Height between tiepoints // Check for tiepoints being in wrong relation to one another if (tp_c_dx < 0) { tp_c_dx = -tp_c_dx; // New width between tiepoints } if (tp_c_dy < 0) { tp_c_dy = -tp_c_dy; // New height between tiepoints } if (debug_level & 512) { fprintf(stderr,"X tiepoint width: %ld\n", tp_c_dx); fprintf(stderr,"Y tiepoint width: %ld\n", tp_c_dy); } // Calculate step size per pixel map_c_dx = ((double) tp_c_dx / abs(tp[1].img_x - tp[0].img_x)); map_c_dy = ((double) tp_c_dy / abs(tp[1].img_y - tp[0].img_y)); // Scaled screen step size for use with XFillRectangle below scr_dx = (int) (map_c_dx / scale_x) + 1; scr_dy = (int) (map_c_dy / scale_y) + 1; if (debug_level & 512) { fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } // calculate top left map corner from tiepoints if (tp[0].img_x != 0) { tp[0].x_long -= (tp[0].img_x * map_c_dx); // map left edge longitude map_c_L = tp[0].x_long - NW_corner_longitude; // delta ?? tp[0].img_x = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 x: %d\t%lu\n", tp[0].img_x, tp[0].x_long); } } if (tp[0].img_y != 0) { tp[0].y_lat -= (tp[0].img_y * map_c_dy); // map top edge latitude map_c_T = tp[0].y_lat - NW_corner_latitude; tp[0].img_y = 0; if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_0 y: %d\t%lu\n", tp[0].img_y, tp[0].y_lat); } } // By this point, geo_image_width & geo_image_height have to // have been initialized to something. if ( (geo_image_width == 0) || (geo_image_height == 0) ) { if ( (strncasecmp ("http", fileimg, 4) == 0) || (strncasecmp ("ftp", fileimg, 3) == 0)) { // what to do for remote files... hmm... -cbell } else { #ifdef HAVE_MAGICK GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", fileimg); if (debug_level & 16) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { fprintf(stderr,"1 "); fprintf(stderr,"File %s could not be read\n",image_info->filename); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); image = PingImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); #ifdef USE_MAP_CACHE // clear from cache if bad if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete map from cache\n"); } } #endif if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 16) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } geo_image_width = image->magick_columns; geo_image_height = image->magick_rows; // close and clean up imagemagick if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); #endif // HAVE_MAGICK } } // fprintf(stderr, "Geo: %s: size %ux%u.\n",file, geo_image_width, geo_image_height); // if that did not generate a valid size, bail out... if ( (geo_image_width == 0) || (geo_image_height == 0) ) { fprintf(stderr,"*** Skipping '%s', IMAGESIZE tag missing or incorrect. ***\n",file); fprintf(stderr,"Perhaps no XPM/ImageMagick/GraphicsMagick library support is installed?\n"); return; } // calculate bottom right map corner from tiepoints // map size is geo_image_width / geo_image_height if (tp[1].img_x != (geo_image_width - 1) ) { tp[1].img_x = geo_image_width - 1; tp[1].x_long = tp[0].x_long + (tp[1].img_x * map_c_dx); // right if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 x: %d\t%lu\n", tp[1].img_x, tp[1].x_long); } } if (tp[1].img_y != (geo_image_height - 1) ) { tp[1].img_y = geo_image_height - 1; tp[1].y_lat = tp[0].y_lat + (tp[1].img_y * map_c_dy); // bottom if (debug_level & 512) { fprintf(stderr,"Translated tiepoint_1 y: %d\t%lu\n", tp[1].img_y, tp[1].y_lat); } } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. if (terraserver_flag) { // Force the extents to the edges of the earth for the // index file. index_update_xastir(filenm, // Filename only 64800000l, // Bottom 0l, // Top 0l, // Left 129600000l, // Right 0); // Default Map Level } else { index_update_xastir(filenm, // Filename only tp[1].y_lat, // Bottom tp[0].y_lat, // Top tp[0].x_long, // Left tp[1].x_long, // Right 0); // Default Map Level } // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Loading/Indexing ... return; // Done indexing this file } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check whether map is inside our current view // bottom top left right if (!map_visible (tp[1].y_lat, tp[0].y_lat, tp[0].x_long, tp[1].x_long)) { if (debug_level & 16) { fprintf(stderr,"Map not in current view, skipping: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr," Map: lat0:%ld\t lon0:%ld\t lat1:%ld\t lon1:%ld\n", tp[0].y_lat, tp[0].x_long, tp[1].y_lat, tp[1].x_long); fprintf(stderr,"Screen: NWlat:%ld\tNWlon:%ld\tSElat:%ld\tSElon:%ld\n", NW_corner_latitude, NW_corner_longitude, SE_corner_latitude, SE_corner_longitude); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } return; // Skip this map #ifdef FUZZYRASTER } else if (((float)(map_c_dx/scale_x) > rasterfuzz) || ((float)(scale_x/map_c_dx) > rasterfuzz) || ((float)(map_c_dy/scale_y) > rasterfuzz) || ((float)(scale_y/map_c_dy) > rasterfuzz)) { fprintf(stderr,"Skipping fuzzy map %s with sx=%f,sy=%f.\n", file, (float)(map_c_dx/scale_x),(float)(map_c_dy/scale_y)); return; #endif //FUZZYRASTER } else if (debug_level & 16) { fprintf(stderr,"Loading imagemap: %s\n", file); fprintf(stderr,"\nImage: %s\n", file); fprintf(stderr,"Image size %d %d\n", geo_image_width, geo_image_height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } // Update statusline xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading/Indexing ... #ifndef NO_XPM atb.valuemask = 0; #endif // NO_XPM HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Best here would be to add the process ID or user ID to the filename // (to keep the filename distinct for different users), and to check // the timestamp on the map file. If it's older than xx minutes, go // get another one. Make sure to delete the temp files when closing // Xastir. It'd probably be good to check for old files and delete // them when starting Xastir as well. // Check to see if we have to use "wget" to go get an internet map if ( (strncasecmp ("http", fileimg, 4) == 0) || (strncasecmp ("ftp", fileimg, 3) == 0) || (terraserver_flag) ) { #ifdef HAVE_MAGICK char *ext; if (debug_level & 16) { fprintf(stderr,"ftp or http file: %s\n", fileimg); } if (terraserver_flag) { ext = "jpg"; } else { ext = get_map_ext(fileimg); // Use extension to determine image type } if (debug_level & 512) { query_start_time=time(&query_start_time); } #ifdef USE_MAP_CACHE if (nocache || map_cache_fetch_disable) { // Delete old copy from the cache if (map_cache_fetch_disable && fileimg[0] != '\0') { if (map_cache_del(fileimg)) { if (debug_level & 512) { fprintf(stderr,"Couldn't delete old map from cache\n"); } } } // Simulate a cache miss map_cache_return = 1; } else { // Look for the file in the cache map_cache_return = map_cache_get(fileimg,local_filename); } if (debug_level & 512) { fprintf(stderr,"map_cache_return: %d\n", map_cache_return); } // If nocache is non-zero, we're supposed to refresh the map // at intervals. Don't use a cached version of the map in // that case. // if (nocache || map_cache_return != 0 ) { // Caching not requested or cached file not found. We // must snag the remote file via libcurl or wget. if (nocache) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext); } else { cache_file_id = map_cache_fileid(); xastir_snprintf(local_filename, sizeof(local_filename), "%s/map_%s.%s", get_user_base_dir("map_cache", temp_file_path, sizeof(temp_file_path)), cache_file_id, ext); free(cache_file_id); } #else // USE_MAP_CACHE xastir_snprintf(local_filename, sizeof(local_filename), "%s/map.%s", get_user_base_dir("tmp", temp_file_path, sizeof(temp_file_path)),ext); #endif // USE_MAP_CACHE // Erase any previously existing local file by the same // name. This avoids the problem of having an old map image // here and the code trying to display it when the download // fails. unlink( local_filename ); if (fetch_remote_file(fileimg, local_filename)) { // Had trouble getting the file. Abort. return; } #ifdef USE_MAP_CACHE // Cache the map only if map_refresh_interval_temp is zero if (!map_refresh_interval_temp) { map_cache_put(fileimg,local_filename); } } // end if is cached #endif // MAP_CACHE if (debug_level & 512) { fprintf (stderr, "Fetch or query took %d seconds\n", (int) (time(&query_end_time) - query_start_time)); } // Set permissions on the file so that any user can overwrite it. chmod(local_filename, 0666); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. // Tell ImageMagick where to find it xastir_snprintf(file, sizeof(file), "%s", local_filename); #endif // HAVE_MAGICK } else { //fprintf(stderr,"Not ftp or http file\n"); // We now re-use the "file" variable. It'll hold the //name of the map file now instead of the .geo file. xastir_snprintf(file, sizeof(file), "%s", fileimg); } //fprintf(stderr,"File = %s\n",file); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // The status line is not updated yet, probably 'cuz we're too busy // getting the map in this thread and aren't redrawing? #ifdef HAVE_MAGICK GetExceptionInfo(&exception); image_info=CloneImageInfo((ImageInfo *) NULL); xastir_snprintf(image_info->filename, sizeof(image_info->filename), "%s", file); if (debug_level & 16) { fprintf(stderr,"Copied %s into image info.\n", file); fprintf(stderr,"image_info got: %s\n", image_info->filename); fprintf(stderr,"Entered ImageMagick code.\n"); fprintf(stderr,"Attempting to open: %s\n", image_info->filename); } // We do a test read first to see if the file exists, so we // don't kill Xastir in the ReadImage routine. f = fopen (image_info->filename, "r"); if (f == NULL) { fprintf(stderr,"2 "); fprintf(stderr,"File %s could not be read\n",image_info->filename); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } (void)fclose (f); HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } image = ReadImage(image_info, &exception); if (image == (Image *) NULL) { MagickWarning(exception.severity, exception.reason, exception.description); //fprintf(stderr,"MagickWarning\n"); if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (debug_level & 16) { fprintf(stderr,"Color depth is %i \n", (int)image->depth); } /* if (image->colorspace != RGBColorspace) { fprintf(stderr,"TBD: I don't think we can deal with colorspace != RGB"); if (image) DestroyImage(image); if (image_info) DestroyImageInfo(image_info); DestroyExceptionInfo(&exception); return; } */ width = image->columns; height = image->rows; if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } // gamma setup if (imagemagick_options.gamma_flag == 0 || imagemagick_options.gamma_flag == 1) { if (imagemagick_options.gamma_flag == 0) // if not set in file, set to 1.0 { imagemagick_options.r_gamma = 1.0; } imagemagick_options.gamma_flag = 1; // set flag to do gamma imagemagick_options.r_gamma += imagemagick_gamma_adjust; if (imagemagick_options.r_gamma > 0.95 && imagemagick_options.r_gamma < 1.05) { imagemagick_options.gamma_flag = 0; // don't bother if near 1.0 } else if (imagemagick_options.r_gamma < 0.1) { imagemagick_options.r_gamma = 0.1; // 0.0 is black and negative is really wacky } xastir_snprintf(gamma, sizeof(gamma), "%.1f", imagemagick_options.r_gamma); } else if (imagemagick_options.gamma_flag == 3) { // No checking if you specify 3 channel gamma correction, so you can try negative // numbers, etc. if you wish. imagemagick_options.gamma_flag = 1; // set flag to do gamma imagemagick_options.r_gamma += imagemagick_gamma_adjust; imagemagick_options.g_gamma += imagemagick_gamma_adjust; imagemagick_options.b_gamma += imagemagick_gamma_adjust; xastir_snprintf(gamma, sizeof(gamma), "%.1f,%.1f,%.1f", imagemagick_options.r_gamma, imagemagick_options.g_gamma, imagemagick_options.b_gamma); } else { imagemagick_options.gamma_flag = 0; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.gamma_flag) { if (debug_level & 16) { fprintf(stderr,"gamma=%s\n", gamma); } GammaImage(image, gamma); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.contrast != 0) { if (debug_level & 16) { fprintf(stderr,"contrast=%d\n", imagemagick_options.contrast); } ContrastImage(image, imagemagick_options.contrast); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.negate != -1) { if (debug_level & 16) { fprintf(stderr,"negate=%d\n", imagemagick_options.negate); } NegateImage(image, imagemagick_options.negate); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.equalize) { if (debug_level & 16) { fprintf(stderr,"equalize"); } EqualizeImage(image); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.normalize) { if (debug_level & 16) { fprintf(stderr,"normalize"); } NormalizeImage(image); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.level[0] != '\0') { if (debug_level & 16) { fprintf(stderr,"level=%s\n", imagemagick_options.level); } LevelImage(image, imagemagick_options.level); } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (imagemagick_options.modulate[0] != '\0') { if (debug_level & 16) { fprintf(stderr,"modulate=%s\n", imagemagick_options.modulate); } ModulateImage(image, imagemagick_options.modulate); } /* // Else check the menu option for raster intensity else if (raster_map_intensity < 1.0) { char tempstr[30]; int temp_i; temp_i = (int)(raster_map_intensity * 100.0); xastir_snprintf(tempstr, sizeof(tempstr), "%d, 100, 100", temp_i); //fprintf(stderr,"Modulate: %s\n", tempstr); ModulateImage(image, tempstr); } */ if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } // crop image: if we just use CropImage(), then the tiepoints will be off // make border pixels transparent. // cbell - this is a first attempt, it will be integrated into the // lower loops to speed them up... if ( do_crop) { int x, y; //PixelPacket target; PixelPacket *q; // target=GetOnePixel(image,0,0); for (y=0; y < (long) image->rows; y++) { #if defined(HAVE_GRAPHICSMAGICK) q=GetImagePixels(image,0,y,image->columns,1); #else q=GetAuthenticPixels(image,0,y,image->columns,1,&exception); #endif if (q == (PixelPacket *) NULL) { fprintf(stderr, "GetImagePixels Failed....\n"); } for (x=0; x < (int) image->columns; x++) { if ( (x < crop_x1) || (x > crop_x2) || (y < crop_y1) || (y > crop_y2)) { q->opacity=(Quantum) 1; } q++; } #if defined(HAVE_GRAPHICSMAGICK) if (!SyncImagePixels(image)) { fprintf(stderr, "SyncImagePixels Failed....\n"); } #else if (!SyncAuthenticPixels(image,&exception)) { fprintf(stderr, "SyncImagePixels Failed....\n"); } #endif } } // If were are drawing to a low bpp display (typically < 8bpp) // try to reduce the number of colors in an image. // This may take some time, so it would be best to do ahead of // time if it is a static image. if (visual_type == NOT_TRUE_NOR_DIRECT && GetNumberColors(image, NULL, &exception) > 128) { if (image->storage_class == PseudoClass) { CompressImageColormap(image); // Remove duplicate colors } // Quantize down to 128 will go here... } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #if defined(HAVE_GRAPHICSMAGICK) pixel_pack = GetImagePixels(image, 0, 0, image->columns, image->rows); #else pixel_pack = GetAuthenticPixels(image, 0, 0, image->columns, image->rows,&exception); #endif if (!pixel_pack) { fprintf(stderr,"pixel_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #if defined(HAVE_GRAPHICSMAGICK) #if (MagickLibVersion < 0x201702) index_pack = GetIndexes(image); #else index_pack = AccessMutableIndexes(image); #endif #else index_pack = GetAuthenticIndexQueue(image); #endif if (image->storage_class == PseudoClass && !index_pack) { fprintf(stderr,"PseudoClass && index_pack == NULL!!!"); if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); return; } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } if (debug_level & 16) #ifdef HAVE_GRAPHICSMAGICK fprintf(stderr,"Colors = %d\n", (int)image->colors); #else // HAVE_GRAPHICSMAGICK fprintf(stderr,"Colors = %ld\n", image->colors); #endif // HAVE_GRAPHICSMAGICK // Set up our own version of the color map. if (image->storage_class == PseudoClass && image->colors <= 256) { for (l = 0; l < (int)image->colors; l++) { int leave_unchanged = 0; // Need to check how to do this for ANY image, as ImageMagick can read in all sorts // of image files temp_pack = image->colormap[l]; if (debug_level & 16) fprintf(stderr,"Colormap color is %1.2f %1.2f %1.2f \n", (float)temp_pack.red, (float)temp_pack.green, (float)temp_pack.blue); // Here's a tricky bit: PixelPacket entries are defined as Quantum's. Quantum // is defined in /usr/include/magick/image.h as either an unsigned short or an // unsigned char, depending on what "configure" decided when ImageMagick was installed. // We can determine which by looking at MaxRGB or QuantumDepth. // if (QuantumDepth == 16) // Defined in /usr/include/magick/magick_config.h { if (debug_level & 16) { fprintf(stderr,"Color quantum is [0..65535]\n"); } my_colors[l].red = temp_pack.red; my_colors[l].green = temp_pack.green; my_colors[l].blue = temp_pack.blue; } else // QuantumDepth = 8 { if (debug_level & 16) { fprintf(stderr,"Color quantum is [0..255]\n"); } my_colors[l].red = temp_pack.red * 256; my_colors[l].green = temp_pack.green * 256; my_colors[l].blue = temp_pack.blue * 256; } // Take care not to screw up the transparency value by // the raster_map_intensity multiplication factor. if ( trans_color_head ) { //fprintf(stderr,"Checking for transparency\n"); // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (check_trans(my_colors[l],trans_color_head) ) { // Found a transparent color. Leave it alone. leave_unchanged++; //fprintf(stderr,"Found transparency\n"); // We never get here! } } // Use the map_intensity value if it's not a transparent // color we're dealing with. if (!leave_unchanged) { my_colors[l].red = my_colors[l].red * raster_map_intensity; my_colors[l].green = my_colors[l].green * raster_map_intensity; my_colors[l].blue = my_colors[l].blue * raster_map_intensity; } // Get the color allocated on < 8bpp displays. pixel color is written to my_colors.pixel if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } if (debug_level & 16) fprintf(stderr,"Color allocated is %li %i %i %i \n", my_colors[l].pixel, my_colors[l].red, my_colors[l].blue, my_colors[l].green); } } if (check_interrupt(image, image_info, &exception, &da, &pixmap, &gc, screen_width, screen_height)) { return; } #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG if (debug_level & 16) { fprintf(stderr,"Image size %d %d\n", width, height); fprintf(stderr,"Unique colors = %ld\n", GetNumberColors(image, NULL, &exception)); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx,(int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); fprintf(stderr,"is Gray Image = %i\n", IsGrayImage( image, &exception )); fprintf(stderr,"is Monochrome Image = %i\n", IsMonochromeImage( image, &exception )); //fprintf(stderr,"is Opaque Image = %i\n", IsOpaqueImage( image, &exception )); //fprintf(stderr,"is PseudoClass = %i\n", image->storage_class == PseudoClass); fprintf(stderr,"image matte is %i\n", image->matte); fprintf(stderr,"Colorspace = %i\n", image->colorspace); if (image->colorspace == UndefinedColorspace) { fprintf(stderr,"Class Type = Undefined\n"); } else if (image->colorspace == RGBColorspace) { fprintf(stderr,"Class Type = RGBColorspace\n"); } else if (image->colorspace == GRAYColorspace) { fprintf(stderr,"Class Type = GRAYColorspace\n"); } else if (image->colorspace == sRGBColorspace) { fprintf(stderr,"Class Type = sRGBColorspace\n"); } } #else // HAVE_MAGICK // We don't have ImageMagick libs compiled in, so use the // XPM library instead, but only if we HAVE XPM. #ifndef NO_XPM HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Check whether file has .xpm or .xpm.Z or .xpm.gz at the end. // If not, don't use the XpmReadFileToImage call below. if ( !strstr(filenm,"xpm") && !strstr(filenm,"XPM") && !strstr(filenm,"Xpm") ) { fprintf(stderr, "Error: File format not supported by XPM library: %s\n", filenm); return; } /* XpmReadFileToImage is the call we wish to avoid if at all * possible. On large images this can take quite a while. We * check above to see whether the image is inside our viewport, * and if not we skip loading the image. */ if (! XpmReadFileToImage (XtDisplay (w), file, &xi, NULL, &atb) == XpmSuccess) { fprintf(stderr,"ERROR loading %s\n", file); if (xi) { XDestroyImage (xi); } return; } if (debug_level & 16) { fprintf(stderr,"Image size %d %d\n", (int)atb.width, (int)atb.height); fprintf(stderr,"XX: %ld YY:%ld Sx %f %d Sy %f %d\n", map_c_L, map_c_T, map_c_dx, (int) (map_c_dx / scale_x), map_c_dy, (int) (map_c_dy / scale_y)); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (xi) { XDestroyImage (xi); } // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } width = atb.width; height = atb.height; #else // NO_XPM fprintf(stderr,"Xastir was configured with neither XPM library nor (Image/Graphics)Magick, cannot display map %s\n",filenm); #endif // NO_XPM #endif // HAVE_MAGICK // draw the image from the file out to the map screen // Get the border values for the X and Y for loops used // for the XFillRectangle call later. map_c_yc = (tp[0].y_lat + tp[1].y_lat) / 2; // vert center of map as reference // map_y_ctr = (long)(height / 2 +0.499); scale_x0 = get_x_scale(0,map_c_yc,scale_y); // reference scaling at vert map center map_c_xc = (tp[0].x_long + tp[1].x_long) / 2; // hor center of map as reference map_x_ctr = (long)(width / 2 +0.499); // scr_x_mc = (map_c_xc - NW_corner_longitude) / scale_x; // screen coordinates of map center // calculate map pixel range in y direction that falls into screen area // c_y_max = 0ul; map_y_min = map_y_max = 0l; for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position if (scr_y > 0) { if (scr_y < screen_height) { map_y_max = map_y_0; // update last map pixel in y // c_y_max = (unsigned long)c_y;// bottom map inside screen coordinate } else { break; // done, reached bottom screen border } } else // pixel is above screen { map_y_min = map_y_0; // update first map pixel in y } } // fprintf(stderr,"map top: %ld bottom: %ld\n",tp[0].y_lat,tp[1].y_lat); c_y_min = (unsigned long)(tp[0].y_lat + map_y_min * map_c_dy); // top map inside screen coordinate // // find the y coordinate nearest to the equator // c_y = 90*60*60*100; // Equator // if ((c_y_min>c_y && c_y_max>c_y) || (c_y_min abs(c_y_max-c_y)) // c_y = c_y_max; // north // else // c_y = c_y_min; // south // } // scale_x0 = get_x_scale(0,(long)c_y,scale_y); // calc widest map area in x // if (map_proj != 1) { // calculate map pixel range in x direction that falls into screen area map_x_min = map_x_max = 0l; for (map_x = 0, c_x = tp[0].x_long; map_x < (long)width; map_x++, c_x += map_c_dx) { scr_x = (c_x - NW_corner_longitude)/ scale_x; // current screen position if (scr_x > 0) { if (scr_x < screen_width) { map_x_max = map_x; // update last map pixel in x } else { break; // done, reached right screen border } } else // pixel is left from screen { map_x_min = map_x; // update first map pixel in x } } c_x_min = (unsigned long)(tp[0].x_long + map_x_min * map_c_dx); // left map inside screen coordinate // } // for (scr_y = scr_y_min; scr_y <= scr_y_max;scr_y++) { // screen lines // } // test = 1; // DK7IN: debuging scr_yp = -1; scr_c_xr = SE_corner_longitude; c_dx = map_c_dx; // map pixel width scale_xa = scale_x0; // the compiler likes it ;-) // for (map_y_0 = 0, c_y = tp[0].y_lat; map_y_0 < (long)height; map_y_0++, c_y += map_c_dy) { // scr_y = (c_y - NW_corner_latitude) / scale_y; // current screen position map_done = 0; map_act = 0; map_seen = 0; scr_y = screen_height - 1; #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG if (check_interrupt( #ifdef HAVE_MAGICK image, image_info, &exception, #else // HAVE_MAGICK xi, #endif // HAVE_MAGICK &da, &pixmap, &gc, screen_width, screen_height)) { return; } // loop over map pixel rows for (map_y_0 = map_y_min, c_y = (double)c_y_min; (map_y_0 <= map_y_max) || (map_proj == 1 && !map_done && scr_y < screen_height); map_y_0++, c_y += map_c_dy) { if (check_interrupt( #ifdef HAVE_MAGICK image, image_info, &exception, #else // HAVE_MAGICK xi, #endif // HAVE_MAGICK &da, &pixmap, &gc, screen_width, screen_height)) { return; } scr_y = (c_y - NW_corner_latitude) / scale_y; if (scr_y != scr_yp) // don't do a row twice { scr_yp = scr_y; // remember as previous y if (map_proj == 1) // Transverse Mercator correction in x { scale_xa = get_x_scale(0,(long)c_y,scale_y); // recalc scale_x for current y c_dx = map_c_dx * scale_xa / scale_x0; // adjusted map pixel width map_x_min = map_x_ctr - (map_c_xc - NW_corner_longitude) / c_dx; if (map_x_min < 0) { map_x_min = 0; } c_x_min = map_c_xc - (map_x_ctr - map_x_min) * c_dx; map_x_max = map_x_ctr - (map_c_xc - scr_c_xr) / c_dx; if (map_x_max > (long)width) { map_x_max = width; } scr_dx = (int) (c_dx / scale_x) + 1; // at least 1 pixel wide } // if (c_y == (double)c_y_min) { // first call // fprintf(stderr,"map: min %ld ctr %ld max %ld, c_dx %ld, c_x_min %ld, c_y_min %ld\n",map_x_min,map_x_ctr,map_x_max,(long)c_dx,c_x_min,c_y_min); // } scr_xp = -1; // loop over map pixel columns map_act = 0; scale_x_nm = calc_dscale_x(0,(long)c_y) / 1852.0; // nm per Xastir coordinate for (map_x = map_x_min, c_x = (double)c_x_min; map_x <= map_x_max; map_x++, c_x += c_dx) { scr_x = (c_x - NW_corner_longitude) / scale_x; if (scr_x != scr_xp) // don't do a pixel twice { scr_xp = scr_x; // remember as previous x if (map_proj == 1) // Transverse Mercator correction in y { // DK7IN-- dist = (90*60 - (c_y / 6000.0)); // equator distance in nm // ?? 180W discontinuity! not done yet ew_ofs = (c_x - (double)map_c_xc) * scale_x_nm; // EW offset from center in nm //corrfact = (map_y_0 - map_y_ctr)/(2*map_y_ctr); // 0..50% //corrfact = fabs(ew_ofs/dist)*3.0; //corrfact = 1.0-1.0*(0.5*map_y_0 / map_y_ctr); corrfact = 1.0; c_y_a = (fabs(dist) - sqrt((double)(dist*dist - ew_ofs*ew_ofs)))*6000.0; // in Xastir units if (dist < 0) // S { map_y = map_y_0 + (long)(corrfact*c_y_a / map_c_dy); // coord per pixel } else // N { map_y = map_y_0 - (long)(corrfact*c_y_a / map_c_dy); } // if (test < 10) { // fprintf(stderr,"dist: %ldkm, ew_ofs: %ldkm, dy: %ldkm\n",(long)(1.852*dist),(long)(1.852*ew_ofs),(long)(1.852*c_y_a/6000.0)); // fprintf(stderr," corrfact: %f, mapy0: %ld, mapy: %ld\n",corrfact,map_y_0,map_y); // test++; // } } else { map_y = map_y_0; } if (map_y >= 0 && map_y <= tp[1].img_y) // check map boundaries in y direction { map_seen = 1; map_act = 1; // detects blank screen rows (end of map) // DK7IN-- //----- copy pixel from map to screen --------------------- // if (c_y == (double)c_y_min && (scr_x < 5 || (c_x == (double)c_x_min))) { // first call // fprintf(stderr,"map: x %ld y %ld scr: x %ld y %ld dx %d, dy %d\n",map_x,map_y,scr_x,scr_y,scr_dx,scr_dy); // fprintf(stderr,"color: %ld\n",XGetPixel (xi, map_x, map_y)); // // 65529 // } // now copy a pixel from the map image to the screen #ifdef HAVE_MAGICK l = map_x + map_y * image->columns; trans_skip = 1; // possibly transparent if (image->storage_class == PseudoClass) { if ( trans_color_head && check_trans(my_colors[(int)index_pack[l]],trans_color_head) ) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[(int)index_pack[l]].pixel); trans_skip = 0; // draw it } } else { // It is not safe to assume that the red/green/blue // elements of pixel_pack of type Quantum are the // same as the red/green/blue of an XColor! if (QuantumDepth==16) { my_colors[0].red=pixel_pack[l].red; my_colors[0].green=pixel_pack[l].green; my_colors[0].blue=pixel_pack[l].blue; } else // QuantumDepth=8 { // shift the bits of the 8-bit quantity so that // they become the high bigs of my_colors.* my_colors[0].red=pixel_pack[l].red*256; my_colors[0].green=pixel_pack[l].green*256; my_colors[0].blue=pixel_pack[l].blue*256; } // NOW my_colors has the right r,g,b range for // pack_pixel_bits pack_pixel_bits(my_colors[0].red * raster_map_intensity, my_colors[0].green * raster_map_intensity, my_colors[0].blue * raster_map_intensity, &my_colors[0].pixel); if ( trans_color_head && check_trans(my_colors[0],trans_color_head) ) { trans_skip = 1; // skip it } else { XSetForeground(XtDisplay(w), gc, my_colors[0].pixel); trans_skip = 0; // draw it } } #else // HAVE_MAGICK (void)XSetForeground (XtDisplay (w), gc, XGetPixel (xi, map_x, map_y)); #endif // HAVE_MAGICK // Skip drawing if a transparent pixel #ifdef HAVE_MAGICK if ( pixel_pack[l].opacity == 0 && !trans_skip ) // skip transparent #else // HAVE_MAGICK if (!trans_skip) // skip transparent #endif // HAVE_MAGICK (void)XFillRectangle (XtDisplay (w),pixmap,gc,scr_x,scr_y,scr_dx,scr_dy); } // check map boundaries in y direction } } // loop over map pixel columns if (map_seen && !map_act) { map_done = 1; } } } // loop over map pixel rows #ifdef HAVE_MAGICK if (image) { DestroyImage(image); } if (image_info) { DestroyImageInfo(image_info); } DestroyExceptionInfo(&exception); #else // HAVE_MAGICK if (xi) { XDestroyImage (xi); } #endif // HAVE_MAGICK #ifdef TIMING_DEBUG time_mark(0); #endif // TIMING_DEBUG #endif // NO_GRAPHICS } Xastir-Release-2.2.4/src/map_gnis.c0000664000175000017500000013162115151324131016055 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" //NOTE: This function has a problem if a non-gnis file is labeled //with a ".gnis" extension. It causes a segfault in Xastir. More //error checking needs to be done in order to prevent this. // draw_gnis_map() // // Allows drawing a background map of labels for the viewport. // Example format (old): // "WA","Abbey View Memorial Park","cemetery","Snohomish","53","061","474647N","1221650W","47.77972","-122.28056","","","","","420","","Edmonds East" // // Example format (new): // 376016|ID|12th Ave Drain|stream|Canyon|16|027|433107N|1163348W|43.51861|-116.56333||||||||Nampa // // These types of files are available from http://geonames.usgs.gov/ // under "Download State Gazetteer Data - Available Via Anonymous FTP". // A typical filename would be: "WA_Features_20090401.zip". Do not get the other // types of files which are columnar. The files that we parse are // pipe-delimited. // void draw_gnis_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags * UNUSED(mdf) ) { char file[MAX_FILENAME]; // Complete path/name of GNIS file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of GNIS file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char name[200]; char type[100]; char county[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; long min_lat, min_lon, max_lat, max_lon; int ok; long x,y; char symbol_table, symbol_id, symbol_over; unsigned long bottom_extent = 0l; unsigned long top_extent = 0l; unsigned long left_extent = 0l; unsigned long right_extent = 0l; char status_text[MAX_FILENAME]; int count = 0; //fprintf(stderr,"draw_gnis_map starting: %s/%s\n",dir,filenm); xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); // Screen view min_lat = SE_corner_latitude; max_lat = NW_corner_latitude; min_lon = NW_corner_longitude; max_lon = SE_corner_longitude; // The map extents in the map index are checked in draw_map to // see whether we should draw the map at all. // Update the statusline for this map name // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); } statusline(status_text,0); // Loading/Indexing ... HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* Latest pipe-delimited format from USGS (as of 08/12/2004): ---------------------------------------------------------- Feature ID Number (FID) State Alpha Code Feature Name Feature Type County Name State Number Code (FIPS Code) County Number Code (FIPS Code) Primary Latitude (DMS) Primary Longitude (DMS) Primary Latitude (decimal degrees) Primary Longitude (decimal degrees) Source Latitude (DMS) Source Longitude (DMS) Source Latitude (decimal degrees) Source Longitude (decimal degrees) Elevation Estimated Population Federal Status Cell Name */ // Attempt to open the file f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) // Loop through entire file { int lat_in_view = 0; count++; if ((count % 16) == 0) { // Check whether map drawing should be interrupted. // Check every 16 lines. // HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose (f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } } if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { // It is common for these lines to have incredible // numbers of spaces at the end, so trim them here. (void)remove_trailing_spaces(line); if (strlen(line) > 0) { // Default population, in case the field isn't // present in the file. xastir_snprintf(population,sizeof(population),"0"); // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // 2008 Format follows //FEATURE_ID|FEATURE_NAME|FEATURE_CLASS|STATE_ALPHA|STATE_NUMERIC|COUNTY_NAME|COUNTY_NUMERIC|PRIMARY_LAT_DMS|PRIM_LONG_DMS|PRIM_LAT_DEC|PRIM_LONG_DEC|SOURCE_LAT_DMS|SOURCE_LONG_DMS|SOURCE_LAT_DEC|SOURCE_LONG_DEC|ELEVATION|MAP_NAME|DATE_CREATED|DATE_EDITED //205110|Appalachian National Scenic Trail|Trail|PA|42|Perry|099|401920N|0770439W|40.3221113|-77.0775473|||||201|Wertzville|09/12/1979|05/19/2008 //NOTE: We handle running off the end of "line" //via the "continue" statement. Skip the line //if we don't find enough parameters while //parsing. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",j); // Find end of Feature Type field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",i); // Find end of State field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); // Find end of State Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Find end of County Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",j); // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); if (!isdigit((int)latitude[0])) // skip record if not { continue; // numeric! (e.g. "UNKNOWN") } //WE7U clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); if (!isdigit((int)longitude[0])) // skip record if not { continue; // numeric (e.g. UNKNOWN) } //WE7U clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Source Latitude field (DMS) (old // format) or elevation (new format) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (DMS) (old // format) or j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Elevation field i = index(++j, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Estimated Population field j = index(++i, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } if ( j != NULL ) { j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i); } FINISH: // There are two more fields (old format), // "Federal Status" and "Cell Name". We ignore // those for now. if (strlen(latitude) < 7) { continue; // We really don't have any latitude here. } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"draw_gnis_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); // Quick test of latitude to see if it's within // our view. If not and we're not doing // indexing, skip this line and go on to the // next. if (coord_lat <= min_lat && coord_lat >= max_lat) { // Latitude is ok lat_in_view++; } else // Latitude not in current view { // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Process the line 'cuz we're indexing } else // Not indexing so skip to the next { // line in the file continue; } } if (strlen(longitude) < 8) { continue; // We really don't have any longitude here. } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"draw_gnis_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Save the min/max extents of the file. We // should really initially set the extents // to the min/max for the Xastir coordinate // system, but in practice zeroes should // work just as well. // if ((coord_lat > (long)bottom_extent) || (bottom_extent == 0l)) { bottom_extent = coord_lat; } if ((coord_lat < (long)top_extent) || (top_extent == 0l)) { top_extent = coord_lat; } if ((coord_lon < (long)left_extent) || (left_extent == 0l)) { left_extent = coord_lon; } if ((coord_lon > (long)right_extent) || (right_extent == 0l)) { right_extent = coord_lon; } } // Now check whether this lat/lon is within our viewport. If it // is, draw a text label at that location. else if (coord_lon >= min_lon && coord_lon <= max_lon && lat_in_view) { clean_string(state); clean_string(name); clean_string(type); clean_string(county); clean_string(population); if (debug_level & 16) { fprintf(stderr,"%s\t%s\t%s\t%s\t%s\t%s\t\t", state, name, type, county, latitude, longitude); fprintf(stderr,"%s %s %s %s\t%s %s %s %s\t\t", lat_dd, lat_mm, lat_ss, lat_dir, long_dd, long_mm, long_ss, long_dir); fprintf(stderr,"%s\t%s\n", lat_str, long_str); } convert_xastir_to_screen_coordinates(coord_lon, coord_lat, &x, &y); ok = 1; /* set default symbol */ symbol_table = '/'; symbol_id = '.'; /* small x */ symbol_over = ' '; if (strcasecmp(type,"airport") == 0) { symbol_id = '^'; if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"arch") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"area") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"arroyo") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"basin") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bay") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"beach") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bench") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bend") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"building") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"canal") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cape") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cave") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cemetery") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"census") == 0) { /* if (scale_y > 50)*/ /* Census divisions */ ok = 0; } else if (strcasecmp(type,"channel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"church") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"civil") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cliff") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crater") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crossing") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"dam") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"falls") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"flat") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"forest") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gap") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"geyser") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"glacier") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gut") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"harbor") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"hospital") == 0) { symbol_id = 'h'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"island") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"isthmus") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lake") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lava") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"levee") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"locale") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"military") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"mine") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"oilfield") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"other") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"park") == 0) { symbol_table = '\\'; symbol_id = ';'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"pillar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"plain") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"po") == 0) { symbol_id = ']'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ppl") == 0) { symbol_id = '/'; if (scale_y > 20000) // Don't draw cities at zoom higher than 20,000 { ok = 0; } else if (scale_y > 4000) // Don't draw cities of less than 20,000 { if (atoi(population) < 50000) { ok = 0; } } else if (scale_y > 1500) // Don't draw cities of less than 10,000 { if (atoi(population) < 20000) { ok = 0; } } else if (scale_y > 750) // Don't draw cities of less than 5,000 { if (atoi(population) < 10000) { ok = 0; } } else if (scale_y > 200) // Don't draw cities { // of less than 1,000 if (atoi(population) < 1000) { ok = 0; //fprintf(stderr, // "Name: %s\tPopulation: %s\n",name, // population); } } } else if (strcasecmp(type,"range") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"rapids") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reserve") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reservoir") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"school") == 0) { symbol_id = 'K'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"sea") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"slope") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"spring") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"stream") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"summit") == 0) { if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"swamp") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"trail") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tower") == 0) { symbol_id = 'r'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tunnel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"valley") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"well") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"woods") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ruin") == 0) { if (scale_y > 50) { ok = 0; } } else { fprintf(stderr,"Something unusual found, Type:%s\tState:%s\tCounty:%s\tName:%s\n", type,state,county,name); } if (ok == 1) // If ok to draw it { symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)name, 0xf, 0x10, strlen(name)); } } else { //fprintf(stderr,"Not in viewport. Coordinates: %ld %ld\n",coord_lat,coord_lon); //fprintf(stderr,"Min/Max Lat: %ld %ld\n",min_lat,max_lat); //fprintf(stderr,"Min/Max Lon: %ld %ld\n",min_lon,max_lon); } } } } // End of while (void)fclose (f); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_extent, // Bottom top_extent, // Top left_extent, // Left right_extent, // Right 99999); // Default Map Level } } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (debug_level & 16) { fprintf(stderr,"Exiting draw_gnis_map\n"); } } // Search for a placename among GNIS files // // We need to search a file in the map directory that has the filename // STATE.gis, where STATE is from the "state" variable passed to us. // Search for the placename/county/state/type that the user requested. // Once found, center the map on that location or bring up a response // dialog that asks whether one wants to go there, and that dialog // provides info about the place found, with a possible selection // out of a list of matches. // Might also need to place a label at that position on the map in // case that GNIS file isn't currently selected. // int gnis_locate_place( Widget UNUSED(w), char *name_in, char *state_in, char *county_in, char *quad_in, char *type_in, char *filename_in, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50] ) { char file[MAX_FILENAME]; // Complete path/name of GNIS file FILE *f; // Filehandle of GNIS file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char state_in2[50]; char name[200]; char name_in2[50]; char type[100]; char type_in2[50]; char county[100]; char county_in2[50]; char quad[100]; char quad_in2[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; int ok; struct stat file_status; int my_count = 0; xastir_snprintf(file,sizeof(file),"%s",filename_in); if (debug_level & 16) { fprintf(stderr,"File: %s\n",file); } xastir_snprintf(name_in2,sizeof(name_in2),"%s",name_in); xastir_snprintf(state_in2,sizeof(state_in2),"%s",state_in); xastir_snprintf(county_in2,sizeof(county_in2),"%s",county_in); xastir_snprintf(quad_in2,sizeof(quad_in2),"%s",quad_in); xastir_snprintf(type_in2,sizeof(type_in2),"%s",type_in); // Convert State/Province to upper-case always (they're // always upper-case in the GNIS files from USGS. to_upper(state_in2); if (debug_level & 16) fprintf(stderr,"Name:%s\tState:%s\tCounty:%s\tQuad:%s\tType:%s\n", name_in,state_in2,county_in,quad_in,type_in); // If "Match Case" togglebutton is not set, convert the // rest of the keys to upper-case. if (!follow_case) { to_upper(name_in2); to_upper(county_in2); to_upper(quad_in2); to_upper(type_in2); } // Check status of the file if (stat(file, &file_status) < 0) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Check for regular file if (!S_ISREG(file_status.st_mode)) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Attempt to open the file f = fopen (file, "r"); if (f == NULL) { // "Can't open file" popup_message_always( langcode("POPEM00028"), filename_in ); return(0); } while (!feof (f)) // Loop through entire file { if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { if (strlen(line) > 0) { //NOTE: How do we handle running off the end of "line" while using "index"? // Short lines here can cause segfaults. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",j); clean_string(name); // Find end of Feature Type field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",i); clean_string(type); // Find end of State field i = index(++j,'|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); clean_string(state); // Find end of State Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of County Name field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",j); clean_string(county); // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (DMS) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude (DMS) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Estimated Population field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",j); clean_string(population); // Find end of Quad field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(quad,sizeof(quad),"%s",i); clean_string(quad); // If "Match Case" togglebutton is not set, convert // the data to upper-case before we do our compare. if (!follow_case) { to_upper(name); to_upper(state); to_upper(county); to_upper(quad); to_upper(type); } // Still need to code for the "Match Exact" togglebutton. // Now compare the input variables with those we've // parsed. If a match, bring up a list of items which // match. // ok = 1; if (get_match) // Looking for exact match { if (name_in2[0] != '\0') if (strcmp(name,name_in2) != 0) { ok = 0; } if (state_in2[0] != '\0') if (strcmp(state,state_in2) != 0) { ok = 0; } if (county_in2[0] != '\0') if (strcmp(county,county_in2) != 0) { ok = 0; } if (quad_in2[0] != '\0') if (strcmp(quad,quad_in2) != 0) { ok = 0; } if (type_in2[0] != '\0') if (strcmp(type,type_in2) != 0) { ok = 0; } } else // Look for substring in file, not exact match { if (name_in2[0] != '\0') if (strstr(name,name_in2) == NULL) { ok = 0; } if (state_in2[0] != '\0') if (strstr(state,state_in2) == NULL) { ok = 0; } if (county_in2[0] != '\0') if (strstr(county,county_in2) == NULL) { ok = 0; } if (quad_in2[0] != '\0') if (strstr(quad,quad_in2) == NULL) { ok = 0; } if (type_in2[0] != '\0') if (strstr(type,type_in2) == NULL) { ok = 0; } } if (ok) { if (debug_level & 16) { fprintf(stderr,"Match: %s,%s,%s,%s\n",name,state,county,type); } // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), name ); if (strlen(latitude) < 7) { continue; // We really don't have any latitude here. } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; if (strlen(longitude) < 8) { continue; // We really don't have any longitude here. } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); //set_map_position(w, coord_lat, coord_lon); // Fill in the array values with what we just // found, increment the counter. xastir_snprintf(match_array_name[my_count],200,"%s",name); match_array_lat[my_count] = coord_lat; match_array_long[my_count] = coord_lon; my_count++; // Check for a max array. Return if it is full. if (my_count > 50) { return(50); } } } } } return(my_count); } Xastir-Release-2.2.4/src/map_pop.c0000664000175000017500000013136615151324131015721 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" //NOTE: This function has a problem if a non-pop file is labeled //with a ".pop" extension. It causes a segfault in Xastir. More //error checking needs to be done in order to prevent this. // draw_pop_map() // // Allows drawing a background map of labels for the viewport. // Example format (old): // "WA","Abbey View Memorial Park","cemetery","Snohomish","53","061","474647N","1221650W","47.77972","-122.28056","","","","","420","","Edmonds East" // // Example format (new): // 376016|ID|12th Ave Drain|stream|Canyon|16|027|433107N|1163348W|43.51861|-116.56333||||||||Nampa // // These types of files are available from ftp://aprs.tamu.edu/ // A typical filename would be: "WA_deci.gz". Do not get the other // types of files which are columnar. The files that we parse are // pipe-delimited. // These files were originally from geonames.usgs.gov but the format changed // on that site from population to elevation and the display of populated sites // was severely broken by the new format. The population information should be // gathered from census.gov or other locations concerned with population mapping. // void draw_pop_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags * UNUSED(mdf) ) { char file[MAX_FILENAME]; // Complete path/name of pop file char short_filenm[MAX_FILENAME]; FILE *f; // Filehandle of pop file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char name[200]; char type[100]; char county[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; long min_lat, min_lon, max_lat, max_lon; int ok; long x,y; char symbol_table, symbol_id, symbol_over; unsigned long bottom_extent = 0l; unsigned long top_extent = 0l; unsigned long left_extent = 0l; unsigned long right_extent = 0l; char status_text[MAX_FILENAME]; int count = 0; //fprintf(stderr,"draw_pop_map starting: %s/%s\n",dir,filenm); xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); // Screen view min_lat = SE_corner_latitude; max_lat = NW_corner_latitude; min_lon = NW_corner_longitude; max_lon = SE_corner_longitude; // The map extents in the map index are checked in draw_map to // see whether we should draw the map at all. // Update the statusline for this map name // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); } statusline(status_text,0); // Loading/Indexing ... HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* Latest pipe-delimited format from USGS (as of 08/12/2004): ---------------------------------------------------------- Feature ID Number (FID) State Alpha Code Feature Name Feature Type County Name State Number Code (FIPS Code) County Number Code (FIPS Code) Primary Latitude (DMS) Primary Longitude (DMS) Primary Latitude (decimal degrees) Primary Longitude (decimal degrees) Source Latitude (DMS) Source Longitude (DMS) Source Latitude (decimal degrees) Source Longitude (decimal degrees) Elevation Estimated Population Federal Status Cell Name */ // Attempt to open the file f = fopen (file, "r"); if (f != NULL) { while (!feof (f)) // Loop through entire file { int lat_in_view = 0; count++; if ((count % 16) == 0) { // Check whether map drawing should be interrupted. // Check every 16 lines. // HandlePendingEvents(app_context); if (interrupt_drawing_now) { (void)fclose (f); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } } if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { // It is common for these lines to have incredible // numbers of spaces at the end, so trim them here. (void)remove_trailing_spaces(line); if (strlen(line) > 0) { // Default population, in case the field isn't // present in the file. xastir_snprintf(population,sizeof(population),"0"); // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria //NOTE: We handle running off the end of "line" //via the "continue" statement. Skip the line //if we don't find enough parameters while //parsing. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } // Find end of State field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j+1); //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",i+1); // Find end of Feature Type field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",j+1); // Find end of County Name field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",i+1); // Find end of State Number Code field i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; // Find end of County Number Code field j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Primary Latitude field (DDMMSSN) i = index(j+1, '|'); if (i == NULL) // Pipe not found { continue; // Skip this line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j+1); if (!isdigit((int)latitude[0])) // skip record if not { continue; // numeric! (e.g. "UNKNOWN") } //WE7U clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(i+1, '|'); if (j == NULL) // Pipe not found { continue; // Skip this line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i+1); if (!isdigit((int)longitude[0])) // skip record if not { continue; // numeric (e.g. UNKNOWN) } //WE7U clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Examples of old/new format: // 1462331|VA|Abingdon Elementary School|school|Arlington|51|013|385023N|0770546W|38.83972|-77.09611||||||||Alexandria // 1462331|VA|Abingdon Elementary School|School|Arlington|51|013|385023N|0770545W|38.8398349|-77.0958117|56|Alexandria // Find end of Source Latitude field (DMS) (old // format) or elevation (new format) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (DMS) (old // format) or j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } j[0] = '\0'; // Find end of Elevation field i = index(j+1, '|'); if (i == NULL) // Pipe not found { goto FINISH; // We have enough to process now } i[0] = '\0'; // Find end of Estimated Population field j = index(i+1, '|'); if (j == NULL) // Pipe not found { goto FINISH; // We have enough to process now } if ( j != NULL ) { j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i+1); } FINISH: // There are two more fields (old format), // "Federal Status" and "Cell Name". We ignore // those for now. if (strlen(latitude) < 7) { continue; // We really don't have any latitude here! } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"draw_pop_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); // Quick test of latitude to see if it's within // our view. If not and we're not doing // indexing, skip this line and go on to the // next. if (coord_lat <= min_lat && coord_lat >= max_lat) { // Latitude is ok lat_in_view++; } else // Latitude not in current view { // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Process the line 'cuz we're indexing } else // Not indexing so skip to the next { // line in the file continue; } } if (strlen(longitude) < 8) { continue; // We really don't have any latitude here! } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"draw_pop_map:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // Save the min/max extents of the file. We // should really initially set the extents // to the min/max for the Xastir coordinate // system, but in practice zeroes should // work just as well. // if ((coord_lat > (long)bottom_extent) || (bottom_extent == 0l)) { bottom_extent = coord_lat; } if ((coord_lat < (long)top_extent) || (top_extent == 0l)) { top_extent = coord_lat; } if ((coord_lon < (long)left_extent) || (left_extent == 0l)) { left_extent = coord_lon; } if ((coord_lon > (long)right_extent) || (right_extent == 0l)) { right_extent = coord_lon; } } // Now check whether this lat/lon is within our viewport. If it // is, draw a text label at that location. else if (coord_lon >= min_lon && coord_lon <= max_lon && lat_in_view) { clean_string(state); clean_string(name); clean_string(type); clean_string(county); clean_string(population); if (debug_level & 16) { fprintf(stderr,"%s\t%s\t%s\t%s\t%s\t%s\t\t", state, name, type, county, latitude, longitude); fprintf(stderr,"%s %s %s %s\t%s %s %s %s\t\t", lat_dd, lat_mm, lat_ss, lat_dir, long_dd, long_mm, long_ss, long_dir); fprintf(stderr,"%s\t%s\n", lat_str, long_str); } convert_xastir_to_screen_coordinates(coord_lon, coord_lat, &x, &y); ok = 1; /* set default symbol */ symbol_table = '/'; symbol_id = '.'; /* small x */ symbol_over = ' '; if (strcasecmp(type,"airport") == 0) { symbol_id = '^'; if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"arch") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"area") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"arroyo") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"basin") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bay") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"beach") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bench") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bend") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"bridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"building") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"canal") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cape") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cave") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cemetery") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"census") == 0) { /* if (scale_y > 50)*/ /* Census divisions */ ok = 0; } else if (strcasecmp(type,"channel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"church") == 0) { symbol_table = '\\'; symbol_id = '+'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"civil") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"cliff") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crater") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"crossing") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"dam") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"falls") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"flat") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"forest") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gap") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"geyser") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"glacier") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"gut") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"harbor") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"hospital") == 0) { symbol_id = 'h'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"island") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"isthmus") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lake") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"lava") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"levee") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"locale") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"military") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"mine") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"oilfield") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"other") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"park") == 0) { symbol_table = '\\'; symbol_id = ';'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"pillar") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"plain") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"po") == 0) { symbol_id = ']'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ppl") == 0) { symbol_id = '/'; if (scale_y > 20000) // Don't draw cities at zoom higher than 20,000 { ok = 0; } else if (scale_y > 4000) // Don't draw cities of less than 20,000 { if (atoi(population) < 50000) { ok = 0; } } else if (scale_y > 1500) // Don't draw cities of less than 10,000 { if (atoi(population) < 20000) { ok = 0; } } else if (scale_y > 750) // Don't draw cities of less than 5,000 { if (atoi(population) < 10000) { ok = 0; } } else if (scale_y > 200) // Don't draw cities { // of less than 1,000 if (atoi(population) < 1000) { ok = 0; //fprintf(stderr, // "Name: %s\tPopulation: %s\n",name, // population); } } } else if (strcasecmp(type,"range") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"rapids") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reserve") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"reservoir") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ridge") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"school") == 0) { symbol_id = 'K'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"sea") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"slope") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"spring") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"stream") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"summit") == 0) { if (scale_y > 100) { ok = 0; } } else if (strcasecmp(type,"swamp") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"trail") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tower") == 0) { symbol_id = 'r'; if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"tunnel") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"valley") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"well") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"woods") == 0) { if (scale_y > 50) { ok = 0; } } else if (strcasecmp(type,"ruin") == 0) { if (scale_y > 50) { ok = 0; } } else { fprintf(stderr,"Something unusual found, Type:%s\tState:%s\tCounty:%s\tName:%s\n", type,state,county,name); } if (ok == 1) // If ok to draw it { symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)name, 0xf, 0x10, strlen(name)); } } else { //fprintf(stderr,"Not in viewport. Coordinates: %ld %ld\n",coord_lat,coord_lon); //fprintf(stderr,"Min/Max Lat: %ld %ld\n",min_lat,max_lat); //fprintf(stderr,"Min/Max Lon: %ld %ld\n",min_lon,max_lon); } } } } // End of while (void)fclose (f); // Check whether we're indexing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only bottom_extent, // Bottom top_extent, // Top left_extent, // Left right_extent, // Right 99999); // Default Map Level } } else { fprintf(stderr,"Couldn't open file: %s\n", file); return; } if (debug_level & 16) { fprintf(stderr,"Exiting draw_pop_map\n"); } } // Search for a placename among pop files // // We need to search a file in the map directory that has the filename // STATE.gis, where STATE is from the "state" variable passed to us. // Search for the placename/county/state/type that the user requested. // Once found, center the map on that location or bring up a response // dialog that asks whether one wants to go there, and that dialog // provides info about the place found, with a possible selection // out of a list of matches. // Might also need to place a label at that position on the map in // case that pop file isn't currently selected. // int pop_locate_place( Widget UNUSED(w), char *name_in, char *state_in, char *county_in, char *quad_in, char *type_in, char *filename_in, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50] ) { char file[MAX_FILENAME]; // Complete path/name of pop file FILE *f; // Filehandle of pop file char line[MAX_FILENAME]; // One line of text from file char *i, *j; char state[50]; char state_in2[50]; char name[200]; char name_in2[50]; char type[100]; char type_in2[50]; char county[100]; char county_in2[50]; char quad[100]; char quad_in2[100]; char latitude[15]; char longitude[15]; char population[15]; char lat_dd[3]; char lat_mm[3]; char lat_ss[3]; char lat_dir[2]; char long_dd[4]; char long_mm[3]; char long_ss[3]; char long_dir[2]; char lat_str[15]; char long_str[15]; int temp1; long coord_lon, coord_lat; int ok; struct stat file_status; int my_count = 0; xastir_snprintf(file,sizeof(file),"%s",filename_in); if (debug_level & 16) { fprintf(stderr,"File: %s\n",file); } xastir_snprintf(name_in2,sizeof(name_in2),"%s",name_in); xastir_snprintf(state_in2,sizeof(state_in2),"%s",state_in); xastir_snprintf(county_in2,sizeof(county_in2),"%s",county_in); xastir_snprintf(quad_in2,sizeof(quad_in2),"%s",quad_in); xastir_snprintf(type_in2,sizeof(type_in2),"%s",type_in); // Convert State/Province to upper-case always (they're // always upper-case in the pop files from USGS. to_upper(state_in2); if (debug_level & 16) fprintf(stderr,"Name:%s\tState:%s\tCounty:%s\tQuad:%s\tType:%s\n", name_in,state_in2,county_in,quad_in,type_in); // If "Match Case" togglebutton is not set, convert the // rest of the keys to upper-case. if (!follow_case) { to_upper(name_in2); to_upper(county_in2); to_upper(quad_in2); to_upper(type_in2); } // Check status of the file if (stat(file, &file_status) < 0) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Check for regular file if (!S_ISREG(file_status.st_mode)) { // "Can't open file" popup_message( langcode("POPEM00028"), filename_in ); return(0); } // Attempt to open the file f = fopen (file, "r"); if (f == NULL) { // "Can't open file" popup_message_always( langcode("POPEM00028"), filename_in ); return(0); } while (!feof (f)) // Loop through entire file { if ( get_line (f, line, MAX_FILENAME) ) // Snag one line of data { if (strlen(line) > 0) { //NOTE: How do we handle running off the end of "line" while using "index"? // Short lines here can cause segfaults. // Find end of Feature ID Number field j = index(line,'|'); if (j == NULL) // Pipe not found { continue; // Skip this line } // Find end of State field i = index(++j,'|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(state,sizeof(state),"%s",j); clean_string(state); //NOTE: It'd be nice to take the part after the comma and put it before the rest // of the text someday, i.e. "Cassidy, Lake". // Find end of Feature Name field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(name,sizeof(name),"%s",i); clean_string(name); // Find end of Feature Type field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(type,sizeof(type),"%s",j); clean_string(type); // Find end of County Name field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(county,sizeof(county),"%s",i); clean_string(county); // Find end of State Number Code field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of County Number Code field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Primary Latitude field (DDMMSSN) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; xastir_snprintf(latitude,sizeof(latitude),"%s",j); clean_string(latitude); // Find end of Primary Longitude field (DDDMMSSW) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(longitude,sizeof(longitude),"%s",i); clean_string(longitude); // Find end of Primary Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Primary Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (DMS) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude (DMS) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Source Latitude field (decimal // degrees) i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Source Longitude field (decimal // degrees) j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; // Find end of Elevation field i = index(++j, '|'); if (i == NULL) // Pipe not found { continue; // Skip line } i[0] = '\0'; // Find end of Estimated Population field j = index(++i, '|'); if (j == NULL) // Pipe not found { continue; // Skip line } j[0] = '\0'; xastir_snprintf(population,sizeof(population),"%s",i); clean_string(population); // Snag Cell Name field (Quad name, last field) xastir_snprintf(quad,sizeof(quad),"%s",j+1); clean_string(quad); // If "Match Case" togglebutton is not set, convert // the data to upper-case before we do our compare. if (!follow_case) { to_upper(name); to_upper(state); to_upper(county); to_upper(quad); to_upper(type); } // Still need to code for the "Match Exact" togglebutton. // Now compare the input variables with those we've // parsed. If a match, bring up a list of items which // match. // ok = 1; if (get_match) // Looking for exact match { if (name_in2[0] != '\0') if (strcmp(name,name_in2) != 0) { ok = 0; } if (state_in2[0] != '\0') if (strcmp(state,state_in2) != 0) { ok = 0; } if (county_in2[0] != '\0') if (strcmp(county,county_in2) != 0) { ok = 0; } if (quad_in2[0] != '\0') if (strcmp(quad,quad_in2) != 0) { ok = 0; } if (type_in2[0] != '\0') if (strcmp(type,type_in2) != 0) { ok = 0; } } else // Look for substring in file, not exact match { if (name_in2[0] != '\0') if (strstr(name,name_in2) == NULL) { ok = 0; } if (state_in2[0] != '\0') if (strstr(state,state_in2) == NULL) { ok = 0; } if (county_in2[0] != '\0') if (strstr(county,county_in2) == NULL) { ok = 0; } if (quad_in2[0] != '\0') if (strstr(quad,quad_in2) == NULL) { ok = 0; } if (type_in2[0] != '\0') if (strstr(type,type_in2) == NULL) { ok = 0; } } if (ok) { if (debug_level & 16) { fprintf(stderr,"Match: %s,%s,%s,%s\n",name,state,county,type); } // This one pops up the names of whatever we found. // "Found It!" //popup_message_always( langcode("POPEM00029"), name ); if (strlen(latitude) < 7) { continue; // We really don't have any latitude here! } lat_dd[0] = latitude[0]; lat_dd[1] = latitude[1]; lat_dd[2] = '\0'; lat_mm[0] = latitude[2]; lat_mm[1] = latitude[3]; lat_mm[2] = '\0'; lat_ss[0] = latitude[4]; lat_ss[1] = latitude[5]; lat_ss[2] = '\0'; lat_dir[0] = latitude[6]; lat_dir[1] = '\0'; if (strlen(longitude) < 8) { continue; // We really don't have any longitude here! } long_dd[0] = longitude[0]; long_dd[1] = longitude[1]; long_dd[2] = longitude[2]; long_dd[3] = '\0'; long_mm[0] = longitude[3]; long_mm[1] = longitude[4]; long_mm[2] = '\0'; long_ss[0] = longitude[5]; long_ss[1] = longitude[6]; long_ss[2] = '\0'; long_dir[0] = longitude[7]; long_dir[1] = '\0'; // Now must convert from DD MM SS format to DD MM.MM format so that we // can run it through our conversion routine to Xastir coordinates. if (1 != sscanf(lat_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(lat_str, sizeof(lat_str), "%s%s.%02d%s", lat_dd, lat_mm, temp1, lat_dir); coord_lat = convert_lat_s2l(lat_str); if (1 != sscanf(long_ss, "%d", &temp1)) { fprintf(stderr,"locate_place:sscanf parsing error\n"); } temp1 = (int)((temp1 / 60.0) * 100 + 0.5); // Poor man's rounding xastir_snprintf(long_str, sizeof(long_str), "%s%s.%02d%s", long_dd, long_mm, temp1, long_dir); coord_lon = convert_lon_s2l(long_str); //set_map_position(w, coord_lat, coord_lon); // Fill in the array values with what we just // found, increment the counter. xastir_snprintf(match_array_name[my_count],200,"%s",name); match_array_lat[my_count] = coord_lat; match_array_long[my_count] = coord_lon; my_count++; // Check for a max array. Return if it is full. if (my_count > 50) { return(50); } } } } } return(my_count); } Xastir-Release-2.2.4/src/map_shp.c0000664000175000017500000027250015151324131015711 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * * Please see separate copyright notice attached to the * shape_ring_direction() function in this file. * * DBFAWK TODO: * - reload .dbfawk's when they've changed (or maps are reindexed) * - scale line widths based on zoom level (see city_flag, for example) * - allow multiple font sizes (font_size=small|medium|large|huge) * - allow multiple font faces? * - allow setting of map layer for individual shapes * - transparency * - allow setting fill_style (solid, stippled, etc.) * - do more config/ *.dbfawk files! * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "db_funcs.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #ifdef HAVE_LIBSHP #include "awk.h" #include "dbfawk.h" #ifdef HAVE_SHAPEFIL_H #include #else // HAVE_SHAPEFIL_H #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else // HAVE_LIBSHP_SHAPEFIL_H #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #include #include "shp_hash.h" // Must be last include file #include "leak_detection.h" // typedef needed in forward decls typedef struct _label_string { char label[50]; int found; struct _label_string *next; } label_string; // forward declarations of functions local to this file // It's OK for this to appear *after* "leak_detection.h" because // it contains nothing that interferes with that file. #include "map_shp_fwd.h" // RTrees are used as a spatial index for shapefiles. We can search them // for shapes that intersect our viewport, and only read those from the // file. // RTree_hitarray is filled in when we do an rtree search. the index is used // to keep track of how many we've found so far while searching, or how // many total have been found after the search is done. static int *RTree_hitarray=NULL; int RTree_hitarray_size=0; int RTree_hitarray_index=0; //This trivial routine is used by the RTreeSearch as a callback when it finds // a match. int RTreeSearchCallback(int id, void* UNUSED(arg) ) { if (!RTree_hitarray) { RTree_hitarray = (int *)malloc(1000*sizeof(int)); RTree_hitarray_size=1000; } if (RTree_hitarray_size <= RTree_hitarray_index) { int *ptr; ptr = realloc(RTree_hitarray, (RTree_hitarray_size+1000)*sizeof(int)); CHECKREALLOC(ptr); // fatal error if we can't get 'em :-( RTree_hitarray=ptr; RTree_hitarray_size += 1000; } RTree_hitarray[RTree_hitarray_index++]=id-1; return 1; // signal to keep searching for more matches } /******************************************************************* * create_shapefile_map() * * Do we have a need for storing date/ time/ speed/ course/ * altitude/ heard-direct for each point? Altitude could be stored * in the Z space. If we store a station's trail as an SHPT_POINT * file, then we can associate a bunch of info with each point: * date/time, altitude, course, speed, status/comments, path, port, * heard-direct, weather data, etc. We could also dynamically * change the number of fields based on what we have a need to * store, using field-names to determine what's stored in each file. * * shapefile_name is the path/name of the map file we wish to create * (without the extension). * * type = SHPT_POINT, SHPT_ARC, SHPT_POLYGON, * SHPT_MULTIPOINT, etc. * * quantity equals the number of vertices we have. * * padfx/padfy/padfz are the vertices themselves, in double format. *******************************************************************/ void create_shapefile_map(char *dir, char *shapefile_name, int type, int quantity, double *padfx, double *padfy, double *padfz, int add_timestamp, char * shape_label) { SHPHandle my_shp_handle; SHPObject *my_object; DBFHandle my_dbf_handle; char timedatestring[101]; int index; int max_objects = 1; char credit_string[] = "Created by Xastir, http://www.xastir.org"; char temp_shapefile_name[MAX_FILENAME]; char temp_prj_name[MAX_FILENAME]; if (debug_level & 16) { fprintf(stderr,"create_shapefile_map\n"); fprintf(stderr,"%s %s %d %d %d\n", dir, shapefile_name, type, quantity, add_timestamp); } if (quantity == 0) { // No reason to make a map if we don't have any points. return; } // Get the time/datestamp get_timestamp(timedatestring); if (add_timestamp) // Prepend a timestamp to the filename { int ii; xastir_snprintf(temp_shapefile_name, sizeof(temp_shapefile_name), "%s%s_%s", dir, timedatestring, shapefile_name); // Change spaces and colons to underlines for (ii = 0; ii < (int)strlen(temp_shapefile_name); ii++) { if (temp_shapefile_name[ii] == ' ' || temp_shapefile_name[ii] == ':') { temp_shapefile_name[ii] = '_'; } } } else // Use the filename directly, no timestamp { xastir_snprintf(temp_shapefile_name, sizeof(temp_shapefile_name), "%s%s", dir, shapefile_name); } if (debug_level & 16) { fprintf(stderr, "Creating file %s\n", temp_shapefile_name); } // Create empty .shp/.shx/.dbf files // my_shp_handle = SHPCreate(temp_shapefile_name, type); my_dbf_handle = DBFCreate(temp_shapefile_name); // Check whether we were able to open these handles if ((my_shp_handle == NULL) || (my_dbf_handle == NULL)) { // Probably write-protected directory fprintf(stderr, "Could not create shapefile %s\n", temp_shapefile_name); return; } // Write out a WKT in a .prj file to go with this shapefile. strcpy(temp_prj_name, temp_shapefile_name); temp_prj_name[sizeof(temp_prj_name)-1] = '\0'; // Terminate string strcat(temp_prj_name, ".prj"); temp_prj_name[sizeof(temp_prj_name)-1] = '\0'; // Terminate string xastirWriteWKT(temp_prj_name); // Create the different fields we'll use to store the // attributes: // // Add a credits field and set the length. Field 0. DBFAddField(my_dbf_handle, "Credits", FTString, strlen(credit_string) + 1, 0); // // Add a date/time field and set the length. Field 1. DBFAddField(my_dbf_handle, "DateTime", FTString, strlen(timedatestring) + 1, 0); // Add a label field DBFAddField(my_dbf_handle, "Label", FTString, strlen(shape_label) + 1, 0); // Note that if were passed additional parameters that went // along with the lat/long/altitude points, we could write those // into the DBF file in the loop below. We would have to change // from a polygon to a point filetype though. // Populate the files with objects and attributes. Perform this // loop once for each object. // for (index = 0; index < max_objects; index++) { // Create a temporary object from the vertices my_object = SHPCreateSimpleObject( type, quantity, padfx, padfy, padfz); // Write out the vertices SHPWriteObject( my_shp_handle, -1, my_object); // Destroy the temporary object SHPDestroyObject(my_object); // Note that with the current setup the below really only get // written into the file once. Check it with dbfinfo/dbfdump. // Write the credits attributes DBFWriteStringAttribute( my_dbf_handle, index, 0, credit_string); // Write the time/date string DBFWriteStringAttribute( my_dbf_handle, index, 1, timedatestring); // Write the label string DBFWriteStringAttribute( my_dbf_handle, index, 2, shape_label); } // Close the .shp/.shx/.dbf files SHPClose(my_shp_handle); DBFClose(my_dbf_handle); } // Function which creates a Shapefile map from an APRS trail. // // Navigate through the linked list of TrackRow structs to pick out // the lat/long and write them into arrays of floats. We then pass // those arrays to create_shapefile_map(). // void create_map_from_trail(char *call_sign) { DataRow *p_station; // Find the station in our database. Count the number of points // for that station first, then allocate some arrays to hold // that quantity of points. Stuff the lat/long into the arrays // and then call create_shapefile_map(). // if (search_station_name(&p_station, call_sign, 1)) { int count; int ii; TrackRow *ptr; char temp[MAX_FILENAME]; char temp2[MAX_FILENAME]; double *x; double *y; double *z; char temp_base_dir[MAX_VALUE]; count = 0; ptr = p_station->oldest_trackpoint; while (ptr != NULL) { count++; ptr = ptr->next; } //fprintf(stderr, "Quantity of points: %d\n", count); if (count == 0) { // No reason to make a map if we don't have any points // in the track list. return; } // We know how many points are in the linked list. Allocate // arrays to hold the values. x = (double *) malloc( count * sizeof(double) ); y = (double *) malloc( count * sizeof(double) ); z = (double *) malloc( count * sizeof(double) ); CHECKMALLOC(x); CHECKMALLOC(y); CHECKMALLOC(z); // Fill in the values. We need to convert from Xastir // coordinate system to lat/long doubles as we go. ptr = p_station->oldest_trackpoint; ii = 0; while ((ptr != NULL) && (ii < count) ) { // Convert from Xastir coordinates to lat/long // Convert to string convert_lon_l2s(ptr->trail_long_pos, temp, sizeof(temp), CONVERT_DEC_DEG); // Convert to double and stuff into array of doubles if (1 != sscanf(temp, "%lf", &x[ii])) { fprintf(stderr,"create_map_from_trail:sscanf parsing error\n"); } // If longitude string contains "W", make the final // result negative. if (index(temp, 'W')) { x[ii] = x[ii] * -1.0; } // Convert to string convert_lat_l2s(ptr->trail_lat_pos, temp, sizeof(temp), CONVERT_DEC_DEG); // Convert to double and stuff into array of doubles if (1 != sscanf(temp, "%lf", &y[ii])) { fprintf(stderr,"create_map_from_trail:sscanf parsing error\n"); } // If latitude string contains "S", make the final // result negative. if (index(temp, 'S')) { y[ii] = y[ii] * -1.0; } z[ii] = ptr->altitude; // Altitude (meters), undefined=-99999 ptr = ptr->next; ii++; } // Create a Shapefile from the APRS trail. Write it into // "~/.xastir/tracklogs" and add a date/timestamp to the end. // xastir_snprintf(temp, sizeof(temp), "%s/", get_user_base_dir("tracklogs", temp_base_dir, sizeof(temp_base_dir))); // Create filename xastir_snprintf(temp2, sizeof(temp2), "%s%s", call_sign, "_APRS_Trail_Red"); create_shapefile_map( temp, temp2, SHPT_ARC, count, x, y, z, 1, // Add a timestamp to the front of the filename call_sign); // Free the storage that we malloc'ed free(x); free(y); free(z); } else // Couldn't find the station of interest { } } // Code borrowed from Shapelib which determines whether a ring is CW // or CCW. Thanks to Frank Warmerdam for permitting us to use this // under the GPL license! Per e-mail of 04/29/2003 between Frank // and Curt, WE7U. Frank gave permission for us to use _any_ // portion of Shapelib inside the GPL'ed Xastir program. // // Test Ring for Clockwise/Counter-Clockwise (fill or hole ring) // // Return 1 for Clockwise (fill ring) // Return -1 for Counter-Clockwise (hole ring) // Return 0 for error/indeterminate (shouldn't get this!) // int shape_ring_direction ( SHPObject *psObject, int Ring ) { int nVertStart; int nVertCount; int iVert; float dfSum; int result; nVertStart = psObject->panPartStart[Ring]; if( Ring == psObject->nParts-1 ) { nVertCount = psObject->nVertices - psObject->panPartStart[Ring]; } else nVertCount = psObject->panPartStart[Ring+1] - psObject->panPartStart[Ring]; dfSum = 0.0; for( iVert = nVertStart; iVert < nVertStart+nVertCount-1; iVert++ ) { dfSum += psObject->padfX[iVert] * psObject->padfY[iVert+1] - psObject->padfY[iVert] * psObject->padfX[iVert+1]; } dfSum += psObject->padfX[iVert] * psObject->padfY[nVertStart] - psObject->padfY[iVert] * psObject->padfX[nVertStart]; if (dfSum < 0.0) { result = 1; } else if (dfSum > 0.0) { result = -1; } else { result = 0; } return(result); } /********************************************************** * draw_shapefile_map() * * This function handles both weather-alert shapefiles (from the * NOAA site) and shapefiles used as maps (from a number of * sources). * * If destination_pixmap equals INDEX_CHECK_TIMESTAMPS or * INDEX_NO_TIMESTAMPS, then we are indexing the file (finding the * extents) instead of drawing it. * * The current implementation can draw Polygon, PolyLine, and Point * Shapefiles. Rendering rules for any shapefile are provided by * an associated "awk-like" DBFAWK file. * * We handle the "hole" drawing in polygon shapefiles, where one * direction around the ring means a fill, and the other direction * means a hole in the polygon. * * If alert is NULL, draw every shape that fits the screen. If * non-NULL, draw only the shape that matches the zone number. * * Weather alerts are handled by having a dbfawk file that defines a * "key" variable. The "key" matches a code in the DBF file that corresponds * to the weather area to alert on. Which field is used to construct * the key depends on the file and whether NWS has changed the format. * See DBFAWK files named "nws*.dbfawk" in the config directory. * If we are processing a weather alert, we are getting passed an * alert_entry that identifies which named shape to search for, and we * find the shape in the dbf file that has a key that matches. * The alert entries are created by alert_build_list. If we're doing * alerts, we're being called from load_alert_maps. * If we're not given an alert_entry, then we're to draw the whole map. **********************************************************/ static dbfawk_sig_info *Dbf_sigs = NULL; static awk_symtab *Symtbl = NULL; /* these have to be static since Symtbl is recycled between calls */ /* used to be static inside draw_shapefile_map, but moved here because they need to be shared among other functions */ static char dbfsig[1024],dbffields[1024],name[64],key[64],sym[4]; static int color,lanes,filled,pattern,display_level,min_display_level,label_level; static int fill_style,fill_color; static int fill_stipple; static int label_color = 8; static int font_size = FONT_DEFAULT; static int label_method=0; static double label_lon=0.0; static double label_lat=0.0; /* default dbfawk rule when no better signature match is found */ static awk_rule dbfawk_default_rules[] = { { 0, BEGIN, NULL, NULL, 0, 0, "dbfinfo=\"\"; key=\"\"; lanes=1; color=8; fill_color=13; fill_stipple=0; name=\"\"; filled=0; fill_style=0; pattern=0; display_level=2147483647; min_display_level=0; label_level=0", 0, 0 }, }; #define dbfawk_default_nrules (sizeof(dbfawk_default_rules)/sizeof(dbfawk_default_rules[0])) static dbfawk_sig_info *dbfawk_default_sig = NULL; void draw_shapefile_map (Widget w, char *dir, char *filenm, alert_entry * alert, u_char alert_color, int destination_pixmap, map_draw_flags *mdf) { DBFHandle hDBF; SHPObject *object; static XPoint points[MAX_MAP_POINTS]; char file[MAX_FILENAME]; /* Complete path/name of image file */ char short_filenm[MAX_FILENAME]; int i, fieldcount, recordcount, structure, ring; SHPHandle hSHP; int nShapeType, nEntities; double adfBndsMin[4], adfBndsMax[4]; char *sType; long x,y; int ok; int numXPoints; int polygon_hole_flag; int *polygon_hole_storage; GC gc_temp = NULL; int gps_flag = 0; char gps_label[100]; int gps_color = 0x0c; int weather_alert_flag = 0; char *filename; // filename itself w/o directory int found_shape = -1; int ok_to_draw = 0; int high_water_mark_index = 0; char status_text[MAX_FILENAME]; dbfawk_sig_info *sig_info = NULL; dbfawk_field_info *fld_info = NULL; int draw_filled_orig; int draw_filled; // Define hash table for label pointers label_string *label_hash[256]; label_string *ptr2 = NULL; struct Rect viewportRect; shpinfo *si; int nhits; // pull this out of the map_draw_flags draw_filled = mdf->draw_filled; // Initialize the hash table label pointers for (i = 0; i < 256; i++) { label_hash[i] = NULL; } // We're going to change draw_filled a bunch if we've got Auto turned // on, but we have to check --- save this! draw_filled_orig=draw_filled; // Re-initialize all static render-control variables every time // through here. initialize_rendering_variables(); if (Dbf_sigs == NULL) { Dbf_sigs = dbfawk_load_sigs(get_data_base_dir("config"),".dbfawk"); } if (debug_level & 16) fprintf(stderr,"DBFAWK signatures %sfound in %s.\n", (Dbf_sigs)?" ":"NOT ",get_data_base_dir("config")); dbfawk_default_sig = initialize_dbfawk_default_sig(); // We don't draw the shapes if alert_color == -1 if (alert_color != 0xff) { ok_to_draw++; } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); // filename is the base name of filenm (path stripped off) filename = filenm; i = strlen(filenm); while ( (i >= 0) && (filenm[i] != '/') ) { filename = &filenm[i--]; } if (alert) { weather_alert_flag++; } // Check for ~/.xastir/GPS directory. We set up the // labels and colors differently for these types of files. if (strstr(filenm,"GPS")) // We're in the maps/GPS directory { gps_flag++; } // Open the .dbf file for reading. This has the textual // data (attributes) associated with each shape. hDBF = DBFOpen( file, "rb" ); if ( hDBF == NULL ) { if (debug_level & 16) { fprintf(stderr,"draw_shapefile_map: DBFOpen(%s,\"rb\") failed.\n", file ); } return; } if (debug_level & 16) { fprintf(stderr,"\n---------------------------------------------\nInfo for %s\n",filenm); } *dbfsig = '\0'; fieldcount = dbfawk_sig(hDBF,dbfsig,sizeof(dbfsig)); if (fieldcount == 0) { DBFClose( hDBF ); // Clean up open file descriptors return; // Should have at least one field } recordcount = DBFGetRecordCount(hDBF); if (recordcount == 0) { DBFClose( hDBF ); // Clean up open file descriptors return; // Should have at least one record } if (debug_level & 16) { fprintf(stderr,"%d Columns, %d Records in file\n", fieldcount, recordcount); fprintf(stderr,"DBF signature: %s\n",dbfsig); } if (Dbf_sigs) /* see if we have a .dbfawk file that matches */ { sig_info = dbfawk_find_sig(Dbf_sigs,dbfsig,file); if (sig_info) { gps_flag = 0; // trump gps_flag-- use dbfawk } if (!sig_info) { fprintf(stderr,"No DBFAWK signature for %s! Using default.\n",filenm); sig_info = dbfawk_default_sig; } } else { sig_info = dbfawk_default_sig; } if (sig_info) /* we've got a .dbfawk, so set up symtbl */ { Symtbl = initialize_dbfawk_symbol_table(dbffields, sizeof(dbffields), &color, &lanes, name, sizeof(name), key, sizeof(key), sym, sizeof(sym), &filled, &fill_style, &fill_color, &fill_stipple, &pattern, &display_level, &min_display_level, &label_level, &label_color, &font_size, &label_method, &label_lon, &label_lat); if (awk_compile_program(Symtbl,sig_info->prog) < 0) { fprintf(stderr,"Unable to compile .dbfawk program\n"); free_dbfawk_sig_info(sig_info); return; } awk_exec_begin(sig_info->prog); /* execute a BEGIN rule if any */ /* find out which dbf fields we care to read */ fld_info = dbfawk_field_list(hDBF, dbffields); } else /* should never be reached anymore! */ { fprintf(stderr,"No DBFAWK signature for %s and no default!\n",filenm); return; } // Search for specific record if we're doing alerts (returns -1 if // alert is null or the shape is not found) found_shape = find_wx_alert_shape(alert, hDBF, recordcount, sig_info,fld_info); if (debug_level & 16) { fprintf(stderr,"Calling SHPOpen()\n"); } // Open the .shx/.shp files for reading. // These are the index and the vertice files. hSHP = SHPOpen( file, "rb" ); if( hSHP == NULL ) { fprintf(stderr,"draw_shapefile_map: SHPOpen(%s,\"rb\") failed.\n", file ); DBFClose( hDBF ); // Clean up open file descriptors free_dbfawk_infos(fld_info, sig_info); return; } // Get the extents of the map file SHPGetInfo( hSHP, &nEntities, &nShapeType, adfBndsMin, adfBndsMax ); // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA039"), short_filenm); statusline(status_text,0); // Indexing ... // We're indexing only. Save the extents in the index. index_update_ll(filenm, // Filename only adfBndsMin[1], // Bottom adfBndsMax[1], // Top adfBndsMin[0], // Left adfBndsMax[0], // Right 1000); // Default Map Level DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); free_dbfawk_infos(fld_info, sig_info); return; // Done indexing this file } else { xastir_snprintf(status_text, sizeof(status_text), langcode ("BBARSTA028"), short_filenm); statusline(status_text,0); // Loading ... } // We put this section AFTER the code that determines whether we're merely // indexing, so we don't bother to generate rtrees unless we're really // drawing the file. si=NULL; // Don't bother even looking at the hash if this shapefile is completely // contained in the current viewport. We'll have to read every shape // in it anyway, and all we'd be doing is extra work searching the // RTree if (!map_inside_viewport_lat_lon(adfBndsMin[1], adfBndsMax[1], adfBndsMin[0], adfBndsMax[0])) { // we keep a hash of all shapefiles encountered so far (and not purged // due to inactivity). Find the record of this shapefile in that // hash if it's there. si = get_shp_from_hash(file); if (!si) { // we don't have what we need, so generate the index and make // the hashtable entry add_shp_to_hash(file,hSHP); // this will index all the shapes in // an RTree and save the root in a // shpinfo structure si=get_shp_from_hash(file); // now get that structure if (!si) { fprintf(stderr, "Panic! added %s, lost it already!\n",file); exit(1); } } } // we need this for the rtree search getViewportRect(&viewportRect); sType = getShapeTypeString(nShapeType); if ((strcmp(sType, "Multipoint")== 0) || (strcmp(sType, "Unknown")==0)) { fprintf(stderr,"%s Shapefile format not implemented: %s\n",sType,file); DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); free_dbfawk_infos(fld_info, sig_info); return; } if (debug_level & 16) { fprintf(stderr,"%s(%d), %d Records in file\n",sType,nShapeType,nEntities); } if (debug_level & 16) fprintf(stderr,"File Bounds: (%15.10g,%15.10g)\n\t(%15.10g,%15.10g)\n", adfBndsMin[0], adfBndsMin[1], adfBndsMax[0], adfBndsMax[1] ); // Check the bounding box for this shapefile. If none of the // file is within our viewport, we can skip the entire file. if (debug_level & 16) { fprintf(stderr,"Calling map_visible_lat_lon on the entire shapefile\n"); } if (! map_visible_lat_lon( adfBndsMin[1], // Bottom adfBndsMax[1], // Top adfBndsMin[0], // Left adfBndsMax[0]) ) // Right { if (debug_level & 16) { fprintf(stderr,"No shapes within viewport. Skipping file...\n"); } DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); free_dbfawk_infos(fld_info, sig_info); return; // The file contains no shapes in our viewport } // Set a default line width for all maps. This will most likely // be modified for particular maps in later code. (void)XSetLineAttributes(XtDisplay(w), gc, 0, LineSolid, CapButt,JoinMiter); if (weather_alert_flag) { char xbm_path[MAX_FILENAME]; unsigned int _w, _h; int _xh, _yh; int ret_val; // This GC is used for weather alerts (writing to the // pixmap: pixmap_alerts) (void)XSetForeground (XtDisplay (w), gc_tint, colors[(int)alert_color]); // GXcopy used here because we have been using stippling for // weather alerts since commit 88d579 (void)XSetFunction(XtDisplay(w), gc_tint, GXcopy); // Get a pixmap that will be used to shade this alert area get_alert_xbm_path(xbm_path, sizeof(xbm_path), alert); // set the stipple GC to the pattern we found in the alert xbm (void)XSetLineAttributes(XtDisplay(w), gc_tint, 0, LineSolid, CapButt,JoinMiter); XFreePixmap(XtDisplay(w), pixmap_wx_stipple); ret_val = XReadBitmapFile(XtDisplay(w), DefaultRootWindow(XtDisplay(w)), xbm_path, &_w, &_h, &pixmap_wx_stipple, &_xh, &_yh); if (ret_val != 0) { fprintf(stderr,"XReadBitmapFile() failed: Bitmap not found? %s\n",xbm_path); // We shouldn't exit on this one, as it's not so severe // that we should kill Xastir. I've seen this happen // after very long runtimes though, so perhaps there's a // problem somewhere in the X11 server and/or it's // caching? // //exit(1); } else { // We successfully loaded the bitmap, so set the stipple // properly to use it. Skip this part if we were // unsuccessful at loading the bitmap. (void)XSetStipple(XtDisplay(w), gc_tint, pixmap_wx_stipple); } } /* ...end if (weather_alert_flag) */ // Now that we have the file open, we can read out the structures. // We can handle Point, PolyLine and Polygon shapefiles at the moment. HandlePendingEvents(app_context); if (interrupt_drawing_now) { DBFClose( hDBF ); // Clean up open file descriptors SHPClose( hSHP ); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); free_dbfawk_infos(fld_info, sig_info); return; } // Now instead of looping over all the shapes, search for the ones that // are in our viewport and only loop over those if (weather_alert_flag) // We're drawing _one_ weather alert shape { if (found_shape != -1) // Found the record { // just in case we haven't drawn any real maps yet, allocate // the RTree hit array and add our found_shape to it as if we // had found it in an rtree... if (!RTree_hitarray) { RTree_hitarray = (int *)malloc(sizeof(int)*1000); RTree_hitarray_size=1000; } CHECKMALLOC(RTree_hitarray); RTree_hitarray[0]=found_shape; nhits=1; } else // Didn't find the record { nhits=0; } } else // Draw an entire Shapefile map { // if it isn't completely inside the viewport, select those shapes // in the file that intersect the viewport. si will be non null // in this case. if (si) { RTree_hitarray_index=0; // the callback will be executed every time the search finds a // shape whose bounding box overlaps the viewport. // RTree_hitarray will contain the shape numbers of every shape // found, nhits will be how many there are. nhits = Xastir_RTreeSearch(si->root, &viewportRect, (void *)RTreeSearchCallback, 0); } else { // we read the entire shapefile nhits=nEntities; } } // only iterate over the hits found by RTreeSearch, not all of them for (RTree_hitarray_index=0; RTree_hitarray_indextop_boundary = object->dfYMax; alert->left_boundary = object->dfXMin; alert->bottom_boundary = object->dfYMin; alert->right_boundary = object->dfXMax; } // Here we check the bounding box for this shape against our // current viewport. If we can't see it, don't draw it. if ( map_visible_lat_lon( object->dfYMin, // Bottom object->dfYMax, // Top object->dfXMin, // Left object->dfXMax) ) // Right { const char *temp; int jj; int x0 = 0; // Used for computing label rotation int x1 = 0; int y0 = 0; int y1 = 0; if (debug_level & 16) { fprintf(stderr,"Shape %d is visible, drawing it.", structure); fprintf(stderr," Parts in shape: %d\n", object->nParts ); // Number of parts in this structure } if (debug_level & 16) { // Print the field contents for (jj = 0; jj < fieldcount; jj++) { if (fieldcount >= (jj + 1) ) { temp = DBFReadStringAttribute( hDBF, structure, jj ); if (temp != NULL) { fprintf(stderr,"%s, ", temp); } } } fprintf(stderr,"\n"); fprintf(stderr,"Done with field contents\n"); } if (sig_info) { dbfawk_parse_record(sig_info->prog,hDBF,fld_info,structure); if (debug_level & 16) { fprintf(stderr,"------\n"); fprintf(stderr,"dbfawk parse of structure %d: ",structure); fprintf(stderr,"color=%d ",color); fprintf(stderr,"lanes=%d ",lanes); fprintf(stderr,"name=%s ",name); fprintf(stderr,"key=%s ",key); fprintf(stderr,"symbol=%s ",sym); fprintf(stderr,"filled=%d ",filled); fprintf(stderr,"fill_style=%d ",fill_style); fprintf(stderr,"fill_color=%d ",fill_color); fprintf(stderr,"fill_stipple=%d ",fill_stipple); fprintf(stderr,"pattern=%d ",pattern); fprintf(stderr,"display_level=%d ",display_level); fprintf(stderr,"min_display_level=%d ",min_display_level); fprintf(stderr,"label_level=%d ",label_level); fprintf(stderr,"label_color=%d\n",label_color); } /* set attributes */ (void)XSetForeground(XtDisplay(w), gc, colors[color]); // Let the user decide whether to make the map // filled or unfilled via the Map Properties dialog. // This allows things like the NOAA counties map to // be used as a base map (filled) or as a vector // overlay map at the user's discretion. The // choices available are: // 0: Global No-Fill. Don't fill any polygons. // 1: Global Fill. Fill all polygons. // 2: Auto. dbfawk file, if present, takes over control. // if (debug_level & 16) { fprintf(stderr," draw_filled is %d\n",draw_filled_orig); } switch (draw_filled_orig) { case 0: // Global No-Fill (Vector) // Do nothing, user has chosen Global // No_Fill for this map. The draw_filled // variable takes precedence. break; case 1: // Global Fill // Do nothing, user has chosen Global // Fill for this map. The draw_filled // variable takes precedence. break; case 2: // Auto default: // User has chosen Auto Fill for this map, // so the Dbfawk file controls the fill // property. If no dbfawk file, "filled" // will take on the default setting listed // in dbfawk_default_rules[] above. draw_filled = filled; break; } if (weather_alert_flag) { fill_style = FillStippled; } skip_it = (map_color_levels && ((scale_y > display_level) || (scale_y < min_display_level))); skip_label = (map_color_levels && (scale_y > label_level)); } switch ( nShapeType ) { case SHPT_POINT: case SHPT_POINTZ: // We hit this case once for each point shape in the file, // if that shape is within our viewport. if (debug_level & 16) { fprintf(stderr,"Found Point Shapefile\n"); } if (!skip_it) { const char *temp = NULL; int ok = 1; if (map_labels) { temp = name; } // Convert point to Xastir coordinates ok = get_vertex_screen_coords(object, 0, &x, &y); if (ok == 1) { // default symbol if dbfawk doesn't set it char symbol_table = '/'; char symbol_id = '.'; /* small x */ char symbol_over = ' '; // Use symbol from dbfawk if given if (*sym) { symbol_table = sym[0]; symbol_id = sym[1]; symbol_over = sym[2]; } // Fine-tuned the location here so that the middle of // the symbol would be at the proper pixel. symbol(w, 0, symbol_table, symbol_id, symbol_over, pixmap, 1, x-10, y-10, ' '); // Labeling of points done here // Fine-tuned this string so that it is to the right of // the symbol and aligned nicely. if (map_labels && !skip_label) { draw_nice_string(w, pixmap, 0, x+10, y+5, (char*)temp, 0xf, 0x10, strlen(temp)); } } } break; case SHPT_ARC: case SHPT_ARCZ: // We hit this case once for each polyline shape in the // file, if at least part of that shape is within our // viewport. // Default in case we forget to set the line width later: (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineSolid, CapButt,JoinMiter); // gps files in the GPS directory are treated specially to // handle an old pre-dbfawk use case. if (gps_flag) get_gps_color_and_label(filename, gps_label, sizeof(gps_label), &gps_color); // these will be used to determine if we label this feature int new_label = 1; int mod_number; if (ok_to_draw && !skip_it) { int nParts = object->nParts; if (nParts==0) nParts=1; // but don't try to read panPartStart! // Read the vertices for each vector now // vectors may have multiple parts, draw them separately for (int part=0; part < nParts; part++) { int nVertices; int partStart; numXPoints = 0; if (nParts == 1) { nVertices =object->nVertices; partStart = 0; } else if (part < nParts-1) { partStart = object->panPartStart[part]; nVertices = object->panPartStart[part+1] - partStart; } else { partStart = object->panPartStart[part]; nVertices = object->nVertices - partStart; } // numXPoints winds up being the number of points we read into // the points array numXPoints = get_vertices_screen_coords_XPoints(object, partStart, nVertices, points, &high_water_mark_index); // Save the endpoints of the first line segment for // later use in label rotation x0=points[0].x; y0=points[0].y; x1=points[1].x; y1=points[1].y; // Reset these for each part, because we might have changed // them for the labels of the last part. set_shpt_arc_attributes(w, (gps_flag)?gps_color:color, (gps_flag)?3:((lanes)?lanes:1), (gps_flag)?LineOnOffDash:pattern); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(numXPoints), CoordModeOrigin); // draw a label temp = (gps_flag)?gps_label:name; if ( (temp != NULL) && (strlen(temp) != 0) && map_labels && !skip_label ) { x=points[0].x; y=points[0].y; // We only do this determination for the first part of // each arc. If we label one part, we label them all. if (part == 0) { // Set up the mod_number, which is used below to // determine how many of each identical label are // skipped at each zoom level. mod_number = select_arc_label_mod(); // Check whether we've written out this string recently. new_label = check_label_skip(label_hash, temp, mod_number, &skip_label); } if (!skip_label) // Draw the string { // Compute the label rotation angle, select color float angle = (gps_flag)?(-90):get_label_angle(x0,x1,y0,y1); int color_to_use=(gps_flag)?gps_color:label_color; (void)draw_rotated_label_text(w, (int)angle, x, y, strlen(temp), colors[color_to_use], (char *)temp, font_size); } if (new_label) add_label_to_label_hash(label_hash, temp); } } } break; case SHPT_POLYGON: case SHPT_POLYGONZ: if (debug_level & 16) { fprintf(stderr,"Found Polygons\n"); } // Set the stipple now. need to do here, because if // done earlier the labels get stippled, too, and if only done // right when we draw the polygon, single-part shapes with holes // won't stippled properly, because this stipple applies to that // GC. set_shpt_polygon_fill_stipple(w, fill_style, fill_stipple, draw_filled); polygon_hole_flag = 0; // Allocate storage for a flag for each ring in // this Shape. // !!Remember to free this storage later!! polygon_hole_storage = (int *)malloc(object->nParts*sizeof(int)); CHECKMALLOC(polygon_hole_storage); // Determine whether we have any holes, and set flags in // polygon_hole_storage for ring that is a hole: polygon_hole_flag = preprocess_shp_polygon_holes(object, polygon_hole_storage); // reset polygon hole flag if we aren't actually going to need // to go through the hole math and clip region setting // But we still use the poly_hole_storage, because we'll draw // the holes with dashed lines if we're not filling the polygons, // so we do the hole determination regardless of fill settings. if (!map_color_fill || !draw_filled) { polygon_hole_flag = 0; } if (polygon_hole_flag) { // set up a graphics context that has a "swiss cheese" // rectangle with all the holes cut out of it as its clipping // mask. We'll draw our filled polygons in that GC and the holes // won't get filled gc_temp = get_hole_clipping_context(w,object, polygon_hole_storage, &high_water_mark_index); } // Read the vertices for each ring in this Shape int nParts = object->nParts; if (nParts == 0) { nParts = 1; // but panPartStart is null, so don't read it! } for (ring = 0; ring < nParts; ring++ ) { int nVertices; int partStart; if (nParts == 1) { nVertices = object->nVertices; partStart = 0; } else if ( (ring+1) < object->nParts) { partStart = object->panPartStart[ring]; nVertices = object->panPartStart[ring+1] - partStart; } else { partStart = object->panPartStart[ring]; nVertices = object->nVertices-partStart; } numXPoints = get_vertices_screen_coords_XPoints(object, partStart, nVertices, points, &high_water_mark_index); if ( (numXPoints >= 3) && (ok_to_draw && !skip_it) && ( !draw_filled || !map_color_fill || (draw_filled && polygon_hole_storage[ring] == 0) ) ) { // We have a polygon to draw! if ((!draw_filled || !map_color_fill) && polygon_hole_storage[ring] == 1) { // We have a hole drawn as unfilled. draw_polygon_boundary_dashed(w,color,points,numXPoints); } else if (!weather_alert_flag) { // it's not a weather alert, so draw it, filling if // necessary and taking into account any holes. // User requested filled polygons with stippling. // Set the stipple now. need to do here, because // if not done inside the loop, only the first part of the // multi-part polygon gets stippled! set_shpt_polygon_fill_stipple(w, fill_style, fill_stipple, draw_filled); draw_filled_polygon(w, (polygon_hole_flag)?gc_temp:gc, points, numXPoints, color, fill_color, lanes, pattern, (map_color_fill && draw_filled)); } else if (weather_alert_flag) { // If we're a weather alert, we're assuming the shape // is simple with no holes. Draw the filled polygon // and the polygon border, all of which will be // stippled with an alert pattern because we already // set that up in gc_tint. draw_wx_polygon(w, points, numXPoints); } else { // the last two elseifs cover all cases not covered by // the first if, and therefore this is unreachable // and ought to be removed fprintf(stderr,"How have we gotten to this strange place?\n"); } } } // Free the storage that we allocated to hold // the "hole" flags for the shape. free(polygon_hole_storage); if (polygon_hole_flag) { //Free the temporary GC that we may have used to //draw polygons using the clip-mask: XFreeGC(XtDisplay(w), gc_temp); } // Done with drawing shapes, now draw labels // Set fill style back to defaults, or labels would get // stippled along with polygons if we haven't already reset it. // At the moment, draw_filled_polygon *does* reset it, and // draw_wx_polygon only frobs gc_tint, but it doesn't hurt to // make sure. XSetFillStyle(XtDisplay(w), gc, FillSolid); if ( (strlen(name) != 0) && map_labels && !skip_label ) { float label_lon, label_lat; if (debug_level & 16) { fprintf(stderr,"I think I should display labels\n"); } ok = 1; /* TODO: consider other label point options */ /* for now, this function just gives us the center of the * bounding box */ choose_polygon_label_point(object,&label_lon, &label_lat); ok=convert_ll_to_screen_coords(&x, &y, label_lon, label_lat); if (ok == 1 && ok_to_draw) { if (debug_level & 16) { fprintf(stderr, " displaying label %s with color %x\n", name,label_color); } (void)draw_centered_label_text(w, -90, x, y, strlen(name), colors[label_color], (char *)name, font_size); } } break; case SHPT_MULTIPOINT: case SHPT_MULTIPOINTZ: // Not implemented. fprintf(stderr,"Shapefile Multi-Point format files aren't supported!\n"); break; default: // Not implemented. fprintf(stderr,"Shapefile format not supported: Subformat unknown (default clause of switch)!\n"); break; } // End of switch } SHPDestroyObject( object ); // Done with this structure } // Free our hash of label strings, if any. Each hash entry may // have a linked list attached below it. for (i = 0; i < 256; i++) { ptr2 = label_hash[i]; while (ptr2 != NULL) { label_hash[i] = ptr2->next; free(ptr2); ptr2 = label_hash[i]; } } free_dbfawk_infos(fld_info, sig_info); DBFClose( hDBF ); SHPClose( hSHP ); // XmUpdateDisplay (XtParent (da)); if (debug_level & 16) { fprintf(stderr,"High-Mark Index:%d\n", high_water_mark_index); } // Set fill style back to defaults XSetFillStyle(XtDisplay(w), gc, FillSolid); } // End of draw_shapefile_map() // This function will delete any pre-loaded dbfawk sigs and clear Dbf_sigs // This will trigger a reload the first time a shapfile is redisplayed void clear_dbfawk_sigs(void) { if (Dbf_sigs ) { dbfawk_free_sigs(Dbf_sigs); Dbf_sigs = NULL; } } void free_dbfawk_infos(dbfawk_field_info *fld_info, dbfawk_sig_info *sig_info) { dbfawk_free_info(fld_info); free_dbfawk_sig_info(sig_info); } void free_dbfawk_sig_info(dbfawk_sig_info *sig_info) { if (sig_info != NULL && sig_info != dbfawk_default_sig && (sig_info->sig == NULL)) { dbfawk_free_sigs(sig_info); } } // Initializes the global "dbfawk_default_sig" if uninitialized. // do nothing if already initialized. // No matter what, return the pointer dbfawk_sig_info *initialize_dbfawk_default_sig(void) { if (dbfawk_default_sig == NULL) { /* set up default dbfawk when no sig matches */ // This one is ok to leave allocated, as it gets malloc'ed // once during each runtime and then gets left alone. We // don't need to free it. dbfawk_default_sig = calloc(1,sizeof(dbfawk_sig_info)); CHECKMALLOC(dbfawk_default_sig); // Calls awk_new_program which allocates memory. Again, we // don't need to free this one, as it gets allocated only // once per runtime. dbfawk_default_sig->prog = awk_load_program_array(dbfawk_default_rules,dbfawk_default_nrules); } return dbfawk_default_sig; } // Allocate and set up a DBFAWK symbol table. // Note that the symbol table is allocated ONCE the very first time // any shapefile is rendered, and persists forever. The pointers we // use to set up the table must therefore be static and never point to // a local variable. // // This function returns the pointer to the symbol table. // if it was already initialized, just return the pointer awk_symtab *initialize_dbfawk_symbol_table(char *dbffields, size_t dbffields_s, int *color, int *lanes, char *name, size_t name_s, char *key, size_t key_s, char *sym, size_t sym_s, int *filled, int *fill_style, int *fill_color, int *fill_stipple, int *pattern, int *display_level, int *min_display_level, int *label_level, int *label_color, int *font_size, int *label_method, double *label_lon, double *label_lat) { if (!Symtbl) { Symtbl = awk_new_symtab(); awk_declare_sym(Symtbl,"dbffields",STRING,dbffields,dbffields_s); awk_declare_sym(Symtbl,"color",INT,color,sizeof(*color)); awk_declare_sym(Symtbl,"lanes",INT,lanes,sizeof(*lanes)); awk_declare_sym(Symtbl,"name",STRING,name,name_s); awk_declare_sym(Symtbl,"key",STRING,key,key_s); awk_declare_sym(Symtbl,"symbol",STRING,sym,sym_s); awk_declare_sym(Symtbl,"filled",INT,filled,sizeof(*filled)); awk_declare_sym(Symtbl,"fill_style",INT,fill_style,sizeof(*fill_style)); awk_declare_sym(Symtbl,"fill_color",INT,fill_color,sizeof(*fill_color)); awk_declare_sym(Symtbl,"fill_stipple",INT,fill_stipple,sizeof(*fill_stipple)); awk_declare_sym(Symtbl,"pattern",INT,pattern,sizeof(*pattern)); awk_declare_sym(Symtbl,"display_level",INT,display_level,sizeof(*display_level)); awk_declare_sym(Symtbl,"min_display_level",INT,min_display_level,sizeof(*min_display_level)); awk_declare_sym(Symtbl,"label_level",INT,label_level,sizeof(*label_level)); awk_declare_sym(Symtbl,"label_color",INT,label_color,sizeof(*label_color)); awk_declare_sym(Symtbl,"font_size",INT,font_size,sizeof(*font_size)); awk_declare_sym(Symtbl,"label_method",INT,label_method,sizeof(label_method)); awk_declare_sym(Symtbl,"label_lon",FLOAT,label_lon,sizeof(*label_lon)); awk_declare_sym(Symtbl,"label_lat",FLOAT,label_lat,sizeof(*label_lat)); } return (Symtbl); } // We have an open DBF file (pointed to by hDBF), and we might be a // weather alert. Try to find a shape in the dbf file that has a key // matching the alert's filename. // // returns -1 if shape not found or if passed a null alert pointer /* * Weather alert dbfawk files set the "key" variable to the * appropriate search key for each record which is compared to the * alert->title[]. Use the key to find the record we need to alert on. */ int find_wx_alert_shape(alert_entry *alert, DBFHandle hDBF, int recordcount, dbfawk_sig_info *sig_info, dbfawk_field_info *fld_info) { int found_shape = -1; if (alert) { if (alert->index== -1) { int done = 0; int i; // Step through all records for( i = 0; i < recordcount && !done; i++ ) { int keylen; char modified_title[50]; dbfawk_parse_record(sig_info->prog,hDBF,fld_info,i); keylen = strlen(key); if (debug_level & 16) { static char old_key[4]; // Used to limit number of output lines in debug mode if (strncmp(old_key, key, 4)) { fprintf(stderr,"dbfawk alert parse: record %d key=%s\n", i,key); memcpy(old_key, key, sizeof(old_key)); } } xastir_snprintf(modified_title, sizeof(modified_title), "%s", alert->title); // Tweak for RED_FLAG alerts: If RED_FLAG alert // we've changed the 'Z' to an 'F' in our // alert->title already. Change the 'F' back to a // 'Z' temporarily (modified_title) for our // compares. // if (modified_title[3] == 'F' && strncmp(alert->filename, "fz", 2) == 0) { modified_title[3] = 'Z'; } // If match using keylen number of chars, try the // same match but using titlelen number of chars if (strncmp(modified_title,key,keylen) == 0) { int titlelen; titlelen = strlen(modified_title); // Try the same match with titlelen number of // chars if (strncmp(modified_title,key,titlelen) == 0) { found_shape = i; done++; if (debug_level & 16) { fprintf(stderr,"dbfawk alert found it: %d \n",i); fprintf(stderr,"Title %s, key %s\n",modified_title,key); } } else { // Found a match using keylen number of // characters, but it's not a match using // titlelen number of characters. if (debug_level & 16) { fprintf(stderr, "dbfawk alert: match w/keylen, not w/titlelen: %s=%d %s=%d\n", key, keylen, modified_title, titlelen); fprintf(stderr,"Title %s, key %s\n",modified_title,key); } } } } alert->index = found_shape; // Fill it in 'cuz we just found it } else { // We've been here before and we already know the index into the // file to fetch this particular shape. found_shape = alert->index; if (debug_level & 16) { fprintf(stderr,"wx_alert: found_shape = %d\n",found_shape); } } } return (found_shape); } // this function fills in a Rect structure with the current viewport // info void getViewportRect(struct Rect *viewportRect) { double rXmin, rYmin, rXmax,rYmax; get_viewport_lat_lon(&rXmin, &rYmin, &rXmax, &rYmax); viewportRect->boundary[0] = (RectReal) rXmin; viewportRect->boundary[1] = (RectReal) rYmin; viewportRect->boundary[2] = (RectReal) rXmax; viewportRect->boundary[3] = (RectReal) rYmax; } // Return a string corresponding to the name of a shape type // This string is only used in debug output char *getShapeTypeString(int nShapeType) { char *sType; switch ( nShapeType ) { case SHPT_POINT: sType = "Point"; break; case SHPT_POINTZ: sType = "3D Point"; break; case SHPT_ARC: sType = "Polyline"; break; case SHPT_ARCZ: sType = "3D Polyline"; break; case SHPT_POLYGON: sType = "Polygon"; break; case SHPT_POLYGONZ: sType = "3D Polygon"; break; case SHPT_MULTIPOINT: sType = "MultiPoint"; break; default: sType = "Unknown"; break; } return (sType); } // Find an xbm in our collection that matches the weather alert type. // Will use "alert.xbm" if we can't find a more appropriate one. // // Note that we can define more alert files for other countries. They just need to match // the alert text that comes along in the NWS packet. // Current alert files we have defined: // winter_storm.xbm * // snow.xbm // winter_weather.xbm * // flood.xbm // torndo.xbm * // red_flag.xbm // wind.xbm // alert.xbm (Used if no match to another filename) // Alert texts we receive: // FLOOD // SNOW // TORNDO // WIND // WINTER_STORM // WINTER_WEATHER // RED_FLAG // SVRTSM (no file defined for this yet) // Many others. void get_alert_xbm_path(char *xbm_path, size_t xbm_path_size, alert_entry *alert) { // Attempt to open the alert filename: .xbm (lower-case alert text) // to detect whether we have a matching filename for our alert text. FILE *alert_fp = NULL; char xbm_filename[MAX_FILENAME]; xastir_snprintf(xbm_filename, sizeof(xbm_filename), "%s", alert->alert_tag); // Convert the filename to lower-case to_lower(xbm_filename); // Construct the complete path/filename xastir_snprintf(xbm_path, xbm_path_size, "%s/%s.xbm",SYMBOLS_DIR, xbm_filename); // Try opening the file alert_fp = fopen(xbm_path, "rb"); if (alert_fp == NULL) { // Failed to find a matching file: Instead use the "alert.xbm" file xastir_snprintf(xbm_path, xbm_path_size, "%s/%s", SYMBOLS_DIR, "alert.xbm"); } else { // Success: Close the file pointer fclose(alert_fp); } } // If the file we're processing is in the GPS directory and has // a color indicated in the file name, set gps_color to that. Also // set a label string based on the file name with the color stripped off. // arguments: // filename: the base name of the file with all directory paths stripped // off. // the rest speak for themselves. // // This technique exists because WE7U said: // I'd like to be able to change the color of each GPS track for // each team in the field. It'll help to differentiate the tracks // where they happen to cross. // // Alan Crosswell later wrote: // WITH_DBFAWK should handle this case too. Need to add a color // attribute to the generated dbf file // // But these GPS tracks were generally downloaded from GPSMan, and so // we had no control over the attributes in the dbf file, so Alan's // suggestion wouldn't work unless we used shapelib code to modify it after // the fact. // // Since commit 6bc21a, however, Xastir creates a per-file dbfawk file // to go with every shapefile it creates from GPS data, so this // filename-based technique is not really the recommended practice // anymore. Now, the recommended technique is to move the files // out of the GPS directory where they got dumped and edit the per-file // dbfawk to change color and other rendering details like labeling. void get_gps_color_and_label(char *filename, char *gps_label, size_t gps_label_size, int *gps_color) { int jj; int done = 0; // Fill in the label we'll use later xastir_snprintf(gps_label, gps_label_size, "%s", filename); // Knock off the "_Color.shp" portion of the label. Find the last // underline character and change it to an end-of-string. jj = strlen(gps_label); while ( !done && (jj > 0) ) { if (gps_label[jj] == '_') { gps_label[jj] = '\0'; // Terminate it here done++; } jj--; } // Check for a color in the filename: i.e. "Team2_Track_Red.shp" if (strstr(filename,"_Red.shp")) { *gps_color = 0x0c; // Red } else if (strstr(filename,"_Green.shp")) { *gps_color = 0x23; // Area Green Hi } else if (strstr(filename,"_Black.shp")) { *gps_color = 0x08; // black } else if (strstr(filename,"_White.shp")) { *gps_color = 0x0f; // white } else if (strstr(filename,"_Orange.shp")) { *gps_color = 0x62; // orange3 (brighter) } else if (strstr(filename,"_Blue.shp")) { *gps_color = 0x03; // cyan } else if (strstr(filename,"_Yellow.shp")) { *gps_color = 0x0e; // yellow } else if (strstr(filename,"_Purple.shp")) { *gps_color = 0x0b; // mediumorchid } else // Default color { *gps_color = 0x0c; // Red } } // This function converts a lat/lon pair to screen coordinates // It probably belongs in util.c int convert_ll_to_screen_coords(long *x, long *y, float lon, float lat) { int temp_ok; int ok; unsigned long my_lat, my_long; ok = 1; // Convert to Xastir coordinates temp_ok = convert_to_xastir_coordinates(&my_long, &my_lat, lon, lat); if (!temp_ok) { fprintf(stderr,"convert_ll_to_screen_coordinates: Problem converting from lat/lon\n"); ok = 0; *x = 0; *y = 0; } else { convert_xastir_to_screen_coordinates(my_long, my_lat, x, y); } return ok; } // This function extracts all of the vertices from a shapefile object // given a starting point and a number of vertices, and deposits them // into the provided XPoint array. // Returns the number of points converted int get_vertices_screen_coords_XPoints(SHPObject *object, int partStart, int nVertices, XPoint *points, int *high_water_mark_index) { int index = 0; for (int vertex = 0 ; vertex < nVertices; vertex++) { index = get_vertex_screen_coords_XPoint( object, vertex+partStart, points, index, high_water_mark_index); } return (index); } // This function extracts a single vertex from a shapefile object given // its index in the vertex list of the SHPObject // They will be deposited in the array of XPoints, converted to screen // coordinates, at index given // high_water_mark_index will be updated if needed // we return the index of the next point that should be stored. // This will not necessarily be one more than what we were given, if doing // so would overrun the points array. // // high_water_mark represents the most points we've read in this file. It // is used only for debugging output. int get_vertex_screen_coords_XPoint(SHPObject *object, int vertex, XPoint *points, int index, int *high_water_mark_index) { int ok; long x, y; ok = get_vertex_screen_coords(object, vertex, &x, &y); if (ok == 1) { // XDrawLines uses 16-bit unsigned integers (shorts). // Make sure we stay within the limits. points[index].x = l16(x); points[index].y = l16(y); index++; } if (index > *high_water_mark_index) { *high_water_mark_index = index; } if (index >= MAX_MAP_POINTS) { index = MAX_MAP_POINTS - 1; fprintf(stderr,"Trying to overrun the XPoints array handling a shapefile, index=%d, dropping points to prevent overrun\n",index); } return index; } // this function gets a vertex's screen coordinates into variables x and y int get_vertex_screen_coords(SHPObject *object, int vertex, long *x, long *y) { return(convert_ll_to_screen_coords(x,y, object->padfX[vertex], object->padfY[vertex])); } // Select a "mod" number based on the y pixel scale that will be used to // reduce the clutter of SHPT_ARC labels. // // Original comments: // The goal here is to have one complete label visible on the screen // for each road. We end up skipping labels based on zoom level, // which, if the road doesn't have very many segments, may end up // drawing one label almost entirely off-screen. :-( // If we could check the first line segment to see if the label // would be drawn off-screen, perhaps we could start drawing at // segment #2? We'd have to check whether there is a segment #2. // Another possibility would be to shift the label on-screen. Would // this work for twisty/turny roads though? I suppose, 'cuz they'd // end up with more line segments and we could just draw at segment // #2 in that case instead of shifting. // Takes no arguments, because scale_y is a global variable int select_arc_label_mod(void) { int mod_number; if (scale_y == 1) { mod_number = 1; } else if (scale_y <= 2) { mod_number = 1; } else if (scale_y <= 4) { mod_number = 2; } else if (scale_y <= 8) { mod_number = 4; } else if (scale_y <= 16) { mod_number = 8; } else if (scale_y <= 32) { mod_number = 16; } else { mod_number = (int)(scale_y); } return (mod_number); } // This function gives a yes/no answer to "should we show this label?" // We search a label hash for a string, if we find a record and it's // been "found" recently (per mod_number), skip it. // returns 1 if this is a new label (not found in hash) // increments skip_label if we determine we should skip // // We do it this way because the caller actually already has a skip_label // variable that might already be 1, and we don't want to clobber // it with a 0. // // The problem with this method is that we might get strings "written" // at the extreme top or right edge of the display, which means the // strings wouldn't be visible, but Xastir thinks that it wrote the // string out visibly. To partially counteract this I've set it up to // write only some of the identical strings. This still doesn't help // in the cases where a street only comes in from the top or right and // doesn't have an intersection with another street (and therefore // another label) within the view. int check_label_skip(label_string **label_hash, const char *label_text, int mod_number, int *skip_label) { uint8_t hash_index = 0; label_string *ptr2 = NULL; int new_label = 1; // Hash index is just the first // character. Tried using lower 6 bits // of first two chars and lower 7 bits // of first two chars but the result was // slower than just using the first // character. hash_index = (uint8_t)(label_text[0]); ptr2 = label_hash[hash_index]; while (ptr2 != NULL) // Step through the list { // Check 2nd character (fast!) if ( (uint8_t)(ptr2->label[1]) == (uint8_t)(label_text[1]) ) { if (strcasecmp(ptr2->label,label_text) == 0) // Found a match { new_label = 0; ptr2->found = ptr2->found + 1; // Increment the "found" quantity // We change this "mod" number based on zoom level, so that // long strings don't overwrite each other, and so that we // don't get too many or too few labels drawn. This will // cause us to skip intersections (the tiger files appear to // have a label at each intersection). Between rural and // urban areas, this method might not work well. Urban areas // have few intersections, so we'll get fewer labels drawn. A // better method might be to check the screen location for // each one and only write the strings if they are far enough // apart, and only count a string as written if the start of // it is onscreen and the angle is correct for it to be // written on the screen. // Draw a number of labels appropriate for the zoom level. // Labeling: Skip label logic if ( ((ptr2->found - 1) % mod_number) != 0) { (*skip_label)++; } ptr2 = NULL; // End the loop } else { ptr2 = ptr2->next; } } else { ptr2 = ptr2->next; } } return (new_label); } // Compute the rotation angle for label text based on two endpoints of a line float get_label_angle(int x0, int x1, int y0, int y1) { float diff_X = (int)x1 - x0; float diff_Y = (int)y1 - y0; float angle = 0.0; // Angle for the beginning of this polyline if (diff_X == 0.0) // Avoid divide by zero errors { diff_X = 0.0000001; } angle = atan( diff_X / diff_Y ); // Compute in radians // Convert to degrees angle = angle / (2.0 * M_PI ); angle = angle * 360.0; // Change to fit our rotate label function's idea of angle angle = 360.0 - angle; if ( angle > 90.0 ) { angle += 180.0; } if ( angle >= 360.0 ) { angle -= 360.0; } return (angle); } // we keep a hash of labels we've found and how many shapes of this // shapefile have been drawn since the same label was last found. When // we encounter a label we haven't found before, we add it to the hash. void add_label_to_label_hash(label_string **label_hash, const char *label_text) { uint8_t hash_index = 0; label_string *ptr2 = NULL; // Create a new record for this string // and add it to the head of the list. // Make sure to "free" this linked // list. ptr2 = (label_string *)malloc(sizeof(label_string)); CHECKMALLOC(ptr2); memcpy(ptr2->label, label_text, sizeof(ptr2->label)); ptr2->label[sizeof(ptr2->label)-1] = '\0'; // Terminate string ptr2->found = 1; // We use first character of string // as our hash index. hash_index = label_text[0]; ptr2->next = label_hash[hash_index]; label_hash[hash_index] = ptr2; } // When we're doing SHPT_ARC we wind up switching back and forth between // line color and label color. Consolidate that in one spot. void set_shpt_arc_attributes(Widget w, int color, int lanes, int pattern) { (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetLineAttributes(XtDisplay (w), gc, (lanes)?lanes:1, pattern, CapButt,JoinMiter); } // Set the fill style and stipple pattern used for filled polygons void set_shpt_polygon_fill_stipple(Widget w, int fill_style, int fill_stipple, int draw_filled) { (void)XSetFillStyle(XtDisplay(w), gc, fill_style); if (draw_filled != 0 && fill_style == FillStippled) { switch (fill_stipple) { case 0: (void)XSetStipple(XtDisplay(w), gc, pixmap_13pct_stipple); break; case 1: (void)XSetStipple(XtDisplay(w), gc, pixmap_25pct_stipple); break; default: (void)XSetStipple(XtDisplay(w), gc, pixmap_25pct_stipple); break; } } } // Run through all the polygons in the object, return 1 if there are // any rings that are "holes" (rings running counterclockwise). // Fill polygon_hole_storage with 1 if the ring is clockwise (not a hole) // or -1 if it's counterclockwise (a hole) // // This code was preceded by the following comment when it still lived // in draw_shapefile_map (TL;DR: We are using option 7 below): // // -------------------------- // We now handle the "hole" drawing in polygon shapefiles, where // clockwise direction around the ring means a fill, and CCW means a // hole in the polygon. // // Possible implementations: // // 1) Snag an algorithm for a polygon "fill" function from // somewhere, but add a piece that will check for being inside a // "hole" polygon and just not draw while traversing it (change the // pen color to transparent over the holes?). // SUMMARY: How to do this? // // 2) Draw to another layer, then copy only the filled pixels to // their final destination pixmap. // SUMMARY: Draw polygons once, then a copy operation. // // 3) Separate area: Draw polygon. Copy from other map layer into // holes, then copy the result back. // SUMMARY: How to determine outline? // // 4) Use clip-masks to prevent drawing over the hole areas: Draw // to another 1-bit pixmap or region. This area can be the size of // the max shape extents. Filled = 1. Holes = 0. Use that pixmap // as a clip-mask to draw the polygons again onto the final pixmap. // SUMMARY: We end up drawing the shape twice! // // MODIFICATION: Draw a filled rectangle onto the map pixmap using // the clip-mask to control where it actually gets drawn. // SUMMARY: Only end up drawing the shape once. // // 5) Inverted clip-mask: Draw just the holes to a separate pixmap: // Create a pixmap filled with 1's (XFillRectangle & GXset). Draw // the holes and use GXinvert to draw zero's to the mask where the // holes go. Use this as a clip-mask to draw the filled areas of // the polygon to the map pixmap. // SUMMARY: Faster than methods 1-4? // // 6) Use Regions to do the same method as #5 but with more ease. // Create a polygon Region, then create a Region for each hole and // subtract the hole from the polygon Region. Once we have a // complete polygon + holes, use that as the clip-mask for drawing // the real polygon. Use XSetRegion() on the GC to set this up. We // might have to do offsets as well so that the region maps properly // to our map pixmap when we draw the final polygon to it. // SUMMARY: Should be faster than methods 1-5. // // 7) Do method 6 but instead of drawing a polygon region, draw a // rectangle region first, then knock holes in it. Use that region // as the clip-mask for the XFillPolygon() later by calling // XSetRegion() on the GC. We don't really need a polygon region // for a clip-mask. A rectangle with holes in it will work just as // well and should be faster overall. We might have to do offsets // as well so that the region maps properly to our map pixmap when // we draw the final polygon to it. // SUMMARY: This might be the fastest method of the ones listed, if // drawing a rectangle region is faster than drawing a polygon // region. We draw the polygon once here instead of twice, and each // hole only once. The only added drawing time would be the // creation of the rectangle region, which should be fairly fast, // and the subtracting of the hole regions from it. // Shapefiles also allow identical points to be next to each other // in the vertice list. We should look for that and get rid of // duplicate vertices. // // Unfortunately, for Polygon shapes we must make one pass through // the entire set of rings to see if we have any "hole" rings (as // opposed to "fill" rings). If we have any "hole" rings, we must // handle the drawing of the Shape quite differently. // // Speedup: Only loop through the vertices once, by determining // hole/fill polygons as we go. // -------------------------- int preprocess_shp_polygon_holes(SHPObject *object, int *polygon_hole_storage) { int ring; int polygon_hole_flag = 0; // Run through the entire shape (all rings of it) once. Create an // array of flags that specify whether each ring is a fill or a // hole. If any holes found, set the global polygon_hole_flag as // well. for (ring = 0; ring < object->nParts; ring++ ) { // Testing for fill or hole ring. This will // determine how we ultimately draw the // entire shape. // switch ( shape_ring_direction( object, ring) ) { case 0: // Error in trying to compute whether fill or hole fprintf(stderr,"Error in computing fill/hole ring\n"); /* Falls through. */ case 1: // It's a fill ring. Do nothing for these two cases except // clear the flag in our storage polygon_hole_storage[ring] = 0; break; case -1: // It's a hole ring Add it to our list of hole rings here and // set a flag. That way we won't have to run through // SHPRingDir_2d again in the next loop. polygon_hole_flag++; polygon_hole_storage[ring] = 1; break; } } return (polygon_hole_flag); } // This function takes a SHPT_POLYGON object and a vector of ints of length // equal to the number of parts in the polygon and returns a graphics context // with a clipping region set to mask out the holes. // // high_water_mark_index is used for debugging and marks the maximum number // of points we've ever encountered in a shape. GC get_hole_clipping_context(Widget w, SHPObject *object, int *polygon_hole_storage, int *high_water_mark_index) { XRectangle rectangle; long width, height; double top_ll, left_ll, bottom_ll, right_ll; Region region[3]; int temp_region1; int temp_region2; int temp_region3; long x,y; int ok; int ring; int index; int i; XPoint points[MAX_MAP_POINTS]; GC gc_temp = NULL; XGCValues gc_temp_values; //WE7U3 //////////////////////////////////////////////////////////////////////// // Now that we know which are fill/hole rings, worry about drawing // each ring of the Shape: // // 1) Create a filled rectangle region, probably the size of the // Shape extents, and at the same screen coordinates as the entire // shape would normally be drawn. // // 2) Create a region for each hole ring and subtract these new // regions one at a time from the rectangle region created above. // // 3) When the "swiss-cheese" rectangle region is complete, draw // only the filled polygons onto the map pixmap using the // swiss-cheese rectangle region as the clip-mask. Use a temporary // GC for this operation, as I can't find a way to remove a // clip-mask from a GC. We may have to use offsets to make this // work properly. // Create three regions and rotate between them, due to the // XSubtractRegion() needing three parameters. If we later find // that two of the parameters can be repeated, we can simplify our // code. We'll rotate through them mod 3. temp_region1 = 0; // Create empty region region[temp_region1] = XCreateRegion(); // Draw a rectangular clip-mask inside the Region. Use the same // extents as the full Shape. // Set up the real sizes from the Shape // extents. top_ll = object->dfYMax; left_ll = object->dfXMin; bottom_ll = object->dfYMin; right_ll = object->dfXMax; // Convert point to screen coordinates: ok = convert_ll_to_screen_coords(&x, &y, left_ll, top_ll); if (ok) { // Here we check for really wacko points that will cause problems // with the X drawing routines, and fix them. (void) clip_x_y_pair(&x, &y, 0l, screen_width, 0l, screen_height); } // Convert point to screen coordinates ok = convert_ll_to_screen_coords(&width, &height, right_ll, bottom_ll); if (ok) { // Here we check for really wacko points that will cause problems // with the X drawing routines, and fix them. (void) clip_x_y_pair(&width, &height, 1l, screen_width, 1l, screen_height); } //TODO // We can run into trouble here because we only have 16-bit values // to work with. If we're zoomed in and the Shape is large in // comparison to the screen, we'll easily exceed these numbers. // Perhaps we'll need to work with something other than screen // coordinates? Perhaps truncating the values will be adequate. rectangle.x = (short) x; rectangle.y = (short) y; rectangle.width = (unsigned short) width; rectangle.height = (unsigned short) height; // Create the initial region containing a filled rectangle. XUnionRectWithRegion(&rectangle, region[temp_region1], region[temp_region1]); // Create a region for each set of hole vertices (CCW rotation of // the vertices) and subtract each from the rectangle region. for (ring = 0; ring < object->nParts; ring++ ) { int endpoint; int on_screen; if (polygon_hole_storage[ring] == 1) { // It's a hole polygon. Cut the // hole out of our rectangle region. int num_vertices = 0; if( ring == object->nParts-1 ) num_vertices = object->nVertices - object->panPartStart[ring]; else num_vertices = object->panPartStart[ring+1] - object->panPartStart[ring]; //TODO // Snag the vertices and put them into the "points" array, // converting to screen coordinates as we go, then subtracting the // starting point, so that the regions remain small? // // We could either subtract the starting point of each shape from // each point, or take the hit on region size and just use the full // screen size (or whatever part of it the shape required plus the // area from the starting point to 0,0). if ( (ring+1) < object->nParts) { endpoint = object->panPartStart[ring+1]; } //else endpoint = object->nVertices; else { endpoint = object->panPartStart[0] + object->nVertices; } i = 0; // i = Number of points to draw for one ring on_screen = 0; // index = ptr into the shapefile's array of points // i = the index into our XPoint array for (index = object->panPartStart[ring]; index < endpoint; index++) { ok = get_vertex_screen_coords(object, index, &x,&y); if (ok) { // Here we check for really wacko points that will // cause problems with the X drawing routines, and // fix them. Increment on_screen if any of the // points might be on screen. on_screen += clip_x_y_pair(&x, &y, 0l, screen_width, 0l, screen_height); points[i].x = l16(x); points[i].y = l16(y); i++; } if (i > *high_water_mark_index) { *high_water_mark_index = i; } } // End of converting vertices for a ring // Create and subtract the region only if it might be on screen. if (on_screen) { temp_region2 = (temp_region1 + 1) % 3; temp_region3 = (temp_region1 + 2) % 3; // Create empty regions. region[temp_region2] = XCreateRegion(); region[temp_region3] = XCreateRegion(); // Draw the hole polygon if (num_vertices >= 3) { XDestroyRegion(region[temp_region2]); // Release the old region[temp_region2] = XPolygonRegion(points, num_vertices, WindingRule); } else { fprintf(stderr, "draw_shapefile_map:XPolygonRegion with too few vertices:%d\n", num_vertices); } // Subtract region2 from region1 and put the result into // region3. XSubtractRegion(region[temp_region1], region[temp_region2], region[temp_region3]); // Get rid of the two regions we no longer need XDestroyRegion(region[temp_region1]); XDestroyRegion(region[temp_region2]); // Indicate the final result region for the next iteration or // the exit of the loop. temp_region1 = temp_region3; } } } // region[temp_region1] now contains a clip-mask of the original // polygon with holes cut out of it (swiss-cheese rectangle). // Create temporary GC. It looks like we don't need this to create // the regions, but we'll need it when we draw the filled polygons // onto the map pixmap using the final region as a clip-mask. gc_temp = XCreateGC(XtDisplay(w), XtWindow(w), 0, &gc_temp_values); // now copy the fill style and stipple from gc. XCopyGC(XtDisplay(w), gc, (GCFillStyle|GCStipple), gc_temp); // Set the clip-mask into the GC. This GC // is now ruined for other purposes, so // destroy it when we're done drawing this // one shape. XSetRegion(XtDisplay(w), gc_temp, region[temp_region1]); XDestroyRegion(region[temp_region1]); return (gc_temp); } // This function clips an x/y pair to the bounding rectangle specified // by the min/max values passed in. // // it returns 1 if we didn't clip and 0 if we did. int clip_x_y_pair(long *x, long *y, long x_min, long x_max, long y_min, long y_max) { int on_screen=0; // Here we check for really wacko points that will // cause problems with the X drawing routines, and // fix them. Increment on_screen if any of the // points might be on screen. if (*x > x_max) { *x = x_max; } else if (*x < x_min) { *x = x_min; } else { on_screen++; } if (*y > y_max) { *y = y_max; } else if (*y < y_min) { *y = y_min; } else { on_screen++; } return (on_screen); } // draw an unfilled polygon with dashed boundary in given color. void draw_polygon_boundary_dashed(Widget w, int color, XPoint *points, int numPoints) { (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineOnOffDash, CapButt, JoinMiter); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(numPoints), CoordModeOrigin); // reset back to solid (void)XSetLineAttributes (XtDisplay (w), gc, 0, LineSolid, CapButt, JoinMiter); } // draw a (possibly) filled polygon using the specified graphics // context into the specified pixmap out of XPoint array of size // numPoints, in specified boundary and fill colors and with specified // line width and pattern. // // // The graphics context passed in is either the normal one or the one // that does polygon hole clipping. // // "do_the_fill" determines whether we should do the fill or not. // void draw_filled_polygon(Widget w, GC theGC, XPoint *points, int numPoints, int color, int fill_color, int lanes, int pattern, int do_the_fill) { (void)XSetLineAttributes(XtDisplay(w), theGC, (lanes)?lanes:1, pattern, CapButt, JoinMiter); (void)XSetForeground(XtDisplay(w), gc, colors[color]); if (do_the_fill) { (void)XSetForeground(XtDisplay(w), theGC, colors[fill_color]); if (numPoints >3) { (void)XFillPolygon(XtDisplay(w), pixmap, theGC, points, numPoints, Nonconvex, CoordModeOrigin); } else { fprintf(stderr,"draw_filled_polygon: too few points: %d, Skipping XFillPolygon()\n",numPoints); } } // Draw the border (void)XSetForeground(XtDisplay(w), gc, colors[color]); (void)XSetFillStyle(XtDisplay(w), gc, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap, gc, points, l16(numPoints), CoordModeOrigin); } // The wx alerts get drawn in a way almost, but not quite, like others, // but into a different graphics context that already has its attributes // set. So we have a second polygon drawing routine. void draw_wx_polygon(Widget w, XPoint *points, int numPoints) { (void)XSetFillStyle(XtDisplay(w), gc_tint, FillStippled); if (numPoints >= 3) { (void)XFillPolygon(XtDisplay(w), pixmap_alerts, gc_tint, points, numPoints, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "draw_wx_polygon:Too few points:%d, Skipping XFillPolygon()", numPoints); } (void)XSetFillStyle(XtDisplay(w), gc_tint, FillSolid); (void)XDrawLines(XtDisplay(w), pixmap_alerts, gc_tint, points, l16(numPoints), CoordModeOrigin); } // This function selects a point at which to display a shape's label. // // If label_method is one and the lat/lon has been set from dbfawk, // use that point. // // otherwise use the center of the shape's bounding box. void choose_polygon_label_point(SHPObject *object, float *lon, float *lat) { if (label_method == 1 && (label_lat != 0.0 || label_lon != 0.0)) { *lon = label_lon; *lat = label_lat; } else { *lon = (float) (object->dfXMax + object->dfXMin)/2.0; *lat = (float) (object->dfYMax + object->dfYMin)/2.0; } } // We have a slew of variables that control shapefile rendering. They are all // static variables in this file and therefore need to be initialized every // time draw_shapefile_map is called, lest unset variables in this shapefiles's // dbfawk file remain at non-default values set by the previously rendered // shapefile's. // // Note that these are intended to match the defaults set in // dbfawk_default_rules, but because INT_MAX and FONT_DEFAULT can't be // embedded in in that default rule, the former is hard coded over there, // and the default font isn't set at all. Since we set it here, there's no // problem. void initialize_rendering_variables(void) { color=8; lanes=1; filled=0; fill_style=0; fill_color=13; fill_stipple=0; pattern=0; display_level=INT_MAX; min_display_level=0; label_level=0; label_color=8; font_size=FONT_DEFAULT; label_method=0; label_lon=0.0; label_lat=0.0; } #endif // HAVE_LIBSHP Xastir-Release-2.2.4/src/map_shp_fwd.h0000664000175000017500000001147715151324131016562 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* This file is intended to be included only in map_shp.c * It contains forward declarations of functions used only internally to * map_shp.c, so that the order of function definitions in that file * doesn't matter, and all functions inside the file can call any other * function inside map_shp.c irrespective of where they appear in the file. */ void free_dbfawk_infos(dbfawk_field_info *fld_info, dbfawk_sig_info *sig_info); void free_dbfawk_sig_info(dbfawk_sig_info *sig_info); dbfawk_sig_info *initialize_dbfawk_default_sig(void); awk_symtab *initialize_dbfawk_symbol_table(char *dbffields, size_t dbffields_s, int *color, int *lanes, char *name, size_t name_s, char *key, size_t key_s, char *sym, size_t sym_s, int *filled, int *fill_style, int *fill_color, int *fill_stipple, int *pattern, int *display_level, int *min_display_level, int *label_level, int *label_color, int *font_size, int *label_method, double *label_lon, double *label_lat); int find_wx_alert_shape(alert_entry *alert, DBFHandle hDBF, int recordcount, dbfawk_sig_info *sig_info, dbfawk_field_info *fld_info); void getViewportRect(struct Rect *viewportRect); char *getShapeTypeString(int nShapeType); void get_alert_xbm_path(char *xbm_path, size_t xbm_path_size, alert_entry *alert); void get_gps_color_and_label(char *filename, char *gps_label, size_t gps_label_size, int *gps_color); int convert_ll_to_screen_coords(long *x, long *y, float lon, float lat); int get_vertices_screen_coords_XPoints(SHPObject *object, int partStart, int nVertices, XPoint *points, int *high_water_mark_index); int get_vertex_screen_coords_XPoint(SHPObject *object, int vertex, XPoint *points, int index, int *high_water_mark_index); int get_vertex_screen_coords(SHPObject *object, int vertex, long *x, long *y); int select_arc_label_mod(void); int check_label_skip(label_string **label_hash, const char *label_text, int mod_number, int *skip_label); void add_label_to_label_hash(label_string **label_hash, const char *label_text); float get_label_angle(int x0, int x1, int y0, int y1); void set_shpt_arc_attributes(Widget w, int color, int lanes, int pattern); void set_shpt_polygon_fill_stipple(Widget w, int fill_style, int fill_stipple, int draw_filled); int preprocess_shp_polygon_holes(SHPObject *object, int *polygon_hole_storage); GC get_hole_clipping_context(Widget w, SHPObject *object, int *polygon_hole_storage, int *high_water_mark_index); int clip_x_y_pair(long *x, long *y, long x_min, long x_max, long y_min, long y_max); void draw_polygon_boundary_dashed(Widget w, int color, XPoint *points, int numPoints); void draw_filled_polygon(Widget w, GC theGC, XPoint *points, int numPoints, int color, int fill_color, int lanes, int pattern, int do_the_fill); void draw_wx_polygon(Widget w, XPoint *points, int numPoints); void choose_polygon_label_point(SHPObject *object, float *lon, float *lat); void initialize_rendering_variables(void); Xastir-Release-2.2.4/src/map_tif.c0000664000175000017500000025215015151324131015700 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #define DOS_HDR_LINES 8 #define GRID_MORE 5000 extern int npoints; /* tsk tsk tsk -- globals */ extern int mag; #ifdef HAVE_LIBGEOTIFF #include "xtiffio.h" //#include "geotiffio.h" #include "geo_normalize.h" // Must be last include file #include "leak_detection.h" /********************************************************** * get_alt_fgd_path() * * Used to search for .fgd in ../metadata subdir, as it is * laid out on a USGS CDROM. **********************************************************/ void get_alt_fgd_path(char *fullpath, int fullpath_length) { int len; int i, j = 0; char *dir = fullpath; char fname[MAX_FILENAME]; // Split up into directory and filename len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i]; break; } } for (++i; i <= len; i++) { fname[j++] = fullpath[i]; // Grab the filename if (fullpath[i] == '\0') { break; } } // We have the filename now. dir now points to // the '/' at the end of the path. // Now do it again to knock off the "data" subdirectory // from the end. dir[0] = '\0'; // Terminate the current string, wiping out the '/' character len = (int)strlen (fullpath); // Length of the new shortened string for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i + 1]; // Dir now points to one past the '/' character break; } } for (++i; i <= len; i++) { if (fullpath[i] == '\0') { break; } } // Add "metadata/" into the path xastir_snprintf(dir, fullpath_length, "metadata/%s", fname); //fprintf(stderr,"FGD Directory: %s\n", fullpath); } /********************************************************** * get_alt_fgd_path2() * * Used to search for .fgd in Metadata subdir. This function * is no longer used. **********************************************************/ void get_alt_fgd_path2(char *fullpath, int fullpath_length) { int len; int i, j = 0; char *dir = fullpath; char fname[MAX_FILENAME]; // Split up into directory and filename len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { dir = &fullpath[i + 1]; break; } } for (++i; i <= len; i++) { fname[j++] = fullpath[i]; if (fullpath[i] == '\0') { break; } } // Add "Metadata/" into the path xastir_snprintf(dir, fullpath_length, "Metadata/%s", fname); } /*********************************************************** * read_fgd_file() * * Read in the "*.fgd" file associated with the geoTIFF * file. Get the corner points from it and return. If * no fgd file exists for this map, return a 0. ***********************************************************/ int read_fgd_file ( char* tif_filename, float* f_west_bounding, float* f_east_bounding, float* f_north_bounding, float* f_south_bounding) { char fgd_file[MAX_FILENAME];/* Complete path/name of .fgd file */ FILE *fgd; /* Filehandle of .fgd file */ char line[MAX_FILENAME]; /* One line from .fgd file */ int length; char *ptr; /* Substring pointer */ int num_coordinates = 0; /* Read the .fgd file to find corners of the map neat-line */ xastir_snprintf(fgd_file, sizeof(fgd_file), "%s", tif_filename); length = strlen(fgd_file); /* Change the extension to ".fgd" */ fgd_file[length-3] = 'f'; fgd_file[length-2] = 'g'; fgd_file[length-1] = 'd'; if (debug_level & 512) { fprintf(stderr,"%s\n",fgd_file); } /* * Search for the WEST/EAST/NORTH/SOUTH BOUNDING COORDINATES * in the .fgd file. */ fgd = fopen (fgd_file, "r"); // Try an alternate path (../metadata/ subdirectory) if the first path didn't work // This allows working with USGS maps directly from CDROM if (fgd == NULL) { get_alt_fgd_path(fgd_file, sizeof(fgd_file) ); if (debug_level & 512) { fprintf(stderr,"%s\n",fgd_file); } fgd = fopen (fgd_file, "r"); } if (fgd != NULL) { while ( ( !feof (fgd) ) && ( num_coordinates < 4 ) ) { get_line (fgd, line, MAX_FILENAME); if (*f_west_bounding == 0.0) { if ( ( (ptr = strstr(line, "WEST BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "West_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 25, " %f", f_west_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"West Bounding: %f\n",*f_west_bounding); } num_coordinates++; } } else if (*f_east_bounding == 0.0) { if ( ( (ptr = strstr(line, "EAST BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "East_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 25, " %f", f_east_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"East Bounding: %f\n",*f_east_bounding); } num_coordinates++; } } else if (*f_north_bounding == 0.0) { if ( ( (ptr = strstr(line, "NORTH BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "North_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 26, " %f", f_north_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"North Bounding: %f\n",*f_north_bounding); } num_coordinates++; } } else if (*f_south_bounding == 0.0) { if ( ( (ptr = strstr(line, "SOUTH BOUNDING COORDINATE:") ) != NULL) || ( (ptr = strstr(line, "South_Bounding_Coordinate:") ) != NULL) ) { if (1 != sscanf (ptr + 26, " %f", f_south_bounding)) { fprintf(stderr,"read_fgd_file:sscanf parsing error\n"); } if (debug_level & 512) { fprintf(stderr,"South Bounding: %f\n",*f_south_bounding); } num_coordinates++; } } } fclose (fgd); } else { if (debug_level & 512) fprintf(stderr,"Couldn't open '.fgd' file, assuming no map collar to chop %s\n", tif_filename); return(0); } /* * We should now have exactly four bounding coordinates. * These specify the map neat-line corners. We can use * them to chop off the white collar from around the map. */ if (num_coordinates != 4) { fprintf(stderr,"Couldn't find 4 bounding coordinates in '.fgd' file, map %s\n", tif_filename); return(0); } if (debug_level & 512) { fprintf(stderr,"%f %f %f %f\n", *f_south_bounding, *f_north_bounding, *f_west_bounding, *f_east_bounding); } return(1); /* Successful */ } /*********************************************************** * draw_geotiff_image_map() * * Here's where we handle geoTIFF files, such as USGS DRG * topo maps. The .fgd file gives us the lat/lon of the map * neat-line corners for USGS maps. We use this info to * chop off the white map border. If no .fgd file is present, * we assume there is no map collar to be cropped and display * every pixel. * We also translate from the map datum to WGS84. We use * libgeotiff/libtiff/libproj for these operations. * TODO: * Provide support for datums other than NAD27/NAD83/WGS84. * Libproj doesn't currently support many datums. * * Provide support for handling different map projections. * Perhaps by reprojecting the map data and storing it on * disk in another format. * * Select 'o', 'f', 'k', or 'c' maps based on zoom level. * Might also put some hysteresis in this so that it keeps * the current type of map through one extra zoom each way. * 'c': Good from x256 to x064. * 'f': Good from x128 to x032. Not very readable at x128. * 'k': Good from x??? to x???. * 'o': Good from x064 to x004. Not very readable at x64. ***********************************************************/ void draw_geotiff_image_map (Widget w, char *dir, char *filenm, alert_entry * UNUSED(alert), u_char UNUSED(alert_color), int destination_pixmap, map_draw_flags *mdf) { char file[MAX_FILENAME]; /* Complete path/name of image file */ char short_filenm[MAX_FILENAME]; TIFF *tif = (TIFF *) 0; /* Filehandle for tiff image file */ GTIF *gtif = (GTIF *) 0; /* GeoKey-level descriptor */ /* enum { VERSION = 0, MAJOR, MINOR }; */ int versions[3]; uint32_t width; /* Width of the image */ uint32_t height; /* Height of the image */ uint16_t bitsPerSample; /* Should be 8 for USGS DRG's */ uint16_t samplesPerPixel = 1; /* Should be 1 for USGS DRG's. Some maps don't have this tag so we default to 1 */ uint32_t rowsPerStrip; /* Should be 1 for USGS DRG's */ uint16_t planarConfig; /* Should be 1 for USGS DRG's */ uint16_t photometric; /* DRGs are RGB (2) */ int bytesPerRow; /* Bytes per scanline row of tiff file */ GTIFDefn defn; /* Stores geotiff details */ u_char *imageMemory; /* Fixed pointer to same memory area */ uint32_t row; /* My row counter for the loop */ int num_colors; /* Number of colors in the geotiff colormap */ uint16_t *red_orig, *green_orig, *blue_orig; /* Used for storing geotiff colors */ XColor my_colors[256]; /* Used for translating colormaps */ unsigned long west_bounding = 0; unsigned long east_bounding = 0; unsigned long north_bounding = 0; unsigned long south_bounding = 0; float f_west_bounding = 0.0; float f_east_bounding = 0.0; float f_north_bounding = 0.0; float f_south_bounding = 0.0; unsigned long west_bounding_wgs84 = 0; unsigned long east_bounding_wgs84 = 0; unsigned long north_bounding_wgs84 = 0; unsigned long south_bounding_wgs84 = 0; float f_NW_x_bounding; float f_NW_y_bounding; float f_NE_x_bounding; float f_NE_y_bounding; float f_SW_x_bounding; float f_SW_y_bounding; float f_SE_x_bounding; float f_SE_y_bounding; unsigned long NW_x_bounding_wgs84 = 0; unsigned long NW_y_bounding_wgs84 = 0; double f_NW_x_bounding_wgs84 = 0.0; double f_NW_y_bounding_wgs84 = 0.0; unsigned long NE_x_bounding_wgs84 = 0; unsigned long NE_y_bounding_wgs84 = 0; double f_NE_x_bounding_wgs84 = 0.0; double f_NE_y_bounding_wgs84 = 0.0; unsigned long SW_x_bounding_wgs84 = 0; unsigned long SW_y_bounding_wgs84 = 0; double f_SW_x_bounding_wgs84 = 0.0; double f_SW_y_bounding_wgs84 = 0.0; unsigned long SE_x_bounding_wgs84 = 0; unsigned long SE_y_bounding_wgs84 = 0; double f_SE_x_bounding_wgs84 = 0.0; double f_SE_y_bounding_wgs84 = 0.0; int NW_x = 0; /* Store pixel values for map neat-line */ int NW_y = 0; /* ditto */ int NE_x = 0; /* ditto */ int NE_y = 0; /* ditto */ int SW_x = 0; /* ditto */ int SW_y = 0; /* ditto */ int SE_x = 0; /* ditto */ int SE_y = 0; /* ditto */ int left_crop; /* Pixel cropping value */ int right_crop; /* Pixel cropping value */ int top_crop; /* Pixel cropping value */ int bottom_crop; /* Pixel cropping value */ double xxx, yyy; /* LFM: needs more accuracy here */ long sxx, syy; /* X Y screen plot positions */ float steph; float stepw; int stepwc, stephc; char map_it[MAX_FILENAME]; /* Used to hold filename for status line */ int have_fgd; /* Tells where we have an associated *.fgd file */ //short datum; char *datum_name; /* Points to text name of datum */ //double *GeoTie; int crop_it = 0; /* Flag which tells whether the image should be cropped */ uint32_t column; float xastir_left_x_increment; float left_x_increment; float xastir_left_y_increment; float left_y_increment; float xastir_right_x_increment; float right_x_increment; float xastir_right_y_increment; float right_y_increment; float xastir_top_y_increment; float top_y_increment; float xastir_bottom_y_increment; float bottom_y_increment; // float xastir_avg_y_increment; float avg_y_increment; int row_offset; unsigned long current_xastir_left; unsigned long current_xastir_right; uint32_t current_left; uint32_t current_right; // uint32_t current_line_width; unsigned long xastir_current_y; uint32_t column_offset; unsigned long xastir_current_x; double *PixelScale; int have_PixelScale; uint16_t qty; int SkipRows; unsigned long view_min_x, view_max_x; unsigned long view_min_y, view_max_y; unsigned long xastir_total_y; int NW_line_offset; int NE_line_offset; int NW_xastir_x_offset; int NE_xastir_x_offset; int NW_xastir_y_offset; int NW_x_offset; int NE_x_offset; float xastir_avg_left_right_y_increment; float total_avg_y_increment; unsigned long view_left_minus_pixel_width; unsigned long view_top_minus_pixel_height; int proj_is_latlong; short PCS; int usgs_drg; char *imagedesc; usgs_drg = mdf->usgs_drg; // yes, no, or auto if (debug_level & 16) { fprintf(stderr,"%s/%s\n", dir, filenm); } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Create a shorter filename for display short_filename_for_status(filenm, short_filenm, sizeof(short_filenm)); /* Check whether we have an associated *.fgd file. This * file contains the neat-line corner points for USGS DRG * maps, which allows us to chop off the map collar. */ have_fgd = read_fgd_file( file, &f_west_bounding, &f_east_bounding, &f_north_bounding, &f_south_bounding ); /* * If we are able to read the fgd file then we have the lat/lon * corner points in floating point variables. If there isn't * an fgd file then we must get the info from the geotiff * tags themselves and we assume that there's no map collar to * chop off. */ /* * What we NEED to do (implemented a bit later in this function * in order to support geotiff files created with other map * datums, is to open up the geotiff file and get the map datum * used for the data. Then convert the corner points to WGS84 * and check to see whether the image is inside our viewport. * Some USGS geotiff maps have map data in NAD83 datum and the * .fgd file incorrectly specifying NAD27 datum. There are also * some USGS geotiff maps created with WGS84 datum. */ /* convert_to_xastir_coordinates( x,y,longitude,latitude ); */ if (have_fgd) /* Could be a USGS file */ { int temp_ok1, temp_ok2; if (debug_level & 16) { fprintf(stderr,"FGD: W:%f E:%f N:%f S:%f\n", f_west_bounding, f_east_bounding, f_north_bounding, f_south_bounding); } crop_it = 1; /* The map collar needs to be cropped */ temp_ok1 = convert_to_xastir_coordinates( &west_bounding, &north_bounding, f_west_bounding, f_north_bounding ); temp_ok2 = convert_to_xastir_coordinates( &east_bounding, &south_bounding, f_east_bounding, f_south_bounding ); if (!temp_ok1 || !temp_ok2) { fprintf(stderr,"draw_geotiff_image_map: problem converting from lat/lon\n"); return; } /* * Check whether map is inside our current view. It'd be * good to do a datum conversion first, but we don't know * what the datum is by this point in the code. I'm just * doing this check here for speed, so that I can eliminate * maps that aren't even close to our viewport area, without * having to open those map files. All other maps that pass * this test (at the next go-around later in the code) must * have their corner points datum-shifted so that we can * REALLY tell whether a map fits within the viewport. * * Perhaps add a bit to the corners (the max datum shift?) * to do our quick check? I decided to add about 10 seconds * to the map edges, which equates to 1000 in the Xastir * coordinate system. That should be greater than any datum * shift in North America for USGS topos. I'm artificially * inflating the size of the map just for this quick * elimination check. * * bottom top left right */ // Check whether we're indexing or drawing the map if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { // We're drawing. if (!map_visible( south_bounding + 1000, north_bounding - 1000, west_bounding - 1000, east_bounding + 1000 ) ) { if (debug_level & 16) { fprintf(stderr,"Map not within current view.\n"); fprintf(stderr,"Skipping map: %s\n", file); } // Map isn't inside our current view. We're done. // Free any memory used and return. // return; // Skip this map } else { if (debug_level & 16) { fprintf(stderr,"Map is viewable\n"); } } } } // End of if have_fgd /* * At this point the map MAY BE in our current view. * We don't know for sure until we do a datum translation * on the bounding coordinates and check again. Note that * if there's not an accompanying .fgd file, we don't have * the bounding coordinates yet by this point. */ if (debug_level & 16) { fprintf(stderr,"XTIFFOpen\n"); } /* Open TIFF descriptor to read GeoTIFF tags */ tif = XTIFFOpen (file, "r"); if (!tif) { return; } if (debug_level & 16) { fprintf(stderr,"GTIFNew\n"); } /* Open GTIF Key parser. Keys will be read at this time */ gtif = GTIFNew (tif); if (!gtif) { /* Close the TIFF file descriptor */ XTIFFClose (tif); return; } if (debug_level & 16) { fprintf(stderr,"GTIFDirectoryInfo\n"); } /* * Get the GeoTIFF directory info. Need this for * some of the operations further down in the code. */ GTIFDirectoryInfo (gtif, versions, 0); /* if (versions[MAJOR] > 1) { fprintf(stderr,"This file is too new for me\n"); GTIFFree (gtif); XTIFFClose (tif); return; } */ if (debug_level & 16) { fprintf(stderr,"GTIFGetDefn\n"); } /* I might want to attempt to avoid the GTIFGetDefn * call, as it takes a bit of time per file. It * normalizes the info. Try getting just the tags * or keys that I need individually instead. I * need "defn" for the GTIFProj4ToLatLong calls though. */ if (GTIFGetDefn (gtif, &defn)) { if (debug_level & 16) { GTIFPrintDefn (&defn, stdout); } } else { fprintf(stderr,"GTIFGetDefn failed\n"); } proj_is_latlong=FALSE; if( !GTIFKeyGet(gtif,ProjectedCSTypeGeoKey, &PCS,0,1)) { // fprintf(stderr,"Warning: no PCS in geotiff file %s, assuming map is in lat/lon!\n", filenm); proj_is_latlong=TRUE; } /* Fetch a few TIFF fields for this image */ if ( !TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width) ) { width = 5493; fprintf(stderr,"No width tag found in file, setting it to 5493\n"); } if ( !TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height) ) { height = 6840; fprintf(stderr,"No height tag found in file, setting it to 6840\n"); } // If we're autodetecting usgs_drg, check the image description tag // Note, the TIFFGetField doesn't allocate a string, it returns a pointer // to an existing one. Don't free it! if (usgs_drg == 2) { if ( TIFFGetField (tif, TIFFTAG_IMAGEDESCRIPTION, &imagedesc)) { if (strncasecmp(imagedesc,"USGS GeoTIFF DRG",16) == 0) { usgs_drg = 1; // Yes } else { usgs_drg = 0; // No } } else { usgs_drg = 0; // No tag, assume not a usgs topo } } /* * If we don't have an associated .fgd file for this map, * check for corner points in the ImageDescription * tag (proposed new USGS DRG standard). Boundary * coordinates will be the outside corners of the image * unless I can find some other proof. * Currently I assume that the map has no * map collar to chop off and set the neat-line corners * to be the outside corners of the image. * * NOTE: For the USGS files (with a map collar), the * image must be cropped and rotated and is slightly * narrower at one end (top for northern hemisphere, bottom * for southern hemisphere). For other files with no map * collar, the image is rectangular but the lat/lon * coordinates may be rotated. */ if (!have_fgd) // Not a USGS map or perhaps a newer spec { crop_it = 1; /* crop this map image */ /* * Snag and parse ImageDescription tag here. */ /* Code goes here for getting ImageDescription tag... */ /* Figure out the bounding coordinates for this map */ if (debug_level & 16) { fprintf(stderr,"\nCorner Coordinates:\n"); } /* Find lat/lon for NW corner of image */ xxx = 0.0; yyy = 0.0; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) // Do all 4 of these in one call? { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Upper Left" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) // Do all 4 of these in one call? { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_NW_x_bounding = (float)xxx; f_NW_y_bounding = (float)yyy; /* Find lat/lon for NE corner of image */ xxx = width - 1; yyy = 0.0; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_NE_x_bounding = (float)xxx; f_NE_y_bounding = (float)yyy; /* Find lat/lon for SW corner of image */ xxx = 0.0; yyy = height - 1; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_SW_x_bounding = (float)xxx; f_SW_y_bounding = (float)yyy; /* Find lat/lon for SE corner of image */ xxx = width - 1; yyy = height - 1; if ( GTIFImageToPCS( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%-13s ", "Lower Right" ); fprintf(stderr,"(%11.3f,%11.3f)\n", xxx, yyy ); } } if ( proj_is_latlong || GTIFProj4ToLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr," (%s,", GTIFDecToDMS( xxx, "Long", 2 ) ); fprintf(stderr,"%s)\n", GTIFDecToDMS( yyy, "Lat", 2 ) ); fprintf(stderr,"%f %f\n", xxx, yyy); } } else { if (!proj_is_latlong) { fprintf(stderr,"Failed GTIFProj4ToLatLong() call\n"); } } f_SE_x_bounding = (float)xxx; f_SE_y_bounding = (float)yyy; if (f_NW_y_bounding > 0) { yyy=((f_NW_y_bounding > f_NE_y_bounding) ? f_NE_y_bounding : f_NW_y_bounding); xxx=((f_SW_y_bounding < f_SE_y_bounding) ? f_SE_y_bounding : f_SW_y_bounding); } else { yyy=((f_NW_y_bounding < f_NE_y_bounding) ? f_NE_y_bounding : f_NW_y_bounding); xxx=((f_SW_y_bounding > f_SE_y_bounding) ? f_SE_y_bounding : f_SW_y_bounding); } f_north_bounding = (float)yyy; f_south_bounding = (float)xxx; if (f_NE_x_bounding > 0) { xxx=((f_NE_x_bounding < f_SE_x_bounding) ? f_SE_x_bounding : f_NE_x_bounding); yyy=((f_NW_x_bounding > f_SW_x_bounding) ? f_SW_x_bounding : f_NW_x_bounding); } else { xxx=((f_NE_x_bounding > f_SE_x_bounding) ? f_SE_x_bounding : f_NE_x_bounding); yyy=((f_NW_x_bounding < f_SW_x_bounding) ? f_SW_x_bounding : f_NW_x_bounding); } f_west_bounding = (float)yyy; f_east_bounding = (float)xxx; } f_NW_x_bounding = f_west_bounding; f_NW_y_bounding = f_north_bounding; f_SW_x_bounding = f_west_bounding; f_SW_y_bounding = f_south_bounding; f_NE_x_bounding = f_east_bounding; f_NE_y_bounding = f_north_bounding; f_SE_x_bounding = f_east_bounding; f_SE_y_bounding = f_south_bounding; // Fill in the wgs84 variables so we can do a datum // conversion but keep our original values also. f_NW_x_bounding_wgs84 = f_NW_x_bounding; f_NW_y_bounding_wgs84 = f_NW_y_bounding; f_SW_x_bounding_wgs84 = f_SW_x_bounding; f_SW_y_bounding_wgs84 = f_SW_y_bounding; f_NE_x_bounding_wgs84 = f_NE_x_bounding; f_NE_y_bounding_wgs84 = f_NE_y_bounding; f_SE_x_bounding_wgs84 = f_SE_x_bounding; f_SE_y_bounding_wgs84 = f_SE_y_bounding; /* Get the datum */ // GTIFKeyGet( gtif, GeogGeodeticDatumGeoKey, &datum, 0, 1 ); // if (debug_level & 16) // fprintf(stderr,"GeogGeodeticDatumGeoKey: %d\n", datum ); /* Get the tiepoints (in UTM coordinates always?) * In our case they look like: * * 0.000000 Y * 0.000000 X * 0.000000 Z * 572983.025771 Y in UTM (longitude for some maps?) * 5331394.085064 X in UTM (latitude for some maps?) * 0.000000 Z * */ /* if (debug_level & 16) { fprintf(stderr,"Tiepoints:\n"); if ( TIFFGetField( tif, TIFFTAG_GEOTIEPOINTS, &qty, &GeoTie ) ) { for ( i = 0; i < qty; i++ ) { fprintf(stderr,"%f\n", *(GeoTie + i) ); } } } */ /* Get the geotiff horizontal datum name */ if ( defn.Datum != 32767 ) { GTIFGetDatumInfo( defn.Datum, &datum_name, NULL ); if (debug_level & 16) { fprintf(stderr,"Datum: %d/%s\n", defn.Datum, datum_name ); } } /* * Perform a datum shift on the bounding coordinates before we * check whether the map is inside our viewport. At the moment * this is still hard-coded to NAD27 datum. If the map is already * in WGS84 or NAD83 datum, skip the datum conversion code. */ if ( (defn.Datum != 6030) /* DatumE_WGS84 */ && (defn.Datum != 6326) /* Datum_WGS84 */ && (defn.Datum != 6269) ) /* Datum_North_American_Datum_1983 */ { if (debug_level & 16) { fprintf(stderr,"***** Attempting Datum Conversions\n"); } // This code uses datum.h/datum.c to do the conversion // instead of the proj.4 library as we had before. // Here we assume that if it's not one of the three datums // listed above, it's NAD27. // Convert NW corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_NW_y_bounding_wgs84, &f_NW_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert NE corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_NE_y_bounding_wgs84, &f_NE_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert SW corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_SW_y_bounding_wgs84, &f_SW_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS // Convert SE corner to WGS84 wgs84_datum_shift(TO_WGS_84, &f_SE_y_bounding_wgs84, &f_SE_x_bounding_wgs84, D_NAD_27_CONUS); // NAD27 CONUS (131) } else if (debug_level & 16) { fprintf(stderr,"***** Skipping Datum Conversion\n"); } /* * Convert new datum-translated bounding coordinates to the * Xastir coordinate system. * convert_to_xastir_coordinates( x,y,longitude,latitude ) */ // NW corner if (!convert_to_xastir_coordinates( &NW_x_bounding_wgs84, &NW_y_bounding_wgs84, (float)f_NW_x_bounding_wgs84, (float)f_NW_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // NE corner if (!convert_to_xastir_coordinates( &NE_x_bounding_wgs84, &NE_y_bounding_wgs84, (float)f_NE_x_bounding_wgs84, (float)f_NE_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // SW corner if (!convert_to_xastir_coordinates( &SW_x_bounding_wgs84, &SW_y_bounding_wgs84, (float)f_SW_x_bounding_wgs84, (float)f_SW_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } // SE corner if (!convert_to_xastir_coordinates( &SE_x_bounding_wgs84, &SE_y_bounding_wgs84, (float)f_SE_x_bounding_wgs84, (float)f_SE_y_bounding_wgs84 ) ) { fprintf(stderr,"draw_geotiff_image_map: Problem converting from lat/lon\n"); fprintf(stderr,"Did you follow the instructions for installing PROJ?\n"); return; } /* * Check whether map is inside our current view. These * are the real datum-shifted bounding coordinates now, * so this is the final decision as to whether the map * should be loaded. */ // Find the largest dimensions if (NW_y_bounding_wgs84 <= NE_y_bounding_wgs84) { north_bounding_wgs84 = NW_y_bounding_wgs84; } else { north_bounding_wgs84 = NE_y_bounding_wgs84; } if (NW_x_bounding_wgs84 <= SW_x_bounding_wgs84) { west_bounding_wgs84 = NW_x_bounding_wgs84; } else { west_bounding_wgs84 = SW_x_bounding_wgs84; } if (SW_y_bounding_wgs84 >= SE_y_bounding_wgs84) { south_bounding_wgs84 = SW_y_bounding_wgs84; } else { south_bounding_wgs84 = SE_y_bounding_wgs84; } if (NE_x_bounding_wgs84 >= SE_x_bounding_wgs84) { east_bounding_wgs84 = NE_x_bounding_wgs84; } else { east_bounding_wgs84 = SE_x_bounding_wgs84; } // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA039"), short_filenm); statusline(map_it,0); // Indexing ... // We're indexing only. Save the extents in the index. index_update_xastir(filenm, // Filename only south_bounding_wgs84, // Bottom north_bounding_wgs84, // Top west_bounding_wgs84, // Left east_bounding_wgs84, // Right 0); // Default Map Level //Free any memory used and return /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); return; // Done indexing this file } else { xastir_snprintf(map_it, sizeof(map_it), langcode ("BBARSTA028"), short_filenm); statusline(map_it,0); // Loading ... } // bottom top left right if (!map_visible( south_bounding_wgs84, north_bounding_wgs84, west_bounding_wgs84, east_bounding_wgs84 ) ) { if (debug_level & 16) { fprintf(stderr,"Map not within current view.\n"); fprintf(stderr,"Skipping map: %s\n", file); } /* * Map isn't inside our current view. We're done. * Free any memory used and return */ /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); return; /* Skip this map */ } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } /* From running in debug mode: Width: 5493 Height: 6840 Rows Per Strip: 1 Bits Per Sample: 8 Samples Per Pixel: 1 Planar Config: 1 */ /* Fetch a few TIFF fields for this image */ if ( !TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric) ) { photometric = PHOTOMETRIC_RGB; fprintf(stderr,"No photometric tag found in file, setting it to RGB\n"); } if ( !TIFFGetField (tif, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip) ) { rowsPerStrip = 1; fprintf(stderr,"No rowsPerStrip tag found in file, setting it to 1\n"); } if ( !TIFFGetField (tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample) ) { bitsPerSample = 8; fprintf(stderr,"No bitsPerSample tag found in file, setting it to 8\n"); } if ( !TIFFGetField (tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel) ) { samplesPerPixel = 1; fprintf(stderr,"No samplesPerPixel tag found in file, setting it to 1\n"); } if ( !TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planarConfig) ) { planarConfig = 1; fprintf(stderr,"No planarConfig tag found in file, setting it to 1\n"); } if (debug_level & 16) { fprintf(stderr," Width: %ld\n", (long int)width); fprintf(stderr," Height: %ld\n", (long int)height); fprintf(stderr," Photometric: %d\n", photometric); fprintf(stderr," Rows Per Strip: %ld\n", (long int)rowsPerStrip); fprintf(stderr," Bits Per Sample: %d\n", bitsPerSample); fprintf(stderr,"Samples Per Pixel: %d\n", samplesPerPixel); fprintf(stderr," Planar Config: %d\n", planarConfig); } /* * Check for properly formatted geoTIFF file. If it isn't * in the standard format we're looking for, spit out an * error message and return. * * Should we also check compression method here? */ /* if ( ( rowsPerStrip != 1) */ if ( (samplesPerPixel != 1) || ( bitsPerSample != 8) || ( planarConfig != 1) ) { fprintf(stderr,"*** geoTIFF file %s is not in the proper format:\n", file); if (samplesPerPixel != 1) fprintf(stderr,"***** Has %d samples per pixel instead of 1\n", samplesPerPixel); if (bitsPerSample != 8) fprintf(stderr,"***** Has %d bits per sample instead of 8\n", bitsPerSample); if (planarConfig != 1) fprintf(stderr,"***** Has planarConfig of %d instead of 1\n", planarConfig); fprintf(stderr,"*** Please reformat it and try again.\n"); XTIFFClose(tif); return; } if (debug_level & 16) { fprintf(stderr,"Loading geoTIFF map: %s\n", file); } /* * Snag the original map colors out of the colormap embedded * inside the tiff file. */ if (photometric == PHOTOMETRIC_PALETTE) { if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &red_orig, &green_orig, &blue_orig)) { TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag"); GTIFFree (gtif); XTIFFClose (tif); return; } } /* Here are the number of possible colors. It turns out to * be 256 for a USGS geotiff file, of which only the first * 13 are used. Other types of geotiff's may use more * colors (and do). A proposed revision to the USGS DRG spec * allows using more colors. */ num_colors = (1L << bitsPerSample); /* Print out the colormap info */ //if (debug_level & 16) { // int l; // // for (l = 0; l < num_colors; l++) // fprintf(stderr," %5u: %5u %5u %5u\n", // l, // red_orig[l], // green_orig[l], // blue_orig[l]); //} // Example output from a USGS 7.5' map: // // 0: 0 0 0 black // 1: 65280 65280 65280 light grey // 2: 0 38656 41984 // 3: 51968 0 5888 // 4: 33536 16896 9472 contour lines, brownish-red // 5: 51456 59904 40192 green // 6: 35072 13056 32768 purple? freeways, some roads // 7: 65280 59904 0 // 8: 42752 57856 57856 blue, bodies of water // 9: 65280 47104 47104 red brick color, cities? // 10: 55808 45824 54784 purple. freeways, some roads // 11: 53504 53504 53504 grey // 12: 52992 41984 36352 contour lines, tan, more dots/less lines // 13: 0 0 0 black, unused slot? // 14: 0 0 0 black, unused slot? // 15: 0 0 0 black, unused slot? // 16: 0 0 0 black, unused slot? // The rest are all 0's. if (crop_it) // USGS geoTIFF map { /* * Next: * Convert the map neat-line corners to image x/y coordinates. * This will give the map neat-line coordinates in pixels. * Use this data to chop the image at these boundaries * and to stretch the shorter lines to fit a rectangle. * * Note that at this stage we're using the bounding coordinates * that are in the map original datum so that the translations * to pixel coordinates will be correct. * * Note that we already have the datum-shifted values for all * the corners in the *_wgs84 variables. In short: We use the * non datum-shifted values to work with the tiff file, and the * datum-shifted values to plot the points in Xastir. */ HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (debug_level & 16) fprintf(stderr,"\nNW neat-line corner = %f\t%f\n", f_NW_x_bounding, f_NW_y_bounding); xxx = (double)f_NW_x_bounding; yyy = (double)f_NW_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) // Do all 4 in one call? { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) // Do all 4 in one call? { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } NW_x = (int)(xxx + 0.5); /* Tricky way of rounding */ NW_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", NW_x, NW_y); } if (NW_x < 0 || NW_y < 0 || NW_x >= (int)width || NW_y >= (int)height) { fprintf(stderr, "\nWarning: NW Neat-line corner calculated at x:%d, y:%d, %s\n", NW_x, NW_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (NW_x < 0) { NW_x = 0; } if (NW_x >= (int)width) { NW_x = width - 1; } if (NW_y < 0) { NW_y = 0; } if (NW_y >= (int)height) { NW_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"NE neat-line corner = %f\t%f\n", f_NE_x_bounding, f_NE_y_bounding); xxx = (double)f_NE_x_bounding; yyy = (double)f_NE_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } NE_x = (int)(xxx + 0.5); /* Tricky way of rounding */ NE_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", NE_x, NE_y); } if (NE_x < 0 || NE_y < 0 || NE_x >= (int)width || NE_y >= (int)height) { fprintf(stderr, "\nWarning: NE Neat-line corner calculated at x:%d, y:%d, %s\n", NE_x, NE_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (NE_x < 0) { NE_x = 0; } if (NE_x >= (int)width) { NE_x = width - 1; } if (NE_y < 0) { NE_y = 0; } if (NE_y >= (int)height) { NE_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"SW neat-line corner = %f\t%f\n", f_SW_x_bounding, f_SW_y_bounding); xxx = (double)f_SW_x_bounding; yyy = (double)f_SW_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } SW_x = (int)(xxx + 0.5); /* Tricky way of rounding */ SW_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", SW_x, SW_y); } if (SW_x < 0 || SW_y < 0 || SW_x >= (int)width || SW_y >= (int)height) { fprintf(stderr, "\nWarning: SW Neat-line corner calculated at x:%d, y:%d, %s\n", SW_x, SW_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (SW_x < 0) { SW_x = 0; } if (SW_x >= (int)width) { SW_x = width - 1; } if (SW_y < 0) { SW_y = 0; } if (SW_y >= (int)height) { SW_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } if (debug_level & 16) fprintf(stderr,"SE neat-line corner = %f\t%f\n", f_SE_x_bounding, f_SE_y_bounding); xxx = (double)f_SE_x_bounding; yyy = (double)f_SE_y_bounding; /* Convert lat/long to projected coordinates */ if ( proj_is_latlong || GTIFProj4FromLatLong( &defn, 1, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"%11.3f,%11.3f\n", xxx, yyy); } /* Convert from PCS coordinates to image pixel coordinates */ if ( GTIFPCSToImage( gtif, &xxx, &yyy ) ) { if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %f, %f\n", xxx, yyy); } SE_x = (int)(xxx + 0.5); /* Tricky way of rounding */ SE_y = (int)(yyy + 0.5); /* Tricky way of rounding */ if (debug_level & 16) { fprintf(stderr,"X/Y Pixels: %d, %d\n", SE_x, SE_y); } if (SE_x < 0 || SE_y < 0 || SE_x >= (int)width || SE_y >= (int)height) { fprintf(stderr, "\nWarning: SE Neat-line corner calculated at x:%d, y:%d, %s\n", SE_x, SE_y, filenm); fprintf(stderr, "Limits are: 0,0 and %ld,%ld. Resetting corner position.\n", (long int)width, (long int)height); fprintf(stderr, "Map may appear in the wrong location or scale incorrectly.\n"); if (SE_x < 0) { SE_x = 0; } if (SE_x >= (int)width) { SE_x = width - 1; } if (SE_y < 0) { SE_y = 0; } if (SE_y >= (int)height) { SE_y = height -1; } /* //Free any memory used and return // We're finished with the geoTIFF key parser, so get rid of it GTIFFree (gtif); // Close the TIFF file descriptor XTIFFClose (tif); return; */ } } } else { fprintf(stderr,"Problem in translating\n"); } } else /* * No map collar to crop off, so we already know * where the corner points are. This is for non-USGS * maps. */ { NW_x = 0; NW_y = 0; NE_x = width - 1; NE_y = 0; SW_x = 0; SW_y = height - 1; SE_x = width - 1; SE_y = height - 1; } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Here's where we crop off part of the black border for USGS maps. if (crop_it) // USGS maps only { int i = 3; NW_x += i; NW_y += i; NE_x -= i; NE_y += i; SW_x += i; SW_y -= i; SE_x -= i; SE_y -= i; } // Now figure out the rough pixel crop values from what we know. // Image rotation means a simple rectangular crop isn't sufficient. if (NW_y < NE_y) { top_crop = NW_y; } else { top_crop = NE_y; } if (SW_y > SE_y) { bottom_crop = SW_y; } else { bottom_crop = SE_y; } if (NE_x > SE_x) { right_crop = NE_x; } else { right_crop = SE_x; } if (NW_x < SW_x) { left_crop = NW_x; } else { left_crop = SW_x; } if (!crop_it) /* If we shouldn't crop the map collar... */ { top_crop = 0; bottom_crop = height - 1; left_crop = 0; right_crop = width - 1; } // The four crop variables are the maximum rectangle that we // wish to keep, rotation notwithstanding (we may want to crop // part of some lines due to rotation). Crop all lines/pixels // outside these ranges. //WE7U if (top_crop < 0 || top_crop >= (int)height) { top_crop = 0; } if (bottom_crop < 0 || bottom_crop >= (int)height) { bottom_crop = height - 1; } if (left_crop < 0 || left_crop >= (int)width) { left_crop = 0; } if (right_crop < 0 || right_crop >= (int)width) { right_crop = width - 1; } if (debug_level & 16) { fprintf(stderr,"Crop points (pixels):\n"); fprintf(stderr,"Top: %d\tBottom: %d\tLeft: %d\tRight: %d\n", top_crop, bottom_crop, left_crop, right_crop); } /* * The color map is embedded in the geoTIFF file as TIFF tags. * We get those tags out of the file and translate to our own * colormap. * Allocate colors for the map image. We allow up to 256 colors * and allow only 8-bits per pixel in the original map file. We * get our 24-bit RGB colors right out of the map file itself, so * the colors should look right. * We're picking existing colormap colors that are closest to * the original map colors, so we shouldn't run out of colors * for other applications. * * Brightness adjust for the colors? Implemented in the * "raster_map_intensity" variable below. */ { int l; switch (photometric) { case PHOTOMETRIC_PALETTE: for (l = 0; l < num_colors; l++) { my_colors[l].red = (uint16_t)(red_orig[l] * raster_map_intensity); my_colors[l].green = (uint16_t)(green_orig[l] * raster_map_intensity); my_colors[l].blue = (uint16_t)(blue_orig[l] * raster_map_intensity); if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; case PHOTOMETRIC_MINISBLACK: for (l = 0; l < num_colors; l++) { int v = (l * 255) / (num_colors-1); my_colors[l].red = my_colors[l].green = my_colors[l].blue = (uint16_t)(v * raster_map_intensity) << 8; if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; case PHOTOMETRIC_MINISWHITE: for (l = 0; l < num_colors; l++) { int v = (((num_colors-1)-l) * 255) / (num_colors-1); my_colors[l].red = my_colors[l].green = my_colors[l].blue = (uint16_t)(v * raster_map_intensity) << 8; if (visual_type == NOT_TRUE_NOR_DIRECT) { // XFreeColors(XtDisplay(w), cmap, &(my_colors[l].pixel),1,0); XAllocColor(XtDisplay(w), cmap, &my_colors[l]); } else { pack_pixel_bits(my_colors[l].red, my_colors[l].green, my_colors[l].blue, &my_colors[l].pixel); } } break; } } HandlePendingEvents(app_context); if (interrupt_drawing_now) { GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Each data value should be an 8-bit value, which is a // pointer into a color // table. Later we perform a translation from the geoTIFF // color table to our current color table (matching values // as close as possible), at the point where we're writing // the image to the pixmap. /* We should be ready now to actually read in some * pixels and deposit them on the screen. We will * allocate memory for the data area based on the * sizes of fields and data in the geoTIFF file. */ bytesPerRow = TIFFScanlineSize(tif); if (debug_level & 16) { fprintf(stderr,"\nInitial Bytes Per Row: %d\n", bytesPerRow); } // Here's a tiny malloc that'll hold only one scanline worth of pixels imageMemory = (u_char *) malloc(bytesPerRow + 2); CHECKMALLOC(imageMemory); // TODO: Figure out the middle boundary on each edge for // lat/long and adjust the crop values to match the largest // of either the middle or the corners for each edge. This // will help to handle edges that are curved. /* * There are some optimizations that can still be done: * * 1) Read in all scanlines but throw away unneeded pixels, * paying attention not to lose smaller details. Compare * neighboring pixels? * * 3) Keep a map cache or a screenmap cache to reduce need * for reading map files so often. */ // Here we wish to start at the top line that may have // some pixels of interest and proceed to the bottom line // of interest. Process scanlines from top_crop to bottom_crop. // Start at the left/right_crop pixels, compute the lat/long // of each, using x/y increments so we can quickly scan across // the line. // Iterate across the line checking whether each pixel is // within the viewport. If so, plot it on the pixmap at // the correct scale. // Later I may wish to get the lat/lon of each pixel and plot // it at the correct point, to handle the curvature of each // line (this might be VERY slow). Right now I treat them as // straight lines. // At this point we have these variables defined. The // first column contains map corners in Xastir coordinates, // the second column contains map corners in pixels: // // NW corner: // NW_x_bounding_wgs84 <-> NW_x // NW_y_bounding_wgs84 <-> NW_y // // NE corner: // NE_x_bounding_wgs84 <-> NE_x // NE_y_bounding_wgs84 <-> NE_y // // SW corner: // SW_x_bounding_wgs84 <-> SW_x // SW_y_bounding_wgs84 <-> SW_y // // SE corner: // SE_x_bounding_wgs84 <-> SE_x // SE_y_bounding_wgs84 <-> SE_y // I should be able to use these variables to figure out // the xastir coordinates of each scanline pixel using // linear interpolation along each edge. // // I don't want to use the crop values in general. I'd // rather crop properly along the neat line instead of a // rectangular crop. // // Define lines along the left/right edges so that I can // compute the Xastir coordinates of each pixel along these // two lines. These will be the start/finish of each of my // scanlines, and I can use these values to compute the // x/y_increment values for each line. This way I can // stretch short lines as I go along, and auto-crop the // white border as well. // Left_line goes from (top to bottom): // NW_x,NW_y -> SW_x,SW_y // and from: // west_bounding_wgs84,north_bounding_wgs84 -> west_bounding_wgs84,south_bounding_wgs84 // // Right_line goes from(top to bottom): // NE_x,NE_y -> SE_x,SE-Y // and from: // east_bounding_wgs84,north_bounding_wgs84 -> east_bounding_wgs84,south_bounding_wgs84 // // Simpler: Along each line, Xastir coordinates change how much // and in what direction as we move down one scanline? // These increments are how much we change in Xastir coordinates and // in pixel coordinates as we move down either the left or right // neatline one pixel. // Be prepared for 0 angle of rotation as well (x-increments = 0). // Xastir Coordinate System: // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // Watch out for division by zero here. // // Left Edge X Increment Per Scanline (Going from top to bottom). // This increment will help me to keep track of the left edge of // the image, both in Xastir coordinates and in pixel coordinates. // if (SW_y != NW_y) { // Xastir coordinates xastir_left_x_increment = (float) (1.0 * labs( (long)SW_x_bounding_wgs84 - (long)NW_x_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SW_y - NW_y)); // Pixel coordinates left_x_increment = (float)(1.0 * abs(SW_x - NW_x) / abs(SW_y - NW_y)); if (SW_x_bounding_wgs84 < NW_x_bounding_wgs84) { xastir_left_x_increment = -xastir_left_x_increment; } if (SW_x < NW_x) { left_x_increment = -left_x_increment; } //WE7U //if (abs(left_x_increment) > (width/10)) { // left_x_increment = 0.0; // xastir_left_x_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_left_x_increment: %f %ld %ld %f %d %d %d %d\n", xastir_left_x_increment, SW_x_bounding_wgs84, NW_x_bounding_wgs84, left_x_increment, SW_x, NW_x, bottom_crop, top_crop); } else { // Xastir coordinates xastir_left_x_increment = 0; // Pixel coordinates left_x_increment = 0; } // // Left Edge Y Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the left edge of // the image, both in Xastir coordinates and in pixel coordinates. // if (SW_y != NW_y) { // Xastir coordinates xastir_left_y_increment = (float) (1.0 * labs( (long)SW_y_bounding_wgs84 - (long)NW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SW_y - NW_y)); // Pixel coordinates left_y_increment = (float)1.0; // Aren't we going down one pixel each time? if (SW_y_bounding_wgs84 < NW_y_bounding_wgs84) // Ain't gonn'a happen { xastir_left_y_increment = -xastir_left_y_increment; } //WE7U //if (abs(left_y_increment) > (width/10)) { // xastir_left_y_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_left_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_left_y_increment, SW_y_bounding_wgs84, NW_y_bounding_wgs84, left_y_increment, SW_y, NW_y, bottom_crop, top_crop); } else { // Xastir coordinates xastir_left_y_increment = 0; // Pixel coordinates left_y_increment = 0; } // // Right Edge X Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the right edge of // the image, both in Xastir coordinates and image coordinates. // if (SE_y != NE_y) { // Xastir coordinates xastir_right_x_increment = (float) (1.0 * labs( (long)SE_x_bounding_wgs84 - (long)NE_x_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_y - NE_y)); // Pixel coordinates right_x_increment = (float)(1.0 * abs(SE_x - NE_x) / abs(SE_y - NE_y)); if (SE_x_bounding_wgs84 < NE_x_bounding_wgs84) { xastir_right_x_increment = -xastir_right_x_increment; } if (SE_x < NE_x) { right_x_increment = -right_x_increment; } //WE7U //if (abs(right_x_increment) > (width/10)) { // right_x_increment = 0.0; // xastir_right_x_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_right_x_increment: %f %ld %ld %f %d %d %d %d\n", xastir_right_x_increment, SE_x_bounding_wgs84, NE_x_bounding_wgs84, right_x_increment, SE_x, NE_x, bottom_crop, top_crop); } else { // Xastir coordinates xastir_right_x_increment = 0; // Pixel coordinates right_x_increment = 0; } // // Right Edge Y Increment Per Scanline (Going from top to bottom) // This increment will help me to keep track of the right edge of // the image, both in Xastir coordinates and in image coordinates. // if (SE_y != NE_y) { // Xastir coordinates xastir_right_y_increment = (float) (1.0 * labs( (long)SE_y_bounding_wgs84 - (long)NE_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_y - NE_y)); // Pixel coordinates right_y_increment = (float)1.0; // Aren't we going down one pixel each time? if (SE_y_bounding_wgs84 < NE_y_bounding_wgs84) // Ain't gonn'a happen { xastir_right_y_increment = -xastir_right_y_increment; } //WE7U //if (abs(right_y_increment) > (width/10)) { // xastir_right_y_increment = 0.0; //} if (debug_level & 16) fprintf(stderr,"xastir_right_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_right_y_increment, SE_y_bounding_wgs84, NE_y_bounding_wgs84, right_y_increment, SE_y, NE_y, bottom_crop, top_crop); } else { // Xastir coordinates xastir_right_y_increment = 0; // Pixel coordinates right_y_increment = 0; } if (debug_level & 16) { fprintf(stderr," Left x increments: %f %f\n", xastir_left_x_increment, left_x_increment); fprintf(stderr," Left y increments: %f %f\n", xastir_left_y_increment, left_y_increment); fprintf(stderr,"Right x increments: %f %f\n", xastir_right_x_increment, right_x_increment); fprintf(stderr,"Right y increments: %f %f\n", xastir_right_y_increment, right_y_increment); } // Compute how much "y" changes per pixel as we traverse from left to right // along a scanline along the top of the image. // // Top Edge Y Increment Per X-Pixel Width (Going from left to right). // This increment will help me to get rid of image rotation. // if (NE_x != NW_x) { // Xastir coordinates xastir_top_y_increment = (float) (1.0 * labs( (long)NE_y_bounding_wgs84 - (long)NW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(NE_x - NW_x)); // And a "+ 1.0" here? // Pixel coordinates top_y_increment = (float)(1.0 * abs(NE_y - NW_y) / abs(NE_x - NW_x)); if (NE_y_bounding_wgs84 < NW_y_bounding_wgs84) { xastir_top_y_increment = -xastir_top_y_increment; } if (NE_y < NW_y) { top_y_increment = -top_y_increment; } if (debug_level & 16) fprintf(stderr,"xastir_top_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_top_y_increment, NE_y_bounding_wgs84, NW_y_bounding_wgs84, top_y_increment, NE_y, NW_y, right_crop, left_crop); } else { // Xastir coordinates xastir_top_y_increment = 0; // Pixel coordinates top_y_increment = 0; } // Compute how much "y" changes per pixel as you traverse from left to right // along a scanline along the bottom of the image. // // Bottom Edge Y Increment Per X-Pixel Width (Going from left to right). // This increment will help me to get rid of image rotation. // if (SE_x != SW_x) { // Xastir coordinates xastir_bottom_y_increment = (float) (1.0 * labs( (long)SE_y_bounding_wgs84 - (long)SW_y_bounding_wgs84 ) // Need to add one pixel worth here yet / abs(SE_x - SW_x)); // And a "+ 1.0" here? // Pixel coordinates bottom_y_increment = (float)(1.0 * abs(SE_y - SW_y) / abs(SE_x - SW_x)); if (SE_y_bounding_wgs84 < SW_y_bounding_wgs84) { xastir_bottom_y_increment = -xastir_bottom_y_increment; } if (SE_y < SW_y) { bottom_y_increment = -bottom_y_increment; } if (debug_level & 16) fprintf(stderr,"xastir_bottom_y_increment: %f %ld %ld %f %d %d %d %d\n", xastir_bottom_y_increment, SE_y_bounding_wgs84, SW_y_bounding_wgs84, bottom_y_increment, SE_y, SW_y, right_crop, left_crop); } else { // Xastir coordinates xastir_bottom_y_increment = 0; // Pixel coordinates bottom_y_increment = 0; } // Find the average change in Y as we traverse from left to right one pixel // xastir_avg_y_increment = (float)(xastir_top_y_increment + xastir_bottom_y_increment) / 2.0; avg_y_increment = (float)(top_y_increment + bottom_y_increment) / 2.0; // Find edges of current viewport in Xastir coordinates // view_min_x = NW_corner_longitude; // left edge of view if (view_min_x > 129600000l) { view_min_x = 0; } view_max_x = SE_corner_longitude; // right edge of view if (view_max_x > 129600000l) { view_max_x = 129600000l; } view_min_y = NW_corner_latitude; // top edge of view if (view_min_y > 64800000l) { view_min_y = 0; } view_max_y = SE_corner_latitude; // bottom edge of view if (view_max_y > 64800000l) { view_max_y = 64800000l; } /* Get the pixel scale */ have_PixelScale = TIFFGetField( tif, TIFFTAG_GEOPIXELSCALE, &qty, &PixelScale ); if (debug_level & 16) { if (have_PixelScale) { fprintf(stderr,"PixelScale: %f %f %f\n", *PixelScale, *(PixelScale + 1), *(PixelScale + 2) ); } else { fprintf(stderr,"No PixelScale tag found in file\n"); } } // Use PixelScale to determine lines to skip at each // zoom level? // O-size map: // ModelPixelScaleTag (1,3): // 2.4384 2.4384 0 // // F-size map: // ModelPixelScaleTag (1,3): // 10.16 10.16 0 // // C-size map: // ModelPixelScaleTag (1,3): // 25.400001 25.400001 0 // if (debug_level & 16) { fprintf(stderr,"Size: x %ld, y %ld\n", scale_x,scale_y); } // I tried to be very aggressive with the scaling factor // below (3.15) in order to skip the most possible rows // to speed things up. If you see diagonal lines across // the maps, increase this number (up to a max of 4.0 // probably). A higher number means less rows skipped, // which improves the look but slows the map drawing down. // // This needs modification somewhat when the raster is already in // lat/long, and the PixelScale is already in degrees per pixel. // The scale_y is the integer number of hundredths of seconds per pixel. // The decision of how many rows to skip can simply be made by converting // the PixelScale to the same units as scale_y, and skipping accordingly. if (have_PixelScale) { double coef; if (!proj_is_latlong) { coef = 3.15; } else { coef=100*60*60; // xastir coords are in 1/100 of a second, // and lat/lon pixel scales will be in degrees } SkipRows = (int)( ( scale_y / ( *PixelScale * coef ) ) + 0.5 ); if (SkipRows < 1) { SkipRows = 1; } if (SkipRows > (int)(height / 10) ) { SkipRows = height / 10; } } else { SkipRows = 1; } if (debug_level & 16) { fprintf(stderr,"SkipRows: %d\n", SkipRows); } // Use SkipRows to set increments for the loops below. if ( top_crop <= 0 ) { top_crop = 0; // First row of image } if ( ( bottom_crop + 1) >= (int)height ) { bottom_crop = height - 1; // Last row of image } // Here I pre-compute some of the values I'll need in the // loops below in order to save some time. NW_line_offset = (int)(NW_y - top_crop); NE_line_offset = (int)(NE_y - top_crop); NW_xastir_x_offset = (int)(xastir_left_x_increment * NW_line_offset); NE_xastir_x_offset = (int)(xastir_right_x_increment * NE_line_offset); NW_xastir_y_offset = (int)(xastir_left_y_increment * NW_line_offset); NW_x_offset = (int)(1.0 * left_x_increment * NW_line_offset); NE_x_offset = (int)(1.0 * right_x_increment * NE_line_offset); xastir_avg_left_right_y_increment = (float)((xastir_right_y_increment + xastir_left_y_increment) / 2.0); total_avg_y_increment = (float)(xastir_avg_left_right_y_increment * avg_y_increment); // (Xastir bottom - Xastir top) / height //steph = (double)( (left_y_increment + right_y_increment) / 2); // NOTE: This one does not take into account current height steph = (float)( (SW_y_bounding_wgs84 - NW_y_bounding_wgs84) / (1.0 * (SW_y - NW_y) ) ); // Compute scaled pixel size for XFillRectangle stephc = (int)( ( (1.50 * steph / scale_x) + 1.0) + 1.5); view_top_minus_pixel_height = (unsigned long)(view_min_y - steph); HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (imageMemory) { free(imageMemory); } GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Set the bit-blitting function to XOR. This is only used if // DRG_XOR_colors is set to a non-zero value, but we set it here // outside the pixel loop for speed reasons. // if (DRG_XOR_colors) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt,JoinMiter); // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); // yellow // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x0f]); // White // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x03]); // cyan // (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x06]); // orange (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); } // Iterate over the rows of interest only. Using the rectangular // top/bottom crop values for these is ok at this point. // // Put row multipliers above loops. Try to get as many // multiplications as possible outside the loops. Adds and // subtracts are ok. Try to do as little floating point stuff // as possible inside the loops. // for ( row = top_crop; (int)row < bottom_crop + 1; row+= SkipRows ) { int skip = 0; HandlePendingEvents(app_context); if (interrupt_drawing_now) { if (imageMemory) { free(imageMemory); } GTIFFree (gtif); XTIFFClose (tif); // Update to screen (void)XCopyArea(XtDisplay(da),pixmap,XtWindow(da),gc,0,0,screen_width,screen_height,0,0); return; } // Our offset from the top row of the map neatline // (kind of... ignoring rotation anyway). row_offset = row - top_crop; //fprintf(stderr,"row_offset: %d\n", row_offset); // Compute the line end-points in Xastir coordinates // Initially was a problem here: Offsetting from NW_x_bounding but // starting at top_crop line. Fixed by last term added to two // equations below. current_xastir_left = (unsigned long) ( NW_x_bounding_wgs84 + ( 1.0 * xastir_left_x_increment * row_offset ) - NW_xastir_x_offset ); current_xastir_right = (unsigned long) ( NE_x_bounding_wgs84 + ( 1.0 * xastir_right_x_increment * row_offset ) - NE_xastir_x_offset ); //if (debug_level & 16) // fprintf(stderr,"Left: %ld Right: %ld\n", // current_xastir_left, // current_xastir_right); // In pixel coordinates: current_left = (int) ( NW_x + ( 1.0 * left_x_increment * row_offset ) + 0.5 - NW_x_offset ); current_right = (int) ( NE_x + ( 1.0 * right_x_increment * row_offset ) + 0.5 - NE_x_offset ); //WE7U: This comparison is always false: current_left is unsigned //therefore always positive! //if (current_left < 0) // current_left = 0; if (current_right >= width) { current_right = width - 1; } // current_line_width = current_right - current_left + 1; // Pixels // if (debug_level & 16) // fprintf(stderr,"Left: %ld Right: %ld Width: %ld\n", // current_left, // current_right, current_line_width); // Compute original pixel size in Xastir coordinates. Note // that this can change for each scanline in a USGS geoTIFF. // (Xastir right - Xastir left) / width-of-line // Need the "1.0 *" or the math will be incorrect (won't be a float) stepw = (float)( (current_xastir_right - current_xastir_left) / (1.0 * (current_right - current_left) ) ); // if (debug_level & 16) // fprintf(stderr,"\t\t\t\t\t\tPixel Width: %f\n",stepw); // Compute scaled pixel size for XFillRectangle stepwc = (int)( ( (1.0 * stepw / scale_x) + 1.0) + 0.5); // In Xastir coordinates xastir_current_y = (unsigned long)(NW_y_bounding_wgs84 + (xastir_left_y_increment * row_offset) ); xastir_current_y = (unsigned long)(xastir_current_y - NW_xastir_y_offset); view_left_minus_pixel_width = view_min_x - stepw; // Check whether any part of the scanline will be within the // view. If so, read the scanline from the file and iterate // across the pixels. If not, skip this line altogether. // Compute right edge of image xastir_total_y = (unsigned long) ( xastir_current_y - ( total_avg_y_increment * (current_right - current_left) ) ); // Check left edge y-value then right edge y-value. // If either are within view, process the line, else skip it. if ( ( ( xastir_current_y <= view_max_y) && (xastir_total_y >= view_top_minus_pixel_height) ) || ( ( xastir_total_y <= view_max_y ) && ( xastir_total_y >= view_top_minus_pixel_height ) ) ) { // Read one geoTIFF scanline if (TIFFReadScanline(tif, imageMemory, row, 0) < 0) { break; // No more lines to read or we couldn't read the file at all } // Iterate over the columns of interest, skipping the left/right // cropped pixels, looking for pixels that fit within our viewport. // for ( column = current_left; column < (current_right + 1); column++ ) { skip = 0; column_offset = column - current_left; // Pixels //fprintf(stderr,"Column Offset: %ld\n", column_offset); // Pixels //fprintf(stderr,"Current Left: %ld\n", current_left); // Pixels xastir_current_x = (unsigned long) current_xastir_left + (stepw * column_offset); // In Xastir coordinates // Left line y value minus // avg y-increment per scanline * avg y-increment per x-pixel * column_offset xastir_total_y = (unsigned long) ( xastir_current_y - ( total_avg_y_increment * column_offset ) ); //fprintf(stderr,"Xastir current: %ld %ld\n", xastir_current_x, xastir_current_y); // Check whether pixel fits within boundary lines (USGS maps) // This is how we get rid of the last bit of white border at // the top and bottom of the image. if (have_fgd) // USGS map { if ( (xastir_total_y > SW_y_bounding_wgs84) || (xastir_total_y < NW_y_bounding_wgs84) ) { skip++; } // Here's a trick to make it look like the map pages join better. // If we're within a certain distance of a border, change any black // pixels to white (changes map border to less obtrusive color). if ( *(imageMemory + column) == 0x00 ) // If pixel is Black { if ( (xastir_total_y > (SW_y_bounding_wgs84 - 25) ) || (xastir_total_y < (NW_y_bounding_wgs84 + 25) ) || (xastir_current_x < (SW_x_bounding_wgs84 + 25) ) || (xastir_current_x > (SE_x_bounding_wgs84 - 25) ) ) { //WE7U: column is unsigned so "column >= 0" is always true // if ((int)column < bytesPerRow && column >= 0) { if ((int)column < bytesPerRow) { *(imageMemory + column) = 0x01; // Change to White } else { //WE7U // fprintf(stderr,"draw_geotiff_image_map: Bad fgd file for map?: %s\n", filenm); } } } } /* Look for left or right map boundaries inside view */ if ( !skip && ( xastir_current_x <= view_max_x ) && ( xastir_current_x >= view_left_minus_pixel_width ) && ( xastir_total_y <= view_max_y ) && ( xastir_total_y >= view_top_minus_pixel_height ) ) { // Here are the corners of our viewport, using the Xastir // coordinate system. Notice that Y is upside down: // // left edge of view = NW_corner_longitude // right edge of view = SE_corner_longitude // top edge of view = NW_corner_latitude // bottom edge of view = SE_corner_latitude // Compute the screen position of the pixel and scale it sxx = (xastir_current_x - NW_corner_longitude) / scale_x; syy = (xastir_total_y - NW_corner_latitude ) / scale_y; // If we wish some colors to be transparent, we could check for a // color match here and refuse to draw those that are on our list of // transparent colors. Might be useful for drawing say contour // lines on top of satellite images. Since the USGS topo's use the // same colormap for all of the topo's (I believe that is true) then // we could just compare on the index into the array instead of the // color contents in the array. // // Example output from a USGS 7.5' map: // // 0: 0 0 0 black // 1: 65280 65280 65280 light grey // 2: 0 38656 41984 // 3: 51968 0 5888 // 4: 33536 16896 9472 contour lines, brownish-red // 5: 51456 59904 40192 green // 6: 35072 13056 32768 purple? freeways, some roads // 7: 65280 59904 0 // 8: 42752 57856 57856 blue, bodies of water // 9: 65280 47104 47104 red brick color, cities? // 10: 55808 45824 54784 purple. freeways, some roads // 11: 53504 53504 53504 grey // 12: 52992 41984 36352 contour lines, tan, more dots/less lines // 13: 0 0 0 black, unused slot? // 14: 0 0 0 black, unused slot? // 15: 0 0 0 black, unused slot? // 16: 0 0 0 black, unused slot? // The rest are all 0's. // either show all colors (usgs_drg==0) or show selected // colors (usgs_drg == 1) if ( usgs_drg == 0 || (usgs_drg ==1 && (*(imageMemory + column) >= 13 || DRG_show_colors[*(imageMemory + column)] == 1))) { // If this is set, use gc_tint for drawing // with "GXxor" as the bit-blit operation. // if (DRG_XOR_colors) { // Draw the pixel using "gc_tint" // instead of "gc". XSetForeground (XtDisplay (w), gc_tint, my_colors[*(imageMemory + column)].pixel); XFillRectangle (XtDisplay (w), pixmap, gc_tint, sxx, syy, stepwc, stephc); } else { // Set the color for the pixel XSetForeground (XtDisplay (w), gc, my_colors[*(imageMemory + column)].pixel); // And draw the pixel XFillRectangle (XtDisplay (w), pixmap, gc, sxx, syy, stepwc, stephc); } } } } } } /* Free up any malloc's that we did */ if (imageMemory) { free(imageMemory); } if (debug_level & 16) { fprintf(stderr,"%d rows read in\n", (int) row); } /* We're finished with the geoTIFF key parser, so get rid of it */ GTIFFree (gtif); /* Close the TIFF file descriptor */ XTIFFClose (tif); // Close the filehandles that are left open after the // four GTIFImageToPCS calls. //(void)CSVDeaccess(NULL); } #endif /* HAVE_LIBGEOTIFF */ Xastir-Release-2.2.4/src/maps.c0000664000175000017500000120643115151324131015223 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //#define MAP_SCALE_CHECK #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #ifdef HAVE_MAGICK #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include // TVR: "stupid ImageMagick" // The problem is that magick/api.h includes Magick's config.h file, and that // pulls in all the same autoconf-generated defines that we use. // plays those games below, but I don't think in the end that they actually // make usable macros with our own data in them. // Fortunately, we don't need them, so I'll just undef the ones that are // causing problems today. See main.c for fixes that preserve our values. #undef PACKAGE #undef VERSION /* JMT - stupid ImageMagick */ #define XASTIR_PACKAGE_BUGREPORT PACKAGE_BUGREPORT #undef PACKAGE_BUGREPORT #define XASTIR_PACKAGE_NAME PACKAGE_NAME #undef PACKAGE_NAME #define XASTIR_PACKAGE_STRING PACKAGE_STRING #undef PACKAGE_STRING #define XASTIR_PACKAGE_TARNAME PACKAGE_TARNAME #undef PACKAGE_TARNAME #define XASTIR_PACKAGE_VERSION PACKAGE_VERSION #undef PACKAGE_VERSION #ifdef HAVE_MAGICK #ifdef HAVE_MAGICKCORE_MAGICKCORE_H #include #else #ifdef HAVE_MAGICK_API_H #include #endif // HAVE_MAGICK_API_H #endif //HAVE_MAGICKCORE_MAGICKCORE_H #endif //HAVE_MAGICK #undef PACKAGE_BUGREPORT #define PACKAGE_BUGREPORT XASTIR_PACKAGE_BUGREPORT #undef XASTIR_PACKAGE_BUGREPORT #undef PACKAGE_NAME #define PACKAGE_NAME XASTIR_PACKAGE_NAME #undef XASTIR_PACKAGE_NAME #undef PACKAGE_STRING #define PACKAGE_STRING XASTIR_PACKAGE_STRING #undef XASTIR_PACKAGE_STRING #undef PACKAGE_TARNAME #define PACKAGE_TARNAME XASTIR_PACKAGE_TARNAME #undef XASTIR_PACKAGE_TARNAME #undef PACKAGE_VERSION #define PACKAGE_VERSION XASTIR_PACKAGE_VERSION #undef XASTIR_PACKAGE_VERSION #endif // HAVE_MAGICK #include #include #include #ifdef HAVE_X11_XPM_H #include #ifdef HAVE_LIBXPM // if we have both, prefer the extra library #undef HAVE_XM_XPMI_H #endif // HAVE_LIBXPM #endif // HAVE_X11_XPM_H #ifdef HAVE_XM_XPMI_H #include #endif // HAVE_XM_XPMI_H #include #include #include "xastir.h" #include "globals.h" #include "maps.h" #include "alert.h" #include "util.h" #include "mutex_utils.h" #include "main.h" #include "datum.h" #include "draw_symbols.h" #include "rotated.h" #include "color.h" #include "xa_config.h" #include "timer_utils.h" #include "mgrs_utils.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #define GRID_MORE 5000 // Check for XPM and/or ImageMagick. We use "NO_GRAPHICS" // to disable some routines below if the support for them // is not compiled in. #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM) || defined(HAVE_MAGICK)) #define NO_GRAPHICS 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM || HAVE_MAGICK) #if !(defined(HAVE_LIBXPM) || defined(HAVE_LIBXPM_IN_XM)) #define NO_XPM 1 #endif // !(HAVE_LIBXPM || HAVE_LIBXPM_IN_XM) void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color); int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize); // Constants defining the color of the labeled grid border. int outline_border_labels = TRUE; // if true put an outline around the border labels int border_foreground_color = 0x20; // color of the map border, if shown // 0x08 is black. // 0x20 is white. int outline_border_labels_color = 0x20; // outline_border_labels_color = border_foreground_color; // color of outline to draw around border labels // use color of border to help make text more legible. // Print options Widget print_properties_dialog = (Widget)NULL; static xastir_mutex print_properties_dialog_lock; Widget print_postscript_dialog = (Widget)NULL; static xastir_mutex print_postscript_dialog_lock; Widget printer_data; Widget previewer_data; Widget rotate_90 = (Widget)NULL; Widget auto_rotate = (Widget)NULL; //char print_paper_size[20] = "Letter"; // Displayed in dialog, but not used yet. int print_rotated = 0; int print_auto_rotation = 0; //float print_scale = 1.0; // Not used yet. int print_auto_scale = 0; //int print_blank_background_color = 0; // Not used yet. int print_in_monochrome = 0; int print_resolution = 150; // 72 dpi is normal for Postscript. // 100 or 150 dpi work well with HP printer int print_invert = 0; // Reverses black/white char printer_program[MAX_FILENAME+1]; char previewer_program[MAX_FILENAME+1]; time_t last_snapshot = 0; // Used to determine when to take next snapshot time_t last_kmlsnapshot = 0; // Used to determine when to take next kml snapshot int doing_snapshot = 0; int snapshot_interval = 0; int mag; int npoints; /* number of points in a line */ float raster_map_intensity = 0.65; // Raster map color intensity, set from Maps->Map Intensity float imagemagick_gamma_adjust = 0.0; // Additional imagemagick map gamma correction, set from Maps->Adjust Gamma // Storage for the index file timestamp time_t map_index_timestamp; int grid_size = 0; // Rounding #ifndef HAVE_ROUNDF // Poor man's rounding, but rounds away from zero as roundf is supposed to. float roundf(float x) { int i; i= (((x)>=0)?(((x)+.5)):(((x)-.5))); return ((float)i); } #endif // UTM Grid stuff // //#define UTM_DEBUG //#define UTM_DEBUG_VERB //#define UTM_DEBUG_ALLOC // static inline int max_i(int a, int b) { return (a > b ? a : b); } #define UTM_GRID_EQUATOR 10000000 // the maximum number of UTM zones that will appear on a screen that has a // high enough resolution to display the within-zone utm grid #define UTM_GRID_MAX_ZONES 4 // the maximum number of grid lines in each direction shown in each zone // on the screen at one time #define UTM_GRID_MAX_COLS_ROWS 64 #define UTM_GRID_DEF_NALLOCED 8 #define UTM_GRID_RC_EMPTY 0xffff // the hash stores the upper left and lower right boundaries of the // display of a utm grid to determine whether it matches the current // screen boundaries or whether the grid needs to be recalculated // for the current screen. typedef struct { long ul_x; long ul_y; long lr_x; long lr_y; } hash_t; // The utm grid is drawn by connecting a grid of points marking the // intersection of the easting and northing lines. col_or_row holds // this grid of points for the portion of a utm zone visible on the // screen. Zone boundaries are not directly represented here. // In particular, the parallels separating lettered zone rows are // not directly represented here. typedef struct { int firstpoint; int npoints; int nalloced; XPoint *points; } col_or_row_t; // The portion of a utm zone visible on the screen has some number of // visible easting lines and northing lines forming a grid that covers // part or all of the screen. Zone holds arrays of the coordinates // of the visible easting and northing intersections, and the next set // of intersections off screen. The coarseness of this grid is // determined by the current scale and stored in utm_grid_spacing_m. typedef struct { unsigned int ncols; col_or_row_t col[UTM_GRID_MAX_COLS_ROWS]; unsigned int nrows; col_or_row_t row[UTM_GRID_MAX_COLS_ROWS]; int boundary_x; } zone_t; // A utm grid is represented by its hash (upper left and lower right coordinates) // which are used to check whether or not it fits the current screen or needs to // be recalculated, and an array of the zones visible on the screen, each containing // arrays of the points marking the easting/northing intersections of a zone (with // one or more lettered zone rows). typedef struct { hash_t hash; unsigned int nzones; zone_t zone[UTM_GRID_MAX_ZONES]; } utm_grid_t; utm_grid_t utm_grid; unsigned int utm_grid_spacing_m; // ^ the above is extern'ed in maps.h for use by draw_ruler_text in // db.c // Clear out/set up the UTM/MGRS minor grid intersection arrays. // // do_alloc = 0: Don't allocate memory // 1: Allocate memory for the points // // Returns: 0 if ok // 1 if malloc problem // int utm_grid_clear(int do_alloc) { int i, j; utm_grid.hash.ul_x = 0; utm_grid.hash.ul_y = 0; utm_grid.hash.lr_x = 0; utm_grid.hash.lr_y = 0; utm_grid.nzones = 0; for (i=0; i < UTM_GRID_MAX_ZONES; i++) { utm_grid.zone[i].ncols = utm_grid.zone[i].nrows = 0; utm_grid.zone[i].boundary_x = 0; for (j=0; j < UTM_GRID_MAX_COLS_ROWS; j++) { // // Clear out column arrays // utm_grid.zone[i].col[j].firstpoint = UTM_GRID_RC_EMPTY; utm_grid.zone[i].col[j].npoints = 0; if (utm_grid.zone[i].col[j].nalloced) { free(utm_grid.zone[i].col[j].points); } utm_grid.zone[i].col[j].nalloced = 0; utm_grid.zone[i].col[j].points = NULL; if (do_alloc) { // Allocate enough space for 8 points utm_grid.zone[i].col[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint)); if (!utm_grid.zone[i].col[j].points) { fprintf(stderr,"calloc(%d, %d) for z=%d col=%d FAILED!\n", UTM_GRID_DEF_NALLOCED, (int)sizeof(XPoint), i, j); // abort(); // Causes a segfault return(1); } utm_grid.zone[i].col[j].nalloced = UTM_GRID_DEF_NALLOCED; } // // Clear out row arrays // utm_grid.zone[i].row[j].firstpoint = UTM_GRID_RC_EMPTY; utm_grid.zone[i].row[j].npoints = 0; utm_grid.zone[i].row[j].nalloced = 0; if (utm_grid.zone[i].row[j].nalloced) { free(utm_grid.zone[i].row[j].points); } utm_grid.zone[i].row[j].nalloced = 0; utm_grid.zone[i].row[j].points = NULL; if (do_alloc) { // Allocate enough space for 8 points utm_grid.zone[i].row[j].points = calloc(UTM_GRID_DEF_NALLOCED, sizeof(XPoint)); if (!utm_grid.zone[i].row[j].points) { fprintf(stderr,"calloc(%d, %d) for z=%d row=%d FAILED!\n", UTM_GRID_DEF_NALLOCED, (int)sizeof(XPoint), i, j); // abort(); // Causes a segfault return(1); } utm_grid.zone[i].row[j].nalloced = UTM_GRID_DEF_NALLOCED; } } } return(0); } void maps_init(void) { fprintf(stderr,"\n\nBuilt-in map types:\n"); fprintf(stderr,"%10s USGS GNIS Datapoints\n","gnis"); fprintf(stderr,"%10s USGS GNIS Datapoints w/population\n","pop"); fprintf(stderr,"%10s APRSdos Maps\n","map"); fprintf(stderr,"%10s WinAPRS/MacAPRS/X-APRS Maps\n","map"); fprintf(stderr,"\nSupport for these additional map types has been compiled in: \n"); #ifdef HAVE_MAGICK fprintf(stderr,"%10s Image Map (ImageMagick/GraphicsMagick library, many formats allowed)\n","geo"); #endif // HAVE_MAGICK #ifndef NO_GRAPHICS #ifdef HAVE_LIBCURL fprintf(stderr,"%10s URL (Internet maps via libcurl library)\n","geo"); fprintf(stderr,"%10s URL (OpenStreetMaps via libcurl library\n","geo"); fprintf(stderr,"%10s Copyright OpenStreetMap and contributors, CC-BY-SA)\n", ""); #else #ifdef HAVE_WGET fprintf(stderr,"%10s URL (Internet maps via wget)\n","geo"); fprintf(stderr,"%10s URL (OpenStreetMaps via wget\n","geo"); fprintf(stderr,"%10s Copyright OpenStreetMap and contributors, CC-BY-SA)\n", ""); #endif // HAVE_WGET #endif // HAVE_LIBCURL #endif // NO_GRAPHICS #ifdef HAVE_LIBSHP fprintf(stderr,"%10s ESRI Shapefile Maps (Shapelib library)\n","shp"); #endif // HAVE_LIBSHP #ifdef HAVE_LIBGEOTIFF fprintf(stderr,"%10s USGS DRG Geotiff Topographic Maps (libgeotiff/libproj)\n","tif"); #endif // HAVE_LIBGEOTIFF #ifndef NO_XPM fprintf(stderr,"%10s X Pixmap Maps (XPM library)\n","xpm"); #endif // NO_XPM init_critical_section( &print_properties_dialog_lock ); init_critical_section( &print_postscript_dialog_lock ); // Clear the minor UTM/MGRS grid arrays. Do _not_ allocate // memory for the points. (void)utm_grid_clear(0); } /* * Calculate NS distance scale at a given location * in meters per Xastir unit */ double calc_dscale_y(long UNUSED(x), long UNUSED(y) ) { // approximation by looking at +/- 0.5 minutes offset // (void)(calc_distance(y-3000, x, y+3000, x)/6000.0); // but this scale is fixed at 1852/6000 return((double)(1852.0/6000.0)); } /* * Calculate EW distance scale at a given location * in meters per Xastir unit */ double calc_dscale_x(long x, long y) { // approximation by looking at +/- 0.5 minutes offset // we should find a better formula... return(calc_distance(y, x-3000, y, x+3000)/6000.0); } /* * Calculate x map scaling for current location * With that we could have equal distance scaling or a better * view for pixel maps */ long get_x_scale(long x, long y, long ysc) { long xsc; double sc_x; double sc_y; sc_x = calc_dscale_x(x,y); // meter per Xastir unit sc_y = calc_dscale_y(x,y); if (sc_x < 0.01 || ysc > 50000) // keep it near the poles (>88 deg) or if big parts of world seen { xsc = ysc; } else // adjust y scale, so that the distance is identical in both directions: { xsc = (long)(ysc * sc_y / sc_x +0.4999); } //fprintf(stderr,"Scale: x %5.3fkm/deg, y %5.3fkm/deg, x %ld y %ld\n",sc_x*360,sc_y*360,xsc,ysc); return(xsc); } /** MAP DRAWING ROUTINES **/ // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d() function below. This // function is set up for float values. See the clipt_long() and // clipt_int() functions for use with other types of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt(float p, float q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / p; if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / p; if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function is set up for float values. See the clip2d_long() // and clip2d_screen() functions for use with other types of values. // int clip2d(float *x0, float *y0, float *x1, float *y1) { float t0, t1; float delta_x, delta_y; int visible = False; float x_left, y_top; // NW corner of screen float x_right, y_bottom; // SE corner of screen // Assign floating point values for screen corners y_top = f_NW_corner_latitude; y_bottom = f_SE_corner_latitude; x_left = f_NW_corner_longitude; x_right = f_SE_corner_longitude; if ( ((*x0 < x_left) && (*x1 < x_left)) || ((*x0 > x_right) && (*x1 > x_right)) || ((*y0 < y_bottom) && (*y1 < y_bottom)) || ((*y0 > y_top) && (*y1 > y_top)) ) { // Both endpoints are on outside and same side of visible // region, so reject. return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } } } } return(visible); } // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d_long() function below. This // function is set up for Xastir coordinate values (unsigned longs). // See the clipt() and clipt_int() functions for use with other // types of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt_long(long p, long q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / (p * 1.0); if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / (p * 1.0); if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } //fprintf(stderr,"clipt_long: %d\n",accept); return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt_long() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function uses the Xastir coordinate system. We had to flip // y_bottom/y_top below due to the coordinate system being // upside-down. // // This function is set up for Xastir coordinate values (unsigned // longs). See the clip2d() or clip2d_screen() functions for use // with other types of values. // int clip2d_long(unsigned long *x0, unsigned long *y0, unsigned long *x1, unsigned long *y1) { float t0, t1; long delta_x, delta_y; int visible = False; unsigned long x_left = NW_corner_longitude; unsigned long x_right = SE_corner_longitude; // Reverse the following two as our Xastir coordinate system is // upside down. The algorithm requires this order. unsigned long y_top = SE_corner_latitude; unsigned long y_bottom = NW_corner_latitude; if ( ( (*x0 < x_left ) && (*x1 < x_left ) ) || ( (*x0 > x_right ) && (*x1 > x_right ) ) || ( (*y0 < y_bottom) && (*y1 < y_bottom) ) || ( (*y0 > y_top ) && (*y1 > y_top ) ) ) { // Both endpoints are on same side of visible region and // outside of it, so reject. //fprintf(stderr,"reject 1\n"); return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt_long(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt_long(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt_long(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt_long(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } else { //fprintf(stderr,"reject top\n"); } } else { //fprintf(stderr,"reject bottom\n"); } } else { //fprintf(stderr,"reject right\n"); } } else { //fprintf(stderr,"reject left\n"); } return(visible); } // Function to perform 2D line-clipping Using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Called by clip2d_screen() function below. This // function is set up for screen coordinate values (unsigned ints). // See the clipt() and clipt_long functions for use with other types // of values. // // Returns False if the line is rejected, True otherwise. May modify // t0 and t1. // int clipt_int(int p, int q, float *t0, float *t1) { float r; int accept = True; if (p < 0) // Entering visible region, so compute t0 { if (q < 0) // t0 will be non-negative, so continue { r = q / (p * 1.0); if (r > *t1) // t0 will exceed t1, so reject { accept = False; } else if (r > *t0) // t0 is max of r's { *t0 = r; } } } else { if (p > 0) // Exiting visible region, so compute t1 { if (q < p) // t1 will be <= 1, so continue { r = q / (p * 1.0); if (r < *t0) // t1 will be <= t0, so reject { accept = False; } else if (r < *t1) // t1 is min of r's { *t1 = r; } } } else // p == 0 { if (q < 0) // Line parallel and outside, so reject { accept = False; } } } //fprintf(stderr,"clipt_int: %d\n",accept); return(accept); } // Function to perform 2D line-clipping using the improved parametric // line-clipping algorithm by Liang, Barsky, and Slater published in // the paper: "Some Improvements to a Parametric Line Clipping // Algorithm", 1992. Uses the clipt_int() function above. // // Returns False if the line is rejected, True otherwise. x0, y0, // x1, y1 may get modified by this function. These will be the new // clipped line ends that fit inside the window. // // Clip 2D line segment with endpoints (x0,y0) and (x1,y1). The clip // window is x_left <= x <= x_right and y_bottom <= y <= y_top. // // This function uses the screen coordinate system. We had to flip // y_bottom/y_top below due to the coordinate system being // upside-down. // // This function is set up for screen coordinate values (unsigned // ints). See the clip2d() and clip2d_long() functions for use // with other types of values. // int clip2d_screen(unsigned int *x0, unsigned int *y0, unsigned int *x1, unsigned int *y1) { float t0, t1; int delta_x, delta_y; int visible = False; unsigned int x_right = screen_width; unsigned int x_left = 0; // Reverse the following two as our screen coordinate system is // upside down. The algorithm requires this order. unsigned int y_top = screen_height; unsigned int y_bottom = 0; if ( ( (*x0 < x_left ) && (*x1 < x_left ) ) || ( (*x0 > x_right ) && (*x1 > x_right ) ) || ( (*y0 < y_bottom) && (*y1 < y_bottom) ) || ( (*y0 > y_top ) && (*y1 > y_top ) ) ) { // Both endpoints are on same side of visible region and // outside of it, so reject. //fprintf(stderr,"reject 1\n"); return(visible); } t0 = 0; t1 = 1; delta_x = *x1 - *x0; if ( clipt_int(-delta_x, *x0 - x_left, &t0, &t1) ) // left { if ( clipt_int(delta_x, x_right - *x0, &t0, &t1) ) // right { delta_y = *y1 - *y0; if ( clipt_int(-delta_y, *y0 - y_bottom, &t0, &t1) ) // bottom { if ( clipt_int(delta_y, y_top - *y0, &t0, &t1) ) // top { // Compute coordinates if (t1 < 1) // Compute V1' (new x1,y1) { *x1 = *x0 + t1 * delta_x; *y1 = *y0 + t1 * delta_y; } if (t0 > 0) // Compute V0' (new x0,y0) { *x0 = *x0 + t0 * delta_x; *y0 = *y0 + t0 * delta_y; } visible = True; } else { //fprintf(stderr,"reject top\n"); } } else { //fprintf(stderr,"reject bottom\n"); } } else { //fprintf(stderr,"reject right\n"); } } else { //fprintf(stderr,"reject left\n"); } return(visible); } // Draws a point onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. If the bounding box containing the point doesn't intersect // with the current view, the point isn't drawn. // // Input point is in the Xastir coordinate system. // void draw_point(Widget w, unsigned long x1, unsigned long y1, GC gc, Pixmap which_pixmap, int skip_duplicates) { long x1i, y1i; static int last_x1i; static int last_y1i; // Check whether the two bounding boxes intersect. If not, skip // the rest of this function. Do we need to worry about // special-case code here to handle vertical/horizontal lines // (width or length of zero)? // // // WE7U // Check to see if we can do this faster than map_visible() can. A // point is a special case that should take only four compares // against the map window boundaries. // if (!map_visible(y1, y1, x1, x1)) { // Skip this vector //fprintf(stderr,"Point not visible\n"); return; } convert_xastir_to_screen_coordinates(x1, y1, &x1i, &y1i); if (skip_duplicates) { if (x1i == last_x1i && y1i == last_y1i) { return; } } // XDrawPoint uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. (void)XDrawPoint(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i)); last_x1i = x1i; last_y1i = y1i; } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. // // Input points are in lat/long coordinates. // void draw_point_ll(Widget w, float y1, // lat1 float x1, // long1 GC gc, Pixmap which_pixmap, int skip_duplicates) { unsigned long x1L, y1L; // // WE7U // We should probably do four floating point compares against the // map boundaries here in order to speed up rejection of points that // don't fit our window. If we change to that, copy the conversion- // to-screen-coordinates and drawing stuff from draw_point() down to // this routine so that we don't go through the comparisons again // there. // // Convert the point to the Xastir coordinate system. convert_to_xastir_coordinates(&x1L, &y1L, x1, y1); // Call the draw routine above. draw_point(w, x1L, y1L, gc, which_pixmap, skip_duplicates); } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. If the bounding box containing the vector doesn't intersect // with the current view, the line isn't drawn. // // Input points are in the Xastir coordinate system. // void draw_vector(Widget w, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2, GC gc, Pixmap which_pixmap, int skip_duplicates) { long x1i, x2i, y1i, y2i; static int last_x1i, last_x2i, last_y1i, last_y2i; //fprintf(stderr,"%ld,%ld %ld,%ld\t",x1,y1,x2,y2); if ( !clip2d_long(&x1, &y1, &x2, &y2) ) { // Skip this vector //fprintf(stderr,"Line not visible\n"); //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1,y1,x2,y2); return; } //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1,y1,x2,y2); convert_xastir_to_screen_coordinates(x1, y1, &x1i, &y1i); convert_xastir_to_screen_coordinates(x2, y2, &x2i, &y2i); if (skip_duplicates) { if (last_x1i == x1i && last_x2i == x2i && last_y1i == y1i && last_y2i == y2i) { return; } } // XDrawLine uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. // clip2d_long() should make sure of this anyway as it clips // lines to fit the window. // (void)XDrawLine(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i), l16(x2i), l16(y2i)); last_x1i = x1i; last_x2i = x2i; last_y1i = y1i; last_y2i = y2i; } // Draws a vector onto a pixmap. Assumes that the proper GC has // already been set up for drawing the correct color/width/linetype, // etc. // // Input points are in lat/long coordinates. // void draw_vector_ll(Widget w, float y1, // lat1 float x1, // long1 float y2, // lat2 float x2, // long2 GC gc, Pixmap which_pixmap, int skip_duplicates) { unsigned long x1L, x2L, y1L, y2L; long x1i, x2i, y1i, y2i; static int last_x1i, last_x2i, last_y1i, last_y2i; //fprintf(stderr,"%lf,%lf %lf,%lf\t",x1,y1,x2,y2); if ( !clip2d(&x1, &y1, &x2, &y2) ) { // Skip this vector //fprintf(stderr,"Line not visible: %lf,%lf %lf,%lf\n",y1,x1,y2,x2); return; } //fprintf(stderr,"%lf,%lf %lf,%lf\n",x1,y1,x2,y2); // Convert the points to the Xastir coordinate system. convert_to_xastir_coordinates(&x1L, &y1L, x1, y1); convert_to_xastir_coordinates(&x2L, &y2L, x2, y2); //fprintf(stderr,"%ld,%ld %ld,%ld\n",x1L,y1L,x2L,y2L); convert_xastir_to_screen_coordinates(x1L, y1L, &x1i, &y1i); convert_xastir_to_screen_coordinates(x2L, y2L, &x2i, &y2i); if (skip_duplicates) { if (last_x1i == x1i && last_x2i == x2i && last_y1i == y1i && last_y2i == y2i) { // fprintf(stderr,"Duplicate line\n"); return; } } //fprintf(stderr,"NW_corner_latitude:%ld, NW_corner_longitude:%ld, scale_x:%ld, scale_y:%ld\n", // NW_corner_latitude, // NW_corner_longitude, // scale_x, // scale_y); //fprintf(stderr,"%d,%d %d,%d\n\n",x1i,y1i,x2i,y2i); // XDrawLine uses 16-bit unsigned integers // (shorts). Make sure we stay within the limits. // clip2d() should make sure of this anyway as it clips lines to // fit the window. // (void)XDrawLine(XtDisplay(w), which_pixmap, gc, l16(x1i), l16(y1i), l16(x2i), l16(y2i)); last_x1i = x1i; last_x2i = x2i; last_y1i = y1i; last_y2i = y2i; } // Find length of a standard string of seven zeroes in the border font. // Supporting function for draw_grid() and the grid drawing functions. int get_standard_border_string_width_pixels(Widget w, int length) { int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels. char seven_zeroes[8] = "0000000"; char five_zeroes[6] = "00000"; if (length==5) { string_width_pixels = get_rotated_label_text_length_pixels(w, five_zeroes, FONT_BORDER); } string_width_pixels = get_rotated_label_text_length_pixels(w, seven_zeroes, FONT_BORDER); return string_width_pixels; } // Find height of a standard string in the border font // Supporting function for draw_grid() and the grid drawing functions. int get_standard_border_string_height_pixels(Widget w) { int string_width_pixels = 0; // Width of the unrotated seven_zeroes label string in pixels. char one_zero[2] = "0"; string_width_pixels = get_rotated_label_text_height_pixels(w, one_zero, FONT_BORDER); return string_width_pixels; } // Find out the width to use for the border to apply when uing a labeled grid. // Border width is determined from the height of the border font. // Supporting function for draw_grid() and the grid drawing functions. int get_border_width(Widget w) { int border_width = 14; // The width of the border to draw around the // map to place labeled tick marks into // should be an even number. // The default here is overidden by size of the border font. int string_height_pixels = 0; // Height of a string in the border font in pixels string_height_pixels = get_standard_border_string_height_pixels(w); // Rotated text functions used to draw the border text add some // blank space at the bottom of the text so make the border wide enough // to compensate for this. border_width = string_height_pixels + (string_height_pixels/2) + 1; // check to see if string_height_pixels is even if ((float)string_height_pixels/2.0!=floor((float)string_height_pixels/2.0)) { border_width++; } // we are using draw nice string to write the metadata in the top border, so // make sure the border is wide enough for it, even if the grid labels are small. if (border_width < 14) { border_width = 14; } return border_width; } // *********************************************************** // // get_horizontal_datum() // // Provides the current map datum. Current default is WGS84. // Parameters: datum, character array ponter for the string // that will be filled with the current datum // sizeof_datum, the size of the datum character array. // //*********************************************************** void get_horizontal_datum(char *datum, int sizeof_datum) { char metadata_datum[6] = "WGS84"; // datum to display in metadata on top border xastir_snprintf(datum, sizeof_datum, "%s", metadata_datum); if (sizeof_datum<6) { fprintf(stderr,"Datum [%s] truncated to [%s]\n",metadata_datum,datum); } } // Lat/Long coordinate system, draw lat/long lines. Called by // draw_grid() below. // void draw_complete_lat_lon_grid(Widget w) { int coord; char dash[2]; unsigned int x,x1,x2; unsigned int y,y1,y2; unsigned int stepsx; // spacing of grid lines unsigned int stepsy; // spacing of grid lines int coordinate_format; // Format to use for coordinates on border (e.g. decimal degrees). char grid_label[25]; // String to draw labels on grid lines int screen_width_xastir; // screen width in xastir units (1/100 of a second) // int screen_height_xastir; // screen height in xastir units (1/100 of a second) int border_width; // the width of the labeled border in pixels. int string_width_pixels = 0;// Width of a grid label string in pixels. float screen_width_degrees; // Width of the screen in degrees int log_screen_width_degrees; // Log10 of the screen width in degrees, used to scale degrees long xx2, yy2; long xx, yy; unsigned int last_label_end; // cordinate of the end of the previous label char metadata_datum[6]; // datum to display in metadata on top border char grid_label1[25]; // String to draw latlong metadata char grid_label2[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border if (!long_lat_grid) // We don't wish to draw a map grid { return; } // convert between selected coordinate format constant and display format constants if (coordinate_system == USE_DDDDDD) { coordinate_format = CONVERT_DEC_DEG; } else if (coordinate_system == USE_DDMMSS) { coordinate_format = CONVERT_DMS_NORMAL_FORMATED; } else { coordinate_format = CONVERT_HP_NORMAL_FORMATED; } border_width = get_border_width(w); // Find xastir coordinates of upper left and lower right corners. xx = NW_corner_longitude + (border_width * scale_x); yy = NW_corner_latitude + (border_width * scale_y); xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); screen_width_xastir = xx2 - xx; // screen_height_xastir = yy2 - yy; // Determine some parameters used in drawing the border. string_width_pixels = get_standard_border_string_width_pixels(w, 7); // 1 xastir coordinate = 1/100 of a second // 100*60*60 xastir coordinates (=360000 xastir coordinates) = 1 degree // 64800000 xastir coordinates = 180 degrees // 360000 xastir coordinates = 1 degree // scale_x * (screen_width/10) = one tenth of the screen width in xastir coordinates // scale_x number of xastir coordinates per pixel screen_width_degrees = (float)(screen_width_xastir / (float)360000); log_screen_width_degrees = log10(screen_width_degrees); if (draw_labeled_grid_border==TRUE) { get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); // Put metadata in top border. // find location of upper left corner of map, convert to Lat/Long convert_lon_l2s(xx, grid_label1, sizeof(grid_label1), coordinate_format); convert_lat_l2s(yy, grid_label2, sizeof(grid_label2), coordinate_format); strcpy(grid_label, grid_label1); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, " "); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, grid_label2); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string // find location of lower right corner of map, convert to Lat/Long convert_lon_l2s(xx2, grid_label1, sizeof(grid_label1), coordinate_format); convert_lat_l2s(yy2, grid_label2, sizeof(grid_label2), coordinate_format); //"XASTIR Map of %s (upper left) to %s %s (lower right). Lat/Long grid, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA002"), grid_label,grid_label1,grid_label2,metadata_datum); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } // A crude grid spacing can be obtained from scaling one tenth of the screen width. // This works, but puts the grid lines at arbitrary increments of a degree. //stepsx = (scale_x*(screen_width/10)); // Setting the grid using the base 10 log of the screen width in degrees allows // both scaling the grid to the screen and spacing the grid lines at appropriately // rounded increments of a degree. // // Set default grid to 0.1 degree. This will be used when the screen width is about 1 degree. stepsx = 36000; // if (log_screen_width_degrees == 0) // Work out an appropriate grid spacing for the screen size and coordinate system. if (log_screen_width_degrees > 0) { // grid spacing is rounded to 10 degree increment. stepsx = ((int)(screen_width_degrees / (pow(10,log_screen_width_degrees)))*pow(10,log_screen_width_degrees)) * 36000; } if (log_screen_width_degrees < 0) { // Grid spacing is rounded to less than one degree. if (coordinate_system == USE_DDDDDD) { // Round to tenths or hundrethds or thousanths of a degree. stepsx = ((float)(int)(((float)screen_width_degrees / pow(10,log_screen_width_degrees)*10.0)))*pow(10,log_screen_width_degrees) * 3600; } else { // For decimal minutes or minutes and seconds. // Find screen width and log screen width in minutes. screen_width_degrees = screen_width_degrees * 60.0; log_screen_width_degrees = log10(screen_width_degrees); // round to minutes or tenths of minutes. stepsx = ((float)(int) ((float)(screen_width_degrees) / pow(10,log_screen_width_degrees) * 10.0) ) * pow(10,log_screen_width_degrees) * 3600; if (log_screen_width_degrees==0) { stepsx = 600; // 6000 = 1 minute } } } // Grid should now be close to reasonable spacing for screen size, but // may need to be tuned. // Test for too tightly or too coarsely spaced grid. if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5)) { stepsx = stepsx * 2.0; } if (stepsx<(unsigned int)(scale_x * string_width_pixels * 1.5)) { stepsx = stepsx * 2.0; } if (stepsx>(unsigned int)((scale_x * screen_width)/3.5)) { stepsx = stepsx / 2.0; } // Handle special case of very small screen - only draw a single grid line if (screen_width < (string_width_pixels * 2)) { stepsx = (scale_x*(screen_width/2)); } // Make sure we don't pass an erronous stepsx of 0 on. if (stepsx==0) { stepsx=36000; } // Use the same grid spacing for both latitude and longitude grids. // We could use a scaling factor related to the screen height width ratio here. stepsy = stepsx; // protect against division by zero if (scale_x==0) { scale_x = 1; } if (scale_y==0) { scale_y = 1; } // Now draw and label the grid. // Draw vertical longitude lines if (NW_corner_latitude >= 0) { y1 = 0; } else { y1 = -NW_corner_latitude/scale_y; } y2 = (180*60*60*100-NW_corner_latitude)/scale_y; if (y2 > (unsigned int)screen_height) { y2 = screen_height-1; } coord = NW_corner_longitude+stepsx-(NW_corner_longitude%stepsx); if (coord < 0) { coord = 0; } last_label_end = 0; for (; coord < SE_corner_longitude && coord <= 360*60*60*100; coord += stepsx) { x = (coord-NW_corner_longitude)/scale_x; if ((coord%(648000*100)) == 0) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt, JoinMiter); (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x), l16(y1), l16(x), l16(y2)); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt, JoinMiter); continue; // Go to next iteration of for loop } else if ((coord%(72000*100)) == 0) { dash[0] = dash[1] = 8; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } else if ((coord%(7200*100)) == 0) { dash[0] = dash[1] = 4; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } else if ((coord%(300*100)) == 0) { dash[0] = dash[1] = 2; (void)XSetDashes (XtDisplay (w), gc_tint, 0, dash, 2); } (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x), l16(y1), l16(x), l16(y2)); if (draw_labeled_grid_border==TRUE) { // Label the longitudes in lower border. convert_lon_l2s(coord, grid_label, sizeof(grid_label), coordinate_format); if (log_screen_width_degrees > 0 && strlen(grid_label) > 5) { // truncate the grid_label string if (coordinate_system==USE_DDMMMM) { // Add ' and move EW and null characters forward. grid_label[strlen(grid_label)-5] = '\''; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)]; } else { // Move EW and null characters forward. grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)]; } } string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER); // test for overlap of label with previously printed label if (x > last_label_end + 3 && x < (unsigned int)(screen_width - string_width_pixels)) { draw_rotated_label_text_to_target (w, 270, x, screen_height, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); last_label_end = x + string_width_pixels; } } } // Draw horizontal latitude lines. last_label_end = 0; if (NW_corner_longitude >= 0) { x1 = 0; } else { x1 = -NW_corner_longitude/scale_x; } x2 = (360*60*60*100-NW_corner_longitude)/scale_x; if (x2 > (unsigned int)screen_width) { x2 = screen_width-1; } coord = NW_corner_latitude+stepsy-(NW_corner_latitude%stepsy); if (coord < 0) { coord = 0; } for (; coord < SE_corner_latitude && coord <= 180*60*60*100; coord += stepsy) { y = (coord-NW_corner_latitude)/scale_y; if ((coord%(324000*100)) == 0) { (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineSolid, CapButt, JoinMiter); (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x1), l16(y), l16(x2), l16(y)); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt, JoinMiter); continue; // Go to next iteration of for loop } else if ((coord%(36000*100)) == 0) { dash[0] = dash[1] = 8; (void)XSetDashes (XtDisplay (w), gc_tint, 4, dash, 2); } else if ((coord%(3600*100)) == 0) { dash[0] = dash[1] = 4; (void)XSetDashes (XtDisplay (w), gc_tint, 2, dash, 2); } else if ((coord%(150*100)) == 0) { dash[0] = dash[1] = 2; (void)XSetDashes (XtDisplay (w), gc_tint, 1, dash, 2); } (void)XDrawLine (XtDisplay (w), pixmap_final, gc_tint, l16(x1), l16(y), l16(x2), l16(y)); if (draw_labeled_grid_border==TRUE) { // label the latitudes on left and right borders // (unlike UTM where easting before northing order is important) convert_lat_l2s(coord, grid_label, sizeof(grid_label), coordinate_format); if (log_screen_width_degrees > 0 && strlen(grid_label) > 5) { // truncate the grid_label string if (coordinate_system==USE_DDMMMM) { // Add ' and move EW and null characters forward. grid_label[strlen(grid_label)-5] = '\''; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-3] = grid_label[strlen(grid_label)]; } else { // Move EW and null characters forward. grid_label[strlen(grid_label)-5] = grid_label[strlen(grid_label)-1]; grid_label[strlen(grid_label)-4] = grid_label[strlen(grid_label)]; } } string_width_pixels = get_rotated_label_text_length_pixels(w, grid_label, FONT_BORDER); // check to make sure we aren't overwriting the previous label text if ((y > last_label_end+3) && (y > (unsigned int)string_width_pixels)) { draw_rotated_label_text_to_target (w, 180, screen_width, y, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); draw_rotated_label_text_to_target (w, 180, border_width, y, sizeof(grid_label),colors[0x09],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); last_label_end = y + string_width_pixels; } } } } // End of draw_complete_lat_lon_grid() // Draw the major zones for UTM and MGRS. Called by draw_grid() // below. // // These are based off 6-degree lat/long lines, with a few irregular // zones that have to be special-cased. This part of the code // handles the irregular zones in SW Norway (31V/32V) and the // regions near Svalbard (31X/33X/35X/37X) just fine. // These are based off the central meridian running up the middle of // each zone (3 degrees from either side of the standard six-degree // zones). Even the irregular zones key off the same medians. UTM // grids are defined in terms of meters instead of lat/long, so they // don't line up with the left/right edges of the zones or with the // longitude lines. // // According to Peter Dana (Geographer's Craft web pages), even when // the major grid boundaries have been shifted, the meridian used // for drawing the subgrids is still based on six-degree boundaries // (as if the major grid hadn't been shifted at all). That means we // are drawing the subgrids correctly as it stands now for the // irregular grids (31V/32V/31X/33X/35X/37X). The irregular zones // have sizes of 3/9/12 degrees (width) instead of 6 degrees. // // UTM NOTES: 84 degrees North to 80 degrees South. 60 zones, each // covering six (6) degrees of longitude. Each zone extends three // degrees eastward and three degrees westward from its central // meridian. Zones are numbered consecutively west to east from the // 180 degree meridian. From 84 degrees North and 80 degrees South // to the respective poles, the Universal Polar Stereographic (UPS) // is used. // // For MGRS and UTM-Special grid only: // UTM Zone 32 has been widened to 9 (at the expense of zone 31) // between latitudes 56 and 64 (band V) to accommodate southwest // Norway. Thus zone 32 extends westwards to 3E in the North Sea. // Similarly, between 72 and 84 (band X), zones 33 and 35 have // been widened to 12 to accommodate Svalbard. To compensate for // these 12 wide zones, zones 31 and 37 are widened to 9 and zones // 32, 34, and 36 are eliminated. Thus the W and E boundaries of // zones are 31: 0 - 9 E, 33: 9 - 21 E, 35: 21 - 33 E and 37: 33 - // 42 E. // // UTM is depending on the ellipsoid and the datum used. For our // purposes, we're always using WGS84 ellipsoid and datum, so it's a // non-issue. // // Horizontal bands corresponding to the NATO UTM/UPS lettering: // Zones go from A (south pole) to Z (north pole). South of -80 are // zones A/B, north of +84 are zones Y/Z. "I" and "O" are not used. // Zones from C to W are 8 degrees high. Zone X is 12 degrees high. // // We need these NATO letters or a N/S designator in order to // specify which hemisphere the UTM coordinates are in. Often, the // same coordinates can appear in either hemisphere. Some computer // software uses +/- to designate northings instead of N/S or the // NATO lettered bands. // // UPS system is used at the poles instead of UTM. UPS uses a false // northing and easting of 2,000,000 meters. // // An arbitrary false northing of 10,000,000 at the equator is used // for southern latitudes only. Northern latitudes assume the // equator northing is at zero. An arbitrary false easting of // 500,000 is along the meridian of each zone (3 degrees from each // side). The lettered grid lines are necessary due to some // coordinates being valid in both the northern and the southern // hemisphere. // // Y/Z 84N to 90N (UPS System) false N/E = 2,000,000 // X 72N to 84N (12 degrees latitude, equator=0) // W 64N to 72N ( 8 degrees latitude, equator=0) // V 56N to 64N ( 8 degrees latitude, equator=0) // U 48N to 56N ( 8 degrees latitude, equator=0) // T 40N to 48N ( 8 degrees latitude, equator=0) // S 32N to 40N ( 8 degrees latitude, equator=0) // R 24N to 32N ( 8 degrees latitude, equator=0) // Q 16N to 24N ( 8 degrees latitude, equator=0) // P 8N to 16N ( 8 degrees latitude, equator=0) // N 0N to 8N ( 8 degrees latitude, equator=0) // M 0S to 8S ( 8 degrees latitude, equator=10,000,000) // L 8S to 16S ( 8 degrees latitude, equator=10,000,000) // K 16S to 24S ( 8 degrees latitude, equator=10,000,000) // J 24S to 32S ( 8 degrees latitude, equator=10,000,000) // H 32S to 40S ( 8 degrees latitude, equator=10,000,000) // G 40S to 48S ( 8 degrees latitude, equator=10,000,000) // F 48S to 56S ( 8 degrees latitude, equator=10,000,000) // E 56S to 64S ( 8 degrees latitude, equator=10,000,000) // D 64S to 72S ( 8 degrees latitude, equator=10,000,000) // C 72S to 80S ( 8 degrees latitude, equator=10,000,000) // A/B 80S to 90S (UPS System) false N/E = 2,000,000 // void draw_major_utm_mgrs_grid(Widget w) { int ii; // need to move metadata to its own function and put it up after grids have been drawn. //******* // variables for metadata in grid border long xx2, yy2; // coordinates of screen corners used for metadata int border_width; // Width of the border to draw labels into. double easting, northing; // Values used in border metadata. int x, y; // Screen coordinates for border labels. char zone_str[10]; char zone_str2[10]; char metadata_datum[6]; char grid_label[25]; // String to draw labels on grid lines char grid_label1[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border // variables to support components of MGRS strings in the metadata char mgrs_zone[4] = " "; // MGRS zone letter char mgrs_eastingL[3] = " "; char mgrs_northingL[3] = " "; unsigned int int_utmEasting; unsigned int int_utmNorthing; char mgrs_space_string[4] = " "; // int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. char mgrs_ul_digraph[3] = " "; // MGRS digraph for upper left corner of screen char mgrs_lr_digraph[3] = " "; // MGRS digraph for lower right corner of screen //fprintf(stderr,"draw_major_utm_mgrs_grid start\n"); if (!long_lat_grid) // We don't wish to draw a map grid { return; } // Vertical lines: // Draw the vertical vectors (except for the irregular regions // and the prime meridian). The polar areas only have two zones // each, so we don't want to draw through those areas. for (ii = -180; ii < 0; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } for (ii = 42; ii <= 180; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } // Draw the short vertical vectors in the polar regions draw_vector_ll(w, -90.0, -180.0, -80.0, -180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -90.0, 180.0, -80.0, 180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, -180.0, 90.0, -180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 180.0, 90.0, 180.0, gc_tint, pixmap_final, 0); if (coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { // For MGRS, we need to draw irregular zones in certain // areas. // Draw the partial vectors from 80S to the irregular region draw_vector_ll(w, -80.0, 6.0, 56.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 12.0, 72.0, 12.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 18.0, 72.0, 18.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 24.0, 72.0, 24.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 30.0, 72.0, 30.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, -80.0, 36.0, 72.0, 36.0, gc_tint, pixmap_final, 0); // Draw the short vertical vectors in the irregular region draw_vector_ll(w, 56.0, 3.0, 64.0, 3.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 64.0, 6.0, 72.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 9.0, 84.0, 9.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 21.0, 84.0, 21.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 72.0, 33.0, 84.0, 33.0, gc_tint, pixmap_final, 0); // Draw the short vertical vectors above the irregular region draw_vector_ll(w, 84.0, 6.0, 84.0, 6.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 12.0, 84.0, 12.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 18.0, 84.0, 18.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 24.0, 84.0, 24.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 30.0, 84.0, 30.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 84.0, 36.0, 84.0, 36.0, gc_tint, pixmap_final, 0); } else { // Draw normal zone boundaries used for civilian UTM // grid. for (ii = 6; ii < 42; ii += 6) { draw_vector_ll(w, -80.0, (float)ii, 84.0, (float)ii, gc_tint, pixmap_final, 0); } } // Horizontal lines: // Draw the 8 degree spaced lines, except for the equator for (ii = -80; ii < 0; ii += 8) { draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0); } // Draw the 8 degree spaced lines for (ii = 8; ii <= 72; ii += 8) { draw_vector_ll(w, (float)ii, -180.0, (float)ii, 180.0, gc_tint, pixmap_final, 0); } // Draw the one 12 degree spaced line draw_vector_ll(w, 84.0, -180.0, 84.0, 180.0, gc_tint, pixmap_final, 0); // Draw the pole lines draw_vector_ll(w, -90.0, -180.0, -90.0, 180.0, gc_tint, pixmap_final, 0); draw_vector_ll(w, 90.0, -180.0, 90.0, 180.0, gc_tint, pixmap_final, 0); // Set to solid line for the equator. Make it extra wide as // well. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 3, LineSolid, CapButt,JoinMiter); // Draw the equator as a solid line draw_vector_ll(w, 0.0, -180.0, 0.0, 180.0, gc_tint, pixmap_final, 0); (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineSolid, CapButt,JoinMiter); // Draw the prime meridian in the same manner draw_vector_ll(w, -80.0, 0.0, 84.0, 0.0, gc_tint, pixmap_final, 0); // add metadata and labels if (draw_labeled_grid_border==TRUE && scale_x > 3000) { // Determine the width of the border border_width = get_border_width(w); // Find out what the map datum is. get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); // Put metadata in top border. // find location of upper left corner of map, convert to UTM xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (border_width * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label, sizeof(grid_label), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing); } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label, zone_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, easting_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, northing_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string } // find location of lower right corner of map, convert to UTM xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label1, sizeof(grid_label1), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing); if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0) { // mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } else { // mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label1, zone_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, easting_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, northing_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string } // Write metadata on upper border of map. //"XASTIR Map of %s (upper left) to %s (lower right). UTM zones, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA003"), grid_label,grid_label1,metadata_datum); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); // Crudely identify zone boundaries by // iterating across bottom border. xastir_snprintf(zone_str2, sizeof(zone_str2), "%s"," "); for (x=1; x<(screen_width - border_width); x++) { xx2 = NW_corner_longitude + (x * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); zone_str[strlen(zone_str)-1] = '\0'; if (strcmp(zone_str,zone_str2) !=0) { draw_rotated_label_text_to_target (w, 270, x + 1, screen_height, sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } xastir_snprintf(zone_str2, sizeof(zone_str2), "%s",zone_str); } // Crudely identify zone letters by iterating down left border for (y=(border_width*2); y<(screen_height - border_width); y++) { xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (y * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); zone_str[0] = zone_str[strlen(zone_str)-1]; zone_str[1] = '\0'; if (strcmp(zone_str,zone_str2) !=0) { draw_rotated_label_text_to_target (w, 270, 1, y, sizeof(zone_str),colors[0x10],zone_str,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } xastir_snprintf(zone_str2, sizeof(zone_str2), "%s",zone_str); } } // end if draw labeled border // Set the line width and style in the GC to 1 pixel wide for // drawing the smaller grid (void)XSetLineAttributes (XtDisplay (w), gc_tint, 1, LineOnOffDash, CapButt,JoinMiter); //fprintf(stderr,"draw_major_utm_mgrs_grid end\n"); } // End of draw_major_utm_mgrs_grid() // This is the function which actually draws a minor UTM grid. // Called by draw_minor_utm_mgrs_grid() function below. // draw_minor_utm_mgrs_grid() is the function which calculates the // grid points. // void actually_draw_utm_minor_grid(Widget w) { int border_width; // Width of the border to draw labels into. int numberofzones = 0; // number of elements in utm_grid.zone[] that are used int Zone; int ii; int easting_color; // Colors for the grid labels int northing_color; int zone_color; // zone label color int label_on_left; // if true, draw northing labels on left long xx, yy, xx2, yy2; char zone_str[10]; char zone_str2[10]; double easting, northing; int short_width_pixels = 0; // Width of an unrotated string of five_zeroes in the border font in pixels. int string_width_pixels = 0;// Width of an unrotated string of seven_zeroes in the border font in pixels. char metadata_datum[6]; char grid_label[25]; // String to draw labels on grid lines char grid_label1[25]; // String to draw latlong metadata char top_label[180]; // String to draw metadata on top border int grid_spacing_pixels; // Spacing of fine grid lines in pixels. int bottom_point; // utm_grid.zone[].col[].npoints can extend past the // bottom of the screen, this is the lowest point in the // points array that is on the screen. int skip_alternate_label; // Skip alternate easting and northing labels // if they would overlap on the // display. int last_line_labeled; // Marks lines that were labeled // when alternate lines are not // being labeled. // variables to support components of MGRS strings char mgrs_zone[4] = " "; // MGRS zone letter char mgrs_eastingL[3] = " "; char mgrs_northingL[3] = " "; unsigned int int_utmEasting; unsigned int int_utmNorthing; char mgrs_space_string[4] = " "; int mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. char mgrs_ul_digraph[3] = " "; // MGRS digraph for upper left corner of screen char mgrs_lr_digraph[3] = " "; // MGRS digraph for lower right corner of screen if (!long_lat_grid) // We don't wish to draw a map grid { return; } // OLD: Draw grid in dashed white lines. // NEW: Tint the lines as they go along, making them appear // no matter what color is underneath. (void)XSetForeground(XtDisplay(w), gc_tint, colors[0x27]); // Note: npoints can be negative here! Make sure our code // checks for that. Initially npoints was an unsigned int. // Changed it to an int so that we can get and check for // negative values, bypassing segfaults. // numberofzones = 0; // Determine the width of the border border_width = get_border_width(w); // Determine some parameters used in drawing the border. string_width_pixels = get_standard_border_string_width_pixels(w, 7); short_width_pixels = get_standard_border_string_width_pixels(w,5); for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { if (utm_grid.zone[Zone].ncols > 0) { // find out how many zones are actually drawn on the map numberofzones++; } } for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++) { if (utm_grid.zone[Zone].col[ii].npoints > 1) { // We need to check for points that are more // than +/- 16383. If we have any, it can cause // X11 to lock up for a while drawing lots of // extra lines, due to bugs in X11. We do that // checking above with xx and yy. // (void)XDrawLines(XtDisplay(w), pixmap_final, gc_tint, utm_grid.zone[Zone].col[ii].points, l16(utm_grid.zone[Zone].col[ii].npoints), CoordModeOrigin); } } for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { if (utm_grid.zone[Zone].row[ii].npoints > 1) { // We need to check for points that are more // than +/- 16383. If we have any, it can cause // X11 to lock up for a while drawing lots of // extra lines, due to bugs in X11. We do that // checking above with xx and yy. // (void)XDrawLines(XtDisplay(w), pixmap_final, gc_tint, utm_grid.zone[Zone].row[ii].points, l16(utm_grid.zone[Zone].row[ii].npoints), CoordModeOrigin); } } // Check each of the 4 possible utm_grid.zone array elements // that might contain a grid, and label the grid if it exists. if (utm_grid.zone[Zone].nrows>0 && utm_grid.zone[Zone].ncols>0) { if (draw_labeled_grid_border==TRUE) { // Label the UTM grid on the border. // Since the coordinate of the current mouse pointer position is // continually updated, labeling the grid is primarily for the // purpose of printing maps and saving screenshots. // // ******* Doesn't work properly near poles when 3 zones are on screen // ******* (e.g. 13,14,15) - overlaps northings for 14 and 15. // ******* Doesn't clearly distinguish one zone with 2 lettered rows // ******* (e.g. 18T,18U) needs color distinction between northings // ******* to indicate which northings are in which lettered row. // // Default labels for just one zone on screen are black text for // zone at lower left corner, eastings on bottom, and northings // at right. // Idea is to normally start at the lower left corner // users can then easily follow left to right to get easting, // and bottom to top to get northing. // For two zones, second zone uses blue text for eastings and northings. easting_color = 0x08; // black text northing_color = 0x08; // black text zone_color = 0x08; // black text // 0x09=blue (0x0e=yellow works well with outline, but not without). label_on_left = FALSE; // Find out what the map datum is. get_horizontal_datum(metadata_datum, sizeof(metadata_datum)); if (numberofzones>1) { // check to see if the upper left and lower left corners are in the same zone // if not, label the upper left corner xx = (border_width * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); yy = (border_width * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy); if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str2); //draw_nice_string(w,pixmap_final,0, // border_width+2, // (2*border_width)+2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); draw_rotated_label_text_to_target (w, 270, border_width+2, (2*border_width)+2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, border_width+2, screen_height - (2*border_width) - 2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } zone_color = 0x09; // likewise for upper and lower right corners xx = ((screen_width - border_width) * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); yy = (border_width * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), xx, yy); if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str2); //draw_nice_string(w,pixmap_final,0, // screen_width - (border_width * 3) , // (2*border_width)+2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); draw_rotated_label_text_to_target (w, 270, screen_width - (border_width * 3), (2*border_width)+2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } if (strcmp(zone_str,zone_str2)!=0) { xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, screen_width - (border_width * 3), screen_height - (2*border_width) - 2, sizeof(grid_label),colors[zone_color],grid_label,FONT_BORDER, pixmap_final, 1, colors[0x0f]); } // are we currently the same zone as the upper left corner // if so, we need to place the northing labels on the left side xx = (utm_grid.zone[Zone].col[0].points[0].x * scale_x) + NW_corner_longitude; yy = (utm_grid.zone[Zone].col[0].points[0].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); convert_xastir_to_UTM(&easting, &northing, zone_str2, sizeof(zone_str2), NW_corner_longitude, NW_corner_latitude); if (strcmp(zone_str,zone_str2)==0) { northing_color = 0x08; // 0x08 = black, same as lower left easting label_on_left = TRUE; } } // check to see if there is a horizontal boundary // compare xone of upper left and lower left corners convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), NW_corner_longitude, NW_corner_latitude); // Overwrite defaults as appropriate and // label zones differently if more than one appears on the screen. if (Zone > 0) { // write the zone label on the bottom border zone_color = 0x09; // blue easting_color = 0x09; // blue northing_color = 0x09; // blue xx2 = utm_grid.zone[Zone].col[0].points[0].x; xx = (xx2 * scale_x) + NW_corner_longitude; yy2 = utm_grid.zone[Zone].col[0].points[utm_grid.zone[Zone].col[0].npoints-1].y; yy = (yy2 * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx,yy); xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, xx2, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); //draw_nice_string(w,pixmap_final,0, // xx2, // screen_height - 2, // grid_label, // 0x10,zone_color,(int)strlen(grid_label)); } if (Zone==0) { // write the zone of the lower left corner of the map xx = (border_width * scale_x) + NW_corner_longitude; yy = ((screen_height - border_width) * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); xastir_snprintf(grid_label, sizeof(grid_label), "%s", zone_str); draw_rotated_label_text_to_target (w, 270, 1, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); //draw_nice_string(w,pixmap_final,0, // 1, // screen_height - 2, // grid_label, // 0x10,0x20,(int)strlen(grid_label)); } // Put metadata in top border. // find location of upper left corner of map, convert to UTM xx2 = NW_corner_longitude + (border_width * scale_x); yy2 = NW_corner_latitude + (border_width * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_ul_digraph, sizeof(mgrs_ul_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label, sizeof(grid_label), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_ul_digraph,(float)int_utmEasting,(float)int_utmNorthing); } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label, zone_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, easting_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string strcat(grid_label, northing_str); grid_label[sizeof(grid_label)-1] = '\0'; // Terminate string } // find location of lower right corner of map, convert to UTM xx2 = NW_corner_longitude + ((screen_width - border_width) * scale_x); yy2 = NW_corner_latitude + ((screen_height - border_width) * scale_y); convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx2, yy2); if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx2, yy2, 0, mgrs_space_string, strlen(mgrs_space_string)); xastir_snprintf(mgrs_lr_digraph, sizeof(mgrs_lr_digraph), "%c%c", mgrs_eastingL[0], mgrs_northingL[0]); xastir_snprintf(grid_label1, sizeof(grid_label1), "%s %s %05.0f %05.0f", mgrs_zone,mgrs_lr_digraph,(float)int_utmEasting,(float)int_utmNorthing); if (strcmp(mgrs_lr_digraph,mgrs_ul_digraph)==0) { mgrs_single_digraph = TRUE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } else { mgrs_single_digraph = FALSE; // mgrs_ul_digraph and mgrs_ur_digraph are the same. } } else { char easting_str[10]; char northing_str[10]; xastir_snprintf(easting_str, sizeof(easting_str), " %07.0f", easting); xastir_snprintf(northing_str, sizeof(northing_str), " %07.0f", northing); strcpy(grid_label1, zone_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, easting_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string strcat(grid_label1, northing_str); grid_label1[sizeof(grid_label1)-1] = '\0'; // Terminate string } //"XASTIR Map of %s (upper left) to %s (lower right). UTM %d m grid, %s datum. ", xastir_snprintf(top_label, sizeof(top_label), langcode("MDATA001"), grid_label,grid_label1,utm_grid_spacing_m,metadata_datum); //draw_nice_string(w,pixmap_final,0, // border_width+2, // border_width-2, // top_label, // 0x10,0x20,(int)strlen(top_label)); draw_rotated_label_text_to_target (w, 270, border_width+2, border_width-1, sizeof(top_label),colors[0x10],top_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); // deterimne whether the easting and northing strings will fit // in a grid box, or whether easting strings in adjacent boxes // will overlap (so that alternate strings can be skipped). if (utm_grid.zone[Zone].ncols > 1) { // find out the number of pixels beteen two grid lines grid_spacing_pixels = utm_grid.zone[Zone].col[1].points[0].x - utm_grid.zone[Zone].col[0].points[0].x; if (grid_spacing_pixels == 0) { grid_spacing_pixels = -1; // Skip } } else { // only one column in this zone, skip alternate doesn't matter grid_spacing_pixels = -1; } // Is truncated easting or northing larger than grid spacing? // If so, skip alternate labels // short_width_pixels+2 seems to work well. if (short_width_pixels+2>grid_spacing_pixels) { skip_alternate_label = TRUE; } else { skip_alternate_label = FALSE; } // Label the grid lines on the border. // Put easting along the bottom for easier correct ordering of easting and northing // by people who are reading the map. last_line_labeled = FALSE; for (ii=1; ii < (int)utm_grid.zone[Zone].ncols; ii++) { // label meridianal grid lines with easting if (utm_grid.zone[Zone].col[ii].npoints > 1) { // adjust up in case npoints goes far below the screen if (grid_spacing_pixels == 0) { continue; // Go to next iteration of for loop } bottom_point = (int)(screen_height/grid_spacing_pixels); if (bottom_point >= utm_grid.zone[Zone].col[ii].npoints) { bottom_point = utm_grid.zone[Zone].col[ii].npoints - 1; } if (skip_alternate_label==TRUE && last_line_labeled==TRUE) { last_line_labeled = FALSE; } else { xx = (utm_grid.zone[Zone].col[ii].points[bottom_point].x * scale_x) + NW_corner_longitude; yy = (utm_grid.zone[Zone].col[ii].points[bottom_point].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); // To display full precision to one meter, use: //xastir_snprintf(grid_label, // sizeof(grid_label), // "%06.0f0", // (float)((utm_grid_spacing_m/10) * roundf(easting/(utm_grid_spacing_m)))); // // Divide easting by utm_grid_spacing to make sure the line is labeled // correctly, and not a few meters off, and truncate to at least 100 m. xastir_snprintf(grid_label, sizeof(grid_label), "%05.0f", (float)((utm_grid_spacing_m/100) * roundf(easting/(utm_grid_spacing_m)))); // truncate the label to an appropriate level of precision for the grid if (utm_grid_spacing_m ==1000) { grid_label[4] = ' '; } if (utm_grid_spacing_m ==10000) { grid_label[3] = ' '; grid_label[4] = ' '; } if (utm_grid_spacing_m ==100000) { grid_label[2] = ' '; grid_label[3] = ' '; grid_label[4] = ' '; } if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, sizeof(mgrs_eastingL), mgrs_northingL, sizeof(mgrs_northingL), &int_utmEasting, &int_utmNorthing, xx, yy, 0, mgrs_space_string, strlen(mgrs_space_string)); grid_label[0] = mgrs_eastingL[0]; grid_label[1] = mgrs_northingL[0]; if (mgrs_single_digraph==FALSE) { grid_label[1] = '_'; } } // draw each number at the bottom of the screen just to the right of the // relevant grid line at its location at the bottom of the screen //draw_nice_string(w,pixmap_final,0, // utm_grid.zone[Zone].col[i].points[bottom_point].x+1, // screen_height-2, // grid_label, // 0x10,easting_color,(int)strlen(grid_label)); // Don't overwrite the zone label, half the seven zeros string should give it room. // Don't draw the label if it will go off the left edge fo the screen. if ((utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 > (string_width_pixels/2)) && (utm_grid.zone[Zone].col[ii].points[bottom_point].x+1 < (screen_width - string_width_pixels)) ) { // ok to draw the label last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 270, utm_grid.zone[Zone].col[ii].points[bottom_point].x+1, screen_height, sizeof(grid_label),colors[easting_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } } } last_line_labeled = FALSE; // put northing along the right border, again for easier correct ordering of easting and northing. for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { // label latitudinal grid lines with northing if (utm_grid.zone[Zone].row[ii].npoints > 1) { if (skip_alternate_label==TRUE && last_line_labeled==TRUE) { last_line_labeled = FALSE; } else { if (label_on_left==TRUE) { xx = (utm_grid.zone[Zone].row[ii].points[0].x * scale_x) + NW_corner_longitude; } else { xx = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].x * scale_x) + NW_corner_longitude; } yy = (utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y * scale_y) + NW_corner_latitude; convert_xastir_to_UTM(&easting, &northing, zone_str, sizeof(zone_str), xx, yy); // To display to full 1 meter precision use: //xastir_snprintf(grid_label, // sizeof(grid_label), // "%06.0f0", // (float)((utm_grid_spacing_m/10) * roundf(northing/(utm_grid_spacing_m)))); // // Divide northing by utm grid spacing to make sure the line is labeled correctly // and displays zeroes in its least significant digits, and truncate to 100 m xastir_snprintf(grid_label, sizeof(grid_label), "%05.0f", (float)((utm_grid_spacing_m/100) * roundf(northing/(utm_grid_spacing_m)))); if (utm_grid_spacing_m ==1000) { grid_label[4] = ' '; } if (utm_grid_spacing_m ==10000) { grid_label[3] = ' '; grid_label[4] = ' '; } if (utm_grid_spacing_m ==100000) { grid_label[2] = ' '; grid_label[3] = ' '; grid_label[4] = ' '; } if (coordinate_system == USE_MGRS) { convert_xastir_to_MGRS_str_components(mgrs_zone, strlen(mgrs_zone), mgrs_eastingL, 3, mgrs_northingL, 3, &int_utmEasting, &int_utmNorthing, xx, yy, 0, mgrs_space_string, strlen(mgrs_space_string)); grid_label[0] = mgrs_eastingL[0]; if (mgrs_single_digraph==FALSE) { grid_label[0] = '_'; } grid_label[1] = mgrs_northingL[0]; } // Draw northing labels. // Draw each number just above the relevant grid line along the right side // of the screen. Don't write in the bottom border or off the top of the screen. if (label_on_left==TRUE) { // label northings on left border // don't overwrite the zone designator in the lower left border if ((utm_grid.zone[Zone].row[ii].points[0].y < (screen_height - border_width)) && (utm_grid.zone[Zone].row[ii].points[0].y > (string_width_pixels)) ) { last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 180, border_width, utm_grid.zone[Zone].row[ii].points[0].y, sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } else { if (((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1) < (screen_height - border_width)) && ((utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1) > (string_width_pixels)) ) { // label northings on right border last_line_labeled = TRUE; draw_rotated_label_text_to_target (w, 180, screen_width, utm_grid.zone[Zone].row[ii].points[utm_grid.zone[Zone].row[ii].npoints-1].y-1, sizeof(grid_label),colors[northing_color],grid_label,FONT_BORDER, pixmap_final, outline_border_labels, colors[outline_border_labels_color]); } } } } } // for i=0 to nrows } // if draw labeled grid border } // if utm_grid.zone[Zone] is non-empty } // for each zone in utm_grid.zone } // End of actually_draw_utm_minor_grid() function // Calculate the minor UTM grids. Called by draw_grid() below. // This function calculates and caches a within-zone UTM grid // for the current map view if one does not allready exist, it // then calls actually_draw_utm_minor_grid() function above to do // the drawing once the grid has been calculated. Zone boundaries // are drawn separately by draw_major_utm_mgrs_grid(). // // This routine appears to draw most of the UTM/UPS grid ok, with // the exceptions of: // // 1) Sometimes fails to draw vertical lines nearest zone // boundaries. // 2) Lines connect across zone boundaries in an incorrect manner, // jumping up one grid interval across the boundary. // 3) Segfaults near the special zone intersections as you zoom in. // // The code currently creates a col and row array per zone visible, // with XPoints malloced that contain the grid intersections in // screen coordinates. If the screen is zoomed or panned they are // recalculated. // // Perhaps we could do the same but with lat/long coordinates in the // future so that we'd only have to recalculate when a new Zone came // into view. We'd use the lat/long vector drawing programs above // then, with a possible slowdown due to more calculations if we're // not moving around. // // Returns: 0 if successful or nothing to draw // 1 if malloc error // 2 if iterations error // 3 if out of zones // 4 if realloc failure // int draw_minor_utm_mgrs_grid(Widget w) { long xx, yy, xx1, yy1; double e[4], n[4]; char place_str[10], zone_str[10]; int done = 0; int z1, z2, Zone, col, col_point, row, row_point, row_point_start; int iterations = 0; int finished_with_current_zone = 0; int ii, jj; float slope; int coordinate_system_backup = coordinate_system; col = 0; row = 0; col_point = 0; row_point = 0; row_point_start = 0; Zone = 0; // Set up for drawing zone grid(s) if (scale_x < 15) { utm_grid_spacing_m = 100; } else if (scale_x < 150) { utm_grid_spacing_m = 1000; } else if (scale_x < 1500) { utm_grid_spacing_m = 10000; } else if (scale_x < 3000) { utm_grid_spacing_m = 100000; } else { utm_grid_spacing_m = 0; // All done! Don't draw the minor grids. Major grids // have already been drawn by this point. return(0); } // Check hash to see if utm_grid is already set up if (utm_grid.hash.ul_x == NW_corner_longitude && utm_grid.hash.ul_y == NW_corner_latitude && utm_grid.hash.lr_x == SE_corner_longitude && utm_grid.hash.lr_y == SE_corner_latitude) { // XPoint arrays are already set up. Go draw the grid. actually_draw_utm_minor_grid(w); return(0); } // If we get to this point, we need to re-create the minor UTM/MGRS // grids as they haven't been set up yet or they don't match the // current view. // Clear the minor UTM/MGRS grid arrays. Alloc space for // the points in the grid structure. if (utm_grid_clear(1)) { // If we got here, we had a problem with malloc's return(1); } // Find top left point of current view xx = NW_corner_longitude; yy = NW_corner_latitude; // Note that the minor grid depends on the STANDARD six degree // UTM zones, not the UTM-Special/MGRS zones. Force our // calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy); coordinate_system = coordinate_system_backup; n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere // Select starting point, NW corner of NW zone // Move the coordinates to the nearest subgrid intersection, // based on our current grid spacing. The grid intersection // we calculate here is northwest of our view's northwest // corner. e[0] /= utm_grid_spacing_m; e[0] = (double)((int)e[0] * utm_grid_spacing_m); n[0] /= utm_grid_spacing_m; n[0] = (double)((int)n[0] * utm_grid_spacing_m); n[0] += utm_grid_spacing_m; //WE7U // It appears that the horizontal grid lines get messed up in cases // where the top horizontal line isn't in view on it's left end. // That's a major clue! Read the comment below (again with a "WE7U" // tag). The problem occurs at the point where we copy the last // point from the previous grid over to the first point of a new // grid. That can cause us to be off by one, as for the grid on the // left, the top horizontal line _is_ in view on the left. We end // up connecting the wrong horizontal lines together because of this // mismatch, but again, only if the top horizontal line on the left // grid is above the current view. // // It also appears that the vertical lines that are missing in some // cases are on the right of the zone boundary. This is probably // because the top of that line doesn't go to the top of the view. // On views where it does, the line is drawn. I assume this is // because we're drawing from NW corner to the right, and then down, // which would cause that line to be skipped if it's not present on // the first line? e[1] = e[0]; n[1] = n[0]; ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // Start filling in the row/column arrays of grid intersections while (!done) { XPoint *temp_point; // Here's our escape in case we get stuck in this loop. // We can go through this loop multiple times for each // zone though, depending on our grid spacing. 64 rows * 64 // colums * 8 points each = 32768, which gives us our upper // limit. if (iterations++ > 32768) { fprintf(stderr, "draw_minor_utm_mgrs_grid() looped too many times, escaping.\n"); utm_grid_clear(1); return(2); } if (finished_with_current_zone) { // Set up to compute the next zone xx = NW_corner_longitude + ((utm_grid.zone[Zone].boundary_x + 1) * scale_x); yy = NW_corner_latitude; // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. // Force our calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[0], &n[0], place_str, sizeof(place_str), xx, yy); coordinate_system = coordinate_system_backup; n[0] += UTM_GRID_EQUATOR; // To work in southern hemisphere // Fix the coordinates to the nearest subgrid intersection based on // our current grid spacing. Bump both the easting and northing up // by one subgrid. e[0] /= utm_grid_spacing_m; e[0] = (double)((int)e[0] * utm_grid_spacing_m); e[0] += utm_grid_spacing_m; n[0] /= utm_grid_spacing_m; n[0] = (double)((int)n[0] * utm_grid_spacing_m); n[0] += utm_grid_spacing_m; e[1] = e[0]; n[1] = n[0]; #ifdef UTM_DEBUG fprintf(stderr,"\nFinished Zone=%d\n", Zone); #endif // We're all done with the current zone. Increment // to the next zone and set up to calculate its // points. Zone++; #ifdef UTM_DEBUG fprintf(stderr,"\nstarting Zone=%d, row_point_start=1\n", Zone); #endif row_point = row_point_start = 1; col = row = col_point = 0; finished_with_current_zone = 0; if (Zone >= UTM_GRID_MAX_ZONES) { fprintf(stderr,"Error: Zone=%d: out of zones!\n", Zone); Zone = 0; done = 1; utm_grid_clear(1); return(3); } } // End of if(finished_with_current_zone) // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. Force // our calculations to use the standard zones. coordinate_system = USE_UTM; convert_UTM_to_xastir(e[1], n[1]-UTM_GRID_EQUATOR, place_str, &xx, &yy); coordinate_system = coordinate_system_backup; xx1 = xx; // Save yy1 = yy; // Save // Note that the minor grid depends on the STANDARD six // degree UTM zones, not the UTM-Special/MGRS zones. Force // our calculations to use the standard zones. coordinate_system = USE_UTM; convert_xastir_to_UTM(&e[2], &n[2], zone_str, sizeof(zone_str), xx, yy); coordinate_system = coordinate_system_backup; n[2] += UTM_GRID_EQUATOR; xx = (xx - NW_corner_longitude) / scale_x; yy = (yy - NW_corner_latitude) / scale_y; // Not all columns (and maybe rows) will start at point // 0 if (utm_grid.zone[Zone].col[col].firstpoint == UTM_GRID_RC_EMPTY) { utm_grid.zone[Zone].col[col].firstpoint = l16(col_point); #ifdef UTM_DEBUG fprintf(stderr,"col[%d] started at point %d\n", col, col_point); #endif } if (utm_grid.zone[Zone].row[row].firstpoint == UTM_GRID_RC_EMPTY) { utm_grid.zone[Zone].row[row].firstpoint = l16(row_point); #ifdef UTM_DEBUG fprintf(stderr,"row[%d] started at point %d\n", row, row_point); #endif } // Check to see if we need to alloc more space for // column points ii = utm_grid.zone[Zone].col[col].npoints + utm_grid.zone[Zone].col[col].firstpoint + 1; if (ii > utm_grid.zone[Zone].col[col].nalloced) { #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].col[%d].points, ", ii, utm_grid.zone[Zone].col[col].nalloced, Zone, col); #endif ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED; #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"%d)\n", ii); #endif temp_point = realloc(utm_grid.zone[Zone].col[col].points, ii * sizeof(XPoint)); if (temp_point) { utm_grid.zone[Zone].col[col].points = temp_point; utm_grid.zone[Zone].col[col].nalloced = ii; } else { puts("realloc FAILED!"); (void)utm_grid_clear(1); // Clear arrays and allocate memory for points return(4); } } // Check to see if we need to alloc more space for row // points ii = utm_grid.zone[Zone].row[row].npoints + utm_grid.zone[Zone].row[row].firstpoint + 1; if (ii > utm_grid.zone[Zone].row[row].nalloced) { #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"i=%d n=%d realloc(utm_grid.zone[%d].row[%d].points, ", ii, utm_grid.zone[Zone].row[row].nalloced, Zone, row); #endif ii = ((ii / UTM_GRID_DEF_NALLOCED) + 1) * UTM_GRID_DEF_NALLOCED; #ifdef UTM_DEBUG_ALLOC fprintf(stderr,"%d)\n", ii); #endif temp_point = realloc(utm_grid.zone[Zone].row[row].points, ii * sizeof(XPoint)); if (temp_point) { utm_grid.zone[Zone].row[row].points = temp_point; utm_grid.zone[Zone].row[row].nalloced = ii; } else { puts("realloc FAILED!"); (void)utm_grid_clear(1); // Clear arrays and allocate memory for points return(4); } } // Here we check to see whether we are inserting points // that are greater than about +/- 32767. If so, // truncate at that. This prevents XDrawLines() from // going nuts and drawing hundreds of extra lines. // xx = l16(xx); yy = l16(yy); utm_grid.zone[Zone].col[col].points[col_point].x = l16(xx); utm_grid.zone[Zone].col[col].points[col_point].y = l16(yy); utm_grid.zone[Zone].col[col].npoints++; utm_grid.zone[Zone].row[row].points[row_point].x = l16(xx); utm_grid.zone[Zone].row[row].points[row_point].y = l16(yy); utm_grid.zone[Zone].row[row].npoints++; #ifdef UTM_DEBUG fprintf(stderr,"utm_grid.zone[%d].col[%d].points[%d] = [ %ld,%ld ] npoints=%d\n", Zone, col, col_point, xx, yy, utm_grid.zone[Zone].col[col].npoints); fprintf(stderr,"utm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone, row, row_point, xx, yy); #endif col++; row_point++; if (col >= UTM_GRID_MAX_COLS_ROWS) { finished_with_current_zone++; } z1 = atoi(place_str); z2 = atoi(zone_str); if (z1 != z2 || xx > screen_width) // We hit a boundary { #ifdef UTM_DEBUG_VERB if (z1 != z2) { fprintf(stderr,"Zone boundary! \"%s\" -> \"%s\"\n", place_str, zone_str); } else { puts("Screen boundary!"); } #endif //#warning //#warning I suspect that I should not use just col for the following. //#warning if (col-2 >= 0) slope = (float)(yy - utm_grid.zone[Zone].col[col-2].points[col_point].y) / (float)(xx - utm_grid.zone[Zone].col[col-2].points[col_point].x + 0.001); else { slope = 0.0; } if (xx > screen_width) { xx1 = screen_width; } else { // 360,000 Xastir units equals one degree. This // code appears to be adjusting xx1 to a major // zone edge. xx1 = (xx1 / (6 * 360000)) * 6 * 360000; xx1 = (xx1 - NW_corner_longitude) / scale_x; } utm_grid.zone[Zone].boundary_x = xx1; yy1 = yy - (xx - xx1) * slope; #ifdef UTM_DEBUG fprintf(stderr,"_tm_grid.zone[%d].col[%d].points[%d] = [ %ld,%ld ]\n", Zone, col-1, col_point, xx1, yy1); fprintf(stderr,"_tm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone, row, row_point-1, xx1, yy1); #endif if (col-1 >= 0 && row_point-1 >= 0) { utm_grid.zone[Zone].col[col-1].points[col_point].x = l16(xx1); utm_grid.zone[Zone].col[col-1].points[col_point].y = l16(yy1); utm_grid.zone[Zone].row[row].points[row_point-1].x = l16(xx1); utm_grid.zone[Zone].row[row].points[row_point-1].y = l16(yy1); if (z1 != z2 && Zone+1 < UTM_GRID_MAX_ZONES) { // copy over last points to start off new // zone #ifdef UTM_DEBUG fprintf(stderr,"ztm_grid.zone[%d].row[%d].points[%d] = [ %ld,%ld ]\n", Zone+1, row, 0, xx1, yy1); #endif //WE7U // This is where we can end up linking up/down one grid width // between zones!!! Without it though, we end up have a blank // section to the right of the zone boundary. Perhaps we could do // this here, but when we get the next points calculated, we could // check to see if we're off by about one grid width in the vertical // direction. If so, shift the initial point by that amount? // // Another possibility might be to draw bottom-to-top if in northern // hemisphere, and top-to-bottom if in southern hemisphere. That // way we'd have the max amount of lines present when we start, and // some might peter out as we draw along N/S. Looking at the // southern hemisphere right now though, that method doesn't appear // to work. We get the same problems there even though we're // drawing top to bottom. // utm_grid.zone[Zone+1].row[row].points[0].x = l16(xx1); utm_grid.zone[Zone+1].row[row].points[0].y = l16(yy1); utm_grid.zone[Zone+1].row[row].firstpoint = 0; utm_grid.zone[Zone+1].row[row].npoints = 1; } } // Check last built row to see if it is all off // screen finished_with_current_zone++; // Assume we're done with this zone for (ii=0; ii < utm_grid.zone[Zone].row[row].npoints; ii++) { if (utm_grid.zone[Zone].row[row].points[ii].y <= screen_height) { finished_with_current_zone = 0; // Some points were within the zone, keep computing } } e[1] = e[0]; // carriage return n[1] -= utm_grid_spacing_m; // line feed // Yea, your comments are real funny Olivier... Gets the point // across though! row++; if (row >= UTM_GRID_MAX_COLS_ROWS) { finished_with_current_zone++; } utm_grid.zone[Zone].ncols = max_i(col, utm_grid.zone[Zone].ncols); utm_grid.zone[Zone].nrows = max_i(row, utm_grid.zone[Zone].nrows); col = 0; row_point = row_point_start; col_point++; if (n[1] < 0) { fprintf(stderr,"n[1] < 0\n"); finished_with_current_zone++; } if (finished_with_current_zone && xx > screen_width) { done = 1; } // Go to next iteration of while loop (skip next statement) continue; } e[1] += utm_grid_spacing_m; } // End of while (done) loop ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// //fprintf(stderr, "After while loop\n"); // utm_grid.zone[] now contains an array of points marking fine grid // line intersections for parts of 1 to 4 zones that appear on // the screen. Each utm_grid.zone[] is a vertical stripe, and may include // more than one zone letter, e.g. zone[0] might include 15U and 15T, // while zone[1] might include 16U and 16T. //#define UTM_DEBUG_VERB for (Zone=0; Zone < UTM_GRID_MAX_ZONES; Zone++) { #ifdef UTM_DEBUG_VERB fprintf(stderr,"\nutm_grid.zone[%d].ncols=%d\nutm_grid.zone[%d].nrows=%d\n", Zone, utm_grid.zone[Zone].ncols, Zone, utm_grid.zone[Zone].nrows); #endif // Cleanup columns for (ii=0; ii < (int)utm_grid.zone[Zone].ncols; ii++) { int np = utm_grid.zone[Zone].col[ii].npoints; int fp = utm_grid.zone[Zone].col[ii].firstpoint; int nbp = 0; #ifdef UTM_DEBUG_VERB fprintf(stderr,"utm_grid.zone[%d].col[%d].npoints=%d .firstpoint=%d\n", Zone, ii, np, fp); if (np < 2) { puts(" Not enough points!"); } else { puts(""); } for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," col[%d].points[%d] = [ %d, %d ]", ii, jj, utm_grid.zone[Zone].col[ii].points[jj].x, utm_grid.zone[Zone].col[ii].points[jj].y); if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { puts(" Boundary"); } else { puts(""); } } #endif for (jj=fp; jj < fp+np; jj++) { if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { nbp++; } else if (nbp > 0) // We had a boundary point, but not anymore { fp = utm_grid.zone[Zone].col[ii].firstpoint = l16(jj - 1); //fprintf(stderr,"np:%d, jj:%d\n",np,jj); // This can result in negative numbers! np = utm_grid.zone[Zone].col[ii].npoints = np - jj + 1; //fprintf(stderr,"new np:%d\n",np); if (np < 0) { np = 0; // Prevents segfaults in // XDrawLines() and memmove() // below. } break; // Exit from for loop } if (nbp == np) // All points are boundary points { fp = utm_grid.zone[Zone].col[ii].firstpoint = 0; np = utm_grid.zone[Zone].col[ii].npoints = 0; } } // What's the below code doing? Can get a segfault without this in // the XDrawLines() functions below (fixed by making npoints an int // instead of an unsigned int). Sometimes we get a segfault right // here due to the memmove() function. In one such case, np was -2. // Latest code keeps some lines from getting drawn, but at least we // don't get a segfault. // if (fp > 0) { if (np > 0) { memmove(&utm_grid.zone[Zone].col[ii].points[0], &utm_grid.zone[Zone].col[ii].points[fp], np * sizeof(XPoint)); fp = utm_grid.zone[Zone].col[ii].firstpoint = 0; } else { //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint)); //fprintf(stderr,"Problem1: in draw_minor_utm_mgrs_grid() memmove, np was %d. Skipping memmove.\n",np); } } #ifdef UTM_DEBUG_VERB fprintf(stderr,"_tm_grid.zone[%d].col[%d].npoints=%d.firstpoint=%d\n", Zone, ii, np, fp); for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," col[%d].points[%d] = [ %d, %d ]", ii, jj, utm_grid.zone[Zone].col[ii].points[jj].x, utm_grid.zone[Zone].col[ii].points[jj].y); if (utm_grid.zone[Zone].col[ii].points[jj].x == utm_grid.zone[Zone].boundary_x) { puts(" Boundary"); } else { puts(""); } } puts(""); #endif } // Cleanup rows for (ii=0; ii < (int)utm_grid.zone[Zone].nrows; ii++) { int np = utm_grid.zone[Zone].row[ii].npoints; int fp = utm_grid.zone[Zone].row[ii].firstpoint; #ifdef UTM_DEBUG_VERB fprintf(stderr,"utm_grid.zone[%d].row[%d].npoints=%d.firstpoint=%d\n", Zone, ii, np, fp); if (np < 2) { puts(" Not enough points!"); } else { puts(""); } #endif // What's this doing? This appears to be important, as things get // really messed up if it's commented out. if (fp > 0) { if (np > 0) { memmove(&utm_grid.zone[Zone].row[ii].points[0], &utm_grid.zone[Zone].row[ii].points[fp], np * sizeof(XPoint)); fp = utm_grid.zone[Zone].row[ii].firstpoint = 0; } else { //fprintf(stderr,"draw_minor_utm_mgrs_grid: ii:%d, np:%d, size:%d\n",ii,np,sizeof(XPoint)); //fprintf(stderr,"Problem2: in draw_minor_utm_mgrs_grid() memmove, np was %d. Skipping memmove.\n",np); } } #ifdef UTM_DEBUG_VERB for (jj=fp; jj < fp+np; jj++) { fprintf(stderr," row[%d].points[%d] = [ %d, %d ]\n", ii, jj, utm_grid.zone[Zone].row[ii].points[jj].x, utm_grid.zone[Zone].row[ii].points[jj].y); } #endif } } // Rows and columns ready to go so setup hash utm_grid.hash.ul_x = NW_corner_longitude; utm_grid.hash.ul_y = NW_corner_latitude; utm_grid.hash.lr_x = SE_corner_longitude; utm_grid.hash.lr_y = SE_corner_latitude; // XPoint arrays are set up. Go draw the grid. actually_draw_utm_minor_grid(w); return(0); } // End of draw_minor_utm_mgrs_grid() function //***************************************************************** // draw_grid() // // Draws a lat/lon or UTM/UPS grid on top of the view. // //***************************************************************** void draw_grid(Widget w) { int half; // Center of the white lines used to draw the borders int border_width = 14; // The width of the border to draw around the // map to place labeled tick marks into // should be an even number. // The default here is overidden by the border fontsize. if (!long_lat_grid) // We don't wish to draw a map grid { return; } if (draw_labeled_grid_border==TRUE) { // Determine how wide the border should be. border_width = get_border_width(w); half = border_width/2; // draw a white border around the map. (void)XSetLineAttributes(XtDisplay(w), gc, border_width, LineSolid, CapRound, JoinRound); (void)XSetForeground(XtDisplay(w), gc, colors[border_foreground_color]); // white (void)XDrawLine(XtDisplay(w), pixmap_final, gc, 0, l16(half), l16(screen_width), l16(half)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(half), 0, l16(half), l16(screen_height)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, 0, l16(screen_height-half), l16(screen_width), l16(screen_height-half)); (void)XDrawLine(XtDisplay(w), pixmap_final, gc, l16(screen_width-half), 0, l16(screen_width-half), l16(screen_height)); } // Set the line width in the GC to 2 pixels wide for the larger // UTM grid and the complete Lat/Long grid. (void)XSetLineAttributes (XtDisplay (w), gc_tint, 2, LineOnOffDash, CapButt,JoinMiter); (void)XSetForeground (XtDisplay (w), gc_tint, colors[0x27]); (void)XSetFunction (XtDisplay (da), gc_tint, GXxor); if (coordinate_system == USE_UTM || coordinate_system == USE_UTM_SPECIAL || coordinate_system == USE_MGRS) { int ret_code; //draw_vector_ll(w, -5.0, -5.0, 5.0, 5.0, gc_tint, pixmap_final, 0); //draw_vector_ll(w, 5.0, 5.0, -5.0, -5.0, gc_tint, pixmap_final, 0); // Draw major UTM/MGRS zones draw_major_utm_mgrs_grid(w); // Draw minor UTM/MGRS zones ret_code = draw_minor_utm_mgrs_grid(w); if (ret_code) { fprintf(stderr, "Encountered problem %d while calculating minor utm grid!\n", ret_code); } } // End of UTM grid section else // Lat/Long coordinate system, draw lat/long lines { draw_complete_lat_lon_grid(w); } // End of Lat/Long section } // End of draw_grid() /********************************************************** * get_map_ext() * * Returns the extension for the filename. We use this to * determine which sort of map file it is. **********************************************************/ char *get_map_ext (char *filename) { int len; int i; char *ext; ext = NULL; len = (int)strlen (filename); for (i = len; i >= 0; i--) { if (filename[i] == '.') { ext = filename + (i + 1); break; } } return (ext); } /********************************************************** * get_map_dir() * * Used to snag just the pathname from a complete filename. * Modifies input parameter "fullpath". **********************************************************/ char *get_map_dir (char *fullpath) { int len; int i; len = (int)strlen (fullpath); for (i = len; i >= 0; i--) { if (fullpath[i] == '/') { fullpath[i + 1] = '\0'; break; } } return (fullpath); } /*********************************************************** * map_visible() * * Tests whether a particular path/filename is within our * current view. We use this to decide whether to plot or * skip a particular image file (major speed-up!). * Input coordinates are in the Xastir coordinate system. * * Had to fix a bug here where the viewport glanced over the * edge of the earth, causing strange results like this. * Notice the View Edges Top value is out of range: * * * Bottom Top Left Right * View Edges: 31,017,956 4,290,923,492 35,971,339 90,104,075 * Map Edges: 12,818,482 12,655,818 64,079,859 64,357,110 * * Left map boundary inside view * Right map boundary inside view * map_inside_view: 1 view_inside_map: 0 parallel_edges: 0 * Map not within current view. * Skipping map: /usr/local/share/xastir/maps/tif/uk/425_0525_bng.tif * * * I had to check for out-of-bounds numbers for the viewport and * set them to min or max values so that this function always * works properly. Here are the bounds of the earth (Xastir * Coordinate System): * * 0 (90 deg. or 90N) * * 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) * * 64,800,000 (-90 deg. or 90S) * ***********************************************************/ int map_visible (unsigned long map_max_y, // bottom_map_boundary unsigned long map_min_y, // top_map_boundary unsigned long map_min_x, // left_map_boundary unsigned long map_max_x) // right_map_boundary) { { //fprintf(stderr,"map_visible\n"); // From computation geometry equations, intersection of two line // segments, they use the bounding box for two lines. This is // the same as what we want to do: // // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa // http://www.gamedev.net/reference/articles/article735.asp // // The quick rejection algorithm: // if (NW_corner_latitude > (long)map_max_y) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: NW_corner_latitude:%ld > map_max_y:%ld\n", NW_corner_latitude, map_max_y); fprintf(stderr, "\tmap or object is above viewport\n"); } return(0); } if ((long)map_min_y > SE_corner_latitude) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: map_min_y:%ld > SE_corner_latitude:%ld\n", map_min_y, SE_corner_latitude); fprintf(stderr, "\tmap or object is below viewport\n"); } return(0); } if (NW_corner_longitude > (long)map_max_x) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: NW_corner_longitude:%ld > map_max_x:%ld\n", NW_corner_longitude, map_max_x); fprintf(stderr, "\tmap or object is left of viewport\n"); } return(0); } if ((long)map_min_x > SE_corner_longitude) { if (debug_level & 16) { fprintf(stderr, "map_visible, rejecting: map_min_x:%ld > SE_corner_longitude:%ld\n", map_min_x, SE_corner_longitude); fprintf(stderr, "\tmap or object is right of viewport\n"); } return(0); } return (1); // At least part of the map is on-screen } ///////////////////////////////////////////////////////////////////// // get_viewport_lat_lon(double *xmin, double *ymin, double* xmax, double *ymax) // Simply returns the floating point corners of the map display. ///////////////////////////////////////////////////////////////////// void get_viewport_lat_lon(double *xmin, double *ymin, double* xmax, double *ymax) { *xmin=(double)f_NW_corner_longitude; *ymin=(double)f_SE_corner_latitude; *xmax=(double)f_SE_corner_longitude; *ymax=(double)f_NW_corner_latitude; } ///////////////////////////////////////////////////////////////////// // map_inside_viewport_lat_lon() // Returns 1 if the given set of xmin,xmax, ymin,ymax defines a // rectangle entirely contained in the current viewport (as opposed to // merely partially overlapping it. Returns zero otherwise. ///////////////////////////////////////////////////////////////////// int map_inside_viewport_lat_lon(double map_min_y, double map_max_y, double map_min_x, double map_max_x) { int retval=0; if (map_min_x >= f_NW_corner_longitude && map_min_y >= f_SE_corner_latitude && map_max_x <= f_SE_corner_longitude && map_max_y <= f_NW_corner_latitude) { retval=1; } return (retval); } ///////////////////////////////////////////////////////////////////// // map_visible_lat_lon() // // We have the center of the view in floating point format: // // float f_center_longitude; // Floating point map center longitude // float f_center_latitude; // Floating point map center latitude // // So we just need to compute the top/bottom/left/right using those // values and the scale_x/scale_y values before doing the compare. // // y scaling in 1/100 sec per pixel // x scaling in 1/100 sec per pixel, calculated from scale_y // // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // ******************* ******************* max_y // *NW * + * * + // * * * * // * * * * // * View * latitude (y) * Map * // * * * * // * * * * // * SE* - * * - // ******************* ******************* min_y // - longitude(x) + - min_x max_x + ///////////////////////////////////////////////////////////////////// int map_visible_lat_lon (double map_min_y, // f_bottom_map_boundary double map_max_y, // f_top_map_boundary double map_min_x, // f_left_map_boundary double map_max_x) // f_right_map_boundary { //fprintf(stderr,"map_visible_lat_lon\n"); // From computation geometry equations, intersection of two line // segments, they use the bounding box for two lines. This is // the same as what we want to do: // // http://www.cs.kent.edu/~dragan/AdvAlg/CompGeom-2x1.pdfa // http://www.gamedev.net/reference/articles/article735.asp // // The quick rejection algorithm: // if (map_max_y < f_SE_corner_latitude ) { return(0); // map below view } if (map_max_x < f_NW_corner_longitude) { return(0); // map left of view } if (map_min_y > f_NW_corner_latitude ) { return(0); // view below map } if (map_min_x > f_SE_corner_longitude) { return(0); // view left of map } return (1); // Draw this map onto the screen } /********************************************************** * draw_label_text() * * Does what it says. Used to draw strings onto the * display. **********************************************************/ void draw_label_text (Widget w, int x, int y, int label_length, int color, char *label_text) { // This draws a gray background rectangle upon which we draw the text. // Probably not needed. It ends up obscuring details underneath. //(void)XSetForeground (XtDisplay (w), gc, colors[0x0ff]); //(void)XFillRectangle (XtDisplay (w), pixmap, gc, x - 1, (y - 10),(label_length * 6) + 2, 11); (void)XSetForeground (XtDisplay (w), gc, color); (void)XDrawString (XtDisplay (w), pixmap, gc, x, y, label_text, label_length); } // Must make sure that fonts are not loaded again and again, as this // takes a big chunk of memory each time. Can you say "memory // leak"? XFontStruct *rotated_label_font[FONT_MAX]= {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; char rotated_label_fontname[FONT_MAX][MAX_LABEL_FONTNAME]; static char current_rotated_label_fontname[FONT_MAX][sizeof(rotated_label_fontname)] = {"","","","","","","","",""}; /********************************************************** * draw_rotated_label_text_common() * call through wrappers: * draw_rotated_label_text_to_pixmap() * draw_rotated_label_text() * draw_centered_label_text() * * Does what it says. Used to draw strings onto the * display. * * Use "xfontsel" or other tools to figure out what fonts * to use here. * * Paramenters: * target_pixmap specifies the pixmap the text is to be drawn to. * draw_outline specifies whether a 1 pixel outline around the * text, TRUE to draw outline. * outline_bg_color is the color of the outline. * color is the color of the text inside the outline, or the * color of the text itself if no outline is added. **********************************************************/ /* common code used by the two entries --- a result of retrofitting a new feature (centered) */ static void draw_rotated_label_text_common (Widget w, float my_rotation, int x, int y, int UNUSED(label_length), int color, char *label_text, int align, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color) { // XPoint *corner; // int i; int x_outline; int y_outline; // Do some sanity checking if (fontsize < 0 || fontsize >= FONT_MAX) { fprintf(stderr,"Font size is out of range: %d\n", fontsize); return; } /* see if fontname has changed */ if (rotated_label_font[fontsize] && strcmp(rotated_label_fontname[fontsize],current_rotated_label_fontname[fontsize]) != 0) { XFreeFont(XtDisplay(w),rotated_label_font[fontsize]); rotated_label_font[fontsize] = NULL; xastir_snprintf(current_rotated_label_fontname[fontsize], sizeof(rotated_label_fontname), "%s", rotated_label_fontname[fontsize]); } /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"draw_rotated_label_text: Couldn't get font %s\n", rotated_label_fontname[fontsize]); return; } } if (draw_outline) { // make outline style (void)XSetForeground(XtDisplay(w),gc,outline_bg_color); // Draw the string repeatedly with 1 pixel offsets in the // background color to make an outline. for (x_outline=-1; x_outline<2; x_outline++) { for (y_outline=-1; y_outline<2; y_outline++) { // draws one extra copy at x,y (void)XRotDrawAlignedString(XtDisplay (w), rotated_label_font[fontsize], my_rotation, target_pixmap, gc, x+x_outline, y+y_outline, label_text, align); } } } // Code to determine the bounding box corner points for the rotated text // corner = XRotTextExtents(w,rotated_label_font,my_rotation,x,y,label_text,BLEFT); // for (i=0;i<5;i++) { // fprintf(stderr,"%d,%d\t",corner[i].x,corner[i].y); // } // fprintf(stderr,"\n"); (void)XSetForeground (XtDisplay (w), gc, color); //fprintf(stderr,"%0.1f\t%s\n",my_rotation,label_text); (void)XRotDrawAlignedString(XtDisplay (w), rotated_label_font[fontsize], my_rotation, target_pixmap, gc, x, y, label_text, align); } // Find the pixel length of an unrotated string in the rotated_label_font. // Parameters: // w - the XtDisplay. // label_text - the string of which the length is to be found. // fontsize - the fontsize in the rotated_label_font in which the string // is to be rendered. // Returns: the length in pixels of the string, -1 on an error. int get_rotated_label_text_length_pixels(Widget w, char *label_text, int fontsize) { int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. int return_value; // value to return int got_font; // flag indicating that a font is available return_value = -1; got_font = TRUE; /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"get_rotated_label_text_length_pixels: Couldn't get font %s\n", rotated_label_fontname[fontsize]); got_font = FALSE; } } if (got_font) { // find out the width in pixels of the unrotated label_text string. XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc, &overall); return_value = overall.width; } return return_value; } // Find the pixel height of an unrotated string in the rotated_label_font. // Parameters: // w - the XtDisplay. // label_text - the string of which the length is to be found. // fontsize - the fontsize in the rotated_label_font in which the string // is to be rendered. // Returns: the height in pixels of the string, -1 on an error. int get_rotated_label_text_height_pixels(Widget w, char *label_text, int fontsize) { int dir, asc, desc; // parameters returned by XTextExtents, but not used here. XCharStruct overall; // description of the space occupied by the string. int return_value; // value to return int got_font; // flag indicating that a font is available return_value = -1; got_font = TRUE; /* load font */ if(!rotated_label_font[fontsize]) { rotated_label_font[fontsize]=(XFontStruct *)XLoadQueryFont(XtDisplay (w), rotated_label_fontname[fontsize]); if (rotated_label_font[fontsize] == NULL) // Couldn't get the font!!! { fprintf(stderr,"get_rotated_label_text_height_pixels: Couldn't get font %s\n", rotated_label_fontname[fontsize]); got_font = FALSE; } } if (got_font) { // find out the width in pixels of the unrotated label_text string. XTextExtents(rotated_label_font[fontsize], label_text, strlen(label_text), &dir, &asc, &desc, &overall); return_value = overall.ascent + overall.descent; } return return_value; } // Draw a rotated label onto the specified pixmap. // Wrapper for draw_rotated_label_text-common(). void draw_rotated_label_text_to_target (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize, Pixmap target_pixmap, int draw_outline, int outline_bg_color) { float my_rotation = (float)((-rotation)-90); if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BRIGHT, fontsize, target_pixmap, draw_outline, outline_bg_color); } else { (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BLEFT, fontsize, target_pixmap, draw_outline, outline_bg_color); } } void draw_rotated_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize) { float my_rotation = (float)((-rotation)-90); if ( ( (my_rotation < -90.0) && (my_rotation > -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BRIGHT, fontsize, pixmap, 0, 0); } else { (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BLEFT, fontsize, pixmap, 0, 0); } } void draw_centered_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize) { float my_rotation = (float)((-rotation)-90); (void)draw_rotated_label_text_common(w, my_rotation, x, y, label_length, color, label_text, BCENTRE, fontsize, pixmap, 0, 0); } static void Print_postscript_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; XtPopdown(shell); begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" ); if (print_postscript_dialog) { // Snag the path to the printer program from the print dialog temp_ptr = XmTextFieldGetString(printer_data); xastir_snprintf(printer_program, sizeof(printer_program), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(printer_program); // Check for empty variable if (printer_program[0] == '\0') { #ifdef LPR_PATH // Path to LPR if defined xastir_snprintf(printer_program, sizeof(printer_program), "%s", LPR_PATH); #else // LPR_PATH // Empty path printer_program[0]='\0'; #endif // LPR_PATH } //fprintf(stderr,"%s\n", printer_program); // Snag the path to the previewer program from the print dialog temp_ptr = XmTextFieldGetString(previewer_data); xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(previewer_program); // Check for empty variable if (previewer_program[0] == '\0') { #ifdef GV_PATH // Path to GV if defined xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", GV_PATH); #else // GV_PATH // Empty string previewer_program[0] = '\0'; #endif // GV_PATH } //fprintf(stderr,"%s\n", previewer_program); } XtDestroyWidget(shell); print_postscript_dialog = (Widget)NULL; end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_postscript_destroy_shell" ); } static void Print_properties_destroy_shell(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; if (!shell) { return; } XtPopdown(shell); begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" ); XtDestroyWidget(shell); print_properties_dialog = (Widget)NULL; end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties_destroy_shell" ); } // Print_window: Prints the drawing area to a Postscript file and // then sends it to the printer program (usually "lpr). // static void Print_window( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef NO_XPM // fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n"); popup_message_always(langcode("POPEM00035"), "XPM or ImageMagick support not compiled into Xastir! Cannot Print!"); #else // NO_XPM char xpm_filename[MAX_FILENAME]; char ps_filename[MAX_FILENAME]; char command[MAX_FILENAME*2]; char temp[MAX_FILENAME]; int xpmretval; char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/print.xpm", temp_base_dir); xastir_snprintf(ps_filename, sizeof(ps_filename), "%s/print.ps", temp_base_dir); busy_cursor(appshell); // Show a busy cursor while we're doing all of this // Get rid of the Print dialog Print_postscript_destroy_shell(widget, print_postscript_dialog, NULL ); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") ); statusline(temp,1); // Dumping image to file... if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for print_window\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display "print.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); popup_message_always(langcode("POPEM00035"), "Error writing xpm image file! Cannot Print!"); return; } else // We now have the xpm file created on disk { chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename ); } // Convert it to a postscript file for printing. This depends // on the ImageMagick command "convert". // if (debug_level & 512) { fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") ); statusline(temp,1); // Converting to Postscript... #ifdef HAVE_CONVERT strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -filter Point "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command ); } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't convert from XPM to PS!"); return; } #endif // HAVE_CONVERT chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // Delete temporary xpm file if ( !(debug_level & 512) ) { unlink( xpm_filename ); } if ( debug_level & 512 ) { fprintf(stderr,"Printing postscript file %s\n", ps_filename); } // Note: This needs to be changed to "lp" for Solaris. // Also need to have a field to configure the printer name. One // fill-in field could do both. // // Since we could be running SUID root, we don't want to be // calling "system" anyway. Several problems with it. strcpy(command, printer_program); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command); } if (printer_program[0] == '\0') { // fprintf(stderr,"\n\nPrint: No print program defined!\n\n\n"); popup_message_always(langcode("POPEM00035"), "No print program defined!"); return; } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't send to the printer!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't send to the printer!"); return; } /* if ( !(debug_level & 512) ) unlink( ps_filename ); */ if ( debug_level & 512 ) { fprintf(stderr," Done printing.\n"); } } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") ); statusline(temp,1); // Finished creating print file. //popup_message( langcode("PRINT0015"), langcode("PRINT0014") ); #endif // NO_XPM } // Print_preview: Prints the drawing area to a Postscript file. If // previewer_program has "gv" in it, then use the various options // selected by the user. If not, skip those options. // static void Print_preview( Widget widget, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { #ifdef NO_XPM // fprintf(stderr,"XPM or ImageMagick support not compiled into Xastir!\n"); popup_message_always(langcode("POPEM00035"), "XPM or ImageMagick support not compiled into Xastir! Cannot Print!"); #else // NO_GRAPHICS char xpm_filename[MAX_FILENAME]; char ps_filename[MAX_FILENAME]; char mono[50] = ""; char invert[50] = ""; char rotate[50] = ""; char scale[50] = ""; char density[50] = ""; char command[MAX_FILENAME*2]; char temp[MAX_FILENAME]; char format[100] = " "; int xpmretval; char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/print.xpm", temp_base_dir); xastir_snprintf(ps_filename, sizeof(ps_filename), "%s/print.ps", temp_base_dir); busy_cursor(appshell); // Show a busy cursor while we're doing all of this // Get rid of the Print Properties dialog if it exists Print_properties_destroy_shell(widget, print_properties_dialog, NULL ); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0012") ); statusline(temp,1); // Dumping image to file... if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for print_preview\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell),// Display *display "print.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); popup_message_always(langcode("POPEM00035"), "Error writing XPM file!"); return; } else // We now have the xpm file created on disk { chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, ps_filename ); } // If we're not using "gv", skip most of the code below and // go straight to the previewer program portion of the code. // if ( strstr(previewer_program,"gv") ) { // Convert it to a postscript file for printing. This // depends on the ImageMagick command "convert". // // Other options to try in the future: // -label // if ( print_auto_scale ) { // sprintf(scale, "-geometry 612x792 -page 612x792 "); // "Letter" size at 72 dpi // sprintf(scale, "-sample 612x792 -page 612x792 "); // "Letter" size at 72 dpi xastir_snprintf(scale, sizeof(scale), "-page 1275x1650+0+0 "); // "Letter" size at 150 dpi } else { scale[0] = '\0'; // Empty string } if ( print_in_monochrome ) { xastir_snprintf(mono, sizeof(mono), "-monochrome +dither " ); // Monochrome } else { xastir_snprintf(mono, sizeof(mono), "+dither "); // Color } if ( print_invert ) { xastir_snprintf(invert, sizeof(invert), "-negate " ); // Reverse Colors } else { invert[0] = '\0'; // Empty string } if (debug_level & 512) { fprintf(stderr,"Width: %ld\tHeight: %ld\n", screen_width, screen_height); } if ( print_rotated ) { xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " ); #ifdef HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "-landscape " ); #else // HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "--orientation=landscape " ); #endif // HAVE_OLD_GV } else if ( print_auto_rotation ) { // Check whether the width or the height of the // pixmap is greater. If width is greater than // height, rotate the image by 270 degrees. if (screen_width > screen_height) { xastir_snprintf(rotate, sizeof(rotate), "-rotate -90 " ); #ifdef HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "-landscape " ); #else // HAVE_OLD_GV xastir_snprintf(format, sizeof(format), "--orientation=landscape " ); #endif // HAVE_OLD_GV if (debug_level & 512) { fprintf(stderr,"Rotating\n"); } } else { rotate[0] = '\0'; // Empty string if (debug_level & 512) { fprintf(stderr,"Not Rotating\n"); } } } else { rotate[0] = '\0'; // Empty string if (debug_level & 512) { fprintf(stderr,"Not Rotating\n"); } } // Higher print densities require more memory and time // to process xastir_snprintf(density, sizeof(density), "-density %dx%d", print_resolution, print_resolution ); xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0013") ); statusline(temp,1); // Converting to Postscript... // Filters: // Point (ok at higher dpi's) // Box (not too bad) // Triangle (no) // Hermite (no) // Hanning (no) // Hamming (no) // Blackman (better but still not good) // Gaussian (no) // Quadratic (no) // Cubic (no) // Catrom (not too bad) // Mitchell (no) // Lanczos (no) // Bessel (no) // Sinc (not too bad) } #ifdef HAVE_CONVERT strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -filter Point "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, mono); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, invert); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, rotate); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, scale); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, density); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command ); } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't convert from XPM to PS!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't convert from XPM to PS!"); return; } #endif // HAVE_CONVERT chmod( ps_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // Delete temporary xpm file if ( !(debug_level & 512) ) { unlink( xpm_filename ); } if ( debug_level & 512 ) { fprintf(stderr,"Printing postscript file %s\n", ps_filename); } // Since we could be running SUID root, we don't want to be // calling "system" anyway. Several problems with it. // Bring up the postscript viewer strcpy(command, previewer_program); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, format); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, ps_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " &"); command[sizeof(command)-1] = '\0'; // Terminate string if ( debug_level & 512 ) { fprintf(stderr,"%s\n", command); } if (previewer_program[0] == '\0') { // fprintf(stderr,"\n\nPrint: No print previewer defined!\n\n\n"); popup_message_always(langcode("POPEM00035"), "No print previewer defined!"); return; } if ( system( command ) != 0 ) { // fprintf(stderr,"\n\nPrint: Couldn't bring up the postscript viewer!\n\n\n"); popup_message_always(langcode("POPEM00035"), "Couldn't bring up the viewer!"); return; } /* if ( !(debug_level & 512) ) unlink( ps_filename ); */ if ( debug_level & 512 ) { fprintf(stderr," Done printing.\n"); } } xastir_snprintf(temp, sizeof(temp), "%s", langcode("PRINT0014") ); statusline(temp,1); // Finished creating print file. //popup_message( langcode("PRINT0015"), langcode("PRINT0014") ); #endif // NO_XPM } /* * Auto_rotate * */ static void Auto_rotate( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_auto_rotation = atoi(which); print_rotated = 0; XmToggleButtonSetState(rotate_90, FALSE, FALSE); } else { print_auto_rotation = 0; } } /* * Rotate_90 * */ static void Rotate_90( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_rotated = atoi(which); print_auto_rotation = 0; XmToggleButtonSetState(auto_rotate, FALSE, FALSE); } else { print_rotated = 0; } } /* * Auto_scale * */ static void Auto_scale( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_auto_scale = atoi(which); } else { print_auto_scale = 0; } } /* * Monochrome * */ void Monochrome( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_in_monochrome = atoi(which); } else { print_in_monochrome = 0; } } /* * Invert * */ static void Invert( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { print_invert = atoi(which); } else { print_invert = 0; } } // Print_properties: Prints the drawing area to a PostScript file. // Provides various togglebuttons for configuring the "gv" previewer // only. // // Perhaps later: // 1) Select an area on the screen to print // 2) -label // void Print_properties( Widget w, XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_ok, button_cancel, sep, auto_scale, // paper_size, paper_size_data, scale, scale_data, blank_background, // res_label1, res_label2, res_x, res_y, monochrome, invert; Atom delw; // Get rid of the Print dialog Print_postscript_destroy_shell(w, print_postscript_dialog, NULL ); // If we're not using "gv", skip the entire dialog below and go // straight to the actual previewer function. // if ( !strstr(previewer_program,"gv") ) { Print_preview(w, NULL, NULL); return; } if (!print_properties_dialog) { begin_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" ); print_properties_dialog = XtVaCreatePopupShell(langcode("PRINT0001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Print_properties pane",xmPanedWindowWidgetClass, print_properties_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Print_properties form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); /* paper_size = XtVaCreateManagedWidget(langcode("PRINT0002"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(paper_size,FALSE); paper_size_data = XtVaCreateManagedWidget("Print_properties paper_size_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, paper_size, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(paper_size_data,FALSE); */ auto_rotate = XtVaCreateManagedWidget(langcode("PRINT0003"),xmToggleButtonWidgetClass,form, // XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, paper_size_data, // XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(auto_rotate,XmNvalueChangedCallback,Auto_rotate,"1"); rotate_90 = XtVaCreateManagedWidget(langcode("PRINT0004"),xmToggleButtonWidgetClass,form, // XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, paper_size_data, // XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, auto_rotate, XmNleftOffset,10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(rotate_90,XmNvalueChangedCallback,Rotate_90,"1"); auto_scale = XtVaCreateManagedWidget(langcode("PRINT0005"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(auto_scale,XmNvalueChangedCallback,Auto_scale,"1"); /* scale = XtVaCreateManagedWidget(langcode("PRINT0006"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, auto_scale, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(scale,FALSE); scale_data = XtVaCreateManagedWidget("Print_properties scale_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, scale, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(scale_data,FALSE); */ /* blank_background = XtVaCreateManagedWidget(langcode("PRINT0007"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, scale_data, XmNtopWidget, auto_rotate, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset ,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(blank_background,FALSE); */ monochrome = XtVaCreateManagedWidget(langcode("PRINT0008"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, // XmNtopWidget, blank_background, XmNtopWidget, auto_scale, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(monochrome,XmNvalueChangedCallback,Monochrome,"1"); invert = XtVaCreateManagedWidget(langcode("PRINT0016"),xmToggleButtonWidgetClass,form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, monochrome, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(invert,XmNvalueChangedCallback,Invert,"1"); /* res_label1 = XtVaCreateManagedWidget(langcode("PRINT0009"),xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(res_label1,FALSE); res_x = XtVaCreateManagedWidget("Print_properties resx_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_label1, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(res_x,FALSE); res_label2 = XtVaCreateManagedWidget("X",xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_x, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtSetSensitive(res_label2,FALSE); res_y = XtVaCreateManagedWidget("Print_properties res_y_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, invert, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, res_label2, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtSetSensitive(res_y,FALSE); */ sep = XtVaCreateManagedWidget("Print_properties sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, // XmNtopWidget, res_y, XmNtopWidget, invert, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // button_ok = XtVaCreateManagedWidget(langcode("PRINT0011"),xmPushButtonGadgetClass, form, button_ok = XtVaCreateManagedWidget(langcode("PRINT0010"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNrightOffset, 2, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNleftOffset, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Print_preview, NULL ); XtAddCallback(button_cancel, XmNactivateCallback, Print_properties_destroy_shell, print_properties_dialog); XmToggleButtonSetState(rotate_90,FALSE,FALSE); XmToggleButtonSetState(auto_rotate,TRUE,FALSE); if (print_auto_rotation) { XmToggleButtonSetState(auto_rotate, TRUE, TRUE); } else { XmToggleButtonSetState(auto_rotate, FALSE, TRUE); } if (print_rotated) { XmToggleButtonSetState(rotate_90, TRUE, TRUE); } else { XmToggleButtonSetState(rotate_90, FALSE, TRUE); } if (print_in_monochrome) { XmToggleButtonSetState(monochrome, TRUE, FALSE); } else { XmToggleButtonSetState(monochrome, FALSE, FALSE); } if (print_invert) { XmToggleButtonSetState(invert, TRUE, FALSE); } else { XmToggleButtonSetState(invert, FALSE, FALSE); } if (print_auto_scale) { XmToggleButtonSetState(auto_scale, TRUE, TRUE); } else { XmToggleButtonSetState(auto_scale, FALSE, TRUE); } // XmTextFieldSetString(paper_size_data,print_paper_size); end_critical_section(&print_properties_dialog_lock, "maps.c:Print_properties" ); pos_dialog(print_properties_dialog); delw = XmInternAtom(XtDisplay(print_properties_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(print_properties_dialog, delw, Print_properties_destroy_shell, (XtPointer)print_properties_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, print_properties_dialog); XtPopup(print_properties_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(print_properties_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(print_properties_dialog), XtWindow(print_properties_dialog)); } } // General print dialog. From here we can either print Postscript // files to the device selected in this dialog, or head off to a // print preview program that might allow us a variety of print // options. From here we should be able to set the print device // and the print preview program & path. // void Print_Postscript( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, form, button_print, button_cancel, sep, button_preview; Atom delw; if (!print_postscript_dialog) { begin_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" ); print_postscript_dialog = XtVaCreatePopupShell(langcode("PULDNFI015"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Print_postscript pane",xmPanedWindowWidgetClass, print_postscript_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); form = XtVaCreateWidget("Print_postscript form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); // "Direct to:" button_print = XtVaCreateManagedWidget(langcode("PRINT1001"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); printer_data = XtVaCreateManagedWidget("Print_Postscript printer_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, MAX_FILENAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_print, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // "Via Previewer:" button_preview = XtVaCreateManagedWidget(langcode("PRINT1002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_print, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); previewer_data = XtVaCreateManagedWidget("Print_Postscript previewer_data", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, MAX_FILENAME, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, button_print, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_preview, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Print_postscript sep", xmSeparatorGadgetClass,form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, button_preview, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); XtAddCallback(button_preview, XmNactivateCallback, Print_properties, NULL ); XtAddCallback(button_print, XmNactivateCallback, Print_window, NULL ); XtAddCallback(button_cancel, XmNactivateCallback, Print_postscript_destroy_shell, print_postscript_dialog); // Fill in the text fields from persistent variables out of the config file. XmTextFieldSetString(printer_data, printer_program); XmTextFieldSetString(previewer_data, previewer_program); end_critical_section(&print_postscript_dialog_lock, "maps.c:Print_Postscript" ); pos_dialog(print_postscript_dialog); delw = XmInternAtom(XtDisplay(print_postscript_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(print_postscript_dialog, delw, Print_postscript_destroy_shell, (XtPointer)print_postscript_dialog); XtManageChild(form); XtManageChild(pane); resize_dialog(form, print_postscript_dialog); XtPopup(print_postscript_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(print_postscript_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(print_postscript_dialog), XtWindow(print_postscript_dialog)); } } // Create png image (for use in web browsers??). Requires that "convert" // from the ImageMagick package be installed on the system. At the // point this thread is started, the XPM file has already been // created. We now create a .geo file to go with the .png file. // #ifndef NO_XPM static void* snapshot_thread(void * UNUSED(arg) ) { char xpm_filename[MAX_FILENAME]; char png_filename[MAX_FILENAME]; char geo_filename[MAX_FILENAME]; char kml_filename[MAX_FILENAME]; // filename for kml file that describes the png file in keyhole markup language char timestring[101]; // string representation of the time heard or the current time FILE *f; FILE *fk; // file handle for kml file time_t expire_time; #ifdef HAVE_CONVERT char command[MAX_FILENAME*2]; #endif // HAVE_CONVERT char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); // The pthread_detach() call means we don't care about the // return code and won't use pthread_join() later. Makes // threading more efficient. (void)pthread_detach(pthread_self()); xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/snapshot.xpm", temp_base_dir); xastir_snprintf(png_filename, sizeof(png_filename), "%s/snapshot.png", temp_base_dir); // Same for the .geo filename xastir_snprintf(geo_filename, sizeof(geo_filename), "%s/snapshot.geo", temp_base_dir); // Same for the .kml filename xastir_snprintf(kml_filename, sizeof(kml_filename), "%s/snapshot.kml", temp_base_dir); // Create a .geo file to match the new png image // Likewise for a matching .kml file f = fopen(geo_filename,"w"); // Overwrite whatever file // is there. fk = fopen(kml_filename,"w"); if (f == NULL || fk == NULL) { if (f==NULL) { fprintf(stderr,"Couldn't open %s\n",geo_filename); } if (fk==NULL) { fprintf(stderr,"Couldn't open %s\n",kml_filename); } } else { float lat1, long1, lat2, long2; long1 = f_NW_corner_longitude; lat1 = f_NW_corner_latitude; long2 = f_SE_corner_longitude; lat2 = f_SE_corner_latitude; // FILENAME world1.xpm // # x y lon lat // TIEPOINT 0 0 -180 90 // TIEPOINT 639 319 180 -90 // IMAGESIZE 640 320 // REFRESH 250 fprintf(f,"FILENAME snapshot.png\n"); fprintf(f,"# x y lon lat\n"); fprintf(f,"TIEPOINT 0 0 %8.5f %8.5f\n", long1, lat1); fprintf(f,"TIEPOINT %-4d %-4d %8.5f %8.5f\n", (int)screen_width-1, (int)screen_height-1, long2, lat2); fprintf(f,"IMAGESIZE %-4d %-4d\n", (int)screen_width, (int)screen_height); fprintf(f,"REFRESH 250\n"); fclose(f); // Write a matching kml file that describes the location of the snapshot on // the Earth's surface. // Another kml file pointing to the location of this file with a networklinkcontrol element // and an update element loaded into a kml application should be able to reload this file // at regular intervals. // See kml documentation of: // // // // // // // // http://www.example.com/cgi-bin/screenshot.kml // onExpire // // // // // // TODO: Calculate a suitable range and tilt for viewing the snapshot draped on the // underlying terrain. fprintf(fk,"\n"); fprintf(fk,"\n"); // Add an expire time matching the time when the next snapshot should // be produced, so that a network link with an onExpire refresh mode // will check for the next snapshot. expire_time = sec_now() + (time_t)(snapshot_interval * 60); if (get_w3cdtf_datetime(expire_time, timestring, False, False)) { if (strlen(timestring) > 0) { fprintf(fk," \n"); fprintf(fk," %s\n",timestring); fprintf(fk," \n"); } } fprintf(fk," \n"); fprintf(fk," XASTIR Snapshot from %s\n",my_callsign); fprintf(fk," 1\n"); fprintf(fk," \n"); fprintf(fk," Xastir snapshot\n"); fprintf(fk," 1\n"); // timestamp the overlay with the current time if (get_w3cdtf_datetime(sec_now(), timestring, True, True)) { if (strlen(timestring) > 0) { fprintf(fk," %s\n",timestring); fprintf(fk," Overlay shows screen visible for %s in Xastir at %s.\n",my_callsign,timestring); } } else { fprintf(fk," Overlay shows screen visible for %s in Xastir.\n",my_callsign); } fprintf(fk," \n"); fprintf(fk," %8.5f\n",f_center_longitude); fprintf(fk," %8.5f\n",f_center_latitude); fprintf(fk," 0\n"); fprintf(fk," 30350.36838438907\n"); // range in meters from viewer to lookat point fprintf(fk," 0\n"); // 0 is looking straight down fprintf(fk," clampToGround\n"); fprintf(fk," 0\n"); // 0 is north at top, 90 east at top fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," snapshot.png\n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," %8.5f\n",lat1); fprintf(fk," %8.5f\n",lat2); fprintf(fk," %8.5f\n",long2); fprintf(fk," %8.5f\n",long1); fprintf(fk," 0\n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk," \n"); fprintf(fk,"\n"); fclose(fk); chmod( geo_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); chmod( kml_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); } if ( debug_level & 512 ) { fprintf(stderr,"Convert %s ==> %s\n", xpm_filename, png_filename ); } #ifdef HAVE_CONVERT // Convert it to a png file. This depends upon having the // ImageMagick command "convert" installed. strcpy(command, CONVERT_PATH); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " -quality 100 -colors 256 "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, xpm_filename); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, " "); command[sizeof(command)-1] = '\0'; // Terminate string strcat(command, png_filename); command[sizeof(command)-1] = '\0'; // Terminate string if ( system( command ) != 0 ) { // We _may_ have had an error. Check errno to make // sure. if (errno) { fprintf(stderr, "%s\n", strerror(errno)); fprintf(stderr, "Failed to convert snapshot: %s -> %s\n", xpm_filename, png_filename); } else { fprintf(stderr, "System call return error: convert: %s -> %s\n", xpm_filename, png_filename); } } else { chmod( png_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); // // Delete temporary xpm file // unlink( xpm_filename ); if ( debug_level & 512 ) { fprintf(stderr," Done creating png.\n"); } } #endif // HAVE_CONVERT // Signify that we're all done and that another snapshot can // occur. doing_snapshot = 0; return(NULL); } #endif // NO_XPM // Starts a separate thread that creates a png image from the // current displayed image. // void Snapshot(void) { #ifndef NO_XPM pthread_t snapshot_thread_id; char xpm_filename[MAX_FILENAME]; int xpmretval; #endif // NO_XPM char temp_base_dir[MAX_VALUE]; get_user_base_dir("tmp", temp_base_dir, sizeof(temp_base_dir)); // Check whether we're already doing a snapshot if (doing_snapshot) { return; } // Time to take another snapshot? // New snapshot interval based on slider in Configure Timing // dialog (in minutes) if (sec_now() < (last_snapshot + (snapshot_interval * 60)) ) { return; } last_snapshot = sec_now(); // Set up timer for next time #ifndef NO_XPM if (debug_level & 512) { fprintf(stderr,"Taking Snapshot\n"); } doing_snapshot++; // Set up the XPM filename that we'll use xastir_snprintf(xpm_filename, sizeof(xpm_filename), "%s/snapshot.xpm", temp_base_dir); if ( debug_level & 512 ) { fprintf(stderr,"Creating %s\n", xpm_filename ); } // Create an XPM file from pixmap_final. if (chdir(temp_base_dir) != 0) { fprintf(stderr,"Couldn't chdir to %s directory for snapshot\n", temp_base_dir); return; } xpmretval=XpmWriteFileFromPixmap(XtDisplay(appshell), // Display *display "snapshot.xpm", // char *filename pixmap_final, // Pixmap pixmap (Pixmap)NULL, // Pixmap shapemask NULL ); if (xpmretval != XpmSuccess) { fprintf(stderr,"ERROR writing %s: %s\n", xpm_filename, XpmGetErrorString(xpmretval)); return; } chmod( xpm_filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ); //----- Start New Thread ----- // // Here we start a new thread. We'll communicate with the main // thread via global variables. Use mutex locks if there might // be a conflict as to when/how we're updating those variables. // if (pthread_create(&snapshot_thread_id, NULL, snapshot_thread, NULL)) { fprintf(stderr,"Error creating snapshot thread\n"); } else { // We're off and running with the new thread! } #endif // NO_XPM } // Function to remove double-quote characters and spaces that occur // outside of the double-quote characters. void clean_string(char *input) { char *i; char *j; //fprintf(stderr,"|%s|\t",input); // Remove any double quote characters i = index(input,'"'); // Find first quote character, if any if (i != NULL) { j = index(i+1,'"'); // Find second quote character, if any if (j != NULL) // Found two quote characters { j[0] = '\0'; // Terminate the string at the 2nd quote // Can't use strcpy here because it can't work with // overlapping strings. strcpy is a dangerous function // anyway and shouldn't be used. memmove(input, i+1, j-i); } else // We only found one quote character. What to do? { // fprintf(stderr,"clean_string: Only one quote found!\n"); } } //fprintf(stderr,"|%s|\n",input); // Remove leading/trailing spaces? } // Test map visibility (on screen) // // Input parameters are in Xastir coordinate system (fastest for us) // check_percentage: // 0 = don't check // 1 = check map size versus viewport scale. Return 0 if map // is too large/small (percentage-wise) to be displayed. // // Returns: MAP_NOT_VIS if map is _not_ visible // MAP_IS_VIS if map _is_ visible // // Xastir Coordinate System: // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Note that we already have map_visible() and map_visible_lat_lon() // routines. // enum map_onscreen_enum map_onscreen(long left, long right, long top, long bottom, int UNUSED(check_percentage) ) { enum map_onscreen_enum in_window = MAP_NOT_VIS; if (map_visible((unsigned long)bottom, (unsigned long)top, (unsigned long)left, (unsigned long)right)) { in_window = MAP_IS_VIS; //fprintf(stderr,"map_onscreen:Map is visible\n"); } #ifdef MAP_SCALE_CHECK // Check whether map is too large/small for our current scale? // Check whether the map extents are < XX% of viewscreen size // (both directions), or viewscreen is > XX% of map extents // (either direction). This will knock out maps that are too // large/small to be displayed at this zoom level. //WE7U if (in_window && check_percentage) { long map_x, map_y, view_x, view_y; float percentage = 0.04; map_x = right - left; if (map_x < 0) { map_x = 0; } map_y = bottom - top; if (map_y < 0) { map_y = 0; } view_x = max_NW_corner_longitude - NW_corner_longitude; if (view_x < 0) { view_x = 0; } view_y = max_NW_corner_latitude - NW_corner_latitude; if (view_y < 0) { view_y = 0; } //fprintf(stderr,"\n map_x: %d\n", map_x); //fprintf(stderr," map_y: %d\n", map_y); //fprintf(stderr,"view_x: %d\n", view_x); //fprintf(stderr,"view_y: %d\n", view_y); if ((map_x < (view_x * percentage )) && (map_y < (view_x * percentage))) { in_window = 0; // Send back "not-visible" flag fprintf(stderr,"map too small for view: %d%%\n",(int)(percentage * 100)); } // if ((view_x < (map_x * percentage)) && (view_y < (map_x * percentage))) { // in_window = 0; // Send back "not-visible" flag //fprintf(stderr,"view too small for map: %d%%\n",(int)(percentage * 100)); // } } #endif // MAP_SCALE_CHECK //fprintf(stderr,"map_onscreen returning %d\n", in_window); return (in_window); } // Function which checks whether a map is onscreen, but does so by // finding the map boundaries from the map index. The only input // parameter is the complete path/filename. // // Returns: MAP_NOT_VIS if map is _not_ visible // MAP_IS_VIS if map _is_ visible // MAP_NOT_INDEXED if the map is not in the index // enum map_onscreen_enum map_onscreen_index(char *filename) { unsigned long top, bottom, left, right; enum map_onscreen_enum onscreen = MAP_NOT_INDEXED; int max_zoom, min_zoom; int map_layer, draw_filled, usgs_drg, auto_maps; // Unused in this function if (index_retrieve(filename, &bottom, &top, &left, &right, &max_zoom, &min_zoom, &map_layer, &draw_filled, &usgs_drg, &auto_maps) ) { //fprintf(stderr, "Map found in index: %s\n", filename); // Map was in the index, check for visibility and scale // Check whether the map extents are < XX% of viewscreen // size (both directions), or viewscreen is > XX% of map // extents (either direction). This will knock out maps // that are too large/small to be displayed at this zoom // level. if (map_onscreen(left, right, top, bottom, 1)) { //fprintf(stderr, "Map found in index and onscreen: %s\n", filename); if (((max_zoom == 0) || ((max_zoom != 0) && (scale_y <= max_zoom))) && ((min_zoom == 0) || ((min_zoom != 0) && (scale_y >= min_zoom)))) { onscreen = MAP_IS_VIS; //fprintf(stderr,"Map in the zoom zone: %s\n",filename); } else { onscreen = MAP_NOT_VIS; //fprintf(stderr,"Map not in the zoom zone: %s\n",filename); } // Check whether the map extents are < XX% of viewscreen size (both // directions), or viewscreen is > XX% of map extents (either // direction). This will knock out maps that are too large/small to // be displayed at this zoom level. } else // Map is not visible { onscreen = MAP_NOT_VIS; //fprintf(stderr,"Map found in index but not onscreen: %s\n",filename); } } else // Map is not in the index { onscreen = MAP_NOT_INDEXED; //fprintf(stderr,"Map not found in index: %s\n",filename); } return(onscreen); } /********************************************************** * draw_map() * * Function which tries to figure out what type of map or * image file we're dealing with, and takes care of getting * it onto the screen. Calls other functions to deal with * .geo/.tif/.shp maps. * * If destination_pixmap == DRAW_NOT, then we'll not draw * the map anywhere, but we'll determine the map extents * and write them to the map index file. **********************************************************/ /* table of map drivers, selected by filename extension */ extern void draw_dos_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_palm_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); #ifdef HAVE_LIBSHP extern void draw_shapefile_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void clear_dbfawk_sigs(void); #endif /* HAVE_LIBSHP */ #ifdef HAVE_LIBGEOTIFF extern void draw_geotiff_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); #endif /* HAVE_LIBGEOTIFF */ extern void draw_geo_image_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_gnis_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); extern void draw_pop_map(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); struct { char *ext; enum {none=0, map, tif, geo, gnis, shp, pop} type; void (*func)(Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags); } map_driver[] = { {"map",map,draw_dos_map}, #ifdef HAVE_LIBGEOTIFF {"tif",tif,draw_geotiff_image_map}, #endif /* HAVE_LIBGEOTIFF */ {"geo",geo,draw_geo_image_map}, {"gnis",gnis,draw_gnis_map}, {"pop",pop,draw_pop_map}, #ifdef HAVE_LIBSHP {"shp",shp,draw_shapefile_map}, #endif /* HAVE_LIBSHP */ {NULL,none,NULL} }, *map_driver_ptr; void draw_map (Widget w, char *dir, char *filenm, alert_entry *alert, u_char alert_color, int destination_pixmap, map_draw_flags *draw_flags) { enum map_onscreen_enum onscreen; char *ext; char file[MAX_FILENAME]; if ((ext = get_map_ext(filenm)) == NULL) { return; } if (debug_level & 16) { fprintf(stderr,"draw_map: Searching for map driver\n"); } for (map_driver_ptr = map_driver; map_driver_ptr->ext; map_driver_ptr++) { if (strcasecmp(ext,map_driver_ptr->ext) == 0) { if (debug_level & 16) fprintf(stderr, "draw_map: Found map driver: %s: %d\n", ext, map_driver_ptr->type); break; /* found our map_driver */ } } if (map_driver_ptr->type == none) /* fall thru: unknown map driver */ { // Check whether we're indexing or drawing the map if ( (destination_pixmap != INDEX_CHECK_TIMESTAMPS) && (destination_pixmap != INDEX_NO_TIMESTAMPS) ) { // We're drawing, not indexing. Output a warning // message. fprintf(stderr,"*** draw_map: Unknown map type: %s ***\n", filenm); } else // We're indexing { if (debug_level & 16) { fprintf(stderr,"draw_map: No map driver found\n"); } } return; } onscreen = map_onscreen_index(filenm); // Check map index // Check whether we're indexing or drawing the map if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { // We're indexing maps if (onscreen != MAP_NOT_INDEXED) // We already have an index entry for this map. // This is where we pick up a big speed increase: // Refusing to index a map that's already indexed. { return; // Skip it. } } else // We're drawing maps { // See if map is visible. If not, skip it. if (onscreen == MAP_NOT_VIS) // Map is not visible, skip it. { //fprintf(stderr,"map not visible\n"); if (alert) { alert->flags[on_screen] = 'N'; } return; } } xastir_snprintf(file, sizeof(file), "%s/%s", dir, filenm); // Used for debugging. If we get a segfault on a map, this is // often the only way of finding out which map file we can't // handle. if (debug_level & 16) { fprintf(stderr,"draw_map: %s\n",file); } /* XXX - aren't alerts just shp maps? Why was there special case code? */ if (map_driver_ptr->func) { map_driver_ptr->func(w, dir, filenm, alert, alert_color, destination_pixmap, draw_flags); } XmUpdateDisplay (XtParent (da)); } // End of draw_map() static void index_update_directory(char *directory); static void index_update_accessed(char *filename); ///////////////////////////////////////////////////////////////////// // map_search() // // Function which recurses through map directories, finding map // files. It's called from load_auto_maps and load_alert_maps. If // a map file is found, it is drawn. We can also call this function // in indexing mode rather than draw mode, specified by the // destination_pixmap parameter. // // If alert == NULL, we looking for a regular map file to draw. // If alert != NULL, we have a weather alert to draw. // // For alert maps, we need to do things a bit differently, as there // should be only a few maps that contain all of the alert maps, and we // can compute which map some of them might be in. We need to fill in // the alert structure with the filename that alert is found in. // For alerts we're not drawing the maps, we're just computing the // full filename for the alert and filling that struct field in. // // The "warn" parameter specifies whether to warn the operator about // the alert on the console as well. If it was received locally or // via local RF, then the answer is yes. The severe weather may be // nearby. // // We have the timestamp of the map_index.sys file stored away in // the global: time_t map_index_timestamp; // Use that timestamp to compare the map file or GEO file timestamps // to. Re-index the map if map_index_timestamp is older. // ///////////////////////////////////////////////////////////////////// static void map_search (Widget w, char *dir, alert_entry * alert, int *alert_count,int warn, int destination_pixmap) { struct dirent *dl = NULL; DIR *dm; char fullpath[MAX_FILENAME]; struct stat nfile; // const time_t *ftime; // char this_time[40]; char *ptr; char *map_dir; int map_dir_length; map_draw_flags mdf; // We'll use the weather alert directory if it's an alert map_dir = alert ? ALERT_MAP_DIR : SELECTED_MAP_DIR; map_dir_length = (int)strlen (map_dir); if (alert) // We're doing weather alerts { // First check whether the alert->filename variable is filled // in. If so, we've already found the file and can just display // that shape in the file if (alert->filename[0] == '\0') // No filename in struct, so will have { // to search for the shape in the files. switch (alert->title[3]) { case 'F': // 'F' in 4th char means fire alert // Use fire alert file fz_?????? //fprintf(stderr,"%c:Fire Alert file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "fz"); break; case 'C': // 'C' in 4th char means county // Use County file c_?????? //fprintf(stderr,"%c:County file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "c_"); break; case 'A': // 'A' in 4th char means county warning area // Use County warning area w_????? //fprintf(stderr,"%c:County warning area file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "w_"); break; case 'Z': // Zone, coastal or offshore marine zone file z_????? or mz?????? or oz?????? // oz: ANZ081-086,088,PZZ081-085 // mz: AM,AN,GM,LC,LE,LH,LM,LO,LS,PH,PK,PM,PS,PZ,SL // z_: All others if (strncasecmp(alert->title,"AM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"AN",2) == 0) { // Need to check for Z081-Z086, Z088, if so use // oz??????, else use mz?????? if ( (strncasecmp(&alert->title[3],"Z081",4) == 0) || (strncasecmp(&alert->title[3],"Z082",4) == 0) || (strncasecmp(&alert->title[3],"Z083",4) == 0) || (strncasecmp(&alert->title[3],"Z084",4) == 0) || (strncasecmp(&alert->title[3],"Z085",4) == 0) || (strncasecmp(&alert->title[3],"Z086",4) == 0) || (strncasecmp(&alert->title[3],"Z088",4) == 0) ) { //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "oz"); } else { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } } else if (strncasecmp(alert->title,"GM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LC",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LE",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LH",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LO",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"LS",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PH",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PK",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PM",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PS",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else if (strncasecmp(alert->title,"PZ",2) == 0) { // Need to check for PZZ081-085, if so use oz??????, else use mz?????? if ( (strncasecmp(&alert->title[3],"Z081",4) == 0) || (strncasecmp(&alert->title[3],"Z082",4) == 0) || (strncasecmp(&alert->title[3],"Z083",4) == 0) || (strncasecmp(&alert->title[3],"Z084",4) == 0) || (strncasecmp(&alert->title[3],"Z085",4) == 0) ) { //fprintf(stderr,"%c:Offshore marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "oz"); } else { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } } else if (strncasecmp(alert->title,"SL",2) == 0) { //fprintf(stderr,"%c:Coastal marine zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "mz"); } else { // Must be regular zone file instead of coastal // marine zone or offshore marine zone. //fprintf(stderr,"%c:Zone file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "z_"); } break; default: // VK2XJG // This section could most likely be moved so that it's not called as part of the default, but in order // to get the shapefiles for BOM working this was the best spot at the time... // Australian BOM alerts use the following shapefiles: // PW = Public Warning = gfe_public_weather // MW = Coastal Waters = gfe_coastal_waters // CW = Coastal Waters Warnings = gfe_coastal_waters_warnings // FW = Fire Weather = gfe_fire_weather // ME = Metro Effects = gfe_metro_areas // Note - Need to cater for both 2 and 3 character state designators // Shapefile filenames are static - there is no datestamp in the filename. if ((strncasecmp(&alert->title[4],"MW",2) == 0) || (strncasecmp(&alert->title[3],"MW",2) == 0)) { //fprintf(stderr,"%c:BOM Coastal Waters file\n",alert->title[4]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_coastal_waters.shp"); } else if ((strncasecmp(&alert->title[4],"CW",2) == 0) || (strncasecmp(&alert->title[3],"CW",2) == 0)) { //fprintf(stderr,"%c:BOM Coastal waters warning file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_coastal_waters_warnings.shp"); } else if ((strncasecmp(&alert->title[4],"PW",2) == 0) || (strncasecmp(&alert->title[3],"PW",2) == 0)) { //fprintf(stderr,"%c:BOM Public Weather file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_public_weather.shp"); } else if ((strncasecmp(&alert->title[4],"FW",2) == 0) || (strncasecmp(&alert->title[3],"FW",2) == 0)) { //fprintf(stderr,"%c:BOM Fire Weather file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_fire_weather.shp"); } else if ((strncasecmp(&alert->title[4],"ME",2) == 0) || (strncasecmp(&alert->title[3],"ME",2) == 0)) { //fprintf(stderr,"%c:BOM Metro Areas file\n",alert->title[3]); xastir_snprintf(alert->filename, sizeof(alert->filename), "gfe_metro_areas.shp"); } // Unknown type //fprintf(stderr,"%c:Can't match weather warning to a Shapefile:%s\n",alert->title[3],alert->title); break; } // fprintf(stderr,"%s\t%s\t%s\n",alert->activity,alert->alert_status,alert->title); //fprintf(stderr,"File: %s\n",alert->filename); } // NOTE: Need to skip this part if we have a full filename. if (alert->filename[0]) // We have at least a partial filename { int done = 0; if (strlen(alert->filename) > 3) { done++; // We already have a filename } if (!done) // We don't have a filename yet { // Look through the warning directory to find a match for // the first few characters that we already figured out. // This is designed so that we don't need to know the exact // filename, but only the lead three characters in order to // figure out which shapefile to use. dm = opendir (dir); if (!dm) // Couldn't open directory { xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir); // If local alert, warn the operator via the // console as well. if (warn) { perror (fullpath); } } else // We could open the directory just fine { while ( (dl = readdir(dm)) && !done ) { int i; // Check the file/directory name for control // characters for (i = 0; i < (int)strlen(dl->d_name); i++) { // Dump out a warning if control // characters other than LF or CR are // found. if ( (dl->d_name[i] != '\n') && (dl->d_name[i] != '\r') && (dl->d_name[i] < 0x20) ) { fprintf(stderr,"\nmap_search: Found control char 0x%02x in alert file/alert directory name. Line was:\n", dl->d_name[i]); fprintf(stderr,"%s\n",dl->d_name); } /* // This part might not work 'cuz we'd be changing a memory area that // we might have only read access to. Check this. if (dl->d_name[i] < 0x20) { // Terminate string at any control character dl->d_name[i] = '\0'; } */ } xastir_snprintf(fullpath, sizeof(fullpath), "%s%s", dir, dl->d_name); /*fprintf(stderr,"FULL PATH %s\n",fullpath); */ if (stat (fullpath, &nfile) == 0) { // ftime = (time_t *)&nfile.st_ctime; switch (nfile.st_mode & S_IFMT) { case (S_IFDIR): // It's a directory, skip it break; case (S_IFREG): // It's a file, check it /*fprintf(stderr,"FILE %s\n",dl->d_name); */ // Here we look for a match for the // first 2 characters of the filename. // if (strncasecmp(alert->filename,dl->d_name,2) == 0) { // We have a match for the // first few characters. // Check that last three are // "shp" //fprintf(stderr,"%s\n",fullpath); if ( (dl->d_name[strlen(dl->d_name)-3] == 's' || dl->d_name[strlen(dl->d_name)-3] == 'S') && (dl->d_name[strlen(dl->d_name)-2] == 'h' || dl->d_name[strlen(dl->d_name)-2] == 'H') && (dl->d_name[strlen(dl->d_name)-1] == 'p' || dl->d_name[strlen(dl->d_name)-1] == 'P') ) { // We have an exact match. // Save the filename in the alert memcpy(alert->filename, dl->d_name, sizeof(alert->filename)); // Terminate string alert->filename[sizeof(alert->filename)-1] = '\0'; done++; //fprintf(stderr,"%s\n",dl->d_name); } } break; default: // Not dir or file, skip it break; } } } } (void)closedir (dm); } if (done) // We found a filename match for the alert { // Go draw the weather alert (kind'a) //WE7U mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"map_search: calling draw_map for an alert\n"); } draw_map (w, dir, // Alert directory alert->filename, // Shapefile filename alert, -1, // Signifies "DON'T DRAW THE SHAPE" destination_pixmap, &mdf ); if (debug_level & 16) { fprintf(stderr,"map_search: returned from draw_map\n"); } } else // No filename found that matches the first two { // characters that we already computed. // // Need code here // } } else // Still no filename for the weather alert. { // Output an error message? // // Need code here // } } // MAPS, not alerts else // We're doing regular maps, not weather alerts { time_t map_timestamp; dm = opendir (dir); if (!dm) // Couldn't open directory { xastir_snprintf(fullpath, sizeof(fullpath), "aprsmap %s", dir); if (warn) { perror (fullpath); } } else { int count = 0; while ((dl = readdir (dm))) { int i; // Check the file/directory name for control // characters for (i = 0; i < (int)strlen(dl->d_name); i++) { // Dump out a warning if control characters // other than LF or CR are found. if ( (dl->d_name[i] != '\n') && (dl->d_name[i] != '\r') && (dl->d_name[i] < 0x20) ) { fprintf(stderr,"\nmap_search: Found control char 0x%02x in map file/map directory name. Line was:\n", dl->d_name[i]); fprintf(stderr,"%s\n",dl->d_name); } /* // This part might not work 'cuz we'd be changing a memory area that // we might have only read access to. Check this. if (dl->d_name[i] < 0x20) { // Terminate string at any control character dl->d_name[i] = '\0'; } */ } xastir_snprintf(fullpath, sizeof(fullpath), "%s/%s", dir, dl->d_name); //fprintf(stderr,"FULL PATH %s\n",fullpath); if (stat (fullpath, &nfile) == 0) { // ftime = (time_t *)&nfile.st_ctime; switch (nfile.st_mode & S_IFMT) { case (S_IFDIR): // It's a directory, recurse //fprintf(stderr,"file %c letter %c\n",dl->d_name[0],letter); if ((strcmp (dl->d_name, ".") != 0) && (strcmp (dl->d_name, "..") != 0)) { //fprintf(stderr,"FULL PATH %s\n",fullpath); // If we're indexing, throw the // directory into the map index as // well. if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) || (destination_pixmap == INDEX_NO_TIMESTAMPS) ) { char temp_dir[MAX_FILENAME]; // Drop off the base part of the // path for the indexing, // usually // "/usr/local/share/xastir/maps". // Add a '/' to the end. xastir_snprintf(temp_dir, sizeof(temp_dir), "%s/", &fullpath[map_dir_length+1]); // Add the directory to the // in-memory map index. index_update_directory(temp_dir); } // xastir_snprintf(this_time, // sizeof(this_time), // "%s", // ctime(ftime)); map_search(w, fullpath, alert, alert_count, warn, destination_pixmap); } break; case (S_IFREG): // It's a file, draw the map /*fprintf(stderr,"FILE %s\n",dl->d_name); */ // Get the last-modified timestamp for the map file //map_timestamp = (time_t)nfile.st_mtime; map_timestamp = (time_t)( (nfile.st_mtime>nfile.st_ctime) ? nfile.st_mtime : nfile.st_ctime ); // Check whether we're doing indexing or // map drawing. If indexing, we only // want to index if the map timestamp is // newer than the index timestamp. if (destination_pixmap == INDEX_CHECK_TIMESTAMPS || destination_pixmap == INDEX_NO_TIMESTAMPS) { // We're doing indexing, not map drawing char temp_dir[MAX_FILENAME]; // Drop off the base part of the // path for the indexing, usually // "/usr/local/share/xastir/maps". xastir_snprintf(temp_dir, sizeof(temp_dir), "%s", &fullpath[map_dir_length+1]); // Update the "accessed" // variable in the record index_update_accessed(temp_dir); // Note: This is not as efficient as it should be, as we're looking // through the in-memory map index here just to update the // "accessed" variable, then in some cases looking through it again // in the next section for updated maps, or if we're ignoring // timestamps while indexing. Looking through a linear linked list // too many times overall. if ( (destination_pixmap == INDEX_CHECK_TIMESTAMPS) && (map_timestamp < map_index_timestamp) ) { // Map is older than index _and_ // we're supposed to check // timestamps. count++; break; // Skip indexing this file } else // Map is newer or we're ignoring timestamps. { // We'll index the map if (debug_level & 16) { fprintf(stderr,"Indexing map: %s\n",fullpath); } } } // Check whether the file is in a subdirectory if (strncmp (fullpath, map_dir, (size_t)map_dir_length) != 0) { if (debug_level & 16) { fprintf(stderr,"Calling draw_map\n"); } mdf.draw_filled=1; mdf.usgs_drg=0; draw_map (w, dir, dl->d_name, alert ? &alert[*alert_count] : NULL, '\0', destination_pixmap, &mdf ); if (debug_level & 16) { fprintf(stderr,"Returned from draw_map\n"); } if (alert_count && *alert_count) { (*alert_count)--; } } else { // File is in the main map directory // Find the '/' character for (ptr = &fullpath[map_dir_length]; *ptr == '/'; ptr++) ; mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"Calling draw_map\n"); } draw_map (w, map_dir, ptr, alert ? &alert[*alert_count] : NULL, '\0', destination_pixmap, &mdf ); if (alert_count && *alert_count) { (*alert_count)--; } } count++; break; default: break; } } } if (debug_level & 16) { fprintf(stderr,"Number of maps queried: %d\n", count); } (void)closedir (dm); } } } // List pointer for the map index linked list. map_index_record *map_index_head = NULL; // Might wish to have another variable in the index which is used to // record that a file has been indexed recently. This could be used // to prune old entries out of the index if a full indexing didn't // touch a file entry. Could also delete an entry from the index // if/when a file can't be opened? // Function to dissect and free all of the records in a map index // linked list, leaving it totally empty. // static void free_map_index(map_index_record *index_list_head) { map_index_record *current; map_index_record *temp; current = index_list_head; while (current != NULL) { temp = current; if (current->XmStringPtr != NULL) { XmStringFree(current->XmStringPtr); } current = current->next; free(temp); } index_list_head = NULL; } // Function to copy just the properties fields from the backup map // index to the primary index. Must match each record before // copying. Once it's done, it frees the backup map index. // static void map_index_copy_properties(map_index_record *primary_index_head, map_index_record *backup_index_head) { map_index_record *primary; map_index_record *backup; backup = backup_index_head; // Walk the backup list, comparing the filename field with the // primary list. When a match is found, copy just the // Properties fields (map_layer/draw_filled/auto_maps/selected) // across to the primary record. // while (backup != NULL) { int done = 0; primary = primary_index_head; while (!done && primary != NULL) { if (strcmp(primary->filename, backup->filename) == 0) // If match { if (debug_level & 16) { fprintf(stderr,"Match: %s\t%s\n", primary->filename, backup->filename); } // Copy the Properties across primary->max_zoom = backup->max_zoom; primary->min_zoom = backup->min_zoom; primary->map_layer = backup->map_layer; primary->draw_filled = backup->draw_filled; primary->usgs_drg = backup->usgs_drg; primary->auto_maps = backup->auto_maps; primary->selected = backup->selected; // Done copying this backup record. Go on to the // next. Skip the rest of the primary list for this // iteration. done++; } else // No match, walk the primary list looking for one. { primary = primary->next; } } // Walk the backup list backup = backup->next; } // We're done copying. Free the backup list. free_map_index(backup_index_head); } // Function used to add map directories to the in-memory map index. // Causes an update of the index list in memory. Input Records are // inserted in alphanumerical order. We mark directories in the // index with a '/' on the end of the name, and zero entries for // top/bottom/left/right. // The input directory to this routine MUST have a '/' character on // the end of it. This is how we differentiate directories from // files in the list. static void index_update_directory(char *directory) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; int i; //fprintf(stderr,"index_update_directory: %s\n", directory ); // Check for initial bad input if ( (directory == NULL) || (directory[0] == '\0') || (directory[strlen(directory) - 1] != '/') || ( (directory[1] == '/') && (strlen(directory) == 1)) ) { fprintf(stderr,"index_update_directory: Bad input: %s\n",directory); return; } // Make sure there aren't any weird characters in the directory // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(directory); i++ ) { // Change any control characters to '\0' chars if (directory[i] < 0x20) { fprintf(stderr,"\nindex_update_directory: Found control char 0x%02x in map file/map directory name:\n%s\n", directory[i], directory); directory[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if ( (directory[0] == '\0') || (directory[strlen(directory) - 1] != '/') || ( (directory[1] == '/') && (strlen(directory) == 1))) { fprintf(stderr,"index_update_directory: Bad input: %s\n",directory); return; } //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Search for a matching directory name in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n", // current->filename, directory); test = strcmp(current->filename, directory); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",directory); temp_record = current; done++; // Exit loop, "current" points to found record } else if (test > 0) // Found a string past us in the { // alphabet. Insert ahead of this // last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,directory); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",directory); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else // Insert between "previous" and "current" { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory); // Fill in some default values for the new record. temp_record->selected = 0; temp_record->auto_maps = 0; temp_record->XmStringPtr = NULL; //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, add a record to { // the end of the list. "previous" points to // the last record in the list or NULL (empty // list). //fprintf(stderr,"Not Found: Adding an index record for %s\n",directory); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",directory); } //fprintf(stderr,"Adding:%d:%s\n",strlen(directory),directory); // Fill in some default values for the new record. temp_record->selected = 0; temp_record->auto_maps = 0; temp_record->XmStringPtr = NULL; } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",directory); temp_record->bottom = 0; temp_record->top = 0; temp_record->left = 0; temp_record->right = 0; temp_record->accessed = 1; temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = 0; temp_record->draw_filled = 0; temp_record->usgs_drg = 2; } // Function called by the various draw_* functions when in indexing // mode. Causes an update of the index list in memory. Input // parameters are in the Xastir coordinate system due to speed // considerations. Records are inserted in alphanumerical order. void index_update_xastir(char *filename, unsigned long bottom, unsigned long top, unsigned long left, unsigned long right, int default_map_layer) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') || (filename[strlen(filename) - 1] == '/') ) { fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_xastir: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_xastir: Bad input: %s\n",filename); return; } //fprintf(stderr,"index_update_xastir: (%lu,%lu)\t(%lu,%lu)\t%s\n", // bottom, top, left, right, filename ); //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",filename); temp_record = current; done++; // Exit the while loop } else if (test > 0) // Found a string past us in the { // alphabet. Insert ahead of this // last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,filename); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, add a { // record to the end of the list //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); temp_record->bottom = bottom; temp_record->top = top; temp_record->left = left; temp_record->right = right; temp_record->accessed = 1; } // Function called by the various draw_* functions when in indexing // mode. Causes an update of the index list in memory. Input // parameters are in lat/long, which are converted to Xastir // coordinates for storage due to speed considerations. Records are // inserted in alphanumerical order. void index_update_ll(char *filename, double bottom, double top, double left, double right, int default_map_layer) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; map_index_record *temp_record = NULL; int done = 0; unsigned long temp_left, temp_right, temp_top, temp_bottom; int ok; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') || (filename[strlen(filename) - 1] == '/') ) { fprintf(stderr,"index_update_ll: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_ll: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_ll: Bad input: %s\n",filename); return; } //fprintf(stderr,"index_update_ll: (%15.10g,%15.10g)\t(%15.10g,%15.10g)\t%s\n", // bottom, top, left, right, filename ); //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n",filename); temp_record = current; done++; // Exit the while loop } else if (test > 0) { // Found a string past us in the alphabet. Insert ahead // of this last record. //fprintf(stderr,"\n%s\n%s\n",current->filename,filename); //fprintf(stderr,"Not Found: Inserting an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); if (current == map_index_head) // Start of list! { // Insert new record at head of list temp_record->next = map_index_head; map_index_head = temp_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert new record before "current" previous->next = temp_record; temp_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } //current = current->next; done++; } else // Haven't gotten to the correct insertion point yet { previous = current; // Save ptr to last record current = current->next; } } if (!done) // Matching record not found, didn't find alpha { // chars after our string either, add record to // the end of the list. //fprintf(stderr,"Not Found: Adding an index record for %s\n",filename); temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); temp_record->next = NULL; if (previous == NULL) // Empty list { map_index_head = temp_record; //fprintf(stderr,"First record in new list\n"); } else // Else at end of list { previous->next = temp_record; //fprintf(stderr,"Adding to end of list: %s\n",filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record //WE7U // Here's where we might look at the file extension and assign // default map_layer fields based on that. temp_record->max_zoom = 0; temp_record->min_zoom = 0; temp_record->map_layer = default_map_layer; temp_record->selected = 0; temp_record->XmStringPtr = NULL; if ( strstr(filename,".geo") || strstr(filename,".GEO") || strstr(filename,".Geo")) { temp_record->auto_maps = 0; } else { temp_record->auto_maps = 1; } if ( strstr(filename,".shp") || strstr(filename,".SHP") || strstr(filename,".Shp") ) { temp_record->draw_filled = 2; // Auto } else { temp_record->draw_filled = 0; // No-Fill } if ( strstr(filename,".tif") || strstr(filename,".TIF") || strstr(filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } // Update the values. By this point we have a struct to fill // in, whether it's a new or old struct doesn't matter. Convert // the values from lat/long to Xastir coordinate system. // In this case the struct uses MAX_FILENAME for the length of // the field, so the below statement is ok. xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); ok = convert_to_xastir_coordinates( &temp_left, &temp_top, (float)left, (float)top); if (!ok) { fprintf(stderr,"%s\n\n",filename); } ok = convert_to_xastir_coordinates( &temp_right, &temp_bottom, (float)right, (float)bottom); if (!ok) { fprintf(stderr,"%s\n\n",filename); } temp_record->bottom = temp_bottom; temp_record->top = temp_top; temp_record->left = temp_left; temp_record->right = temp_right; temp_record->accessed = 1; } // Function which will update the "accessed" variable on either a // directory or a filename in the map index. static void index_update_accessed(char *filename) { map_index_record *current = map_index_head; int done = 0; int i; // Check for initial bad input if ( (filename == NULL) || (filename[0] == '\0') ) { fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for control characters // and convert them to string-end characters. for ( i = 0; i < (int)strlen(filename); i++ ) { // Change any control characters to '\0' chars if (filename[i] < 0x20) { fprintf(stderr,"\nindex_update_accessed: Found control char 0x%02x in map file/map directory name:\n%s\n", filename[i], filename); filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (filename[0] == '\0') { fprintf(stderr,"index_update_accessed: Bad input: %s\n",filename); return; } // Skip dbf and shx map extensions. Really should make this // case-independent... if ( strstr(filename,"shx") || strstr(filename,"dbf") || strstr(filename,"SHX") || strstr(filename,"DBF") ) { return; } // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n",current->filename,filename); test = strcmp(current->filename,filename); if (test == 0) { // Found a match! //fprintf(stderr,"Found: Updating entry for %s\n\n",filename); current->accessed = 1; done++; // Exit the while loop } else // Haven't gotten to the correct insertion point yet { current = current->next; } } } // Function called by map_onscreen_index() // // This function returns: // 0 if the map isn't in the index // 1 if the map is listed in the index // Four parameters listing the extents of the map // // The updated parameters are in the Xastir coordinate system for // speed reasons. // // Note that the index retrieval could be made much faster by // storing the data in a hash instead of a linked list. This is // just an initial implementation to see what speedups are possible. // Hashing might be next. --we7u // // Note that since we've alphanumerically ordered the list, we can // stop when we hit something after this filename in the alphabet. // It speeds things up quite a bit. // // In order to speed this up slightly for the general case, we'll // assume that we'll be fetching indexes in alphabetical order, as // that's how we store them everywhere. We'll save the last map // index pointer away and start searching there each time. That // should make all but the _first_ lookup much faster. // map_index_record *last_index_lookup = NULL; int index_retrieve(char *filename, unsigned long *bottom, unsigned long *top, unsigned long *left, unsigned long *right, int *max_zoom, int *min_zoom, int *map_layer, int *draw_filled, int *usgs_drg, int *auto_maps) { map_index_record *current; int status = 0; if ( (filename == NULL) || (strlen(filename) >= MAX_FILENAME) ) { return(status); } // Attempt to start where we left off last time if (last_index_lookup != NULL) { current = last_index_lookup; } else { current = map_index_head; //fprintf(stderr,"Start at beginning:%s\t", filename); } // Check to see if we're past the correct area. If so, start at // the beginning of the index instead. // if (current && ((current->filename[0] > filename[0]) || (strcmp(current->filename, filename) > 0))) { // // We're past the correct point. Start at the beginning of // the list unless we're already there. // if (current != map_index_head) { current = map_index_head; } //fprintf(stderr,"Start at beginning:%s\t", filename); } // // Search for a matching filename in the linked list. // // Check the first char only. Loop until they match or go past. // This is our high-speed method to get to the correct search // area. // while (current && (current->filename[0] < filename[0])) { // Save the pointer away for next time. There's a reason we // save it before we increment the counter: For "z" weather // alerts, it's nice to have it scan just the very last of // the list before it fails, instead of scanning the entire // list each time and then failing. Need to find out why // weather alerts always fail, and therefore why this // routine gets called every time for them. // last_index_lookup = current; current = current->next; //fprintf(stderr,"1"); } // Stay in this loop while the first char matches. This is our // active search area. // while (current && (current->filename[0] == filename[0])) { int result; // Check the entire string result = strcmp(current->filename, filename); if (result == 0) { // Found a match! status = 1; *bottom = current->bottom; *top = current->top; *left = current->left; *right = current->right; *max_zoom = current->max_zoom; *min_zoom = current->min_zoom; *map_layer = current->map_layer; *draw_filled = current->draw_filled; *usgs_drg = current->usgs_drg; *auto_maps = current->auto_maps; //fprintf(stderr," Found it\n"); return(status); } else if (result > 0) { // We're past it in the index. We didn't find it in the // index. //fprintf(stderr," Did not find1\n"); return(status); } else // Not found yet, look at the next { // Save the pointer away for next time. There's a // reason we save it before we increment the counter: // For "z" weather alerts, it's nice to have it scan // just the very last of the list before it fails, // instead of scanning the entire list each time and // then failing. Need to find out why weather alerts // always fail, and therefore why this routine gets // called every time for them. // last_index_lookup = current; current = current->next; //fprintf(stderr,"2"); } } // We're past the correct search area and didn't find it. //fprintf(stderr," Did not find2\n"); return(status); } // Saves the linked list pointed to by map_index_head to a file. // Keeps the same order as the memory linked list. Delete records // in the in-memory linked list for which the "accessed" variable is // 0 or filename is empty. // void index_save_to_file(void) { FILE *f; map_index_record *current; // map_index_record *last; char out_string[MAX_FILENAME*2]; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); //fprintf(stderr,"Saving map index to file\n"); f = fopen( map_index_path, "w" ); if (f == NULL) { fprintf(stderr,"Couldn't create/update map index file: %s\n", map_index_path ); return; } current = map_index_head; // last = current; while (current != NULL) { int i; // Make sure there aren't any weird characters in the // filename that might cause problems later. Look for // control characters and convert them to string-end // characters. for ( i = 0; i < (int)strlen(current->filename); i++ ) { // Change any control characters to '\0' chars if (current->filename[i] < 0x20) { fprintf(stderr,"\nindex_save_to_file: Found control char 0x%02x in map name:\n%s\n", current->filename[i], current->filename); current->filename[i] = '\0'; // Terminate it here } } // Save to file if filename non-blank and record has the // accessed field set. if ( (current->filename[0] != '\0') && (current->accessed != 0) ) { // Write each object out to the file as one // comma-delimited line xastir_snprintf(out_string, sizeof(out_string), "%010lu,%010lu,%010lu,%010lu,%05d,%01d,%01d,%01d,%05d,%05d,%s\n", current->bottom, current->top, current->left, current->right, current->map_layer, current->draw_filled, current->usgs_drg, current->auto_maps, current->max_zoom, current->min_zoom, current->filename); if (fprintf(f,"%s",out_string) < (int)strlen(out_string)) { // Failed to write fprintf(stderr,"Couldn't write objects to map index file: %s\n", map_index_path ); current = NULL; // All done } // Set up pointers for next loop iteration // last = current; if (current != NULL) { current = current->next; } } else { // last = current; current = current->next; } /* //WE7U else { // Delete this record from our list! It's a record // for a map file that doesn't exist in the // filesystem anymore. if (last == current) { // We're at the head of the list map_index_head = current->next; // Remember to free the XmStringPtr if we use this bit of code // again. free(current); // Set up pointers for next loop iteration current = map_index_head; last = current; } else { // Not the first record in the list map_index_record *gone; gone = current; // Save ptr to record we wish to delete last->next = current->next; // Unlink from list // Remember to free the XmStringPtr if we use this bit of code // again. free(gone); // Set up pointers for next loop iteration // "last" is still ok current = last->next; } } */ } (void)fclose(f); } // This function is currently not used. // // Function used to add map directories/files to the in-memory map // index. Causes an update of the index list in memory. Input // records are inserted in alphanumerical order. This function is // called from the index_restore_from_file() function below. When // this function is called the new record has all of the needed // information in it. // /* static void index_insert_sorted(map_index_record *new_record) { map_index_record *current = map_index_head; map_index_record *previous = map_index_head; int done = 0; int i; //fprintf(stderr,"index_insert_sorted: %s\n", new_record->filename ); // Check for bad input. if (new_record == NULL) { fprintf(stderr,"index_insert_sorted: Bad input.\n"); return; } // Make sure there aren't any weird characters in the filename // that might cause problems later. Look for any control // characters and convert them to string-end characters. for ( i = 0; i < (int)strlen(new_record->filename); i++ ) { if (new_record->filename[i] < 0x20) { fprintf(stderr,"\nindex_insert_sorted: Found control char 0x%02x in map name:\n%s\n", new_record->filename[i], new_record->filename); new_record->filename[i] = '\0'; // Terminate it here } } // Check if the string is _now_ bogus if (new_record->filename[0] == '\0') { fprintf(stderr,"index_insert_sorted: Bad input.\n"); return; } //if (map_index_head == NULL) // fprintf(stderr,"Empty list\n"); // Search for a matching filename in the linked list while ((current != NULL) && !done) { int test; //fprintf(stderr,"Comparing %s to\n %s\n", // current->filename, new_record->filename); test = strcmp(current->filename, new_record->filename); if (test == 0) { // Found a match! int selected; //fprintf(stderr,"Found a match: Updating entry for %s\n",new_record->filename); // Save this away temporarily. selected = current->selected; // Copy the fields across and then free new_record. We // overwrite the contents of the existing record. xastir_snprintf(current->filename, MAX_FILENAME, "%s", new_record->filename); current->bottom = new_record->bottom; current->top = new_record->top; current->left = new_record->left; current->right = new_record->right; current->accessed = 1; current->max_zoom = new_record->max_zoom; current->min_zoom = new_record->min_zoom; current->map_layer = new_record->map_layer; current->draw_filled = new_record->draw_filled; current->usgs_drg = new_record->usgs_drg; current->selected = selected; // Restore it current->auto_maps = new_record->auto_maps; // Remember to free the XmStringPtr if we use this bit of code // again. free(new_record); // Don't need it anymore done++; // Exit loop, "current" points to found record } else if (test > 0) { // Found a string past us in the // alphabet. Insert ahead of this // last record. //fprintf(stderr,"Not Found, inserting: %s\n", new_record->filename); //fprintf(stderr," Before record: %s\n", current->filename); if (current == map_index_head) { // Start of list! // Insert new record at head of list new_record->next = map_index_head; map_index_head = new_record; //fprintf(stderr,"Inserting at head of list\n"); } else { // Insert between "previous" and "current" // Insert new record before "current" previous->next = new_record; new_record->next = current; //fprintf(stderr,"Inserting before current\n"); } //fprintf(stderr,"Adding:%d:%s\n",strlen(filename),filename); // Fill in some default values for the new record that // don't exist in the map_index.sys file. new_record->selected = 0; if ( strstr(new_record->filename,".geo") || strstr(new_record->filename,".GEO") || strstr(new_record->filename,".Geo") ) { new_record->auto_maps = 0; } else { new_record->auto_maps = 1; } //current = current->next; done++; } else { // Haven't gotten to the correct insertion point yet previous = current; // Save ptr to last record current = current->next; } } if (!done) { // Matching record not found, add the record to // the end of the list. "previous" points to the last // record in the list or NULL (empty list). //fprintf(stderr,"Not Found: Adding to end: %s\n",new_record->filename); new_record->next = NULL; if (previous == NULL) { // Empty list map_index_head = new_record; //fprintf(stderr,"First record in new list\n"); } else { // Else at end of list previous->next = new_record; //fprintf(stderr,"Adding to end of list: %s\n",new_record->filename); } //fprintf(stderr,"Adding:%d:%s\n",strlen(new_record->filename),new_record->filename); // Fill in some default values for the new record. new_record->selected = 0; if ( strstr(new_record->filename,".geo") || strstr(new_record->filename,".GEO") || strstr(new_record->filename,".Geo") ) { new_record->auto_maps = 0; } else { new_record->auto_maps = 1; } } } */ // sort map index // simple bubble sort, since we should be sorted already // static void index_sort(void) { map_index_record *current, *previous, *next; int changed = 1; previous = map_index_head; next = NULL; // fprintf(stderr, "index_sort: start.\n"); // check if we have any records at all, and at least two if ( (previous != NULL) && (previous->next != NULL) ) { current = previous->next; while ( changed == 1) { changed = 0; if (current->next != NULL) { next = current->next; } if ( strcmp( previous->filename, current->filename) >= 0 ) { // out of order - swap them current->next = previous; previous->next = next; map_index_head = current; current = previous; previous = map_index_head; changed = 1; } while ( next != NULL ) { if ( strcmp( current->filename, next->filename) >= 0 ) { // out of order - swap them current->next = next->next; previous->next = next; next->next = current; // get ready for the next iteration previous = next; // current already moved ahead from the swap next = current->next; changed = 1; } else { previous = current; current = next; next = current->next; } } previous = map_index_head; current = previous->next; next = current->next; } } } // Snags the file and creates the linked list pointed to by the // map_index_head pointer. The memory linked list keeps the same // order as the entries in the file. // // NOTE: If we're converting from the old format to the new, we // need to call index_save_to_file() in order to write out the new // format once we're done. // void index_restore_from_file(void) { FILE *f; map_index_record *temp_record; map_index_record *last_record; char in_string[MAX_FILENAME*2]; int doing_migration = 0; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); //fprintf(stderr,"\nRestoring map index from file\n"); if (map_index_head != NULL) { fprintf(stderr,"Warning: index_restore_from_file(): map_index_head was non-null!\n"); } map_index_head = NULL; // Starting with empty list last_record = NULL; f = fopen( map_index_path, "r" ); if (f == NULL) // No map_index file yet { return; } while (!feof (f)) // Loop through entire map_index file { // Read one line from the file if ( get_line (f, in_string, MAX_FILENAME*2) ) { if (strlen(in_string) >= 15) // We have some data. { // Try to process the // line. char scanf_format[50]; char old_scanf_format[50]; char older_scanf_format[50]; int processed; int i, jj; //fprintf(stderr,"%s\n",in_string); // Tweaked the string below so that it will track // along with MAX_FILENAME-1. We're constructing // the string "%lu,%lu,%lu,%lu,%d,%d,%2000c", where // the 2000 example number is from MAX_FILENAME. xastir_snprintf(scanf_format, sizeof(scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%d,%", MAX_FILENAME, "c"); //fprintf(stderr,"%s\n",scanf_format); // index predates addition of usgs_drg flag (26 Jul 2005) xastir_snprintf(old_scanf_format, sizeof(old_scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%", MAX_FILENAME, "c"); // index predates addition of min/max zoom (29 Oct 2003) xastir_snprintf(older_scanf_format, sizeof(older_scanf_format), "%s%d%s", "%lu,%lu,%lu,%lu,%d,%d,%d,%", MAX_FILENAME, "c"); // Malloc an index record. We'll add it to the list // only if the data looks reasonable. temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); memset(temp_record->filename, 0, sizeof(temp_record->filename)); temp_record->next = NULL; temp_record->bottom = 64800001l;// Too high temp_record->top = 64800001l; // Too high temp_record->left = 129600001l; // Too high temp_record->right = 129600001l;// Too high temp_record->map_layer = -1; // Too low temp_record->draw_filled = -1; // Too low temp_record->usgs_drg = -1; // Too low temp_record->auto_maps = -1; // Too low temp_record->max_zoom = -1; // Too low temp_record->min_zoom = -1; // Too low temp_record->filename[0] = '\0';// Empty processed = sscanf(in_string, scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->usgs_drg, &temp_record->auto_maps, &temp_record->max_zoom, &temp_record->min_zoom, temp_record->filename); if (processed < 11) { // We're upgrading from an old format index file // that doesn't have usgs_drg. Try the // old_scanf_format string instead. doing_migration = 1; processed = sscanf(in_string, old_scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->auto_maps, &temp_record->max_zoom, &temp_record->min_zoom, temp_record->filename); if (processed < 10) { // It's really old, doesn't have min/max zoom either temp_record->max_zoom = -1; // Too low temp_record->min_zoom = -1; // Too low processed = sscanf(in_string, older_scanf_format, &temp_record->bottom, &temp_record->top, &temp_record->left, &temp_record->right, &temp_record->map_layer, &temp_record->draw_filled, &temp_record->auto_maps, temp_record->filename); } // either way, it doesn't have usgs_drg, so add one // defaulting to Auto if it's a tif file, no if not if ( strstr(temp_record->filename,".tif") || strstr(temp_record->filename,".TIF") || strstr(temp_record->filename,".Tif") ) { temp_record->usgs_drg = 2; // Auto } else { temp_record->usgs_drg = 0; // No } } temp_record->XmStringPtr = NULL; // Do some reasonableness checking on the parameters // we just parsed. //WE7U: First comparison here is always false // if ( (temp_record->bottom < 0l) // || (temp_record->bottom > 64800000l) ) { if (temp_record->bottom > 64800000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: bottom extent incorrect %lu in map name:\n%s\n", temp_record->bottom, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->top < 0l) // || (temp_record->top > 64800000l) ) { if (temp_record->top > 64800000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: top extent incorrect %lu in map name:\n%s\n", temp_record->top, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->left < 0l) // || (temp_record->left > 129600000l) ) { if (temp_record->left > 129600000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: left extent incorrect %lu in map name:\n%s\n", temp_record->left, temp_record->filename); } //WE7U: First comparison here is always false // if ( (temp_record->right < 0l) // || (temp_record->right > 129600000l) ) { if (temp_record->right > 129600000l) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: right extent incorrect %lu in map name:\n%s\n", temp_record->right, temp_record->filename); } if ( (temp_record->max_zoom < 0) || (temp_record->max_zoom > 99999) ) { // processed = 0; // Reject this record // fprintf(stderr,"\nindex_restore_from_file: max_zoom field incorrect %d in map name:\n%s\n", // temp_record->max_zoom, // temp_record->filename); // Assign a reasonable value temp_record->max_zoom = 0; //fprintf(stderr,"Assigning max_zoom of 0\n"); } if ( (temp_record->min_zoom < 0) || (temp_record->min_zoom > 99999) ) { // processed = 0; // Reject this record // fprintf(stderr,"\nindex_restore_from_file: min_zoom field incorrect %d in map name:\n%s\n", // temp_record->min_zoom, // temp_record->filename); // Assign a reasonable value temp_record->min_zoom = 0; //fprintf(stderr,"Assigning min_zoom of 0\n"); } if ( (temp_record->map_layer < -99999) || (temp_record->map_layer > 99999) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: map_layer field incorrect %d in map name:\n%s\n", temp_record->map_layer, temp_record->filename); } if ( (temp_record->draw_filled < 0) || (temp_record->draw_filled > 2) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: draw_filled field incorrect %d in map name:\n%s\n", temp_record->draw_filled, temp_record->filename); } if ( (temp_record->usgs_drg < 0) || (temp_record->usgs_drg > 2) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: usgs_drg field incorrect %d in map name:\n%s\n", temp_record->usgs_drg, temp_record->filename); } if ( (temp_record->auto_maps < 0) || (temp_record->auto_maps > 1) ) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: auto_maps field incorrect %d in map name:\n%s\n", temp_record->auto_maps, temp_record->filename); } // Check whether the filename is empty if (strlen(temp_record->filename) == 0) { processed = 0; // Reject this record } // Check for control characters in the filename. // Reject any that have them. jj = (int)strlen(temp_record->filename); for (i = 0; i < jj; i++) { if (temp_record->filename[i] < 0x20) { processed = 0; // Reject this record fprintf(stderr,"\nindex_restore_from_file: Found control char 0x%02x in map name:\n%s\n", temp_record->filename[i], temp_record->filename); } } // Mark the record as accessed at this point. // At the stage where we're writing this list off to // disk, if the record hasn't been accessed by the // re-indexing, it doesn't get written. This has // the effect of flushes deleted files from the // index quickly. temp_record->accessed = 1; // Default is not-selected. Later we read in the // selected_maps.sys file and tweak some of these // fields. temp_record->selected = 0; temp_record->filename[MAX_FILENAME-1] = '\0'; // If correct number of parameters for either old or // new format if (processed == 11 || processed == 10 || processed == 8) { //fprintf(stderr,"Restored: %s\n",temp_record->filename); // Insert the new record into the in-memory map // list in sorted order. // --slow for large lists // index_insert_sorted(temp_record); // -- so we just add it to the end of the list // and sort it at the end tp make sure nobody // messed us up by editting the file by hand if ( last_record == NULL ) // first record { map_index_head = temp_record; } else { last_record->next = temp_record; } last_record = temp_record; // Remember that we may just have attached the // record to our in-memory map list, or we may // have free'ed it in the above function call. // Set the pointer to NULL to make sure we don't // try to do anything else with the memory. temp_record = NULL; } else // sscanf didn't parse the proper number of { // items. Delete the record. // Remember to free the XmString pointer if necessary. free(temp_record); // fprintf(stderr,"index_restore_from_file:sscanf parsing error\n"); } } } } (void)fclose(f); // now that we have read the whole file, make sure it is sorted index_sort(); // probably should check for dup records if (doing_migration) { // Save in new file format if we just did a migration from // old format to new. fprintf(stderr,"Migrating from old map_index.sys format to new format.\n"); index_save_to_file(); } } // map_indexer() // // Recurses through the map directories finding map extents // and recording them in the map index. Once the indexing is // complete, write the current index out to a file. // // It'd be nice to call index_restore_from_file() from main.c:main() // so that an earlier copy of the index is restored before the map // display is created. // // If we set the "accessed" variable in the in-memory index to 0 for // each record and then run the indexer, the save-to-file function // will delete those with a value of 0 when writing to disk. Those // maps no longer exist in the filesystem and should be deleted. We // could either wipe them from the in-memory database at that time // as well, or wipe the whole list and re-read it from disk to get // the current list. // // If parameter is 0, we'll do the smart timestamp-checking // indexing. // If 1, we'll erase the in-memory index and do full indexing. // void map_indexer(int parameter) { struct stat nfile; int check_times = 1; FILE *f; map_index_record *current; map_index_record *backup_list_head = NULL; char map_index_path[MAX_VALUE]; get_user_base_dir(MAP_INDEX_DATA, map_index_path, sizeof(map_index_path)); if (debug_level & 16) { fprintf(stderr,"map_indexer() start\n"); } fprintf(stderr,"Indexing maps...\n"); #ifdef HAVE_LIBSHP // get rid of stored dbfawk signatures and force reload. clear_dbfawk_sigs(); #endif // Find the timestamp on the index file first. Save it away so // that the timestamp for each map file can be compared to it. if (stat ( map_index_path, &nfile) != 0) { // File doesn't exist yet. Create it. f = fopen( map_index_path, "w" ); if (f != NULL) { (void)fclose(f); } else fprintf(stderr,"Couldn't create map index file: %s\n", map_index_path ); check_times = 0; // Don't check the timestamps. Do them all. } else // File exists { map_index_timestamp = (time_t)nfile.st_mtime; check_times = 1; } if (parameter == 1) // Full indexing instead of timestamp-check indexing { // Move the in-memory index to a backup pointer backup_list_head = map_index_head; map_index_head = NULL; // // Set the timestamp to 0 so that everything gets indexed // map_index_timestamp = (time_t)0l; check_times = 0; } // Set the "accessed" field to zero for every record in the // index. Note that the list could be empty at this point. current = map_index_head; while (current != NULL) { current->accessed = 0; current = current->next; } if (check_times) { if (debug_level & 16) { fprintf(stderr,"map_indexer: Calling map_search\n"); } map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_CHECK_TIMESTAMPS); if (debug_level & 16) { fprintf(stderr,"map_indexer: Returned from map_search\n"); } } else { if (debug_level & 16) { fprintf(stderr,"map_indexer: Calling map_search\n"); } map_search (NULL, AUTO_MAP_DIR, NULL, NULL, (int)FALSE, INDEX_NO_TIMESTAMPS); if (debug_level & 16) { fprintf(stderr,"map_indexer: Returned from map_search\n"); } } if (debug_level & 16) { fprintf(stderr,"map_indexer() middle\n"); } if (parameter == 1) // Full indexing instead of timestamp-check indexing { // Copy the Properties from the backup list to the new list, // then free the backup list. map_index_copy_properties(map_index_head, backup_list_head); } // Save the updated index to the file index_save_to_file(); fprintf(stderr,"Finished indexing maps\n"); if (debug_level & 16) { fprintf(stderr,"map_indexer() end\n"); } } /* moved these here and made them static so it will function on FREEBSD */ #define MAX_ALERT 7000 // If we comment this out, we link, but get a segfault at runtime. // Take out the "static" and we get a segfault when we zoom out too // far with the lakes or counties shapefile loaded. No idea why // yet. --we7u //static alert_entry alert[MAX_ALERT]; static int alert_count; /******************************************************************* * fill_in_new_alert_entries() * * Fills in the index and filename portions of any alert entries * that are missing them. This function should be called at the * point where we've just received a new weather alert. * //WE7U // Later we should change this so that it doesn't scan the entire // message list, but is passed the important info directly from the // decode routines in db.c, and the message should NOT be added to // the message list. //WE7U * * This function is designed to use ESRI Shapefile map files. The * base directory where the Shapefiles are located is passed to us * in the "dir" variable. * * map_search() fills in the filename field of the alert struct. * draw_shapefile_map() fills in the index field. *******************************************************************/ void fill_in_new_alert_entries(void) { // int ii; char alert_scan[MAX_FILENAME]; // char *dir_ptr; struct hashtable_itr *iterator = NULL; alert_entry *temp; char dir[MAX_FILENAME]; if (debug_level & 2) { fprintf(stderr,"fill_in_new_alert_entries start\n"); } xastir_snprintf(dir, sizeof(dir), "%s", ALERT_MAP_DIR); alert_count = MAX_ALERT - 1; // Set up our path to the wx alert maps memset(alert_scan, 0, sizeof (alert_scan)); // Zero our alert_scan string xastir_snprintf(alert_scan, // Fetch the base directory sizeof(alert_scan), "%s", dir); strncat(alert_scan, // Complete alert directory is now set up in the string "/", sizeof(alert_scan) - 1 - strlen(alert_scan)); // dir_ptr = &alert_scan[strlen (alert_scan)]; // Point to end of path // Iterate through the weather alerts. It looks like we wish to // just fill in the alert struct and to determine whether the // alert is within our viewport here. We don't wish to draw the // alerts at this stage, that happens in the load_alert_maps() // function below. iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { if (!temp->filename[0]) // Filename is { // empty, we need to fill it in. // fprintf(stderr,"fill_in_new_alert_entries() Title: %s\n",temp->title); // The last parameter denotes loading into // pixmap_alerts instead of pixmap or pixmap_final. // Note that just calling map_search does not get // the alert areas drawn on the screen. The // draw_map() function called by map_search just // fills in the filename field in the struct and // exits. // // The "warn" parameter (next to last) specifies whether // to dump warnings out to the console as well. If the // warning was received on local RF or locally, warn the // operator (the weather must be near). map_search (da, alert_scan, temp, &alert_count, (int)temp->flags[source], DRAW_TO_PIXMAP_ALERTS); // fprintf(stderr,"fill_in_new_alert_entries() Title1:%s\n",temp->title); } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 4\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC if (debug_level & 2) { fprintf(stderr,"fill_in_new_alert_entries end\n"); } } /******************************************************************* * load_alert_maps() * * Used to load weather alert maps, based on NWS weather alerts that * are received. Called from create_image() and refresh_image(). * This function is designed to use ESRI Shapefile map files. The * base directory where the Shapefiles are located is passed to us * in the "dir" variable. * * map_search() fills in the filename field of the alert struct. * draw_shapefile_map() fills in the index field. *******************************************************************/ void load_alert_maps (Widget w, char *dir) { // int ii; int level; unsigned char fill_color[] = { (unsigned char)0x69, // gray86 (unsigned char)0x4a, // red2 (unsigned char)0x63, // yellow2 (unsigned char)0x66, // cyan2 (unsigned char)0x61, // RoyalBlue (unsigned char)0x64, // ForestGreen (unsigned char)0x62 }; // orange3 struct hashtable_itr *iterator = NULL; alert_entry *temp; map_draw_flags mdf; //fprintf(stderr,"load_alert_maps\n"); // TODO: // Figure out how to pass a quantity of zones off to the map drawing // routines, then we can draw them all with one pass through each // map file. Alphanumerically sort the zones to make it easier for // the map drawing functions? Note that the indexing routines fill // in both the filename and the shapefile index for each record. // // Alternative: Call map_draw for each filename listed and have the // draw_shapefile function iterate through the array looking for all // filename matches, pulling non-negative indexes out of each index // field for matches and drawing them. That should be fast and // require no sorting of the array. Downside: The alerts won't be // layered based on alert level unless we modify the above: Drawing // each file once for each alert-level in the proper layering order. // Perhaps we could keep a list of which filenames have been called, // and only call each one once per load_alert_maps() call. // Just for a test //draw_shapefile_map (w, dir, filenm, alert, alert_color, destination_pixmap); //draw_shapefile_map (w, dir, "c_16my01.shp", NULL, '\0', DRAW_TO_PIXMAP_ALERTS); // Are we drawing them in reverse order so that the important // alerts end up drawn on top of the less important alerts? // Actually, since the alert hash isn't ordered, perhaps we need to // order them by priority, then by map file, so that we can draw the // shapes from each map file in the correct order. This might cause // each map file to be drawn up to three times (once for each // priority level), but that's better than calling each map for each // zone as is done now. iterator = create_wx_alert_iterator(); temp = get_next_wx_alert(iterator); while (iterator != NULL && temp) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 5\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } if (disable_all_maps) { #ifndef USING_LIBGC //fprintf(stderr,"free iterator 6\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC return; } // Check whether the alert slot is filled/empty if (temp->title[0] == '\0') // Empty slot { temp = get_next_wx_alert(iterator); continue; } if ( (level = alert_active(temp, ALERT_ALL) ) ) { if (level >= (int)sizeof (fill_color)) { level = 0; } // The last parameter denotes drawing into pixmap_alert // instead of pixmap or pixmap_final. if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Drawing %s\n",temp->filename); fprintf(stderr,"load_alert_maps() Title4:%s\n",temp->title); } // Attempt to draw alert if ( temp->index != -1 ) // Shape found in shapefile { // Check whether we've ever tried to draw this alert // before. If not, attempt it and get the boundary // limits filled in. // if ( temp->bottom_boundary == 0.0 && temp->top_boundary == 0.0 && temp->left_boundary == 0.0 && temp->right_boundary == 0.0) { if (temp->alert_level != 'C') { draw_map (w, dir, temp->filename, temp, fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf); // draw filled } } if (map_visible_lat_lon(temp->bottom_boundary, // Shape visible temp->top_boundary, temp->left_boundary, temp->right_boundary) ) { if (temp->alert_level != 'C') // Alert not cancelled { mdf.draw_filled=1; mdf.usgs_drg=0; if (debug_level & 16) { fprintf(stderr,"load_alert_maps: Calling draw_map\n"); } draw_map (w, dir, temp->filename, temp, fill_color[level], DRAW_TO_PIXMAP_ALERTS, &mdf); // draw filled } if (temp) { temp->flags[on_screen] = 'Y'; } } else { // Not in our viewport, don't draw it! if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Alert not visible\n"); } //fprintf(stderr,"B:%f T:%f L:%f R:%f\n", temp->bottom_boundary, temp->top_boundary, temp->left_boundary, temp->right_boundary); if (temp) { temp->flags[on_screen] = 'N'; } } } else { // Can't find this shape in the shapefile. if (debug_level & 16) { fprintf(stderr, "load_alert_maps() Shape %s, strlen=%d, not found in %s\n", temp->title, (int)strlen(temp->title), temp->filename ); } } } temp = get_next_wx_alert(iterator); } #ifndef USING_LIBGC //fprintf(stderr,"free iterator 7\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC if (debug_level & 16) { fprintf(stderr,"load_alert_maps() Done drawing all active alerts\n"); } if (alert_display_request()) { alert_redraw_on_update = redraw_on_new_data = 2; } } // Here's the head of our sorted-by-layer maps list static map_index_record *map_sorted_list_head = NULL; static void empty_map_sorted_list(void) { map_index_record *current = map_sorted_list_head; while (map_sorted_list_head != NULL) { current = map_sorted_list_head; map_sorted_list_head = current->next; if (current->XmStringPtr != NULL) { XmStringFree(current->XmStringPtr); } free(current); } } // Insert a map into the list at the end of the maps with the same // layer number. We'll need to look up the parameters for it from // the master map_index list and then attach a new record to our new // sorted list in the proper place. // // This function should be called when we're first starting up // Xastir and anytime that selected_maps.sys is changed. // static void insert_map_sorted(char *filename) { map_index_record *current; map_index_record *last; map_index_record *temp_record; unsigned long bottom; unsigned long top; unsigned long left; unsigned long right; int max_zoom; int min_zoom; int map_layer; int draw_filled; int usgs_drg; int auto_maps; int done; if (index_retrieve(filename, &bottom, &top, &left, &right, &max_zoom, &min_zoom, &map_layer, &draw_filled, &usgs_drg, &auto_maps)) // Found a match { // Allocate a new record temp_record = (map_index_record *)malloc(sizeof(map_index_record)); CHECKMALLOC(temp_record); // Fill in the values xastir_snprintf(temp_record->filename,MAX_FILENAME,"%s",filename); temp_record->bottom = bottom; temp_record->top = top; temp_record->left = left; temp_record->right = right; temp_record->max_zoom = max_zoom; temp_record->min_zoom = min_zoom; temp_record->map_layer = map_layer; temp_record->draw_filled = draw_filled; temp_record->usgs_drg = usgs_drg; temp_record->auto_maps = auto_maps; temp_record->selected = 1; // Always, we already know this! temp_record->accessed = 0; temp_record->next = NULL; temp_record->XmStringPtr = NULL; // Now find the proper place for it and insert it in // layer-order into the list. current = map_sorted_list_head; last = map_sorted_list_head; done = 0; // Possible cases: // Empty list // insert at beginning of list // insert at end of list // insert between other entries if (map_sorted_list_head == NULL) { // Empty list. Insert record. map_sorted_list_head = temp_record; done++; } else if (map_layer < current->map_layer) { // Insert at beginning of list temp_record->next = current; map_sorted_list_head = temp_record; done++; } else // Need to insert between records or at end of list { while (!done && (current != NULL) ) { if (map_layer >= current->map_layer) // Not to our layer yet { last = current; current = current->next; // May point to NULL now } else if (map_layer < current->map_layer) { temp_record->next = current; last->next = temp_record; done++; } } } // Handle running off the end of the list if (!done && (current == NULL) ) { last->next = temp_record; } } else { // We failed to find it in the map index } } /********************************************************** * load_auto_maps() * * NEW: Uses the in-memory map_index to scan through the * maps. * * OLD: Recurses through the map directories looking for * maps to load. **********************************************************/ void load_auto_maps (Widget w, char * UNUSED(dir) ) { map_index_record *current = map_index_head; map_draw_flags mdf; HandlePendingEvents(app_context); if (interrupt_drawing_now) { return; } // Skip the sorting of the maps if we don't need to do it if (re_sort_maps) { //fprintf(stderr,"*** Sorting the selected maps by layer...\n"); // Empty the sorted list first. We'll create a new one. empty_map_sorted_list(); // Run through the entire map_index linked list while (current != NULL) { if (auto_maps_skip_raster && ( strstr(current->filename,".geo") || strstr(current->filename,".GEO") || strstr(current->filename,".Geo") || strstr(current->filename,".tif") || strstr(current->filename,".TIF") || strstr(current->filename,".Tif"))) { // Skip this map } else // Draw this map { //fprintf(stderr,"Loading: %s/%s\n",SELECTED_MAP_DIR,current->filename); //WE7U insert_map_sorted(current->filename); /* draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP); */ } current = current->next; } // All done sorting until something is changed in the Map // Chooser. re_sort_maps = 0; //fprintf(stderr,"*** DONE sorting the selected maps.\n"); } // We have the maps in sorted order. Run through the list and // draw them. Only include those that have the auto_maps field // set to 1. current = map_sorted_list_head; while (current != NULL) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (disable_all_maps) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Debug // fprintf(stderr,"Drawing level:%05d, file:%s\n", // current->map_layer, // current->filename); // Draw the maps in sorted-by-layer order if (current->auto_maps) { mdf.draw_filled = current->draw_filled; mdf.usgs_drg = current->usgs_drg; if (debug_level & 16) { fprintf(stderr,"load_auto_maps: Calling draw_map\n"); } draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP, &mdf); } current = current->next; } } /******************************************************************* * load_maps() * * Loads maps, draws grid, updates the display. * * We now create a linked list of maps in layer-order and use this * list to draw the maps. This preserves the correct ordering in * all cases. The layer to draw each map is specified in the * map_index.sys file (fifth parameter). Eventually code will be * added to the Map Chooser in order to change the layer each map is * drawn at. *******************************************************************/ void load_maps (Widget w) { FILE *f; char mapname[MAX_FILENAME]; int i; char selected_dir[MAX_FILENAME]; map_index_record *current; map_draw_flags mdf; char selected_map_path[MAX_VALUE]; get_user_base_dir(SELECTED_MAP_DATA, selected_map_path, sizeof(selected_map_path)); // int dummy; if (debug_level & 16) { fprintf(stderr,"Load maps start\n"); } HandlePendingEvents(app_context); if (interrupt_drawing_now) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Skip the sorting of the maps if we don't need to do it if (re_sort_maps) { //fprintf(stderr,"*** Sorting the selected maps by layer...\n"); // Empty the sorted list first. We'll create a new one. empty_map_sorted_list(); // Make sure the string is empty before we start selected_dir[0] = '\0'; // Create empty file if it doesn't exist (void)filecreate( selected_map_path ); f = fopen ( selected_map_path, "r" ); if (f != NULL) { if (debug_level & 16) { fprintf(stderr,"Load maps Open map file\n"); } while (!feof (f)) { // Grab one line from the file if ( fgets( mapname, MAX_FILENAME-1, f ) != NULL ) { // Forced termination (just in case) mapname[MAX_FILENAME-1] = '\0'; // Get rid of the newline at the end for (i = strlen(mapname); i > 0; i--) { if (mapname[i] == '\n') { mapname[i] = '\0'; } } if (debug_level & 16) { fprintf(stderr,"Found mapname: %s\n", mapname); } // Test for comment if (mapname[0] != '#') { // Check whether it's a directory that was // selected. If so, save it in a special // variable and use that to match all the files // inside the directory. Note that with the way // we have things ordered in the list, the // directories appear before their member files. if (mapname[strlen(mapname)-1] == '/') { int len; // Found a directory. Save the name. xastir_snprintf(selected_dir, sizeof(selected_dir), "%s", mapname); len = strlen(mapname); //fprintf(stderr,"Selected %s directory\n",selected_dir); // Here we need to run through the map_index // list to find all maps that match the // currently selected directory. Attempt to // load all of those maps as well. //fprintf(stderr,"Load all maps under this directory: %s\n",selected_dir); // Point to the start of the map_index list current = map_index_head; while (current != NULL) { if (strncmp(current->filename,selected_dir,len) == 0) { if (current->filename[strlen(current->filename)-1] != '/') { //fprintf(stderr,"Loading: %s\n",current->filename); //WE7U insert_map_sorted(current->filename); /* draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP); */ } } current = current->next; } } // Else must be a regular map file else { //fprintf(stderr,"%s\n",mapname); //start_timer(); //WE7U insert_map_sorted(mapname); /* draw_map (w, SELECTED_MAP_DIR, mapname, NULL, '\0', DRAW_TO_PIXMAP); */ //stop_timer(); //print_timer_results(); if (debug_level & 16) { fprintf(stderr,"Load maps -%s\n", mapname); } XmUpdateDisplay (da); } } } else // We've hit EOF { break; } } (void)fclose (f); statusline(" ",1); // delete status line } else { fprintf(stderr,"Couldn't open file: %s\n", selected_map_path ); } // All done sorting until something is changed in the Map // Chooser. re_sort_maps = 0; //fprintf(stderr,"*** DONE sorting the selected maps.\n"); } // We have the maps in sorted order. Run through the list and // draw them. current = map_sorted_list_head; while (current != NULL) { HandlePendingEvents(app_context); if (interrupt_drawing_now) { statusline(" ",1); // delete status line // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } if (disable_all_maps) { // Update to screen (void)XCopyArea(XtDisplay(da), pixmap, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); return; } // Debug // fprintf(stderr,"Drawing level:%05d, file:%s\n", // current->map_layer, // current->filename); // Draw the maps in sorted-by-layer order mdf.draw_filled = current->draw_filled; mdf.usgs_drg = current->usgs_drg; if (debug_level & 16) { fprintf(stderr,"load_maps: Calling draw_map\n"); } // Map profiling, set up for 800x600 window at "Map Profile Test // Site" bookmark. // // Loading "rd011802.shp" 500 times takes // 302->256->264->269->115->116 seconds. // // 100 times on PP200 takes 192->183 seconds. // //start_timer(); //fprintf(stderr,"Calling draw_map() 500 times...\n"); //for (dummy = 0; dummy < 500; dummy++) { draw_map (w, SELECTED_MAP_DIR, current->filename, NULL, '\0', DRAW_TO_PIXMAP, &mdf); //} //stop_timer(); print_timer_results(); current = current->next; } if (debug_level & 16) { fprintf(stderr,"Load maps stop\n"); } } Xastir-Release-2.2.4/src/maps.h0000664000175000017500000002061315151324131015223 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_MAPS_H #define __XASTIR_MAPS_H #include #include #define MAX_OUTBOUND 900 #define MAX_MAP_POINTS 500000 #define DRAW_TO_PIXMAP 0 #define DRAW_TO_PIXMAP_FINAL 1 #define DRAW_TO_PIXMAP_ALERTS 2 #define INDEX_CHECK_TIMESTAMPS 9998 #define INDEX_NO_TIMESTAMPS 9999 /* memory structs */ typedef struct { unsigned char vector_start_color; unsigned char object_behavior; unsigned long longitude; unsigned long latitude; } map_vectors; typedef struct { unsigned long longitude; unsigned long latitude; unsigned int mag; char label_text[33]; unsigned char text_color_quad; } text_label; typedef struct { unsigned long longitude; unsigned long latitude; unsigned int mag; unsigned char symbol; unsigned char aprs_symbol; unsigned char text_color; char label_text[30]; } symbol_label; typedef struct _map_index_record { char filename[MAX_FILENAME]; XmString XmStringPtr; unsigned long bottom; unsigned long top; unsigned long left; unsigned long right; int accessed; int max_zoom; // Specify maximum zoom at which this layer is drawn. int min_zoom; // Specify minimum zoom at which this layer is drawn. int map_layer; // Specify which layer to draw the map on. int draw_filled; // Specify whether to fill polygons when drawing. // 0 = Global No-Fill (Vector) // 1 = Global Fill // 2 = Auto (dbfawk controls it if present) int usgs_drg; // Specify whether the map has USGS DRG colormap // and should have color configuration applied // 0 = No // 1 = Yes // 2 = Auto (detect from TIFFTAG_IMAGEDESCRIPTION) int selected; // Specifies if map is currently selected int temp_select; // Temporary selection used in map properties dialog int auto_maps; // Specifies if map included in automaps function struct _map_index_record *next; } map_index_record; extern map_index_record *map_index_head; typedef struct { int img_x; int img_y; unsigned long x_long; unsigned long y_lat; } tiepoint; void draw_point(Widget w, unsigned long x1, unsigned long y1, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_point_ll(Widget w, float y1, float x1, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_vector(Widget w, unsigned long x1, unsigned long y1, unsigned long x2, unsigned long y2, GC gc, Pixmap which_pixmap, int skip_duplicates); void draw_vector_ll(Widget w, float y1, float x1, float y2, float x2, GC gc, Pixmap which_pixmap, int skip_duplicates); char *get_map_ext (char *filename); char *get_map_dir (char *fullpath); void load_auto_maps(Widget w, char *dir); void load_maps(Widget w); void fill_in_new_alert_entries(void); void load_alert_maps(Widget w, char *dir); void index_update_xastir(char *filename, unsigned long bottom, unsigned long top, unsigned long left, unsigned long right, int default_map_layer); void index_update_ll(char *filename, double bottom, double top, double left, double right, int default_map_layer); extern void get_horizontal_datum(char *datum, int sizeof_datum); void draw_grid (Widget w); void Snapshot(void); extern int index_retrieve(char *filename, unsigned long *bottom, unsigned long *top, unsigned long *left, unsigned long *right, int *max_zoom, int *min_zoom, int *map_layer, int *draw_filled, int *usgs_drg, int *automaps); extern void index_restore_from_file(void); extern void index_save_to_file(void); extern void map_indexer(int parameter); extern void get_viewport_lat_lon(double *xmin, double *ymin, double *xmax, double *ymax); extern int map_visible (unsigned long bottom_map_boundary, unsigned long top_map_boundary, unsigned long left_map_boundary, unsigned long right_map_boundary); extern int map_visible_lat_lon (double f_bottom_map_boundary, double f_top_map_boundary, double f_left_map_boundary, double f_right_map_boundary); extern int map_inside_viewport_lat_lon(double map_min_y, double map_max_y, double map_min_x, double map_max_x); extern void draw_label_text (Widget w, int x, int y, int label_length, int color, char *label_text); extern void draw_rotated_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize); extern int get_rotated_label_text_length_pixels(Widget w, char *label_text, int fontsize); extern void draw_centered_label_text (Widget w, int rotation, int x, int y, int label_length, int color, char *label_text, int fontsize); extern void Monochrome( Widget widget, XtPointer clientData, XtPointer callData); extern void Snapshot(void); extern void clean_string(char *input); extern int print_rotated; extern int print_auto_rotation; extern int print_auto_scale; extern int print_in_monochrome; extern int print_invert; extern char printer_program[MAX_FILENAME+1]; extern char previewer_program[MAX_FILENAME+1]; extern int gnis_locate_place(Widget w, char *name, char *state, char *county, char *quad, char* type, char *filename, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50]); extern int pop_locate_place(Widget w, char *name, char *state, char *county, char *quad, char* type, char *filename, int follow_case, int get_match, char match_array_name[50][200], long match_array_lat[50], long match_array_long[50]); extern void maps_init(void); enum map_onscreen_enum {MAP_NOT_VIS=0,MAP_IS_VIS,MAP_NOT_INDEXED}; extern enum map_onscreen_enum map_onscreen(long left, long right, long top, long bottom, int checkpercentage); extern enum map_onscreen_enum map_onscreen_index(char *filename); extern time_t last_snapshot; extern time_t last_kmlsnapshot; extern int snapshot_interval; extern int grid_size; #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) extern float imagemagick_gamma_adjust; #endif // HAVE_MAGICK #endif // NO_GRAPHICS extern float raster_map_intensity; extern void Print_Postscript(Widget widget, XtPointer clientData, XtPointer callData); extern void map_plot (Widget w, long max_x, long max_y, long x_long_cord, long y_lat_cord, unsigned char color, long object_behavior, int destination_pixmap, int draw_filled); // A struct to pass down in to map driver functions so they can have // driver-specific flags. Most drivers won't care about any (or even all) // of the flags, but this way we can just pass a single pointer rather than // adding new arguments to the generic interface each time we want new flags typedef struct { int draw_filled; int usgs_drg; } map_draw_flags; #endif /* __XASTIR_MAPS_H */ Xastir-Release-2.2.4/src/messages.c0000664000175000017500000012621715151324131016074 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "messages.h" #include "util.h" #include "interface.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" char group_data_file[400]; char *group_data_list = NULL; // Need this NULL for Solaris! int group_data_count = 0; int group_data_max = 0; char message_counter[5+1]; int auto_reply; char auto_reply_message[100]; Message_Window mw[MAX_MESSAGE_WINDOWS+1]; // Send Message widgets Message_transmit message_pool[MAX_OUTGOING_MESSAGES+1]; // Transmit message queue void clear_message_windows(void) { int i; begin_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" ); for (i = 0; i < MAX_MESSAGE_WINDOWS; i++) { if (mw[i].send_message_dialog) { XtDestroyWidget(mw[i].send_message_dialog); } mw[i].send_message_dialog = (Widget)NULL; mw[i].to_call_sign[0] = '\0'; mw[i].send_message_call_data = (Widget)NULL; mw[i].D700_mode = (Widget)NULL; mw[i].D7_mode = (Widget)NULL; mw[i].HamHUD_mode = (Widget)NULL; mw[i].message_data_line1 = (Widget)NULL; mw[i].message_data_line2 = (Widget)NULL; mw[i].message_data_line3 = (Widget)NULL; mw[i].message_data_line4 = (Widget)NULL; mw[i].send_message_text = (Widget)NULL; } end_critical_section(&send_message_dialog_lock, "messages.c:clear_message_windows" ); } static int group_comp(const void *a, const void *b) { if (!*(char *)a) { return ((int)(*(char *)b != '\0')); } return strcasecmp(a, b); } void group_build_list(char *filename) { char *ptr; FILE *f; struct stat group_stat; int i; if (group_data_count == group_data_max) { ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10); if (ptr) { group_data_list = ptr; group_data_max += 10; //fprintf(stderr, "group_data_max: %d\n", group_data_max); } else { fprintf(stderr, "Unable to allocate more memory for group_data_list (1)\n"); } } // Make sure we always listen for ourself, XASTIR, & our Version groups xastir_snprintf(&group_data_list[0],10,"%s",my_callsign); xastir_snprintf(&group_data_list[10],10,"XASTIR"); xastir_snprintf(&group_data_list[20],10,"%s",XASTIR_TOCALL); group_data_count = 3; // If we are in special group look for messages. if (altnet) { xastir_snprintf(&group_data_list[group_data_count*10],10,"%s",altnet_call); group_data_count++; } // if (! stat(filename, &group_stat) ) { f = fopen(filename, "r"); // File exists } else { f = fopen(filename, "w+"); // No file. Create it and open it. } if (f == NULL) { fprintf(stderr,"Couldn't open file for reading -or- appending: %s\n", filename); return; } while (!feof(f)) { if (group_data_count == group_data_max) { ptr = realloc(group_data_list, (size_t)(group_data_max+10)*10); if (ptr) { group_data_list = ptr; group_data_max += 10; //fprintf(stderr, "group_data_max(2): %d\n", group_data_max); } else { fprintf(stderr, "Unable to allocate more memory for group_data_list (2)\n"); } } if (group_data_count < group_data_max) { group_data_list[group_data_count*10] = '\0'; if (fgets(&group_data_list[group_data_count*10], 10, f) == NULL) { // Error reading file or end-of-file. Continue processing // the (partial?) string we just read, in the code below. } if ((ptr = strchr(&group_data_list[group_data_count*10], '\n'))) { *ptr = '\0'; } else while ((i = fgetc(f)) != EOF && i != '\n'); // clean-up after long group name // check for DOS EOL markup! if ((ptr = strchr(&group_data_list[group_data_count*10], '\r'))) { *ptr = '\0'; } if (group_data_list[group_data_count*10]) { group_data_count++; } } } (void)fclose(f); qsort(group_data_list, (size_t)group_data_count, 10, group_comp); if (debug_level & 2) { for (i = 0; i < group_data_count; i++) { fprintf(stderr,"Group %2d: %s\n", i, &group_data_list[i*10]); } } } int group_active(char *from) { static struct stat current_group_stat; struct stat group_stat; static char altgroup[10]; char group_data_path[MAX_VALUE]; get_user_base_dir(group_data_file, group_data_path, sizeof(group_data_path)); (void)remove_trailing_spaces(from); // If we cycle to/from special group or file changes, rebuild group list. if ((!stat( group_data_path, &group_stat ) && (current_group_stat.st_size != group_stat.st_size || current_group_stat.st_mtime != group_stat.st_mtime || current_group_stat.st_ctime != group_stat.st_ctime))) { // altgroup equates to "address of altgroup" which always evaluates // as true. Commenting it out of the conditional. --we7u. // || (altgroup && strcasecmp(altgroup, VERSIONFRM))) { group_build_list( group_data_path ); current_group_stat = group_stat; xastir_snprintf(altgroup,sizeof(altgroup),"%s",VERSIONFRM); } if (group_data_list != NULL) // Causes segfault on Solaris 2.5 without this! { return (int)(bsearch(from, group_data_list, (size_t)group_data_count, (size_t)10, group_comp) != NULL); } else { return(0); } } int look_for_open_group_data(char *to) { int i,found; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; begin_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" ); found = FALSE; for(i = 0; i < MAX_MESSAGE_WINDOWS; i++) { /* find station */ if(mw[i].send_message_dialog != NULL) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,to);*/ if(strcmp(temp1,to)==0) { found=(int)TRUE; break; } } } end_critical_section(&send_message_dialog_lock, "messages.c:look_for_open_group_data" ); return(found); } // What we wish to do here: Check for an active Send Message dialog // that contains the callsign of interest. If one doesn't exist, // create one and pop it up. We don't want to do this for duplicate // message lines or duplicate acks for any particular QSO. To do so // would cause the Send Message dialog to pop up on every such // received message, which is VERY annoying (that was the default in // Xastir for years, and nobody liked it!). // int check_popup_window(char *from_call_sign, int group) { int i,found,j,ret; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; //fprintf(stderr,"\tcheck_popup_window()\n"); ret = -1; found = -1; begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" ); // Check for an already-created dialog for talking to this // particular call_sign. // for (i = 0; i < MAX_MESSAGE_WINDOWS; i++) { if (mw[i].send_message_dialog != NULL) // If dialog created { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); /*fprintf(stderr,"Looking at call <%s> for <%s>\n",temp1,from_call_sign);*/ if (strcasecmp(temp1, from_call_sign) == 0) { // Found a call_sign match in a Send Message dialog! //fprintf(stderr,"\tFound a Send_message dialog match\n"); found = i; break; } } } end_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window" ); // If found == -1 at this point, we haven't found a Send Message // dialog that contains the call_sign of interest. // if (found == -1 && (group == 2 || group_active(from_call_sign))) { /* no window found Open one! */ //fprintf(stderr,"\tNo Send Message dialog found, creating one\n"); begin_critical_section(&send_message_dialog_lock, "messages.c:check_popup_window2" ); i= -1; for (j=0; j to <%s>\n",from,to); } // Repeat until we process the entire message. We'll process it // a chunk at a time, size of chunk to correspond to max APRS // message line length. // while (!error && (message_ptr < (int)strlen(message))) { ok=0; space_loc=0; // Break a long message into smaller chunks that can be // processed into APRS messages. Break at a space character // if possible. // for (j=0; j %d %d\n",message_out,message_ptr,last_space); } if (j >= MAX_MESSAGE_OUTPUT_LENGTH) { message_ptr = MAX_MESSAGE_OUTPUT_LENGTH; } else { message_ptr=last_space; } /* check for others in the queue */ wait_on_first_ack=0; for (i=0; iRF // QSO's if we're sending to the internet too, but that's a bug in // the igate software, and not something that Xastir should try to // correct itself. // void transmit_message_data(char *to, char *message, char *path) { DataRow *p_station; if (debug_level & 2) { fprintf(stderr,"Transmitting data to %s : %s\n",to,message); } p_station = NULL; if (strcmp(to, my_callsign) == 0) // My station message { // Send out all active ports if (debug_level & 2) { fprintf(stderr,"My call VIA any way\n"); } output_my_data(message,-1,0,0,0,path); // All done return; } if (!search_station_name(&p_station,to,1)) { // No data record found for this station. Send to all // active ports. if (debug_level & 2) { fprintf(stderr,"VIA any way\n"); } output_my_data(message,-1,0,0,0,path); // All done return; } if (debug_level & 2) { fprintf(stderr,"found station %s\n",p_station->call_sign); } // It's not being sent to my callsign but to somebody else // "out there". Because the truth is... if ( ((p_station->flag & ST_VIATNC) != 0) && (heard_via_tnc_in_past_hour(to)) ) { int port_num; // Station was heard via a TNC port within the previous // hour. Send to TNC port it was heard on. // output_my_data(message,p_station->heard_via_tnc_port,0,0,0,path); // Send to all internet ports. Iterate through the port // definitions looking for internet ports, send the message // out once to each. // for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++) { // If it's an internet port, send the message. if (port_data[port_num].device_type == DEVICE_NET_STREAM) { output_my_data(message,port_num,0,0,0,path); } } // All done return; } else if (p_station->data_via==DATA_VIA_NET) { int port_num; int active_internet_ports_found = 0; // Station was heard over an internet interface. Check // whether we have any internet interfaces available with TX // enabled. If so, send out those ports. Else drop through // and hit the TRANSMIT-ALL clause at the end of this // function. // Iterate through the port definitions looking for internet // ports with transmit enabled. Send the message out once // to each. // for (port_num = 0; port_num < MAX_IFACE_DEVICES; port_num++) { // If it's an internet port and transmit is enabled, // send the message and set the flag. if ( (port_data[port_num].device_type == DEVICE_NET_STREAM) && (port_data[port_num].active == DEVICE_IN_USE) && (port_data[port_num].status == DEVICE_UP) && (devices[port_num].transmit_data == 1) ) { // Found a tx-enabled internet port that was up and // running. Send the message out this port. output_my_data(message,port_num,0,0,0,path); active_internet_ports_found++; } } if (active_internet_ports_found) { // We found at least one tx-enabled internet interface // that was up and running. // All done. return; } else // No active tx-enabled internet ports were found. { // Drop through to the TRANSMIT-ALL clause below. } } // We've NOT heard this station on a TNC port within the // last hour and have no active tx-enabled internet ports to // send to. Send to ALL active ports. if (debug_level & 2) { fprintf(stderr,"VIA any way\n"); } output_my_data(message,-1,0,0,0,path); } // The below variables and functions implement the capability to // schedule ACK's some number of seconds out from the current time. // We use it to schedule duplicate ACK's at 30/60/120 seconds out, // but only if we see duplicate message lines from remote stations. // // Create a struct to hold the delayed ack's. typedef struct _delayed_ack_record { char to_call_sign[MAX_CALLSIGN+1]; char message_line[MAX_MESSAGE_OUTPUT_LENGTH+1+5+1]; char path[200]; time_t active_time; struct _delayed_ack_record *next; } delayed_ack_record, *delayed_ack_record_p; // And a pointer to a list of them. delayed_ack_record_p delayed_ack_list_head = NULL; void transmit_message_data_delayed(char *to, char *message, char *path, time_t when) { delayed_ack_record_p ptr = delayed_ack_list_head; // We need to run down the current list looking for any records // that are identical and within 30 seconds time-wise of this // one. If so, don't allocate a new record. This keeps the // dupes down on transmit so that at the most we transmit one // ack per 30 seconds per QSO, except of course for real-time // ack's which don't go through this function. // Run through the queue and check each record while (ptr != NULL) { if ( strcmp(ptr->to_call_sign,to) == 0 && strcmp(ptr->message_line,message) == 0 ) { // // We have matches on call_sign and message. Check the // time next. // if (labs(when - ptr->active_time) < 30) { // // We're within 30 seconds of an identical ack. // Drop this new one (don't add it). // //fprintf(stderr,"Dropping delayed ack: Too close timewise to another: %s, %s\n", // to, message); return; // Don't allocate new record on queue } } ptr = ptr->next; } // If we made it to here, there aren't any queued ACK's that are // close enough in time to drop this new one. Add it to the // queue. //fprintf(stderr, "Queuing ACK for delayed transmit: %s, %s\n", // to, message); // Allocate a record to hold it ptr = (delayed_ack_record_p)malloc(sizeof(delayed_ack_record)); // Fill in the record xastir_snprintf(ptr->to_call_sign, sizeof(ptr->to_call_sign), "%s", to); xastir_snprintf(ptr->message_line, sizeof(ptr->message_line), "%s", message); if (path == NULL) { ptr->path[0] = '\0'; } else { xastir_snprintf(ptr->path, sizeof(ptr->path), "%s", path); } ptr->active_time = when; // Add the record to the head of the list ptr->next = delayed_ack_list_head; delayed_ack_list_head = ptr; } time_t delayed_transmit_last_check = (time_t)0; void check_delayed_transmit_queue(int curr_sec) { delayed_ack_record_p ptr = delayed_ack_list_head; int active_records = 0; // Skip this function if we did it during this second already. if (delayed_transmit_last_check == curr_sec) { return; } delayed_transmit_last_check = curr_sec; //fprintf(stderr, "Checking delayed TX queue for something to transmit.\n"); //fprintf(stderr, "."); // Run down the linked list checking every record. while (ptr != NULL) { if (ptr->active_time != 0) // Active record { char new_path[MAX_LINE_SIZE+1]; //fprintf(stderr, "Found active record\n"); active_records++; // Check for a custom path having been set in the Send // Message dialog. If so, use this for our outgoing // path instead and reset all of the queued message // paths to this station to this new path. // get_send_message_path(ptr->to_call_sign, new_path, sizeof(new_path)); if (new_path[0] != '\0' && strcmp(new_path, ptr->path) != 0) { // We have a custom path set which is different than // the path saved with the outgoing message. Change // the path to match the new path. // //fprintf(stderr, // "Changing queued ack's to new path: %s\n", // new_path); memcpy(ptr->path, new_path, sizeof(ptr->path)); ptr->path[sizeof(ptr->path)-1] = '\0'; // Terminate string } if (ptr->active_time <= sec_now()) { // Transmit it //fprintf(stderr,"Found something delayed to transmit! %ld\n",sec_now()); if (ptr->path[0] == '\0') { transmit_message_data(ptr->to_call_sign, ptr->message_line, NULL); } else { transmit_message_data(ptr->to_call_sign, ptr->message_line, ptr->path); } ptr->active_time = (time_t)0; } } ptr = ptr->next; } // Check if entire list contains inactive records. If so, // delete the list. // if (!active_records && (delayed_ack_list_head != NULL)) { // No active records, but the list isn't empty. Reclaim the // records in the list. while (delayed_ack_list_head != NULL) { ptr = delayed_ack_list_head->next; free(delayed_ack_list_head); //fprintf(stderr,"Free'ing delayed_ack record\n"); delayed_ack_list_head = ptr; } } } void check_and_transmit_messages(time_t time) { int i; char temp[200]; char to_call[40]; // Skip this function if we did it during this second already. if (last_check_and_transmit == time) { return; } last_check_and_transmit = time; for (i=0; i from <%s>:%s-%s\n", message_pool[i].tries, message_pool[i].to_call_sign, message_pool[i].from_call_sign, message_pool[i].message_line, message_pool[i].seq); pad_callsign(to_call,message_pool[i].to_call_sign); // Add Leading ":" as per APRS Spec. // Add trailing '}' to signify that we're // Reply/Ack protocol capable. last_ack_ptr = get_most_recent_ack(to_call); if (last_ack_ptr != NULL) xastir_snprintf(last_ack, sizeof(last_ack), "%s", last_ack_ptr); else { last_ack[0] = '\0'; } xastir_snprintf(temp, sizeof(temp), ":%s:%s{%s}%s", to_call, message_pool[i].message_line, message_pool[i].seq, last_ack); if (debug_level & 2) { fprintf(stderr,"MESSAGE OUT>%s<\n",temp); } // Check for a custom path having been set // in the Send Message dialog. If so, use // this for our outgoing path instead and // reset all of the queued message paths to // this station to this new path. // get_send_message_path(to_call, new_path, sizeof(new_path)); //fprintf(stderr,"get_send_message_path(%s) returned: %s\n",to_call,new_path); if (new_path[0] != '\0' && strcmp(new_path,message_pool[i].path) != 0) { // We have a custom path set which is // different than the path saved with // the outgoing message. // // Change all messages to that callsign // to match the new path. // change_path_outgoing_messages_to(to_call,new_path); } // Transmit the message transmit_message_data(message_pool[i].to_call_sign, temp, message_pool[i].path); message_pool[i].active_time = time + message_pool[i].next_time; //fprintf(stderr,"%d\n",(int)message_pool[i].next_time); } /* fprintf(stderr, "Msg Interval = %3ld seconds or %4.1f minutes\n", message_pool[i].next_time, message_pool[i].next_time / 60.0); */ // Record the interval we're using. Put it with // the message in the general message pool, so // that the Send Message dialog can display it. // It will only display it if the message is // actively being transmitted. If it has been // cancelled, timed out, or hasn't made it to // the transmit position yet, it won't be shown. // msg_record_interval_tries(message_pool[i].to_call_sign, message_pool[i].from_call_sign, message_pool[i].seq, message_pool[i].next_time, // Interval message_pool[i].tries); // Tries // Start at 7 seconds for the interval. We set // it to 7 seconds in output_message() above. // Double the interval each retry until we hit // 10 minutes. Keep transmitting at 10 minute // intervals until we hit MAX_TRIES. // Double the interval between messages message_pool[i].next_time = message_pool[i].next_time * 2; // Limit the max interval to 10 minutes if (message_pool[i].next_time > (time_t)600L) { message_pool[i].next_time = (time_t)600L; } message_pool[i].tries++; // Expire it if we hit the limit if (message_pool[i].tries > MAX_TRIES) { char temp[150]; char temp_to[20]; xastir_snprintf(temp,sizeof(temp),"To: %s, Msg: %s", message_pool[i].to_call_sign, message_pool[i].message_line); //popup_message(langcode("POPEM00004"),langcode("POPEM00017")); popup_message( "Retries Exceeded!", temp ); // Fake the system out: We're pretending // that we got an ACK back from it so that // we can either release the next message to // go out, or at least make the send button // sensitive again. // We need to copy the to_call_sign into // another variable because the // clear_acked_message() function clears out // the message then needs this parameter to // do another compare (to enable the Send Msg // button again). xastir_snprintf(temp_to, sizeof(temp_to), "%s", message_pool[i].to_call_sign); // Record a fake ack and add "*TIMEOUT*" to // the message. This will be displayed in // the Send Message dialog. msg_record_ack(temp_to, message_pool[i].from_call_sign, message_pool[i].seq, 1, // "1" specifies a timeout 0); // Not a cancel clear_acked_message(temp_to, message_pool[i].from_call_sign, message_pool[i].seq); // if (mw[i].send_message_dialog!=NULL) /* clear submit */ // XtSetSensitive(mw[i].button_ok,TRUE); } } } else { if (debug_level & 2) { fprintf(stderr,"Message #%s is waiting to have a previous one cleared\n",message_pool[i].seq); } } } } } // Function which marks a message as ack'ed in the transmit queue // and releases the next message to allow it to be transmitted. // Handles REPLY-ACK format or normal ACK format just fine. // void clear_acked_message(char *from, char *to, char *seq) { int i,ii; int found; char lowest[3]; char temp1[MAX_CALLSIGN+1]; char *temp_ptr; char msg_id[5+1]; // Copy seq into local variable xastir_snprintf(msg_id, sizeof(msg_id), "%s", seq); // Check for REPLY-ACK protocol. If found, terminate at the end // of the first ack. temp_ptr = strchr(msg_id, '}'); if (temp_ptr) { *temp_ptr = '\0'; } (void)remove_trailing_spaces(msg_id); // This is IMPORTANT here!!! //lowest=100000; // Highest Base-90 2-char string xastir_snprintf(lowest,sizeof(lowest),"zz"); found= -1; for (i=0; i <%s> from <%s> <%s> seq <%s> <%s>\n", to, message_pool[i].to_call_sign, from, message_pool[i].from_call_sign, msg_id, message_pool[i].seq); if (strcmp(message_pool[i].to_call_sign,from)==0) { if (debug_level & 1) { fprintf(stderr,"Matched message to_call_sign\n"); } if (strcmp(message_pool[i].from_call_sign,to)==0) { if (debug_level & 1) { fprintf(stderr,"Matched message from_call_sign\n"); } if (strcmp(message_pool[i].seq,msg_id)==0) { if (debug_level & 2) { fprintf(stderr,"Found and cleared\n"); } clear_outgoing_message(i); // now find and release next message, look for the lowest sequence? // What about when the sequence rolls over? for (i=0; i #include // printf #include #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "lang.h" #include "mutex_utils.h" #include "xa_config.h" #include "log_utils.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist #if defined(LESSTIF_VERSION) #define NO_DYNAMIC_WIDGETS 1 #endif #define MAX_PATH 200 Widget auto_msg_on, auto_msg_off; Widget auto_msg_dialog = (Widget)NULL; Widget auto_msg_set_data = (Widget)NULL; static xastir_mutex auto_msg_dialog_lock; xastir_mutex send_message_dialog_lock; void select_station_type(int ii); void messages_gui_init(void) { init_critical_section( &auto_msg_dialog_lock ); init_critical_section( &send_message_dialog_lock ); } /**** Send Message ******/ // This function chops off the first callsign, then returns a string // containing the same string in reversed callsign order. Note that // if RELAY was used by the sending station and that RELAY did _not_ // do callsign substitution, that part of the path will be chopped // heading back. If the sending station really needed that relay // station in order to receive the reply, he/she should have put in // a callsign instead of RELAY. We can't in good conscience use // RELAY on the end of the return path. // // We also chop off anything after comma "q" two letters, and a // comma. This is the injection-ID called the Q-construct, which // lets us know how a signal was injected into the NET and by whom. // void reverse_path(char *input_string) { char reverse_path[200]; int indexes[20]; int i, j, len; char temp[MAX_CALLSIGN+1]; // Check for NULL pointer if (input_string == NULL) { return; } // Check for zero-length string len = strlen(input_string); if (len == 0) { return; } // Initialize reverse_path[0] = '\0'; for (i = 0; i < 20; i++) { indexes[i] = -1; } // Add a comma onto the end (makes later code easier) input_string[len++] = ','; input_string[len] = '\0'; // Terminate it // Find each comma j = 0; for (i = 0; i < (int)strlen(input_string); i++) { if (input_string[i] == ',') { indexes[j++] = i; //fprintf(stderr,"%d\n",i); // Debug code } } // Get rid of asterisks and commas in the original string: for (i = 0; i < len; i++) { if (input_string[i] == '*' || input_string[i] == ',') { input_string[i] = '\0'; } } // Go left to right looking for a 3-letter callsign starting // with 'q'. If found readjust 'j' to skip that callsign and // everything after it. // for ( i = 0; i < j; i++) { char *c = &input_string[indexes[i] + 1]; //fprintf(stderr,"'%s'\t", c ); if (c[0] == 'q') { if ( strlen(c) == 3 ) // "qAR" { //fprintf(stderr,"Found:%s\n", c); j = i; } } } // Convert used "WIDEn-N"/"TRACEn-N" paths back to their // original glory. Convert "TRACE" to "WIDE" as well. We could // also choose to change "WIDEn-N" to a slimmer version based on // how many digi's were used, for instance "WIDE7-6" could // change to "WIDE1-1" or "WIDE7-1", and "WIDE5-2" could change // to "WIDE3-3" or "WIDE5-3". // for () // j now tells us how many were found. Now go in the reverse // order and concatenate the substrings together. Get rid of // "RELAY" and "TCPIP" calls as we're doing it. input_string[0] = '\0'; // Clear out the old string first for ( i = j - 1; i >= 0; i-- ) { if ( (input_string[indexes[i]+1] != '\0') && (strncasecmp(&input_string[indexes[i]+1],"RELAY",5) != 0) && (strncasecmp(&input_string[indexes[i]+1],"TCPIP",5) != 0) ) { // Snag each callsign into temp: xastir_snprintf(temp, sizeof(temp), "%s", &input_string[indexes[i]+1]); // Massage temp until it resembles something we want to // use. // "WIDEn" -> "WIDEn-N," // "TRACEn" -> "WIDEn-N," // "TRACE" -> "WIDE," if (strncasecmp(temp,"WIDE",4) == 0) { if ( (temp[4] != ',') && is_num_chr(temp[4]) ) { //fprintf(stderr,"Found a WIDEn-N\n"); xastir_snprintf(temp, sizeof(temp), "WIDE%c-%c", temp[4], temp[4]); } else { //fprintf(stderr,"Found a WIDE\n"); // Leave temp alone, it's just a WIDE } } else if (strncasecmp(temp,"TRACE",5) == 0) { if ( (temp[5] != ',') && is_num_chr(temp[5]) ) { //fprintf(stderr,"Found a TRACEn-N\n"); xastir_snprintf(temp, sizeof(temp), "WIDE%c-%c", temp[5], temp[5]); } else { //fprintf(stderr,"Found a TRACE\n"); // Convert it from TRACE to WIDE xastir_snprintf(temp, sizeof(temp), "WIDE"); } } // Add temp to the end of our path: strncat(reverse_path,temp,sizeof(reverse_path)-strlen(reverse_path)-1); strncat(reverse_path,",",sizeof(reverse_path)-strlen(reverse_path)-1); } } // Remove the ending comma reverse_path[strlen(reverse_path) - 1] = '\0'; // Save the new path back into the string we were given. strncat(input_string, reverse_path, len); } void get_path_data(char *callsign, char *path, int max_length) { DataRow *p_station; if (search_station_name(&p_station,callsign,1)) // Found callsign { char new_path[200]; if (p_station->node_path_ptr) { xastir_snprintf(new_path,sizeof(new_path), "%s", p_station->node_path_ptr); if(debug_level & 2) fprintf(stderr,"\nPath from %s: %s\n", callsign, new_path); // We need to chop off the first call, remove asterisks // and injection ID's, and reverse the order of the // callsigns. We need to do the same thing in the // callback for button_submit_call, so that we get a new // path whenever the callsign is changed. Create a new // TextFieldWidget to hold the path info, which gets // filled in here (and the callback) but can be changed by // the user. Must find a nice way to use this path from // output_my_data() as well. reverse_path(new_path); if (debug_level & 2) fprintf(stderr," Path to %s: %s\n", callsign, new_path); xastir_snprintf(path, max_length, "%s", new_path); } else { if (debug_level & 2) { fprintf(stderr," Path from %s is (null)\n",callsign); } path[0]='\0'; } } else // Couldn't find callsign. It's { // not in our station database. if(debug_level & 2) { fprintf(stderr,"Path from %s: No Path Known\n",callsign); } path[0] = '\0'; } } static Widget change_path_dialog = NULL; static Widget current_path = NULL; void Send_message_change_path_destroy_shell(Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { if (change_path_dialog) { XtPopdown(change_path_dialog); XtDestroyWidget(change_path_dialog); } change_path_dialog = (Widget)NULL; } // Apply button // Fetch the text from the "current_path" widget and place it into // the mw[ii].send_message_path widget. // void Send_message_change_path_apply(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { char path[MAX_PATH+1]; char *temp_ptr; if (current_path != NULL && clientData != NULL) { temp_ptr = XmTextFieldGetString(current_path); xastir_snprintf(path, sizeof(path), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(path); (void)to_upper(path); // Check here for "DIRECT PATH" or "DEFAULT PATH". If one of them, // do some special processing if need be so that lower layers will // interpret it correctly. XmTextFieldSetString(clientData, path); Send_message_change_path_destroy_shell(NULL, NULL, NULL); } } // "Direct Path" button // // Put "DIRECT PATH" in the widgets. We pass "DIRECT PATH" all the // way to the transmit routines, then change it to an empty path // when the transmit actually goes out. // void Send_message_change_path_direct(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { if (current_path == NULL || clientData == NULL) { Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Change current_path widget XmTextFieldSetString(current_path, "DIRECT PATH"); Send_message_change_path_apply(NULL, clientData, NULL); } // "Default Path(s)" button // // Blank out the path so the default paths get used. We pass // "DEFAULT PATH" all the way to the transmit routines, then change // it there to be a blank. // void Send_message_change_path_default(Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { if (current_path == NULL || clientData == NULL) { Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Change current_path widget XmTextFieldSetString(current_path, "DEFAULT PATH"); Send_message_change_path_apply(NULL, clientData, NULL); } // TODO: Change the "Path:" box so that clicking or double-clicking // on it will bring up a "Change Path" dialog. Could also use a // "Change" or "Change Path" button if easier. This new dialog // should have the current path (editable), the reverse path (not // editable), and these buttons: // // "DIRECT path" // "DEFAULT path(s)" // "Apply" // "Cancel" // // Of course the underlying code will have to tweaked to be able to // pass an EMPTY path all the way down through the layers. We can't // currently do that. We'll have to define a specific string for // that. Insert the text "--DEFAULT--", "--BLANK--", or the actual // path in the editable box and in the "Path:" box on the Send // Message dialog so that the user knows which one is in effect. // // Remember to close the Change Path dialog if we close the Send // Message dialog which corresponds to it. // // Adding this new CHANGE PATH dialog will allow us to get rid of // three bugs on the active bug-list: #1499820, #1326975, and // #1326973. // void Send_message_change_path( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { int ii; //Atom delw; Widget pane, form, current_path_label, reverse_path_label, reverse_path, button_default, button_direct, button_apply, button_cancel; Widget button_wide11, button_wide21, button_wide22, button_nogate; char *temp_ptr; char temp1[MAX_LINE_SIZE+1]; char path[MAX_PATH+1]; //begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_change_path" ); if (clientData == NULL) { return; } if (change_path_dialog) { // Destroy the old one before creating a new one Send_message_change_path_destroy_shell(NULL, NULL, NULL); } // Fetch Send Message dialog number from clientData, store in // "ii". // ii = atoi(clientData); // "Change Path" change_path_dialog = XtVaCreatePopupShell(langcode("WPUPMSB019"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNtitleString,"Change Path", XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Send_message_change_path pane", xmPanedWindowWidgetClass, change_path_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); form = XtVaCreateWidget("Send_message_change_path form", xmFormWidgetClass, pane, XmNfractionBase, 4, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Path:" current_path_label = XtVaCreateManagedWidget(langcode("WPUPMSB010"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); current_path = XtVaCreateManagedWidget("Send_message_change_path path", xmTextFieldWidgetClass, form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 26, XmNwidth, ((26*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, current_path_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // "Reverse Path:" reverse_path_label = XtVaCreateManagedWidget(langcode("WPUPMSB022"), xmLabelWidgetClass, form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, current_path, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); reverse_path = XtVaCreateManagedWidget("Send_message_change_path reverse path", xmTextFieldWidgetClass, form, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 26, XmNwidth, ((26*7)+2), XmNmaxLength, 199, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, reverse_path_label, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide11 = XtVaCreateManagedWidget("WIDE1-1", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide21 = XtVaCreateManagedWidget("WIDE2-1", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_wide22 = XtVaCreateManagedWidget("WIDE2-2", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_nogate = XtVaCreateManagedWidget("NOGATE", xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, current_path_label, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtSetSensitive(button_wide11, FALSE); XtSetSensitive(button_wide21, FALSE); XtSetSensitive(button_wide22, FALSE); XtSetSensitive(button_nogate, FALSE); // "Use Default Path(s)" button_default = XtVaCreateManagedWidget(langcode("WPUPMSB020"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Direct (No path)" button_direct = XtVaCreateManagedWidget(langcode("WPUPMSB021"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Apply" button_apply = XtVaCreateManagedWidget(langcode("UNIOP00032"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Close" button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, button_wide11, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_default, XmNactivateCallback, Send_message_change_path_default, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_direct, XmNactivateCallback, Send_message_change_path_direct, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_apply, XmNactivateCallback, Send_message_change_path_apply, (XtPointer)mw[ii].send_message_path); XtAddCallback(button_cancel, XmNactivateCallback, Send_message_change_path_destroy_shell,(XtPointer)mw[ii].win); // Fill in the fields if(mw[ii].send_message_dialog != NULL) { char call_sign[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); XmTextFieldSetString(current_path, temp1); // Go get the reverse path. Start with the callsign. temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(call_sign, sizeof(call_sign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_dash_zero(call_sign); // Try lowercase get_path_data(call_sign, path, MAX_PATH); if (strlen(path) == 0) { // Try uppercase (void)to_upper(call_sign); get_path_data(call_sign, path, MAX_PATH); } XmTextFieldSetString(reverse_path, path); } pos_dialog(change_path_dialog); //delw (void)XmInternAtom(XtDisplay(change_path_dialog),"WM_DELETE_WINDOW", FALSE); // XmAddWMProtocolCallback(change_path_dialog, delw, Send_message_destroy_shell, (XtPointer)mw[ii].win); XtManageChild(form); XtManageChild(pane); XtPopup(change_path_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(change_path_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); //end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_change_path" ); } // Find a custom path set in a Send Message dialog, using the remote // callsign as the key. If no custom path, sets path to '\0'. // void get_send_message_path(char *callsign, char *path, int path_size) { int ii; int found = -1; char *temp_ptr; char temp1[MAX_LINE_SIZE+1]; char my_callsign[20]; xastir_snprintf(my_callsign,sizeof(my_callsign),"%s",callsign); remove_trailing_spaces(my_callsign); //fprintf(stderr,"Looking for %s\n", my_callsign); for(ii = 0; ii < MAX_MESSAGE_WINDOWS; ii++) { // find matching callsign if(mw[ii].send_message_dialog != NULL) { temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_dash_zero(temp1); (void)to_upper(temp1); if(strcmp(temp1,my_callsign)==0) { found = ii; break; } } } if (found == -1) { //fprintf(stderr,"Didn't find dialog\n"); path[0] = '\0'; return; } // We have the correct Send Message dialog. Snag the path. // temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)to_upper(temp1); (void)remove_leading_spaces(temp1); (void)remove_trailing_spaces(temp1); // Path empty? if (temp1[0] == '\0') { //fprintf(stderr,"Didn't find custom path\n"); path[0] = '\0'; return; } // We have a real path! Stuff it into the path variable. xastir_snprintf(path, path_size, "%s", temp1); //fprintf(stderr,"Found custom path: %s\n", path); } void Send_message_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData)) { int ii; // char *temp_ptr; // char temp1[MAX_LINE_SIZE+1]; //fprintf(stderr,"3Send_message_destroy_shell() start\n"); ii=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_destroy_shell" ); if (mw[ii].send_message_dialog) { /* // Check whether the send_message_call_data field has a // custom path entered. temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(temp1); (void)remove_trailing_spaces(temp1); (void)remove_trailing_dash_zero(temp1); if(temp1[0] != '\0') { // Yep, we have a custom path. Warn the user that // they're going to lose this path by destroying the // dialog. popup_message_always(langcode("POPEM00036"), langcode("POPEM00040")); } */ XtPopdown(mw[ii].send_message_dialog); XtDestroyWidget(mw[ii].send_message_dialog); } mw[ii].send_message_dialog = (Widget)NULL; mw[ii].to_call_sign[0] = '\0'; mw[ii].send_message_call_data = (Widget)NULL; mw[ii].D700_mode = (Widget)NULL; mw[ii].D7_mode = (Widget)NULL; mw[ii].HamHUD_mode = (Widget)NULL; mw[ii].message_data_line1 = (Widget)NULL; mw[ii].message_data_line2 = (Widget)NULL; mw[ii].message_data_line3 = (Widget)NULL; mw[ii].message_data_line4 = (Widget)NULL; mw[ii].send_message_text = (Widget)NULL; Send_message_change_path_destroy_shell(NULL, NULL, NULL); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_destroy_shell" ); //fprintf(stderr,"3Send_message_destroy_shell() finished\n"); } void Check_new_call_messages( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { int pos; intptr_t i; i=(intptr_t)clientData; /* clear window*/ pos=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Check_new_call_messages" ); if (mw[i].send_message_dialog) { // If we have a dialog already, clear out the message area // from 0 to the last text position. // Known to have memory leaks with some versions of Motif: //XmTextSetString(mw[i].send_message_text,""); XmTextReplace(mw[i].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[i].send_message_text), ""); // Set the cursor position to 0 XtVaSetValues(mw[i].send_message_text,XmNcursorPosition,pos,NULL); } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Check_new_call_messages" ); update_messages(1); // Force an immediate update if (mw[i].send_message_dialog) { // Re-arrange the outgoing message boxes based on the type of device we're talking to. select_station_type(i); } } void Clear_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { clear_outgoing_messages(); } void Send_message_now( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; char temp2[121]; char temp_line1[68] = ""; #ifndef NO_DYNAMIC_WIDGETS char temp_line2[23] = ""; char temp_line3[23] = ""; char temp_line4[10] = ""; #endif // NO_DYNAMIC_WIDGETS char path[200]; int ii, jj; char *temp_ptr; int substitution_made = 0; int d700; int d7; int hamhud; char temp_file_path[MAX_VALUE]; ii=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_now" ); if (mw[ii].send_message_dialog) { d700 = XmToggleButtonGetState(mw[ii].D700_mode); d7 = XmToggleButtonGetState(mw[ii].D7_mode); hamhud = XmToggleButtonGetState(mw[ii].HamHUD_mode); temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); // Fetch message_data_line1 in all cases temp_ptr = XmTextFieldGetString(mw[ii].message_data_line1); xastir_snprintf(temp_line1, sizeof(temp_line1), "%s", temp_ptr); XtFree(temp_ptr); #ifndef NO_DYNAMIC_WIDGETS // If D700/D7 mode, fetch message_data_line2 if (d700 || d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line2); xastir_snprintf(temp_line2, sizeof(temp_line2), "%s", temp_ptr); XtFree(temp_ptr); } // If D700/D7 mode, fetch message_data_line3 if (d700 || d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line3); xastir_snprintf(temp_line3, sizeof(temp_line3), "%s", temp_ptr); XtFree(temp_ptr); } // If D7 mode, fetch message_data_line4 if (d7) { temp_ptr = XmTextFieldGetString(mw[ii].message_data_line4); xastir_snprintf(temp_line4, sizeof(temp_line4), "%s", temp_ptr); XtFree(temp_ptr); } // Construct the entire message now if (hamhud) // Combine two lines together { xastir_snprintf(temp2, sizeof(temp2), "%-20s%-47s", temp_line1, temp_line2); } else if (d700) // Combine three lines together { xastir_snprintf(temp2, sizeof(temp2), "%-22s%-22s%-20s", temp_line1, temp_line2, temp_line3); } else if (d7) // Combine four lines together { xastir_snprintf(temp2, sizeof(temp2), "%-12s%-12s%-12s%-9s", temp_line1, temp_line2, temp_line3, temp_line4); } else #endif // NO_DYNAMIC_WIDGETS { // Use line1 only xastir_snprintf(temp2, sizeof(temp2), "%s", temp_line1); } // We have the message text now. Check it for illegal // characters, remove them and substitute '.' if found. // Illegal characters are '|', '{', and '~' for messaging. for (jj = 0; jj < (int)strlen(temp2); jj++) { if ( temp2[jj] == '|' || temp2[jj] == '{' || temp2[jj] == '~' ) { temp2[jj] = '.'; // Replace with a dot substitution_made++; } } if (substitution_made) { popup_message_always(langcode("POPEM00022"), langcode("POPEM00039")); } (void)remove_trailing_spaces(temp2); temp_ptr = XmTextFieldGetString(mw[ii].send_message_path); xastir_snprintf(path, sizeof(path), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(path); (void)to_upper(path); if(debug_level & 2) fprintf(stderr, "Send message to <%s> from <%s> :%s\n", temp1, mw[ii].to_call_sign, temp2); if ( (strlen(temp1) != 0) // Callsign field is not blank && (strlen(temp2) != 0) // Message field is not blank && (strcmp(temp1,my_callsign) ) ) // And not my own callsign { /* if you're sending a message you must be at the keyboard */ auto_reply=0; XmToggleButtonSetState(auto_msg_toggle,FALSE,FALSE); statusline(langcode("BBARSTA011"),0); // Auto Reply Messages OFF output_message(mw[ii].to_call_sign,temp1,temp2,path); //fprintf(stderr," 1111111111222222222233333333334444444444555555555566666666\n"); //fprintf(stderr,"1234567890123456789012345678901234567890123456789012345678901234567\n"); //fprintf(stderr,"%s\n",temp2); XmTextFieldSetString(mw[ii].message_data_line1,""); if (mw[ii].message_data_line2) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line2,""); } if (mw[ii].message_data_line3) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line3,""); } if (mw[ii].message_data_line4) // If exists, blank it { XmTextFieldSetString(mw[ii].message_data_line4,""); } // if (mw[ii].message_group!=1) // XtSetSensitive(mw[ii].button_ok,FALSE); // Do message logging if that feature is enabled. if (log_message_data) { char temp_msg[MAX_MESSAGE_LENGTH+1]; strcpy(temp_msg, mw[ii].to_call_sign);// To temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ">"); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, temp1); // From temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ","); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, path); // Path temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, ":"); temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string strcat(temp_msg, temp2); // Message temp_msg[sizeof(temp_msg)-1] = '\0'; // Terminate string log_data( get_user_base_dir(LOGFILE_MESSAGE, temp_file_path, sizeof(temp_file_path)), temp_msg ); } } else { if ( strcmp(temp1,my_callsign) == 0 ) // It's my own callsign { popup_message_always(langcode("POPEM00022"), langcode("POPEM00054")); // We're trying to talk to ourselves! } else if ( strlen(temp1) == 0 ) // Callsign field is blank { popup_message_always(langcode("POPEM00022"), langcode("POPEM00052")); // Callsign is EMPTY! } else if ( strlen(temp2) == 0 ) // Message field is blank { popup_message_always(langcode("POPEM00022"), langcode("POPEM00053")); // Message is EMPTY! } } } // Move focus to the first message box to make typing the next // message easier. XmProcessTraversal(mw[ii].message_data_line1, XmTRAVERSE_CURRENT); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message_now" ); } void Clear_message_from( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; int i; char *temp_ptr; /* int pos;*/ i=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_from" ); if (mw[i].send_message_dialog) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); /*fprintf(stderr,"Clear message from <%s> to <%s>\n",temp1,my_callsign);*/ mdelete_messages_from(temp1); new_message_data=1; } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_from" ); } void Clear_message_to( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char temp1[MAX_CALLSIGN+1]; int i; char *temp_ptr; i=atoi((char *)clientData); begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to" ); if (mw[i].send_message_dialog) { temp_ptr = XmTextFieldGetString(mw[i].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); /*fprintf(stderr,"Clear message to <%s>\n",temp1);*/ mdelete_messages_to(temp1); new_message_data=1; } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to" ); } void Clear_message_to_from( Widget w, XtPointer clientData, XtPointer callData) { int i, pos; Clear_message_to(w, clientData, callData); Clear_message_from(w, clientData, callData); i=atoi((char *)clientData); /* clear window*/ pos=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); if (mw[i].send_message_dialog) { // Known to have memory leaks with some versions of Motif: //XmTextSetString(mw[i].send_message_text,""); // Clear out the message window XmTextReplace(mw[i].send_message_text, (XmTextPosition) 0, XmTextGetLastPosition(mw[i].send_message_text), ""); // Set the cursor position to 0 XtVaSetValues(mw[i].send_message_text,XmNcursorPosition,pos,NULL); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); update_messages(1); // Force an update to clear the window begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); } end_critical_section(&send_message_dialog_lock, "messages_gui.c:Clear_message_to_from" ); } void Kick_timer( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp_ptr; char temp1[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[atoi(clientData)].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); kick_outgoing_timer(temp1); } void Clear_messages_to( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char *temp_ptr; char temp1[MAX_CALLSIGN+1]; temp_ptr = XmTextFieldGetString(mw[atoi(clientData)].send_message_call_data); xastir_snprintf(temp1, sizeof(temp1), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp1); (void)to_upper(temp1); (void)remove_trailing_dash_zero(temp1); clear_outgoing_messages_to(temp1); update_messages(1); // Force an update to the window } void Send_message_call( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { char call[20]; if(clientData != NULL) { xastir_snprintf(call, sizeof(call), "%s", (char *)clientData); Send_message(appshell, call, NULL); } } // These are used for callbacks below so that we have a unique // identifier for the XtRemoveCallback() function to work with. The // last two parameters of an XtAddCallback() or XtRemoveCallback() // must be unique. // void Send_message_now_1( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_2( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_3( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void Send_message_now_4( Widget w, XtPointer clientData, XtPointer callData) { Send_message_now( w, clientData, callData); } void build_send_message_input_boxes(int i, int hamhud, int d700, int d7) { //fprintf(stderr, "\n build: i:%d hamhud:%d d700:%d d7:%d\n", i, hamhud, d700, d7); // Skip most of these sections and go to the default section if // using LSB. We have problems with Lesstif segfaulting on us // otherwise. #ifndef NO_DYNAMIC_WIDGETS // HamHUD mode (Here we're assuming the 4x20 LCD in the HamHUD-II) if (hamhud) { // Draw a textfield widget of size 20 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // HamHUD will display all 67 chars, but only stores the first 20, // therefore if you want the recipient to be able to look at it // later, only send them 20 chars per message. /* // Draw another textfield widget of size 47 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 43, XmNwidth, ((43*7)), XmNmaxLength, 47, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); */ } // D700A mode else if (d700) { // Draw a textfield widget of size 22 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 22, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw another textfield widget of size 22 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 22, XmNwidth, ((22*7)), XmNmaxLength, 22, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw another textfield widget of size 20 mw[i].message_data_line3 = XtVaCreateManagedWidget("Send_message line3", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 21, XmNwidth, ((21*7)), XmNmaxLength, 20, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line2, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } // D7A/D7E Mode else if (d7) { // Draw a textfield widget of size 12 mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw a textfield widget of size 12 mw[i].message_data_line2 = XtVaCreateManagedWidget("Send_message line2", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line1, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Separate the next two from the previous two for a bit, to help // indicate that the first two are one screen on a TH-D7, the next // two are another screen. // Draw a textfield widget of size 12 mw[i].message_data_line3 = XtVaCreateManagedWidget("Send_message line3", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 12, XmNwidth, ((12*7)+4), XmNmaxLength, 12, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line2, XmNleftOffset, 15, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); // Draw a textfield widget of size 9 mw[i].message_data_line4 = XtVaCreateManagedWidget("Send_message line4", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNwidth, ((10*7)+0), XmNmaxLength, 9, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message_data_line3, XmNleftOffset, 2, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } // Standard APRS Mode else // Standard APRS message box size (67) #endif // NO_DYNAMIC_WIDGETS { mw[i].message_data_line1 = XtVaCreateManagedWidget("Send_message smmd", xmTextFieldWidgetClass, mw[i].form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 67, XmNwidth, ((65*7)+2), XmNmaxLength, 67, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, mw[i].button_clear_old_msgs, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, mw[i].message, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); } //fprintf(stderr,"Starting to add callbacks\n"); if (mw[i].message_data_line1) // If exists, add another callback { XtAddCallback(mw[i].message_data_line1, XmNactivateCallback, Send_message_now_1, (XtPointer)mw[i].win); } if (mw[i].message_data_line2) // If exists, add another callback { XtAddCallback(mw[i].message_data_line2, XmNactivateCallback, Send_message_now_2, (XtPointer)mw[i].win); } if (mw[i].message_data_line3) // If exists, add another callback { XtAddCallback(mw[i].message_data_line3, XmNactivateCallback, Send_message_now_3, (XtPointer)mw[i].win); } if (mw[i].message_data_line4) // If exists, add another callback { XtAddCallback(mw[i].message_data_line4, XmNactivateCallback, Send_message_now_4, (XtPointer)mw[i].win); } //fprintf(stderr,"Exiting build_send_message_input_boxes()\n"); } void rebuild_send_message_input_boxes(int ii, int hamhud, int d700, int d7) { //fprintf(stderr, "\nrebuild: ii:%d hamhud:%d d700:%d d7:%d\n", ii, hamhud, d700, d7); // Lesstif appears to have a problem with removing/adding widgets to // a dialog that's already been created and will segfault in this // case. In order to make LSB-Xastir more reliable we disable the // dynamically-created widget code here and stick with the default // setup (one long TextField widget for input). // // Perhaps we need to do a Lesstif detect and do the same thing // anytime Lesstif is used as well? #ifndef NO_DYNAMIC_WIDGETS // Remove the current message widgets if (mw[ii].message_data_line4) { XtDestroyWidget(mw[ii].message_data_line4); } if (mw[ii].message_data_line3) { XtDestroyWidget(mw[ii].message_data_line3); } if (mw[ii].message_data_line2) { XtDestroyWidget(mw[ii].message_data_line2); } if (mw[ii].message_data_line1) { XtDestroyWidget(mw[ii].message_data_line1); } mw[ii].message_data_line1 = (Widget)NULL; mw[ii].message_data_line2 = (Widget)NULL; mw[ii].message_data_line3 = (Widget)NULL; mw[ii].message_data_line4 = (Widget)NULL; // Build the new boxes build_send_message_input_boxes(ii, hamhud, d700, d7); #endif // NO_DYNAMIC_WIDGETS } void HamHUD_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii =(intptr_t)clientData; int hamhud; hamhud = XmToggleButtonGetState(mw[ii].HamHUD_mode); if (hamhud) { XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, hamhud, 0, 0); } void D700_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii = (intptr_t)clientData; int d700; d700 = XmToggleButtonGetState(mw[ii].D700_mode); if (d700) { XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, 0, d700, 0); } void D7_Msg( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { intptr_t ii = (intptr_t)clientData; int d7; d7 = XmToggleButtonGetState(mw[ii].D7_mode); if (d7) { XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); } rebuild_send_message_input_boxes(ii, 0, 0, d7); } // Select HamHUD/D7/D700/Normal APRS messaging based on info // available in the station record. Change the Send Message dialog // to match. // // Only call this when the Send Message dialog is first constructed // or when we hit the New/Refresh Call button. We don't want to // have the user fighting against this function every sent or // received packet if this function happens to guess wrong. // void select_station_type(int ii) { DataRow *p_station; char call_sign[MAX_CALLSIGN+1]; char *temp_ptr; if (mw[ii].send_message_call_data == NULL) { fprintf(stderr,"messages_gui.c:select_station_type():mw[ii].send_message_call_data is NULL\n"); return; } temp_ptr = XmTextFieldGetString(mw[ii].send_message_call_data); xastir_snprintf(call_sign, sizeof(call_sign), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(call_sign); (void)to_upper(call_sign); // We have the callsign. See if we have the station name in our // database. if (call_sign[0] != '\0' && search_station_name(&p_station, call_sign, 1) ) // Exact match { int hamhud = 0; int d700 = 0; int d7 = 0; // int tx_only = 0; //fprintf(stderr,"Found callsign: %s\n", call_sign); // check if station appears to be a transmit only station such as the TinyTrak and OpenTrak trackers. // ********* wrong test ********** //if (p_station->aprs_symbol != NULL) { // if (p_station->aprs_symbol.aprs_type != NULL) { // fprintf(stderr,"Has Type: %s\n", p_station->aprs_symbol.aprs_type); // if is_tx_only(p_station) { // tx_only++; // } // } //} // Check first two comment records, if they exist if (p_station->comment_data != NULL) { // Check first comment record if (strstr(p_station->comment_data->text_ptr,"TM-D700")) { d700++; } else if (strstr(p_station->comment_data->text_ptr,"TH-D7")) { d7++; } else if (p_station->comment_data->next) { // Check second comment record if (strstr(p_station->comment_data->next->text_ptr,"TM-D700")) { d700++; } else if (strstr(p_station->comment_data->next->text_ptr,"TH-D7")) { d7++; } } } // If not D700 or D7, check for HamHUD in the TOCALL. // APHH2/APRHH2. We'll skip the version number so-as to // catch future versions as well. // if (!d700 && !d7) { if (p_station->node_path_ptr) { if (strncmp(p_station->node_path_ptr,"APRHH",5) == 0 || strncmp(p_station->node_path_ptr,"APHH",4) == 0) { hamhud++; } } } if (hamhud) { // fprintf(stderr,"HamHUD found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,TRUE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, hamhud, 0, 0); } else if (d700) { // fprintf(stderr,"D700 found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,TRUE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, 0, d700, 0); } else if (d7) { // fprintf(stderr,"D7 found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,TRUE,FALSE); rebuild_send_message_input_boxes(ii, 0, 0, d7); } else { // fprintf(stderr,"Standard APRS found\n"); XmToggleButtonSetState(mw[ii].HamHUD_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D700_mode,FALSE,FALSE); XmToggleButtonSetState(mw[ii].D7_mode,FALSE,FALSE); rebuild_send_message_input_boxes(ii, 0, 0, d7); } } } // The main Send Message dialog. db.c:update_messages() is the // function which fills in the message history information. // // The underlying code has been tweaked so that we can pass an EMPTY // path all the way down through the layers. We defined special // strings for that and for setting default paths, and display these // to the user in this and the Change Path dialogs: // // "DEFAULT PATH" // "DIRECT PATH" // // A note from Jim Fuller, N7VR: // // "I just set a test setup to my TH-D7GA. First Display shows // two lines 12 characters each, with the a third line of 12 // character and fourth line of 9 characters on the second display // by pressing ok. This means 45 characters for max message. // // On my D-700, main first display is like the TH-D7GA. But when // I go to the message display it displays three lines. The first // two are 22 characters and the last is 20 characters. This // means 64 characters total. // // I would only send a 24 character message to field troops, based // on first read capability." // // void Send_message( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(callData) ) { Arg args[50]; char temp[60]; unsigned int n; int j; intptr_t i; char group[MAX_CALLSIGN+1]; int groupon; int box_len; Atom delw; //fprintf(stderr,"\n1Send_message\n"); groupon=0; box_len=105; i=0; begin_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message" ); for(j=0; j key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(mw[i].send_message_dialog); XmProcessTraversal(mw[i].button_cancel, XmTRAVERSE_CURRENT); } //fprintf(stderr,"2calling select_station_type()\n"); // Re-arrange the outgoing message boxes based on the type of // device we're talking to. select_station_type(i); //fprintf(stderr,"2returned from select_station_type()\n"); //fprintf(stderr,"1end of Send_message()\n"); end_critical_section(&send_message_dialog_lock, "messages_gui.c:Send_message" ); } // Bring up a Send Message dialog for each QSO that has pending // outbound messages. // void Show_pending_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { intptr_t ii; int msgs_found = 0; // Look through the outgoing message queue. Find all callsigns // that we're currently trying to send messages to. // for (ii = 0; ii < MAX_OUTGOING_MESSAGES; ii++) { // If it matches the callsign we're talking to if (message_pool[ii].active==MESSAGE_ACTIVE) { msgs_found++; // Bring up a Send Message box for each callsign found. Send_message_call(NULL, message_pool[ii].to_call_sign, NULL); // Fill in the old data in case it doesn't auto-fill Check_new_call_messages(NULL, (XtPointer)ii, NULL); } } if (msgs_found == 0) { fprintf(stderr, "No Pending Messages.\n"); } } /************************* Auto msg **************************************/ /*************************************************************************/ void Auto_msg_option( Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { int item_no = XTPOINTER_TO_INT(clientData); if (item_no) { auto_reply = 1; } else { auto_reply = 0; } } void Auto_msg_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_destroy_shell" ); XtDestroyWidget(shell); auto_msg_dialog = (Widget)NULL; end_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_destroy_shell" ); } void Auto_msg_set_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[110]; char *temp_ptr; temp_ptr = XmTextFieldGetString(auto_msg_set_data); substr(temp, temp_ptr, 99); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); memcpy(auto_reply_message, temp, sizeof(auto_reply_message)); auto_reply_message[sizeof(auto_reply_message)-1] = '\0'; // Terminate string Auto_msg_destroy_shell(w, clientData, callData); } void Auto_msg_set( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, reply; Atom delw; begin_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_set" ); if(!auto_msg_dialog) { auto_msg_dialog = XtVaCreatePopupShell(langcode("WPUPARM001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Auto_msg_set pane", xmPanedWindowWidgetClass, auto_msg_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Auto_msg_set my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); reply = XtVaCreateManagedWidget(langcode("WPUPARM002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); auto_msg_set_data = XtVaCreateManagedWidget("Auto_msg_set auto_msg_set_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 40, XmNwidth, ((40*7)+2), XmNmaxLength, 100, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, reply, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("UNIOP00001"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_msg_set_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, auto_msg_set_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Auto_msg_set_now, auto_msg_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Auto_msg_destroy_shell, auto_msg_dialog); pos_dialog(auto_msg_dialog); delw = XmInternAtom(XtDisplay(auto_msg_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(auto_msg_dialog, delw, Auto_msg_destroy_shell, (XtPointer)auto_msg_dialog); XmTextFieldSetString(auto_msg_set_data,auto_reply_message); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, auto_msg_dialog); XtPopup(auto_msg_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(auto_msg_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(auto_msg_dialog), XtWindow(auto_msg_dialog)); } end_critical_section(&auto_msg_dialog_lock, "messages_gui.c:Auto_msg_set" ); } Xastir-Release-2.2.4/src/mgrs_utils.c0000664000175000017500000002606015151324131016450 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include "snprintf.h" #include "xastir.h" #include "main.h" #include "datum.h" // To produce MGRS coordinates, we'll call ll_to_utm_ups() // [?? Earlier text: "the above function" ??] // then convert the result to the 2-letter digraph format used // for MGRS. The ll_to_utm_ups() function switches to the special // irregular UTM zones for the areas near Svalbard and SW Norway // if the "coordinate_system" variable is set to "USE_MGRS", // so we'll be using the correct zone boundaries for MGRS if that // variable is set when we make the call. // // If "nice_format" == 1, we add leading spaces plus spaces between // the easting and northing in order to line up more nicely with the // UTM output format. // // convert_xastir_to_MGRS_str is a wrapper around the components // function below that returns the MGRS coordinate of x and y as a // single MGRS string. // /* convert_xastir_to_MGRS_str_components returns each of the components of the MGRS string separately. Example MGRS string: 18T VK 66790 55998 Parameters: utmZone Returns the UTM zone: e.g. 18T utmZone_len length of the utmZone char[] EastingL Returns the first letter of the MGRS digraph: e.g. V EastingL_len length of the EastingL char[] NorthingL Returns the second letter of the MGRS digraph: e.g. K NorthingL_len length of the NorthingL char[] int_utmEasting returns the MGRS easting: e.g. 66790 int_utmNorthing returns the MGRS northing: e.g. 55998 x xastir x coordinate to obtain MGRS coordinate for. y xastir x coordinate to obtain MGRS coordinate for. nice_format 1 for populate space_string with three spaces 0 to make space_string and empty string, see above. space_string Returned string that can be used to make MGRS strings allign more cleanly with UTM strings. space_string_len length of the space_string char[] */ void convert_xastir_to_MGRS_str_components(char *utmZone, int UNUSED(utmZone_len), char *EastingL, int EastingL_len, char *NorthingL, int NorthingL_len, unsigned int *int_utmEasting, unsigned int *int_utmNorthing, long x, long y, int nice_format, char *space_string, int UNUSED(space_string_len) ) { double utmNorthing; double utmEasting; //char utmZone[10]; int start; int my_east, my_north; //unsigned int int_utmEasting, int_utmNorthing; int UPS = 0; int North_UPS = 0; int coordinate_system_save = coordinate_system; //char space_string[4] = " "; // Three spaces // Set for correct zones coordinate_system = USE_MGRS; ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), &utmNorthing, &utmEasting, utmZone, sizeof(utmZone) ); utmZone[9] = '\0'; // Restore it coordinate_system = coordinate_system_save; //fprintf(stderr,"%s %07.0f %07.0f\n", utmZone, utmEasting, //utmNorthing ); //xastir_snprintf(str, str_len, "%s %07.0f %07.0f", // utmZone, utmEasting, utmNorthing ); // Convert the northing and easting values to the digraph letter // format. Letters 'I' and 'O' are skipped for both eastings // and northings. Letters 'W' through 'Z' are skipped for // northings. // // N/S letters alternate in a cycle of two. Begins at the // equator with A and F in alternate zones. Odd-numbered zones // use A-V, even-numbered zones use F-V, then A-V. // // E/W letters alternate in a cycle of three. Each E/W zone // uses an 8-letter block. Starts at A-H, then J-R, then S-Z, // then repeats every 18 degrees. // // N/S letters have a cycle of two, E/W letters have a cycle of // three. The same lettering repeats after six zones (2,000,000 // meter intervals). // // AA is at equator and 180W. // Easting: Each zone covers 6 degrees. Zone 1 = A-H, Zone 2 = // J-R, Zone 3 = S-Z, then repeat. So, take zone number-1, // modulus 3, multiple that number by 8. Modulus 24. That's // our starting letter for the zone. Take the easting number, // divide by 100,000, , add the starting number, compute modulus // 24, then use that index into our E_W array. // // Northing: Figure out whether even/odd zone number. Divide // by 100,000. If even, add 5 (starts at 'F' if even). Compute // modulus 20, then use that index into our N_S array. *int_utmEasting = (unsigned int)utmEasting; *int_utmNorthing = (unsigned int)utmNorthing; *int_utmEasting = *int_utmEasting % 100000; *int_utmNorthing = *int_utmNorthing % 100000; // Check for South Polar UPS area, set flags if found. if ( utmZone[0] == 'A' || utmZone[0] == 'B' || utmZone[1] == 'A' || utmZone[1] == 'B' || utmZone[2] == 'A' || utmZone[2] == 'B' ) { // We're in the South Polar UPS area UPS++; } // Check for North Polar UPS area, set flags if found. else if ( utmZone[0] == 'Y' || utmZone[0] == 'Z' || utmZone[1] == 'Y' || utmZone[1] == 'Z' || utmZone[2] == 'Y' || utmZone[2] == 'Z') { // We're in the North Polar UPS area UPS++; North_UPS++; } else { // We're in the UTM area. Set no flags. } if (UPS) // Special processing for UPS area (A/B/Y/Z bands) { // Note: Zone number isn't used for UPS, but zone letter is. if (nice_format) // Add two leading spaces { utmZone[2] = utmZone[0]; utmZone[0] = ' '; utmZone[1] = ' '; utmZone[3] = '\0'; } else { space_string[0] = '\0'; } if (North_UPS) // North polar UPS zone { char UPS_N_Easting[15] = "RSTUXYZABCFGHJ"; char UPS_N_Northing[15] = "ABCDEFGHJKLMNP"; // Calculate the index into the 2-letter digraph arrays. my_east = (int)(utmEasting / 100000.0); my_east = my_east - 13; my_north = (int)(utmNorthing / 100000.0); my_north = my_north - 13; /*xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, UPS_N_Easting[my_east], UPS_N_Northing[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL,EastingL_len, "%c", UPS_N_Easting[my_east]); xastir_snprintf(NorthingL,NorthingL_len, "%c", UPS_N_Northing[my_north]); } else // South polar UPS zone { char UPS_S_Easting[25] = "JKLPQRSTUXYZABCFGHJKLPQR"; char UPS_S_Northing[25] = "ABCDEFGHJKLMNPQRSTUVWXYZ"; // Calculate the index into the 2-letter digraph arrays. my_east = (int)(utmEasting / 100000.0); my_east = my_east - 8; my_north = (int)(utmNorthing / 100000.0); my_north = my_north - 8; /* xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, UPS_S_Easting[my_east], UPS_S_Northing[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL,EastingL_len, "%c", UPS_S_Easting[my_east]); xastir_snprintf(NorthingL,NorthingL_len, "%c", UPS_S_Northing[my_north]); } } else // UTM Area { char E_W[25] = "ABCDEFGHJKLMNPQRSTUVWXYZ"; char N_S[21] = "ABCDEFGHJKLMNPQRSTUV"; if (!nice_format) { space_string[0] = '\0'; } // Calculate the indexes into the 2-letter digraph arrays. start = atoi(utmZone); start--; start = start % 3; start = start * 8; start = start % 24; // "start" is now an index into the starting letter for the // zone. my_east = (int)(utmEasting / 100000.0) - 1; my_east = my_east + start; my_east = my_east % 24; // fprintf(stderr, "Start: %c East (guess): %c ", // E_W[start], // E_W[my_east]); start = atoi(utmZone); start = start % 2; if (start) // Odd-numbered zone { start = 0; } else // Even-numbered zone { start = 5; } my_north = (int)(utmNorthing / 100000.0); my_north = my_north + start; my_north = my_north % 20; // fprintf(stderr, "Start: %c North (guess): %c\n", // N_S[start], // N_S[my_north]); /* xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, E_W[my_east], N_S[my_north], int_utmEasting, space_string, int_utmNorthing ); */ xastir_snprintf(EastingL, EastingL_len, "%c", E_W[my_east]); xastir_snprintf(NorthingL, NorthingL_len, "%c", N_S[my_north]); } } /* Wrapper around convert_xastir_to_MGRS_str_components to return an MGRS coordinate as a single string. Parameters: str The character array to be populated with the MGRS string. str_len Length of str. x xastir x coordinate. y xastir y coordinate. If "nice_format" == 1, we add leading spaces plus spaces between the easting and northing in order to line up more nicely with the UTM output format. */ void convert_xastir_to_MGRS_str(char *str, int str_len, long x, long y, int nice_format) { char space_string[4] = " "; // Three spaces unsigned int intEasting = 0; unsigned int intNorthing = 0; char EastingL[3] = " "; char NorthingL[3] = " "; char utmZone[10]; convert_xastir_to_MGRS_str_components(utmZone, strlen(utmZone), EastingL, sizeof(EastingL), NorthingL, sizeof(NorthingL), &intEasting, &intNorthing, x, y, nice_format, space_string, strlen(space_string)) ; xastir_snprintf(str, str_len, "%s %c%c %05d %s%05d", utmZone, EastingL[0], NorthingL[0], intEasting, space_string, intNorthing ); } Xastir-Release-2.2.4/src/mgrs_utils.h0000664000175000017500000000261315151324131016453 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_MGRS_UTILS_H #define __XASTIR_MGRS_UTILS_H extern void convert_xastir_to_MGRS_str_components(char *utmZone, int utmZone_len, char *EastingL, int EastingL_len, char *NorthingL, int NorthingL_len, unsigned int *int_utmEasting, unsigned int *int_utmNorthing, long x, long y, int nice_format, char *space_string, int space_string_len); extern void convert_xastir_to_MGRS_str(char *str, int str_len, long x, long y, int nice_format); #endif Xastir-Release-2.2.4/src/mutex_utils.c0000664000175000017500000001720115151324131016637 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xa_config.h" #include "mutex_utils.h" // For mutex debugging with Linux threads only #ifdef MUTEX_DEBUG #include // // Newer pthread function #ifdef HAVE_PTHREAD_MUTEXATTR_SETTYPE extern int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); #endif // HAVE_PTHREAD_MUTEXATTR_SETTYPE // // Older, deprecated pthread function #ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP extern int pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind); #endif // HAVE_PTHREAD_MUTEXATTR_SETKIND_NP // #endif // MUTEX_DEBUG //---------------------------------------------------------------------- // Implements safer mutex locking. Posix-compatible mutex's will lock // up a thread if lock's/unlock's aren't in perfect pairs. They also // allow one thread to unlock a mutex that was locked by a different // thread. // Remember to keep this thread-safe. Need dynamic storage (no statics) // and thread-safe calls. // // In order to keep track of process ID's in a portable way, we probably // can't use the process ID stored inside the pthread_mutex_t struct. // There's no easy way to get at it. For that reason we'll create // another struct that contains both the process ID and a pointer to // the pthread_mutex_t, and pass pointers to those structs around in // our programs instead. The new struct is "xastir_mutex". // // Function to initialize the new xastir_mutex // objects before use. // void init_critical_section(xastir_mutex *lock) { #ifdef MUTEX_DEBUG pthread_mutexattr_t attr; // Note that this stuff is not POSIX, so is considered non-portable. // Exists in Linux Threads implementation only? // Check first for newer pthread function # ifdef HAVE_PTHREAD_MUTEXATTR_SETTYPE (void)pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # else // Use older, deprecated pthread function (void)pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_ERRORCHECK_NP); # endif // HAVE_PTHREAD_MUTEXATTR_SETTYPE (void)pthread_mutexattr_init(&attr); (void)pthread_mutex_init(&lock->lock, &attr); #else // MUTEX_DEBUG (void)pthread_mutex_init(&lock->lock, NULL); // Set to default POSIX-compatible type #endif // MUTEX_DEBUG lock->threadID = 0; // No thread has locked it yet } // Function which uses xastir_mutex objects to lock a // critical shared section of code or variables. Makes // sure that only one thread can access the critical section // at a time. If there are no problems, it returns zero. // int begin_critical_section(xastir_mutex *lock, char *text) { pthread_t calling_thread; int problems; #ifdef MUTEX_DEBUG int ret; #endif // MUTEX_DEBUG problems = 0; // Note that /usr/include/bits/pthreadtypes.h has the // definition for pthread_mutex_t, and it includes the // owner thread number: _pthread_descr pthread_mutex_t.__m_owner // It's probably not portable to use it though. // Get thread number we're currently running under calling_thread = pthread_self(); if (pthread_equal( lock->threadID, calling_thread )) { // We tried to lock something that we already have the lock on. fprintf(stderr,"%s:Warning:This thread already has the lock on this resource\n", text); problems++; return(0); // Return the OK code. Skip trying the lock. } //if (lock->threadID != 0) //{ // We tried to lock something that another thread has the lock on. // This is normal operation. The pthread_mutex_lock call below // will put our process to sleep until the mutex is unlocked. //} // Try to lock it. #ifdef MUTEX_DEBUG // Instead of blocking the thread, we'll loop here until there's // no deadlock, printing out status as we go. do { ret = pthread_mutex_lock(&lock->lock); if (ret == EDEADLK) // Normal operation. At least two threads want this lock. { fprintf(stderr,"%s:pthread_mutex_lock(&lock->lock) == EDEADLK\n", text); sched_yield(); // Yield the cpu to another thread } else if (ret == EINVAL) { fprintf(stderr,"%s:pthread_mutex_lock(&lock->lock) == EINVAL\n", text); fprintf(stderr,"Forgot to initialize the mutex object...\n"); problems++; sched_yield(); // Yield the cpu to another thread } } while (ret == EDEADLK); if (problems) { fprintf(stderr,"Returning %d to calling thread\n", problems); } #else // MUTEX_DEBUG pthread_mutex_lock(&lock->lock); #endif // MUTEX_DEBUG // Note: This can only be set AFTER we already have the mutex lock. // Otherwise there may be contention with other threads for setting // this variable. // lock->threadID = calling_thread; // Save the threadID that we used // to lock this resource return(problems); } // Function which ends the locking of a critical section // of code. If there are no problems, it returns zero. // int end_critical_section(xastir_mutex *lock, char *text) { pthread_t calling_thread; int problems; #ifdef MUTEX_DEBUG int ret; #endif // MUTEX_DEBUG problems = 0; // Get thread number we're currently running under calling_thread = pthread_self(); if (lock->threadID == 0) { // We have a problem. This resource hasn't been locked. fprintf(stderr,"%s:Warning:Trying to unlock a resource that hasn't been locked:%ld\n", text, (long int)lock->threadID); problems++; } if (! pthread_equal( lock->threadID, calling_thread )) { // We have a problem. We just tried to unlock a mutex which // a different thread originally locked. Not good. fprintf(stderr,"%s:Trying to unlock a resource that a different thread locked originally: %ld:%ld\n", text, (long int)lock->threadID, (long int)calling_thread); problems++; } // We need to clear this variable BEFORE we unlock the mutex, 'cuz // other threads might be waiting to lock the mutex. // lock->threadID = 0; // We're done with this lock. // Try to unlock it. Compare the thread identifier we used before to make // sure we should. #ifdef MUTEX_DEBUG // EPERM error: We're trying to unlock something that we don't have a lock on. ret = pthread_mutex_unlock(&lock->lock); if (ret == EPERM) { fprintf(stderr,"%s:pthread_mutex_unlock(&lock->lock) == EPERM\n", text); problems++; } else if (ret == EINVAL) { fprintf(stderr,"%s:pthread_mutex_unlock(&lock->lock) == EINVAL\n", text); fprintf(stderr,"Someone forgot to initialize the mutex object\n"); problems++; } if (problems) { fprintf(stderr,"Returning %d to calling thread\n", problems); } #else // MUTEX_DEBUG (void)pthread_mutex_unlock(&lock->lock); #endif // MUTEX_DEBUG return(problems); } Xastir-Release-2.2.4/src/mutex_utils.h0000664000175000017500000000245315151324131016647 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_MUTEX_UTILS_H #define __XASTIR_MUTEX_UTILS_H #include #include typedef struct { pthread_mutex_t lock; pthread_t threadID; } xastir_mutex; extern void init_critical_section(xastir_mutex *lock); extern int begin_critical_section(xastir_mutex *lock, char *text); extern int end_critical_section(xastir_mutex *lock, char *text); #endif Xastir-Release-2.2.4/src/nominatim.c0000664000175000017500000004643115151324131016257 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_NOMINATIM #include "snprintf.h" #include #include #include #include #include #include #include "xastir.h" #include "nominatim.h" #include "geocoder.h" #include "xa_config.h" #include "mutex_utils.h" #include "main.h" #ifdef HAVE_LIBCURL #include #include "fetch_remote.h" #endif #ifdef HAVE_CJSON #include #endif // Must be last include file #include "leak_detection.h" // Configuration variables char nominatim_server_url[400]; int nominatim_cache_enabled = 1; int nominatim_cache_days = 30; char nominatim_user_email[100]; char nominatim_country_default[20]; // Error message storage static char nominatim_error[512] = ""; // Rate limiting (1 request per second per Nominatim usage policy) static time_t last_request_time = 0; static xastir_mutex rate_limit_lock; // Cache entry structure (Nominatim usage policy suggests caching results) struct nominatim_cache_entry { char query_hash[33]; // MD5 hash of normalized query time_t timestamp; // When cached int result_count; struct geocode_result *results; struct nominatim_cache_entry *next; }; static struct nominatim_cache_entry *cache_head = NULL; static xastir_mutex cache_lock; // Buffer for HTTP response struct http_response { char *data; size_t size; }; /** * Callback for libcurl to write response data */ static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct http_response *response = (struct http_response *)userp; char *ptr = realloc(response->data, response->size + realsize + 1); if (!ptr) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Out of memory"); return 0; } response->data = ptr; memcpy(&(response->data[response->size]), contents, realsize); response->size += realsize; response->data[response->size] = 0; return realsize; } /** * Enforce rate limiting - wait if needed to maintain 1 req/sec * (Unlikely to happen but required by Nominatim usage policy) */ static void enforce_rate_limit(void) { begin_critical_section(&rate_limit_lock, "nominatim.c:enforce_rate_limit"); time_t now = time(NULL); time_t elapsed = now - last_request_time; if (last_request_time > 0 && elapsed < 1) { // Wait to maintain 1 request per second sleep(1 - elapsed); } last_request_time = time(NULL); end_critical_section(&rate_limit_lock, "nominatim.c:enforce_rate_limit"); } /** * Simple hash function for cache keys * Uses basic string hash (not cryptographic - just for cache lookup) */ #ifdef NOMINATIM_UNIT_TEST void compute_query_hash(const char *query, const char *country_codes, char *hash, size_t hash_size) #else static void compute_query_hash(const char *query, const char *country_codes, char *hash, size_t hash_size) #endif { unsigned long h = 5381; int c; const char *str = query; // Normalize to lowercase for case-insensitive matching while ((c = *str++)) { h = ((h << 5) + h) + tolower(c); } // Include country codes in hash if present if (country_codes && country_codes[0]) { str = country_codes; while ((c = *str++)) { h = ((h << 5) + h) + tolower(c); } } xastir_snprintf(hash, hash_size, "%016lx", h); } /** * Look up query in cache * Returns 1 if found, 0 if not found or expired */ #ifdef NOMINATIM_UNIT_TEST int cache_lookup(const char *query, const char *country_codes, struct geocode_result_list *results) #else static int cache_lookup(const char *query, const char *country_codes, struct geocode_result_list *results) #endif { char query_hash[33]; struct nominatim_cache_entry *entry; time_t now = time(NULL); int found = 0; compute_query_hash(query, country_codes, query_hash, sizeof(query_hash)); begin_critical_section(&cache_lock, "nominatim.c:cache_lookup"); for (entry = cache_head; entry != NULL; entry = entry->next) { if (strcmp(entry->query_hash, query_hash) == 0) { // Check if expired if (nominatim_cache_days > 0 && (now - entry->timestamp) > (nominatim_cache_days * 86400)) { // Expired - will be cleaned up later break; } // Found valid cached entry if (entry->result_count > 0) { results->capacity = entry->result_count; results->count = entry->result_count; results->results = malloc(sizeof(struct geocode_result) * entry->result_count); if (results->results) { memcpy(results->results, entry->results, sizeof(struct geocode_result) * entry->result_count); found = 1; } } break; } } end_critical_section(&cache_lock, "nominatim.c:cache_lookup"); return found; } /** * Store results in cache */ #ifdef NOMINATIM_UNIT_TEST void cache_store(const char *query, const char *country_codes, const struct geocode_result_list *results) #else static void cache_store(const char *query, const char *country_codes, const struct geocode_result_list *results) #endif { char query_hash[33]; struct nominatim_cache_entry *entry; if (!nominatim_cache_enabled || results->count == 0) { return; } compute_query_hash(query, country_codes, query_hash, sizeof(query_hash)); begin_critical_section(&cache_lock, "nominatim.c:cache_store"); // Check if already in cache (update if so) for (entry = cache_head; entry != NULL; entry = entry->next) { if (strcmp(entry->query_hash, query_hash) == 0) { // Update existing entry if (entry->results) { free(entry->results); } entry->results = malloc(sizeof(struct geocode_result) * results->count); if (entry->results) { memcpy(entry->results, results->results, sizeof(struct geocode_result) * results->count); entry->result_count = results->count; entry->timestamp = time(NULL); } end_critical_section(&cache_lock, "nominatim.c:cache_store"); return; } } // Create new entry entry = malloc(sizeof(struct nominatim_cache_entry)); if (entry) { xastir_snprintf(entry->query_hash, sizeof(entry->query_hash), "%s", query_hash); entry->timestamp = time(NULL); entry->result_count = results->count; entry->results = malloc(sizeof(struct geocode_result) * results->count); if (entry->results) { memcpy(entry->results, results->results, sizeof(struct geocode_result) * results->count); entry->next = cache_head; cache_head = entry; } else { free(entry); } } end_critical_section(&cache_lock, "nominatim.c:cache_store"); } /** * Parse a single JSON result into geocode_result structure */ static int parse_nominatim_result(cJSON *json_result, struct geocode_result *result) { cJSON *item; memset(result, 0, sizeof(struct geocode_result)); result->service = GEOCODE_SERVICE_NOMINATIM; // Extract core fields item = cJSON_GetObjectItem(json_result, "lat"); if (item && cJSON_IsString(item)) { result->lat = atof(item->valuestring); } else { return -1; // Lat is required } item = cJSON_GetObjectItem(json_result, "lon"); if (item && cJSON_IsString(item)) { result->lon = atof(item->valuestring); } else { return -1; // Lon is required } // Display name item = cJSON_GetObjectItem(json_result, "display_name"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->display_name, sizeof(result->display_name), "%s", item->valuestring); } // Bounding box item = cJSON_GetObjectItem(json_result, "boundingbox"); if (item && cJSON_IsArray(item) && cJSON_GetArraySize(item) == 4) { result->bbox[0] = atof(cJSON_GetArrayItem(item, 0)->valuestring); // min_lat result->bbox[1] = atof(cJSON_GetArrayItem(item, 1)->valuestring); // max_lat result->bbox[2] = atof(cJSON_GetArrayItem(item, 2)->valuestring); // min_lon result->bbox[3] = atof(cJSON_GetArrayItem(item, 3)->valuestring); // max_lon } // Importance/relevance item = cJSON_GetObjectItem(json_result, "importance"); if (item && cJSON_IsNumber(item)) { result->relevance = item->valuedouble; } // Place ID (service-specific) item = cJSON_GetObjectItem(json_result, "place_id"); if (item && cJSON_IsNumber(item)) { xastir_snprintf(result->service_id, sizeof(result->service_id), "%d", item->valueint); } // Classification item = cJSON_GetObjectItem(json_result, "class"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->place_class, sizeof(result->place_class), "%s", item->valuestring); } item = cJSON_GetObjectItem(json_result, "type"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->place_type, sizeof(result->place_type), "%s", item->valuestring); } // Address components (optional) cJSON *address = cJSON_GetObjectItem(json_result, "address"); if (address && cJSON_IsObject(address)) { // House number item = cJSON_GetObjectItem(address, "house_number"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->house_number, sizeof(result->house_number), "%s", item->valuestring); } // Road item = cJSON_GetObjectItem(address, "road"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->road, sizeof(result->road), "%s", item->valuestring); } // Neighbourhood item = cJSON_GetObjectItem(address, "neighbourhood"); if (!item || !cJSON_IsString(item)) { item = cJSON_GetObjectItem(address, "suburb"); } if (item && cJSON_IsString(item)) { xastir_snprintf(result->neighbourhood, sizeof(result->neighbourhood), "%s", item->valuestring); } // Settlement (check city, town, village, hamlet in priority order) item = cJSON_GetObjectItem(address, "city"); if (!item || !cJSON_IsString(item)) { item = cJSON_GetObjectItem(address, "town"); } if (!item || !cJSON_IsString(item)) { item = cJSON_GetObjectItem(address, "village"); } if (!item || !cJSON_IsString(item)) { item = cJSON_GetObjectItem(address, "hamlet"); } if (item && cJSON_IsString(item)) { xastir_snprintf(result->settlement, sizeof(result->settlement), "%s", item->valuestring); } // County item = cJSON_GetObjectItem(address, "county"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->county, sizeof(result->county), "%s", item->valuestring); } // State item = cJSON_GetObjectItem(address, "state"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->state, sizeof(result->state), "%s", item->valuestring); } // State district item = cJSON_GetObjectItem(address, "state_district"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->state_district, sizeof(result->state_district), "%s", item->valuestring); } // Postcode item = cJSON_GetObjectItem(address, "postcode"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->postcode, sizeof(result->postcode), "%s", item->valuestring); } // Country item = cJSON_GetObjectItem(address, "country"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->country, sizeof(result->country), "%s", item->valuestring); } // Country code item = cJSON_GetObjectItem(address, "country_code"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->country_code, sizeof(result->country_code), "%s", item->valuestring); } // ISO3166-2 item = cJSON_GetObjectItem(address, "ISO3166-2-lvl4"); if (item && cJSON_IsString(item)) { xastir_snprintf(result->iso3166_2, sizeof(result->iso3166_2), "%s", item->valuestring); } } return 0; } /** * Initialize Nominatim subsystem */ void nominatim_init(void) { init_critical_section(&rate_limit_lock); init_critical_section(&cache_lock); nominatim_error[0] = '\0'; last_request_time = 0; cache_head = NULL; } /** * Search Nominatim for locations matching query */ int nominatim_search(const char *query, const char *country_codes, int limit, struct geocode_result_list *results) { #ifndef HAVE_LIBCURL xastir_snprintf(nominatim_error, sizeof(nominatim_error), "libcurl not available - cannot perform network request"); return -1; #else CURL *curl = NULL; CURLcode res; struct http_response response = {0}; char url[2048]; char user_agent[256]; char *escaped_query = NULL; cJSON *json = NULL; int ret = -1; int i; // Check cache first if (nominatim_cache_enabled && cache_lookup(query, country_codes, results)) { return results->count; } // Enforce rate limiting enforce_rate_limit(); // Initialize curl curl = xastir_curl_init(nominatim_error); if (!curl) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Failed to initialize HTTP client"); return -1; } // URL-encode the query escaped_query = curl_easy_escape(curl, query, 0); if (!escaped_query) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Failed to encode query"); curl_easy_cleanup(curl); return -1; } // Build URL xastir_snprintf(url, sizeof(url), "%s/search?q=%s&format=jsonv2&addressdetails=1&limit=%d", nominatim_server_url, escaped_query, limit); if (country_codes && country_codes[0]) { char *escaped_countries = curl_easy_escape(curl, country_codes, 0); if (escaped_countries) { strncat(url, "&countrycodes=", sizeof(url) - strlen(url) - 1); strncat(url, escaped_countries, sizeof(url) - strlen(url) - 1); curl_free(escaped_countries); } } // Add email if configured if (nominatim_user_email[0]) { char *escaped_email = curl_easy_escape(curl, nominatim_user_email, 0); if (escaped_email) { strncat(url, "&email=", sizeof(url) - strlen(url) - 1); strncat(url, escaped_email, sizeof(url) - strlen(url) - 1); curl_free(escaped_email); } } curl_free(escaped_query); // Set up HTTP request curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&response); xastir_snprintf(user_agent, sizeof(user_agent), "Xastir/%s", PACKAGE_VERSION); curl_easy_setopt(curl, CURLOPT_USERAGENT, user_agent); // Perform request res = curl_easy_perform(curl); curl_easy_cleanup(curl); if (res != CURLE_OK) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Network error: %s", curl_easy_strerror(res)); if (response.data) free(response.data); return -1; } if (!response.data || response.size == 0) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Empty response from server"); if (response.data) free(response.data); return -1; } // Parse JSON response json = cJSON_Parse(response.data); free(response.data); if (!json) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Invalid JSON response"); return -1; } if (!cJSON_IsArray(json)) { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Unexpected JSON format"); cJSON_Delete(json); return -1; } // Process results int array_size = cJSON_GetArraySize(json); if (array_size == 0) { // No results found - not an error results->count = 0; results->capacity = 0; results->results = NULL; ret = 0; } else { results->capacity = array_size; results->results = malloc(sizeof(struct geocode_result) * array_size); if (results->results) { results->count = 0; for (i = 0; i < array_size; i++) { cJSON *item = cJSON_GetArrayItem(json, i); if (parse_nominatim_result(item, &results->results[results->count]) == 0) { results->count++; } } ret = results->count; // Store in cache cache_store(query, country_codes, results); } else { xastir_snprintf(nominatim_error, sizeof(nominatim_error), "Out of memory"); ret = -1; } } cJSON_Delete(json); return ret; #endif // HAVE_LIBCURL } /** * Get last Nominatim error message */ const char *nominatim_get_error(void) { if (nominatim_error[0]) { return nominatim_error; } return NULL; } /** * Clear the Nominatim result cache */ void nominatim_clear_cache(void) { struct nominatim_cache_entry *entry, *next; begin_critical_section(&cache_lock, "nominatim.c:nominatim_clear_cache"); entry = cache_head; while (entry) { next = entry->next; if (entry->results) { free(entry->results); } free(entry); entry = next; } cache_head = NULL; end_critical_section(&cache_lock, "nominatim.c:nominatim_clear_cache"); } #endif // HAVE_NOMINATIM Xastir-Release-2.2.4/src/nominatim.h0000664000175000017500000000436415151324131016263 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_NOMINATIM_H #define XASTIR_NOMINATIM_H #ifdef HAVE_NOMINATIM #include "geocoder.h" /* * Nominatim Geocoding Service Implementation * * This module provides Nominatim-specific implementation for the abstract * geocoding API. It handles: * - HTTP requests to Nominatim servers * - JSON response parsing * - Rate limiting (1 request/second per Nominatim usage policy) * - Result caching * - Address component extraction */ /** * Initialize Nominatim subsystem * Sets up rate limiting, cache, and configuration */ void nominatim_init(void); /** * Search Nominatim for locations matching query * * @param query Search query string * @param country_codes Optional country filter (e.g., "us,ca"), NULL for none * @param limit Maximum number of results * @param results Output parameter for results * @return Number of results, or negative error code */ int nominatim_search(const char *query, const char *country_codes, int limit, struct geocode_result_list *results); /** * Get last Nominatim error message * * @return Error message string, or NULL if no error */ const char *nominatim_get_error(void); /** * Clear the Nominatim result cache * Useful for testing or when configuration changes */ void nominatim_clear_cache(void); #endif // HAVE_NOMINATIM #endif // XASTIR_NOMINATIM_H Xastir-Release-2.2.4/src/object_utils.c0000664000175000017500000006721715151324131016757 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include "object_utils.h" // forward declaration so we don't need to include util.h and all that // drags in, and so we can mock them up in unit testing time_t sec_now(void); char *compress_posit(const char *input_lat, const char group, const char *input_lon, const char symbol, const unsigned int last_course, const unsigned int last_speed, const char *phg); char compress_group(char group_in); // Pad an item name out to at least 3 characters // Direct cut and paste from Create_object_item_tx_string. // Replaces given name with padded name. void pad_item_name(char *name, size_t name_size) { char tempstr[10]; // max name is 9 characters xastir_snprintf(tempstr, sizeof(tempstr), "%s", name); if (strlen(tempstr) < 3) xastir_snprintf(name, name_size,"%-3s",tempstr); } // Given strings representing course and speed, return an appropriate // CSE/SPD string for transmitting of object in the dst array, and integer // representations of course and speed void format_course_speed(char *dst, size_t dst_size, char *course_str, char *speed_str, int *course, int *speed) { char tempstr[50]; int temp; xastir_snprintf(dst, dst_size, ".../"); // Start with invalid-data string *course = 0; if (strlen(course_str) != 0) // Course was entered { // Need to check for 1 to three digits only, and 001-360 // degrees) temp = atoi(course_str); if ( (temp >= 1) && (temp <= 360) ) { xastir_snprintf(dst, dst_size, "%03d/",temp); *course = temp; } else if (temp == 0) // Spec says 001 to 360 degrees... { xastir_snprintf(dst, dst_size, "360/"); } } *speed = 0; if (strlen(speed_str) != 0) // Speed was entered (we only handle knots currently) { // Need to check for 1 to three digits, no alpha characters temp = atoi(speed_str); if ( (temp >= 0) && (temp <= 999) ) { xastir_snprintf(tempstr, sizeof(tempstr), "%03d",temp); strncat(dst, tempstr, dst_size - 1 - strlen(dst)); *speed = temp; } else { strncat(dst, "...", dst_size - 1 - strlen(dst)); } } else // No speed entered, blank it out { strncat(dst, "...", dst_size - 1 - strlen(dst)); } if ( (dst[0] == '.') && (dst[4] == '.') ) { dst[0] = '\0'; // No speed or course entered, so blank it } } // Given a string representation of altitude, return the correctly // formatted string for transmission of that altitude as part of an object // packet. Returns an empty string if the altitude is out of range or empty. // // At the moment (and for at least 20 years prior to the moment) this code // only handles input altitudes in feet. These altitudes are converted to // meters for purposes of transmission. void format_altitude(char *dst, size_t dst_size, char *altitude_str) { long alt_in_meters; dst[0] = '\0'; // Start with empty string if (strlen(altitude_str) != 0) // Altitude was entered (we only handle feet currently) { // Need to check for all digits, and 1 to 6 digits if (isdigit((int)altitude_str[0])) { // Must convert from meters to feet before transmitting alt_in_meters = (int)( (atof(altitude_str) / 0.3048) + 0.5); if ( (alt_in_meters >= 0) && (alt_in_meters <= 99999l) ) { xastir_snprintf(dst, dst_size, "/A=%06ld",alt_in_meters); } } } } // Return a string suitable for placing the current zulu time into an APRS // packet void format_zulu_time(char *dst, size_t dst_size) { struct tm *day_time; time_t sec; sec = sec_now(); day_time = gmtime(&sec); xastir_snprintf(dst, dst_size, "%02d%02d%02dz", day_time->tm_mday, day_time->tm_hour, day_time->tm_min); } // APRS Area objects are transmitted with colors from /0 through /9 and 10 // through 15. /0-/7 are "high intensity" colors and /8 through 15 are low // intensity values of the same. They are stored in the DataRow as an unsigned // four-bit bit field. // This function formats a color as stored numerically into the format needed // for transmit // Because the DataRow only stores this value in a 4-bit bit unsigned bit // field, we'll never get an invalid color, but guard against misuse just in // case. void format_area_color_from_numeric(char * dst, size_t dst_size, unsigned int color) { dst[0] = '\0'; // start with null string // Because the DataRow only stores this value in a 4-bit bit unsigned bit // field, we'll never get an invalid color, but guard against misuse just in // case. if (color <= 15) { xastir_snprintf(dst,dst_size,"%02d", color); if ( dst[0] == '0') dst[0]='/'; } else { xastir_snprintf(dst,dst_size,"/4"); fprintf(stderr,"Invalid color value passed to format_area_from_numeric. Returning string for bright red instead.\n"); } } // When decoding a color from a packet, we need to convert it to a number // This function takes such a string and returns the appropriate value // (it is currently unused by any object code, but db.c does some goofy stuff // to decode a received area object's color in extract_area, and this // function might just come in useful later in a refactor) unsigned int area_color_from_string(char *color_string) { unsigned int return_color=0; // we might be getting passed a pointer to the middle of an APRS packet // that might not end at the color's end, so let's just make sure we // have enough characters to read and not make assumptions that we're // ONLY getting the color. // Valid colors are /0-/9 and 10-15. If invalid, just return 0. if (strlen(color_string) >= 2 && ((color_string[0] == '/' && isdigit((int)color_string[1])) || (color_string[0] == '1' && color_string[1] >= '0' && color_string[1] <= '5'))) { if (color_string[0] == '/') { return_color = color_string[1] - '0'; } else // first character must be a one if we get here { return_color = color_string[1] - '0' + 10; } } return (return_color); } // When we *create* an object from the dialog box, the color is // determined from a combination of the selected color and the // selected (or not-selected) "Bright color" button. The dialog // provides '/0' through '/7' for the color and an integer // representing the button state (0 is deselected) // // This function takes values that came from the dialog box and formats // it into an appropriate two-character color string that combines the // two bits of information void format_area_color_from_dialog(char *dst, size_t dst_size, char *color, int bright) { unsigned int color_int; // We are going to be passed a color /0 through /7. decode it. color_int = area_color_from_string(color); // If it's bright, just use it. If it's low-intensity we need to add 8 if (!bright) color_int += 8; // now encode it format_area_color_from_numeric(dst, dst_size, color_int); } // Area objects of the linear type may have a corridor width, which // is transmitted as "{xxx}". // // The corridor width is stored in the DataRow as a 16-bit bitfield, // and so has a maximum value of 65535, too big to fit in the 6-byte // buffer that Create_object_item_tx_string reserves for the formatted // string. So really we mustmake sure that the corridor is less than // 1000 (miles) before formatting it. Otherwise we'd create a // truncated string and a malformed corridor. Fortunately, Xastir's // object creation dialog doesn't let us enter more than three digits, // so there has never been a problem. void format_area_corridor(char *dst, size_t dst_size, unsigned int type, unsigned int width) { dst[0] = '\0'; if ( (type == 1) || (type == 6)) { if (width > 0 && width < 1000) { xastir_snprintf(dst, dst_size, "{%d}", width); } } } // Signpost objects can have a 3 character string attached. // The resulting packet is supposed to get that string inserted as "{xxx}", // just as for area object corridors. If we are given too many characters, // just ignore the whole thing. void format_signpost(char *dst, size_t dst_size, char *signpost) { dst[0]='\0'; if (strlen(signpost) > 0 && strlen(signpost)<=3) { xastir_snprintf(dst, dst_size, "{%s}", signpost); } } // If we are a probability ring object we have pmin and/or pmax data and // should prepend the data to the object comment. // void format_probability_ring_data(char *dst, size_t dst_size, char *pmin, char *pmax) { char comment2[43+1]; if ( (pmin[0] != '\0') || (pmax[0] != '\0') ) { strncpy(comment2,dst,sizeof(comment2)-1); comment2[sizeof(comment2)-1] = '\0'; // assure that we're null terminated if (pmax[0] == '\0') { xastir_snprintf(dst, dst_size, "Pmin%s,%s",pmin,comment2); } else if (pmin[0] == '\0') { xastir_snprintf(dst, dst_size, "Pmax%s,%s",pmax,comment2); } else // Have both { xastir_snprintf(dst, dst_size, "Pmin%s,Pmax%s,%s",pmin,pmax,comment2); } } } // While Xastir doesn't actually allow you to enter PHG and RNG for // objects (?) it does check to see if a station record for an object // has such data and tries to insert it. Perhaps this is possible only // when Xastir adopts an object created elsewhere, and that other station // transmitted the object with PHG? // // If it's there, this data needs to be prepended to the comment // string. We are given the comment string in dst. void prepend_rng_phg(char *dst, size_t dst_size, char *power_gain) { char comment2[43+1]; xastir_snprintf(comment2,sizeof(comment2),"%s%s",power_gain,dst); strncpy(dst,comment2,dst_size-1); } // given a mess of data, format into an area object or item packet, // compressed or otherwise. // If compressed, lat_str and lon_str must be in high precision, we do not // check that here --- do it in the caller void format_area_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, int area_type, char *area_color, int lat_offset, int lon_offset, char *speed_course, char *corridor, char *altitude, int course, int speed, int is_object, int compressed) { if (is_object) // It's an object { if (compressed) { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%1d%02d%2s%02d%s%s%s", name, time, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank area_type, lat_offset, area_color, lon_offset, speed_course, corridor, altitude); } else // Non-compressed posit object { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%c%s%c%1d%02d%2s%02d%s%s%s", name, time, lat_str, object_group, lon_str, object_symbol, area_type, lat_offset, area_color, lon_offset, speed_course, corridor, altitude); } } else // It's an item { if (compressed) { xastir_snprintf(dst, dst_size, ")%s!%s%1d%02d%2s%02d%s%s%s", name, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank area_type, lat_offset, area_color, lon_offset, speed_course, corridor, altitude); } else // Non-compressed item { xastir_snprintf(dst, dst_size, ")%s!%s%c%s%c%1d%02d%2s%02d%s%s%s", name, lat_str, object_group, lon_str, object_symbol, area_type, lat_offset, area_color, lon_offset, speed_course, corridor, altitude); } } } // Format a signpost object or item packet given all the pre-formatted // bits and bobs void format_signpost_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char * lat_str, char *lon_str, char *speed_course, char *altitude, char *signpost, int course, int speed, int is_object, int compressed) { if (is_object) // It's an object { if (compressed) { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%s%s", name, time, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude, signpost); } else // Non-compressed posit object { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%c%s%c%s%s%s", name, time, lat_str, object_group, lon_str, object_symbol, speed_course, altitude, signpost); } } else // It's an item { if (compressed) { xastir_snprintf(dst, dst_size, ")%s!%s%s%s", name, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude, signpost); } else // Non-compressed item { xastir_snprintf(dst, dst_size, ")%s!%s%c%s%c%s%s%s", name, lat_str, object_group, lon_str, object_symbol, speed_course, altitude, signpost); } } } void format_omni_df_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *signal_gain, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed) { if (is_object) // It's an object { if (compressed) { char temp_group = object_group; xastir_snprintf(dst, dst_size, ";%-9s*%s%s%s/%s%s", name, time, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank signal_gain, speed_course, altitude); } else // Non-compressed posit object { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%c%s%c%s/%s%s", name, time, lat_str, object_group, lon_str, object_symbol, signal_gain, speed_course, altitude); } } else // It's an item { if (compressed) { char temp_group = object_group; xastir_snprintf(dst, dst_size, ")%s!%s%s/%s%s", name, compress_posit(lat_str, temp_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank signal_gain, speed_course, altitude); } else // Non-compressed item { xastir_snprintf(dst, dst_size, ")%s!%s%c%s%c%s/%s%s", name, lat_str, object_group, lon_str, object_symbol, signal_gain, speed_course, altitude); } } } void format_beam_df_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *bearing_string, char *NRQ, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed) { int bearing = atoi(bearing_string); char *spd_cse; spd_cse = (strlen(speed_course)!=7)?"000/000":speed_course; bearing = atoi(bearing_string); if ( (bearing < 1) || (bearing > 360) ) { bearing = 360; } if (is_object) // It's an object { if (compressed) { xastir_snprintf(dst, dst_size, ";%-9s*%s%s/%03i/%s%s", name, time, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank bearing, NRQ, altitude); } else // Non-compressed posit object { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%c%s%c%s/%03i/%s%s", name, time, lat_str, object_group, lon_str, object_symbol, spd_cse, bearing, NRQ, altitude); } } else // It's an item { if (compressed) { xastir_snprintf(dst, dst_size, ")%s!%s/%03i/%s%s", name, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank bearing, NRQ, altitude); } else // Non-compressed item { xastir_snprintf(dst, dst_size, ")%s!%s%c%s%c%s/%03i/%s%s", name, lat_str, object_group, lon_str, object_symbol, spd_cse, bearing, NRQ, altitude); } } } void format_normal_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed) { if (is_object) // It's an object { if (compressed) { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%s", name, time, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude); } else // Non-compressed posit object { xastir_snprintf(dst, dst_size, ";%-9s*%s%s%c%s%c%s%s", name, time, lat_str, object_group, lon_str, object_symbol, speed_course, altitude); } } else // It's an item { if (compressed) { xastir_snprintf(dst, dst_size, ")%s!%s%s", name, compress_posit(lat_str, object_group, lon_str, object_symbol, course, speed, // In knots ""), // PHG, must be blank altitude); } else // Non-compressed item { xastir_snprintf(dst, dst_size, ")%s!%s%c%s%c%s%s", name, lat_str, object_group, lon_str, object_symbol, speed_course, altitude); } } } // If the object or item has been marked killed, change the character in the // line to reflect a killed object int reformat_killed_object_item_packet(char *dst, size_t dst_size, int is_object, int is_active) { int i; int done; int killed; killed = 0; if (is_object) // It's an object { if (!is_active) // It's been killed { dst[10] = '_'; killed++; } } // If it's a "killed" item, change '!' to an '_' else // It's an item { if (!is_active) // It's been killed { killed++; done = 0; i = 0; while ( (!done) && (i < 11) ) { if (dst[i] == '!') { dst[i] = '_'; // mark as deleted object done++; // Exit from loop } i++; } } } return (killed); } // Surely this could be done in a more straightforward manner // // Append the comment string to the otherwise fully assembled object/item // packet string, but make sure it does not exceed allowable length // by copying ONLY the characters of the comment that don't exceed that // length. // // Before refactoring this in any way, make absolutely sure it actually // conforms to spec. A comment in the original suggests it does not for // the case of compressed objects/items void append_comment_to_object_item_packet(char *line, size_t line_length, char *comment, char *name, int is_object) { int temp = 0; // We need to tack the comment on the end, but need to make // sure we don't go over the maximum length for an object/item. if (strlen(comment) != 0) { temp = 0; if (is_object) { while ( (strlen(line) < 80) && (temp < (int)strlen(comment)) ) { line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; } } else // It's an item { while ( (strlen(line) < (64 + strlen(name))) && (temp < (int)strlen(comment)) ) { line[strlen(line) + 1] = '\0'; line[strlen(line)] = comment[temp++]; } } } // This note was in the original: //--- // NOTE: Compressed mode will be shorter still. Account // for that when compressed mode is implemented for objects/items. //--- // But compressed mode IS implemented for objects/items, so clearly // this stuff is not accounted for yet. // According to spec, an object with compressed position can have a max // length of 74 chars, not 80, and an item with compressed position can have // a max length of 58+strlen(name), not 64+strlen(name). // When we refactor this function, make it so, and pass in the compressed // boolean. } Xastir-Release-2.2.4/src/object_utils.h0000664000175000017500000001257215151324131016756 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_OBJECT_UTILS_H #define __XASTIR_OBJECT_UTILS_H #include extern void pad_item_name(char *name, size_t name_size); extern void format_course_speed(char *dst, size_t dst_size, char *course_str, char *speed_str, int *course, int *speed); extern void format_altitude(char *dst, size_t dst_size, char *altitude_str); extern void format_zulu_time(char *dst, size_t dst_size); extern void format_area_color_from_numeric(char * dst, size_t dst_size, unsigned int color); extern unsigned int area_color_from_string(char *color_string); extern void format_area_color_from_dialog(char *dst, size_t dst_size, char *color, int bright); extern void format_area_corridor(char *dst, size_t dst_size, unsigned int type, unsigned int width); extern void format_signpost(char *dst, size_t dst_size, char *signpost); extern void format_probability_ring_data(char *dst, size_t dst_size, char *pmin, char *pmax); extern void prepend_rng_phg(char *dst, size_t dst_size, char *power_gain); extern void format_area_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, int area_type, char *area_color, int lat_offset, int lon_offset, char *speed_course, char *corridor, char *altitude, int course, int speed, int is_object, int compressed); extern void format_signpost_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char * lat_str, char *lon_str, char *speed_course, char *altitude, char *signpost, int course, int speed, int is_object, int compressed); extern void format_omni_df_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *signal_gain, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed); extern void format_beam_df_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *bearing_string, char *NRQ, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed); extern void format_normal_object_item_packet(char *dst, size_t dst_size, char *name, char object_group, char object_symbol, char *time, char *lat_str, char *lon_str, char *speed_course, char *altitude, int course, int speed, int is_object, int compressed); extern int reformat_killed_object_item_packet(char *dst, size_t dst_size, int is_object, int is_active); extern void append_comment_to_object_item_packet(char *line, size_t line_length, char *comment, char *name, int is_object); #endif Xastir-Release-2.2.4/src/objects.c0000664000175000017500000012705515151324131015717 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "xa_config.h" #include "interface.h" #include "objects.h" #include "object_utils.h" #include "dr_utils.h" void move_station_time(DataRow *p_curr, DataRow *p_time); // forward declaration of a function present in db.c but not advertised by // any of the headers we include. void init_station(DataRow *p_station); int delete_comments_and_status(DataRow *fill); void add_comment(DataRow *p_station, char *comment_string); // Must be last include file #include "leak_detection.h" // ---------------------------- object ------------------------------- ///////////////////////////////////////////////////////////////////////// /* * Check for a valid object name */ int valid_object(char *name) { int len, i; // max 9 printable ASCII characters, case sensitive [APRS // Reference] len = (int)strlen(name); if (len > 9 || len == 0) { return(0); // wrong size } for (i=0; i 9 || len < 3) { return(0); // Wrong size } for (i=0; icoord_lon; long y_lat = p_station->coord_lat;; (void)remove_trailing_spaces(p_station->call_sign); if ((p_station->flag & ST_OBJECT) != 0) // We have an object { if (!valid_object(p_station->call_sign)) { line[0] = '\0'; return(0); } } else if ((p_station->flag & ST_ITEM) != 0) // We have an item { pad_item_name(p_station->call_sign, sizeof(p_station->call_sign)); if (!valid_item(p_station->call_sign)) { line[0] = '\0'; return(0); } } else // Not an item or an object, what are we doing here! { line[0] = '\0'; return(0); } // If the object or item has an associated speed, use the dead-reckoned // position instead of the one in p_station. if (strlen(p_station->speed) != 0) { int temp = atoi(p_station->speed); if ( (temp >=0) && (temp <= 999)) { compute_current_DR_position(p_station,&x_long,&y_lat); } } // Lat/lon are in Xastir coordinates, so we need to convert // them to APRS string format here. // Need low-precision if uncompressed, high precision if compressed convert_lat_l2s(y_lat, lat_str, sizeof(lat_str), (transmit_compressed_objects_items)?CONVERT_HP_NOSP:CONVERT_LP_NOSP); convert_lon_l2s(x_long, lon_str, sizeof(lon_str), (transmit_compressed_objects_items)?CONVERT_HP_NOSP:CONVERT_LP_NOSP); // Check for an overlay character. Replace the group character // (table char) with the overlay if present. if (p_station->aprs_symbol.special_overlay != '\0') { // Overlay character found object_group = p_station->aprs_symbol.special_overlay; if ( (object_group >= '0' && object_group <= '9') || (object_group >= 'A' && object_group <= 'Z') ) { // Valid overlay character, use what we have } else { // Bad overlay character, throw it away object_group = '\\'; } } else // No overlay character { object_group = p_station->aprs_symbol.aprs_type; } object_symbol = p_station->aprs_symbol.aprs_symbol; // In this case we grab only the first comment field (if it // exists) for the object/item if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { xastir_snprintf(comment, sizeof(comment), "%s", p_station->comment_data->text_ptr); } else { comment[0] = '\0'; // Empty string } format_probability_ring_data(comment,sizeof(comment), p_station->probability_min, p_station->probability_max); prepend_rng_phg(comment,sizeof(comment),p_station->power_gain); (void)remove_trailing_spaces(comment); // This is for objects only, not items. Uses current time but // should use the transmitted time from the DataRow struct. // Which time field in the struct would that be? Have to find // out // from the extract_?? code. if ((p_station->flag & ST_OBJECT) != 0) { format_zulu_time(time,sizeof(time)); } // Handle Generic Options // Speed/Course Fields if (p_station->aprs_symbol.area_object.type != AREA_NONE) // It's an area object { speed_course[0] = '\0'; // Course/Speed not allowed if Area Object course=0; speed=0; } else { format_course_speed(speed_course,sizeof(speed_course),p_station->course,p_station->speed,&course,&speed); } // Altitude Field format_altitude(altitude, sizeof(altitude), p_station->altitude); // Handle Specific Options // Area Objects if (p_station->aprs_symbol.area_object.type != AREA_NONE) // It's an area object { format_area_color_from_numeric(complete_area_color, sizeof(complete_area_color), p_station->aprs_symbol.area_object.color); complete_area_type = p_station->aprs_symbol.area_object.type; lat_offset = p_station->aprs_symbol.area_object.sqrt_lat_off; lon_offset = p_station->aprs_symbol.area_object.sqrt_lon_off; // Corridor format_area_corridor(complete_corridor, sizeof(complete_corridor), complete_area_type, p_station->aprs_symbol.area_object.corridor_width); format_area_object_item_packet(line, line_length, p_station->call_sign, object_group, object_symbol, time, lat_str, lon_str, complete_area_type, complete_area_color, lat_offset, lon_offset, speed_course, complete_corridor, altitude, course, speed, (p_station->flag & ST_OBJECT), transmit_compressed_objects_items); } else if ( (p_station->aprs_symbol.aprs_type == '\\') // We have a signpost object && (p_station->aprs_symbol.aprs_symbol == 'm' ) ) { format_signpost(signpost,sizeof(signpost),p_station->signpost); format_signpost_object_item_packet(line, line_length, p_station->call_sign, object_group,object_symbol, time, lat_str, lon_str, speed_course, altitude, signpost, course,speed, (p_station->flag&ST_OBJECT), transmit_compressed_objects_items); } else if (p_station->signal_gain[0] != '\0') // Must be an Omni-DF object/item { format_omni_df_object_item_packet(line, line_length, p_station->call_sign, object_group, object_symbol, time, lat_str, lon_str, p_station->signal_gain, speed_course, altitude, course, speed, (p_station->flag & ST_OBJECT), transmit_compressed_objects_items); } else if (p_station->NRQ[0] != 0) // It's a Beam Heading DFS object/item { format_beam_df_object_item_packet(line, line_length, p_station->call_sign, object_group, object_symbol, time, lat_str, lon_str, p_station->bearing, p_station->NRQ, speed_course, altitude, course,speed, (p_station->flag & ST_OBJECT), transmit_compressed_objects_items); } else // Else it's a normal object/item { format_normal_object_item_packet(line, line_length, p_station->call_sign, object_group, object_symbol, time, lat_str, lon_str, speed_course, altitude, course, speed, (p_station->flag & ST_OBJECT), transmit_compressed_objects_items); } // If it's a "killed" object, change '*' to an '_' killed=reformat_killed_object_item_packet(line, line_length, (p_station->flag & ST_OBJECT), (p_station->flag & ST_ACTIVE)); // Check whether we need to stop transmitting particular killed // object/items now. if (killed) { // Check whether we should decrement the object_retransmit // counter so that we will eventually stop sending this // object/item. if (p_station->object_retransmit == 0) { // We shouldn't be transmitting this killed object/item // anymore. We're already done transmitting it. return(0); } // Check whether the timeout has been set yet on this killed // object/item. If not, change it from -1 (continuous // transmit of non-killed objects) to // MAX_KILLED_OBJECT_RETRANSMIT. if (p_station->object_retransmit <= -1) { if ((MAX_KILLED_OBJECT_RETRANSMIT - 1) < 0) { p_station->object_retransmit = 0; return(0); // No retransmits desired } else { p_station->object_retransmit = MAX_KILLED_OBJECT_RETRANSMIT - 1; } } else { // Decrement the timeout if it is a positive number. if (p_station->object_retransmit > 0) { p_station->object_retransmit--; } } } // We need to tack the comment on the end, but need to make // sure we don't go over the maximum length for an object/item. append_comment_to_object_item_packet(line, line_length, comment, p_station->call_sign, (p_station->flag & ST_OBJECT)); return(1); } // check_and_transmit_objects_items // // This function checks the last_transmit_time for each // locally-owned object/item. If it has been at least the // transmit_time_increment since the last transmit, the increment is // doubled and the object/item transmitted. // // Killed objects/items are transmitted for // MAX_KILLED_OBJECT_RETRANSMIT times and then transmitting of those // objects ceases. // // This would be a good place to implement auto-expiration of // objects that's been discussed on the mailing lists. // // This function depends on the local loopback that is in // interface.c. If we don't hear & decode our own packets, we won't // have our own objects/items in our list. // // We need to check DataRow objects for ST_OBJECT or ST_ITEM types // that were transmitted by our callsign & SSID. We might also need // to modify the remove_time() and check_station_remove functions in // order not to delete our own objects/items too quickly. // // insert_time/remove_time/next_station_time/prev_station_time // // It would be nice if the create/modify object dialog and this // routine went // through the same functions to create the transmitted packets: // objects.c:Setup_object_data // objects.c:Setup_item_data // Unfortunately those routines snag their data directly from the // dialog. // In order to make them use the same code we'd have to separate out // the // fetch-from-dialog code from the create-transmit-packet code. // // This is what aprsDOS does, from Bob's APRS.TXT file: "a // fundamental precept is that old data is less important than new // data." "Each new packet is transmitted immediately, then 20 // seconds later. After every transmission, the period is doubled. // After 20 minutes only six packets have been transmitted. From // then on the rate remains at 10 minutes times the number of // digipeater hops you are using." // Actually, talking to Bob, he's used a period of 15 seconds as his // base unit. We now do the same using the OBJECT_CHECK_RATE define // to set the initial timing. // // Added these to database.h:DataRow struct: // time_t last_transmit_time; // Time we last transmitted // an object/item. Used to // // implement decaying // transmit time algorithm // short transmit_time_increment; // Seconds to add to transmit // next time around. Used // // to implement decaying // transmit time algorithm // // The earlier code here transmitted objects/items at a specified // rate. This can cause large transmissions every OBJECT_rate // seconds, as all objects/items are transmitted at once. With the // new code, the objects/items may be spaced a bit from each other // time-wise, plus they are transmitted less and less often with // each transmission until they hit the max interval specified by // the "Object/Item TX Interval" slider. When they hit that max // interval, they are transmitted at the constant interval until // killed. When they are killed, they are transmitted for // MAX_KILLED_OBJECT_RETRANSMIT iterations using the decaying // algorithm, then transmissions cease. // void check_and_transmit_objects_items(time_t time) { DataRow *p_station; // pointer to station data char line[256]; int first = 1; // Used to output debug message only once int increment; // Time to re-transmit objects/items? // Check every OBJECT_CHECK_RATE seconds - 20%. No faster else // we'll be running through the station list too often and // wasting cycles. if (time < (last_object_check + (int)(4.0 * OBJECT_CHECK_RATE/5.0 + 1.0) ) ) { return; } // Set up timer for next go-around last_object_check = time; if (debug_level & 1) { fprintf(stderr,"Checking whether to retransmit any objects/items\n"); } // We could speed things up quite a bit here by either keeping a // separate list of our own objects/items, or going through the list // of stations by time instead of by name (If by time, only check // backwards from the current time by the max transmit interval plus // some increment. Watch out for the user changing the slider). for (p_station = n_first; p_station != NULL; p_station = p_station->n_next) { // If station is owned by me (Exact match includes SSID) // and it's an object or item if ((p_station->flag & (ST_OBJECT|ST_ITEM)) && is_my_object_item(p_station)) { long x_long_save, y_lat_save; // If dead-reckoning, we need to send out a new // position for this object instead of just // overwriting the old position, which will cause // the track to skip. Here we save the old position // away so we can save it back to the record later. // x_long_save = p_station->coord_lon; y_lat_save = p_station->coord_lat; if (debug_level & 1) { fprintf(stderr, "Found a locally-owned object or item: %s\n", p_station->call_sign); } // Call the DR function to compute a new lat/long // and change the object's lat/long to match so that // we move the object along each time we transmit // it. // // WE7U // Here we should log the new position to file if it's not done // automatically. // if (p_station->speed[0] != '\0') { long x_long, y_lat; compute_current_DR_position(p_station, &x_long, &y_lat); // Put the new position into the record // temporarily so that we can p_station->coord_lon = x_long; p_station->coord_lat = y_lat; } // Keep the timestamp current on my own // objects/items so they don't expire. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // Implementing sped-up transmission of new objects, regular // transmission of old objects (decaying algorithm). We'll do this // by keeping a last_transmit_time variable and a // transmit_time_increment with each DataRow struct. If the // last_transmit_time is older than the transmit_time_increment, we // transmit the object and double the increment variable, until we // hit the OBJECT_rate limit for the increment. This will make // newer objects/items transmit more often, and will also space out // the transmissions of old objects so they're not transmitted all // at once in a group. Each time a new object/item is created that // is owned by us, it needs to have it's timer set to 20 (seconds). // If an object/item is touched, it needs to again be set to 20 // seconds. /////////////////////////////////// // Run through the station list. // Transmit any objects/items that have equalled or gone past // (last_transmit_time + transmit_time_increment). Update the // last_transmit_time to current time. // // Double the transmit_time_increment. If it has gone beyond // OBJECT_rate, set it to OBJECT_rate instead. // /////////////////////////////////// // Check for the case where the timing slider has // been reduced and the expire time is too long. // Reset it to the current max expire time so that // it'll get transmitted more quickly. if (p_station->transmit_time_increment > OBJECT_rate) { p_station->transmit_time_increment = OBJECT_rate; } increment = p_station->transmit_time_increment; if ( ( p_station->last_transmit_time + increment) <= time ) { // We should transmit this object/item as it has // hit its transmit interval. float randomize; int one_fifth_increment; int new_increment; if (first && !object_tx_disable) // "Transmitting objects/items" { statusline(langcode("BBARSTA042"),1); first = 0; } // Set up the new doubling increment increment = increment * 2; if (increment > OBJECT_rate) { increment = OBJECT_rate; } // Randomize the distribution a bit, so that all // objects are not transmitted at the same time. // Allow the random number to vary over 20% // (one-fifth) of the newly computed increment. one_fifth_increment = (int)((increment / 5) + 0.5); // Scale the random number from 0.0 to 1.0. // Must convert at least one of the numbers to a // float else randomize will be zero every time. randomize = rand() / (float)RAND_MAX; // Scale it to the range we want (0% to 20% of // the interval) randomize = randomize * one_fifth_increment; // Subtract it from the increment, use // poor-man's rounding to turn the random number // into an int (so we get the full range). new_increment = increment - (int)(randomize + 0.5); p_station->transmit_time_increment = (short)new_increment; // Set the last transmit time into the object. // Keep this based off the time the object was // last created/modified/deleted, so that we // don't end up with a bunch of them transmitted // together. p_station->last_transmit_time = p_station->last_transmit_time + new_increment; // Here we need to re-assemble and re-transmit // the object or item // Check whether it is a "live" or "killed" // object and vary the // number of retransmits accordingly. Actually // we should be able // to keep retransmitting "killed" objects until // they expire out of // our station queue with no problems. If // someone wants to ressurect // the object we'll get new info into our struct // and this function will // ignore that object from then on, unless we // again snatch control of // the object. // if signpost, area object, df object, or // generic object // check p_station->APRS_Symbol->aprs_type: // APRS_OBJECT // APRS_ITEM // APRS_DF (looks like I didn't use this one // when I implemented DF objects) // Whether area, df, signpost. // Check ->signpost for signpost data. Check // ->df_color also. // call_sign, sec_heard, coord_lon, coord_lat, // packet_time, origin, // aprs_symbol, pos_time, altitude, speed, // course, bearing, NRQ, // power_gain, signal_gain, signpost, // station_time, station_time_type, // comments, df_color if (Create_object_item_tx_string(p_station, line, sizeof(line)) ) { // Restore the original lat/long before we // transmit the (possibly) new position. // p_station->coord_lon = x_long_save; p_station->coord_lat = y_lat_save; // Attempt to transmit the object/item again if (object_tx_disable || transmit_disable) // Send to loopback only { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else // Send to all active tx-enabled interfaces { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } else { // Don't transmit it. } } else // Not time to transmit it yet { } } } } // // Disown function called by object/item decode routines. // If an object/item is received that matches something in our // object.log file, we immediately cease to transmit that object and // we mark each line containing that object in our log file with a // hash mark ('#'). This comments out that object so that the next // time we reboot, we won't start transmitting it again. // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void disown_object_item(char *call_sign, char *new_owner) { char file[200]; char file_temp[200]; FILE *f; FILE *f_temp; char line[300]; char name[15]; int ret; // If it's my call in the new_owner field, then I must have just // deleted the object and am transmitting a killed object for // it. If it's not my call, someone else has assumed control of // the object. // // Comment out any references to the object in the log file so // that we don't start retransmitting it on a restart. if (is_my_call(new_owner,1)) // Exact match includes SSID { } else { fprintf(stderr,"Disowning '%s': '%s' is taking over control of it.\n", call_sign, new_owner); } get_user_base_dir("config/object.log", file, sizeof(file)); get_user_base_dir("config/object-temp.log", file_temp, sizeof(file_temp)); // Our own internal function from util.c ret = copy_file(file, file_temp); if (ret) { fprintf(stderr,"\n\nCouldn't create temp file %s!\n\n\n", file_temp); return; } // Open the temp file and write to the original file, with hash // marks in front of the appropriate lines. f_temp=fopen(file_temp,"r"); f=fopen(file,"w"); if (f == NULL) { fprintf(stderr,"Couldn't open %s\n",file); return; } if (f_temp == NULL) { fprintf(stderr,"Couldn't open %s\n",file_temp); return; } // Read lines from the temp file and write them to the standard // file, modifying them as necessary. while (fgets(line, 300, f_temp) != NULL) { // Need to check that the length matches for both! Best way // is to parse the object/item name out of the string and // then do a normal string compare between the two. if (line[0] == ';') // Object { substr(name,&line[1],9); name[9] = '\0'; remove_trailing_spaces(name); } else if (line[0] == ')') // Item { int i; // 3-9 char name for (i = 1; i <= 9; i++) { if (line[i] == '!' || line[i] == '_') { name[i-1] = '\0'; break; } name[i-1] = line[i]; } name[9] = '\0'; // In case we never saw '!' || '_' // Don't remove trailing spaces for Items, else we won't // get a match. } else if (line[1] == ';') // Commented out Object { substr(name,&line[2],10); name[9] = '\0'; remove_trailing_spaces(name); } else if (line[1] == ')') // Commented out Item { int i; // 3-9 char name for (i = 2; i <= 10; i++) { if (line[i] == '!' || line[i] == '_') { name[i-1] = '\0'; break; } name[i-1] = line[i]; } name[9] = '\0'; // In case we never saw '!' || '_' // Don't remove trailing spaces for Items, else we won't // get a match. } if (valid_object(name)) { if ( strcmp(name,call_sign) == 0 ) { // Match. Comment it out in the file unless it's // already commented out. if (line[0] != '#') { fprintf(f,"#%s",line); } else { fprintf(f,"%s",line); } } else { // No match. Copy the line verbatim unless it's // just a // blank line. if (line[0] != '\n') { fprintf(f,"%s",line); } } } } fclose(f); fclose(f_temp); } // // Logging function called by object/item create/modify routines. // We log each object/item as one line in a file. // // We need to check for objects of the same name in the file, // deleting lines that have the same name, and adding new records to // the end. Actually BAD IDEA! We want to keep the history of the // object so that we can trace its movements later. // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // Change this function so that deleted objects/items get disowned // instead (commented out in the file so that they're not // transmitted again after a restart). See disown_object_item(). // void log_object_item(char *line, int disable_object, char *object_name) { char file[MAX_VALUE]; FILE *f; get_user_base_dir("config/object.log", file, sizeof(file)); f=fopen(file,"a"); if (f!=NULL) { fprintf(f,"%s\n",line); (void)fclose(f); if (debug_level & 1) { fprintf(stderr,"Saving object/item to file: %s",line); } // Comment out all instances of the object/item in the log // file. This will make sure that the object is not // retransmitted again when Xastir is restarted. if (disable_object) { disown_object_item(object_name, my_callsign); } } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } } /* This function exists to take all the strings that are obtained directly from the Object/Item create/modify dialog box and create a stand-alone DataRow structure that can be read by Create_object_item_tx_string to craft a correctly formatted object or item packet. Some of the character strings in the argument list will be null strings, either because the user left them blank or because they don't apply to the object type being created. The integer types here are all booleans that reflect the settings of toggle buttons in the dialog. This function will return a null pointer if the name string is empty. It will abort with a fatal error if the memory allocation call fails. It is ASSUMED that the caller will have done all required sanity checking on the name and latitude/longitude strings. We do only very basic checking here, mostly to avoid overrunning buffers. In order to get a valid pointer return, at least name, lat/lon_str, obj_group, and obj_symbol must be provided, in which case the object is just a simple static object. Parameters: name: the object or item name with trailing spaces deleted lat_str,lon_str: latitude and longitude in DDMM.MM[M]H/DDDMM.MM[M]H format. They will be converted to Xastir coordinates before storage in the data row. obj_group, obj_symbol: The group and symbol taken from the dialog box. if obj_group is neither '/' nor '\' then it must be a valid overlay character, the upper case letters A-Z or digits 0-9. The actual group stored in the record as the object symbol group will be '\' and the group given will be stored instead in the overlay field. If the overlay character is invalid, it will be ignored and we'll just use '\' as the group. comment: A comment string up to 43 characters long. May be null. course, speed: course in degrees, speed in knots. May be null. must be no more than three digits. altitude: altitude in feet. While the dialog prompts the user for altitude in feet, it gets converted into meters for storage in the DataRow comments per comments in database.h and as handled by functions in db.c. Create_object_item_tx_string converts back to feet for transmit. Eep. area_object, area_type, area_filled: If area_object is nonzero, we are doing an area object and the following flags define the type (0-15) and whether or not it's filled. area_color: two character color string /0 through 15. lat_offset_str, lon_offset_str: latitude and longitude offset values in 1/100 of a degree. The actual value stored will be the square root of this number. May be null. corridor: optional three digit corridor used only by area object types 1 and 6 (lines left and right) signpost_object: if nonzero, we're creating a signpost object. signpost_str: character string up to three characters to be displayed as signpost text. May be null. df_object: if nonzero, this is a DF report object. omni_df: if nonzero, it's an omnidirectional report and we need the SHGD string beam_df: if nonzero, we're a beam reading DF report and need bearing and NRQ. df_shgd: signal quality, etc. for omni DF bearing: beam DF bearing NRQ: beam width, etc. for beam df object prob_circles: if nonzero, we're a probability circles object, and expect prob_min and/or prob_max to be non-null. prob_min, prob_max: min and max radii of probability circles. May be null (if both are null, this winds up being just another ordinary object) is_object: if nonzero, set this record's flag to have the ST_OBJECT bit set. Otherwise, set ST_ITEM. killed: if nonzero, unset the ST_ACTIVE flag. Otherwise, set the ST_ACTIVE flag. THIS FUNCTION ALLOCATES DATA THAT MUST BE FREED. DO NOT USE THE STATION DELETE FUNCTIONS IN DB.C BECAUSE THEY PRESUME THE RECORD IS LINKED INTO THE LINKED LISTS, AND THESE WILL NOT BE. This function is in objects.c and not db.c because it is intended ONLY as a function for preparing a fake record to be used in object packet creation, which will then be discarded after the string is created. */ DataRow *construct_object_item_data_row(char *name, char *lat_str, char *lon_str, char obj_group, char obj_symbol, char *comment, char *course, char *speed, char *altitude, int area_object, int area_type, int area_filled, char *area_color, char *lat_offset_str, char *lon_offset_str, char *corridor, int signpost_object, char *signpost_str, int df_object, int omni_df, int beam_df, char *df_shgd, char *bearing, char *NRQ, int prob_circles, char *prob_min, char *prob_max, int is_object, int killed) { DataRow *theDataRow = NULL; // if we have these three strings and they're not null, go ahead and try // to do the thing. We are ASSUMING the caller has already taken care // of sanity checking them. if (name!=NULL && lat_str != NULL && lon_str != NULL && strlen(name) != 0 && strlen(lat_str) != 0 && strlen(lon_str) != 0) { theDataRow = (DataRow *)calloc(1,sizeof(DataRow)); CHECKMALLOC(theDataRow); init_station(theDataRow); // populate with defaults // // Generic data for all object types // // Truncate name if necessary if (strlen(name) > sizeof(theDataRow->call_sign)-1) { char *copy_name; copy_name=(char *)malloc(strlen(name)+1); strncpy(copy_name,name,strlen(name)); copy_name[sizeof(theDataRow->call_sign)-1] = '\0'; strncpy(theDataRow->call_sign,copy_name,sizeof(theDataRow->call_sign)-1); free(copy_name); } else { strncpy(theDataRow->call_sign,name,sizeof(theDataRow->call_sign)-1); } theDataRow->coord_lat = convert_lat_s2l(lat_str); theDataRow->coord_lon = convert_lon_s2l(lon_str); theDataRow->flag |= (is_object)?(ST_OBJECT):(ST_ITEM); if (killed) theDataRow->flag &= ~ST_ACTIVE; else theDataRow->flag |= ST_ACTIVE; if (obj_group == '/' || obj_group == '\\') { theDataRow->aprs_symbol.aprs_type=obj_group; } else { theDataRow->aprs_symbol.aprs_type='\\'; if ((obj_group >= 'A' && obj_group <= 'Z') || (obj_group >= '0' && obj_group <= '9')) { theDataRow->aprs_symbol.special_overlay = obj_group; } else { theDataRow->aprs_symbol.special_overlay = '\0'; } } theDataRow->aprs_symbol.aprs_symbol = obj_symbol; if (course && strlen(course) >= 1 && strlen(course)<=3 && atoi(course)>0 && atoi(course) <=360) { xastir_snprintf(theDataRow->course,sizeof(theDataRow->course),"%03d",atoi(course)); } if (speed && strlen(speed) >= 1 && strlen(speed)<=3 ) { xastir_snprintf(theDataRow->speed,sizeof(theDataRow->speed),"%3d",atoi(speed)); } if (altitude && strlen(altitude) > 0) { long alt_in_feet=atoi(altitude); if (alt_in_feet >=0 && alt_in_feet <= 999999) { double alt_in_meters=atof(altitude)*0.3048; xastir_snprintf(theDataRow->altitude,sizeof(theDataRow->altitude),"%.2f",alt_in_meters); } } if (comment && strlen(comment)>0) { add_comment(theDataRow,comment); } // Specific data for fancier object types if (prob_circles) { if (prob_min && strlen(prob_min)>0) { xastir_snprintf(theDataRow->probability_min, sizeof(theDataRow->probability_min), "%s", prob_min); } if (prob_max && strlen(prob_max)>0) { xastir_snprintf(theDataRow->probability_max, sizeof(theDataRow->probability_max), "%s", prob_max); } } if (area_object) { // Enforce correct symbol. Must be '\l', no overlay. theDataRow->aprs_symbol.aprs_type='\\'; theDataRow->aprs_symbol.aprs_symbol='l'; theDataRow->aprs_symbol.special_overlay = '\0'; // Area objects are not allowed to have course/speed, clobber those // if they were given theDataRow->speed[0] = '\0'; theDataRow->course[0] = '\0'; if (area_filled && area_type != 1 && area_type != 6) { theDataRow->aprs_symbol.area_object.type = area_type+5; } else { theDataRow->aprs_symbol.area_object.type = area_type; } // here we assume that the area color has already been processed // as far as correcting it for dim/bright by the caller, and that it // is provided us *exactly* as it needs to be theDataRow->aprs_symbol.area_object.color = area_color_from_string(area_color); // The dialog asks the user to input the lat/lon offsets in 1/100 degree, // but the value is actually stored as the integer part of the square // root of the value input, because that's what's actually transmitted // per spec. if (lat_offset_str && strlen(lat_offset_str) != 0) { int lat_offset; lat_offset = sqrt(atof(lat_offset_str)); if (lat_offset > 99) lat_offset = 99; theDataRow->aprs_symbol.area_object.sqrt_lat_off = lat_offset; } if (lon_offset_str && strlen(lon_offset_str) != 0) { int lon_offset; lon_offset = sqrt(atof(lon_offset_str)); if (lon_offset > 99) lon_offset = 99; theDataRow->aprs_symbol.area_object.sqrt_lon_off = lon_offset; } // only line left and line right get this set: if (corridor && strlen(corridor) != 0 && (area_type == AREA_LINE_LEFT || area_type == AREA_LINE_RIGHT)) { unsigned int cwidth = atoi(corridor); if (cwidth >0 && cwidth < 999) { theDataRow->aprs_symbol.area_object.corridor_width = cwidth; } } } else if (signpost_object) { // Enforce correct symbol. Must be '\m', no overlay. theDataRow->aprs_symbol.aprs_type='\\'; theDataRow->aprs_symbol.aprs_symbol='m'; theDataRow->aprs_symbol.special_overlay = '\0'; if (signpost_str && strlen(signpost_str) >0 && strlen(signpost_str) <= 3) { xastir_snprintf(theDataRow->signpost,sizeof(theDataRow->signpost),"%s",signpost_str); } } else if (df_object) { // Enforce correct symbol. Must be '/\', no overlay. theDataRow->aprs_symbol.aprs_type='/'; theDataRow->aprs_symbol.aprs_symbol='\\'; theDataRow->aprs_symbol.special_overlay = '\0'; if (omni_df) { if (df_shgd && strlen(df_shgd) == 4) { xastir_snprintf(theDataRow->signal_gain,sizeof(theDataRow->signal_gain),"DFS%s",df_shgd); } } else if (NRQ && strlen(NRQ) != 0) // must be a beam df object { // now we are just presuming the bearing is set, coz that's what // the gui code already does int bearing_value=atoi(bearing); if (bearing_value < 1 || bearing_value > 360) { bearing_value=360; } xastir_snprintf(theDataRow->bearing,sizeof(theDataRow->bearing),"%03d",bearing_value); xastir_snprintf(theDataRow->NRQ,sizeof(theDataRow->NRQ),"%3s",NRQ); } } // and finally, make sure we set the time we created this record, // or the attempts to DR are hosed. theDataRow->sec_heard=sec_now(); } return theDataRow; } // // this function is sufficient to deallocate a DataRow structure as created // by the previous function, which can only set the comment field. The // comment field is a dynamically allocated string pointed to by a pointer // stored in the DataRow, so has to be deallocated before freeing the row // structure itself. This is much simpler than the function station_del // in db.c, which must look up the record in a linked list, deallocate lots // of dynamic pieces, then call a function to unlink the record and then // deallocate it. Don't call that one, because we aren't in the linked list // in the first place. // void destroy_object_item_data_row(DataRow *theDataRow) { (void) delete_comments_and_status(theDataRow); free(theDataRow); } Xastir-Release-2.2.4/src/objects.h0000664000175000017500000000571215151324131015717 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_OBJECTS_H #define XASTIR_OBJECTS_H #include // -------------------------------------------------------------------- extern void move_station_time(DataRow *p_curr, DataRow *p_time); extern int valid_object(char *name); extern int valid_item(char *name); extern void check_and_transmit_objects_items(time_t time); extern int Create_object_item_tx_string(DataRow *p_station, char *line, int line_length); extern DataRow *construct_object_item_data_row(char *name, char *lat_str, char *lon_str, char obj_group, char obj_symbol, char *comment, char *course, char *speed, char *altitude, int area_object, int area_type, int area_filled, char *area_color, char *lat_offset_str, char *lon_offset_str, char *corridor, int signpost_object, char *signpost_str, int df_object, int omni_df, int beam_df, char *df_shgd, char *bearing, char *NRQ, int prob_circles, char *prob_min, char *prob_max, int is_object, int killed); extern void destroy_object_item_data_row(DataRow *theDataRow); #endif /* XASTIR_OBJECTS_H */ Xastir-Release-2.2.4/src/objects_gui.c0000664000175000017500000076112715151324131016567 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include "xastir.h" #include "draw_symbols.h" #include "main.h" #include "db_funcs.h" #include "xa_config.h" #include "interface.h" #include "objects.h" #include "objects_gui.h" #include "object_utils.h" #include "dr_utils.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget object_dialog = (Widget)NULL; Widget df_object_dialog = (Widget)NULL; Widget object_name_data, object_lat_data_deg, object_lat_data_min, object_lat_data_ns, object_lon_data_deg, object_lon_data_min, object_lon_data_ew, object_group_data, object_symbol_data, object_icon, object_comment_data, ob_frame, ob_group, ob_symbol, ob_option_frame, signpost_frame, area_frame, area_toggle, signpost_toggle, df_bearing_toggle, map_view_toggle, probabilities_toggle, ob_bearing_data, frameomni, framebeam, ob_speed, ob_speed_data, ob_course, ob_course_data, ob_comment, ob_altitude, ob_altitude_data, signpost_data, probability_data_min, probability_data_max, open_filled_toggle, ob_lat_offset_data, ob_lon_offset_data, ob_corridor, ob_corridor_data, ob_corridor_miles, omni_antenna_toggle, beam_antenna_toggle; Pixmap Ob_icon0, Ob_icon; void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata); // Array to hold predefined objects to display on Create/Move popup menu. predefinedObject predefinedObjects[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; void Populate_predefined_objects(predefinedObject *predefinedObjects); int number_of_predefined_objects; char predefined_object_definition_filename[256] = "predefined_SAR.sys"; int predefined_menu_from_file = 0; int Area_object_enabled = 0; int Map_View_object_enabled = 0; int Area_type = 0; char Area_color[3] = "/0"; int Area_bright = 0; int Area_filled = 0; int Signpost_object_enabled = 0; int Probability_circles_enabled = 0; int DF_object_enabled = 0; int Omni_antenna_enabled = 0; int Beam_antenna_enabled = 0; char object_shgd[5] = "0000\0"; char object_NRQ[4] = "960\0"; XtPointer global_parameter1 = (XtPointer)NULL; XtPointer global_parameter2 = (XtPointer)NULL; int doing_move_operation = 0; // forward declare function to read object/item dialog box values int Read_object_item_dialog_values(char *name, size_t name_size, char *lat_str, size_t lat_str_size, char *ext_lat_str, size_t ext_lat_str_size, char *lon_str, size_t lon_str_size, char *ext_lon_str, size_t ext_lon_str_size, char *obj_group, char *obj_symbol, char *comment, size_t comment_size, char *course, size_t course_size, char *speed, size_t speed_size, char *altitude, size_t altitude_size, int *area_object, int *area_type, int *area_filled, char *area_color, size_t area_color_size, char *lat_offset_str, size_t lat_offset_str_size, char *lon_offset_str, size_t lon_offset_str_size, char *corridor, size_t corridor_size, int *signpost_object, char *signpost_str, size_t signpost_str_size, int *df_object, int *omni_df, int *beam_df, char *df_shgd, size_t df_shgd_size, char *bearing, size_t bearing_size, char *NRQ, size_t NRQ_size, int *prob_circles, char *prob_min, size_t prob_min_size, char *prob_max, size_t prob_max_size ); int Setup_object_item_data(char *line, int line_length, DataRow *p_station, int is_object, int is_killed); //////////////////////////////////////////////////////////////////////////////////////////////////// // Init values for Objects dialog char last_object[9+1]; char last_obj_grp; char last_obj_sym; char last_obj_overlay; /* * Clear out object/item history log file */ void Object_History_Clear( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char *file; FILE *f; char temp_file_path[MAX_VALUE]; file = get_user_base_dir("config/object.log", temp_file_path, sizeof(temp_file_path)); f=fopen(file,"w"); if (f!=NULL) { (void)fclose(f); if (debug_level & 1) { fprintf(stderr,"Clearing Object/Item history file...\n"); } } else { fprintf(stderr,"Couldn't open file for writing: %s\n", file); } } /* * Re-read object/item history log file */ void Object_History_Refresh( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { // Reload saved objects and items from previous runs. reload_object_item(); } ///////////////////////////////////////// Object Dialog ////////////////////////////////////////// /* * Destroy Object Dialog Popup Window */ void Object_destroy_shell( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; XtPopdown(shell); (void)XFreePixmap(XtDisplay(appshell),Ob_icon0); (void)XFreePixmap(XtDisplay(appshell),Ob_icon); XtDestroyWidget(shell); object_dialog = (Widget)NULL; // Take down the symbol selection dialog as well (if it's up) if (select_symbol_dialog) { Select_symbol_destroy_shell( widget, select_symbol_dialog, callData); } // NULL out the dialog field in the global struct used for // Coordinate Calculator. Prevents segfaults if the calculator is // still up and trying to write to us. coordinate_calc_array.calling_dialog = NULL; } // Snag the latest DR'ed position for an object/item and create the // types of strings that we need for Setup_object_data() and // Setup_item_data() for APRS and Base-91 compressed formats. // void fetch_current_DR_strings(DataRow *p_station, char *lat_str, char *lon_str, char *ext_lat_str, char *ext_lon_str) { long x_long, y_lat; // Fetch the latest position for a DR'ed object. Returns the // values in two longs, x_long and y_lat. compute_current_DR_position(p_station, &x_long, &y_lat); // Normal precision for APRS format convert_lat_l2s(y_lat, lat_str, MAX_LAT, CONVERT_LP_NOSP); convert_lon_l2s(x_long, lon_str, MAX_LONG, CONVERT_LP_NOSP); // Extended precision for Base-91 compressed format convert_lat_l2s(y_lat, ext_lat_str, MAX_LAT, CONVERT_HP_NOSP); convert_lon_l2s(x_long, ext_lon_str, MAX_LONG, CONVERT_HP_NOSP); } /* * Setup APRS Information Field for Objects and Items * * We do this by reading the dialog box, creating a DataRow from that * information, then formatting the packet exactly as we would do for * an existing object packet by calling Create_object_item_tx_string. * * If we are passed a p_station, that means the modify dialog was called * and we're creating a new packet for an existing object. But we still * create a new DataRow for our new packet. In this case, we discard * any position entered in the modify dialog box and replace it with * dead-reckoned position. I'm not sure this is a desirable feature, but * it was exactly what Xastir did before my refactor. * * returns zero if an error occurred, in which case the line is not to be * used by the caller */ /* * Construct an object/item transmit data string from dialog box values * * This function consolidates the work of both Setup_object_data and * Setup_item_data in a single place. * * Returns zero if unable to produce a transmit line (mainly due to invalid * names). * * is_object should be 1 if we are asking to produce an object packet, * and zero if it's an item. */ int Setup_object_item_data(char *line, int line_length, DataRow *p_station, int is_object, int is_killed) { char name[MAX_CALLSIGN+1]; char obj_group, obj_symbol; char lat_str[MAX_LAT]; char lon_str[MAX_LONG]; char ext_lat_str[20]; char ext_lon_str[20]; char comment[43+1]; char course[MAX_COURSE+1]; char speed[MAX_SPEED+1]; char altitude[MAX_ALTITUDE]; int area_object, area_type,area_filled; char area_color[3]; char lat_offset_str[5]; char lon_offset_str[5]; char corridor[4]; int signpost_object; char signpost_str[4]; int df_object, omni_df, beam_df; char df_shgd[MAX_POWERGAIN+1]; char bearing[MAX_COURSE+1]; char NRQ[MAX_COURSE+1]; int prob_circles; char prob_min[10+1]; char prob_max[10+1]; DataRow *theDataRow; int object_speed; int retval=0; if (Read_object_item_dialog_values(name, sizeof(name), lat_str, sizeof(lat_str), ext_lat_str, sizeof(ext_lat_str), lon_str, sizeof(lon_str), ext_lon_str, sizeof(ext_lon_str), &obj_group, &obj_symbol, comment, sizeof(comment), course, sizeof(course), speed, sizeof(speed), altitude, sizeof(altitude), &area_object, &area_type, &area_filled, area_color, sizeof(area_color), lat_offset_str, sizeof(lat_offset_str), lon_offset_str, sizeof(lon_offset_str), corridor, sizeof(corridor), &signpost_object, signpost_str, sizeof(signpost_str), &df_object, &omni_df, &beam_df, df_shgd, sizeof(df_shgd), bearing, sizeof(bearing), NRQ, sizeof(NRQ), &prob_circles, prob_min, sizeof(prob_min), prob_max, sizeof(prob_max))) { xastir_snprintf(last_object,sizeof(last_object),"%s",name); if (p_station != NULL) { object_speed = atoi(p_station->speed); if (object_speed > 0 && !doing_move_operation) { fetch_current_DR_strings(p_station, lat_str, lon_str, ext_lat_str, ext_lon_str); } // Keep the time current for our own objects. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); } theDataRow=construct_object_item_data_row(name, ext_lat_str, ext_lon_str, obj_group, obj_symbol, comment, course, speed, altitude, area_object, area_type, area_filled, area_color, lat_offset_str, lon_offset_str, corridor, signpost_object, signpost_str, df_object, omni_df, beam_df, df_shgd, bearing, NRQ, prob_circles, prob_min, prob_max, is_object, is_killed); if (theDataRow) { retval=Create_object_item_tx_string(theDataRow, line,line_length); destroy_object_item_data_row(theDataRow); } else { // This can never happen, as the constructor will abort with a fatal // error if it can't allocate data. fprintf(stderr,"BOO!\n"); retval=0; } return(retval); } else { return(0); } } /* * Set an Object */ void Object_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; //fprintf(stderr,"Object_change_data_set\n"); // p_station will be NULL if the object is new. if (Setup_object_item_data(line, sizeof(line), p_station, 1, 0)) { // Update this object in our save file log_object_item(line,0,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // Keep the time current for our own objects. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Object_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } sched_yield(); // Wait for transmitted data to get processed Object_destroy_shell(widget,clientData,NULL); // Getting a segfault here on a Move operation, so just // comment it out. A redraw will occur shortly anyway. //redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else { // error message popup_message_always(langcode("POPEM00022"),langcode("POPEM00027")); } } /* * Set an Item */ void Item_change_data_set(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; if (Setup_object_item_data(line,sizeof(line), p_station, 0, 0)) { // Update this item in our save file log_object_item(line,0,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // Keep the time current for our own items. p_station->sec_heard = sec_now(); move_station_time(p_station,NULL); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Item_change_data_set(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit/loopback item data, not igating } sched_yield(); // Wait for transmitted data to get processed Object_destroy_shell(widget,clientData,NULL); // Getting a segfault here on a Move operation, so just // comment it out. A redraw will occur shortly anyway. //redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else { // error message popup_message_always(langcode("POPEM00022"),langcode("POPEM00027")); } } // Check the name of a new Object. If it already exists in our // database, warn the user. Confirmation dialog to continue? // void Object_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; char line[MAX_CALLSIGN+1]; DataRow *p_station; temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, sizeof(line), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(line); (void)remove_trailing_spaces(line); //fprintf(stderr,"Object name:%s\n", line); // We have the name now. Check it against our database of // stations/objects/items. Do an exact match. // if (search_station_name(&p_station,line,1) && (p_station->flag & ST_ACTIVE)) { // Found a live object with that name. Don't allow Object // creation. Bring up a warning message instead. popup_message_always(langcode("POPEM00035"), langcode("POPEM00038")); } else { // Not found. Allow the Object to be created. Object_change_data_set(widget, clientData, callData); } } // Check the name of a new Item. If it already exists in our // database, warn the user. Confirmation dialog to continue? // void Item_confirm_data_set(Widget widget, XtPointer clientData, XtPointer callData) { char *temp_ptr; char line[MAX_CALLSIGN+1]; DataRow *p_station; temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(line, sizeof(line), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_leading_spaces(line); (void)remove_trailing_spaces(line); //fprintf(stderr,"Item name:%s\n", line); // We have the name now. Check it against our database of // stations/objects/items. Do an exact match. // if (search_station_name(&p_station,line,1) && (p_station->flag & ST_ACTIVE)) { // Found a live object with that name. Don't allow Object // creation. Bring up a warning message instead. popup_message_always(langcode("POPEM00035"), langcode("POPEM00038")); } else { // Not found. Allow the Item to be created. Item_change_data_set(widget, clientData, callData); } } /* * Delete an Object */ void Object_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; if (Setup_object_item_data(line, sizeof(line), p_station, 1, 1)) { // Update this object in our save file, then comment all // instances out in the file. log_object_item(line,1,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Object_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit object data, not igating } Object_destroy_shell(widget,clientData,NULL); } } /* * Delete an Item */ void Item_change_data_del(Widget widget, XtPointer clientData, XtPointer UNUSED(callData) ) { char line[43+1+40]; // ??? DataRow *p_station = global_parameter1; if (Setup_object_item_data(line,sizeof(line), p_station, 0, 1)) { // Update this item in our save file, then comment all // instances out in the file. log_object_item(line,1,last_object); // Set up the timer properly for the decaying algorithm if (p_station != NULL) { p_station->transmit_time_increment = OBJECT_CHECK_RATE; p_station->last_transmit_time = sec_now(); // p_station->last_modified_time = sec_now(); // For dead-reckoning //fprintf(stderr,"Item_change_data_del(): Setting transmit increment to %d\n", OBJECT_CHECK_RATE); } if (object_tx_disable || transmit_disable) { output_my_data(line,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(line,-1,0,0,0,NULL); // Transmit item data, not igating } Object_destroy_shell(widget,clientData,NULL); } } /* * Select a symbol graphically */ void Ob_change_symbol(Widget widget, XtPointer clientData, XtPointer callData) { //fprintf(stderr,"Trying to change a symbol\n"); symbol_change_requested_from = 2; // Tell Select_symbol who to return the data to Select_symbol(widget, clientData, callData); } /* * Update symbol picture for changed symbol or table */ void updateObjectPictureCallback(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { char table, overlay; char symb, group; char *temp_ptr; XtVaSetValues(object_icon, XmNlabelPixmap, Ob_icon0, NULL); // clear old icon XtManageChild(object_icon); temp_ptr = XmTextFieldGetString(object_group_data); group = temp_ptr[0]; XtFree(temp_ptr); temp_ptr = XmTextFieldGetString(object_symbol_data); symb = temp_ptr[0]; XtFree(temp_ptr); if (group == '/' || group == '\\') { // No overlay character table = group; overlay = ' '; } else { // Found overlay character. Check that it's a valid // overlay. if ( (group >= '0' && group <= '9') || (group >= 'A' && group <= 'Z') ) { // Valid overlay character table = '\\'; overlay = group; } else { // Bad overlay character table = '\\'; overlay = ' '; } } symbol(object_icon,0,table,symb,overlay,Ob_icon,0,0,0,' '); // create icon XtVaSetValues(object_icon,XmNlabelPixmap,Ob_icon,NULL); // draw new icon XtManageChild(object_icon); } // Handler for "Signpost" toggle button void Signpost_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Signpost_object_enabled = 1; Area_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"Signpost Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'm'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Signpost_object_enabled = 0; //fprintf(stderr,"Signpost Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Probability Circles" toggle button void Probability_circle_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Signpost_object_enabled = 0; Area_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 1; //fprintf(stderr,"Probability Circles are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); // Set to hiker symbol by default, but can be changed by // user to something else. temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '['; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Probability_circles_enabled = 0; //fprintf(stderr,"Signpost Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Enable Area Type" toggle button void Area_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Area_object_enabled = 1; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"Area Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); XtSetSensitive(ob_speed,FALSE); XtSetSensitive(ob_speed_data,FALSE); XtSetSensitive(ob_course,FALSE); XtSetSensitive(ob_course_data,FALSE); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'l'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Area_object_enabled = 0; //fprintf(stderr,"Area Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XtSetSensitive(ob_speed,TRUE); XtSetSensitive(ob_speed_data,TRUE); XtSetSensitive(ob_course,TRUE); XtSetSensitive(ob_course_data,TRUE); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "DF Bearing Object" toggle button void DF_bearing_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 1; Map_View_object_enabled = 0; Probability_circles_enabled = 0; //fprintf(stderr,"DF Objects are ENABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(map_view_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); XtSetSensitive(ob_speed,TRUE); XtSetSensitive(ob_speed_data,TRUE); XtSetSensitive(ob_course,TRUE); XtSetSensitive(ob_course_data,TRUE); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 0; temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { DF_object_enabled = 0; //fprintf(stderr,"DF Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); XmTextFieldSetString(object_comment_data,comment); } // Handler for "Map View Object" toggle button void Map_View_object_toggle( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; char temp_data[40]; char comment[43+1]; // max 43 characters of comment char signpost_name[10]; char *temp_ptr; // Save name and comment fields temporarily temp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(signpost_name, sizeof(signpost_name), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(signpost_name); temp_ptr = XmTextFieldGetString(object_comment_data); xastir_snprintf(comment, sizeof(comment), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(comment); if(state->set) { // Make a bunch of the fields insensitive that we don't use // here. Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 1; Probability_circles_enabled = 0; //fprintf(stderr,"Map View Objects are ENABLED\n"); // Make a bunch of the fields insensitive that we don't use here? // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); XmToggleButtonSetState(signpost_toggle, FALSE, FALSE); XmToggleButtonSetState(area_toggle, FALSE, FALSE); XmToggleButtonSetState(df_bearing_toggle, FALSE, FALSE); XmToggleButtonSetState(probabilities_toggle, FALSE, FALSE); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'E'; // Eyeball symbol temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); XtSetSensitive(ob_option_frame,FALSE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } else { Map_View_object_enabled = 0; //fprintf(stderr,"Map View Objects are DISABLED\n"); // Call Set_Del_Object again, causing it to redraw with the new options. //Set_Del_Object( widget, clientData, callData ); Set_Del_Object( widget, global_parameter1, global_parameter2 ); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,TRUE); XtSetSensitive(ob_option_frame,TRUE); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); } // Restore name and comment fields XmTextFieldSetString(object_name_data,signpost_name); // Don't want to restore the comment if it is a Map View object, // as Set_Del_Object() changes that field in that case. if (!Map_View_object_enabled) { XmTextFieldSetString(object_comment_data,comment); } } /* Area object type radio buttons */ void Area_type_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_type = atoi(which); // Set to shape desired if ( (Area_type == 1) || (Area_type == 6) ) // If either line type { //fprintf(stderr,"Line type: %d\n", Area_type); XtSetSensitive(ob_corridor,TRUE); XtSetSensitive(ob_corridor_data,TRUE); XtSetSensitive(ob_corridor_miles,TRUE); XtSetSensitive(open_filled_toggle,FALSE); } else // Not line type { //fprintf(stderr,"Not line type: %d\n", Area_type); XtSetSensitive(ob_corridor,FALSE); XtSetSensitive(ob_corridor_data,FALSE); XtSetSensitive(ob_corridor_miles,FALSE); XtSetSensitive(open_filled_toggle,TRUE); } } else { Area_type = 0; // Open circle //fprintf(stderr,"Type zero\n"); } //fprintf(stderr,"Area type: %d\n", Area_type); } /* Area object color radio buttons */ void Area_color_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_color[0] = which[0]; // Set to color desired. Area_color[1] = which[1]; Area_color[2] = '\0'; } else { Area_color[0] = '/'; Area_color[1] = '0'; // Black Area_color[2] = '\0'; } //fprintf(stderr,"Area color: %s\n", Area_color); } /* Area bright color enable button */ void Area_bright_dim_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_bright = atoi(which); //fprintf(stderr,"Bright colors are ENABLED: %d\n", Area_bright); } else { Area_bright = 0; //fprintf(stderr,"Bright colors are DISABLED: %d\n", Area_bright); } } /* Area filled enable button */ void Area_open_filled_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Area_filled = atoi(which); //fprintf(stderr,"Filled shapes ENABLED: %d\n", Area_filled); } else { Area_filled = 0; //fprintf(stderr,"Filled shapes DISABLED: %d\n", Area_filled); } } // Handler for "Omni Antenna" toggle button void Omni_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { //fprintf(stderr,"Omni Antenna ENABLED\n"); XmToggleButtonSetState(beam_antenna_toggle, FALSE, FALSE); XtSetSensitive(frameomni,TRUE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 1; Beam_antenna_enabled = 0; } else { //fprintf(stderr,"Omni Antenna DISABLED\n"); XtSetSensitive(frameomni,FALSE); Omni_antenna_enabled = 0; } } // Handler for "Beam Antenna" toggle button void Beam_antenna_toggle( Widget UNUSED(widget), XtPointer UNUSED(clientData), XtPointer callData) { XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { //fprintf(stderr,"Beam Antenna ENABLED\n"); XmToggleButtonSetState(omni_antenna_toggle, FALSE, FALSE); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,TRUE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 1; } else { //fprintf(stderr,"Beam Antenna DISABLED\n"); XtSetSensitive(framebeam,FALSE); Beam_antenna_enabled = 0; } } /* Object signal radio buttons */ void Ob_signal_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[0] = which[0]; // Set to signal quality heard } else { object_shgd[0] = '0'; // 0 (Signal not heard) } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object height radio buttons */ void Ob_height_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[1] = which[0]; // Set to height desired } else { object_shgd[1] = '0'; // 0 (10ft HAAT) } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object gain radio buttons */ void Ob_gain_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[2] = which[0]; // Set to antenna gain desired } else { object_shgd[2] = '0'; // 0dB gain } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object directivity radio buttons */ void Ob_directivity_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_shgd[3] = which[0]; // Set to antenna pattern desired } else { object_shgd[3] = '0'; // Omni-directional pattern } object_shgd[4] = '\0'; //fprintf(stderr,"SHGD: %s\n",object_shgd); } /* Object beamwidth radio buttons */ void Ob_width_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { object_NRQ[2] = which[0]; // Set to antenna beamwidth desired } else { object_NRQ[2] = '0'; // Beamwidth = "Useless" } object_NRQ[3] = '\0'; //fprintf(stderr,"NRQ: %s\n", object_NRQ); } /* populate predefined object (SAR) struct */ void Populate_predefined_objects(predefinedObject *predefinedObjects) { // The number of objects you are defining below must be // exactly equal to number_of_predefined_objects // and less than MAX_NUMBER_OF_PREDEFINED_OBJECTS. // using counter j for this seems inelegant ** // A set of predefined SAR objects are hardcoded and used by default // other sets of predefined objects (SAR in km, public service event, // and user defined objects) can be loaded from a file. // // Detailed instructions for the format of the files can be found in // the two example files provided: predefined_SAR.sys and // predefined_EVENT.sys char predefined_object_definition_file[263]; int read_file_ok = 0; int line_max_length = 255; int object_read_ok = 0; char line[line_max_length]; char *value; char *variable; FILE *fp_file; int j = 0; char error_correct_location[300]; char predef_obj_path[MAX_VALUE]; #ifdef OBJECT_DEF_FILE_USER_BASE char temp_file_path[MAX_VALUE]; #endif xastir_snprintf(line,sizeof(line),"%s","\0"); xastir_snprintf(predefined_object_definition_file,sizeof(predefined_object_definition_file),"config/%s",predefined_object_definition_filename); get_user_base_dir(predefined_object_definition_file, predef_obj_path, sizeof(predef_obj_path)); number_of_predefined_objects = 0; if (predefined_menu_from_file == 1 ) { // Check to see if a file containing predefined object definitions // exists, if it does, open it and try to read the definitions // if this fails, use the hardcoded SAR default instead. // fprintf(stderr,"Checking for predefined objects menu file\n"); #ifdef OBJECT_DEF_FILE_USER_BASE if (filethere(predef_obj_path)) { fp_file = fopen(predef_obj_path,"r"); #else // OBJECT_DEF_FILE_USER_BASE if (filethere(get_data_base_dir(predefined_object_definition_file))) { fp_file = fopen(get_data_base_dir(predefined_object_definition_file),"r"); #endif // OBJECT_DEF_FILE_USER_BASE xastir_snprintf(error_correct_location, sizeof(error_correct_location), "Loading from %s/%s \n", #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_file_path, sizeof(temp_file_path)), #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config"), #endif // OBJECT_DEF_FILE_USER_BASE predefined_object_definition_file); fprintf(stderr, "%s", error_correct_location); while (!feof(fp_file)) { // read lines to end of file (void)get_line(fp_file, line, line_max_length); // ignore blank lines and lines starting with # if ((strncmp("#",line,1)!=0) && (strlen(line) > 2)) { // if line starts "NAME" begin an object // next five lines should be PAGE, SYMBOL, DATA, MENU, HIDDENCHILD // NAME, PAGE, SYMBOL, MENU, and HIDDENCHILD are required. // HIDDENCHILD must come last (it is being used to identify the // end of one object). // split line into variable/value pairs on tab // See predefined_SAR.sys and predefined_event.sys for more details. variable = strtok((char *)&line,"\t"); if (strcmp("NAME",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call), "%s", value); // by default, set data to an empty string, allowing DATA to be ommitted xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); object_read_ok ++; } } if (strcmp("PAGE",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page), "%s", value); object_read_ok ++; } } if (strcmp("SYMBOL",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol), "%s", value); object_read_ok ++; } } if (strcmp("DATA",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value == NULL || strcmp(value,"NULL")==0) { xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); } else { xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data), "%s", value); } } if (strcmp("MENU",variable)==0) { value = strtok(NULL,"\t\r\n"); if (value != NULL) { xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call), "%s", value); object_read_ok ++; } } if (strcmp("HIDDENCHILD",variable)==0) { value = strtok(NULL,"\t\r\n"); if (strcmp(value,"YES")==0) { predefinedObjects[j].show_on_menu = 0; predefinedObjects[j].index_of_child = j - 1; predefinedObjects[j].index = j; } else { predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; } if (object_read_ok == 4) { // All elements for an object were read correctly. // Begin filling next element in array. j++; // Read of at least one object was successful, // don't display default hardcoded menu items. read_file_ok = 1; // Reset value counter for next object. object_read_ok = 0; } else { // Something was missing or HIDDENCHILD was out of order. // Don't increment array (overwrite a partly filled entry). fprintf(stderr,"Error in reading predefined object menu file:\nAn object is not correctly defined.\n"); } } } } // end while !feof() fclose(fp_file); if (read_file_ok==0) { fprintf(stderr,"Error in reading predefined objects menu file:\nNo valid objects found.\n"); } } else { fprintf(stderr,"Error: Predefined objects menu file not found.\n"); xastir_snprintf(error_correct_location, sizeof(error_correct_location), "File should be in %s\n", #ifdef OBJECT_DEF_FILE_USER_BASE get_user_base_dir("config", temp_file_path, sizeof(temp_file_path))); #else // OBJECT_DEF_FILE_USER_BASE get_data_base_dir("config")); #endif // OBJECT_DEF_FILE_USER_BASE fprintf(stderr, "%s", error_correct_location); } } if (read_file_ok==0) { // file read failed or was not requested, display default SAR menu // command post xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"ICP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"c"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"ICP: Command Post"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Staging area xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Staging"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"S"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Staging"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Initial Planning Point // set up to draw as two objects with different probability circles xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP_"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.75,Pmax1.0"); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"[not shown]"); // show on menu = 0 will hide this entry on menu predefinedObjects[j].show_on_menu = 0; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"IPP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data)," Pmin0.25,Pmax0.5"); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"IPP: InitialPlanningPoint"); predefinedObjects[j].show_on_menu = 1; // index of child j - 1 will add additional callback to IPP_ predefinedObjects[j].index_of_child = j - 1; predefinedObjects[j].index = j; j++; // Point last seen xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"PLS"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"PLS: Point Last Seen"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Last known point xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"LKP"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"."); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"LKP: Last Known Point"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Base xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Base"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"B"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Base"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Helibase (helicopter support base) xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Helibase"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"H"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Helibase"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Helispot (helicopter landing spot) // Heli- will be created as Heli-1, Heli-2, Heli-3, etc. // terminal - on a call is a magic character. see Create_SAR+Object. xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Heli-"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"/"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"/"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Heli-n: Helispot"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; // Camp xastir_snprintf(predefinedObjects[j].call,sizeof(predefinedObjects[j].call),"Camp"); xastir_snprintf(predefinedObjects[j].page,sizeof(predefinedObjects[j].page),"C"); xastir_snprintf(predefinedObjects[j].symbol,sizeof(predefinedObjects[j].symbol),"0"); xastir_snprintf(predefinedObjects[j].data,sizeof(predefinedObjects[j].data),"%c",'\0'); xastir_snprintf(predefinedObjects[j].menu_call,sizeof(predefinedObjects[j].menu_call),"Camp"); predefinedObjects[j].show_on_menu = 1; predefinedObjects[j].index_of_child = -1; predefinedObjects[j].index = j; j++; } // Could read additional entries from a file here. // The total number of entries should be left fairly small // to prevent the menu from becoming too large and unweildy. number_of_predefined_objects = j; if (number_of_predefined_objects>MAX_NUMBER_OF_PREDEFINED_OBJECTS) { // need beter handling of this - we will allready have run // past the end of the array if we have reached here. number_of_predefined_objects=MAX_NUMBER_OF_PREDEFINED_OBJECTS; } } /* Create a predefined SAR/Public Event object Create an object of the specified type at the current mouse position without a dialog. Current undesirable behavior: If an object of the same name exists, takes control of that object and moves it to the current mouse position. clientData is pointer to an integer representing the index of a predefined object in the predefinedObjects array */ void Create_SAR_Object(Widget UNUSED(w), XtPointer clientData, XtPointer UNUSED(calldata) ) { Dimension width, height; char call[MAX_CALLSIGN+1]; long x_lat,x_lon; char origin[MAX_CALLSIGN+1]; // mycall char data[MAX_LINE_SIZE]; char page[2]; // reserve space for probability circle as well as symbol /Pmin0.25,Pmax0.5, char symbol_plus[PREDEFINED_OBJECT_DATA_LENGTH]; char symbol[2]; char c_lon[10]; char c_lat[10]; char time[7]; intptr_t i; DataRow *p_station; int done = 0; int iterations_left = 1000; // Max iterations of while loop below int extra_num = 1; char orig_call[MAX_CALLSIGN+1]; // set some defaults in case of a non-matched value xastir_snprintf(page,sizeof(page),"/"); xastir_snprintf(symbol,sizeof(symbol),"/"); xastir_snprintf(call, sizeof(call), "Marker"); //for (i=0;i -1) { if (i <= number_of_predefined_objects) { xastir_snprintf(page,sizeof(page), "%s", predefinedObjects[i].page); xastir_snprintf(symbol,sizeof(symbol), "%s", predefinedObjects[i].symbol); xastir_snprintf(call, sizeof(call), "%s", predefinedObjects[i].call); xastir_snprintf(symbol_plus, sizeof(symbol_plus), "%s%s",symbol,predefinedObjects[i].data); } } // Get mouse position. XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); x_lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); x_lat = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); if(debug_level & 1) fprintf(stderr, "Creating symbol %s %s at: %lu %lu with calldata: [%li]\n", page, symbol, x_lat, x_lon, (intptr_t)clientData); // CONVERT_LP_NOSP = DDMM.MMN convert_lat_l2s(x_lat, (char *)c_lat, sizeof(c_lat), CONVERT_LP_NOSP); convert_lon_l2s(x_lon, (char *)c_lon, sizeof(c_lon), CONVERT_LP_NOSP); // Save "call" away in "orig_call" so that we can use it again // and again as we try to come up with a unique name for the // object. // xastir_snprintf(orig_call, sizeof(orig_call), "%s", call); // '-' is a magic character. // // If the last character in call is a "-", the symbol is expected // to be a numeric series starting with call-1, so change call to // call-1. This lets us describe Heli- and create Heli-1, Heli-2 // and similar series. Storing call to orig_call before appending // the number should allow the sequence to increment normally. if ((int)'-'==(int)*(call+(strlen(call)-1))) { // make sure that we don't write past the end of call if (strlen(call)flag & (ST_OBJECT | ST_ITEM)) != 0) // It's an object or item { // Check whether object/item has been killed already if ((p_station->flag & ST_ACTIVE) != ST_ACTIVE) { // // The object or item has been killed. Ok to use // this object name. Get out of the while loop and // create the object. // done++; continue; // Next loop iteration (Exit the while loop) } } // If we get to this point we have an object name that matches // another in our database. We must come up with a new name. We // add digits to the end of the original name until we get one that // works for us. /* // If my_callsign (Exact match includes SSID) // if (is_my_call(p_station->origin,1)) { if (is_my_object_item(p_station)) { // The previous object with the same name is owned by // me. // a) MOVE the EXISTING object (default), perhaps with the option // to clear the track. Clearing the track would only take // effect on our local map screen, not on everyone else's. // b) RENAME the NEW object, perhaps tacking a number // onto the end until we get to an unused name. // c) CANCEL request fprintf(stderr, "Object with same name exists, owned by me\n"); // Pop up a new dialog with the various options on it. Save our // state here so that we can create the object in the callbacks for // the next dialog. // // Code goes here... else { // The previous object with the same name is NOT owned // by me. // a) ADOPT the existing object and MOVE it (a very // poor idea). // Same track-clearing as option 1a. // b) RENAME the NEW object (default), perhaps tacking // a number onto the end until we get to an unused // name. // c) CANCEL request fprintf(stderr, "Object with same name exists, owned by %s\n", p_station->origin); // Pop up a new dialog with the various options on it. Save our // state here so that we can create the object in the callbacks for // the next dialog. // // Code goes here... } */ extra_num++; // Append extra_num to the object name (starts at "2"), try // again to see if it is unique. // // Note: Converting to float only to use width specifiers // properly and quiet a compiler warning. xastir_snprintf(num_string, sizeof(num_string), "%2.0f", (float)extra_num); strcpy(call, orig_call); call[sizeof(call)-1] = '\0'; // Terminate string strcat(call, num_string); call[sizeof(call)-1] = '\0'; // Terminate string // ****** Bug ******** // need to check length of call - if it has gone over 9 characters only // the first 9 will be treated as unique, thus FirstAid11 will become FirstAid1 // and become new position for existing FirstAid1. // MAX_CALLSIGN is the constraining global. // In that case, need to fail gracefully and throw an error message. iterations_left--; } // End of while loop if (iterations_left == 0) { // Pop up a message stating that we couldn't find an empty name in // 1000 iterations. Call popup_message_always() fprintf(stderr, "No more iterations left\n"); } xastir_snprintf(origin, sizeof(origin), "%s", my_callsign); xastir_snprintf(time, sizeof(time), "%02d%02d%02d", get_hours(), get_minutes(), get_seconds() ); // Prepare APRS data string using latitude and longitude from mouse click location // and page, symbol, and any additional data from the prepared object. xastir_snprintf(data, sizeof(data), ";%-9s*%sh%s%s%s%s", call, time, c_lat, page, c_lon, symbol_plus); //fprintf(stderr,"Packet:%s\n", data); log_object_item(data,0,last_object); // *********** New objects not being displayed on map untill restart if (object_tx_disable || transmit_disable) { output_my_data(data,-1,0,1,0,NULL); // Local loopback only, not igating } else { output_my_data(data,-1,0,0,0,NULL); // Transmit/loopback object data, not igating } } // Fill in fields from an existing object/item or create the proper // transmit string for a new object/item from these fields. /* * Setup Object/Item Dialog * clientData = pointer to object struct, if it's a modify or a move operation, * else it's NULL. * If calldata = 2, then we're doing a move object operation. We want in that * case to fill in the new values for lat/long and make them take effect. * If calldata = 1, then we've dropped through Station_info/Station_data * on the way to Modify->Object. * Need to put the tests for the different types of objects * at the top of this function, then the dialog will build properly for * the type of object initially. */ void Set_Del_Object( Widget w, XtPointer clientData, XtPointer calldata) { Dimension width, height; long lat,lon; char lat_str[MAX_LAT]; char lon_str[MAX_LONG]; static Widget ob_pane, ob_scrollwindow, ob_form, ob_name,ob_latlon_frame,ob_latlon_form, ob_lat, ob_lat_deg, ob_lat_min, ob_lon, ob_lon_deg, ob_lon_min, ob_lon_ew, ob_form1, signpost_form, signpost_label, probability_frame,probability_form, probability_label_min, probability_label_max, ob_option_form, area_form, bright_dim_toggle, shape_box,toption1,toption2,toption3,toption4,toption5, color_box,coption1,coption2,coption3,coption4,coption5,coption6,coption7,coption8, formomni, signal_box,soption0,soption1,soption2,soption3,soption4,soption5,soption6,soption7,soption8,soption9, height_box,hoption0,hoption1,hoption2,hoption3,hoption4,hoption5,hoption6,hoption7,hoption8,hoption9, gain_box,goption0,goption1,goption2,goption3,goption4,goption5,goption6,goption7,goption8,goption9, directivity_box,doption0,doption1,doption2,doption3,doption4,doption5,doption6,doption7,doption8, formbeam, width_box,woption0,woption1,woption2,woption3,woption4,woption5,woption6,woption7,woption8,woption9, ob_bearing, ob_lat_offset,ob_lon_offset, ob_sep, ob_button_set,ob_button_del,ob_button_cancel,it_button_set, ob_button_symbol, compute_button; char temp_data[40]; Atom delw; DataRow *p_station = (DataRow *)clientData; Arg al[50]; /* Arg List */ unsigned int ac; /* Arg Count */ long x,y; /* if (p_station != NULL) fprintf(stderr,"Have a pointer to an object. "); else fprintf(stderr,"No pointer, new object? "); if (calldata != NULL) { if (strcmp(calldata,"2") == 0) fprintf(stderr,"Set_Del_Object: calldata: 2. Move object.\n"); else if (strcmp(calldata,"1") == 0) fprintf(stderr,"Set_Del_Object: calldata: 1. Modify object.\n"); else if (strcmp(calldata,"0") == 0) fprintf(stderr,"Set_Del_Object: calldata: 0. New object.\n"); else fprintf(stderr,"Set_Del_Object: calldata: invalid. New object.\n"); } */ // Save the data so that other routines can access it. Some of the // callbacks can only handle one parameter, and we need two. if (p_station != NULL) { global_parameter1 = clientData; } else { global_parameter1 = NULL; } global_parameter2 = calldata; // This function can be invoked from the mouse menus or by being called // directly by other routines. We look at the p_station pointer to decide // how we were called. // if (p_station != NULL) // We were called from the Modify_object() { // or Move() functions //fprintf(stderr,"Got a pointer!\n"); lon = p_station->coord_lon; // Fill in values from the original object lat = p_station->coord_lat; } else { // We were called from the "Create New Object" mouse menu or // by the "Move" option get default position for object, the // position we have clicked at. For the special case of a // Map View object, we instead want the screen center for // this new object. // if (Map_View_object_enabled) { // Get center of screen lon = center_longitude; lat = center_latitude; } else { // Get mouse position XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); lon = center_longitude - ((width *scale_x)/2) + (menu_x*scale_x); lat = center_latitude - ((height*scale_y)/2) + (menu_y*scale_y); } } // If the object dialog is up, we need to kill it and draw a new // one so that we have the correct values filled in. if (object_dialog) { Object_destroy_shell( w, object_dialog, NULL); } // Check for the three "Special" types of objects we deal with and set // the global variables for them here. This will result in the correct // type of dialog being drawn for each type of object. // Question: What about for Modify->Object where we're trying to change // the type of the object? if (p_station != NULL) { /* if (calldata != NULL) { if (strcmp(calldata,"2") == 0) fprintf(stderr,"Set_Del_Object: calldata: 2. Move object.\n"); else if (strcmp(calldata,"1") == 0) fprintf(stderr,"Set_Del_Object: calldata: 1. Modify object.\n"); else if (strcmp(calldata,"0") == 0) fprintf(stderr,"Set_Del_Object: calldata: 0. New object.\n"); else fprintf(stderr,"Set_Del_Object: calldata: invalid. New object.\n"); } */ // Check to see whether we should even be here at all! if ( !(p_station->flag & ST_OBJECT) && !(p_station->flag & ST_ITEM)) // Not an object or item { //fprintf(stderr,"flag: %i\n", (int)p_station->flag); popup_message_always(langcode("POPEM00022"), langcode("POPEM00043") ); // "Not an Object/Item!" return; } // Set to known defaults first Area_object_enabled = 0; Signpost_object_enabled = 0; DF_object_enabled = 0; Map_View_object_enabled = 0; Probability_circles_enabled = 0; if (p_station->aprs_symbol.area_object.type != AREA_NONE) // Found an area object { Area_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == 'm') // Found a signpost object && (p_station->aprs_symbol.aprs_type == '\\') ) { Signpost_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == '\\') // Found a DF object && (p_station->aprs_symbol.aprs_type == '/') && ((strlen(p_station->signal_gain) == 7) // That has data associated with it || (strlen(p_station->bearing) == 3) || (strlen(p_station->NRQ) == 3) ) ) { DF_object_enabled = 1; } else if ( (p_station->aprs_symbol.aprs_symbol == 'E') // Found a Map View object && (p_station->aprs_symbol.aprs_type == '/') && (strstr(p_station->power_gain,"RNG") != 0) ) // Has a range value { //fprintf(stderr,"Found a range\n"); Map_View_object_enabled = 1; } else if (p_station->probability_min[0] != '\0' // Found some data || p_station->probability_max[0] != '\0') // Found some data { Probability_circles_enabled = 1; } } //fprintf(stderr,"Area:Signpost:DF %i:%i:%i\n",Area_object_enabled,Signpost_object_enabled,DF_object_enabled); // Ok. The stage is now set to draw the proper type of dialog for the // type of object we're interested in currently. if(object_dialog) // it is already open { (void)XRaiseWindow(XtDisplay(object_dialog), XtWindow(object_dialog)); } else // create new popup window { object_dialog = XtVaCreatePopupShell(langcode("POPUPOB001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); ob_pane = XtVaCreateWidget("Set_Del_Object pane", xmPanedWindowWidgetClass, object_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, ob_pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); ob_form = XtVaCreateWidget("Set_Del_Object ob_form", xmFormWidgetClass, ob_scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Name" ob_name = XtVaCreateManagedWidget(langcode("POPUPOB002"), xmLabelWidgetClass, ob_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // object name object_name_data = XtVaCreateManagedWidget("Set_Del_Object name_data", xmTextFieldWidgetClass, ob_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNmaxLength, 9, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_name, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); //----- Frame for table / symbol ob_frame = XtVaCreateManagedWidget("Set_Del_Object ob_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, object_name_data, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Station Symbol" // ob_ts (void)XtVaCreateManagedWidget(langcode("WPUPCFS009"), xmLabelWidgetClass, ob_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_form1 = XtVaCreateWidget("Set_Del_Object form1", xmFormWidgetClass, ob_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Group/overlay" ob_group = XtVaCreateManagedWidget(langcode("WPUPCFS010"), xmLabelWidgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // table object_group_data = XtVaCreateManagedWidget("Set_Del_Object group", xmTextFieldWidgetClass, ob_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_group, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Symbol" ob_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS011"), xmLabelWidgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_group_data, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // symbol object_symbol_data = XtVaCreateManagedWidget("Set_Del_Object symbol", xmTextFieldWidgetClass, ob_form1, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_symbol, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // icon Ob_icon0 = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); Ob_icon = XCreatePixmap(XtDisplay(appshell), RootWindowOfScreen(XtScreen(appshell)), 20, 20, DefaultDepthOfScreen(XtScreen(appshell))); object_icon = XtVaCreateManagedWidget("Set_Del_Object icon", xmLabelWidgetClass, ob_form1, XmNlabelType, XmPIXMAP, XmNlabelPixmap, Ob_icon, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_symbol_data, XmNleftOffset, 15, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_button_symbol = XtVaCreateManagedWidget(langcode("WPUPCFS028"), xmPushButtonGadgetClass, ob_form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_icon, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_symbol, XmNactivateCallback, Ob_change_symbol, object_dialog); //----- Frame for Lat/Long ob_latlon_frame = XtVaCreateManagedWidget("Set_Del_Object ob_latlon_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Location" //ob_latlon_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB028"), xmLabelWidgetClass, ob_latlon_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_latlon_form = XtVaCreateWidget("Set_Del_Object ob_latlon_form", xmFormWidgetClass, ob_latlon_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "LAT" ob_lat = XtVaCreateManagedWidget(langcode("WPUPCFS003"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 15, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lat deg object_lat_data_deg = XtVaCreateManagedWidget("Set_Del_Object lat_deg", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 2, XmNtopOffset, 5, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "deg" ob_lat_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // lat min object_lat_data_min = XtVaCreateManagedWidget("Set_Del_Object lat_min", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "min" ob_lat_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // N/S object_lat_data_ns = XtVaCreateManagedWidget("Set_Del_Object lat_ns", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 5, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "(N/S)" // ob_lat_ns (void)XtVaCreateManagedWidget(langcode("WPUPCFS006"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lat_data_ns, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "LONG" ob_lon = XtVaCreateManagedWidget(langcode("WPUPCFS007"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // long object_lon_data_deg = XtVaCreateManagedWidget("Set_Del_Object long_deg", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 14, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "deg" ob_lon_deg = XtVaCreateManagedWidget(langcode("WPUPCFS004"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_deg, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // min object_lon_data_min = XtVaCreateManagedWidget("Set_Del_Object long_min", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 14, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_deg, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "min" ob_lon_min = XtVaCreateManagedWidget(langcode("WPUPCFS005"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_min, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // E/W object_lon_data_ew = XtVaCreateManagedWidget("Set_Del_Object long_ew", xmTextFieldWidgetClass, ob_latlon_form, XmNeditable, TRUE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 1, XmNmaxLength, 1, XmNtopOffset, 14, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_min, XmNleftOffset, 10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); // "(E/W)" ob_lon_ew = XtVaCreateManagedWidget(langcode("WPUPCFS008"), xmLabelWidgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, object_lon_data_ew, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); compute_button = XtVaCreateManagedWidget(langcode("COORD002"), xmPushButtonGadgetClass, ob_latlon_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_lat, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_ew, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Fill in the pointers to our input textfields so that the coordinate // calculator can fiddle with them. coordinate_calc_array.calling_dialog = object_dialog; coordinate_calc_array.input_lat_deg = object_lat_data_deg; coordinate_calc_array.input_lat_min = object_lat_data_min; coordinate_calc_array.input_lat_dir = object_lat_data_ns; coordinate_calc_array.input_lon_deg = object_lon_data_deg; coordinate_calc_array.input_lon_min = object_lon_data_min; coordinate_calc_array.input_lon_dir = object_lon_data_ew; // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, ob_latlon_form); // XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, "Set_Del_Object"); XtAddCallback(compute_button, XmNactivateCallback, Coordinate_calc, langcode("POPUPOB001")); //----- Frame for generic options ob_option_frame = XtVaCreateManagedWidget("Set_Del_Object ob_option_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Generic Options" // ob_option_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB027"), xmLabelWidgetClass, ob_option_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_option_form = XtVaCreateWidget("Set_Del_Object ob_option_form", xmFormWidgetClass, ob_option_frame, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Speed" ob_speed = XtVaCreateManagedWidget(langcode("POPUPOB036"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_speed_data = XtVaCreateManagedWidget("Set_Del_Object ob_speed_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_speed, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Course" ob_course = XtVaCreateManagedWidget(langcode("POPUPOB037"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_speed_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_course_data = XtVaCreateManagedWidget("Set_Del_Object ob_course_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_course, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Altitude" ob_altitude = XtVaCreateManagedWidget(langcode("POPUPOB035"), xmLabelWidgetClass, ob_option_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_course_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_altitude_data = XtVaCreateManagedWidget("Set_Del_Object ob_altitude_data", xmTextFieldWidgetClass, ob_option_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 6, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_altitude, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); //----- Comment Field // "Comment:" ob_comment = XtVaCreateManagedWidget(langcode("WPUPCFS017"), xmLabelWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_option_frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); object_comment_data = XtVaCreateManagedWidget("Set_Del_Object comment", xmTextFieldWidgetClass, ob_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 37, // max 43 without Data Extension XmNmaxLength, 43, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_comment, XmNleftOffset, 5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_option_frame, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Probability Circles" probabilities_toggle = XtVaCreateManagedWidget(langcode("POPUPOB047"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_latlon_frame, XmNtopOffset, 2, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(probabilities_toggle,XmNvalueChangedCallback,Probability_circle_toggle,(XtPointer)p_station); // "Signpost Enable" signpost_toggle = XtVaCreateManagedWidget(langcode("POPUPOB029"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probabilities_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(signpost_toggle,XmNvalueChangedCallback,Signpost_object_toggle,(XtPointer)p_station); // "Area Enable" area_toggle = XtVaCreateManagedWidget(langcode("POPUPOB008"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(area_toggle,XmNvalueChangedCallback,Area_object_toggle,(XtPointer)p_station); // "Area Enable" df_bearing_toggle = XtVaCreateManagedWidget(langcode("POPUPOB038"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, area_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(df_bearing_toggle,XmNvalueChangedCallback,DF_bearing_object_toggle,(XtPointer)p_station); // "Map View Object" map_view_toggle = XtVaCreateManagedWidget(langcode("POPUPOB048"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, df_bearing_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_option_frame, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(map_view_toggle,XmNvalueChangedCallback,Map_View_object_toggle,(XtPointer)p_station); //----- Frame for Probability Circles info if (Probability_circles_enabled) { //fprintf(stderr,"Drawing probability circle data\n"); probability_frame = XtVaCreateManagedWidget("Set_Del_Object probability_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Probability Circles" // probability_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB047"), xmLabelWidgetClass, probability_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_form = XtVaCreateWidget("Set_Del_Object probability_form", xmFormWidgetClass, probability_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Min (mi):" probability_label_min = XtVaCreateManagedWidget(langcode("POPUPOB049"), xmLabelWidgetClass, probability_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_data_min = XtVaCreateManagedWidget("Set_Del_Object probability_data_min", xmTextFieldWidgetClass, probability_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNmaxLength, 10, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, probability_label_min, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Max (mi):" probability_label_max = XtVaCreateManagedWidget(langcode("POPUPOB050"), xmLabelWidgetClass, probability_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_label_min, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); probability_data_max = XtVaCreateManagedWidget("Set_Del_Object probability_data_max", xmTextFieldWidgetClass, probability_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 10, XmNmaxLength, 10, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, probability_label_max, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_label_min, XmNbottomAttachment, XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, probability_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for signpost info else if (Signpost_object_enabled) { //fprintf(stderr,"Drawing signpost data\n"); signpost_frame = XtVaCreateManagedWidget("Set_Del_Object signpost_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Signpost" // signpost_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB031"), xmLabelWidgetClass, signpost_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); signpost_form = XtVaCreateWidget("Set_Del_Object signpost_form", xmFormWidgetClass, signpost_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // "Signpost Data" signpost_label = XtVaCreateManagedWidget(langcode("POPUPOB030"), xmLabelWidgetClass, signpost_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); signpost_data = XtVaCreateManagedWidget("Set_Del_Object signpost_data", xmTextFieldWidgetClass, signpost_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 3, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, signpost_label, XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for area info else if (Area_object_enabled) { //fprintf(stderr,"Drawing Area data\n"); area_frame = XtVaCreateManagedWidget("Set_Del_Object area_frame", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Area Options" // area_ts (void)XtVaCreateManagedWidget(langcode("POPUPOB007"), xmLabelWidgetClass, area_frame, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); area_form = XtVaCreateWidget("Set_Del_Object area_form", xmFormWidgetClass, area_frame, XmNfractionBase, 5, XmNautoUnmanage, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // "Bright Color Enable" bright_dim_toggle = XtVaCreateManagedWidget(langcode("POPUPOB009"), xmToggleButtonGadgetClass, area_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNset, FALSE, // Select default to be OFF MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(bright_dim_toggle,XmNvalueChangedCallback,Area_bright_dim_toggle,"1"); Area_bright = 0; // Set to default each time dialog is created // "Color-Fill Enable" open_filled_toggle = XtVaCreateManagedWidget(langcode("POPUPOB010"), xmToggleButtonGadgetClass, area_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, bright_dim_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNset, FALSE, // Select default to be OFF MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(open_filled_toggle,XmNvalueChangedCallback,Area_open_filled_toggle,"1"); Area_filled = 0; // Set to default each time dialog is created // Shape of object ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; shape_box = XmCreateRadioBox(area_form, "Set_Del_Object Shape Options box", al, ac); XtVaSetValues(shape_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, bright_dim_toggle, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,1, NULL); // "Circle" toption1 = XtVaCreateManagedWidget(langcode("POPUPOB011"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption1,XmNvalueChangedCallback,Area_type_toggle,"0"); // "Line-Right '/'" toption2 = XtVaCreateManagedWidget(langcode("POPUPOB013"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption2,XmNvalueChangedCallback,Area_type_toggle,"1"); // "Line-Left '\' toption3 = XtVaCreateManagedWidget(langcode("POPUPOB012"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption3,XmNvalueChangedCallback,Area_type_toggle,"6"); // "Triangle" toption4 = XtVaCreateManagedWidget(langcode("POPUPOB014"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption4,XmNvalueChangedCallback,Area_type_toggle,"3"); // "Rectangle" toption5 = XtVaCreateManagedWidget(langcode("POPUPOB015"), xmToggleButtonGadgetClass, shape_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(toption5,XmNvalueChangedCallback,Area_type_toggle,"4"); // Color of object color_box = XmCreateRadioBox(area_form, "Set_Del_Object Color Options box", al, ac); XtVaSetValues(color_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, shape_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, NULL); XtVaSetValues(color_box, XmNnumColumns,4, NULL); // "Black" coption1 = XtVaCreateManagedWidget(langcode("POPUPOB016"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption1,XmNvalueChangedCallback,Area_color_toggle,"/0"); // "Blue" coption2 = XtVaCreateManagedWidget(langcode("POPUPOB017"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption2,XmNvalueChangedCallback,Area_color_toggle,"/1"); // "Green" coption3 = XtVaCreateManagedWidget(langcode("POPUPOB018"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption3,XmNvalueChangedCallback,Area_color_toggle,"/2"); // "Cyan" coption4 = XtVaCreateManagedWidget(langcode("POPUPOB019"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption4,XmNvalueChangedCallback,Area_color_toggle,"/3"); // "Red" coption5 = XtVaCreateManagedWidget(langcode("POPUPOB020"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption5,XmNvalueChangedCallback,Area_color_toggle,"/4"); // "Violet" coption6 = XtVaCreateManagedWidget(langcode("POPUPOB021"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption6,XmNvalueChangedCallback,Area_color_toggle,"/5"); // "Yellow" coption7 = XtVaCreateManagedWidget(langcode("POPUPOB022"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption7,XmNvalueChangedCallback,Area_color_toggle,"/6"); // "Grey" coption8 = XtVaCreateManagedWidget(langcode("POPUPOB023"), xmToggleButtonGadgetClass, color_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(coption8,XmNvalueChangedCallback,Area_color_toggle,"/7"); // Latitude offset // "Offset Up" ob_lat_offset = XtVaCreateManagedWidget(langcode("POPUPOB024"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_lat_offset_data = XtVaCreateManagedWidget("Set_Del_Object lat offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNmaxLength, 4, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_offset, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // Longitude offset // "Offset Left (except for '/')" ob_lon_offset = XtVaCreateManagedWidget(langcode("POPUPOB025"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lat_offset_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_lon_offset_data = XtVaCreateManagedWidget("Set_Del_Object long offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 4, XmNmaxLength, 4, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_offset, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Corridor (Lines only)" ob_corridor = XtVaCreateManagedWidget(langcode("POPUPOB026"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_lon_offset_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); ob_corridor_data = XtVaCreateManagedWidget("Set_Del_Object lat offset", xmTextFieldWidgetClass, area_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 3, XmNmaxLength, 3, XmNtopOffset, 5, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_corridor, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNbottomAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, XmNfontList, fontlist1, NULL); // "Miles" ob_corridor_miles = XtVaCreateManagedWidget(langcode("UNIOP00004"), xmLabelWidgetClass, area_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, color_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 10, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_corridor_data, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtSetSensitive(ob_corridor,FALSE); XtSetSensitive(ob_corridor_data,FALSE); XtSetSensitive(ob_corridor_miles,FALSE); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, area_frame, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Frame for DF-omni info else if (DF_object_enabled) { //fprintf(stderr,"Drawing DF data\n"); // "Omni Antenna" omni_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB041"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, signpost_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, area_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(omni_antenna_toggle,XmNvalueChangedCallback,Omni_antenna_toggle,(XtPointer)p_station); // "Beam Antenna" beam_antenna_toggle = XtVaCreateManagedWidget(langcode("POPUPOB042"), xmToggleButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, omni_antenna_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNbottomOffset, 0, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, area_toggle, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(beam_antenna_toggle,XmNvalueChangedCallback,Beam_antenna_toggle,(XtPointer)p_station); frameomni = XtVaCreateManagedWidget("Set_Del_Object frameomni", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // omnilabel (void)XtVaCreateManagedWidget(langcode("POPUPOB039"), xmLabelWidgetClass, frameomni, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formomni = XtVaCreateWidget("Set_Del_Object formomni", xmFormWidgetClass, frameomni, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Power ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; signal_box = XmCreateRadioBox(formomni, "Set_Del_Object Power Radio Box", al, ac); XtVaSetValues(signal_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns, 11, NULL); // No signal detected what-so-ever soption0 = XtVaCreateManagedWidget("0", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption0,XmNvalueChangedCallback,Ob_signal_toggle,"0"); // Detectible signal (Maybe) soption1 = XtVaCreateManagedWidget("1", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption1,XmNvalueChangedCallback,Ob_signal_toggle,"1"); // Detectible signal (certain but not copyable) soption2 = XtVaCreateManagedWidget("2", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption2,XmNvalueChangedCallback,Ob_signal_toggle,"2"); // Weak signal marginally readable soption3 = XtVaCreateManagedWidget("3", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption3,XmNvalueChangedCallback,Ob_signal_toggle,"3"); // Noisy but copyable soption4 = XtVaCreateManagedWidget("4", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption4,XmNvalueChangedCallback,Ob_signal_toggle,"4"); // Some noise but easy to copy soption5 = XtVaCreateManagedWidget("5", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption5,XmNvalueChangedCallback,Ob_signal_toggle,"5"); // Good signal with detectible noise soption6 = XtVaCreateManagedWidget("6", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption6,XmNvalueChangedCallback,Ob_signal_toggle,"6"); // Near full-quieting signal soption7 = XtVaCreateManagedWidget("7", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption7,XmNvalueChangedCallback,Ob_signal_toggle,"7"); // Dead full-quieting signal, no noise detectible soption8 = XtVaCreateManagedWidget("8", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption8,XmNvalueChangedCallback,Ob_signal_toggle,"8"); // Extremely strong signal "pins the meter" soption9 = XtVaCreateManagedWidget("9", xmToggleButtonGadgetClass, signal_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(soption9,XmNvalueChangedCallback,Ob_signal_toggle,"9"); // Height height_box = XmCreateRadioBox(formomni, "Set_Del_Object Height Radio Box", al, ac); XtVaSetValues(height_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,signal_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 10 Feet hoption0 = XtVaCreateManagedWidget( (english_units) ? "10ft" : "3m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption0,XmNvalueChangedCallback,Ob_height_toggle,"0"); // 20 Feet hoption1 = XtVaCreateManagedWidget( (english_units) ? "20ft" : "6m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption1,XmNvalueChangedCallback,Ob_height_toggle,"1"); // 40 Feet hoption2 = XtVaCreateManagedWidget( (english_units) ? "40ft" : "12m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption2,XmNvalueChangedCallback,Ob_height_toggle,"2"); // 80 Feet hoption3 = XtVaCreateManagedWidget( (english_units) ? "80ft" : "24m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption3,XmNvalueChangedCallback,Ob_height_toggle,"3"); // 160 Feet hoption4 = XtVaCreateManagedWidget( (english_units) ? "160ft" : "49m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption4,XmNvalueChangedCallback,Ob_height_toggle,"4"); // 320 Feet hoption5 = XtVaCreateManagedWidget( (english_units) ? "320ft" : "98m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption5,XmNvalueChangedCallback,Ob_height_toggle,"5"); // 640 Feet hoption6 = XtVaCreateManagedWidget( (english_units) ? "640ft" : "195m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption6,XmNvalueChangedCallback,Ob_height_toggle,"6"); // 1280 Feet hoption7 = XtVaCreateManagedWidget( (english_units) ? "1280ft" : "390m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption7,XmNvalueChangedCallback,Ob_height_toggle,"7"); // 2560 Feet hoption8 = XtVaCreateManagedWidget( (english_units) ? "2560ft" : "780m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption8,XmNvalueChangedCallback,Ob_height_toggle,"8"); // 5120 Feet hoption9 = XtVaCreateManagedWidget( (english_units) ? "5120ft" : "1561m", xmToggleButtonGadgetClass, height_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(hoption9,XmNvalueChangedCallback,Ob_height_toggle,"9"); // Gain gain_box = XmCreateRadioBox(formomni, "Set_Del_Object Gain Radio Box", al, ac); XtVaSetValues(gain_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,height_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // 0 dB goption0 = XtVaCreateManagedWidget("0dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption0,XmNvalueChangedCallback,Ob_gain_toggle,"0"); // 1 dB goption1 = XtVaCreateManagedWidget("1dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption1,XmNvalueChangedCallback,Ob_gain_toggle,"1"); // 2 dB goption2 = XtVaCreateManagedWidget("2dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption2,XmNvalueChangedCallback,Ob_gain_toggle,"2"); // 3 dB goption3 = XtVaCreateManagedWidget("3dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption3,XmNvalueChangedCallback,Ob_gain_toggle,"3"); // 4 dB goption4 = XtVaCreateManagedWidget("4dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption4,XmNvalueChangedCallback,Ob_gain_toggle,"4"); // 5 dB goption5 = XtVaCreateManagedWidget("5dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption5,XmNvalueChangedCallback,Ob_gain_toggle,"5"); // 6 dB goption6 = XtVaCreateManagedWidget("6dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption6,XmNvalueChangedCallback,Ob_gain_toggle,"6"); // 7 dB goption7 = XtVaCreateManagedWidget("7dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption7,XmNvalueChangedCallback,Ob_gain_toggle,"7"); // 8 dB goption8 = XtVaCreateManagedWidget("8dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption8,XmNvalueChangedCallback,Ob_gain_toggle,"8"); // 9 dB goption9 = XtVaCreateManagedWidget("9dB", xmToggleButtonGadgetClass, gain_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(goption9,XmNvalueChangedCallback,Ob_gain_toggle,"9"); // Gain directivity_box = XmCreateRadioBox(formomni, "Set_Del_Object Directivity Radio Box", al, ac); XtVaSetValues(directivity_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,gain_box, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns,10, NULL); // Omni-directional doption0 = XtVaCreateManagedWidget(langcode("WPUPCFS016"), xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption0,XmNvalueChangedCallback,Ob_directivity_toggle,"0"); // 45 NE doption1 = XtVaCreateManagedWidget("45\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption1,XmNvalueChangedCallback,Ob_directivity_toggle,"1"); // 90 E doption2 = XtVaCreateManagedWidget("90\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption2,XmNvalueChangedCallback,Ob_directivity_toggle,"2"); // 135 SE doption3 = XtVaCreateManagedWidget("135\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption3,XmNvalueChangedCallback,Ob_directivity_toggle,"3"); // 180 S doption4 = XtVaCreateManagedWidget("180\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption4,XmNvalueChangedCallback,Ob_directivity_toggle,"4"); // 225 SW doption5 = XtVaCreateManagedWidget("225\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption5,XmNvalueChangedCallback,Ob_directivity_toggle,"5"); // 270 W doption6 = XtVaCreateManagedWidget("270\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption6,XmNvalueChangedCallback,Ob_directivity_toggle,"6"); // 315 NW doption7 = XtVaCreateManagedWidget("315\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption7,XmNvalueChangedCallback,Ob_directivity_toggle,"7"); // 360 N doption8 = XtVaCreateManagedWidget("360\xB0", xmToggleButtonGadgetClass, directivity_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(doption8,XmNvalueChangedCallback,Ob_directivity_toggle,"8"); //----- Frame for DF-beam info framebeam = XtVaCreateManagedWidget("Set_Del_Object framebeam", xmFrameWidgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frameomni, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // beamlabel (void)XtVaCreateManagedWidget(langcode("POPUPOB040"), xmLabelWidgetClass, framebeam, XmNchildType, XmFRAME_TITLE_CHILD, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); formbeam = XtVaCreateWidget("Set_Del_Object formbeam", xmFormWidgetClass, framebeam, XmNfractionBase, 5, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); // Beam width ac = 0; XtSetArg(al[ac], XmNforeground, MY_FG_COLOR); ac++; XtSetArg(al[ac], XmNbackground, MY_BG_COLOR); ac++; width_box = XmCreateRadioBox(formbeam, "Set_Del_Object Width Box", al, ac); XtVaSetValues(width_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNnumColumns, 11, NULL); // Useless woption0 = XtVaCreateManagedWidget(langcode("POPUPOB043"), xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption0,XmNvalueChangedCallback,Ob_width_toggle,"0"); // < 240 Degrees woption1 = XtVaCreateManagedWidget("<240\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption1,XmNvalueChangedCallback,Ob_width_toggle,"1"); // < 120 Degrees woption2 = XtVaCreateManagedWidget("<120\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption2,XmNvalueChangedCallback,Ob_width_toggle,"2"); // < 64 Degrees woption3 = XtVaCreateManagedWidget("<64\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption3,XmNvalueChangedCallback,Ob_width_toggle,"3"); // < 32 Degrees woption4 = XtVaCreateManagedWidget("<32\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption4,XmNvalueChangedCallback,Ob_width_toggle,"4"); // < 16 Degrees woption5 = XtVaCreateManagedWidget("<16\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption5,XmNvalueChangedCallback,Ob_width_toggle,"5"); // < 8 Degrees woption6 = XtVaCreateManagedWidget("<8\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption6,XmNvalueChangedCallback,Ob_width_toggle,"6"); // < 4 Degrees woption7 = XtVaCreateManagedWidget("<4\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption7,XmNvalueChangedCallback,Ob_width_toggle,"7"); // < 2 Degrees woption8 = XtVaCreateManagedWidget("<2\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption8,XmNvalueChangedCallback,Ob_width_toggle,"8"); // < 1 Degrees woption9 = XtVaCreateManagedWidget("<1\xB0", xmToggleButtonGadgetClass, width_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(woption9,XmNvalueChangedCallback,Ob_width_toggle,"9"); // "Bearing" ob_bearing = XtVaCreateManagedWidget(langcode("POPUPOB046"), xmLabelWidgetClass, formbeam, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, width_box, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Bearing data ob_bearing_data = XtVaCreateManagedWidget("Set_Del_Object ob_bearing_data", xmTextFieldWidgetClass, formbeam, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 9, XmNmaxLength, 9, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, width_box, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, ob_bearing, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); XtSetSensitive(frameomni,FALSE); XtSetSensitive(framebeam,FALSE); Omni_antenna_enabled = 0; Beam_antenna_enabled = 0; ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, framebeam, XmNtopOffset, 14, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } // End of DF-specific widgets //----- No Special options selected. We need a widget here for the next widget to attach to. if (!DF_object_enabled && !Area_object_enabled && !Signpost_object_enabled && !Probability_circles_enabled) { //fprintf(stderr,"No special object types\n"); ob_sep = XtVaCreateManagedWidget("Set_Del_Object ob_sep", xmSeparatorGadgetClass, ob_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, map_view_toggle, XmNtopOffset, 0, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); } //----- Buttons if (p_station != NULL) // We were called from the Modify_object() or Move function { // Change the buttons/callbacks based on whether we're dealing with an item or an object if ((p_station->flag & ST_ITEM) != 0) // Modifying an Item { // Here we need Modify Item/Delete Item/Cancel buttons ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB034"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_set, XmNactivateCallback, Item_change_data_set, object_dialog); // Check whether we own this item if (strcasecmp(p_station->origin,my_callsign)==0) { // We own this item, set up the "Delete" // button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB033"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_del, object_dialog); } else { // Somebody else owns this item, set up the // "Adopt" button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB045"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Item_change_data_set, object_dialog); } } else // Modifying an Object { // Here we need Modify Object/Delete Object/Cancel buttons ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB005"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_set, XmNactivateCallback, Object_change_data_set, object_dialog); // Check whether we own this Object if (strcasecmp(p_station->origin,my_callsign)==0) { // We own this object, set up the "Delete" // button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB004"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_del, object_dialog); } else { // Somebody else owns this object, set up the // "Adopt" button. ob_button_del = XtVaCreateManagedWidget(langcode("POPUPOB044"), xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_del, XmNactivateCallback, Object_change_data_set, object_dialog); } } } else // We were called from Create->Object mouse menu { ob_button_set = XtVaCreateManagedWidget(langcode("POPUPOB003"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); it_button_set = XtVaCreateManagedWidget(langcode("POPUPOB006"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); // Changed to different callback routines here which // check the new object/item name against our internal // database then call // Object_change_data_set/Item_change_data_set if all // ok. If a conflict (object/item already exists), do a // popup_message() instead or bring up a confirmation // dialog before creating the object/item. // //XtAddCallback(ob_button_set, // XmNactivateCallback, // Object_change_data_set, // object_dialog); //XtAddCallback(it_button_set, // XmNactivateCallback, // Item_change_data_set, // object_dialog); XtAddCallback(ob_button_set, XmNactivateCallback, Object_confirm_data_set, object_dialog); XtAddCallback(it_button_set, XmNactivateCallback, Item_confirm_data_set, object_dialog); } ob_button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"),xmPushButtonGadgetClass, ob_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, ob_sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(ob_button_cancel, XmNactivateCallback, Object_destroy_shell, object_dialog); // Set ToggleButtons for the current state. Don't notify the callback // functions associated with them or we'll be in an infinite loop. if (Area_object_enabled) { XmToggleButtonSetState(area_toggle, TRUE, FALSE); } if (Signpost_object_enabled) { XmToggleButtonSetState(signpost_toggle, TRUE, FALSE); } if (DF_object_enabled) { XmToggleButtonSetState(df_bearing_toggle, TRUE, FALSE); } if (Map_View_object_enabled) { XmToggleButtonSetState(map_view_toggle, TRUE, FALSE); } if (Probability_circles_enabled) { XmToggleButtonSetState(probabilities_toggle, TRUE, FALSE); } // Fill in current data if object already exists if (p_station != NULL) // We were called from the Modify_object() or Move functions { // Don't allow changing types if the object is already created. // Already tried allowing it, and it causes other problems. XtSetSensitive(area_toggle, FALSE); XtSetSensitive(signpost_toggle, FALSE); XtSetSensitive(df_bearing_toggle, FALSE); XtSetSensitive(map_view_toggle, FALSE); XtSetSensitive(probabilities_toggle, FALSE); XmTextFieldSetString(object_name_data,p_station->call_sign); // Need to make the above field non-editable 'cuz we're trying to modify // _parameters_ of the object and the name has to stay the same in order // to do this. Change the name and we'll be creating a new object instead // of modifying an old one. XtSetSensitive(object_name_data, FALSE); // Would be nice to change the colors too // Check for overlay character if (p_station->aprs_symbol.special_overlay) { // Found an overlay character temp_data[0] = p_station->aprs_symbol.special_overlay; } else // No overlay character { temp_data[0] = p_station->aprs_symbol.aprs_type; } temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = p_station->aprs_symbol.aprs_symbol; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // We only check the first possible comment string in // the record //if (strlen(p_station->comments) > 0) if (Map_View_object_enabled) { if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { char temp[100]; xastir_snprintf(temp, sizeof(temp), "%s%s", p_station->power_gain, p_station->comment_data->text_ptr); XmTextFieldSetString(object_comment_data,temp); } else { XmTextFieldSetString(object_comment_data,p_station->power_gain); } } else if ( (p_station->comment_data != NULL) && (p_station->comment_data->text_ptr != NULL) ) { XmTextFieldSetString(object_comment_data,p_station->comment_data->text_ptr); } else { XmTextFieldSetString(object_comment_data,""); } // if ( (p_station->aprs_symbol.area_object.type != AREA_NONE) // Found an area object // && Area_object_enabled ) { if (Area_object_enabled) { XtSetSensitive(ob_frame,FALSE); XtSetSensitive(area_frame,TRUE); switch (p_station->aprs_symbol.area_object.type) { case (1): // Line '/' XmToggleButtonSetState(toption2, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); if (p_station->aprs_symbol.area_object.corridor_width > 0) xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.corridor_width ); else { temp_data[0] = '\0'; // Empty string } XmTextFieldSetString( ob_corridor_data, temp_data ); break; case (6): // Line '\' XmToggleButtonGadgetSetState(toption3, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); if (p_station->aprs_symbol.area_object.corridor_width > 0) xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.corridor_width ); else { temp_data[0] = '\0'; // Empty string } XmTextFieldSetString( ob_corridor_data, temp_data ); break; case (3): // Open Triangle XmToggleButtonGadgetSetState(toption4, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; case (4): // Open Rectangle XmToggleButtonGadgetSetState(toption5, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; case (5): // Filled Circle XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (8): // Filled Triangle XmToggleButtonGadgetSetState(toption4, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (9): // Filled Rectangle XmToggleButtonGadgetSetState(toption5, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, TRUE, TRUE); break; case (0): // Open Circle default: XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); XmToggleButtonGadgetSetState(open_filled_toggle, FALSE, TRUE); break; } switch (p_station->aprs_symbol.area_object.color) { case (1): // Blue Bright XmToggleButtonGadgetSetState(coption2, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (2): // Green Bright XmToggleButtonGadgetSetState(coption3, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (3): // Cyan Bright XmToggleButtonGadgetSetState(coption4, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (4): // Red Bright XmToggleButtonGadgetSetState(coption5, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (5): // Violet Bright XmToggleButtonGadgetSetState(coption6, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (6): // Yellow Bright XmToggleButtonGadgetSetState(coption7, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (7): // Gray Bright XmToggleButtonGadgetSetState(coption8, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; case (8): // Black Dim XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (9): // Blue Dim XmToggleButtonGadgetSetState(coption2, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (10): // Green Dim XmToggleButtonGadgetSetState(coption3, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (11): // Cyan Dim XmToggleButtonGadgetSetState(coption4, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (12): // Red Dim XmToggleButtonGadgetSetState(coption5, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (13): // Violet Dim XmToggleButtonGadgetSetState(coption6, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (14): // Yellow Dim XmToggleButtonGadgetSetState(coption7, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (15): // Gray Dim XmToggleButtonGadgetSetState(coption8, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); break; case (0): // Black Bright default: XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); XmToggleButtonGadgetSetState(bright_dim_toggle, TRUE, TRUE); break; } xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.sqrt_lat_off * p_station->aprs_symbol.area_object.sqrt_lat_off ); XmTextFieldSetString( ob_lat_offset_data, temp_data ); xastir_snprintf(temp_data, sizeof(temp_data), "%d", p_station->aprs_symbol.area_object.sqrt_lon_off * p_station->aprs_symbol.area_object.sqrt_lon_off ); XmTextFieldSetString( ob_lon_offset_data, temp_data ); } // Done with filling in Area Objects else // Signpost/Probability/Normal Object { // Handle Generic Options (common to Signpost/Normal Objects) if (strlen(p_station->speed) != 0) { xastir_snprintf(temp_data, sizeof(temp_data), "%d", (int)(atof(p_station->speed) + 0.5) ); XmTextFieldSetString( ob_speed_data, temp_data ); } else { XmTextFieldSetString( ob_speed_data, "" ); } if (strlen(p_station->course) != 0) { XmTextFieldSetString( ob_course_data, p_station->course); } else { XmTextFieldSetString( ob_course_data, "" ); } // if ( (p_station->aprs_symbol.aprs_symbol == 'm') // Found a signpost object // && (p_station->aprs_symbol.aprs_type == '\\') // && Signpost_object_enabled) { if (Signpost_object_enabled) { XtSetSensitive(ob_frame,FALSE); XtSetSensitive(signpost_frame,TRUE); XmTextFieldSetString( signpost_data, p_station->signpost); } // Done with filling in Signpost Objects if (Probability_circles_enabled) { // Fetch the min/max fields from the object data and // write that data into the input fields. XmTextFieldSetString( probability_data_min, p_station->probability_min ); XmTextFieldSetString( probability_data_max, p_station->probability_max ); } // else if ( (p_station->aprs_symbol.aprs_type == '/') // Found a DF object // && (p_station->aprs_symbol.aprs_symbol == '\\' )) { if (DF_object_enabled) { XtSetSensitive(ob_frame,FALSE); //fprintf(stderr,"Found a DF object\n"); // Decide if it was an omni-DF object or a beam heading object if (p_station->NRQ[0] == '\0') // Must be an omni-DF object { //fprintf(stderr,"omni-DF\n"); //fprintf(stderr,"Signal_gain: %s\n", p_station->signal_gain); XmToggleButtonSetState(omni_antenna_toggle, TRUE, TRUE); // Set the received signal quality toggle switch (p_station->signal_gain[3]) { case ('1'): // 1 XmToggleButtonGadgetSetState(soption1, TRUE, TRUE); break; case ('2'): // 2 XmToggleButtonGadgetSetState(soption2, TRUE, TRUE); break; case ('3'): // 3 XmToggleButtonGadgetSetState(soption3, TRUE, TRUE); break; case ('4'): // 4 XmToggleButtonGadgetSetState(soption4, TRUE, TRUE); break; case ('5'): // 5 XmToggleButtonGadgetSetState(soption5, TRUE, TRUE); break; case ('6'): // 6 XmToggleButtonGadgetSetState(soption6, TRUE, TRUE); break; case ('7'): // 7 XmToggleButtonGadgetSetState(soption7, TRUE, TRUE); break; case ('8'): // 8 XmToggleButtonGadgetSetState(soption8, TRUE, TRUE); break; case ('9'): // 9 XmToggleButtonGadgetSetState(soption9, TRUE, TRUE); break; case ('0'): // 0 default: XmToggleButtonGadgetSetState(soption0, TRUE, TRUE); break; } // Set the HAAT toggle switch (p_station->signal_gain[4]) { case ('1'): // 20ft XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); break; case ('2'): // 40ft XmToggleButtonGadgetSetState(hoption2, TRUE, TRUE); break; case ('3'): // 80ft XmToggleButtonGadgetSetState(hoption3, TRUE, TRUE); break; case ('4'): // 160ft XmToggleButtonGadgetSetState(hoption4, TRUE, TRUE); break; case ('5'): // 320ft XmToggleButtonGadgetSetState(hoption5, TRUE, TRUE); break; case ('6'): // 640ft XmToggleButtonGadgetSetState(hoption6, TRUE, TRUE); break; case ('7'): // 1280ft XmToggleButtonGadgetSetState(hoption7, TRUE, TRUE); break; case ('8'): // 2560ft XmToggleButtonGadgetSetState(hoption8, TRUE, TRUE); break; case ('9'): // 5120ft XmToggleButtonGadgetSetState(hoption9, TRUE, TRUE); break; case ('0'): // 10ft default: XmToggleButtonGadgetSetState(hoption0, TRUE, TRUE); break; } // Set the antenna gain toggle switch (p_station->signal_gain[5]) { case ('1'): // 1dB XmToggleButtonGadgetSetState(goption1, TRUE, TRUE); break; case ('2'): // 2dB XmToggleButtonGadgetSetState(goption2, TRUE, TRUE); break; case ('3'): // 3dB XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); break; case ('4'): // 4dB XmToggleButtonGadgetSetState(goption4, TRUE, TRUE); break; case ('5'): // 5dB XmToggleButtonGadgetSetState(goption5, TRUE, TRUE); break; case ('6'): // 6dB XmToggleButtonGadgetSetState(goption6, TRUE, TRUE); break; case ('7'): // 7dB XmToggleButtonGadgetSetState(goption7, TRUE, TRUE); break; case ('8'): // 8dB XmToggleButtonGadgetSetState(goption8, TRUE, TRUE); break; case ('9'): // 9dB XmToggleButtonGadgetSetState(goption9, TRUE, TRUE); break; case ('0'): // 0dB default: XmToggleButtonGadgetSetState(goption0, TRUE, TRUE); break; } // Set the antenna directivity toggle switch (p_station->signal_gain[6]) { case ('1'): // 45 XmToggleButtonGadgetSetState(doption1, TRUE, TRUE); break; case ('2'): // 90 XmToggleButtonGadgetSetState(doption2, TRUE, TRUE); break; case ('3'): // 135 XmToggleButtonGadgetSetState(doption3, TRUE, TRUE); break; case ('4'): // 180 XmToggleButtonGadgetSetState(doption4, TRUE, TRUE); break; case ('5'): // 225 XmToggleButtonGadgetSetState(doption5, TRUE, TRUE); break; case ('6'): // 270 XmToggleButtonGadgetSetState(doption6, TRUE, TRUE); break; case ('7'): // 315 XmToggleButtonGadgetSetState(doption7, TRUE, TRUE); break; case ('8'): // 360 XmToggleButtonGadgetSetState(doption8, TRUE, TRUE); break; case ('0'): // Omni default: XmToggleButtonGadgetSetState(doption0, TRUE, TRUE); break; } } else // Must be a beam-heading object { //fprintf(stderr,"beam-heading\n"); XmToggleButtonSetState(beam_antenna_toggle, TRUE, TRUE); XmTextFieldSetString(ob_bearing_data, p_station->bearing); switch (p_station->NRQ[2]) { case ('1'): // 240° XmToggleButtonGadgetSetState(woption1, TRUE, TRUE); break; case ('2'): // 120° XmToggleButtonGadgetSetState(woption2, TRUE, TRUE); break; case ('3'): // 64° XmToggleButtonGadgetSetState(woption3, TRUE, TRUE); break; case ('4'): // 32° XmToggleButtonGadgetSetState(woption4, TRUE, TRUE); break; case ('5'): // 16° XmToggleButtonGadgetSetState(woption5, TRUE, TRUE); break; case ('6'): // 8° XmToggleButtonGadgetSetState(woption6, TRUE, TRUE); break; case ('7'): // 4° XmToggleButtonGadgetSetState(woption7, TRUE, TRUE); break; case ('8'): // 2° XmToggleButtonGadgetSetState(woption8, TRUE, TRUE); break; case ('9'): // 1° XmToggleButtonGadgetSetState(woption9, TRUE, TRUE); break; case ('0'): // Useless default: XmToggleButtonGadgetSetState(woption0, TRUE, TRUE); break; } } } else // Found a normal object { // Nothing needed in this block currently } // Done with filling in Normal objects } // Done with filling in Signpost, DF, or Normal Objects // Handle Generic Options (common to all) // Convert altitude from meters to feet if (strlen(p_station->altitude) != 0) { xastir_snprintf(temp_data, sizeof(temp_data), "%d", (int)((atof(p_station->altitude) / 0.3048) + 0.5) ); XmTextFieldSetString( ob_altitude_data, temp_data ); } else { XmTextFieldSetString( ob_altitude_data, "" ); } } // Else we're creating a new object from scratch: p_station == NULL else { if (Area_object_enabled) { XmToggleButtonGadgetSetState(coption1, TRUE, TRUE); // Black XmToggleButtonGadgetSetState(bright_dim_toggle, FALSE, TRUE); // Dim XmToggleButtonGadgetSetState(toption1, TRUE, TRUE); // Circle } XmTextFieldSetString(object_name_data,""); // Set the symbol type based on the global variables if (Area_object_enabled) { temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'l'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); } else if (Signpost_object_enabled) { temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'm'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XmTextFieldSetString( signpost_data, "" ); XtSetSensitive(ob_frame,FALSE); } else if (Probability_circles_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '['; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XmTextFieldSetString( probability_data_min, "" ); XmTextFieldSetString( probability_data_max, "" ); } else if (DF_object_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '\\'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); // Defaults Omni-DF XmToggleButtonGadgetSetState(soption0, TRUE, TRUE); // Nothing heard XmToggleButtonGadgetSetState(hoption1, TRUE, TRUE); // 20 feet HAAT XmToggleButtonGadgetSetState(goption3, TRUE, TRUE); // 3dB gain antenna XmToggleButtonGadgetSetState(doption0, TRUE, TRUE); // No directivity // Defaults Beam-DF XmToggleButtonGadgetSetState(woption5, TRUE, TRUE); // 16 degree beamwidth XtSetSensitive(ob_frame,FALSE); } else if (Map_View_object_enabled) { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = 'E'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); XtSetSensitive(ob_frame,FALSE); XtSetSensitive(ob_option_frame,FALSE); } else // Normal object/item { temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_group_data,temp_data); temp_data[0] = '/'; temp_data[1] = '\0'; XmTextFieldSetString(object_symbol_data,temp_data); } // Compute the range for the Map View object and store // it in the comment field. if (Map_View_object_enabled) { double top_range, left_range, max_range; char range[10]; Dimension width, height; // Get the display parameters XtVaGetValues(da,XmNwidth, &width,XmNheight, &height, NULL); // Find distance from center to top of screen. // top_range = distance from center_longitude, // center_latitude to center_longitude, // center_latitude-((height*scale_y)/2). top_range = calc_distance(center_latitude, center_longitude, NW_corner_latitude, center_longitude); //fprintf(stderr," top_range:%1.0f meters\n", top_range); // Find distance from center to left of screen. // left_range = distance from center_longitude, // center_latitude to // center_longitude-((width*scale_x)/2), // center_latitude. left_range = calc_distance(center_latitude, center_longitude, center_latitude, NW_corner_longitude); //fprintf(stderr,"left_range:%1.0f meters\n", left_range); // Compute greater of the two. This is our range in // meters. if (top_range > left_range) { max_range = top_range; } else { max_range = left_range; } // Convert from meters to miles max_range = max_range / 1000.0; // kilometers max_range = max_range * 0.62137; // miles // Restrict it to four digits. if (max_range > 9999.0) { max_range = 9999.0; } //fprintf(stderr,"Range:%04d miles\n", (int)(max_range + 0.5)); xastir_snprintf(range, sizeof(range), "RNG%04d", (int)(max_range + 0.5)); // Poor man's rounding XmTextFieldSetString(object_comment_data, range); } else { XmTextFieldSetString(object_comment_data,""); } } if (strcmp(calldata,"2") != 0) // Normal Modify->Object or Create->Object behavior { // Fill in original lat/lon values convert_lat_l2s(lat, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); substr(temp_data,lat_str,2); XmTextFieldSetString(object_lat_data_deg,temp_data); substr(temp_data,lat_str+2,6); XmTextFieldSetString(object_lat_data_min,temp_data); substr(temp_data,lat_str+8,1); XmTextFieldSetString(object_lat_data_ns,temp_data); convert_lon_l2s(lon, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); substr(temp_data,lon_str,3); XmTextFieldSetString(object_lon_data_deg,temp_data); substr(temp_data,lon_str+3,6); XmTextFieldSetString(object_lon_data_min,temp_data); substr(temp_data,lon_str+9,1); XmTextFieldSetString(object_lon_data_ew,temp_data); } else // We're in the middle of moving an object, calldata was "2" { // Fill in new lat/long values //fprintf(stderr,"Here we will fill in the new lat/long values\n"); x = (center_longitude - ((screen_width * scale_x)/2) + (input_x * scale_x)); y = (center_latitude - ((screen_height * scale_y)/2) + (input_y * scale_y)); if (x < 0) { x = 0l; // 180°W } if (x > 129600000l) { x = 129600000l; // 180°E } if (y < 0) { y = 0l; // 90°N } if (y > 64800000l) { y = 64800000l; // 90°S } convert_lat_l2s(y, lat_str, sizeof(lat_str), CONVERT_HP_NOSP); substr(temp_data,lat_str,2); XmTextFieldSetString(object_lat_data_deg,temp_data); substr(temp_data,lat_str+2,6); XmTextFieldSetString(object_lat_data_min,temp_data); substr(temp_data,lat_str+8,1); XmTextFieldSetString(object_lat_data_ns,temp_data); convert_lon_l2s(x, lon_str, sizeof(lon_str), CONVERT_HP_NOSP); substr(temp_data,lon_str,3); XmTextFieldSetString(object_lon_data_deg,temp_data); substr(temp_data,lon_str+3,6); XmTextFieldSetString(object_lon_data_min,temp_data); substr(temp_data,lon_str+9,1); XmTextFieldSetString(object_lon_data_ew,temp_data); } XtAddCallback(object_group_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog); XtAddCallback(object_symbol_data, XmNvalueChangedCallback, updateObjectPictureCallback, object_dialog); // update symbol picture (void)updateObjectPictureCallback((Widget)NULL,(XtPointer)NULL,(XtPointer)NULL); pos_dialog(object_dialog); delw = XmInternAtom(XtDisplay(object_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(object_dialog, delw, Object_destroy_shell, (XtPointer)object_dialog); if (Signpost_object_enabled) { XtManageChild(signpost_form); } else if (Probability_circles_enabled) { XtManageChild(probability_form); } else if (Area_object_enabled) { XtManageChild(shape_box); XtManageChild(color_box); XtManageChild(area_form); } else if (DF_object_enabled) { XtManageChild(signal_box); XtManageChild(height_box); XtManageChild(gain_box); XtManageChild(directivity_box); XtManageChild(width_box); XtManageChild(formomni); XtManageChild(formbeam); } XtManageChild(ob_latlon_form); XtManageChild(ob_option_form); XtManageChild(ob_form1); XtManageChild(ob_form); XtManageChild(ob_pane); resize_dialog(ob_form, object_dialog); XtPopup(object_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(object_dialog); XmProcessTraversal(ob_button_cancel, XmTRAVERSE_CURRENT); } // This will cause the move to happen quickly without any button presses. if (calldata != NULL) // If we're doing a "move" operation { if (strcmp(calldata,"2") == 0) { if ((p_station->flag & ST_ITEM) != 0) // Moving an Item { //fprintf(stderr,"Calling Item_change_data_set()\n"); Item_change_data_set(w,object_dialog,object_dialog); // Move it now! //fprintf(stderr,"Done with call\n"); } else // Moving an Object { //fprintf(stderr,"Calling Object_change_data_set()\n"); Object_change_data_set(w,object_dialog,object_dialog); // Move it now! //fprintf(stderr,"Done with call\n"); } } } } // End of Set_Del_Object /* * Change data for current object * If calldata = 2, we're doing a move object operation. Pass the * value on through to Set_Del_Object. */ void Modify_object( Widget w, XtPointer clientData, XtPointer calldata) { DataRow *p_station = clientData; //if (calldata != NULL) // fprintf(stderr,"Modify_object: calldata: %s\n", (char *)calldata); //fprintf(stderr,"Object Name: %s\n", p_station->call_sign); // Only move the object if it is our callsign, else force the // user to adopt the object first, then move it. // // Not exact match (this one is useful for testing) //// if (!is_my_call(p_station->origin,0)) { // if (!is_my_object_item(p_station)) { // // Exact match includes SSID (this one is for production code) // if (!is_my_call(p_station->origin,1)) { if (!is_my_object_item(p_station)) { // It's not from my callsign if (strncmp(calldata,"2",1) == 0) { // We're doing a Move Object operation //fprintf(stderr,"Modify_object: Object not owned by //me!\n"); popup_message_always(langcode("POPEM00035"), langcode("POPEM00042")); return; } } Set_Del_Object( w, p_station, calldata ); } // // Function to load saved objects and items back into Xastir. This // is called on startup. This implements persistent objects/items // across Xastir restarts. // // Note that the length of "line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // // This appears to skip the loading of killed objects/items. We may // instead want to begin transmitting them again until they time // out, then mark them with a '#' in the log file at that point. // void reload_object_item(void) { char file[MAX_VALUE]; FILE *f; char line[300+1]; char line2[350]; int save_state; get_user_base_dir("config/object.log", file, sizeof(file)); f=fopen(file,"r"); if (f!=NULL) { // Turn off duplicate point checking (need this in order to // work with SAR objects). Save state so that we don't mess // it up. save_state = skip_dupe_checking; skip_dupe_checking++; while (fgets(line, 300, f) != NULL) { if (debug_level & 1) { fprintf(stderr,"Loading object/item from file: %s",line); } if (line[0] != '#') // Skip comment lines { xastir_snprintf(line2, sizeof(line2), "%s>%s:%s", my_callsign, VERSIONFRM, line); // Decode this packet. This will put it into our // station database and cause it to be transmitted // at // regular intervals. Port is set to -1 here. decode_ax25_line( line2, DATA_VIA_LOCAL, -1, 1); // Right about here we could do a lookup for the object/item // matching the name and change the timing on it. This could serve // to spread the transmit timing out a bit so that all objects/items // are not transmitted together. Another easier option would be to // change the routine which chooses when to transmit, having it // randomize the numbers a bit each time. I chose the second // option. } } (void)fclose(f); // Restore the skip_dupe_checking state skip_dupe_checking = save_state; // Update the screen redraw_symbols(da); (void)XCopyArea(XtDisplay(da), pixmap_final, XtWindow(da), gc, 0, 0, screen_width, screen_height, 0, 0); } else { if (debug_level & 1) { fprintf(stderr,"Couldn't open file for reading: %s\n", file); } } // Start transmitting these objects in about 30 seconds. // Prevent transmission of objects until sometime after we're // done with our initial load. last_object_check = sec_now() + 30; } // // This function was extracted from the original implementation of // Setup_object_data. It reads all the values out of the Object/Item // create/modify dialog box and populates the buffers provided. // // Notes: // while most of these 'char *' arguments are intended to be char arrays // of appropriate size, obj_group and obj_symbols are pointers to a // 'char' variable, not an array. This is so they'll be passed by reference // and we can return values in them. // // Per the original implementation, we return both the low-precision and // high-precision lat/lon strings. The caller will decide which to use. // // Note that ALL char arrays passed in have their associated buffer size // passed in with them, so we can always make sure we don't overrun them. // // Function returns 1 if all values read // Function returns 0 if any value determined to be invalid. // int Read_object_item_dialog_values(char *name, size_t name_size, char *lat_str, size_t lat_str_size, char *ext_lat_str, size_t ext_lat_str_size, char *lon_str, size_t lon_str_size, char *ext_lon_str, size_t ext_lon_str_size, char *obj_group, char *obj_symbol, char *comment, size_t comment_size, char *course, size_t course_size, char *speed, size_t speed_size, char *altitude, size_t altitude_size, int *area_object, int *area_type, int *area_filled, char *area_color, size_t area_color_size, char *lat_offset_str, size_t lat_offset_str_size, char *lon_offset_str, size_t lon_offset_str_size, char *corridor, size_t corridor_size, int *signpost_object, char *signpost_str, size_t signpost_str_size, int *df_object, int *omni_df, int *beam_df, char *df_shgd, size_t df_shgd_size, char *bearing, size_t bearing_size, char *NRQ, size_t NRQ_size, int *prob_circles, char *prob_min, size_t prob_min_size, char *prob_max, size_t prob_max_size ) { char *tmp_ptr; // components of lat/lon char hemisphere; int degrees; double minutes; // Initialize all the things name[0] = lat_str[0] = ext_lat_str[0] = lon_str[0] = ext_lon_str[0] = '\0'; *obj_group = *obj_symbol = '\0'; comment[0] = course[0] = speed[0] = altitude[0] = '\0'; *area_object = *area_type = *area_filled = '\0'; area_color[0] = lat_offset_str[0] = lon_offset_str[0] = corridor[0] = '\0'; *signpost_object = 0; signpost_str[0] = '\0'; *df_object = *omni_df = *beam_df = 0; df_shgd[0] = bearing[0] = NRQ[0] = '\0'; *prob_circles = 0; prob_min[0] = prob_max[0] = '\0'; // ---------------------------------------------------------------- // All the generic data fields // name tmp_ptr = XmTextFieldGetString(object_name_data); xastir_snprintf(name,name_size,"%s",tmp_ptr); XtFree(tmp_ptr); (void) remove_trailing_spaces(name); // assemble latitude tmp_ptr = XmTextFieldGetString(object_lat_data_ns); if ((char)toupper((int)(tmp_ptr[0])) == 'S') hemisphere='S'; else hemisphere='N'; XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(object_lat_data_deg); degrees=atoi(tmp_ptr); XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(object_lat_data_min); minutes=atof(tmp_ptr); XtFree(tmp_ptr); // Check latitude validity if ((degrees > 90) || (degrees < 0)) return (0); if ((minutes >= 60.0) || (minutes < 0.0)) return (0); if ((degrees == 90) && (minutes != 0.0)) return (0); // Format both low and high precision versions. xastir_snprintf(lat_str,lat_str_size, "%02d%05.2f%c", degrees, minutes, hemisphere); xastir_snprintf(ext_lat_str,ext_lat_str_size, "%02d%06.3f%c", degrees, minutes, hemisphere); // assemble longitude tmp_ptr = XmTextFieldGetString(object_lon_data_ew); if ((char)toupper((int)(tmp_ptr[0])) == 'E') hemisphere='E'; else hemisphere='W'; XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(object_lon_data_deg); degrees=atoi(tmp_ptr); XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(object_lon_data_min); minutes=atof(tmp_ptr); XtFree(tmp_ptr); // Check longitude validity if ((degrees > 180) || (degrees < 0)) return (0); if ((minutes >= 60.0) || (minutes < 0.0)) return (0); if ((degrees == 180) && (minutes != 0.0)) return (0); // Format both low and high precision versions. xastir_snprintf(lon_str,lon_str_size, "%03d%05.2f%c", degrees, minutes, hemisphere); xastir_snprintf(ext_lon_str,ext_lon_str_size, "%03d%06.3f%c", degrees, minutes, hemisphere); // Get symbol // We don't bother processing the group other than to upcase it. // Handling of whether this is an overlay character or not is taken care // of by construct_object_item_data_row. tmp_ptr = XmTextFieldGetString(object_group_data); if (isalpha((int)tmp_ptr[0])) *obj_group = toupper((int)(tmp_ptr[0])); else *obj_group = tmp_ptr[0]; XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(object_symbol_data); *obj_symbol = tmp_ptr[0]; XtFree(tmp_ptr); // Get the comment tmp_ptr = XmTextFieldGetString(object_comment_data); if (tmp_ptr[0] == '}') { // this is a multiline comment, but thoseshould start with a space, // so add one xastir_snprintf(comment,comment_size," %s",tmp_ptr); } else { xastir_snprintf(comment,comment_size,"%s",tmp_ptr); } XtFree(tmp_ptr); (void)remove_trailing_spaces(comment); // course/speed tmp_ptr = XmTextFieldGetString(ob_course_data); if (strlen(tmp_ptr) != 0) { int tmp_int = atoi(tmp_ptr); tmp_int = (tmp_int==0)?360:tmp_int; if (tmp_int >=1 && tmp_int <= 360) { xastir_snprintf(course, course_size,"%03d",tmp_int); } } else { course[0]='\0'; } XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(ob_speed_data); if (strlen(tmp_ptr) != 0) { int tmp_int = atoi(tmp_ptr); if (tmp_int >=0 && tmp_int <= 999) { xastir_snprintf(speed, speed_size,"%3d",tmp_int); } } else { speed[0]='\0'; } XtFree(tmp_ptr); // Altitude tmp_ptr = XmTextFieldGetString(ob_altitude_data); if (strlen(tmp_ptr) != 0) { if (isdigit((int)tmp_ptr[0])) { long tmp_int=atoi(tmp_ptr); if (tmp_int >= 0 && tmp_int <= 999999) xastir_snprintf(altitude,altitude_size,"%06ld",tmp_int); } } XtFree(tmp_ptr); // ---------------------------------------------------------------- // Now handle fields that are only to be read under certain conditions: // ---------------------------------------------------------------- if (Area_object_enabled) { *area_object=1; // ---------------------------------------------------------------- // Area objects // The "Area_" variables are globals that are set by other callback // functions and represent values from radio and check buttons. // ---------------------------------------------------------------- format_area_color_from_dialog(area_color,area_color_size, Area_color, Area_bright); *area_type = Area_type; *area_filled = Area_filled; // don't take the square root here, the function that processes this input // will do that. tmp_ptr = XmTextFieldGetString(ob_lat_offset_data); if (strlen(tmp_ptr) != 0) { xastir_snprintf(lat_offset_str,lat_offset_str_size,"%s",tmp_ptr); } XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(ob_lon_offset_data); if (strlen(tmp_ptr) != 0) { xastir_snprintf(lon_offset_str,lon_offset_str_size,"%s",tmp_ptr); } XtFree(tmp_ptr); if (Area_type == 1 || Area_type == 6) { tmp_ptr = XmTextFieldGetString(ob_corridor_data); if (strlen(tmp_ptr) != 0) { int tmp_int = atoi(tmp_ptr); if (tmp_int >0 && tmp_int <= 999) { xastir_snprintf(corridor,corridor_size,"%d",tmp_int); } } XtFree(tmp_ptr); } } else if (Signpost_object_enabled) { *signpost_object = 1; tmp_ptr = XmTextFieldGetString(signpost_data); if (strlen(tmp_ptr) >= 0 && strlen(tmp_ptr) <= 3) { xastir_snprintf(signpost_str,signpost_str_size,"%s",tmp_ptr); } XtFree(tmp_ptr); } else if (DF_object_enabled) { // ---------------------------------------------------------------- // DF objects // ---------------------------------------------------------------- *df_object=1; if (Omni_antenna_enabled) { // The Omni_antenna_enabled variable is a global set by other callback // functions, and "object_shgd" is also set from callbacks using // values from the dialog box check- and radio-buttons. *omni_df=1; xastir_snprintf(df_shgd,df_shgd_size,"%s",object_shgd); } else // it's a beam-df { int tmp_int; // In this case, "object_NRQ" is a global being set by callbacks. *beam_df = 1; tmp_ptr = XmTextFieldGetString(ob_bearing_data); tmp_int = atoi(tmp_ptr); XtFree(tmp_ptr); if (tmp_int < 1 || tmp_int > 360) tmp_int = 360; xastir_snprintf(bearing,bearing_size,"%03d",tmp_int); xastir_snprintf(NRQ,NRQ_size,"%s",object_NRQ); } } else // just a normal object, but could have probability circles { if (Probability_circles_enabled) { *prob_circles = 1; tmp_ptr = XmTextFieldGetString(probability_data_min); if (strlen(tmp_ptr)!=0) { xastir_snprintf(prob_min,prob_min_size,"%s",tmp_ptr); } XtFree(tmp_ptr); tmp_ptr = XmTextFieldGetString(probability_data_max); if (strlen(tmp_ptr)!=0) { xastir_snprintf(prob_max,prob_max_size,"%s",tmp_ptr); } XtFree(tmp_ptr); } } return(1); } Xastir-Release-2.2.4/src/objects_gui.h0000664000175000017500000001035615151324131016563 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_OBJECTS_GUI_H #define XASTIR_OBJECTS_GUI_H #include #include extern Widget object_dialog; extern Widget object_group_data; extern Widget object_symbol_data; extern void updateObjectPictureCallback(Widget w,XtPointer clientData,XtPointer callData); extern int doing_move_operation; extern char last_object[9+1]; extern char last_obj_grp; extern char last_obj_sym; // -------------------------------------------------------------------- // // Function protypes and globals to support predefined SAR/Public service // objects. // // // MAX_NUMBER_OF_PREDEFINED_OBJECTS is the maximum number of predefined // objects that can appear on the Create/Move Here popup menu. #define MAX_NUMBER_OF_PREDEFINED_OBJECTS 11 // // PREDEFINED_OBJECT_DATA_LENGTH is the maximum length of a string // that can follow the symbol specifier in a predefined object (such // as a probability circle definition) plus one (for the terminator). #define PREDEFINED_OBJECT_DATA_LENGTH 44 // // number_of_predefined_objects holds the actual number of predefined // objects available to display on the Create/Move popup menu. extern int number_of_predefined_objects; // File name of ~/.xastir/config file containing definitions for // a predefined object menu. extern char predefined_object_definition_filename[256]; // Flag to indicate whether or not to load the predefined objects menu // from the file specified by predefined_object_definition_filename or // to use the hardcoded SAR object set. 0=use hardcoded SAR // 1=use predefined_object_definition_filename extern int predefined_menu_from_file; extern void Set_Del_Object(Widget w, XtPointer clientData, XtPointer calldata); extern void Create_SAR_Object(Widget w, XtPointer clientData, XtPointer calldata); typedef struct { char call[MAX_CALLSIGN+1]; // Callsign = object name. char page[2]; // APRS symbol code page. char symbol[2]; // APRS symbol specifier. char data[PREDEFINED_OBJECT_DATA_LENGTH]; // Data following the symbol. char menu_call[26]; // Name to display on menu. intptr_t index; // Index of this object // in the predefinedObjects array. int show_on_menu; // !=1 to hide on menu. int index_of_child; // > -1 to create two objects // in the same place at the // same time, value is the // index of the second object // in the predefinedObjects array. } predefinedObject; // predefinedObjects is an array of predefined object definitions, // once filled using Populate_predefined_objects it can be traversed // to build a list of predefined objects for menus, picklists, or // other user interface controls. // extern predefinedObject predefinedObjects[MAX_NUMBER_OF_PREDEFINED_OBJECTS]; extern void Populate_predefined_objects(predefinedObject *predefinedObjects); extern void Object_History_Refresh( Widget w, XtPointer clientData, XtPointer callData); extern void Object_History_Clear( Widget w, XtPointer clientData, XtPointer callData); extern void Move_Object( Widget widget, XtPointer clientData, XtPointer callData); extern void Modify_object( Widget w, XtPointer clientData, XtPointer calldata); extern void disown_object_item(char *call_sign, char *new_owner); extern void log_object_item(char *line, int disable_object, char *object_name); extern void reload_object_item(void); #endif Xastir-Release-2.2.4/src/popup.h0000664000175000017500000000265115151324131015430 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_POPUP_H #define XASTIR_POPUP_H #define MAX_POPUPS 30 #define MAX_POPUPS_TIME 600 /* Max time popups will display 600=10min*/ typedef struct { char name[10]; Widget popup_message_dialog; Widget popup_message_data; Widget pane, scrollwindow, form, button_close; time_t sec_opened; } Popup_Window; /* from popup_gui.c */ extern void popup_gui_init(void); extern void clear_popup_message_windows(void); extern void popup_time_out_check(int curr_sec); #endif /* XASTIR_POPUP_H */ Xastir-Release-2.2.4/src/popup_gui.c0000664000175000017500000002725015151324131016271 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include "xastir.h" #include "main.h" #include "popup.h" #include "main.h" #include "lang.h" #include "rotated.h" #include "mutex_utils.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist static Popup_Window pw[MAX_POPUPS]; static Popup_Window pwb; static xastir_mutex popup_message_dialog_lock; void popup_gui_init(void) { init_critical_section( &popup_message_dialog_lock ); } /**** Popup Message ******/ void clear_popup_message_windows(void) { int i; begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:clear_popup_message_windows" ); for (i=0; iMAX_POPUPS_TIME) { XtPopdown(pw[i].popup_message_dialog); begin_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" ); XtDestroyWidget(pw[i].popup_message_dialog); pw[i].popup_message_dialog = (Widget)NULL; pw[i].popup_message_data = (Widget)NULL; end_critical_section(&popup_message_dialog_lock, "popup_gui.c:popup_time_out_check" ); } } } } } void popup_message_always(char *banner, char *message) { XmString msg_str; int j,i; Atom delw; if (disable_all_popups) { return; } if (banner == NULL || message == NULL) { return; } i=0; for (j=0; j -270.0) ) || ( (my_rotation > 90.0) && (my_rotation < 270.0) ) ) { my_rotation = my_rotation + 180.0; (void)XRotDrawAlignedString(XtDisplay(da), id_font, my_rotation, pixmap_alerts, gc, x, y, message, BRIGHT); } else { (void)XRotDrawAlignedString(XtDisplay(da), id_font, my_rotation, pixmap_alerts, gc, x, y, message, BLEFT); } // Schedule a screen update in roughly 3 seconds remove_ID_message_time = sec_now() + 3; pending_ID_message = 1; // Write it to the screen. Symbols/tracks will disappear during // this short interval time. (void)XCopyArea(XtDisplay(da), pixmap_alerts, XtWindow(da), gc, 0, 0, (unsigned int)screen_width, (unsigned int)screen_height, 0, 0); } else // ATV Screen ID is not enabled { pending_ID_message = 0; } } Xastir-Release-2.2.4/src/rac_data.c0000664000175000017500000003067015151324131016020 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ //==================================================================== // Canadian Callsign Lookup // Richard Hagemeyer, VE3UNW // GNU COPYLEFT applies // 1999-11-08 // // For use with XASTIR by Frank Giannandrea //******************************************************************** #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include "xastir.h" #include "rac_data.h" #include "xa_config.h" #include "main.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" /* ==================================================================== */ /* my version of chomp from perl, removes spaces and dashes */ /* */ /* ******************************************************************** */ int chomp(char *input, unsigned int i) { unsigned int x; for (x=i; input[x] == ' ' || input[x] == '-'; x--) { input[x] = '\0'; } return ( (int)(i-x) ); } /* ==================================================================== */ /* build a new (or newer if I check the file date) index file */ /* check for current ic index file */ /* FG: added a date check in case the RAC file has been updated. */ /* AMACALL.LST must have a time stamp newer than the index file */ /* time stamp. Use the touch command on the AMACALL.LST file to */ /* make the time current if necessary. */ /* ******************************************************************** */ int build_rac_index(void) { FILE *fdb; FILE *fndx; unsigned long call_offset = 0; unsigned long x = 0; char racdata[RAC_DATA_LEN+8]; char amacall_path[MAX_VALUE]; get_user_base_dir("data/AMACALL.ndx", amacall_path, sizeof(amacall_path)); /* ==================================================================== */ /* If the index file is there, exit */ /* */ if (filethere(amacall_path)) { /* if file is there make sure the index date is newer */ if(file_time(amacall_path)<=file_time(amacall_path)) { return(1); } else { // RAC index old, rebuilding statusline(langcode("STIFCC0103"), 1); fprintf(stderr,"RAC index is old. Rebuilding index.\n"); // XmTextFieldSetString(text,"RAC Index old rebuilding"); // XtManageChild(text); // XmUpdateDisplay(XtParent(text)); } } /* ==================================================================== */ /* Open the database and index file */ /* */ fdb=fopen(get_data_base_dir("fcc/AMACALL.LST"),"rb"); if (fdb==NULL) { fprintf(stderr,"Build:Could not open RAC data base: %s\n", get_data_base_dir("fcc/AMACALL.LST") ); return(0); } fndx=fopen(amacall_path,"w"); if (fndx==NULL) { fprintf(stderr,"Build:Could not open/create RAC data base index: %s\n", amacall_path ); (void)fclose(fdb); return(0); } /* ==================================================================== */ /* Skip past the header to the first callsign (VA2AA) */ /* */ memset(racdata, 0, sizeof(racdata)); while (!feof(fdb) && strncmp(racdata,"VA",2)) { call_offset = (unsigned long)ftell(fdb); if (fgets(racdata, (int)sizeof(racdata), fdb)==NULL) { fprintf(stderr,"Build:header:Unable to read data base\n"); (void)fclose(fdb); (void)fclose(fndx); fprintf(stderr,"rc=0\n"); return (0); } } /* ==================================================================== */ /* write out the current callsign and RBA of the db file */ /* skip 100 records and do it again until no more */ /* */ while (!feof(fdb)) { fprintf(fndx,"%6.6s%li\n",racdata,(long)call_offset); call_offset = (unsigned long)ftell(fdb); for (x=0; x<=100 && !feof(fdb); x++) if (fgets(racdata, (int)sizeof(racdata), fdb)==NULL) { break; } } (void)fclose(fdb); (void)fclose(fndx); // XmTextFieldSetString(text,""); // XtManageChild(text); return(1); } /* ==================================================================== */ /* Check for ic data base file */ /* Check/build the index */ /* */ /* ******************************************************************** */ int check_rac_data(void) { int rac_data_available = 0; if( filethere( get_data_base_dir("fcc/AMACALL.LST") ) ) { if (build_rac_index()) { rac_data_available=1; } else { fprintf(stderr,"Check:Could not build ic data base index\n"); rac_data_available=0; } } return(rac_data_available); } /* ==================================================================== */ /* The real work. Pass the callsign, get the info */ /* */ /* ******************************************************************** */ int search_rac_data(char *callsign, rac_record *data) { FILE *fdb; FILE *fndx; long call_offset = 0l; char char_offset[16]; char index[32]; int found = 0; rac_record racdata; /*char filler[8];*/ char amacall_path[MAX_VALUE]; get_user_base_dir("data/AMACALL.ndx", amacall_path, sizeof(amacall_path)); xastir_snprintf(index, sizeof(index)," "); xastir_snprintf(racdata.callsign, sizeof(racdata.callsign)," "); /* ==================================================================== */ /* Search thru the index, get the RBA */ /* */ fndx = fopen(amacall_path, "r"); if(fndx != NULL) { if (fgets(index, (int)sizeof(index), fndx) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base index: %s\n", amacall_path ); return (0); } memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string while (!feof(fndx) && strncmp(callsign, index, 6) > 0) { memcpy(char_offset, &index[6], sizeof(char_offset)); char_offset[sizeof(char_offset)-1] = '\0'; // Terminate string if (fgets(index, (int)sizeof(index), fndx) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base index(2): %s\n", amacall_path ); return (0); } } } else { fprintf(stderr, "Search:Could not open RAC data base index: %s\n", amacall_path ); return (0); } call_offset = atol(char_offset); (void)fclose(fndx); /* ==================================================================== */ /* Now we have our pointer into the main database (text) file. */ /* Start from there and linear search the data. */ /* This will take an avg of 1/2 of the # skipped making the index */ /* */ fdb = fopen(get_data_base_dir("fcc/AMACALL.LST"), "r"); if (fdb != NULL) { (void)fseek(fdb, call_offset, SEEK_SET); if (callsign[5] == '-') { (void)chomp(callsign,5); } while (!feof(fdb) && strncmp((char *)&racdata, callsign, 6) < 0) //WE7U // Problem here: We're sticking 8 bytes too many into racdata! if (fgets((char *)&racdata, sizeof(racdata), fdb) == NULL) { // Error occurred fprintf(stderr, "Search:Could not read RAC data base: %s\n", amacall_path ); return (0); } } else { fprintf(stderr,"Search:Could not open RAC data base: %s\n", get_data_base_dir("fcc/AMACALL.LST") ); } /* || (callsign[5] == '-' && strncmp((char *)&racdata,callsign,5) < 0)) */ (void)chomp(racdata.callsign, 6); if (!strncmp((char *)racdata.callsign, callsign, 6)) { found = 1; // Some of these cause problems on 64-bit processors, so commented // them out for now. // (void)chomp(racdata.first_name, 35); // (void)chomp(racdata.last_name, 35); // (void)chomp(racdata.address, 70); // (void)chomp(racdata.city, 35); // (void)chomp(racdata.province, 2); // (void)chomp(racdata.postal_code, 10); // (void)chomp(racdata.qual_a, 1); // (void)chomp(racdata.qual_b, 1); // (void)chomp(racdata.qual_c, 1); // (void)chomp(racdata.qual_d, 1); // (void)chomp(racdata.club_name, 141); // (void)chomp(racdata.club_address, 70); // (void)chomp(racdata.club_city, 35); // (void)chomp(racdata.club_province, 2); // (void)chomp(racdata.club_postal_code, 9); xastir_snprintf(data->callsign, sizeof(data->callsign), "%s", racdata.callsign); xastir_snprintf(data->first_name, sizeof(data->first_name), "%s", racdata.first_name); xastir_snprintf(data->last_name, sizeof(data->last_name), "%s", racdata.last_name); xastir_snprintf(data->address, sizeof(data->address), "%s", racdata.address); xastir_snprintf(data->city, sizeof(data->city), "%s", racdata.city); xastir_snprintf(data->province, sizeof(data->province), "%s", racdata.province); xastir_snprintf(data->postal_code, sizeof(data->postal_code), "%s", racdata.postal_code); xastir_snprintf(data->qual_a, sizeof(data->qual_a), "%s", racdata.qual_a); xastir_snprintf(data->qual_b, sizeof(data->qual_b), "%s", racdata.qual_b); xastir_snprintf(data->qual_c, sizeof(data->qual_c), "%s", racdata.qual_c); xastir_snprintf(data->qual_d, sizeof(data->qual_d), "%s", racdata.qual_d); xastir_snprintf(data->club_name, sizeof(data->club_name), "%s", racdata.club_name); xastir_snprintf(data->club_address, sizeof(data->club_address), "%s", racdata.club_address); xastir_snprintf(data->club_city, sizeof(data->club_city), "%s", racdata.club_city); xastir_snprintf(data->club_province, sizeof(data->club_province), "%s", racdata.club_province); xastir_snprintf(data->club_postal_code, sizeof(data->club_postal_code), "%s", racdata.club_postal_code); } (void)fclose(fdb); if (!found) { // "Callsign Search", "Callsign Not Found!" popup_message_always(langcode("STIFCC0101"), langcode("STIFCC0102") ); } return(found); } Xastir-Release-2.2.4/src/rac_data.h0000664000175000017500000000340415151324131016020 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Industry Canada/RAC Database structure * 472 bytes -- filler is club info * qual fields represent basic, 5wpm, 12wpm, advanced */ #ifndef __XASTIR_RAC_DATA_H #define __XASTIR_RAC_DATA_H #define RAC_DATA_LEN 472 typedef struct { char callsign[7]; char first_name[36]; char last_name[36]; char address[71]; char city[36]; char province[3]; char postal_code[11]; char qual_a[2]; char qual_b[2]; char qual_c[2]; char qual_d[2]; char club_name[142]; char club_address[71]; char club_city[36]; char club_province[3]; char club_postal_code[10]; char crlf[2]; char filler[8]; // To prevent overruns } rac_record; extern int search_rac_data(char *callsign, rac_record *data); extern int search_rac_data_appl(char *callsign, rac_record *data); extern int check_rac_data(void); #endif /* __XASTIR_RAC_DATA_H */ Xastir-Release-2.2.4/src/rotated.c0000664000175000017500000013325315151324131015725 0ustar hibbyhibby // // Portions Copyright (C) 2000-2026 The Xastir Group // // Note that this version has been changed since xvertext 5.0 in order // to get rid of compiler warnings and such. The original 5.0 notice // is below. --we7u /* ********************************************************************** */ /* xvertext 5.0, Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both the * copyright notice and this permission notice appear in supporting * documentation. All work developed as a consequence of the use of * this program should duly acknowledge such use. No representations are * made about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. */ /* ********************************************************************** */ /* BETTER: xvertext now does rotation at any angle!! * * BEWARE: function arguments have CHANGED since version 2.0!! */ /* ********************************************************************** */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "rotated.h" #include "snprintf.h" #include "xastir.h" // Must be last include file #include "leak_detection.h" /* ---------------------------------------------------------------------- */ /* Make sure cache size is set */ #ifndef CACHE_SIZE_LIMIT #define CACHE_SIZE_LIMIT 0 #endif /*CACHE_SIZE_LIMIT */ /* Make sure a cache method is specified */ #ifndef CACHE_XIMAGES #ifndef CACHE_BITMAPS #define CACHE_BITMAPS #endif /*CACHE_BITMAPS*/ #endif /*CACHE_XIMAGES*/ /* ---------------------------------------------------------------------- */ /* Debugging macros */ #ifdef DEBUG static int debug=1; #else // DEBUG static int debug=0; #endif /*DEBUG*/ #define DEBUG_PRINT1(a) if (debug) fprintf(stderr, a) #define DEBUG_PRINT2(a, b) if (debug) fprintf(stderr, a, b) #define DEBUG_PRINT3(a, b, c) if (debug) fprintf(stderr, a, b, c) #define DEBUG_PRINT4(a, b, c, d) if (debug) fprintf(stderr, a, b, c, d) #define DEBUG_PRINT5(a, b, c, d, e) if (debug) fprintf(stderr, a, b, c, d, e) /* ---------------------------------------------------------------------- */ #ifndef M_PI #define M_PI 3.14159265358979323846 #endif // M_PI // constants used to check for approximate equality with 90, 180, and 270 degrees // (int)((M_PI/2)*1000) #define INT_M_PI_2_1000 1570 // (int)(M_PI*1000) #define INT_M_PI_1000 3141 // (int)((3*M_PI/2)*1000) #define INT_3_M_PI_2_1000 4712 /* ---------------------------------------------------------------------- */ /* A structure holding everything needed for a rotated string */ typedef struct rotated_text_item_template { Pixmap bitmap; XImage *ximage; char *text; char *font_name; Font fid; float angle; int align; float magnify; int cols_in; int rows_in; int cols_out; int rows_out; int nl; int max_width; float *corners_x; float *corners_y; long int size; int cached; struct rotated_text_item_template *next; } RotatedTextItem; RotatedTextItem *first_text_item=NULL; /* ---------------------------------------------------------------------- */ /* A structure holding current magnification and bounding box padding */ static struct style_template { float magnify; int bbx_pad; } style= { 1., 0 }; /* ---------------------------------------------------------------------- */ static char *my_strdup(char *); static char *my_strtok(char *, char *); static XImage *MakeXImage(Display *, int, int); static int XRotPaintAlignedString(Display *,XFontStruct *,float, Drawable, GC, int, int, char*, int, int); static int XRotDrawHorizontalString(Display *, XFontStruct *, Drawable, GC, int, int, char*, int, int); static RotatedTextItem *XRotRetrieveFromCache(Display *, XFontStruct *, float, char *, int); static RotatedTextItem *XRotCreateTextItem(Display *, XFontStruct *, float, char *, int); static void XRotAddToLinkedList(Display *, RotatedTextItem *); static void XRotFreeTextItem(Display *, RotatedTextItem *); static XImage *XRotMagnifyImage(Display *, XImage *); /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Routine to mimic `strdup()' (some machines don't have it) */ /**************************************************************************/ // // This function allocates some memory without freeing it. // static char *my_strdup(char *str) { char *s; if(str==NULL) { return NULL; } s=(char *)malloc((unsigned)(strlen(str)+1)); if(s!=NULL) { xastir_snprintf(s, strlen(str)+1, "%s", str); } else { fprintf(stderr,"Couldn't allocate memory in my_strdup()\n"); } return s; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Routine to replace `strtok' : this one returns a zero length string if */ /* it encounters two consecutive delimiters */ /**************************************************************************/ static char *my_strtok(char *str1, char *str2) { char *ret; int i, j, stop; static int start, len; static char *stext; if(str2==NULL) { return NULL; } /* initialise if str1 not NULL */ if(str1!=NULL) { start=0; stext=str1; len=strlen(str1); } /* run out of tokens ? */ if(start>=len) { return NULL; } /* loop through characters */ for(i=start; i0.) { style.magnify=m; } } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Set the padding used when calculating bounding boxes */ /**************************************************************************/ void XRotSetBoundingBoxPad(int p) { if(p>=0) { style.bbx_pad=p; } } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Create an XImage structure and allocate memory for it */ /**************************************************************************/ // // Function does not free the memory. // static XImage *MakeXImage(Display *dpy, int w, int h) { XImage *I; char *data; /* reserve memory for image */ data=(char *)calloc((unsigned)(((w-1)/8+1)*h), 1); if(data==NULL) { fprintf(stderr,"Couldn't allocate memory in MakeXImage()\n"); return NULL; } /* create the XImage */ I=XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 1, XYBitmap, 0, data, w, h, 8, 0); if(I==NULL) { return NULL; } I->byte_order=I->bitmap_bit_order=MSBFirst; return I; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -no alignment, no background */ /**************************************************************************/ int XRotDrawString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str) { return (XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, str, NONE, 0)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -no alignment, paints background */ /**************************************************************************/ int XRotDrawImageString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *str) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, str, NONE, 1)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -does alignment, no background */ /**************************************************************************/ int XRotDrawAlignedString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text, align, 0)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* A front end to XRotPaintAlignedString: */ /* -does alignment, paints background */ /**************************************************************************/ int XRotDrawAlignedImageString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align) { return(XRotPaintAlignedString(dpy, font, angle, drawable, gc, x, y, text, align, 1)); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Aligns and paints a rotated string */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static int XRotPaintAlignedString( Display *dpy, XFontStruct *font, float angle, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg) { int i; GC my_gc; int xp, yp; float hot_x, hot_y; float hot_xp, hot_yp; float sin_angle, cos_angle; RotatedTextItem *item; Pixmap bitmap_to_paint; /* return early for NULL/empty strings */ if(text==NULL) { return 0; } if(strlen(text)==0) { return 0; } /* manipulate angle to 0<=angle<360 degrees */ while(angle<0) { angle+=360; } while(angle>=360) { angle-=360; } angle*=M_PI/180; /* horizontal text made easy */ if(angle==0. && style.magnify==1.) return(XRotDrawHorizontalString(dpy, font, drawable, gc, x, y, text, align, bg)); /* get a rotated bitmap */ item=XRotRetrieveFromCache(dpy, font, angle, text, align); if(item==NULL) { return(0); } /* this gc has similar properties to the user's gc */ my_gc=XCreateGC(dpy, drawable, 0, 0); XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCPlaneMask, my_gc); /* alignment : which point (hot_x, hot_y) relative to bitmap centre coincides with user's specified point? */ /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { hot_y=(float)item->rows_in/2*style.magnify; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { hot_y=0; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { hot_y=-(float)item->rows_in/2*style.magnify; } else { hot_y=-((float)item->rows_in/2-(float)font->descent)*style.magnify; } /* x position */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { hot_x=-(float)item->max_width/2*style.magnify; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { hot_x=0; } else { hot_x=(float)item->max_width/2*style.magnify; } /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* rotate hot_x and hot_y around bitmap centre */ hot_xp= hot_x*cos_angle - hot_y*sin_angle; hot_yp= hot_x*sin_angle + hot_y*cos_angle; /* text background will be drawn using XFillPolygon */ if(bg) { GC depth_one_gc; XPoint *xpoints; Pixmap empty_stipple; /* reserve space for XPoints, free'd later */ xpoints=(XPoint *)malloc((unsigned)(4*item->nl*sizeof(XPoint))); if(!xpoints) { fprintf(stderr,"Couldn't allocate memory in XRotPaintAlignedString()\n"); return 1; } /* rotate corner positions */ for(i=0; i<4*item->nl; i++) { xpoints[i].x=(float)x + ( (item->corners_x[i]-hot_x)*cos_angle + (item->corners_y[i]+hot_y)*sin_angle); xpoints[i].y=(float)y + (-(item->corners_x[i]-hot_x)*sin_angle + (item->corners_y[i]+hot_y)*cos_angle); } /* we want to swap foreground and background colors here; XGetGCValues() is only available in R4+ */ empty_stipple=XCreatePixmap(dpy, drawable, 1, 1, 1); depth_one_gc=XCreateGC(dpy, empty_stipple, 0, 0); XSetForeground(dpy, depth_one_gc, 0); XFillRectangle(dpy, empty_stipple, depth_one_gc, 0, 0, 2, 2); XSetStipple(dpy, my_gc, empty_stipple); XSetFillStyle(dpy, my_gc, FillOpaqueStippled); if (item->nl >= 1) { XFillPolygon(dpy, drawable, my_gc, xpoints, 4*item->nl, Nonconvex, CoordModeOrigin); } else { fprintf(stderr, "XRotPaintAlignedString: Points too few:%d, skipping XFillPolygon", item->nl); } /* free our resources */ free((char *)xpoints); XFreeGC(dpy, depth_one_gc); XFreePixmap(dpy, empty_stipple); } /* where should top left corner of bitmap go ? */ xp=(float)x-((float)item->cols_out/2 +hot_xp); yp=(float)y-((float)item->rows_out/2 -hot_yp); /* by default we draw the rotated bitmap, solid */ bitmap_to_paint=item->bitmap; /* handle user stippling */ #ifndef X11R3 { GC depth_one_gc; XGCValues values; Pixmap new_bitmap, inverse; /* try and get some GC properties */ if(XGetGCValues(dpy, gc, GCStipple|GCFillStyle|GCForeground|GCBackground| GCTileStipXOrigin|GCTileStipYOrigin, &values)) { /* only do this if stippling requested */ if((values.fill_style==FillStippled || values.fill_style==FillOpaqueStippled) && !bg) { /* opaque stipple: draw rotated text in background colour */ if(values.fill_style==FillOpaqueStippled) { XSetForeground(dpy, my_gc, values.background); XSetFillStyle(dpy, my_gc, FillStippled); XSetStipple(dpy, my_gc, item->bitmap); XSetTSOrigin(dpy, my_gc, xp, yp); XFillRectangle(dpy, drawable, my_gc, xp, yp, item->cols_out, item->rows_out); XSetForeground(dpy, my_gc, values.foreground); } /* this will merge the rotated text and the user's stipple */ new_bitmap=XCreatePixmap(dpy, drawable, item->cols_out, item->rows_out, 1); /* create a GC */ depth_one_gc=XCreateGC(dpy, new_bitmap, 0, 0); XSetForeground(dpy, depth_one_gc, 1); XSetBackground(dpy, depth_one_gc, 0); /* set the relative stipple origin */ XSetTSOrigin(dpy, depth_one_gc, values.ts_x_origin-xp, values.ts_y_origin-yp); /* fill the whole bitmap with the user's stipple */ XSetStipple(dpy, depth_one_gc, values.stipple); XSetFillStyle(dpy, depth_one_gc, FillOpaqueStippled); XFillRectangle(dpy, new_bitmap, depth_one_gc, 0, 0, item->cols_out, item->rows_out); /* set stipple origin back to normal */ XSetTSOrigin(dpy, depth_one_gc, 0, 0); /* this will contain an inverse copy of the rotated text */ inverse=XCreatePixmap(dpy, drawable, item->cols_out, item->rows_out, 1); /* invert text */ XSetFillStyle(dpy, depth_one_gc, FillSolid); XSetFunction(dpy, depth_one_gc, GXcopyInverted); XCopyArea(dpy, item->bitmap, inverse, depth_one_gc, 0, 0, item->cols_out, item->rows_out, 0, 0); /* now delete user's stipple everywhere EXCEPT on text */ XSetForeground(dpy, depth_one_gc, 0); XSetBackground(dpy, depth_one_gc, 1); XSetStipple(dpy, depth_one_gc, inverse); XSetFillStyle(dpy, depth_one_gc, FillStippled); XSetFunction(dpy, depth_one_gc, GXcopy); XFillRectangle(dpy, new_bitmap, depth_one_gc, 0, 0, item->cols_out, item->rows_out); /* free resources */ XFreePixmap(dpy, inverse); XFreeGC(dpy, depth_one_gc); /* this is the new bitmap */ bitmap_to_paint=new_bitmap; } } } #endif /*X11R3*/ /* paint text using stipple technique */ XSetFillStyle(dpy, my_gc, FillStippled); XSetStipple(dpy, my_gc, bitmap_to_paint); XSetTSOrigin(dpy, my_gc, xp, yp); XFillRectangle(dpy, drawable, my_gc, xp, yp, item->cols_out, item->rows_out); /* free our resources */ XFreeGC(dpy, my_gc); /* stippled bitmap no longer needed */ if(bitmap_to_paint!=item->bitmap) { XFreePixmap(dpy, bitmap_to_paint); } #ifdef CACHE_XIMAGES XFreePixmap(dpy, item->bitmap); #endif /*CACHE_XIMAGES*/ /* if item isn't cached, destroy it completely */ if(!item->cached) { XRotFreeTextItem(dpy,item); } /* we got to the end OK! */ return 0; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Draw a horizontal string in a quick fashion */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static int XRotDrawHorizontalString( Display *dpy, XFontStruct *font, Drawable drawable, GC gc, int x, int y, char *text, int align, int bg) { GC my_gc; int nl=1, i; int height; int xp, yp; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int dir, asc, desc; XCharStruct overall; DEBUG_PRINT1("**\nHorizontal text.\n"); /* this gc has similar properties to the user's gc (including stipple) */ my_gc=XCreateGC(dpy, drawable, 0, 0); XCopyGC(dpy, gc, GCForeground|GCBackground|GCFunction|GCStipple|GCFillStyle| GCTileStipXOrigin|GCTileStipYOrigin|GCPlaneMask, my_gc); XSetFont(dpy, my_gc, font->fid); /* count number of sections in string */ if(align!=NONE) for(i=0; i < (int)(strlen(text)-1); i++) if(text[i]=='\n') { nl++; } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* overall font height */ height=font->ascent+font->descent; /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { yp=y+font->ascent; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { yp=y-nl*height/2+font->ascent; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { yp=y-nl*height+font->ascent; } else { yp=y; } // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return 1; } str3=my_strtok(str1, str2); /* loop through each section in the string */ do { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); /* where to draw section in x ? */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { xp=x; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { xp=x-overall.rbearing/2; } else { xp=x-overall.rbearing; } /* draw string onto bitmap */ if(!bg) { XDrawString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); } else { XDrawImageString(dpy, drawable, my_gc, xp, yp, str3, strlen(str3)); } /* move to next line */ yp+=height; str3=my_strtok((char *)NULL, str2); } while(str3!=NULL); free(str1); XFreeGC(dpy, my_gc); return 0; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Query cache for a match with this font/text/angle/alignment */ /* request, otherwise arrange for its creation */ /**************************************************************************/ static RotatedTextItem *XRotRetrieveFromCache( Display *dpy, XFontStruct *font, float angle, char *text, int align) { Font fid; char *font_name=NULL; unsigned long name_value; RotatedTextItem *item=NULL; RotatedTextItem *i1=first_text_item; /* get font name, if it exists */ if(XGetFontProperty(font, XA_FONT, &name_value)) { DEBUG_PRINT1("got font name OK\n"); font_name=XGetAtomName(dpy, name_value); fid=0; } #ifdef CACHE_FID /* otherwise rely (unreliably?) on font ID */ else { DEBUG_PRINT1("can't get fontname, caching FID\n"); font_name=NULL; fid=font->fid; } #else // CACHE_FID /* not allowed to cache font ID's */ else { DEBUG_PRINT1("can't get fontname, can't cache\n"); font_name=NULL; fid=0; } #endif /*CACHE_FID*/ /* look for a match in cache */ /* matching formula: identical text; identical fontname (if defined, font ID's if not); angles close enough (<0.00001 here, could be smaller); HORIZONTAL alignment matches, OR it's a one line string; magnifications the same */ while(i1 && !item) { /* match everything EXCEPT fontname/ID */ if(strcmp(text, i1->text)==0 && fabs(angle-i1->angle)<0.00001 && style.magnify==i1->magnify && (i1->nl==1 || ((align==0)?9:(align-1))%3== ((i1->align==0)?9:(i1->align-1))%3)) { /* now match fontname/ID */ if(font_name!=NULL && i1->font_name!=NULL) { if(strcmp(font_name, i1->font_name)==0) { item=i1; DEBUG_PRINT1("Matched against font names\n"); } else { i1=i1->next; } } #ifdef CACHE_FID else if(font_name==NULL && i1->font_name==NULL) { if(fid==i1->fid) { item=i1; DEBUG_PRINT1("Matched against FID's\n"); } else { i1=i1->next; } } #endif /*CACHE_FID*/ else { i1=i1->next; } } else { i1=i1->next; } } if(item) { DEBUG_PRINT1("**\nFound target in cache.\n"); } if(!item) { DEBUG_PRINT1("**\nNo match in cache.\n"); } /* no match */ if(!item) { /* create new item */ item=XRotCreateTextItem(dpy, font, angle, text, align); if(!item) { return NULL; } /* record what it shows */ // Allocates some memory item->text=my_strdup(text); /* fontname or ID */ if(font_name!=NULL) { // Allocates some memory item->font_name=my_strdup(font_name); item->fid=0; } else { item->font_name=NULL; item->fid=fid; } item->angle=angle; item->align=align; item->magnify=style.magnify; /* cache it */ XRotAddToLinkedList(dpy, item); } if(font_name) { XFree(font_name); } /* if XImage is cached, need to recreate the bitmap */ #ifdef CACHE_XIMAGES { GC depth_one_gc; /* create bitmap to hold rotated text */ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_out, item->rows_out, 1); /* depth one gc */ depth_one_gc=XCreateGC(dpy, item->bitmap, NULL, 0); XSetBackground(dpy, depth_one_gc, 0); XSetForeground(dpy, depth_one_gc, 1); /* make the text bitmap from XImage */ XPutImage(dpy, item->bitmap, depth_one_gc, item->ximage, 0, 0, 0, 0, item->cols_out, item->rows_out); XFreeGC(dpy, depth_one_gc); } #endif /*CACHE_XIMAGES*/ return item; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Create a rotated text item */ /**************************************************************************/ // // This function allocates some memory but appears to free it // properly. // static RotatedTextItem *XRotCreateTextItem( Display *dpy, XFontStruct *font, float angle, char *text, int align) { RotatedTextItem *item=NULL; Pixmap canvas; GC font_gc; XImage *I_in; int i, j; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int height; int byte_w_in, byte_w_out; int xp, yp; float sin_angle, cos_angle; int it, jt; float di, dj; int ic=0; float xl, xr, xinc; int byte_out; int dir, asc, desc; XCharStruct overall; int old_cols_in=0, old_rows_in=0; int cols_in2, rows_in2; int intAngle1000; // stores first few digits of angle, // used to avoid problems with rounding error in // recognition of 90 degree angles /* allocate memory */ item=(RotatedTextItem *)malloc((unsigned)sizeof(RotatedTextItem)); if(!item) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } /* count number of sections in string */ item->nl=1; if(align!=NONE) for(i=0; i < (int)(strlen(text)-1); i++) if(text[i]=='\n') { item->nl++; } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* find width of longest section */ // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); item->max_width=overall.rbearing; /* loop through each section */ do { str3=my_strtok((char *)NULL, str2); if(str3!=NULL) { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); if(overall.rbearing>item->max_width) { item->max_width=overall.rbearing; } } } while(str3!=NULL); free(str1); /* overall font height */ height=font->ascent+font->descent; /* dimensions horizontal text will have */ item->cols_in=item->max_width; item->rows_in=item->nl*height; /* bitmap for drawing on */ canvas=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_in, item->rows_in, 1); /* create a GC for the bitmap */ font_gc=XCreateGC(dpy, canvas, 0, 0); XSetBackground(dpy, font_gc, 0); XSetFont(dpy, font_gc, font->fid); /* make sure the bitmap is blank */ XSetForeground(dpy, font_gc, 0); XFillRectangle(dpy, canvas, font_gc, 0, 0, item->cols_in+1, item->rows_in+1); XSetForeground(dpy, font_gc, 1); /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* text background will be drawn using XFillPolygon */ item->corners_x= (float *)malloc((unsigned)(4*item->nl*sizeof(float))); if(!item->corners_x) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } item->corners_y= (float *)malloc((unsigned)(4*item->nl*sizeof(float))); if(!item->corners_y) { fprintf(stderr,"Couldn't allocate memory in RotatedTextItem()\n"); return NULL; } /* draw text horizontally */ /* start at top of bitmap */ yp=font->ascent; // Allocates some memory str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); /* loop through each section in the string */ do { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); /* where to draw section in x ? */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { xp=0; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { xp=(item->max_width-overall.rbearing)/2; } else { xp=item->max_width-overall.rbearing; } /* draw string onto bitmap */ XDrawString(dpy, canvas, font_gc, xp, yp, str3, strlen(str3)); /* keep a note of corner positions of this string */ item->corners_x[ic]=((float)xp-(float)item->cols_in/2)*style.magnify; item->corners_y[ic]=((float)(yp-font->ascent)-(float)item->rows_in/2) *style.magnify; item->corners_x[ic+1]=item->corners_x[ic]; item->corners_y[ic+1]=item->corners_y[ic]+(float)height*style.magnify; item->corners_x[item->nl*4-1-ic]=item->corners_x[ic]+ (float)overall.rbearing*style.magnify; item->corners_y[item->nl*4-1-ic]=item->corners_y[ic]; item->corners_x[item->nl*4-2-ic]= item->corners_x[item->nl*4-1-ic]; item->corners_y[item->nl*4-2-ic]=item->corners_y[ic+1]; ic+=2; /* move to next line */ yp+=height; str3=my_strtok((char *)NULL, str2); } while(str3!=NULL); free(str1); /* create image to hold horizontal text */ I_in=MakeXImage(dpy, item->cols_in, item->rows_in); if(I_in==NULL) { return NULL; } /* extract horizontal text */ XGetSubImage(dpy, canvas, 0, 0, item->cols_in, item->rows_in, 1, XYPixmap, I_in, 0, 0); I_in->format=XYBitmap; /* magnify horizontal text */ if(style.magnify!=1.) { I_in=XRotMagnifyImage(dpy, I_in); old_cols_in=item->cols_in; old_rows_in=item->rows_in; item->cols_in=(float)item->cols_in*style.magnify; item->rows_in=(float)item->rows_in*style.magnify; } /* how big will rotated text be ? */ item->cols_out=fabs((float)item->rows_in*sin_angle) + fabs((float)item->cols_in*cos_angle) +0.99999 +2; item->rows_out=fabs((float)item->rows_in*cos_angle) + fabs((float)item->cols_in*sin_angle) +0.99999 +2; if(item->cols_out%2==0) { item->cols_out++; } if(item->rows_out%2==0) { item->rows_out++; } /* create image to hold rotated text */ item->ximage=MakeXImage(dpy, item->cols_out, item->rows_out); if(item->ximage==NULL) { return NULL; } byte_w_in=(item->cols_in-1)/8+1; byte_w_out=(item->cols_out-1)/8+1; /* we try to make this bit as fast as possible - which is why it looks a bit over-the-top */ /* vertical distance from centre */ dj=0.5-(float)item->rows_out/2; /* where abouts does text actually lie in rotated image? */ intAngle1000 = (int)(angle*1000); if ( intAngle1000==0 || intAngle1000==INT_M_PI_2_1000 || intAngle1000==INT_M_PI_1000 || intAngle1000==INT_3_M_PI_2_1000 ) { // 0, 90, 180, 270 degrees are special cases // floating point errors may prevent recognition of them unless // we round off, that is a value that started as 180 may not be // recognized as == M_PI/2. Rounding to .001 radian seems a // reasonable choice for the purpose of orienting text strings. xl=0; xr=(float)item->cols_out; xinc=0; } else if(anglecols_out/2+ (dj-(float)item->rows_in/(2*cos_angle))/ tan(angle)-2; xr=(float)item->cols_out/2+ (dj+(float)item->rows_in/(2*cos_angle))/ tan(angle)+2; xinc=1./tan(angle); } else { xl=(float)item->cols_out/2+ (dj+(float)item->rows_in/(2*cos_angle))/ tan(angle)-2; xr=(float)item->cols_out/2+ (dj-(float)item->rows_in/(2*cos_angle))/ tan(angle)+2; xinc=1./tan(angle); } // Set up some constants for loops below cols_in2 = item->cols_in / 2; rows_in2 = item->rows_in / 2; // Handle special cases of 90 degree rotation if ( intAngle1000 == INT_M_PI_2_1000 ) { // angle is 180 degrees, text is rotated 90 degrees from horizontal and runs up x axis for(j=0; jrows_out; j++) { di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2; byte_out=(item->rows_out-j-1)*byte_w_out; for(i=((xl<0)?0:(int)xl); i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) { jt=(float)rows_in2 + di; it=(float)cols_in2 + dj; if(it>=0 && itcols_in && jt>=0 && jtrows_in) if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0) { item->ximage->data[byte_out+i/8]|=128>>i%8; } di+=1; } dj+=1; xl+=xinc; xr+=xinc; } // handling for special cases of 90 and 270 not written yet. // need elseif clauses here. } else { // not a 90 degree rotation, use sin/cos transform /* loop through all relevant bits in rotated image */ for(j=0; jrows_out; j++) { float dj_sin, dj_cos; float temp_it, temp_jt; /* no point re-calculating these every pass */ di=(float)((xl<0)?0:(int)xl)+0.5-(float)item->cols_out/2; byte_out=(item->rows_out-j-1)*byte_w_out; // New code: Calculate these outside the inner loop for // major speed gains. dj_sin = dj * sin_angle; dj_cos = dj * cos_angle; temp_it = (float)cols_in2 + dj_sin; temp_jt = (float)rows_in2 - dj_cos; /* loop through meaningful columns */ for(i=((xl<0)?0:(int)xl); i<((xr>=item->cols_out)?item->cols_out:(int)xr); i++) { // rotate coordinates // Original code (very slow) //it=(float)item->cols_in/2 + ( di*cos_angle + dj*sin_angle); //jt=(float)item->rows_in/2 - (-di*sin_angle + dj*cos_angle); // New code (much faster) //it=(float)cols_in2 + ( di*cos_angle + dj_sin); //jt=(float)rows_in2 - (-di*sin_angle + dj_cos); it=(float)temp_it + di*cos_angle; jt=(float)temp_jt + di*sin_angle; /* set pixel if required */ if(it>=0 && itcols_in && jt>=0 && jtrows_in) if((I_in->data[jt*byte_w_in+it/8] & 128>>(it%8))>0) { item->ximage->data[byte_out+i/8]|=128>>i%8; } di+=1; } dj+=1; xl+=xinc; xr+=xinc; } } XDestroyImage(I_in); if(style.magnify!=1.) { item->cols_in=old_cols_in; item->rows_in=old_rows_in; } #ifdef CACHE_BITMAPS /* create a bitmap to hold rotated text */ item->bitmap=XCreatePixmap(dpy, DefaultRootWindow(dpy), item->cols_out, item->rows_out, 1); /* make the text bitmap from XImage */ XPutImage(dpy, item->bitmap, font_gc, item->ximage, 0, 0, 0, 0, item->cols_out, item->rows_out); XDestroyImage(item->ximage); #endif /*CACHE_BITMAPS*/ XFreeGC(dpy, font_gc); XFreePixmap(dpy, canvas); return item; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Adds a text item to the end of the cache, removing as many items */ /* from the front as required to keep cache size below limit */ /**************************************************************************/ static void XRotAddToLinkedList( Display *dpy, RotatedTextItem *item) { static long int current_size=0; static RotatedTextItem *last=NULL; RotatedTextItem *i1=first_text_item, *i2=NULL; #ifdef CACHE_BITMAPS /* I don't know how much memory a pixmap takes in the server - probably this + a bit more we can't account for */ item->size=((item->cols_out-1)/8+1)*item->rows_out; #else // CACHE_BITMAPS /* this is pretty much the size of a RotatedTextItem */ item->size=((item->cols_out-1)/8+1)*item->rows_out + sizeof(XImage) + strlen(item->text) + item->nl*8*sizeof(float) + sizeof(RotatedTextItem); if(item->font_name!=NULL) { item->size+=strlen(item->font_name); } else { item->size+=sizeof(Font); } #endif /*CACHE_BITMAPS */ #ifdef DEBUG /* count number of items in cache, for debugging */ { int i=0; while(i1) { i++; i1=i1->next; } DEBUG_PRINT2("Cache has %d items.\n", i); i1=first_text_item; } #endif // DEBUG DEBUG_PRINT4("current cache size=%ld, new item=%ld, limit=%ld\n", current_size, item->size, (long)(CACHE_SIZE_LIMIT*1024)); /* if this item is bigger than whole cache, forget it */ if(item->size>CACHE_SIZE_LIMIT*1024) { DEBUG_PRINT1("Too big to cache\n\n"); item->cached=0; return; } /* remove elements from cache as needed */ while(i1 && current_size+item->size>CACHE_SIZE_LIMIT*1024) { DEBUG_PRINT2("Removed %d bytes\n", (int)i1->size); if(i1->font_name!=NULL) DEBUG_PRINT5(" (`%s'\n %s\n angle=%f align=%d)\n", i1->text, i1->font_name, i1->angle, i1->align); #ifdef CACHE_FID if(i1->font_name==NULL) DEBUG_PRINT5(" (`%s'\n FID=%ld\n angle=%f align=%d)\n", i1->text, i1->fid, i1->angle, i1->align); #endif /*CACHE_FID*/ current_size-=i1->size; i2=i1->next; /* free resources used by the unlucky item */ XRotFreeTextItem(dpy, i1); /* remove it from linked list */ first_text_item=i2; i1=i2; } /* add new item to end of linked list */ if(first_text_item==NULL) { item->next=NULL; first_text_item=item; last=item; } else { item->next=NULL; last->next=item; last=item; } /* new cache size */ current_size+=item->size; item->cached=1; DEBUG_PRINT1("Added item to cache.\n"); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Free the resources used by a text item */ /**************************************************************************/ static void XRotFreeTextItem( Display *dpy, RotatedTextItem *item) { free(item->text); if(item->font_name!=NULL) { free(item->font_name); } free((char *)item->corners_x); free((char *)item->corners_y); #ifdef CACHE_BITMAPS XFreePixmap(dpy, item->bitmap); #else // CACHE_BITMAPS XDestroyImage(item->ximage); #endif /* CACHE_BITMAPS */ free((char *)item); } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Magnify an XImage using bilinear interpolation */ /**************************************************************************/ static XImage *XRotMagnifyImage( Display *dpy, XImage *ximage) { int i, j; float x, y; float u,t; XImage *I_out; int cols_in, rows_in; int cols_out, rows_out; int i2, j2; float z1, z2, z3, z4; int byte_width_in, byte_width_out; float mag_inv; /* size of input image */ cols_in=ximage->width; rows_in=ximage->height; /* size of final image */ cols_out=(float)cols_in*style.magnify; rows_out=(float)rows_in*style.magnify; /* this will hold final image */ I_out=MakeXImage(dpy, cols_out, rows_out); if(I_out==NULL) { return NULL; } /* width in bytes of input, output images */ byte_width_in=(cols_in-1)/8+1; byte_width_out=(cols_out-1)/8+1; /* for speed */ mag_inv=1./style.magnify; y=0.; /* loop over magnified image */ for(j2=0; j2data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=z1; z3=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; z4=z3; } /* top edge */ else if(i!=cols_in-1 && j==rows_in-1) { t=x-(float)i; u=0; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z3=z2; z4=z1; } /* top right corner */ else if(i==cols_in-1 && j==rows_in-1) { u=0; t=0; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=z1; z3=z1; z4=z1; } /* somewhere `safe' */ else { t=x-(float)i; u=y-(float)j; z1=(ximage->data[j*byte_width_in+i/8] & 128>>(i%8))>0; z2=(ximage->data[j*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z3=(ximage->data[(j+1)*byte_width_in+(i+1)/8] & 128>>((i+1)%8))>0; z4=(ximage->data[(j+1)*byte_width_in+i/8] & 128>>(i%8))>0; } /* if interpolated value is greater than 0.5, set bit */ if(((1-t)*(1-u)*z1 + t*(1-u)*z2 + t*u*z3 + (1-t)*u*z4)>0.5) { I_out->data[j2*byte_width_out+i2/8]|=128>>i2%8; } x+=mag_inv; } y+=mag_inv; } /* destroy original */ XDestroyImage(ximage); /* return big image */ return I_out; } /* ---------------------------------------------------------------------- */ /**************************************************************************/ /* Calculate the bounding box some text will have when painted */ /**************************************************************************/ // // This function allocates some memory, frees all but xp_out which // is returned. // XPoint *XRotTextExtents( Display * UNUSED(dpy), XFontStruct *font, float angle, int x, int y, char *text, int align) { int i; char *str1, *str2, *str3; char *str2_a="\0", *str2_b="\n\0"; int height; float sin_angle, cos_angle; int nl, max_width; int cols_in, rows_in; float hot_x, hot_y; XPoint *xp_in, *xp_out; int dir, asc, desc; XCharStruct overall; /* manipulate angle to 0<=angle<360 degrees */ while(angle<0) { angle+=360; } while(angle>360) { angle-=360; } angle*=M_PI/180; /* count number of sections in string */ nl=1; if(align!=NONE) { for (i=0; i < (int)(strlen(text)-1); i++) { if(text[i]=='\n') { nl++; } } } /* ignore newline characters if not doing alignment */ if(align==NONE) { str2=str2_a; } else { str2=str2_b; } /* find width of longest section */ // Allocates some memory, free'd below str1=my_strdup(text); if(str1==NULL) { return NULL; } str3=my_strtok(str1, str2); XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); max_width=overall.rbearing; /* loop through each section */ do { str3=my_strtok((char *)NULL, str2); if(str3!=NULL) { XTextExtents(font, str3, strlen(str3), &dir, &asc, &desc, &overall); if(overall.rbearing>max_width) { max_width=overall.rbearing; } } } while(str3!=NULL); free(str1); /* overall font height */ height=font->ascent+font->descent; /* dimensions horizontal text will have */ cols_in=max_width; rows_in=nl*height; /* pre-calculate sin and cos */ sin_angle=sin(angle); cos_angle=cos(angle); /* y position */ if(align==TLEFT || align==TCENTRE || align==TRIGHT) { hot_y=(float)rows_in/2*style.magnify; } else if(align==MLEFT || align==MCENTRE || align==MRIGHT) { hot_y=0; } else if(align==BLEFT || align==BCENTRE || align==BRIGHT) { hot_y=-(float)rows_in/2*style.magnify; } else { hot_y=-((float)rows_in/2-(float)font->descent)*style.magnify; } /* x position */ if(align==TLEFT || align==MLEFT || align==BLEFT || align==NONE) { hot_x=-(float)max_width/2*style.magnify; } else if(align==TCENTRE || align==MCENTRE || align==BCENTRE) { hot_x=0; } else { hot_x=(float)max_width/2*style.magnify; } /* reserve space for XPoints */ xp_in=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); if(!xp_in) { fprintf(stderr,"Couldn't allocate memory in XRotTextExtents()\n"); return NULL; } xp_out=(XPoint *)malloc((unsigned)(5*sizeof(XPoint))); if(!xp_out) { fprintf(stderr,"Couldn't allocate memory in XRotTextExtents()\n"); return NULL; } /* bounding box when horizontal, relative to bitmap centre */ xp_in[0].x=-(float)cols_in*style.magnify/2-style.bbx_pad; xp_in[0].y= (float)rows_in*style.magnify/2+style.bbx_pad; xp_in[1].x= (float)cols_in*style.magnify/2+style.bbx_pad; xp_in[1].y= (float)rows_in*style.magnify/2+style.bbx_pad; xp_in[2].x= (float)cols_in*style.magnify/2+style.bbx_pad; xp_in[2].y=-(float)rows_in*style.magnify/2-style.bbx_pad; xp_in[3].x=-(float)cols_in*style.magnify/2-style.bbx_pad; xp_in[3].y=-(float)rows_in*style.magnify/2-style.bbx_pad; xp_in[4].x=xp_in[0].x; xp_in[4].y=xp_in[0].y; /* rotate and translate bounding box */ for(i=0; i<5; i++) { xp_out[i].x=(float)x + ( ((float)xp_in[i].x-hot_x)*cos_angle + ((float)xp_in[i].y+hot_y)*sin_angle); xp_out[i].y=(float)y + (-((float)xp_in[i].x-hot_x)*sin_angle + ((float)xp_in[i].y+hot_y)*cos_angle); } free((char *)xp_in); return xp_out; } Xastir-Release-2.2.4/src/rotated.h0000664000175000017500000000530515151324131015726 0ustar hibbyhibby // // Portions Copyright (C) 2000-2026 The Xastir Group // /* ************************************************************************ */ /* Header file for the `xvertext 5.0' routines. Copyright (c) 1993 Alan Richardson (mppa3@uk.ac.sussex.syma) */ /* ************************************************************************ */ #ifndef _XVERTEXT_INCLUDED_ #define _XVERTEXT_INCLUDED_ #define XV_VERSION 5.0 #define XV_COPYRIGHT \ "xvertext routines Copyright (c) 1993 Alan Richardson" /* ---------------------------------------------------------------------- */ /* text alignment */ #define NONE 0 #define TLEFT 1 #define TCENTRE 2 #define TRIGHT 3 #define MLEFT 4 #define MCENTRE 5 #define MRIGHT 6 #define BLEFT 7 #define BCENTRE 8 #define BRIGHT 9 /* ---------------------------------------------------------------------- */ /* this shoulf be C++ compliant, thanks to vlp@latina.inesc.pt (Vasco Lopes Paulo) */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { float XRotVersion(char*, int); void XRotSetMagnification(float); void XRotSetBoundingBoxPad(int); int XRotDrawString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); int XRotDrawImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); int XRotDrawAlignedString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); int XRotDrawAlignedImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); XPoint *XRotTextExtents(Display*, XFontStruct*, float, int, int, char*, int); } #else // _cplusplus || c_plusplus extern float XRotVersion(char *, int); extern void XRotSetMagnification(float); extern void XRotSetBoundingBoxPad(int); extern int XRotDrawString(Display *, XFontStruct*, float, Drawable, GC, int, int, char*); extern int XRotDrawImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*); extern int XRotDrawAlignedString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); extern int XRotDrawAlignedImageString(Display*, XFontStruct*, float, Drawable, GC, int, int, char*, int); extern XPoint *XRotTextExtents(Display*, XFontStruct*, float, int, int, char*, int); #endif /* __cplusplus */ /* ---------------------------------------------------------------------- */ #endif /* _XVERTEXT_INCLUDED_ */ Xastir-Release-2.2.4/src/rpl_malloc.c0000664000175000017500000000332115151324131016377 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* // // We DON'T want config.h to redefine malloc in this file else we'll // get an infinite loop. // #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H */ #include #include "rpl_malloc.h" // // Work around bug on some systems where malloc (0) fails. // written by Jim Meyering // // configure.ac calls out AC_FUNC_MALLOC which checks the malloc() // function. If malloc() is determined to do the wrong thing when // passed a 0 value, the Autoconf macro will do this: // #define malloc rpl_malloc // We then need to have an rpl_malloc function defined. Here it is: // // Allocate an N-byte block of memory from the heap. // If N is zero, allocate a 1-byte block. // void *rpl_malloc (size_t size) { if (size == 0) { size++; } return malloc (size); } Xastir-Release-2.2.4/src/rpl_malloc.h0000664000175000017500000000207315151324131016407 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_RPL_MALLOC_H #define __XASTIR_RPL_MALLOC_H extern void *rpl_malloc (size_t size); #endif // __XASTIR_RPL_MALLOC_H Xastir-Release-2.2.4/src/rtree/0000775000175000017500000000000015151324131015231 5ustar hibbyhibbyXastir-Release-2.2.4/src/rtree/.vimrc0000664000175000017500000000143315151324131016353 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/src/rtree/Makefile.am0000664000175000017500000000047215151324131017270 0ustar hibbyhibby # Copyright (C) 2000-2026 The Xastir Group noinst_LIBRARIES=librtree.a librtree_a_SOURCES= card.c \ card.h \ index.c \ index.h \ node.c \ rect.c \ split_l.c \ split_l.h Xastir-Release-2.2.4/src/rtree/card.c0000664000175000017500000000355215151324131016313 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include "index.h" #include "card.h" int Xastir_NODECARD = MAXCARD; int Xastir_LEAFCARD = MAXCARD; static int set_max(int *which, int new_max) { if(2 > new_max || new_max > MAXCARD) { return 0; } *which = new_max; return 1; } int Xastir_RTreeSetNodeMax(int new_max) { return set_max(&Xastir_NODECARD, new_max); } int Xastir_RTreeSetLeafMax(int new_max) { return set_max(&Xastir_LEAFCARD, new_max); } int Xastir_RTreeGetNodeMax(void) { return Xastir_NODECARD; } int Xastir_RTreeGetLeafMax(void) { return Xastir_LEAFCARD; } Xastir-Release-2.2.4/src/rtree/card.h0000664000175000017500000000333015151324131016312 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #ifndef __CARD__ #define __CARD__ extern int Xastir_NODECARD; extern int Xastir_LEAFCARD; /* balance criteria for node splitting */ /* NOTE: can be changed if needed. */ #define MinNodeFill (Xastir_NODECARD / 2) #define MinLeafFill (Xastir_LEAFCARD / 2) #define MAXKIDS(n) ((n)->level > 0 ? Xastir_NODECARD : Xastir_LEAFCARD) #define MINFILL(n) ((n)->level > 0 ? MinNodeFill : MinLeafFill) #endif Xastir-Release-2.2.4/src/rtree/gammavol.c0000664000175000017500000000377415151324131017213 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #ifndef M_PI #define M_PI 3.1415926535 #endif #ifndef ABS #define ABS(a) ((a) > 0 ? (a) : -(a)) #endif #define EP .0000000001 const double log_pi = log(M_PI); double sphere_volume(double dimension) { double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } int main(void) { double dim=0, delta=1; while(ABS(delta) > EP) if(sphere_volume(dim + delta) > sphere_volume(dim)) { dim += delta; } else { delta /= -2; } printf("max volume = %.10f at dimension %.10f\n", sphere_volume(dim), dim); return 0; } Xastir-Release-2.2.4/src/rtree/index.c0000664000175000017500000002313715151324131016512 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include "card.h" // Make a new index, empty. Consists of a single node. // struct Node * Xastir_RTreeNewIndex(void) { struct Node *x; x = Xastir_RTreeNewNode(); x->level = 0; /* leaf */ return x; } // Search in an index tree or subtree for all data rectangles that // overlap the argument rectangle. // Return the number of qualifying data rects. // int Xastir_RTreeSearch(struct Node *N, struct Rect *R, SearchHitCallback shcb, void* cbarg) { struct Node *n = N; struct Rect *r = R; // NOTE: Suspected bug was R sent in as Node* and cast to Rect* here. Fix not yet tested. int hitCount = 0; int i; assert(n); assert(n->level >= 0); assert(r); if (n->level > 0) /* this is an internal node in the tree */ { for (i=0; ibranch[i].child && Xastir_RTreeOverlap(r,&n->branch[i].rect)) { hitCount += Xastir_RTreeSearch(n->branch[i].child, R, shcb, cbarg); } } else /* this is a leaf node */ { for (i=0; ibranch[i].child && Xastir_RTreeOverlap(r,&n->branch[i].rect)) { hitCount++; if(shcb) // call the user-provided callback if( ! shcb(n->branch[i].child, cbarg)) { return hitCount; // callback wants to terminate search early } } } return hitCount; } // Inserts a new data rectangle into the index structure. // Recursively descends tree, propagates splits back up. // Returns 0 if node was not split. Old node updated. // If node was split, returns 1 and sets the pointer pointed to by // new_node to point to the new node. Old node updated to become one of two. // The level argument specifies the number of steps up from the leaf // level to insert; e.g. a data rectangle goes in at level = 0. // static int Xastir_RTreeInsertRect2(struct Rect *r, void *tid, struct Node *n, struct Node **new_node, int level) { /* register struct Rect *r = R; register int tid = Tid; register struct Node *n = N, **new_node = New_node; register int level = Level; */ int i; struct Branch b; struct Node *n2; assert(r && n && new_node); assert(level >= 0 && level <= n->level); // Still above level for insertion, go down tree recursively // if (n->level > level) { i = Xastir_RTreePickBranch(r, n); if (!Xastir_RTreeInsertRect2(r, tid, n->branch[i].child, &n2, level)) { // child was not split // n->branch[i].rect = Xastir_RTreeCombineRect(r,&(n->branch[i].rect)); return 0; } else // child was split { n->branch[i].rect = Xastir_RTreeNodeCover(n->branch[i].child); b.child = n2; b.rect = Xastir_RTreeNodeCover(n2); return Xastir_RTreeAddBranch(&b, n, new_node); } } // Have reached level for insertion. Add rect, split if necessary // else if (n->level == level) { b.rect = *r; b.child = (struct Node *) tid; /* child field of leaves contains tid of data record */ return Xastir_RTreeAddBranch(&b, n, new_node); } else { /* Not supposed to happen */ assert (FALSE); return 0; } } // Insert a data rectangle into an index structure. // Xastir_RTreeInsertRect provides for splitting the root; // returns 1 if root was split, 0 if it was not. // The level argument specifies the number of steps up from the leaf // level to insert; e.g. a data rectangle goes in at level = 0. // Xastir_RTreeInsertRect2 does the recursion. // int Xastir_RTreeInsertRect(struct Rect *R, void *Tid, struct Node **Root, int Level) { struct Rect *r = R; void *tid = Tid; struct Node **root = Root; int level = Level; int i; struct Node *newroot; struct Node *newnode; struct Branch b; int result; assert(r && root); assert(level >= 0 && level <= (*root)->level); for (i=0; iboundary[i] <= r->boundary[NUMDIMS+i]); } if (Xastir_RTreeInsertRect2(r, tid, *root, &newnode, level)) /* root split */ { newroot = Xastir_RTreeNewNode(); /* grow a new root, & tree taller */ newroot->level = (*root)->level + 1; b.rect = Xastir_RTreeNodeCover(*root); b.child = *root; Xastir_RTreeAddBranch(&b, newroot, NULL); b.rect = Xastir_RTreeNodeCover(newnode); b.child = newnode; Xastir_RTreeAddBranch(&b, newroot, NULL); *root = newroot; result = 1; } else { result = 0; } return result; } // Allocate space for a node in the list used in DeletRect to // store Nodes that are too empty. // static struct ListNode * Xastir_RTreeNewListNode(void) { return (struct ListNode *) malloc(sizeof(struct ListNode)); //return new ListNode; } static void Xastir_RTreeFreeListNode(struct ListNode *p) { free(p); //delete(p); } // Add a node to the reinsertion list. All its branches will later // be reinserted into the index structure. // static void Xastir_RTreeReInsert(struct Node *n, struct ListNode **ee) { struct ListNode *l; l = Xastir_RTreeNewListNode(); l->node = n; l->next = *ee; *ee = l; } // Delete a rectangle from non-root part of an index structure. // Called by Xastir_RTreeDeleteRect. Descends tree recursively, // merges branches on the way back up. // Returns 1 if record not found, 0 if success. // static int Xastir_RTreeDeleteRect2(struct Rect *R, void *Tid, struct Node *N, struct ListNode **Ee) { struct Rect *r = R; void *tid = Tid; struct Node *n = N; struct ListNode **ee = Ee; int i; assert(r && n && ee); assert(tid != NULL); assert(n->level >= 0); if (n->level > 0) // not a leaf node { for (i = 0; i < Xastir_NODECARD; i++) { if (n->branch[i].child && Xastir_RTreeOverlap(r, &(n->branch[i].rect))) { if (!Xastir_RTreeDeleteRect2(r, tid, n->branch[i].child, ee)) { if (n->branch[i].child->count >= MinNodeFill) n->branch[i].rect = Xastir_RTreeNodeCover( n->branch[i].child); else { // not enough entries in child, // eliminate child node // Xastir_RTreeReInsert(n->branch[i].child, ee); Xastir_RTreeDisconnectBranch(n, i); } return 0; } } } return 1; } else // a leaf node { for (i = 0; i < Xastir_LEAFCARD; i++) { if (n->branch[i].child && n->branch[i].child == (struct Node *) tid) { Xastir_RTreeDisconnectBranch(n, i); return 0; } } return 1; } } // Delete a data rectangle from an index structure. // Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. // Returns 1 if record not found, 0 if success. // Xastir_RTreeDeleteRect provides for eliminating the root. // int Xastir_RTreeDeleteRect(struct Rect *R, void *Tid, struct Node**Nn) { struct Rect *r = R; void *tid = Tid; struct Node **nn = Nn; int i; struct Node *tmp_nptr=NULL; // Original superliminal.com // source did not initialize. // Code analysis says shouldn't // matter, but let's initialize // to shut up GCC struct ListNode *reInsertList = NULL; struct ListNode *e; assert(r && nn); assert(*nn); assert(tid != NULL); if (!Xastir_RTreeDeleteRect2(r, tid, *nn, &reInsertList)) { /* found and deleted a data item */ /* reinsert any branches from eliminated nodes */ while (reInsertList) { tmp_nptr = reInsertList->node; for (i = 0; i < MAXKIDS(tmp_nptr); i++) { if (tmp_nptr->branch[i].child) { Xastir_RTreeInsertRect( &(tmp_nptr->branch[i].rect), tmp_nptr->branch[i].child, nn, tmp_nptr->level); } } e = reInsertList; reInsertList = reInsertList->next; Xastir_RTreeFreeNode(e->node); Xastir_RTreeFreeListNode(e); } /* check for redundant root (not leaf, 1 child) and eliminate */ if ((*nn)->count == 1 && (*nn)->level > 0) { for (i = 0; i < Xastir_NODECARD; i++) { tmp_nptr = (*nn)->branch[i].child; if(tmp_nptr) { break; } } assert(tmp_nptr); Xastir_RTreeFreeNode(*nn); *nn = tmp_nptr; } return 0; } else { return 1; } } Xastir-Release-2.2.4/src/rtree/index.h0000664000175000017500000001045715151324131016520 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #ifndef _INDEX_ #define _INDEX_ /* PGSIZE is normally the natural page size of the machine */ #define PGSIZE 512 #define NUMDIMS 2 /* number of dimensions */ #define NDEBUG // This is what GRASS does //typedef double RectReal; // but this is the original, and saves lots of RAM --- these indices are // huge for big shapefiles! typedef float RectReal; /*----------------------------------------------------------------------------- | Global definitions. -----------------------------------------------------------------------------*/ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define NUMSIDES 2*NUMDIMS struct Rect { RectReal boundary[NUMSIDES]; /* xmin,ymin,...,xmax,ymax,... */ }; struct Node; struct Branch { struct Rect rect; struct Node *child; }; /* max branching factor of a node */ #define MAXCARD (int)((PGSIZE-(2*sizeof(int))) / sizeof(struct Branch)) struct Node { int count; int level; /* 0 is leaf, others positive */ struct Branch branch[MAXCARD]; }; struct ListNode { struct ListNode *next; struct Node *node; }; /* * If passed to a tree search, this callback function will be called * with the ID of each data rect that overlaps the search rect * plus whatever user specific pointer was passed to the search. * It can terminate the search early by returning 0 in which case * the search will return the number of hits found up to that point. */ typedef int (*SearchHitCallback)(void *id, void* arg); extern int Xastir_RTreeSearch(struct Node*, struct Rect*, SearchHitCallback, void*); extern int Xastir_RTreeInsertRect(struct Rect*, void *, struct Node**, int depth); extern int Xastir_RTreeDeleteRect(struct Rect*, void *, struct Node**); extern struct Node * Xastir_RTreeNewIndex(void); extern struct Node * Xastir_RTreeNewNode(void); extern void Xastir_RTreeInitNode(struct Node*); extern void Xastir_RTreeFreeNode(struct Node *); extern void Xastir_RTreePrintNode(struct Node *, int); extern void Xastir_RTreeDestroyNode(struct Node*); extern void Xastir_RTreeTabIn(int); extern struct Rect Xastir_RTreeNodeCover(struct Node *); extern void Xastir_RTreeInitRect(struct Rect*); extern struct Rect Xastir_RTreeNullRect(void); extern RectReal Xastir_RTreeRectArea(struct Rect*); extern RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R); extern RectReal Xastir_RTreeRectVolume(struct Rect *R); extern struct Rect Xastir_RTreeCombineRect(struct Rect*, struct Rect*); extern int Xastir_RTreeOverlap(struct Rect*, struct Rect*); extern void Xastir_RTreePrintRect(struct Rect*, int); extern int Xastir_RTreeAddBranch(struct Branch *, struct Node *, struct Node **); extern int Xastir_RTreePickBranch(struct Rect *, struct Node *); extern void Xastir_RTreeDisconnectBranch(struct Node *, int); extern void Xastir_RTreeSplitNode(struct Node*, struct Branch*, struct Node**); extern int Xastir_RTreeSetNodeMax(int); extern int Xastir_RTreeSetLeafMax(int); extern int Xastir_RTreeGetNodeMax(void); extern int Xastir_RTreeGetLeafMax(void); #endif /* _INDEX_ */ Xastir-Release-2.2.4/src/rtree/node.c0000664000175000017500000001572415151324131016333 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include "card.h" //static int nnodes_alloced=0; //static long int bytes_malloced=0; // Initialize one branch cell in a node. // static void Xastir_RTreeInitBranch(struct Branch *b) { Xastir_RTreeInitRect(&(b->rect)); b->child = NULL; } // Initialize a Node structure. // void Xastir_RTreeInitNode(struct Node *N) { register struct Node *n = N; register int i; n->count = 0; n->level = -1; for (i = 0; i < MAXCARD; i++) { Xastir_RTreeInitBranch(&(n->branch[i])); } } // Make a new node and initialize to have all branch cells empty. // struct Node * Xastir_RTreeNewNode(void) { register struct Node *n; //n = new Node; n = (struct Node*)malloc(sizeof(struct Node)); assert(n); // nnodes_alloced++; // bytes_malloced+= sizeof(struct Node); // fprintf(stderr," Currently %d nodes (%ld bytes) in all rtrees\n",nnodes_alloced, bytes_malloced); Xastir_RTreeInitNode(n); return n; } void Xastir_RTreeFreeNode(struct Node *p) { assert(p); //delete p; // nnodes_alloced--; // bytes_malloced-= sizeof(struct Node); free(p); } static void Xastir_RTreePrintBranch(struct Branch *b, int depth) { Xastir_RTreePrintRect(&(b->rect), depth); Xastir_RTreePrintNode(b->child, depth); } extern void Xastir_RTreeTabIn(int depth) { int i; for(i=0; ilevel == 0) { printf(" LEAF"); } else if (n->level > 0) { printf(" NONLEAF"); } else { printf(" TYPE=?"); } // Original superliminal.com implementation had no cast before // n, gcc gripes about "int format, pointer arg" printf(" level=%d count=%d address=%lx\n", n->level, n->count, (unsigned long) n); for (i=0; icount; i++) { if(n->level == 0) { // Xastir_RTreeTabIn(depth); // printf("\t%d: data = %d\n", i, n->branch[i].child); } else { Xastir_RTreeTabIn(depth); printf("branch %d\n", i); Xastir_RTreePrintBranch(&n->branch[i], depth+1); } } } // Find the smallest rectangle that includes all rectangles in // branches of a node. // struct Rect Xastir_RTreeNodeCover(struct Node *N) { register struct Node *n = N; register int i, first_time=1; struct Rect r; assert(n); Xastir_RTreeInitRect(&r); for (i = 0; i < MAXKIDS(n); i++) if (n->branch[i].child) { if (first_time) { r = n->branch[i].rect; first_time = 0; } else { r = Xastir_RTreeCombineRect(&r, &(n->branch[i].rect)); } } return r; } // Pick a branch. Pick the one that will need the smallest increase // in area to accommodate the new rectangle. This will result in the // least total area for the covering rectangles in the current node. // In case of a tie, pick the one which was smaller before, to get // the best resolution when searching. // int Xastir_RTreePickBranch(struct Rect *R, struct Node *N) { register struct Rect *r = R; register struct Node *n = N; register struct Rect *rr; register int i, first_time=1; // Although it is impossible for bestArea and best to be used // unininitialized the way the code is structured, gcc complains // about possible uninitialized usage. Let's keep it happy. // Original superliminal.com had no initializers here. RectReal increase, bestIncr=(RectReal)-1, area, bestArea=0.0; int best=0; struct Rect tmp_rect; assert(r && n); for (i=0; ibranch[i].child) { rr = &n->branch[i].rect; area = Xastir_RTreeRectSphericalVolume(rr); tmp_rect = Xastir_RTreeCombineRect(r, rr); increase = Xastir_RTreeRectSphericalVolume(&tmp_rect) - area; if (increase < bestIncr || first_time) { best = i; bestArea = area; bestIncr = increase; first_time = 0; } else if (increase == bestIncr && area < bestArea) { best = i; bestArea = area; bestIncr = increase; } } } return best; } // Add a branch to a node. Split the node if necessary. // Returns 0 if node not split. Old node updated. // Returns 1 if node split, sets *new_node to address of new node. // Old node updated, becomes one of two. // int Xastir_RTreeAddBranch(struct Branch *B, struct Node *N, struct Node **New_node) { register struct Branch *b = B; register struct Node *n = N; register struct Node **new_node = New_node; register int i; assert(b); assert(n); if (n->count < MAXKIDS(n)) /* split won't be necessary */ { for (i = 0; i < MAXKIDS(n); i++) /* find empty branch */ { if (n->branch[i].child == NULL) { n->branch[i] = *b; n->count++; break; } } return 0; } else { assert(new_node); Xastir_RTreeSplitNode(n, b, new_node); return 1; } } // Disconnect a dependent node. // void Xastir_RTreeDisconnectBranch(struct Node *n, int i) { assert(n && i>=0 && ibranch[i].child); Xastir_RTreeInitBranch(&(n->branch[i])); n->count--; } // Destroy (free) node recursively. void Xastir_RTreeDestroyNode (struct Node *n) { int i; // fprintf(stderr," Freeing node %lx\n",(unsigned long int) n); if (n->level > 0) //it is not leaf -> destroy childs { for ( i = 0; i < Xastir_NODECARD; i++) { if ( n->branch[i].child ) { Xastir_RTreeDestroyNode ( n->branch[i].child ); } } } // Xastir_RTreeFreeNode( n ); } Xastir-Release-2.2.4/src/rtree/rect.c0000664000175000017500000002721215151324131016336 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include #include "assert.h" #include "index.h" #include #include #define BIG_NUM (FLT_MAX/4.0) #define Undefined(x) ((x)->boundary[0] > (x)->boundary[NUMDIMS]) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) /*----------------------------------------------------------------------------- | Initialize a rectangle to have all 0 coordinates. -----------------------------------------------------------------------------*/ void Xastir_RTreeInitRect(struct Rect *R) { register struct Rect *r = R; register int i; for (i=0; iboundary[i] = (RectReal)0; } } /*----------------------------------------------------------------------------- | Return a rect whose first low side is higher than its opposite side - | interpreted as an undefined rect. -----------------------------------------------------------------------------*/ struct Rect Xastir_RTreeNullRect(void) { struct Rect r; register int i; r.boundary[0] = (RectReal)1; r.boundary[NUMDIMS] = (RectReal)-1; for (i=1; iboundary[i] = drand48() * (1000-width); /* low side */ r->boundary[i + NUMDIMS] = r->boundary[i] + width; // high side } } /*----------------------------------------------------------------------------- | Fill in the boundaries for a random search rectangle. | Pass in a pointer to a rect that contains all the data, | and a pointer to the rect to be filled in. | Generated rect is centered randomly anywhere in the data area, | and has size from 0 to the size of the data area in each dimension, | i.e. search rect can stick out beyond data area. -----------------------------------------------------------------------------*/ void Xastir_RTreeSearchRect(struct Rect *Search, struct Rect *Data) { register struct Rect *search = Search, *data = Data; register int i, j; register RectReal size, center; assert(search); assert(data); for (i=0; iboundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) { size = (drand48() * (data->boundary[j] - data->boundary[i] + 1)) / 2; center = data->boundary[i] + drand48() * (data->boundary[j] - data->boundary[i] + 1); search->boundary[i] = center - size/2; search->boundary[j] = center + size/2; } else // some open boundary, search entire dimension { search->boundary[i] = -BIG_NUM; search->boundary[j] = BIG_NUM; } } } #endif /*----------------------------------------------------------------------------- | Print out the data for a rectangle. -----------------------------------------------------------------------------*/ void Xastir_RTreePrintRect(struct Rect *R, int depth) { register struct Rect *r = R; register int i; assert(r); Xastir_RTreeTabIn(depth); printf("rect:\n"); for (i = 0; i < NUMDIMS; i++) { Xastir_RTreeTabIn(depth+1); printf("%f\t%f\n", r->boundary[i], r->boundary[i + NUMDIMS]); } } /*----------------------------------------------------------------------------- | Calculate the n-dimensional volume of a rectangle -----------------------------------------------------------------------------*/ RectReal Xastir_RTreeRectVolume(struct Rect *R) { register struct Rect *r = R; register int i; register RectReal volume = (RectReal)1; assert(r); if (Undefined(r)) { return (RectReal)0; } for(i=0; iboundary[i+NUMDIMS] - r->boundary[i]; } assert(volume >= 0.0); return volume; } /*----------------------------------------------------------------------------- | Define the NUMDIMS-dimensional volume the unit sphere in that dimension into | the symbol "Xastir_UnitSphereVolume" | Note that if the gamma function is available in the math library and if the | compiler supports static initialization using functions, this is | easily computed for any dimension. If not, the value can be precomputed and | taken from a table. The following code can do it either way. -----------------------------------------------------------------------------*/ #ifdef gamma /* computes the volume of an N-dimensional sphere. */ /* derived from formule in "Regular Polytopes" by H.S.M Coxeter */ static double sphere_volume(double dimension) { static const double log_pi = log(3.1415926535); double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } static const double Xastir_UnitSphereVolume = sphere_volume(NUMDIMS); #else /* Precomputed volumes of the unit spheres for the first few dimensions */ const double Xastir_UnitSphereVolumes[] = { 0.000000, /* dimension 0 */ 2.000000, /* dimension 1 */ 3.141593, /* dimension 2 */ 4.188790, /* dimension 3 */ 4.934802, /* dimension 4 */ 5.263789, /* dimension 5 */ 5.167713, /* dimension 6 */ 4.724766, /* dimension 7 */ 4.058712, /* dimension 8 */ 3.298509, /* dimension 9 */ 2.550164, /* dimension 10 */ 1.884104, /* dimension 11 */ 1.335263, /* dimension 12 */ 0.910629, /* dimension 13 */ 0.599265, /* dimension 14 */ 0.381443, /* dimension 15 */ 0.235331, /* dimension 16 */ 0.140981, /* dimension 17 */ 0.082146, /* dimension 18 */ 0.046622, /* dimension 19 */ 0.025807, /* dimension 20 */ }; #if NUMDIMS > 20 # error "not enough precomputed sphere volumes" #endif #define Xastir_UnitSphereVolume Xastir_UnitSphereVolumes[NUMDIMS] #endif /*----------------------------------------------------------------------------- | Calculate the n-dimensional volume of the bounding sphere of a rectangle -----------------------------------------------------------------------------*/ #if 0 /* * A fast approximation to the volume of the bounding sphere for the * given Rect. By Paul B. */ RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R) { register struct Rect *r = R; register int i; RectReal maxsize=(RectReal)0, c_size; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[i+NUMDIMS] - r->boundary[i]; if (c_size > maxsize) { maxsize = c_size; } } return (RectReal)(pow(maxsize/2, NUMDIMS) * Xastir_UnitSphereVolume); } #endif /* * The exact volume of the bounding sphere for the given Rect. */ RectReal Xastir_RTreeRectSphericalVolume(struct Rect *R) { register struct Rect *r = R; register int i; register double sum_of_squares=0, radius; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[i+NUMDIMS] - r->boundary[i]) / 2; sum_of_squares += half_extent * half_extent; } radius = sqrt(sum_of_squares); return (RectReal)(pow(radius, NUMDIMS) * Xastir_UnitSphereVolume); } /*----------------------------------------------------------------------------- | Calculate the n-dimensional surface area of a rectangle -----------------------------------------------------------------------------*/ RectReal Xastir_RTreeRectSurfaceArea(struct Rect *R) { register struct Rect *r = R; register int i, j; register RectReal sum = (RectReal)0; assert(r); if (Undefined(r)) { return (RectReal)0; } for (i=0; iboundary[j+NUMDIMS] - r->boundary[j]; face_area *= j_extent; } sum += face_area; } return 2 * sum; } /*----------------------------------------------------------------------------- | Combine two rectangles, make one that includes both. -----------------------------------------------------------------------------*/ struct Rect Xastir_RTreeCombineRect(struct Rect *R, struct Rect *Rr) { register struct Rect *r = R, *rr = Rr; register int i, j; struct Rect new_rect; assert(r && rr); if (Undefined(r)) { return *rr; } if (Undefined(rr)) { return *r; } for (i = 0; i < NUMDIMS; i++) { new_rect.boundary[i] = MIN(r->boundary[i], rr->boundary[i]); j = i + NUMDIMS; new_rect.boundary[j] = MAX(r->boundary[j], rr->boundary[j]); } return new_rect; } /*----------------------------------------------------------------------------- | Decide whether two rectangles overlap. -----------------------------------------------------------------------------*/ int Xastir_RTreeOverlap(struct Rect *R, struct Rect *S) { register struct Rect *r = R, *s = S; register int i, j; assert(r && s); for (i=0; iboundary[i] > s->boundary[j] || s->boundary[i] > r->boundary[j]) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- | Decide whether rectangle r is contained in rectangle s. -----------------------------------------------------------------------------*/ int Xastir_RTreeContained(struct Rect *R, struct Rect *S) { register struct Rect *r = R, *s = S; register int i, j, result; assert(r && s); // undefined rect is contained in any other // if (Undefined(r)) { return TRUE; } // no rect (except an undefined one) is contained in an undef rect // if (Undefined(s)) { return FALSE; } result = TRUE; for (i = 0; i < NUMDIMS; i++) { j = i + NUMDIMS; /* index for high sides */ result = result && r->boundary[i] >= s->boundary[i] && r->boundary[j] <= s->boundary[j]; } return result; } Xastir-Release-2.2.4/src/rtree/sources.htm0000664000175000017500000000755515151324131017442 0ustar hibbyhibby Free Source Code
Free Source Code

Xastir note: This file is intended to point you at the original sources of the rtree implementation used in xastir.]

Here are a few useful bits of free source code. You're completely free to use them for any purpose whatsoever. All I ask is that if you find one to be particularly valuable, then consider sending a brief thank you note to the email address in the code comments. Enjoy.



C & C++ Code

R-Trees

Straight "C" implementation of Tony Gutman's R-Tree method, R-Trees provide Log(n) speed rectangular indexing into multi-dimensional data. Based on his original implementation, I've brought it up to date with ANCI specifications and added a nice improvement based on sphere volumes.

    Download R-Tree code

Skiplists

Skiplists are fast associative collections invented by William Pugh. Key/Value pairs are added to skiplist containers and can then values looked up extremely quickly by key. The implementation is based on a fairly generic one originally in "C" by Bruno Grossniklaus which I converted into a C++ class library.

    Download SkipList code

Quaternions

Implementation of a simple C++ quaternion class called "Squat". Popularized by a seminal paper by Ken Shoemake, a quaternion represents a rotation about an axis.  Squats can be concatenated together via the * and *= operators and converted back and forth between transformation matrices. Implementation also includes a wonderful 3D vector macro library by Don Hatch.

    Download Squat code

Polygon-Cube Intersection Testing

"C" implementation of an extremely fast and robust polygon-cube intersection test by Don Hatch and myself as published in Graphics Gems V. Very useful for collision detection and view frustum visibility checking.

    View the readme file
    Download PCube code
 
 

Back to the Superliminal home page.

Xastir-Release-2.2.4/src/rtree/sphvol.c0000664000175000017500000000551615151324131016717 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /* * SPHERE VOLUME * by Melinda Green * melinda@superliminal.com * * Calculates and prints the volumes of the unit hyperspheres for * dimensions zero through the given value, or 9 by default. * Prints in the form of a C array of double called sphere_volumes. * * From formule in "Regular Polytopes" by H.S.M Coxeter, the volume * of a hypersphere of dimension d is: * Pi^(d/2) / gamma(d/2 + 1) * * This implementation works by first computing the log of the above * function and then returning the exp of that value in order to avoid * instabilities due to the huge values that the real gamma function * would return. * * Multiply the output volumes by R^n to get the volume of an n * dimensional sphere of radius R. */ #include #include #ifndef M_PI #define M_PI 3.1415926535 #endif static void print_volume(int dimension, double volume) { printf("\t%.6f, /* dimension %3d */\n", volume, dimension); } static double sphere_volume(double dimension) { const double log_pi = log(M_PI); double log_gamma, log_volume; log_gamma = gamma(dimension/2.0 + 1); log_volume = dimension/2.0 * log_pi - log_gamma; return exp(log_volume); } extern int main(int argc, char *argv[]) { int dim, max_dims=9; if(2 == argc) { max_dims = atoi(argv[1]); } printf("static const double sphere_volumes[] = {\n"); for(dim=0; dim #include "assert.h" #include "index.h" #include "card.h" #include "split_l.h" /*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void Xastir_RTreeGetBranches(struct Node *N, struct Branch *B) { register struct Node *n = N; register struct Branch *b = B; register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; ibranch[i].child); /* every entry should be full */ Xastir_BranchBuf[i] = n->branch[i]; } Xastir_BranchBuf[MAXKIDS(n)] = *b; Xastir_BranchCount = MAXKIDS(n) + 1; /* calculate rect containing all in the set */ Xastir_CoverSplit = Xastir_BranchBuf[0].rect; for (i=1; icount[0] = p->count[1] = 0; p->total = maxrects; p->minfill = minfill; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | Put a branch in one of the groups. -----------------------------------------------------------------------------*/ static void Xastir_RTreeClassify(int i, int group, struct PartitionVars *p) { assert(p); assert(!p->taken[i]); p->partition[i] = group; p->taken[i] = TRUE; if (p->count[group] == 0) { p->cover[group] = Xastir_BranchBuf[i].rect; } else p->cover[group] = Xastir_RTreeCombineRect(&Xastir_BranchBuf[i].rect, &p->cover[group]); p->area[group] = Xastir_RTreeRectSphericalVolume(&p->cover[group]); p->count[group]++; } /*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that are separated most along any dimension, or overlap least. | Distance for separation or overlap is measured modulo the width of the | space covered by the entire set along that dimension. -----------------------------------------------------------------------------*/ static void Xastir_RTreePickSeeds(struct PartitionVars *P) { register struct PartitionVars *p = P; register int i, dim, high; register struct Rect *r, *rlow, *rhigh; // Original superliminal.com implementation had no initializers here. // They are not strictly necessary, as the variables are initialized // in the first iteration of the first for loop, but GCC complains // anyway. Initializers added to keep it happy. register float w, separation, bestSep=0.0; RectReal width[NUMDIMS]; int leastUpper[NUMDIMS], greatestLower[NUMDIMS]; int seed0=0, seed1=0; assert(p); for (dim=0; dimboundary[dim] > Xastir_BranchBuf[greatestLower[dim]].rect.boundary[dim]) { greatestLower[dim] = i; } if (r->boundary[high] < Xastir_BranchBuf[leastUpper[dim]].rect.boundary[high]) { leastUpper[dim] = i; } } /* find width of the whole collection along this dimension */ width[dim] = Xastir_CoverSplit.boundary[high] - Xastir_CoverSplit.boundary[dim]; } /* pick the best separation dimension and the two seed rects */ for (dim=0; dim= 0); if (width[dim] == 0) { w = (RectReal)1; } else { w = width[dim]; } rlow = &Xastir_BranchBuf[leastUpper[dim]].rect; rhigh = &Xastir_BranchBuf[greatestLower[dim]].rect; if (dim == 0) { seed0 = leastUpper[0]; seed1 = greatestLower[0]; separation = bestSep = (rhigh->boundary[0] - rlow->boundary[NUMDIMS]) / w; } else { separation = (rhigh->boundary[dim] - rlow->boundary[dim+NUMDIMS]) / w; if (separation > bestSep) { seed0 = leastUpper[dim]; seed1 = greatestLower[dim]; bestSep = separation; } } } if (seed0 != seed1) { Xastir_RTreeClassify(seed0, 0, p); Xastir_RTreeClassify(seed1, 1, p); } } /*----------------------------------------------------------------------------- | Put each rect that is not already in a group into a group. | Process one rect at a time, using the following hierarchy of criteria. | In case of a tie, go to the next test. | 1) If one group already has the max number of elements that will allow | the minimum fill for the other group, put r in the other. | 2) Put r in the group whose cover will expand less. This automatically | takes care of the case where one group cover contains r. | 3) Put r in the group whose cover will be smaller. This takes care of the | case where r is contained in both covers. | 4) Put r in the group with fewer elements. | 5) Put in group 1 (arbitrary). | | Also update the covers for both groups. -----------------------------------------------------------------------------*/ static void Xastir_RTreePigeonhole(struct PartitionVars *P) { register struct PartitionVars *p = P; struct Rect newCover[2]; register int i, group; RectReal newArea[2], increase[2]; for (i=0; itaken[i]) { /* if one group too full, put rect in the other */ if (p->count[0] >= p->total - p->minfill) { Xastir_RTreeClassify(i, 1, p); continue; } else if (p->count[1] >= p->total - p->minfill) { Xastir_RTreeClassify(i, 0, p); continue; } /* find areas of the two groups' old and new covers */ for (group=0; group<2; group++) { if (p->count[group]>0) newCover[group] = Xastir_RTreeCombineRect( &Xastir_BranchBuf[i].rect, &p->cover[group]); else { newCover[group] = Xastir_BranchBuf[i].rect; } newArea[group] = Xastir_RTreeRectSphericalVolume( &newCover[group]); increase[group] = newArea[group]-p->area[group]; } /* put rect in group whose cover will expand less */ if (increase[0] < increase[1]) { Xastir_RTreeClassify(i, 0, p); } else if (increase[1] < increase[0]) { Xastir_RTreeClassify(i, 1, p); } /* put rect in group that will have a smaller cover */ else if (p->area[0] < p->area[1]) { Xastir_RTreeClassify(i, 0, p); } else if (p->area[1] < p->area[0]) { Xastir_RTreeClassify(i, 1, p); } /* put rect in group with fewer elements */ else if (p->count[0] < p->count[1]) { Xastir_RTreeClassify(i, 0, p); } else { Xastir_RTreeClassify(i, 1, p); } } } assert(p->count[0] + p->count[1] == Xastir_NODECARD + 1); } /*----------------------------------------------------------------------------- | Method 0 for finding a partition: | First find two seeds, one for each group, well separated. | Then put other rects in whichever group will be smallest after addition. -----------------------------------------------------------------------------*/ static void Xastir_RTreeMethodZero(struct PartitionVars *p, int minfill) { Xastir_RTreeInitPVars(p, Xastir_BranchCount, minfill); Xastir_RTreePickSeeds(p); Xastir_RTreePigeonhole(p); } /*----------------------------------------------------------------------------- | Copy branches from the buffer into two nodes according to the partition. -----------------------------------------------------------------------------*/ static void Xastir_RTreeLoadNodes(struct Node *N, struct Node *Q, struct PartitionVars *P) { register struct Node *n = N, *q = Q; register struct PartitionVars *p = P; register int i; assert(n); assert(q); assert(p); for (i=0; ipartition[i] == 0) { Xastir_RTreeAddBranch(&Xastir_BranchBuf[i], n, NULL); } else if (p->partition[i] == 1) { Xastir_RTreeAddBranch(&Xastir_BranchBuf[i], q, NULL); } else { assert(FALSE); } } } /*----------------------------------------------------------------------------- | Split a node. | Divides the nodes branches and the extra one between two nodes. | Old node is one of the new ones, and one really new one is created. -----------------------------------------------------------------------------*/ void Xastir_RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; // This variable is declared, assigned a value, then never used. // Newer GCCs warn about that. Shut them up. // RectReal area; assert(n); assert(b); /* load all the branches into a buffer, initialize old node */ level = n->level; Xastir_RTreeGetBranches(n, b); /* find partition */ p = &Xastir_Partitions[0]; /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */ Xastir_RTreeMethodZero(p, level>0 ? MinNodeFill : MinLeafFill); /* record how good the split was for statistics */ // This variable is declared, assigned a value, then never used. // Newer GCCs warn about that. Shut them up. // area = p->area[0] + p->area[1]; /* put branches from buffer in 2 nodes according to chosen partition */ *nn = Xastir_RTreeNewNode(); (*nn)->level = n->level = level; Xastir_RTreeLoadNodes(n, *nn, p); assert(n->count + (*nn)->count == Xastir_NODECARD+1); } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ // This is not used at the moment, and because it's declared static gcc // warns us it's not used. Commented out to shut gcc up #if 0 static void Xastir_RTreePrintPVars(struct PartitionVars *p) { int i; assert(p); printf("\npartition:\n"); for (i=0; itaken[i]) { printf(" t\t"); } else { printf("\t"); } } printf("\n"); for (i=0; ipartition[i]); } printf("\n"); printf("count[0] = %d area = %f\n", p->count[0], p->area[0]); printf("count[1] = %d area = %f\n", p->count[1], p->area[1]); printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], Xastir_RTreeRectSphericalVolume(&Xastir_CoverSplit)/(p->area[0]+p->area[1])); printf("cover[0]:\n"); Xastir_RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); Xastir_RTreePrintRect(&p->cover[1], 0); } #endif // shut up GCC Xastir-Release-2.2.4/src/rtree/split_l.h0000664000175000017500000000357715151324131017064 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /*----------------------------------------------------------------------------- | Definitions and global variables used in linear split code. -----------------------------------------------------------------------------*/ #define METHODS 1 struct Branch Xastir_BranchBuf[MAXCARD+1]; int Xastir_BranchCount; struct Rect Xastir_CoverSplit; /* variables for finding a partition */ struct PartitionVars { int partition[MAXCARD+1]; int total, minfill; int taken[MAXCARD+1]; int count[2]; struct Rect cover[2]; RectReal area[2]; } Xastir_Partitions[METHODS]; Xastir-Release-2.2.4/src/rtree/split_q.c0000664000175000017500000002361315151324131017055 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ #include #include "assert.h" #include "index.h" #include "card.h" #include "split_q.h" /*----------------------------------------------------------------------------- | Load branch buffer with branches from full node plus the extra branch. -----------------------------------------------------------------------------*/ static void RTreeGetBranches(struct Node *n, struct Branch *b) { register int i; assert(n); assert(b); /* load the branch buffer */ for (i=0; ibranch[i].child); /* n should have every entry full */ BranchBuf[i] = n->branch[i]; } BranchBuf[MAXKIDS(n)] = *b; BranchCount = MAXKIDS(n) + 1; /* calculate rect containing all in the set */ CoverSplit = BranchBuf[0].rect; for (i=1; itaken[i]); p->partition[i] = group; p->taken[i] = TRUE; if (p->count[group] == 0) { p->cover[group] = BranchBuf[i].rect; } else p->cover[group] = RTreeCombineRect(&BranchBuf[i].rect, &p->cover[group]); p->area[group] = RTreeRectSphericalVolume(&p->cover[group]); p->count[group]++; } /*----------------------------------------------------------------------------- | Pick two rects from set to be the first elements of the two groups. | Pick the two that waste the most area if covered by a single rectangle. -----------------------------------------------------------------------------*/ static void RTreePickSeeds(struct PartitionVars *p) { register int i, j, seed0, seed1; RectReal worst, waste, area[MAXCARD+1]; for (i=0; itotal; i++) { area[i] = RTreeRectSphericalVolume(&BranchBuf[i].rect); } worst = -CoverSplitArea - 1; for (i=0; itotal-1; i++) { for (j=i+1; jtotal; j++) { struct Rect one_rect = RTreeCombineRect( &BranchBuf[i].rect, &BranchBuf[j].rect); waste = RTreeRectSphericalVolume(&one_rect) - area[i] - area[j]; if (waste > worst) { worst = waste; seed0 = i; seed1 = j; } } } RTreeClassify(seed0, 0, p); RTreeClassify(seed1, 1, p); } /*----------------------------------------------------------------------------- | Copy branches from the buffer into two nodes according to the partition. -----------------------------------------------------------------------------*/ static void RTreeLoadNodes(struct Node *n, struct Node *q, struct PartitionVars *p) { register int i; assert(n); assert(q); assert(p); for (i=0; itotal; i++) { assert(p->partition[i] == 0 || p->partition[i] == 1); if (p->partition[i] == 0) { RTreeAddBranch(&BranchBuf[i], n, NULL); } else if (p->partition[i] == 1) { RTreeAddBranch(&BranchBuf[i], q, NULL); } } } /*----------------------------------------------------------------------------- | Initialize a PartitionVars structure. -----------------------------------------------------------------------------*/ static void RTreeInitPVars(struct PartitionVars *p, int maxrects, int minfill) { register int i; assert(p); p->count[0] = p->count[1] = 0; p->cover[0] = p->cover[1] = RTreeNullRect(); p->area[0] = p->area[1] = (RectReal)0; p->total = maxrects; p->minfill = minfill; for (i=0; itaken[i] = FALSE; p->partition[i] = -1; } } /*----------------------------------------------------------------------------- | Print out data for a partition from PartitionVars struct. -----------------------------------------------------------------------------*/ static void RTreePrintPVars(struct PartitionVars *p) { register int i; assert(p); printf("\npartition:\n"); for (i=0; itotal; i++) { printf("%3d\t", i); } printf("\n"); for (i=0; itotal; i++) { if (p->taken[i]) { printf(" t\t"); } else { printf("\t"); } } printf("\n"); for (i=0; itotal; i++) { printf("%3d\t", p->partition[i]); } printf("\n"); printf("count[0] = %d area = %f\n", p->count[0], p->area[0]); printf("count[1] = %d area = %f\n", p->count[1], p->area[1]); if (p->area[0] + p->area[1] > 0) { printf("total area = %f effectiveness = %3.2f\n", p->area[0] + p->area[1], (float)CoverSplitArea / (p->area[0] + p->area[1])); } printf("cover[0]:\n"); RTreePrintRect(&p->cover[0], 0); printf("cover[1]:\n"); RTreePrintRect(&p->cover[1], 0); } /*----------------------------------------------------------------------------- | Method #0 for choosing a partition: | As the seeds for the two groups, pick the two rects that would waste the | most area if covered by a single rectangle, i.e. evidently the worst pair | to have in the same group. | Of the remaining, one at a time is chosen to be put in one of the two groups. | The one chosen is the one with the greatest difference in area expansion | depending on which group - the rect most strongly attracted to one group | and repelled from the other. | If one group gets too full (more would force other group to violate min | fill requirement) then other group gets the rest. | These last are the ones that can go in either group most easily. -----------------------------------------------------------------------------*/ static void RTreeMethodZero(struct PartitionVars *p, int minfill) { register int i; RectReal biggestDiff; register int group, chosen, betterGroup; assert(p); RTreeInitPVars(p, BranchCount, minfill); RTreePickSeeds(p); while (p->count[0] + p->count[1] < p->total && p->count[0] < p->total - p->minfill && p->count[1] < p->total - p->minfill) { biggestDiff = (RectReal)-1.; for (i=0; itotal; i++) { if (!p->taken[i]) { struct Rect *r, rect_0, rect_1; RectReal growth0, growth1, diff; r = &BranchBuf[i].rect; rect_0 = RTreeCombineRect(r, &p->cover[0]); rect_1 = RTreeCombineRect(r, &p->cover[1]); growth0 = RTreeRectSphericalVolume( &rect_0)-p->area[0]; growth1 = RTreeRectSphericalVolume( &rect_1)-p->area[1]; diff = growth1 - growth0; if (diff >= 0) { group = 0; } else { group = 1; diff = -diff; } if (diff > biggestDiff) { biggestDiff = diff; chosen = i; betterGroup = group; } else if (diff==biggestDiff && p->count[group]count[betterGroup]) { chosen = i; betterGroup = group; } } } RTreeClassify(chosen, betterGroup, p); } /* if one group too full, put remaining rects in the other */ if (p->count[0] + p->count[1] < p->total) { if (p->count[0] >= p->total - p->minfill) { group = 1; } else { group = 0; } for (i=0; itotal; i++) { if (!p->taken[i]) { RTreeClassify(i, group, p); } } } assert(p->count[0] + p->count[1] == p->total); assert(p->count[0] >= p->minfill && p->count[1] >= p->minfill); } /*----------------------------------------------------------------------------- | Split a node. | Divides the nodes branches and the extra one between two nodes. | Old node is one of the new ones, and one really new one is created. | Tries more than one method for choosing a partition, uses best result. -----------------------------------------------------------------------------*/ extern void RTreeSplitNode(struct Node *n, struct Branch *b, struct Node **nn) { register struct PartitionVars *p; register int level; assert(n); assert(b); /* load all the branches into a buffer, initialize old node */ level = n->level; RTreeGetBranches(n, b); /* find partition */ p = &Partitions[0]; /* Note: can't use MINFILL(n) below since n was cleared by GetBranches() */ RTreeMethodZero(p, level>0 ? MinNodeFill : MinLeafFill); /* * put branches from buffer into 2 nodes * according to chosen partition */ *nn = RTreeNewNode(); (*nn)->level = n->level = level; RTreeLoadNodes(n, *nn, p); assert(n->count+(*nn)->count == p->total); } Xastir-Release-2.2.4/src/rtree/split_q.h0000664000175000017500000000354115151324131017060 0ustar hibbyhibby/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /**************************************************************************** * MODULE: R-Tree library * * AUTHOR(S): Antonin Guttman - original code * Melinda Green (melinda@superliminal.com) - major clean-up * and implementation of bounding spheres * * PURPOSE: Multidimensional index * */ /*----------------------------------------------------------------------------- | Definitions and global variables. -----------------------------------------------------------------------------*/ #define METHODS 1 struct Branch BranchBuf[MAXCARD+1]; int BranchCount; struct Rect CoverSplit; RectReal CoverSplitArea; /* variables for finding a partition */ struct PartitionVars { int partition[MAXCARD+1]; int total, minfill; int taken[MAXCARD+1]; int count[2]; struct Rect cover[2]; RectReal area[2]; } Partitions[METHODS]; Xastir-Release-2.2.4/src/shp_hash.c0000664000175000017500000002104115151324131016047 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #ifdef HAVE_LIBSHP #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #include #include "xastir.h" #include "globals.h" #include "util.h" #include "hashtable.h" #include "hashtable_itr.h" /// THIS ONLY FOR DEBUGGING! //#include "hashtable_private.h" #include "shp_hash.h" #include "snprintf.h" // Must be last include file #include "leak_detection.h" #define PURGE_PERIOD 3600 // One hour, hard coded for now. // This should be in a slider in the timing // configuration instead. //#define PURGE_PERIOD 120 // debugging static struct hashtable *shp_hash=NULL; static time_t purge_time; #define SHP_HASH_SIZE 65535 unsigned int shape_hash_from_key(void *key) { char *str=(char *)key; unsigned int shphash=5381; int c; int i=0; while (str[i]!='\0') { c=str[i++]; shphash = ((shphash << 5) + shphash)^c; } return (shphash); } int shape_keys_equal(void *key1, void *key2) { if (strncmp((char *)key1,(char *)key2,strlen((char *)key1))==0) { return(1); } else { return(0); } } void init_shp_hash(int clobber) { // make sure we don't leak if (shp_hash) { if (clobber) { hashtable_destroy(shp_hash, 1); shp_hash=create_hashtable(SHP_HASH_SIZE, shape_hash_from_key, shape_keys_equal); } } else { shp_hash=create_hashtable(SHP_HASH_SIZE, shape_hash_from_key, shape_keys_equal); } // Now set the static timer value to the next time we need to run the purge // routine purge_time = sec_now() + PURGE_PERIOD; } // destructor for a single shapeinfo structure void destroy_shpinfo(shpinfo *si) { if (si) { empty_shpinfo(si); free(si); } } // free the pointers in a shapinfo object void empty_shpinfo(shpinfo *si) { if (si) { if (si->root) { Xastir_RTreeDestroyNode(si->root); si->root=NULL; } // The hashtable functions free the // key, which is in our case the filename. So since we're only going // to empty the shpinfo when we're removing from the hashtable, we // must not free the filename in si->filename ourselves. } } void destroy_shp_hash(void) { struct hashtable_itr *iterator=NULL; shpinfo *si; int ret; if (shp_hash) { // walk through the hashtable, free any pointers in the values // that aren't null, or we'll leak like a sieve. // the hashtable functions always attempt to dereference iterator, // and don't check if you give it a null, but will return null if // there's nothing in the table. Grrrr. iterator=hashtable_iterator(shp_hash); do { ret=0; if (iterator) { si = hashtable_iterator_value(iterator); if (si) { empty_shpinfo(si); } ret=hashtable_iterator_advance(iterator); } } while (ret); hashtable_destroy(shp_hash, 1); // destroy the hashtable, freeing // what's left of the entries shp_hash=NULL; if (iterator) { free(iterator); } } } void add_shp_to_hash(char *filename, SHPHandle sHP) { // This function does NOT check whether there already is something in // the hashtable that matches. // Check that before calling this routine. shpinfo *temp; int filenm_len; filenm_len=strlen(filename); if (!shp_hash) // no table to add to { init_shp_hash(1); // so create one } temp = (shpinfo *)malloc(sizeof(shpinfo)); CHECKMALLOC(temp); // leave room for terminator temp->filename = (char *) malloc(sizeof(char)*(filenm_len+1)); CHECKMALLOC(temp->filename); strncpy(temp->filename,filename,filenm_len+1); temp->filename[filenm_len]='\0'; // just to be safe // xastir_snprintf(temp->filename,sizeof(shpinfo),"%s",filename); temp->root = Xastir_RTreeNewIndex(); temp->creation = sec_now(); temp->last_access = temp->creation; build_rtree(&(temp->root),sHP); if (!hashtable_insert(shp_hash,temp->filename,temp)) { fprintf(stderr,"Insert failed on shapefile hash --- fatal\n"); free(temp->filename); free(temp); exit(1); } } shpinfo *get_shp_from_hash(char *filename) { shpinfo *result; if (!shp_hash) // no table to search { init_shp_hash(1); // so create one return NULL; } result=hashtable_search(shp_hash,filename); // If there is one, we have now accessed it, so bump the last access time if (result) { result->last_access = sec_now(); } return (result); } //CAREFUL: note how adding things to the tree can change the root // Must not ever use cache a value of the root pointer if there's any // chance that the tree needs to be expanded! void build_rtree (struct Node **root, SHPHandle sHP) { int nEntities; intptr_t i; SHPObject *psCShape; struct Rect bbox_shape; SHPGetInfo(sHP, &nEntities, NULL, NULL, NULL); for( i = 0; i < nEntities; i++ ) { psCShape = SHPReadObject ( sHP, i ); if (psCShape != NULL) { bbox_shape.boundary[0]=(RectReal) psCShape->dfXMin; bbox_shape.boundary[1]=(RectReal) psCShape->dfYMin; bbox_shape.boundary[2]=(RectReal) psCShape->dfXMax; bbox_shape.boundary[3]=(RectReal) psCShape->dfYMax; SHPDestroyObject ( psCShape ); // Only insert the rect if it will not fail the assertion in // Xastir_RTreeInsertRect --- this will cause us to ignore any shapes that // have invalid bboxes (or that return invalid bboxes from shapelib // for whatever reason if (bbox_shape.boundary[0] <= bbox_shape.boundary[2] && bbox_shape.boundary[1] <= bbox_shape.boundary[3]) { Xastir_RTreeInsertRect(&bbox_shape, (void *)(i+1), root, 0); } } } } void purge_shp_hash(time_t secs_now) { struct hashtable_itr *iterator=NULL; shpinfo *si; int ret; if (secs_now > purge_time) // Time to purge { purge_time += PURGE_PERIOD; if (shp_hash) { // walk through the hash table and kill entries that are old iterator=hashtable_iterator(shp_hash); do { ret=0; if (iterator) // must check this, because could be null { // if the iterator malloc failed si=hashtable_iterator_value(iterator); if (si) { if (secs_now > si->last_access+PURGE_PERIOD) { // this is stale, hasn't been accessed in a while ret=hashtable_iterator_remove(iterator); // Important that we NOT do the // destroy first, because we've used // the filename pointer field of the // structure as the key, and the // remove function will free that. If // we clobber the struct first, we // invite segfaults destroy_shpinfo(si); } else { ret=hashtable_iterator_advance(iterator); } } } } while (ret); // we're now done with the iterator. Free it to stop us from // leaking! if (iterator) { free(iterator); } } } } #endif // HAVE_LIBSHP // To get rid of "-pedantic" compiler warning: int NON_EMPTY_SOURCE_FILE; Xastir-Release-2.2.4/src/shp_hash.h0000664000175000017500000000152115151324131016055 0ustar hibbyhibby // Copyright (C) 2000-2026 The Xastir Group #ifndef __XASTIR_SHP_HASH_H #define __XASTIR_SHP_HASH_H #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H typedef struct _shpinfo { char *filename; struct Node* root; time_t creation; time_t last_access; int num_accesses; } shpinfo; void init_shp_hash(int clobber); void add_shp_to_hash(char *filename,SHPHandle sHP); void build_rtree(struct Node **root, SHPHandle sHP); void destroy_shp_hash(void); void empty_shpinfo(shpinfo *si); void destroy_shpinfo(shpinfo *si); void purge_shp_hash(time_t secs_now); shpinfo *get_shp_from_hash(char *filename); #endif // __XASTIR_SHP_HASH_H Xastir-Release-2.2.4/src/snprintf.c0000664000175000017500000004760515151324131016133 0ustar hibbyhibby/* * snprintf.c - a portable implementation of snprintf and vsnprintf * */ /* * Portions Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ /************************************************************** * Original: * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 * A bombproof version of doprnt (dopr) included. * Sigh. This sort of thing is always nasty do deal with. Note that * the version here does not include floating point... * * snprintf() is used instead of sprintf() as it does limit checks * for string length. This covers a nasty loophole. * * The other functions are there to prevent NULL pointers from * causing nast effects. * * More Recently: * Brandon Long 9/15/96 for mutt 0.43 * This was ugly. It is still ugly. I opted out of floating point * numbers, but the formatter understands just about everything * from the normal C string format, at least as far as I can tell from * the Solaris 2.5 printf(3S) man page. * * Brandon Long 10/22/97 for mutt 0.87.1 * Ok, added some minimal floating point support, which means this * probably requires libm on most operating systems. Don't yet * support the exponent (e,E) and sigfig (g,G). Also, fmtint() * was pretty badly broken, it just wasn't being exercised in ways * which showed it, so that's been fixed. Also, formated the code * to mutt conventions, and removed dead code left over from the * original. Also, there is now a builtin-test, just compile with: * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm * and run snprintf for results. * * Thomas Roessler 01/27/98 for mutt 0.89i * The PGP code was using unsigned hexadecimal formats. * Unfortunately, unsigned formats simply didn't work. * * Michael Elkins 03/05/98 for mutt 0.90.8 * The original code assumed that both snprintf() and vsnprintf() were * missing. Some systems only have snprintf() but not vsnprintf(), so * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. * * Andrew Tridgell (tridge@samba.org) Oct 1998 * fixed handling of %.0f * added test for HAVE_LONG_DOUBLE * * **************************************************************/ #include #include #include #ifndef HAVE_VSNPRINTF /* varargs declarations: */ #if defined(__STDC__) #ifdef HAVE_STDARG_H #include #else // HAVE_STDARG_H #ifdef HAVE_STD_ARGS_H #include #endif // HAVE_STD_ARGS_H #endif // HAVE_STDARG_H #include #define HAVE_STDARGS /* let's hope that works everywhere (mj) */ #define VA_LOCAL_DECL va_list ap #define VA_START(f) va_start(ap, f) #define VA_SHIFT(v,t); /* no-op for ANSI */ #define VA_END va_end(ap) #else // __STDC__ #include #undef HAVE_STDARGS #define VA_LOCAL_DECL va_list ap #define VA_START(f) va_start(ap) /* f is ignored! */ #define VA_SHIFT(v,t) v = va_arg(ap,t) #define VA_END va_end(ap) #endif // __STDC__ // Must be last include file #include "leak_detection.h" #ifdef HAVE_LONG_DOUBLE #define LDOUBLE long double #else // HAVE_LONG_DOUBLE #define LDOUBLE double #endif // HAVE_LONG_DOUBLE static void dopr(char *buffer, size_t maxlen, const char *format, va_list args); static void fmtstr(char *buffer, size_t * currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t * currlen, size_t maxlen, long value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t * currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c); /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_SHORT 1 #define DP_C_LONG 2 #define DP_C_LDOUBLE 3 #define char_to_int(p) (p - '0') #define MAX(p, q) ((p >= q) ? p : q) static void dopr(char *buffer, size_t maxlen, const char *format, va_list args) { char ch; long value; LDOUBLE fvalue; char *strvalue; int min; int max; int state; int flags; int cflags; size_t currlen; state = DP_S_DEFAULT; currlen = flags = cflags = min = 0; max = -1; ch = *format++; while (state != DP_S_DONE) { if ((ch == '\0') || (currlen >= maxlen)) { state = DP_S_DONE; } switch (state) { case DP_S_DEFAULT: if (ch == '%') { state = DP_S_FLAGS; } else { dopr_outch(buffer, &currlen, maxlen, ch); } ch = *format++; break; case DP_S_FLAGS: switch (ch) { case '-': flags |= DP_F_MINUS; ch = *format++; break; case '+': flags |= DP_F_PLUS; ch = *format++; break; case ' ': flags |= DP_F_SPACE; ch = *format++; break; case '#': flags |= DP_F_NUM; ch = *format++; break; case '0': flags |= DP_F_ZERO; ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit(ch)) { min = 10 * min + char_to_int(ch); ch = *format++; } else if (ch == '*') { min = va_arg(args, int); ch = *format++; state = DP_S_DOT; } else { state = DP_S_DOT; } break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else { state = DP_S_MOD; } break; case DP_S_MAX: if (isdigit(ch)) { if (max < 0) { max = 0; } max = 10 * max + char_to_int(ch); ch = *format++; } else if (ch == '*') { max = va_arg(args, int); ch = *format++; state = DP_S_MOD; } else { state = DP_S_MOD; } break; case DP_S_MOD: /* Currently, we don't support Long Long, bummer */ switch (ch) { case 'h': cflags = DP_C_SHORT; ch = *format++; break; case 'l': cflags = DP_C_LONG; ch = *format++; break; case 'L': cflags = DP_C_LDOUBLE; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: switch (ch) { case 'd': case 'i': if (cflags == DP_C_SHORT) { value = va_arg(args, short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, long int); } else { value = va_arg(args, int); } fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; case 'x': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) { value = va_arg(args, unsigned short int); } else if (cflags == DP_C_LONG) { value = va_arg(args, unsigned long int); } else { value = va_arg(args, unsigned int); } fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } /* um, floating point? */ fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; case 'e': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } break; case 'G': flags |= DP_F_UP; case 'g': if (cflags == DP_C_LDOUBLE) { fvalue = va_arg(args, LDOUBLE); } else { fvalue = va_arg(args, double); } break; case 'c': dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); break; case 's': strvalue = va_arg(args, char *); if (max < 0) { max = maxlen; /* ie, no max */ } fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); break; case 'p': strvalue = va_arg(args, void *); fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) { short int *num; num = va_arg(args, short int *); *num = currlen; } else if (cflags == DP_C_LONG) { long int *num; num = va_arg(args, long int *); *num = currlen; } else { int *num; num = va_arg(args, int *); *num = currlen; } break; case '%': dopr_outch(buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ ch = *format++; break; default: /* Unknown, skip */ break; } ch = *format++; state = DP_S_DEFAULT; flags = cflags = min = 0; max = -1; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } if (currlen < maxlen - 1) { buffer[currlen] = '\0'; } else { buffer[maxlen - 1] = '\0'; } } static void fmtstr(char *buffer, size_t * currlen, size_t maxlen, char *value, int flags, int min, int max) { int padlen, strln; /* amount to pad */ int cnt = 0; if (value == 0) { value = ""; } for (strln = 0; value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) { padlen = 0; } if (flags & DP_F_MINUS) { padlen = -padlen; /* Left Justify */ } while ((padlen > 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; ++cnt; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t * currlen, size_t maxlen, long value, int base, int min, int max, int flags) { int signvalue = 0; unsigned long uvalue; char convert[20]; int place = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ int caps = 0; if (max < 0) { max = 0; } uvalue = value; if (!(flags & DP_F_UNSIGNED)) { if (value < 0) { signvalue = '-'; uvalue = -value; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ { signvalue = '+'; } else if (flags & DP_F_SPACE) { signvalue = ' '; } } if (flags & DP_F_UP) { caps = 1; /* Should characters be upper case? */ } do { convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [uvalue % (unsigned) base]; uvalue = (uvalue / (unsigned) base); } while (uvalue && (place < 20)); if (place == 20) { place--; } convert[place] = 0; zpadlen = max - place; spadlen = min - MAX(max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) { zpadlen = 0; } if (spadlen < 0) { spadlen = 0; } if (flags & DP_F_ZERO) { zpadlen = MAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) { spadlen = -spadlen; /* Left Justifty */ } #ifdef DEBUG_SNPRINTF dprint(1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", zpadlen, spadlen, min, max, place)); #endif // DEBUG_SNPRINTF /* Spaces */ while (spadlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); } /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) { dopr_outch(buffer, currlen, maxlen, convert[--place]); } /* Left Justified spaces */ while (spadlen < 0) { dopr_outch(buffer, currlen, maxlen, ' '); ++spadlen; } } static LDOUBLE abs_val(LDOUBLE value) { LDOUBLE result = value; if (value < 0) { result = -value; } return result; } static LDOUBLE pow10(int exp) { LDOUBLE result = 1; while (exp) { result *= 10; exp--; } return result; } static long round(LDOUBLE value) { long intpart; intpart = value; value = value - intpart; if (value >= 0.5) { intpart++; } return intpart; } static void fmtfp(char *buffer, size_t * currlen, size_t maxlen, LDOUBLE fvalue, int min, int max, int flags) { int signvalue = 0; LDOUBLE ufvalue; char iconvert[20]; char fconvert[20]; int iplace = 0; int fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0; int caps = 0; long intpart; long fracpart; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) { max = 6; } ufvalue = abs_val(fvalue); if (fvalue < 0) { signvalue = '-'; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ { signvalue = '+'; } else if (flags & DP_F_SPACE) { signvalue = ' '; } #if 0 if (flags & DP_F_UP) { caps = 1; /* Should characters be upper case? */ } #endif // 0 intpart = ufvalue; /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) { max = 9; } /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ fracpart = round((pow10(max)) * (ufvalue - intpart)); if (fracpart >= pow10(max)) { intpart++; fracpart -= pow10(max); } /* Convert integer part */ do { iconvert[iplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10]; intpart = (intpart / 10); } while (intpart && (iplace < 20)); if (iplace == 20) { iplace--; } iconvert[iplace] = 0; /* Convert fractional part */ do { fconvert[fplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10]; fracpart = (fracpart / 10); } while (fracpart && (fplace < 20)); if (fplace == 20) { fplace--; } fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) { zpadlen = 0; } if (padlen < 0) { padlen = 0; } if (flags & DP_F_MINUS) { padlen = -padlen; /* Left Justifty */ } if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); } while (iplace > 0) { dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); } /* * Decimal point. This should probably use locale to find the correct * char to print out. */ if (max > 0) { dopr_outch(buffer, currlen, maxlen, '.'); while (fplace > 0) { dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); } } while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, char c) { if (*currlen < maxlen) { buffer[(*currlen)++] = c; } } int xastir_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { str[0] = 0; dopr(str, count, fmt, args); return (strlen(str)); } #endif /* !HAVE_VSNPRINTF */ #ifndef HAVE_SNPRINTF #ifdef HAVE_STDARGS int xastir_snprintf(char *str, size_t count, const char *fmt, ...) #else // HAVE_STDARGS int xastir_snprintf(va_alist) va_dcl #endif // HAVE_STDARGS { # ifndef HAVE_STDARGS char *str; size_t count; char *fmt; # endif // HAVE_STDARGS VA_LOCAL_DECL; VA_START(fmt); VA_SHIFT(str, char *); VA_SHIFT(count, size_t); VA_SHIFT(fmt, char *); (void) xastir_vsnprintf(str, count, fmt, ap); VA_END; return (strlen(str)); } #endif /* !HAVE_SNPRINTF */ Xastir-Release-2.2.4/src/snprintf.h0000664000175000017500000000324215151324131016125 0ustar hibbyhibby/* * snprintf.h * header file for snprintf.c * */ /* * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _XASTIR_COMPAT_SNPRINTF_H_ #define _XASTIR_COMPAT_SNPRINTF_H_ #include #include "config.h" #ifdef HAVE_STDARG_H #include #endif // HAVE_STDARG_H /* Use the system libraries version of vsnprintf() if available. Otherwise * use our own. */ #ifndef HAVE_VSNPRINTF int xastir_vsnprintf(char *str, size_t count, const char *fmt, va_list ap); #else // HAVE_VSNPRINTF #define xastir_vsnprintf vsnprintf #endif // HAVE_VSNPRINTF /* Use the system libraries version of snprintf() if available. Otherwise * use our own. */ #ifndef HAVE_SNPRINTF #ifdef __STDC__ int xastir_snprintf(char *str, size_t count, const char *fmt, ...); #else // __STDC__ int xastir_snprintf(); #endif // __STDC__ #else // HAVE_SNPRINTF #define xastir_snprintf snprintf #endif // HAVE_SNPRINTF #endif /* !XASTIR_COMPAT_SNPRINTF_H_ */ Xastir-Release-2.2.4/src/sound.c0000664000175000017500000000621615151324131015411 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include "xastir.h" #include "main.h" // Must be last include file #include "leak_detection.h" pid_t play_sound(char *sound_cmd, char *soundfile) { pid_t sound_pid; char command[600]; sound_pid=0; if (strlen(sound_cmd)>3 && strlen(soundfile)>1) { if (last_sound_pid==0) { // Create a new process to run in sound_pid = fork(); if (sound_pid!=-1) { if(sound_pid==0) { // This is the child process // Go back to default signal handler instead of // calling restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So // far this only works for "ps" listings, not // for "top". This code only works on Linux. // For BSD use setproctitle(3), NetBSD can use // setprogname(2). #ifdef __linux__ init_set_proc_title(my_argc, my_argv, my_envp); set_proc_title("%s", "festival process (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); #endif // __linux__ xastir_snprintf(command, sizeof(command), "%s %s/%s", sound_cmd, SOUND_DIR, soundfile); if (system(command) != 0) {} // We don't care whether it succeeded exit(0); // Exits only this process, not Xastir itself } else { // This is the parent process last_sound_pid=sound_pid; } } else { fprintf(stderr,"Error! trying to play sound\n"); } } else { sound_pid=last_sound_pid; /*fprintf(stderr,"Sound already running\n");*/ } } return(sound_pid); } int sound_done(void) { int done; int *status; status=NULL; done=0; if(last_sound_pid!=0) { if(waitpid(last_sound_pid,status,WNOHANG)==last_sound_pid) { done=1; last_sound_pid=0; } } return(done); } Xastir-Release-2.2.4/src/sound.h0000664000175000017500000000036015151324131015410 0ustar hibbyhibby#ifndef XASTIR_SOUND_H #define XASTIR_SOUND_H #include #define SPEECH_TEST_STRING "Greeteengz frum eggzaster" extern pid_t play_sound(char *sound_cmd, char *soundfile); extern int sound_done(void); #endif // XASTIR_SOUND_HXastir-Release-2.2.4/src/symbols.h0000664000175000017500000000203715151324131015753 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef XASTIR_SYMBOLS_H #define XASTIR_SYMBOLS_H /* define Symbol Active */ #endif /* XASTIR_SYMBOLS_H */ Xastir-Release-2.2.4/src/tactical_call_utils.c0000664000175000017500000002411715151324131020260 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "hashtable.h" #include "hashtable_itr.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include "xastir.h" #include "globals.h" #include "snprintf.h" #include "main.h" #include "xa_config.h" static struct hashtable *tactical_hash = NULL; #define TACTICAL_HASH_SIZE 1024 // Multiply all the characters in the callsign, truncated to // TACTICAL_HASH_SIZE // unsigned int tactical_hash_from_key(void *key) { unsigned char *jj = key; unsigned int tac_hash = 1; while (*jj != '\0') { tac_hash = tac_hash * (unsigned int)*jj++; } tac_hash = tac_hash % TACTICAL_HASH_SIZE; // fprintf(stderr,"hash = %d\n", tac_hash); return (tac_hash); } int tactical_keys_equal(void *key1, void *key2) { //fprintf(stderr,"Comparing %s to %s\n",(char *)key1,(char *)key2); if (strlen((char *)key1) == strlen((char *)key2) && strncmp((char *)key1,(char *)key2,strlen((char *)key1))==0) { //fprintf(stderr," match\n"); return(1); } else { //fprintf(stderr," no match\n"); return(0); } } void init_tactical_hash(int clobber) { // fprintf(stderr," Initializing tactical hash \n"); // make sure we don't leak //fprintf(stderr,"init_tactical_hash\n"); if (tactical_hash) { //fprintf(stderr,"Already have one!\n"); if (clobber) { //fprintf(stderr,"Clobbering hash table\n"); hashtable_destroy(tactical_hash, 1); tactical_hash=create_hashtable(TACTICAL_HASH_SIZE, tactical_hash_from_key, tactical_keys_equal); } } else { //fprintf(stderr,"Creating hash table from scratch\n"); tactical_hash=create_hashtable(TACTICAL_HASH_SIZE, tactical_hash_from_key, tactical_keys_equal); } } char *get_tactical_from_hash(char *callsign) { char *result; if (callsign == NULL || *callsign == '\0') { fprintf(stderr,"Empty callsign passed to get_tactical_from_hash()\n"); return(NULL); } if (!tactical_hash) // no table to search { //fprintf(stderr,"Creating hash table\n"); init_tactical_hash(1); // so create one return NULL; } // fprintf(stderr," searching for %s...",callsign); result=hashtable_search(tactical_hash,callsign); if (result) { // fprintf(stderr,"\t\tFound it, %s, len=%d, %s\n", // callsign, // strlen(callsign), // result); } else { // fprintf(stderr,"\t\tNot found, %s, len=%d\n", // callsign, // strlen(callsign)); } return (result); } // This function checks whether there already is something in the // hashtable that matches. If a match found, it overwrites the // tactical call for that entry, else it inserts a new record. // void add_tactical_to_hash(char *callsign, char *tactical_call) { char *temp1; // tac-call char *temp2; // callsign char *ptr; // Note that tactical_call can be '\0', which means we're // getting rid of a previous tactical call. // if (callsign == NULL || *callsign == '\0' || tactical_call == NULL) { return; } if (!tactical_hash) // no table to add to { //fprintf(stderr,"init_tactical_hash\n"); init_tactical_hash(1); // so create one } // Remove any matching entry to avoid duplicates ptr = hashtable_remove(tactical_hash, callsign); if (ptr) // If value found, free the storage space for it as { // the hashtable_remove function doesn't. It does // however remove the key (callsign) ok. free(ptr); } temp1 = (char *)malloc(MAX_TACTICAL_CALL+1); CHECKMALLOC(temp1); temp2 = (char *)malloc(MAX_CALLSIGN+1); CHECKMALLOC(temp2); //fprintf(stderr, "\t\t\tAdding %s = %s...\n", callsign, tactical_call); xastir_snprintf(temp2, MAX_CALLSIGN+1, "%s", callsign); xastir_snprintf(temp1, MAX_TACTICAL_CALL+1, "%s", tactical_call); // (key) (value) // hash call tac-call if (!hashtable_insert(tactical_hash, temp2, temp1)) { fprintf(stderr,"Insert failed on tactical hash --- fatal\n"); free(temp1); free(temp2); exit(1); } // A check to see whether hash insert/update worked properly ptr = get_tactical_from_hash(callsign); if (!ptr) { fprintf(stderr,"***Failed hash insert/update***\n"); } else { //fprintf(stderr,"Current: %s -> %s\n", // callsign, // ptr); } } void destroy_tactical_hash(void) { struct hashtable_itr *iterator = NULL; char *value; if (tactical_hash && hashtable_count(tactical_hash) > 0) { iterator = hashtable_iterator(tactical_hash); do { if (iterator) { value = hashtable_iterator_value(iterator); if (value) { free(value); } } } while (hashtable_iterator_remove(iterator)); // Destroy the hashtable, freeing what's left of the // entries. hashtable_destroy(tactical_hash, 1); tactical_hash = NULL; if (iterator) { free(iterator); } } } // // Tactical callsign logging // // Logging function called from the Assign Tactical Call right-click // menu option and also from db.c:fill_in_tactical_call. Each // tactical assignment is logged as one line. // // We need to check for identical callsigns in the file, deleting // lines that have the same name and adding new records to the end. // Actually BAD IDEA! We want to keep the history of the tactical // calls so that we can trace the changes later. // // Best method: Look for lines containing matching callsigns and // comment them out, adding the new tactical callsign at the end of // the file. // // Do we need to use a special marker to mean NO tactical callsign // is assigned? This is for when we had a tactical call but now // we're removing it. The reload_tactical_calls() routine below // would need to match. Since we're using comma-delimited files, we // can just check for an empty string instead. // void log_tactical_call(char *call_sign, char *tactical_call_sign) { char file[MAX_VALUE]; FILE *f; // Add it to our in-memory hash so that if stations expire and // then appear again they get assigned the same tac-call. add_tactical_to_hash(call_sign, tactical_call_sign); get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"a"); if (f!=NULL) { if (tactical_call_sign == NULL) { fprintf(f,"%s,\n",call_sign); } else { fprintf(f,"%s,%s\n",call_sign,tactical_call_sign); } (void)fclose(f); if (debug_level & 1) { fprintf(stderr, "Saving tactical call to file: %s:%s", call_sign, tactical_call_sign); } } else { fprintf(stderr,"Couldn't open file for appending: %s\n", file); } } // // Function to load saved tactical calls back into xastir. This // is called on startup. This implements persistent tactical calls // across xastir restarts. // // Here we create a hash lookup and store one record for each valid // line read from the tactical calls log file. The key for each // hash entry is the callsign-SSID. Here we simply read them in and // create the hash. When a new station is heard on the air, it is // checked against this hash and the tactical call field filled in // if there is a match. // // Note that the length of "line" can be up to max_device_buffer, // which is currently set to 4096. // void reload_tactical_calls(void) { char file[MAX_VALUE]; FILE *f; char line[300+1]; get_user_base_dir("config/tactical_calls.log", file, sizeof(file)); f=fopen(file,"r"); if (f!=NULL) { while (fgets(line, 300, f) != NULL) { if (debug_level & 1) { fprintf(stderr,"loading tactical calls from file: %s",line); } if (line[0] != '#') // skip comment lines { char *ptr; // we're dealing with comma-separated files, so // break the two pieces at the comma. ptr = index(line,','); if (ptr != NULL) { char *ptr2; ptr[0] = '\0'; // terminate the callsign ptr++; // point to the tactical callsign // check for lf ptr2 = index(ptr,'\n'); if (ptr2 != NULL) { ptr2[0] = '\0'; } // check for cr ptr2 = index(ptr,'\r'); if (ptr2 != NULL) { ptr2[0] = '\0'; } if (debug_level & 1) { fprintf(stderr, "Call=%s,\tTactical=%s\n", line, ptr); } // call tac-call add_tactical_to_hash(line, ptr); } } } (void)fclose(f); } else { if (debug_level & 1) { fprintf(stderr,"couldn't open file for reading: %s\n", file); } } /* if (tactical_hash) { fprintf(stderr,"Stations w/tactical calls defined: %d\n", hashtable_count(tactical_hash)); } */ } Xastir-Release-2.2.4/src/tactical_call_utils.h0000664000175000017500000000236115151324131020262 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_TACTICAL_CALL_UTILS_H #define __XASTIR_TACTICAL_CALL_UTILS_H #include "hashtable.h" extern char *get_tactical_from_hash(char *callsign); extern void destroy_tactical_hash(void); extern void log_tactical_call(char *call_sign, char *tactical_call_sign); extern void reload_tactical_calls(void); #endif Xastir-Release-2.2.4/src/testdbfawk.c0000664000175000017500000002161315151324131016415 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #ifdef HAVE_LIBSHP #ifdef HAVE_SHAPEFIL_H #include #else #ifdef HAVE_LIBSHP_SHAPEFIL_H #include #else #error HAVE_LIBSHP defined but no corresponding include defined #endif // HAVE_LIBSHP_SHAPEFIL_H #endif // HAVE_SHAPEFIL_H #include #include #include "awk.h" #include "dbfawk.h" // Must be last include file #include "leak_detection.h" /* * Sample test program */ void die(const char *s) { fprintf(stderr,"%s\n",s); exit(1); } /* * print_symtbl: debugging */ void print_symtbl(awk_symtab *this) { awk_symbol *s; char buf[1024]; int len; int i; // fprintf(stderr,"symtbl 0%0x dump:\n",(u_int)this); fprintf(stderr,"symtbl 0x%0lx dump:\n", (uintptr_t)this); for (i = 0; i < AWK_SYMTAB_HASH_SIZE; i++) { for (s = this->hash[i]; s; s = s->next_sym) { *buf = '\0'; awk_get_sym(s,buf,sizeof(buf),&len); fprintf(stderr,"%d %s = '%.*s'\n",i,s->name,len,buf); } } } awk_rule rules[] = { { 0, BEGIN, NULL, NULL, 0, 0, "key=\"\"; lanes=1; color=8; name=\"\"; filled=0; pattern=1; display_level=8192; label_level=32",0,0 }, { 0, REGEXP, "^TLID=(.*)$", NULL, 0, 0, "key=\"$1\"",0,0 }, { 0, REGEXP, "^FENAME=United States Highway (.*)$", NULL, 0, 0, "name=\"US $1\"; next",0,0 }, { 0, REGEXP, "^FENAME=(.*)$", NULL, 0, 0, "name=\"$1\"; next",0,0 }, { 0, REGEXP, "^CFCC=A1", NULL, 0, 0, "lanes=4; color=4; next",0,0 }, { 0, REGEXP, "^CFCC=A3", NULL, 0, 0, "lanes=2; color=8",0,0 }, { 0, REGEXP, "^CFCC=A3[1-6]", NULL, 0, 0, "display_level=256; next",0,0 }, }; int nrules = sizeof(rules)/sizeof(rules[0]); void usage(void) { fprintf(stderr,"Usage: testdbfawk [-f file.awk| -D dir] -d file.dbf\n"); fprintf(stderr," -D for dir containing *.dbfawk files.\n"); fprintf(stderr," or -f for file containing awk rules.\n"); fprintf(stderr," -d for dbf file to parse \n"); } int debug = 0; int main(int argc, char *argv[]) { awk_program *rs = NULL; // int args; awk_symtab *symtbl; /* variables to bind to: */ char dbfinfo[1024]; /* list of DBF field names */ char dbffields[1024]; /* subset we want to read */ char name[128]; char key[128]; char symbol[4]; int color = 0; int lanes = 0; int filled = 5; int pattern=0; int display_level = 1234; int min_display_level = 0; int label_level = 9; int fill_style=0, fill_color=0; int fill_stipple=0; int label_color = 8; int font_size = 0; int label_method = 0; double label_lon = 0.0; double label_lat = 0.0; char *dir = NULL,*file = NULL,*dfile = NULL; dbfawk_sig_info *si = NULL, *sigs = NULL; // Allocates new memory! symtbl = awk_new_symtab(); if (argc >= 2 && (strcmp(argv[1],"--help") == 0 || strcmp(argv[1],"-?") == 0)) { usage(); exit(1); } if (argc > 2 && strcmp(argv[1],"-D") == 0) { dir = argv[2]; argv++; argv++; argc -= 2; sigs = dbfawk_load_sigs(dir,".dbfawk"); if (!sigs) { die("Couldn't find dbfawk sigs\n"); } } else if (argc > 2 && strcmp(argv[1],"-f") == 0) { file = argv[2]; argv++; argv++; argc -= 2; rs = awk_load_program_file(file); /* load up the program */ } else { rs = awk_load_program_array(rules,nrules); /* load up the program */ } if (argc > 2 && strcmp(argv[1],"-d") == 0) { dfile = argv[2]; argv++; argv++; argc -= 2; } /* declare/bind these symbols */ // Allocates new memory! awk_declare_sym(symtbl,"dbfinfo",STRING,dbfinfo,sizeof(dbfinfo)); awk_declare_sym(symtbl,"dbffields",STRING,dbffields,sizeof(dbffields)); awk_declare_sym(symtbl,"color",INT,&color,sizeof(color)); awk_declare_sym(symtbl,"lanes",INT,&lanes,sizeof(lanes)); awk_declare_sym(symtbl,"name",STRING,name,sizeof(name)); awk_declare_sym(symtbl,"key",STRING,key,sizeof(key)); awk_declare_sym(symtbl,"symbol",STRING,symbol,sizeof(symbol)); awk_declare_sym(symtbl,"filled",INT,&filled,sizeof(filled)); awk_declare_sym(symtbl,"fill_style",INT,&fill_style,sizeof(fill_style)); awk_declare_sym(symtbl,"fill_color",INT,&fill_color,sizeof(fill_color)); awk_declare_sym(symtbl,"fill_stipple",INT,&fill_stipple,sizeof(fill_stipple)); awk_declare_sym(symtbl,"pattern",INT,&pattern,sizeof(pattern)); awk_declare_sym(symtbl,"display_level",INT,&display_level,sizeof(display_level)); awk_declare_sym(symtbl,"min_display_level",INT,&min_display_level,sizeof(min_display_level)); awk_declare_sym(symtbl,"label_level",INT,&label_level,sizeof(label_level)); awk_declare_sym(symtbl,"label_color",INT,&label_color,sizeof(label_color)); awk_declare_sym(symtbl,"font_size",INT,&font_size,sizeof(font_size)); awk_declare_sym(symtbl,"label_method",INT,&label_method,sizeof(label_method)); awk_declare_sym(symtbl,"label_lon",FLOAT,&label_lon,sizeof(label_lon)); awk_declare_sym(symtbl,"label_lat",FLOAT,&label_lat,sizeof(label_lat)); if (dfile) /* parse dbf file */ { DBFHandle dbf = DBFOpen(dfile,"rb"); int i; char sig[sizeof(dbfinfo)]; /* write the signature here */ int nf; dbfawk_field_info *fi; if (!dbf) { die("DBFopen: could not open dbf file"); } nf = dbfawk_sig(dbf,sig,sizeof(sig)); fprintf(stderr,"%d Columns, %d Records in file\n",nf, DBFGetRecordCount(dbf)); fprintf(stderr,"sig: %s\n",sig); /* If -D then search for matching sig; else use the supplied awk_prog */ if (sigs) { si = dbfawk_find_sig(sigs,sig,dfile); if (!si) { die("No matching dbfawk signature found"); } rs = si->prog; } if (awk_compile_program(symtbl,rs) < 0) { die("couldn't compile rules"); } awk_exec_begin(rs); /* execute a BEGIN rule if any */ // print_symtbl(symtbl); if (strcmp(sig,dbfinfo) == 0) { fprintf(stderr,"DBF Signatures match!\n"); } else { fprintf(stderr,"DBF Signatures DON'T match\n"); } fi = dbfawk_field_list(dbf, dbffields); /* now actually read the whole file */ for (i = 0; i < DBFGetRecordCount(dbf); i++ ) { dbfawk_parse_record(rs,dbf,fi,i); fprintf(stderr,"name=%s, ",name); fprintf(stderr,"key=%s, ",key); fprintf(stderr,"symbol=%s, ",symbol); fprintf(stderr,"color=%d, ", color); fprintf(stderr,"lanes=%d, ", lanes); fprintf(stderr,"filled=%d, ",filled); fprintf(stderr,"fill_style=%d ",fill_style); fprintf(stderr,"fill_color=%d ",fill_color); fprintf(stderr,"fill_stipple=%d ",fill_stipple); fprintf(stderr,"pattern=%d, ",pattern); fprintf(stderr,"display_level=%d, ",display_level); fprintf(stderr,"min_display_level=%d, ",min_display_level); fprintf(stderr,"font_size=%d, ", font_size); fprintf(stderr,"label_level=%d, ",label_level); fprintf(stderr,"label_color=%d, ",label_color); fprintf(stderr,"label_method=%d, ",label_method); fprintf(stderr,"label_lon=%lf, ",label_lon); fprintf(stderr,"label_lat=%lf\n",label_lat); // print_symtbl(symtbl); } DBFClose(dbf); } else /* use cmdline args */ { usage(); exit(1); /* * remove this capability because it leads to * segfaults if user gives invalid command line arguments. * better to just print usage string awk_exec_begin_record(rs); for (args = 1; args < argc; args++) { fprintf(stderr,"==> %s\n",argv[args]); awk_exec_program(rs,argv[args],strlen(argv[args])); // print_symtbl(symtbl); } awk_exec_end_record(rs); */ } awk_exec_end(rs); /* execute an END rule if any */ // print_symtbl(symtbl); if (si) { dbfawk_free_sigs(si); } else if (rs) { awk_free_program(rs); } awk_free_symtab(symtbl); free(symtbl); exit(0); } #else /* HAVE_LIBSHP */ int main(int argc, char *argv[]) { fprintf(stderr,"DBFAWK support not compiled.\n"); exit(1); } #endif /* HAVE_LIBSHP */ Xastir-Release-2.2.4/src/tile_mgmnt.c0000664000175000017500000002213615151324131016417 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "globals.h" #include "fetch_remote.h" #include "util.h" #include "snprintf.h" #include "maps.h" #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL #include "tile_mgmnt.h" // Must be last include file #include "leak_detection.h" // OSM Minimum cache time #define SECONDS_7_DAYS (7 * 24 * 3600) /* * latLon2tileNum - calculate tile number * * The tile number is returned in in the structure pointed to by the * tilenum argument. */ void latLon2tileNum (double lon_deg, double lat_deg, int zoom, tileNum_t *tilenum) { unsigned long ntiles; double lat_rad; ntiles = 1 << zoom; if (lat_deg > MAX_LAT_OSM) { lat_deg = MAX_LAT_OSM; } else if (lat_deg < (-1.0 * MAX_LAT_OSM)) { lat_deg = -1.0 * MAX_LAT_OSM; } if (lon_deg > MAX_LON_OSM) { lon_deg = MAX_LON_OSM; } else if (lon_deg < (-1.0 * MAX_LON_OSM)) { lon_deg = -1.0 * MAX_LON_OSM; } lat_rad = (lat_deg * M_PI) / 180.0; tilenum->x = ((lon_deg + 180.0) / 360.0) * ntiles; tilenum->y = ((1 - (log(tan(lat_rad) + (1.0 / cos(lat_rad))) / M_PI)) / 2.0) * ntiles; if (tilenum->y >= ntiles) { tilenum->y = (ntiles - 1); } if (tilenum->x >= ntiles) { tilenum->x = (ntiles - 1); } return; } // latLon2tileNum() /* * tile2coord - calculate lat/lon of NW corner of tile * * Use tilex+1 and tiley+1 to get the coordinates of the SE corner. * * Based on example code at * http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames * */ void tile2coord (unsigned long tilex, unsigned long tiley, int zoom, coord_t *NWcorner) { unsigned long ntiles; double lat_rad; ntiles = 1 << zoom; lat_rad = M_PI - ((2.0 * M_PI) * ((double)(tiley) / (double)ntiles)); NWcorner->lat = (180.0 / M_PI) * atan(0.5 * (exp((double)lat_rad) - exp(-1.0 * (double)lat_rad))); NWcorner->lon = (((double)(tilex) / (double)ntiles) * 360.0) - 180.0; return; } // tile2coord() /* * calcTileArea - calculate the x and y range of tile numbers * * Returns the calculated values in the structure pointed to by the * tiles argument. */ void calcTileArea (double lon_upper_left, double lat_upper_left, double lon_lower_right, double lat_lower_right, int zoom, tileArea_t *tiles) { tileNum_t tilenum; latLon2tileNum(lon_upper_left, lat_upper_left, zoom, &tilenum); tiles->startx = tilenum.x; tiles->starty = tilenum.y; latLon2tileNum(lon_lower_right, lat_lower_right, zoom, &tilenum); tiles->endx = tilenum.x; tiles->endy = tilenum.y; return; } // calcTileArea() /* * tilesMissing - return the count of tiles that are missing from the cache */ int tilesMissing (unsigned long startx, unsigned long endx, unsigned long starty, unsigned long endy, int zoom, char *cacheDir, char *tileExt) { struct stat sb; char local_filename[1100]; unsigned long x, y; int numMissing = 0; for (x = startx; x <= endx; x++) { for (y = starty; y <= endy; y++) { xastir_snprintf(local_filename, sizeof(local_filename), "%s/%u/%lu/%lu.%s", cacheDir, zoom, x, y, tileExt); if (stat(local_filename, &sb) == -1) { numMissing++; } } } return(numMissing); } // end of tilesMissing() /* * getOneTile - get one tile from the web * * The tile is fetched if it does not exist and 1 is returned. * * If the tile exists in the cache and it is older than 7 days, then it * will be refreshed from the server. * * Returns 1 if a tile did not exist and download was attempted. * Returns 0 if a tile exists in the cache (tile might be updated). * * Returns libcurl errors as a negative integer. * * WARNING: Download failures are not reported for wget. * */ #ifdef HAVE_LIBCURL int getOneTile (CURL *session, char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt) { CURLcode res; time_t cacheTimeout; #else int getOneTile (char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt) { #endif // HAVE_LIBCURL struct stat sb; char url[1100]; char local_filename[1100]; int result = 0; xastir_snprintf(url, sizeof(url), "%s/%u/%lu/%lu.%s", baseURL, zoom, x, y, tileExt); xastir_snprintf(local_filename, sizeof(local_filename), "%s/%u/%lu/%lu.%s", baseDir, zoom, x, y, tileExt); if (stat(local_filename, &sb) == -1) { if (debug_level & 512) { fprintf(stderr, "Fetching %s\n", url); } result = 1; // only count files that do not exist #ifdef HAVE_LIBCURL res = fetch_remote_tile(session, url, local_filename); } else { // Check for updated tiles after 7 days, per // OSM Tile Usage Policy, // http://wiki.openstreetmap.org/wiki/Tile_usage_policy, // 2010/07/29 cacheTimeout = sb.st_mtime + SECONDS_7_DAYS; if (cacheTimeout <= time(NULL)) { // tile exists in the cache, but is older than 7 days, so // check the server for a newer version. if (debug_level & 512) { fprintf(stderr, "Refreshing %s.\n", url); } res = fetch_remote_tile(session, url, local_filename); } else { if (debug_level & 512) { fprintf(stderr, "Skipping- %s\n", url); fprintf(stderr, " because cache time has not expired.\n"); fprintf(stderr, " cache expires %s", ctime(&cacheTimeout)); } res = CURLE_OK; } } if (CURLE_OK != res) { // return the curl error as a negative value to distinqusih it // successful values result = -1 * (int)res; } #else // don't HAVE_LIBCURL (void)fetch_remote_file(url, local_filename); } #endif // HAVE_LIBCURL return(result); } // getOneTile() /* * mkpath() - attempt to make each directory in a path */ static void mkpath(const char *dir) { char tmp[MAX_FILENAME]; char *p = NULL; size_t len; xastir_snprintf(tmp, sizeof(tmp),"%s", dir); len = strlen(tmp); if(tmp[len - 1] == '/') { tmp[len - 1] = 0; } for (p = tmp + 1; *p; p++) { if(*p == '/') { *p = 0; mkdir(tmp, S_IRWXU); *p = '/'; } } mkdir(tmp, S_IRWXU); return; } // end of mkpath() /* * mkOSMmapDirs - try to create all the directories needed for the tiles * * This is simply a best-effort attempt because there are valid reasons * for mkdir() to fail. For example, the tiles could be buffered in a RO * structure. */ void mkOSMmapDirs (char *baseDir, unsigned long startx, unsigned long endx, int zoom) { char fullPath[MAX_FILENAME]; #ifdef HAVE_POSIX_STRERROR_R char errmsg[1024]; #endif struct stat sb; unsigned long dnum; xastir_snprintf(fullPath, sizeof(fullPath), "%s/%u/", baseDir, zoom); mkpath(fullPath); for (dnum = startx; dnum <= endx; dnum++) { xastir_snprintf(fullPath, sizeof(fullPath), "%s/%u/%lu/", baseDir, zoom, dnum); mkdir(fullPath, S_IRWXU); if (debug_level & 512) { if (stat(fullPath, &sb) == -1) { #ifdef HAVE_POSIX_STRERROR_R strerror_r(errno, errmsg, sizeof(errmsg)); fprintf(stderr, "%s: %s\n", errmsg, fullPath); #else fprintf(stderr, "%s: %s\n", strerror(errno), fullPath); #endif } else if ((sb.st_mode & S_IWUSR) != S_IWUSR) { fprintf(stderr, "warning: directory %s is not writable\n", fullPath); } else if (!S_ISDIR(sb.st_mode)) { fprintf(stderr, "warning: %s is not a directory\n", fullPath); } } } return; } // mkOSMmapDirs() Xastir-Release-2.2.4/src/tile_mgmnt.h0000664000175000017500000000421515151324131016422 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __TILE_MGMNT_H #define __TILE_MGMNT_H #ifdef HAVE_LIBCURL #include #endif // HAVE_LIBCURL typedef struct tileNum_s { unsigned long x; unsigned long y; } tileNum_t; typedef struct coord_s { double lat; double lon; } coord_t; typedef struct tileArea_s { unsigned long startx; unsigned long endx; unsigned long starty; unsigned long endy; } tileArea_t; #define MAX_LAT_OSM 85.0511 #define MAX_LON_OSM 180.0 void latLon2tileNum(double lon_deg, double lat_deg, int zoom, tileNum_t *tilenum); void tile2coord(unsigned long tilex, unsigned long tiley, int zoom, coord_t *NWcorner); void calcTileArea(double lon_upper_left,double lat_upper_left,double lon_lower_right,double lat_lower_right,int zoom,tileArea_t *tiles); #ifdef HAVE_LIBCURL int getOneTile(CURL *session, char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt); #else int getOneTile(char *baseURL, unsigned long x, unsigned long y, int zoom, char *baseDir, char *tileExt); #endif // HAVE_LIBCURL void mkOSMmapDirs(char *baseDir, unsigned long startx, unsigned long endx, int zoom); int tilesMissing (unsigned long startx, unsigned long endx, unsigned long starty, unsigned long endy, int zoom, char *baseDir, char *tileExt); #endif // __TILE_MGMNT_H Xastir-Release-2.2.4/src/timer_utils.c0000664000175000017500000000325215151324131016616 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include struct timeval timer_start; struct timeval timer_stop; struct timezone tz; // Save the current time, used for timing code sections. void start_timer(void) { gettimeofday(&timer_start,&tz); } // Save the current time, used for timing code sections. void stop_timer(void) { gettimeofday(&timer_stop,&tz); } // Print the difference in the two times saved above. void print_timer_results(void) { fprintf(stderr,"Total: %f sec\n", (float)(timer_stop.tv_sec - timer_start.tv_sec + ((timer_stop.tv_usec - timer_start.tv_usec) / 1000000.0) )); } Xastir-Release-2.2.4/src/timer_utils.h0000664000175000017500000000213315151324131016620 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_timer_UTILS_H #define __XASTIR_timer_UTILS_H extern void start_timer(void); extern void stop_timer(void); extern void print_timer_results(void); #endif Xastir-Release-2.2.4/src/track_gui.c0000664000175000017500000011533215151324131016231 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "db_gui.h" #include "lang.h" #include "objects.h" #include "popup.h" #include "fetch_remote.h" #include "util.h" #include "mutex_utils.h" #include "xa_config.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget track_station_dialog = (Widget)NULL; Widget track_station_data = (Widget)NULL; Widget download_findu_dialog = (Widget)NULL; static xastir_mutex track_station_dialog_lock; static xastir_mutex download_findu_dialog_lock; // track values Widget track_case_data, track_match_data; // Download findu values Widget download_trail_station_data; Widget posit_start_value; Widget posit_length_value; int fetching_findu_trail_now = 0; int track_station_on = 0; /* used for tracking stations */ int track_me; int track_case; /* used for tracking stations */ int track_match; /* used for tracking stations */ char tracking_station_call[30]; /* Tracking station callsign */ char download_trail_station_call[30]; /* Trail station callsign */ //N0VH #define MAX_FINDU_DURATION 120 #define MAX_FINDU_START_TIME 336 // Make these two match, as that will be the most desired case: Snag // the track for as far back as possible up to the present in one // shot... int posit_start = MAX_FINDU_DURATION; int posit_length = MAX_FINDU_DURATION; void track_gui_init(void) { init_critical_section( &track_station_dialog_lock ); init_critical_section( &download_findu_dialog_lock ); if (temp_tracking_station_call[0] != '\0') { xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", temp_tracking_station_call); track_station_on = 1; } else { tracking_station_call[0] = '\0'; } } /**** Track STATION ******/ void track_station_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&track_station_dialog_lock, "track_gui.c:track_station_destroy_shell" ); XtDestroyWidget(shell); track_station_dialog = (Widget)NULL; end_critical_section(&track_station_dialog_lock, "track_gui.c:track_station_destroy_shell" ); } void Track_station_clear(Widget w, XtPointer clientData, XtPointer callData) { /* clear station */ track_station_on=0; //track_station_data=NULL; //tracking_station_call[0] = '\0'; // Clear the TrackMe button as well XmToggleButtonSetState(trackme_button,FALSE,TRUE); track_station_destroy_shell(w, clientData, callData); display_zoom_status(); } void Track_station_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[MAX_CALLSIGN+1]; char temp2[200]; int found = 0; char *temp_ptr; temp_ptr = XmTextFieldGetString(track_station_data); xastir_snprintf(temp, sizeof(temp), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); (void)remove_trailing_dash_zero(temp); xastir_snprintf(tracking_station_call, sizeof(tracking_station_call), "%s", temp); track_case = (int)XmToggleButtonGetState(track_case_data); track_match = (int)XmToggleButtonGetState(track_match_data); found = locate_station(da, temp, track_case, track_match, 0); if ( valid_object(tracking_station_call) // Name of object is legal || valid_call(tracking_station_call) || valid_item(tracking_station_call ) ) { track_station_on = 1; // Track it whether we've seen it yet or not if (!found) { xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00026"), temp); popup_message_always(langcode("POPEM00025"),temp2); } // Check for exact match, includes SSID if ( track_me & !is_my_call( tracking_station_call, 1) ) { XmToggleButtonSetState( trackme_button, FALSE, FALSE ); track_me = 0; } } else { tracking_station_call[0] = '\0'; // Empty it out again track_station_on = 0; xastir_snprintf(temp2, sizeof(temp2), langcode("POPEM00002"), temp); popup_message_always(langcode("POPEM00003"),temp2); } track_station_destroy_shell(w, clientData, callData); display_zoom_status(); } void Track_station( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_close, button_clear, call, sep; Atom delw; if (!track_station_dialog) { begin_critical_section(&track_station_dialog_lock, "track_gui.c:Track_station" ); track_station_dialog = XtVaCreatePopupShell(langcode("WPUPTSP001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Track_station pane", xmPanedWindowWidgetClass, track_station_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Track_station my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 3, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPTSP002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); track_station_data = XtVaCreateManagedWidget("Track_station track locate data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); track_case_data = XtVaCreateManagedWidget(langcode("WPUPTSP003"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset,10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); track_match_data = XtVaCreateManagedWidget(langcode("WPUPTSP004"), xmToggleButtonWidgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 20, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget,track_case_data, XmNrightOffset,20, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); sep = XtVaCreateManagedWidget("Track_station sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,track_case_data, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPTSP005"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_clear = XtVaCreateManagedWidget(langcode("WPUPTSP006"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Track_station_now, track_station_dialog); XtAddCallback(button_close, XmNactivateCallback, track_station_destroy_shell, track_station_dialog); XtAddCallback(button_clear, XmNactivateCallback, Track_station_clear, track_station_dialog); XmToggleButtonSetState(track_case_data,FALSE,FALSE); XmToggleButtonSetState(track_match_data,TRUE,FALSE); pos_dialog(track_station_dialog); delw = XmInternAtom(XtDisplay(track_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(track_station_dialog, delw, track_station_destroy_shell, (XtPointer)track_station_dialog); // if (track_station_on==1) XmTextFieldSetString(track_station_data,tracking_station_call); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, track_station_dialog); end_critical_section(&track_station_dialog_lock, "track_gui.c:Track_station" ); XtPopup(track_station_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(track_station_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(track_station_dialog), XtWindow(track_station_dialog)); } } /***** DOWNLOAD FINDU TRAILS *****/ // Struct used for passing two parameters to findu_transfer_thread typedef struct { char *download_client_ptrs[2]; } track_ptrs_struct; track_ptrs_struct track_ptrs; // This is the separate execution thread that fetches the track from // findu. The thread is started up by the Download_trail_now() // function below. // static void* findu_transfer_thread(void *arg) { char *fileimg; char *log_filename; // char log_filename_tmp[210]; char **ptrs; char sys_cmd[128]; // Get fileimg and log_filename from parameters ptrs = arg; log_filename = ptrs[0]; fileimg = ptrs[1]; // Set global "busy" variable fetching_findu_trail_now = 1; if (fetch_remote_file(fileimg, log_filename)) { // Had trouble getting the file. Abort. // We may not be able to do any GUI stuff from multiple // threads/processes at the same time. If that is found to be the // case we can write to STDERR instead. // Dump a message to STDERR // fprintf(stderr, // "%s %s\n", // langcode("POPEM00035"), // langcode("POPEM00044")); // Fetch Findu Trail: Failed popup_message_always(langcode("POPEM00035"), langcode("POPEM00044")); // Reset global "busy" variable fetching_findu_trail_now = 0; // End the thread return(NULL); } // We need to move this message up to the main thread if possible so // that we don't have multiple threads writing to the GUI. This // sort of operation can cause segfaults. In practice I haven't // seen any segfaults due to this particular popup though. // Fetch Findu Trail: Complete popup_message_always(langcode("POPEM00036"), langcode("POPEM00045")); // Set permissions on the file so that any user can overwrite it. chmod(log_filename, 0666); #if defined(HAVE_SED) // Add three spaces before each "
" and axe the "
". This // is so that Base-91 compressed packets with no comment and no // speed/course/altitude will get decoded ok. Otherwise the // spaces that are critical to the Base-91 packets won't be // there due to findu.com filtering them out. // // "sed -i -e \"s/
/
/\" %s", sprintf(sys_cmd, "%s -i -e \"s/
/ /\" %s", SED_PATH, log_filename); if (system(sys_cmd)) { fprintf(stderr,"Couldn't execute command: %s\n", sys_cmd); } // Greater-than symbol '>' sprintf(sys_cmd, "%s -i -e \"s/>/>/\" %s", SED_PATH, log_filename); if (system(sys_cmd)) { fprintf(stderr,"Couldn't execute command: %s\n", sys_cmd); } // Less-than symbol '<' sprintf(sys_cmd, "%s -i -e \"s/</Open Log File" routine. HTML // tags will be ignored just fine. read_file_ptr = fopen(log_filename, "r"); if (read_file_ptr != NULL) { read_file = 1; } else { fprintf(stderr,"Couldn't open file: %s\n", log_filename); } // Reset global "busy" variable fetching_findu_trail_now = 0; // End the thread return(NULL); } void Download_trail_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail_destroy_shell" ); XtDestroyWidget(shell); download_findu_dialog = (Widget)NULL; end_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail_destroy_shell" ); } void Download_trail_now(Widget w, XtPointer clientData, XtPointer callData) { char temp[MAX_CALLSIGN+1]; static char fileimg[400]; static char log_filename[200]; char *temp_ptr; pthread_t download_trail_thread; static XtPointer download_client_data = NULL; char tmp_base_dir[MAX_VALUE]; get_user_base_dir("tmp",tmp_base_dir, sizeof(tmp_base_dir)); // If we're already fetching a trail, we shouldn't be calling // this callback function. Get out. if (fetching_findu_trail_now) { return; } // Pass two parameters to findu_transfer_thread via a struct track_ptrs.download_client_ptrs[0] = log_filename; track_ptrs.download_client_ptrs[1] = fileimg; download_client_data = &track_ptrs; // Check whether it's ok to do a download currently. if (read_file) { // No, we're already in the middle of reading in some file. // Skip trying to download yet another file. fprintf(stderr,"Processing another file. Wait a bit, then try again\n"); popup_message_always(langcode("POPEM00035"), langcode("POPEM00041")); return; } // busy_cursor(appshell); strcpy(log_filename, tmp_base_dir); log_filename[sizeof(log_filename)-1] = '\0'; // Terminate string strcat(log_filename, "/map.log"); log_filename[sizeof(log_filename)-1] = '\0'; // Terminate string // Erase any previously existing local file by the same name. // This avoids the problem of having an old tracklog here and // the code trying to display it when the download fails. unlink( log_filename ); XmScaleGetValue(posit_start_value, &posit_start); XmScaleGetValue(posit_length_value, &posit_length); temp_ptr = XmTextFieldGetString(download_trail_station_data); xastir_snprintf(temp, sizeof(temp), "%s", temp_ptr); XtFree(temp_ptr); (void)remove_trailing_spaces(temp); (void)remove_trailing_dash_zero(temp); xastir_snprintf(download_trail_station_call, sizeof(download_trail_station_call), "%s", temp); //Download_trail_destroy_shell(w, clientData, callData); // New URL's for findu. The second one looks very promising. //http://www.findu.com/cgi-bin/raw.cgi?call=k4hg-8&time=1 //http://www.findu.com/cgi-bin/rawposit.cgi?call=k4hg-8&time=1 // // The last adds this to the beginning of the line: // // "20030619235323," // // which is a date/timestamp. We'll need to do some extra stuff // here in order to actually use that date/timestamp though. // Setting the read_file_ptr to the downloaded file won't do it. // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d&time=1", // New, with timestamp xastir_snprintf(fileimg, sizeof(fileimg), // // Posits only: // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d", // // Posits plus timestamps (we can't handle timestamps yet): // "http://www.findu.com/cgi-bin/rawposit.cgi?call=%s&start=%d&length=%d&time=1", // New, with timestamp // // Download all packets, not just posits: "http://www.findu.com/cgi-bin/raw.cgi?call=%s&start=%d&length=%d", // download_trail_station_call,posit_start,posit_length); if (debug_level & 1024) { fprintf(stderr, "%s\n", fileimg); } //----- Start New Thread ----- if (pthread_create(&download_trail_thread, NULL, findu_transfer_thread, download_client_data)) { fprintf(stderr,"Error creating findu transfer thread\n"); } else { // We're off and running with the new thread! } display_zoom_status(); Download_trail_destroy_shell(w, clientData, callData); } void Reset_posit_length_max(Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { XmScaleGetValue(posit_length_value, &posit_length); XmScaleGetValue(posit_start_value, &posit_start); // Check whether start hours is greater than max findu allows // for duration // if (posit_start > MAX_FINDU_DURATION) // Set the duration slider to { // findu's max duration hours XtVaSetValues(posit_length_value, XmNvalue, MAX_FINDU_DURATION, NULL); posit_length = MAX_FINDU_DURATION; } else // Not near the max, so set the duration slider to match { // the start hours XtVaSetValues(posit_length_value, XmNvalue, posit_start, NULL); posit_length = posit_start; } } void Download_findu_trail( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, button_ok, button_cancel, call, sep; Atom delw; XmString x_str; if (!download_findu_dialog) { begin_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_findu_trail" ); download_findu_dialog = XtVaCreatePopupShell(langcode("WPUPTSP007"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse,XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Download_findu_trail pane", xmPanedWindowWidgetClass, download_findu_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Download_findu_trail my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 2, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); call = XtVaCreateManagedWidget(langcode("WPUPTSP008"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); download_trail_station_data = XtVaCreateManagedWidget("download_trail_station_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 15, XmNwidth, ((15*7)+2), XmNmaxLength, 15, XmNbackground, colors[0x0f], XmNtopAttachment,XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, call, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, XmNfontList, fontlist1, NULL); x_str = XmStringCreateLocalized(langcode("WPUPTSP009")); posit_start_value = XtVaCreateManagedWidget("Start of Trail (hrs ago)", xmScaleWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, call, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, //XmNwidth, 190, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, XmNmaximum, MAX_FINDU_START_TIME, XmNshowValue, TRUE, XmNvalue, posit_start, // Note: Some versions of OpenMotif (distributed with Fedora, // perhaps others) don't work properly with XtVaTypedArg() as used // here, instead showing blank labels for the Scale widgets. // XtVaTypedArg, XmNtitleString, XmRString, langcode("WPUPTSP009"), 22, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); x_str = XmStringCreateLocalized(langcode("WPUPTSP010")); posit_length_value = XtVaCreateManagedWidget("Length of trail (hrs)", xmScaleWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, posit_start_value, XmNtopOffset, 15, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, //XmNwidth, 190, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 10, XmNsensitive, TRUE, XmNorientation, XmHORIZONTAL, XmNborderWidth, 1, XmNminimum, 1, XmNmaximum, MAX_FINDU_DURATION, XmNshowValue, TRUE, XmNvalue, posit_length, // Note: Some versions of OpenMotif (distributed with Fedora, // perhaps others) don't work properly with XtVaTypedArg() as used // here, instead showing blank labels for the Scale widgets. // XtVaTypedArg, XmNtitleString, XmRString, langcode("WPUPTSP010"), 19, XmNtitleString, x_str, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XmStringFree(x_str); sep = XtVaCreateManagedWidget("Download_findu_trail sep", xmSeparatorGadgetClass, my_form, XmNorientation, XmHORIZONTAL, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget,posit_length_value, XmNtopOffset, 10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment,XmATTACH_FORM, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_ok = XtVaCreateManagedWidget(langcode("WPUPTSP007"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 0, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 1, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); if (fetching_findu_trail_now) { XtSetSensitive(button_ok, FALSE); } button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00002"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, sep, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 5, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 1, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 2, XmNrightOffset, 5, XmNnavigationType, XmTAB_GROUP, XmNtraversalOn, TRUE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_ok, XmNactivateCallback, Download_trail_now, download_findu_dialog); XtAddCallback(button_cancel, XmNactivateCallback, Download_trail_destroy_shell, download_findu_dialog); XtAddCallback(posit_start_value, XmNvalueChangedCallback, Reset_posit_length_max, download_findu_dialog); pos_dialog(download_findu_dialog); delw = XmInternAtom(XtDisplay(download_findu_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(download_findu_dialog, delw, Download_trail_destroy_shell, (XtPointer)download_findu_dialog); XmTextFieldSetString(download_trail_station_data,download_trail_station_call); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, download_findu_dialog); end_critical_section(&download_findu_dialog_lock, "track_gui.c:Download_trail" ); XtPopup(download_findu_dialog,XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(download_findu_dialog); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(download_findu_dialog), XtWindow(download_findu_dialog)); } } Xastir-Release-2.2.4/src/track_gui.h0000664000175000017500000000254415151324131016236 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. * * */ #ifndef __TRACK_GUI_H #define __TRACK_GUI_H /* from track_gui.c */ extern void track_gui_init(void); extern void Track_station(Widget w, XtPointer clientData, XtPointer callData); extern int track_station_on; extern int track_me; extern int track_case; extern int track_match; extern char tracking_station_call[30]; extern void Download_findu_trail(Widget w, XtPointer clientData, XtPointer callData); #endif // __TRACK_GUI_H Xastir-Release-2.2.4/src/util.c0000664000175000017500000034263315151324131015244 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "globals.h" #include "util.h" #include "db_funcs.h" #include "xa_config.h" #include "datum.h" // Needed for size_t #include // Must be last include file #include "leak_detection.h" #define ACCEPT_0N_0E /* set this to see stations at 0N/0E on the map */ ///////////////////////////////////////////////////////////////////// // convert_from_xastir_coordinates() // // Converts from Xastir coordinate system to lat/lon. First two // parameters are the output floating point lat/lon values. 2nd two // are the input Xastir X/Y values. // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Returns 0 if error, 1 if good values were converted. // Errors are due to the x and/or y values exceeding the above // limits. In such cases the float values are set to appropriate // minimum or maximum values. ///////////////////////////////////////////////////////////////////// int convert_from_xastir_coordinates ( float *f_longitude, float *f_latitude, long x, long y ) { //fprintf(stderr,"convert_from_xastir_coordinates\n"); int result = 1; // assume the input values are in range if (x < 0l ) { fprintf(stderr, "convert_from_xastir_coordinates:X out-of-range (too low):%lu\n", x); x = 0; result = 0; } if (x > 129600000l) { fprintf(stderr, "convert_from_xastir_coordinates:X out-of-range (too high):%lu\n", x); x = 129600000l; result = 0; } if (y < 0l) { fprintf(stderr, "convert_from_xastir_coordinates:Y out-of-range (too low):%lu\n", y); y = 0; result = 0; } if (y > 64800000l) { fprintf(stderr, "convert_from_xastir_coordinates:Y out-of-range (too high):%lu\n", y); y = 64800000l; result = 0; } *f_latitude = (float)( -((y - 32400000l) / 360000.0) ); *f_longitude = (float)( (x - 64800000l) / 360000.0 ); //fprintf(stderr,"input x: %lu\tinput y: %lu\n", // x, // y); //fprintf(stderr,"latitude: %f\tlongitude: %f\n", // *f_latitude, // *f_longitude); return(result); } ///////////////////////////////////////////////////////////////////// // convert_to_xastir_coordinates() // // Converts from lat/lon to Xastir coordinate system. // First two parameters are the output Xastir X/Y values, // 2nd two are the input floating point lat/lon values. // // 0 (90 deg. or 90N) // // 0 (-180 deg. or 180W) 129,600,000 (180 deg. or 180E) // // 64,800,000 (-90 deg. or 90S) // // Returns 0 if error, 1 if good values were converted. ///////////////////////////////////////////////////////////////////// int convert_to_xastir_coordinates ( unsigned long* x, unsigned long* y, float f_longitude, float f_latitude ) { int ok = 1; *y = (unsigned long)(32400000l + (360000.0 * (-f_latitude))); *x = (unsigned long)(64800000l + (360000.0 * f_longitude)); if (f_longitude < -180.0) { fprintf(stderr, "convert_to_xastir_coordinates:Longitude out-of-range (too low):%f\n", f_longitude); *x = 0; ok = 0; } if (f_longitude > 180.0) { fprintf(stderr, "convert_to_xastir_coordinates:Longitude out-of-range (too high):%f\n", f_longitude); *x = 129600000l; ok = 0; } if (f_latitude < -90.0) { fprintf(stderr, "convert_to_xastir_coordinates:Latitude out-of-range (too low):%f\n", f_latitude); *y = 0; ok = 0; } if (f_latitude > 90.0) { fprintf(stderr, "convert_to_xastir_coordinates:Latitude out-of-range (too high):%f\n", f_latitude); *y = 64800000l; ok =0; } return(ok); } char *remove_all_spaces(char *data) { char *ptr; int length = strlen(data); ptr = data; while ( (ptr = strpbrk(data, " ")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); length--; } // Terminate at the new string length data[length] = '\0'; return(data); } char *remove_leading_spaces(char *data) { int i,j; int count; if (data == NULL) { return NULL; } if (strlen(data) == 0) { return NULL; } count = 0; // Count the leading space characters for (i = 0; i < (int)strlen(data); i++) { if (data[i] == ' ') { count++; } else // Found a non-space { break; } } // Check whether entire string was spaces if (count == (int)strlen(data)) { // Empty the string data[0] = '\0'; } else if (count > 0) // Found some spaces { i = 0; for( j = count; j < (int)strlen(data); j++ ) { data[i++] = data[j]; // Move string left } data[i] = '\0'; // Terminate the new string } return(data); } char *remove_trailing_spaces(char *data) { int datalen; if (data != NULL) { datalen=strlen(data); for(datalen--; datalen>=0; datalen--) if(data[datalen] == ' ') { data[datalen] = '\0'; } else { break; } } // May end up with nothing left. return(data); } char *remove_trailing_asterisk(char *data) { int datalen; if (data != NULL) { datalen=strlen(data); for(datalen--; datalen>0; datalen--) { if(data[datalen] == '*') { data[datalen] = '\0'; } else { break; } } } // May end up with nothing left. return(data); } // Removes trailing "-0" from string. // // Modifies "data" variable. // char *remove_trailing_dash_zero(char *data) { char *ptr; char *ptr2; int len = strlen(data); // String too short? if (len < 2) { return(data); } ptr2 = data + len - 1; // Point to last char ptr = ptr2 - 1; // Point to next-to-last char // Check for "-0" at end. Remove if found. if (*ptr == '-' && *ptr2 == '0') { *ptr = '\0'; // Terminate } return(data); } // // Inserts localtime date/time in "timestring". Timestring // Should be at least 101 characters long. // void get_timestamp(char *timestring) { struct tm *time_now; time_t secs_now; secs_now=sec_now(); time_now = localtime(&secs_now); // %e is not implemented on all systems, but %d should be // (void)strftime(timestring,100,"%a %b %e %H:%M:%S %Z %Y",time_now); (void)strftime(timestring,100,"%a %b %d %H:%M:%S %Z %Y",time_now); } /* function get_iso_datetime converts time in seconds to an ISO date * time in the form yyyy-mm-dd hh:mm:ss utc_offset * @param aTime time in seconds since the begining of the unix epoch * @param timestring pointer to a char[101] into which the timestamp * is written in the format yyyy-mm-dd hh:mm:ss followed by a utc * offset for the timezone. * @param nowIfNotSet when true, if aTime is not set (int)aTime==0, * then return the current time rather than formatting aTime, when * false, returns formatted aTime even if it was zero. * @param nowIfInvalid when true, if aTime is invalid (int)aTime=-1, * then returns the formatted current time rather than formatting * aTime, otherwise returns formatted invalid time. * @returns 0 on when (int)aTime==-1 where time provided invalid * returns 1 otherwise. */ int get_iso_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid) { struct tm *time_now; time_t secs_now; int returnvalue = 1; if (((int)aTime==0 && nowIfNotSet) || ((int)aTime==-1 && nowIfInvalid)) { secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%F %H:%M:%S %z",time_now); } else { // will also end up here if time_t is -1 (void)strftime(timestring,100,"%F %H:%M:%S %z",localtime(&aTime)); } if ((int)aTime==-1) { returnvalue = 0; } return returnvalue; } /* function get_W3CDTF_datetime converts time in seconds to a W3CDTF date * time in the form yyyy-mm-ddThh:mm:ss-utc_offsethh:mm * See: http://www.w3.org/TR/NOTE-datetime * This is effectively an ISO date, with a T between the date and the * time, no space between the time and the utc offset, and a colon * separating utc offset hours from utc offset seconds. * Example: 2008-01-25T08:35:20-05:00 * @param aTime time in seconds since the begining of the unix epoch * @param timestring pointer to a char[101] into which the timestamp * is written in the format yyyy-mm-ddThh:mm:ss followed by a utc * offset for the timezone, (e.g. -05:00). * @param nowIfNotSet when true, if aTime is not set (int)aTime==0, * then return the current time rather than formatting aTime, when * false, returns formatted aTime even if it was zero. * @param nowIfInvalid when true, if aTime is invalid (int)aTime=-1, * then returns the formatted current time rather than formatting * aTime, otherwise returns formatted invalid time. * @returns 0 on when (int)aTime==-1 where time provided invalid * returns 1 otherwise. */ int get_w3cdtf_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid) { struct tm *time_now; time_t secs_now; int returnvalue = 1; if (((int)aTime==0 && nowIfNotSet) || ((int)aTime==-1 && nowIfInvalid)) { secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(timestring,100,"%FT%H:%M:%S %z",time_now); timestring[19] = timestring[20]; timestring[20] = timestring[21]; timestring[21] = timestring[22]; timestring[22] = ':'; } else { // will also end up here if time_t is -1 (void)strftime(timestring,100,"%FT%H:%M:%S %z",localtime(&aTime)); timestring[19] = timestring[20]; timestring[20] = timestring[21]; timestring[21] = timestring[22]; timestring[22] = ':'; } if ((int)aTime==-1) { returnvalue = 0; } return returnvalue; } /***********************************************************/ /* returns the hour (00..23), localtime */ /***********************************************************/ int get_hours(void) { struct tm *time_now; time_t secs_now; char shour[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(shour,4,"%H",time_now); return(atoi(shour)); } /***********************************************************/ /* returns the minute (00..59), localtime */ /***********************************************************/ int get_minutes(void) { struct tm *time_now; time_t secs_now; char sminute[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(sminute,4,"%M",time_now); return(atoi(sminute)); } /***********************************************************/ /* returns the second (00..61), localtime */ /***********************************************************/ int get_seconds(void) { struct tm *time_now; time_t secs_now; char sminute[5]; secs_now=sec_now(); time_now = localtime(&secs_now); (void)strftime(sminute,4,"%S",time_now); return(atoi(sminute)); } /*********************************************************************/ /* PHG range calculation */ /* NOTE: Keep these calculations consistent with phg_decode! */ /* Yes, there is a reason why they both exist. */ /*********************************************************************/ double phg_range(char p, char h, char g) { double power, height, gain, range; if ( (p < '0') || (p > '9') ) // Power is outside limits { power = 0.0; } else { power = (double)( (p-'0')*(p-'0') ); // lclint said: "Assignment of char to double" here } if (h < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(h-'0')); } if ( (g < '0') || (g > '9') ) // Gain is outside limits { gain = 1.0; } else { gain = pow(10.0, (double)(g-'0') / 10.0); } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // if (range > 70.0) // fprintf(stderr,"PHG%c%c%c results in range of %f\n", p, h, g, range); // Note: Bob Bruninga, WB4APR, decided to cut PHG circles by // 1/2 in order to show more realistic mobile ranges. range = range / 2.0; return(range); } /*********************************************************************/ /* shg range calculation (for DF'ing) */ /* */ /*********************************************************************/ double shg_range(char s, char h, char g) { double power, height, gain, range; if ( (s < '0') || (s > '9') ) // Power is outside limits { s = '0'; } if (s == '0') // No signal strength { power = 10.0 / 0.8; // Preventing divide by zero (same as DOSaprs does it) } else { power = 10 / (s - '0'); // Makes circle smaller with higher signal strengths } if (h < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(h-'0')); } if ( (g < '0') || (g > '9') ) // Gain is outside limits { gain = 1.0; } else { gain = pow(10.0, (double)(g-'0') / 10.0); } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); range = (range * 40) / 51; // Present fudge factors used in DOSaprs //fprintf(stderr,"SHG%c%c%c results in range of %f\n", s, h, g, range); return(range); } /*********************************************************************/ /* PHG decode */ /* NOTE: Keep these calculations consistent with phg_range! */ /* Yes, there is a reason why they both exist. */ /*********************************************************************/ void phg_decode(const char *langstr, const char *phg, char *phg_decoded, int phg_decoded_length, int english_units) { double power, height, gain, range; char directivity[6], temp[64]; int gain_db; if (strlen(phg) != 7) { xastir_snprintf(phg_decoded, phg_decoded_length, "%s %s", langstr, langcode("WPUPSTI073") ); // "BAD PHG" return; } if ( (phg[3] < '0') || (phg[3] > '9') ) // Power is outside limits { power = 0.0; } else { power = (double)( (phg[3]-'0')*(phg[3]-'0') ); } if (phg[4] < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(phg[4]-'0')); } if ( (phg[5] < '0') || (phg[5] > '9') ) // Gain is outside limits { gain = 1.0; gain_db = 0; } else { gain = pow(10.0, (double)(phg[5]-'0') / 10.0); gain_db = phg[5]-'0'; } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // Note: Bob Bruninga, WB4APR, decided to cut PHG circles by // 1/2 in order to show more realistic mobile ranges. range = range / 2.0; switch (phg[6]) { case '0': xastir_snprintf(directivity, sizeof(directivity), "%s", langcode("WPUPSTI071") ); // "omni" break; case '1': xastir_snprintf(directivity, sizeof(directivity), "%s", " NE"); break; case '2': xastir_snprintf(directivity, sizeof(directivity), "%s", " E"); break; case '3': xastir_snprintf(directivity, sizeof(directivity), "%s", " SE"); break; case '4': xastir_snprintf(directivity, sizeof(directivity), "%s", " S"); break; case '5': xastir_snprintf(directivity, sizeof(directivity), "%s", " SW"); break; case '6': xastir_snprintf(directivity, sizeof(directivity), "%s", " W"); break; case '7': xastir_snprintf(directivity, sizeof(directivity), "%s", " NW"); break; case '8': xastir_snprintf(directivity, sizeof(directivity), "%s", " N"); break; default: directivity[0] = '\0'; break; } if (english_units) xastir_snprintf(temp, sizeof(temp), "%.0fW @ %.0fft %s, %ddB%s, %s %.1fmi", power, height, langcode("WPUPSTI070"), // HAAT gain_db, directivity, langcode("WPUPSTI072"), // range range); else xastir_snprintf(temp, sizeof(temp), "%.0fW @ %.1fm %s, %ddB%s, %s %.1fkm", power, height*0.3048, langcode("WPUPSTI070"), // HAAT gain_db, directivity, langcode("WPUPSTI072"), // range range*1.609344); xastir_snprintf(phg_decoded, phg_decoded_length, "%s %s", langstr, temp); } /*********************************************************************/ /* SHG decode */ /* */ /*********************************************************************/ void shg_decode(const char *langstr, const char *shg, char *shg_decoded, int shg_decoded_length, int english_units) { double power, height, gain, range; char directivity[6], temp[100], signal[64]; int gain_db; char s; if (strlen(shg) != 7) { xastir_snprintf(shg_decoded, shg_decoded_length, langstr, langcode("WPUPSTI074") ); // "BAD SHG" return; } s = shg[3]; if ( (s < '0') || (s > '9') ) // Signal is outside limits { s = '0'; // force to lowest legal value } switch (s) { case '0': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI076") ); // "No signal detected" break; case '1': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI077") ); // "Detectible signal (Maybe)" break; case '2': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI078") ); // "Detectible signal but not copyable)" break; case '3': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI079") ); // "Weak signal, marginally readable" break; case '4': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI080") ); // "Noisy but copyable signal" break; case '5': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI081") ); // "Some noise, easy to copy signal" break; case '6': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI082") ); // "Good signal w/detectible noise" break; case '7': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI083") ); // "Near full-quieting signal" break; case '8': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI084") ); // "Full-quieting signal" break; case '9': xastir_snprintf(signal, sizeof(signal), "%s", langcode("WPUPSTI085") ); // "Extremely strong & full-quieting signal" break; default: signal[0] = '\0'; break; } if (s == '0') { power = (double)( 10 / 0.8 ); // Preventing divide by zero (same as DOSaprs does it) } else { power = (double)( 10 / (s - '0') ); } if (shg[4] < '0') // Height is outside limits (there is no upper limit according to the spec) { height = 10.0; } else { height = 10.0 * pow(2.0, (double)(shg[4]-'0')); } if ( (shg[5] < '0') || (shg[5] > '9') ) // Gain is outside limits { gain = 1.0; gain_db = 0; } else { gain = pow(10.0, (double)(shg[5]-'0') / 10.0); gain_db = shg[5]-'0'; } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); range = range * 0.85; // Present fudge factor (used by DOSaprs) switch (shg[6]) { case '0': xastir_snprintf(directivity, sizeof(directivity), "%s ", langcode("WPUPSTI071") ); // "omni" break; case '1': xastir_snprintf(directivity, sizeof(directivity), "%s", " NE"); break; case '2': xastir_snprintf(directivity, sizeof(directivity), "%s", " E"); break; case '3': xastir_snprintf(directivity, sizeof(directivity), "%s", " SE"); break; case '4': xastir_snprintf(directivity, sizeof(directivity), "%s", " S"); break; case '5': xastir_snprintf(directivity, sizeof(directivity), "%s", " SW"); break; case '6': xastir_snprintf(directivity, sizeof(directivity), "%s", " W"); break; case '7': xastir_snprintf(directivity, sizeof(directivity), "%s", " NW"); break; case '8': xastir_snprintf(directivity, sizeof(directivity), "%s", " N"); break; default: directivity[0] = '\0'; break; } if (english_units) { xastir_snprintf(temp, sizeof(temp), "%.0fft %s, %ddB%s, %s: %.1fmi, %s", height, langcode("WPUPSTI070"), // "HAAT" gain_db, directivity, langcode("WPUPSTI075"), // "DF Range" range, signal); } else { xastir_snprintf(temp, sizeof(temp), "%.1fm %s, %ddB%s, %s: %.1fkm, %s", height*0.3048, langcode("WPUPSTI070"), // "HAAT" gain_db, directivity, langcode("WPUPSTI075"), // "DF Range" range*1.609344, signal); } xastir_snprintf(shg_decoded, shg_decoded_length, langstr, temp); } /*********************************************************************/ /* Bearing decode */ /* */ /*********************************************************************/ void bearing_decode(const char *langstr, const char *bearing_str, const char *NRQ, char *bearing_decoded, int bearing_decoded_length, int english_units) { int bearing, range, width; char N,R,Q; char temp[64]; //fprintf(stderr,"bearing_decode incoming: bearing is %s, NRQ is %s\n", bearing_str, NRQ); if (strlen(bearing_str) != 3) { xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, langcode("WPUPSTI086") ); // "BAD BEARING" return; } if (strlen(NRQ) != 3) { xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, langcode("WPUPSTI087") ); // "BAD NRQ" return; } bearing = atoi(bearing_str); N = NRQ[0]; R = NRQ[1]; Q = NRQ[2]; range = 0; width = 0; if (N != 0) { //fprintf(stderr,"N != 0\n"); range = pow(2.0,R - '0'); switch (Q) { case('1'): width = 240; // Degrees of beam width. What's the point? break; case('2'): width = 120; // Degrees of beam width. What's the point? break; case('3'): width = 64; // Degrees of beam width. What's the point? break; case('4'): width = 32; // Degrees of beam width. Starting to be usable. break; case('5'): width = 16; // Degrees of beam width. Usable. break; case('6'): width = 8; // Degrees of beam width. Usable. break; case('7'): width = 4; // Degrees of beam width. Nice! break; case('8'): width = 2; // Degrees of beam width. Nice! break; case('9'): width = 1; // Degrees of beam width. Very Nice! break; default: width = 8; // Degrees of beam width break; } //fprintf(stderr,"Width = %d\n",width); if (english_units) { xastir_snprintf(temp, sizeof(temp), "%i%c, %s: %i%c, %s: %i mi", bearing, 0xb0, // Degree symbol langcode("WPUPSTI088"), // DF Beamwidth width, 0xb0, // Degree symbol langcode("WPUPSTI089"), // DF Length range); } else { xastir_snprintf(temp, sizeof(temp), "%i%c, %s: %i%c, %s: %0.2f km", bearing, 0xb0, // Degree symbol langcode("WPUPSTI088"), // DF Beamwidth width, 0xb0, // Degree symbol langcode("WPUPSTI089"), // DF Length range*1.609344); } } else { xastir_snprintf(temp, sizeof(temp), "%s", langcode("WPUPSTI090") ); // "Not Valid" //fprintf(stderr,"N was 0\n"); } xastir_snprintf(bearing_decoded, bearing_decoded_length, langstr, temp); //fprintf(stderr,"bearing_decoded:%s\n", bearing_decoded); //fprintf(stderr,"temp:%s\n", temp); } //********************************************************************/ // get_line - read a line from a file */ // // NOTE: This routine will not work for binary files. It works only // for ASCII-format files, and terminates each line at the first // control-character found (unless it's a tab). Converts tab // character to 1 space character. // //********************************************************************/ /* char *get_line(FILE *f, char *linedata, int maxline) { char temp_line[32768]; int i; // Snag one string from the file. We'll end up with a // terminating zero at temp_line[32767] in any case, because the // max quantity we'll get here will be 32767 with a terminating // zero added after whatever quantity is read. (void)fgets(temp_line, 32768, f); // A newline may have been added by the above fgets call. // Change any newlines or other control characters to line-end // characters. for (i = 0; i < strlen(temp_line); i++) { // Change any control characters to '\0'; if (temp_line[i] < 0x20) { if (temp_line[i] == '\t') { // Found a tab char temp_line[i] = ' '; // Convert to a space char } else { // Not a tab if (temp_line[i] != '\n') { // LF if ( (i != (strlen(temp_line) - 2) ) // CRLF && (i != (strlen(temp_line) - 1) ) ) { // CR fprintf(stderr,"get_line: found control chars in: %s\n", temp_line); } } temp_line[i] = '\0'; // Terminate the string } } } xastir_snprintf(linedata, maxline, "%s", temp_line); return(linedata); } */ char *get_line(FILE *f, char *linedata, int maxline) { int length; // Write terminating chars throughout variable memset(linedata,0,maxline); // Get the data if (fgets(linedata, maxline, f) == 0) { return "\0"; // Couldn't read from file: Return empty string } // Change CR/LF to '\0' length = strlen(linedata); // Check the last two characters if (length > 0) { if ( (linedata[length - 1] == '\n') || (linedata[length - 1] == '\r') ) { linedata[length - 1] = '\0'; } } if (length > 1) { if ( (linedata[length - 2] == '\n') || (linedata[length - 2] == '\r') ) { linedata[length - 2] = '\0'; } } return(linedata); } // time_from_aprsstring() // // Called from alert.c:alert_build_list() only. Converts to // localtime if it's a zulu time string we're parsing. // time_t time_from_aprsstring(char *aprs_time) { int day, hour, minute; char tz[20]; struct tm *time_now, alert_time; time_t timenw; long zone; #ifndef HAVE_TM_GMTOFF #ifdef __CYGWIN__ // Use "_timezone" instead of timezone in Cygwin #define timezone _timezone #else // __CYGWIN__ extern time_t timezone; #endif // __CYGWIN__ #endif // HAVE_TM_GMTOFF #ifdef __CYGWIN__ // Must call tzset before using the _timezone variable in // Cygwin, else the timezone won't have been initialized. tzset(); #endif // __CYGWIN__ // Compute our current time and the offset from GMT. If // daylight savings time is in effect, factor that in as well. (void)time(&timenw); time_now = localtime(&timenw); #ifdef HAVE_TM_GMTOFF // tm_gmtoff is the GMT offset in seconds. Some Unix systems // have this extra field in the tm struct, some don't. // tm_gmtoff is seconds EAST of UTC. zone = time_now->tm_gmtoff; //fprintf(stderr,"gmtoff: %ld, tm_isdst: %d\n", //time_now->tm_gmtoff, //time_now->tm_isdst); #else // HAVE_TM_GMTOFF // Note: timezone is seconds WEST of UTC. Need to negate // timezone to have the offset occur in the correct direction. zone = -((int)timezone - 3600 * (int)(time_now->tm_isdst > 0)); //fprintf(stderr,"timezone: %d, tm_isdst: %d\n", //timezone, //time_now->tm_isdst); #endif // HAVE_TM_GMTOFF // zone should now be the number to subtract in order to get // localtime, in seconds. For PST, I get -28800 which equals -8 // hours. Summertime I should get -25200, or -7 hours. //fprintf(stderr,"Zone: %ld\n",zone); // Split the input time string into its component parts. tz[0] = tz[1] = '\0'; switch (sscanf(aprs_time, "%2d%2d%2d%19s", &day, &hour, &minute, tz)) { case 0: day = 0; /* Falls through. */ case 1: hour = 0; /* Falls through. */ case 2: minute = 0; /* Falls through. */ default: break; } if (day > 31) { day = 31; // Wierd, can't have too many days in the month! hour = 23; minute = 59; } // We set up our alert_time so that it points into the same // struct as time_now. We do this both so that we can get // automatically filled in pieces of the struct (year, etc), and // so that we have a more global struct to return the time in. // We'll have to adjust a few things like month/year if the time // is too far distant from our current time and crosses some // boundary. alert_time = *time_now; alert_time.tm_sec = 0; //fprintf(stderr,"alert_time: %d %d %d\n", // alert_time.tm_mday, // alert_time.tm_hour, // alert_time.tm_min); // Check to see how many parameters we parsed, and do our // computations accordingly. if (day) // If we parsed out the day { // Check whether our new day is more than ten days +/- from // the current day of the month. If so, assume it was from // the month previous or after. if (day < (time_now->tm_mday - 10)) { // Day of month went down drastically. Must be a date // in the next month. Bump up by one month and check // whether we overflowed into the next year. Note that // month ranges from 0 to 11. if (++alert_time.tm_mon > 11) { alert_time.tm_mon = 0; alert_time.tm_year++; } } else if (day > (time_now->tm_mday + 10)) { // Day of month went up drastically. Must be a date // during last month. Decrement by one month and check // whether we need to also decrement the year. if (--alert_time.tm_mon < 0) { alert_time.tm_mon = 11; alert_time.tm_year--; } } // Fill in the struct with our new values that we parsed. alert_time.tm_mday = day; alert_time.tm_min = minute; alert_time.tm_hour = hour; // Need to do conversions from zulu time? if ((char)tolower((int)tz[0]) == 'z') { // Yep, do the conversions. Note that the zone variable // already has the sign set correctly to get the correct // time by using addition (PDT zone = -28800). // Initialize daylight savings time to 0 in this // instance, 'cuz we're starting with Zulu time and we // want the localtime conversion to change it correctly. // Zulu time has no daylight savings time offset. // // WE7U: // No, it gave us an offset of 6 hours from UTC when we set this to // zero, 7 hours (correct) when we set it to one, during the summer. // Hopefully it will give us an 8-hour offset during the wintertime // but that remains to be seen... // // FYI: We're in daylight savings time during the summer, when // we're at a 7-hour offset. Winter is actual time and a -8 hour // offset. // // One on-line resource suggested setting it to -1 for automatic // determination of DST. This works too, during the summer. Again, // check during the wintertime too when we're at normal time. // alert_time.tm_isdst = -1; // Do the hour offset alert_time.tm_hour += zone/3600; // Now check whether we have any offsets left to do. zone %= 3600; if (zone) { alert_time.tm_min += zone/60; } // Now check whether we have any overflows. According // to the "mktime()" man page, we probably don't need to // do this for overflow (It normalizes the time itself), // but I think we still need to for underflow. //WE7U: Check this stuff carefully! if (alert_time.tm_min > 59) { alert_time.tm_hour++; alert_time.tm_min -= 60; } if (alert_time.tm_hour > 23) { alert_time.tm_mday++; alert_time.tm_hour -= 24; if (mktime(&alert_time) == -1) { alert_time.tm_mday = 1; alert_time.tm_mon++; if (mktime(&alert_time) == -1) { alert_time.tm_mon = 0; alert_time.tm_year++; } } } else if (alert_time.tm_hour < 0) { alert_time.tm_hour += 24; if (--alert_time.tm_mday <= 0) { if (--alert_time.tm_mon < 0) { alert_time.tm_year--; alert_time.tm_mon = 11; alert_time.tm_mday = 31; } else if (alert_time.tm_mon == 3 || alert_time.tm_mon == 5 || alert_time.tm_mon == 8 || alert_time.tm_mon == 10) { alert_time.tm_mday = 30; } else if (alert_time.tm_mon == 1) { alert_time.tm_mday = (alert_time.tm_year%4 == 0) ? 29: 28; } else { alert_time.tm_mday = 31; } } } } } else // We didn't parse out the day from the input string. { // What's this all about??? Different format of APRS // time/date string? alert_time.tm_year--; } if ( debug_level & 2 ) { time_t a_time,now_time,diff; fprintf(stderr,"\n Input: %s\n",aprs_time); fprintf(stderr,"Output: %02d%02d%02d\n\n", alert_time.tm_mday, alert_time.tm_hour, alert_time.tm_min); a_time = mktime(&alert_time); fprintf(stderr,"Alert: %ld\n", (long)a_time); now_time = sec_now(); fprintf(stderr," Now: %ld\n", (long)now_time); diff = now_time - a_time; if (diff >= 0) { fprintf(stderr,"Expired by %ld minutes\n", (long)(diff/60) ); } else { fprintf(stderr,"%ld minutes until expiration\n", (long)((-diff)/60) ); } if (alert_time.tm_isdst > 0) { fprintf(stderr,"Daylight savings time is in effect\n"); } } return(mktime(&alert_time)); } // Note: last_speed should be in knots. // // Input format for lat/long is DDMM.MM or DDMM.MMM format, like: // 4722.93N 12244.17W or // 4722.938N 12244.177W // char *compress_posit(const char *input_lat, const char group, const char *input_lon, const char symbol, const unsigned int last_course, const unsigned int last_speed, const char *phg) { static char pos[100]; char lat[5], lon[5]; char c, s, t, ext; int temp, deg; double minutes; char temp_str[20]; //fprintf(stderr,"lat:%s, long:%s, symbol:%c%c, course:%d, speed:%d, phg:%s\n", // input_lat, // input_lon, // group, // symbol, // last_course, // last_speed, // phg); // Fetch degrees (first two chars) temp_str[0] = input_lat[0]; temp_str[1] = input_lat[1]; temp_str[2] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) xastir_snprintf(temp_str, sizeof(temp_str), "%s", input_lat); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for North latitude if (strstr(input_lat, "N") || strstr(input_lat, "n")) { ext = 'N'; } else { ext = 'S'; } //fprintf(stderr,"ext:%c\n", ext); temp = 380926 * (90 - (deg + minutes / 60.0) * ( ext=='N' ? 1 : -1 )); //fprintf(stderr,"temp: %d\t",temp); lat[3] = (char)(temp%91 + 33); temp /= 91; lat[2] = (char)(temp%91 + 33); temp /= 91; lat[1] = (char)(temp%91 + 33); temp /= 91; lat[0] = (char)(temp + 33); lat[4] = '\0'; //fprintf(stderr,"%s\n",lat); // Fetch degrees (first three chars) temp_str[0] = input_lon[0]; temp_str[1] = input_lon[1]; temp_str[2] = input_lon[2]; temp_str[3] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) xastir_snprintf(temp_str, sizeof(temp_str), "%s", input_lon); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees temp_str[2] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for West longitude if (strstr(input_lon, "W") || strstr(input_lon, "w")) { ext = 'W'; } else { ext = 'E'; } //fprintf(stderr,"ext:%c\n", ext); temp = 190463 * (180 + (deg + minutes / 60.0) * ( ext=='W' ? -1 : 1 )); //fprintf(stderr,"temp: %d\t",temp); lon[3] = (char)(temp%91 + 33); temp /= 91; lon[2] = (char)(temp%91 + 33); temp /= 91; lon[1] = (char)(temp%91 + 33); temp /= 91; lon[0] = (char)(temp + 33); lon[4] = '\0'; //fprintf(stderr,"%s\n",lon); // Set up csT bytes for course/speed if either are non-zero c = s = t = ' '; if (last_course > 0 || last_speed > 0) { if (last_course >= 360) { c = '!'; // 360 would be past 'z'. Set it to zero. } else { c = (char)(last_course/4 + 33); } s = (char)(log(last_speed + 1.0) / log(1.08) + 33.5); // Poor man's rounding + ASCII t = 'C'; } // Else set up csT bytes for PHG if within parameters else if (strlen(phg) >= 6) { double power, height, gain, range, s_temp; c = '{'; if ( (phg[3] < '0') || (phg[3] > '9') ) // Power is out of limits { power = 0.0; } else { power = (double)((int)(phg[3]-'0')); power = power * power; // Lowest possible value is 0.0 } if (phg[4] < '0') // Height is out of limits (no upper limit according to the spec) { height = 10.0; } else { height= 10.0 * pow(2.0,(double)phg[4] - (double)'0'); // Lowest possible value is 10.0 } if ( (phg[5] < '0') || (phg[5] > '9') ) // Gain is out of limits { gain = 1.0; } else { gain = pow(10.0,((double)(phg[5]-'0') / 10.0)); // Lowest possible value is 1.0 } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // Lowest possible value is 0.0 // Check for range of 0, and skip log10 if so if (range != 0.0) { s_temp = log10(range/2) / log10(1.08) + 33.0; } else { s_temp = 0.0 + 33.0; } s = (char)(s_temp + 0.5); // Cheater's way of rounding, add 0.5 and truncate t = 'C'; } // Note that we can end up with three spaces at the end if no // course/speed/phg were supplied. Do not knock this down, as // the compressed posit has a fixed 13-character length // according to the spec! // xastir_snprintf(pos, sizeof(pos), "%c%s%s%c%c%c%c", compress_group(group), lat, lon, symbol, c, s, t); //fprintf(stderr,"New compressed pos: (%s)\n",pos); return pos; } char compress_group(char group_in) { char group_out=group_in; if (group_in >= '0' && group_in <= '9') { group_out=group_in - '0' + 'a'; } return (group_out); } /* * See if position is defined * 90°N 180°W (0,0 in internal coordinates) is our undefined position * 0N/0E is excluded from trails, could be excluded from map (#define ACCEPT_0N_0E) */ int position_defined(long lat, long lon, int UNUSED(strict)) { if (lat == 0l && lon == 0l) { return(0); // undefined location } #ifndef ACCEPT_0N_0E if (strict) #endif // ACCEPT_0N_0E if (lat == 90*60*60*100l && lon == 180*60*60*100l) // 0N/0E { return(0); // undefined location } return(1); } // Function to convert from screen (pixel) coordinates to the Xastir // coordinate system. // void convert_screen_to_xastir_coordinates(int x, int y, long *lat, long *lon) { *lon = (center_longitude - ((screen_width * scale_x)/2) + (x * scale_x)); *lat = (center_latitude - ((screen_height * scale_y)/2) + (y * scale_y)); if (*lon < 0) { *lon = 0l; // 180°W } if (*lon > 129600000l) { *lon = 129600000l; // 180°E } if (*lat < 0) { *lat = 0l; // 90°N } if (*lat > 64800000l) { *lat = 64800000l; // 90°S } } // function to convert from Xastir (long, centi-seconds from 90N/180W) coords // to screen coordinates void convert_xastir_to_screen_coordinates(long lon, long lat, long *x, long *y) { // Convert to screen coordinates. Careful // here! The format conversions you'll need // if you try to compress this into two // lines will get you into trouble. *x = lon - NW_corner_longitude; *y = lat - NW_corner_latitude; *x = (*x)/scale_x; *y = (*y)/scale_y; } // Convert Xastir lat/lon to UTM printable string void convert_xastir_to_UTM_str(char *str, int str_len, long x, long y) { double utmNorthing; double utmEasting; char utmZone[10]; ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), &utmNorthing, &utmEasting, utmZone, sizeof(utmZone) ); utmZone[9] = '\0'; //fprintf(stderr,"%s %07.0f %07.0f\n", utmZone, utmEasting, //utmNorthing ); xastir_snprintf(str, str_len, "%s %07.0f %07.0f", utmZone, utmEasting, utmNorthing); } // Convert Xastir lat/lon to UTM void convert_xastir_to_UTM(double *easting, double *northing, char *zone, int zone_len, long x, long y) { ll_to_utm_ups(E_WGS_84, (double)(-((y - 32400000l )/360000.0)), (double)((x - 64800000l )/360000.0), northing, easting, zone, zone_len); zone[zone_len-1] = '\0'; } // Convert UTM to Xastir lat/lon void convert_UTM_to_xastir(double easting, double northing, char *zone, long *x, long *y) { double lat, lon; utm_ups_to_ll(E_WGS_84, northing, easting, zone, &lat, &lon); // Reverse latitude to fit our coordinate system then convert to // Xastir units. *y = (long)(lat * -360000.0) + 32400000l; // Convert longitude to xastir units *x = (long)(lon * 360000.0) + 64800000l; } // convert latitude from long to string // Input is in Xastir coordinate system // // CONVERT_LP_NOSP = DDMM.MMN // CONVERT_HP_NOSP = DDMM.MMMN // CONVERT_VHP_NOSP = DDMM.MMMMN // CONVERT_LP_NORMAL = DD MM.MMN // CONVERT_HP_NORMAL = DD MM.MMMN // CONVERT_UP_TRK = NDD MM.MMMM // CONVERT_DEC_DEG = DD.DDDDDN // CONVERT_DMS_NORMAL = DD MM SS.SN // CONVERT_DMS_NORMAL_FORMATED = DD'MM'SS.SN // CONVERT_HP_NORMAL_FORMATED = DD'MM.MMMMN // void convert_lat_l2s(long lat, char *str, int str_len, int type) { char ns; float deg, min, sec; int ideg, imin; long temp; str[0] = '\0'; deg = (float)(lat - 32400000l) / 360000.0; // Switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(deg * 100000); ns = 'S'; if (temp <= 0) { ns = 'N'; temp = labs(temp); } ideg = (int)temp / 100000; min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(min * 1000); imin = (int)(temp / 1000); sec = (temp % 1000) * 60.0 / 1000.0; switch (type) { case(CONVERT_LP_NOSP): /* do low P w/no space */ xastir_snprintf(str, str_len, "%02d%05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_LP_NORMAL): /* do low P normal */ xastir_snprintf(str, str_len, "%02d %05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_HP_NOSP): /* do HP w/no space */ xastir_snprintf(str, str_len, "%02d%06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_VHP_NOSP): /* do Very HP w/no space */ xastir_snprintf(str, str_len, "%02d%07.4f%c", ideg, // min+0.00001, // Correct possible unbiased rounding min, ns); break; case(CONVERT_UP_TRK): /* for tracklog files */ xastir_snprintf(str, str_len, "%c%02d %07.4f", ns, ideg, // min+0.00001); // Correct possible unbiased rounding min); break; case(CONVERT_DEC_DEG): xastir_snprintf(str, str_len, "%08.5f%c", // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding ideg+min/60.0, ns); break; case(CONVERT_DMS_NORMAL): xastir_snprintf(str, str_len, "%02d %02d %04.1f%c", ideg, imin, // sec+0.01, // Correct possible unbiased rounding sec, ns); break; case(CONVERT_DMS_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%02d%c%02d\'%04.1f%c", ideg, 0xb0, // Degree symbol imin, // sec+0.01, // Correct possible unbiased rounding sec, ns); break; case(CONVERT_HP_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%02d%c%06.3f%c", ideg, 0xb0, // Degree symbol // min+0.0001, // Correct possible unbiased roundin min, ns); break; case(CONVERT_HP_NORMAL): default: /* do HP normal */ xastir_snprintf(str, str_len, "%02d %06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ns); break; } } // convert longitude from long to string // Input is in Xastir coordinate system // // CONVERT_LP_NOSP = DDDMM.MME // CONVERT_HP_NOSP = DDDMM.MMME // CONVERT_VHP_NOSP = DDDMM.MMMME // CONVERT_LP_NORMAL = DDD MM.MME // CONVERT_HP_NORMAL = DDD MM.MMME // CONVERT_UP_TRK = EDDD MM.MMMM // CONVERT_DEC_DEG = DDD.DDDDDE // CONVERT_DMS_NORMAL = DDD MM SS.SN // CONVERT_DMS_NORMAL_FORMATED = DDD'MM'SS.SN // void convert_lon_l2s(long lon, char *str, int str_len, int type) { char ew; float deg, min, sec; int ideg, imin; long temp; str[0] = '\0'; deg = (float)(lon - 64800000l) / 360000.0; // Switch to integer arithmetic to avoid floating-point rounding // errors. temp = (long)(deg * 100000); ew = 'E'; if (temp <= 0) { ew = 'W'; temp = labs(temp); } ideg = (int)temp / 100000; min = (temp % 100000) * 60.0 / 100000.0; // Again switch to integer arithmetic to avoid floating-point // rounding errors. temp = (long)(min * 1000); imin = (int)(temp / 1000); sec = (temp % 1000) * 60.0 / 1000.0; switch(type) { case(CONVERT_LP_NOSP): /* do low P w/nospacel */ xastir_snprintf(str, str_len, "%03d%05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_LP_NORMAL): /* do low P normal */ xastir_snprintf(str, str_len, "%03d %05.2f%c", ideg, // min+0.001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_HP_NOSP): /* do HP w/nospace */ xastir_snprintf(str, str_len, "%03d%06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_VHP_NOSP): /* do Very HP w/nospace */ xastir_snprintf(str, str_len, "%03d%07.4f%c", ideg, // min+0.00001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_UP_TRK): /* for tracklog files */ xastir_snprintf(str, str_len, "%c%03d %07.4f", ew, ideg, // min+0.00001); // Correct possible unbiased rounding min); break; case(CONVERT_DEC_DEG): xastir_snprintf(str, str_len, "%09.5f%c", // (ideg+min/60.0)+0.000001, // Correct possible unbiased rounding ideg+min/60.0, ew); break; case(CONVERT_DMS_NORMAL): xastir_snprintf(str, str_len, "%03d %02d %04.1f%c", ideg, imin, // sec+0.01, // Correct possible unbiased rounding sec, ew); break; case(CONVERT_DMS_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%03d%c%02d\'%04.1f%c", ideg, 0xb0, // Degree symbol imin, // sec+0.01, // Correct possible unbiased rounding sec, ew); break; case(CONVERT_HP_NORMAL_FORMATED): xastir_snprintf(str, str_len, "%03d%c%06.3f%c", ideg, 0xb0, // Degree symbol // min+0.0001, // Correct possible unbiased rounding min, ew); break; case(CONVERT_HP_NORMAL): default: /* do HP normal */ xastir_snprintf(str, str_len, "%03d %06.3f%c", ideg, // min+0.0001, // Correct possible unbiased rounding min, ew); break; } } /* convert latitude from string to long with 1/100 sec resolution */ // // Input is in [D]DMM.MM[MM]N format (degrees/decimal // minutes/direction) // long convert_lat_s2l(char *lat) /* N=0°=°, Ctr=90°, S=180° */ { long centi_sec; char copy[15]; char n[15]; char *p; char offset; // Find the decimal point if present p = strstr(lat, "."); if (p == NULL) // No decimal point found { return(0l); } memset(copy, '\0', sizeof(copy)); offset = p - lat; // Arithmetic on pointers switch (offset) { case 0: // .MM[MM]N return(0l); // Bad, no degrees or minutes break; case 1: // M.MM[MM]N return(0l); // Bad, no degrees break; case 2: // MM.MM[MM]N return(0l); // Bad, no degrees break; case 3: // DMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "0%s", // Add a leading '0' lat); break; case 4: // DDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "%s", // Copy verbatim lat); break; default: break; } copy[14] = '\0'; centi_sec=0l; if (copy[4]=='.' && ( (char)toupper((int)copy[ 5])=='N' || (char)toupper((int)copy[ 6])=='N' || (char)toupper((int)copy[ 7])=='N' || (char)toupper((int)copy[ 8])=='N' || (char)toupper((int)copy[ 9])=='N' || (char)toupper((int)copy[10])=='N' || (char)toupper((int)copy[11])=='N' || (char)toupper((int)copy[ 5])=='S' || (char)toupper((int)copy[ 6])=='S' || (char)toupper((int)copy[ 7])=='S' || (char)toupper((int)copy[ 8])=='S' || (char)toupper((int)copy[ 9])=='S' || (char)toupper((int)copy[10])=='S' || (char)toupper((int)copy[11])=='S')) { substr(n, copy, 2); // degrees centi_sec=atoi(n)*60*60*100; substr(n, copy+2, 2); // minutes centi_sec += atoi(n)*60*100; substr(n, copy+5, 4); // fractional minutes // Keep the fourth digit if present, as it resolves to 0.6 // of a 1/100 sec resolution. Two counts make one count in // the Xastir coordinate system. // Extend the digits to full precision by adding zeroes on // the end. strncat(n, "0000", sizeof(n) - 1 - strlen(n)); // Get rid of the N/S character if (!isdigit((int)n[2])) { n[2] = '0'; } if (!isdigit((int)n[3])) { n[3] = '0'; } // Terminate substring at the correct digit n[4] = '\0'; //fprintf(stderr,"Lat: %s\n", n); // Add 0.5 (Poor man's rounding) centi_sec += (long)((atoi(n) * 0.6) + 0.5); if ( (char)toupper((int)copy[ 5])=='N' || (char)toupper((int)copy[ 6])=='N' || (char)toupper((int)copy[ 7])=='N' || (char)toupper((int)copy[ 8])=='N' || (char)toupper((int)copy[ 9])=='N' || (char)toupper((int)copy[10])=='N' || (char)toupper((int)copy[11])=='N') { centi_sec = -centi_sec; } centi_sec += 90*60*60*100; } return(centi_sec); } /* convert longitude from string to long with 1/100 sec resolution */ // // Input is in [DD]DMM.MM[MM]W format (degrees/decimal // minutes/direction). // long convert_lon_s2l(char *lon) /* W=0°, Ctr=180°, E=360° */ { long centi_sec; char copy[16]; char n[16]; char *p; char offset; // Find the decimal point if present p = strstr(lon, "."); if (p == NULL) // No decimal point found { return(0l); } memset(copy, '\0', sizeof(copy)); offset = p - lon; // Arithmetic on pointers switch (offset) { case 0: // .MM[MM]N return(0l); // Bad, no degrees or minutes break; case 1: // M.MM[MM]N return(0l); // Bad, no degrees break; case 2: // MM.MM[MM]N return(0l); // Bad, no degrees break; case 3: // DMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "00%s", // Add two leading zeroes lon); break; case 4: // DDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "0%s", // Add leading '0' lon); break; case 5: // DDDMM.MM[MM]N xastir_snprintf(copy, sizeof(copy), "%s", // Copy verbatim lon); break; default: break; } copy[15] = '\0'; centi_sec=0l; if (copy[5]=='.' && ( (char)toupper((int)copy[ 6])=='W' || (char)toupper((int)copy[ 7])=='W' || (char)toupper((int)copy[ 8])=='W' || (char)toupper((int)copy[ 9])=='W' || (char)toupper((int)copy[10])=='W' || (char)toupper((int)copy[11])=='W' || (char)toupper((int)copy[12])=='W' || (char)toupper((int)copy[ 6])=='E' || (char)toupper((int)copy[ 7])=='E' || (char)toupper((int)copy[ 8])=='E' || (char)toupper((int)copy[ 9])=='E' || (char)toupper((int)copy[10])=='E' || (char)toupper((int)copy[11])=='E' || (char)toupper((int)copy[12])=='E')) { substr(n,copy,3); // degrees 013 centi_sec=atoi(n)*60*60*100; substr(n,copy+3,2); // minutes 26 centi_sec += atoi(n)*60*100; // 01326.66E 01326.660E substr(n,copy+6,4); // fractional minutes 66E 660E or 6601 // Keep the fourth digit if present, as it resolves to 0.6 // of a 1/100 sec resolution. Two counts make one count in // the Xastir coordinate system. // Extend the digits to full precision by adding zeroes on // the end. strncat(n, "0000", sizeof(n) - 1 - strlen(n)); // Get rid of the E/W character if (!isdigit((int)n[2])) { n[2] = '0'; } if (!isdigit((int)n[3])) { n[3] = '0'; } n[4] = '\0'; // Make sure substring is terminated //fprintf(stderr,"Lon: %s\n", n); // Add 0.5 (Poor man's rounding) centi_sec += (long)((atoi(n) * 0.6) + 0.5); if ( (char)toupper((int)copy[ 6])=='W' || (char)toupper((int)copy[ 7])=='W' || (char)toupper((int)copy[ 8])=='W' || (char)toupper((int)copy[ 9])=='W' || (char)toupper((int)copy[10])=='W' || (char)toupper((int)copy[11])=='W' || (char)toupper((int)copy[12])=='W') { centi_sec = -centi_sec; } centi_sec +=180*60*60*100;; } return(centi_sec); } /* * Convert latitude from Xastir format to radian */ double convert_lat_l2r(long lat) { double ret; double degrees; degrees = (double)(lat / (100.0*60.0*60.0)) -90.0; ret = (-1)*degrees*(M_PI/180.0); return(ret); } /* * Convert longitude from Xastir format to radian */ double convert_lon_l2r(long lon) { double ret; double degrees; degrees = (double)(lon / (100.0*60.0*60.0)) -180.0; ret = (-1)*degrees*(M_PI/180.0); return(ret); } // Distance calculation (Great Circle) using the Haversine formula // (2-parameter arctan version), which gives better accuracy than // the "Law of Cosines" for short distances. It should be // equivalent to the "Law of Cosines for Spherical Trigonometry" for // longer distances. Haversine is a great-circle calculation. // // // Inputs: lat1/long1/lat2/long2 in radians (double) // // Outputs: Distance in meters between them (double) // double calc_distance_haversine_radian(double lat1, double lon1, double lat2, double lon2) { double dlon, dlat; double a, c, d; double R = EARTH_RADIUS_METERS; #define square(x) (x)*(x) dlon = lon2 - lon1; dlat = lat2 - lat1; a = square((sin(dlat/2.0))) + cos(lat1) * cos(lat2) * square((sin(dlon/2.0))); c = 2.0 * atan2(sqrt(a), sqrt(1.0-a)); d = R * c; return(d); } // Distance calculation (Great Circle) using the Haversine formula // (2-parameter arctan version), which gives better accuracy than // the "Law of Cosines" for short distances. It should be // equivalent to the "Law of Cosines for Spherical Trigonometry" for // longer distances. Haversine is a great-circle calculation. // // // Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) // // Outputs: Distance in meters between them (double) // double calc_distance_haversine(long lat1, long lon1, long lat2, long lon2) { double r_lat1,r_lat2; double r_lon1,r_lon2; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); return(calc_distance_haversine_radian(r_lat1, r_lon1, r_lat2, r_lon2)); } /* * Calculate distance in meters between two locations * * What type of calculation is this, Rhumb Line distance or Great * Circle distance? * Answer: "Law of Cosines for Spherical Trigonometry", which is a * great-circle calculation. * * * Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) * * Outputs: Distance in meters between them (double) * */ double calc_distance_law_of_cosines(long lat1, long lon1, long lat2, long lon2) { double r_lat1,r_lat2; double r_lon1,r_lon2; double r_d; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); r_d = acos(sin(r_lat1) * sin(r_lat2) + cos(r_lat1) * cos(r_lat2) * cos(r_lon1-r_lon2)); //fprintf(stderr,"Law of Cosines Distance: %f\n", // r_d*180*60/M_PI*1852); //fprintf(stderr," Haversine Distance: %f\n\n", // calc_distance_haversine(lat1, lon1, lat2, lon2)); return(r_d*180*60/M_PI*1852); } // Here's where we choose which of the above two functions get used. // double calc_distance(long lat1, long lon1, long lat2, long lon2) { // return(calc_distance_law_of_cosines(lat1, lon1, lat2, lon2)); return(calc_distance_haversine(lat1, lon1, lat2, lon2)); } /* * Calculate distance between two locations in nautical miles and course from loc2 to loc1 * * What type of calculation is this, Rhumb Line distance or Great * Circle distance? * Answer: "Law of Cosines for Spherical Trigonometry", which is a * great-circle calculation, or Haversine, also a great-circle * calculation. * * NOTE: The angle returned is a separate calculation, but using * the unit sphere distance in it's calculation. A great circle * bearing is computed, not a Rhumb-line bearing. * * * Inputs: lat1/long1/lat2/long2 in Xastir coordinate system (long) * Length of course_deg string (int) * * Outputs: Distance in nautical miles between them (double). * course_deg (string) * */ double calc_distance_course(long lat1, long lon1, long lat2, long lon2, char *course_deg, int course_deg_length) { double ret; double r_lat1, r_lat2; double r_lon1, r_lon2; double r_d, r_c, r_m; r_lat1 = convert_lat_l2r(lat1); r_lon1 = convert_lon_l2r(lon1); r_lat2 = convert_lat_l2r(lat2); r_lon2 = convert_lon_l2r(lon2); // Compute the distance. We have a choice between using Law of // Cosines or Haversine Formula here. // 1) Law of Cosines for Spherical Trigonometry. This is // unreliable for small distances because the inverse cosine is // ill-conditioned. A computer carrying seven significant // digits can't distinguish the cosines of distances smaller // than about one minute of arc. // r_d = acos(sin(r_lat1) * sin(r_lat2) + cos(r_lat1) * cos(r_lat2) * cos(r_lon1-r_lon2)); // 2) Haversine Formula. Returns answer in meters. r_m = calc_distance_haversine_radian(r_lat1, r_lon1, r_lat2, r_lon2); // // Conversion from distance in meters back to unit sphere. This // is needed for the course calculation below as well as the // later scaling up to feet/meters or miles/km. r_d = r_m / EARTH_RADIUS_METERS; // Compute the great-circle bearing if (cos(r_lat1) < 0.0000000001) { if (r_lat1>0.0) { r_c=M_PI; } else { r_c=0.0; } } else { if (sin((r_lon2-r_lon1))<0.0) { r_c = acos((sin(r_lat2)-sin(r_lat1)*cos(r_d))/(sin(r_d)*cos(r_lat1))); } else { r_c = (2*M_PI) - acos((sin(r_lat2)-sin(r_lat1)*cos(r_d))/(sin(r_d)*cos(r_lat1))); } } // Return the course xastir_snprintf(course_deg, course_deg_length, "%.1f", (180.0/M_PI)*r_c); // Return the distance (nautical miles?) ret = r_d*180*60/M_PI; /* // Convert from nautical miles to feet fprintf(stderr,"Law of Cosines Distance: %fft\t%fmi\n", ret*5280.0*1.15078, ret*1.15078); // Convert from meters to feet fprintf(stderr," Haversine Distance: %fft\t%fmi\n\n", calc_distance_haversine(lat1, lon1, lat2, lon2)*3.28084, calc_distance_haversine(lat1, lon1, lat2, lon2)/1000/1.609344); */ return(ret); } //***************************************************************** // distance_from_my_station - compute distance from my station and // course with a given call // // return distance and course // // Returns 0.0 for distance if station not found in database or the // station hasn't sent out a posit yet. //***************************************************************** double distance_from_my_station(char *call_sign, char *course_deg, int english_units) { DataRow *p_station; double distance; float value; long l_lat, l_lon; distance = 0.0; l_lat = convert_lat_s2l(my_lat); l_lon = convert_lon_s2l(my_long); p_station = NULL; if (search_station_name(&p_station,call_sign,1)) { // Check whether we have a posit yet for this station if ( (p_station->coord_lat == 0l) && (p_station->coord_lon == 0l) ) { distance = 0.0; } else { value = (float)calc_distance_course(l_lat, l_lon, p_station->coord_lat, p_station->coord_lon, course_deg, sizeof(course_deg)); if (english_units) { distance = value * 1.15078; // nautical miles to miles } else { distance = value * 1.852; // nautical miles to km } } // fprintf(stderr,"DistFromMy: %s %s -> %f\n",temp_lat,temp_long,distance); } else // Station not found { distance = 0.0; } //fprintf(stderr,"Distance for %s: %f\n", call_sign, distance); return(distance); } /*********************************************************************/ /* convert_bearing_to_name - converts a bearing in degrees to */ /* name for the bearing. Expects the degrees as a text string */ /* since that's what the preceding functions output. */ /* Set the opposite flag true for the inverse bearing (from vs to) */ /*********************************************************************/ static struct { double low,high; char *dircode,*lang; } directions[] = { {327.5,360,"N","SPCHDIRN00"}, {0,22.5,"N","SPCHDIRN00"}, {22.5,67.5,"NE","SPCHDIRNE0"}, {67.5,112.5,"E","SPCHDIRE00"}, {112.5,157.5,"SE","SPCHDIRSE0"}, {157.5,202.5,"S","SPCHDIRS00"}, {202.5,247.5,"SW","SPCHDIRSW0"}, {247.5,292.5,"W","SPCHDIRW00"}, {292.5,327.5,"NW","SPCHDIRNW0"}, }; char *convert_bearing_to_name(char *bearing, int opposite) { double deg = atof(bearing); int i; if (opposite) { if (deg > 180) { deg -= 180.0; } else if (deg <= 180) { deg += 180.0; } } for (i = 0; i < (int)( sizeof(directions)/sizeof(directions[0]) ); i++) { if (deg >= directions[i].low && deg < directions[i].high) { return langcode(directions[i].lang); } } return "?"; } int filethere(char *fn) { FILE *f; int ret; ret =0; f=fopen(fn,"r"); if (f != NULL) { ret=1; (void)fclose(f); } return(ret); } int filecreate(char *fn) { FILE *f; int ret; if (! filethere(fn)) // If no file { ret = 0; fprintf(stderr,"Making user %s file\n", fn); f=fopen(fn,"w+"); // Create it if (f != NULL) { ret=1; // We were successful (void)fclose(f); } return(ret); // Couldn't create file for some reason } return(1); // File already exists } time_t file_time(char *fn) { struct stat file_status; if(stat(fn,&file_status)==0) { return((time_t)file_status.st_ctime); } return(-1); } // Function written by Adam Hahn, AI4QB. Contributed to the public // domain. We've modified it from his initial code so any bugs are // our fault. int copy_file(char *infilename, char *outfilename) { FILE *infile, *outfile; char *buffer; size_t numread = 0; if ((infile = fopen(infilename,"rb")) > (FILE *)0) { if ((outfile = fopen(outfilename,"wb")) > (FILE *)0) { buffer = (char *)malloc(1024); while (!feof(infile)) { numread = fread(buffer, 1, 1024, infile); fwrite(buffer, 1, numread, outfile); } free(buffer); fflush(outfile); fclose(outfile); } else { fprintf(stderr,"Error opening destination file %s for writing", outfilename); fclose(infile); return(1); } fclose(infile); } else { fprintf(stderr,"Error opening source file %s for reading", infilename); return(1); } return 0; } // Returns time in seconds since the Unix epoch. // time_t sec_now(void) { time_t timenw; time_t ret; ret = time(&timenw); return(ret); } char *get_time(char *time_here) { struct tm *time_now; time_t timenw; (void)time(&timenw); time_now = localtime(&timenw); (void)strftime(time_here,MAX_TIME,"%m%d%Y%H%M%S",time_now); return(time_here); } /////////////////////////////////// Utilities //////////////////////////////////////////////////// /* * Check for valid path and change it to TAPR format * Add missing asterisk for stations that we must have heard via a digi * Extract port for KAM TNCs * Handle igate injection ID formats: "callsign-ssid,I" & "callsign-0ssid" * * TAPR-2 Format: * KC2ELS-1*>SX0PWT,RELAY,WIDE:`2`$l##>/>"4)} * * AEA Format: * KC2ELS-1*>RELAY>WIDE>SX0PWT:`2`$l##>/>"4)} */ int valid_path(char *path) { int i,len,hops,j; int type,ast,allast,ins; char ch; len = (int)strlen(path); type = 0; // 0: unknown, 1: AEA '>', 2: TAPR2 ',', 3: mixed hops = 1; ast = 0; allast = 0; // There are some multi-port TNCs that deliver the port at the end // of the path. For now we discard this information. If there is // multi-port TNC support some day, we should write the port into // our database. // KAM: /V /H // KPC-9612: /0 /1 /2 if (len > 2 && path[len-2] == '/') { ch = path[len-1]; if (ch == 'V' || ch == 'H' || ch == '0' || ch == '1' || ch == '2') { path[len-2] = '\0'; len = (int)strlen(path); } } // One way of adding igate injection ID is to add "callsign-ssid,I". // We need to remove the ",I" portion so it doesn't count as another // digi here. This should be at the end of the path. if (len > 2 && path[len-2] == ',' && path[len-1] == 'I') // Found ",I" { //fprintf(stderr,"%s\n",path); //fprintf(stderr,"Found ',I'\n"); path[len-2] = '\0'; len = (int)strlen(path); //fprintf(stderr,"%s\n\n",path); } // Now look for the same thing but with a '*' character at the end. // This should be at the end of the path. if (len > 3 && path[len-3] == ',' && path[len-2] == 'I' && path[len-1] == '*') // Found ",I*" { //fprintf(stderr,"%s\n",path); //fprintf(stderr,"Found ',I*'\n"); path[len-3] = '\0'; len = (int)strlen(path); //fprintf(stderr,"%s\n\n",path); } // Another method of adding igate injection ID is to add a '0' in front of // the SSID. For WE7U it would change to WE7U-00, for WE7U-15 it would // change to WE7U-015. Take out this zero so the rest of the decoding will // work. This should be at the end of the path. // Also look for the same thing but with a '*' character at the end. if (len > 6) { for (i=len-1; i>len-6; i--) { if (path[i] == '-' && path[i+1] == '0') { //fprintf(stderr,"%s\n",path); for (j=i+1; j' || ch == ',') // found digi call separator { // We're at the start of a callsign entry in the path if (ast > 1 || (ast == 1 && i-j > 10) || (ast == 0 && (i == j || i-j > 9))) { if (debug_level & 1) { fprintf(stderr, "valid_path(): Bad Path: More than one * in call or wrong call size\n"); } return(0); // more than one asterisk in call or wrong call size } ast = 0; // reset local asterisk counter j = i+1; // set to start of next call if (ch == ',') { type |= 0x02; // set TAPR2 flag } else { type |= 0x01; // set AEA flag (found '>') } hops++; // count hops } else // digi call character or asterisk { // We're in the middle of a callsign entry if (ch == '*') { ast++; // count asterisks in call allast++; // count asterisks in path } else if ((ch <'A' || ch > 'Z') // Not A-Z && (ch <'a' || ch > 'z') // Not a-z && (ch <'0' || ch > '9') // Not 0-9 && ch != '-') { // Note that Q-construct and internet callsigns can // have a-z in them, AX.25 callsigns cannot unless // they are in a 3rd-party packet. if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: Anti-loop stuff from aprsd or lower-case chars found\n"); } return(0); // wrong character in path } } } if (ast > 1 || (ast == 1 && i-j > 10) || (ast == 0 && (i == j || i-j > 9))) { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: More than one * or wrong call size (2)\n"); } return(0); // more than one asterisk or wrong call size } if (type == 0x03) { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: Wrong format, both > and , in path\n"); } return(0); // wrong format, both '>' and ',' in path } if (hops > 9) // [APRS Reference chapter 3] { if (debug_level & 1) { fprintf(stderr, "valid_path: Bad Path: hops > 9\n"); } return(0); // too much hops, destination + 0-8 digipeater addresses } if (type == 0x01) { int delimiters[20]; int k = 0; char dest[15]; char rest[100]; for (i=0; i') { path[i] = ','; // Exchange separator character delimiters[k++] = i; // Save the delimiter indexes } } // We also need to move the destination callsign to the end. // AEA has them in a different order than TAPR-2 format. // We'll move the destination address between delimiters[0] // and [1] to the end of the string. //fprintf(stderr,"Orig. Path:%s\n",path); // Save the destination xastir_snprintf(dest,sizeof(dest),"%s",&path[delimiters[--k]+1]); dest[strlen(path) - delimiters[k] - 1] = '\0'; // Terminate it dest[14] = '\0'; // Just to make sure path[delimiters[k]] = '\0'; // Delete it from the original path //fprintf(stderr,"Destination: %s\n",dest); // TAPR-2 Format: // KC2ELS-1*>SX0PWT,RELAY,WIDE:`2`$l##>/>"4)} // // AEA Format: // KC2ELS-1*>RELAY>WIDE>SX0PWT:`2`$l##>/>"4)} // 9 15 20 // We now need to insert the destination into the middle of // the string. Save part of it in another variable first. xastir_snprintf(rest, sizeof(rest), "%s", path); //fprintf(stderr,"Rest:%s\n",rest); xastir_snprintf(path,len+1,"%s,%s",dest,rest); //fprintf(stderr,"New Path:%s\n",path); } if (allast < 1) // try to insert a missing asterisk { ins = 0; hops = 0; for (i=0; i 0 && (j - i) == 5) // WIDE3 { if ( path[ i ] == 'W' && path[i+1] == 'I' && path[i+2] == 'D' && path[i+3] == 'E' && path[i+4] >= '0' && path[i+4] <= '9') { ins = j; } } /* Don't do this! It can mess up relay/wide1-1 digipeating by adding an asterisk later in the path than the first unused digi. if (hops > 0 && (j - i) == 7) { // WIDE3-2 if ( path[ i ] == 'W' && path[i+1] == 'I' && path[i+2] == 'D' && path[i+3] == 'E' && path[i+4] >= '0' && path[i+4] <= '9' && path[i+5] == '-' && path[i+6] >= '0' && path[i+6] <= '9' && (path[i+4] != path[i+6]) ) { ins = j; } } */ if (hops > 0 && (j - i) == 6) // TRACE3 { if ( path[ i ] == 'T' && path[i+1] == 'R' && path[i+2] == 'A' && path[i+3] == 'C' && path[i+4] == 'E' && path[i+5] >= '0' && path[i+5] <= '9') { if (hops == 1) { ins = j; } else { ins = i-1; } } } /* Don't do this! It can mess up relay/wide1-1 digipeating by adding an asterisk later in the path than the first unused digi. if (hops > 0 && (j - i) == 8) { // TRACE3-2 if ( path[ i ] == 'T' && path[i+1] == 'R' && path[i+2] == 'A' && path[i+3] == 'C' && path[i+4] == 'E' && path[i+5] >= '0' && path[i+5] <= '9' && path[i+6] == '-' && path[i+7] >= '0' && path[i+7] <= '9' && (path[i+5] != path[i+7]) ) { if (hops == 1) ins = j; else ins = i-1; } } */ hops++; i = j; // skip to start of next call } if (ins > 0) { for (i=len; i>=ins; i--) { path[i+1] = path[i]; // generate space for '*' // we work on a separate path copy which is long enough to do it } path[ins] = '*'; // and insert it } } return(1); // Path is good } /* * Check for a valid AX.25 call * Valid calls consist of up to 6 uppercase alphanumeric characters * plus optional SSID (four-bit integer) [APRS Reference, AX.25 Reference] * * We originally required at least one number so-as to get rid of calls like * "NOCALL", but got rid of that code. */ int valid_call(char *call) { int len, ok; int i, del, has_chr; char c; has_chr = 0; ok = 1; len = (int)strlen(call); if (len == 0) { return(0); // wrong size } while (call[0]=='c' && call[1]=='m' && call[2]=='d' && call[3]==':') { // Erase TNC prompts from beginning of callsign. This may // not be the right place to do this, but it came in handy // here, so that's where I put it. -- KB6MER if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call); makePrintable(filtered_data); fprintf(stderr,"valid_call: Command Prompt removed from: %s", filtered_data); } for(i=0; call[i+4]; i++) { call[i]=call[i+4]; } call[i++]=0; call[i++]=0; call[i++]=0; call[i++]=0; len=strlen(call); if (debug_level & 1) { char filtered_data[MAX_LINE_SIZE+1]; xastir_snprintf(filtered_data, sizeof(filtered_data), "%s", call); makePrintable(filtered_data); fprintf(stderr," result: %s", filtered_data); } } if (len > 9) { return(0); // Too long for valid call (6-2 max e.g. KB6MER-12) } del = 0; for (i=len-2; ok && i>0 && i>=len-3; i--) // search for optional SSID { if (call[i] =='-') { del = i; // found the delimiter } } if (del) // we have a SSID, so check it { if (len-del == 2) // 2 char SSID { if (call[del+1] < '1' || call[del+1] > '9') // -1 ... -9 { del = 0; } } else // 3 char SSID { if (call[del+1] != '1' || call[del+2] < '0' || call[del+2] > '5') // -10 ... -15 { del = 0; } } } if (del) { len = del; // length of base call } for (i=0; ok && i= 'A' && c <= 'Z') { has_chr = 1; // we need at least one char } else if (c >= '0' && c <= '9') { // We originally required at least one number } else { ok = 0; // wrong character in call } } // if (!has_num || !has_chr) // with this we also discard NOCALL etc. if (!has_chr) { ok = 0; } ok = (ok && strcmp(call,"NOCALL") != 0); // check for errors ok = (ok && strcmp(call,"ERROR!") != 0); ok = (ok && strcmp(call,"WIDE") != 0); ok = (ok && strcmp(call,"RELAY") != 0); ok = (ok && strcmp(call,"MAIL") != 0); return(ok); } /* * Check for a valid internet name. * Accept darned-near anything here as long as it is the proper * length and printable. */ int valid_inet_name(char *name, char *info, char *origin, int origin_size) { int len, i, ok, oknws, okbom; char *ptr; len = (int)strlen(name); if (len > 9 || len == 0) // max 9 printable ASCII characters { return(0); // wrong size } for (i=0; i= 5 && strncmp(name,"aprsd",5) == 0) { xastir_snprintf(origin, origin_size, "INET"); origin[4] = '\0'; // Terminate it return(1); // aprsdXXXX is ok } // Modifies "origin" if a match found if (len == 6) // check for NWS or BOM { ok = 1; oknws = 0; okbom = 0; for (i=0; i<6; i++) if (name[i] <'A' || name[i] > 'Z') // 6 uppercase characters { ok = 0; } ok = ok && (info != NULL); // check if we can test info if (ok) { ptr = strstr(info,":NWS-"); // "NWS-" in info field (non-compressed alert) oknws = (ptr != NULL); if (!oknws) { ptr = strstr(info,":NWS_"); // "NWS_" in info field (compressed alert) oknws = (ptr != NULL); } // If we've got here, it's not an NWS message, let's see if its a BOM message if (!oknws) { ptr = strstr(info,":BOM-"); // "BOM-" in info field (compressed alert) okbom = (ptr != NULL); } if (!okbom) { ptr = strstr(info,":BOM_"); // "BOM_" in info field (compressed alert) okbom = (ptr != NULL); } } // Depending on whether we had an NWS or BOM message, se the origin appropriately if (oknws) { xastir_snprintf(origin, origin_size, "INET-NWS"); origin[8] = '\0'; return(1); // weather alerts } if (okbom) { xastir_snprintf(origin, origin_size, "INET-BOM"); origin[8] = '\0'; return(1); // weather alerts } } return(1); // Accept anything else if we get to this point in // the code. After all, the message came from the // internet, not from RF. } // dl9sau: // I liked to have xastir to compute the locator along with the normal coordinates. // The algorithm derives from dk5sg's util/qth.c (wampes) // // This computes Maidenhead grid coordinates and is used for both // the status line ("text2" widget) and the Coordinate Calculator at // present. // char *sec_to_loc(long longitude, long latitude) { static char buf[7]; char *loc = buf; // database.h: long coord_lon; // Xastir coordinates 1/100 sec, 0 = 180°W // database.h: long coord_lat; // Xastir coordinates 1/100 sec, 0 = 90°N longitude /= 100L; latitude = 2L * 90L * 3600L - 1L - (latitude / 100L); *loc++ = (char) (longitude / 72000L + 'A'); longitude = longitude % 72000L; *loc++ = (char) (latitude / 36000L + 'A'); latitude = latitude % 36000L; *loc++ = (char) (longitude / 7200L + '0'); longitude = longitude % 7200L; *loc++ = (char) (latitude / 3600L + '0'); latitude = latitude % 3600L; *loc++ = (char) (longitude / 300L + 'a'); *loc++ = (char) (latitude / 150L + 'a'); *loc = 0; // Terminate the string return buf; } /* * Substring function WITH a terminating NULL char, needs a string of at least size+1 */ void substr(char *dest, char *src, int size) { memcpy(dest, src, size+1); dest[size] = '\0'; // Terminate string } char *to_upper(char *data) { int i; for(i=strlen(data)-1; i>=0; i--) if(islower((int)data[i])) { data[i]=toupper((int)data[i]); } return(data); } char *to_lower(char *data) { int i; for(i=strlen(data)-1; i>=0; i--) if(isupper((int)data[i])) { data[i]=tolower((int)data[i]); } return(data); } int is_num_chr(char ch) { return((int)isdigit(ch)); } int is_num_or_sp(char ch) { return((int)((ch >= '0' && ch <= '9') || ch == ' ')); } int is_xnum_or_dash(char *data, int max) { int i; int ok; ok=1; for(i=0; i=0; i--) if(!isdigit((int)data[i])) { ok=0; break; } return(ok); } //-------------------------------------------------------------------- //Removes all control codes ( < 1Ch ) from a string and set the 8th bit to zero void removeCtrlCodes(char *cp) { int i,j; int len = (int)strlen(cp); unsigned char *ucp = (unsigned char *)cp; for (i=0, j=0; i<=len; i++) { ucp[i] &= 0x7f; // Clear 8th bit if ( (ucp[i] >= (unsigned char)0x1c) // Check for printable plus the Mic-E codes || ((char)ucp[i] == '\0') ) // or terminating 0 { ucp[j++] = ucp[i] ; // Copy to temp if printable } } } //-------------------------------------------------------------------- //Removes all control codes ( <0x20 or >0x7e ) from a string, including // CR's, LF's, tab's, etc. // void makePrintable(char *cp) { int i,j; int len = (int)strlen(cp); unsigned char *ucp = (unsigned char *)cp; for (i=0, j=0; i<=len; i++) { ucp[i] &= 0x7f; // Clear 8th bit if ( ((ucp[i] >= (unsigned char)0x20) && (ucp[i] <= (unsigned char)0x7e)) || ((char)ucp[i] == '\0') ) // Check for printable or terminating 0 { ucp[j++] = ucp[i] ; // Copy to (possibly) new location if printable } } } #ifdef TIMING_DEBUG void time_mark(int start) { static struct timeval t_start; struct timeval t_cur; long sec, usec; if (start) { gettimeofday(&t_start, NULL); fprintf(stderr,"\nstart: 0.000000s"); } else { gettimeofday(&t_cur, NULL); sec = t_cur.tv_sec - t_start.tv_sec; usec = t_cur.tv_usec - t_start.tv_usec; if (usec < 0) { sec--; usec += 1000000; } fprintf(stderr,"time: %ld.%06lds\n", sec, usec); } } #endif // TIMING_DEBUG // Function which adds commas to callsigns (and other abbreviations?) // in order to make the text sound better when run through a Text-to- // Speech system. We try to change only normal amateur callsigns. // If we find a number in the text before a dash is found, we // consider it to be a normal callsign. We don't add commas to the // SSID portion of a call. void spell_it_out(char *text, int max_length) { char buffer[2000]; int i = 0; int j = 0; int number_found_before_dash = 0; int dash_found = 0; while (text[i] != '\0') { if (text[i] == '-') { dash_found++; } if (is_num_chr(text[i]) && !dash_found) { number_found_before_dash++; } buffer[j++] = text[i]; if (!dash_found) // Don't add commas to SSID { buffer[j++] = ','; } i++; } buffer[j] = '\0'; // Only use the new string if it kind'a looks like a callsign if (number_found_before_dash) { xastir_snprintf(text, max_length, "%s", buffer); } } #define kKey 0x73e2 // This is the seed for the key static short doHash(char *theCall) { char rootCall[10]; // need to copy call to remove ssid from parse char *p1 = rootCall; short hash; short i,len; char *ptr = rootCall; while ((*theCall != '-') && (*theCall != '\0')) { *p1++ = toupper((int)(*theCall++)); } *p1 = '\0'; hash = kKey; // Initialize with the key value i = 0; len = (short)strlen(rootCall); while (i MAX_WIDES) { // N is greater than MAX_WIDES bad_path = 1; } else if (prev > MAX_WIDES) { // n is greater than MAX_WIDES bad_path = 1; } else if (last == 0) { // N is 0, it's a used-up digipeater slot bad_path = 1; } if (debug_level & 1 && bad_path) { fprintf(stderr,"n-N wrong\n"); } return(bad_path); } // This function checks to make sure an unproto path falls within // the socially acceptable values, such as only one RELAY or // WIDE1-1 which may appear only as the first option, use of WIDE4-4 // and higher should be questioned, etc. // // "MAX_WIDES" is defined in util.h // // Returns: // 1 = bad path // 0 = good path // int check_unproto_path ( char *data ) { char *tmpdata; char *tmp; char *ViaCalls[10]; int bad_path, ii, have_relay, have_wide, have_widen; int have_trace, have_tracen; int lastp = 0; int prevp = 0; int last = 0; int prev = 0; int total_digi_length = 0; if (debug_level & 1) { fprintf(stderr, "Input string: %s\n", data); } bad_path = ii = have_relay = have_wide = 0; have_widen = have_trace = have_tracen = 0; // Remember to free() tmpdata before we return #ifdef HAVE_STRNDUP tmpdata = (char *)strndup(data, strlen(data)); #else tmpdata = (char *)strdup(data); #endif (void)to_upper(tmpdata); if ((tmp = strchr(tmpdata, '/'))) { *tmp ='\0'; // Only check VHF portion of path } split_string(tmpdata, ViaCalls, 10, ','); for (ii = 0; ii < 10; ii++) { lastp = 0; prevp = 0; last = 0; prev = 0; // Check for empty string in this slot if (ViaCalls[ii] == NULL) { // We're done. Exit the loop with whatever flags were // set in previous iterations. if (debug_level & 1) { fprintf(stderr,"NULL string, slot %d\n", ii); } break; } else { if (debug_level & 1) { fprintf(stderr,"%s string, slot %d\n", ViaCalls[ii], ii); } } lastp = strlen(ViaCalls[ii]) - 1; prevp = lastp - 2; // Snag the N character, convert to integer last = ViaCalls[ii][lastp] - 0x30; if (prevp >= 0) { // Snag the n character, convert to integer prev = ViaCalls[ii][prevp] - 0x30; } // Check whether RELAY appears later in the path if (!strncmp(ViaCalls[ii], "RELAY", 5)) { have_relay++; total_digi_length++; if (ii != 0) { // RELAY should not appear after the first item in a // path! bad_path = 1; if (debug_level & 1) { fprintf(stderr,"RELAY appears later in the path\n"); } break; } } // Check whether WIDE1-1 appears later in the path (the new // "RELAY") else if (!strncmp(ViaCalls[ii], "WIDE1-1", 7)) { have_relay++; total_digi_length++; if (ii != 0) { // WIDE1-1 should not appear after the first item in // a path! bad_path = 1; if (debug_level & 1) { fprintf(stderr,"WIDE1-1 appears later in the path\n"); } break; } } // Check whether WIDE2-1 appears first in the path. This is // fine, but don't trigger an error later because of another // WIDEn-N after an initial WIDE2-1. This is to allow paths // like "WIDE2-1,WIDE-2-2" or "WIDE2-1,MD2-2" else if ( (ii == 0) && (!strncmp(ViaCalls[ii], "WIDE2-1", 7)) ) { total_digi_length++; if (debug_level & 1) { fprintf(stderr,"Found initial WIDE2-1 (a good thing)\n"); } } // Check for WIDE/TRACE/WIDEn-N/TRACEn-N in the path else if (strstr(ViaCalls[ii], "WIDE") || strstr(ViaCalls[ii], "TRACE")) { // This is some variant of WIDE or TRACE, could be // WIDE/WIDEn-N/TRACE/TRACEn-N int is_wide = 0; if (strstr(ViaCalls[ii], "WIDE")) { is_wide++; } // Check for WIDEn-N or TRACEn-N if (strstr(ViaCalls[ii], "-")) { // This is a WIDEn-N or TRACEn-N callsign // Here we are adding the unused portion of the // WIDEn-N/TRACEn-N to the total_digi_length // variable. We use the unused portion because that // way we're not fooled if people start with a // number for N that is higher/lower than n. The // initial thought was to grab the higher of n or N, // but those lines are commented out here. // //if (last > prev) total_digi_length += last; //else // total_digi_length += prev; // Check for previous WIDEn-N/TRACEn-N if (have_widen || have_tracen) { // Already have a large area via bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Previous WIDEn-N or TRACEn-N\n"); } break; } // Perform WIDEn-N checks if (is_wide) { if (debug_level & 1) { fprintf(stderr,"Found wideN-n at slot %d\n", ii); } if (strcmp(ViaCalls[ii], "WIDE1-1") !=0) // Home station, RELAY replacement { have_widen++; // Note: We mark "have_relay" for } // "WIDE1-1" instead of "have_widen" // We know its a WIDEn-N, time to find out what n is if (strlen(ViaCalls[ii]) != 7) { // This should be WIDEn-N and should be // exactly 7 characters bad_path = 1; if (debug_level & 1) { fprintf(stderr,"String length of widen-N is not 7 characters, slot %d\n", ii); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In WIDEn-N checks, slot %d\n", ii); } break; } } // Perform similar checks for TRACEn-N else { if (debug_level & 1) { fprintf(stderr,"Found traceN-n, slot %d\n", ii); } have_tracen++; // We know its a TRACEn-N time to find out what // n is if (strlen(ViaCalls[ii]) != 8) { // This should be TRACEn-N and should be // exactly 8 characters bad_path = 1; if (debug_level & 1) { fprintf(stderr,"String length of tracen-N is not 8 characters, slot %d\n", ii); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In TRACEn-N checks, slot %d\n", ii); } break; } } } else { // We know we have a WIDE or TRACE in this callsign slot total_digi_length++; if (is_wide) { have_wide++; } else { have_trace++; } if (have_relay && (ii > MAX_WIDES)) { // RELAY and more than "MAX_WIDES" WIDE/TRACE calls // Here we could check have_wide/have_trace to see what the actual // count of WIDE/TRACE calls is at this point... bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Have relay and ii > MAX_WIDES\n"); } break; } else if (!have_relay && ii > (MAX_WIDES - 1)) { // More than WIDE,WIDE,WIDE or TRACE,TRACE,TRACE // Here we could check have_wide/have_trace to see what the actual // count of WIDE/TRACE calls is at this point... bad_path = 1; if (debug_level & 1) { fprintf(stderr,"No relay, but ii > MAX_WIDES-1\n"); } break; } else if (have_widen || have_tracen) { // WIDE/TRACE after something other than RELAY // or WIDE1-1 bad_path = 1; if (debug_level & 1) { fprintf(stderr,"WIDE or TRACE after something other than RELAY or WIDE1-1\n"); } break; } } } // Not RELAY/WIDE/TRACE/WIDEn-N/TRACEn-N call else { // Might as well stub this out, could be anything at // this point, a LINKn-N or LANn-N or a explicit // callsign if (!strstr(ViaCalls[ii], "-")) { /* // We do not have an SSID, treat it as a RELAY if (have_relay) { bad_path = 1; if (debug_level & 1) fprintf(stderr,"No SSID\n"); break; } */ have_relay++; } else { // Could be a LAN or LINK or explicit call, check // for a digit preceding the dash if (prev > 0 && prev <= 9) // Found a digit { // We've found an n-N */ if (have_widen || have_tracen) { // Already have a previous wide path bad_path = 1; if (debug_level & 1) { fprintf(stderr,"Found n-N and previous WIDEn-N or TRACEn-N\n"); } break; } // Check for proper relations between the n-N // numbers. if ( check_n_N(prev, last) ) { bad_path = 1; if (debug_level & 1) { fprintf(stderr,"In OTHER checks\n"); } break; } if (debug_level & 1) { fprintf(stderr,"Found wideN-n, slot %d\n", ii); } have_widen++; } else { /* // Must be an explicit callsign, treat as relay if (have_relay) { bad_path = 1; if (debug_level & 1) fprintf(stderr,"\n"); break; } */ have_relay++; } } } } // End of for loop if (debug_level & 1) { fprintf(stderr,"Total digi length: %d\n", total_digi_length); } if (total_digi_length > MAX_WIDES + 1) { if (debug_level & 1) { fprintf(stderr,"Total digi count is too high!\n"); } bad_path = 1; } // Free the memory we allocated with strndup() free(tmpdata); return(bad_path); } // End of check_unproto_path // Set string printed out by segfault handler void set_dangerous( char *ptr ) { xastir_snprintf(dangerous_operation, sizeof(dangerous_operation), "%s", ptr); } // Clear string printed out by segfault handler void clear_dangerous(void) { dangerous_operation[0] = '\0'; } // Write out a WKT file void xastirWriteWKT(char *filename) { // This "WKT" string describes the coordinate system we use in Xastir. // We'll use this string to write out ".prj" files to associate with // shapefiles we create from GPS or APRS tracks. char Xastir_WKT[] = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"Degree\",0.017453292519943295]]"; FILE *f; f=fopen(filename,"w"); // open for write if (f != NULL) { fprintf(f,"%s\n",Xastir_WKT); fclose(f); } else { fprintf(stderr,"Could not open file %s for writing\n",filename); } } // makeMultiline // Create an APRS multiline string given an array of lat/lon pairs. // // Allocates memory that must be freed by the caller. // // lon and lat are arrays. lonObj, latObj are return values of object // location (point from which offsets are computed). // // lineType is 0 for a closed polygon, 1 for a polyline // // colorStyle is a character as defined in the wxsvr.net multiline protocol // web site at wxsvr.net. // // character | color | style // a red solid // b red dashed // c red double-dashed // d yellow solid // e yellow dashed // f yellow double-dashed // g blue solid // h blue dashed // i blue double-dashed // j green solid // k green dashed // l green double-dashed // Returns a null pointer if user requested too many vertices, or if scale // is out of range, or if we fail to malloc the string. // // One could pass only a list of lat/lons here and get back a point at which // to create an object (at the centroid) and a string representing the // multiline. #define minFun(a,b) ( ((a)<(b))?(a):(b)) #define maxFun(a,b) ( ((a)>(b))?(a):(b)) char * makeMultiline(int numPairs, double *lon, double *lat, char colorStyle, int lineType, char* sqnc, double *lonCentr, double *latCentr ) { char * returnString; // the APRS spec requires a max of 43 chars in the comment section of // objects, which leaves room for only so many vertices in a multiline // number allowed= (43-(6-5))/2=16 // 43chars - 6 for the sequence number- 5 for the starting pattern leaves // 32 characters for lat/lon pairs, or 16 pairs if ( numPairs > 16) { returnString = NULL; } else { double minLat, minLon; double maxLat, maxLon; int iPair; double scale1,scale2,scale; // find min/max of arrays minLat=minLon=180; maxLat=maxLon=-180; for ( iPair=0; iPair < numPairs; iPair++) { minLon = minFun(minLon,lon[iPair]); minLat = minFun(minLat,lat[iPair]); maxLon = maxFun(maxLon,lon[iPair]); maxLat = maxFun(maxLat,lat[iPair]); } *lonCentr = (maxLon+minLon)/2; *latCentr = (maxLat+minLat)/2; // Compute scale: // The scale is the value that makes the maximum or minimum offset // map to +44 or -45. Pick the scale factor that keeps the // offsets in that range: if (maxLat > maxLon) { scale1= (maxLat-*latCentr)/44.0; } else { scale1= (maxLon-*lonCentr)/44.0; } if (minLat < minLon) { scale2 = (minLat-*latCentr)/(-45.0); } else { scale2 = (minLon-*lonCentr)/(-45.0); } scale = maxFun(scale1,scale2); if (scale < .0001) { scale=0.0001; } if (scale > 1) { // Out of range, no shape returned returnString = NULL; } else { // Not all systems have a log10(), but they all have log() // So let's stick with natural logs double ln10=log(10.0); // KLUDGE: the multiline spec says we use // 20*(int)(log10(scale/.0001)) to generate the scale char, // but this means we'll often produce real scales that are smaller // than the one we just calculated, which means we'd produce // offsets outside the (-45,44) allowed range. So kludge and // add 1 to the value int lnscalefac=20*log(scale/.0001)/ln10+1; int rsMaxLen=numPairs*2+6+4+1; int stringOffset=0; // Now recompute the scale to be the one we actually transmitted // This pretty much means we'll never have the best precision // we could possibly have, but it'll be close enough scale=pow(10,(double)lnscalefac/20-4); // We're ready to produce the multiline string. So get on with it // multiline string is "}CTS" (literal "}" followed by // line Color-style specifier, followed by open/closed // Type specifier, followed by Scale character), followed // by even number of character pairs, followed by "{seqnc" // (sequence number). returnString=malloc(sizeof(char)*rsMaxLen); if (returnString != NULL) { returnString[stringOffset++]=' '; returnString[stringOffset++]='}'; returnString[stringOffset++]=colorStyle; returnString[stringOffset++]= (lineType == 0)?'0':'1'; returnString[stringOffset++] = lnscalefac+33; for ( iPair=0; iPair (41 - 9)) { int avail = 41 - 11; int new_len = strlen(filename) - avail; xastir_snprintf(short_filename, short_filename_size, "..%s", &filename[new_len]); } else { xastir_snprintf(short_filename, short_filename_size, "%s", filename); } } Xastir-Release-2.2.4/src/util.h0000664000175000017500000001363115151324131015242 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_UTIL_H #define __XASTIR_UTIL_H #include #include "database.h" // Max number of WIDE digipeaters allowed #define MAX_WIDES 3 static __inline__ short l16(long val) { // This limits large integer values to the 16 bit range for X // drawing if (val < -32768) { val = -32768; } if (val > 32767) { val = 32767; } return (short)val; } static __inline__ unsigned short lu16(long val) { // This limits large unsigned integer values to the 16 bit range // for X drawing if (val < 0) { val = 0; } if (val > 65535) { val = 65535; } return (unsigned short)val; } extern int convert_from_xastir_coordinates ( float *f_longitude, float *f_latitude, long x, long y ); extern int convert_to_xastir_coordinates (unsigned long* x, unsigned long* y, float f_longitude, float f_latitude); extern char *remove_all_spaces(char *data); extern char *remove_leading_spaces(char *data); extern char *remove_trailing_spaces(char *data); extern char *remove_trailing_asterisk(char *data); extern char *remove_trailing_dash_zero(char *data); extern void get_timestamp(char *timestring); extern int get_iso_datetime(time_t aTime, char *timestring, int nowIfNotSet, int nowIfInvalid); extern int get_w3cdtf_datetime(time_t aTime, char *timestring,int nowIfNotSet, int nowIfInvalid); extern int get_hours(void); extern int get_minutes(void); extern int get_seconds(void); extern double phg_range(char p, char h, char g); extern double shg_range(char s, char h, char g); extern void phg_decode(const char *langstr, const char *phg, char *phg_decoded, int phg_decoded_length, int english_units); extern void shg_decode(const char *langstr, const char *shg, char *shg_decoded, int shg_decoded_length, int english_units); extern void bearing_decode(const char *langstr, const char *bearing_str, const char *NRQ, char *bearing_decoded, int bearing_decoded_length, int english_units); extern char *get_line(FILE *f, char *linedata, int maxline); extern time_t time_from_aprsstring(char *timestamp); extern char *compress_posit(const char *lat, const char group, const char *lon, const char symbol, const unsigned int course, const unsigned int speed, const char *phg); extern char compress_group(char group_in); extern int position_defined(long lat, long lon, int strict); extern void convert_screen_to_xastir_coordinates(int x, int y, long *lat, long *lon); extern void convert_xastir_to_screen_coordinates(long lon, long lat, long *x, long *y); extern void convert_xastir_to_UTM_str(char *str, int str_len, long x, long y); extern void convert_xastir_to_UTM(double *easting, double *northing, char *zone, int zone_len, long x, long y); extern void convert_UTM_to_xastir(double easting, double northing, char *zone, long *x, long *y); extern double convert_lat_l2r(long lat); extern double convert_lon_l2r(long lon); extern void convert_lat_l2s(long lat, char *str, int str_len, int type); extern void convert_lon_l2s(long lon, char *str, int str_len, int type); extern long convert_lat_s2l(char *lat); extern long convert_lon_s2l(char *lon); extern double calc_distance(long lat1, long lon1, long lat2, long lon2); extern double calc_distance_course(long lat1, long lon1, long lat2, long lon2, char *course_deg, int course_deg_length); extern double distance_from_my_station(char *call_sign, char *course_deg, int english_units); extern char *convert_bearing_to_name(char *bearing, int opposite); extern int filethere(char *fn); extern int filecreate(char *fn); extern int copy_file(char *infilename, char *outfilename); extern time_t file_time(char *fn); extern time_t sec_now(void); extern char *get_time(char *time_here); extern void substr(char *dest, char *src, int size); extern int valid_path(char *path); extern int valid_call(char *call); extern int valid_inet_name(char *name, char *info, char *origin, int origin_size); extern char echo_digis[6][9+1]; extern void upd_echo(char *path); extern char *to_upper(char *data); extern char *to_lower(char *data); extern int is_num_chr(char ch); extern int is_num_or_sp(char ch); extern int is_xnum_or_dash(char *data, int max); extern void removeCtrlCodes(char *cp); extern void makePrintable(char *cp); extern void spell_it_out(char *text, int max_length); //#define TIMING_DEBUG #ifdef TIMING_DEBUG void time_mark(int start); #endif // TIMING_DEBUG // dl9sau extern char *sec_to_loc(long longitude, long latitude); extern short checkHash(char *theCall, short theHash); extern void split_string ( char *data, char *cptr[], int max, char search_char ); extern int check_unproto_path( char *data ); extern void set_dangerous( char *ptr ); extern void clear_dangerous(void); void xastirWriteWKT(char *name); char * makeMultiline(int numPairs, double *lon, double *lat, char colorStyle, int lineType, char* sqnc, double *lonCentr, double *latCentr ); void short_filename_for_status(char *filename, char *short_filename, size_t short_filename_size); #endif // __XASTIR_UTIL_H Xastir-Release-2.2.4/src/view_message_gui.c0000664000175000017500000006327115151324131017607 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "util.h" #include "mutex_utils.h" // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist Widget All_messages_dialog = NULL; Widget view_messages_text = NULL; Widget vm_dist_data = NULL; static xastir_mutex All_messages_dialog_lock; int vm_range; int view_message_limit = 10000; int Read_messages_packet_data_type = 0; // 1=tnc_only, 2=net_only, 0=tnc&net int Read_messages_mine_only = 0; void view_message_gui_init(void) { init_critical_section( &All_messages_dialog_lock ); } void view_message_print_record(Message *m_fill) { int pos; char *temp; int i; int my_size = 200; char temp_my_course[10]; XmTextPosition drop_ptr; int distance; // Make sure it's within our distance range we have set distance = distance_from_my_station(m_fill->from_call_sign,temp_my_course, english_units); if (Read_messages_mine_only || (!Read_messages_mine_only && ( (vm_range == 0) || (distance <= vm_range) ) ) ) { // Check that it's coming from the correct type of interface // Compare Read_messages_packet_data_type against the port // type associated with data_port to determine whether or // not to display it. // // I = Internet // L = Local // T = TNC // F = File // switch (Read_messages_packet_data_type) { case 2: // Display NET data only // if not network_interface, return if (m_fill->data_via != 'I') { return; // Don't display it } break; case 1: // Display TNC data only // if not local_tnc_interface, return if (m_fill->data_via != 'T') { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // Check for my stations only if set if (Read_messages_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(m_fill->call_sign, short_call) && !strstr(m_fill->from_call_sign, short_call)) { return; } } if ((temp = malloc((size_t)my_size)) == NULL) { return; } sprintf(temp,"%-9s>%-9s %s:%5s %s:%c :%s\n", m_fill->from_call_sign, m_fill->call_sign, langcode("WPUPMSB013"), m_fill->seq, langcode("WPUPMSB014"), m_fill->type, m_fill->message_line); pos = (int)XmTextGetLastPosition(view_messages_text); XmTextInsert(view_messages_text, pos, temp); pos += strlen(temp); while (pos > view_message_limit) { for (drop_ptr = i = 0; i < 3; i++) { (void)XmTextFindString(view_messages_text, drop_ptr, "\n", XmTEXT_FORWARD, &drop_ptr); drop_ptr++; } XmTextReplace(view_messages_text, 0, drop_ptr, ""); pos = (int)XmTextGetLastPosition(view_messages_text); } XtVaSetValues(view_messages_text, XmNcursorPosition, pos, NULL); free(temp); } } void view_message_display_file(char msg_type) { int pos; if ((All_messages_dialog != NULL)) { mscan_file(msg_type, view_message_print_record); } pos = (int)XmTextGetLastPosition(view_messages_text); XmTextShowPosition(view_messages_text, pos); } void all_messages(char from, char *call_sign, char *from_call, char *message) { char temp_my_course[10]; char *temp; char data1[97]; char data2[97]; int pos; int i; int my_size = 200; XmTextPosition drop_ptr; if (Read_messages_mine_only || (!Read_messages_mine_only && ((vm_range == 0) || (distance_from_my_station(call_sign,temp_my_course, english_units) <= vm_range)) ) ) { // Check that it's coming from the correct type of interface // Compare Read_messages_packet_data_type against the port // type associated with data_port to determine whether or // not to display it. // // I = Internet // L = Local // T = TNC // F = File // switch (Read_messages_packet_data_type) { case 2: // Display NET data only // if not network_interface, return if (from != 'I') { return; // Don't display it } break; case 1: // Display TNC data only // if not local_tnc_interface, return if (from != 'T') { return; // Don't display it } break; case 0: // Display both TNC and NET data default: break; } // Check for my stations only if set if (Read_messages_mine_only) { char short_call[MAX_CALLSIGN]; char *p; memcpy(short_call, my_callsign, sizeof(short_call)); short_call[sizeof(short_call)-1] = '\0'; // Terminate string if ( (p = index(short_call,'-')) ) { *p = '\0'; // Terminate it } if (!strstr(call_sign, short_call) && !strstr(from_call, short_call)) { return; } } if ((temp = malloc((size_t)my_size)) == NULL) { return; } if (strlen(message)>95) { xastir_snprintf(data1, sizeof(data1), "%s", message); data1[95]='\0'; xastir_snprintf(data2, sizeof(data2), "\n\t%s", message+95); } else { xastir_snprintf(data1, sizeof(data1), "%s", message); data2[0] = '\0'; } if (strncmp(call_sign, "java",4) == 0) { xastir_snprintf(call_sign, MAX_CALLSIGN+1, "%s", langcode("WPUPMSB015") ); // Broadcast xastir_snprintf(temp, my_size, "%s %s\t%s%s\n", from_call, call_sign, data1, data2); } else if (strncmp(call_sign, "USER", 4) == 0) { xastir_snprintf(call_sign, MAX_CALLSIGN+1, "%s", langcode("WPUPMSB015") ); // Broadcast xastir_snprintf(temp, my_size, "%s %s\t%s%s\n", from_call, call_sign, data1, data2); } else { char from_str[10]; xastir_snprintf(from_str, sizeof(from_str), "%c", from); strcpy(temp, from_call); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " to "); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, call_sign); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, " via:"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, from_str); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "\t"); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data1); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, data2); temp[sizeof(temp)-1] = '\0'; // Terminate string strcat(temp, "\n"); temp[sizeof(temp)-1] = '\0'; // Terminate string } if ((All_messages_dialog != NULL)) { begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:all_messages" ); pos = (int)XmTextGetLastPosition(view_messages_text); XmTextInsert(view_messages_text, pos, temp); pos += strlen(temp); while (pos > view_message_limit) { for (drop_ptr = i = 0; i < 3; i++) { (void)XmTextFindString(view_messages_text, drop_ptr, "\n", XmTEXT_FORWARD, &drop_ptr); drop_ptr++; } XmTextReplace(view_messages_text, 0, drop_ptr, ""); pos = (int)XmTextGetLastPosition(view_messages_text); } XtVaSetValues(view_messages_text, XmNcursorPosition, pos, NULL); XmTextShowPosition(view_messages_text, pos); end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:all_messages" ); } free(temp); } } void All_messages_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; char *temp_ptr; temp_ptr = XmTextFieldGetString(vm_dist_data); vm_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:All_messages_destroy_shell" ); XtDestroyWidget(shell); All_messages_dialog = (Widget)NULL; end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:All_messages_destroy_shell" ); } void All_messages_change_range( Widget widget, XtPointer clientData, XtPointer callData) { Widget shell = (Widget) clientData; char *temp_ptr; temp_ptr = XmTextFieldGetString(vm_dist_data); vm_range = atoi(temp_ptr); XtFree(temp_ptr); XtPopdown(shell); All_messages_destroy_shell(widget, clientData, callData); view_all_messages(widget, clientData, callData); } void Read_messages_packet_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Read_messages_packet_data_type = atoi(which); } else { Read_messages_packet_data_type = 0; } } Widget button_range; void Read_messages_mine_only_toggle( Widget UNUSED(widget), XtPointer clientData, XtPointer callData) { char *which = (char *)clientData; XmToggleButtonCallbackStruct *state = (XmToggleButtonCallbackStruct *)callData; if(state->set) { Read_messages_mine_only = atoi(which); XtSetSensitive(vm_dist_data, FALSE); } else { Read_messages_mine_only = 0; XtSetSensitive(vm_dist_data, TRUE); } } void view_all_messages( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { Widget pane, scrollwindow, my_form, button_close, dist, dist_units; Widget option_box, tnc_data, net_data, tnc_net_data, read_mine_only_button; unsigned int n; #define NCNT 50 #define IncN(n) if (n< NCNT) n++; else fprintf(stderr, "Oops, too many arguments for array!\a") Arg args[NCNT]; Atom delw; char temp[10]; if (!All_messages_dialog) { begin_critical_section(&All_messages_dialog_lock, "view_message_gui.c:view_all_messages" ); All_messages_dialog = XtVaCreatePopupShell(langcode("AMTMW00001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("view_all_messages pane", xmPanedWindowWidgetClass, All_messages_dialog, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("view_all_messages my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase, 5, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, NULL); dist = XtVaCreateManagedWidget(langcode("AMTMW00002"), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); vm_dist_data = XtVaCreateManagedWidget("view_all_messages dist_data", xmTextFieldWidgetClass, my_form, XmNeditable, TRUE, XmNcursorPositionVisible, TRUE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 8, XmNwidth, ((8*7)+2), XmNmaxLength, 8, XmNbackground, colors[0x0f], XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); dist_units = XtVaCreateManagedWidget((english_units?langcode("UNIOP00004"):langcode("UNIOP00005")), xmLabelWidgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, vm_dist_data, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNtraversalOn, FALSE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); button_range = XtVaCreateManagedWidget(langcode("BULMW00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dist_units, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_range, XmNactivateCallback, All_messages_change_range, All_messages_dialog); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"), xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, button_range, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_FORM, XmNnavigationType, XmTAB_GROUP, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, All_messages_destroy_shell, All_messages_dialog); n=0; XtSetArg(args[n],XmNforeground, MY_FG_COLOR); n++; XtSetArg(args[n],XmNbackground, MY_BG_COLOR); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNtopWidget, dist); n++; XtSetArg(args[n], XmNtopOffset, 5); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 5); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++; XtSetArg(args[n], XmNfontList, fontlist1); n++; option_box = XmCreateRadioBox(my_form, "View Messages option box", args, n); XtVaSetValues(option_box, XmNpacking, XmPACK_TIGHT, XmNorientation, XmHORIZONTAL, NULL); tnc_data = XtVaCreateManagedWidget(langcode("WPUPDPD002"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"1"); net_data = XtVaCreateManagedWidget(langcode("WPUPDPD003"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(net_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"2"); tnc_net_data = XtVaCreateManagedWidget(langcode("WPUPDPD004"), xmToggleButtonGadgetClass, option_box, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(tnc_net_data,XmNvalueChangedCallback,Read_messages_packet_toggle,"0"); read_mine_only_button = XtVaCreateManagedWidget(langcode("WPUPDPD008"), xmToggleButtonGadgetClass, my_form, XmNvisibleWhenOff, TRUE, XmNindicatorSize, 12, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dist, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, option_box, XmNleftOffset, 20, XmNrightAttachment, XmATTACH_NONE, MY_FOREGROUND_COLOR, MY_BACKGROUND_COLOR, XmNfontList, fontlist1, NULL); XtAddCallback(read_mine_only_button,XmNvalueChangedCallback,Read_messages_mine_only_toggle,"1"); n=0; XtSetArg(args[n], XmNrows, 15); IncN(n); XtSetArg(args[n], XmNcolumns, 85); IncN(n); XtSetArg(args[n], XmNeditable, FALSE); IncN(n); XtSetArg(args[n], XmNtraversalOn, TRUE); IncN(n); XtSetArg(args[n], XmNlistSizePolicy, XmVARIABLE); IncN(n); XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); IncN(n); XtSetArg(args[n], XmNwordWrap, TRUE); IncN(n); XtSetArg(args[n], XmNscrollHorizontal, TRUE); IncN(n); XtSetArg(args[n], XmNscrollVertical, TRUE); IncN(n); // XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); IncN(n); XtSetArg(args[n], XmNselectionPolicy, XmMULTIPLE_SELECT); IncN(n); XtSetArg(args[n], XmNcursorPositionVisible, FALSE); IncN(n); XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); IncN(n); XtSetArg(args[n], XmNtopWidget, option_box); IncN(n); XtSetArg(args[n], XmNtopOffset, 5); IncN(n); XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNleftOffset, 5); IncN(n); XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); IncN(n); XtSetArg(args[n], XmNrightOffset, 5); IncN(n); XtSetArg(args[n], XmNforeground, MY_FG_COLOR); IncN(n); XtSetArg(args[n], XmNbackground, MY_BG_COLOR); IncN(n); XtSetArg(args[n], XmNfontList, fontlist1); n++; view_messages_text = XmCreateScrolledText(my_form, "view_all_messages text", args, n); // It's hard to get tab groups working with ScrolledText widgets. Tab'ing in is // fine, but then I'm stuck in insert mode and it absorbs the tabs and beeps. pos_dialog(All_messages_dialog); delw = XmInternAtom(XtDisplay(All_messages_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(All_messages_dialog, delw, All_messages_destroy_shell, (XtPointer)All_messages_dialog); sprintf(temp,"%d",vm_range); XmTextFieldSetString(vm_dist_data,temp); switch (Read_messages_packet_data_type) { case(0): XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; case(1): XmToggleButtonSetState(tnc_data,TRUE,FALSE); break; case(2): XmToggleButtonSetState(net_data,TRUE,FALSE); break; default: XmToggleButtonSetState(tnc_net_data,TRUE,FALSE); break; } if (Read_messages_mine_only) { XmToggleButtonSetState(read_mine_only_button,TRUE,FALSE); XtSetSensitive(vm_dist_data, FALSE); } else { XmToggleButtonSetState(read_mine_only_button,FALSE,FALSE); XtSetSensitive(vm_dist_data, TRUE); } XtManageChild(option_box); XtManageChild(view_messages_text); XtVaSetValues(view_messages_text, XmNbackground, colors[0x0f], NULL); XtManageChild(my_form); XtManageChild(pane); resize_dialog(my_form, All_messages_dialog); redraw_on_new_packet_data=1; // Dump all currently active messages to the new window view_message_display_file('M'); end_critical_section(&All_messages_dialog_lock, "view_message_gui.c:view_all_messages" ); XtPopup(All_messages_dialog,XtGrabNone); // Move focus to the Close button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(All_messages_dialog); XmProcessTraversal(button_close, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(All_messages_dialog), XtWindow(All_messages_dialog)); } } Xastir-Release-2.2.4/src/wx.c0000664000175000017500000041420115151324131014714 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // // The code currently supports these types of locally-connected or // network-connected weather stations: // // Peet Brothers Ultimeter 2000 (Set to Data logging mode) // Peet Brothers Ultimeter 2000 (Set to Packet mode) // Peet Brothers Ultimeter 2000 (Set to Complete Record Mode) // Peet Brothers Ultimeter-II // Qualimetrics Q-Net? // Radio Shack WX-200/Huger WM-918/Oregon Scientific WM-918 // Dallas One-Wire Weather Station (via OWW network daemon) // Davis Weather Monitor II/Wizard III/Vantage Pro (via meteo/db2APRS link) // // Need to modify code to use WX_rain_gauge_type. Peet brothers. // See http://www.peetbros.com, FAQ's and owner's manuals for // details: // // Peet Bros Ultimeter II: 0.1"/0.5mm or 0.01"/0.25mm // Divide by 10 or 100 from the serial output. // // Peet Bros Ultimeter 2000, 800, & 100: 0.01"/0.25mm or 0.1mm // If 0.01" gauge, divide by 100. If 0.1mm gauge, convert to // proper English units. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #include "wx.h" #include "main.h" #include "db_funcs.h" #include "xastir.h" #include "interface.h" #include "lang.h" #include "util.h" #include "mutex_utils.h" // Must be last include file #include "leak_detection.h" #define MAX_RAW_WX_STRING 800 char wx_station_type[100]; char raw_wx_string[MAX_RAW_WX_STRING+1]; #define MAX_WX_STRING 300 #define WX_TYPE 'X' /* rain totals */ float rain_minute[60]; // Total rain for each min. of last hour, hundredths of an inch float rain_minute_total = 0.0; // Total for last hour, hundredths of an inch int rain_minute_last_write = -1; // Write pointer for rain_minute[] array, set to an invalid number float rain_00 = 0.0; // hundredths of an inch float rain_24 = 0.0; // hundredths of an inch float rain_base[24]; // hundredths of an inch int rain_check = 0; // Flag for re-checking rain_total each hour float wind_chill = 0; // holder for wind chill calc // Gust totals float gust[60]; // High wind gust for each min. of last hour int gust_write_ptr = 0; int gust_read_ptr = 0; int gust_last_write = 0; /* Other WX station data */ char wx_dew_point[10]; char wx_dew_point_on; char wx_high_wind[10]; char wx_high_wind_on; char wx_wind_chill[10]; char wx_wind_chill_on; char wx_three_hour_baro[10]; // hPa char wx_three_hour_baro_on; char wx_hi_temp[10]; char wx_hi_temp_on; char wx_low_temp[10]; char wx_low_temp_on; char wx_heat_index[10]; char wx_heat_index_on; /***********************************************************/ /* clear rain data */ /***********************************************************/ void clear_rain_data(void) { int x; // Clear rain_base queue (starting rain total for each hour) for ( x = 0; x < 24; x++ ) { rain_base[x] = 0.0; } rain_00 = 0.0; rain_24 = 0.0; rain_check = 0; // Set flag so we'll recheck rain_total // a few times at start of each hour // Clear hourly rain queue for ( x = 0; x < 60; x++ ) { rain_minute[x] = 0.0; } rain_minute_total = 0.0; rain_minute_last_write = 70; // Invalid number so we'll know we're just starting. } /**************************************************************/ /* compute_rain_hour - rolling average for the last 59.x */ /* minutes of rain. I/O numbers are in hundredths of an inch.*/ /* Output is in "rain_minute_total", a global variable. */ /**************************************************************/ void compute_rain_hour(float rain_total) { int current, j; float lowest; // Deposit the _starting_ rain_total for each minute into a separate bucket. // Subtract lowest rain_total in queue from current rain_total to get total // for the last hour. current = get_minutes(); // Fetch the current minute value. Use this as an index // into our minute "buckets" where we store the data. rain_minute[ (current + 1) % 60 ] = 0.0; // Zero out the next bucket (probably have data in // there from the previous hour). if (rain_minute[current] == 0.0) // If no rain_total stored yet in this minute's bucket { rain_minute[current] = rain_total; // Write into current bucket } // Find the lowest non-zero value for rain_total. The max value is "rain_total". lowest = rain_total; // Set to maximum to get things going for (j = 0; j < 60; j++) { if ( (rain_minute[j] > 0.0) && (rain_minute[j] < lowest) ) // Found a lower non-zero value? { lowest = rain_minute[j]; // Snag it } } // Found it, subtract the two to get total for the last hour rain_minute_total = rain_total - lowest; if (debug_level & 2) { fprintf(stderr,"Rain_total:%0.2f Hourly:%0.2f (Low:%0.2f) ", rain_total, rain_minute_total, lowest); } } /***********************************************************/ /* compute_rain - compute rain totals from the total rain */ /* so far. rain_total (in hundredths of an inch) keeps on */ /* incrementing. */ /***********************************************************/ void compute_rain(float rain_total) { int current, i; float lower; // Skip the routine if input is outlandish (Negative value, zero, or 512 inches!). // We seem to get occasional 0.0 packets from wx200d. This makes them go away. if ( (rain_total <= 0.0) || (rain_total > 51200.0) ) { return; } compute_rain_hour(rain_total); current = get_hours(); // Set rain_base: The first rain_total for each hour. if (rain_base[current] == 0.0) // If we don't have a start value yet for this hour, { rain_base[current] = rain_total; // save it away. rain_check = 0; // Set up rain_check so we'll do the following // "else" clause a few times at start of each hour. } else // rain_base has been set, is it wrong? We recheck three times at start of hour. { if (rain_check < 3) { rain_check++; // Is rain less than base? It shouldn't be. if (rain_total < rain_base[current]) { rain_base[current] = rain_total; } // Difference greater than 10 inches since last reading? It shouldn't be. if (fabs(rain_total - rain_base[current]) > 1000.0) // Remember: Hundredths of an inch { rain_base[current] = rain_total; } } } rain_base[ (current + 1) % 24 ] = 0.0; // Clear next hour's index. // Compute total rain in last 24 hours: Really we'll compute the total rain // in the last 23 hours plus the portion of an hour we've completed (Sum up // all 24 of the hour totals). This isn't the perfect way to do it, but to // really do it right we'd need finer increments of time (to get closer to // the goal of 24 hours of rain). lower = rain_total; for ( i = 0; i < 24; i++ ) // Find the lowest non-zero rain_base value in last 24 hours { if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) ) { lower = rain_base[i]; } } rain_24 = rain_total - lower; // Hundredths of an inch // Compute rain since midnight. Note that this uses whatever local time was set // on the machine. It might not be local midnight if your box is set to GMT. lower = rain_total; for ( i = 0; i <= current; i++ ) // Find the lowest non-zero rain_base value since midnight { if ( (rain_base[i] > 0.0) && (rain_base[i] < lower) ) { lower = rain_base[i]; } } rain_00 = rain_total - lower; // Hundredths of an inch // It is the responsibility of the calling program to save // the new totals in the data structure for our station. // We don't return anything except in global variables. if (debug_level & 2) { fprintf(stderr,"24hrs:%0.2f ", rain_24); fprintf(stderr,"rain_00:%0.2f\n", rain_00); } } /**************************************************************/ /* compute_gust - compute max wind gust during last 5 minutes */ /* */ /**************************************************************/ float compute_gust(float wx_speed, float UNUSED(last_speed), time_t *last_speed_time) { float computed_gust; int current, j; // Deposit max gust for each minute into a different bucket. // Check all buckets for max gust within the last five minutes // (Really 4 minutes plus whatever portion of a minute we've completed). current = get_minutes(); // Fetch the current minute value. We use this as an index // into our minute "buckets" where we store the data. // If we haven't started collecting yet, set up to do so if (gust_read_ptr == gust_write_ptr) // We haven't started yet { gust_write_ptr = current; // Set to write into current bucket gust_last_write = current; gust_read_ptr = current - 1; // Set read pointer back one, modulus 60 if (gust_read_ptr < 0) { gust_read_ptr = 59; } gust[gust_write_ptr] = 0.0; // Zero the max gust gust[gust_read_ptr] = 0.0; // for both buckets. //WE7U: Debug //gust[gust_write_ptr] = 45.9; } // Check whether we've advanced at least one minute yet if (current != gust_write_ptr) // We've advanced to a different minute { gust_write_ptr = current; // Start writing into a new bucket. gust[gust_write_ptr] = 0.0; // Zero the new bucket // Check how many bins of real data we have currently. Note that this '5' is // correct, as we just advanced "current" to the next minute. We're just pulling // along the read_ptr behind us if we have 5 bins worth of data by now. if ( ((gust_read_ptr + 5) % 60) == gust_write_ptr) // We have 5 bins of real data { gust_read_ptr = (gust_read_ptr + 1) % 60; // So advance the read pointer, } // Check for really bad pointers, perhaps the weather station got // unplugged for a while or it's just REALLY slow at sending us data? // We're checking to see if gust_last_write happened in the previous // minute. If not, we skipped a minute or more somewhere. if ( ((gust_last_write + 1) % 60) != current ) { // We lost some time somewhere: Reset the pointers, older gust data is // lost. Start over collecting new gust data. gust_read_ptr = current - 1; // Set read pointer back one, modulus 60 if (gust_read_ptr < 0) { gust_read_ptr = 59; } gust[gust_read_ptr] = 0.0; } gust_last_write = current; } // Is current wind speed higher than the current minute bucket? if (wx_speed > gust[gust_write_ptr]) { gust[gust_write_ptr] = wx_speed; // Save it in the bucket } // Read the last (up to) five buckets and find the max gust computed_gust=gust[gust_write_ptr]; j = gust_read_ptr; while (j != ((gust_write_ptr + 1) % 60) ) { if ( computed_gust < gust[j] ) { computed_gust = gust[j]; } j = (j + 1) % 60; } if (debug_level & 2) { j = gust_read_ptr; while (j != ((gust_write_ptr + 1) % 60) ) { fprintf(stderr,"%0.2f ", gust[j]); j = (j + 1) % 60; } fprintf(stderr,"gust:%0.2f\n", computed_gust); } *last_speed_time = sec_now(); return(computed_gust); } // // cycle_weather - keep the weather queues moving even if data from // weather station is scarce. This is called from main.c:UpdateTime() // on a periodic basis. This routine also does the 30 second timestamp // for the log files. // void cycle_weather(void) { DataRow *p_station; WeatherRow *weather; float last_speed, computed_gust; time_t last_speed_time; // Find my own local weather data if (search_station_name(&p_station,my_callsign,1)) { if (p_station->weather_data != NULL) // If station has WX data { weather = p_station->weather_data; // Cycle the rain queues, feed in the last rain total we had (void)compute_rain((float)atof(weather->wx_rain_total)); // Note: Some weather stations provide the per-hour, 24-hour, // and since-midnight rain rates already. Further, some stations // don't even provide total rain (Davis APRS DataLogger and the // db2APRS program), so anything we compute here is actually wrong. // Do NOT clobber these if so. This flag is set in fill_wx_data // when the station provides its data. if (weather->wx_compute_rain_rates) { // Hourly rain total xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); // Last 24 hour rain xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); // Rain since midnight xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { // LaCrosse stations don't provide the since-midnight // numbers and so this will be blank. // So if we have blanks here, fill it in. if ( weather->wx_prec_00[0] == '\0' && weather->wx_rain_total[0] != '\0') { // Rain since midnight xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } /* get last gust speed */ if (strlen(weather->wx_gust) > 0) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } else { last_speed = 0.0; } /* wind speed */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(computed_gust + 0.5)); // Cheater's way of rounding } } } /***********************************************************/ /* clear other wx data */ /***********************************************************/ void clear_local_wx_data(void) { memset(wx_dew_point,0,sizeof(wx_dew_point)); wx_dew_point_on = 0; memset(wx_high_wind,0,sizeof(wx_high_wind)); wx_high_wind_on = 0; memset(wx_wind_chill,0,sizeof(wx_wind_chill)); wx_wind_chill_on = 0; memset(wx_three_hour_baro,0,sizeof(wx_three_hour_baro)); wx_three_hour_baro_on = 0; memset(wx_hi_temp,0,sizeof(wx_hi_temp)); wx_hi_temp_on = 0; memset(wx_low_temp,0,sizeof(wx_low_temp)); wx_low_temp_on = 0; memset(wx_heat_index,0,sizeof(wx_heat_index)); wx_heat_index_on = 0; } /***************************************************/ /* Check last WX data received - clear data if old */ /***************************************************/ void wx_last_data_check(void) { DataRow *p_station; p_station = NULL; if (search_station_name(&p_station,my_callsign,1)) { if (p_station->weather_data != NULL) if (p_station->weather_data->wx_speed_sec_time+360 < sec_now()) if (p_station->weather_data->wx_gust[0] != 0) xastir_snprintf(p_station->weather_data->wx_gust, sizeof(p_station->weather_data->wx_gust), "%03d", 0); } } //********************************************************************* // Decode Peet Brothers Ultimeter 2000 weather data (Data logging mode) // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. // // The Ultimeter 2000 can be in any of three modes, Data Logging Mode, // Packet Mode, or Complete Record Mode. This routine handles only // the Data Logging Mode. //********************************************************************* void decode_U2000_L(int from, unsigned char *data, WeatherRow *weather) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; last_speed = 0.0; last_speed_time = 0; computed_gust = 0.0; if (debug_level & 1) { fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode): |%s|\n", data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } // 006B 00 58 // 00A4 00 46 01FF 380E 2755 02C1 03E8 ---- 0052 04D7 0001 007BM // ^ ^ ^ ^ ^ ^ ^ // 0 6 8 12 16 24 40 /* wind speed */ if (data[0] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)data,4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); // Cheater's way of rounding } } else { if (!from) { weather->wx_speed[0] = 0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may be FF // if a direction calibration has been entered. We should zero // them. // if (data[4] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+4),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", ((strtol(temp_data1,&temp_conv,16)/256.0)*360.0)); } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[8] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+8),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) { weather->wx_temp[0]=0; } } /* rain total long term */ if (data[12] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0]=0; } } /* baro */ if (data[16] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+16),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_baro[0]=0; } } /* outdoor humidity */ if (data[24] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+24),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", (strtol(temp_data1,&temp_conv,16)/10.0)); } else { if (!from) { weather->wx_hum[0]=0; } } /* todays rain total */ if (data[40] != '-') // '-' signifies invalid data { if (from) { substr(temp_data1,(char *)(data+40),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) { weather->wx_prec_00[0] = 0; } } } //******************************************************************** // Decode Peet Brothers Ultimeter 2000 weather data (Packet mode) // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. // // The Ultimeter 2000 can be in any of three modes, Data Logging Mode, // Packet Mode, or Complete Record Mode. This routine handles only // the Packet Mode. //******************************************************************** void decode_U2000_P(int from, unsigned char *data, WeatherRow *weather) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; int len; last_speed = 0.0; last_speed_time = 0; computed_gust = 0.0; len = (int)strlen((char *)data); if (debug_level & 1) { fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode): |%s|\n",data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } // $ULTW 0031 00 37 02CE 0069 ---- 0000 86A0 0001 ---- 011901CC 0000 0005 // ^ ^ ^ ^ ^ ^ ^ ^ // 0 6 8 12 16 32 44 48 /* wind speed peak over last 5 min */ if (data[0] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)data,4); if (from) { xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); /* this may be the only wind data */ xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { /* local station and may be the only wind data */ if (len < 51) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } } else { if (!from) { weather->wx_gust[0] = 0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may be FF // if a direction calibration has been entered. We should zero // them. // if (data[4] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+4),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) { weather->wx_course[0] = 0; } } /* outdoor temp */ if (data[8] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+8),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) { weather->wx_temp[0] = 0; } } /* todays rain total (on some units) */ if ((data[44]) != '-') // '-' signifies invalid data { if (from) { substr(temp_data1,(char *)(data+44),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) { weather->wx_prec_00[0] = 0; } } /* rain total long term */ if (data[12] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0] = 0; } } /* baro */ if (data[16] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+16),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_baro[0] = 0; } } /* outdoor humidity */ if (data[32] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+32),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) { weather->wx_hum[0] = 0; } } /* 1 min wind speed avg */ if (len > 48 && (data[48]) != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+48),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) { if (len > 48) { weather->wx_speed[0] = 0; } } } } //***************************************************************** // Decode Peet Brothers Ultimeter-II weather data // // This function is called from db.c:data_add() only. Used for // decoding incoming packets, not for our own weather station data. //***************************************************************** void decode_Peet_Bros(int from, unsigned char *data, WeatherRow *weather, int type) { time_t last_speed_time; float last_speed; float computed_gust; char temp_data1[10]; char *temp_conv; last_speed = 0.0; computed_gust = 0.0; last_speed_time = 0; if (debug_level & 1) { fprintf(stderr,"APRS WX4 Peet Bros U-II: |%s|\n",data); } weather->wx_type = WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "UII"); // '*' = MPH // '#' = km/h // // # 5 0B 75 0082 0082 // * 7 00 76 0000 0000 // ^ ^ ^ ^ // rain [1/100 inch ?] // outdoor temp // wind speed [mph / km/h] // wind dir /* wind direction */ // // 0x00 is N // 0x04 is E // 0x08 is S // 0x0C is W // substr(temp_data1,(char *)data,1); xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/16.0)*360.0); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) { /* get last speed */ last_speed = (float)atof(weather->wx_gust); last_speed_time = weather->wx_speed_sec_time; } /* wind speed */ substr(temp_data1,(char *)(data+1),2); if (type == APRS_WX4) // '#' speed in km/h, convert to mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137))); } else // type == APRS_WX6, '*' speed in mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (1.0 * strtol(temp_data1,&temp_conv,16)) ); } if (from) { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } /* outdoor temp */ if (data[3] != '-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+3),2); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03.0f", (float)(temp4-56) ); } else { if (!from) { weather->wx_temp[0] = 0; } } // Rain divided by 100 for readings in hundredth of an inch if (data[5] != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+5),4); xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); if (!from) { /* local station */ compute_rain((float)atof(weather->wx_rain_total)); /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) { weather->wx_rain_total[0] = 0; } } } /**************************************************/ /* RSW num convert. For Radio Shack WX-200, */ /* converts two decimal nibbles into integer */ /* number. */ /**************************************************/ int rswnc(unsigned char c) { return( (int)( (c>>4) & 0x0f) * 10 + (int)(c&0x0f) ); } //********************************************************* // wx fill data field // from: 0=local station, 1=regular decode (other stations) // type: type of WX packet // data: the packet of WX data // fill: the station data to fill // // This function is called only by wx.c:wx_decode() // // It is always called with a first parameter of 0, so we // use this only for our own serially-connected or network // connected weather station, not for decoding other // people's weather packets. //********************************************************* // // Note that the length of "data" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void wx_fill_data(int from, int type, unsigned char *data, DataRow *fill) { time_t last_speed_time; float last_speed; float computed_gust; int temp1; int temp2; int temp3; float temp_temp; char temp[MAX_DEVICE_BUFFER+1]; char temp_data1[10]; char *temp_conv; int len; int t2; int hidx_temp; int rh2; int hi_hum; int heat_index; WeatherRow *weather; float tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp9,tmp10,tmp11,tmp12,tmp13,tmp14,tmp15,tmp16,tmp17,tmp18,tmp19; int tmp7,tmp8; int dallas_type = 19; last_speed=0.0; computed_gust=0.0; last_speed_time=0; len=(int)strlen((char*)data); weather = fill->weather_data; // should always be defined switch (type) { //WE7U ///////////////////////////////////// // Dallas One-Wire Weather Station // ///////////////////////////////////// // KB1MTS - Added values for T13 thru T19 for humidity and barometer, // however only current values (not min or max) are used. case (DALLAS_ONE_WIRE): if (debug_level & 1) { fprintf(stderr,"APRS WX Dallas One-Wire %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "OWW"); if (19 == sscanf((const char *)data, "%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &tmp8, &tmp9, &tmp10, &tmp11, &tmp12, &tmp13, &tmp14, &tmp15, &tmp16, &tmp17, &tmp18, &tmp19)) { dallas_type = 19; } else if (12 == sscanf((const char *)data, "%f %f %f %f %f %f %d %d %f %f %f %f", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &tmp8, &tmp9, &tmp10, &tmp11, &tmp12)) { dallas_type = 12; } else { fprintf(stderr,"wx_fill_data:sscanf parsing error\n"); } // The format of the data originates here: // http://weather.henriksens.net/ // tmp1: primary temp (C) // tmp2: temp max (C) // tmp3: temp min (C) // tmp4: anemometer (mps) // tmp5: anemometer gust (peak speed MS) // tmp6: anemometer speed max * 0.447040972 (max speed MS) // tmp7: vane bearing - 1 (current wind direction) // tmp8: vane mode (max dir) // tmp9: rain rate // tmp10: rain total today // tmp11: rain total week // tmp12: rain since month // tmp13: Current Humidity // tmp14: Max Humidity // tmp15: Min Humidity // tmp16: Current Barometer // tmp17: Max Barometer // tmp18: Min Barometer // tmp19: Barometer Rate // Temperature xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)(tmp1 * 9.0 / 5.0 + 32.0 + 0.5)); //fprintf(stderr,"Read: %2.1f C, Storing: %s F\n",tmp1,weather->wx_temp); // Wind direction. Each vane increment equals 22.5 degrees. xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03d", (int)(tmp7 * 22.5 + 0.5)); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } // Wind speed. We get it in meters per second, store it // in mph. tmp4 = tmp4 * 3600.0 / 1000.0; // kph tmp4 = tmp4 * 0.62137; // mph xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(tmp4 + 0.5)); if (dallas_type == 19) { // Humidity. This is received by percentage. xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%2.1f", (double)(tmp13)); // Barometer. Sent in inHg xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%4.4f", (float)(tmp16 * 33.864)); } // Rain: I don't have a rain gauge, and I couldn't tell from the // "OWW" docs exactly which of the four rain fields did what. If // someone can help me with that I'll add rain gauge code for the // Dallas One-Wire. break; //////////////////////////////// // Peet Brothers Ultimeter-II // //////////////////////////////// case (APRS_WX4): // '#', Wind speed in km/h case (APRS_WX6): // '*', Wind speed in mph // This one assumes 0.1" rain gauge. Must correct in software if // any other type is used. if (debug_level & 1) { fprintf(stderr,"APRS WX4 Peet Bros U-II %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "UII"); /* wind direction */ // // 0x00 is N // 0x04 is E // 0x08 is S // 0x0C is W // substr(temp_data1,(char *)(data+1),1); xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/16.0)*360.0); // Check for course == 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed */ substr(temp_data1,(char *)(data+2),2); if (type == APRS_WX4) // '#', Data is in km/h, convert to mph { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (float)(strtol(temp_data1,&temp_conv,16)*0.62137))); } else // APRS_WX6 or '*', Data is in MPH { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)*1.0) ); } if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } /* outdoor temp */ if (data[4]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+4),2); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03.0f", (float)(temp4-56) ); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* rain div by 100 for readings 0.1 inch */ // What? Shouldn't this be /10? if (data[6]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+6),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } break; /////////////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in data logging mode // /////////////////////////////////////////////////////// case (APRS_WX3): if (debug_level & 1) { fprintf(stderr,"APRS WX3 Peet Bros U-2k (data logging mode) %s:<%s>\n",fill->call_sign,data+2); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed */ if (data[2]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+2),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + ((strtol(temp_data1,&temp_conv,16) /10.0)*0.62137)); if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) // From local station { weather->wx_speed[0]=0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may // be FF if a direction calibration has been entered. // We should zero them. // if (data[6]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+6),4); // Zero out the first two bytes temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) // From local station { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[10]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+10),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* rain total long term */ if (data[14]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+14),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } /* baro */ if (data[18]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+18),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } /* outdoor humidity */ if (data[26]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+26),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) // From local station { weather->wx_hum[0]=0; } } // Isn't this replaced by the above switch-case? // No, I don't think so. We can get these packets over // RF as well. /* todays rain total */ if (strlen((const char *)data) > 45) { if (data[42]!='-') // '-' signifies invalid data { if (from) // From remote station { substr(temp_data1,(char *)(data+42),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) // From local station { weather->wx_prec_00[0]=0; } } } break; ///////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in packet mode // ///////////////////////////////////////////////// case(APRS_WX5): if (debug_level & 1) { fprintf(stderr,"APRS WX5 Peet Bros U-2k Packet (Packet mode) %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); /* get last gust speed */ if (strlen(weather->wx_gust) > 0 && !from) // From local station { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* wind speed peak over last 5 min */ if (data[5]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+5),4); if (from) // From remote station { xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); /* this may be the only wind data */ xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { /* local station and may be the only wind data */ if (len<56) { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + ( strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } } else { if (!from) // From local station { weather->wx_gust[0]=0; } } /* wind direction */ // // Note that the first two digits here may be 00, or may // be FF if a direction calibration has been entered. // We should zero them. // if (data[9]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+9),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); if (!from) // From local station { weather->wx_course[0]=0; } } /* outdoor temp */ if (data[13]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+13),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { if (!from) // From local station { weather->wx_temp[0]=0; } } /* todays rain total (on some units) */ if (data[49]!='-') // '-' signifies invalid data { if (from) // From remote station { substr(temp_data1,(char *)(data+49),4); xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", strtol(temp_data1,&temp_conv,16)/100.0); } } else { if (!from) // From local station { weather->wx_prec_00[0]=0; } } /* rain total long term */ if (data[17]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+17),4); if (!from) // From local station { switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* local station */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } else { if (!from) // From local station { weather->wx_rain_total[0]=0; } } /* baro */ if (data[21]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+21),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1, &temp_conv, 16)/10.0); } else { if (!from) // From local station { weather->wx_baro[0]=0; } } /* outdoor humidity */ if (data[37]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+37),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { if (!from) // From local station { weather->wx_hum[0]=0; } } /* 1 min wind speed avg */ if (len>53 && (data[53]) != '-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+53),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); if (from) // From remote station { weather->wx_speed_sec_time = sec_now(); } else { /* local station */ computed_gust = compute_gust((float)atof(weather->wx_speed), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); } } else { if (!from) // From local station { if (len>53) { weather->wx_speed[0]=0; } } } break; ////////////////////////////////////////////////////////// // Peet Brothers Ultimeter 2000 in complete record mode // ////////////////////////////////////////////////////////// // // In this mode most fields are 4-bytes two's complement. A // few fields are 2-bytes wide. // // // case(PEET_COMPLETE): if (debug_level & 1) { fprintf(stderr,"Peet Bros U-2k Packet (Complete Record Mode) %s:<%s>\n",fill->call_sign,data); } if (!from) // From local station { int done_with_wx_speed = 0; /* decode only for local station */ weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "U2k"); if (data[12]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+12),4); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } else { weather->wx_gust[0]=0; } // Check whether field 115 is available at bytes 452 // through 455. If so, that's the one-minute wind // speed average in 0.1kph, which matches the APRS // spec except for the units (which should be MPH). if ( (len >= 456) && (data[452] != '-') ) // '-' signifies invalid data { substr(temp_data1,(char *)(data+452),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); done_with_wx_speed++; } // Some Peet units don't have that particular wind // speed field, so snag what wind speed we can from // the other wind speed fields, which don't quite // match the APRS spec as they're instantaneous // values, not one-minute sustained speeds. // KG9AE // Peet Bros CR mode wind values should be selected based on which are highest. /* Wind Speed fields 1, 34, and 71. Wind direction fields 2, 35, 72. */ if (data[4] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+4, 4); temp1 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp1=0; } if (data[136] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+136, 4); temp2 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp2=0; } if (data[284] !='-') // '-' signifies invalid data { substr(temp_data1, (char *)data+284, 4); temp3 = 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137; } else { temp3=0; } // fprintf(stderr,"WIND: wind1 %d, wind2 %d, wind3 %d\n", temp1, temp2, temp3); // Select wind speed and direction based on which // wind speed is the highest. Ugh, surely there's a // way to make this pretty. A function might be // better. if ( temp1 >= temp2 && temp1 >= temp3 ) { // fprintf(stderr,"WIND: ***\n"); /* wind speed */ if (!done_with_wx_speed) { substr(temp_data1,(char *)(data+4),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[8]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+8),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else if ( temp2 >= temp1 && temp2 >= temp3 ) { // fprintf(stderr,"WIND: ***\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+136),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[140]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+140),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else if ( temp3 >= temp2 && temp3 >= temp1 ) { // fprintf(stderr,"WIND: ***\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+284),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[288]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+288),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } else /* Or default to the first value */ { // fprintf(stderr,"WIND: DEFAULTING!\n"); if (!done_with_wx_speed) { /* wind speed */ substr(temp_data1,(char *)(data+4),4); xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); } /* wind direction */ // // Note that the first two digits here may be // 00, or may be FF if a direction calibration // has been entered. We should zero them. // if (data[8]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+8),4); temp_data1[0] = '0'; temp_data1[1] = '0'; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03.0f", (strtol(temp_data1,&temp_conv,16)/256.0)*360.0); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } } else { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "000"); weather->wx_course[0]=0; } } /* outdoor temp */ if (data[24]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+24),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); } else { weather->wx_temp[0]=0; } // We don't want to parse this here because compute_rain() // calculates this for us from the accumulating long-term rain // total. If we were to do it here as well, we'll get conflicting // results. Since only some units put out today's rain total, we'll // just rely on our own calculations for it instead. It'll work // across more units. /* // todays rain total (on some units) if (data[28]!='-') { // '-' signifies invalid data substr(temp_data1,(char *)(data+28),4); switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/254.0); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", (float)strtol(temp_data1,&temp_conv,16)/100.0); break; } } else weather->wx_prec_00[0]=0; */ /* rain total long term */ if ((char)data[432]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+432),4); switch (WX_rain_gauge_type) { case 1: // 0.1" rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*10.0); break; case 3: // 0.1mm rain gauge xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)/2.54); break; case 2: // 0.01" rain gauge case 0: // No conversion default: xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", strtol(temp_data1,&temp_conv,16)*1.0); break; } /* Since local station only */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /*last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /*last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { weather->wx_rain_total[0]=0; } /* baro */ if (data[32]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+32),4); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", strtol(temp_data1,&temp_conv,16)/10.0); } else { weather->wx_baro[0]=0; } /* outdoor humidity */ if (data[52]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+52),4); xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03.0f", strtol(temp_data1,&temp_conv,16)/10.0); } else { weather->wx_hum[0]=0; } /* dew point */ if (data[60]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+60),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_dew_point, sizeof(wx_dew_point), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_dew_point_on = 1; } /*high winds for today*/ if (data[248]!='-') // '-' signifies invalid data { substr(temp_data1,(char *)(data+248),4); xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%03.0f", 0.5 + (strtol(temp_data1,&temp_conv,16)/10.0)*0.62137); wx_high_wind_on = 1; } /*wind chill */ if (data[20]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+20),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_wind_chill_on = 1; } /*3-Hr Barometric Change */ if (data[36]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+36),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_three_hour_baro, sizeof(wx_three_hour_baro), "%0.2f", // Old code // (float)((strtol(temp_data1,&temp_conv,16)<<16)/65536)/100.0/3.38639); // New code, fix by Matt Werner, kb0kqa: (float)((temp4<<16)/65536)/10.0); wx_three_hour_baro_on = 1; } /* High Temp for Today*/ if (data[276]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+276),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_hi_temp_on = 1; } else { wx_hi_temp_on = 0; } /* Low Temp for Today*/ if (data[100]!='-') // '-' signifies invalid data { int temp4; substr(temp_data1,(char *)(data+100),4); temp4 = (int)strtol(temp_data1,&temp_conv,16); if (temp_data1[0] > '7') // Negative value, convert { temp4 = (temp4 & (temp4-0x7FFF)) - 0x8000; } xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%03d", (int)((float)((temp4<<16)/65536)/10.0)); wx_low_temp_on = 1; } else { wx_low_temp_on = 0; } /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2; xastir_snprintf (wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on = 1; } else { wx_heat_index_on = 0; } } break; //////////////////////// // Qualimetrics Q-Net // //////////////////////// case(QM_WX): if (debug_level & 1) { fprintf(stderr,"Qualimetrics Q-Net %s:<%s>\n",fill->call_sign,data); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "Q-N"); // Can this sscanf overflow the "temp" buffer? I // changed the length of temp to MAX_DEVICE_BUFFER to // avoid this problem. if (6 != sscanf((char *)data,"%19s %d %19s %d %19s %d",temp,&temp1,temp,&temp2,temp,&temp3)) { fprintf(stderr,"wx_fill_data:sscanf parsing error\n"); } /* outdoor temp */ xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((temp2/10.0))); /* baro */ xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", ((float)temp3/100.0)*33.864); /* outdoor humidity */ xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d", temp1); if (!from) // From local station { weather->wx_gust[0]=0; weather->wx_course[0]=0; weather->wx_rain[0]=0; weather->wx_prec_00[0]=0; weather->wx_prec_24[0]=0; weather->wx_rain_total[0]=0; weather->wx_gust[0]=0; weather->wx_speed[0]=0; } break; /////////////////////////////////////////////////////////// // Radio Shack WX-200 or Huger/Oregon Scientific WM-918 // /////////////////////////////////////////////////////////// case(RSWX200): // Notes: Many people run the wx200d daemon connected to the weather station, // with Xastir then connected to wx200d. Note that wx200d changes the protocol // slightly: It only sends frames that have changed to the clients. This means // even if the weather station is sending regular packets, wx200d won't send // them along to Xastir if all the bits are the same as the last packet of that // type. To fix this I had to tie into the main.c:UpdateTime() function to do // regular updates at a 30 second rate, to keep the rain and gust queues cycling // on a regular basis. // // 2nd Note: Some WX-200 weather stations send bogus data. I had to add in a // bunch of filtering to keep the global variables from getting corrupted by // this data. More filtering may need to be done and/or the limits may need to // be changed. if (!from) // From local station { if (debug_level & 1) { fprintf(stderr,"RSWX200 WX (binary)\n"); } weather->wx_type=WX_TYPE; xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "RSW"); switch (data[0]) { case 0x8f: /* humidity */ if ( (rswnc(data[20]) <= 100) && (rswnc(data[2]) >= 0) ) xastir_snprintf(weather->wx_hum, sizeof(weather->wx_hum), "%03d", rswnc(data[20])); else //sprintf(weather->wx_hum,"100"); { fprintf(stderr,"Humidity out-of-range, ignoring: %03d\n",rswnc(data[20]) ); } break; case 0x9f: /* temp */ /* all data in C ?*/ xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%0.1f", ((data[17]&0x08) ? '-' : '+'),(data[17]&0x7),rswnc(data[16])/10.0); /*fprintf(stderr,"temp data: <%s> %d %d %d\n", temp_data1,((data[17]&0x08)==0x08),(data[17]&0x7),rswnc(data[16]));*/ temp_temp = (float)((atof(temp_data1)*1.8)+32); if ( (temp_temp >= -99.0) && (temp_temp < 200.0) ) { xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); /*fprintf(stderr,"Temp %s C %0.2f %03d\n",temp_data1,atof(temp_data1),(int)atof(temp_data1)); fprintf(stderr,"Temp F %0.2f %03d\n",(atof(temp_data1)*1.8)+32,(int)(atof(temp_data1)*1.8)+32); */ } else // We don't want to save this one { fprintf(stderr,"Temp out-of-range, ignoring: %0.2f\n", temp_temp); } xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%d.%d", ((data[18]&0x80) ? '-' : '+'),(data[18]&0x70)>>4,(data[18]&0x0f),(data[17] & 0xf0) >> 4); xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); wx_hi_temp_on=1; xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d%d.%d", ((data[23]&0x80) ? '-' : '+'),(data[23]&0x70)>>4,(data[23]&0x0f),(data[22] & 0xf0) >> 4); xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%03d", (int)((atof(temp_data1)*1.8)+32)); wx_low_temp_on=1; break; case 0xaf: /* baro/dewpt */ // local baro pressure in mb? // sprintf(weather->wx_baro,"%02d%02d",rswnc(data[2]),rswnc(data[1])); // Sea Level Adjusted baro in mb xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0d%02d%0.1f", (data[5]&0x0f), rswnc(data[4]), rswnc(data[3])/10.0); /* dew point in C */ temp_temp = (int)((rswnc(data[18])*1.8)+32); if ( (temp_temp >= 32.0) && (temp_temp < 150.0) ) xastir_snprintf(wx_dew_point, sizeof(wx_dew_point), "%03d", (int)((rswnc(data[18])*1.8)+32)); else { fprintf(stderr,"Dew point out-of-range, ignoring: %0.2f\n", temp_temp); } break; case 0xbf: /* Rain */ // All data in mm. Convert to hundredths of an inch. xastir_snprintf(temp_data1, sizeof(temp_data1), "%02d%02d", rswnc(data[6]), rswnc(data[5])); temp_temp = (float)(atof(temp_data1) * 3.9370079); if ( (temp_temp >= 0) && (temp_temp < 51200.0) ) // Between 0 and 512 inches { xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%0.2f", atof(temp_data1) * 3.9370079); /* Since local station only */ compute_rain((float)atof(weather->wx_rain_total)); weather->wx_compute_rain_rates=1; /* Last hour rain */ xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%0.2f", rain_minute_total); /* Last 24 hour rain */ xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%0.2f", rain_24); /* Rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } else { fprintf(stderr,"Total Rain out-of-range, ignoring: %0.2f\n", temp_temp); } break; case 0xcf: /* Wind w/chill*/ /* get last gust speed */ if (strlen(weather->wx_gust) > 0) { /* get last speed */ last_speed=(float)atof(weather->wx_gust); last_speed_time=weather->wx_speed_sec_time; } /* all data in m/s */ /* average wind speed */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[5]&0xf), (float)( rswnc(data[4]) / 10 )); // Convert to mph xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%03d", (int)(0.5 + (atof(temp_data1)*2.2369))); /* wind gust */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[2]&0xf), (float)( rswnc(data[1]) / 10 )); /*sprintf(weather->wx_gust,"%03d",(int)(0.5 + (atof(temp_data1)*2.2369)));*/ /* do computed gust, convert to mph */ computed_gust = compute_gust((int)(0.5 + (atof(temp_data1)*2.2369)), last_speed, &last_speed_time); weather->wx_speed_sec_time = sec_now(); xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%03d", (int)(0.5 + computed_gust)); /* high wind gust */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%01d%0.1f", (data[8]&0xf), (float)( rswnc(data[7]) / 10 )); xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%03d", (int)(0.5 + (atof(temp_data1)*2.2369))); wx_high_wind_on = 1; xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%03d", ( ((rswnc(data[3])*10) + ((data[2]&0xf0)>>4)) %1000 ) ); // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } /* wind chill in C */ xastir_snprintf(temp_data1, sizeof(temp_data1), "%c%d", ((data[21]&0x20) ? '-' : '+'), rswnc(data[16])); temp_temp = (float)((atof(temp_data1)*1.8)+32); if ( (temp_temp > -200.0) && (temp_temp < 200.0) ) xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%03d", (int)((atof(temp_data1)*1.8)+32)); else { fprintf(stderr,"Wind_chill out-of-range, ignoring: %0.2f\n", temp_temp); } wx_wind_chill_on = 1; break; default: break; } if (strlen(weather->wx_hum) > 0 && strlen(weather->wx_temp) > 0) { /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=(-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2); xastir_snprintf(wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on=1; } else { wx_heat_index[0] = 0; } } // end of heat index calculation } // end of if (!from) break; // End of case for RSWX200 weather station /////////////////////////////////////////////////////////// // Davis WMII/WWIII/Vantage Pro via meteo & db2APRS // /////////////////////////////////////////////////////////// // Note: format is really APRS Spec 'positionless' WX string w/tag for X and Davis case(DAVISMETEO) : // todo - need to deal with lack of values, such as c...s...g...t045 string memset(weather->wx_course,0,4); // Keep out fradulent data... memset(weather->wx_speed,0,4); memset(weather->wx_temp,0,5); memset(weather->wx_rain,0,10); memset(weather->wx_prec_00,0,10); memset(weather->wx_prec_24,0,10); memset(weather->wx_rain_total,0,10); memset(weather->wx_hum,0,5); memset(weather->wx_baro,0,10); memset(weather->wx_station,0,MAX_WXSTATION); if ((temp_conv=strchr((char *)data,'c'))) // Wind Direction in Degrees { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "%s", temp_conv+1); weather->wx_course[3] = '\0'; } // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } if ((temp_conv=strchr((char *)data,'s'))) // Wind Speed in MPH - not snowfall { xastir_snprintf(weather->wx_speed, sizeof(weather->wx_speed), "%s", temp_conv+1); weather->wx_speed[3] = '\0'; } if ((temp_conv=strchr((char *)data,'g'))) // Wind Gust in MPH { // Don't read if data is "..." (missing gust data) // If we aren't getting gust data from the station, don't clobber // the gust data we're computing! if (strncmp(temp_conv+1,"...",3) != 0) { memset(weather->wx_gust,0,4); // keep out fraudulent data xastir_snprintf(weather->wx_gust, sizeof(weather->wx_gust), "%s", temp_conv+1); weather->wx_gust[3] = '\0'; // compute high wind if(wx_high_wind[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_gust) > atol(wx_high_wind))) // gust { xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%s", weather->wx_gust); } wx_high_wind_on=1; } } if ((temp_conv=strchr((char *)data,'t'))) // Temperature in Degrees F { xastir_snprintf(weather->wx_temp, sizeof(weather->wx_temp), "%s", temp_conv+1); weather->wx_temp[3] = '\0'; // compute hi temp, since APRS doesn't send that if(wx_hi_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) > atol(wx_hi_temp))) { xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%s", weather->wx_temp); } wx_hi_temp_on=1; // compute low temp, since APRS doesn't send that if(wx_low_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) < atol(wx_low_temp))) { xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%s", weather->wx_temp); } wx_low_temp_on=1; } if ((temp_conv=strchr((char *)data,'r'))) // Rain per hour { xastir_snprintf(weather->wx_rain, sizeof(weather->wx_rain), "%s", temp_conv+1); weather->wx_rain[3] = '\0'; } if ((temp_conv=strchr((char *)data,'p'))) // Rain per 24 hrs/total { xastir_snprintf(weather->wx_prec_24, sizeof(weather->wx_prec_24), "%s", temp_conv+1); weather->wx_prec_24[3] = '\0'; } if ((temp_conv=strchr((char *)data,'P'))) // Rain since midnight { xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%s", temp_conv+1); weather->wx_prec_00[3] = '\0'; } if ((temp_conv=strchr((char *)data,'T'))) // Total Rain since { // wx station reset xastir_snprintf(weather->wx_rain_total, sizeof(weather->wx_rain_total), "%s", temp_conv+1); weather->wx_rain_total[4] = '\0'; } // Ok, here's the deal --- if we got total rain AND we didn't get // rain-since-midnight, fix it up. // This is a problem with LaCrosse --- no rain-since-midnight // provided. Don't do anything at all if we didn't get total rain // from the station. compute_rain *depends* on "total rain" being // a strictly increasing number that is never reset to zero during // Xastir's run. if (strlen(weather->wx_rain_total) >0 ) { compute_rain((float)atof(weather->wx_rain_total)); if (weather->wx_prec_00[0] == '\0') { /* rain since midnight */ xastir_snprintf(weather->wx_prec_00, sizeof(weather->wx_prec_00), "%0.2f", rain_00); } } // we are should be getting total rain from the station, but // we are also getting the rates. // Davis gives 24-hour, since-midnight, and 1-hour rates. // LaCrosse gives 24 and 1 hour. // Don't recompute what the station already gave us. weather->wx_compute_rain_rates=0; if ((temp_conv=strchr((char *)data,'h'))) // Humidity % { if (!strncmp(temp_conv+1,"00",2)) // APRS says 00 is { xastir_snprintf(weather->wx_hum, // 100% humidity sizeof(weather->wx_hum), "%s", "100"); weather->wx_hum[3] = '\0'; } else { xastir_snprintf(weather->wx_hum, // humidity less than sizeof(weather->wx_hum), // 100% "%s", temp_conv+1); weather->wx_hum[2] = '\0'; } } if ((temp_conv=strchr((char *)data,'b'))) // Air Pressure in 1/10 hPa { memset(temp_data1,0,sizeof(temp_data1)); xastir_snprintf(temp_data1, sizeof(temp_data1), "%s", temp_conv+1); temp_data1[5] = '\0'; temp_temp = (float)(atof(temp_data1))/10.0; xastir_snprintf(temp_data1, sizeof(temp_data1), "%0.1f", temp_temp); xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%s", temp_data1); } if ((temp_conv=strchr((char *)data,'x'))) // WX Station Identifier { xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "%s", temp_conv+1); weather->wx_station[MAX_WXSTATION-1] = '\0'; } // now compute wind chill wind_chill = 35.74 + .6215 * atof(weather->wx_temp) - 35.75 * pow(atof(weather->wx_gust), .16) + .4275 * atof(weather->wx_temp) * pow(atof(weather->wx_gust), .16); if((wind_chill < atof(weather->wx_temp)) && (atof(weather->wx_temp) < 50)) { xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%.0f", wind_chill); wx_wind_chill_on = 1; } else { wx_wind_chill_on = 0; wx_wind_chill[0] = '\0'; } // The rest of the optional WX data is not used by // xastir (Luminosity, etc), except for snow, which // conflicts with wind speed (both are lower case 's') if (debug_level & 1) fprintf(stdout,"Davis Decode: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r00-%s,r24-%s,rt-%s,h-%s,ap-%s,station-%s\n", weather->wx_course,weather->wx_speed,weather->wx_gust, weather->wx_temp,weather->wx_rain,weather->wx_prec_00, weather->wx_prec_24,weather->wx_rain_total, weather->wx_hum,weather->wx_baro,weather->wx_station); break; // This is the output of the Davis APRS Data Logger. The format // is in fact exactly the same as a regular APRS weather packet, // complete with position information. Ignore that. // @xxxxxxzDDMM.mmN/DDDMM.mmW_CSE/SPDgGGGtTTTrRRRpRRRPRRRhXXbXXXXX.DsVP case (DAVISAPRSDL): memset(weather->wx_course,0,4); // Keep out fradulent data... memset(weather->wx_speed,0,4); memset(weather->wx_gust,0,4); memset(weather->wx_temp,0,5); memset(weather->wx_rain,0,10); memset(weather->wx_prec_00,0,10); memset(weather->wx_prec_24,0,10); memset(weather->wx_rain_total,0,10); memset(weather->wx_hum,0,5); memset(weather->wx_baro,0,10); memset(weather->wx_station,0,MAX_WXSTATION); if (sscanf((char *)data, "%*27s%3s/%3sg%3st%3sr%3sp%3sP%3sh%2sb%5s.DsVP", weather->wx_course, weather->wx_speed, weather->wx_gust, weather->wx_temp, weather->wx_rain, weather->wx_prec_24, weather->wx_prec_00, weather->wx_hum, weather->wx_baro) == 9) { // then we got all the data out of the packet... now process // First null-terminate all the strings: weather->wx_course[3]='\0'; weather->wx_speed[3]='\0'; weather->wx_gust[3]='\0'; weather->wx_temp[3]='\0'; weather->wx_rain[3]='\0'; weather->wx_prec_24[3]='\0'; weather->wx_prec_00[3]='\0'; weather->wx_hum[2]='\0'; weather->wx_baro[6]='\0'; // NOTE: Davis APRS Data Logger does NOT provide total rain, // and so data from compute_rain (which needs total rain) will // be wrong. Set this flag to stop that from clobbering our // good rain rate data. weather->wx_compute_rain_rates=0; // Check for course = 0. Change to 360. if (strncmp(weather->wx_course,"000",3) == 0) { xastir_snprintf(weather->wx_course, sizeof(weather->wx_course), "360"); } // compute high wind if(wx_high_wind[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_gust) > atol(wx_high_wind))) // gust { xastir_snprintf(wx_high_wind, sizeof(wx_high_wind), "%s", weather->wx_gust); } wx_high_wind_on=1; // compute hi temp, since APRS doesn't send that if(wx_hi_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) > atol(wx_hi_temp))) { xastir_snprintf(wx_hi_temp, sizeof(wx_hi_temp), "%s", weather->wx_temp); } wx_hi_temp_on=1; // compute low temp, since APRS doesn't send that if(wx_low_temp[0] == '\0' || // first time (get_hours() == 0 && get_minutes() == 0) || // midnite (atol(weather->wx_temp) < atol(wx_low_temp))) { xastir_snprintf(wx_low_temp, sizeof(wx_low_temp), "%s", weather->wx_temp); } wx_low_temp_on=1; // fix up humidity --- 00 in APRS means 100%: if (strncmp(weather->wx_hum,"00",2)==0) { weather->wx_hum[0]='1'; weather->wx_hum[1]=weather->wx_hum[2]='0'; weather->wx_hum[3]='\0'; } // fix up barometer. APRS sends in 10ths of millibars: temp_temp=(float)(atof(weather->wx_baro))/10.0; weather->wx_baro[0]='\0'; // zero out so snprintf doesn't append xastir_snprintf(weather->wx_baro, sizeof(weather->wx_baro), "%0.1f", temp_temp); // this should terminate Just Fine. // now compute wind chill wind_chill = 35.74 + .6215 * atof(weather->wx_temp) - 35.75 * pow(atof(weather->wx_gust), .16) + .4275 * atof(weather->wx_temp) * pow(atof(weather->wx_gust), .16); if((wind_chill < atof(weather->wx_temp)) && (atof(weather->wx_temp) < 50)) { xastir_snprintf(wx_wind_chill, sizeof(wx_wind_chill), "%.0f", wind_chill); wx_wind_chill_on = 1; } else { wx_wind_chill_on = 0; wx_wind_chill[0] = '\0'; } xastir_snprintf(weather->wx_station, sizeof(weather->wx_station), "%s", (char *) &(data[63])); /* Heat Index Calculation*/ hi_hum=atoi(weather->wx_hum); rh2= atoi(weather->wx_hum); rh2=(rh2 * rh2); hidx_temp=atoi(weather->wx_temp); t2= atoi(weather->wx_temp); t2=(t2 * t2); if (hidx_temp >= 70) { heat_index=-42.379+2.04901523 * hidx_temp+10.1433127 * hi_hum-0.22475541 * hidx_temp * hi_hum-0.00683783 * t2-0.05481717 * rh2+0.00122874 * t2 * hi_hum+0.00085282 * hidx_temp * rh2-0.00000199 * t2 * rh2; xastir_snprintf (wx_heat_index, sizeof(wx_heat_index), "%03d", heat_index); wx_heat_index_on = 1; } else { wx_heat_index_on = 0; } if (debug_level & 1) fprintf(stdout,"Davis APRS DataLogger Decode $Revision$: wd-%s,ws-%s,wg-%s,t-%s,rh-%s,r24-%s,r00-%s,h-%s,ap-%s,station-%s\n", weather->wx_course,weather->wx_speed,weather->wx_gust, weather->wx_temp, weather->wx_rain, weather->wx_prec_24, weather->wx_prec_00,weather->wx_hum,weather->wx_baro, weather->wx_station); } break; } // End of big switch } // End of wx_fill_data() //********************************************************** // Decode WX data line // wx_line: raw wx data to decode // // This is called from main.c:UpdateTime() only. It // decodes data for serially-connected and network-connected // WX interfaces only. It calls wx_fill_data() to do the // real work once it figures out what type of data it has. //********************************************************** // // Note that the length of "wx_line" can be up to MAX_DEVICE_BUFFER, // which is currently set to 4096. // void wx_decode(unsigned char *wx_line, int data_length, int port) { DataRow *p_station; int decoded; int find; int i; int len; char time_data[MAX_TIME]; unsigned int check_sum; int max; WeatherRow *weather; float t1,t2,t3,t4,t5,t6,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19; int t7,t8; //fprintf(stderr,"wx_decode: %s\n",wx_line); //fprintf(stderr,"\nwx_decode: %d bytes\n", data_length); find=0; len = data_length; if (len == 0) { len=strlen((char *)wx_line); } if (len>10 || ((int)wx_line[0]!=0 && port_data[port].data_type==1)) { if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // DK7IN: only add record if we found something... { weather = p_station->weather_data; decoded=0; /* Ok decode wx data */ if (wx_line[0]=='!' && wx_line[1]=='!' && is_xnum_or_dash((char *)(wx_line+2),40) && port_data[port].data_type==0) { /* Found Peet Bros U-2k */ if (debug_level & 1) { fprintf(stderr,"Found Peet Bros U-2k WX:%s\n",wx_line+2); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI011")); xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,APRS_WX3,wx_line,p_station); decoded=1; } else if (((wx_line[0]=='#') || (wx_line[0]=='*')) && is_xnum_or_dash((char *)(wx_line+1),13) && port_data[port].data_type==0) { /* Found Peet Bros raw U2 data */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI012")); if (debug_level & 1) { fprintf(stderr,"Found Peet Bros raw U2 data WX#:%s\n",wx_line+1); } xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; if (wx_line[0]=='#') // Wind speed in km/h { wx_fill_data(0,APRS_WX4,wx_line,p_station); } else // '*', Wind speed in mph { wx_fill_data(0,APRS_WX6,wx_line,p_station); } decoded=1; } else if (strncmp("$ULTW",(char *)wx_line,5)==0 && is_xnum_or_dash((char *)(wx_line+5),44) && port_data[port].data_type==0) { /* Found Peet Bros raw U2 data */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI013")); if (debug_level & 1) { fprintf(stderr,"Found Peet Bros Ultimeter Packet data WX#:%s\n",wx_line+5); } xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,APRS_WX5,wx_line,p_station); decoded=1; } else if (wx_line[2]==' ' && wx_line[5]==' ' && wx_line[8]=='/' && wx_line[11]=='/' && wx_line[14]==' ' && wx_line[17]==':' && wx_line[20]==':' && strncmp(" #0:",(char *)wx_line+23,4)==0 && port_data[port].data_type==0) { find=0; for (i=len; i>23 && !find; i--) { if ((int)wx_line[i]==0x03) { find=1; wx_line[i] = 0; } } if (find) { /* found Qualimetrics Q-Net station */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI016")); if (debug_level & 1) { fprintf(stderr,"Found Qualimetrics Q-Net station data WX#:%s\n",wx_line+23); } xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,QM_WX,wx_line+24,p_station); decoded=1; } } //WE7U // else look for ten ASCII decimal point chars in the input, or do an // sscanf looking for the correct number and types of fields for the // OWW server in ARNE mode. 6 %f's, 2 %d's, 11 %f's. else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f %f %f %f %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12,&t13,&t14,&t15,&t16,&t17,&t18,&t19) == 19) { // Found Dallas One-Wire Weather Station if (debug_level & 1) { fprintf(stderr,"Found OWW ARNE-mode(19) one-wire weather station data\n"); } weather->wx_sec_time=sec_now(); wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station); decoded=1; } else if (sscanf((const char *)wx_line,"%f %f %f %f %f %f %d %d %f %f %f %f", &t1,&t2,&t3,&t4,&t5,&t6,&t7,&t8,&t9,&t10,&t11,&t12) == 12) { // Found Dallas One-Wire Weather Station if (debug_level & 1) { fprintf(stderr,"Found OWW ARNE-mode(12) one-wire weather station data\n"); } weather->wx_sec_time=sec_now(); wx_fill_data(0,DALLAS_ONE_WIRE,wx_line,p_station); decoded=1; } else if (strncmp("&CR&",(char *)wx_line,4)==0 && is_xnum_or_dash((char *)(wx_line+5),44) && port_data[port].data_type==0) { if (debug_level & 1) { fprintf(stderr,"Found Peet Complete station data\n"); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI017")); xastir_snprintf(raw_wx_string, sizeof(raw_wx_string), "%s", wx_line); raw_wx_string[MAX_RAW_WX_STRING] = '\0'; // Terminate it weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,PEET_COMPLETE,wx_line,p_station); decoded=1; } else if (port_data[port].data_type==1) { // int jj; /* binary data type */ if (debug_level & 1) { fprintf(stderr,"Found binary data: %d bytes\n", len); } /* clear raw string */ memset(raw_wx_string,0,sizeof(raw_wx_string)); max=0; switch (wx_line[0]) { case 0x8f: max=34; break; case 0x9f: max=33; break; case 0xaf: max=30; break; case 0xbf: max=13; break; case 0xcf: max=26; break; default: break; } // fprintf(stderr, "wx_decode binary: "); // for (jj = 0; jj < len+1; jj++) { // fprintf(stderr, "%02x ", wx_line[jj]); // } // fprintf(stderr, "\n"); // fprintf(stderr, "Integers: "); // for (jj = 0; jj < max+1; jj++) { // fprintf(stderr, "%0d ", wx_line[jj]); // } // fprintf(stderr, "\n"); if (len < (max+1)) { fprintf(stderr, " Short NET_WX packet, %d bytes\n", len); } if (max > 0 && len >= (max+1) ) { // Compute the checksum from the data check_sum = 0; for (i = 0; i < max; i++) { check_sum += wx_line[i]; } // fprintf(stderr," Checksum: 0x%02x ", 0x0ff & check_sum); if ( wx_line[max] == (0xff & check_sum) ) { /* good RS WX-200 data */ //fprintf(stderr,"GOOD RS WX-200 %0X data\n",wx_line[0]); /* found RS WX-200 */ xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI025")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); //weather->wx_data=1; wx_fill_data(0,RSWX200,wx_line,p_station); decoded=1; } else { // fprintf(stderr, "bad"); } } } else if (wx_line[0]=='@' && strncmp((char *)&(wx_line[63]),".DsVP",5)==0) { // this is a Davis Vantage Pro with APRS Data Logger if (debug_level & 1) { fprintf(stdout,"Davis VP APRS Data Logger data found ... %s\n", wx_line); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI028")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); wx_fill_data(0,DAVISAPRSDL,wx_line,p_station); decoded=1; } else // ASCII data of undetermined type { // Davis Weather via meteo -> db2APRS -> TCP port if (strstr((const char *)wx_line, "xDvs")) // APRS 'postionless' WX data w/ Davis & X tag { if (debug_level & 1) { fprintf(stdout,"Davis Data found... %s\n",wx_line); } xastir_snprintf(wx_station_type, sizeof(wx_station_type), "%s", langcode("WXPUPSI026")); xastir_snprintf(weather->wx_time, sizeof(weather->wx_time), "%s", get_time(time_data)); weather->wx_sec_time=sec_now(); wx_fill_data(0,DAVISMETEO,wx_line,p_station); decoded=1; } else if (debug_level & 1) { fprintf(stderr,"Unknown WX DATA:%s\n",wx_line); } } if (decoded) { /* save data back */ if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(1)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].decode_errors=0; if (end_critical_section(&port_data_lock, "wx.c:wx_decode(2)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } statusline(langcode("BBARSTA032"),1); // Decoded WX Data /* redraw now */ //redraw_on_new_data=2; redraw_on_new_data=1; fill_wx_data(); } else { /* Undecoded packet */ memset(raw_wx_string,0,sizeof(raw_wx_string)); if (begin_critical_section(&port_data_lock, "wx.c:wx_decode(3)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } port_data[port].decode_errors++; // We have errors in decoding if (port_data[port].decode_errors>10) { /* wrong data type? */ port_data[port].data_type++; // Try another data type. 0=ascii, 1=wx binary port_data[port].data_type&=0x01; /*if (debug_level & 1)*/ fprintf(stderr,"Data type %d\n",port_data[port].data_type); port_data[port].decode_errors=0; } if (end_critical_section(&port_data_lock, "wx.c:wx_decode(4)" ) > 0) { fprintf(stderr,"port_data_lock, Port = %d\n", port); } } } } } } /***********************************************************/ /* fill string with WX data for transmit */ /* */ /***********************************************************/ time_t wx_tx_data1(char *st, int st_size) { DataRow *p_station; time_t wx_time; char temp[100]; WeatherRow *weather; st[0] = '\0'; wx_time = 0; if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // station has wx data { weather = p_station->weather_data; //WE7U: For debugging purposes only //weather->wx_sec_time=sec_now(); //sprintf(weather->wx_course,"359"); // degrees //sprintf(weather->wx_speed,"001"); // mph //sprintf(weather->wx_gust,"010"); // mph //sprintf(weather->wx_temp,"069"); // Fahrenheit //if ( strlen(weather->wx_rain_total) == 0) // sprintf(weather->wx_rain_total,"1900.40"); //sprintf(weather->wx_rain_total,"1987.6"); // hundredths of an inch //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain_total,"1988.6"); //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain_total,"1990.6"); //compute_rain(atof(weather->wx_rain_total)); //sprintf(weather->wx_rain,"%0.2f",rain_minute_total); //sprintf(weather->wx_prec_24,"%0.2f",rain_24); //sprintf(weather->wx_prec_00,"%0.2f",rain_00); //sprintf(weather->wx_rain,"0"); // hundredths of an inch //sprintf(weather->wx_prec_00,"0"); // hundredths of an inch //sprintf(weather->wx_prec_24,"0"); // hundredths of an inch //sprintf(weather->wx_hum,"92"); // % //sprintf(weather->wx_baro,"1013.0"); // hPa //weather->wx_type = WX_TYPE; //xastir_snprintf(weather->wx_station,sizeof(weather->wx_station),"RSW"); // 359/000g000t065r010P020p030h92b01000 if (strlen(weather->wx_course) > 0 && strlen(weather->wx_speed) > 0) { // We have enough wx_data wx_time=weather->wx_sec_time; xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_course); if (strlen(temp) > 3) { if (debug_level & 1) { fprintf(stderr,"wx_course too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "..."); } if ( (atoi(weather->wx_course) > 360) || (atoi(weather->wx_course) < 0) ) { if (debug_level & 1) { fprintf(stderr,"wx_course out-of-range: %s\n", weather->wx_course); } xastir_snprintf(temp, sizeof(temp), "..."); } //sprintf(st,"%s/%s",weather->wx_course,weather->wx_speed); strncat(st, temp, st_size - 1 - strlen(st)); strncat(st, "/", st_size - 1 - strlen(st)); xastir_snprintf(temp, sizeof(temp), "%s", weather->wx_speed); if (strlen(temp) > 3) { if (debug_level & 1) { fprintf(stderr,"wx_speed too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "..."); } if ( (atoi(weather->wx_speed) < 0) || (atoi(weather->wx_speed) > 999) ) { if (debug_level & 1) { fprintf(stderr,"wx_speed out-of-range: %s\n", weather->wx_speed); } xastir_snprintf(temp, sizeof(temp), "..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // We don't have enough wx_data, may be from a Qualimetrics Q-Net? wx_time=weather->wx_sec_time; xastir_snprintf(st, st_size, ".../..."); if (debug_level & 1) { fprintf(stderr,"\n\nAt least one field was empty: Course: %s\tSpeed: %s\n", weather->wx_course, weather->wx_speed); fprintf(stderr,"Will be sending '.../...' instead of real values.\n\n\n"); } } if (strlen(weather->wx_gust) > 0) { xastir_snprintf(temp, sizeof(temp), "g%s", weather->wx_gust); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_gust too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "g..."); } if (atoi(weather->wx_gust) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_gust out-of-range: %s\n", weather->wx_gust); } xastir_snprintf(temp, sizeof(temp), "g..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { strncat(st, "g...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_temp) > 0) { xastir_snprintf(temp, sizeof(temp), "t%s", weather->wx_temp); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_temp too long: %s\n", temp); } xastir_snprintf(temp, sizeof(temp), "t..."); } if ( (atoi(weather->wx_temp) > 999) || (atoi(weather->wx_temp) < -99) ) { if (debug_level & 1) { fprintf(stderr,"wx_temp out-of-bounds: %s\n", weather->wx_temp); } xastir_snprintf(temp, sizeof(temp), "t..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { strncat(st, "t...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_rain) > 0) { xastir_snprintf(temp, sizeof(temp), "r%03d", (int)(atof(weather->wx_rain) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_rain too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "r "); } if (atoi(weather->wx_rain) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_rain out-of-bounds: %s\n", weather->wx_rain); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "r..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "r...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_prec_00) > 0) { xastir_snprintf(temp, sizeof(temp), "P%03d", (int)(atof(weather->wx_prec_00) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_prec_00 too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "P "); } if (atoi(weather->wx_prec_00) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_prec_00 out-of-bounds: %s\n", weather->wx_prec_00); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "P..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "P...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_prec_24) > 0) { xastir_snprintf(temp, sizeof(temp), "p%03d", (int)(atof(weather->wx_prec_24) + 0.5) ); // Cheater's way of rounding if (strlen(temp)>4) { if (debug_level & 1) { fprintf(stderr,"wx_prec_24 too long: %s\n", temp); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "p "); } if (atoi(weather->wx_prec_24) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_prec_24 out-of-bounds: %s\n", weather->wx_prec_24); } // Don't transmit this field if it's not valid xastir_snprintf(temp, sizeof(temp), "p..."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "p...", st_size - 1 - strlen(st)); } if (strlen(weather->wx_hum) > 0) { if (atoi(weather->wx_hum)>99) { xastir_snprintf(temp, sizeof(temp), "h00"); } else xastir_snprintf(temp, sizeof(temp), "h%02d", atoi(weather->wx_hum)); if (strlen(temp) > 4) { if (debug_level & 1) { fprintf(stderr,"wx_hum too long: %s\n", temp); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"h.."); } if (atoi(weather->wx_hum) < 0) { if (debug_level & 1) { fprintf(stderr,"wx_hum out-of-bounds: %s\n", weather->wx_hum); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"h.."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "h..", st_size - 1 - strlen(st)); } if (strlen(weather->wx_baro) > 0) { xastir_snprintf(temp, sizeof(temp), "b%05d", (int)((atof(weather->wx_baro) * 10.0)) ); if (strlen(temp)>6) { if (debug_level & 1) { fprintf(stderr,"wx_baro too long: %s\n", temp); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"b....."); } if ((int)((atof(weather->wx_baro) * 10.0) < 0)) { if (debug_level & 1) { fprintf(stderr,"wx_baro out-of-bounds: %s\n", weather->wx_baro); } // Don't transmit this field if it's not valid //xastir_snprintf(temp,sizeof(temp),"b....."); } strncat(st, temp, st_size - 1 - strlen(st)); } else { // Don't transmit this field if it's not valid //strncat(st, "b.....", st_size - 1 - strlen(st)); } xastir_snprintf(temp, sizeof(temp), "%c%s", weather->wx_type, weather->wx_station); strncat(st, temp, st_size - 1 - strlen(st)); } } if (debug_level & 1) { fprintf(stderr,"Weather String: %s\n", st); } return(wx_time); } /***********************************************************/ /* transmit raw wx data */ /* */ /***********************************************************/ void tx_raw_wx_data(void) { if (strlen(raw_wx_string)>10) { output_my_data(raw_wx_string,-1,0,0,0,NULL); if (debug_level & 1) { fprintf(stderr,"Sending Raw WX data <%s>\n",raw_wx_string); } } } Xastir-Release-2.2.4/src/wx.h0000664000175000017500000000476515151324131014733 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_WX_H #define __XASTIR_WX_H #include "database.h" extern void fill_wx_data(void); extern Widget GetTopShell(Widget w); extern void pos_dialog(Widget w); extern char wx_station_type[]; /* from wx.c */ extern char wx_dew_point[10]; extern char wx_dew_point_on; extern char wx_high_wind[10]; extern char wx_high_wind_on; extern char wx_wind_chill[10]; extern char wx_wind_chill_on; extern char wx_three_hour_baro[10]; // hPa extern char wx_three_hour_baro_on; // hPa extern char wx_hi_temp[10]; extern char wx_hi_temp_on; extern char wx_low_temp[10]; extern char wx_low_temp_on; extern char wx_heat_index[10]; extern char wx_heat_index_on; extern char wx_station_type[]; /* from wx.c */ extern time_t wx_tx_data1(char *st, int st_size); extern void wx_decode(unsigned char *wx_line, int data_length, int port); extern void fill_wx_data(void); extern void clear_rain_data(void); extern void tx_raw_wx_data(void); extern void clear_local_wx_data(void); extern void wx_last_data_check(void); extern void wx_fill_data(int from, int type, unsigned char *data, DataRow *fill); extern void decode_U2000_L(int from, unsigned char *data, WeatherRow *weather); extern void decode_U2000_P(int from, unsigned char *data, WeatherRow *weather); extern void decode_Peet_Bros(int from, unsigned char *data, WeatherRow *weather, int type); extern void cycle_weather(void); /* wx_gui.c */ extern void wx_alert_update_list(void); extern void WX_station(Widget w, XtPointer clientData, XtPointer callData); extern void wx_alert_finger_output( Widget widget, char *handle); #endif // __XASTIR_WX_H Xastir-Release-2.2.4/src/wx_gui.c0000664000175000017500000027052315151324131015567 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include "xastir.h" #include "wx.h" #include "main.h" #include "db_funcs.h" #include "alert.h" #include "lang.h" #include "mutex_utils.h" #include #ifdef HAVE_XBAE_MATRIX_H #include #endif // HAVE_XBAE_MATRIX_H #include // Must be last include file #include "leak_detection.h" extern XmFontList fontlist1; // Menu/System fontlist /************ Weather Alerts ****************/ Widget wx_alert_shell = (Widget)NULL; Widget wx_detailed_alert_shell = (Widget)NULL; static Widget wx_alert_list; static xastir_mutex wx_alert_shell_lock; static xastir_mutex wx_detailed_alert_shell_lock; static xastir_mutex wx_station_dialog_lock; void wx_gui_init(void) { init_critical_section( &wx_alert_shell_lock ); init_critical_section( &wx_detailed_alert_shell_lock ); init_critical_section( &wx_station_dialog_lock ); } void wx_detailed_alert_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_detailed_alert_destroy_shell" ); XtDestroyWidget(shell); wx_detailed_alert_shell = (Widget)NULL; end_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_detailed_alert_destroy_shell" ); } // This gets/displays the "finger" output from the WXSVR. Called // from both the Station Info "NWS" button and by double-clicking on // the view weather alerts window. // void wx_alert_finger_output( Widget UNUSED(widget), char *handle) { static Widget pane, scrollwindow, my_form, mess, button_cancel,wx_detailed_alert_list; Atom delw; Arg al[50]; // Arg List unsigned int ac = 0; // Arg Count char temp[1024]; XmString item; FILE *fd; int ret; int server_fd; struct sockaddr_in serv_addr; struct hostent *serverhost; if (debug_level & 1) { fprintf(stderr,"Handle: %s\n",handle); } if(!wx_detailed_alert_shell) { begin_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_alert_double_click_action" ); wx_detailed_alert_shell = XtVaCreatePopupShell(langcode("WPUPWXA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 600, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("wx_alert_double_click_action pane",xmPanedWindowWidgetClass, wx_detailed_alert_shell, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("wx_alert_double_click_action my_form", xmFormWidgetClass, scrollwindow, XmNtraversalOn, TRUE, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNwidth, 600, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); mess = XtVaCreateManagedWidget(langcode("WPUPWXA002"), xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNvisualPolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNscrollingPolicy,XmAUTOMATIC); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNscrollBarDisplayPolicy,XmAS_NEEDED); ac++; XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, mess); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomOffset, 45); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; wx_detailed_alert_list = XmCreateScrolledList(my_form, "wx_alert_double_click_action wx_detailed_alert_list", al, ac); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, wx_detailed_alert_destroy_shell, wx_detailed_alert_shell); end_critical_section(&wx_detailed_alert_shell_lock, "wx_gui.c:wx_alert_double_click_action" ); pos_dialog(wx_detailed_alert_shell); delw = XmInternAtom(XtDisplay(wx_detailed_alert_shell), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_detailed_alert_shell, delw, wx_detailed_alert_destroy_shell, (XtPointer)wx_detailed_alert_shell); XtManageChild(my_form); XtManageChild(wx_detailed_alert_list); XtVaSetValues(wx_detailed_alert_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, wx_detailed_alert_shell); XtPopup(wx_detailed_alert_shell, XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(wx_detailed_alert_shell); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(wx_detailed_alert_shell), XtWindow(wx_detailed_alert_shell)); } // Erase the entire list before we start writing to it in // case it was left up from a previous query. XmListDeleteAllItems(wx_detailed_alert_list); // Perform a "finger" command, which is really just a telnet // with a single line command sent to the remote host, then a // bunch of text sent back. We implement it here via our own // TCP code, as it's really very simple. // Allocate a socket for our use if ((server_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { // fprintf(stderr,"wx_alert_finger_output: can't get socket\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: can't get socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); return; } memset(&serv_addr, 0, sizeof(serv_addr)); // Changing Finger host because WXSVR.net has been down for a // month or more and Pete, AE5PL, has a replacement online that // performs this function. //serverhost = gethostbyname("wxsvr.net"); serverhost = gethostbyname("wx.aprs-is.net"); if (serverhost == (struct hostent *)0) { // fprintf(stderr,"wx_alert_finger_output: gethostbyname failed\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: gethostbyname failed"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } memmove(&serv_addr.sin_addr,serverhost->h_addr, (size_t)serverhost->h_length); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(79); // Finger protocol uses port 79 if (connect(server_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) != 0) { // fprintf(stderr,"wx_alert_finger_output: connect to server failed\n"); xastir_snprintf(temp, sizeof(temp), "wx_alert_finger_output: connect to server failed"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Create a file descriptor for the socket fd = fdopen(dup(server_fd),"wb"); if (fd == NULL) { // fprintf(stderr,"Couldn't create duplicate write socket\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't create duplicate write socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Set up the text we're going to send to the remote finger // server. xastir_snprintf(temp, sizeof(temp), "%s\r\n", handle); // Send the request text out the socket ret = fprintf(fd, "%s", temp); if (ret == 0 || ret == -1) { // fprintf(stderr,"Couldn't send finger command to wxsvr\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't send finger command to wxsvr"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)fclose(fd); (void)close(server_fd); // Close the socket return; } // Close the duplicate port we used for writing (void)fclose(fd); // // Read back the results from the socket // // Create a file descriptor for the socket fd = fdopen(dup(server_fd),"rb"); if (fd == NULL) { // fprintf(stderr,"Couldn't create duplicate read socket\n"); xastir_snprintf(temp, sizeof(temp), "Couldn't create duplicate read socket"); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); (void)close(server_fd); // Close the socket return; } // Process the data we received from the remote finger server // while (fgets (temp, sizeof (temp), fd)) // While we have data to process { char *ptr; // Remove any linefeeds or carriage returns from each // string. ptr = temp; while ( (ptr = strpbrk(temp, "\n\r")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); } if (debug_level & 1) { fprintf(stderr,"%s\n",temp); } // Create an XmString for each line and add it to the // end of the list. item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); XmListAddItemUnselected(wx_detailed_alert_list, item, 0); XmStringFree(item); } // All done! fclose(fd); (void)close(server_fd); // Close the socket } void wx_alert_double_click_action( Widget widget, XtPointer UNUSED(clientData), XtPointer callData) { char *choice; XmListCallbackStruct *selection = callData; char handle[14]; char *ptr; XmStringGetLtoR(selection->item, XmFONTLIST_DEFAULT_TAG, &choice); //fprintf(stderr,"Selected item %d (%s)\n", selection->item_position, choice); // Grab the first 13 characters. Remove spaces. This is our handle // into the weather server for the full weather alert text. xastir_snprintf(handle, sizeof(handle), "%s", choice); XtFree(choice); // Release as soon as we're done! handle[13] = '\0'; // Terminate the string // Remove spaces ptr = handle; while ( (ptr = strpbrk(handle, " ")) ) { memmove(ptr, ptr+1, strlen(ptr)+1); } handle[9] = '\0'; // Terminate after first 9 chars if (debug_level & 1) { fprintf(stderr,"Handle: %s\n",handle); } wx_alert_finger_output( widget, handle); } void wx_alert_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_destroy_shell" ); XtDestroyWidget(shell); wx_alert_shell = (Widget)NULL; end_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_destroy_shell" ); } static int alert_comp(const void *a, const void *b) { alert_entry *a_entry = *(alert_entry **)a; alert_entry *b_entry = *(alert_entry **)b; int a_active, b_active; if (a_entry->title[on_screen] && !b_entry->title[on_screen]) { return (-1); } if (!a_entry->title[0] && b_entry->title[0]) { return (1); } if (a_entry->flags[on_screen] == 'Y' && b_entry->flags[on_screen] != 'Y') { return (-1); } if (a_entry->flags[on_screen] != 'Y' && b_entry->flags[on_screen] == 'Y') { return (1); } if (a_entry->flags[on_screen] == '?' && b_entry->flags[on_screen] == 'N') { return (-1); } if (a_entry->flags[on_screen] == 'N' && b_entry->flags[on_screen] == '?') { return (1); } a_active = alert_active(a_entry, ALERT_ALL); b_active = alert_active(b_entry, ALERT_ALL); if (a_active && b_active) { if (a_active - b_active) { return (a_active - b_active); } } else if (a_active) { return (-1); } else if (b_active) { return (1); } return (strcmp(a_entry->title, b_entry->title)); } void wx_alert_update_list(void) { int nn; // index into alert table. Starts at 0 int ii; // index into dialog lines. Starts at 1 int max_item_count; // max dialog lines char temp[600]; XmString item; static alert_entry **alert_list; static int alert_list_limit; if (wx_alert_shell) { struct hashtable_itr *iterator; alert_entry *alert; begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_update_list" ); // Get the previous alert count from the alert list window XtVaGetValues(wx_alert_list, XmNitemCount, &max_item_count, NULL); if ((nn = alert_list_count()) > alert_list_limit) { alert_entry **tmp = realloc(alert_list, nn * sizeof(alert_entry *)); if (tmp) { alert_list = tmp; alert_list_limit = nn; } else { fprintf(stderr, "wx_gui: Alert list allocation error\n"); exit(1); } } // Iterate through the alert hash. Create a string for each // non-expired/non-blank entry. iterator = create_wx_alert_iterator(); for (nn = 0, alert = get_next_wx_alert(iterator); iterator != NULL && alert; alert = get_next_wx_alert(iterator)) { // Check whether alert record is empty/filled. This // code is from the earlier array implementation. If // we're expiring records from our hash properly we // probably don't need this anymore. // // if (alert->title[0] == '\0') { // It's empty // fprintf(stderr, "wx_gui:alert->title NULL\n"); // break; // } alert_list[nn++] = alert; } qsort(alert_list, nn, sizeof(alert_entry *), alert_comp); for (ii = 0; ii < nn; ) { alert = alert_list[ii]; // AFGNPW NWS-WARN Until: 191500z AK_Z213 WIND P7IAA // TSATOR NWS-ADVIS Until: 190315z OK_C127 TORNDO H2VAA //xastir_snprintf(temp, sizeof(temp), "%-9s %-9s Until: %-7s %-7s %-20s %s", xastir_snprintf(temp, sizeof(temp), "%-9s %-5s %-9s %c%c @%c%c%c%cz ==> %c%c @%c%c%c%cz %c%c %-7s %s %s%s%s%s", alert->from, alert->seq, alert->to, alert->issue_date_time[0], alert->issue_date_time[1], alert->issue_date_time[2], alert->issue_date_time[3], alert->issue_date_time[4], alert->issue_date_time[5], alert->activity[0], alert->activity[1], alert->activity[2], alert->activity[3], alert->activity[4], alert->activity[5], alert->flags[on_screen], alert->flags[source], alert->title, alert->alert_tag, alert->desc0, alert->desc1, alert->desc2, alert->desc3); item = XmStringGenerate(temp, XmFONTLIST_DEFAULT_TAG, XmCHARSET_TEXT, NULL); ii++; // It looks like if we are higher than 'max_item_count', // it must be a new entry that we haven't written to the // window yet. Add it. if (max_item_count < ii) { XmListAddItemUnselected(wx_alert_list, item, 0); } else { // Replace it in the window. Note: This might re-order the list each time. XmListReplaceItemsPos(wx_alert_list, &item, 1, ii); } XmStringFree(item); } // End of for loop #ifndef USING_LIBGC //fprintf(stderr,"free iterator 9\n"); if (iterator) { free(iterator); } #endif // USING_LIBGC // If we have fewer alerts now, delete the extras from the window if (ii < max_item_count) { XmListDeleteItemsPos(wx_alert_list, max_item_count - ii, ii+1); } end_critical_section(&wx_alert_shell_lock, "wx_gui.c:wx_alert_update_list" ); } } void Display_Wx_Alert( Widget UNUSED(wdgt), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, mess, button_cancel; Atom delw; Arg al[50]; /* Arg List */ unsigned int ac = 0; /* Arg Count */ if(!wx_alert_shell) { begin_critical_section(&wx_alert_shell_lock, "wx_gui.c:Display_Wx_Alert" ); wx_alert_shell = XtVaCreatePopupShell(langcode("WPUPWXA001"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNminWidth, 600, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("Display_Wx_Alert pane",xmPanedWindowWidgetClass, wx_alert_shell, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("Display_Wx_Alert my_form", xmFormWidgetClass, scrollwindow, XmNtraversalOn, TRUE, XmNfractionBase, 5, XmNbackground, colors[0xff], XmNwidth, 600, XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); mess = XtVaCreateManagedWidget(langcode("WPUPWXA002"), xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 5, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 5, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); /* set args for color */ ac=0; XtSetArg(al[ac], XmNbackground, colors[0xff]); ac++; XtSetArg(al[ac], XmNvisibleItemCount, 13); ac++; XtSetArg(al[ac], XmNtraversalOn, TRUE); ac++; XtSetArg(al[ac], XmNshadowThickness, 3); ac++; // XtSetArg(al[ac], XmNselectionPolicy, XmMULTIPLE_SELECT); ac++; XtSetArg(al[ac], XmNselectionPolicy, XmSINGLE_SELECT); ac++; XtSetArg(al[ac], XmNvisualPolicy, XmCONSTANT); ac++; XtSetArg(al[ac], XmNscrollingPolicy,XmAUTOMATIC); ac++; XtSetArg(al[ac], XmNscrollBarPlacement, XmBOTTOM_RIGHT); ac++; XtSetArg(al[ac], XmNscrollBarDisplayPolicy,XmAS_NEEDED); ac++; // XtSetArg(al[ac], XmNscrollBarDisplayPolicy, XmSTATIC); ac++; XtSetArg(al[ac], XmNlistSizePolicy, XmCONSTANT); ac++; // XtSetArg(al[ac], XmNlistSizePolicy, XmVARIABLE); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; XtSetArg(al[ac], XmNtopWidget, mess); ac++; XtSetArg(al[ac], XmNtopOffset, 5); ac++; XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNbottomOffset, 45); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightOffset, 5); ac++; XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNleftOffset, 5); ac++; XtSetArg(al[ac], XmNfontList, fontlist1); ac++; wx_alert_list = XmCreateScrolledList(my_form, "Display_Wx_Alert wx_alert_list", al, ac); end_critical_section(&wx_alert_shell_lock, "wx_gui.c:Display_Wx_Alert" ); wx_alert_update_list(); button_cancel = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtopAttachment, XmATTACH_NONE, // XmNtopOffset, 265, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 3, XmNbackground, colors[0xff], XmNnavigationType, XmTAB_GROUP, XmNfontList, fontlist1, NULL); XtAddCallback(button_cancel, XmNactivateCallback, wx_alert_destroy_shell, wx_alert_shell); XtAddCallback(wx_alert_list, XmNdefaultActionCallback, wx_alert_double_click_action, NULL); pos_dialog(wx_alert_shell); delw = XmInternAtom(XtDisplay(wx_alert_shell), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_alert_shell, delw, wx_alert_destroy_shell, (XtPointer)wx_alert_shell); XtManageChild(my_form); XtManageChild(wx_alert_list); XtVaSetValues(wx_alert_list, XmNbackground, colors[0x0f], NULL); XtManageChild(pane); resize_dialog(my_form, wx_alert_shell); XtPopup(wx_alert_shell, XtGrabNone); // Move focus to the Cancel button. This appears to highlight the // button fine, but we're not able to hit the key to // have that default function happen. Note: We _can_ hit the // key, and that activates the option. // XmUpdateDisplay(wx_alert_shell); XmProcessTraversal(button_cancel, XmTRAVERSE_CURRENT); } else { (void)XRaiseWindow(XtDisplay(wx_alert_shell), XtWindow(wx_alert_shell)); } } /* Display_Wx_Alert */ ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /**** WX Station *******/ Widget wx_station_dialog=(Widget)NULL; Widget WX_type_data; Widget WX_temp_data; Widget WX_wind_cse_data; Widget WX_wind_spd_data; Widget WX_wind_gst_data; Widget WX_rain_data; Widget WX_to_rain_data; Widget WX_rain_h_data; Widget WX_rain_24_data; Widget WX_humidity_data; Widget WX_speed_label; Widget WX_gust_label; Widget WX_temp_label; Widget WX_rain_label; Widget WX_to_rain_label; Widget WX_rain_h_label; Widget WX_rain_24_label; Widget WX_dew_point_data; Widget WX_high_wind_data; Widget WX_wind_chill_data; Widget WX_heat_index_data; Widget WX_baro_data; Widget WX_baro_label; Widget WX_three_hour_baro_data; Widget WX_three_hour_baro_label; Widget WX_hi_temp_data; Widget WX_low_temp_data; Widget WX_dew_point_label; Widget WX_wind_chill_label; Widget WX_heat_index_label; Widget WX_hi_temp_label; Widget WX_low_temp_label; Widget WX_high_wind_label; void WX_station_destroy_shell( Widget UNUSED(widget), XtPointer clientData, XtPointer UNUSED(callData) ) { Widget shell = (Widget) clientData; XtPopdown(shell); begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station_destroy_shell" ); XtDestroyWidget(shell); wx_station_dialog = (Widget)NULL; end_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station_destroy_shell" ); } void WX_station_change_data(Widget widget, XtPointer clientData, XtPointer callData) { WX_station_destroy_shell(widget,clientData,callData); } // This is the "Own Weather Station" Dialog // void WX_station( Widget UNUSED(w), XtPointer UNUSED(clientData), XtPointer UNUSED(callData) ) { static Widget pane, scrollwindow, my_form, form1, button_close, frame, WX_type, temp, wind_cse, wind_spd, wind_gst, my_rain, to_rain, rain_h, my_rain_24, baro, dew_point, high_wind, wind_chill, heat_index, three_hour_baro, hi_temp; Atom delw; if(!wx_station_dialog) { begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station" ); wx_station_dialog = XtVaCreatePopupShell(langcode("WXPUPSI000"), xmDialogShellWidgetClass, appshell, XmNdeleteResponse, XmDESTROY, XmNdefaultPosition, FALSE, XmNfontList, fontlist1, NULL); pane = XtVaCreateWidget("WX_station pane",xmPanedWindowWidgetClass, wx_station_dialog, XmNbackground, colors[0xff], NULL); scrollwindow = XtVaCreateManagedWidget("scrollwindow", xmScrolledWindowWidgetClass, pane, XmNscrollingPolicy, XmAUTOMATIC, NULL); my_form = XtVaCreateWidget("WX_station my_form", xmFormWidgetClass, scrollwindow, XmNfractionBase,7, XmNbackground, colors[0xff], XmNautoUnmanage, FALSE, XmNshadowThickness, 1, NULL); WX_type = XtVaCreateManagedWidget(langcode("WXPUPSI001"),xmLabelWidgetClass, my_form, XmNtraversalOn, FALSE, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_type_data = XtVaCreateManagedWidget("WX_station type data", xmTextFieldWidgetClass, my_form, XmNtraversalOn, FALSE, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 1, XmNcolumns, 70, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment,XmATTACH_WIDGET, XmNleftWidget, WX_type, XmNleftOffset, 5, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 30, XmNfontList, fontlist1, NULL); frame = XtVaCreateManagedWidget("WX_station frame", xmFrameWidgetClass, my_form, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, WX_type_data, XmNtopOffset,10, XmNbottomAttachment,XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 10, XmNrightAttachment,XmATTACH_FORM, XmNrightOffset, 10, XmNbackground, colors[0xff], NULL); // sts (void)XtVaCreateManagedWidget(langcode("WXPUPSI002"),xmLabelWidgetClass,frame, XmNtraversalOn, FALSE, XmNchildType, XmFRAME_TITLE_CHILD, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); form1 = XtVaCreateWidget("WX_station form1",xmFormWidgetClass, frame, XmNtraversalOn, FALSE, XmNfractionBase, 7, XmNbackground, colors[0xff], XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNfontList, fontlist1, NULL); wind_cse = XtVaCreateManagedWidget(langcode("WXPUPSI003"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_cse_data = XtVaCreateManagedWidget("WX_station wc data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 6, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_FORM, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // wind_deg (void)XtVaCreateManagedWidget(langcode("UNIOP00024"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_cse_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_spd = XtVaCreateManagedWidget(langcode("WXPUPSI004"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_spd_data = XtVaCreateManagedWidget("WX_station ws data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_speed_label= XtVaCreateManagedWidget("WX_station speed label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_cse, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_spd_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_gst = XtVaCreateManagedWidget(langcode("WXPUPSI005"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_gst_data = XtVaCreateManagedWidget("WX_station wg data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 3, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_gust_label= XtVaCreateManagedWidget("WX_station gust label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_spd, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_gst_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); temp = XtVaCreateManagedWidget(langcode("WXPUPSI006"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_temp_data = XtVaCreateManagedWidget("WX_station temp data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 8, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_temp_label= XtVaCreateManagedWidget("WX_station temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_gst, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_temp_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); my_rain = XtVaCreateManagedWidget(langcode("WXPUPSI007"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, temp, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_data = XtVaCreateManagedWidget("WX_station rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, temp, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_label= XtVaCreateManagedWidget("WX_station rain label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,5, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, temp, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); to_rain = XtVaCreateManagedWidget(langcode("WXPUPSI008"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_to_rain_data = XtVaCreateManagedWidget("WX_station today rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_to_rain_label= XtVaCreateManagedWidget("WX_station to label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_to_rain_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); rain_h = XtVaCreateManagedWidget(langcode("WXPUPSI014"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_h_data = XtVaCreateManagedWidget("WX_station hour rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_h_label= XtVaCreateManagedWidget("WX_station hour label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, to_rain, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_h_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); my_rain_24 = XtVaCreateManagedWidget(langcode("WXPUPSI015"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_rain_24_data = XtVaCreateManagedWidget("WX_station 24h rain data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 10, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); WX_rain_24_label= XtVaCreateManagedWidget("WX_station 24h label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness, 0, XmNcolumns,10, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, rain_h, XmNtopOffset, 9, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_rain_24_data, XmNleftOffset, 0, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // humidity (void)XtVaCreateManagedWidget(langcode("WXPUPSI010"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_humidity_data = XtVaCreateManagedWidget("WX_station Humidity data", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, TRUE, XmNshadowThickness, 1, XmNcolumns, 6, XmNmaxLength, 8, XmNtopOffset, 7, XmNbackground, colors[0x0f], XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 2, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNbottomAttachment,XmATTACH_NONE, XmNfontList, fontlist1, NULL); // humidity_n (void)XtVaCreateManagedWidget(langcode("UNIOP00026"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, my_rain_24, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_humidity_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); dew_point = XtVaCreateManagedWidget(langcode("WXPUPSI018"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_dew_point_data = XtVaCreateManagedWidget("WX_station dew point", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,1, XmNcolumns, 6, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_dew_point_label = XtVaCreateManagedWidget("WX_station dew label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_dew_point_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); high_wind = XtVaCreateManagedWidget(langcode("WXPUPSI019"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, dew_point, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_high_wind_data = XtVaCreateManagedWidget("WX_station High Wind", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive, TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, dew_point, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_high_wind_label = XtVaCreateManagedWidget("WX_station high wind label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,dew_point, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_high_wind_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); wind_chill = XtVaCreateManagedWidget(langcode("WXPUPSI020"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, high_wind, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_wind_chill_data = XtVaCreateManagedWidget("WX_station Wind Chill", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, high_wind, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_wind_chill_label = XtVaCreateManagedWidget("WX_station wind label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,high_wind, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_wind_chill_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); heat_index = XtVaCreateManagedWidget(langcode("WXPUPSI021"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, wind_chill, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_heat_index_data = XtVaCreateManagedWidget("WX_station Heat Index", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, wind_chill, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_heat_index_label = XtVaCreateManagedWidget("WX_station heat label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,wind_chill, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_heat_index_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); baro = XtVaCreateManagedWidget(langcode("WXPUPSI009"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, heat_index, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_baro_data = XtVaCreateManagedWidget("WX_station Baro", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, heat_index, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_baro_label = XtVaCreateManagedWidget("WX_Station baro unit label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget,heat_index, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_baro_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); three_hour_baro = XtVaCreateManagedWidget(langcode("WXPUPSI022"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_three_hour_baro_data = XtVaCreateManagedWidget("WX_station 3-Hr Baro", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_three_hour_baro_label = XtVaCreateManagedWidget("WX_station 3hr baro unit label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, baro, XmNtopOffset, 12, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_three_hour_baro_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); hi_temp = XtVaCreateManagedWidget(langcode("WXPUPSI023"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_hi_temp_data = XtVaCreateManagedWidget("WX_station Today's High Temp", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_hi_temp_label = XtVaCreateManagedWidget("WX_station high temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, three_hour_baro, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_hi_temp_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); // low_temp (void)XtVaCreateManagedWidget(langcode("WXPUPSI024"),xmLabelWidgetClass, form1, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 11, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 4, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); WX_low_temp_data = XtVaCreateManagedWidget("WX_station Today's Low Temp", xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNcolumns, 6, XmNsensitive,TRUE, XmNshadowThickness,1, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 5, XmNrightAttachment, XmATTACH_NONE, XmNtopAttachment,XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 7, XmNbottomAttachment,XmATTACH_NONE, XmNbackground, colors[0x0f], XmNfontList, fontlist1, NULL); WX_low_temp_label = XtVaCreateManagedWidget("WX_station low temp label",xmTextFieldWidgetClass, form1, XmNeditable, FALSE, XmNcursorPositionVisible, FALSE, XmNsensitive, STIPPLE, XmNshadowThickness,0, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, hi_temp, XmNtopOffset, 8, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, WX_low_temp_data, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_NONE, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); button_close = XtVaCreateManagedWidget(langcode("UNIOP00003"),xmPushButtonGadgetClass, my_form, XmNtraversalOn, TRUE, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frame, XmNtopOffset, 10, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset,10, XmNleftAttachment, XmATTACH_POSITION, XmNleftPosition, 3, XmNrightAttachment, XmATTACH_POSITION, XmNrightPosition, 4, XmNbackground, colors[0xff], XmNfontList, fontlist1, NULL); XtAddCallback(button_close, XmNactivateCallback, WX_station_destroy_shell, wx_station_dialog); pos_dialog(wx_station_dialog); delw = XmInternAtom(XtDisplay(wx_station_dialog),"WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(wx_station_dialog, delw, WX_station_destroy_shell, (XtPointer)wx_station_dialog); XtManageChild(my_form); XtManageChild(form1); XtManageChild(pane); resize_dialog(my_form, wx_station_dialog); end_critical_section(&wx_station_dialog_lock, "wx_gui.c:WX_station" ); XtPopup(wx_station_dialog,XtGrabNone); fill_wx_data(); } else { (void)XRaiseWindow(XtDisplay(wx_station_dialog), XtWindow(wx_station_dialog)); } } void fill_wx_data(void) { DataRow *p_station; char temp[20]; WeatherRow *weather; if (wx_station_dialog != NULL) { begin_critical_section(&wx_station_dialog_lock, "wx_gui.c:fill_wx_data" ); if (search_station_name(&p_station,my_callsign,1)) { if (get_weather_record(p_station)) // DK7IN: only add record if we found something... { weather = p_station->weather_data; if (strlen(wx_station_type) > 1) { XmTextFieldSetString(WX_type_data,wx_station_type); } else { XmTextFieldSetString(WX_type_data,""); } XtManageChild(WX_type_data); if (weather != 0) // we have weather data { if (strlen(weather->wx_temp) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(weather->wx_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_temp_data,temp); } else { XmTextFieldSetString(WX_temp_data,weather->wx_temp); } } else { XmTextFieldSetString(WX_temp_data,""); } XtManageChild(WX_temp_data); if (strlen(weather->wx_course) > 0) { XmTextFieldSetString(WX_wind_cse_data,weather->wx_course); } else { XmTextFieldSetString(WX_wind_cse_data,""); } XtManageChild(WX_wind_cse_data); if (strlen(weather->wx_speed) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(weather->wx_speed)*1.6094)); XmTextFieldSetString(WX_wind_spd_data,temp); } else { XmTextFieldSetString(WX_wind_spd_data,weather->wx_speed); } } else { XmTextFieldSetString(WX_wind_spd_data,""); } XtManageChild(WX_wind_spd_data); if (strlen(weather->wx_gust) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(weather->wx_gust)*1.6094)); XmTextFieldSetString(WX_wind_gst_data,temp); } else { XmTextFieldSetString(WX_wind_gst_data,weather->wx_gust); } } else { XmTextFieldSetString(WX_wind_gst_data,""); } XtManageChild(WX_wind_gst_data); if (strlen(weather->wx_rain_total) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain_total)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain_total)/100.0); XmTextFieldSetString(WX_rain_data,temp); } else { XmTextFieldSetString(WX_rain_data,""); } XtManageChild(WX_rain_data); if (strlen(weather->wx_rain) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_rain)/100.0); XmTextFieldSetString(WX_rain_h_data,temp); } else { XmTextFieldSetString(WX_rain_h_data,""); } XtManageChild(WX_rain_h_data); if (strlen(weather->wx_prec_24) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_24)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_24)/100.0); XmTextFieldSetString(WX_rain_24_data,temp); } else { XmTextFieldSetString(WX_rain_24_data,""); } XtManageChild(WX_rain_24_data); if (strlen(weather->wx_prec_00) > 0) { if (!english_units) xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_00)*.254); else xastir_snprintf(temp, sizeof(temp), "%0.2f", atof(weather->wx_prec_00)/100.0); XmTextFieldSetString(WX_to_rain_data,temp); } else { XmTextFieldSetString(WX_to_rain_data,""); } XtManageChild(WX_rain_data); if (strlen(weather->wx_hum) > 0) { XmTextFieldSetString(WX_humidity_data,weather->wx_hum); } else { XmTextFieldSetString(WX_humidity_data,""); } XtManageChild(WX_humidity_data); if (strlen(wx_dew_point) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_dew_point)-32)*5.0)/9.0)); XmTextFieldSetString(WX_dew_point_data,temp); } else { XmTextFieldSetString(WX_dew_point_data,wx_dew_point); } } else { XmTextFieldSetString(WX_dew_point_data,""); } XtManageChild(WX_dew_point_data); if (strlen(wx_high_wind) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(atof(wx_high_wind)*1.6094)); XmTextFieldSetString(WX_high_wind_data,temp); } else { XmTextFieldSetString(WX_high_wind_data,wx_high_wind); } } else { XmTextFieldSetString(WX_high_wind_data,""); } XtManageChild(WX_high_wind_data); if (strlen(wx_wind_chill) > 0) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_wind_chill)-32)*5.0)/9.0)); XmTextFieldSetString(WX_wind_chill_data,temp); } else { XmTextFieldSetString(WX_wind_chill_data,wx_wind_chill); } } else { XmTextFieldSetString(WX_wind_chill_data,""); } XtManageChild(WX_wind_chill_data); if (strlen(weather->wx_baro) > 0) { if (!english_units) { //xastir_snprintf(temp, sizeof(temp), "%0.0f", // atof(wx_baro_inHg)*25.4); // inch Hg -> mm Hg //XmTextFieldSetString(WX_baro_data,temp); XmTextFieldSetString(WX_baro_data,weather->wx_baro); // hPa } else // inches mercury { xastir_snprintf(temp, sizeof(temp), "%0.2f", (atof(weather->wx_baro)*0.02953)); XmTextFieldSetString(WX_baro_data,temp); } } else { XmTextFieldSetString(WX_baro_data,""); } XtManageChild(WX_baro_data); if (wx_three_hour_baro_on) { if (!english_units) // hPa { //xastir_snprintf(temp, sizeof(temp), "%0.0f", // atof(wx_three_hour_baro)*25.4); // inch Hg -> mm Hg XmTextFieldSetString(WX_three_hour_baro_data,wx_three_hour_baro); } else // inches mercury { xastir_snprintf(temp, sizeof(temp), "%0.2f", (atof(wx_three_hour_baro)*0.02953)); XmTextFieldSetString(WX_three_hour_baro_data,temp); } } else { XmTextFieldSetString(WX_three_hour_baro_data,""); } XtManageChild(WX_three_hour_baro_data); if (wx_hi_temp_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_hi_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_hi_temp_data,temp); } else { XmTextFieldSetString(WX_hi_temp_data,wx_hi_temp); } } else { XmTextFieldSetString(WX_hi_temp_data,""); } XtManageChild(WX_hi_temp_data); if (wx_low_temp_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_low_temp)-32)*5.0)/9.0)); XmTextFieldSetString(WX_low_temp_data,temp); } else { XmTextFieldSetString(WX_low_temp_data,wx_low_temp); } } else { XmTextFieldSetString(WX_low_temp_data,""); } XtManageChild(WX_low_temp_data); if (wx_heat_index_on) { if (!english_units) { xastir_snprintf(temp, sizeof(temp), "%03d", (int)(((atof(wx_heat_index)-32)*5.0)/9.0)); XmTextFieldSetString(WX_heat_index_data,temp); } else { XmTextFieldSetString(WX_heat_index_data,wx_heat_index); } } else { XmTextFieldSetString(WX_heat_index_data,""); } XtManageChild(WX_heat_index_data); } } } /* labels */ if (!english_units) { XmTextFieldSetString(WX_speed_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_speed_label,langcode("UNIOP00013")); } XtManageChild(WX_speed_label); if (!english_units) { XmTextFieldSetString(WX_gust_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_gust_label,langcode("UNIOP00013")); } XtManageChild(WX_gust_label); if (!english_units) { XmTextFieldSetString(WX_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_temp_label); if (!english_units) { XmTextFieldSetString(WX_rain_label,langcode("UNIOP00016")); } else { XmTextFieldSetString(WX_rain_label,langcode("UNIOP00017")); } XtManageChild(WX_rain_label); if (!english_units) { XmTextFieldSetString(WX_to_rain_label,langcode("UNIOP00022")); } else { XmTextFieldSetString(WX_to_rain_label,langcode("UNIOP00023")); } XtManageChild(WX_to_rain_label); if (!english_units) { XmTextFieldSetString(WX_rain_h_label,langcode("UNIOP00020")); } else { XmTextFieldSetString(WX_rain_h_label,langcode("UNIOP00021")); } XtManageChild(WX_rain_h_label); if (!english_units) { XmTextFieldSetString(WX_rain_24_label,langcode("UNIOP00018")); } else { XmTextFieldSetString(WX_rain_24_label,langcode("UNIOP00019")); } XtManageChild(WX_rain_24_label); if (!english_units) { XmTextFieldSetString(WX_dew_point_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_dew_point_label,langcode("UNIOP00015")); } XtManageChild(WX_dew_point_label); if (!english_units) { XmTextFieldSetString(WX_wind_chill_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_wind_chill_label,langcode("UNIOP00015")); } XtManageChild(WX_wind_chill_label); if (!english_units) { XmTextFieldSetString(WX_heat_index_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_heat_index_label,langcode("UNIOP00015")); } XtManageChild(WX_heat_index_label); if (!english_units) { XmTextFieldSetString(WX_hi_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_hi_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_hi_temp_label); if (!english_units) { XmTextFieldSetString(WX_low_temp_label,langcode("UNIOP00014")); } else { XmTextFieldSetString(WX_low_temp_label,langcode("UNIOP00015")); } XtManageChild(WX_low_temp_label); if (!english_units) { XmTextFieldSetString(WX_high_wind_label,langcode("UNIOP00012")); } else { XmTextFieldSetString(WX_high_wind_label,langcode("UNIOP00013")); } XtManageChild(WX_high_wind_label); if (!english_units) { XmTextFieldSetString(WX_baro_label,langcode("UNIOP00025")); } else { XmTextFieldSetString(WX_baro_label,langcode("UNIOP00027")); } XtManageChild(WX_baro_label); if (!english_units) { XmTextFieldSetString(WX_three_hour_baro_label,langcode("UNIOP00025")); } else { XmTextFieldSetString(WX_three_hour_baro_label,langcode("UNIOP00027")); } XtManageChild(WX_three_hour_baro_label); end_critical_section(&wx_station_dialog_lock, "wx_gui.c:fill_wx_data" ); } } Xastir-Release-2.2.4/src/x_spider.c0000664000175000017500000015321615151324131016101 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ // // The idea here: Have Xastir spawn off a separate server (via a // system() call?) which can provide listening sockets for other // APRS clients to connect to. This allows other clients to share // Xastir's TNC ports. Forking Xastir directly and running the // server code doesn't work out well: The new process ends up with // the large Xastir memory image. We need a separate app with a // small memory image for the server. It might spawn off quite a // few processes, and we need it to be small and fast. // // The initial goal here is to take one box that is RF-rich (running // one or more TNC's), and have the ability to let other APRS // clients (Xastir or otherwise) to share the RF and/or internet // connections of the "master" Xastir session. This could be useful // in an EOC (Emergency Operations Center), a large SAR mission with // multiple computers, or simply to allow one to connect to their // home Xastir session from work and gain the use of the RF ports. // My use: On a SAR mission, using wireless networking and laptops // to let everyone see the same picture, multiplexing to one Xastir // session running a TNC. As usual, I'm sure other users will // figure out new and inventive uses for it. // // Yes, this does pose some security risks to the license of the // operator. I wouldn't recommend having an open port on the // internet to allow people to use your RF ports. Of course with // the authentication stuff that'll be in here, it's as secure as // the igating stuff that we currently have for APRS. // // I thought about using IPC Messaging or FIFO's (named pipes) in // order to make the connection from this server back to the // "master" Xastir session. I looked at the lack of support for // them in Cygwin and decided to use sockets instead. We'll set up // a special registration for Xastir so that this server code knows // which port is the "master" port (controlling port). // // Xastir will end up with a togglebutton to enable the server: // Starts up x_spider. // Connects to x_spider with a socket. // Sends a special string so x_spider knows which one is the // controlling (master) socket. // All packets received/transmitted by Xastir on any port also get // sent to x_spider. // // x_spider: // Accepts client socket connections. // Spawns a new process for each one. // Each new process talks to the main x_spider via two pipes. // Authenticate each connecting client in the normal manner. // Accept data from any socket, echo data out _all_ sockets. // If the "master" Xastir sends a shutdown packet, all connections // are dropped and x_spider and all it's children will exit. // x_spider uses select() calls to multiplex all pipes and the // listening socket. It shouldn't use up much CPU as it'll be // in the blocking select call until it has data to process. // x_spider's children should also wait in blocking calls until // there is data to process. // // This makes the design of the server rather simple: It needs to // authenticate clients and it needs to parse the shutdown message // from the "master" socket. Other than that it just needs to // re-transmit anything heard on one socket to all of the other // connected sockets. // // Xastir itself will have to change a bit in order to add the // togglebutton, to send anything transmit/received to the special // socket, and to send the registration and shutdown strings to the // server at the appropriate times. Not earth-shaking changes, but // changes nonetheless. // // Most of this code is adapted directly from W. Richard Steven's // book: "Unix Network Programming". Highly recommended book, as // are the other books by him that I own. I was sorry to hear of // his passing. // // Name for this? Spider, centipede, millipede, octopus, // multiplexer, repeater. #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include "x_spider.h" #include "snprintf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include #include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #include #if HAVE_SYS_TIME_H #include #endif // HAVE_SYS_TIME_H #include #include #include #ifndef SIGRET #define SIGRET void #endif // SIGRET #include "xastir.h" // Must be last include file #include "leak_detection.h" // Define this if you wish to use this as a standalone program // instead of as a function in another program. // //#define STANDALONE_PROGRAM // These are from util.h/util.c. We can't include util.h here // because it causes other problems. extern short checkHash(char *theCall, short theHash); extern void get_timestamp(char *timestring); extern void split_string( char *data, char *cptr[], int max, char search_char ); // From database.h extern char my_callsign[]; extern char *pname; typedef struct _pipe_object { int to_child[2]; int to_parent[2]; char callsign[20]; int authenticated; int active; // Mark for deletion after every task is finished struct _pipe_object *next; } pipe_object; pid_t parent_pid; pipe_object *pipe_head = NULL; //int master_fd = -1; // Start with an invalid value pipe_object *xastir_tcp_pipe = NULL; pipe_object *xastir_udp_pipe = NULL; // TCP server pipes to/from Xastir proper int pipe_xastir_to_tcp_server = -1; int pipe_tcp_server_to_xastir = -1; // UDP server pipes to/from Xastir proper int pipe_xastir_to_udp_server = -1; // (not currently used) int pipe_udp_server_to_xastir = -1; /* // Read "n" bytes from a descriptor. Use in place of read() when fd // is a stream socket. This routine is from "Unix Network // Programming". // // This routine is not used currently. // int readn(int fd, char *ptr, int nbytes) { int nleft, nread; nleft = nbytes; while (nleft > 0) { nread = read(fd, ptr, nleft); if (nread < 0) { return(nread); // Error, return < 0 } else if (nread == 0) { break; // EOF } nleft -= nread; ptr += nread; } return(nbytes - nleft); // Return >= 0 } */ // Write "n" bytes to a descriptor. Use in place of write() when fd // is a stream socket. This routine is from "Unix Network // Programming". // int writen(int fd, char *ptr, int nbytes) { int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) { return(nwritten); // Error } nleft -= nwritten; ptr += nwritten; } // fprintf(stderr, // "writen: %d bytes written, %d bytes left to write\n", // nleft, // nbytes - nleft); return(nbytes - nleft); } // Read a line from a descriptor. Read the line one byte at a time, // looking for the newline. We store the newline in the buffer, // then follow it with a null (the same as fgets(3)). We return the // number of characters up to, but not including, the null (the same // as strlen(3)); This routine is from "Unix Network Programming". // int readline(int fd, char *ptr, int maxlen) { int n, rc; char c; for (n = 1; n < maxlen; n++) { if ( (rc = read(fd, &c, 1)) == 1) { *ptr++ = c; if (c == '\n') { break; } } else if (rc == 0) { if (n == 1) { return(0); // EOF, no data read } else { break; // EOF, some data was read } } else { return(-1); // Error } } *ptr = 0; return(n); } #define MAXLINE 512 // Read a stream socket one line at a time, and write each line back // to the sender. Return when the connection is terminated. This // routine is from "Unix Network Programming". // /* void str_echo(int sockfd) { int n; char line[MAXLINE]; for ( ; ; ) { n = readline(sockfd, line, MAXLINE); if (n == 0) { return; // Connection terminated } if (n < 0) { fprintf(stderr,"str_echo: No data to read\n"); } if (writen(sockfd, line, n) != n) { fprintf(stderr,"str_echo: Writen error\n"); } } } */ // Read a stream socket one line at a time, and write each line back // to the sender. Return when the connection is terminated. This // routine is from "Unix Network Programming". // void str_echo2(int sockfd, int pipe_from_parent, int pipe_to_parent) { int n; char line[MAXLINE]; // Set socket to be non-blocking. // if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"str_echo2: Couldn't set socket non-blocking\n"); } // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_from_parent, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"str_echo2: Couldn't set read-end of pipe_from_parent non-blocking\n"); } //Send our callsign to spider clients as "#callsign" much like APRS-IS sends "# javaAPRS" // # xastir 1.5.1 callsign: sprintf(line,"# Welcome to Xastir's server port, callsign: %s\r\n",my_callsign); writen(sockfd,line,strlen(line)); // Infinite loop for ( ; ; ) { // // Read data from socket, write to pipe (parent) // if (!sockfd) // Socket is closed { return; // Connection terminated } n = readline(sockfd, line, MAXLINE); if (n == 0) { return; // Connection terminated } if (n < 0) { //fprintf(stderr,"str_echo2: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"str_echo2: Readline error socket: %d\n",errno); //close(sockfd); return; } } else // We received some data. Send it down the pipe. { // fprintf(stderr,"str_echo2: %s\n",line); if (writen(pipe_to_parent, line, n) != n) { fprintf(stderr,"str_echo2: Writen error socket: %d\n",errno); //close(sockfd); return; } } // // Read data from pipe (parent), write to socket // if (!pipe_from_parent) { exit(0); } n = readline(pipe_from_parent, line, MAXLINE); if (n == 0) { exit(0); // Connection terminated } if (n < 0) { //fprintf(stderr,"str_echo2: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"str_echo2: Readline error pipe: %d\n",errno); //close(pipe_from_parent); return; } } else // We received some data. Send it down the socket. { // fprintf(stderr,"str_echo2: %s\n",line); if (writen(sockfd, line, n) != n) { fprintf(stderr,"str_echo2: Writen error pipe: %d\n",errno); //close(pipe_from_parent); return; } } // Slow the loop down to prevent excessive CPU. // NOTE: We must be faster at processing packets than the // main.c:UpdateTime() can send them to us through the pipe! If // we're not, we lose or corrupt packets. usleep(1000); // 1ms } } // Function which checks the incoming pipes to see if there's any // data. If there is, checks to see if it is a control packet or a // registration packet from the master. If not, echoes the data out // all outgoing pipes. // // If we get a shutdown from the verified master, send a "1" as the // return value, which will shut down the server. Otherwise send a // "0" return value. // // Incoming registration data: Record only the master socket. All // others should be handled by the child processes, and they should // not pass the registration info down to us. Same for control // packets. Actually, the child process handling the master socket // could skip notifying us as well, and just pass down the control // packets if the master sent any (like the shutdown packet). If we // lost the connection between Xastir and x_spider, we might not // have a clean way of shutting down the server in that case though. // Might be better to record it down here, and if the pipes ever // closed, we shut down x_spider and all the child processes. // int pipe_check(char *client_address) { pipe_object *p = pipe_head; int n; char line[MAXLINE]; // Need a select here with a timeout? Also need a method of // revising the read bits we send to select. Should we revise // them every time through the loop, or set a variable in the // main() routine whenever a new connect comes in. What about // connects that go away? We need a way to free up the pipes // and sockets in that case, and revise the select bits again. // select(); //fprintf(stderr,"pipe_check()\n"); // All of the read ends of the pipes have been set non-blocking // by this point. // Check all the pipes in the linked list looking for something // to read. while (p != NULL) { // fprintf(stderr,"Running through pipes\n"); // // Read data from pipe, write to all pipes except the one // who sent it. // n = p->active ? readline(p->to_parent[0], line, MAXLINE): 0; if (n == 0 && p->active) { char timestring[101]; get_timestamp(timestring); if (p->authenticated) { fprintf(stderr, "%s X_spider session terminated, callsign: %s, address: %s\n", timestring, p->callsign, client_address); } else { fprintf(stderr, "%s X_spider session terminated, unauthenticated user, address %s\n", timestring, client_address); } // Close the pipe close(p->to_child[1]); close(p->to_parent[0]); p->active = 0; // This task is ready to let go. wait(NULL); // Reap the status of the dead process } else if (n < 0) { //fprintf(stderr,"pipe_check: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"pipe_check: Readline error: %d\n",errno); } } else if (p->active) // We received some data. Send it down all of the { // pipes except the one that sent it. pipe_object *q; // Check for an authentication string. If the pipe has not been // authenticated, we don't allow it to send anything to the upstream // server. It's probably ok to send it to downstream connections // though. // Check for "user" "pass" string. // "user WE7U-13 pass XXXX vers XASTIR 1.3.3" if (strstr(line,"user") && strstr(line,"pass")) { char line2[MAXLINE]; char *callsign; char *passcode_str; short passcode; char *space; // We have a string with user/pass in it, but they // can be anywhere along the line. We'll have to // search for each piece. //fprintf(stderr,"x_spider:Found an authentication string\n"); // Copy the line xastir_snprintf(line2, sizeof(line2), "%s", line); // Add white space to the end. strncat(line2, " ", sizeof(line2) - 1 - strlen(line2)); // Find the "user" string position callsign = strstr(line2,"user"); if (callsign == NULL) { continue; } // Fast-forward past the "user" word. callsign += 4; // Skip past any additional spaces that might be // present between "user" and callsign. while (callsign[0] == ' ' && callsign[0] != '\0') { callsign += 1; } if (callsign[0] == '\0') { continue; } // We should now be pointing at the beginning of the // callsign. // Find the space after the callsign space = strstr(callsign," "); if (space == NULL) { continue; } // Terminate the callsign string space[0] = '\0'; // Snag the passcode string // Find the "pass" string passcode_str = strstr(&space[1],"pass"); if (passcode_str == NULL) { continue; } // Fast-forward past the "pass" word. passcode_str = passcode_str + 4; // Skip past any additional spaces that might be // present between "pass" and the passcode. while (passcode_str[0] == ' ' && passcode_str[0] != '\0') { passcode_str += 1; } if (passcode_str[0] == '\0') { continue; } // Find the space after the passcode space = strstr(&passcode_str[0]," "); if (space == NULL) { continue; } // Terminate the passcode string space[0] = '\0'; passcode = atoi(passcode_str); //fprintf(stderr,"x_spider: user:.%s., pass:%d\n", callsign, passcode); if (checkHash(callsign, passcode)) { // Authenticate the pipe. It is now allowed to send // to the upstream server. //fprintf(stderr, // "x_spider: Authenticated user %s\n", // callsign); p->authenticated = 1; xastir_snprintf(p->callsign, sizeof(p->callsign), "%s", callsign); p->callsign[19] = '\0'; } else { fprintf(stderr, "X_spider: Bad authentication, user %s, pass %d\n", callsign, passcode); fprintf(stderr, "Line: %s\n", line); } } q = pipe_head; while (q != NULL) { // fprintf(stderr,"pipe_check: %s\n",line); // Only send to active pipes if (q != p && q->active) { if (writen(q->to_child[1], line, n) != n) { fprintf(stderr,"pipe_check: Writen error1: %d\n",errno); } } q = q->next; } // Here we send it to Xastir itself. We use a couple of // global variables just like channel_data() does, but // we don't have to protect them in the same manner as // we only have one process on each end. // // Send it down the pipe to Xastir's main thread. Knock off any // carriage return that might be present. We only want a linefeed // on the end. if (n > 0 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } if (n > 0 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } // Add the linefeed on the end strncat(line,"\n",sizeof(line)-strlen(line)-1); n++; // Only send to upstream server if this client has authenticated. if (p->authenticated) { //fprintf(stderr,"Data available, sending to server\n"); //fprintf(stderr,"\t%s\n",line); if (writen(pipe_tcp_server_to_xastir, line, n) != n) { fprintf(stderr, "pipe_check: Writen error2: %d\n", errno); } } } if (p) { p = p->next; } } // Check the pipe from Xastir's main thread to see if it is // sending us any data n = readline(pipe_xastir_to_tcp_server, line, MAXLINE); if (n == 0) { exit(0); // Connection terminated } if (n < 0) { //fprintf(stderr,"pipe_check: Readline error: %d\n",errno); if (errno == EAGAIN || errno == EWOULDBLOCK) { // This is normal if we have no data to read //fprintf(stderr,"EAGAIN or EWOULDBLOCK\n"); } else // Non-normal error. Report it. { fprintf(stderr,"pipe_check: Readline error: %d\n",errno); } } else // We received some data. Send it down all of the { // pipes. // Also send it down the socket. // Check for disconnected clients and delete their records // from the chain. pipe_object *q = pipe_head; pipe_object *r = pipe_head; for (q = pipe_head; q != NULL; ) { if (!q->active) // Marked for deletion. { // Check for head of list, handle it in a special // manner. We don't have to fix up the "next" // pointer on the previous object (it doesn't exist) // but must fix up "pipe_head" pointer. if (q == pipe_head) { pipe_head = q->next; // New head of list p = q; // Assign temporary pointer q = q->next; // Keep pointer to next object r = q; // Keep 'r' and 'q' the same for now, // later 'r' will lag 'q' by one object free(p); // Free struct at temporary pointer } else // Not the head object { r->next = q->next; // Bridge soon-to-be-made gap p = q; // Assign temporary pointer q = q->next; // Keep pointer to next connection. free(p); // Free struct at temp pointer } } else { r = q; // Pointer to last object (so we can get to // the "next" pointer) q = q->next; // Pointer to next object } } q = pipe_head; // Reset pointer to beginning of list //fprintf(stderr,"n:%d\n",n); // Terminate it line[n] = '\0'; //fprintf(stderr,"sp %s\n", line); // The internet protocol for sending lines is "\r\n". Knock // off any line-end characters that might be present, then // add a "\r\n" combo on the end. // if (n >= 1 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } if (n >= 1 && (line[n-1] == '\r' || line[n-1] == '\n')) { line[n-1] = '\0'; n--; } // Add carriage-return/linefeed onto the end strncat(line, "\r\n", sizeof(line)-strlen(line)-1); n += 2; while (q != NULL && q->active) { // fprintf(stderr,"pipe_check: %s\n",line); if (writen(q->to_child[1], line, n) != n) { fprintf(stderr,"pipe_check: Writen error1: %d\n",errno); } q = q->next; } } return(0); } // The below three functions init_set_proc_title() and // set_proc_title() are from: // http://lightconsulting.com/~thalakan/process-title-notes.html // They seems to work fine on Linux, but they only change the "ps" // listings, not the top listings. I don't know why yet. // Here's another good web page for Linux: // http://www.uwsg.iu.edu/hypermail/linux/kernel/0006.1/0610.html // clear_proc_title is to clean up internal pointers for environment. /* Globals */ static char **Argv = ((void *)0); #ifdef __linux__ extern char *__progname, *__progname_full; #endif // __linux__ static char *LastArgv = ((void *)0); static char **local_environ; #ifdef __linux__ static char *old_progname, *old_progname_full; #endif // __linux__ void clear_proc_title(void) { int i; for(i = 0; local_environ && local_environ[i] != NULL; i++) { free(local_environ[i]); } if (local_environ) { free(local_environ); local_environ = NULL; } #ifdef __linux__ free(__progname); free(__progname_full); __progname = old_progname; __progname_full = old_progname_full; #endif // __linux__ } void init_set_proc_title(int UNUSED(argc), char *argv[], char *envp[]) { int i, envpsize; char **p; for(i = envpsize = 0; envp[i] != NULL; i++) { envpsize += strlen(envp[i]) + 1; } if((p = (char **) malloc((i + 1) * sizeof(char *))) != NULL ) { local_environ = p; for(i = 0; envp[i] != NULL; i++) { if((local_environ[i] = malloc(strlen(envp[i]) + 1)) != NULL) xastir_snprintf(local_environ[i], strlen(envp[i])+1, "%s", envp[i]); } } local_environ[i] = NULL; Argv = argv; for(i = 0; argv[i] != NULL; i++) { if((LastArgv + 1) == argv[i]) // Not sure if this conditional is needed { LastArgv = envp[i] + strlen(envp[i]); } } #ifdef __linux__ // Pretty sure you don't need this either old_progname = __progname; old_progname_full = __progname_full; __progname = strdup("xastir"); __progname_full = strdup(argv[0]); #endif // __linux__ atexit(clear_proc_title); } void set_proc_title(char *fmt,...) { va_list msg; static char statbuf[8192]; char *p; int i,maxlen = (LastArgv - Argv[0]) - 2; //fprintf(stderr,"DEBUG: maxlen: %i\n", maxlen); va_start(msg,fmt); memset(statbuf, 0, sizeof(statbuf)); xastir_vsnprintf(statbuf, sizeof(statbuf), fmt, msg); va_end(msg); i = strlen(statbuf); xastir_snprintf(Argv[0], maxlen, "%s", statbuf); p = &Argv[0][i]; while(p < LastArgv) { *p++ = '\0'; } Argv[1] = ((void *)0) ; } #define ADDR_STR_LEN 39 char *addr_str(const struct sockaddr *sa, char *s) { switch(sa->sa_family) { case AF_INET: inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), s, ADDR_STR_LEN); break; case AF_INET6: inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), s, ADDR_STR_LEN); break; default: xastir_snprintf(s, ADDR_STR_LEN, "", sa->sa_family); return NULL; } return s; } #define MAXSOCK 8 int open_spider_server_sockets(int socktype, int port, int **s_in) { struct addrinfo hints, *res, *res0; int error; int nsock; int buf; int *s; char port_str[16]; xastir_snprintf(port_str, 16, "%d", port); *s_in = calloc(MAXSOCK, sizeof(int)); s = *s_in; // Query for socketrs we need to create (probably 1 each for IPv4 + IPv6) memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = socktype; hints.ai_flags = AI_PASSIVE; error = getaddrinfo(NULL, port_str, &hints, &res0); if (error) { fprintf(stderr, "Error: Unable to lookup addresses for port %s\n", port_str); return 0; } // Create and setup each socket nsock = 0; for (res = res0; res && nsock < MAXSOCK; res = res->ai_next) { s[nsock] = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s[nsock] < 0) { fprintf(stderr, "Error: Opening socket (family %d protocol %d\n", res->ai_family, res->ai_protocol); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); continue; } #ifdef IPV6_V6ONLY if(res->ai_family == AF_INET6) { buf = 1; if (setsockopt(s[nsock], IPPROTO_IPV6, IPV6_V6ONLY, (char *)&buf, sizeof(buf)) < 0) { fprintf(stderr, "x_spider: Unable to set IPV6_V6ONLY.\n"); } } #endif if(socktype == SOCK_STREAM) { // Set the new socket to be non-blocking. // if (fcntl(s[nsock], F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set socket non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // Set up to reuse the port number (good for debug so we can // restart the server quickly against the same port). buf = 1; if (setsockopt(s[nsock], SOL_SOCKET, SO_REUSEADDR, (char *)&buf, sizeof(buf)) < 0) { fprintf(stderr,"x_spider: Couldn't set socket REUSEADDR\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } } if (bind(s[nsock], res->ai_addr, res->ai_addrlen) < 0) { fprintf(stderr, "x_spider: Can't bind local address for AF %d: %d - %s\n", res->ai_family, errno, strerror(errno)); fprintf(stderr, "Either this OS maps IPv4 addresses to IPv6 and this may be expected or\n"); fprintf(stderr,"could some processes still be running from a previous run of Xastir?\n"); close(s[nsock]); continue; } if(socktype == SOCK_STREAM) { // Set up to listen. We allow up to five backlog connections // (unserviced connects that get put on a queue until we can // service them). (void) listen(s[nsock], 5); } nsock++; } if (nsock == 0) { fprintf(stderr, "x_spider: Couldn't open any sockets\n"); } freeaddrinfo(res0); return nsock; } // Create a poll structure from an array of sockets struct pollfd* setup_poll_array(int nsock, int* sockfds) { int i; struct pollfd* polls; polls = calloc(nsock, sizeof(struct pollfd)); for(i=0; iauthenticated = 0; p->callsign[0] = '\0'; get_timestamp(timestring); fprintf(stderr,"%s X_spider client connected from address %s\n", timestring, addr_str((struct sockaddr*)&cli_addr, addrstring)); if (pipe(p->to_child) < 0 || pipe(p->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); if (p->to_child[1]) { close(p->to_child[1]); } if (p->to_child[0]) { close(p->to_child[0]); } free(p); // Free the malloc'd memory. p = NULL; close(newsockfd); goto finis; } // Indicate active connection! p->active = 1; // Link it into the head of the chain. // p->next = pipe_head; pipe_head = p; flag = 1; // Turn on the socket keepalive option (void)setsockopt(newsockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &flag, sizeof(int)); // Disable the Nagle algorithm (speeds things up) (void)setsockopt(newsockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); if ( (childpid = fork()) < 0) { // // Problem forking. Clean up and continue loop. // fprintf(stderr,"x_spider: Fork error\n"); // Close pipes close(p->to_child[0]); close(p->to_child[1]); close(p->to_parent[0]); close(p->to_parent[1]); pipe_head = p->next; free(p); // Free the malloc'd memory. p = NULL; close(newsockfd); goto finis; } else if (childpid == 0) { // // child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); /* fprintf(stderr, "Client address: %s\n", inet_ntoa(cli_addr.sin_addr)); */ // Change the name of the new child process. So far // this only works for "ps" listings, not for "top". // This code only works on Linux. For BSD use // setproctitle(3), NetBSD can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s%s %s", "x-spider client @", addr_str((struct sockaddr*)&cli_addr, addrstring), "(xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ // It'd be very cool here to include the IP address of the remote // client on the "ps" line, and include the callsign of the // connecting client once the client authenticates. Both of these // are do-able. // New naming system so that we don't have to remember // the longer name: // pipe_to_parent = p->to_parent[1]; pipe_from_parent = p->to_child[0]; close(sockfd); // Close original socket. Child // doesn't need the listening // socket. close(p->to_child[1]); // Close write end of pipe close(p->to_parent[0]); // Close read end of pipe // str_echo(newsockfd); // Process the request str_echo2(newsockfd, pipe_from_parent, pipe_to_parent); // Clean up and exit // close(pipe_to_parent); close(pipe_from_parent); exit(0); } // // Parent process // close(newsockfd); close(p->to_parent[1]); // Close write end of pipe close(p->to_child[0]); // Close read end of pipe // Set read-end of pipe to be non-blocking. // if (fcntl(p->to_parent[0], F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_to_parent non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } finis: // Need a delay so that we don't use too much CPU, at least // for debug. Put the delay into the select() call in the // pipe_check() function once we get to that stage of // coding. // // NOTE: We must be faster at processing packets than the // main.c:UpdateTime() can send them to us through the pipe! If // we're not, we lose or corrupt packets. usleep(1000); // 1ms } } // Send a nack back to the xastir_udp_client program void send_udp_nack(int sock, struct sockaddr *from, int fromlen) { int n; n = sendto(sock, "NACK", // Negative Acknowledgment 5, 0, (struct sockaddr *)from, fromlen); if (n < 0) { fprintf(stderr, "Error: sendto"); } } // Create a UDP listening port. This allows scripts and other // programs to inject packets into Xastir via UDP protocol. // void UDP_Server(int UNUSED(argc), char * UNUSED(argv[]), char * UNUSED(envp[]) ) { int sock, n1, n2; socklen_t fromlen; struct sockaddr_storage from; struct pollfd *polls; char buf[1024]; char buf2[512]; char *callsign; short passcode; char *cptr[10]; char *message = NULL; char message2[1024]; int send_to_inet; int send_to_rf; int *sockfds; int nsock; int i, rc; char addrstring[ADDR_STR_LEN+1]; nsock = open_spider_server_sockets(SOCK_DGRAM, SERV_UDP_PORT, &sockfds); if(!nsock) { fprintf(stderr, "Unable to setup any x_spider UDP server sockets.\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); return; } // Setup socket polling array and free the socket array // (since the FDs were copied into the poll array) polls = setup_poll_array(nsock, sockfds); free(sockfds); while (1) { rc = poll(polls, nsock, 5000); // Wait for data if(rc == -1) { fprintf(stderr, "x_spider: UDP poll() returned error %d: %s.\n", errno, strerror(errno)); continue; } else if (rc == 0) { // Timeout, check if parent is still alive rc = kill(parent_pid, 0); if(rc == -1 && errno == ESRCH) { // Parent died, exit return; } continue; } // Data should be waiting. Scan the poll set for an FD that has one waiting and use that. sock = -1; for(i=0; ito_child) < 0 || pipe(xastir_tcp_pipe->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); free(xastir_tcp_pipe); // Free the malloc'd memory. xastir_tcp_pipe = NULL; return(0); } xastir_tcp_pipe->authenticated = 1; xastir_tcp_pipe->callsign[0] = '\0'; if ( (childpid = fork()) < 0) { fprintf(stderr,"Fork_TCP_server: Fork error\n"); // Close pipes close(xastir_tcp_pipe->to_child[0]); close(xastir_tcp_pipe->to_child[1]); close(xastir_tcp_pipe->to_parent[0]); close(xastir_tcp_pipe->to_parent[1]); free(xastir_tcp_pipe); // Free the malloc'd memory. xastir_tcp_pipe = NULL; return(0); } else if (childpid == 0) { // // Child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Change the name of the new child process. So far this // only works for "ps" listings, not for "top". This code // only works on Linux. For BSD use setproctitle(3), NetBSD // can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s", "x-spider TCP daemon (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ close(xastir_tcp_pipe->to_child[1]); // Close write end of pipe close(xastir_tcp_pipe->to_parent[0]); // Close read end of pipe // Assign the global variables pipe_tcp_server_to_xastir = xastir_tcp_pipe->to_parent[1]; pipe_xastir_to_tcp_server = xastir_tcp_pipe->to_child[0]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_xastir_to_tcp_server, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_tcp_server non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } TCP_Server(argc, argv, envp); fprintf(stderr,"TCP_Server process died.\n"); exit(1); } // // Parent process // close(xastir_tcp_pipe->to_parent[1]); // Close write end of pipe close(xastir_tcp_pipe->to_child[0]); // Close read end of pipe // Assign the global variables so that Xastir itself will know // how to talk to the pipes pipe_tcp_server_to_xastir = xastir_tcp_pipe->to_parent[0]; pipe_xastir_to_tcp_server = xastir_tcp_pipe->to_child[1]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_tcp_server_to_xastir, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_tcp_server_to_xastir non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // // Set write-end of pipe to be non-blocking. // // // if (fcntl(pipe_xastir_to_tcp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_tcp_server non-blocking\n"); // } // We don't need to do anything here except return back to the // calling routine with the PID of the new server process, so // that it can request the server and all it's children to quit // when Xastir quits or segfaults. return(childpid); // Really the parent PID in this case } #endif // STANDALONE_PROGRAM int Fork_UDP_server(int argc, char *argv[], char *envp[]) { int childpid; // Allocate a pipe before we fork. // xastir_udp_pipe = (pipe_object *)malloc(sizeof(pipe_object)); if (xastir_udp_pipe == NULL) { fprintf(stderr,"x_spider: Couldn't malloc pipe_object\n"); return(0); } if (pipe(xastir_udp_pipe->to_child) < 0 || pipe(xastir_udp_pipe->to_parent) < 0) { fprintf(stderr,"x_spider: Can't create pipes\n"); free(xastir_udp_pipe); // Free the malloc'd memory. xastir_udp_pipe = NULL; return(0); } xastir_udp_pipe->authenticated = 1; xastir_udp_pipe->callsign[0] = '\0'; if ( (childpid = fork()) < 0) { fprintf(stderr,"Fork_UDP_server: Fork error\n"); // Close pipes close(xastir_udp_pipe->to_child[0]); close(xastir_udp_pipe->to_child[1]); close(xastir_udp_pipe->to_parent[0]); close(xastir_udp_pipe->to_parent[1]); free(xastir_udp_pipe); // Free the malloc'd memory. xastir_udp_pipe = NULL; return(0); } else if (childpid == 0) { // // Child process // // Go back to default signal handler instead of calling // restart() on SIGHUP (void) signal(SIGHUP,SIG_DFL); // Store parent pid parent_pid = getppid(); // Change the name of the new child process. So far this // only works for "ps" listings, not for "top". This code // only works on Linux. For BSD use setproctitle(3), NetBSD // can use setprogname(2). #ifdef __linux__ init_set_proc_title(argc, argv, envp); set_proc_title("%s", "x-spider UDP daemon (xastir)"); //fprintf(stderr,"DEBUG: %s\n", Argv[0]); (void) signal(SIGHUP, exit); #endif // __linux__ close(xastir_udp_pipe->to_child[1]); // Close write end of pipe close(xastir_udp_pipe->to_parent[0]); // Close read end of pipe // Assign the global variables pipe_udp_server_to_xastir = xastir_udp_pipe->to_parent[1]; pipe_xastir_to_udp_server = xastir_udp_pipe->to_child[0]; // Set read-end of pipe to be non-blocking. // // if (fcntl(pipe_xastir_to_udp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr, // "x_spider: Couldn't set read-end of pipe_xastir_to_udp_server non-blocking\n"); // } UDP_Server(argc, argv, envp); fprintf(stderr,"UDP_Server process died.\n"); exit(1); } // // Parent process // close(xastir_udp_pipe->to_parent[1]); // Close write end of pipe close(xastir_udp_pipe->to_child[0]); // Close read end of pipe // Assign the global variables so that Xastir itself will know // how to talk to the pipes pipe_udp_server_to_xastir = xastir_udp_pipe->to_parent[0]; pipe_xastir_to_udp_server = xastir_udp_pipe->to_child[1]; // Set read-end of pipe to be non-blocking. // if (fcntl(pipe_udp_server_to_xastir, F_SETFL, O_NONBLOCK) < 0) { fprintf(stderr,"x_spider: Couldn't set read-end of pipe_udp_server_to_xastir non-blocking\n"); fprintf(stderr,"Could some processes still be running from a previous run of Xastir?\n"); } // // Set write-end of pipe to be non-blocking. // // // if (fcntl(pipe_xastir_to_udp_server, F_SETFL, O_NONBLOCK) < 0) { // fprintf(stderr,"x_spider: Couldn't set read-end of pipe_xastir_to_udp_server non-blocking\n"); // } // We don't need to do anything here except return back to the // calling routine with the PID of the new server process, so // that it can request the server and all it's children to quit // when Xastir quits or segfaults. return(childpid); // Really the parent PID in this case } Xastir-Release-2.2.4/src/x_spider.h0000664000175000017500000000275015151324131016102 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifndef __XASTIR_SERVER_H #define __XASTIR_SERVER_H //#include "xastir.h" #define NET_CONNECT_TIMEOUT 20 #define SERV_TCP_PORT 2023 #define SERV_UDP_PORT 2023 extern char *pname; extern int pipe_xastir_to_tcp_server; extern int pipe_tcp_server_to_xastir; extern int pipe_xastir_to_udp_server; extern int pipe_udp_server_to_xastir; extern int writen(int fd, char *ptr, int nbytes); extern int readline(int fd, char *ptr, int maxlen); extern int Fork_TCP_server(int argc, char *argv[], char *envp[]); extern int Fork_UDP_server(int argc, char *argv[], char *envp[]); #endif /* XASTIR_SERVER_H */ Xastir-Release-2.2.4/src/xa_config.c0000664000175000017500000026213315151324131016220 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include #include "xa_config.h" #include "interface.h" #include "xastir.h" #include "main.h" #include "db_funcs.h" #include "util.h" #include "bulletin_gui.h" #include "list_gui.h" #include "messages.h" #include "draw_symbols.h" #include "maps.h" #include "track_gui.h" #include "snprintf.h" #include "objects.h" #include "objects_gui.h" #include "db_gis.h" #include "ambiguity_utils.h" #include "cad_objects.h" // Must be last include file #include "leak_detection.h" #define CONFIG_FILE "config/xastir.cnf" #define CONFIG_FILE_BAK1 "config/xastir.cnf.1" #define CONFIG_FILE_BAK2 "config/xastir.cnf.2" #define CONFIG_FILE_BAK3 "config/xastir.cnf.3" #define CONFIG_FILE_BAK4 "config/xastir.cnf.4" #define CONFIG_FILE_TMP "config/xastir.cnf.tmp" #define MAX_VALUE 300 char xa_config_dir[1000]; /* cmdline option user config dir */ void store_string(FILE * fout, char *option, char *value) { // if (debug_level & 1) // fprintf(stderr,"Store String Start\n"); // TODO: Replace with function which doesn't depend on locale. // We'd also need to replace any xastir_snprintf() functions // throughout. fprintf (fout, "%s:%s\n", option, value); // if (debug_level & 1) // fprintf(stderr,"Store String Stop\n"); } void store_char(FILE * fout, char *option, char value) { char value_o[2]; value_o[0] = value; value_o[1] = '\0'; store_string (fout, option, value_o); } void store_int(FILE * fout, char *option, int value) { char value_o[MAX_VALUE]; xastir_snprintf (value_o, sizeof(value_o), "%d", value); store_string (fout, option, value_o); } void store_long (FILE * fout, char *option, long value) { char value_o[MAX_VALUE]; xastir_snprintf(value_o, sizeof(value_o), "%ld", value); store_string (fout, option, value_o); } void store_float (FILE * fout, char *option, float value) { char value_o[MAX_VALUE]; xastir_snprintf(value_o, sizeof(value_o), "%f", value); store_string (fout, option, value_o); } FILE * fin; void input_close(void) { if(fin != NULL) { (void)fclose(fin); } fin = NULL; } /* This function will read the configuration file (xastir.cnf) until it finds the requested option. When the requested option is found it will return the value of that option. The return value of the function will be 1 if the option is found and 0 if the option is not found. May return empty string in "value". */ int get_string(char *option, char *value, int value_size) { char config_file[MAX_VALUE]; char config_line[256]; short option_found; char *value_array[2]; option_found = 0; if (fin == NULL) { get_user_base_dir(CONFIG_FILE, config_file, sizeof(config_file)); // filecreate() refuses to create a new file if it already // exists. (void)filecreate(config_file); fin = fopen (config_file, "r"); } if (fin != NULL) { int loop_counter = 0; while (!option_found && loop_counter < 2) { // Search to the end of file and then repeat from the // beginning (once) if not found the first time. As // long as we keep the order of saves/restores to/from // the file the same, this will mean exactly one fgets() // per variable sought. if (loop_counter == 1) { // We didn't find it the first time through, try // once more from the start of file. (void)fseek(fin, 0, SEEK_SET); } // Read the file line-by-line. fgets() also reads in // the line-end characters so we'll have to remove // those. while (!option_found && (fgets (&config_line[0], 256, fin) != NULL)) { // Find the line containing "option" // Here we assume no leading/trailing white space // for value_array[0]. split_string(config_line, value_array, 2, ':'); if (strcmp (value_array[0], option) == 0) { int len; // Found the correct line option_found = 1; remove_leading_spaces(value_array[1]); // Eliminate line-end chars. Do this twice 'cuz // some operating systems add two characters // (\r\n) len = strlen(value_array[1]); if (len > 0) { if ( (value_array[1][len-1] == '\n') || (value_array[1][len-1] == '\r') ) { value_array[1][len-1] = '\0'; } } len = strlen(value_array[1]); if (len > 0) { if ( (value_array[1][len-1] == '\n') || (value_array[1][len-1] == '\r') ) { value_array[1][len-1] = '\0'; } } remove_trailing_spaces(value_array[1]); if (value_array[1] == NULL) { value = ""; } else xastir_snprintf(value, value_size, "%s", value_array[1]); //fprintf(stderr,"%s = %s\n", value_array[0], value); } } // End of while (fgets) loop_counter++; } // End of while (!option_found) } // End of if else { fprintf(stderr,"Couldn't open file: %s\n", config_file); } return (option_found); } int get_char(char *option, char *value) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret) { *value = value_o[0]; } return (ret); } // Snags an int and checks whether it is within the correct range. // If not, it assigns a default value. Returns the value. int get_int(char *option, int low, int high, int def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (atoi(value_o) >= low) && (atoi(value_o) <= high) ) { return(atoi (value_o)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %d\n", // option, // def); return(def); } fprintf(stderr,"xastir.cnf: %s out-of-range: %d, changing to default: %d\n", option, atoi(value_o), def); return(def); } // Snags a long and checks whether it is within the correct range. // If not, it assigns a default value. Returns the value. long get_long(char *option, long low, long high, long def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (atol(value_o) >= low) && (atol(value_o) <= high) ) { return(atol(value_o)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %ld\n", // option, // def); return(def); } fprintf(stderr, "xastir.cnf: %s out-of-range: %ld, changing to default: %ld\n", option, atol(value_o), def); return(def); } // Snags a float value and checks whether it is within the correct // range. If not, it assigns a default value. Returns the value. float get_float(char *option, float low, float high, float def) { char value_o[MAX_VALUE]; int ret; ret = get_string (option, value_o, sizeof(value_o)); if (ret && (strtof(value_o, NULL) >= low) && (strtof(value_o, NULL) <= high ) ) { return(strtof(value_o, NULL)); } if (!ret) { // fprintf(stderr,"xastir.cnf: %s not found, inserting default: %f\n", // option, // def); return(def); } fprintf(stderr, "xastir.cnf: %s out-of-range: %f, changing to default: %f\n", option, strtof(value_o, NULL), def); return(def); } // Note on get_user_base_dir // // The original implementation of this function used a static char array // to do all the path construction, and returned a pointer to that array. // // This function was changed in Sept 2012 to remove its original use // of a single static char array. That version was highly unsafe in a // threaded environment, and was used routinely in multiple threads. // Even inserting mutexes to prevent simultaneous writes by multiple threads // wasn't good enough, because once the mutex was released there was no // guarantee that one thread would not write into the static array while // another thread was reading it. The result was that it was sometimes // possible for paths to get corrupted, especially if multiple logging // options and png snapshots were simultaneously selected. // // Prior to the change, one called this as: // ptr = get_user_base_dir("pathfragment"); // and ptr was always a pointer to the static char array. Now // the caller is responsible for passing in the array into which we'll // write. This way, threads should never be clobbering each other's paths // returned from this routine. // char *get_user_base_dir(char *dir, char * base, size_t base_size) { char *env_ptr; // fprintf(stderr,"base: %s \nxa_config_dir: %s\n", base, xa_config_dir); switch (xa_config_dir[0]) { case '/': //have some path xastir_snprintf(base, base_size, "%s",xa_config_dir); break; case '\0' : // build from scratch xastir_snprintf(base, base_size, "%s", ((env_ptr = getenv ("XASTIR_USER_BASE")) != NULL) ? env_ptr : user_dir); if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } strncat (base, ".xastir/", base_size - 1 - strlen(base)); break ; default: // Unqualified path xastir_snprintf(base, base_size, "%s", ((env_ptr = getenv ("PWD")) != NULL) ? env_ptr : user_dir); if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } strncat (base, xa_config_dir, base_size - 1 - strlen(base)); } if (base[strlen (base) - 1] != '/') { strncat (base, "/", base_size - 1 - strlen(base)); } // Save base so we monkey around less later. xastir_snprintf(xa_config_dir,sizeof(xa_config_dir),"%s", base); // Append dir and return return strncat(base, dir, base_size - 1 - strlen(base)); } char *get_data_base_dir(char *dir) { static char base[MAX_VALUE]; char *env_ptr; // Snag this variable from the environment if it exists there, // else grab it from the define from the compile command-line // that should look like one of these: // // -DXASTIR_DATA_BASE=\"/opt/Xastir/share/xastir\" // -DXASTIR_DATA_BASE=\"/usr/local/share/xastir\" // xastir_snprintf(base, sizeof(base), "%s", ((env_ptr = getenv ("XASTIR_DATA_BASE")) != NULL) ? env_ptr : XASTIR_DATA_BASE); if (base[strlen (base) - 1] != '/') { strncat(base, "/", sizeof(base) - 1 - strlen(base)); } strncat(base, dir, sizeof(base) - 1 - strlen(base)); return base; } // Care should be taken here to make sure that no out-of-range data // is saved, as it will mess up Xastir startup from that point on. // Also: Config file should be owned by the user, and not by root. // If chmod 4755 is done on the executable, then the config file ends // up being owned by root from then on. // // Yea, I could have made this nicer by algorithmically figuring out // the backup filenames and rotating among .1 through .9. Perhaps // next go-around! Just having multiples is a big win, in case some // of them get blown away. // // Another step that needs to be made is to restore config settings // for the cases where Xastir comes up with a nonexistent or empty // xastir.cnf file. If the backups exist, we should copy them // across. // void save_data(void) { int i; char name_temp[20]; char name[50]; FILE * fout; char config_file_tmp[MAX_VALUE]; char config_file[MAX_VALUE]; char config_file_bak1[MAX_VALUE]; char config_file_bak2[MAX_VALUE]; char config_file_bak3[MAX_VALUE]; char config_file_bak4[MAX_VALUE]; struct stat file_status; // Force the locale to a default so that we don't have // conversion problems due to LANG/LC_ALL/LC_CTYPE/LC_NUMERIC // environment variables. (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); // if (debug_level & 1) // fprintf(stderr,"Store String Start\n"); // The new file we'll create get_user_base_dir(CONFIG_FILE_TMP, config_file_tmp, sizeof(config_file_tmp)); // Save to the new config file fout = fopen (config_file_tmp, "a"); if (fout != NULL) { // Position x_return; // Position y_return; if (debug_level & 1) { fprintf(stderr,"Save Data Start\n"); } /* language */ store_string (fout, "LANGUAGE", lang_to_use); /* my data */ store_string (fout, "STATION_CALLSIGN", my_callsign); store_string (fout, "STATION_LAT", my_lat); store_string (fout, "STATION_LONG", my_long); store_char (fout, "STATION_GROUP", my_group); store_char (fout, "STATION_SYMBOL", my_symbol); store_char (fout, "STATION_MESSAGE_TYPE", aprs_station_message_type); store_string (fout, "STATION_POWER", my_phg); store_string (fout, "STATION_COMMENTS", my_comment); store_int (fout, "MY_TRAIL_DIFF_COLOR", my_trail_diff_color); if (debug_level & 1) { fprintf(stderr,"Save Data 1\n"); } /* default values */ store_long (fout, "SCREEN_WIDTH", screen_width); store_long (fout, "SCREEN_HEIGHT", screen_height); /* // Get the X/Y offsets for the main window XtVaGetValues(appshell, XmNx, &x_return, XmNy, &y_return, NULL); fprintf(stderr,"X:%d y:%d\n", (int)x_return, (int)y_return); store_int (fout, "SCREEN_X_OFFSET", (int)x_return); store_int (fout, "SCREEN_Y_OFFSET", (int)y_return); */ store_long (fout, "SCREEN_LAT", center_latitude); store_long (fout, "SCREEN_LONG", center_longitude); store_string(fout, "RELAY_DIGIPEAT_CALLS", relay_digipeater_calls); store_int (fout, "COORDINATE_SYSTEM", coordinate_system); store_int (fout, "STATION_TRANSMIT_AMB", position_amb_chars); if (scale_y > 0) { store_long (fout, "SCREEN_ZOOM", scale_y); } else { store_long (fout, "SCREEN_ZOOM", 1); } store_int (fout, "MAP_BGCOLOR", map_background_color); store_int (fout, "MAP_DRAW_FILLED_COLORS", map_color_fill); #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) store_float (fout, "IMAGEMAGICK_GAMMA_ADJUST", imagemagick_gamma_adjust); #endif // HAVE_MAGICK store_float(fout, "RASTER_MAP_INTENSITY", raster_map_intensity); #endif // NO_GRAPHICS store_string(fout, "PRINT_PROGRAM", printer_program); store_string(fout, "PREVIEWER_PROGRAM", previewer_program); store_int (fout, "MAP_LETTERSTYLE", letter_style); store_int (fout, "MAP_ICONOUTLINESTYLE", icon_outline_style); store_int (fout, "MAP_WX_ALERT_STYLE", wx_alert_style); store_string(fout, "ALTNET_CALL", altnet_call); store_int(fout, "ALTNET", altnet); store_int(fout, "SKIP_DUPE_CHECK", skip_dupe_checking); store_string (fout, "AUTO_MAP_DIR", AUTO_MAP_DIR); store_string (fout, "ALERT_MAP_DIR", ALERT_MAP_DIR); store_string (fout, "SELECTED_MAP_DIR", SELECTED_MAP_DIR); store_string (fout, "SELECTED_MAP_DATA", SELECTED_MAP_DATA); store_string (fout, "MAP_INDEX_DATA", MAP_INDEX_DATA); store_string (fout, "SYMBOLS_DIR", SYMBOLS_DIR); store_string (fout, "SOUND_DIR", SOUND_DIR); store_string (fout, "GROUP_DATA_FILE", group_data_file); store_string (fout, "GNIS_FILE", locate_gnis_filename); #ifdef HAVE_NOMINATIM /* Nominatim geocoding configuration */ store_string (fout, "NOMINATIM_SERVER_URL", nominatim_server_url); store_int (fout, "NOMINATIM_CACHE_ENABLED", nominatim_cache_enabled); store_int (fout, "NOMINATIM_CACHE_DAYS", nominatim_cache_days); store_string (fout, "NOMINATIM_USER_EMAIL", nominatim_user_email); store_string (fout, "NOMINATIM_COUNTRY_DEFAULT", nominatim_country_default); #endif /* maps */ store_int (fout, "MAPS_LONG_LAT_GRID", long_lat_grid); store_int (fout, "MAPS_LABELED_GRID_BORDER", draw_labeled_grid_border); store_int (fout, "MAPS_LEVELS", map_color_levels); store_int (fout, "MAPS_LABELS", map_labels); store_int (fout, "MAP_LOCK_PAN_ZOOM", map_lock_pan_zoom); store_int (fout, "MAPS_AUTO_MAPS", map_auto_maps); store_int (fout, "MAPS_AUTO_MAPS_SKIP_RASTER", auto_maps_skip_raster); store_int (fout, "MAPS_INDEX_ON_STARTUP", index_maps_on_startup); store_string (fout, "MAPS_LABEL_FONT_TINY", rotated_label_fontname[FONT_TINY]); store_string (fout, "MAPS_LABEL_FONT_SMALL", rotated_label_fontname[FONT_SMALL]); store_string (fout, "MAPS_LABEL_FONT_MEDIUM", rotated_label_fontname[FONT_MEDIUM]); // NOTE: FONT_DEFAULT points to FONT_MEDIUM. store_string (fout, "MAPS_LABEL_FONT_LARGE", rotated_label_fontname[FONT_LARGE]); store_string (fout, "MAPS_LABEL_FONT_HUGE", rotated_label_fontname[FONT_HUGE]); store_string (fout, "MAPS_LABEL_FONT_BORDER", rotated_label_fontname[FONT_BORDER]); store_string (fout, "SYSTEM_FIXED_FONT", rotated_label_fontname[FONT_SYSTEM]); store_string (fout, "STATION_FONT", rotated_label_fontname[FONT_STATION]); store_string (fout, "ATV_ID_FONT", rotated_label_fontname[FONT_ATV_ID]); #ifdef HAVE_LIBGEOTIFF store_int (fout, "DRG_XOR_COLORS", DRG_XOR_colors); store_int (fout, "DRG_SHOW_COLORS_0", DRG_show_colors[0]); store_int (fout, "DRG_SHOW_COLORS_1", DRG_show_colors[1]); store_int (fout, "DRG_SHOW_COLORS_2", DRG_show_colors[2]); store_int (fout, "DRG_SHOW_COLORS_3", DRG_show_colors[3]); store_int (fout, "DRG_SHOW_COLORS_4", DRG_show_colors[4]); store_int (fout, "DRG_SHOW_COLORS_5", DRG_show_colors[5]); store_int (fout, "DRG_SHOW_COLORS_6", DRG_show_colors[6]); store_int (fout, "DRG_SHOW_COLORS_7", DRG_show_colors[7]); store_int (fout, "DRG_SHOW_COLORS_8", DRG_show_colors[8]); store_int (fout, "DRG_SHOW_COLORS_9", DRG_show_colors[9]); store_int (fout, "DRG_SHOW_COLORS_10", DRG_show_colors[10]); store_int (fout, "DRG_SHOW_COLORS_11", DRG_show_colors[11]); store_int (fout, "DRG_SHOW_COLORS_12", DRG_show_colors[12]); #endif // HAVE_LIBGEOTIFF // filter values // NOT SAVED: Select_.none store_int (fout, "DISPLAY_MY_STATION", Select_.mine); store_int (fout, "DISPLAY_TNC_STATIONS", Select_.tnc); store_int (fout, "DISPLAY_TNC_DIRECT_STATIONS", Select_.direct); store_int (fout, "DISPLAY_TNC_VIADIGI_STATIONS", Select_.via_digi); store_int (fout, "DISPLAY_NET_STATIONS", Select_.net); store_int (fout, "DISPLAY_TACTICAL_STATIONS", Select_.tactical); store_int (fout, "DISPLAY_OLD_STATION_DATA", Select_.old_data); store_int (fout, "DISPLAY_STATIONS", Select_.stations); store_int (fout, "DISPLAY_FIXED_STATIONS", Select_.fixed_stations); store_int (fout, "DISPLAY_MOVING_STATIONS", Select_.moving_stations); store_int (fout, "DISPLAY_WEATHER_STATIONS", Select_.weather_stations); store_int (fout, "DISPLAY_CWOP_WX_STATIONS", Select_.CWOP_wx_stations); store_int (fout, "DISPLAY_OBJECTS", Select_.objects); store_int (fout, "DISPLAY_STATION_WX_OBJ", Select_.weather_objects); store_int (fout, "DISPLAY_WATER_GAGE_OBJ", Select_.gauge_objects); store_int (fout, "DISPLAY_OTHER_OBJECTS", Select_.other_objects); store_int (fout, "DISPLAY_AIRCRAFT_OBJECTS", Select_.aircraft_objects); store_int (fout, "DISPLAY_VESSEL_OBJECTS", Select_.vessel_objects); // display values store_int (fout, "DISPLAY_CALLSIGN", Display_.callsign); store_int (fout, "DISPLAY_LABEL_ALL_TRACKPOINTS", Display_.label_all_trackpoints); store_int (fout, "DISPLAY_SYMBOL", Display_.symbol); store_int (fout, "DISPLAY_SYMBOL_ROTATE", Display_.symbol_rotate); store_int (fout, "DISPLAY_STATION_PHG", Display_.phg); store_int (fout, "DISPLAY_DEFAULT_PHG", Display_.default_phg); store_int (fout, "DISPLAY_MOBILES_PHG", Display_.phg_of_moving); store_int (fout, "DISPLAY_ALTITUDE", Display_.altitude); store_int (fout, "DISPLAY_COURSE", Display_.course); store_int (fout, "DISPLAY_SPEED", Display_.speed); store_int (fout, "DISPLAY_SPEED_SHORT", Display_.speed_short); store_int (fout, "DISPLAY_DIST_COURSE", Display_.dist_bearing); store_int (fout, "DISPLAY_WEATHER", Display_.weather); store_int (fout, "DISPLAY_STATION_WX", Display_.weather_text); store_int (fout, "DISPLAY_TEMP_ONLY", Display_.temperature_only); store_int (fout, "DISPLAY_WIND_BARB", Display_.wind_barb); store_int (fout, "DISPLAY_STATION_TRAILS", Display_.trail); store_int (fout, "DISPLAY_LAST_HEARD", Display_.last_heard); store_int (fout, "DISPLAY_POSITION_AMB", Display_.ambiguity); store_int (fout, "DISPLAY_DF_INFO", Display_.df_data); store_int (fout, "DISPLAY_DF_BEAMWIDTH_INFO", Display_.df_beamwidth_data); store_int (fout, "DISPLAY_DF_BEARING_INFO", Display_.df_bearing_data); store_int (fout, "DISPLAY_DEAD_RECKONING_INFO", Display_.dr_data); store_int (fout, "DISPLAY_DEAD_RECKONING_ARC", Display_.dr_arc); store_int (fout, "DISPLAY_DEAD_RECKONING_COURSE", Display_.dr_course); store_int (fout, "DISPLAY_DEAD_RECKONING_SYMBOL", Display_.dr_symbol); store_int (fout, "DISPLAY_UNITS_ENGLISH", english_units); store_int (fout, "DISPLAY_DIST_BEAR_STATUS", do_dbstatus); // CAD Objects store_int (fout, "DISPLAY_CAD_OBJECT_LABEL", CAD_show_label); store_int (fout, "DISPLAY_CAD_OBJECT_PROBABILITY", CAD_show_raw_probability); store_int (fout, "DISPLAY_CAD_OBJECT_COMMENT", CAD_show_comment); store_int (fout, "DISPLAY_CAD_OBJECT_AREA", CAD_show_area); // Interface values store_int (fout, "DISABLE_TRANSMIT", transmit_disable); store_int (fout, "DISABLE_POSIT_TX", posit_tx_disable); store_int (fout, "DISABLE_OBJECT_TX", object_tx_disable); store_int (fout, "ENABLE_SERVER_PORT", enable_server_port); for (i = 0; i < MAX_IFACE_DEVICES; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "DEVICE%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].device_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "NAME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_name); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RADIO_PORT", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].radio_port); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "CONVERSE_CMD", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_converse_string); #ifdef HAVE_DB xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].database_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA_TYPE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].database_schema_type); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_USERNAME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_username); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_schema); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_UNIX_SOCKET", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].database_unix_socket); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "QUERY_ON_STARTUP", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].query_on_startup); #endif /* HAVE_DB */ xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "INTERFACE_COMMENT", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].comment); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "HOST", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_name); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "PASSWD", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_pswd); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "FILTER_PARAMS", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].device_host_filter_string); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO1", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO2", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto2); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO3", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto3); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO_IGATE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].unproto_igate); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_UP_FILE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].tnc_up_file); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_DOWN_FILE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].tnc_down_file); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXDELAY", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].txdelay); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_PERSISTENCE", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].persistence); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_SLOTTIME", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].slottime); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXTAIL", sizeof(name) - 1 - strlen(name)); store_string (fout, name, devices[i].txtail); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_FULLDUPLEX", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].fullduplex); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_INIT_KISSMODE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].init_kiss); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SPEED", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].sp); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "STYLE", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].style); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "IGATE_OPTION", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].igate_options); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TXMT", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].transmit_data); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RELAY_DIGIPEAT", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].relay_digipeat); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RECONN", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].reconnect); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "ONSTARTUP", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].connect_on_startup); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat(name, "GPSRETR", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].gps_retrieve); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SETTIME", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].set_time); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNCEXTRADELAY", sizeof(name) - 1 - strlen(name)); store_int (fout, name, devices[i].tnc_extra_delay); } /* TNC */ store_int (fout, "TNC_LOG_DATA", log_tnc_data); store_string (fout, "LOGFILE_TNC", LOGFILE_TNC); /* NET */ store_int (fout, "NET_LOG_DATA", log_net_data); store_int (fout, "NET_RUN_AS_IGATE", operate_as_an_igate); store_int (fout, "NETWORK_WAITTIME", NETWORK_WAITTIME); // LOGGING store_int (fout, "LOG_IGATE", log_igate); store_int (fout, "LOG_WX", log_wx); store_int (fout, "LOG_MESSAGE", log_message_data); store_int (fout, "LOG_WX_ALERT", log_wx_alert_data); store_string (fout, "LOGFILE_IGATE", LOGFILE_IGATE); store_string (fout, "LOGFILE_NET", LOGFILE_NET); store_string (fout, "LOGFILE_WX", LOGFILE_WX); store_string (fout, "LOGFILE_MESSAGE", LOGFILE_MESSAGE); store_string (fout, "LOGFILE_WX_ALERT", LOGFILE_WX_ALERT); // SNAPSHOTS store_int (fout, "SNAPSHOTS_ENABLED", snapshots_enabled); // KML SNAPSHOTS store_int (fout, "KMLSNAPSHOTS_ENABLED", kmlsnapshots_enabled); /* WX ALERTS */ store_long (fout, "WX_ALERTS_REFRESH_TIME", (long)WX_ALERTS_REFRESH_TIME); /* GPS */ store_long (fout, "GPS_TIME", (long)gps_time); /* still needed */ /* POSIT RATE */ store_long (fout, "POSIT_RATE", (long)POSIT_rate); /* OBJECT RATE */ store_long (fout, "OBJECT_RATE", (long)OBJECT_rate); /* UPDATE DR RATE */ store_long (fout, "UPDATE_DR_RATE", (long)update_DR_rate); /* station broadcast type */ store_int (fout, "BST_TYPE", output_station_type); #ifdef TRANSMIT_RAW_WX store_int (fout, "BST_WX_RAW", transmit_raw_wx); #endif // TRANSMIT_RAW_WX store_int (fout, "BST_COMPRESSED_POSIT", transmit_compressed_posit); store_int (fout, "COMPRESSED_OBJECTS_ITEMS", transmit_compressed_objects_items); store_int (fout, "SMART_BEACONING", smart_beaconing); store_int (fout, "SB_TURN_MIN", sb_turn_min); store_int (fout, "SB_TURN_SLOPE", sb_turn_slope); store_int (fout, "SB_TURN_TIME", sb_turn_time); store_int (fout, "SB_POSIT_FAST", sb_posit_fast); store_int (fout, "SB_POSIT_SLOW", sb_posit_slow); store_int (fout, "SB_LOW_SPEED_LIMIT", sb_low_speed_limit); store_int (fout, "SB_HIGH_SPEED_LIMIT", sb_high_speed_limit); store_int (fout, "POP_UP_NEW_BULLETINS", pop_up_new_bulletins); store_int (fout, "VIEW_ZERO_DISTANCE_BULLETINS", view_zero_distance_bulletins); store_int (fout, "WARN_ABOUT_MOUSE_MODIFIERS", warn_about_mouse_modifiers); /* -dk7in- variable beacon interval */ /* mobile: max 2 min */ /* fixed: max 15 min */ if ((output_station_type >= 1) && (output_station_type <= 3)) { max_transmit_time = (time_t)120l; /* 2 min @ mobile */ } else { max_transmit_time = (time_t)900l; /* 15 min @ fixed */ } /* Audio Alarms */ store_string (fout, "SOUND_COMMAND", sound_command); store_int (fout, "SOUND_PLAY_ONS", sound_play_new_station); store_string (fout, "SOUND_ONS_FILE", sound_new_station); store_int (fout, "SOUND_PLAY_ONM", sound_play_new_message); store_string (fout, "SOUND_ONM_FILE", sound_new_message); store_int (fout, "SOUND_PLAY_PROX", sound_play_prox_message); store_string (fout, "SOUND_PROX_FILE", sound_prox_message); store_string (fout, "PROX_MIN", prox_min); store_string (fout, "PROX_MAX", prox_max); store_int (fout, "SOUND_PLAY_BAND", sound_play_band_open_message); store_string (fout, "SOUND_BAND_FILE", sound_band_open_message); store_string (fout, "BANDO_MIN", bando_min); store_string (fout, "BANDO_MAX", bando_max); store_int (fout, "SOUND_PLAY_WX_ALERT", sound_play_wx_alert_message); store_string (fout, "SOUND_WX_ALERT_FILE", sound_wx_alert_message); #ifdef HAVE_FESTIVAL /* Festival speech settings */ store_int (fout, "SPEAK_NEW_STATION",festival_speak_new_station); store_int (fout, "SPEAK_PROXIMITY_ALERT",festival_speak_proximity_alert); store_int (fout, "SPEAK_TRACKED_ALERT",festival_speak_tracked_proximity_alert); store_int (fout, "SPEAK_BAND_OPENING",festival_speak_band_opening); store_int (fout, "SPEAK_MESSAGE_ALERT",festival_speak_new_message_alert); store_int (fout, "SPEAK_MESSAGE_BODY",festival_speak_new_message_body); store_int (fout, "SPEAK_WEATHER_ALERT",festival_speak_new_weather_alert); store_int (fout, "SPEAK_ID",festival_speak_ID); #endif // HAVE_FESTIVAL store_int (fout, "ATV_SCREEN_ID", ATV_screen_ID); /* defaults */ store_long (fout, "DEFAULT_STATION_OLD", (long)sec_old); store_long (fout, "DEFAULT_STATION_CLEAR", (long)sec_clear); store_long (fout, "DEFAULT_AIRCRAFT_CLEAR", (long)aircraft_sec_clear); store_long(fout, "DEFAULT_STATION_REMOVE", (long)sec_remove); store_string (fout, "HELP_DATA", HELP_FILE); store_string (fout, "MESSAGE_COUNTER", message_counter); store_string (fout, "AUTO_MSG_REPLY", auto_reply_message); store_int (fout, "DISPLAY_PACKET_TYPE", Display_packet_data_type); store_int (fout, "BULLETIN_RANGE", bulletin_range); store_int(fout,"VIEW_MESSAGE_RANGE",vm_range); store_int(fout,"VIEW_MESSAGE_LIMIT",view_message_limit); store_int(fout,"PREDEF_MENU_LOAD",predefined_menu_from_file); store_string(fout,"PREDEF_MENU_FILE",predefined_object_definition_filename); store_int(fout, "READ_MESSAGES_PACKET_DATA_TYPE", Read_messages_packet_data_type); store_int(fout, "READ_MESSAGES_MINE_ONLY", Read_messages_mine_only); /* printer variables */ store_int (fout, "PRINT_ROTATED", print_rotated); store_int (fout, "PRINT_AUTO_ROTATION", print_auto_rotation); store_int (fout, "PRINT_AUTO_SCALE", print_auto_scale); store_int (fout, "PRINT_IN_MONOCHROME", print_in_monochrome); store_int (fout, "PRINT_INVERT_COLORS", print_invert); /* Rain Gauge Type, set in the Serial Weather interface properties dialog, but really a global default */ store_int (fout, "RAIN_GAUGE_TYPE", WX_rain_gauge_type); /* list attributes */ for (i = 0; i < LST_NUM; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "LIST%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "H", sizeof(name) - 1 - strlen(name)); store_int (fout, name, list_size_h[i]); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "W", sizeof(name) - 1 - strlen(name)); store_int (fout, name, list_size_w[i]); } store_int (fout, "TRACK_ME", track_me); store_string (fout, "TRACKING_STATION_CALLSIGN", tracking_station_call); store_int (fout, "MAP_CHOOSER_EXPAND_DIRS", map_chooser_expand_dirs); store_int (fout, "ST_DIRECT_TIMEOUT", st_direct_timeout); store_int (fout, "DEAD_RECKONING_TIMEOUT", dead_reckoning_timeout); store_int (fout, "SERIAL_CHAR_PACING", serial_char_pacing); store_int (fout, "TRAIL_SEGMENT_TIME", trail_segment_time); store_int (fout, "TRAIL_SEGMENT_DISTANCE", trail_segment_distance); store_int (fout, "RINO_DOWNLOAD_INTERVAL", RINO_download_interval); store_int (fout, "SNAPSHOT_INTERVAL", snapshot_interval); if (debug_level & 1) { fprintf(stderr,"Save Data Stop\n"); } // Close the config_file_tmp file, we're done writing it. (void)fclose (fout); get_user_base_dir(CONFIG_FILE, config_file, sizeof(config_file)); get_user_base_dir(CONFIG_FILE_BAK1, config_file_bak1, sizeof(config_file_bak1)); get_user_base_dir(CONFIG_FILE_BAK2, config_file_bak2, sizeof(config_file_bak2)); get_user_base_dir(CONFIG_FILE_BAK3, config_file_bak3, sizeof(config_file_bak3)); get_user_base_dir(CONFIG_FILE_BAK4,config_file_bak4, sizeof(config_file_bak4)); // // Rename the old config files so that we have a few // backups in case of corruption: // // xastir.cnf.3 -> xastir.cnf.4 // xastir.cnf.2 -> xastir.cnf.3 // xastir.cnf.1 -> xastir.cnf.2 // xastir.cnf -> xastir.cnf.1 // xastir.cnf.tmp -> xastir.cnf // // Rename bak3 to bak4 // NOTE: bak3 won't exist until a few saves have happened. // // Check whether bak3 exists if (stat(config_file_bak3, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak3); return; } if ( rename (config_file_bak3, config_file_bak4) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak3, config_file_bak4); // Attempt to restore to previous state // Nothing to do here! return; } } // Rename bak2 to bak3 // NOTE: bak2 won't exist until a few saves have happened. // // Check whether bak2 exists if (stat(config_file_bak2, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak2); return; } if ( rename (config_file_bak2, config_file_bak3) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak2, config_file_bak3); // Attempt to restore to previous state rename (config_file_bak4, config_file_bak3); // Nothing to do here! return; } } // Rename bak1 to bak2 // NOTE: bak1 won't exist until a couple of saves have happened. // // Check whether bak1 exists if (stat(config_file_bak1, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_bak1); return; } if ( rename (config_file_bak1, config_file_bak2) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_bak1, config_file_bak2); // Attempt to restore to previous state rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } // NOTE: To minimize the possibility that we'll end up with a // missing or corrupt config file, we actually should COPY // config_file to config_file_bak1 here so that there's always a // config file in place no matter what. In the next block we can do // the rename of config_file_tmp to config_file and not miss a beat. // See "man 2 rename". // Rename config to bak1 // NOTE: config won't exist until the first save happens. // // Check whether config exists if (stat(config_file, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file); return; } // // Note "copy_file()" instead of "rename()". This // assures that we always have a config file in place no // matter what errors might occur. // if ( copy_file(config_file, config_file_bak1) ) { fprintf(stderr, "Couldn't copy %s to %s, cancelling save_data()\n", config_file, config_file_bak1); // Attempt to restore to previous state rename (config_file_bak2, config_file_bak1); rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } // Rename config.tmp to xastir.cnf // NOTE: config won't exist until the first save happens. // // Check whether config.tmp exists if (stat(config_file_tmp, &file_status) == 0) { if (!S_ISREG(file_status.st_mode)) { fprintf(stderr, "Couldn't stat %s, cancelling save_data()\n", config_file_tmp); return; } if ( rename (config_file_tmp, config_file) ) { fprintf(stderr, "Couldn't rename %s to %s, cancelling save_data()\n", config_file_tmp, config_file); // Attempt to restore to previous state rename (config_file_bak1, config_file); rename (config_file_bak2, config_file_bak1); rename (config_file_bak3, config_file_bak2); rename (config_file_bak4, config_file_bak3); return; } } } else { // Couldn't create new config (out of filespace?). fprintf(stderr,"Couldn't open config file for appending: %s\n", config_file); // Back out the changes done to the config and backup files. // // Continue using original config file. if ( rename (config_file_bak1, config_file) ) { // Problem here, couldn't rename bak1 file to xastir.cnf fprintf(stderr, "Couldn't recover %s from %s file\n", config_file, config_file_bak1); return; } } } void load_data_or_default(void) { int i; char name_temp[20]; char name[50]; long temp; char user_base_dir[MAX_VALUE]; // Force the locale to a default so that we don't have // conversion problems due to LANG/LC_ALL/LC_CTYPE/LC_NUMERIC // environment variables. (void)setlocale(LC_NUMERIC, "C"); (void)setlocale(LC_CTYPE, "C"); /* language */ if (!get_string ("LANGUAGE", lang_to_use, sizeof(lang_to_use)) || lang_to_use[0] == '\0') { xastir_snprintf(lang_to_use, sizeof(lang_to_use), "English"); } /* my data */ if (!get_string ("STATION_CALLSIGN", my_callsign, sizeof(my_callsign)) || my_callsign[0] == '\0') { xastir_snprintf(my_callsign, sizeof(my_callsign), "NOCALL"); } if (!get_string ("STATION_LAT", my_lat, sizeof(my_lat)) || my_lat[0] == '\0') { xastir_snprintf(my_lat, sizeof(my_lat), "0000.000N"); } if ( (my_lat[4] != '.') || (my_lat[8] != 'N' && my_lat[8] != 'S') ) { xastir_snprintf(my_lat, sizeof(my_lat), "0000.000N"); fprintf(stderr,"Invalid Latitude, changing it to 0000.000N\n"); } // convert old data to high prec temp = convert_lat_s2l (my_lat); convert_lat_l2s (temp, my_lat, sizeof(my_lat), CONVERT_HP_NOSP); if (!get_string ("STATION_LONG", my_long, sizeof(my_long)) || my_long[0] == '\0') { xastir_snprintf(my_long, sizeof(my_long), "00000.000W"); } if ( (my_long[5] != '.') || (my_long[9] != 'W' && my_long[9] != 'E') ) { xastir_snprintf(my_long, sizeof(my_long), "00000.000W"); fprintf(stderr,"Invalid Longitude, changing it to 00000.000W\n"); } // convert old data to high prec temp = convert_lon_s2l (my_long); convert_lon_l2s (temp, my_long, sizeof(my_long), CONVERT_HP_NOSP); position_amb_chars = get_int ("STATION_TRANSMIT_AMB", 0, 4, 0); if (!get_char ("STATION_GROUP", &my_group)) { my_group = '/'; } if (!get_char ("STATION_SYMBOL", &my_symbol)) { my_symbol = 'x'; } if (!get_char ("STATION_MESSAGE_TYPE", &aprs_station_message_type)) { aprs_station_message_type = '='; } // Empty string is ok here. if (!get_string ("STATION_POWER", my_phg, sizeof(my_phg))) { my_phg[0] = '\0'; } if (!get_string ("STATION_COMMENTS", my_comment, sizeof(my_comment)) || my_comment[0] == '\0') { // We used to put "XASTIR-Linux" (or similar) here... //xastir_snprintf (my_comment, sizeof(my_comment), "XASTIR-%s", XASTIR_SYSTEM); // Now we put the empty string. my_comment[0] = '\0'; } /* replacing defined MY_TRAIL_DIFF_COLOR from db.c, default 0 matches default value of MY_TRAIL_DIFF_COLOR to show all mycall-ssids in the same color. */ my_trail_diff_color = get_int ("MY_TRAIL_DIFF_COLOR", 0, 1, 0); /* default values */ screen_width = get_long ("SCREEN_WIDTH", 61l, 10000l, DEFAULT_STARTUP_SCREEN_WIDTH); screen_height = get_long ("SCREEN_HEIGHT", 1l, 10000l, DEFAULT_STARTUP_SCREEN_HEIGHT); // screen_x_offset = (Position)get_int ("SCREEN_X_OFFSET", 0, 10000, 0); // screen_y_offset = (Position)get_int ("SCREEN_Y_OFFSET", 0, 10000, 0); center_latitude = get_long ("SCREEN_LAT", 0l, 64800000l, 32400000l); center_longitude = get_long ("SCREEN_LONG", 0l, 129600000l, 64800000l); // Empty string is ok here if (!get_string("RELAY_DIGIPEAT_CALLS", relay_digipeater_calls, sizeof(relay_digipeater_calls))) { xastir_snprintf (relay_digipeater_calls, sizeof(relay_digipeater_calls), "WIDE1-1"); } // Make them all upper-case. (void)to_upper(relay_digipeater_calls); // And take out all spaces (void)remove_all_spaces(relay_digipeater_calls); coordinate_system = get_int ("COORDINATE_SYSTEM", 0, 5, USE_DDMMMM); scale_y = get_long ("SCREEN_ZOOM", 1l, 500000l, 327680l); scale_x = get_x_scale(center_longitude,center_latitude,scale_y); map_background_color = get_int ("MAP_BGCOLOR", 0, 11, 0); map_color_fill = get_int ( "MAP_DRAW_FILLED_COLORS", 0, 1, 1); #if !defined(NO_GRAPHICS) #if defined(HAVE_MAGICK) imagemagick_gamma_adjust = get_float("IMAGEMAGICK_GAMMA_ADJUST", 0.0, 1.0, 0.0); #endif // HAVE_MAGICK raster_map_intensity = get_float("RASTER_MAP_INTENSITY", 0.0, 1.0, 1.0); #endif // NO_GRAPHICS if (!get_string ("PRINT_PROGRAM", printer_program, sizeof(printer_program)) || printer_program[0] == '\0') { xastir_snprintf(printer_program, sizeof(printer_program), "%s", #ifdef LPR_PATH // Path to LPR if defined LPR_PATH #else // LPR_PATH // Empty path "" #endif // LPR_PATH ); } if (!get_string ("PREVIEWER_PROGRAM", previewer_program, sizeof(previewer_program)) || previewer_program[0] == '\0') { xastir_snprintf(previewer_program, sizeof(previewer_program), "%s", #ifdef GV_PATH // Path to GV if defined GV_PATH #else // GV_PATH // Empty path "" #endif // GV_PATH ); } letter_style = get_int ("MAP_LETTERSTYLE", 0, 3, 0 ); icon_outline_style = get_int ("MAP_ICONOUTLINESTYLE", 0, 3, 0); wx_alert_style = get_int ("MAP_WX_ALERT_STYLE", 0, 1, 0); // Empty string is ok here if (!get_string("ALTNET_CALL", altnet_call, sizeof(altnet_call))) xastir_snprintf(altnet_call, sizeof(altnet_call), "XASTIR"); altnet = get_int("ALTNET", 0, 1, 0); skip_dupe_checking = get_int("SKIP_DUPE_CHECK", 0, 1, 0); if (!get_string ("AUTO_MAP_DIR", AUTO_MAP_DIR, sizeof(AUTO_MAP_DIR)) || AUTO_MAP_DIR[0] == '\0') { xastir_snprintf(AUTO_MAP_DIR, sizeof(AUTO_MAP_DIR), "%s", get_data_base_dir ("maps")); } if (!get_string ("ALERT_MAP_DIR", ALERT_MAP_DIR, sizeof(ALERT_MAP_DIR)) || ALERT_MAP_DIR[0] == '\0') { xastir_snprintf(ALERT_MAP_DIR, sizeof(ALERT_MAP_DIR), "%s", get_data_base_dir ("Counties")); } if (!get_string ("SELECTED_MAP_DIR", SELECTED_MAP_DIR, sizeof(SELECTED_MAP_DIR)) || SELECTED_MAP_DIR[0] == '\0') { xastir_snprintf(SELECTED_MAP_DIR, sizeof(SELECTED_MAP_DIR), "%s", get_data_base_dir ("maps")); } if (!get_string ("SELECTED_MAP_DATA", SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA)) || SELECTED_MAP_DATA[0] == '\0') { xastir_snprintf(SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA), "%s", "config/selected_maps.sys"); } // get the base path for the user base directory, so we can use it over // and over without having to call get_user_base_dir a godzillion times. get_user_base_dir("",user_base_dir, sizeof(user_base_dir)); // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, SELECTED_MAP_DATA, strlen(user_base_dir)) == 0) xastir_snprintf(SELECTED_MAP_DATA, sizeof(SELECTED_MAP_DATA), "%s", "config/selected_maps.sys"); if (!get_string ("MAP_INDEX_DATA", MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA)) || MAP_INDEX_DATA[0] == '\0') { xastir_snprintf(MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA), "%s", "config/map_index.sys"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, MAP_INDEX_DATA, strlen(user_base_dir)) == 0) xastir_snprintf(MAP_INDEX_DATA, sizeof(MAP_INDEX_DATA), "%s", "config/map_index.sys"); if (!get_string ("SYMBOLS_DIR", SYMBOLS_DIR, sizeof(SYMBOLS_DIR)) || SYMBOLS_DIR[0] == '\0') { xastir_snprintf(SYMBOLS_DIR, sizeof(SYMBOLS_DIR), "%s", get_data_base_dir ("symbols")); } if (!get_string ("SOUND_DIR", SOUND_DIR, sizeof(SOUND_DIR)) || SOUND_DIR[0] == '\0') { xastir_snprintf(SOUND_DIR, sizeof(SOUND_DIR), "%s", get_data_base_dir ("sounds")); } if (!get_string ("GROUP_DATA_FILE", group_data_file, sizeof(group_data_file)) || group_data_file[0] == '\0') { xastir_snprintf(group_data_file, sizeof(group_data_file), "%s", "config/groups"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, group_data_file, strlen(user_base_dir)) == 0) xastir_snprintf(group_data_file, sizeof(group_data_file), "%s", "config/groups"); if (!get_string ("GNIS_FILE", locate_gnis_filename, sizeof(locate_gnis_filename)) || locate_gnis_filename[0] == '\0') { xastir_snprintf(locate_gnis_filename, sizeof(locate_gnis_filename), "%s", get_data_base_dir ("GNIS/WA.gnis")); } #ifdef HAVE_NOMINATIM /* Nominatim geocoding configuration */ if (!get_string ("NOMINATIM_SERVER_URL", nominatim_server_url, sizeof(nominatim_server_url)) || nominatim_server_url[0] == '\0') { xastir_snprintf(nominatim_server_url, sizeof(nominatim_server_url), "%s", "https://nominatim.openstreetmap.org"); } nominatim_cache_enabled = get_int ("NOMINATIM_CACHE_ENABLED", 0, 1, 1); nominatim_cache_days = get_int ("NOMINATIM_CACHE_DAYS", 0, 365, 30); // Empty string is ok here if (!get_string ("NOMINATIM_USER_EMAIL", nominatim_user_email, sizeof(nominatim_user_email))) { nominatim_user_email[0] = '\0'; } // Empty string is ok here if (!get_string ("NOMINATIM_COUNTRY_DEFAULT", nominatim_country_default, sizeof(nominatim_country_default))) { nominatim_country_default[0] = '\0'; } #endif /* maps */ long_lat_grid = get_int ("MAPS_LONG_LAT_GRID", 0, 1, 1); draw_labeled_grid_border = get_int ("MAPS_LABELED_GRID_BORDER", 0, 1, 0); map_color_levels = get_int ("MAPS_LEVELS", 0, 1, 1); map_labels = get_int ("MAPS_LABELS", 0, 1, 1); map_lock_pan_zoom = get_int ("MAP_LOCK_PAN_ZOOM", 0, 1, 0); map_auto_maps = get_int ("MAPS_AUTO_MAPS", 0, 1, 0); auto_maps_skip_raster = get_int ("MAPS_AUTO_MAPS_SKIP_RASTER", 0, 1, 0); index_maps_on_startup = get_int ("MAPS_INDEX_ON_STARTUP", 0, 1, 1); if (!get_string ("MAPS_LABEL_FONT_TINY", rotated_label_fontname[FONT_TINY], sizeof(rotated_label_fontname[FONT_TINY])) || rotated_label_fontname[FONT_TINY][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_TINY], sizeof(rotated_label_fontname[FONT_TINY]), "-adobe-helvetica-medium-r-normal--8-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_SMALL", rotated_label_fontname[FONT_SMALL], sizeof(rotated_label_fontname[FONT_SMALL])) || rotated_label_fontname[FONT_SMALL][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_SMALL], sizeof(rotated_label_fontname[FONT_SMALL]), "-adobe-helvetica-medium-r-normal--10-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_MEDIUM", rotated_label_fontname[FONT_MEDIUM], sizeof(rotated_label_fontname[FONT_MEDIUM])) || rotated_label_fontname[FONT_MEDIUM][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_MEDIUM], sizeof(rotated_label_fontname[FONT_MEDIUM]), "-adobe-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1"); } // NOTE: FONT_DEFAULT points to FONT_MEDIUM if (!get_string ("MAPS_LABEL_FONT_LARGE", rotated_label_fontname[FONT_LARGE], sizeof(rotated_label_fontname[FONT_LARGE])) || rotated_label_fontname[FONT_LARGE][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_LARGE], sizeof(rotated_label_fontname[FONT_LARGE]), "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_HUGE", rotated_label_fontname[FONT_HUGE], sizeof(rotated_label_fontname[FONT_HUGE])) || rotated_label_fontname[FONT_HUGE][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_HUGE], sizeof(rotated_label_fontname[FONT_HUGE]), "-adobe-helvetica-medium-r-normal--24-*-*-*-*-*-iso8859-1"); } if (!get_string ("MAPS_LABEL_FONT_BORDER", rotated_label_fontname[FONT_BORDER], sizeof(rotated_label_fontname[FONT_BORDER])) || rotated_label_fontname[FONT_BORDER][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_BORDER], sizeof(rotated_label_fontname[FONT_BORDER]), "-adobe-helvetica-medium-r-normal--14-*-*-*-*-*-iso8859-1"); } if (!get_string ("SYSTEM_FIXED_FONT", rotated_label_fontname[FONT_SYSTEM], sizeof(rotated_label_fontname[FONT_SYSTEM])) || rotated_label_fontname[FONT_SYSTEM][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_SYSTEM], sizeof(rotated_label_fontname[FONT_SYSTEM]), "fixed"); // NOTE: This same default font is hard-coded into // main.c, to be used for the case when the user enters // an invalid font (so the program won't crash). } if (!get_string ("STATION_FONT", rotated_label_fontname[FONT_STATION], sizeof(rotated_label_fontname[FONT_STATION])) || rotated_label_fontname[FONT_STATION][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_STATION], sizeof(rotated_label_fontname[FONT_STATION]), "fixed"); // NOTE: This same default font is hard-coded into // main.c, to be used for the case when the user enters // an invalid font (so the program won't crash). } if (!get_string ("ATV_ID_FONT", rotated_label_fontname[FONT_ATV_ID], sizeof(rotated_label_fontname[FONT_ATV_ID])) || rotated_label_fontname[FONT_ATV_ID][0] == '\0') { xastir_snprintf(rotated_label_fontname[FONT_ATV_ID], sizeof(rotated_label_fontname[FONT_ATV_ID]), "-*-helvetica-*-*-*-*-*-240-*-*-*-*-*-*"); } //N0VH #if defined(HAVE_MAGICK) net_map_timeout = get_int ("NET_MAP_TIMEOUT", 10, 300, 120); #endif //HAVE_MAGICK #ifdef HAVE_LIBGEOTIFF DRG_XOR_colors = get_int ("DRG_XOR_COLORS", 0, 1, 0); DRG_show_colors[0] = get_int ("DRG_SHOW_COLORS_0", 0, 1, 1); DRG_show_colors[1] = get_int ("DRG_SHOW_COLORS_1", 0, 1, 1); DRG_show_colors[2] = get_int ("DRG_SHOW_COLORS_2", 0, 1, 1); DRG_show_colors[3] = get_int ("DRG_SHOW_COLORS_3", 0, 1, 1); DRG_show_colors[4] = get_int ("DRG_SHOW_COLORS_4", 0, 1, 1); DRG_show_colors[5] = get_int ("DRG_SHOW_COLORS_5", 0, 1, 1); DRG_show_colors[6] = get_int ("DRG_SHOW_COLORS_6", 0, 1, 1); DRG_show_colors[7] = get_int ("DRG_SHOW_COLORS_7", 0, 1, 1); DRG_show_colors[8] = get_int ("DRG_SHOW_COLORS_8", 0, 1, 1); DRG_show_colors[9] = get_int ("DRG_SHOW_COLORS_9", 0, 1, 1); DRG_show_colors[10] = get_int ("DRG_SHOW_COLORS_10", 0, 1, 1); DRG_show_colors[11] = get_int ("DRG_SHOW_COLORS_11", 0, 1, 1); DRG_show_colors[12] = get_int ("DRG_SHOW_COLORS_12", 0, 1, 1); #endif // HAVE_LIBGEOTIFF // filter values // NOT SAVED: Select_.none Select_.mine = get_int ("DISPLAY_MY_STATION", 0, 1, 1); Select_.tnc = get_int ("DISPLAY_TNC_STATIONS", 0, 1, 1); Select_.direct = get_int ("DISPLAY_TNC_DIRECT_STATIONS", 0, 1, 1); Select_.via_digi = get_int ("DISPLAY_TNC_VIADIGI_STATIONS", 0, 1, 1); Select_.net = get_int ("DISPLAY_NET_STATIONS", 0, 1, 1); Select_.tactical = get_int ("DISPLAY_TACTICAL_STATIONS", 0, 1, 0); Select_.old_data = get_int ("DISPLAY_OLD_STATION_DATA", 0, 1, 0); Select_.stations = get_int ("DISPLAY_STATIONS", 0, 1, 1); Select_.fixed_stations = get_int ("DISPLAY_FIXED_STATIONS", 0, 1, 1); Select_.moving_stations = get_int ("DISPLAY_MOVING_STATIONS", 0, 1, 1); Select_.weather_stations = get_int ("DISPLAY_WEATHER_STATIONS", 0, 1, 1); Select_.CWOP_wx_stations = get_int ("DISPLAY_CWOP_WX_STATIONS", 0, 1, 1); Select_.objects = get_int ("DISPLAY_OBJECTS", 0, 1, 1); Select_.weather_objects = get_int ("DISPLAY_STATION_WX_OBJ", 0, 1, 1); Select_.gauge_objects = get_int ("DISPLAY_WATER_GAGE_OBJ", 0, 1, 1); Select_.other_objects = get_int ("DISPLAY_OTHER_OBJECTS", 0, 1, 1); Select_.aircraft_objects = get_int ("DISPLAY_AIRCRAFT_OBJECTS", 0, 1, 1); Select_.vessel_objects = get_int ("DISPLAY_VESSEL_OBJECTS", 0, 1, 1); // display values Display_.callsign = get_int ("DISPLAY_CALLSIGN", 0, 1, 1); Display_.label_all_trackpoints = get_int ("DISPLAY_LABEL_ALL_TRACKPOINTS", 0, 1, 0); Display_.symbol = get_int ("DISPLAY_SYMBOL", 0, 1, 1); Display_.symbol_rotate = get_int ("DISPLAY_SYMBOL_ROTATE", 0, 1, 1); Display_.phg = get_int ("DISPLAY_STATION_PHG", 0, 1, 0); Display_.default_phg = get_int ("DISPLAY_DEFAULT_PHG", 0, 1, 0); Display_.phg_of_moving = get_int ("DISPLAY_MOBILES_PHG", 0, 1, 0); Display_.altitude = get_int ("DISPLAY_ALTITUDE", 0, 1, 0); Display_.course = get_int ("DISPLAY_COURSE", 0, 1, 0); Display_.speed = get_int ("DISPLAY_SPEED", 0, 1, 1); Display_.speed_short = get_int ("DISPLAY_SPEED_SHORT", 0, 1, 0); Display_.dist_bearing = get_int ("DISPLAY_DIST_COURSE", 0, 1, 0); Display_.weather = get_int ("DISPLAY_WEATHER", 0, 1, 1); Display_.weather_text = get_int ("DISPLAY_STATION_WX", 0, 1, 1); Display_.temperature_only = get_int ("DISPLAY_TEMP_ONLY", 0, 1, 0); Display_.wind_barb = get_int ("DISPLAY_WIND_BARB", 0, 1, 1); Display_.trail = get_int ("DISPLAY_STATION_TRAILS", 0, 1, 1); Display_.last_heard = get_int ("DISPLAY_LAST_HEARD", 0, 1, 0); Display_.ambiguity = get_int ("DISPLAY_POSITION_AMB", 0, 1, 1); Display_.df_data = get_int ("DISPLAY_DF_INFO", 0, 1, 1); Display_.df_beamwidth_data = get_int ("DISPLAY_DF_BEAMWIDTH_INFO", 0, 1, 1); Display_.df_bearing_data = get_int ("DISPLAY_DF_BEARING_INFO", 0, 1, 0); Display_.dr_data = get_int ("DISPLAY_DEAD_RECKONING_INFO", 0, 1, 1); Display_.dr_arc = get_int ("DISPLAY_DEAD_RECKONING_ARC", 0, 1, 1); Display_.dr_course = get_int ("DISPLAY_DEAD_RECKONING_COURSE", 0, 1, 1); Display_.dr_symbol = get_int ("DISPLAY_DEAD_RECKONING_SYMBOL", 0, 1, 1); english_units = get_int ("DISPLAY_UNITS_ENGLISH", 0, 1, 0); do_dbstatus = get_int ("DISPLAY_DIST_BEAR_STATUS", 0, 1, 0); CAD_show_label = get_int ("DISPLAY_CAD_OBJECT_LABEL", 0, 1, 1); CAD_show_raw_probability = get_int ("DISPLAY_CAD_OBJECT_PROBABILITY", 0, 1, 1 ); CAD_show_comment = get_int ("DISPLAY_CAD_OBJECT_COMMENT", 0, 1, 1 ); CAD_show_area = get_int ("DISPLAY_CAD_OBJECT_AREA", 0, 1, 1 ); transmit_disable = get_int ("DISABLE_TRANSMIT", 0, 1, 0); posit_tx_disable = get_int ("DISABLE_POSIT_TX", 0, 1, 0); object_tx_disable = get_int ("DISABLE_OBJECT_TX", 0, 1, 0); enable_server_port = get_int ("ENABLE_SERVER_PORT", 0, 1, 0); for (i = 0; i < MAX_IFACE_DEVICES; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "DEVICE%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TYPE", sizeof(name) - 1 - strlen(name)); devices[i].device_type = get_int (name, 0,MAX_IFACE_DEVICE_TYPES,DEVICE_NONE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "NAME", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_name, sizeof(devices[i].device_name))) { devices[i].device_name[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RADIO_PORT", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].radio_port, sizeof(devices[i].radio_port))) xastir_snprintf(devices[i].radio_port, sizeof(devices[i].radio_port), "0"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "CONVERSE_CMD", sizeof(name) - 1 - strlen(name)); if (!get_string (name, devices[i].device_converse_string, sizeof(devices[i].device_converse_string)) || (strlen(devices[i].device_converse_string) == 0)) xastir_snprintf(devices[i].device_converse_string, sizeof(devices[i].device_converse_string), "k"); #ifdef HAVE_DB xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_TYPE", sizeof(name) - 1 - strlen(name)); devices[i].database_type = get_int (name, 0,MAX_DB_TYPE,MAX_DB_TYPE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA_TYPE", sizeof(name) - 1 - strlen(name)); devices[i].database_schema_type = get_int (name, 0,MAX_XASTIR_SCHEMA,XASTIR_SCHEMA_SIMPLE); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_USERNAME", sizeof(name) - 1 - strlen(name)); // default to xastir if (!get_string (name, devices[i].database_username, sizeof(devices[i].database_username))) xastir_snprintf(devices[i].database_username, sizeof(devices[i].database_username), "xastir"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_SCHEMA", sizeof(name) - 1 - strlen(name)); // default to xastir if (!get_string (name, devices[i].database_schema, sizeof(devices[i].database_schema))) xastir_snprintf(devices[i].database_schema, sizeof(devices[i].database_schema), "xastir"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "DATABASE_UNIX_SOCKET", sizeof(name) - 1 - strlen(name)); // empty string is ok here if (!get_string (name, devices[i].database_unix_socket, sizeof(devices[i].database_unix_socket))) xastir_snprintf(devices[i].database_unix_socket, sizeof(devices[i].database_unix_socket), "0"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "QUERY_ON_STARTUP", sizeof(name) - 1 - strlen(name)); devices[i].query_on_startup = get_int (name, 0,1,0); #endif /* HAVE_DB */ xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "INTERFACE_COMMENT", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].comment, sizeof(devices[i].comment))) { devices[i].comment[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "HOST", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_name, sizeof(devices[i].device_host_name))) { devices[i].device_host_name[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "PASSWD", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_pswd, sizeof(devices[i].device_host_pswd))) { devices[i].device_host_pswd[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "FILTER_PARAMS", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].device_host_filter_string, sizeof(devices[i].device_host_filter_string))) { devices[i].device_host_filter_string[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO1", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto1, sizeof(devices[i].unproto1))) { devices[i].unproto1[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO2", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto2, sizeof(devices[i].unproto2))) { devices[i].unproto2[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO3", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto3, sizeof(devices[i].unproto3))) { devices[i].unproto3[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "UNPROTO_IGATE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].unproto_igate, sizeof(devices[i].unproto_igate)) || devices[i].unproto_igate[0] == '\0') { xastir_snprintf(devices[i].unproto_igate, sizeof(devices[i].unproto_igate), "WIDE2-1"); } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_UP_FILE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].tnc_up_file, sizeof(devices[i].tnc_up_file))) { devices[i].tnc_up_file[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_DOWN_FILE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].tnc_down_file, sizeof(devices[i].tnc_down_file))) { devices[i].tnc_down_file[0] = '\0'; } xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXDELAY", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].txdelay, sizeof(devices[i].txdelay))) xastir_snprintf(devices[i].txdelay, sizeof(devices[i].txdelay), "40"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_PERSISTENCE", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].persistence, sizeof(devices[i].persistence))) xastir_snprintf(devices[i].persistence, sizeof(devices[i].persistence), "63"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_SLOTTIME", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].slottime, sizeof(devices[i].slottime))) xastir_snprintf(devices[i].slottime, sizeof(devices[i].slottime), "10"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_TXTAIL", sizeof(name) - 1 - strlen(name)); // Empty string is ok here. if (!get_string (name, devices[i].txtail, sizeof(devices[i].txtail))) xastir_snprintf(devices[i].txtail, sizeof(devices[i].txtail), "30"); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_FULLDUPLEX", sizeof(name) - 1 - strlen(name)); devices[i].fullduplex = get_int (name, 0, 1, 0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNC_INIT_KISSMODE", sizeof(name) - 1 - strlen(name)); devices[i].init_kiss = get_int (name, 0, 1, 0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SPEED", sizeof(name) - 1 - strlen(name)); devices[i].sp = get_int (name, 0,230400,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "STYLE", sizeof(name) - 1 - strlen(name)); devices[i].style = get_int (name, 0,2,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "IGATE_OPTION", sizeof(name) - 1 - strlen(name)); devices[i].igate_options = get_int (name, 0,2,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TXMT", sizeof(name) - 1 - strlen(name)); devices[i].transmit_data = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RELAY_DIGIPEAT", sizeof(name) - 1 - strlen(name)); devices[i].relay_digipeat = get_int (name, 0,1,1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "RECONN", sizeof(name) - 1 - strlen(name)); devices[i].reconnect = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "ONSTARTUP", sizeof(name) - 1 - strlen(name)); devices[i].connect_on_startup = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "GPSRETR", sizeof(name) - 1 - strlen(name)); devices[i].gps_retrieve = get_int (name, 0,255,DEFAULT_GPS_RETR); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "SETTIME", sizeof(name) - 1 - strlen(name)); devices[i].set_time = get_int (name, 0,1,0); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "TNCEXTRADELAY", sizeof(name) - 1 - strlen(name)); devices[i].tnc_extra_delay = get_int (name, 0,9999999,0); } /* TNC */ log_tnc_data = get_int ("TNC_LOG_DATA", 0,1,0); if (!get_string ("LOGFILE_TNC", LOGFILE_TNC, sizeof(LOGFILE_TNC)) || LOGFILE_TNC[0] == '\0') { xastir_snprintf(LOGFILE_TNC, sizeof(LOGFILE_TNC), "%s", "logs/tnc.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_TNC, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_TNC, sizeof(LOGFILE_TNC), "%s", "logs/tnc.log"); /* NET */ log_net_data = get_int ("NET_LOG_DATA", 0,1,0); operate_as_an_igate = get_int ("NET_RUN_AS_IGATE", 0,2,0); log_igate = get_int ("LOG_IGATE", 0,1,0); NETWORK_WAITTIME = get_int ("NETWORK_WAITTIME", 10,120,10); // LOGGING log_wx = get_int ("LOG_WX", 0,1,0); log_message_data = get_int ("LOG_MESSAGE", 0, 1, 0); log_wx_alert_data = get_int ("LOG_WX_ALERT", 0, 1, 0); if (!get_string ("LOGFILE_IGATE", LOGFILE_IGATE, sizeof(LOGFILE_IGATE)) || LOGFILE_IGATE[0] == '\0') { xastir_snprintf(LOGFILE_IGATE, sizeof(LOGFILE_IGATE), "%s", "logs/igate.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_IGATE, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_IGATE, sizeof(LOGFILE_IGATE), "%s", "logs/igate.log"); if (!get_string ("LOGFILE_NET", LOGFILE_NET, sizeof(LOGFILE_NET)) || LOGFILE_NET[0] == '\0') { xastir_snprintf(LOGFILE_NET, sizeof(LOGFILE_NET), "%s", "logs/net.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_NET, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_NET, sizeof(LOGFILE_NET), "%s", "logs/net.log"); if (!get_string ("LOGFILE_WX", LOGFILE_WX, sizeof(LOGFILE_WX)) || LOGFILE_WX[0] == '\0') { xastir_snprintf(LOGFILE_WX, sizeof(LOGFILE_WX), "%s", "logs/wx.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_WX, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_WX, sizeof(LOGFILE_WX), "%s", "logs/wx.log"); if (!get_string ("LOGFILE_MESSAGE", LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE)) || LOGFILE_MESSAGE[0] == '\0') { xastir_snprintf(LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE), "%s", "logs/message.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_MESSAGE, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_MESSAGE, sizeof(LOGFILE_MESSAGE), "%s", "logs/message.log"); if (!get_string ("LOGFILE_WX_ALERT", LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT)) || LOGFILE_WX_ALERT[0] == '\0') { xastir_snprintf(LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT), "%s", "logs/wx_alert.log"); } // Check for old complete path, change to new short path if a // match if (strncmp( user_base_dir, LOGFILE_WX_ALERT, strlen(user_base_dir)) == 0) xastir_snprintf(LOGFILE_WX_ALERT, sizeof(LOGFILE_WX_ALERT), "%s", "logs/wx_alert.log"); // SNAPSHOTS snapshots_enabled = get_int ("SNAPSHOTS_ENABLED", 0,1,0); // KML SNAPSHOTS kmlsnapshots_enabled = get_int ("KMLSNAPSHOTS_ENABLED", 0,1,0); /* WX ALERTS */ WX_ALERTS_REFRESH_TIME = (time_t) get_long ("WX_ALERTS_REFRESH_TIME", 10l, 86400l, 60l); /* gps */ gps_time = (time_t) get_long ("GPS_TIME", 1l, 86400l, 60l); /* POSIT RATE */ POSIT_rate = (time_t) get_long ("POSIT_RATE", 0l, 86400l, 30*60l); /* OBJECT RATE */ OBJECT_rate = (time_t) get_long ("OBJECT_RATE", 1l, 86400l, 30*60l); /* UPDATE DR RATE */ update_DR_rate = (time_t) get_long ("UPDATE_DR_RATE", 1l, 86400l, 30l); /* station broadcast type */ output_station_type = get_int ("BST_TYPE", 0,5,0); #ifdef TRANSMIT_RAW_WX /* raw wx transmit */ transmit_raw_wx = get_int ("BST_WX_RAW", 0,1,0); #endif // TRANSMIT_RAW_WX /* compressed posit transmit */ transmit_compressed_posit = get_int ("BST_COMPRESSED_POSIT", 0,1,0); /* compressed objects/items transmit */ transmit_compressed_objects_items = get_int ("COMPRESSED_OBJECTS_ITEMS", 0,1,0); smart_beaconing = get_int ("SMART_BEACONING", 0,1,1); sb_turn_min = get_int ("SB_TURN_MIN", 1,360,20); sb_turn_slope = get_int ("SB_TURN_SLOPE", 0,360,25); sb_turn_time = get_int ("SB_TURN_TIME", 0,3600,5); sb_posit_fast = get_int ("SB_POSIT_FAST", 1,1440,60); sb_posit_slow = get_int ("SB_POSIT_SLOW", 1,1440,30); sb_low_speed_limit = get_int ("SB_LOW_SPEED_LIMIT", 0,999,2); sb_high_speed_limit = get_int ("SB_HIGH_SPEED_LIMIT", 0,999,60); pop_up_new_bulletins = get_int ("POP_UP_NEW_BULLETINS", 0,1,1); view_zero_distance_bulletins = get_int ("VIEW_ZERO_DISTANCE_BULLETINS", 0,1,1); warn_about_mouse_modifiers = get_int ("WARN_ABOUT_MOUSE_MODIFIERS", 0,1,1); /* Audio Alarms*/ // Empty string is ok here. if (!get_string ("SOUND_COMMAND", sound_command, sizeof(sound_command))) xastir_snprintf(sound_command, sizeof(sound_command), "play"); sound_play_new_station = get_int ("SOUND_PLAY_ONS", 0,1,0); if (!get_string ("SOUND_ONS_FILE", sound_new_station, sizeof(sound_new_station)) || sound_new_station[0] == '\0') { xastir_snprintf(sound_new_station, sizeof(sound_new_station), "newstation.wav"); } sound_play_new_message = get_int ("SOUND_PLAY_ONM", 0,1,0); if (!get_string ("SOUND_ONM_FILE", sound_new_message, sizeof(sound_new_message)) || sound_new_message[0] == '\0') { xastir_snprintf(sound_new_message, sizeof(sound_new_message), "newmessage.wav"); } sound_play_prox_message = get_int ("SOUND_PLAY_PROX", 0,1,0); if (!get_string ("SOUND_PROX_FILE", sound_prox_message, sizeof(sound_prox_message)) || sound_prox_message[0] == '\0') { xastir_snprintf(sound_prox_message, sizeof(sound_prox_message), "proxwarn.wav"); } if (!get_string ("PROX_MIN", prox_min, sizeof(prox_min)) || prox_min[0] == '\0') { xastir_snprintf(prox_min, sizeof(prox_min), "0.01"); } if (!get_string ("PROX_MAX", prox_max, sizeof(prox_max)) || prox_max[0] == '\0') { xastir_snprintf(prox_max, sizeof(prox_max), "10"); } sound_play_band_open_message = get_int ("SOUND_PLAY_BAND", 0,1,0); if (!get_string ("SOUND_BAND_FILE", sound_band_open_message, sizeof(sound_band_open_message)) || sound_band_open_message[0] == '\0') { xastir_snprintf(sound_band_open_message, sizeof(sound_band_open_message), "bandopen.wav"); } if (!get_string ("BANDO_MIN", bando_min, sizeof(bando_min)) || bando_min[0] == '\0') { xastir_snprintf(bando_min, sizeof(bando_min), "200"); } if (!get_string ("BANDO_MAX", bando_max, sizeof(bando_max)) || bando_max[0] == '\0') { xastir_snprintf(bando_max, sizeof(bando_max), "2000"); } sound_play_wx_alert_message = get_int ("SOUND_PLAY_WX_ALERT", 0,1,0); if (!get_string ("SOUND_WX_ALERT_FILE", sound_wx_alert_message, sizeof(sound_wx_alert_message)) || sound_wx_alert_message[0] == '\0') { xastir_snprintf(sound_wx_alert_message, sizeof(sound_wx_alert_message), "thunder.wav"); } #ifdef HAVE_FESTIVAL /* Festival Speech defaults */ festival_speak_new_station = get_int ("SPEAK_NEW_STATION",0,1,0); festival_speak_proximity_alert = get_int ("SPEAK_PROXIMITY_ALERT",0,1,0); festival_speak_tracked_proximity_alert = get_int ("SPEAK_TRACKED_ALERT",0,1,0); festival_speak_band_opening = get_int ("SPEAK_BAND_OPENING",0,1,0); festival_speak_new_message_alert = get_int ("SPEAK_MESSAGE_ALERT",0,1,0); festival_speak_new_message_body = get_int ("SPEAK_MESSAGE_BODY",0,1,0); festival_speak_new_weather_alert = get_int ("SPEAK_WEATHER_ALERT",0,1,0); festival_speak_ID = get_int ("SPEAK_ID",0,1,0); #endif // HAVE_FESTIVAL ATV_screen_ID = get_int ("ATV_SCREEN_ID",0,1,0); /* defaults */ sec_old = (time_t) get_long ("DEFAULT_STATION_OLD", 1l, 604800l, 4800l); sec_clear = (time_t) get_long ("DEFAULT_STATION_CLEAR", 1l, 604800l, 43200l); aircraft_sec_clear = (time_t) get_long ("DEFAULT_AIRCRAFT_CLEAR", 0l, 604800l, 0l); sec_remove = get_long("DEFAULT_STATION_REMOVE", 1l, 604800*2, sec_clear*2); if (!get_string ("MESSAGE_COUNTER", message_counter, sizeof(message_counter)) || message_counter[0] == '\0') { xastir_snprintf(message_counter, sizeof(message_counter), "00"); } message_counter[2] = '\0'; // Terminate at 2 chars // Check that chars are within the correct ranges if ( (message_counter[0] < '0') || (message_counter[1] < '0') || ( (message_counter[0] > '9') && (message_counter[0] < 'A') ) || ( (message_counter[1] > '9') && (message_counter[1] < 'A') ) || ( (message_counter[0] > 'Z') && (message_counter[0] < 'a') ) || ( (message_counter[1] > 'Z') && (message_counter[1] < 'a') ) || (message_counter[0] > 'z') || (message_counter[1] > 'z') ) { message_counter[0] = '0'; message_counter[1] = '0'; } if (!get_string ("AUTO_MSG_REPLY", auto_reply_message, sizeof(auto_reply_message)) || auto_reply_message[0] == '\0') { xastir_snprintf(auto_reply_message, sizeof(auto_reply_message), "Autoreply- No one is at the keyboard"); } Display_packet_data_type = get_int ("DISPLAY_PACKET_TYPE", 0,2,0); bulletin_range = get_int ("BULLETIN_RANGE", 0,99999,0); vm_range = get_int("VIEW_MESSAGE_RANGE", 0,99999,0); view_message_limit = get_int("VIEW_MESSAGE_LIMIT", 10000,99999,10000); predefined_menu_from_file = get_int("PREDEF_MENU_LOAD",0,1,0); if (!get_string ("PREDEF_MENU_FILE", predefined_object_definition_filename, sizeof(predefined_object_definition_filename)) || predefined_object_definition_filename[0] == '\0') { xastir_snprintf(predefined_object_definition_filename, sizeof(predefined_object_definition_filename), "predefined_SAR.sys"); } Read_messages_packet_data_type = get_int ("READ_MESSAGES_PACKET_DATA_TYPE", 0,2,0); Read_messages_mine_only = get_int ("READ_MESSAGES_MINE_ONLY", 0,1,0); /* printer variables */ print_rotated = get_int ("PRINT_ROTATED", 0,1,0); print_auto_rotation = get_int ("PRINT_AUTO_ROTATION", 0,1,1); print_auto_scale = get_int ("PRINT_AUTO_SCALE", 0,1,1); print_in_monochrome = get_int ("PRINT_IN_MONOCHROME", 0,1,0); print_invert = get_int ("PRINT_INVERT_COLORS", 0,1,0); // 0 = no correction WX_rain_gauge_type = get_int ("RAIN_GAUGE_TYPE", 0,3,0); /* list attributes */ for (i = 0; i < LST_NUM; i++) { xastir_snprintf (name_temp, sizeof(name_temp), "LIST%0d_", i); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "H", sizeof(name) - 1 - strlen(name)); list_size_h[i] = get_int (name, -1,8192,-1); xastir_snprintf(name, sizeof(name), "%s", name_temp); strncat (name, "W", sizeof(name) - 1 - strlen(name)); list_size_w[i] = get_int (name, -1,8192,-1); } // 0 = no tracking track_me = get_int ("TRACK_ME", 0,1,0); // store_string (fout, "TRACKING_STATION_CALLSIGN", tracking_station_call); if (!get_string ("TRACKING_STATION_CALLSIGN", tracking_station_call, sizeof(tracking_station_call))) { tracking_station_call[0] = '\0'; } map_chooser_expand_dirs = get_int ("MAP_CHOOSER_EXPAND_DIRS", 0,1,1); // One hour default st_direct_timeout = get_int ("ST_DIRECT_TIMEOUT", 1,60*60*24*30,60*60); // Ten minute default dead_reckoning_timeout = get_int ("DEAD_RECKONING_TIMEOUT", 1,60*60*24*30,60*10); // 1ms default serial_char_pacing = get_int ("SERIAL_CHAR_PACING", 0,50,1); // 45 minutes default, 12 hours max trail_segment_time = get_int ("TRAIL_SEGMENT_TIME", 0,12*60,45); // 1 degree default trail_segment_distance = get_int ("TRAIL_SEGMENT_DISTANCE", 0,45,1); // 0 minutes default (function disabled) RINO_download_interval = get_int ("RINO_DOWNLOAD_INTERVAL", 0,30,0); // 5 minutes default snapshot_interval = get_int ("SNAPSHOT_INTERVAL", 1,30,5); input_close(); } Xastir-Release-2.2.4/src/xa_config.h0000664000175000017500000000244015151324131016216 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #define MAX_VALUE 300 #define DEFAULT_STARTUP_SCREEN_WIDTH 590l #define DEFAULT_STARTUP_SCREEN_HEIGHT 420l extern time_t next_time; char *get_user_base_dir(char *dir, char *dest, size_t dest_size); char *get_data_base_dir(char *dir); void save_data(void); void load_data_or_default(void); extern char xa_config_dir[1000]; /* cmdline option user config dir */ Xastir-Release-2.2.4/src/xastir.h0000664000175000017500000001474015151324131015601 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 1999,2000 Frank Giannandrea * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* All of the misc entry points to be included for all packages */ #ifndef _XASTIR_H #define _XASTIR_H // Macros that help us avoid warnings on 64-bit CPU's. // Borrowed from the freeciv project (also a GPL project). #define INT_TO_XTPOINTER(m_i) ((XtPointer)((long)(m_i))) #define XTPOINTER_TO_INT(m_p) ((int)((long)(m_p))) // Defines we can use to mark functions and parameters as "unused" to the compiler #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif #define SERIAL_KISS_RELAY_DIGI #include //#include "database.h" #include "util.h" #include "messages.h" #include "fcc_data.h" #include "rac_data.h" #define MAX_CALLSIGN 9 // Objects are up to 9 chars // black #define MY_FG_COLOR colors[0x08] #define MY_FOREGROUND_COLOR XmNforeground,colors[0x08] // gray73 #define MY_BG_COLOR colors[0xff] #define MY_BACKGROUND_COLOR XmNbackground,colors[0xff] #ifndef M_PI /* if not defined in math.h */ #define M_PI 3.14159265358979323846 #endif // M_PI /* GLOBAL DEFINES */ extern char dangerous_operation[200]; extern GC gc; extern Pixmap pixmap; extern Pixmap pixmap_final; extern Pixmap pixmap_alerts; extern Pixmap pixmap_50pct_stipple; extern Pixmap pixmap_25pct_stipple; extern Pixmap pixmap_13pct_stipple; extern Pixmap pixmap_wx_stipple; extern Widget appshell; extern int wait_to_redraw; void resize_dialog( Widget form, Widget dialog); extern int debug_level; extern GC gc; extern Pixel colors[]; extern float f_center_longitude; // Floating point map center longitude extern float f_center_latitude; // Floating point map center latitude extern float f_NW_corner_longitude;// longitude of NW corner extern float f_NW_corner_latitude; // latitude of NW corner extern float f_SE_corner_longitude;// longitude of SE corner extern float f_SE_corner_latitude; // latitude of SE corner extern long center_longitude; // Longitude at center of map extern long center_latitude; // Latitude at center of map extern long NW_corner_longitude; // longitude of NW corner extern long NW_corner_latitude; // latitude of NW corner extern long SE_corner_longitude; // longitude of SE corner extern long SE_corner_latitude; // latitude of SE corner extern long scale_x; // x scaling in 1/100 sec per pixel extern long scale_y; // y scaling in 1/100 sec per pixel extern long screen_width; extern long screen_height; extern Position screen_x_offset; extern Position screen_y_offset; extern int long_lat_grid; //extern Pixmap pixmap; //extern Pixmap pixmap_final; //extern Pixmap pixmap_alerts; extern int map_color_levels; extern int map_labels; extern int map_lock_pan_zoom; extern int map_auto_maps; extern int auto_maps_skip_raster; extern time_t sec_remove; extern Widget da; extern Widget text; extern XtAppContext app_context; extern int redraw_on_new_data; //extern Widget hidden_shell; extern int index_maps_on_startup; #define MAX_LABEL_FONTNAME 256 #define FONT_SYSTEM 0 #define FONT_STATION 1 #define FONT_TINY 2 #define FONT_SMALL 3 #define FONT_MEDIUM 4 #define FONT_LARGE 5 #define FONT_HUGE 6 #define FONT_BORDER 7 #define FONT_ATV_ID 8 #define FONT_MAX 9 #define FONT_DEFAULT FONT_MEDIUM #define MAX_FONTNAME 256 extern char rotated_label_fontname[FONT_MAX][MAX_LABEL_FONTNAME]; #ifdef HAVE_LIBGEOTIFF extern int DRG_XOR_colors; extern int DRG_show_colors[13]; #endif // HAVE_LIBGEOTIFF extern int net_map_timeout; extern void sort_list(char *filename,int size, Widget list, int *item); extern void redraw_symbols(Widget w); extern Colormap cmap; /* from messages.c */ extern char message_counter[5+1]; extern int auto_reply; extern char auto_reply_message[100]; extern int satellite_ack_mode; extern void clear_outgoing_messages(void); extern void reset_outgoing_messages(void); extern void output_message(char *from, char *to, char *message, char *path); extern void check_and_transmit_messages(time_t time); extern Message_Window mw[MAX_MESSAGE_WINDOWS+1]; extern void clear_message_windows(void); /* from lang.c */ extern int load_language_file(char *filename); extern char *langcode(char *code); extern char langcode_hotkey(char *code); /* from location.c */ extern void set_last_position(void); extern void map_pos_last_position(void); /* from location_gui.c */ extern char locate_station_call[30]; extern void Last_location(Widget w, XtPointer clientData, XtPointer callData); extern void Jump_location(Widget w, XtPointer clientData, XtPointer callData); extern void map_pos(long mid_y, long mid_x, long sz); extern char locate_gnis_filename[200]; // This needs to be quite long for some of the weather station // serial data to get through ok (Peet Bros U2k Complete Record Mode // for one). #define MAX_LINE_SIZE 512 // from main.c extern char gprmc_save_string[MAX_LINE_SIZE+1]; extern char gpgga_save_string[MAX_LINE_SIZE+1]; extern int gps_port_save; // from map.c extern double calc_dscale_x(long x, long y); /* from popup_gui.c */ extern void popup_message_always(char *banner, char *message); extern void popup_message(char *banner, char *message); extern void popup_ID_message(char *banner, char *message); /* from view_messages.c */ extern void all_messages(char from, char *call_sign, char *from_call, char *message); extern void view_all_messages(Widget w, XtPointer clientData, XtPointer callData); #endif /* XASTIR_H */ Xastir-Release-2.2.4/src/xastir_udp_client.c0000664000175000017500000001525215151324131020001 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2000-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include // Moved ahead of inet.h as reports of some *BSD's not // including this as they should. #include //#include // Needed for TCP_NODELAY setsockopt() (disabling Nagle algorithm) #include #include #include #include #include #include "xastir.h" // Must be last include file #include "leak_detection.h" // Atttempt to send to one of the addresses, waiting for 10 seconds // for (hopefully) a response. Returns 1 on success or 0 if we didn't // get a response. (Any response is considered a success) int try_exchange(struct addrinfo *addr, char *buffer, int UNUSED(buflen) ) { int sockfd, n; socklen_t length; struct sockaddr_storage from; struct pollfd polls; sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sockfd < 0) { fprintf(stderr, "socket error: %s\n", strerror(errno)); return(0); } n = sendto(sockfd, buffer, (size_t)strlen(buffer), 0, addr->ai_addr, addr->ai_addrlen); if (n < 0) { fprintf(stderr, "Sendto error %s\n", strerror(errno)); close(sockfd); return(0); } polls.fd = sockfd; polls.events = POLLIN; // wait for up to 10 seconds for a response. n = poll(&polls, 1, 10 * 1000); if(n == 0) { fprintf(stderr, "Timeout waiting for response\n"); close(sockfd); return 0; } else if (n < 0 ) { fprintf(stderr, "poll() returned an error: %s\n", strerror(errno)); close(sockfd); return 0; } // Response should be waiting, get it. length = sizeof(from); n = recvfrom(sockfd, buffer, 256, 0, (struct sockaddr *)&from, &length); if (n < 0) { fprintf(stderr, "recvfrom: %s\n", strerror(errno)); close(sockfd); return(0); } close(sockfd); return 1; } // Loop through the possible addresses for hostname (probably IPv6 and IPv4) // Tries until we are successful (get a response) or we run out of addresses int exchange_packet(char *hostname, char *port, char *buffer, int buflen) { struct addrinfo hints, *res, *r; int error; int success = 0; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = (AI_V4MAPPED|AI_ADDRCONFIG); error = getaddrinfo(hostname, port, &hints, &res); if (error) { fprintf(stderr, "Error: Unable to lookup addresses for host %s port %s\n", hostname, port); fprintf(stderr, "Getaddrinfo returned error: %s\n",gai_strerror(error)); return 1; } r = res; while(!success && r) { success = try_exchange(r, buffer, buflen); r = r->ai_next; if(!success && r) { fprintf(stderr, "Trying next address to send to\n"); } } freeaddrinfo(res); return success; } // Send a UDP packet to a UDP listening port. This allows scripts // and other programs to inject packets into Xastir via UDP // protocol. // Inputs: // hostname (argv[1]) // port (argv[2]) // callsign (argv[3]) // passcode (argv[4]) // optional flags: -identify // -to_rf // -to_inet // APRS Packet (argv[5]) // Returns: // 0: Message sent, ack received // 1: Error condition // // // int main(int argc, char *argv[]) { char buffer[512]; char callsign[10]; char extra[100]; int passcode; char message[256]; int ii, success; if (argc < 6) { fprintf(stderr, "\nUsage: xastir_udp_client server port call passcode -identify\n"); fprintf(stderr, " xastir_udp_client server port call passcode [-to_rf] [-to_inet] \"APRS Packet\"\n"); fprintf(stderr, "\nExample: xastir_udp_client localhost 2023 ab7cd 1234 \"APRS packet goes here\"\n"); return(1); } // Fetch the callsign snprintf(callsign, sizeof(callsign), "%s", argv[3]); callsign[sizeof(callsign)-1] = '\0'; // Terminate it // Fetch the passcode passcode = atoi(argv[4]); // Check for optional flags here: // -identify // -to_rf // -to_inet // extra[0] = '\0'; for (ii = 5; ii < argc; ii++) { if (strstr(argv[ii], "-identify")) { //fprintf(stderr,"Found -identify\n"); strncat(extra, ",-identify", sizeof(extra)-strlen(extra)-1); } else if (strstr(argv[ii], "-to_rf")) { //fprintf(stderr,"Found -to_rf\n"); strncat(extra, ",-to_rf", sizeof(extra)-strlen(extra)-1); } else if (strstr(argv[ii], "-to_inet")) { //fprintf(stderr,"Found -to_inet\n"); strncat(extra, ",-to_inet", sizeof(extra)-strlen(extra)-1); } } // fprintf(stdout, "Please enter the message: "); // Fetch message portion from the end of the command-line snprintf(message, sizeof(message), "%s", argv[argc-1]); message[sizeof(message)-1] = '\0'; // Terminate it if (message[0] == '\0') // Empty message { return(1); } memset(buffer, 0, 256); // fgets(buffer, 255, stdin); snprintf(buffer, sizeof(buffer), "%s,%d%s\n%s\n", callsign, passcode, extra, message); //fprintf(stderr, "%s", buffer); success = exchange_packet(argv[1], argv[2], buffer, 256); if(!success) { fprintf(stdout, "No response received.\n"); return(1); } fprintf(stdout,"Received: %s\n", buffer); if (strncmp(buffer, "NACK", 4) == 0) { //fprintf(stderr,"returning 1\n"); return(1); // Received a NACK } else if (strncmp(buffer, "ACK", 3) == 0) { //fprintf(stderr,"returning 0\n"); return(0); // Received an ACK } else { //fprintf(stderr,"returning 1\n"); return(1); // Received something other than ACK or NACK } } Xastir-Release-2.2.4/stamp-h.in0000664000175000017500000000001215151324131015213 0ustar hibbyhibbytimestamp Xastir-Release-2.2.4/symbols/0000775000175000017500000000000015151324131015011 5ustar hibbyhibbyXastir-Release-2.2.4/symbols/.vimrc0000664000175000017500000000143315151324131016133 0ustar hibbyhibby" " Per-project .vimrc file: Configures Vim per Xastir project standards. " " Add these two files to the end of your ~/.vimrc file: " " set exrc " set secure " " Set compatibility to Vim only set nocompatible " Turn on syntax highlighting syntax on " Tab equals 2 columns set tabstop=2 set softtabstop=2 " Insert spaces instead of tab characters set expandtab " Control how many columns text is indented with the reindent " operations (<< and >>) and automatic C-style indentation. set shiftwidth=2 " When off, a always inserts blanks according to 'tabstop' or " 'softtabstop'. 'shiftwidth' is only used for shifting text left or " right |shift-left-right|. set nosmarttab " Display different types of white spaces. "set list "set listchars=tab:#\ ,trail:#,extends:#,nbsp:. Xastir-Release-2.2.4/symbols/13pct.xbm0000664000175000017500000000021415151324131016450 0ustar hibbyhibby/* Created with The GIMP */ #define 13pct_width 4 #define 13pct_height 4 static unsigned char 13pct_bits[] = { 0x01, 0x00, 0x04, 0x00 }; Xastir-Release-2.2.4/symbols/25pct.xbm0000664000175000017500000000021415151324131016453 0ustar hibbyhibby/* Created with The GIMP */ #define 25pct_width 4 #define 25pct_height 4 static unsigned char 25pct_bits[] = { 0x01, 0x04, 0x01, 0x04 }; Xastir-Release-2.2.4/symbols/2x2.xbm0000664000175000017500000000017215151324131016134 0ustar hibbyhibby/* Created with The GIMP */ #define 2x2_width 2 #define 2x2_height 2 static unsigned char 2x2_bits[] = { 0x01, 0x02 }; Xastir-Release-2.2.4/symbols/Makefile.am0000664000175000017500000000066015151324131017047 0ustar hibbyhibby# # Copyright (C) 2000-2026 The Xastir Group # symbolsdir=${pkgdatadir}/symbols EXTRA_DIST=symbols.dat 2x2.xbm 25pct.xbm 13pct.xbm alert.xbm flood.xbm red_flag.xbm snow.xbm torndo.xbm wind.xbm winter_storm.xbm winter_weather.xbm icon.png icon.svg symbols_DATA= symbols.dat 2x2.xbm 25pct.xbm 13pct.xbm alert.xbm flood.xbm red_flag.xbm snow.xbm torndo.xbm wind.xbm winter_storm.xbm winter_weather.xbm icon.png icon.svg Xastir-Release-2.2.4/symbols/alert.xbm0000664000175000017500000000551215151324131016633 0ustar hibbyhibby#define alert_width 109 #define alert_height 32 static unsigned char alert_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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0xef, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x82, 0x20, 0x22, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x50, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x82, 0xe7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x82, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xbe, 0x2f, 0x22, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/flood.xbm0000664000175000017500000000551215151324131016627 0ustar hibbyhibby#define flood_width 110 #define flood_height 32 static unsigned char flood_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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 0xc0, 0x17, 0x38, 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x13, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x44, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x10, 0x44, 0x51, 0x54, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf0, 0x39, 0xce, 0x03, 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, 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, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/icon.png0000664000175000017500000003033415151324131016452 0ustar hibbyhibbyPNG  IHDRL\zTXtRaw profile type exifxڝi䶒< $h672ҳgS-ueg2I,rrmI=sxx=ϱgk~{o_8?Fϯ+~ݨzq\'~Kͩܯ\q.+Ok;U<kDWJ#>oׯW8>XqSϟپ]>p;6fw;M үW(O{]F*&Ngߟ?17;5smv?}X#lq-_. k9|k3 BEڕ=ǵ-R-:bu3)̀(HGQH?G;`=#2l8qQϞ4RIkvOMgc .}o_J\5ژq_3Ƽrߵ_3<)]~Zf<}[wo-=^7QJ-i4ƾzz.gI{K鸶>]8s;xYJ,=eۑKz[sTؘ[gjnLYv7𥳐g_׺Y;6ӷu)J=3tzT| 8fMJnwMrZmϙc˞ݟ+g lw}Ǽ^yZ[lϷ+VX,Қ׽1^y0ZӊX7c,yL(c̞yh%=Oj<{n6s>\Q^%xsGlkoZ>kΫ3gYVnGe/`z|O:Ԇ},t5Da7VWli嫚v?agI>0r5S^q_:j)>ǩdcL j/; Ӯ],%_Ye0uW-Iu.h"%G-w>ny\Q sTɷK^F9ɐ=)۸ʺXhIvO3*yEː{< =ۄwYZ:}C$Զ[dׄAݓkPzahJ}Ab#8(X m,ۛW&{ͦuRa ՠ~)WSm 8 tI%@@;@2"ڔU8ASm H}dlJy4l^Nu@)(p$s [Ju|a(X_eJvR{FQN&@ )vYs'f/O+acVJ%#Z15`nYW9lR▛&g n},~$HF&`Զe<@qڝփAuP?,)]?,#E0=|EǏ`@s&бsCTVr(Ƽ1LQRo Mۡ2fׯ<'_VmȌԵ~r@rr]]Aʙ _/ /QC\Vމ׻o*VXT=SWSl{XTK=Ԡ`6濒H)M[uw[ȣ@t[E/~X#{YķOW6_ J 2ڱyٖ.Pǩf@Z5##> B8}btHWTZy{@T#FĎug.<',ǧ[mox{DzbQl) jDʡ{S y9'UCOKJl}zxlU!Pz; (sfHPیX,)H(Pv`7Ի aO'Qezj*VGvFUV0 ĵ6DžϐPm?ytYMEx*ՂӘ0M\VXCmTŬtL9b5y?)n 8+e^x2fJ^:"[k0\굅an$1쫴S[@PJtCI`WiO .^lyPrV r (r!Fr aF->6Y4CPg1{B!y ˊ `Du;`^\CfcGL'Z4&mP X_} ͉_\q3Ġݟٔ=[cZ$G2)!=| I{_%Q㓅[><4؍؇EAc*O(aL1OR=ָ9=.Hym >iLeHsF""l/|!%iZX։>"Nf<*Ȇb N| .-w$j{%y46>>%IAI1 k+-UA($&Qn"OoFf@FS'$7A\$N B-f[Q*<[!d,T!3]]@TR5_kB_FG8%a%qU(sRRȸкgskOLU'+%Hzh=L]+4 px"xPKHF>!i[#HM΀=)"{9-fjIxF=/jO&6x"8̈́)2Sy1WfKѤJ #^X 46dCoJ>읤r?|=11<ЈaoL[!(~eX6K5KU Yw1h+a~dGAi ֏xRuHHl$Ynb@~qᑀO| &d)[|<9:BTf7]VX'-gpFsK v($zpa&Y~,T؏?R ُiHʄwɎZ'yl+>,a  pC;/ B.A>I:3 GR_:0|u,2jں&aF|D6r wJ7$" N%b2gX? !zPKEM2(˧,r+"Q;0)= ϦՀl.L`X)ů'Y8ԶYc^0!) qs)${^c3.aZH "]@\Њ2]>qVP Zt-/>'!n_@i\d 9a(mmȒopFPo_FV%=EXa=g;? naNVbqWXLZc'/-([+,b@RWp5jUʻَk'{x%-uQG,El &id,9qJ% Ì#, ăBlsF;V.!-&n2+X;5Tj,D37 ]:9>_bpܠƄkp KE45 {0ꩌ<#ܐ32C$͛ci8kJR͹ +&\Cv`BXuY9z[H-{Z]yʕiR)7R?lgdB}GiPD79GGelas@9xHG 3GF +%2xl#,~:M1b˜Rz/ج:У8--Y6ӤUC:jzXdoJ7+ɯu:w&s;BiA^("EoEϊf§| _ 6G'\HA4ygema&RBvמ0QB{O+BhsE~)~ߝ5xE'"eM@A&RsDҰ00pdF 篇z$ TLV:yPG䞂'.ك]wYl>*XtT "mӹoF`O*J#Q!LvNo7Ȕe4ew$fѷPoH~{Fͣ/AgDKsF(kŨQ[Sw#N>њvf?֌XXѤ6TI\,bd ɨ9p z'3S5huM}&~3mG#4R.6}[K |ݞ6GYP(7~gqG<^}mBM{xXXѣ%IV`0ǃfAEg4uOb-"rkE= $¢F ajIr <6<=P7%RP7bJ,p_Q_d F qq * 4'FúIOȢldg y|36(EX>vT[v>. P%^+9Z h *N7XW ɕc Ue "akF@ϝ~#V'ltZ md]hBQ g]hQbɃVqbMX m瑺6i|G>q]>^rm p=,]In'iy7;Ol8BaaOMAhsQZ**Ү᮲5K Ϯ)C37ZGXrx!587b8 -uc^kqhFD I>*Ƃqt25+8cS,>Z!3~fբ!bxo(ÄRN+>}z1fR3~?SFZڧ~F)Oau]Q<5_<ײƥ}Qh#;LKmUcC0βF qS>jyR:Iv^aa .+L Tg[ Gt=V7VF,G;WkJ5Yd̢ظmW?C\0&&WI6kU)'8@iqoNQ[TB? b`F-3d~jFWُ :^Xۣ+mGTW%"d#&=]geP'D9g"lqe6 QZ-8H԰.U싪@=8۠AsE& &F{􄃕ӰLm8/>g(> dW4srIӨq+3KE͖ F4{=@N/BkZm_[> Xɡhn}m_ךOăg@5k6@ ccF(h"E^Ǚߏǧo7~E<9}_DJsBITOIDATxylT2kۡشTSAcY( H-S *"(E) P Y (lP@;37o9KDQX,xOl6l;w.ɓ'hZsլV+qj:??رR(zzrgfYVP0 0 zҽUS`٬VkNNJbyhݺul -bW(/))_9A+( ?DVV/^t)0aSNynnGS;v50g}UiӦ1 V;vlII -A. 4oV*JիWp-ք`9sfxx89 &TWW r-(999,rT*jp6C2n8X_|#5k?0`qͥ?"4hPdd=ν_֭yǭ`fɓ'ثW/OJO j}aݝB"gdv`Ekk2FGŗ?0 ,bemxD[=SC 9y$k_ 641fYVX1KŲwׯ_zuvD8Z;!e?:m61v8k׮>*->ׯgdd7.''[UUUF.3gμƍꫯ0F%1V_v1ʹsXDu֑>C/'ivhLOOK޽\^߻wo\ l6h>|8E/^h5r` & {Gk׮+T\\ܳgO/_m/^0 rJj^p&i (Jw޼yd/XN,8S?߯T*9S(,"sӧO'+o%Kh\\\eeeᔲ:uכmA+"0< qf p*@EEȴEqP!RL&R+SXʕ+{y^R)ʍ7kc:Ḹr;_| Z@p΄=Y@}™cʿ'wA('n:R}XE & <,jU*W](sN^^^aa!IIsfYTѰ˗'NXXXsؙI_İbsFeTFc'$qZVPjeZa.]0 -f3fĈeɓ'ᅯogYG "ncA1L#FpuqO8͛ld@!Ѐ<۔)S8N٪T*eU*N tJ.T*Zo wy *_~QQQehľWF#=łN*@(?3J)]gٲewޭ5LfbXV:=zGAy敗f~_|A`#GqLrX*8 t 998ܹs^4vJHH}+:b{IMMyl6gee}ǨNڻk0DMtS=9+cbbZ-zy9Ie۷`ѪU.\(>8iҌs0wZǏX ^-[ЁXJ2;;*syXJPNYO?M :Jm]:,dM6+JJ3o}Qg͚E?n'xѣKKKOQׯ_y)\Ė-[_,XyȹqoM'l}'؜Nt&еYҒj]k}Q?#,B<0L( /R]]~9ȀEtgϞSb첗"ӡ'^zjvUTT=g@P߿刣BjjjΟ?h}BNIIILL<{, XꪩZ8JEL& @?0@Sު(A5k־}Z|V#,+MkAuuumf8uL#111jQ:@Z,`Z` xK,6kcPUc=܎ہqgaaaEE O&iBRCu•mєEEE3f040m% Zu(0 . Tq>|<cia_v-66f; nbHs'LwٳZ\\\tttxxxTTJ¨b`_ŋi6ŷwA;Mxmc\Op.͹ -Jb!Ey!Q O0V3=*<"&-ER_^qB=KG#إ%h=\EQ1gG"`ؿ>v"!@{L#yW!Z򰰰cǎ!Amo !W^v45h4ND!ZJg);gh ]TT۷oȐ! ƄI}ݫyyy{E8'W 9ZFC=z?NKh_cةM &!!U$Z#թ|>}T* ܟ9 VИc@Qn6a2m(Ja3S`=-kmۆ=}уPb`ϧk/ (ʤ$yV7<$$l XEm>z*}+ĈCxz聎!st6]tc 1 ׽ͩ6,2220bbb/z<""n-kZIL4  }(+@sXyRRROu_C*-8/HqN 2))o4(#GZmTZ-b@@CEDDg u:ݙ3g(}s96n܈3oTP:'P֭[5m۶` l9k5ثJ\/RP^zyuځf[br hҤIQ[dysPU$''a4WXAA^b.V54̘1IN2rKoÆ yp>SIEh 6+UpĕӦMCe_hY4\dz2{\ZPi&h*pɓIEoiAT^sΈ:}˩8([<4Wov؁G0uZL:>%%ޫ^׎pmGfJl"ı>::z֭ˡvpPDZc*T@yȐ!xx$)3p$22r8scfdd<䓎] Created by potrace 1.16, written by Peter Selinger 2001-2019 Xastir-Release-2.2.4/symbols/red_flag.xbm0000664000175000017500000000552315151324131017271 0ustar hibbyhibby#define red_flag_width 110 #define red_flag_height 32 static unsigned char red_flag_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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0xf7, 0x00, 0x5f, 0x40, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0x40, 0x44, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x51, 0x10, 0x01, 0x41, 0xa0, 0x04, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x13, 0x01, 0x4f, 0xa0, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0xf0, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x10, 0x01, 0x41, 0x10, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf7, 0x00, 0xc1, 0x17, 0x79, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a }; Xastir-Release-2.2.4/symbols/snow.xbm0000664000175000017500000000550715151324131016516 0ustar hibbyhibby#define snow_width 110 #define snow_height 32 static unsigned char snow_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x22, 0x27, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xa6, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xaa, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xb2, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0xa2, 0x28, 0xa9, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x88, 0xa2, 0x28, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x22, 0xe7, 0x07, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/symbols.dat0000664000175000017500000027650115151324131017206 0ustar hibbyhibby# XASTIR, Amateur Station Tracking and Information Reporting # Copyright (C) 1999,2000 Frank Giannandrea # Copyright (C) 2000-2026 The Xastir Group # # # Symbol definitions for XASTIR # # If the 20th char in the APRS symbol line is a "l" (small letter L), # all four orientations of that symbol will be generated, in this # case the symbol graphic should be oriented to the left. # # The text behind the APRS symbol line is the definition text # according to the APRS Reference, optionally followed by the # current use of that symbol in [] braces. # # Symbol graphics are defined similar to XPM but with a fixed # palette. # # If an entry doesn't exist, it will display as the first entry # defined here (currently says "NO SYM YET"). # # Symbol colors are defined in: # draw_symbols.c:read_symbol_from_file() # # # ------------------------------- # TABLE ! description from APRS101.pdf [used here as] APRS # .................... ....q...q...qqq..... ....qq..q..q...q.... ....q.q.q..q...q.... ....q..qq..q...q.... ....q...q...qqq..... .................... ..qqq..q...q..q...q. .q......q.q...qq.qq. ..qq.....q....q.q.q. ....q....q....q...q. .qqq.....q....q...q. .................... .q...q..qqqq..qqqqq. ..q.q...q.......q... ...q....qqq.....q... ...q....q.......q... ...q....qqqq....q... .................... .................... # # # ----------------------------------- # Primary table section starts here # TABLE / # APRS ! Police, Sheriff .................... .........pp......... .........pp......... ........p##p........ ........p##p........ .......p####p....... .......p#####p...... ppppppp#######pppppp .p################p. ...p############p... ...p############p... .....p########p..... .....p########p..... ....p##########p.... .................... pp....pppppp.pp...p. pp....pp...p.pp.p.p. pp....pppppp.pp.p.p. pp....pp...p.pppppp. ppppp.pp...p.pppppp. #APRS " Reserved # APRS # Digi (green star with white center) .................... .................... .........kk......... .........kk......... ........kkkk........ .......kkkkkk....... ..kkkkkkkkkkkkkkkk.. ...kkkkkmmmmkkkkk... ....kkkmmmmmmkkk.... .....kkmmmmmmkk..... .....kkmmmmmmkk..... ....kkkmmmmmmkkk.... ...kkkkkmmmmkkkkk... ..kkkkkkkkkkkkkkkk.. .......kkkkkk....... ........kkkk........ .........kk......... .........kk......... .................... .................... # APRS $ Phone .................... .................... ..llllllllllllllll.. ..llllllllllmmmmll.. ..lllllllllmllllml.. ..lllllllllmllllml.. ..lllllllllmllllml.. ..llllllllllmlllml.. ..llllllllllmlllml.. ..lllllllllmlllmll.. ..llllllllmlllmlll.. ..llmmmllmlllmllll.. ..lmlllmmlllmlllll.. ..lmlllllllmllllll.. ..lmllllllmlllllll.. ..lmlllllmllllllll.. ..llmmmmmlllllllll.. ..llllllllllllllll.. .................... .................... # APRS % DX Cluster .................... .................... .mmmmmm..mmmm..mmmm. .mqqqqqm.mqqm..mqqm. .mqqqqqqmmqqm..mqqm. .mqqmmqqqmmqqmmqqm.. .mqqm.mqqmmqqmmqqm.. .mqqm.mqqm.mqqqqm... .mqqm.mqqm.mqqqqm... .mqqm.mqqm..mqqm.... .mqqm.mqqm..mqqm.... .mqqm.mqqm.mqqqqm... .mqqm.mqqm.mqqqqm... .mqqm.mqqmmqqmmqqm.. .mqqmmqqqmmqqmmqqm.. .mqqqqqqmmqqm..mqqm. .mqqqqqm.mqqm..mqqm. .mmmmmm..mmmm..mmmm. .................... .................... # APRS & HF Gateway .................... .................... .........qq......... ........qqqq........ .......qqqqqq....... ......qqqqqqqq...... .....qqq####qqq..... ....qqq######qqq.... ...qqq##qqqq##qqq... ..qqqq##qqqqqqqqqq.. ..qqqq##qqq###qqqq.. ...qqq##qqqq##qqq... ....qqq######qqq.... .....qqq####qqq..... ......qqqqqqqq...... .......qqqqqq....... ........qqqq........ .........qq......... .................... .................... # APRS ' l Small Aircraft (SSID -7) .................... .................... ........ooo......... .......oooo......... .......oooo......... .......oooo...oo.... .......oooo...oo.... .......oooo...oo.... .....ooooooooooo.... .....ooooooooooo.... .....ooooooooooo.... .....ooooooooooo.... .......oooo...oo.... .......oooo...oo.... .......oooo...oo.... .......oooo......... .......oooo......... ........ooo......... .................... .................... # APRS ( Mobile Satellite Groundstation .................p.. .................p.. ................ppp. ................ppp. .................... ..............p..... .................... ............p....... .................... ..........p......... p................... p.......p........... p................... p................... p................... p................... pp.p................ ppp................. pppp................ pppppppppp.......... # APRS ) Wheelchair (handicapped) .................... ..llllllllllllllll.. .llllllmmmlllllllll. .llllllmmmlllllllll. .llllllmmllllllllll. .llllllmmllllllllll. .lllllllmmlllllllll. .llllmmlmmmmmmmllll. .llmmmllmmlllllllll. .llmmllllmmmmmmmlll. .lmmllllllmmmmmmlll. .lmmlllllllmmlmmlll. .lmmlllllllmmlmmlll. .lmmlllllllmmlmmlll. .llmmlllllmmllmmlll. .llmmmllllmmllmmmml. .lllmmmmmmmllllllll. .llllmmmmmlllllllll. ..llllllllllllllll.. .................... # APRS * l Snowmobile .................... .................... .................... .................... ...........qq....... ..........qq........ .........qq......... ........qq.......... ......q###q......... .....q#####q.......q ....q######qqqqqqqqq ....q######qqqqqqqqq q....q######qqqqqqqq qqq..qqqqqqqqqqqqqqq .qqqqqqqqqqqqqqqqqqq .................... .................... .................... .................... .................... # APRS + Red Cross .................... .................... ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ ........jjjj........ .................... .................... # APRS , Boy Scouts .........n.......... ........nbn......... .......nbbbn........ .......nbbbn........ ....n.nbbbbbn.n..... ...nbnnbbbbbnnbn.... ..nbbbbnbbbnbbbbn... ..nbbbbbnbnbbbbbn... ..nbbnnbnbnbnnbbn... ...nn..qqqqq..nn.... .......qqqqq........ ......nbbnbbn....... .....nbbnbnbbn...... .....nnnbbbnnn...... .......nbbbn........ .ppp....nnn......p.. p................p.. .pp..pp.ppp.p.p.ppp. ...p.p..p.p.p.p..p.. ppp..pp.ppp.ppp..p.. # APRS - House QTH (VHF) .................... ......q............. ......q............. ......q...q......... ......q..qqq........ ......q.qqqqq....... ......qqqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... .................... .................... # APRS . X .................... .................... .................... .................... .................... .................... ......j......j...... .......j....j....... ........j..j........ .........jj......... .........jj......... ........j..j........ .......j....j....... ......j......j...... .................... .................... .................... .................... .................... .................... # APRS / Dot .................... .................... .................... .................... .................... .................... .................... ........jjjj........ .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... ........jjjj........ .................... .................... .................... .................... .................... .................... .................... # APRS 0 Numerical Circle 0 (obsolete, use overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqmmmmqqqqqq.. ..qqqqqmmmmmmqqqqq.. ..qqqqmmmqqmmmqqqq.. ..qqqqmmqqqqmmqqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqmmmqqqqmmmqqq.. ..qqqqmmqqqqmmqqqq.. ..qqqqmmmqqmmmqqqq.. ..qqqqqmmmmmmqqqqq.. ..qqqqqqmmmmqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS 1 Numerical Circle 1 (obsolete, use overlay) .................... .................... ..ffffffffffffffff.. ..ffffffffffffffff.. ..ffffffffmmffffff.. ..fffffffmmmffffff.. ..ffffffmmmmffffff.. ..fffffmmmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffffmmmffffff.. ..fffffmmmmmmmffff.. ..fffffmmmmmmmffff.. ..ffffffffffffffff.. ..ffffffffffffffff.. ..ffffffffffffffff.. .................... .................... # APRS 2 Numerical Circle 2 (obsolete, use overlay) .................... .................... ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjmmmmmmmmjjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjmmmjjjjmmmjjj.. ..jjjjjjjjjjmmmjjj.. ..jjjjjjjjjmmmjjjj.. ..jjjjjjjmmmjjjjjj.. ..jjjjjmmmjjjjjjjj.. ..jjjjmmmjjjjjjjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjmmmmmmmmmmjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjjj.. .................... .................... # APRS 3 Numerical Circle 3 (obsolete, use overlay) .................... .................... ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaammmmmmmaaaaa.. ..aaaammmmmmmmaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaammmmmaaaaa.. ..aaaaaammmmmaaaaa.. ..aaaaaaaaaammaaaa.. ..aaaaaaaaaammaaaa.. ..aaaammmmmmmmaaaa.. ..aaaammmmmmmaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. ..aaaaaaaaaaaaaaaa.. .................... .................... # APRS 4 Numerical Circle 4 (obsolete, use overlay) .................... .................... ..################.. ..################.. ..################.. ..#####ooo#ooo####.. ..#####ooo#ooo####.. ..####ooo##ooo####.. ..####ooo##ooo####.. ..###oooooooooo###.. ..###oooooooooo###.. ..#########ooo####.. ..#########ooo####.. ..#########ooo####.. ..#########ooo####.. ..################.. ..################.. ..################.. .................... .................... # APRS 5 Numerical Circle 5 (obsolete, use overlay) .................... .................... ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmkkkkkkkkkk.. ..kkkkmmkkkkkkkkkk.. ..kkkkmmmmmmmkkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkkkkkkkmmkkkk.. ..kkkkkkkkkkmmkkkk.. ..kkkkmmmmmmmmkkkk.. ..kkkkmmmmmmmkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. ..kkkkkkkkkkkkkkkk.. .................... .................... # APRS 6 Numerical Circle 6 (obsolete, use overlay) .................... .................... ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..lllllmmmmmmmllll.. ..llllmmmmmmmmllll.. ..llllmmllllllllll.. ..llllmmllllllllll.. ..llllmmmmmmmlllll.. ..llllmmmmmmmmllll.. ..llllmmllllmmllll.. ..llllmmllllmmllll.. ..llllmmmmmmmmllll.. ..lllllmmmmmmlllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. .................... .................... # APRS 7 Numerical Circle 7 (obsolete, use overlay) .................... .................... ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbmmmmmmmbbbbb.. ..bbbbmmmmmmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbbmmbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbbmmbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbmmbbbbbbb.. ..bbbbbbbbbbbbbbbb.. ..bbbbbbbbbbbbbbbb.. .................... .................... # APRS 8 Numerical Circle 8 (obsolete, use overlay) .................... .................... ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccmmmmmmccccc.. ..ccccmmmmmmmmcccc.. ..ccccmmccccmmcccc.. ..ccccmmccccmmcccc.. ..cccccmmmmmmccccc.. ..cccccmmmmmmccccc.. ..ccccmmccccmmcccc.. ..ccccmmccccmmcccc.. ..ccccmmmmmmmmcccc.. ..cccccmmmmmmccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. ..cccccccccccccccc.. .................... .................... # APRS 9 Numerical Circle 9 (obsolete, use overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmqqqqqqmmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmqqmmmmqqmmmq.. ..qmmmqqmmmmqqmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmmqqqqqqqmmmq.. ..qmmmmmmmmmqqmmmq.. ..qmmmmmmmmmqqmmmq.. ..qmmmqqqqqqqqmmmq.. ..qmmmqqqqqqqmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS : Fire .................... .................... ....q............... ...q#q...........q.. ...qjq..........q#q. ...q#q.........q##q. ...qqq..qq.qq.q#qq.. ..q#q#qq#q.q#qq#q... ...qq#q##qq#jqqq#q.. ...q#q#jfj##j#f#qq.. ..q#j#jj#j#jj#jjq... ..qjjjfjjj#j#j#q.... ...qjjfjj#jjjjfq.... ....qjjffjjfjfjjq... ...qjjffjfjjfjjfqq.. ...qjfffjjfjfjfjjq.. ..qjffjjfffjjffjq... ..qjffjjfjffjjffjq.. ..qffffffffffffffq.. .................... # APRS ; Campground (Portable Ops!) .................... .................... ..........e......... ..........e......... ..........e......... ..........e......... .........iei........ .........iei........ ........ikeki....... .......ikkekki...... ......ikkceckki..... .....ikkkoeokkki.... ....ikkkcieickkki... ...ikkkkoieiokkkki.. ....kkkciieiickkk... ....kkkoiieiiokkk... ....kkciiieiiickk... ..eeeeeeeeeeeeeeee.. .................... .................... # APRS < l Motorcycle (SSID -10) .................... .................... .................... .......ppp.......... .......p............ .......ppppp........ ......pp.........p.. .....pppppp....pp... .pppppp####pppppppp. p.pmppp####pppppmp.p .pmppp.ppppppqpmmmp. pmmpmmppppppppppppmp pmpmmmppppppppmmmmmp .pmmmp..ppppp.pmmmp. ..pmp..........pmp.. ...p............p... .................... .................... .................... .................... # APRS = l Railroad Engine .................... .................... .....cmccmcccc...... ....ccccmc.......... ....pp.............. ..qqqqqq...qqqqqqq.. ...qqqq....qqqqqqq.. ....qq.....qq...qq.. ....qq.....qq...qq.. ....qq.....qq...qq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ..qqqqqqqqqqqqqqqq.. ...q..q..qmmq.qmmq.. ..qmqqmq.qmmq.qmmq.. ...q..q...qq...qq... .................... .................... # APRS > l Car (SSID -9) .................... .................... .................... .................... .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppdqdddddddddp.. ..pjjjjdjjjjdjjjjjp. .pjjjjjdjjjjdjjjjjdp p#jjoojdjjjjdjjoojjp pjjonnodjjjjdjonnojp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # APRS ? File Server .................... .................... pppp..p..p.....pppp. p.....p..p.....p.... p.....p..p.....p.... pppp..p..p.....pppp. p.....p..p.....p.... p.....p..p.....p.... p.....p..pppp..pppp. .................... .................... .................... .ppp.pp.ppp..p.p.ppp p....p..p..p.p.p.p.. p....p..p..p.p.p.p.. .pp..pp.ppp..p.p.ppp ...p.p..p.p..p.p.p.. ...p.p..p.p..p.p.p.. ppp..pp.p..p..p..ppp .................... # APRS @ Hurricane Future Prediction (dot) ppp..ppp...ppp..ppp. p..p.p..p..p....p..p ppp..ppp...ppp..p..p p....p.p...p....p..p p....p..p..ppp..ppp. .................... ....ll.....ll....... ...ll....ll..ll..... ...ll...llll...ll... ....ll.lllllll...... ......lllllll.ll.... ...ll...llll...ll... .....ll..ll...ll.... .......ll....ll..... .................... ppp...ppp...ppppp... .p...p...p....p..... .p...p........p..... .p...p...p....p..... ppp...ppp.....p..... # APRS A Aid Station .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhmmmmmmmmmmmmhh.. ..hhmmmmmmmmmmmmhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS B BBS or PBBS .................... .................... .................... .................... .................... ...ggg..ggg...gg.... ...g..g.g..g.g..g... ...g..g.g..g.g...... ...ggg..ggg...g..... ...g..g.g..g..g..... ...g..g.g..g...g.... ...g..g.g..g....g... ...g..g.g..g.g..g... ...gggg.ggg...gg.... .................... .................... .................... .................... .................... .................... # APRS C l Canoe .................... .................... .................... .................... .................... .............p...... pppp........p...pppp peeppppppppppppppeep peeeeeeeeepeeeeeeeep .peeeeeeepeeeeeeeep. ..peeeeepeeeeeeeep.. ...pppppppppppppp... ......p............. .....p.............. ...ppp.............. ..ppp............... .ppp................ .................... .................... .................... # #APRS D # APRS E Eyeball (eye catcher) .................... .................... ........pppp........ ......pmmmmmmp...... ....pmmmmmmmmmmp.... ..pmmmmmhhhhmmmmmp.. .pmmmmhhhhhhhhmmmmp. .pmmmmhhhhhhhhmmmmp. pmmmhhhhhpphhhhhmmmp pmmmhhhhpppphhhhmmmp pmmmhhhhpppphhhhmmmp pmmmhhhhhpphhhhhmmmp .pmmmmhhhhhhhhmmmmp. .pmmmmhhhhhhhhmmmmp. ..pmmmmmhhhhmmmmmp.. ....pmmmmmmmmmmp.... ......pmmmmmmp...... ........pppp........ .................... .................... # APRS F l Farm Equipment .................... .................... .................... .................... .................... ............qqqqqqq. ............qkkkkkq. ...qq.......qkmmmkq. ...qq.......qkmmmkq. ...qq.......qkmmmkq. ..qqqqqqqqqqkkkkkkq. .qkkkkkkkkkkkqqqqqq. .qkkkkkkkkkkqqqqqqq. ..qqqkkkkkkqqqkkkqq. .qqqqqqqqqqqqqkkkqq. .qqqqq......qqkkkqq. .qqqqq......qqqqqqq. .qqqq........qqqqq.. .................... .................... # APRS G Grid Square (6-character) .................... ..q.q.q......q.q.q.. ..q.q.q.qjjq.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.qjjq.q.q.q.. ..q.q.q.qjjq.q.q.q.. ........qjjq........ ........qjjq........ ........qjjq........ ........qjjq........ .......qqjjqq....... .......qjqqjq....... ...qq..qqjjqq..qq... ..q..q.qqjjqq.q..q.. ..q....qjqqjq..q.... ..q.qq.qjqqjq...q... ..q..q.qqjjqq.q..q.. ...qq..qqqqqq..qq... .................... .................... # APRS H Hotel (blue bed icon) .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhhhhhhhhhhhhhh.. ..hmhmmhhmmmmmmhmh.. ..hmhmmmmmmmmmmhmh.. ..hmhmmhhmmmmmmhmh.. ..hmhhhhhhhhhhhhmh.. ..hmmmmmmmmmmmmmmh.. ..hmhhhhhhhhhhhhmh.. ..hmhhhhhhhhhhhhmh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS I TCP/IP on air network station .................... .................... .................... .#################.. .##iiiii#iii#iii##.. ..###i###i#i#i#i#... ..###i###i###iii#... ..###i###i#i#i###... ...##i###iii#i##.... ...#############.... ...#############.... ...###iii#iii###.... ....###i##i#i##..... ....###i##iii##..... ....###i##i####..... .....#iii#i###...... .....#########...... .....#########...... .................... .................... # #APRS J # APRS K School .........pp......... ........p##p........ .......p####p....... ......p######p...... .....p########p..... ....p##########p.... ...p############p... ..pppppppppppppppp.. ..p##############p.. ..p##pp##ppp##pp#p.. ..p##pp##ppp##pp#p.. ..p######ppp#####p.. ..pppppppppppppppp.. .................... .................... .pp....p...........p p......p...........p .p..pp.ppp.ppp.ppp.p ..p.p..p.p.p.p.p.p.p pp..pp.p.p.ppp.ppp.p # APRS L Logged-on Internet User (Desktop Computer) qqqqq.qqqqqqqqqqqqqq qmqmq.qqqqqqqqqqqqqq qqmqq.qqmmmmmmmmmmqq qmqmq.qqmmmqmmmqmmqq qqmqq.qqmmmmqmqmmmqq qmqmq.qqmmmmmqmmmmqq qqmqq.qqmmmmqmqmmmqq qmqmq.qqmmmqmmmqmmqq qqmqq.qqmmmmmmmmmmqq qmqmq.qqqqqqqqqqqqqq qqmqq.qqqqqqqqqqqqqq qmqmq.q............q qqqqq.qqqqqqqqqqqqqq .................... .................... ....qqqqqqqqqqqqqqqq ...qmqmqmqmqmqmqmqq. ..qqmqmqmqmqmqmqmq.. .qmmqmqmqmqmqmqmq... qqqqqqqqqqqqqqqq.... # APRS M MacAPRS .................... .................... ...........kk....... ..........kkk....... .........kkk........ .........kkk........ .....kkkkkkkkkk..... ....kkkkkkkkkkkk.... ...############..... ...###########...... ...aaaaaaaaaaa...... ...aaaaaaaaaaa...... ...jjjjjjjjjjjj..... ...jjjjjjjjjjjj..... ....bbbbbbbbbbbb.... ....bbbbbbbbbbbb.... .....llllllllll..... ......llllllll...... .................... .................... # APRS N NTS Station .................... .......gggggg....... ......gggggggg...... .....ggmmgggmgg..... .....ggmgmggmgg..... ....gggmggmgmggg.... ....gggmgggmmggg.... ...gggggggggggggg... ...ggggmmmmmmgggg... ..gggggggmmggggggg.. ..gggggggmmggggggg.. ...gggggggggggggg... ...gggggmmmmmgggg... ....gggmgggggggg.... ....ggggmmmmgggg.... .....gggggggmgg..... .....ggmmmmmggg..... ......gggggggg...... .......gggggg....... .................... # APRS O Balloon (SSID -11) .................... .................... ......hffjffh....... .....h##kjk##h...... ....h###jjj###h..... ...h####jjj####h.... ...###jj###jj###.... ...jjjjj###jjjjj.... ...jjjjj###jjjjj.... ...jjjblllllbjjj.... ....lllllllllll..... .....lllllllll...... ......lllllll....... .......h.a.h........ ........pcp......... .......fefef........ .......fefef........ .......oqqqo........ .................... .................... # APRS P l Police .................... .................... ..........ll........ ..........ll........ .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppnqnnnnnnnnnp.. ..pmmmmkkkkkkmmmmmp. .pmmmmmkccckkmmmmmep p#mmoomkkkkkkmmoommp pmmonnokkkkkkmonnomp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # #APRS Q # APRS R l Recreational Vehicle (SSID -13) (motor-home) .................... .................... .................... .................... .................... ........pppppppppp.. ..pqqqqqqqqqqqqqqqqq .pmmmmmmmmmmmmmmmmmq ppppmmmmmpppmmpppmmq qpppmmmmmpppmmpppmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmqmmmqmmmqmmq qmmmmmmmmmmmmmmmmmmq qqqqqqqqqqqqqqqqqqqq .qqqq.......qqqq.... ..qq.........qq..... .................... .................... .................... .................... # APRS S l Space Shuttle ................qqq. ...............qmcq. ..............qmmcq. .............qnmecq. ............qnmmhcq. ..........qqnmmmmcq. ........pqnmmmmmcnqq ...oqqqonnnnnnnncmmq .qqomcmmmmmmmmmcmmmq qqmqcnmmmmmmmmmcqqqn .qqomcmmmmmmmmmcmmmq ...oqqqonnnnnnnncmmq ........pqnmmmmmcnqq ..........qqnmmmmcq. ............qnmmecq. .............qnhlcq. ..............qmmcq. ...............qmcq. ................qqq. .................... # APRS T SSTV ..pppp.......pppp... .p....p.....p....p.. p......p...p......p. p....... ..p........ .pppppp.....pppppp.. .......p..........p. p......p...p......p. .p....p.....p....p.. ..pppp.......pppp... .................... .................... ppppppp....p.......p ...p.......p.......p ...p.......p.......p ...p........p.....p. ...p........p.....p. ...p.........p...p.. ...p.........p...p.. ...p..........p.p... ...p...........p.... # APRS U l Bus (SSID -2) .................... .................... .................... .................... .................... .....aaaaaaaaaaaaaa. ....a##############a ...ac#cc#cc#cc#cc#ca ..acc#cc#cc#cc#cc#ca aa#################a a##################a a##################a aannaaaaaaaaaaaannaa .qooq..........qooq. ..qq............qq.. .................... .................... .................... .................... .................... # APRS V ATV .........pp......... ........p..p........ .......p....p....... ......p. ....p...... .....p........p..... ....pppppppppppp.... ...p............p... ..p..............p.. .p................p. .................... .................... ppppppp....p.......p ...p.......p.......p ...p.......p.......p ...p........p.....p. ...p........p.....p. ...p.........p...p.. ...p.........p...p.. ...p..........p.p... ...p...........p.... # APRS W National Weather Service Site .................... .................... .......gggggg....... .....gghhhhhhgg..... ....ghhhhhhhhhhg.... ...ghhhhhhhhhhhhg... ...ghhhhhhhhhhhhg... ..gmmhhhmmhmmhhmmg.. ..gmmhhhmmhmmmmmmg.. ..gmmhhhmmhhmmmmhg.. ..gmmhmhmmhhmmmmhg.. ..gmmmmmmmhmmmmmmg.. ..gmmmhmmmhmmhhmmg.. ...ghhhhhhhhhhhhg... ...ghhhhhhhhhhhhg... ....ghhhhhhhhhhg.... .....gghhhhhhgg..... .......gggggg....... .................... .................... # APRS X l Helicopter (SSID -6) .................... .................... .................... ..mqqmqqmqqmqqm..... qmqmqmqmqmqmqmqmq... ..qmqqmqqmqqmqq..... .......mq........... ...qqqqqq........... ..qqqqjjq.......mmm. .qmmmqjjjq.....mqqqm qmmmmqjjjjqjqjqmqmqm qqqqqqjjjjjqjqjmqqqm .qjjjjjjjq......mmm. ..qjqqjqq........... ...jq.jq............ j..jq.jq............ qjjjjjjjjjjj........ .qqqqqqqqqqq........ .................... .................... # APRS Y l Yacht (sail boat) (SSID -5) .................... .................... ...........q........ ..........qqq....... .........qcqcq...... ........qccqcq...... .......qcccqcq...... ......qccccqccq..... .....qcccccqccq..... ....qccccccqcccq.... ...qcccccccqcccq.... ..qqqqqqqqqqqqqqqq.. ...qkkkkkkkkkkkkq... ....qkkkkkkkkkkq.... .....qqqqqqqqqq..... .................... .................... .................... .................... .................... # APRS Z WinAPRS .................... .................... .................... .........qqqqqq..... ........qjjjqkkqq... .qq...qqjjjjqkkkkq.. ...qqq.qjjjjqkkkkq.. .qq...qqjjjjqkkkkq.. ...qqq.qjjjjqkkkkq.. .qq...qqjjqqqqkkkq.. ...qqq.qqqllq#qqkq.. .qq...qqllllq###qq.. ...qqq.qllllq####q.. .qq...qqllllq####q.. ...qqq.qllllq####q.. .qq...qqllllq####q.. ...qqq.qlqqqqq###q.. .qq...qqq.....qq#q.. ...qqq..........qq.. .................... # APRS [ l Jogger .................... .................... .................... .................... .......qq........... .......qq........... .......qqllpp....... ...p...lelleep...... ...pe...lll..ep..... ....pe..lll..ep..... .....ppqqll..ep..... ......qqqqqq........ .....qqqqqqq........ .....qqq..qqqqq..... ......llq..qllq..... .....qqq......q..... .................... .................... .................... .................... # APRS \ Triangle (DF station) .................... .................... .........qq......... ........q##q........ ........q##q........ .......q####q....... .......q####q....... ......q######q...... ......q######q...... .....q########q..... .....q########q..... ....q#qqq##qqq#q.... ....q#q##q#q###q.... ...q##q##q#qq###q... ...q##q##q#q####q... ..q###qqq##q#####q.. ..q##############q.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS ] Mail/Post Office .................... .................... .....llllllllll..... ...llllllllllllll... ..llllmhmhmhmhllll.. ..lllmhmhmhmhmhlll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llmlmllmllmlmlll.. ..llmmmlmlmlmlmlll.. ..llmhmlmmmlmlmlll.. ..llmlmlmlmlmlmlll.. ..llmlmlmlmlmlmmll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llll........llll.. ..lll..........lll.. ..lll..........lll.. .................... .................... # APRS ^ l Large Aircraft .................... .................... .........oo......... .........oo......... ........ooo......... ........ooo......... ........ooo......o.. .......oooo.....oo.. .......oooo....ooo.. ..oooooooooooooooo.. ..oooooooooooooooo.. .......oooo....ooo.. .......oooo.....oo.. ........ooo......o.. ........ooo......... ........ooo......... .........oo......... .........oo......... .................... .................... # APRS _ Weather Station (blue) .................... .................... .......hhhhhh....... .....hhhhhhhhhh..... ....hhhhhhhhhhhh.... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ..hmmhhhmmhmmhhmmh.. ..hmmhhhmmhmmmmmmh.. ..hmmhhhmmhhmmmmhh.. ..hmmhmhmmhhmmmmhh.. ..hmmmmmmmhmmmmmmh.. ..hmmmhmmmhmmhhmmh.. ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ....hhhhhhhhhhhh.... .....hhhhhhhhhh..... .......hhhhhh....... .................... .................... # APRS ` Dish Antenna .................... .................... ..q................. ..qq................ ..qoq............... ..qooq.............. ...qooqqqqqqqq...... ...qoooq....qq...... ...qooooq..q.q...... ...pqooooqq..q...... ....qoooooq..q...... .....qoooooq.q...... ....qpqoooooqq...... ...qqqpqoooooq...... ..qqqqqpqoooooq..... ..qqqqqq.qqooooq.... ..qqqqqqp..pqqooq... ..qqqqqqqp....qqqq.. .................... .................... # APRS a l Ambulance (SSID -1) .................... .................... .................... .................... .................... .......qqqqqqqqqqq.. ......qqmmjjmmmmmq.. .....qoqmmjjmmmmmq.. ..qqqqqqjjjjjjmmmq.. ..qmmmmmjjjjjjmmmq.. ..qmmmmmmmjjmmmmmq.. ..qmqqqqmmjjqqqqmq.. ..qqqqqqqmmqqqqqqq.. ..qqqoqqqqqqqqoqqq.. ....qqoq....qoqq.... .....qq......qq..... .................... .................... .................... .................... # APRS b l Bicycle (SSID -4) .................... .................... .........q.......... .........qqq........ .........q.......... ........q........... .......qq...qqq..... ....qqqmqq..q....... ...qq..m.qqqq....... ..qq......qqqq...... ..q....m...q.qq..... ..q...m....q..qq.... ..q....m...q...qq... ..q.....m..q...qq... ..qq......qq..q..q.. ...qq....qq...q..q.. ....qqqqqq.....qq... .................... .................... .................... # APRS c Incident Command Post qqqqqqqqqqqqqqqqqqqq qmmmmmmmmmmmmmmmmmlq qmmmmmmmmmmmmmmmmllq qmmmmmmmmmmmmmmmlllq qmmmmmmmmmmmmmmllllq qmmmmmmmmmmmmmlllllq qmmmmmmmmmmmmllllllq qmmmmmmmmmmmlllllllq qmmmmmmmmmmllllllllq qmmmmmmmmmlllllllllq qmmmmmmmmllllllllllq qmmmmmmmlllllllllllq qmmmmmmllllllllllllq qmmmmmlllllllllllllq qmmmmllllllllllllllq qmmmlllllllllllllllq qmmllllllllllllllllq qmlllllllllllllllllq qllllllllllllllllllq qqqqqqqqqqqqqqqqqqqq # APRS d Dual Garage (Fire Department) .................... .........qq......... ........qjjq........ .......qjjjjq....... ......qjjjjjjq...... .....qjjjjjjjjq..... ....qjjjjjjjjjjq.... ...qjjjjjjjjjjjjq... ..qqqqqqqqqqqqqqqq.. ..qjjjjjjjjjjjjjjq.. ..qjmmmjmjmmmjmmjq.. ..qjmjjjmjmjmjmjjq.. ..qjmmjjmjmmmjmmjq.. ..qjmjjjmjmjmjmjjq.. ..qjmjjjmjmjmjmmjq.. ..qjjjjjjjjjjjjjjq.. ..qqqqqqqqqqqqqqqq.. .................... .................... .................... # APRS e l Horse (equestrian) .................... .................... .................... ..........qq........ .........qqqq....... ..........qq........ .........qqq........ ...qq...q.qq........ ..qqqq....qq........ .qqqqqqqqqqqqqqqq... .qq..qqqqqqqqqqq.q.. ......qqqqqqqqqq..q. .......qqq....q.q... ......q.q....q...q.. .....q...q....q..q.. .....q....q....q..q. .................... .................... .................... .................... # APRS f l Fire Truck (SSID -3) .................... .................... .................... .................... .................... .................... ...jjjjmmmmmmmmmmmm. ..jcccjjmjjmjjmjjmj. .jccccjjmjjmjjmjjmj. .jjjjjjmmmmmmmmmmmm. .jjjjjjjjjjjjjjjjoo. .oojqjjjjjjqjjjqjoo. ...qqq....qqq.qqq... ....q......q...q.... .................... .................... .................... .................... .................... .................... # APRS g Glider .................... .................... .................... .................... ..jjjj.............. ..jaaajjjj.......... ..jaaaaaaajjjj...... ..j###########jjjj.. ..jjjjjjjjjjjjjjjj.. ....p..........p.... .....p........p..... ......p......p...... .......pccccp....... .....gggggggggg..... .....ggggggg.gg..... .................... .................... .................... .................... .................... # APRS h Hospital .................... .........qq......... ........qmmq........ .......qmmmmq....... ......qmmmmmmq...... .....qmmmmmmmmq..... ....qmmmmmmmmmmq.... ...qmmmmmmmmmmmmq... ..qqqqqqqqqqqqqqqq.. ...qmmmmmjjmmmmmq... ...qmmmmmjjmmmmmq... ...qmmmjjjjjjmmmq... ...qmmmjjjjjjmmmq... ...qmmmjjjjjjmmmq... ...qmmmmmjjmmmmmq... ...qmmmmmjjmmmmmq... ...qqqqqqqqqqqqqq... .................... .................... .................... # APRS i IOTA (island on the air) .................... ......k..k.......... ....kkkkkkkkkk...... ....kkkiiiik#kkk.... ..kk##kkii#kk#k.kk.. ..k#kkk#ffk#k.#k.... .k.k.k#.ffk....k.... k..k..k.ff.......... ........ff.......... ........ff.......... ........ff.......... ....aeaeffaeaea..... ..eaeaeaeaeaeaeaea.. .haeaeaeaeaeaeaeaeh. .hhaeaeaeaeaeaeaehh. ..hhhhhhhhhhhhhhhh.. ...hhhhhhhhhhhhh.... .................... .................... .................... # APRS j l Jeep (SSID -12) .................... .................... .................... .................... ..........koooooo... .........k...o...o.. ........k...co...co. .......kkp..no...po. .kkkkkkkkc..nkkkkkkq k#kkkkkkk..okkkkkkkq nkqqqkkkkpppkkqqqkkq nqqcqqkkkkkkkqqcqqnn .qcmcqoonnnnnqcmcqq. .oqcqo.......oqcqo.. ..oqo.........oqo... .................... .................... .................... .................... .................... # APRS k l Truck (SSID -14) .................... .................... .................... .................... ........jjj......... .......jjmj......... ......jjmmj......... .....jjmmmj......... ..jjjjpjjqpjjjjjjj.. ..jjjjpjjjpjjjjjjj.. ..jjjjjpjjpjjjjjjj.. ..qpppjppppjjpppjq.. ..qpcpjjjjjjjpcpjq.. ...ppp.......ppp.... .................... .................... .................... .................... .................... .................... # APRS l Logged-on Laptop .................... .................... ....qqqqqqqqqqqqqqqq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmqmmqmmmmmq ....qmmmmmmqqmmmmmmq ....qmmmmmmqqmmmmmmq ....qmmmmmqmmqmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qmmmmmmmmmmmmmmq ....qqqqqqqqqqqqqqqq ...qmqmqmqmqmqmqmqq. ..qqmqmqmqmqmqmqmq.. .qmmqmqmqmqmqmqmq... qqqqqqqqqqqqqqqq.... .................... .................... # APRS m Mic-Repeater .................... .......g....g....... .......gg..gg....... .......g.gg.g....... .......g....g....... .......g....g....... .................... ........gggg........ .........gg......... .........gg......... ........gggg........ .................... ........gggg........ .......g....g....... .......g............ .......g....g....... ........gggg........ ..ggggg......ggggg.. .................... .................... # APRS n Node .................... .................... .................... .................... .................... .................... ......qqq..qq....... ......qqq..qq....... ......qqqq.qq....... ......qqqq.qq....... ......qq.qqqq....... ......qq.qqqq....... ......qq..qqq....... ......qq..qqq....... ......qq...qq....... .................... .................... .................... .................... .................... # APRS o Emergency Operations Center .................... .........pp......... ........pjjp........ .......pjjjjp....... ......pjjjjjjp...... .....pjjjjjjjjp..... ....pjjjjjjjjjjp.... ...pjjjjjjjjjjjjp... ..pjjjjjjjjjjjjjjp.. ...pjmmjjmjjjmjjp... ...pjmjjmjmjmjmjp... ...pjmjjmjmjmjjjp... ...pjmmjmjmjmjjjp... ...pjmjjmjmjmjjjp... ...pjmjjmjmjmjmjp... ...pjmmjjmjjjmjjp... ...pjjjjjjjjjjjjp... .................... .................... .................... # APRS p l Rover (puppy dog) .................... .................... .................... .................... ....qqqq............ ....qqqq.........q.. ...qmqmq........qq.. ..qqmmmqq......qmq.. ..qqqqmmmqqqqqqmmq.. .....qmmmmqqqqmmqq.. ......qqmmmmmmmmq... ......qqmmmmmmmmq... ......qmqqqqqmmmq... ......qmq....qmmq... ......qmq.....qmq... .....qqqq....qqmq... .....qqq.....qqq.... .................... .................... .................... # APRS q Grid Square Above 128m .................... ..q.q.q......q.q.q.. ..q.q.q.ikki.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.ikki.q.q.q.. ..q.q.q.ikki.q.q.q.. ........ikki........ ........ikki........ ........ikki........ ........ikki........ .......iikkii....... .......ikiiki....... ...qq..iikkii..qq... ..q..q.iikkii.q..q.. ..q....ikiiki..q.... ..q.qq.ikiiki...q... ..q..q.iikkii.q..q.. ...qq..iiiiii..qq... .................... .................... # APRS r Antenna, like radio station .................... ..q.q.q......q.q.q.. ..q.q.q.lhhl.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.lhhl.q.q.q.. ..q.q.q.lhhl.q.q.q.. ........lhhl........ ........lhhl........ ........lhhl........ ........lhhl........ .......llhhll....... .......lhllhl....... .......llhhll....... .......llhhll....... .......lhllhl....... .......lhllhl....... .......llhhll....... .......llllll....... .................... .................... # APRS s l Ship (power boat) (SSID -8) .................... .................... .................... .................... .................... .................... ........qqqq.....q.. .......qqccq....q... ......qqqqqq...q.... ..iiiiiiiiiiiiiiii.. ..iiiiiiiiiiiiiiii.. ...iiiiiiiiiiiiiii.. ....iiiiiiiiiiiiii.. .................... .................... .................... .................... .................... .................... .................... # APRS t Truck Stop .................... .................... ..gggggggggggggggg.. ..gggggggggggggggg.. ..gmmmmmmmmggggggg.. ..gmmmmmmmmggggggg.. ..ggggmmggggmmmmgg.. ..ggggmmgggmmmmmmg.. ..ggggmmgggmmggmmg.. ..ggggmmgggmmggggg.. ..ggggmmggggmmgggg.. ..ggggmmgggggmmggg.. ..ggggmmggggggmmgg.. ..ggggmmgggggggmmg.. ..gggggggggmmggmmg.. ..gggggggggmmmmmmg.. ..ggggggggggmmmmgg.. ..gggggggggggggggg.. .................... .................... # APRS u l Truck (18-wheeler) .................... .................... .................... .................... .................... .................... .llll.llllllllllllll .lcll.llllllllllllll .lcll.llgggllgglggll lllll.llllllllllllll lllll.llllllllllllll lnlnlqnnnllllllnnnll oqoqooqoqo....oqoqo. .o....o.o......o.o.. .................... .................... .................... .................... .................... .................... # APRS v l Van (SSID -15) .................... .................... .................... .................... .................... .......hhhhhhhhhhh.. ......hccchccchccch. .....hcccchccchccch. ....hccccchccchccch. ..hhhphhhhhhhhhhhhh. .hhhhhhhhhhhhhhhhhj. .hhhhhhhhhhhhhhhhhh. .ohqqhhhhhhhhhhqqho. .hqccqhhhhhhhhqccqh. ..qccq........qccq.. ...qq..........qq... .................... .................... .................... .................... # APRS w Water Station .................... .................... ..gggggggggggggggg.. ..gggggggggggggggg.. ..gmggmgggggggmmgg.. ..gmggmggggggmggmg.. ..gmggmggggggmggmg.. ..gmggmggggggmggmg.. ..gmmmmggmmggmggmg.. ..gmggmgmggmgmggmg.. ..gmggmggggmgmggmg.. ..gmggmggggmgmggmg.. ..gmggmgggmggmggmg.. ..gmggmggmggggmmgg.. ..ggggggmggggggggg.. ..ggggggmmmmgggggg.. ..gggggggggggggggg.. ..gggggggggggggggg.. .................... .................... # APRS x X-APRS (Unix) .................... .................... .................... .qqqq............qq. ..qqqq..........qq.. ...qqqq........qq... ....qqqq......qq.... .....qqqq....qq..... ......qqqq..qq...... .......qqq.qq....... .......qq.qqq....... ......qq..qqqq...... .....qq....qqqq..... ....qq......qqqq.... ...qq........qqqq... ..qq..........qqqq.. .qq............qqqq. .................... .................... .................... # APRS y Yagi at QTH .................... ..q.q.q.q.q......... ..qqqqqqqqq......... ..q.q.q.q.q......... ......q............. ......q..qqq........ ......q.qqqqq....... ......qqqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... .................... # #APRS z # #APRS { # #APRS | Reserved - TNC Stream Switch # #APRS } # #APRS ~ Reserved - TNC Stream Switch # # # # ----------------------------------- # ----------------------------------- # # Secondary table section starts here # ----------------------------------- # ----------------------------------- # # # TABLE \ # APRS ! Emergency .................... .........jj......... ........jjjj........ ........jjjj........ .......jjmmjj....... .......jjmmjj....... ......jjmqqmjj...... ......jjmqqmjj...... .....jjmmqqmmjj..... .....jjmmqqmmjj..... ....jjmmmqqmmmjj.... ....jjmmmqqmmmjj.... ...jjmmmmmmmmmmjj... ...jjmmmmqqmmmmjj... ..jjmmmmmqqmmmmmjj.. ..jjmmmmmmmmmmmmjj.. .jjjjjjjjjjjjjjjjjj. ..jjjjjjjjjjjjjjjj.. .................... .................... # #APRS " Reserved # APRS # Digi (green star) (w overlay) .................... .................... .........kk......... .........kk......... ........kmmk........ ........kmmk........ ..kkkkkkkmmkkkkkkk.. ...kmmmmmmmmmmmmk... ....kmmmmmmmmmmk.... .....kmmmmmmmmk..... .....kmmmmmmmmk..... ....kmmmmmmmmmmk.... ...kmmmmmmmmmmmmk... ..kkkkkkkmmkkkkkkk.. ........kmmk........ ........kmmk........ .........kk......... .........kk......... .................... .................... # APRS $ Bank or ATM (green box) .................... .................... ....kkkkkkkkkkk..... ...kkkkkmkmkkkkk.... ..kkkkkmmmmmkkkkk... ..kkkkmkmkmkmkkkk... ..kkkkmkmkmkkkkkk... ..kkkkmkmkmkkkkkk... ..kkkkkmmkmkkkkkk... ..kkkkkkmkmkkkkkk... ..kkkkkkmmmkkkkkk... ..kkkkkkmkmmkkkkk... ..kkkkkkmkmkmkkkk... ..kkkkkkmkmkmkkkk... ..kkkkmkmkmkmkkkk... ..kkkkkmmmmmkkkkk... ...kkkkkmkmkkkkk.... ....kkkkkkkkkkk..... .................... .................... # APRS % Power Plant (w overlay) nnoooooooooonn...... ..nnnooooooooon..... .....nnnooooooonn... ........nnnoooooon.. ...........nnnoooon. ..............nnnoon ................qqqq ................qqqq ..........q...q.qqqq .........qq..qq.qqqq ........qqq.qqq.qqqq ......qqqqqqqqqqqqqq ......qqqqqqqq#qqqqq ......qqqqqqq#qqqqqq ......qqqqqq#qqqqqqq ......qqqqqqq#qqqqqq ......qqqqqqqq#qqqqq ......qqqqqqq#qqqqqq ......qqqqqq#qqqqqqq ......qqqqqqqqqqqqqq # APRS & Any Gateway (diamond) (w overlay) .................... .................... .........qq......... ........qqqq........ .......qqqqqq....... ......qqmmmmqq...... .....qqmmmmmmqq..... ....qqmmmmmmmmqq.... ...qqmmmmmmmmmmqq... ..qqqmmmmmmmmmmqqq.. ..qqqmmmmmmmmmmqqq.. ...qqmmmmmmmmmmqq... ....qqmmmmmmmmqq.... .....qqmmmmmmqq..... ......qqmmmmqq...... .......qqqqqq....... ........qqqq........ .........qq......... .................... .................... # APRS ' Crash Site ..ppppppppp......... ....pppppppp........ .......ppppp........ .......ppppp........ .......pppp......... ......pppp.......... .....ppp........j... .....ppp.......jmj.. ......ppp.....jmmj.. .......ppp....jmaj.. ..jjj....pp...jamj.. ..jmmj...pp..jammj.. ..jmmmj.p...jmmmj... ...jmmmjj..jmmmj.... ....jmmmj.jmmmj..... .....jmmjjjjjj...... ..kkkkjjjjjjjkkkkk.. ..ffffffffffffffff.. j.....j.j........... ..jj..j..j.......... # APRS ( Cloudy .................... .................... ..ccccccccc......... ...ccccccccccc...... .....ccnccccccc..... ........ncccccccc... ...cccccccccccccc... ..ccccccccnccccccc.. ..cccccccccncccccc.. ..cccccccccncccccc.. ..ccccccccnccccccc.. ..nnnccnnnccccccnn.. ...nnpppnnnppppnn... .................... .................... .................... .................... .................... .................... .................... # APRS ) MEO (MODIS EARTH OBSERVATION) .................... .................... .................... .................... .................... ....jjjjjqqjjjjj.... ....jqqjjqqjjqqj.... ....jjjqjqqjqjjj.... ....jjjjqqqqjjjj.... ....jqqqqqqqqqqj.... ....jqqqqqqqqqqj.... ....jjjjqqqqjjjj.... ....jjjqjqqjqjjj.... ....jqqjjqqjjqqj.... ....jjjjjqqjjjjj.... .................... .................... .................... .................... .................... # APRS * Snow .................... .................... ............h....... ...........hh....... ....hh....hhh....... ....hhhh..hhh....... .....hhhh.hhh....... ......hhhhhh..hhhh.. ......hhhhhhhhhhh... .......hhhhhhhhh.... ....hhhhhhhhh....... ...hhhhhhhhhhh...... ..hhhh..hhhhhh...... ........hh.hhhh..... .......hhh..hhhh.... .......hhh....hh.... .......hh........... .......h............ .................... .................... # APRS + Church .................... .................... .........qq......... .........qq......... .........qq......... ...qqqqqqqqqqqqqq... ...qqqqqqqqqqqqqq... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .................... .................... # APRS , Girl Scouts .................... .................... ......jjjjjjj....... ......j.....j....... .......j...j........ ..jj...j...j...jjj.. ..j.jjjj...jjjj..j.. ..j..............j.. ..j..............j.. ..j..............j.. ..j..............j.. ..jjjj.......jjjjj.. ......j.....j....... .......j...j........ ........j.j......... .ppp.....j.......p.. p................p.. .pp..pp.ppp.p.p.ppp. ...p.p..p.p.p.p..p.. ppp..pp.ppp.ppp..p.. # APRS - House (HF) .................... .........qqq........ ..q..q....q...qqqq.. ..q..q....q...q..... ..qqqq....q...qqq... ..q..q....q...q..... ..q..q...qqq..q..... ........qqqqq....... .......qqqqqqq...... ......qqqqqqqqq..... .....qqqqqqqqqqq.... ....qqqqqqqqqqqqq... ......q#######q..... ......q#q###q#q..... ......q###q###q..... ......q###q###q..... ......qqqqqqqqq..... .................... .................... .................... # APRS . Ambiguous Plot (Big Question Mark) .....jjjjjjjjjj..... ....jjjjjjjjjjjj.... ..jjjj........jjjj.. .jjj............jjj. jjj..............jjj jjj..............jjj .................jjj ................jjj. ...............jjj.. ..............jjj... ...........jjjjj.... ........jjjjjj...... ........jjjj........ ........jjjj........ ........jjjj........ .................... .................... ........jjjj........ ........jjjj........ ........jjjj........ # APRS / Waypoint (destination) ..q.......q.qqqqqq.. ..q.......q.q....q.. ..q.......q.q....q.. ...q..q..q..qqqqqq.. ...qq.q.qq..q....... ....qq.qq...q....... .................... ........jjjj........ .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... .......jjjjjj....... ........jjjj........ .................... .................... .................... .................... .................... .................... .................... # APRS 0 Circle (w overlay) ........qqqq........ ......qmmmmmmq...... .....qmmmmmmmmq..... ...qmmmmmmmmmmmmq... ..qmmmmmmmmmmmmmmq.. .qmmmmmmmmmmmmmmmmq. .qmmmmmmmmmmmmmmmmq. qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq qmmmmmmmmmmmmmmmmmmq .qmmmmmmmmmmmmmmmmq. .qmmmmmmmmmmmmmmmmq. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... .....qmmmmmmmmq..... ......qmmmmmmq...... ........qqqq........ # #APRS 1 # #APRS 2 # #APRS 3 # #APRS 4 # #APRS 5 # #APRS 6 # #APRS 7 # #APRS 8 # APRS 9 Gas Station (blue pump) .................... .................... ......llll.......... .....llllll......... ....llmmmmlll....... ....lllllllll....... ....llmmmmll.l...... ....llllllll.l...... ....llllllll..l..... ....llllllll..l..... ....llllllll..l..... ....llllllll..l..... ....lllllllll.l..... ....llllllll.l...... ....llllllll........ ....llllllll........ ....llllllll........ ....llllllll........ .................... .................... # APRS : Hail .................... .................... .........qq......... ........qmmq........ .......qmmmmq....... ......qmmmmmmq...... .....qmmmmmmmmq..... ....qmmmmmmmmmmq.... ...qqqqqqqqqqqqqq... .................... .................... ...qqqqqqqqqqqqqq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS ; Park/Picnic Area .................... .................... ....hhhhhhhhhhhh.... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ...hhhhmmmmmmhhhh... ...hhhhhmhhmhhhhh... ...hhhhhhmmhhhhhh... ...hhhhhhmmhhhhhh... ...hhhhhmhhmhhhhh... ...hmmmmmmmmmmmmh... ...hhhmhhhhhhmhhh... ...hhmhhhhhhhhmhh... ...hmhhhhhhhhhhmh... ...hhhhhhhhhhhhhh... ...hhhhhhhhhhhhhh... ....hhhhhhhhhhhh.... .................... .................... # APRS < NWS Advisory (gale flag) .................... .................... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjjqq...... ........qjqq........ ........qq.......... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... ........q........... .................... .................... # #APRS = # APRS > l Car (w overlay) .................... .................... .................... .................... .........ppppp...... ........pcccncp..... .......pccccnccp.... ......pcccccncccp... ...pppnqnnnnnnnnnp.. ..pmmmmmmmmmmmmmmmp. .pmmmmmmmmmmmmmmmmep p#mmoommmmmmmmmoommp pmmonnommmmmmmonnomp .ppqnnqpppppppqnnqp. ....qq.........qq... .................... .................... .................... .................... .................... # APRS ? Information Kiosk (blue box with ?) .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhmmmhhhhhhh.. ..hhhhhmmmmmhhhhhh.. ..hhhhmmhhhmmhhhhh.. ..hhhmmhhhhhmmhhhh.. ..hhhmmhhhhhmmhhhh.. ..hhhhhhhhhhmmhhhh.. ..hhhhhhhhhmmhhhhh.. ..hhhhhhhhmmhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhmmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS @ Hurricane/Tropical Storm .................... .................... .....l...lggggl..... ....g..lgllllllgl... ...lg..glllgggllg... ...g..llllglllglll.. ..ll..gllglllllglg.. ..gl..lllglllllllg.. ..ll..llgllgll.lll.. ..ll..lll..lll..ll.. ..ll..lll..lll..ll.. ..gll.llgllgll..lg.. ..glllllllglll..lg.. ..glglllllgllg..ll.. ..lllglllgllll..g... ...lllggglllg..gl... ...lgglllllgl..g.... .....lggggl...l..... .................... .................... # APRS A Box (w overlay) .................... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qqqqqqqqqqqqqqqq.. .................... .................... # APRS B Blowing Snow .................... .................... .................... ..qq..q...q..q...q.. ..q.q.q..q.q.q...q.. ..qq..q..q.q.q.q.q.. ..q.q.q..q.q.qq.qq.. ..qq..qq..q..q...q.. .................... ..qq.q.q..q..q...q.. ..q..qqq.q.q.q...q.. ...q.qqq.q.q.q.q.q.. ...q.qqq.q.q.qq.qq.. ..qq.q.q..q..q...q.. .................... .................... .................... .................... .................... .................... # APRS C Coast Guard .................... .................... .................... .................... .................... ...qqqq.....qqqqq... ..q....q...q........ ..q........q........ ..q........q........ ..q........q..qqqq.. ..q........q.....q.. ..q....q...q.....q.. ...qqqq.....qqqqqq.. .................... ..g.g.g.g.g.g.g.g... ...g.g.g.g.g.g.g.g.. .................... .................... .................... .................... # APRS D Drizzle .................... .................... .................... ..qq..qqq..q.qqqqq.. ..q.q.q..q.q....q... ..q.q.qqq..q...q.... ..q.q.q.q..q..q..... ..qq..q..q.q.qqqqq.. .................... ..qqq....q...q.q.q.. ..q..q..q.q..q.qqq.. ..qqq..qqqqq.q.qqq.. ..q.q..q...q.q.qqq.. ..q..q.q...q.q.q.q.. .................... .................... .................... .................... .................... .................... # APRS E Smoke .................... .................... ...mqqqqqqqqqqqm.... .mqqqqqqqqqqqqqqm... ...mqqqqqqqqqqqm.... ......mqqqqqqqqqqm.. ........mqqqqm...... ..........mqppqm.... ........mqqqqm...... .......mqppqm....... ........mqjjqm...... ........mqjpqm...... ......mqqjjqqqm..... ....mqqqjjqqqqqm.... ...mqqqjjjqqqppqm... ..mqqqqqjjppqqqqqm.. .mqqqqqqqjjqqqqqqqm. .mqqqqqqppjjjjrqqqm. .mmmmmmmmmmmmmmmmmm. .................... # APRS F Freezing Rain .................... .................... .................... ..qqqqq.qqq..qqqqq.. ..q.....q..q....q... ..qqqq..qqq....q.... ..q.....q.q...q..... ..q.....q..q.qqqqq.. .................... ..qqq....q...q.q.q.. ..q..q..q.q..q.qqq.. ..qqq..qqqqq.q.qqq.. ..q.q..q...q.q.qqq.. ..q..q.q...q.q.q.q.. .................... .................... .................... .................... .................... .................... # APRS G Snow Shower .................... .................... .......q....q....... ........qq.q........ .........qqqqq...... ......qqqqq......... ........q.qq........ .......q....q....... .................... ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS H Haze q..q................ q..q................ qqqq................ q..q................ q..q................ ......q............. .....q.q............ ....q...q........... ....qqqqq........... ....q...q........... ..........qqqqq..... .............q...... ............q....... ...........q........ ..........qqqqq..... ................qqqq ................q... ................qqqq ................q... ................qqqq # APRS I Rain Shower .................... .................... ........qqqq........ .......qqqqqq....... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .......qqqqqq....... ........qqqq........ ..qqqqqqqqqqqqqqqq.. ..qmmmmmmmmmmmmmmq.. ...qmmmmmmmmmmmmq... ....qmmmmmmmmmmq.... .....qmmmmmmmmq..... ......qmmmmmmq...... .......qmmmmq....... ........qmmq........ .........qq......... .................... .................... # APRS J Lightning .................... .................... ..............qqqq.. .............qq##q.. .............q###q.. ............qq##qq.. .......q....q###q... ......qqq...q##qq... ......q#qq.q##qq.... .....qq##qqq##q..... .....q####q##qq..... ....qq#qq###qq...... ....q#qqqq#qq....... ...qq#q..qqq........ ...q#q....q......... ..qq#q.............. ..q#q............... ..qq................ ..q................. .................... # APRS K Kenwood .................... .................... .................... .......jjjjjjj...... ....qqq.jjjjj.qqq... ....qqq..jjj..qqq... ....qqq..jjj..qqq... ....qqqq.cqc.qqq.... .....qqqqcqcqqqq.... ......qqqqqqqqq..... ......qqqqcqqqq..... .......qqq.qqq...... .......qqq.qqq...... ........qq.qq....... ........q...q....... .................... .................... .................... .................... .................... # APRS L Lighthouse .................... .................... ....q..........q.... .....q..qqqq..q..... ......q.qmmq.q...... ......qqqmmqqq...... .....q.qqqqqq.q..... ....q..qqqqqq..q.... .......qqqqqq....... .......qqqqqq....... .......qqqqqq....... .......qqqqqq....... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .................... .................... # #APRS M # APRS N Navigation Buoy .................... .................... ........qqqqq....... ........q...q....... ........q...q....... ........qqqqq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ...qqqqqqqqqqqqqqq.. hh.....hhh.....hhh.. ..h...h...h...h...h. ...hhh.....hhh.....h ....h.......h......h .................... .................... # APRS O Rocket ..........q......... ..........q......... ..........q......... ..........q......... .........qmq........ ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmmmq....... ........qmqmq....... ........qmqmq....... .......qqmqmqq...... ......qqqmqmqqq..... .....qqqqmqmqqqq.... ....qqqqqmqmqqqqq... ....qqqqqqqqqqqqq... # APRS P Parking .................... .................... ....hhhhhhhhhhh..... ...hhhhhhhhhhhhh.... ...hhmmmmmmmmhhh.... ...hhmmmmmmmmmhh.... ...hhmmhhhhhmmhh.... ...hhmmhhhhhmmhh.... ...hhmmhhhhhmmhh.... ...hhmmmmmmmmmhh.... ...hhmmmmmmmmhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhmmhhhhhhhhh.... ...hhhhhhhhhhhhh.... ....hhhhhhhhhhh..... .................... .................... # APRS Q Earthquake .................... .................... .......qqqqqq....... .....qqmmmmmmqq..... ....qmmmmmmmmmmq.... ...qmmmmqqqqmmmmq... ...qmmqqmmmmqqmmq... ..qmmmqmmmmmmqmmmq.. ..qmmqmmmmmmmmqmmq.. ..qmmqmmmqqmmmqmmq.. ..qmmqmmmqqmmmqmmq.. ..qmmqmmmmmmmmqmmq.. ..qmmmqmmmmmmqmmmq.. ...qmmqqmmmmqqmmq... ...qmmmmqqqqmmmmq... ....qmmmmmmmmmmq.... .....qqmmmmmmqq..... .......qqqqqq....... .................... .................... # APRS R Restaurant .................... .................... ..hhhhhhhhhhhhhhhh.. ..hhhhhhhhmhhhhhhh.. ..hmhhhmhhmhhhmhhh.. ..hmhmhmhhmhhmhmhh.. ..hmhmhmhhmhmhhhmh.. ..hmhmhmhhmhmhhhmh.. ..hmhmhmhhmhmhhhmh.. ..hhmmmhhhmhhmhmhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhmhhhhmhhhmhhh.. ..hhhhhhhhmhhhhhhh.. ..hhhhhhhhhhhhhhhh.. .................... .................... # APRS S Satellite/Pacsat .................... ..........q......... ..........q......... ..........q......... ..........q......... ....n...qqqqqqqq.... ....cn.q..q...qq.... ....cnqqqqqqqq.q.... ....cnqqqqqqqq.q.... ....cnqqqqqqqq.q.... ....n.qqqqqqqq.q.... ......qqqqqqqq.q.... ......qqqqqqqqq..... ......qqqqqqqq...... .....q........q..... ....q..........q.... ...q............q... ..q..............q.. .................... .................... # APRS T Thunderstorm .................... .................... .....qqqqqqqqqqq.... ...qqqmmqqqcmmmmq... ...qmmmmmqqcmmmmq... ..qmmmmmmqqqcmpppq.. ..qmmmccqqqqcppppq.. ..pqqqqccqqqcppppq.. ..pppqpcpppppppppp.. ..pppppppppppppppp.. ..ppppppppppppppp... ...pppppppppppp..... .........q#q........ ........q#q......... .......q###q........ ........q#q......... .......q#q.......... .......qq........... .................... .................... # APRS U Sunny .................... .................... .................... ......a..a..a....... .......a.a.a........ ....a.........a..... .....a.#####.a...... ..a...#######...a... ...a.#########.a.... .....#########...... ..aa.#########.aa... .....#########...... ...a.#########.a.... ..a...#######...a... .....a.#####.a...... ....a.........a..... .......a.a.a........ ......a..a..a....... .................... .................... # APRS V VORTAC Nav Aid .................... .................... .................... .................... ...qq..........qq... ..qqqqqqqqqqqqqqqq.. .qqqqq........qqqqq. qqqqq..........qqqqq qqqq.....qq.....qqqq .qq.....qqqq.....qq. ..q.....qqqq.....q.. ...q.....qq.....q... ....q..........q.... .....q........q..... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... ......qqqqqqqq...... .................... .................... # APRS W NWS Site (w overlay) .................... .................... .......hhhhhh....... .....hhmmmmmmhh..... ....hmmmmmmmmmmh.... ...hmmmmmmmmmmmmh... ...hmmmmmmmmmmmmh... ..hppmmmppmppmmpph.. ..hppmmmppmpppppph.. ..hppmmmppmmppppmh.. ..hppmpmppmmppppmh.. ..hpppppppmpppppph.. ..hpppmpppmppmmpph.. ...hmmmmmmmmmmmmh... ...hmmmmmmmmmmmmh... ....hmmmmmmmmmmh.... .....hhmmmmmmhh..... .......hhhhhh....... .................... .................... # APRS X Pharmacy Rx .................... .................... ..pppppppp.......... ..ppppppppp......... ..pp.....pp......... ..pp.....pp......... ..pp....pp.......... ..ppppppp........... ..pppppp............ ..pp..pp............ ..pp...pp........... ..pp....pp.....pp... ..pp.....pp...pp.... ..pp......pp.pp..... ...........ppp...... ...........pp....... ..........pp.pp..... .........pp...pp.... ........pp.....pp... .................... # #APRS Y # #APRS Z # APRS [ Wall Cloud .................... .................... ................ll.. ..............llcl.. ............llcccl.. ..........llccllcl.. ........llccclllcl.. ......llccccllcccl.. ....llcccllcllcccl.. ..llcccccllcllcccl.. ..lccccccllcllcccl.. ..lcllcccllcllcccl.. ..lcllclcllcllcccl.. ..lclllllllcllcccl.. ..lclllclllcllllcl.. ..lcllcccllcclllcl.. ..lccccccccccccccl.. ..llllllllllllllll.. .................... .................... # #APRS \ # #APRS ] # APRS ^ l Aircraft (w overlay) .................... .................... .........nn......... .........nn......... ........n.n......... ........n.n......... ........n.n......n.. .......n..n.....nn.. .......n..n....n.n.. ..n.n.n.n.n.n.n..n.. ..n.n.n.n.n.n.n..n.. .......n..n....n.n.. .......n..n.....nn.. ........n.n......n.. ........n.n......... ........n.n......... .........nn......... .........nn......... .................... .................... # APRS _ WX Stn with digi (green) (w overlay) .................... .................... .......kkkkkk....... .....kkkkkkkkkk..... ....kkkkkkkkkkkk.... ...kkkkkkkkkkkkkk... ...kkkkkkkkkkkkkk... ..kmmkkkmmkmmkkmmk.. ..kmmkkkmmkmmmmmmk.. ..kmmkkkmmkkmmmmkk.. ..kmmkmkmmkkmmmmkk.. ..kmmmmmmmkmmmmmmk.. ..kmmmkmmmkmmkkmmk.. ...kkkkkkkkkkkkkk... ...kkkkkkkkkkkkkk... ....kkkkkkkkkkkk.... .....kkkkkkkkkk..... .......kkkkkk....... .................... .................... # APRS ` Rain .................... .................... pppppppppppppppppppp pppppppppppppppppppp pppppppppppppppppppp pppppppppppppppppppp ...pp...pp...pp...pp .................... .................... ..p..p..p..p..p..p.. .................... .................... .p..p..p..p..p..p... .................... .................... ...p..p..p..p..p..p. .................... .................... .p..p...p...p...p... .................... # APRS a A=ARES R=RACES W=Winlink etc. (w overlay) .........j.......... ........jjj......... .......jjjjj........ ......jjjjjjj....... .....jjjjjjjjj...... ....jjjjjjjjjjj..... ...jjjjjjjjjjjjj.... ..jjjjjjjjjjjjjjj... .jjjjjjjjjjjjjjjjj.. jjjjjjjjjjjjjjjjjjj. .jjjjjjjjjjjjjjjjj.. ..jjjjjjjjjjjjjjj... ...jjjjjjjjjjjjj.... ....jjjjjjjjjjj..... .....jjjjjjjjj...... ......jjjjjjj....... .......jjjjj........ ........jjj......... .........j.......... .................... # APRS b Blowing Dust/Sand .................... .................... .....qqq............ ...qqqmmq.......q... ...qmmmmmq....qq..q. ..qmmmmmmq..qq..qq.. ..qmmmmqqqqqqqqq.... ..qnmnmccqqqqq...... ..qmnmncqqqq..qqqq.. ..qnmnmnmnq.qqq..... ..qmnmnmnmq....qqq.. ...qqqqqqq.......q.. .................... ..qq..q...q..q...q.. ..q.q.q..q.q.q...q.. ..qq..q..q.q.q.q.q.. ..q.q.q..q.q.qq.qq.. ..qq..qq..q..q...q.. .................... .................... # APRS c Civil Defense (R=RACES, C=CERTS) (w overlay) .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ...qqqq...qqqq...... ..q.......q...q..... ..q.......q...q..... ..q.......q...q..... ...qqqq...qqqq...... .................... .................... # APRS d DX spot (by callsign prefix) .................... ..q.q.q......q.q.q.. ..q.q.q.lhhl.q.q.q.. ..qqqqqqqqqqqqqqqq.. ..q.q.q.lhhl.q.q.q.. ..q.q.q.lhhl.q.q.q.. ........lhhl........ ........lhhl........ ........lhhl........ ........lhhl........ .......llhhll....... .......lhllhl....... .......llhhll....... ..qqq..llhhll.q..q.. ..q..q.lhllhl.q..q.. ..q..q.lhllhl..qq... ..q..q.llhhll.q..q.. ..qqq..llllll.q..q.. .................... .................... # APRS e Sleet .................... .................... .....qqqqqqqqqqq.... ...qqqmmqqqqmmmmq... ..qmmmmmmqqqmmmmmq.. .qmmmmmmmqqqcmppppq. .qmmmmqqqqqqcpppppq. .ppqqqqccqqqcpppppq. .pppqpccppppppppppp. .pppppppppppppppppp. ..pppppppppppppppp.. ...ppppppppppppp.... .................... ...qq.q..qq.qq.qqq.. ..q...q..q..q...q... ...q..q..qq.qq..q... ....q.q..q..q...q... ..qq..qq.qq.qq..q... .................... .................... # APRS f Funnel Cloud .................... .................... ..qqqq....cnnnnnc... ..q......cnnppppnc.. ..qqq....nnppppppn.. ..q......cnpppppnc.. ..q.......cnpppnc... ..q........cpppn.... ............npppc... ............cpppc... ...qq......cnppn.... ..q..q.....pppc..... ..q.......npp....... ..q.......pppc...... ..q.......pppc..c... ..q..q....npncc.c... ...qq......cppcc.... .............pq..... .................... .................... # APRS g Gale Flags .................... .................... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjqqq...... ........qjq......... ........qq.......... ........qjqq........ ........qjjjqq...... ........qjjjjjq..... ........qjjjqq...... ........qjqq........ ........qq.......... ........q........... ........q........... ........q........... .................... .................... # APRS h Ham Store .................... .........pp......... ........p##p........ .......p####p....... ......p######p...... .....p########p..... ....p##########p.... ...p############p... ..p##############p.. .pp##############pp. ..p##############p.. ..p#p##p##p##p#p#p.. ..p#p##p#p#p#ppp#p.. ..p#pppp#ppp#p#p#p.. ..p#p##p#p#p#p#p#p.. ..p#p##p#p#p#p#p#p.. ..p##############p.. ..pppppppppppppppp.. .................... .................... .................... # APRS i Indoor Short Range Digi (w overlay) .................... .................... ..ppp............... ..p..p.............. ..p..p.............. ..p..p.............. ..ppp...p........... ........p........... ........p........... ........p........... ........p...ppp..... ...........p........ ...........p.pp..... ...........p..p..... ............ppp..p.. .................p.. .................p.. .................p.. .................p.. .................... # APRS j l Work Zone (steam shovel) .................... .................... .................... .................... ........pp.......... .......pppp......... ......pp..pp........ .....pp....pp....... p...pp......pppppp.. .ppppp......p#pp#p.. .p###p......p#pp#p.. .ppppp....pp#####p.. ..........p######p.. ..........ppppppppp. .........pmmmp.pmmmp .........ppppp.ppppp .................... .................... .................... .................... # APRS k l SUV .................... .................... .................... .................... ..........ddddddddd. .........d...d....d. ........d....d....d. .......ddp...d....d. .ddddddddddddddddddq d#dddddddddddddddddq ndqqqddddpppddqqqddq nqqcqqdddddddqqcqqnn .qcmcqoonnnnnqcmcqq. .oqcqo.......oqcqo.. ..oqo.........oqo... .................... .................... .................... .................... .................... # APRS l Area Symbols (box, circle, etc) .................... .................... .................... .................... .................... .................... .................... .................... .................... .........jj......... .........jj......... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS m Value Signpost (3-char display) .................... .................... .........qq......... ...qqqqqqqqqqqqqq... ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ..qmmmmmmmmmmmmmmq.. ...qqqqqqqqqqqqqq... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .........qq......... .................... .................... # APRS n Triangle (w overlay) .................... .................... .................... .................... .................... .................... .........jj......... .........jj......... ........jjjj........ ........jjjj........ .......jjjjjj....... .......jjjjjj....... ......jjjjjjjj...... ......jjjjjjjj...... .................... .................... .................... .................... .................... .................... # APRS o Small Circle .................... .................... .................... .................... .................... .................... .................... .........jj......... .......j....j....... ......j......j...... ......j......j...... ......j......j...... .......j....j....... .........jj......... .................... .................... .................... .................... .................... .................... # APRS p Partly Cloudy ............q....... ........i.i.k.i.k... .........k......i... ...........q#q...i.. ......iqqq#####k.k.. .....qooooq#####i.ik ....ioooooo#####q... ...iioonnooqqq###.ki ..qooqqncoqqonq##... .qoonooonooooooqk.ik .qnncnonnnonnooq.... .qoonnnccnnccnoq.i.. ..qqoonnnnnnoqi.k... ....qqqqqqqqq.i.i... ....hlhlh.lhq.k..... ....h.h.l.hh........ ....l.lh.l.l........ ....h.hh.h.h........ ...l.l.l.lh......... .................... # #APRS q # APRS r Restrooms hhhhhhhhhhhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhmhhhhmhhhhhmhhhh hhhmmmhhhmhhhhmmmhhh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhhmhhhh hmmmmmmmhmhhmmmmmmmh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhhmhhhh hhhhmhhhhmhhhhmmmhhh hhhhmhhhhmhhhhmmmhhh hhhmhmhhhmhhhmmmmmhh hhmhhhmhhmhhhmmmmmhh hmhhhhhmhmhhmmmmmmmh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhmhhhhhhhhhh hhhhhhhhhhhhhhhhhhhh # APRS s l Ship/Boat (top view) (w overlay) .................... .................... .................... .................... .................... .................... ........qqqq.....q.. .......q...q....q... ......q....q...q.... ..iiii.....iiiiiii.. ..i..............i.. ...i.............i.. ....iiiiiiiiiiiiii.. .................... .................... .................... .................... .................... .................... .................... # APRS t Tornado .......mmmmmmmm..... ......mmqqqqqqmm.... ....mmqjnnnnnnnqjmm ...mmqjnnnppppnnjqmm ...mmqjnnppppppppjqm ....mmqjnpppppnjqmm. .....mmqjnpppnjqmm.. ......mmqjpppnqmm... .......mmqnpppqqmm.. .......mmqjpppqqmm.. ......mmqjnppnqmm... ......mmqpppqqmm.... .....mmqnppqmm...... .....mmqpppbmmqmm... .....mmqpppbmmbqmm.. .....mmqnpnbbmbqmm.. ......mmqcppmbqmm... ........mmqpqqmm.... .........mmqmm...... ..........mmm....... # APRS u l Truck (w overlay) .................... .................... .................... .................... ........jjj......... .......j..j......... ......j...j......... .....j....j......... ..jjj......jjjjjjj.. ..j..............j.. ..j..............j.. ..qpppj.....jpppjq.. ..qpcpjjjjjjjpcpjq.. ...ppp.......ppp.... .................... .................... .................... .................... .................... .................... # APRS v l Van (w overlay) .................... .................... .................... .................... .................... .......hhhhhhhhhhh.. ......h...........h. .....h............h. ....h.............h. ..h...............h. .h................j. .h................h. .ohqqh........hqqho. .hqccqhhhhhhhhqccqh. ..qccq........qccq.. ...qq..........qq... .................... .................... .................... .................... # APRS w Flooding .................... .................... .................... .................... .................... ...c.....c.....c.... ....h.....h.....h... ...lll...lll...lll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..llllllllllllllll.. ..cchclhchlhchlcch.. ..cllclclclclclclc.. ..cclclclclclclclc.. ..cllcchchlhchlcch.. ..llllllllllllllll.. .................... .................... # #APRS x # APRS y Skywarn qqqqqqqqqmmqqqqqqqqq qqqqqqqmqqqqmqqqqqqq qqqqqmqqqqqqqqmqqqqq qqqqmqqqqqqqqqqmqqqq qqqmmqqqqqqqqqqmmqqq qqmmqqaqqqqqqaqqmmqq qmmmqqaaqqqqaaqqmmmq qmmqqaaaqqqqaaaqqmmq mmmqqaaaqqqqaaaqqmmm mmmqqaaaqqqaaaaqqmmm mmmqqaaaqqqaaaaqqmmm mmmqqaaaaqqaaaaqqmmm qmmqqaaaaaqqaaaqqmmq qmmmqqaaaaqqaaqqmmmq qqmmqqaaaaqqaaqqmmqq qqqmmqqaaqqaaqqmmqqq qqqqmqqaaqaaaqqmqqqq qqqqqmqqqqqqqqmqqqqq qqqqqqqmqqqqmqqqqqqq qqqqqqqqqmmqqqqqqqqq # APRS z Shelter (Evacuation) w overlay .................... .........pp......... ........pjjp........ .......pjjjjp....... ......pjjjjjjp...... .....pjjjjjjjjp..... ....pjjjjjjjjjjp.... ...pjjjjjjjjjjjjp... ..pjjjjjjjjjjjjjjp.. ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... ...pjjjjjjjjjjjjp... .................... .................... .................... # APRS { Fog .................... .................... .................... .................... .................... ..qqqq..qqq...qqq... ..q....q...q.q...q.. ..q....q...q.q...q.. ..qqq..q...q.q...... ..q....q...q.q...... ..q....q...q.q..qq.. ..q....q...q.q...q.. ..q....q...q.q...q.. ..q.....qqq...qqq... .................... .................... .................... .................... .................... .................... # #APRS | Reserved - TNC Stream Switch # #APRS } # #APRS ~ Reserved - TNC Stream Switch # # # ------------------------- # TABLE # # APRS 0 Overlay Characters, etc .................... .................... .................... .................... .........cc......... ........cqqc........ .......cqccqc....... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... .......cqccqc....... ........cqqc........ .........cc......... .................... .................... .................... .................... .................... # APRS 1 .................... .................... .................... .................... .........ccc........ ........ccqc........ ........cqqc........ ........ccqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS 2 .................... .................... .................... .................... ........ccccc....... .......ccqqqqc...... ......ccqcccqc...... ......cqcc.cqc...... ......ccc.ccqc...... .........ccqcc...... ........ccqcc....... .......ccqcc........ ......ccqccccc...... ......cqqqqqqc...... ......cccccccc...... .................... .................... .................... .................... .................... # APRS 3 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......cccccqcc...... ........ccqcc....... .........qqcc....... ........cccqcc...... ..........ccqc...... ......ccc.ccqc...... ......cqcccqcc...... ......ccqqqcc....... .......ccccc........ .................... .................... .................... .................... .................... # APRS 4 .................... .................... .................... .................... ...........ccc...... ..........ccqc...... .........ccqqc...... ........ccqcqc...... .......ccqccqc...... ......ccqc.cqc...... ......cqccccqcc..... ......cqqqqqqqc..... ......ccccccqcc..... ...........cqc...... ...........ccc...... .................... .................... .................... .................... .................... # APRS 5 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......cqcccccc...... ......cqcccc........ ......cqqqqqc....... .......cccccqc...... ...........cqc...... ......ccc..cqc...... ......cqccccqc...... ......ccqqqqc....... .......cccccc....... .................... .................... .................... .................... .................... # APRS 6 .................... .................... .................... .................... .........ccc........ ........cqqqc....... .......cqccc........ ......cqcccc........ ......cqqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS 7 .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqc...... ......ccccccqc...... ..........cqcc...... .........ccqc....... .........cqcc....... ........ccqc........ ........cqcc........ ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS 8 .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqccccqc...... ......ccqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS 9 .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqqc...... ........ccccqc...... ........cccqcc...... .......cqqqcc....... ........cccc........ .................... .................... .................... .................... .................... # APRS A .................... .................... .................... .................... .........ccc........ .........cqc........ ........ccqcc....... ........cqcqc....... .......ccqcqcc...... .......cqc.cqc...... ......ccqc.cqcc..... ......cqqqqqqqc..... ......cqcccccqc..... ......cqc...cqc..... ......ccc...ccc..... .................... .................... .................... .................... .................... # APRS B .................... .................... .................... .................... ......cccccc........ ......cqqqqqc....... ......cqccccqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqccccqc...... ......cqc...qc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS C .................... .................... .................... .................... .......cccccc....... ......ccqqqqcc...... ......cqccccqc...... ......cqc..ccc...... ......cqc........... ......cqc........... ......cqc........... ......cqc..ccc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS D .................... .................... .................... .................... ......cccccc........ ......cqqqqcc....... ......cqcccqcc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqcccqcc...... ......cqqqqcc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS E .................... .................... .................... .................... ......ccccccc....... ......cqqqqqc....... ......cqccccc....... ......cqc........... ......cqcccc........ ......cqqqqc........ ......cqcccc........ ......cqc........... ......cqccccc....... ......cqqqqqc....... ......ccccccc....... .................... .................... .................... .................... .................... # APRS F .................... .................... .................... .................... ......ccccccc....... ......cqqqqqc....... ......cqccccc....... ......cqc........... ......cqcccc........ ......cqqqqc........ ......cqcccc........ ......cqc........... ......cqc........... ......cqc........... ......ccc........... .................... .................... .................... .................... .................... # APRS G .................... .................... .................... .................... .......cccccc....... ......ccqqqqcc...... ......cqccccqc...... ......cqc...c....... ......cqc.cccc...... ......cqccqqqc...... ......cqc.ccqc...... ......cqc...qc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS H .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqqc...... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS I .................... .................... .................... .................... ........ccc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS J .................... .................... .................... .................... ..........ccc....... ..........cqc....... ..........cqc....... ..........cqc....... ..........cqc....... ..........cqc....... .....ccc..cqc....... .....cqc..cqc....... .....cqccccqc....... .....ccqqqqcc....... ......cccccc........ .................... .................... .................... .................... .................... # APRS K .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc.cqcc...... ......cqccqcc....... ......cqcqcc........ ......cqqcc......... ......cqcqcc........ ......cqccqcc....... ......cqc.cqcc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS L .................... .................... .................... .................... ......ccc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqc........... ......cqccccc....... ......cqqqqqc....... ......ccccccc....... .................... .................... .................... .................... .................... # APRS M .................... .................... .................... .................... ......ccc...ccc..... ......cqcc.ccqc..... ......cqqc.cqqc..... ......cqcqcqcqc..... ......cqccqccqc..... ......cqcccccqc..... ......cqc...cqc..... ......cqc...cqc..... ......cqc...cqc..... ......cqc...cqc..... ......ccc...ccc..... .................... .................... .................... .................... .................... # APRS N .................... .................... .................... .................... ......cccc.ccc...... ......cqqc.cqc...... ......cqqc.cqc...... ......cqcqccqc...... ......cqcqccqc...... ......cqccqcqc...... ......cqccqcqc...... ......cqc.cqqc...... ......cqc.cqqc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS O .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS P .................... .................... .................... .................... ......ccccccc....... ......cqqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqccccc....... ......cqc........... ......cqc........... ......cqc........... ......ccc........... .................... .................... .................... .................... .................... # APRS Q .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......cqccqcqc...... .......cqqqqc....... ........ccccqc...... ............cc...... .................... .................... .................... .................... # APRS R .................... .................... .................... .................... ......ccccccc....... ......cqqqqqcc...... ......cqccccqc...... ......cqc..cqc...... ......cqccccqc...... ......cqqqqqcc...... ......cqcqccc....... ......cqccqcc....... ......cqc.cqcc...... ......cqc..cqc...... ......ccc..ccc...... .................... .................... .................... .................... .................... # APRS S .................... .................... .................... .................... ........cccc........ .......cqqqqc....... ......cqccccqc...... ......cqc...c....... ......cqcccc........ .......cqqqqc....... ........ccccqc...... ......ccc..cqc...... ......cqccccqc...... .......cqqqqc....... ........cccc........ .................... .................... .................... .................... .................... # APRS T .................... .................... .................... .................... ......ccccccccc..... ......cqqqqqqqc..... ......ccccqcccc..... .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS U .................... .................... .................... .................... ......ccc..ccc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqc..cqc...... ......cqccccqc...... ......ccqqqqcc...... .......cccccc....... .................... .................... .................... .................... .................... # APRS V .................... .................... .................... .................... ......ccc...ccc..... ......cqc...cqc..... ......cqc...cqc..... ......cqcc.ccqc..... ......ccqc.cqcc..... .......cqc.cqc...... .......ccqcqcc...... ........cqcqc....... ........ccqcc....... .........cqc........ .........ccc........ .................... .................... .................... .................... .................... # APRS W .................... .................... .................... .................... .....ccc.....ccc.... .....cqc.....cqc.... .....cqc..c..cqc.... .....cqc.cqc.cqc.... .....ccqccqccqcc.... ......cqcqcqcqc..... ......cqcqcqcqc..... ......ccqc.cqcc..... .......cqc.cqc...... .......cqc.cqc...... .......ccc.ccc...... .................... .................... .................... .................... .................... # APRS X .................... .................... .................... .................... .......ccc.ccc...... .......cqc.cqc...... .......cqc.cqc...... .......ccqcqcc...... ........cqcqc....... .........cqc........ ........cqcqc....... .......ccqcqcc...... .......cqc.cqc...... .......cqc.cqc...... .......ccc.ccc...... .................... .................... .................... .................... .................... # APRS Y .................... .................... .................... .................... ......ccc.ccc....... ......cqc.cqc....... ......cqc.cqc....... ......cqc.cqc....... ......ccqcqcc....... .......cqcqc........ .......ccqcc........ ........cqc......... ........cqc......... ........cqc......... ........ccc......... .................... .................... .................... .................... .................... # APRS Z .................... .................... .................... .................... ......cccccccc...... ......cqqqqqqq...... ......ccccccqc...... ..........ccqc...... .........ccqcc...... ........ccqcc....... .......ccqcc........ ......ccqcc......... ......cqcccccc...... ......cqqqqqqc...... ......cccccccc...... .................... .................... .................... .................... .................... # APRS > .................... .................... .................... .................... .....d.............. .....dd............. .ddddddd............ ndddddddd........... nddddddd............ nnnnndd............. ....nd.............. .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # APRS < .................... .................... .................... .................... ...d................ ..dd................ .dddddddd........... ddddddddd........... ndddddddd........... .nddnnnn............ ..nd................ .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # APRS * .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ..ddddddd........... .nddddddd........... .nddddddd........... .nddddddd........... .nddddddd........... .nnnnnnn............ .................... # APRS ^ .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... ..kkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nkkkkkkk........... .nnnnnnn............ .................... # # # ------------------------- # TABLE ~ # APRS 0 ..gggggg............ .gggggggg........... gggggggggg.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 1 ..hhhhhh............ .hhhhhhhh........... hhhhhhhhhh.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 2 ..iiiiii............ .iiiiiiii........... iiiiiiiiii.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 3 ..aaaaaa............ .aaaaaaaa........... aaaaaaaaaa.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 4 ..######............ .########........... ##########.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 5 ..llllll............ .llllllll........... llllllllll.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 6 ..kkkkkk............ .kkkkkkkk........... kkkkkkkkkk.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 7 ..jjjjjj............ .jjjjjjjj........... jjjjjjjjjj.......... nnnnnnnnn........... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS 8 npllllllpn.......... lnllllllnl.......... lhhhhhhhhl.......... npllllllpn.......... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... .................... # APRS # ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... ~~~~~~~~~~.......... # APRS $ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~ DONE Xastir-Release-2.2.4/symbols/torndo.xbm0000664000175000017500000000552015151324131017030 0ustar hibbyhibby#define tornado_width 110 #define tornado_height 32 static unsigned char tornado_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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 0xf8, 0x9c, 0x27, 0x22, 0x1e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x68, 0x22, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0xa8, 0x52, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x27, 0x53, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x28, 0xfa, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa2, 0x28, 0x8a, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x9c, 0x28, 0x8a, 0x1e, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/wind.xbm0000664000175000017500000000550715151324131016471 0ustar hibbyhibby#define wind_width 109 #define wind_height 32 static unsigned char wind_bits[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 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, 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, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x15, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x12, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x32, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x52, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x92, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x12, 0x45, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x49, 0x12, 0x45, 0x54, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x12, 0x3d, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/winter_storm.xbm0000664000175000017500000000552615151324131020265 0ustar hibbyhibby#define wntr_strm_width 110 #define wntr_strm_height 32 static unsigned char wntr_strm_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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0xf4, 0x7d, 0x0f, 0xe0, 0x7c, 0xce, 0x13, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0xc9, 0x44, 0x04, 0x11, 0x10, 0x11, 0x51, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x45, 0x04, 0x11, 0x10, 0x10, 0x51, 0x54, 0x05, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x46, 0x3c, 0x0f, 0xe0, 0x10, 0xd1, 0x93, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x44, 0x04, 0x11, 0x00, 0x11, 0x51, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x24, 0x49, 0x44, 0x04, 0x11, 0x10, 0x11, 0x51, 0x14, 0x04, 0xaa, 0xaa, 0xaa, 0xaa, 0xfc, 0x48, 0x44, 0x7c, 0x11, 0xe0, 0x10, 0x4e, 0x14, 0x24, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x2a, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; Xastir-Release-2.2.4/symbols/winter_weather.xbm0000664000175000017500000000552615151324131020560 0ustar hibbyhibby#define winter_wx_width 109 #define winter_wx_height 32 static unsigned char winter_wx_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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 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, 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, 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, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0xdf, 0xf7, 0x00, 0x49, 0x11, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x4a, 0x92, 0x4c, 0x44, 0x10, 0x01, 0x49, 0x8a, 0xaa, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x54, 0x44, 0x10, 0x01, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x64, 0xc4, 0xf3, 0x00, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0x44, 0x10, 0x01, 0x49, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x92, 0x44, 0x44, 0x10, 0x01, 0x49, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x8f, 0x44, 0xc4, 0x17, 0x01, 0x3f, 0x11, 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, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x0a, 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 }; Xastir-Release-2.2.4/testdbfawk.10000664000175000017500000000246615151324131015551 0ustar hibbyhibby.TH testdbfawk 1 2009-12-22 "The Xastir Group" .SH NAME testdbfawk \- scan dbfawk files for matching dbf file for map rendering in xastir .SH SYNOPSIS .B testdbfawk .I [-f file.awk| -D dir] -d file.dbf .SH DESCRIPTION Scan dbfawk files for matching dbf file for map rendering in xastir .br .PP .B --help prints command line usage .br .B -D for dir containing *.dbfawk files. .br .B -f for file containing awk rules. .br .B -d for dbf file to parse .SH EXAMPLES testdbfawk \-D . \-d tgr36119lkA.dbf 2>&1|less testdbfawk scans the current directory for dbfawk files with signatures that match tgr36119lkA.dbf's signature. testdbfawk dumps its output to standard error, so in the example standard error is redirected to standard out and piped into "less" for paging. .SH NOTES Dbfawk hints and kinks: You have to think like an awk programmer and realize that the order that rules are listed matters, that it's important to use "next" as soon as it makes sense so other rules aren't looked at unnecessarily and, to use "skip" when you want to fix bad dbf data. .SH SEE ALSO https://github.com/Xastir/Xastir/wiki/DBFAWK .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2026 The Xastir Group Xastir-Release-2.2.4/tests/0000775000175000017500000000000015151324131014463 5ustar hibbyhibbyXastir-Release-2.2.4/tests/Makefile.am0000664000175000017500000000673615151324131016533 0ustar hibbyhibby# Makefile.am for Xastir tests # Autotest-based test suite for interface helper functions TESTSUITE = $(srcdir)/testsuite AUTOTEST = $(AUTOM4TE) --language=autotest TESTSUITE_AT = testsuite.at interface_helpers.at db_tests.at object_utils_tests.at output_my_aprs_data_tests.at util_tests.at objects_tests.at if HAVE_NOMINATIM TESTSUITE_AT += nominatim_tests.at endif EXTRA_DIST = $(TESTSUITE_AT) $(TESTSUITE) package.m4 atlocal.in nominatim_tests.at # Test programs check_PROGRAMS = test_interface_helpers test_db test_object_utils test_output_my_aprs_data test_util test_objects # Conditionally add nominatim test program if HAVE_NOMINATIM check_PROGRAMS += test_nominatim endif test_interface_helpers_SOURCES = test_interface_helpers.c test_interface_helpers_CPPFLAGS = -I$(top_srcdir)/src test_db_SOURCES = test_db.c test_db_stubs.c $(top_srcdir)/src/db.c test_db_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) #test_db_LDADD = -L$(top_builddir)/src/rtree -lrtree test_object_utils_SOURCES = test_object_utils.c test_object_utils_stubs.c $(top_srcdir)/src/object_utils.c test_object_utils_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) test_output_my_aprs_data_SOURCES = test_output_my_aprs_data.c mock_output_my_aprs_data.c \ $(top_srcdir)/src/interface.c test_output_my_aprs_data_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) test_output_my_aprs_data_LDADD = -lpthread test_util_SOURCES = test_util.c test_util_stubs.c $(top_srcdir)/src/util.c test_util_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) test_objects_SOURCES = test_objects.c test_objects_stubs.c $(top_srcdir)/src/objects.c $(top_srcdir)/src/util.c $(top_srcdir)/src/object_utils.c $(top_srcdir)/src/db.c test_objects_CPPFLAGS = $(CPPFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) # Nominatim tests (conditional on HAVE_NOMINATIM) if HAVE_NOMINATIM test_nominatim_SOURCES = test_nominatim.c test_nominatim_stubs.c $(top_srcdir)/src/nominatim.c test_nominatim_CPPFLAGS = $(CPPFLAGS) $(LIBCURL_CFLAGS) $(CJSON_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_builddir) -DNOMINATIM_UNIT_TEST test_nominatim_LDADD = $(LIBCURL_LIBS) $(CJSON_LIBS) -lpthread endif # Run tests check-local: atconfig atlocal $(TESTSUITE) $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) # Install check installcheck-local: atconfig atlocal $(TESTSUITE) $(SHELL) '$(TESTSUITE)' AUTOTEST_PATH='$(bindir)' $(TESTSUITEFLAGS) # Clean test artifacts clean-local: test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean rm -rf testsuite.dir # Convenience targets check-unit: check-local AUTOM4TE = autom4te # Generate testsuite $(TESTSUITE): $(TESTSUITE_AT) package.m4 $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at mv $@.tmp $@ # Generate atconfig atconfig: $(top_builddir)/config.status cd $(top_builddir) && $(SHELL) ./config.status tests/$@ # Generate package.m4 package.m4: $(top_srcdir)/configure.ac { \ echo '# Signature of the current package.'; \ echo 'm4_define([AT_PACKAGE_NAME], [@PACKAGE_NAME@])'; \ echo 'm4_define([AT_PACKAGE_TARNAME], [@PACKAGE_TARNAME@])'; \ echo 'm4_define([AT_PACKAGE_VERSION], [@PACKAGE_VERSION@])'; \ echo 'm4_define([AT_PACKAGE_STRING], [@PACKAGE_STRING@])'; \ echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \ if test "x@HAVE_NOMINATIM_TRUE@" = "x"; then \ echo 'm4_define([HAVE_NOMINATIM])'; \ fi; \ } > $(srcdir)/package.m4 .PHONY: check-unit Xastir-Release-2.2.4/tests/atlocal.in0000664000175000017500000000046415151324131016436 0ustar hibbyhibby# atlocal.in - Test environment setup # This file is processed by configure to create atlocal # Paths PATH="@abs_top_builddir@/tests:@abs_top_builddir@/src:$PATH" export PATH # Build directories abs_top_builddir="@abs_top_builddir@" abs_top_srcdir="@abs_top_srcdir@" export abs_top_builddir abs_top_srcdir Xastir-Release-2.2.4/tests/db_tests.at0000664000175000017500000001547715151324131016636 0ustar hibbyhibby# Autotest tests for db.c Functions # Tests for standalone utility functions from db.c AT_BANNER([Database Utility Functions]) # pad_callsign() tests AT_BANNER([pad_callsign() Function Tests]) AT_SETUP([pad_callsign: basic callsign]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_basic], [0], [PASS: pad_callsign with basic callsign ]) AT_CLEANUP AT_SETUP([pad_callsign: callsign with SSID]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_with_ssid], [0], [PASS: pad_callsign with SSID ]) AT_CLEANUP AT_SETUP([pad_callsign: full length callsign]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_full_length], [0], [PASS: pad_callsign with full length callsign ]) AT_CLEANUP AT_SETUP([pad_callsign: empty string]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_empty], [0], [PASS: pad_callsign with empty string ]) AT_CLEANUP AT_SETUP([pad_callsign: short callsign]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_short], [0], [PASS: pad_callsign with short callsign ]) AT_CLEANUP AT_SETUP([pad_callsign: invalid characters]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_invalid_chars], [0], [PASS: pad_callsign with invalid characters ]) AT_CLEANUP AT_SETUP([pad_callsign: multiple invalid characters]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_multiple_invalid], [0], [PASS: pad_callsign with multiple invalid characters ]) AT_CLEANUP AT_SETUP([pad_callsign: lowercase letters]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_lowercase], [0], [PASS: pad_callsign with lowercase letters ]) AT_CLEANUP AT_SETUP([pad_callsign: mixed case]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_mixed_case], [0], [PASS: pad_callsign with mixed case ]) AT_CLEANUP AT_SETUP([pad_callsign: numbers only]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_numbers_only], [0], [PASS: pad_callsign with numbers only ]) AT_CLEANUP AT_SETUP([pad_callsign: single hyphen]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_hyphen_only], [0], [PASS: pad_callsign with single hyphen ]) AT_CLEANUP AT_SETUP([pad_callsign: spaces in input]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_spaces_in_input], [0], [PASS: pad_callsign with spaces in input ]) AT_CLEANUP AT_SETUP([pad_callsign: trailing hyphen]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_trailing_hyphen], [0], [PASS: pad_callsign with trailing hyphen ]) AT_CLEANUP AT_SETUP([pad_callsign: leading hyphen]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_leading_hyphen], [0], [PASS: pad_callsign with leading hyphen ]) AT_CLEANUP AT_SETUP([pad_callsign: multiple hyphens]) AT_KEYWORDS([db pad_callsign]) AT_CHECK(["$abs_top_builddir/tests/test_db" pad_callsign_multiple_hyphens], [0], [PASS: pad_callsign with multiple hyphens ]) AT_CLEANUP # extract_speed_course() tests AT_BANNER([extract_speed_course() Function Tests]) AT_SETUP([extract_speed_course: valid basic format]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_valid_basic], [0], [PASS: extract_speed_course with valid basic format ]) AT_CLEANUP AT_SETUP([extract_speed_course: exact length input]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_valid_no_extra_data], [0], [PASS: extract_speed_course with exact length ]) AT_CLEANUP AT_SETUP([extract_speed_course: course zero (undefined)]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_course_zero], [0], [PASS: extract_speed_course with course=000 (undefined) ]) AT_CLEANUP AT_SETUP([extract_speed_course: with spaces]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_with_spaces], [0], [PASS: extract_speed_course with spaces in numbers ]) AT_CLEANUP AT_SETUP([extract_speed_course: with periods]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_with_periods], [0], [PASS: extract_speed_course with periods ]) AT_CLEANUP AT_SETUP([extract_speed_course: invalid separator]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_invalid_separator], [0], [PASS: extract_speed_course with invalid separator ]) AT_CLEANUP AT_SETUP([extract_speed_course: too short]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_too_short], [0], [PASS: extract_speed_course with too short input ]) AT_CLEANUP AT_SETUP([extract_speed_course: invalid characters]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_invalid_chars], [0], [PASS: extract_speed_course with invalid characters ]) AT_CLEANUP AT_SETUP([extract_speed_course: empty string]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_empty_string], [0], [PASS: extract_speed_course with empty string ]) AT_CLEANUP AT_SETUP([extract_speed_course: maximum values]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_max_values], [0], [PASS: extract_speed_course with maximum values ]) AT_CLEANUP AT_SETUP([extract_speed_course: leading zeros]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_leading_zeros], [0], [PASS: extract_speed_course with leading zeros ]) AT_CLEANUP AT_SETUP([extract_speed_course: mixed valid characters]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_mixed_valid_chars], [0], [PASS: extract_speed_course with mixed valid characters ]) AT_CLEANUP AT_SETUP([extract_speed_course: partial match]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_partial_match], [0], [PASS: extract_speed_course with partial match ]) AT_CLEANUP AT_SETUP([extract_speed_course: long additional data]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_long_string], [0], [PASS: extract_speed_course with long additional data ]) AT_CLEANUP AT_SETUP([extract_speed_course: minimum valid course]) AT_KEYWORDS([db extract_speed_course]) AT_CHECK(["$abs_top_builddir/tests/test_db" extract_speed_course_course_001], [0], [PASS: extract_speed_course with course=001 (minimum valid) ]) AT_CLEANUP Xastir-Release-2.2.4/tests/interface_helpers.at0000664000175000017500000000036515151324131020477 0ustar hibbyhibby# Autotest tests for Interface Helper Functions AT_BANNER([Infrastructure Tests]) AT_SETUP([Test framework is working]) AT_KEYWORDS([infrastructure]) AT_CHECK([echo "Test framework operational"], [0], [Test framework operational ]) AT_CLEANUP Xastir-Release-2.2.4/tests/mock_output_my_aprs_data.c0000664000175000017500000002700215151324131021724 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Mock implementations for output_my_aprs_data() testing * * This file contains mock/stub implementations of all external dependencies * needed to test output_my_aprs_data() in isolation. */ #include #include #include #include #include #include #include "interface.h" /* Define necessary constants and types */ #define MAX_COMMENT 80 #define MAX_PHG 8 /* Global variables that output_my_aprs_data needs */ int transmit_disable = 0; int emergency_beacon = 0; int posit_tx_disable = 0; char my_callsign[MAX_CALLSIGN+1] = ""; char my_lat[MAX_LAT] = ""; char my_long[MAX_LONG] = ""; char my_group = '/'; char my_symbol = '-'; char my_comment[MAX_COMMENT+1] = ""; char my_phg[MAX_PHG+1] = ""; int my_last_course = 0; int my_last_speed = 0; long my_last_altitude = 0; time_t my_last_altitude_time = 0; int transmit_compressed_posit = 0; int output_station_type = 0; int debug_level = 0xfff; char aprs_station_message_type = '!'; ioparam devices[MAX_IFACE_DEVICES]; xastir_mutex devices_lock; #define VERSIONFRM "APX999" /* Mock control variables - track what was written */ typedef struct { int write_count; char last_write[4096]; char all_writes[10][4096]; int total_writes; } mock_port_state_t; static mock_port_state_t mock_ports[MAX_IFACE_DEVICES]; /* Popup tracking */ static int popup_count = 0; static char last_popup_title[256] = ""; static char last_popup_message[1024] = ""; /* Mock control functions */ void mock_reset_all(void) { int i; transmit_disable = 0; emergency_beacon = 0; posit_tx_disable = 0; strcpy(my_callsign, ""); strcpy(my_lat, ""); strcpy(my_long, ""); my_group = '/'; my_symbol = '-'; strcpy(my_comment, ""); strcpy(my_phg, ""); my_last_course = 0; my_last_speed = 0; my_last_altitude = 0; my_last_altitude_time = 0; transmit_compressed_posit = 0; output_station_type = 0; /* Reset popup tracking */ popup_count = 0; last_popup_title[0] = '\0'; last_popup_message[0] = '\0'; for (i = 0; i < MAX_IFACE_DEVICES; i++) { memset(&port_data[i], 0, sizeof(iface)); memset(&devices[i], 0, sizeof(iodevices)); memset(&mock_ports[i], 0, sizeof(mock_port_state_t)); port_data[i].device_type = DEVICE_NONE; port_data[i].status = DEVICE_DOWN; devices[i].transmit_data = 0; strcpy(devices[i].device_converse_string, "CONV"); } } void mock_set_transmit_disable(int value) { transmit_disable = value; } void mock_set_emergency_beacon(int value) { emergency_beacon = value; } void mock_set_my_callsign(const char *callsign) { strncpy(my_callsign, callsign, MAX_CALLSIGN); my_callsign[MAX_CALLSIGN] = '\0'; } void mock_set_my_position(const char *lat, const char *lon) { strncpy(my_lat, lat, sizeof(my_lat)-1); my_lat[sizeof(my_lat)-1] = '\0'; strncpy(my_long, lon, sizeof(my_long)-1); my_long[sizeof(my_long)-1] = '\0'; } void mock_set_output_station_type(int type) { output_station_type = type; } void mock_set_compressed_posit(int value) { transmit_compressed_posit = value; } void mock_set_phg(const char *phg) { strncpy(my_phg, phg, MAX_PHG); my_phg[MAX_PHG] = '\0'; } void mock_set_course_speed(int course, int speed) { my_last_course = course; my_last_speed = speed; } void mock_set_altitude(long altitude) { my_last_altitude = altitude; my_last_altitude_time = time(NULL); } void mock_set_comment(const char *comment) { strncpy(my_comment, comment, MAX_COMMENT); my_comment[MAX_COMMENT] = '\0'; } void mock_set_message_type(char type) { aprs_station_message_type = type; } void mock_add_interface(int port, int device_type, int status, int transmit_enabled) { if (port < 0 || port >= MAX_IFACE_DEVICES) return; port_data[port].device_type = device_type; port_data[port].status = status; port_data[port].active = 1; port_data[port].write_in_pos = 0; port_data[port].write_out_pos = 0; devices[port].transmit_data = transmit_enabled; devices[port].device_type = device_type; // Set up some defaults strcpy(devices[port].unproto1, "WIDE1-1,WIDE2-1"); devices[port].unprotonum = 0; strcpy(devices[port].device_converse_string, "CONV"); } int mock_get_write_count(int port) { if (port < 0 || port >= MAX_IFACE_DEVICES) return 0; /* Debug: print buffer positions */ if (debug_level & 2) { fprintf(stderr, "mock_get_write_count: Port %d: write_in_pos=%d, write_out_pos=%d, error_count=%d\n", port, port_data[port].write_in_pos, port_data[port].write_out_pos, port_data[port].errors); } /* Check if anything was written to the device buffer */ if (port_data[port].write_in_pos != port_data[port].write_out_pos) return 1; return 0; } const char *mock_get_last_write(int port) { static char buffer[MAX_DEVICE_BUFFER]; int start, end, i, j; if (port < 0 || port >= MAX_IFACE_DEVICES) return NULL; start = port_data[port].write_out_pos; end = port_data[port].write_in_pos; if (start == end) return NULL; /* Copy data from circular buffer to linear buffer */ j = 0; i = start; while (i != end && j < MAX_DEVICE_BUFFER - 1) { buffer[j++] = port_data[port].device_write_buffer[i]; i++; if (i >= MAX_DEVICE_BUFFER) i = 0; } buffer[j] = '\0'; return buffer; } int mock_get_popup_count(void) { return popup_count; } const char *mock_get_last_popup_title(void) { return last_popup_title; } const char *mock_get_last_popup_message(void) { return last_popup_message; } /* Mock implementations of external functions */ int begin_critical_section(xastir_mutex *lock, char *msg) { /* Mock - return 0 to indicate success */ return 0; } int end_critical_section(xastir_mutex *lock, char *msg) { /* Mock - return 0 to indicate success */ return 0; } time_t sec_now(void) { return time(NULL); } void popup_message_always(char *title, char *message) { /* Track popup calls */ popup_count++; strncpy(last_popup_title, title, sizeof(last_popup_title) - 1); last_popup_title[sizeof(last_popup_title) - 1] = '\0'; strncpy(last_popup_message, message, sizeof(last_popup_message) - 1); last_popup_message[sizeof(last_popup_message) - 1] = '\0'; /* In tests, also print to stderr for debugging */ fprintf(stderr, "POPUP: %s - %s\n", title, message); } char *langcode(char *code) { /* Return the code itself as the "translated" string */ return (char *)code; } int xastir_snprintf(char *str, size_t size, const char *format, ...) { va_list args; int result; va_start(args, format); result = vsnprintf(str, size, format, args); va_end(args); return result; } long convert_lat_s2l(char *lat) { /* Simple mock - just return a fixed value */ return 47000000; /* ~47 degrees */ } long convert_lon_s2l(char *lon) { /* Simple mock - just return a fixed value */ return -122000000; /* ~-122 degrees */ } void convert_lat_l2s(long lat, char *str, int str_len, int type) { /* Simple mock conversion */ snprintf(str, str_len, "4700.00N"); } void convert_lon_l2s(long lon, char *str, int str_len, int type) { /* Simple mock conversion */ snprintf(str, str_len, "12200.00W"); } char *output_lat(char *lat, int compressed) { /* Mock - just return success */ return lat; } char *output_long(char *lon, int compressed) { /* Mock - just return success */ return lon; } char *compress_posit(const char *input_lat, const char group, const char *input_lon, const char symbol, const unsigned int last_course, const unsigned int last_speed, const char *phg) { /* Return a mock compressed position */ static char compressed[20]; snprintf(compressed, sizeof(compressed), "/5L!!<*e7>"); return compressed; } void makePrintable(char *str) { /* Mock - just ensure it's printable by removing control chars */ char *p = str; while (*p) { if (*p == '\r' || *p == '\n') *p = ' '; p++; } } void packet_data_add(const char *from, char *data, int port) { /* Mock - do nothing, just for incoming data display */ } time_t wx_tx_data1(char *wx_data, int wx_data_size) { /* Mock - return 0 to indicate no weather data */ return 0; } /* Additional stubs for other functions interface.c needs */ char LOGFILE_NET[400]; char LOGFILE_TNC[400]; int altnet = 0; char altnet_call[MAX_CALLSIGN+1] = ""; Widget appshell; void busy_cursor(void *w) { (void)w; } int check_unproto_path(char* data) { return 1; } int decode_ax25_header(unsigned char *data_string, int *length) { (void)data_string; (void)length; return 0; } int decode_ax25_line(char *line, char from, int port, int dbadd) { (void)line; (void)from; (void)port; (void)dbadd; return 0; } int egid = 0; int euid = 0; int enable_server_port = 0; int filethere(char *path) { return 0; } void forked_freeaddrinfo(struct addrinfo *ai) {} int forked_getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **resout, int time) { return -1; } char *get_data_base_dir(char *dir) { strcpy(dir, "/tmp"); return dir; } char *get_user_base_dir(char *dir, char *path, size_t pathsize) { strcpy(dir, "/tmp"); return dir; } char gpgga_save_string[MAX_LINE_SIZE+1] = ""; char gprmc_save_string[MAX_LINE_SIZE+1] = ""; int gps_port_save = 0; void init_critical_section(xastir_mutex *lock){} int isGGA(char *line) { (void)line; return 0; } int isRMC(char *line) { (void)line; return 0; } void log_data(char *file, char *line) { (void)file; (void)line; } int log_net_data = 0; int log_tnc_data = 0; int my_position_valid = 0; int pipe_xastir_to_tcp_server = 0; void popup_message(char *title, char *message) { popup_count++; strncpy(last_popup_title, title, sizeof(last_popup_title) - 1); fprintf(stderr, "POPUP: %s - %s\n", title, message); } int serial_char_pacing = 0; void split_string( char *data, char *cptr[], int max, char search_char ) { int ii; char *temp; char *current = data; // NULL each char pointer for (ii = 0; ii < max; ii++) { cptr[ii] = NULL; } // Save the beginning substring address cptr[0] = current; for (ii = 1; ii < max; ii++) { temp = strchr(current,search_char); // Find next search character if(!temp) // No search characters found { return; // All done with string } // Store pointer to next substring in array cptr[ii] = &temp[1]; current = &temp[1]; // Overwrite search character with end-of-string char and bump // pointer by one. temp[0] = '\0'; } } void statusline(const char *msg, int clear){} void substr(char *dest, char *src, int size) { memcpy(dest, src, size); dest[size] = '\0'; } char *to_upper(char *str) { return str; } void update_interface_list(void) { } int using_gps_position = 0; int writen(int fd, char *ptr, int nbytes) { return 0; } Xastir-Release-2.2.4/tests/nominatim_tests.at0000664000175000017500000000764015151324131020235 0ustar hibbyhibby# Autotest tests for nominatim.c Functions # Tests for Nominatim geocoding functionality including cache, rate limiting, and URL formation # These tests only run if Nominatim support is compiled in AT_BANNER([Nominatim Geocoding Functions]) # Query hash function tests AT_BANNER([Nominatim compute_query_hash() Function Tests]) AT_SETUP([compute_query_hash: consistency]) AT_KEYWORDS([nominatim hash]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" compute_query_hash_consistency], [0], [PASS: compute_query_hash produces consistent hashes ]) AT_CLEANUP AT_SETUP([compute_query_hash: case insensitive]) AT_KEYWORDS([nominatim hash]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" compute_query_hash_case_insensitive], [0], [PASS: compute_query_hash is case-insensitive ]) AT_CLEANUP AT_SETUP([compute_query_hash: includes country codes]) AT_KEYWORDS([nominatim hash]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" compute_query_hash_with_country], [0], [PASS: compute_query_hash includes country codes ]) AT_CLEANUP AT_SETUP([compute_query_hash: different queries produce different hashes]) AT_KEYWORDS([nominatim hash]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" compute_query_hash_different_queries], [0], [PASS: compute_query_hash produces different hashes for different queries ]) AT_CLEANUP # Cache lookup tests AT_BANNER([Nominatim Cache Lookup Function Tests]) AT_SETUP([cache_lookup: empty cache returns 0]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_lookup_empty], [0], [PASS: Cache lookup returns 0 for empty cache ]) AT_CLEANUP AT_SETUP([cache_lookup: store and lookup round-trip]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_store_and_lookup], [0], [PASS: Cache store and lookup round-trip works ]) AT_CLEANUP AT_SETUP([cache_lookup: case insensitive]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_case_insensitive], [0], [PASS: Cache is case-insensitive ]) AT_CLEANUP AT_SETUP([cache_lookup: distinguishes country codes]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_country_codes], [0], [PASS: Cache distinguishes queries with different country codes ]) AT_CLEANUP AT_SETUP([cache_lookup: multiple results]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_multiple_results], [0], [PASS: Cache handles multiple results correctly ]) AT_CLEANUP AT_SETUP([cache_lookup: update existing entry]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_update_existing], [0], [PASS: Cache updates existing entries correctly ]) AT_CLEANUP # Cache management tests AT_BANNER([Nominatim Cache Management Function Tests]) AT_SETUP([nominatim_clear_cache: clears all entries]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_clear], [0], [PASS: Cache clear removes all entries ]) AT_CLEANUP AT_SETUP([cache: respects disabled setting]) AT_KEYWORDS([nominatim cache]) AT_SKIP_IF([test ! -x "$abs_top_builddir/tests/test_nominatim"]) AT_CHECK(["$abs_top_builddir/tests/test_nominatim" cache_disabled], [0], [PASS: Cache respects disabled setting ]) AT_CLEANUP Xastir-Release-2.2.4/tests/object_utils_tests.at0000664000175000017500000011322415151324131020724 0ustar hibbyhibby# Autotest tests for object_utils.c Functions # Tests for standalone utility functions from object_utils.c AT_BANNER([Object Utility Functions]) AT_BANNER([pad_item_name() tests]) AT_SETUP([pad_item_name: no padding9]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad9], [0], [PASS: pad_item_name: 9 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding8]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad8], [0], [PASS: pad_item_name: 8 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding7]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad7], [0], [PASS: pad_item_name: 7 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding6]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad6], [0], [PASS: pad_item_name: 6 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding5]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad5], [0], [PASS: pad_item_name: 5 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding4]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad4], [0], [PASS: pad_item_name: 4 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: no padding3]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_nopad3], [0], [PASS: pad_item_name: 3 character name not modified ]) AT_CLEANUP AT_SETUP([pad_item_name: padding by 1]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_pad2], [0], [PASS: pad_item_name: 2 character name padded with one space ]) AT_CLEANUP AT_SETUP([pad_item_name: padding by 2]) AT_KEYWORDS([object_utils pad_item_name]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" pad_item_name_pad1], [0], [PASS: pad_item_name: 1 character name padded with two spaces ]) AT_CLEANUP AT_BANNER([format_course_speed() tests]) AT_SETUP([format_course_speed: valid input]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_basic], [0], [PASS: format_course_speed with valid input for both ]) AT_CLEANUP AT_SETUP([format_course_speed: bad input for course]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_bad_course], [0], [PASS: format_course_speed with bad input for course ]) AT_CLEANUP AT_SETUP([format_course_speed: null input for course]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_null_course], [0], [PASS: format_course_speed with null input for course ]) AT_CLEANUP AT_SETUP([format_course_speed: bad input for speed]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_bad_speed], [0], [PASS: format_course_speed with bad input for speed ]) AT_CLEANUP AT_SETUP([format_course_speed: null input for speed]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_null_speed], [0], [PASS: format_course_speed with null input for speed ]) AT_CLEANUP AT_SETUP([format_course_speed: null inputs]) AT_KEYWORDS([object_utils format_course_speed]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_course_speed_null_inputs], [0], [PASS: format_course_speed with null input for both ]) AT_CLEANUP AT_BANNER([format_altitude() tests]) AT_SETUP([format_altitude: valid input]) AT_KEYWORDS([object_utils format_altitude]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_altitude_basic], [0], [PASS: format_altitude with valid input ]) AT_CLEANUP AT_SETUP([format_altitude: null input]) AT_KEYWORDS([object_utils format_altitude]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_altitude_null_input], [0], [PASS: format_altitude with null input ]) AT_CLEANUP AT_SETUP([format_altitude: invalid input]) AT_KEYWORDS([object_utils format_altitude]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_altitude_invalid_input], [0], [PASS: format_altitude with invalid input ]) AT_CLEANUP AT_BANNER([format_zulu_time() tests]) AT_SETUP([format_zulu_time: specific timestamp]) AT_KEYWORDS([object_utils format_zulu_time]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_zulu_time], [0], [PASS: format_zulu_time for specific unix timestamp ]) AT_CLEANUP AT_BANNER([object color function tests]) AT_SETUP([format_area_color_from_numeric: valid colors]) AT_KEYWORDS([object_utils format_area_color_from_numeric]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_color_from_numeric_basic], [0], [PASS: format_area_color_from_numeric for valid colors ]) AT_CLEANUP AT_SETUP([format_area_color_from_numeric: invalid color]) AT_KEYWORDS([object_utils format_area_color_from_numeric]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_color_from_numeric_invalid], [0], [PASS: format_area_color_from_numeric for invalid colors ], [Invalid color value passed to format_area_from_numeric. Returning string for bright red instead. ]) AT_CLEANUP AT_SETUP([area_color_from_string: valid colors]) AT_KEYWORDS([object_utils area_color_from_string]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" area_color_from_string_basic], [0], [PASS: area_color_from_string for valid color strings ]) AT_CLEANUP AT_SETUP([area_color_from_string: invalid colors]) AT_KEYWORDS([object_utils area_color_from_string]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" area_color_from_string_invalid], [0], [PASS: area_color_from_string for invalid color strings ]) AT_CLEANUP AT_SETUP([area_color_from_string: color is substring]) AT_KEYWORDS([object_utils area_color_from_string]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" area_color_from_string_midstring], [0], [PASS: area_color_from_string for color string inside longer string ]) AT_CLEANUP AT_SETUP([format_area_color_from_dialog: valid inputs]) AT_KEYWORDS([object_utils area_color_from_string]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_color_from_dialog_basic], [0], [PASS: format_area_color_from_dialog for valid bright and dim colors ]) AT_CLEANUP AT_BANNER([object corridor function tests]) AT_SETUP([format_area_corridor: three-digit inputs]) AT_KEYWORDS([object_utils area_corridor]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_corridor_threedigit], [0], [PASS: format_area_corridor for three-digit corridor values ]) AT_CLEANUP AT_SETUP([format_area_corridor: two-digit inputs]) AT_KEYWORDS([object_utils area_corridor]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_corridor_twodigit], [0], [PASS: format_area_corridor for two-digit corridor values ]) AT_CLEANUP AT_SETUP([format_area_corridor: one-digit inputs]) AT_KEYWORDS([object_utils area_corridor]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_corridor_onedigit], [0], [PASS: format_area_corridor for one-digit corridor values ]) AT_CLEANUP AT_BANNER([signpost value function tests]) AT_SETUP([format_signpost: three-char inputs]) AT_KEYWORDS([object_utils signpost]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_threechar], [0], [PASS: format_signpost for three-char signpost values ]) AT_CLEANUP AT_SETUP([format_signpost: two-char inputs]) AT_KEYWORDS([object_utils signpost]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_twochar], [0], [PASS: format_signpost for two-char signpost values ]) AT_CLEANUP AT_SETUP([format_signpost: one-char inputs]) AT_KEYWORDS([object_utils signpost]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_onechar], [0], [PASS: format_signpost for one-char signpost values ]) AT_CLEANUP AT_BANNER([probability ring formatting tests]) AT_SETUP([format_probability_ring_data: both inputs]) AT_KEYWORDS([object_utils probability_ring]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_probability_ring_data_both], [0], [PASS: format_probability_ring_data when min and max specified ]) AT_CLEANUP AT_SETUP([format_probability_ring_data: max input only]) AT_KEYWORDS([object_utils probability_ring]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_probability_ring_data_max_only], [0], [PASS: format_probability_ring_data when only max specified ]) AT_CLEANUP AT_BANNER([prepend rng/png formatting tests]) AT_SETUP([prepend_rng_phg with short comment]) AT_KEYWORDS([object_utils prepend_rng_phg]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" prepend_rng_phg_short_comment], [0], [PASS: prepend_rng_phg when comment is shorter than max ]) AT_CLEANUP AT_SETUP([prepend_rng_phg with long comment]) AT_KEYWORDS([object_utils prepend_rng_phg]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" prepend_rng_phg_long_comment], [0], [PASS: prepend_rng_phg when comment is already max ]) AT_CLEANUP AT_BANNER([area object formatting tests]) AT_SETUP([format_area_object_item_packet: circle object with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_circle_uncomp_nodata], [0], [PASS: format_area_object_item_packet produces correct result for simple circle case ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle item with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_circle_uncomp_nodata], [0], [PASS: format_area_object_item_packet produces correct result for simple circle item case ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle object with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_circle_comp_nodata], [0], [PASS: format_area_object_item_packet produces correct result for simple circle case, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle item with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_circle_comp_nodata], [0], [PASS: format_area_object_item_packet produces correct result for simple circle item case, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle object with altitude]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_circle_uncomp_alt], [0], [PASS: format_area_object_item_packet produces correct result for circle case with alt ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle item with altitude]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_circle_uncomp_alt], [0], [PASS: format_area_object_item_packet produces correct result for circle item case with alt ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle object with altitude, compressed]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_circle_comp_alt], [0], [PASS: format_area_object_item_packet produces correct result for circle case with alt, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: circle item with altitude, compressed]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_circle_comp_alt], [0], [PASS: format_area_object_item_packet produces correct result for circle item case with alt, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line object with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_line_uncomp_nodata], [0], [PASS: format_area_object_item_packet produces correct result with corridor for simple line case ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line item with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_line_uncomp_nodata], [0], [PASS: format_area_object_item_packet produces correct result with corridor for simple line item case ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line object with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_line_comp_nodata], [0], [PASS: format_area_object_item_packet produces correct result with corridor for simple line case, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line item with no data]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_line_comp_nodata], [0], [PASS: format_area_object_item_packet produces correct result with corridor for simple line item case, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line object with altitude]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_line_uncomp_alt], [0], [PASS: format_area_object_item_packet produces correct result with corridor for line case with alt ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line item with altitude]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_line_uncomp_alt], [0], [PASS: format_area_object_item_packet produces correct result with corridor for line item case with alt ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line object with altitude, compressed]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_object_line_comp_alt], [0], [PASS: format_area_object_item_packet produces correct result with corridor for line case with alt, compressed ]) AT_CLEANUP AT_SETUP([format_area_object_item_packet: line item with altitude, compressed]) AT_KEYWORDS([object_utils area_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_area_object_item_packet_item_line_comp_alt], [0], [PASS: format_area_object_item_packet produces correct result with corridor for line item case with alt, compressed ]) AT_CLEANUP AT_BANNER([signpost formatting tests]) AT_SETUP([format_signpost_object_item_packet: signpost object with no text, speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_notxt_nospeed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result with no text, velocity, or altitude ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with no text, speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_notxt_nospeed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result with no text, velocity, or altitude, compressed ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with no text, speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_notxt_nospeed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result with no text, velocity, or altitude ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with no text, speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_notxt_nospeed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result with no text, velocity, or altitude, compressed ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, no speed or altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_nospeed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, no speed or altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_nospeed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, no speed or altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_nospeed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, no speed or altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_nospeed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, speed no altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_speed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, speed no altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_speed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, speed no altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_speed_noalt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, speed no altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_speed_noalt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_speed_alt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with text, speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_txt_speed_alt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_speed_alt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with text, speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_txt_speed_alt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with no text, with speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_notxt_speed_alt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost object with no text, with speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_object_notxt_speed_alt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with no text, with speed, altitude]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_notxt_speed_alt], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_signpost_object_item_packet: signpost item with no text, with speed, altitude, compressed]) AT_KEYWORDS([object_utils signpost_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_signpost_object_item_packet_item_notxt_speed_alt_comp], [0], [PASS: format_signpost_object_item_packet produces correct result ]) AT_CLEANUP AT_BANNER([omni df formatting tests]) AT_SETUP([format_omni_df_object_item_packet: omni_df object with no speed, altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_nospeed_noalt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df object with no speed, altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_nospeed_noalt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with no speed, altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_nospeed_noalt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with no speed, altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_nospeed_noalt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df object with speed, no altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_speed_noalt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df object with speed, no altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_speed_noalt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with speed, no altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_speed_noalt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with speed, no altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_speed_noalt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df object with speed, altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_speed_alt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df object with speed, altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_object_speed_alt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with speed, altitude]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_speed_alt], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_omni_df_object_item_packet: omni_df item with speed, altitude, compressed]) AT_KEYWORDS([object_utils omni_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_omni_df_object_item_packet_item_speed_alt_comp], [0], [PASS: format_omni_df_object_item_packet produces correct result ]) AT_CLEANUP AT_BANNER([beam df formatting tests]) AT_SETUP([format_beam_df_object_item_packet: beam df object with NULL speed no altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_nullspeed_noalt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with no speed or altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_nospeed_noalt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with speed no altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_speed_noalt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with speed and altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_speed_alt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with no speed or altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_nospeed_noalt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with speed no altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_speed_noalt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with speed and altitude]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_speed_alt], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with no speed or altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_nospeed_noalt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with speed no altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_speed_noalt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df object with speed and altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_object_speed_alt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with no speed or altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_nospeed_noalt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with speed no altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_speed_noalt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_beam_df_object_item_packet: beam df item with speed and altitude, compressed]) AT_KEYWORDS([object_utils beam_df_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_beam_df_object_item_packet_item_speed_alt_comp], [0], [PASS: format_beam_df_object_item_packet produces correct result ]) AT_CLEANUP AT_BANNER([normal object/item tests]) AT_SETUP([format_normal_object_item_packet: object with no speed or altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_nospeed_noalt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, no altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_speed_noalt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_speed_alt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with no speed or altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_nospeed_noalt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, no altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_speed_noalt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, altitude]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_speed_alt], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with no speed or altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_nospeed_noalt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, no altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_speed_noalt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_speed_alt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with no speed or altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_nospeed_noalt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with no speed or altitude, overlay symbol]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_overlay], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with no speed or altitude, overlay symbol, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_object_overlay_compressed], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, no altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_speed_noalt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([format_normal_object_item_packet: object with speed, altitude, compressed]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" format_normal_object_item_packet_item_speed_alt_comp], [0], [PASS: format_normal_object_item_packet produces correct result ]) AT_CLEANUP AT_BANNER([killed object/item tests]) AT_SETUP([reformat_killed_object_item_packet: active object]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" reformat_killed_object_item_packet_object_active], [0], [PASS: reformat_killed_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([reformat_killed_object_item_packet: active item]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" reformat_killed_object_item_packet_item_active], [0], [PASS: reformat_killed_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([reformat_killed_object_item_packet: killed object]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" reformat_killed_object_item_packet_object_inactive], [0], [PASS: reformat_killed_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([reformat_killed_object_item_packet: killed item]) AT_KEYWORDS([object_utils normal_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" reformat_killed_object_item_packet_item_inactive], [0], [PASS: reformat_killed_object_item_packet produces correct result ]) AT_CLEANUP AT_BANNER([append comment tests]) AT_SETUP([append_comment_to_object_item_packet: comment that should fit in object]) AT_KEYWORDS([object_utils append_comment_to_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" append_comment_to_object_item_packet_object_notlong], [0], [PASS: append_comment_to_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([append_comment_to_object_item_packet: comment that should get truncated in object]) AT_KEYWORDS([object_utils append_comment_to_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" append_comment_to_object_item_packet_object_toolong], [0], [PASS: append_comment_to_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([append_comment_to_object_item_packet: comment that should fit in item]) AT_KEYWORDS([object_utils append_comment_to_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" append_comment_to_object_item_packet_item_notlong], [0], [PASS: append_comment_to_object_item_packet produces correct result ]) AT_CLEANUP AT_SETUP([append_comment_to_object_item_packet: comment that should get truncated in item]) AT_KEYWORDS([object_utils append_comment_to_object_item_packet]) AT_CHECK(["$abs_top_builddir/tests/test_object_utils" append_comment_to_object_item_packet_item_toolong], [0], [PASS: append_comment_to_object_item_packet produces correct result ]) AT_CLEANUP Xastir-Release-2.2.4/tests/objects_tests.at0000664000175000017500000003112115151324131017662 0ustar hibbyhibby# Autotest tests for objects.c Functions # Tests for standalone utility functions from objects.c AT_BANNER([Object Functions]) AT_BANNER([construct_object_item_data_row() tests]) AT_SETUP([construct_object_item_data_row: returns null given no inputs]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_null_everything], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object with numeric overlay]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_numeric_overlay], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object with numeric overlay, compressed]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_numeric_overlay_compressed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object truncating overlong name]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_name_too_long], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple item]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_item], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple killed object]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_killed_object], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple killed item]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_killed_item], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object with speed,course]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_course_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple item with speed,course]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_item_course_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object with speed,course,alt]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_course_speed_alt], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple item with speed,course,alt]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_item_course_speed_alt], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple object with speed,course,alt,long comment]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_object_course_speed_alt_comment], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good simple item with speed,course,alt, long]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_simple_item_course_speed_alt_comment], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for area objects/items]) AT_SETUP([construct_object_item_data_row: returns good area object with minimal data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_basic], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area item with minimal data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_basic], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area object with course and speed incorrectly specified]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area item with course and speed incorrectly specified]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area object with offsets data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_offsets], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area item with offsets data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_offsets], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area object with offsets data input, filled circle]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_offsets_filled], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area item with offsets data input filled circle]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_offsets_filled], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good line area object with corridor data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_line_corridor], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good line area item with corridor data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_line_corridor], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area object with offsets and altitude data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_offsets_alt], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good area item with offsets and altitude data input]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_offsets_alt], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for signposts]) AT_SETUP([construct_object_item_data_row: returns good signpost with text]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_signpost_basic], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good signpost with text]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_signpost_basic], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good signpost with text and course/speed]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_object_signpost_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good signpost with text and course/speed]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_area_item_signpost_speed], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for omni-df objects]) AT_SETUP([construct_object_item_data_row: returns good omni-df object]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_df_omni], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good omni-df item ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_df_omni], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for beam-df objects]) AT_SETUP([construct_object_item_data_row: returns good omni-df object]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_df_beam], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good beam-df item ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_df_beam], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for probability ring objects]) AT_SETUP([construct_object_item_data_row: returns good probability ring object with no radii]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_prob_circles_noring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring item with no radii ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_prob_circles_noring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_BANNER([construct_object_item_data_row() tests for probability ring objects]) AT_SETUP([construct_object_item_data_row: returns good probability ring object with only min radius]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_prob_circles_minring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring item with only min radius ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_prob_circles_minring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring object with only max radius]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_prob_circles_maxring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring item with only max radius ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_prob_circles_maxring], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring object with min and max radius]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_object_prob_circles_minmax], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP AT_SETUP([construct_object_item_data_row: returns good probability ring item with min and max radius ]) AT_KEYWORDS([objects construct_object_item_data_row]) AT_CHECK(["$abs_top_builddir/tests/test_objects" constructor_item_prob_circles_minmax], [0], [PASS: construct_object_item_data_row ]) AT_CLEANUP Xastir-Release-2.2.4/tests/output_my_aprs_data_tests.at0000664000175000017500000001061315151324131022317 0ustar hibbyhibby# output_my_aprs_data_tests.at - Autotest suite for output_my_aprs_data function AT_BANNER([output_my_aprs_data function tests]) # Test: transmit_disabled AT_SETUP([output_my_aprs_data: transmit disabled]) AT_CHECK([test_output_my_aprs_data transmit_disabled], [0], [ignore], [ignore]) AT_CLEANUP # Test: transmit_disabled_with_emergency AT_SETUP([output_my_aprs_data: transmit disabled with emergency beacon]) AT_CHECK([test_output_my_aprs_data transmit_disabled_with_emergency], [0], [ignore], [ignore]) AT_CLEANUP # Test: no_active_interfaces AT_SETUP([output_my_aprs_data: no active interfaces]) AT_CHECK([test_output_my_aprs_data no_active_interfaces], [0], [ignore], [ignore]) AT_CLEANUP # Test: basic_position_output AT_SETUP([output_my_aprs_data: basic position output]) AT_CHECK([test_output_my_aprs_data basic_position_output], [0], [ignore], [ignore]) AT_CLEANUP # Test: network_stream_output AT_SETUP([output_my_aprs_data: network stream output]) AT_CHECK([test_output_my_aprs_data network_stream_output], [0], [ignore], [ignore]) AT_CLEANUP # Test: interface_down AT_SETUP([output_my_aprs_data: interface down]) AT_CHECK([test_output_my_aprs_data interface_down], [0], [ignore], [ignore]) AT_CLEANUP # Test: transmit_disabled_on_interface AT_SETUP([output_my_aprs_data: transmit disabled on interface]) AT_CHECK([test_output_my_aprs_data transmit_disabled_on_interface], [0], [ignore], [ignore]) AT_CLEANUP # Test: mobile_local_time_format AT_SETUP([output_my_aprs_data: mobile local time format]) AT_CHECK([test_output_my_aprs_data mobile_local_time_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: mobile_zulu_datetime_format AT_SETUP([output_my_aprs_data: mobile zulu datetime format]) AT_CHECK([test_output_my_aprs_data mobile_zulu_datetime_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: mobile_zulu_time_with_seconds_format AT_SETUP([output_my_aprs_data: mobile zulu time with seconds format]) AT_CHECK([test_output_my_aprs_data mobile_zulu_time_with_seconds_format], [0], [ignore], [ignore]) AT_CLEANUP # Core Position Formatting Tests # Test: uncompressed_fixed_basic AT_SETUP([output_my_aprs_data: uncompressed fixed basic]) AT_CHECK([test_output_my_aprs_data uncompressed_fixed_basic], [0], [ignore], [ignore]) AT_CLEANUP # Test: uncompressed_fixed_phg AT_SETUP([output_my_aprs_data: uncompressed fixed with PHG]) AT_CHECK([test_output_my_aprs_data uncompressed_fixed_phg], [0], [ignore], [ignore]) AT_CLEANUP # Test: uncompressed_mobile_course_speed AT_SETUP([output_my_aprs_data: uncompressed mobile with course/speed]) AT_CHECK([test_output_my_aprs_data uncompressed_mobile_course_speed], [0], [ignore], [ignore]) AT_CLEANUP # Test: uncompressed_fixed_altitude AT_SETUP([output_my_aprs_data: uncompressed fixed with altitude]) AT_CHECK([test_output_my_aprs_data uncompressed_fixed_altitude], [0], [ignore], [ignore]) AT_CLEANUP # Test: compressed_fixed_basic AT_SETUP([output_my_aprs_data: compressed fixed basic]) AT_CHECK([test_output_my_aprs_data compressed_fixed_basic], [0], [ignore], [ignore]) AT_CLEANUP # Test: message_type_equals AT_SETUP([output_my_aprs_data: message type equals]) AT_CHECK([test_output_my_aprs_data message_type_equals], [0], [ignore], [ignore]) AT_CLEANUP # Test: message_type_exclamation AT_SETUP([output_my_aprs_data: message type exclamation]) AT_CHECK([test_output_my_aprs_data message_type_exclamation], [0], [ignore], [ignore]) AT_CLEANUP # Device-specific Formatting Tests # Test: network_stream_format AT_SETUP([output_my_aprs_data: network stream format]) AT_CHECK([test_output_my_aprs_data network_stream_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: serial_tnc_format AT_SETUP([output_my_aprs_data: serial TNC format]) AT_CHECK([test_output_my_aprs_data serial_tnc_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: kiss_tnc_format AT_SETUP([output_my_aprs_data: KISS TNC format]) AT_CHECK([test_output_my_aprs_data kiss_tnc_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: agwpe_format AT_SETUP([output_my_aprs_data: AGWPE format]) AT_CHECK([test_output_my_aprs_data agwpe_format], [0], [ignore], [ignore]) AT_CLEANUP # Test: multiple_interfaces AT_SETUP([output_my_aprs_data: multiple interfaces]) AT_CHECK([test_output_my_aprs_data multiple_interfaces], [0], [ignore], [ignore]) AT_CLEANUP # Test: mixed_interface_states AT_SETUP([output_my_aprs_data: mixed interface states]) AT_CHECK([test_output_my_aprs_data mixed_interface_states], [0], [ignore], [ignore]) AT_CLEANUP Xastir-Release-2.2.4/tests/test_db.c0000664000175000017500000004323615151324131016263 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for db.c functions * * This test program tests standalone utility functions from db.c that * don't require complex Xastir infrastructure. */ #include #include #include #include #include "tests/test_framework.h" /* Forward declarations of functions under test */ void pad_callsign(char *callsignout, char *callsignin); int extract_speed_course(char *info, char *speed, char *course); /* Local implementation of substr helper function */ static void substr(char *dest, char *src, int size) { memcpy(dest, src, size+1); dest[size] = '\0'; // Terminate string } /* Test cases for pad_callsign() */ int test_pad_callsign_basic(void) { char output[10]; pad_callsign(output, "N7ABC"); TEST_ASSERT_STR_EQ("N7ABC ", output, "Basic callsign should be padded to 9 characters"); TEST_PASS("pad_callsign with basic callsign"); } int test_pad_callsign_with_ssid(void) { char output[10]; pad_callsign(output, "N7ABC-15"); TEST_ASSERT_STR_EQ("N7ABC-15 ", output, "Callsign with SSID should preserve hyphen"); TEST_PASS("pad_callsign with SSID"); } int test_pad_callsign_full_length(void) { char output[10]; pad_callsign(output, "ABCDEF-12"); TEST_ASSERT_STR_EQ("ABCDEF-12", output, "9-character callsign should not be padded"); TEST_PASS("pad_callsign with full length callsign"); } int test_pad_callsign_empty(void) { char output[10]; pad_callsign(output, ""); TEST_ASSERT_STR_EQ(" ", output, "Empty callsign should produce all spaces"); TEST_PASS("pad_callsign with empty string"); } int test_pad_callsign_short(void) { char output[10]; pad_callsign(output, "AB"); TEST_ASSERT_STR_EQ("AB ", output, "Short callsign should be right-padded with spaces"); TEST_PASS("pad_callsign with short callsign"); } int test_pad_callsign_invalid_chars(void) { char output[10]; pad_callsign(output, "N7*ABC"); TEST_ASSERT_STR_EQ("N7 ABC ", output, "Invalid character (*) should be replaced with space"); TEST_PASS("pad_callsign with invalid characters"); } int test_pad_callsign_multiple_invalid(void) { char output[10]; pad_callsign(output, "AB@#CD!EF"); TEST_ASSERT_STR_EQ("AB CD EF", output, "Multiple invalid characters should be replaced with spaces"); TEST_PASS("pad_callsign with multiple invalid characters"); } int test_pad_callsign_lowercase(void) { char output[10]; pad_callsign(output, "n7abc"); TEST_ASSERT_STR_EQ("n7abc ", output, "Lowercase letters are alphanumeric and should be preserved"); TEST_PASS("pad_callsign with lowercase letters"); } int test_pad_callsign_mixed_case(void) { char output[10]; pad_callsign(output, "N7aBc-1"); TEST_ASSERT_STR_EQ("N7aBc-1 ", output, "Mixed case should be preserved"); TEST_PASS("pad_callsign with mixed case"); } int test_pad_callsign_numbers_only(void) { char output[10]; pad_callsign(output, "12345"); TEST_ASSERT_STR_EQ("12345 ", output, "Numbers-only callsign should work"); TEST_PASS("pad_callsign with numbers only"); } int test_pad_callsign_hyphen_only(void) { char output[10]; pad_callsign(output, "-"); TEST_ASSERT_STR_EQ("- ", output, "Single hyphen should be preserved"); TEST_PASS("pad_callsign with single hyphen"); } int test_pad_callsign_spaces_in_input(void) { char output[10]; pad_callsign(output, "AB CD"); TEST_ASSERT_STR_EQ("AB CD ", output, "Spaces in input should be converted to spaces in output"); TEST_PASS("pad_callsign with spaces in input"); } int test_pad_callsign_trailing_hyphen(void) { char output[10]; pad_callsign(output, "N7ABC-"); TEST_ASSERT_STR_EQ("N7ABC- ", output, "Trailing hyphen should be preserved"); TEST_PASS("pad_callsign with trailing hyphen"); } int test_pad_callsign_leading_hyphen(void) { char output[10]; pad_callsign(output, "-N7ABC"); TEST_ASSERT_STR_EQ("-N7ABC ", output, "Leading hyphen should be preserved"); TEST_PASS("pad_callsign with leading hyphen"); } int test_pad_callsign_multiple_hyphens(void) { char output[10]; pad_callsign(output, "A-B-C"); TEST_ASSERT_STR_EQ("A-B-C ", output, "Multiple hyphens should be preserved"); TEST_PASS("pad_callsign with multiple hyphens"); } /* Test cases for extract_speed_course() */ int test_extract_speed_course_valid_basic(void) { char info[100] = "090/036more data"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("036", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("090", course, "Course should be extracted"); TEST_ASSERT_STR_EQ("more data", info, "Speed/course should be removed from info"); TEST_PASS("extract_speed_course with valid basic format"); } int test_extract_speed_course_valid_no_extra_data(void) { char info[100] = "180/050"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("050", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("180", course, "Course should be extracted"); TEST_ASSERT_STR_EQ("", info, "Info should be empty after extraction"); TEST_PASS("extract_speed_course with exact length"); } int test_extract_speed_course_course_zero(void) { char info[100] = "000/025data"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 (format is valid)"); TEST_ASSERT_STR_EQ("025", speed, "Speed should still be extracted"); TEST_ASSERT_STR_EQ("", course, "Course should be empty (000 means undefined)"); TEST_ASSERT_STR_EQ("data", info, "Info should be updated"); TEST_PASS("extract_speed_course with course=000 (undefined)"); } int test_extract_speed_course_with_spaces(void) { char info[100] = "1 0/ 25rest"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 (spaces allowed in format check)"); // Note: The function does a second validation pass that checks if first 2 chars // are digits, so both speed and course will be cleared TEST_ASSERT_STR_EQ("", speed, "Speed should be empty (space is not digit in validation)"); TEST_ASSERT_STR_EQ("", course, "Course should be empty (space is not digit in validation)"); TEST_ASSERT_STR_EQ("rest", info, "Info should be updated"); TEST_PASS("extract_speed_course with spaces in numbers"); } int test_extract_speed_course_with_periods(void) { char info[100] = "123/456more"; // Use valid format first char speed[10]; char course[10]; int result; // First test with valid numeric format result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("456", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("123", course, "Course should be extracted"); // Now test with periods (which pass format check but fail atoi) strcpy(info, "1.2/3.4more"); result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 (periods pass format check)"); // atoi("1.2") = 1, which is >= 1, so we enter the else block for validation // The validation checks if first 2 chars are digits - they're not (position 1 is '.') TEST_ASSERT_STR_EQ("", speed, "Speed should be empty (period in position 1)"); TEST_ASSERT_STR_EQ("", course, "Course should be empty (period in position 1)"); TEST_ASSERT_STR_EQ("more", info, "Info should be updated"); TEST_PASS("extract_speed_course with periods"); } int test_extract_speed_course_invalid_separator(void) { char info[100] = "090-036data"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 0, "Should return 0 for invalid separator"); TEST_ASSERT_STR_EQ("", speed, "Speed should be empty"); TEST_ASSERT_STR_EQ("", course, "Course should be empty"); TEST_ASSERT_STR_EQ("090-036data", info, "Info should be unchanged"); TEST_PASS("extract_speed_course with invalid separator"); } int test_extract_speed_course_too_short(void) { char info[100] = "090/03"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 0, "Should return 0 for too short string"); TEST_ASSERT_STR_EQ("", speed, "Speed should be empty"); TEST_ASSERT_STR_EQ("", course, "Course should be empty"); TEST_ASSERT_STR_EQ("090/03", info, "Info should be unchanged"); TEST_PASS("extract_speed_course with too short input"); } int test_extract_speed_course_invalid_chars(void) { char info[100] = "ABC/DEFdata"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 0, "Should return 0 for invalid characters"); TEST_ASSERT_STR_EQ("", speed, "Speed should be empty"); TEST_ASSERT_STR_EQ("", course, "Course should be empty"); TEST_ASSERT_STR_EQ("ABC/DEFdata", info, "Info should be unchanged"); TEST_PASS("extract_speed_course with invalid characters"); } int test_extract_speed_course_empty_string(void) { char info[100] = ""; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 0, "Should return 0 for empty string"); TEST_ASSERT_STR_EQ("", speed, "Speed should be empty"); TEST_ASSERT_STR_EQ("", course, "Course should be empty"); TEST_ASSERT_STR_EQ("", info, "Info should be unchanged"); TEST_PASS("extract_speed_course with empty string"); } int test_extract_speed_course_max_values(void) { char info[100] = "360/999end"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("999", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("360", course, "Course should be extracted"); TEST_ASSERT_STR_EQ("end", info, "Info should be updated"); TEST_PASS("extract_speed_course with maximum values"); } int test_extract_speed_course_leading_zeros(void) { char info[100] = "001/002text"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("002", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("001", course, "Course should be extracted"); TEST_ASSERT_STR_EQ("text", info, "Info should be updated"); TEST_PASS("extract_speed_course with leading zeros"); } int test_extract_speed_course_mixed_valid_chars(void) { char info[100] = "1.0/0 5data"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 (periods and spaces allowed in format)"); // Second validation pass checks first 2 chars for digits, so both will be cleared TEST_ASSERT_STR_EQ("", speed, "Speed should be empty (space in first 2 chars)"); TEST_ASSERT_STR_EQ("", course, "Course should be empty (period in first 2 chars)"); TEST_ASSERT_STR_EQ("data", info, "Info should be updated"); TEST_PASS("extract_speed_course with mixed valid characters"); } int test_extract_speed_course_partial_match(void) { char info[100] = "123/45Xrest"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 0, "Should return 0 for partial invalid match"); TEST_ASSERT_STR_EQ("", speed, "Speed should be empty"); TEST_ASSERT_STR_EQ("", course, "Course should be empty"); TEST_ASSERT_STR_EQ("123/45Xrest", info, "Info should be unchanged"); TEST_PASS("extract_speed_course with partial match"); } int test_extract_speed_course_long_string(void) { char info[100] = "270/045this is a long additional string"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("045", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("270", course, "Course should be extracted"); TEST_ASSERT_STR_EQ("this is a long additional string", info, "Rest of string should remain"); TEST_PASS("extract_speed_course with long additional data"); } int test_extract_speed_course_course_001(void) { char info[100] = "001/100end"; char speed[10]; char course[10]; int result; result = extract_speed_course(info, speed, course); TEST_ASSERT(result == 1, "Should return 1 for valid format"); TEST_ASSERT_STR_EQ("100", speed, "Speed should be extracted"); TEST_ASSERT_STR_EQ("001", course, "Course 001 is valid (>0)"); TEST_ASSERT_STR_EQ("end", info, "Info should be updated"); TEST_PASS("extract_speed_course with course=001 (minimum valid)"); } /* Test runner */ typedef struct { const char *name; int (*func)(void); } test_case_t; int main(int argc, char *argv[]) { test_case_t tests[] = { /* pad_callsign tests */ {"pad_callsign_basic", test_pad_callsign_basic}, {"pad_callsign_with_ssid", test_pad_callsign_with_ssid}, {"pad_callsign_full_length", test_pad_callsign_full_length}, {"pad_callsign_empty", test_pad_callsign_empty}, {"pad_callsign_short", test_pad_callsign_short}, {"pad_callsign_invalid_chars", test_pad_callsign_invalid_chars}, {"pad_callsign_multiple_invalid", test_pad_callsign_multiple_invalid}, {"pad_callsign_lowercase", test_pad_callsign_lowercase}, {"pad_callsign_mixed_case", test_pad_callsign_mixed_case}, {"pad_callsign_numbers_only", test_pad_callsign_numbers_only}, {"pad_callsign_hyphen_only", test_pad_callsign_hyphen_only}, {"pad_callsign_spaces_in_input", test_pad_callsign_spaces_in_input}, {"pad_callsign_trailing_hyphen", test_pad_callsign_trailing_hyphen}, {"pad_callsign_leading_hyphen", test_pad_callsign_leading_hyphen}, {"pad_callsign_multiple_hyphens", test_pad_callsign_multiple_hyphens}, /* extract_speed_course tests */ {"extract_speed_course_valid_basic", test_extract_speed_course_valid_basic}, {"extract_speed_course_valid_no_extra_data", test_extract_speed_course_valid_no_extra_data}, {"extract_speed_course_course_zero", test_extract_speed_course_course_zero}, {"extract_speed_course_with_spaces", test_extract_speed_course_with_spaces}, {"extract_speed_course_with_periods", test_extract_speed_course_with_periods}, {"extract_speed_course_invalid_separator", test_extract_speed_course_invalid_separator}, {"extract_speed_course_too_short", test_extract_speed_course_too_short}, {"extract_speed_course_invalid_chars", test_extract_speed_course_invalid_chars}, {"extract_speed_course_empty_string", test_extract_speed_course_empty_string}, {"extract_speed_course_max_values", test_extract_speed_course_max_values}, {"extract_speed_course_leading_zeros", test_extract_speed_course_leading_zeros}, {"extract_speed_course_mixed_valid_chars", test_extract_speed_course_mixed_valid_chars}, {"extract_speed_course_partial_match", test_extract_speed_course_partial_match}, {"extract_speed_course_long_string", test_extract_speed_course_long_string}, {"extract_speed_course_course_001", test_extract_speed_course_course_001}, {NULL, NULL} }; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "Available tests:\n"); for (int i = 0; tests[i].name != NULL; i++) { fprintf(stderr, " %s\n", tests[i].name); } return 1; } const char *test_name = argv[1]; /* Run the requested test */ for (int i = 0; tests[i].name != NULL; i++) { if (strcmp(test_name, tests[i].name) == 0) { return tests[i].func(); } } fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_db_stubs.c0000664000175000017500000001654015151324131017501 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Stub implementations for symbols referenced by db.o * but not used by the unit tests. * * These stubs allow us to link with the real db.o for testing * without pulling in the entire Xastir codebase. */ #include #include #include #include "tests/test_framework.h" #define MAX_CALLSIGN 9 // Objects are up to 9 chars /* Add stub implementations for all the undefined symbols */ /* Note: These are intentionally empty/abort to catch any unexpected usage */ /* Global variables that db.o references */ int debug_level = 0; char my_callsign[MAX_CALLSIGN+1] = "TEST"; int altnet = 0; int track_case = 0; int track_match = 0; int track_station_on = 0; char tracking_station_call[100] = ""; int trail_segment_distance = 0; int trail_segment_time = 0; int transmit_disable = 0; int transmit_now = 0; int wait_to_redraw = 0; /* Stub functions */ STUB_IMPL(alert_build_list) STUB_IMPL(alert_match) STUB_IMPL(alert_on_alert_list) STUB_IMPL(all_messages) STUB_IMPL(bulletin_message_check) STUB_IMPL(draw_area) STUB_IMPL(draw_labeled_area) STUB_IMPL(output_my_data) STUB_IMPL(request_new_image) STUB_IMPL(schedule_reboot) STUB_IMPL(setup_message_data) STUB_IMPL(sound_play) STUB_IMPL(transmit_message_data) STUB_IMPL(transmit_message_data_delayed) STUB_IMPL(track_station) STUB_IMPL(valid_call) STUB_IMPL(valid_inet_name) STUB_IMPL(valid_object) STUB_IMPL(valid_path) STUB_IMPL(split_string) STUB_IMPL(statusline) STUB_IMPL(begin_critical_section) STUB_IMPL(bulletin_data_add) STUB_IMPL(calc_distance_course) STUB_IMPL(check_popup_window) STUB_IMPL(clear_acked_message) STUB_IMPL(convert_bearing_to_name) STUB_IMPL(convert_lat_l2s) STUB_IMPL(convert_lat_s2l) STUB_IMPL(convert_lon_l2s) STUB_IMPL(convert_lon_s2l) STUB_IMPL(create_garmin_waypoint) STUB_IMPL(decode_Peet_Bros) STUB_IMPL(decode_U2000_L) STUB_IMPL(decode_U2000_P) STUB_IMPL(disown_object_item) STUB_IMPL(display_station) STUB_IMPL(distance_from_my_station) STUB_IMPL(draw_trail) STUB_IMPL(end_critical_section) STUB_IMPL(filecreate) STUB_IMPL(fill_in_new_alert_entries) STUB_IMPL(get_iso_datetime) STUB_IMPL(get_send_message_path) STUB_IMPL(get_tactical_from_hash) STUB_IMPL(get_time) STUB_IMPL(get_timestamp) STUB_IMPL(get_user_base_dir) STUB_IMPL(get_w3cdtf_datetime) STUB_IMPL(insert_into_heard_queue) STUB_IMPL(is_local_interface) STUB_IMPL(is_network_interface) STUB_IMPL(is_num_chr) STUB_IMPL(is_num_or_sp) STUB_IMPL(is_xnum_or_dash) STUB_IMPL(langcode) STUB_IMPL(Locate_station) STUB_IMPL(log_data) STUB_IMPL(log_tactical_call) STUB_IMPL(look_for_open_group_data) STUB_IMPL(makePrintable) STUB_IMPL(play_sound) STUB_IMPL(popup_message) STUB_IMPL(popup_message_always) STUB_IMPL(port_write_string) STUB_IMPL(position_defined) STUB_IMPL(remove_leading_spaces) STUB_IMPL(remove_trailing_asterisk) STUB_IMPL(remove_trailing_spaces) STUB_IMPL(SayText) STUB_IMPL(spell_it_out) STUB_IMPL(sec_now) STUB_IMPL(send_agwpe_packet) STUB_IMPL(send_ax25_frame) STUB_IMPL(stations_types) STUB_IMPL(output_igate_net) STUB_IMPL(output_igate_rf) STUB_IMPL(output_message) STUB_IMPL(output_nws_igate_rf) /* Functions we actually need - not stubs */ void substr(char *dest, char *src, int size) { /* Simple implementation - copy size characters */ int i; for (i = 0; i < size && src[i] != '\0'; i++) { dest[i] = src[i]; } dest[i] = '\0'; } char *to_upper(char *data) { /* Simple stub - just return data unchanged for now */ return data; } /* Widget and display related globals */ void *Display_ = NULL; void *Display_data_dialog = NULL; void *Display_data_text = NULL; int Display_packet_data_mine_only = 0; int Display_packet_data_type = 0; void *LOGFILE_MESSAGE = NULL; void *LOGFILE_WX_ALERT = NULL; /* Screen coordinate globals */ long NW_corner_latitude = 0; long NW_corner_longitude = 0; long SE_corner_latitude = 0; long SE_corner_longitude = 0; long center_latitude = 0; long center_longitude = 0; /* Display selection globals */ void *Select_ = NULL; time_t aircraft_sec_clear = 0; /* Alert and message globals */ char altnet_call[MAX_CALLSIGN+1] = ""; int auto_reply = 0; char auto_reply_message[256] = ""; /* Band open globals */ int bando_min = 0; int bando_max = 0; /* Device globals */ void *devices = NULL; void *mw = NULL; void *port_data = NULL; int transmit_compressed_posit; /* Distance and angle globals */ float da = 0.0; /* English units flag */ int english_units = 0; /* Igate globals */ int igate_msgs_tx = 0; int operate_as_an_igate = 0; /* Data copy buffers */ char incoming_data_copy[1024] = ""; char incoming_data_copy_previous[1024] = ""; /* Locate station globals */ char locate_station_call[MAX_CALLSIGN+1] = ""; /* My station globals */ long my_last_altitude = 0; time_t my_last_altitude_time = 0; int my_last_course = 0; int my_last_speed = 0; long my_lat = 0; long my_long = 0; int my_position_valid = 0; int my_trail_diff_color = 0; /* Proximity globals */ int prox_min = 0; int prox_max = 0; /* Redraw globals */ int redo_list = 0; int redraw_on_new_data = 0; /* Screen dimensions */ unsigned long scale_x = 0; unsigned long scale_y = 0; int screen_height = 0; int screen_width = 0; /* Station clear time globals */ time_t sec_clear = 0; time_t sec_remove = 0; /* Send message dialog lock */ void *send_message_dialog_lock = NULL; /* Smart beaconing globals */ int smart_beaconing = 0; int sb_POSIT_rate = 0; int sb_current_heading = 0; int sb_high_speed_limit = 0; int sb_last_heading = 0; int sb_low_speed_limit = 0; int sb_posit_fast = 0; int sb_posit_slow = 0; int sb_turn_min = 0; int sb_turn_slope = 0; time_t sb_turn_time = 0; /* Position timing globals */ time_t posit_last_time = 0; time_t posit_next_time = 0; /* Sound globals */ int sound_band_open_message = 0; char sound_command[256] = ""; int sound_new_message = 0; int sound_new_station = 0; int sound_play_band_open_message; int sound_play_new_message; int sound_play_new_station; int sound_play_prox_message; int sound_prox_message = 0; /* Festival speak globals */ int festival_speak_ID=0; int festival_speak_new_station=0; int festival_speak_proximity_alert=0; int festival_speak_tracked_proximity_alert=0; int festival_speak_band_opening=0; int festival_speak_new_message_alert=0; int festival_speak_new_message_body=0; int festival_speak_new_weather_alert=0; /* Station capability globals */ int show_only_station_capabilities = 0; /* Trail color global */ int current_trail_color = 0; /* Logging globals */ int log_wx_alert_data; int log_message_data; int read_file; /* Conversion globals */ double cvt_kn2len; // from knots double cvt_mi2len; // from miles Xastir-Release-2.2.4/tests/test_framework.h0000664000175000017500000000331215151324131017667 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* This file contains test framework macros for unit testing */ #define TEST_ASSERT(cond, msg) do { \ if (!(cond)) { \ fprintf(stderr, "FAIL: %s\n Assertion failed: %s\n", msg, #cond); \ return 1; \ } \ } while(0) #define TEST_ASSERT_STR_EQ(expected, actual, msg) do { \ if (strcmp(expected, actual) != 0) { \ fprintf(stderr, "FAIL: %s\n Expected: '%s'\n Got: '%s'\n", \ msg, expected, actual); \ return 1; \ } \ } while(0) #define TEST_PASS(msg) do { \ printf("PASS: %s\n", msg); \ return 0; \ } while(0) /* Stub implementations - these should never be called by our tests */ #define STUB_IMPL(name) \ void name(void) { \ fprintf(stderr, "ERROR: Stub function %s called - test is using untested code path\n", #name); \ abort(); \ } Xastir-Release-2.2.4/tests/test_interface_helpers.c0000664000175000017500000000351615151324131021355 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* test_interface_helpers.c * This are some stub tests to verify that the test framework is working. * This file is planned to be used later for a planned refactoring of interface.c */ #include #include #include int test_build(void) { /* This test just verifies that the test program compiled and linked successfully */ printf("Testing that test program builds correctly...\n"); printf("PASS: Build test\n"); return 0; } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "Available tests:\n"); fprintf(stderr, " infrastructure - Basic infrastructure test\n"); fprintf(stderr, " build - Test program build verification\n"); return 1; } const char *test = argv[1]; if (strcmp(test, "build") == 0) { return test_build(); } else { fprintf(stderr, "Unknown test: %s\n", test); return 1; } return 0; } Xastir-Release-2.2.4/tests/test_nominatim.c0000664000175000017500000004051315151324131017664 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for nominatim.c functions * * This test program tests the Nominatim geocoding implementation including: * - Cache lookup and storage * - Rate limiting * - URL formation with country codes and email */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include "tests/test_framework.h" // Geocoder structures needed for tests #include "geocoder.h" // External config variables that nominatim.c depends on extern char nominatim_server_url[400]; extern int nominatim_cache_enabled; extern int nominatim_cache_days; extern char nominatim_user_email[100]; // Functions from nominatim.c that we need to test // Note: Some are static and exposed via test-specific build or we test through public API extern void nominatim_init(void); extern void nominatim_clear_cache(void); // Helper functions exposed for testing (these would normally be static) // We'll declare them here and conditionally compile them in nominatim.c for testing extern void compute_query_hash(const char *query, const char *country_codes, char *hash, size_t hash_size); extern int cache_lookup(const char *query, const char *country_codes, struct geocode_result_list *results); extern void cache_store(const char *query, const char *country_codes, const struct geocode_result_list *results); /* Test cases */ /** * Test: compute_query_hash produces consistent hashes */ int test_compute_query_hash_consistency(void) { char hash1[33]; char hash2[33]; compute_query_hash("This is a query that should produce a consistent hash", NULL, hash1, sizeof(hash1)); compute_query_hash("This is a query that should produce a consistent hash", NULL, hash2, sizeof(hash2)); TEST_ASSERT_STR_EQ(hash1, hash2, "Same query should produce same hash"); TEST_PASS("compute_query_hash produces consistent hashes"); } /** * Test: compute_query_hash is case-insensitive */ int test_compute_query_hash_case_insensitive(void) { char hash1[33]; char hash2[33]; compute_query_hash("Seattle", NULL, hash1, sizeof(hash1)); compute_query_hash("seattle", NULL, hash2, sizeof(hash2)); TEST_ASSERT_STR_EQ(hash1, hash2, "Hash should be case-insensitive"); TEST_PASS("compute_query_hash is case-insensitive"); } /** * Test: compute_query_hash includes country codes in hash */ int test_compute_query_hash_with_country(void) { char hash1[33]; char hash2[33]; compute_query_hash("Paris", NULL, hash1, sizeof(hash1)); compute_query_hash("Paris", "fr", hash2, sizeof(hash2)); TEST_ASSERT(strcmp(hash1, hash2) != 0, "Hash with country code should differ from hash without"); TEST_PASS("compute_query_hash includes country codes"); } /** * Test: compute_query_hash produces different hashes for different queries */ int test_compute_query_hash_different_queries(void) { char hash1[33]; char hash2[33]; compute_query_hash("Seattle", NULL, hash1, sizeof(hash1)); compute_query_hash("Portland", NULL, hash2, sizeof(hash2)); TEST_ASSERT(strcmp(hash1, hash2) != 0, "Different queries should produce different hashes"); TEST_PASS("compute_query_hash produces different hashes for different queries"); } /** * Test: Cache lookup returns 0 for empty cache */ int test_cache_lookup_empty(void) { struct geocode_result_list results; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; memset(&results, 0, sizeof(results)); int found = cache_lookup("Test Query", NULL, &results); TEST_ASSERT(found == 0, "Cache lookup should return 0 for empty cache"); TEST_PASS("Cache lookup returns 0 for empty cache"); } /** * Test: Cache store and lookup round-trip */ int test_cache_store_and_lookup(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Create a result to store memset(&result, 0, sizeof(result)); result.lat = 47.6062; result.lon = -122.3321; strncpy(result.display_name, "Seattle, WA", sizeof(result.display_name)); strncpy(result.settlement, "Seattle", sizeof(result.settlement)); strncpy(result.state, "Washington", sizeof(result.state)); strncpy(result.country, "United States", sizeof(result.country)); // Store in cache store_results.count = 1; store_results.capacity = 1; store_results.results = &result; cache_store("Seattle", NULL, &store_results); // Look up from cache memset(&lookup_results, 0, sizeof(lookup_results)); int found = cache_lookup("Seattle", NULL, &lookup_results); TEST_ASSERT(found == 1, "Cache lookup should find stored result"); TEST_ASSERT(lookup_results.count == 1, "Cache should return correct number of results"); TEST_ASSERT(lookup_results.results != NULL, "Cache should return result data"); TEST_ASSERT(lookup_results.results[0].lat == 47.6062, "Cached result should have correct latitude"); TEST_ASSERT(lookup_results.results[0].lon == -122.3321, "Cached result should have correct longitude"); // Clean up free(lookup_results.results); TEST_PASS("Cache store and lookup round-trip works"); } /** * Test: Cache respects case-insensitive lookup */ int test_cache_case_insensitive(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Create and store result memset(&result, 0, sizeof(result)); result.lat = 47.6062; result.lon = -122.3321; store_results.count = 1; store_results.capacity = 1; store_results.results = &result; cache_store("Seattle", NULL, &store_results); // Look up with different case memset(&lookup_results, 0, sizeof(lookup_results)); int found = cache_lookup("SEATTLE", NULL, &lookup_results); TEST_ASSERT(found == 1, "Cache lookup should be case-insensitive"); // Clean up if (lookup_results.results) { free(lookup_results.results); } TEST_PASS("Cache is case-insensitive"); } /** * Test: Cache distinguishes queries with different country codes */ int test_cache_country_codes(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result1, result2; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Store Paris, France memset(&result1, 0, sizeof(result1)); result1.lat = 48.8566; result1.lon = 2.3522; strncpy(result1.settlement, "Paris", sizeof(result1.settlement)); strncpy(result1.country, "France", sizeof(result1.country)); store_results.count = 1; store_results.capacity = 1; store_results.results = &result1; cache_store("Paris", "fr", &store_results); // Store Paris, Texas (US) memset(&result2, 0, sizeof(result2)); result2.lat = 33.6609; result2.lon = -95.5555; strncpy(result2.settlement, "Paris", sizeof(result2.settlement)); strncpy(result2.country, "United States", sizeof(result2.country)); store_results.results = &result2; cache_store("Paris", "us", &store_results); // Look up Paris, France memset(&lookup_results, 0, sizeof(lookup_results)); int found_fr = cache_lookup("Paris", "fr", &lookup_results); TEST_ASSERT(found_fr == 1, "Cache should find Paris, France"); TEST_ASSERT(lookup_results.results[0].lat == 48.8566 && lookup_results.results[0].lon == 2.3522, "Should return Paris, France coordinates"); free(lookup_results.results); // Look up Paris, US memset(&lookup_results, 0, sizeof(lookup_results)); int found_us = cache_lookup("Paris", "us", &lookup_results); TEST_ASSERT(found_us == 1, "Cache should find Paris, US"); TEST_ASSERT(lookup_results.results[0].lat == 33.6609, "Should return US Paris coordinates"); free(lookup_results.results); TEST_PASS("Cache distinguishes queries with different country codes"); } /** * Test: Cache clear removes all entries */ int test_cache_clear(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Store a result memset(&result, 0, sizeof(result)); result.lat = 47.6062; result.lon = -122.3321; store_results.count = 1; store_results.capacity = 1; store_results.results = &result; cache_store("Seattle", NULL, &store_results); // Verify it's in cache memset(&lookup_results, 0, sizeof(lookup_results)); int found_before = cache_lookup("Seattle", NULL, &lookup_results); if (lookup_results.results) { free(lookup_results.results); } // Clear cache nominatim_clear_cache(); // Verify it's gone memset(&lookup_results, 0, sizeof(lookup_results)); int found_after = cache_lookup("Seattle", NULL, &lookup_results); TEST_ASSERT(found_before == 1, "Result should be in cache before clear"); TEST_ASSERT(found_after == 0, "Result should not be in cache after clear"); TEST_PASS("Cache clear removes all entries"); } /** * Test: Cache respects disabled setting */ int test_cache_disabled(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 0; // Disable cache nominatim_cache_days = 30; // Try to store a result memset(&result, 0, sizeof(result)); result.lat = 47.6062; result.lon = -122.3321; store_results.count = 1; store_results.capacity = 1; store_results.results = &result; cache_store("Seattle", NULL, &store_results); // Try to look up (should not find because cache was disabled during store) memset(&lookup_results, 0, sizeof(lookup_results)); int found = cache_lookup("Seattle", NULL, &lookup_results); TEST_ASSERT(found == 0, "Cache lookup should not find results when cache was disabled"); TEST_PASS("Cache respects disabled setting"); } /** * Test: Multiple results in cache */ int test_cache_multiple_results(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result results[3]; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Create multiple results memset(results, 0, sizeof(results)); results[0].lat = 47.6062; results[0].lon = -122.3321; strncpy(results[0].settlement, "Seattle", sizeof(results[0].settlement)); results[1].lat = 45.5152; results[1].lon = -122.6784; strncpy(results[1].settlement, "Portland", sizeof(results[1].settlement)); results[2].lat = 49.2827; results[2].lon = -123.1207; strncpy(results[2].settlement, "Vancouver", sizeof(results[2].settlement)); // Store multiple results store_results.count = 3; store_results.capacity = 3; store_results.results = results; cache_store("Pacific Northwest Cities", NULL, &store_results); // Look up memset(&lookup_results, 0, sizeof(lookup_results)); int found = cache_lookup("Pacific Northwest Cities", NULL, &lookup_results); TEST_ASSERT(found == 1, "Cache should find stored results"); TEST_ASSERT(lookup_results.count == 3, "Cache should return all 3 results"); TEST_ASSERT(lookup_results.results[0].lat == 47.6062, "First result should be Seattle"); TEST_ASSERT(lookup_results.results[1].lat == 45.5152, "Second result should be Portland"); TEST_ASSERT(lookup_results.results[2].lat == 49.2827, "Third result should be Vancouver"); free(lookup_results.results); TEST_PASS("Cache handles multiple results correctly"); } /** * Test: Cache update existing entry */ int test_cache_update_existing(void) { struct geocode_result_list store_results; struct geocode_result_list lookup_results; struct geocode_result result1, result2; // Clear cache and initialize nominatim_clear_cache(); nominatim_init(); nominatim_cache_enabled = 1; nominatim_cache_days = 30; // Store initial result memset(&result1, 0, sizeof(result1)); result1.lat = 47.6062; result1.lon = -122.3321; strncpy(result1.settlement, "Seattle", sizeof(result1.settlement)); store_results.count = 1; store_results.capacity = 1; store_results.results = &result1; cache_store("Test City", NULL, &store_results); // Update with different result memset(&result2, 0, sizeof(result2)); result2.lat = 45.5152; result2.lon = -122.6784; strncpy(result2.settlement, "Portland", sizeof(result2.settlement)); store_results.results = &result2; cache_store("Test City", NULL, &store_results); // Look up - should get updated result memset(&lookup_results, 0, sizeof(lookup_results)); int found = cache_lookup("Test City", NULL, &lookup_results); TEST_ASSERT(found == 1, "Cache should find updated result"); TEST_ASSERT(lookup_results.results[0].lat == 45.5152, "Cache should return updated latitude"); TEST_ASSERT(strcmp(lookup_results.results[0].settlement, "Portland") == 0, "Cache should return updated settlement"); free(lookup_results.results); TEST_PASS("Cache updates existing entries correctly"); } /* Main test runner */ int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char *test_name = argv[1]; // Hash tests if (strcmp(test_name, "compute_query_hash_consistency") == 0) return test_compute_query_hash_consistency(); if (strcmp(test_name, "compute_query_hash_case_insensitive") == 0) return test_compute_query_hash_case_insensitive(); if (strcmp(test_name, "compute_query_hash_with_country") == 0) return test_compute_query_hash_with_country(); if (strcmp(test_name, "compute_query_hash_different_queries") == 0) return test_compute_query_hash_different_queries(); // Cache tests if (strcmp(test_name, "cache_lookup_empty") == 0) return test_cache_lookup_empty(); if (strcmp(test_name, "cache_store_and_lookup") == 0) return test_cache_store_and_lookup(); if (strcmp(test_name, "cache_case_insensitive") == 0) return test_cache_case_insensitive(); if (strcmp(test_name, "cache_country_codes") == 0) return test_cache_country_codes(); if (strcmp(test_name, "cache_clear") == 0) return test_cache_clear(); if (strcmp(test_name, "cache_disabled") == 0) return test_cache_disabled(); if (strcmp(test_name, "cache_multiple_results") == 0) return test_cache_multiple_results(); if (strcmp(test_name, "cache_update_existing") == 0) return test_cache_update_existing(); fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_nominatim_stubs.c0000664000175000017500000000463615151324131021112 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Stub implementations for symbols referenced by nominatim.o * but not needed by the unit tests. * * These stubs allow us to link with the nominatim code for testing * without pulling in the entire Xastir codebase. */ #include #include #include #include #include "tests/test_framework.h" // Debug level (used throughout Xastir) int debug_level = 0; // Package version (for User-Agent string) const char PACKAGE_VERSION[] = "2.2.0-test"; // Stub implementations of functions called by nominatim.c // Mutex functions - for testing, we can use no-op implementations void init_critical_section(void *mutex) { // No-op for testing (void)mutex; } void begin_critical_section(void *mutex, const char *location) { // No-op for testing (void)mutex; (void)location; } void end_critical_section(void *mutex, const char *location) { // No-op for testing (void)mutex; (void)location; } // snprintf wrapper - just use system snprintf int xastir_snprintf(char *str, size_t size, const char *format, ...) { va_list args; int ret; va_start(args, format); ret = vsnprintf(str, size, format, args); va_end(args); return ret; } #include // curl initialization wrapper - stub implementation for tests CURL* xastir_curl_init(char *error_buffer) { (void)error_buffer; // Unused in stub CURL *curl = curl_easy_init(); return curl; } // Leak detection - no-op for tests void leak_detection_init(void) {} void leak_detection_cleanup(void) {} Xastir-Release-2.2.4/tests/test_object_utils.c0000664000175000017500000034104515151324131020363 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for object_utils.c functions * */ #include #include #include #include #include #include "tests/test_framework.h" // This file contains (and should always contain) only declarations of // function prototypes, so it is safe to include here #include "object_utils.h" /* test cases for pad_item_name */ int test_pad_item_name_nopad9(void) { char name[10]; snprintf(name,sizeof(name),"A12345678"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A12345678",name,"9-char name not modified"); TEST_PASS("pad_item_name: 9 character name not modified"); } int test_pad_item_name_nopad8(void) { char name[10]; snprintf(name,sizeof(name),"A1234567"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A1234567",name,"8-char name not modified"); TEST_PASS("pad_item_name: 8 character name not modified"); } int test_pad_item_name_nopad7(void) { char name[10]; snprintf(name,sizeof(name),"A123456"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A123456",name,"7-char name not modified"); TEST_PASS("pad_item_name: 7 character name not modified"); } int test_pad_item_name_nopad6(void) { char name[10]; snprintf(name,sizeof(name),"A12345"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A12345",name,"6-char name not modified"); TEST_PASS("pad_item_name: 6 character name not modified"); } int test_pad_item_name_nopad5(void) { char name[10]; snprintf(name,sizeof(name),"A1234"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A1234",name,"5-char name not modified"); TEST_PASS("pad_item_name: 5 character name not modified"); } int test_pad_item_name_nopad4(void) { char name[10]; snprintf(name,sizeof(name),"A123"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A123",name,"4-char name not modified"); TEST_PASS("pad_item_name: 4 character name not modified"); } int test_pad_item_name_nopad3(void) { char name[10]; snprintf(name,sizeof(name),"A12"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A12",name,"3-char name not modified"); TEST_PASS("pad_item_name: 3 character name not modified"); } int test_pad_item_name_pad2(void) { char name[10]; snprintf(name,sizeof(name),"A1"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A1 ",name,"2-char name padded with one space"); TEST_PASS("pad_item_name: 2 character name padded with one space"); } int test_pad_item_name_pad1(void) { char name[10]; snprintf(name,sizeof(name),"A"); pad_item_name(name,sizeof(name)); TEST_ASSERT_STR_EQ("A ",name,"1-char name padded with two spaces"); TEST_PASS("pad_item_name: 1 character name padded with two spaces"); } /* test cases for format_course_speed */ int test_format_course_speed_basic(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "090","005", &course, &speed); TEST_ASSERT_STR_EQ("090/005",course_speed_string, "Valid course and speed should be CSE/SPD"); TEST_ASSERT(course == 90, "Integer course should be 90"); TEST_ASSERT(speed == 5, "Integer speed should be 5"); TEST_PASS("format_course_speed with valid input for both"); } int test_format_course_speed_bad_course(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "390","005", &course, &speed); TEST_ASSERT_STR_EQ(".../005",course_speed_string, "Valid course and speed should be CSE/SPD, invalid course should be ..."); TEST_ASSERT(course == 0, "Integer course should be 00"); TEST_ASSERT(speed == 5, "Integer speed should be 5"); TEST_PASS("format_course_speed with bad input for course"); } int test_format_course_speed_null_course(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "","005", &course, &speed); TEST_ASSERT_STR_EQ(".../005",course_speed_string, "Valid course and speed should be CSE/SPD, null course should be ..."); TEST_ASSERT(course == 0, "Integer course should be 00"); TEST_ASSERT(speed == 5, "Integer speed should be 5"); TEST_PASS("format_course_speed with null input for course"); } int test_format_course_speed_bad_speed(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "090","1005", &course, &speed); TEST_ASSERT_STR_EQ("090/...",course_speed_string, "Valid course and speed should be CSE/SPD, invalid speed should be ..."); TEST_ASSERT(course == 90, "Integer course should be 90"); TEST_ASSERT(speed == 0, "Integer speed should be 0"); TEST_PASS("format_course_speed with bad input for speed"); } int test_format_course_speed_null_speed(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "090","", &course, &speed); TEST_ASSERT_STR_EQ("090/...",course_speed_string, "Valid course and speed should be CSE/SPD, missing speed should be ..."); TEST_ASSERT(course == 90, "Integer course should be 90"); TEST_ASSERT(speed == 0, "Integer speed should be 0"); TEST_PASS("format_course_speed with null input for speed"); } int test_format_course_speed_null_inputs(void) { char course_speed_string[8]; int speed,course; format_course_speed(course_speed_string,sizeof(course_speed_string), "","", &course, &speed); TEST_ASSERT_STR_EQ("",course_speed_string, "Valid course and speed should be CSE/SPD, missing both should be empty string"); TEST_ASSERT(course == 0, "Integer course should be 90"); TEST_ASSERT(speed == 0, "Integer speed should be 0"); TEST_PASS("format_course_speed with null input for both"); } // tests for format_altitude int test_format_altitude_basic(void) { char altitude[10]; format_altitude(altitude, sizeof(altitude),"15"); TEST_ASSERT_STR_EQ("/A=000049",altitude,"15 feet altitude should be 49 meters, properly formatted"); TEST_PASS("format_altitude with valid input"); } int test_format_altitude_null_input(void) { char altitude[10]; format_altitude(altitude, sizeof(altitude),""); TEST_ASSERT_STR_EQ("",altitude,"Null input should yield null output"); TEST_PASS("format_altitude with null input"); } int test_format_altitude_invalid_input(void) { char altitude[10]; format_altitude(altitude, sizeof(altitude),"330000"); TEST_ASSERT_STR_EQ("",altitude,"Excessive altitude should yield null output"); TEST_PASS("format_altitude with invalid input"); } // test for format_zulu_time int test_format_zulu_time(void) { char time[8]; format_zulu_time(time,sizeof(time)); TEST_ASSERT_STR_EQ("111618z",time,"Format of unix timestamp 1762877880 should map to day 11 hour 16 minute 18 zulu"); TEST_PASS("format_zulu_time for specific unix timestamp"); } // area color tests int test_format_area_color_from_numeric_basic(void) { char color[3]; format_area_color_from_numeric(color,sizeof(color),0); TEST_ASSERT_STR_EQ("/0",color,"Bright black correct"); format_area_color_from_numeric(color,sizeof(color),1); TEST_ASSERT_STR_EQ("/1",color,"Bright blue correct"); format_area_color_from_numeric(color,sizeof(color),8); TEST_ASSERT_STR_EQ("/8",color,"Low black correct"); format_area_color_from_numeric(color,sizeof(color),14); TEST_ASSERT_STR_EQ("14",color,"Low yellow correct"); TEST_PASS("format_area_color_from_numeric for valid colors"); } int test_format_area_color_from_numeric_invalid(void) { char color[3]; format_area_color_from_numeric(color,sizeof(color),16); TEST_ASSERT_STR_EQ("/4",color,"Bad color gives bright red"); TEST_PASS("format_area_color_from_numeric for invalid colors"); } int test_area_color_from_string_basic(void) { int color; color = area_color_from_string("/1"); TEST_ASSERT(color == 1, " /1 maps to 1"); color = area_color_from_string("/8"); TEST_ASSERT(color == 8, " /8 maps to 8"); color = area_color_from_string("15"); TEST_ASSERT(color == 15, " 15 maps to 15"); TEST_PASS("area_color_from_string for valid color strings"); } int test_area_color_from_string_invalid(void) { int color; color = area_color_from_string("16"); TEST_ASSERT(color == 0, " invalid value maps to 0"); color = area_color_from_string("20"); TEST_ASSERT(color == 0, " invalid string maps to 0"); color = area_color_from_string("FOOBIE"); TEST_ASSERT(color == 0, " non-numeric string maps to 0"); color = area_color_from_string(""); TEST_ASSERT(color == 0, " empty string maps to 0"); TEST_PASS("area_color_from_string for invalid color strings"); } int test_area_color_from_string_midstring(void) { int color; char *color_string = "XXX/1XXX"; color = area_color_from_string(&(color_string[3])); TEST_ASSERT(color == 1, " /1 maps to 1"); TEST_PASS("area_color_from_string for color string inside longer string"); } int test_format_area_color_from_dialog_basic(void) { char outstring[3]; format_area_color_from_dialog(outstring, sizeof(outstring), "/1", 1); TEST_ASSERT_STR_EQ("/1", outstring, "Bright blue maps correctly"); format_area_color_from_dialog(outstring, sizeof(outstring), "/1", 0); TEST_ASSERT_STR_EQ("/9", outstring, "Dim blue maps correctly"); format_area_color_from_dialog(outstring, sizeof(outstring), "/7", 1); TEST_ASSERT_STR_EQ("/7", outstring, "Bright grey maps correctly"); format_area_color_from_dialog(outstring, sizeof(outstring), "/7", 0); TEST_ASSERT_STR_EQ("15", outstring, "Dim grey maps correctly"); TEST_PASS("format_area_color_from_dialog for valid bright and dim colors"); } int test_format_area_corridor_threedigit(void) { char complete_corridor[6]; format_area_corridor(complete_corridor, sizeof(complete_corridor), 1, 100); TEST_ASSERT_STR_EQ("{100}", complete_corridor, "Three-digit corridor correctly formatted"); TEST_PASS("format_area_corridor for three-digit corridor values"); } int test_format_area_corridor_twodigit(void) { char complete_corridor[6]; format_area_corridor(complete_corridor, sizeof(complete_corridor), 1, 10); TEST_ASSERT_STR_EQ("{10}", complete_corridor, "Two-digit corridor correctly formatted"); TEST_PASS("format_area_corridor for two-digit corridor values"); } int test_format_area_corridor_onedigit(void) { char complete_corridor[6]; format_area_corridor(complete_corridor, sizeof(complete_corridor), 1, 1); TEST_ASSERT_STR_EQ("{1}", complete_corridor, "one-digit corridor correctly formatted"); TEST_PASS("format_area_corridor for one-digit corridor values"); } // test format_signpost int test_format_signpost_threechar(void) { char signpost[6]; format_signpost(signpost, sizeof(signpost), "100"); TEST_ASSERT_STR_EQ("{100}", signpost, "Three-char signpost correctly formatted"); TEST_PASS("format_signpost for three-char signpost values"); } int test_format_signpost_twochar(void) { char signpost[6]; format_signpost(signpost, sizeof(signpost), "10"); TEST_ASSERT_STR_EQ("{10}", signpost, "Two-char signpost correctly formatted"); TEST_PASS("format_signpost for two-char signpost values"); } int test_format_signpost_onechar(void) { char signpost[6]; format_signpost(signpost, sizeof(signpost), "1"); TEST_ASSERT_STR_EQ("{1}", signpost, "one-char signpost correctly formatted"); TEST_PASS("format_signpost for one-char signpost values"); } // test probability ring formatting int test_format_probability_ring_data_both(void) { char comment[43+1]; snprintf(comment,sizeof(comment),"Pointless Noise"); format_probability_ring_data(comment,sizeof(comment),"1","2"); TEST_ASSERT_STR_EQ("Pmin1,Pmax2,Pointless Noise", comment, "Probability rings correctly formatted when both min and max specified."); TEST_PASS("format_probability_ring_data when min and max specified"); } int test_format_probability_ring_data_min_only(void) { char comment[43+1]; snprintf(comment,sizeof(comment),"Pointless Noise"); format_probability_ring_data(comment,sizeof(comment),"1",""); TEST_ASSERT_STR_EQ("Pmin1,Pointless Noise", comment, "Probability rings correctly formatted when only min specified."); TEST_PASS("format_probability_ring_data when only min specified"); } int test_format_probability_ring_data_max_only(void) { char comment[43+1]; snprintf(comment,sizeof(comment),"Pointless Noise"); format_probability_ring_data(comment,sizeof(comment),"","1"); TEST_ASSERT_STR_EQ("Pmax1,Pointless Noise", comment, "Probability rings correctly formatted when only max specified."); TEST_PASS("format_probability_ring_data when only max specified"); } // tests of prepend_rng_phg int test_prepend_rng_phg_short_comment(void) { char comment[43+1]; snprintf(comment,sizeof(comment),"A little comment"); prepend_rng_phg(comment,sizeof(comment),"PHG5400"); TEST_ASSERT_STR_EQ("PHG5400A little comment",comment, "PHG prepended to comment and not truncated"); TEST_PASS("prepend_rng_phg when comment is shorter than max"); } int test_prepend_rng_phg_long_comment(void) { char comment[43+1]; snprintf(comment,sizeof(comment),"An unbelievably long and verbose comment..."); prepend_rng_phg(comment,sizeof(comment),"PHG5400"); TEST_ASSERT_STR_EQ("PHG5400An unbelievably long and verbose com",comment, "PHG prepended to comment and truncated"); TEST_PASS("prepend_rng_phg when comment is already max"); } // Tests of format_area_object_item_packet int test_format_area_object_item_packet_object_circle_uncomp_nodata(void) { char line[256]; format_area_object_item_packet(line,sizeof(line), "TestAr", '\\', // name, group 'l',"111618z","3501.63N", // sym, time, lat "10612.38W", 0, // lon, type(cir) "/8", // color (dark, bla) 6, 6, //sqrt lat, lon offsets "","", //spd/cse, corridor "", 0, 0, //alt, speed, course 1, 0); // object, uncomp TEST_ASSERT_STR_EQ(";TestAr *111618z3501.63N\\10612.38Wl006/806", line, "circle, dim black, no course/speed/alt, object, uncompressed is as expected."); TEST_PASS("format_area_object_item_packet produces correct result for simple circle case"); } int test_format_area_object_item_packet_item_circle_uncomp_nodata(void) { char line[256]; format_area_object_item_packet(line,sizeof(line), "TestAr", '\\', // name, group 'l',"111618z","3501.63N", // sym, time, lat "10612.38W", 0, // lon, type(cir) "/8", // color (dark, bla) 6, 6, //sqrt lat, lon offsets "","", //spd/cse, corridor "", 0, 0, //alt, speed, course 0, 0); // item, uncomp TEST_ASSERT_STR_EQ(")TestAr!3501.63N\\10612.38Wl006/806", line, "circle, dim black, no course/speed/alt, item, uncompressed is as expected."); TEST_PASS("format_area_object_item_packet produces correct result for simple circle item case"); } int test_format_area_object_item_packet_object_circle_comp_nodata(void) { char line[256]; format_area_object_item_packet(line,sizeof(line), "TestAr", '\\', // name, group 'l',"111618z","3501.630N", // sym, time, lat "10612.380W", 0, // lon, type(cir) "/8", // color (dark, bla) 6, 6, //sqrt lat, lon offsets "","", //spd/cse, corridor "", 0, 0, //alt, speed, course 1, 1); // object, comp TEST_ASSERT_STR_EQ(";TestAr *111618z\\\n", argv[0]); fprintf(stderr, "Available tests: \n"); for (int i = 0; tests[i].name != NULL; i++) { fprintf(stderr, " %s\n", tests[i].name); } return 1; } const char *test_name = argv[1]; /* Run the requested test */ for (int i = 0; tests[i].name != NULL; i++) { if (strcmp(test_name, tests[i].name) == 0) { return tests[i].func(); } } fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_object_utils_stubs.c0000664000175000017500000001434315151324131021601 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Stub implementations for symbols referenced by object_utils.c * but not used by the unit tests. * * These stubs allow us to link with the real object_utils.o for testing * without pulling in the entire Xastir codebase. */ #include #include #include #include #include #include "tests/test_framework.h" // Not actually a stub, a fake implementation of sec_now() time_t sec_now(void) { // Unix timestamp for 2025-11-11 16:18:00 UTC return( (time_t) 1762877880); } // Complete implementation of compress_posit, cut/pasted from util.c, coz // I need to test with more than fake data, and utils.c isn't ready to be // used in unit tests char compress_group(char group_in) { char group_out=group_in; if (group_in >= '0' && group_in <= '9') { group_out=group_in - '0' + 'a'; } return (group_out); } char *compress_posit(const char *input_lat, const char group, const char *input_lon, const char symbol, const unsigned int last_course, const unsigned int last_speed, const char *phg) { static char pos[100]; char lat[5], lon[5]; char c, s, t, ext; int temp, deg; double minutes; char temp_str[20]; //fprintf(stderr,"lat:%s, long:%s, symbol:%c%c, course:%d, speed:%d, phg:%s\n", // input_lat, // input_lon, // group, // symbol, // last_course, // last_speed, // phg); // Fetch degrees (first two chars) temp_str[0] = input_lat[0]; temp_str[1] = input_lat[1]; temp_str[2] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) snprintf(temp_str, sizeof(temp_str), "%s", input_lat); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for North latitude if (strstr(input_lat, "N") || strstr(input_lat, "n")) { ext = 'N'; } else { ext = 'S'; } //fprintf(stderr,"ext:%c\n", ext); temp = 380926 * (90 - (deg + minutes / 60.0) * ( ext=='N' ? 1 : -1 )); //fprintf(stderr,"temp: %d\t",temp); lat[3] = (char)(temp%91 + 33); temp /= 91; lat[2] = (char)(temp%91 + 33); temp /= 91; lat[1] = (char)(temp%91 + 33); temp /= 91; lat[0] = (char)(temp + 33); lat[4] = '\0'; //fprintf(stderr,"%s\n",lat); // Fetch degrees (first three chars) temp_str[0] = input_lon[0]; temp_str[1] = input_lon[1]; temp_str[2] = input_lon[2]; temp_str[3] = '\0'; deg = atoi(temp_str); // Fetch minutes (rest of numbers) snprintf(temp_str, sizeof(temp_str), "%s", input_lon); temp_str[0] = ' '; // Blank out degrees temp_str[1] = ' '; // Blank out degrees temp_str[2] = ' '; // Blank out degrees minutes = atof(temp_str); // Check for West longitude if (strstr(input_lon, "W") || strstr(input_lon, "w")) { ext = 'W'; } else { ext = 'E'; } //fprintf(stderr,"ext:%c\n", ext); temp = 190463 * (180 + (deg + minutes / 60.0) * ( ext=='W' ? -1 : 1 )); //fprintf(stderr,"temp: %d\t",temp); lon[3] = (char)(temp%91 + 33); temp /= 91; lon[2] = (char)(temp%91 + 33); temp /= 91; lon[1] = (char)(temp%91 + 33); temp /= 91; lon[0] = (char)(temp + 33); lon[4] = '\0'; //fprintf(stderr,"%s\n",lon); // Set up csT bytes for course/speed if either are non-zero c = s = t = ' '; if (last_course > 0 || last_speed > 0) { if (last_course >= 360) { c = '!'; // 360 would be past 'z'. Set it to zero. } else { c = (char)(last_course/4 + 33); } s = (char)(log(last_speed + 1.0) / log(1.08) + 33.5); // Poor man's rounding + ASCII t = 'C'; } // Else set up csT bytes for PHG if within parameters else if (strlen(phg) >= 6) { double power, height, gain, range, s_temp; c = '{'; if ( (phg[3] < '0') || (phg[3] > '9') ) // Power is out of limits { power = 0.0; } else { power = (double)((int)(phg[3]-'0')); power = power * power; // Lowest possible value is 0.0 } if (phg[4] < '0') // Height is out of limits (no upper limit according to the spec) { height = 10.0; } else { height= 10.0 * pow(2.0,(double)phg[4] - (double)'0'); // Lowest possible value is 10.0 } if ( (phg[5] < '0') || (phg[5] > '9') ) // Gain is out of limits { gain = 1.0; } else { gain = pow(10.0,((double)(phg[5]-'0') / 10.0)); // Lowest possible value is 1.0 } range = sqrt(2.0 * height * sqrt((power / 10.0) * (gain / 2.0))); // Lowest possible value is 0.0 // Check for range of 0, and skip log10 if so if (range != 0.0) { s_temp = log10(range/2) / log10(1.08) + 33.0; } else { s_temp = 0.0 + 33.0; } s = (char)(s_temp + 0.5); // Cheater's way of rounding, add 0.5 and truncate t = 'C'; } // Note that we can end up with three spaces at the end if no // course/speed/phg were supplied. Do not knock this down, as // the compressed posit has a fixed 13-character length // according to the spec! // snprintf(pos, sizeof(pos), "%c%s%s%c%c%c%c", compress_group(group), lat, lon, symbol, c, s, t); //fprintf(stderr,"New compressed pos: (%s)\n",pos); return pos; } Xastir-Release-2.2.4/tests/test_objects.c0000664000175000017500000041214615151324131017327 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for object_utils.c functions * */ #include #include #include #include #include #include "tests/test_framework.h" #include "database.h" #include "objects.h" //forward declaration of function not exported by objects.h (yet) int Create_object_item_tx_string(DataRow *p_station, char *line, int line_length); void destroy_object_item_data_row(DataRow *theDataRow); // this is defined and set to zero in test_objects_stubs.c, and // Create_object_item_tx_string reads it to decide whether to compress // the posit. extern int transmit_compressed_objects_items; int test_constructor_null_everything(void) { DataRow *theDataRow; theDataRow=construct_object_item_data_row("","","", // name, lat/lon '/','/', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow == NULL, "Constructor returns null appropriately"); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3501.63N/10612.38W/",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object_numeric_overlay(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '5','0', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '5',"overlay correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '0',"Symbol correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3501.63N510612.38W0",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object_numeric_overlay_compressed(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.633)*60*100; long expect_lon = 180*60*60*100-(106*60+12.384)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.633N", "10612.384W", // lat/lon '5','0', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '5',"overlay null"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '0',"Symbol correct"); transmit_compressed_objects_items = 1; Create_object_item_tx_string(theDataRow,line,sizeof(line)); transmit_compressed_objects_items = 0; // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618zfcall_sign,"Name populated correctly with truncated name"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST56789*111618z3501.63N/10612.38W/",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_item(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3501.63N/10612.38W/",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_killed_object(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 1); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT((theDataRow->flag & ST_ACTIVE) == 0, "Constructor creates killed object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST _111618z3501.63N/10612.38W/",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_killed_item(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 1); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT((theDataRow->flag & ST_ACTIVE) == 0, "Constructor creates killed item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST_3501.63N/10612.38W/",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object_course_speed(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "90","5", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3501.63N/10612.38W/090/005",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_item_course_speed(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "90","5", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3501.63N/10612.38W/090/005",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object_course_speed_alt(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "90","5", //course, speed "100", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3501.63N/10612.38W/090/005/A=000100",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_item_course_speed_alt(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "", //comment "90","5", //course, speed "100", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3501.63N/10612.38W/090/005/A=000100",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_object_course_speed_alt_comment(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "A123456789012345678901234567890123456789012", //comment "90","5", //course, speed "100", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->comment_data,"Comment Data Pointer non-null"); TEST_ASSERT(theDataRow->comment_data->text_ptr,"Comment text Pointer non-null"); TEST_ASSERT_STR_EQ("A123456789012345678901234567890123456789012",theDataRow->comment_data->text_ptr,"Comment correctly stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3501.63N/10612.38W/090/005/A=000100A12345678901234567890123456",line, "Object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_simple_item_course_speed_alt_comment(void) { DataRow *theDataRow; long expect_lat = 90*60*60*100-(35*60+1.63)*60*100; long expect_lon = 180*60*60*100-(106*60+12.38)*60*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3501.63N", "10612.38W", // lat/lon '/','/', // group, symbol "A123456789012345678901234567890123456789012", //comment "90","5", //course, speed "100", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '/',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->comment_data,"Comment Data Pointer non-null"); TEST_ASSERT(theDataRow->comment_data->text_ptr,"Comment text Pointer non-null"); TEST_ASSERT_STR_EQ("A123456789012345678901234567890123456789012",theDataRow->comment_data->text_ptr,"Comment correctly stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3501.63N/10612.38W/090/005/A=000100A12345678901234567890123456",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } // Area objects tests. int test_constructor_area_object_basic(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl000/800",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_basic(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl000/800",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_speed(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "090","5", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); // Area objects/items are not allowed to have course/speed, should get // zeroed out even if somehow the user has specified them. // The dialog doesn't actually allow them to enter it, but let's be sure // we handle correctly TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl000/800",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_speed(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "090","5", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); // Area objects/items are not allowed to have course/speed, should get // zeroed out even if somehow the user has specified them. // The dialog doesn't actually allow them to enter it, but let's be sure // we handle correctly TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl000/800",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_offsets(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl006/806",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_offsets(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,0, //area, type, filled "/8", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl006/806",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_line_corridor(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,1,0, //area, type, filled "/4", // area color "40","40", // offsets "1", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.corridor_width == 1,"Correct corridor width stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl106/406{1}",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_line_corridor(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,1,0, //area, type, filled "/4", // area color "40","40", // offsets "1", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.corridor_width == 1,"Correct corridor width stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl106/406{1}",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_offsets_filled(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,1, //area, type, filled "/5", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl506/506",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_offsets_filled(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "", //altitude 1,0,1, //area, type, filled "/5", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl506/506",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_offsets_alt(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "100", //altitude 1,0,0, //area, type, filled "/8", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wl006/806/A=000100",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_offsets_alt(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','l', // group, symbol "", //comment "","", //course, speed "100", //altitude 1,0,0, //area, type, filled "/8", // area color "40","40", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'l',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("30.48",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lat_off == 6,"Correct lat offset value stored"); TEST_ASSERT(theDataRow->aprs_symbol.area_object.sqrt_lon_off == 6,"Correct lon offset value stored"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wl006/806/A=000100",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } // Tests for signpost objects // Fortunately, there are only a couple of variants here, and the only // thing special about these objects is that their symbol must be a specific // one and they may have a 3-character bit of signpost data // int test_constructor_area_object_signpost_basic(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','m', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 1, // signpost "111", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'm',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("111",theDataRow->signpost,"Signpost data stored properly."); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wm{111}",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_signpost_basic(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','m', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 1, // signpost "111", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'm',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("111",theDataRow->signpost,"Signpost data stored properly."); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wm{111}",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_object_signpost_speed(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','m', // group, symbol "", //comment "90","5", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 1, // signpost "111", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'm',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("111",theDataRow->signpost,"Signpost data stored properly."); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N\\10617.83Wm090/005{111}",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_area_item_signpost_speed(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '\\','m', // group, symbol "", //comment "90","5", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 1, // signpost "111", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '\\',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == 'm',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("090",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ(" 5",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("111",theDataRow->signpost,"Signpost data stored properly."); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N\\10617.83Wm090/005{111}",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } // Omni DF objects int test_constructor_object_df_omni(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','\\', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 1, 1, 0, // df, omni, beam "4133", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '\\',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("DFS4133",theDataRow->signal_gain, "signal/gain correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W\\DFS4133/",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_df_omni(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','\\', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 1, 1, 0, // df, omni, beam "4133", // shgd "", //bearing "", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '\\',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("DFS4133",theDataRow->signal_gain, "signal/gain correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W\\DFS4133/",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } // beam DF objects int test_constructor_object_df_beam(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','\\', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 1, 0, 1, // df, omni, beam "", // shgd "140", //bearing "965", // NRQ 0, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '\\',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("140",theDataRow->bearing, "bearing correct"); TEST_ASSERT_STR_EQ("965",theDataRow->NRQ, "NRQ correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W\\000/000/140/965",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_df_beam(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','\\', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 1, 0, 1, // df, omni, beam "", // shgd "140", //bearing "965", // NRQ 0, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '\\',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("140",theDataRow->bearing, "bearing correct"); TEST_ASSERT_STR_EQ("965",theDataRow->NRQ, "NRQ correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W\\000/000/140/965",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } // Tests for probability circles // Probability circles are just like normal objects but they get a // bit of Xastir-specific text added to their comments reflecting radii. // beam DF objects int test_constructor_object_prob_circles_noring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W[",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_prob_circles_noring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W[",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_object_prob_circles_minring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "1","", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("1",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W[Pmin1,",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_prob_circles_minring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "1","", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("1",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W[Pmin1,",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_object_prob_circles_maxring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "","5", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("5",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W[Pmax5,",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_prob_circles_maxring(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "","5", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("5",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W[Pmax5,",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_object_prob_circles_minmax(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "1","5", // prob min, max 1, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_OBJECT, "Constructor creates object"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active object"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("1",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("5",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); // clobber the time with our standard fake time, don't worry about termination // coz it's in the middle of an existing string memcpy(&(line[11]),"111618z",7); TEST_ASSERT_STR_EQ(";TEST *111618z3502.64N/10617.83W[Pmin1,Pmax5,",line, "object string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } int test_constructor_item_prob_circles_minmax(void) { DataRow *theDataRow; // this is not *exactly* what convert_lon_s2l does, and so rounding can // make us a little off. These coords chosen because rounding does NOT // bite us. long expect_lat = 90*60*60*100-(35*60+2.644)*60*100; long expect_lon = 180*60*60*100-((106*60+17.833)*60)*100; char line[256]; theDataRow=construct_object_item_data_row("TEST", // name "3502.644N", "10617.833W", // lat/lon '/','[', // group, symbol "", //comment "","", //course, speed "", //altitude 0,0,0, //area, type, filled "", // area color "","", // offsets "", // corridor 0, // signpost "", // signpost string 0, 0, 0, // df, omni, beam "", // shgd "", //bearing "", // NRQ 1, // prob circles "1","5", // prob min, max 0, // is_object 0); // killed TEST_ASSERT(theDataRow, "Constructor returns valid pointer appropriately"); TEST_ASSERT_STR_EQ("TEST",theDataRow->call_sign,"Name populated correctly"); TEST_ASSERT(theDataRow->flag & ST_ITEM, "Constructor creates item"); TEST_ASSERT(theDataRow->flag & ST_ACTIVE, "Constructor creates active item"); TEST_ASSERT(theDataRow->coord_lat == expect_lat, "lat is correct"); TEST_ASSERT(theDataRow->coord_lon == expect_lon, "lon is correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_type == '/',"Symbol table correct"); TEST_ASSERT(theDataRow->aprs_symbol.aprs_symbol == '[',"Symbol correct"); TEST_ASSERT(theDataRow->aprs_symbol.special_overlay == '\0',"overlay null"); TEST_ASSERT_STR_EQ("",theDataRow->course,"Course correct"); TEST_ASSERT_STR_EQ("",theDataRow->speed,"Speed correct"); TEST_ASSERT_STR_EQ("",theDataRow->altitude,"Altitude correct in meters"); TEST_ASSERT_STR_EQ("1",theDataRow->probability_min,"Probability min correct"); TEST_ASSERT_STR_EQ("5",theDataRow->probability_max,"Probability max correct"); Create_object_item_tx_string(theDataRow,line,sizeof(line)); TEST_ASSERT_STR_EQ(")TEST!3502.64N/10617.83W[Pmin1,Pmax5,",line, "item string correctly formatted"); if (theDataRow) destroy_object_item_data_row(theDataRow); TEST_PASS("construct_object_item_data_row"); } /* Test runner */ typedef struct { const char *name; int (*func)(void); } test_case_t; int main(int argc, char *argv[]) { test_case_t tests[] = { {"constructor_null_everything",test_constructor_null_everything}, {"constructor_simple_object",test_constructor_simple_object}, {"constructor_simple_object_numeric_overlay",test_constructor_simple_object_numeric_overlay}, {"constructor_simple_object_numeric_overlay_compressed",test_constructor_simple_object_numeric_overlay_compressed}, {"constructor_simple_object_name_too_long",test_constructor_simple_object_name_too_long}, {"constructor_simple_item",test_constructor_simple_item}, {"constructor_simple_killed_object",test_constructor_simple_killed_object}, {"constructor_simple_killed_item",test_constructor_simple_killed_item}, {"constructor_simple_object_course_speed",test_constructor_simple_object_course_speed}, {"constructor_simple_item_course_speed",test_constructor_simple_item_course_speed}, {"constructor_simple_object_course_speed_alt",test_constructor_simple_object_course_speed_alt}, {"constructor_simple_item_course_speed_alt",test_constructor_simple_item_course_speed_alt}, {"constructor_simple_object_course_speed_alt_comment",test_constructor_simple_object_course_speed_alt_comment}, {"constructor_simple_item_course_speed_alt_comment",test_constructor_simple_item_course_speed_alt_comment}, {"constructor_area_object_basic",test_constructor_area_object_basic}, {"constructor_area_item_basic",test_constructor_area_item_basic}, {"constructor_area_object_speed",test_constructor_area_object_speed}, {"constructor_area_item_speed",test_constructor_area_item_speed}, {"constructor_area_object_offsets",test_constructor_area_object_offsets}, {"constructor_area_item_offsets",test_constructor_area_item_offsets}, {"constructor_area_object_line_corridor",test_constructor_area_object_line_corridor}, {"constructor_area_item_line_corridor",test_constructor_area_item_line_corridor}, {"constructor_area_object_offsets_filled",test_constructor_area_object_offsets_filled}, {"constructor_area_item_offsets_filled",test_constructor_area_item_offsets_filled}, {"constructor_area_object_offsets_alt",test_constructor_area_object_offsets_alt}, {"constructor_area_item_offsets_alt",test_constructor_area_item_offsets_alt}, {"constructor_area_object_signpost_basic",test_constructor_area_object_signpost_basic}, {"constructor_area_item_signpost_basic",test_constructor_area_item_signpost_basic}, {"constructor_area_object_signpost_speed",test_constructor_area_object_signpost_speed}, {"constructor_area_item_signpost_speed",test_constructor_area_item_signpost_speed}, {"constructor_object_df_omni",test_constructor_object_df_omni}, {"constructor_item_df_omni",test_constructor_item_df_omni}, {"constructor_object_df_beam",test_constructor_object_df_beam}, {"constructor_item_df_beam",test_constructor_item_df_beam}, {"constructor_object_prob_circles_noring",test_constructor_object_prob_circles_noring}, {"constructor_item_prob_circles_noring",test_constructor_item_prob_circles_noring}, {"constructor_object_prob_circles_minring",test_constructor_object_prob_circles_minring}, {"constructor_item_prob_circles_minring",test_constructor_item_prob_circles_minring}, {"constructor_object_prob_circles_maxring",test_constructor_object_prob_circles_maxring}, {"constructor_item_prob_circles_maxring",test_constructor_item_prob_circles_maxring}, {"constructor_object_prob_circles_minmax",test_constructor_object_prob_circles_minmax}, {"constructor_item_prob_circles_minmax",test_constructor_item_prob_circles_minmax}, {NULL,NULL} }; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "Available tests: \n"); for (int i = 0; tests[i].name != NULL; i++) { fprintf(stderr, " %s\n", tests[i].name); } return 1; } const char *test_name = argv[1]; /* Run the requested test */ for (int i = 0; tests[i].name != NULL; i++) { if (strcmp(test_name, tests[i].name) == 0) { return tests[i].func(); } } fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_objects_stubs.c0000664000175000017500000001536715151324131020553 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Stub implementations for symbols referenced by util.o * but not used by the unit tests. * * These stubs allow us to link with the real util.o for testing * without pulling in the entire Xastir codebase. */ #include #include #include #include "globals.h" #include "database.h" #include "tests/test_framework.h" // define from xastir.h #define MAX_LINE_SIZE 512 // global variables referenced but unused in tests so far: int transmit_compressed_objects_items=0; int object_tx_disable=0; int transmit_disable=0; int debug_level=0; long center_longitude, center_latitude; char dangerous_operation[200]; char my_long[MAX_LONG], my_lat[MAX_LAT]; char my_callsign[MAX_CALLSIGN+1]="TEST"; time_t OBJECT_rate=0l; // These are cut/pasted out of test_db_stubs (duplicates removed) int altnet = 0; int track_case = 0; int track_match = 0; int track_station_on = 0; char tracking_station_call[100] = ""; int trail_segment_distance = 0; int trail_segment_time = 0; int transmit_now = 0; int wait_to_redraw = 0; void *da=NULL; /* Widget and display related globals */ void *Display_ = NULL; void *Display_data_dialog = NULL; void *Display_data_text = NULL; int Display_packet_data_mine_only = 0; int Display_packet_data_type = 0; void *LOGFILE_MESSAGE = NULL; void *LOGFILE_WX_ALERT = NULL; /* Screen coordinate globals */ long NW_corner_latitude = 0; long NW_corner_longitude = 0; long SE_corner_latitude = 0; long SE_corner_longitude = 0; long center_latitude = 0; long center_longitude = 0; /* Display selection globals */ void *Select_ = NULL; time_t aircraft_sec_clear = 0; /* Alert and message globals */ char altnet_call[MAX_CALLSIGN+1] = ""; int auto_reply = 0; char auto_reply_message[256] = ""; /* Band open globals */ int bando_min = 0; int bando_max = 0; /* Device globals */ void *devices = NULL; void *mw = NULL; void *port_data = NULL; int transmit_compressed_posit; /* English units flag */ int english_units = 0; /* Igate globals */ int igate_msgs_tx = 0; int operate_as_an_igate = 0; /* Data copy buffers */ char incoming_data_copy[1024] = ""; char incoming_data_copy_previous[1024] = ""; /* Locate station globals */ char locate_station_call[MAX_CALLSIGN+1] = ""; /* My station globals */ long my_last_altitude = 0; time_t my_last_altitude_time = 0; int my_last_course = 0; int my_last_speed = 0; int my_position_valid = 0; int my_trail_diff_color = 0; /* Proximity globals */ int prox_min = 0; int prox_max = 0; /* Redraw globals */ int redo_list = 0; int redraw_on_new_data = 0; /* Screen dimensions */ unsigned long scale_x = 0; unsigned long scale_y = 0; int screen_height = 0; int screen_width = 0; /* Station clear time globals */ time_t sec_clear = 0; time_t sec_remove = 0; /* Send message dialog lock */ void *send_message_dialog_lock = NULL; /* Smart beaconing globals */ int smart_beaconing = 0; int sb_POSIT_rate = 0; int sb_current_heading = 0; int sb_high_speed_limit = 0; int sb_last_heading = 0; int sb_low_speed_limit = 0; int sb_posit_fast = 0; int sb_posit_slow = 0; int sb_turn_min = 0; int sb_turn_slope = 0; time_t sb_turn_time = 0; /* Position timing globals */ time_t posit_last_time = 0; time_t posit_next_time = 0; /* Sound globals */ int sound_band_open_message = 0; char sound_command[256] = ""; int sound_new_message = 0; int sound_new_station = 0; int sound_play_band_open_message; int sound_play_new_message; int sound_play_new_station; int sound_play_prox_message; int sound_prox_message = 0; /* Festival speak globals */ int festival_speak_ID=0; int festival_speak_new_station=0; int festival_speak_proximity_alert=0; int festival_speak_tracked_proximity_alert=0; int festival_speak_band_opening=0; int festival_speak_new_message_alert=0; int festival_speak_new_message_body=0; int festival_speak_new_weather_alert=0; /* Station capability globals */ int show_only_station_capabilities = 0; /* Trail color global */ int current_trail_color = 0; /* Logging globals */ int log_wx_alert_data; int log_message_data; int read_file; /* Conversion globals */ double cvt_kn2len; // from knots double cvt_mi2len; // from miles // stubs needed to get objects.c linked in: STUB_IMPL(output_my_data); STUB_IMPL(langcode); STUB_IMPL(get_user_base_dir); STUB_IMPL(statusline); STUB_IMPL(ll_to_utm_ups); STUB_IMPL(utm_ups_to_ll); //stubs needed to get db.c linked in (duplicates removed): STUB_IMPL(alert_build_list) STUB_IMPL(alert_match) STUB_IMPL(alert_on_alert_list) STUB_IMPL(all_messages) STUB_IMPL(bulletin_message_check) STUB_IMPL(draw_area) STUB_IMPL(draw_labeled_area) STUB_IMPL(request_new_image) STUB_IMPL(schedule_reboot) STUB_IMPL(setup_message_data) STUB_IMPL(sound_play) STUB_IMPL(transmit_message_data) STUB_IMPL(transmit_message_data_delayed) STUB_IMPL(track_station) STUB_IMPL(begin_critical_section) STUB_IMPL(bulletin_data_add) STUB_IMPL(check_popup_window) STUB_IMPL(clear_acked_message) STUB_IMPL(create_garmin_waypoint) STUB_IMPL(decode_Peet_Bros) STUB_IMPL(decode_U2000_L) STUB_IMPL(decode_U2000_P) STUB_IMPL(display_station) STUB_IMPL(draw_trail) STUB_IMPL(end_critical_section) STUB_IMPL(fill_in_new_alert_entries) STUB_IMPL(get_send_message_path) STUB_IMPL(get_tactical_from_hash) STUB_IMPL(insert_into_heard_queue) STUB_IMPL(is_local_interface) STUB_IMPL(is_network_interface) STUB_IMPL(Locate_station) STUB_IMPL(log_data) STUB_IMPL(log_tactical_call) STUB_IMPL(look_for_open_group_data) STUB_IMPL(play_sound) STUB_IMPL(popup_message) STUB_IMPL(popup_message_always) STUB_IMPL(port_write_string) STUB_IMPL(SayText) STUB_IMPL(send_agwpe_packet) STUB_IMPL(send_ax25_frame) STUB_IMPL(stations_types) STUB_IMPL(output_igate_net) STUB_IMPL(output_igate_rf) STUB_IMPL(output_message) STUB_IMPL(output_nws_igate_rf) // Fake implementation of compute_current_DR_position, just returns // position of station without dead reckoning. void compute_current_DR_position(DataRow *p_station, long *x_long, long *y_lat) { *x_long = p_station->coord_lon; *y_lat = p_station->coord_lat; } Xastir-Release-2.2.4/tests/test_output_my_aprs_data.c0000664000175000017500000006666115151324131021770 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for output_my_aprs_data() function * * This test program tests the APRS position data output function from interface.c. * It requires mocking most of the Xastir infrastructure. */ #include #include #include #include #include "tests/test_framework.h" #include "interface.h" /* Forward declaration of function under test */ void output_my_aprs_data(void); /* Forward declarations of mock control functions */ void mock_reset_all(void); void mock_set_transmit_disable(int value); void mock_set_emergency_beacon(int value); void mock_set_my_callsign(const char *callsign); void mock_set_my_position(const char *lat, const char *lon); void mock_set_output_station_type(int type); void mock_set_compressed_posit(int value); void mock_set_phg(const char *phg); void mock_set_course_speed(int course, int speed); void mock_set_altitude(long altitude); void mock_set_comment(const char *comment); void mock_set_message_type(char type); void mock_add_interface(int port, int device_type, int status, int transmit_enabled); int mock_get_write_count(int port); const char *mock_get_last_write(int port); int mock_get_popup_count(void); const char *mock_get_last_popup_title(void); const char *mock_get_last_popup_message(void); /* Test cases */ int test_transmit_disabled(void) { mock_reset_all(); mock_set_transmit_disable(1); mock_set_emergency_beacon(0); // Add one active TNC interface mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); // Should not transmit anything TEST_ASSERT(mock_get_write_count(0) == 0, "No data should be transmitted when transmit is disabled"); TEST_PASS("output_my_aprs_data with transmit disabled"); } int test_transmit_disabled_with_emergency(void) { mock_reset_all(); mock_set_transmit_disable(1); mock_set_emergency_beacon(1); // Add one active TNC interface mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); // Should not transmit but should popup warning TEST_ASSERT(mock_get_write_count(0) == 0, "No data should be transmitted when transmit is disabled even with emergency beacon"); // Verify that a popup occurred warning about the situation TEST_ASSERT(mock_get_popup_count() > 0, "A popup warning should be displayed when emergency beacon is on but transmit is disabled"); // Optionally check the popup content const char *popup_msg = mock_get_last_popup_message(); if (popup_msg != NULL) { fprintf(stderr, "DEBUG: Popup message was: %s\n", popup_msg); } TEST_PASS("output_my_aprs_data with transmit disabled and emergency beacon"); } int test_no_active_interfaces(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); output_my_aprs_data(); // Should not transmit with no interfaces configured TEST_ASSERT(mock_get_write_count(0) == 0, "No data should be transmitted with no active interfaces"); TEST_PASS("output_my_aprs_data with no active interfaces"); } int test_basic_position_output(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED // Add one active TNC interface mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); int write_count = mock_get_write_count(0); // Should transmit something TEST_ASSERT(write_count > 0, "Data should be transmitted with active interface"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); TEST_PASS("output_my_aprs_data basic position output"); } int test_network_stream_output(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED // Add network stream interface mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); // Should transmit with proper header TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on network stream"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Network stream should have TCPIP* in the path TEST_ASSERT(strstr(output, "TCPIP*") != NULL, "Network stream output should contain TCPIP* in path"); TEST_PASS("output_my_aprs_data network stream output"); } int test_interface_down(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); // Add interface but mark it as down mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_DOWN, 1); // transmit enabled output_my_aprs_data(); // Should not transmit on down interface TEST_ASSERT(mock_get_write_count(0) == 0, "No data should be transmitted on down interface"); TEST_PASS("output_my_aprs_data with interface down"); } int test_transmit_disabled_on_interface(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); // Add interface but disable transmit on it mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 0); // transmit disabled output_my_aprs_data(); // Should not transmit on interface with transmit disabled TEST_ASSERT(mock_get_write_count(0) == 0, "No data should be transmitted on interface with transmit disabled"); TEST_PASS("output_my_aprs_data with interface transmit disabled"); } int test_mobile_local_time_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(1); // APRS_MOBILE LOCAL TIME mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Mobile local time should have @ and / in the timestamp // The @ comes after any header (like MYCALL, UNPROTO commands for TNC) const char *at_pos = strchr(output, '@'); TEST_ASSERT(at_pos != NULL, "Mobile local time format should contain @ for timestamp"); TEST_ASSERT(strchr(at_pos, '/') != NULL, "Mobile local time format should contain / in timestamp"); TEST_PASS("output_my_aprs_data mobile local time format"); } int test_mobile_zulu_datetime_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(2); // APRS_MOBILE ZULU DATE-TIME mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Mobile zulu should have @ and z in the timestamp // The @ comes after any header (like MYCALL, UNPROTO commands for TNC) const char *at_pos = strchr(output, '@'); TEST_ASSERT(at_pos != NULL, "Mobile zulu format should contain @ for timestamp"); TEST_ASSERT(strchr(at_pos, 'z') != NULL, "Mobile zulu format should contain 'z' in timestamp"); TEST_PASS("output_my_aprs_data mobile zulu datetime format"); } int test_mobile_zulu_time_with_seconds_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(3); // APRS_MOBILE ZULU TIME w/SEC mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); // transmit enabled output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Mobile zulu with seconds should have @ and h in the timestamp // The @ comes after any header (like MYCALL, UNPROTO commands for TNC) const char *at_pos = strchr(output, '@'); TEST_ASSERT(at_pos != NULL, "Mobile zulu with seconds format should contain @ for timestamp"); TEST_ASSERT(strchr(at_pos, 'h') != NULL, "Mobile zulu with seconds format should contain 'h' in timestamp"); TEST_PASS("output_my_aprs_data mobile zulu time with seconds format"); } /* Tests: Core Position Formatting */ int test_uncompressed_fixed_basic(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should have uncompressed position format (may use low-res format like 470..0N) TEST_ASSERT(strstr(output, "470") != NULL, "Output should contain latitude starting with 470"); TEST_ASSERT(strstr(output, "1220") != NULL, "Output should contain longitude starting with 1220"); // Should have position without timestamp (! or =) TEST_ASSERT(strchr(output, '!') != NULL || strchr(output, '=') != NULL, "Output should contain position identifier (! or =)"); TEST_PASS("output_my_aprs_data uncompressed fixed basic"); } int test_uncompressed_fixed_phg(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_phg("PHG5132"); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should have uncompressed position with PHG TEST_ASSERT(strstr(output, "470") != NULL, "Output should contain latitude starting with 470"); TEST_ASSERT(strstr(output, "PHG5132") != NULL, "Output should contain PHG data"); TEST_PASS("output_my_aprs_data uncompressed fixed with PHG"); } int test_uncompressed_mobile_course_speed(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(1); // APRS_MOBILE LOCAL TIME (required for course/speed) mock_set_compressed_posit(0); mock_set_course_speed(90, 36); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should have uncompressed position with course/speed TEST_ASSERT(strstr(output, "470") != NULL, "Output should contain latitude starting with 470"); TEST_ASSERT(strstr(output, "090/036") != NULL, "Output should contain course/speed 090/036"); TEST_PASS("output_my_aprs_data uncompressed mobile with course/speed"); } int test_uncompressed_fixed_altitude(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_altitude(1234); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should have uncompressed position with altitude TEST_ASSERT(strstr(output, "470") != NULL, "Output should contain latitude starting with 470"); TEST_ASSERT(strstr(output, "/A=001234") != NULL, "Output should contain altitude /A=001234"); TEST_PASS("output_my_aprs_data uncompressed fixed with altitude"); } int test_compressed_fixed_basic(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(1); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Compressed position should be much shorter and not contain readable lat/lon TEST_ASSERT(strstr(output, "4700.00N") == NULL, "Compressed output should not contain readable latitude"); // Should still have position identifier TEST_ASSERT(strchr(output, '!') != NULL || strchr(output, '=') != NULL, "Output should contain position identifier (! or =)"); TEST_PASS("output_my_aprs_data compressed fixed basic"); } int test_message_type_equals(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_message_type('='); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should use = for message-capable station const char *equals_pos = strchr(output, '='); TEST_ASSERT(equals_pos != NULL, "Output should contain = for message-capable station"); TEST_PASS("output_my_aprs_data message type equals"); } int test_message_type_exclamation(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_message_type('!'); mock_set_comment("Test Comment"); mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // Should use ! for non-message-capable station const char *exclaim_pos = strchr(output, '!'); TEST_ASSERT(exclaim_pos != NULL, "Output should contain ! for non-message-capable station"); TEST_PASS("output_my_aprs_data message type exclamation"); } /* Device-Specific Formatting Tests */ int test_network_stream_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add network stream interface (DEVICE_NET_STREAM = 5) mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on network stream"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); fprintf(stderr, "DEBUG: Network stream output: %s\n", output); // Network stream should have proper header format TEST_ASSERT(strstr(output, "N7ABC>") != NULL, "Network stream should include source callsign in header"); TEST_ASSERT(strstr(output, "APX2") != NULL, "Network stream should include destination in header (APX2xx)"); TEST_ASSERT(strstr(output, "TCPIP*") != NULL, "Network stream should include TCPIP* in path"); // Should have a colon separator before data TEST_ASSERT(strchr(output, ':') != NULL, "Network stream should have colon separator"); // Should end with \r\n (network format) size_t len = strlen(output); TEST_ASSERT(len >= 2 && output[len-2] == '\r' && output[len-1] == '\n', "Network stream should end with \\r\\n"); TEST_PASS("output_my_aprs_data network stream format"); } int test_serial_tnc_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add serial TNC interface mock_add_interface(0, DEVICE_SERIAL_TNC, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on serial TNC"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); fprintf(stderr, "DEBUG: Serial TNC output: %s\n", output); // Serial TNC should have TNC commands // The output should contain MYCALL, UNPROTO, and CONV commands followed by data // These may be in the buffer as separate writes or combined TEST_ASSERT(strstr(output, "MYCALL") != NULL || strstr(output, "N7ABC") != NULL, "Serial TNC should include MYCALL command or callsign"); // Should contain actual position data TEST_ASSERT(strstr(output, "470") != NULL, "Serial TNC should include position data"); TEST_PASS("output_my_aprs_data serial TNC format"); } int test_kiss_tnc_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add KISS TNC interface mock_add_interface(0, DEVICE_SERIAL_KISS_TNC, DEVICE_UP, 1); output_my_aprs_data(); // KISS TNC uses send_ax25_frame() which we're mocking // The data should still be written to the device buffer TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on KISS TNC"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); // KISS format should NOT have TNC commands like MYCALL or UNPROTO TEST_ASSERT(strstr(output, "MYCALL") == NULL, "KISS TNC should not include MYCALL command"); TEST_ASSERT(strstr(output, "UNPROTO") == NULL, "KISS TNC should not include UNPROTO command"); // Should have AX.25 framing (starts with FEND byte 0xC0 in KISS) // and at least contain the position data TEST_ASSERT(output != NULL && (unsigned char)output[0] == 0xC0, "KISS TNC output should start with FEND (0xC0)"); TEST_ASSERT(strstr(output+2, "470") != NULL, "KISS TNC should contain position data starting with 470"); TEST_PASS("output_my_aprs_data KISS TNC format"); } int test_agwpe_format(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add AGWPE interface mock_add_interface(0, DEVICE_NET_AGWPE, DEVICE_UP, 1); output_my_aprs_data(); TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on AGWPE"); const char *output = mock_get_last_write(0); TEST_ASSERT(output != NULL, "Output should not be NULL"); fprintf(stderr, "DEBUG: AGWPE output: %s\n", output); // AGWPE should not have TNC commands TEST_ASSERT(strstr(output, "MYCALL") == NULL, "AGWPE should not include MYCALL command"); TEST_ASSERT(strstr(output, "UNPROTO") == NULL, "AGWPE should not include UNPROTO command"); // Note - I would like to expand this test to verify proper AGWPE framing, TEST_PASS("output_my_aprs_data AGWPE format"); } int test_multiple_interfaces(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add multiple interfaces mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); mock_add_interface(1, DEVICE_SERIAL_TNC, DEVICE_UP, 1); output_my_aprs_data(); // Both interfaces should receive data TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on first interface"); TEST_ASSERT(mock_get_write_count(1) > 0, "Data should be transmitted on second interface"); // Get output from port 0 and make a copy since mock_get_last_write uses a static buffer const char *output0_tmp = mock_get_last_write(0); TEST_ASSERT(output0_tmp != NULL, "First output should not be NULL"); char output0_copy[1024]; strncpy(output0_copy, output0_tmp, sizeof(output0_copy) - 1); output0_copy[sizeof(output0_copy) - 1] = '\0'; const char *output0 = output0_copy; const char *output1 = mock_get_last_write(1); TEST_ASSERT(output1 != NULL, "Second output should not be NULL"); fprintf(stderr, "DEBUG: Port 0 output: '%s'\n", output0); fprintf(stderr, "DEBUG: Port 1 output: '%s'\n", output1); // Network stream should have TCPIP*, TNC should not TEST_ASSERT(strstr(output0, "TCPIP*") != NULL, "Network stream should have TCPIP* in output"); TEST_ASSERT(strstr(output1, "TCPIP*") == NULL, "Serial TNC should not have TCPIP* in output"); /* Require both MYCALL and callsign to be present */ TEST_ASSERT(strstr(output1, "MYCALL") != NULL, "Serial TNC should include MYCALL command"); TEST_ASSERT(strstr(output1, "N7ABC") != NULL, "Serial TNC should include callsign"); TEST_PASS("output_my_aprs_data multiple interfaces"); } int test_mixed_interface_states(void) { mock_reset_all(); mock_set_transmit_disable(0); mock_set_my_callsign("N7ABC"); mock_set_my_position("4700.00N", "12200.00W"); mock_set_output_station_type(0); // APRS_FIXED mock_set_compressed_posit(0); mock_set_comment("Test"); // Add interfaces with different states mock_add_interface(0, DEVICE_NET_STREAM, DEVICE_UP, 1); // Active, TX enabled mock_add_interface(1, DEVICE_SERIAL_TNC, DEVICE_DOWN, 1); // Down mock_add_interface(2, DEVICE_NET_STREAM, DEVICE_UP, 0); // Active, TX disabled output_my_aprs_data(); // Only first interface should transmit TEST_ASSERT(mock_get_write_count(0) > 0, "Data should be transmitted on active interface with TX enabled"); TEST_ASSERT(mock_get_write_count(1) == 0, "No data should be transmitted on down interface"); TEST_ASSERT(mock_get_write_count(2) == 0, "No data should be transmitted on interface with TX disabled"); TEST_PASS("output_my_aprs_data mixed interface states"); } /* Test runner */ typedef struct { const char *name; int (*func)(void); } test_case_t; int main(int argc, char *argv[]) { test_case_t tests[] = { {"transmit_disabled", test_transmit_disabled}, {"transmit_disabled_with_emergency", test_transmit_disabled_with_emergency}, {"no_active_interfaces", test_no_active_interfaces}, {"basic_position_output", test_basic_position_output}, {"network_stream_output", test_network_stream_output}, {"interface_down", test_interface_down}, {"transmit_disabled_on_interface", test_transmit_disabled_on_interface}, /* Mobile time formats */ {"mobile_local_time_format", test_mobile_local_time_format}, {"mobile_zulu_datetime_format", test_mobile_zulu_datetime_format}, {"mobile_zulu_time_with_seconds_format", test_mobile_zulu_time_with_seconds_format}, /* Basic packet format tests */ {"uncompressed_fixed_basic", test_uncompressed_fixed_basic}, {"uncompressed_fixed_phg", test_uncompressed_fixed_phg}, {"uncompressed_mobile_course_speed", test_uncompressed_mobile_course_speed}, {"uncompressed_fixed_altitude", test_uncompressed_fixed_altitude}, {"compressed_fixed_basic", test_compressed_fixed_basic}, {"message_type_equals", test_message_type_equals}, {"message_type_exclamation", test_message_type_exclamation}, /* Phase 3: Device-specific formatting tests */ {"network_stream_format", test_network_stream_format}, {"serial_tnc_format", test_serial_tnc_format}, {"kiss_tnc_format", test_kiss_tnc_format}, {"agwpe_format", test_agwpe_format}, {"multiple_interfaces", test_multiple_interfaces}, {"mixed_interface_states", test_mixed_interface_states}, {NULL, NULL} }; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "Available tests:\n"); for (int i = 0; tests[i].name != NULL; i++) { fprintf(stderr, " %s\n", tests[i].name); } return 1; } const char *test_name = argv[1]; /* Run the requested test */ for (int i = 0; tests[i].name != NULL; i++) { if (strcmp(test_name, tests[i].name) == 0) { return tests[i].func(); } } fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_util.c0000664000175000017500000004274615151324131016660 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Test program for object_utils.c functions * */ #include #include #include #include #include #include "tests/test_framework.h" #include "util.h" #include "globals.h" extern long scale_x, scale_y; extern long center_longitude, center_latitude; extern long NW_corner_longitude, NW_corner_latitude; extern long SE_corner_longitude, SE_corner_latitude; extern long screen_height, screen_width; int test_convert_lat_l2s_basic(void) { long lat; char lat_str[20]; // Compute Xastir coordinates for 35d01.631'N // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lat = 90*60*60*100-(35*60+1.631)*60*100; convert_lat_l2s(lat,lat_str, sizeof(lat_str),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ("3501.631N",lat_str,"xastir y value correctly converted to string"); TEST_PASS("convert_lat_l2s: correct"); } int test_convert_lon_l2s_basic(void) { long lon; char lon_str[20]; // Compute Xastir coordinates for 106d12.385'W // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lon = 180*60*60*100-(106*60+12.385)*60*100; convert_lon_l2s(lon,lon_str, sizeof(lon_str),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ("10612.385W",lon_str,"xastir x value correctly converted to string"); TEST_PASS("convert_lon_l2s: correct"); } int test_convert_lat_l2s_basic_s(void) { long lat; char lat_str[20]; // Compute Xastir coordinates for 35d01.631'S // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lat = 90*60*60*100+(35*60+1.631)*60*100; convert_lat_l2s(lat,lat_str, sizeof(lat_str),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ("3501.631S",lat_str,"xastir y value correctly converted to string"); TEST_PASS("convert_lat_l2s: correct"); } int test_convert_lon_l2s_basic_e(void) { long lon; char lon_str[20]; // Compute Xastir coordinates for 106d12.385'E // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lon = 180*60*60*100+(106*60+12.385)*60*100; convert_lon_l2s(lon,lon_str, sizeof(lon_str),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ("10612.385E",lon_str,"xastir x value correctly converted to string"); TEST_PASS("convert_lon_l2s: correct"); } int test_convert_lat_l2s_lp(void) { long lat; char lat_str[20]; // Compute Xastir coordinates for 35d01.631'N // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lat = 90*60*60*100-(35*60+1.631)*60*100; convert_lat_l2s(lat,lat_str, sizeof(lat_str),CONVERT_LP_NOSP); TEST_ASSERT_STR_EQ("3501.63N",lat_str,"xastir y value correctly converted to string"); TEST_PASS("convert_lat_l2s: correct"); } int test_convert_lon_l2s_lp(void) { long lon; char lon_str[20]; // Compute Xastir coordinates for 106d12.384'W // Xastir coordinates are in hundredths of seconds, with 0 being 90d N // we're using ".384" here because ".385" would get rounded up, not truncated. lon = 180*60*60*100-(106*60+12.384)*60*100; convert_lon_l2s(lon,lon_str, sizeof(lon_str),CONVERT_LP_NOSP); TEST_ASSERT_STR_EQ("10612.38W",lon_str,"xastir x value correctly converted to string"); TEST_PASS("convert_lon_l2s: correct"); } int test_convert_lat_s2l_basic(void) { long lat; long lat_expect; // Compute Xastir coordinates for 35d01.631'N // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lat_expect = 90*60*60*100-(35*60+1.631)*60*100; lat = convert_lat_s2l("3501.631N"); TEST_ASSERT(lat==lat_expect,"xastir y value correctly converted from string"); TEST_PASS("convert_lat_s2l: correct"); } int test_convert_lon_s2l_basic(void) { long lon; long lon_expect; // Compute Xastir coordinates for 106d12.385'W // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lon_expect = 180*60*60*100-(106*60+12.385)*60*100; lon = convert_lon_s2l("10612.385W"); TEST_ASSERT(lon==lon_expect,"xastir x value correctly converted from string"); TEST_PASS("convert_lon_s2l: correct"); } int test_convert_lat_s2l_basic_s(void) { long lat; long lat_expect; // Compute Xastir coordinates for 35d01.631'S // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lat_expect = 90*60*60*100+(35*60+1.631)*60*100; lat = convert_lat_s2l("3501.631S"); TEST_ASSERT(lat==lat_expect,"xastir y value correctly converted from string"); TEST_PASS("convert_lat_s2l: correct"); } int test_convert_lon_s2l_basic_e(void) { long lon; long lon_expect; // Compute Xastir coordinates for 106d12.385'E // Xastir coordinates are in hundredths of seconds, with 0 being 90d N lon_expect = 180*60*60*100+(106*60+12.385)*60*100; lon = convert_lon_s2l("10612.385E"); TEST_ASSERT(lon==lon_expect,"xastir x value correctly converted from string"); TEST_PASS("convert_lon_s2l: correct"); } // Check that s2l->l2s gives back what we started with. int test_s2l_l2s_consistency(void) { long lon; long lat; char lon_s[10+1]; char lat_s[9+1]; lon=convert_lon_s2l("10612.385W"); lat=convert_lat_s2l("3501.631N"); convert_lon_l2s(lon,lon_s,sizeof(lon_s),CONVERT_HP_NOSP); convert_lat_l2s(lat,lat_s,sizeof(lat_s),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ("3501.631N",lat_s,"Round-trip latitude consistent"); TEST_ASSERT_STR_EQ("10612.385W",lon_s,"Round-trip longitude consistent"); TEST_PASS("convert_lon_s2l and back: correct"); } // Check that l2s->s2l gives back what we started with. int test_l2s_s2l_consistency(void) { long lon; long lat; long lon_return; long lat_return; char lon_s[10+1]; char lat_s[9+1]; lon = 180*60*60*100-(106*60+12.385)*60*100; lat = 90*60*60*100-(35*60+1.631)*60*100; convert_lon_l2s(lon,lon_s,sizeof(lon_s),CONVERT_HP_NOSP); convert_lat_l2s(lat,lat_s,sizeof(lat_s),CONVERT_HP_NOSP); lat_return = convert_lat_s2l(lat_s); lon_return = convert_lon_s2l(lon_s); TEST_ASSERT(lat==lat_return,"Round-trip latitude consistent"); TEST_ASSERT(lon==lon_return,"Round-trip longitude consistent"); TEST_PASS("convert_lon_s2l and back: correct"); } // test screen/xastir/other converters int test_convert_screen_to_xastir_coordinates(void) { // presume screen to be 1900x712 pixels // NW corner 3515.704N 10706.340W // SW corner 3454.727N 10548.923W // the "long" coords are in centi-seconds (1/100 second) // scale_x and scale_y are centi-seconds per pixel char center_lat_s[10] = "3505.215N"; char center_lon_s[11] = "10627.632W"; char corner_lat_s[10]; char corner_lon_s[11]; char computed_lat[10]; char computed_lon[11]; long lon_xa, lat_xa; long screen_x, screen_y; screen_width=1900; screen_height=712; NW_corner_longitude = convert_lon_s2l("10706.340W"); NW_corner_latitude = convert_lat_s2l("3515.704N"); SE_corner_longitude = convert_lon_s2l("10548.923W"); SE_corner_latitude = convert_lat_s2l("3454.727N"); // Remember that Xastir coords are 0,0 at 90N 180W and increase as we // go east and south. scale_x = (SE_corner_longitude - NW_corner_longitude)/screen_width; scale_y = (SE_corner_latitude - NW_corner_latitude)/screen_height; center_latitude = (NW_corner_latitude + SE_corner_latitude)/2; center_longitude = (NW_corner_longitude + SE_corner_longitude)/2; // Now, Xastir itself actually makes the center lat/lon the primary // variable, and recomputes NW and SW based on that and the scale. Let's // do that ourselves now. Otherwise we get rounding problems later. NW_corner_longitude = center_longitude - (screen_width*scale_x)/2; NW_corner_latitude = center_latitude - (screen_height*scale_y)/2; SE_corner_longitude = center_longitude + (screen_width*scale_x)/2; SE_corner_latitude = center_latitude + (screen_height*scale_y)/2; convert_screen_to_xastir_coordinates(screen_width/2, screen_height/2, &lat_xa, &lon_xa); convert_lon_l2s(lon_xa, computed_lon, sizeof(computed_lon),CONVERT_HP_NOSP); convert_lat_l2s(lat_xa, computed_lat, sizeof(computed_lat),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ(center_lon_s,computed_lon,"center lon correct"); TEST_ASSERT_STR_EQ(center_lat_s,computed_lat,"center lat correct"); TEST_ASSERT(lon_xa == center_longitude, "Center pixel mapped correctly to center longitude"); TEST_ASSERT(lat_xa == center_latitude, "Center pixel mapped correctly to center latitude"); // Now try to convert this back to screen coords the way // map_shp and others do screen_x = center_longitude - NW_corner_longitude; screen_y = center_latitude - NW_corner_latitude; screen_x = screen_x/scale_x; screen_y = screen_y/scale_y; // We expect these screen coords to be screen_width/2, screen_height/2 TEST_ASSERT(screen_x == screen_width/2, "center lon maps onto center pixel"); TEST_ASSERT(screen_y == screen_height/2, "center lat maps onto center pixel."); // Now what about NW and SE corners? // Remember we fudged the corners based on screen size and original intended // scale, and rounding probably moved the actual xastir coords of the / // corners. So recompute what we *expect* the conversions to be. // This is what we should be expecting for the NW corner strings. // Note that they are almost certainly different from the strings // we used to initialize NW_corner_lat/lon convert_lon_l2s(NW_corner_longitude,corner_lon_s,sizeof(corner_lon_s), CONVERT_HP_NOSP); convert_lat_l2s(NW_corner_latitude,corner_lat_s,sizeof(corner_lat_s), CONVERT_HP_NOSP); convert_screen_to_xastir_coordinates(0,0, &lat_xa, &lon_xa); convert_lon_l2s(lon_xa, computed_lon, sizeof(computed_lon),CONVERT_HP_NOSP); convert_lat_l2s(lat_xa, computed_lat, sizeof(computed_lat),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ(corner_lon_s,computed_lon,"NW corner lon correct"); TEST_ASSERT_STR_EQ(corner_lat_s,computed_lat,"NW corner lat correct"); TEST_ASSERT(lon_xa == NW_corner_longitude, "Top left pixel mapped correctly to NW corner longitude"); TEST_ASSERT(lat_xa == NW_corner_latitude, "top left pixel mapped correctly to NW corner latitude"); // No point checking the formula for converting back to screen, because // it is trivially 0,0 // now the SE corner // This is what we should be expecting for the SE corner strings. // Note that they are almost certainly different from the strings // we used to initialize SE_corner_lat/lon convert_lon_l2s(SE_corner_longitude,corner_lon_s,sizeof(corner_lon_s), CONVERT_HP_NOSP); convert_lat_l2s(SE_corner_latitude,corner_lat_s,sizeof(corner_lat_s), CONVERT_HP_NOSP); convert_screen_to_xastir_coordinates(screen_width, screen_height, &lat_xa, &lon_xa); convert_lon_l2s(lon_xa, computed_lon, sizeof(computed_lon),CONVERT_HP_NOSP); convert_lat_l2s(lat_xa, computed_lat, sizeof(computed_lat),CONVERT_HP_NOSP); TEST_ASSERT_STR_EQ(corner_lon_s,computed_lon,"SE corner lon correct"); TEST_ASSERT_STR_EQ(corner_lat_s,computed_lat,"SE corner lat correct"); TEST_ASSERT(lon_xa == SE_corner_longitude, "Top left pixel mapped correctly to SE corner longitude"); TEST_ASSERT(lat_xa == SE_corner_latitude, "top left pixel mapped correctly to SE corner latitude"); // Now try to convert this back to screen coords the way // map_shp and others do screen_x = SE_corner_longitude - NW_corner_longitude; screen_y = SE_corner_latitude - NW_corner_latitude; screen_x = screen_x/scale_x; screen_y = screen_y/scale_y; // We expect these screen coords to be screen_width, screen_height TEST_ASSERT(screen_x == screen_width, "SE corner lon maps onto bot right pixel"); TEST_ASSERT(screen_y == screen_height, "SE corner lat maps onto bot right pixel."); TEST_PASS("convert_screen_to_xastir_coordinates: works as expected"); } // Note that this is *identical* to the previous function except it // calls convert_xastir_to_screen_coordinates instead of having hard-coded // junk in it. int test_convert_xastir_to_screen_coordinates(void) { // presume screen to be 1900x712 pixels // NW corner 3515.704N 10706.340W // SW corner 3454.727N 10548.923W // the "long" coords are in centi-seconds (1/100 second) // scale_x and scale_y are centi-seconds per pixel long screen_x, screen_y; screen_width=1900; screen_height=712; NW_corner_longitude = convert_lon_s2l("10706.340W"); NW_corner_latitude = convert_lat_s2l("3515.704N"); SE_corner_longitude = convert_lon_s2l("10548.923W"); SE_corner_latitude = convert_lat_s2l("3454.727N"); // Remember that Xastir coords are 0,0 at 90N 180W and increase as we // go east and south. scale_x = (SE_corner_longitude - NW_corner_longitude)/screen_width; scale_y = (SE_corner_latitude - NW_corner_latitude)/screen_height; center_latitude = (NW_corner_latitude + SE_corner_latitude)/2; center_longitude = (NW_corner_longitude + SE_corner_longitude)/2; // Now, Xastir itself actually makes the center lat/lon the primary // variable, and recomputes NW and SW based on that and the scale. Let's // do that ourselves now. Otherwise we get rounding problems later. NW_corner_longitude = center_longitude - (screen_width*scale_x)/2; NW_corner_latitude = center_latitude - (screen_height*scale_y)/2; SE_corner_longitude = center_longitude + (screen_width*scale_x)/2; SE_corner_latitude = center_latitude + (screen_height*scale_y)/2; // Now try to convert this back to screen coords using the // utility function convert_xastir_to_screen_coordinates(center_longitude, center_latitude, &screen_x, &screen_y); // We expect these screen coords to be screen_width/2, screen_height/2 TEST_ASSERT(screen_x == screen_width/2, "center lon maps onto center pixel"); TEST_ASSERT(screen_y == screen_height/2, "center lat maps onto center pixel."); // Now what about NW and SE corners? convert_xastir_to_screen_coordinates(NW_corner_longitude, NW_corner_latitude, &screen_x, &screen_y); // We expect these screen coords to be 0,0 TEST_ASSERT(screen_x == 0, "NW corner lon maps onto top left pixel"); TEST_ASSERT(screen_y == 0, "NW corner lat maps onto top left pixel."); // now the SE corner convert_xastir_to_screen_coordinates(SE_corner_longitude, SE_corner_latitude, &screen_x, &screen_y); // We expect these screen coords to be screen_width, screen_height TEST_ASSERT(screen_x == screen_width, "SE corner lon maps onto bot right pixel"); TEST_ASSERT(screen_y == screen_height, "SE corner lat maps onto bot right pixel."); TEST_PASS("convert_xastir_to_screen_coordinates: works as expected"); } int test_short_filename_for_status_notrunc(void) { char filename[MAX_FILENAME]="this_is_short.shp"; char short_filename[MAX_FILENAME]; short_filename_for_status(filename, short_filename, sizeof(short_filename)); TEST_ASSERT_STR_EQ("this_is_short.shp", short_filename, "Name not truncated if already short enough"); TEST_PASS("short_filename_for_status"); } int test_short_filename_for_status_trunc(void) { char filename[MAX_FILENAME]="/a/long/path/with/lots/of/components/basename.shp"; char short_filename[MAX_FILENAME]; short_filename_for_status(filename, short_filename, sizeof(short_filename)); TEST_ASSERT_STR_EQ("..ots/of/components/basename.shp", short_filename, "Name truncated if long"); TEST_PASS("short_filename_for_status"); } /* Test runner */ typedef struct { const char *name; int (*func)(void); } test_case_t; int main(int argc, char *argv[]) { test_case_t tests[] = { {"convert_lat_l2s_basic",test_convert_lat_l2s_basic}, {"convert_lon_l2s_basic",test_convert_lon_l2s_basic}, {"convert_lat_l2s_basic_s",test_convert_lat_l2s_basic_s}, {"convert_lon_l2s_basic_e",test_convert_lon_l2s_basic_e}, {"convert_lat_l2s_lp",test_convert_lat_l2s_lp}, {"convert_lon_l2s_lp",test_convert_lon_l2s_lp}, {"convert_lat_s2l_basic",test_convert_lat_s2l_basic}, {"convert_lon_s2l_basic",test_convert_lon_s2l_basic}, {"convert_lat_s2l_basic_s",test_convert_lat_s2l_basic_s}, {"convert_lon_s2l_basic_e",test_convert_lon_s2l_basic_e}, {"s2l_l2s_consistency",test_s2l_l2s_consistency}, {"l2s_s2l_consistency",test_l2s_s2l_consistency}, {"convert_screen_to_xastir_coordinates", test_convert_screen_to_xastir_coordinates}, {"convert_xastir_to_screen_coordinates", test_convert_xastir_to_screen_coordinates}, {"short_filename_for_status_notrunc",test_short_filename_for_status_notrunc}, {"short_filename_for_status_trunc",test_short_filename_for_status_trunc}, {NULL,NULL} }; if (argc < 2) { fprintf(stderr, "Usage: %s \n", argv[0]); fprintf(stderr, "Available tests: \n"); for (int i = 0; tests[i].name != NULL; i++) { fprintf(stderr, " %s\n", tests[i].name); } return 1; } const char *test_name = argv[1]; /* Run the requested test */ for (int i = 0; tests[i].name != NULL; i++) { if (strcmp(test_name, tests[i].name) == 0) { return tests[i].func(); } } fprintf(stderr, "Unknown test: %s\n", test_name); return 1; } Xastir-Release-2.2.4/tests/test_util_stubs.c0000664000175000017500000000317315151324131020067 0ustar hibbyhibby/* * * XASTIR, Amateur Station Tracking and Information Reporting * Copyright (C) 2025-2026 The Xastir Group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Look at the README for more information on the program. */ /* * Stub implementations for symbols referenced by util.o * but not used by the unit tests. * * These stubs allow us to link with the real util.o for testing * without pulling in the entire Xastir codebase. */ #include #include #include #include "globals.h" #include "tests/test_framework.h" STUB_IMPL(langcode); STUB_IMPL(ll_to_utm_ups); STUB_IMPL(utm_ups_to_ll); STUB_IMPL(search_station_name); // global variables referenced but unused: int debug_level=0; long scale_x, scale_y; long center_longitude, center_latitude; long NW_corner_longitude, NW_corner_latitude; long SE_corner_longitude, SE_corner_latitude; char dangerous_operation[200]; char my_long[MAX_LONG], my_lat[MAX_LAT]; long screen_height, screen_width; Xastir-Release-2.2.4/tests/testsuite.at0000664000175000017500000000137615151324131017051 0ustar hibbyhibby# Main Autotest suite for Xastir # This file defines the test suite structure AT_INIT([Xastir Tests]) AT_COPYRIGHT([Copyright (C) 2025-2026 The Xastir Group]) AT_COLOR_TESTS # Include interface helper function tests m4_include([interface_helpers.at]) # Include database function tests m4_include([db_tests.at]) # Include output_my_aprs_data function tests m4_include([output_my_aprs_data_tests.at]) # Include object utility function tests m4_include([object_utils_tests.at]) # Include basic utility function tests m4_include([util_tests.at]) # Include basic objects function tests m4_include([objects_tests.at]) # Include nominatim geocoding tests (conditionally compiled if HAVE_NOMINATIM) m4_ifdef([HAVE_NOMINATIM], [ m4_include([nominatim_tests.at]) ]) Xastir-Release-2.2.4/tests/util_tests.at0000664000175000017500000001032715151324131017213 0ustar hibbyhibby# Autotest tests for utils.c Functions # Tests for standalone utility functions from util.c AT_BANNER([Utility Functions]) AT_BANNER([convert_lat/lon_l2s/s2l() tests]) AT_SETUP([convert_lat_l2s: convert Xastir lat to high-prec string]) AT_KEYWORDS([util convert_lat_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lat_l2s_basic], [0], [PASS: convert_lat_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lon_l2s: convert Xastir lon to high-prec string]) AT_KEYWORDS([util convert_lon_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lon_l2s_basic], [0], [PASS: convert_lon_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lat_l2s: convert Xastir lat to high-prec string (south lat)]) AT_KEYWORDS([util convert_lat_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lat_l2s_basic_s], [0], [PASS: convert_lat_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lon_l2s: convert Xastir lon to high-prec string (east long)]) AT_KEYWORDS([util convert_lon_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lon_l2s_basic_e], [0], [PASS: convert_lon_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lat_l2s: convert Xastir lat to low-prec string]) AT_KEYWORDS([util convert_lat_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lat_l2s_lp], [0], [PASS: convert_lat_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lon_l2s: convert Xastir lon to low-prec string]) AT_KEYWORDS([util convert_lon_l2s]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lon_l2s_lp], [0], [PASS: convert_lon_l2s: correct ]) AT_CLEANUP AT_SETUP([convert_lat_l2s: convert Xastir lat from high-prec string]) AT_KEYWORDS([util convert_lat_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lat_s2l_basic], [0], [PASS: convert_lat_s2l: correct ]) AT_CLEANUP AT_SETUP([convert_lon_l2s: convert Xastir lon from high-prec string]) AT_KEYWORDS([util convert_lon_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lon_s2l_basic], [0], [PASS: convert_lon_s2l: correct ]) AT_CLEANUP AT_SETUP([convert_lat_l2s: convert Xastir lat from high-prec string (south)]) AT_KEYWORDS([util convert_lat_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lat_s2l_basic_s], [0], [PASS: convert_lat_s2l: correct ]) AT_CLEANUP AT_SETUP([convert_lon_l2s: convert Xastir lon from high-prec string (east)]) AT_KEYWORDS([util convert_lon_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_lon_s2l_basic_e], [0], [PASS: convert_lon_s2l: correct ]) AT_CLEANUP AT_BANNER([tests of round-trip conversion consistency]) AT_SETUP([convert_lat/lon_s2l -> convert_lat/lon_l2s round-trip consistency]) AT_KEYWORDS([util convert_lon_s2l convert_lon_l2s convert_lat_s2l convert_lon_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" s2l_l2s_consistency], [0], [PASS: convert_lon_s2l and back: correct ]) AT_CLEANUP AT_SETUP([convert_lat/lon_l2s -> convert_lat/lon_s2l round-trip consistency]) AT_KEYWORDS([util convert_lon_s2l convert_lon_l2s convert_lat_s2l convert_lon_s2l]) AT_CHECK(["$abs_top_builddir/tests/test_util" l2s_s2l_consistency], [0], [PASS: convert_lon_s2l and back: correct ]) AT_CLEANUP AT_BANNER([tests of screen coordinate converters]) AT_SETUP([convert_screen_to_xastir: center and corners convert as expected]) AT_KEYWORDS([util convert_screen_to_xastir_coordinates]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_screen_to_xastir_coordinates], [0], [PASS: convert_screen_to_xastir_coordinates: works as expected ]) AT_CLEANUP AT_SETUP([convert_xastir_to_screen: center and corners convert as expected]) AT_KEYWORDS([util convert_screen_to_xastir_coordinates]) AT_CHECK(["$abs_top_builddir/tests/test_util" convert_xastir_to_screen_coordinates], [0], [PASS: convert_xastir_to_screen_coordinates: works as expected ]) AT_CLEANUP AT_BANNER([tests of filename shortener for status line]) AT_SETUP([short_filename_for_status: short name not truncated]) AT_KEYWORDS([util short_filename_for_status]) AT_CHECK(["$abs_top_builddir/tests/test_util" short_filename_for_status_notrunc], [0], [PASS: short_filename_for_status ]) AT_CLEANUP AT_SETUP([short_filename_for_status: long name truncated]) AT_KEYWORDS([util short_filename_for_status]) AT_CHECK(["$abs_top_builddir/tests/test_util" short_filename_for_status_trunc], [0], [PASS: short_filename_for_status ]) AT_CLEANUP Xastir-Release-2.2.4/worldhi.map0000664000175000017500000103017415151324131015476 0ustar hibbyhibbyWU2ZBetaWolrdMap.MWDB.Map HiWorld Map HighWU2ZC `Ź`ck&@+p @+p X8+ + 0+ , {`, r, ,h p,x fH, y, P,p ,k 6,K 4,1H + S,3 h,, jp, +(+0 o , z, B+ v(+ @+ UX+x +( +` l+ +X +@ +` +@ `+ ʈ+ 4+ B+q +4( + P + * h*X x* ո* * * *h@ * 0*e @*Z0 p*8 * )h )H () ) ) )X ( [( b(( Rx( Y( 8(u 8(| (M0 p(T8 x(,` ( l' l' B' a' W'| ('i 0'p &0 H& p&s h&N@ l& @& v(% % % % % %@ %@ %x /P%0 ?%( 1%i(+ P i(+ P f*0 + p0+ P+(p ~@+(p {+F +x x+u 0+M ٨+x 0+H + + + @+hP. P. - - - ]- #`-yh -p -O8 x-) -0 -O8 -r` !-yh x,P , P, ,Tp c0,[x n,F` Wx, e+0 Wx+p j8+p c0+X +sp +8 X* P*{ *E *! *x #`) [* H*}X Հ*}X H* * *8 * * p* :H*Ѹ <*H i(+ P- - 8.)0 .h ,. /8 H/;h 1p/N( / 0/` x/ p0 J0l p0 0 0X 0 08 0P 0H 0 +0X 0 / / /` 0/8 (.@ {.o ..4  . P.8+ 8+ h, H,b ,y 8, , ݘ, , `, X,޸ , , !- K- G-5p g-` %\ Ԡ%\ %` %} % 0%8 Ԡ% 8% % & &0 Ԡ& &` & (& & P& P'h p& ('` '  x'( ' '/@ x'K` 'K` h'[ 'n h'l0 @'ǘ $P(] >( ^(( oP(x e( hH( (P hH( {)'( ()G )E x)O X){ )( ) *^ *^ *c /* K*p ?* z+1 p+8 +0 +H +X ژ, , (+ , ̈,: ژ,[x , ,P X, ', w-  , `, ,p A0,Y (,i J,R 7,: rh+( +x h+( h+M h+M +4( +;0 +1 * * *@ و)h ) )h * @) 0)` )o و)'( X(p 0@(P EX( Q( ax(ĸ (r `(pX (V (* H( ' h'b l &H &H (& & & `& & @& &0 & C& T(&xp 3X&a X&v &= &P x& 0&@ p% 0%8 `% N%N )p% S%Eh Z% ]%v d% f`%X v%h }%a 0%p @%>` %c P%G H%p `%{P %h %a %f8X# X# # p# #( %(# <# 0# ː# # (#z #uX # f@#0 q# h#|` P#gH /#s UP#] 0#8 }(# ш# x# $ @$5 `$7 X$Q ($_ =X$b B$Q P$m Rp$T W $b} 0 } 0 }h }` H } }@ 0 } H }h } h ~ h ~ ~N` ` ~e h ~j ~!@ ~!o` ~!x ~@! ~h! "` 6h"# sX"&0 P"D "\ `"j( :" bh"Ő "Ő P" :" Z"0 rH" Ը"@ X" ;"@ \#Fx #K( H#[ /#d Ph#|` 0#~ # @#~ #X#w ,# # X#}7x ( }7x ( }5 p }9 } 0}y!h }y!h }J8!P }!L8 }9!) }U!4 }7x (~# ~# ~p# ~#z ~l#R0 ~}@#[ ~e#*X ~W#( ~Z# ~j##P ~v8# ~v8" ~Uh" ~o0"̘ ~(" ~" }"H }ۈ"^p }P"\ }H"P` }"D }X"&0 }"&0 }y!h# # @# !P# ;#H &#k 4#6 # ~#, ~#[ ~P#i ~H#s ~8#p ~## # #V #H # # #( ("x " Ͱ# # # x#H d8#b E# # H# #@ H# $h $. O$:8 $) $. |$HH W8$A@ P0$0 R$ 6h$ X 4$  8$ *# # # (M0 (M0 P(H @(H 7'H S'p Ը'` ': X'# ' 8& P&UH 8& 8&; h&9( & z%0 %< % % ( ($ G$J #z`*x z`*x {*` {H*x {``*e {*q {*a8 {*oH {`*P {*@ |X*0 | ) }>)x }) })y0 })fp H) x(( ( 0( (Jz`(n z`(n zg( zU0(p ze) ` zIx) zl) zv)9 z) z) z8)X z0*& z̸*vPv!N v!N u@! up" u0! v8" vH# wh# w#Fx wMh#( wTp#` wF`# wr$ w$" w$_ x7$٘ xC$P xO8$ xa%"@ xQ%q xE%f8 x]H% xf% x&B x&N@ yB& y}& y'8 yH'p z'X z&P(H z&P' z@( zW(? z`(pXv!4 v!4 v!Nv!4 v!4 v!4v(pA v(pA uH u8 :vPg vPg vu( vsp v(pAvPg vPg vH vX vH vH vH v}8 vxNX vX& vlhD v(D vI@^ u9@ uH u}X}8 ua8 th tP tv\h s28 s28 s s.X rܰs rXL rGP r- rz@; rl0D rFZ rRh9@ qI rF; rDX( rpp q0p q@ r r  q qр q q` q0X q q qr q} p qIk qqhU q^Q8 qcX2 qfP q0S qQ8 qQ8 q5 q q@ q qx` q0 q;Ę q60 q=~H q? rM r*? r,@ rF3H r:F rC rX5 r(. rH0 sQx r p r r s%X s%X s0@ tp0 t  tup u0[ ue vXO v8[ v(pi vB8 vH v vx v w8Px w~ w wX xx8 xX yPxـx xـx yQ y yHup yPwhx whx x3w x8 xXw xr`{ xx wP w(Ƹ xH w w0@ x& w w& wHEH wP$x w& w_ wc w wK@ wA w0{0 w@ w( w. vX wOx ww w w` x)@ xxw8P w8P wb wP( wxs,` s,` s#v s'EH s5ah sV@ s~h>@ sh( t"x t'( t> t+p tfp to tQX{ tvp tp t t0x tG t{ tX` t(" u!  u>$x uUh uW4 ul4 uI tx uNx uP u4 uZ0 u( u v&֘ vc vx vڐp vH v`} v} v`H vB8} v v*P v4(0 vKH v" v8 v v wp w:Hs,` s,` sP rΠ r rP r( rǘ r(X rΠ r  rx r@ r8 rgrg rg r rM r3@ r3 q r(#h rDX`XrDX`X rDX`X r^  rܰ rH q qߐ q7 qBp8 qG8J q" q9(" q-p q-p q-p q/ pH p px oPx o? pGb( ohC oPOh p (f p (~H oHVp opb( o op{ ohVp orxAX oy0 oHH5 oJt o o o{P om o@0 o o> o' oh5 oJ0 oJ0 pt` p0 oҐx o o o oxh oˈ0 o o[p oH= ol o]`9@ oA@D o:8s o,(e o X nx nD n6 nP n nw n0r n(aov ov op  o o{h odho oQZ oCh o.Q8 o,(a nHfP nQ8 n~fP ngH2 nD  nH n8 nOx nR0 n?p8 n n mXmX mX m@r mx8< mX:P mz mH mX m m m@ mw msms ms m( m# l lX l9x` l@ l& kp kx kxqH k2* kC` kh@ k k j j j0 jJt( jihcjihc jihc jQI j<Z` j`LP jX_ i{0 ix ip i i@ i( i&H j[X j j`RH k5Pi ki kH|x kp k( l m hd lP` l lOh lo`H` lS@< lc0 lB. l8i0 k lNˠ lS@ lE0 k k0S k8 kv kvo kG k7p kH' k k{r kC`r k(Vp k? jh jx' j0 jH jihx j ( i`YP iB3 hp% h h h8 h h hlBh gP gNR gc8gc8 gc8 fgf(g f(g flf j@ f j@ fp fP fCX e0 e( eP( ep eP ep e eup e( e,h e  e!z e dp dp d` d!d! d! d1x dx? dnh d  cj cEH c_x cG c2" b~H b b @ b b$ b9 b{h bf b{h b" ax8 aB a4 abxGP `shD `Rcp `o( __P _P _x_x _x _ʨ _ _h8^ _WB _x& _a09@ _S & _0X _8H _ ^͈X^͈X ^͈X ^0x ^'  ] ]X ^` ^ mX ]L ^' U ^@ ]U ]+ ]HP ]H ^ Xf ]]x ^ ^+ ^  ^ ^ Ո ^P ^ ]( ^b^b ^b ]M ^$, ^ X: ^ ! ]@` ^` ] ]0 ]H ]( ]`p ] ^c8 ^@s ^` ^(j@ _ _qH `j `` a8H a] a0 a a a b ` b.`h bO0 bG bV8SX b>>@ bL& bCx a` aP aɘ0 ap ay` ah a|@t aX aOX adE a*8J a']@ a'5h a0 `@ `zp.` `q `F `( `qp `` `^P` `8 `n` `P `B0` `?ɘ `X `0 ` `( ` a(` a*8 ag( a a8 aɘɘ aР b"0 b0 bg( aO aР b0#0 bA V bV c&A b8< b c8 c( dG`dG` dG` dH6xd8 d8 eAD e6(1 dP!` e:(h eX e1xX e#h dx e0 eX eO ez W eW f) fx fX/g@E g@E gx0 g gp gx g͈ hGP g@ g@Ԑ g! g gfP gfP g\ g@X f f f$@ fp( f2Pg@G g@G g' g)x g' g8 gr@ gQ8 gZ g_H g}P gfP gU gU| gr gX@[8 gfPM( go_ g[8 g(< gۀ_ h] g. hW gH g gx? g] gh:h g h ` hW h h( h" hW h%P hJ hsJ hxk hH[8 hXpP h0 h0 h h hxİ hLX hap hxp hI( hp h4 h50 h=JH h(C@ hhShP͈ hP͈ h8x hp` h  h hs hz hL8 hZZ hhQPj j jwxۘ ju p jCp j P iX i@ i i ihp i iDpp i*Ԑ i(( hP͈j@ j@ jPۘ j jj j jnh jr( jH jwxۘ j@m m mWhH mp8 mXX m8mp lQP ky( k jrFh rFh qh p p p`h p{P p<p p0x p8 oĀ o  o  o(0 o(0 o01 oe ps0 p>`^ p_0gx p7X pG o%P o oJ( nh n8 np8 nkd ndy n@ n(> np nuX nO"p n@ mP@ mpr/@+ r/@+ r r+ r;x r~+ r`D r` s:p` s~hp spX rըp r08 rP ru rM rFhp& H p& H pq : pa H pm@ b pȨ r ph ¨ p P pȨ h p X p\ o٘E odh{ oHHrp o. o8 o.H o% ` n n nh nɸ҈ nw nE` npc nhx n8( n n8( n6 nx( n6 oOPB oA@^ oI orxe o`v ox ohxh orx oq` o p>`q` paq` p\e pe pG0 qY qPB q9(K q6 qWG0 qh6 qxp&` ql9 q0@( q( q;x r/@+i(P i(P iP h` i e i(PW i#n i6`e i8R` i1s0 ige iI p iM0 ie@ inh i8,X i8T0 im iθr ip iH j i0 j. j` j jİ j8 j j kh kxAp k  l  k( lH0 k l  kX lPh l8w lXw lgx kR` l-P l? kH: l;* lj* l l l lX l m( mp l؀ l lU8 lc( lh l$`x k kx k l lqh lm lh l@ l  lj l l l m\@ m* m? mY( m6jX m4@z m*jX mq` lHP m Y l&` lPP lE0 l\ l>( lL8X l}p lhXh l@ lf l  l lր m8 l mBP m-8 mY mz@ m m0 n=d` n nz ( nnP  nX n n@ n( p o` nH np V o. p o d o) A oQ R( o Y0 o Fp p& Hsh  sh  sp su ) s - s1  s3h 8 s0  s. 0 r p s| p s@ Ԩ sH s[@ sx siP s1  rx  rܰ rX ` rDX rp 0 r, rl0 r rT ` rg X rX t r _x r v q v rp q ` qp qv H qxp q( p qY p q0 v p p p p 0 q` pϰ t pH X p { p t pc t ph X p5 P pv p@ 8 oˈ o ( oh  o h o p o~0 ` o'x ` n@ n h nP n ` n x oP  n o oP " n8 ( n H n[  n] 8 n P nT E( n 7 n E( m e n 4 n m 8 m8 ) mh 7 m 7 m P m0  mIX 2h mP` I m j m \ m;H ; m I mP` aH m  aH l E( l \ l t l0 { lt 0 lP lx lH H lW H l8 X l X k p lx p l lS@ 0 lf P lI 0 kP l  kH 8 k k P lH ` k ` k # kƠ  k( 1 k kh  kE  k h k # j 1 k.H ;@ k IP kQp * kP 48 k D k7 K kQp Y kp R kh ` kP x0 k]( ` k7 Y kp ` k'@ R j` \ j k kS kd0 k) k k j jx H j  jO  j jn ň jQ 8 j0 j%p 8 jh @ jh @ j* jk ڠ jC P j: i X j x jO  j 8 jX x jb` 0 jy  i % j P % jh D i0 3 iθ D i( b i8 i i( |X i  i i( i x i@ p i i  iM ɰ i ix i` i# i4 iY 8 i* iF i 0 i@ P h h( hH h P h( h^:0 hU`OH hWS hxQ hxi h@Hi h!w hli h@Hw h\h hkh hߨVP hpd` i7 i1H@ hp]X i*f hÈ hߨ h@H hjx h@` hGPX h6{ g8 h g@P h g gx@ g g g g\x g@8 g g gQ8 g5 g gC(ِ f`҈ fx fX f0 fph gZ g f( g' g0 fPp fˠ fĘ fOhx fX fM"8 f"8 fp9 f8< f0Q fҨSp fSp f"8 fb(- fw@Sp fX- f%8>X f]xZx f(Zx fE` f U e8G eZx eXG e_( eo f'm8 ft@ f0 f"v ext@ eH e e e8 e ex f  e e e e  e eְ e f  fi0ݸ f f{Ϩ fְ f`8 g( fH gPP f fH f  fְ f_ f<ݸ e e e e ep eܐ! e@ @ ehX ehX e -h eH f X e@( eI e8h fhG0 ee f } fF9 f( f4p f4p f`= fto fP@( f[ G0 f5` fTjX e f) fVp f p eP e8 e@ eh eܐ eH e eX߈ f(( e f ` fAXh f"( fVp fOh fy f,@؀ fM؀ fm f f0p fX f<h fC f(  fh e e* f.^ fs0 fgx fn f fh fz8 fH fP f fX g5 gGu gc g@6@ gۀ, h `% gP h6 h  hGPh h@ hh hX h}8@ h h@ hp( hʐ0 h h@ h i@ i(P ( c ( c \ x +` O @ 3 +`  0 *` j ] 0  8 P R ( P H 8 @ 0 X ݐ ( W h Ch h  P ` ` 8 , , 8 ݀ bh X 8 R 0   `   8  ø ~ 0 } ( }  }0 IP }' PX } |[( |t |" x { { q( {Έ ;@ | / |%@ {` z z {, {%  {F ` {  z {A P {[ @ {h x {% A z 8 zH #H z 3 z *P z 0 z h z8 y  xh d x y"( p y @ x x8 x h wH 0 w ` w  w w0 v ¨ vX wMhX w˜ wE w~b vE v% vjvI@` vI@` u8 v p u8 p u u u |X u K v V u0  u- x uh@  t X uL t` u- Ә t 8 t td tp tX u ( uL 8 u` u 0 ux @ u` w #H xp  x ( y y @ yf = yx 8 x P xh  x, w v q v/x c u Z@ uGp t ux ( u9` t u@h I tX ^ u G tX L0 tp 9p tv 9p t  t` 7 u0  tk 0 t  tL  tX` ) sh   (  VǨ Pp * ( [P P h 8  e8 8( K < B [P u d $ . @ ' x =` 8(8 J  J`l@ W  ۰ ` G ;` q aH 7  PX  0 }0 O l GH ,I #e Sh -  h( ` h D p  { O( K8ch hz Fe (jp  \( 8 % Pp 0 &@@ vx  À (h _(    T`X @ 18h  8 18À x WX (p H 5(/P (H ; Ĩ? 0u :`W( e8 h| ` b8 Hpx 8( p P hp  Ĩ (  h X  x h 0 (  * "0 8( P ?0 EX [P 7H @ v   h  ׈ I p ( _x 0  ͠ qX D  h 0 jP o 0 x  ` x &X  J` } 7  0  G ׈  b 0 P i  8 (  uH E @

H S ) 5 ) A   0  0 P 3  H H  R   v   h B Ѐ X E  p P H  #h d b 8 ` G p j@ Ѐ j@ H X ̰ .@ K .@  x h 0 X

 P  IP0 7 P p ' 8 k x I n ; H h X 0 06( 06( àX @  @  @ I8 j KŨ 0 0Ũ x @ p ڈ ( P n0  Cxg ~ G 6rX c8,  @ x X5 @ *pH   A8 H Ѱ ʨ g` z h8 *pB iUx B 8+H b X (x  j@ (P (  x 8( ƀ p N 0 LP @ + I 2 H Xk )d 'XC@ @ \ wX ϐpP (] " P 6(i 3H x p  H @H ^ X Kx g  px xh  PP X ` 0h X p 5P0 X @ h k8p X p P 8 S@8 }pX  (  `  8 PX ( ( I   Ϩ p b} Tm8 `  `h P X (ݸ  p @( hH 5 ` ` ` 9( a` j`x 8` cX} ( * "8 X"8 x4 ?"8 h<  X@     Y @( cP x XR` P  p  H  O U' h8   ڨ? xc h|  X a0 0P c ,(P +H ˈE ` x  x hۘ Ґ` <y( @0 (Z  p -p u \PpP sk &h Y  F K? Dh  @0 P  ` 6@ o Y X s  } pv  z  #o K`v i8 v h F(4p P0 ]z 8= -h Ԙ$ ex K h;x (-h  T8 T( ^X8 x  ^X h (` h  0 0 8P ~x ɠx ɠc P_( '`J  @   7@ Zh EPx Bp9 ň U0 n  4`X   0 @0  { H@ C  ĵ, U P J  ( Þ @  x Ó0 ɰ dP ²0 ( f  × ¨ p 4  p  2 H q x   8 xX h xX h*0 0 *0 0 ` p  6 *0 8 ix 8 R r h P  , ' נ T r  d $p w >8 H {(   ` # xH  p % p`  =( P  8    @  R@  x A x O uP , g@ x Y0 3 ] |p p [ w  w  Fp  d 3@ ] ' D  /  @ ]p  Q  " 0 C x  h X X (  h  ( h Š X xH X ;X R ! n Ih  Ih      @ H ݘ x0 h ^h 8 q(  D rP L d@ X h Cp   H ø C (ŝ x ŝ x ń x \8 c  ^ 4` W +` Þ    P @ `   S( 2h 4 p 0 @  x H ( }h QX hP   E( B 4 X P  +`d9 d9 x h (H ٰ 0 0r ]x 05 ۘ( ! 8 1x 06(y y  rP d  u   ( x @H h! _ iH+0 T0 Hx; Ap! 3`- '= ApW HxB M(P ]D [8jx mh kP ]X wX  m p y hʐ XP wX` ] C T04 :h% C? T0; M(T iHDp uP( J[ mlH [8n JlH <b Ox b@sP _( p xh W0 ` Hx  p p pP( P( lH P( F 8 C@F _`=h kM tx6` fh1 /X  (P 1 ( h (h   d91i0 1i0 DPt * M T gx   ` x. 7p 2 >x wa Hr [  H8  ( H ` 8 ܨ * M( yy y [ Sph q  h 0 Xw@  ( v8 8 P `ˠ  ( f0 q+     H p 0     1i0h h p0h h Hh 0  3( bˠ p yf- f- HX pߨ p 8H H  +H -o( Sp^ 4S `GP h4 = B ݸ p+0  4 ++0 / p 2 G0 0 p    2   h X _ 5 LX ){h {h hp"| p"| +"Wh $"1 C" 0!X N" U!X h! o! X! h! 0! ! {H! j! p!P ! ! !( ! 0!t !j !W 0!W !f Ƞ!N !hX ݸ!f h!0 Ƞ!>( !I h!9x ! 8 0  P $ h < ( ` @ Lh X } X m $OP $% ¨$ # $ ɰ#( и#@ # # # #p # #ɸ <# ># :0#0 .x#x E#x J# Q#x p#x L#|` kh#`@ # #s H#h ~(#T #T P#( _#( L# ~(#*X @#@ #( p"x "x " " "H 8"H 8"0 "( "x "̘ " ҈"0 "X @" 0"p " " "H "s "z1% 1% T% P % [% b%X u%p % sH%h %a % % %tH %h `% P%0 `% %( @% P%} `% 1 % F8%( A% ,p% `%8(& 8(& *& 3x&+ O&6 :&; A&R u&P &6 wp&X | & (% bX%8 i`% %ϰ ~x%0 8%@ 0%X P%P %0 % ސ% `%0 % 2%x H%h 9%x Qh%` f%{P Xp%f8 k0%v X% h%{P h%Q %a 0%{P X%_0 %f8 0%< %U )%@ % 0%@ @x%@ B% ( )$ 9p$ $ 7$٘ +`$ hP$x > $Ā E($@ G$٘ G$P m% p% t%& %5 % ( `% ( %8 % h$ $ % % X$ H$ 6$ *$X =$ \$ `$ F$٘ s$@ |$` $@ $8 $@ P$h $ ($ $H 0$H $p /$ ?h$w(}Q8 }Q8 }ۈ ~q8 ~ ~pB lPW D $( R/ 89@ |0}S }S }pp }8 }Ԁ } ~` } ~b( ~GXC ~Vp ~a %8 ~  } }up}up }up } | }PW |W | |0e |Ұ&H |X | |X }hp |N } j |8LP }$c })hSX }aLP }000 }HEH } }ۈh } }PX }}H }H } }@ }Px ~p0 ~ x ~(0 ~GXx x P0   H  h    j @ Mx H  8 ~߰x ~X 4 ~HX ~v8 ~ ~(   H DxH eH  8  8  @O ( 8 000 0 XT [`H |0T 0   P h € g V ?@ 3  p H 7  p8  t O{ 88 d8 8 ' h8  pP MPҨ MP ]( dp  pxG |0W#]X W#]X Ve_ VhP< VL Vp< V 'p V W#X V W VP V V( h U Ux ` V$X H V- X Ve Vx P V V V` V{ 0 V |X V |X V g@ V}h b VoX r Vc uP VS8 d U@ ` Uf uP U b U͠ p U͠ g@ Up K Up g@ VH ] U V V" Mx U@ A V Fp UH , V / U`  U  VW : Vj ' VoX Fp V 3 V Fp V #H V@x 0 V0 V4 x V-  V  V , W( , W 6 W/ : W( T V8 O W* g@ Wh ~ W;@ ~ WK 0 Wc W` i W w W ] Wh #H WP #H X/ T X1X % X  X % X `8 X  Y< : Yt  Y #H Y Y Zm8  Z(  Zh  ZX  Z / Z R( Z R( Z uP [ `8 [cP z [cP z [/ [l [+ [v @ [ [Y X [+ X [P ` [$ x Z [ @ Zݸ 8 [ Zh Z% Za Zm8 h Y҈VP YS Yf Ykh Y Xи X@ W̐ Wrp Wxm Wh_ WPrp W[ Wq(f W?[ WPXOH W#]X^0 ^0 _   _P _h _2 _QP _xmp _`mp _H _àv _Ѱ _ _q_o@ _o@ _Xƀ _^8 _p _ _vH! _W _W _a0 _0 _  ^Ѱ ^y( ^E( ^QP ^0 ]* ]- ] ]wX ] ]M( ] ]O@ ]*( ] ]  ][8 ] ]iH ] ^` ] ]k ]vH ]`> ]4 ](2P ]( ]~` ]Hx ]F  ]pP ] ]0Ԑ ]k@ ]8 ]k ]Qp ]~` ]`P ]  ] ^2` ^H ^mpo ^ fh ^C@] ^.(S ^NQP ^S$ ^$ ^ ^`' ^ ^$ ^> ^(' ^ ` ^` ^P _ ^0`!`: `!`: `P@F `B0T `YA `jT `? a8H: a*8`p ` ` `sh@ `@ `P a  a@ a|@] ay aHm au8 `ڈ aP a b:r b8 b b( bP b@ b b b~ bX b c; bc chs c-W ce c c( c} c cEH@ cf@ cSXP cf ch- cG- ch4 cWH cP b b` bm b@x b" a88 aH a aY `@ `8ڈ `p `D `ڈ `@ _@ _Ӏ `- `` `eXj `R a:M a?P6x aX a 6x `p `!` ` ` ` `zp8 `* `P `1 ` ` _ `0 `h `Xx `a0 `eXs `I8h8 `$@ a.2P a#0 a` $@ a, aR a1@ aTh` a' a a` `} aL a8H<8 `<8 `Z `uE `xfh `8L `4 mp `N `!`G `WH `-p `1 `j `6x `/p( `# `P `@İ _( `* _ _˸ _ظP _ _İ _àİ _Ѱ _ _X~` _8pP _iH __ _Q `J _8J `:h _iH _hT0 _ѰM( _sHx _8? _ 1 _0 _ظ _8 _p _H 0 _x _@ _ _X _0 _ظՠ _ǐ _0 _ʨ _ʨ ` _` ` _ _8H _xp `(hs0 ` e `!`:uؠ uؠ u u=h u^=h u b usP tY t- t`!H th ux uؠ~#0 ~#0 ~x# ~p#Fx ~#0`-C `-C 0- H.  .- .` - P- X-p -0 , ,H q, , Sh, C,Tp , p @, ,. , , )8,?X ,*@ ,= و,F` ,[x , - @ - , P, `-C(0 (0 h0 H0p P0 (0p% p% t%& %5 % 0% H%0 8% (#8 #8 # # #ɸ X# $5 $x Sp% @%h 0H%c "8%0P % $ˈ ҈$ $w( X # #81 1 l`Y TTP I8?8 T,x * = 4 8  8 ظ h @ W LX 7 4' (h 3 Ig -d 8C 8g 7wx & Uxn a08 z~ xd Wd Z(?8 h85 n  0 h` c0 c x ( o@ .H Z( 0 j E S C` 0  @   0 h C` )  5P 1РH РH  ( . V x . O y hr ] ] @5 # X eX  @@ θ :ǰ ?P  ר0 Рg` g` @` @" xQ  Ո  @5 k ~X@ YPk M{h V @ D8 ` # @F #  0 h Pؠ  x#  R N I &Hn =h /1 8% F ϐp ve@ $xp SX^8 $xW0 B pb `[ * (` h   t @h %@ @( H(u 7^8 @lH T ^8 rp Hp r *8  x h X  8   j q ? θ ` à( Xh h   XX % pX 'Xʐ 5hp H(X ph @ 8  H@H P Gx U0 ` )(h 28 >@@H  # u{h X ̰`  XX "  8x #h , D8 i` up 30 H g`8ox 8ox TP ٰ6 6 .K _HPx 9 X e 0 H   Ӹ fP (p ( i  P RH3 1x P : pz RH0 |x  ̰X `X : H 00 `   l  l K  P {0 ܐqvq$ vq$ v^X$HH v8$L v- # u`"̘ u"p uGp"? uU"? uB"&0 uS("# t`! t8!x t!S@ t`!- tƈ tH!0 u! u!!h u"4@ u" u!8 u!W v!4u8 : u8 : ue V u O tH d0 t S t8 a t S t A tX Xx ty0 S tS > td  t A tfp  s  s 8 s + s 0 s0  sx " su C` s H sV E r r| ]( r6H Z r, E r Qp q ) q ( pȨ " p8 xp8 x p8 x p o oh( o` oH0 o XV nhV n, m` mH  m k8 m0 m@ ͨ mD ͨ l X lj ]( k )V YS)V Yp)d Y) YX) Y) Y) Y)ƈ Y)P Y҈)ƈ Y҈)۠ Yp) Y ) Y0) Y)Y) Y) Y* Y@*@ ZU* Zx* Y* Y*& Y*0 Yx* Y`* YP*@ Y*GpY*E Y*E Y*s Y* Y *j Yp*{ Y* Z(*q ZJ* ZX *h@ Zm8*c ZJ* Z(* Yx* Y* Y*8Y*8 Y*8 Y8*P Z * Y*ʰ Z*( Z@*h Z)@*p Z0*@ Z2*( Z0H* Zf0*p Z *p Z*0 Z* Z* Zf0*( ZU+ Zh+H Zc+ Z* ZP+ Z+ ZX+ P Zt@+XZ\+6 Z\+6 Z{H+- Zf0+;0 Zq+R Z+D ZP+e` Z+D Z+j Z+lhZ+lh Z+lh Zx+0 Z+` Z+` ZȠ+j Z+| ZH+ Zְ+( ZP+ Zp+u Z+ Zh+` Zx+ [+ڐ [+ [/+ [&`+P [G0, [\H+ [R, [l,x [W,8P [ ,A [ ,V [0,Mh [,d [H,d [0,y[0,y [0,y [, [, [,h [H,˜ [H, [X,8 [,( [ , [, [X,װ [, [, [, [,0 [(- [-P [-5p \`-) \`-J \/8-C \-X \p-a \-a \-\P-@ \P-@ \- \-@ \p- ]3`. ]. ^ / ^ / ^ / _(. `!`.` _x.` _.P `(h.` `.P `=. `P@. `M.P `(. ` .{8 `Ӏ. `. `. ap. a%.} a.P aO. a?P.h a. a,.ha,.h a,.h a`. a.֠ b.`.h b.Zh c .B c>@.G c00.& b.p c)(.x cB.G chp.@ c@.pc@.p c@.p cȈ.c0. c0. d`-d^- d^- dH- d- d0- d- eK@- e.G ex.2 e.EP e.\ e΀.LX e(.Zh eH._ e._ e.t0 e.f e.{8 e΀. e0. e. eՈ. e@.8 f/ f7/( f:P/@ fM/ fM.p f[ / fOh/ f~H/ fy.p f/ f/( f`.` f/ f / f.Ȑ f / f/ 0 f0. f/ fҨ. f@.H f.p f.` g8.P g. g.p go.h gy. g_H.x gx.P g.@g. g. g. gH. g.֠ g. g. gp// g/;h h/K h /;h h/-X h$(/;h h;/+ h(/D h=/D h;/W h&/W hx/W h+0/v hD/s h-/` hZ/ hD0%hD0% hD0% hD0b h(0 h9@0@ h&0 hX0 h$(0 h60 hB0hB0 hB0 h!0 h&1. h1 h 1 gP1%@ hp1Hh hcp1Vx h=1] hD1m hX1Vx hX1< g1Vx gP1x g 1x g1X g1 gH1P g2' g27x h2' g2L h!2S g2S g2 gH2th h2v h 2 g2v h(2h hNX2 hq2( ha2 h42 i3i3 i3 iW03 izX41izX41 izX41 ih4/` izX44 i 4n i 4i 4 i 4 iH4 i848 jh4@jh4@ jh4@ i(4 i5< i05k j:6 ( j:6<` j6m j`6O jH6m jO7& jpp7N ju 7 jF@8N i8u i@8` i8P i9( i9 ix: iR:" iW0:iW0: iW0: i[;_8 iǰ;0 jh< j<8 jЈ>%`jЈ>%` jЈ>%` j> k?2 kp?X k0?` k)@ kH@q kX@p kxA#kxA# kxA# lXAj l^B8 lB0 lC]P lրCrh lCyp lpC l(C lC mCP lHD4 mDN mD+ m;HD2 m6DSh m`DU mx8DX mzDt8 mDX n#PD_ n DSh o XD+ oHHD o D- oD( pD9 pD pD"0 qC qsCX r3C sB׸ s]Bx tpA thA t@0t@0 t@0 t?8 t? t ?( t? tX?@ u?V v!h>P v`>P ve`> vI@>8 vq> v^X= vg= vc= v`= vT= vR=P vI@= v?=T v= v*< u< u< uH9X yG9 y29 yQ9p yJ9Y@ y29p yB9H y$98p y49#X y$8 y-8 y8 y48s y 8N y)08@ y8-@ yx7 y 7 y)07 y7t y087c yx7ZP y47N yp72xyp72x yp72x y7 x7X xـ7@ x(7 x6( x6 x`6h x6( xH6~ x6V( x6V( xp67 xt6 x(5x xp5x xyh5u( x85H x: 4 x.h4 xi4xi4 xi4 x(3 x3 x83p x3p x3 x3h( x 3E x3; x3 xH2 y22 yQ2P y_2 yS`2 y_28 yc2} yhx2 y2 y2Zyx2Z yx2Z y2 y1 y1 z 1 zX1 {z(0~ |'0 }7x. }(.h ~=-0 ~@P- ~h(,x ~,D ~P+x + ~+P + ~+ ~+ ~+6  8*0 ~* ~cx+ }+B8 }(+8 }Q@+R | +K |d+ |p+u {+h {3+ z8+( zX+/x z8+z8+ z8+ z + P z;h+` z* z@* z*vPz*vP z*vP z`*Z0 zv*j z`*a8 z=*+P z&P*- z) z) y8) y})fp yEP)] y"()0 x)7 x8) x( x( xh)p x)'( x(8 xr`( xV@(H x'Pvq$ vq$ v$P v%p w%%U w%%h wY % wF`% w=%p wR&( wp'x wp'* w޸'n x'Pz=s@ z=s@ zŰ=Yx z=% z8= {H9 }@9z }X9u` }P9[ } 9?x }5 9D( }29, }@96 }C09F }@9P }0p8 }<(8ڰ }S8 }fX98 }o8 }8` }x8 }8Ө }8 }p8z }8D }p8D }8( }8 ~`8&8 }8( ~ 88 ~&8x@ ~;8x@ ~P8 ~z9x ~9( ~x:5 ~\p:' ~I9 ~$09 ~-:> ~E:X ~2@:` ~B: ~:( ~ h:` ~ h;h } z >p` z>bP z= z0= z=s@"@ "@ "sO"sO "sO "?X !X !ր( ! !q !7 h 8 sP # } }p  HU` h6  Hx H h @ۀ ( p .H(  hx {h P ɀx Xy P H [X O TPo g 0 @  7    P 8^8^ 8^ ux p( 8h xx l 8n ϐ pox X x   80`    X@ p h (    8  8 5h ^8 `x A d@ r  P n

hZ 9 5  + @    ` X ΀ H0 iX (` nh b 8h V` b  lp 1xT0 T0 *p:h 05   ̰h ph Θ zΘ xP0 `   g s~ U(X = eKX /w ^ (!( @ j  j w t(P v`p 78^ EH? " !( N $x h *    !( !( 3 =H =H e 0W i e u e H(? a6@   ` D A} ] ]0  ?Ps  -( F} 6xh  zjX Xv ƀs ^ C@P o I 9  !  @ QP  J T0 ph r` %P   Θ` @  ( H  ~ݸ [ ~ e  1 T @ 6@ `p Yh! s0 w! 3;x T/ s0;x H&` 2 ^R W` we ~e 8x s  jX `   p   v   Ph \H 9  4p X (@  ݸ X c߈ h p  8  q D  Bp 8 q` 8  zP 6 +  X Zx &R R xo x     8  [ mp OH "H .x H  /8 :0P l( 7l( `H Hw 8  p b TH *P   " %P @Ap ep5 `V X] &(k (m X H Xp ( @ `8 p P( H L0˸ ; 2h0 "X x   h L )P + ]  0( 8 + 7 @+ +  @ 2 5+ O@ 'V *)x  ` Z 0 p  +H  j -j - j - r B  hP { (   X ah  8   / c X G p - , - H ) 8 P  " K@ )    H  p X p   (  9p ^ >  q  aH  j  x  }h  ̰ x 8 %    #h hP ` { 1x hP ? v`  P 8 G  Z@  G  \ x 7  U  2h 8 \  ; H v`  W C &  0 p H  ) _H  x   Ԩ t` Ƙ  x  > p \ * I ߨ N % E(  ) P( $X   i @  u h | " P &  W  N TP  ) P ԰ S8 "H #H " #1` # $OP ݀ $> #` # #8 h #i # # 1 $ D %h BH % 8 &h  &@ = & = '( q( ', IP 'I q( ' x0 'h X '8 H 'B X 'l0 x 'x ' 0 '8 ' '  ( ( '` ' ? '8  'h  'x  (:p  (O (iP (d ( ( (x (X  (X (5 ( ( @ 'p '@ P 'M 'M 'M '( @ '[ ` ( (@ ( ( )+ )@ )k )y0  )  * P *  * BH + BH + * , ? , 1 ,x  ,8  - ? -{ K -w  -7 h -8 !x - -0 , !x ,8  ,޸ P ,x 0 -.h 0 - X h -p - 8 - h .2 . ;@ - U . ep .X 8 .J lx .hx q( .; .t0 @ .@ .f .- h .+ . h - .>H .U . .  .o IP .LX ;@ .o ` . ` / /`  /Y  /2 8 /2 . H .` /= t / t / \ /z I /` \ /U0 q / \ /p E( / 0 E( . ) .Ȑ 9p .B " -ـ .X .B . .>H .  - -0 H .x 5H .f H .{8 '8 .2 ( . . H . @ . h /(  /!  /g h / A /Ű 0? x 0  0  0 x 0`` ( / & / +` 0/( +` 0s E( 0ǀ - 0H B 1F I 1 I 0h e 0X W 13P 1 x 1M 1 X 1p 1X e 2 hP 20 2 ݀ 2 2m` 0 2Q@ 2d 1 2 | 2x 3 8 3 8 32@ g 3Z q( 3Z BH 3Ѡ 4M 4 ( 4K ( 4q 3 c 3߰ @ 4& P 4 & 5 0 5k 7 5H B 5p > 5p P 5 hP 63 oX 58 6+ 6<` 5 ( 5 5y 5 5ט 50 # 6> ` 6 ` 5ט  5( 8 5` 4X 4Ǹ 4@ ̐ 4p  4b 4  4lP p 4 40 8 4sX 4p  4 3h 36 3I x 3x 8 3p *P 3Uh ] 2  2x h 2P b 2N b 1 8` 1p@ 6 1 H 0P 6 0H K 0 : 1t Mx 1 3p 3 2.x 2"`L 1`0 10OH 1OH 1C 1% 1p@3( 1Q 1JH@ 1tb 1[({ 00 /]X /\8.x /nX /]X 0Ap 0`8 0wp 0 1( 10ˀ 0hX 0 0gh 0O 0H 0 "8 /(0H 0Lh /8- /G /Lh /Sp /c /\ /0q /sh /8 /@ /-X /@ .-h .@4p .D . .X( . X .H /(/8 /!# /P /P / 0u /&P(0 /@* /XYh 0h /. 03@ 0 2P8 2pP 2h@ 3p 4 3<8 4/` 4p 4' 40 5MP 5O+ 50 5$ 5 N 5P 5€H 5+H 5W 6 5 6$ 6x 68 6_g 6@= 7"j 7L@8 7X[ 74 7L@ 70R 7(h 7vp 7π 7p 78vH 7c 7}xP 70- 7j 7p 7fX 70H 7h`͈ 7}x( 7SH 7t 7E8` 72xtx 7Pk 750 8x 8 8 8H 7=H 7  7  84H 8x 8( 8g 8I` 8j0 8Wpx 8zs 8;Pq` 8\ h 8*@( 8Y-h 80! 8K 7 81 8# 8R 8X 72 8R 9T9 9/Lh 94 9(Lh 9 >X :f :>X :Q :x ;G ;G ;)Pp ;Z ;p ;c0 ; ;mH ; <h M >HP >iXx >=H >gx >DP >0(0 >`x >p > > >X >H >h >x >߈ >0h ?.8x >H >ވ@ > ?.8 ? ( ?CPG0 ?W ?cP ?E} ?h ?o ?s ?h} ? ?8 ? ?P ? ? ? x ?X ?Ԡ ?( ? @8߈ @(P ?x @- @- @x @S0# @P? @0KX ?i @R` @-`p @hP @S0u @u @@X @ z8 @P @t` @ @( @hP @( @h @8 A* A-(' @< AV @Hx @Hx @p? @ʸ8 @h8 @xV @HV Ab@ @m A Xh @hp A-( A8 A=8 A@ AM AX Aeh A A0 A` A ˸ A8 A Ax A AH"p A9 AӐ A A7 B x A)x B:' A`] B`0 BA> Br$ BN C_tx C.p CVH8 C:( B Bh B'x Bа B0 Br A@ A@ Aq  AjX A Ah! Ah- Aژ- Ah Bk B͈ C" Bɨ B CS C{ Cx CC CdX C]P0 C C C`` Dp C D>P9X DNp D9j Dl D@ C0` D@p D; D` DShH C1 BI8 BWH Bwj BuH Bn@| A@ @H A X8 @8 @lx @0ڈ ?vx ?vx >H( >8 >]Ӏ >]@ = =V =u` =[i =M~ =Fk <p F0u8 >` ?PP ?h ?k( ?0 ? ?L ?@ >P >'@ > >H( ?$'X ?Xh7 ?0w >P( ?H( ?9P ?Sh ?V ?o ? ?p)( ?ۨB @$PG @HSX @tLP @hHah @ ah @x; @(X AX A=q A Ac @X Ah @\ @0 ? ?x ? ? ? ? ?P ?0 ?X@ ?d / ?CP^ ?'0n ? ` >e >@ >0 > >` >qH >Y > >X >x ( > >֘ >hP ?{ ?t@ ?` ?hx ?h @ ?5@ ?LP ?; ?oLP ?O ?h@ ?Oah > > > >@v > @ >8 >bP >  >X =X=X =X > x = >Pϐ = =H =0 =x = ( =~ =l8 =Kh ( =D`p ==X! =( =% ( = <Bh <Bh <(;` <D <Y <Bh ( 08!) 0! 0i!X 0np! 0:!P 0T!+h 0/(!7 /! /U0! /Y /\8 /\8 /D! /R!" .!N .!2p .@!4 .H! .0!$` .!X .!N .!f .`!{ .}! .LX! .! .&!X . !P -H!X -! -! -! -(! -@! -!8 -P!( -H! -!@ -!X -~! -" -" -{"( -O8"! -t"8 -_"l -,"Y -: "q0 -,"s -]H"u -H0"` -H0" -t#*X - #,O3 @ O3 @ OYH O/  O 0 O8 h OP ( O0 p OP O ڠ P  P P7 ň P7 Pt Pb Pk n P j P BH Q9 * QL  Q 8 QC Q  QL @ Q Qv  Q  R+( ` Q @ Ra X R; Rh Rx ( Rx Rؘ S| x Sx S( T Tx }h U 0 x Uh c UZ e UJ` L0 Up N UH 4 U` ; U  V  V  V>  V4  V V h U U 0 T U Tn ` T X Sΰ  S, p TX TQ ST 0 R@ @ Si p S SDh t S t S ] SP y@ TTH t T Xp TH J` T ) S ) S=` " S  S=` S* Ѐ T%h " T]  T $ U( E UXp > U(  V Vt 8 V V Vp Ƙ W VP X V W v V t VH f V h V _x W CX V '8 V L V + V  Vv` 0 V  V2h  V@x  Vp P UH UԨ  U_x U  T T׈ T׈ UZ U9 ~x T0 n TV Tk | T* ~x T` wp Sո k T u U p ` U J TX : S F8 S ` S C T3x C TbX 5 SX X T 3x UO P T Uo U V^  V VhP H U0 U(  V 3x W  W X W(h V@ V8 V V V Vx Vh VXw VP Wp X0 Xr X=i X w WIPn Wb W4 VDh V% V@? WX* W V W  Vߠ W0 WӘ Wh(H XA Wx Vp W  X W` WN WX WF VH WXs Vpqx Vl VHh VXW Vch V ; WUX Wu; V@4 Wu6 WY&x XI X+( X XuP8 X6P X08 Wx0 WPX W Wc` WX XFp XK P Wj ( W48ȸ V@x Wp V Wep@ Wp< W=$ WH W X?h Xd X  W X XO Xh YJw8 XHp0 W  Wp0 X0Vh Yyx]p Z7 X0 W" Wz7 W48. WH( X8' Y h Z ZϨX [+ \3@ Zn` YCw YX X X/ W W` Uo3@ V VYH Ub U0 S S@P TXx Ue Re P P P|p RsV QhH Uk0H V6 W* V8x U( U TP0 UEڸ U Se8X RchŠ Q} Pth PC Op Ob OR@p Q0Ӱ P~@H TXH T  Sո S* RGH P PC O N@` N N4P N M8p M@ NH M@ Ng` Mc` M M4h Kk J@ KRP I߸Š K  JP Ih̨ I; I Ix Kx L@ L1p L  K! Kˆ I0 Jp6 KF J^H=( J[( G`X F8! Gp F@n` G| Ep`P EjP EsT Dx1p DU=( DO D+? B8V B6gX C8 A@n` A( AWX8 @܈ @c ?܈ =ΨO` > w8 ?9t ?`[ ?i( ?"{ ?E >` =Ψ AX > >A >~p =H8  >g _x =pP > @ >] >  >@ >h >P ?d  ?H ? @8}0 @c @ Asx A AHh AHh B x BY(À Bn@ Bؘ B B ( B B6X C0I Cl@ D`| C D C C( CdX D ( C D$ DU D$ D8 Dh # Dh 3x DG M@ DȘ V D` ph D u D u D E H DQ D֨ DU D E D D  D+  D} 9 D + D@ > EBx 0 E( p EU8  EBx  E X E= Es  EK E  E @ E8 p F8 ( F  EŸ 5H Fh + F* > F Z F8

X G< GLh GN GpQ G@U G a Gp_( GE` GU H PX Gj G} Go GҸX Hc GX HH Gh H0x G˰ G HQH H> Ha G HS H)pP HXPϨ HG` H@ Hvh HPX Hp HJ@ H Ha H H I x I$8 @ I Ich Iz Iqh Ixh IX I@ IѨ` I I I߸ Ih J  IP @ I}H I Ix J80 IXP I( IѨX Iذ9 I J I4p JX J = J[ J @h Js`2 Jq` J?xh J; e JW@l J`} JK JD JcP K3l K\H K5W KhG0 K*0B J@P K;x J;x J! J-h J0 K%9 K-h KY+ K,&` Kd K  K`H J K` @ J KC Kk J` Ku0 K'Ϩ Kp Kx@ Ku0H K K5 K KX KT`P K K Kxt@ Ka Kh K7P KC K+ K K, Kkh KH Ky K@ K KhP L(8 K@҈ K K0 K L KP@ K LJx L L: L H0 LJx L30 LQ LX L~8 Lhyx L(i L[ Lrp LrPOH L7 L]8< L 0" L LJx 8 L H L L L L 0 M x M ` L uP MH uP M` [ M9 p ME@ p MB R( Mj nH M k MH Y0 M b M K M , N 8` N 0 N* M N Ns N ?h Nq@ O N % N Fp N #H Np : N / O 8` O3 @- #, - #, -E# -%$_ -.h$rx -3$dh -0$ -% -5p%_0 -kX%p -]H% -S%0 -dP% -)%N -p& -8& -P&р .G' .-' .7@'(8 ._'* .X'* .Ϙ'DX . 'w /Y'g /z'T /xX'Rh /'^ /'P /8': /@'P /'6H 0', 0``', 0i': 0O'? 0gh'? 0s 'W 0s 'I 0'I 0'/@0' 0' 0'h 0'( 1 &( 1(& 10&xp 1,H&+ 1A`% 1A`%p 1% 2J8%p 2% 3%p 2ۈ% 3%h 3-%0 3;% 20&UH 2Ԁ&8 2(&xp 2`&P 2& 2`& 2ۈ&X 2& 2& 2Ԁ& 2P'Rh 2's8 2 'F 2' 2th'* 2_P'I2a'I 2a'I 2U'b 2}'n 2a' 2r'P 2_P' 2m`(P 2XH(_ 2\(H 2>( 2(P2(P 2(P 20p(p 2E(X 25 ( 2k(2k( 2k( 2( 2Ԁ(ĸ 3q( 3( 3( 3( 44( 4( 4i( 4( 4( 4( 4( 4H) 4Ǹ) 4p) ` 4P( 4)X 4() 4)  4) 5)h 4) 55)255)2 55)2 5)> 5)O 5p)S 5.) 4H* 5* 4* 4H*h@ 4* 4* 4* 4* 4*P 4p* 40* 48+ 4+8 48+q48+q 48+q 4+8 5*(+@ 5,.5,. 5,. 5`,D 5,b 5,b 5,~ 5,X 5,~ 5P,g0 5p,~ 6, 6f, 6,V6,Y 6,Y 7,K7,K 7,K 70 ,' 7,1H 7(,K 8,] 8I`, 8`,(8(-w 8(-w 7-8 7,0 7ݐ, 7, 8-@, 8h, 7X, 7,Ш 7,X 7H,@ 70,Ш 7π, 7,` 7, 7,p 7oh, 7}x,i 7j, 70 ,70 , 70 , 7&,7&, 7&, 7, 7,8 6, 68- 6-O8 6-t 6k@-t 6Z-P 6Ch-P 6Ch-C 6-5p 5h,x 5x, 5x,` 5bh,h 5V-5V- 5V- 53, 510,0 5,( 5 ,@ 5 ,װ 4,8 4, 4,y 4,= 4eH,. 4T+ 4+( 4+P 4B , 4,1H 3(, p 3Ѡ, 3+ 3P+H 3Ѡ+0 3+u 3ʘ+q 3H+\3H+\ 3H+\ 3\p* 34* 2*Z0 2*@h 2@*P2*Nx 2*Nx 2x*& 2* 2* 2X* 2*02*0 2*0 2*$H 2*7 2$*& 2J8*4 2*+P 1Ұ*( 1* 1b0)1b0) 1b0) 1) 0) 03)r(/)'( /)'( 03)r( /0)p /G (@ /K( / 0(| /(( /Bp(@ .( .(y .(iP .( .(p .H( .(x .v( -(x -{( -)( ,0( ,(y ,p(X ,0(C +^X' *'X *s' *('^ )0' )2&( (&x (&; )&$ )X& (& )% )% (% (x%\ (% (k$ (%X$T ' #H 'P$` '# '`#0 'X#0 'X#P '#h '^ # 'z@#P 'w# '# '# 'Yp# '!0#~ '!0#gH &#i '#D &#b &8#T &H#gH & #[ &؈#O &p#Fx &##P &8" &" &#( &8" &"0 &" &" &xp"P &+"q0 &"? &+"! %"&0 %" %0! %! %a! %o!@ %C! %>`!W %$!S@ $!8 $  $(  $( H $w( : $t " $E $> " $% 8 #H # x # S # t #0 $ ! $f!P $! $! $x! $! $! $! $"6 %)H"P` %<"@ %a"P %U"` %o"@ %"Ӡ %o"p %"X %#Fx &#° &$ X &I$'x &@0$0 &UH$ &xp$:8 &$:8 &H$p & $ &$ &z$ &cX$ &G8$~0 %$ %#8 %v# %Z# %_0# %Lp# %Lp# %Q #O %"@# $"8 $ " $" $"x $y" $A@" #"` #H"4@ #"! $"( $h"4@ $E"6 $"! $,(" $." h $7! #!L8 #R0!P #?p Ơ ##P 8 # " m " Jh "  "Ӡ "x@ "?O ?O= 'W = 'W > @'DX >('Yp >׀'l0 >'X > ' ='` = 'W;tP& ;tP& ;`& ; &} ` 4%x 5'$ 5А$ 6$ 68$ 6O $h 6:$x 6Jp$0 6@$@ 7 $ 7$ 7$ 7L@%"@ 7P%$ 8%N 8(%m@ 8#%_0 8*%v 8U%x 8c(% 8=%j 8j0%} 8% 8`% 8n%( 8% 8% 8p% 8Ө%H 8%X 8p% 9V% 9D(% 9`H& 9A& 9F&P 9& :X&K :'&Y 9p&l 98&( 9&l 9|h&( 9@&v 84H& 8R&^ 8&@0 8x@& 7& 7p%p 7% 7%` 6P%h 6%@ 6%U 6rH%U 6S%Lp 6H%2 6Ch%Sx 6>%Eh 5%@ 5%"@ 6x% 5$h 5g$h 5%>` 4Ǹ%C 4P%f8 4|%{P 4u%c 4I(%tH 4;%f88(-w 8(-w 84H- 84H- 8I`- 8e- 8Ph. 8q8.J 8G.j 8\ .q 8q8. 8^x/ 8s/ 8Wp/# 8Wp/;h 8`/Ix 8n// 8x@/9 8q8/U0 8/Ix 8x@/` 8/l 8g/} 8g/ 8R/ 81/X 8=/ 8!/0 8*0 7ֈ0 7x0 70 70: 70w 7(0w 7t0 70;* ;* ;ϸ*ʰ ;* ;p*x ;*( ;f@*0 ;X0* ;Z*è ;X0*@ ;<* ;0X*( :+;0 :%(+4( :X+ 9+ 9+u :h+e` 9`+R 9b+P 9d+ 9H+ 9b+8 9H,0 9Y@, 9T,?X 9H,O 8x, 8h, 80, 8- 8- 8, 8`,70 70 7}x08 7t0( 7;0@ 7"0 7$h0 70 6 0 6 1f 601 61P 61P 6x1 6m2 62+ 6v2Q@ 6`2 6X2@ 6_2 6m2 6X2 6ƨ2 6(2` 62x 62x 6 2ۈ 620 7@2 62 7P2 7@2 72 632@ 63I63I 63I 6:3 604 6V(41 6E4K 6t4 6m4 6L4 6H4 65' 795h 76'H 76{ 76 84H7q 887P 8x@7 8z8 88= 98P 89 89 89 8(98p 9@9A 9*`9~ 990 :dp:[ ;: ;C:8 ;: ;8;)P <4;<4; <4; <;;  <6> <> <>X <6>g <>@ <-x?] <?` <? ;@E ;@^ ;@ ;p@ ;ȰA ;xAY ;HA ;B ;B( ;{XBA ; C ` ;C_ ;pC8 ;vC ;`C ;Q(D2 ;5D0 :D( ;xE :E4h :8E0 :E :Ex :E :tEx :fE@ :i F* :FW :~8F :F :G] :bGf :<HH :THE :H> :]hH_X :~8Hf` : H_X :H9 ;HU ;)PH+ ;)PHQH :HHv ;H} ;H : HH :H ;H0 :H0 :`I :ҘI :xIL :Ie :Iv@ :I :ĈI :xI :I :I :I ;xI : I :`J :J& :J=x :JP8 :PJb :hJR :~8Jg :tJ :J :i JP :fJ :J :_K ::@KX :[J0 :JJ :7Jx :OXJ8 :0J :38J 9J ::@Jh :38J :"J :"J 9J 9J 9܀J8 9Jx 9J 9Jx 9J8 9K0K 9gPK: 9|hK. 9pKp 9Y@Kp 9J 9HKx 9K3 9PK. 9K% 9K% 9K% :'K*0 :'K?H :CKFP :>Kd :'Kd :,0Kr :"K` : `Kd 9@K~ :5KX :K :K : xK 9HK : K 9K 9 Kh :CK( :XKh :bK :_Kh :hK@ :mK0 :kxK :K :`K :yKh :[K : K :K 9K 9KИ 9K :K :.K :pKx :HPL :<L" : L8 :L$ :38L5` 9PL> 9L :pL :"L : xLyX :ELZ :5Lf :OXL :38L` :,0L :)L :fL :.L : `LH :0LX : L` :0L :HPL :JL8 :L( :MM : M : L8 9M :M :hM :hM$p :7M :)M$p :JM4 :M+x :38M\ :w0M :bM70 :@ME@ :XMG :V`Mop :EMa` :Mj : M{( :0Mm :.M@ :7M0 :HPMH :dpM :rM :HPM :HPM :bM0 :dpMH :@M8 :rMݘ :N :kxMP :yN :XN0 :N :Mψ :N x :ҘM :M :MH :M ;MH :M :`Mp :(M ;MH :M ;N ;(NB` :@N@ ;N8 :XM :HN :N :٠N&@ :(N! :8N :XN8 :_Np :ND :fNg :NN :`N^ :N= :HNIh :NIh :Nn :w0Nq@ :NP :N` :Np :N` :ĈNu :N\( :8Nc0 :NG ;NG ;(NR ;N\( ;CNIh ;NY ;<NY ;Nz :Nz :Nc0 :8NxH :@Np :N :N :hN0 ;Nڸ ;N` :N ;N ;9N( ;(N ;X0N ;Ng ;ϸNxH ;@Np ;vN ;oN ;SN` ;qN̨ ;hN ;@NH ;@NH ;CN ;8NŠ ;CNx ;HO ;xN0 ;xN ;8Ne <NK L'P >PKP >Kɐ >K >iXK >Kp >Kw >PKO >:xKFP =hK =J >JK >T@JD > J# >׀J* >I0 ? Iʠ >XIj ?7I/ ?PI ?+H ?0H@ ?y8H ?H@ ?H ?HX ?H8 ?ۨH8 ?HP ? HX ?Hp ?y8H ?d Hp ?vH ?)H ? G ?5@G ?Q`Gh ?Fb CLF8 CEP C`EcH CEcH CZE2 CwD֨ BD\ BDEX BXD7H B@Cو BPC B(C B CCB CC B CC B8C BаC BPD CDc C(Dc CDh DGDP D(D ED E 8Dm0 ED} EIDZp ECXEC EC EC FDHC FDHC F,C H F=@B F,B( FDHBP FPBа FTB FXBX FBFh F B[ F B1P FB FB x FAX FB' GB GB*H G B G BY( FBi FB` F0BX FxB@ FeB FDHB FFC FBp GhA HA HA HXA H)p@ H+@hH H>@\ H+@U H0x@& H. ?p H? H? H"h?ۨ H. ? H2? H? H7?h HN?} H ?r0 H?] H>?o HE?O HU?_p Ho?Q` Ha?m Hr?] H?9 H}?.8 Ie> Ie> Iq> IX> I(>~p I> I>iX J6p>A Jn>< JY>< JR># Jzh> @ J8> J(> @ J@> J> K*0> @ K =x K5= K<>H Kɐ> K= KИ=հ K=8 L_= LQ=B L_=0 L{2)h H<02> HS2> H>2E HG2Z H. 2> G@2k G@2k G2{p G2 G2 G2 GH2k G2v G2 G~X2{p G2 GpH2r G.28 Gx2k Fh2 F2 F1( F32\ F*2E E82Q@ F/02. FY`2+ F[2P F1@ Fx1 F1{ Fp1Vx Gy00 Gm0 G'0p G 0D@ Fp0O G (060 FH/ F/K F/n F/4` F/ F/G F/ F|/9F|/9 F|/9 Fl .` FY`.` FKP/ FW/( FM.ݨ F1. F! . F((. E.q EG(.B EP.EP. EP. E4h.>H D.$ D`.- D.9 D.>H Dt8.)0 D2.+ D+.S` D(.>H C.$ Cm.m(Cm.m( Cm.m( Ct.h CH8- C-X B׸- B(- BH-dP Bg8- B(,Ш A,@AX,@ AX,@ Ap,0 A`,@ A`,@ AU, AY, A, A?, Aeh,g0 AR,p A|,Tp Asx,A A/,% A, A ,x @, p @@,*@ @,( @0, @P+ @h, @P, @H,% @H+ @8,0 @x+` @+0 @a@+X @B+ @{+ @c+ @E +̀ @E + @\+ @Z8+X @E + @P+ @+ @+ ?+@ ?+X ?`+ ?`+` ?+ ?t+0 ?Q`+ ? (+P >+ӈ >+( >+ >8+ >~p+ =+ =n+ =[+ =e0+u =Rp+q =`+q =M+I@ =x+& @C D hDx y`DX DP xD tD` ]@Dp Dq "D\ O0Dt8 %D C XC C C C |@Ci hC_ CC bxCL ]C" AC %C C `B0 xC@ B Bа ͈B` `C.p C0 C C@ D( sD  xD( hD PD hD D @D4 8DU bDm0 0Dc 0D D D( D 8D8 wD8 ]D ڠD D D` gDax DSh XC `C BHC nC ^hCb gCQ nCp uCZ sB0 B3 Az @x @oP 8?͘ ? P?͘ "? $X? 0?͘ 7? P@ j?x hP?X @x? +`? 7?r0 W? W? j? ?p ?@ ? {?} &>8 +`> +`> 0> ^>T@ e> N=X p=l8 =i = =H ø= =g PX=; =h < < :< R(<ш < ɰX >[H ɀ>r >g (> O>` v> ? ?CP h?V ?` x? ? ? x@q @X )@ BA? XA xBMp B C H CE yHCi XxCdX SCp vCp .Y5 >%`X0 =X =X =0X8` =MWh =W Wx =W =iW| =hW ><WW` =PW= >W6 =W =0V >M8V =xVh >.V >:xV > VH > V >bPV =V =ΨVE( >V0 >%`VE( >bPVm >dVG >XV8 > U >pU@ ?pU@ ?U( ?5@U ?vU( ?ZU ?U ?@U{ ?Uo ?XUk0 ?xUa ?U) @&U9 @@pU) @+XU @NU @U @{U @xTH @U @T AT A(xT AUT( A`T AT BTwp BHT BXTg BXTV CiT* CTX CTg C]PTM@ B8Ti` BXT BT@ B8XT B1PT@ BT( A8T@ AYU$ APUE @pU> @Ua @HUo @ðUt @xU @U A-(U A1U AUU A^`Up AU AlpUP AKU` A& U AUԨ @U @ʸU͠ @cUP @Up @{V @-U۰ ?U ?Uh ?ԠV ?V ?`VH ?ۨV0 ?EV4 ?ZVS8 ?LVj >8Vv` >(V ?V >(VX >V >V݀ ?0V ?LV( >VH ?0W ? hW!x ?W8 ?W48 ?XW ?HW ` @NW ` ?@W* @&W? ?XWW` @HW^h @(Wu @>Wx0 @0W @}`W @W @X @X' A*X3 @Xd A8Xb A#Xw AehX AehX0 A`X@ A0X @X @ X A@X AYY AY) A`Y0 AHY5 A!pY< AY[ AXY[ AHY B Y{ BY A`Y AY AHYp AzYX AlpYh @ Y AY @Y AY AYِ AgYP AgZx @8Z AYZ"8 AZ@ AZJ AKZa @@ZU @ZX @Z @HZm8 @;Z ?(Z @9hZ ?vZϨ @4ZX >[ >0[X ^G B^p B_ D^` G ^r H^_` K.^fh L^"p Ox] R(] Rh]f R ]" Rp\p OF\ O \P O[\H O?\T O\W O(\3 Q_@[@ Q[h Q[ R[h Si[p SsH[P Sո[` TH[K Sh[D S8[4p T[4p VøZp XAZְ XrZ@ X0Z YZf0 ZZSp [WZx ZY Z2Z YZ YZ Z YX YY Z(Yh Z{HY Z Y [PY@ Z Ym [Ym \XY \`X \X \^Xx \@XP \X` ]VX ]CXi ]Xi ] XuP ]HX ^GX ^@X ^X _pXp _xXFp _pX`8 _X _hX8 `I8Xx aX a0X b>Xx bkPX b_X¨ bPX` bX cBX duXY0 fX/ g8Wp g@X% gX gW` gWh h8XA ipXK i X jWp kxX( lpWP nOX o X/ sW̐ sW0 tW| u@hWPX u-W/ uW u(W vW w?XW wAW wWp w(W0 x8W xW xpW xXWR yt0Wh zVP zV {RPVh {V@ |OpV |i8Ve |hVq }V( }}V( }Ve }yVW }{pV7 }V& ~UhVP ~VS8 ~VE( ~ÐV" ~xV ~U( lPU( kUh EUx U WU \V `V (V0 VE( VG BXVZ@ YVx 3Vv` V XV V VH VH s@VX #V F0W-0 WR :xWN 0Wg 'W| |W8 (WP bW W IW ;Xx X X0 XR( Xp @Xh  Xx XO ]X ;W8 sxW( WW` W` W8 0Wp >V݀ PV V V Vp V\ G(Vv` VU VP V0 GV XPU0 U( VH V& gU V HU `V@ pU 3U U͠ V0U `V 0(Ux XV B`U 8U` lU` U( UX ӰUH UP UƘ ]UP U bU TUh U U` xUx aU ;V V2h V- @V @U xU +`U U͠ hU HU HU V& pV; ZxV& (U sV@ sV V 6@U VH XU :hU V0 .(V; VB BU HU@ g(U U רU A U U @U V& 8VP 0V> V) VL0 9V@x LVaH V@x PVZ@ HV &V V BV gV !HV 1W W ЈW( WBH WF {W6 ^VH ݈W `W8 PWW` Wlx BPW^h Wlx WU Ws =W\ gHWq( Wj W :8W Wň "@Wڠ W X(X ȨX X pX G8X XA ؈X= X% X3 XH |X: dXO XO JPX eX lX @X` @X` `X IY 0Y3( oHY3( oHYOH Y ͐Yˀ _hY8 7Y XYˀ xY 8Z <Z iZ+ ǘZo ?Zh Zq Z cXZo Z KZ@ ZH ,Z iZݸ bZ aZ z[( [= ^[D 4x[x s[ [X H[ \ F\#  \^ z@\M w\[ |\l( \^ \I X\[ \@ ĸ\ *\ \` K\Θ Eh\ܨ Ā\@ "@] T]T0 ]X OP] ] G] N] ] o]P ˈ]h C] ^ @^ 5^<8 ^L ^ X^h ^p F(^P ^ _( v_ x _7 Ix_ ś_à_Ѱ _Ѱ _p `#"hn0"hn0 PC8(2X/,Z )PP߸)(c0I0*0xH @`!![9^Z@`z yb@hz83H1i0PPPPXppppppP((x K(RBLÈxÈg8xxx"xtHÈPوh(P(P(Pe@e@P7ǰJ:(<`~ 800A0%0@8p%ޘ0 ( 8% >Q +dX >x d0 m ` c `ax `ax `q ( 8Ϡ 0 h!4p!{!Wh!ZH!@|!!! (!8" )" 5!?"pi@"p""p`"-8L"!L"!L"!!X"!P"Nh"nh"nh"n"P!8!P""p "; " 8"/; "/; "/X"!"p! `!p!]!PP!S@!jE!}p8!@P!^!^!vh!0!x!08!!(! ;!ZX!HZX!HZX!Hx!h!!!H"N";H0"IX#"Ӡ#8p##:#=#gH0#]Ȁ#~##ɸvx#t $P$P$)t $J8$.4P$30$E1$w(1$$($@q@$xH%0Y%CP%Sx%tHp%%,%(l%{Pp%pp%pp%px%X%`(%%x%%7X%0%"@%"@%"@,8$y%$%xH$X%0$5$hh$tX$$$$$$٘B$$h%8z%_0%c%tHH%%%Dh%s s s( ;spX +`sn ;r( \r pr pr pr~ 0r 8rH rp r s_ ?rX sn Vs3h bs# xsH 8s# s? sn psbHs<s[@mt9t `0sAxr,+mmn8op @o(o0͈o0͈o0͈p xoPoo@#o@!`o@!`oB0p$xpxp"@oVX5orxoCyoCyoCyo Xרo Xרo XרotHotHotHoPopcph:pqqUHxqq(q(qhqߐCxrM8re( rM" rYpvrps 8{0s,`y y yPyz4`zP@zqPPzPz Xz(z̸5zf{Aw@{~{|x{|x{Ր|<P|p@}"`}Q@}r}N`}m`0}@P}X@}Q8|0|0XpV(kL@hohx@ pNXwNXsxxx#pH\qv xHpKpH000?(0@8Hp`kUNpmX85@h@I@P$PۀhH0Pa@P0PPPPP-(PHN2E\qPUqp8H`.ehuM78FHXV$h̰EXH9h2hX(ݠ0;p`G({0Hhp}hHepPܠHpXr@ wwww n0"hn0"hn0N` UDDh8H,3+@ !P`Kx HPPZXݘHXPl`-֐-009ʨ9ʨ9ʨX@= Ph'X= 1,%XVi`n0p[pP?PH(H0DxPppp?P P_rpxQِ9X0H0sE`+HpXuGh7XLc%PsT0CàdT0(6xFeXx >::0ThKh8``hH0)7)m))Ҡ)8)tX)8))H)H)H)@))84)x)98)e)k H)P`))k )]%"@%"@<%cHX%[%ob %Xr%[%P%8&X%x2%\&7h&4xX8&9(&Y&sv&8Z&0&&&0h''*'`x'p'GH'jp(z(fP(d@((((ĸ ) `)0)])])]@)p)X*I***pUX*p\`+!*8++;04+^X6+0+zxH+cX+zx0+lh+0{`+@+h&B&Bp&R(&=&B!&^@&&x&w&&b'Puh'O's'~''nHX' {'X 'P('`x)X'fH'Pj([@(0ȸ(`(`0( )())"x)58 )r()HxxYPY8|*e@PTgc x(1(HJXppgHIHh ) S _}`  `2` !}ph!_p"pp"8@" |"H"`H"n"_#*X|#R0#Tވ#$$ pH$P0$X$)@$`($`x$El8$EW $bZX!HZX!H\""D;"8"g"""H@" )# #K(P#|`H#(`#HX$T`$A@:$E*0$5,$T,$  $ˈ `$$X%7X%>`%Z%C`%\c `c `!X!f!!{@!0!X"#0"#N0"6W"U"l"Wh"j("^p"U["l`h"X"0" "0 ("P""@X"P`"h@""E"S"07"L"!h"nh"n"H"h;"Ő"p0"0["x"plX"Pzh"sj"Wh; "Wh8"/%f8%f80%Eh% (`$Ґ$H$$0$rx$L$J@#>#(J@#Xh#`v##x##kG#?pQH#"pf`"`r""#̀#p"Ԉ##((#($8#0>#1`;##n#@#P#(#zh$ ^H$`[$,($30$t$($`4$P8$(eP$b$fn$rxp$f$i$t`%\`%\`%\%% % %`ppppp6W(06HDQ`q9h .8ј>@ވuPhF0g   J~0 pRp8 h  :8 Jh JhZ r@B D! !7 <!4!L8!;38!IO!@O!@O!@0!]h!]h"u"u"",0"P#(##8h¸#TX#} 0} 0}C0 }C0 h}P h}+`||_Y|3PTP|?* | {ǰ{P{Hp{p{[|(P|<%|'H|Vx|pÈ{{{xs{Xl{I{9@{|xxlP(:zXVx3xP@![(F@MpM "h 2( fO!@|r!t|r!t{H!{p!f|r!t|r!t{@!@{p!f~#~#~߰#8#n'`n'`^@'8x'(  X(M0{)${)${)L{)}|)_h|5)v|0)h{){ǀ){^)H{RP){:* {M*-{*Iz(*@hz`*x{|{|{~{^{b{*x{O_H{60Z{60P{{FH{``{|x{RP'`{RP'`{'pz'`z'Πz0'`z(#z(Hz`(pX}y!h}y!h}!h|! |r!t|r!t|r!t|P (}7x (v!Nv!Nv`!hXv0!Pwx!@wy w` Ơw@ 0w3 "xL@xwpxwpxwpxـz} `z z zh!-{p!fv(pAv(pAv`Ave`.ve`.vq,xvx ,xvx ,xvu|(v^X "v^X "v!4vu|(vu|(vP|(vw0wu@~x0x0x0xwpvPgvPgvivzXvXhwvθvpv`pv8v`vq,xx0x0yf hyTyߨyxy`^yPU`z# z#z#zyxhy9hxmLx'`GPwh(wrPw:Pw4vXewvHvpÈvH z#z#z`8z{h{8!{eX{z(u@ Jhu@ Jhu8 :u@ Jhu@ JhuѸ v P!>(v P!>(u@ JhoCyoCynxFXn][pn M`mn0mimM`m.mUM`m8.mllPXllxl)l0xl9xڈlHkxkƠkPk`@kSk5Pjkl`kp kp kp k"Fjj`j@jPjh8jЈ-jhߨhߨh8hh i=hNph8jhʨhph(hS8hRhxl`hNXheXhhÈhiӀiXi4ixixixiijHhjɀzpjpeXjאeXkp ixixiXi@iHjypjypjypj jj8k0pk"Hkl& lްlNlL8@lL8@lH5hm!3m;H,m;H 8mmppmHn hn#P@nO8nzHnn`o XרlNlNlE0:kij<ްjCjkɘjypfX/fX/ffXhf@f`fppf%8fJ*fCWHfeXf7xf.f.0f.0fd f?@f?@f?@fOh hftf_Df_Df_Df 8Hf_Df_Df`n0fu8fn0gfPPg.g g Lf?@f?@f0ffx8Hf4f4g24gpgXgghBg78g0h0h$(PhWhh  hlhh`Hh`Hh`Hhhqh$(h&h&hh wh y`h y`h/fh!Sh9@Sh!Sh&h&h y`h`h`hii0iǰjihi@Pxi@Pxi@Px^b^b^_`H^fhup^8e^͈up^X`X_Ghe_I_z__&C_X_t_ ^^_ x^ԐS^v_(r_p^xp^͈Xf4f4fhhfhfX@fAXhf' f<f? fi0@f@mfxmfXg Lg Lg LgJg}`u%2v$vF$vq$ p&p&k$k0$8k0$8k0$8j%jQ$piu$8^"s^"s`=#`=#`=#b%qc%c& c0&$c&Rd!&Rd4X&ld0&d8&xd&Hd@'e6(&Ha*a*ahYaXlHaa`axHaHa * bwxbQb0`b:0aOЈa:` p`p Qp`@ Z` m`u `- 0_`!_S ! _B!2p^!)^!^"=Y&Y&Y%@[`%@[P$[P$\I$\I#(^#(^"q0^"q0^"q0^"=["=["=^"=Yˀ(8Yˀ(8Y(]ZX (]Zx(CZ(M0[D([x([(([([x)h\A)Z\A)X`\A)X`\e )@\l((@\P(x\)$\x(]H(](p](_(_(w`_(__B#`=#Y)Y)Z_()Zo)Z)Z)hZ)[* [4p)[K*8[H*+PZH*8Z)Z{H*8ZC*Z2*Z0H*4Y*7Y*B\%)S\%)S\,)@\KX)\P)\=H)\b*!\@*\*Nx\X*h\h* \h* \h* \*[p*h[* [*[W*x[W*x[W*xZP*{ZC*Y*8Z+lhZ+lhZϨ+[W+[Y*h[4p*è[^*8[W*x\*\*\P*P\*\*H\*]*]3`*H]h*]*]X*p]8*^ *^P+^G+1^h+j^7+\^S+lh^V+^0+ ^}+^0+ڐ^0+ڐ^d+^h,8P^,D^8,b^,r^8,|H^,^,^,X^tx,^],X^XX,^},x^-^tx-^]-J^9-H0^9-H0^9-H0^-5p^-H0^-r`]x-{]-a]-dP]-H0],],][8,Ш]V,˜]<,H]?,H]?,H\,] 0,H] ,(],u@\ ,r],Tp\(+\ ,h[؀,Tp[h,V[,w[0,y]<,H]<,H]8,x] -] -,\-@^9-H0^9-H0^S-^L-^' -0^E-8^C@-H^-^.+^͈.;^Ԑ.^.0^x/ a,.ha,.ha` .`a[p._a8H.Nax-a[p-HaH, ap,Xa[p,wag(,:ag(,:ag(,:a],F`aO,:a +`+`@, p`zp,,`eX,(`M, `&,`+_+_ظ+_ظ+_ظ+_+h_+8_vH+_z+_q+_Z(+_Z(+_9X+@_9X+p_(+_ x+^+^(+`^0+ڐ_ظ+_ظ+_+zx_h+Y_0+R`@+*_*_ *0`D*`x*`l`*q`*c` *;`*`*8`*2Xa*$Ha )XaK)aO)ar)a@)`a)tbH()Lb{)'(b)2cP)2e6(&He6(&Hfx&f(%8iu$8cP)2cP)2cm )2c) d)d(d)d`(e(e/ (ne6(&HcP)2cP)2b)vc)Xc" )8c78)c*cj*cj*Ec(*d*vPd@*(d *d2*d2*(d2*(d;`*hd/*dn*d*d2*d2*c+*c+*c+B8c+?c}+`chp+e`chp+e`chp+e`b+WPb+Rb+Rb+Rb+qbp+caR+e`aD+Ha[p+ha]+̀aV,ag(,:c@.pc@.pcN-c+-Pc>@-mc)(-V@c9-5pc2, cG,޸ch,pc)(,c-,Db,?Xch,,c,#8c, c+b+b+b+qb+qb+jb+WPbh+Rcah+e`cah+e`cN+cX+c,1Hc,wcȈ-cx-cݠ-c0.k$k$k:%kv%(ko&k&BkX&} ka('j(j~).0jd)r(jF@)}j])Xd^-d^-dl-Qdg,wdp,rd ,Ad, d+dx+ڐdh+̀dx+d+d+Td+(pd*d+d+d*e!*L e(*(e8)fT)f*L g+*gU*!g@*S(h+0*h@hs*&h0*8i**8i*Ei*(j * j])Xj])Xj])Xj*Bj*@hj*@hj*j*jޘ+j+j+B8j@+=jr+`jF@+ڐj'+j%p,,i,Ki,pi,i,i(,ix-iT-r`ig-(i=h-i8-i@-h-h-`h - hh-Hh-Hhv0-hB-h6-g`.;gX.Xg.ob+lhob+lho)+lhnh+nh+(n(,Rn,kmN,Pm=,mc ,m-l0- lX-Jk0-k-Qkd0-Lkd0-Lkd0-Lko-.hk:,Hj8,%j+Xk}+Xk0+k 8+I@k.H*8k$*k x*èkp*jޘ*ljЈ*@hj*@hq.q.q.q.pqo.q;.px.{8pϰ.p.pv.pQ .pEh.o.o~0.ȐoJ. oA@/Ho% /+n/nd/n//(n8.m(.`m.`ml.m-8/m/8m/hm/hm/hm/qPl/hl{/ek/hk/xkƠ08kd0-Lkd0-Lk>-wk-j.xj.2j@.j.Xj`.k)/k7/6k$/9kA/jHk/pkƠ08orx+qorx+qo,oH,Vo(,|Ho,~oˈ,xp2,p)H,޸p,p-p@-QqcX-qW-qz.`qo.qр.LXq.q.kƠ08kƠ08k80?k0|k08kP0``k0WjH0:j.0?i@0?i@0?ha0?hD0%i@0?i@0?i0hB0j.0?j.0?j0ej'0j0j00j`0jp0xjא0j(10j1%@j1Qj1{j01XjX1j@1j01jɀ2SjЈ2{pj2(j2j2j2j2 j82jpp2jJ2pj2hi2xi2oiH2yiP2pip2`i=h2`iF28i83ib3iR3!ix3=ie@3a in3v8i6`3Pi 03v8i3m/hm/hmx/Hl08l 0l0l10l1l1@lf1l&2k(2vkƠ2HkP3Ekp3kk83k](3@k%`jЈ>%`j>3pjX=j@=t@0t@0t@@-t@@-t@@-t8?to?xto?to?t"x?sH?xs? s@)s@\t+@oPtr(@ltt@+Xt@@-to?xto?xtv>td>t58>Vt=t=t=s=sp=8s:p=s0=s= s= r=r=Hrl0=ܸr>3pr`>Hq >]qH>qcX>Pq?`p?p?p?oĀ?SoX?Q`o~0?Zof?HoA@?oh?`nH@np@n`@2`n8h@-n3?nV?͘nO?n?0m? m? m? mAmAmuA;8m`AYm(AFlqA6lhX@l@@pl&@lAkxA#rpA(xrpA(xrARqAXqApqAqHBrB?`rPBHrwBprAHrA s ArAjrpA(xs0= s0= r=r=irDX=Irx=r(0uNx7 u-6u46Ըu@6@u 6t6vX7vX7vx 7v7v7v7ݐvX7@w07wr7@w 7xw7x7x>7xr`7yp72xp&p&p&sp &sp %Zob+lhob+lhorx+lho~0+=oE+ PoOP*`o:8*Ѹo,(* o7*o*oHn8*}Xn*h@o p*o)oC)o,()ooX)_hoT)Eo)hoy(oH(p(pp&r2r2r`2ۈr2s02sH2sT82spX2ps(2s2s2s2sp2s28sp2Zs82@s2s2s2s3s3sp39Hs3cxs_3@s83`s 83s /hs /ht/Yt2/nt]/Ytmx/vt/t/`ux/N(uI/`u/Hu/Hu/Hu/N(u8/N(u0/\8u`/lu/v0v0bv0u08u1b0u1u/Hu/Huè.v.y/@y/@yc/yf 1 yx2Zv.v.vX. w8P/wP/qPx/px/PyG/y}/Dy/=y/@y/@z(/!zl/zx.z .{.0}<(- @|- @{X,~zP,Az,hzjH+ӈzP+zxX+e`zxX+e`zxX+e`z+!hzxX+e`zxX+e`zK+WPy+nyH+e`y+z2*zU0*0zn*z*sv.v.v0.@v.vD.}u0-hu-ue-?6p%77qP7qP7q7q7q7aX7PxP8xP869= 9= 9= 9x::P:P;;;;0;h;;;<X< Php5y:75:dp5:[58:{6:ː6_:6 ;60;>h6;6<$6<6>=>=b>׀=6P? =T?P:LX: L:@Lh:tL:{L@:M:pMP:M>8;)PMB;@M;0XMH;M;\MhH=Ψ>3p=>8 =>u=>~p=g>h=h?d =x?=?=@^=@x=@vX=@vX=@=@>AM>gA^`>xAP>B? hB`?+C'h?ECA0?{C%?B(?HBx@B@Z8B@qC,@qC@hC@(Dh@qD>P@hDX@lDo@BD`@>D@@D`?{@x=@x=@=h@@F06p>6>06>6?6h?7 >72x>X7oh>7?7@?"7?.88?t8(?@8I`?8U?8I`@@8j0@;8c(@c8@X8x@08A`8A`9A9A 9iA9AP9A09AӐ:_B`:bBH:B:C);@CQ;oC%;hC.p;(BD>Dݰ> E>HE>D`?{C7B C7B CB6C `Bg8BB@BBB BB0C0B CCC7B C7B CACpB DB[DBXDShBbD{@BXDBDB@E!BEYC HEsCA0EPCiEzCEx`CExCXD`?{D`?{D?E(?r0EI?Eg?ۨER@WE@hHE@D@ D@D>P@DGA XD(AC7B(C0^C0^D(0npD)80^D 01D"00 DEX0D(0 D`0( D0( D0( E&X0FEY0#pEx`03E0%E0:E0?E0( F/HF|/9D`0( D`0( E/E/HE6/E6/sE0/9D.HDx.EP.A.A.A.A.A.B/B/HB./G B/vAX/A0#pB0/(B(0iB0wBTx0Bh0B0 B0XB׸0@C@0C0CC00CVH0bC0TCX0iC0^>%`0(>%`0(>r1>0>81? 0?Q`0x?0?0?0^@ 0A@0h?0`?/8?/?/v?H/?fx/-X?/-X?(/N(@/Bp@U/z@j/jH@hH/9@h/9@/#@//A/@A/A`.A.ȐA.xA.;*;*;U+;.+PH; 0+T:+:ː, p:,d:,Tp:,p:,n8:,0;,װ;$,0;-H;-S;9-a;S-<\X-8%`0(AX,@AX,@Bp,pAX-%A8-LAH-{A(-A-AK-AM. A(x.+A.0~>00>%`0(C0^C0^Ch0RPCt/xCf/xC3 /xB8/=C.XC.ȐC0.Ci.Cf.Cw.Cb.Cm.m(=/HN\(=/HN\(=,O80M0M 0e`000O0y@0Έ0Xx0x00N0(v`0Xp00M03-00Xh/!x/pY/\/Ix@/ 0///Fp/ 0z/&Px.x.x/;h@/-X/.֠...p/?/!x.0T2T2T4?5V5:T6t"+"+!- HSX SahXUhpy_n@CH8^8^ ^"+"+"X""^"^"-P""|"c"p)( ^ ^"^#6`#6`  ^%p%p%H%h$hp$P0$$ ֘$$]`c$CU$t(#hp#$#pƸ#Oa#Ox6806v06Ch6.P@605H5 77(77(77(7787p808-@77(77(6607P87P87P^9~^9up99h9h9h:HP:0:V:V:(:bܐ:kxH:::V:V:V:X^:^:^;o^;h;o[;o[;8[;`:::}:`:;8;8:;;;;;h;h;x <Ũ;;;;N;@;77(77(9?x9z(9z(9O09?x9?x9s9Q89Q89HQ89?x8-@8-@8U8 @9h9h99%89x_9t8"X8"X8p8 8 8 8h h ixBjvHj3qjMHsj[Xxjppjyju jihjTPj5àjHi6`-ha@i1Z(i1Z(i`hhhi8i#hsWHj j jy( jJ j'v j?8fh jpp j< jh` h`ag(h ag(h a a a(H a: a'` ag(h`| `| `u `? `|_}P[ _}P[ _cu _^w _a0 _P` _2PP _  ^p _ ^`X _ps0 _lM _}P[b:9 b:9 b)! a(9 b.`I aR be b.`Y b P( b:9 k k k27 j`.( ki 0@ i 0@ i?V ib] i*r hXX i 0@i`@ i`@ iQP ipv iKxC@ i`@i2 i2 i@ ipJH i2i i i` i 8 iH izX"p i9 iDp0 i^850 iM i ix h h hؠ i i4 i iW0 i?˸ iY ilH ilHx i ib ih' h' h0_` h QP h' h( h( h0 hh .( h28 hH( h8 h h(o o oH@ ph oOP ob nY8 n8 nV okptX oĀh on@tX n@tX oEx mhU n:} n@tXqx' qx'rh rh s. r( r,"P rhpM pM p}[ qp0 q0P q ( qҠ p okp otH nR0H mx mx nz0 n  o"` m` l(P mGw8 lHk mk mNO` m8_ mO` m 7 nR0_ nX o o_Q ob5 opAP om p)HJ pZ[ pMu0_ u0_h h i 0 ih iKx iP i in>p j L iS j{` j`a jЈ9 k>9 kS kZX8 k2 k`X8 laP\ kh jhp jx0 jVx j8X l7  lGP j`` k0 j j kO$ k$ kd04 k۸a lS@NP lE0 l l lX( m^pp mKX8 m(@ n+ mŐ mDp l l0P l l^ k԰t kyH k jH` j` jH iH0 j jwx ih i  i iM hh0` h0` h ipy h0`kXx kXx k @ k @ k > ( @ [ H 8H (  ( xx ; 3H ( )( Ę P P ph y p8{ ,@0 p8r ˠ[p O d c0 `( M P X!` ~H `  h8 X@ p8 C 0 P %8 F 5 M H` ' AX x x! h 8 >ox ox 0@  X x x ֘  !H} 4 ox@c @c ]9   wx  @c{ { > {x&0 &0  X ` c  !( &01 1  nh 3h HDP HDP !( Tp F x` ` HDP  ` } ` } L _x _ H ɐ 0` 2 ` 2 ( d(  P P ` @ O ( X  ` 9p PCx Cx P Cxh h Ӹ8 8( [Ǩ Hih ih %h : * )p lhZX ZX x P([ M *   b  ZXY Y Ո=` ܐF 0W( PF 7/P @ pؘ rߠ ' _* 8 } ` p0 0  X H ^ ( H \  +ؘ _x h 0^0 Dn ^0 ? `W(H( H(  H kPÀ Z H(xX X  a`  X  x{` mPh Q0 $ S+ 5  ($ PX  h xP w YH X 8 M 8 s. .   X w8  Ip vx xw8 t f 5`{ p0 P X   g  [h˘ @ p  c$ "P  d@ d@  % (5 Y> HX Q T xVh 8f s`f V~@ cT ; x d@ `  ` X 0 ( H   A Q A Q O ` 8 P  X ވ 1  %h @ < A O}_P }h }_P }h }y W }x @x ~h( aH ~}@  } }_P }a }h    8 ׈  ׈  h    H    |  bX 3 g  A ip ,p  ` . 0 ?0 ` M@ Ը V m [P P g S u x k@ @ d8 'H h 5X P S 0 ` h`  \ (   ( h  x Qx  .P (  ?@ g v A a px ]  _x < L 8 .@ A H . 0 ` 5H  9  .@   @ .@ (   .@ W8 0  `-i -i an rHX X Jp ~ @  h ΰ Y @ H H # ( %h p  H 3x 0 %h SH P H _ H (0 h   j8 8 π@ @ &8 ֈzP Ph c(w Y` w Y [ /Dh ̠=` P, = ; x  g PNP P+( `+( P !e 8 5 l@ =  HX  hߠ 0 vp @ P x4 !@ =` Dh Y +pi<  <   UՀ X X( <  P-@~@ -@~@ m | -@~@0p0 0p0 +p:H q8O` f 0mm m (O` J @m `kb b @C w[ _~^ ~^ ~߰p0  ~a }r }r }7x]p |~PT }XHO` }F }N< | > }3@ ~+8x } p ~= ~ ~x K( }XHX }i( } p0{%0 {%0 |0 } }H' }Xp |0AP |). {%0s3@ s3@ H   %0 gPF u3@<  <   UՀ X X( <` ` @8  VX `  `  K     @X @  @  ( @ 0H 0H X8 PH  B 0HXx Xx x h' ]0xf( f( Z x   (0 d8(   `   X  `+0 +0 ^ `2 xu \0 +0poOP oOP ox oE3 nH oOPoX oX o  oo6@ o6@ oI o@A o6@o oo? o? oW oz8 nH o`~ n(l( n@b nM oYh o?BX BX X X * X  ͠ N    $X  $X @ =& =& BX&+ (&\P &B =&X"h X"h x" >"ڨ >"̘ " X"h X"h* * X*& *B *W * * x*` + * *H (* *` 0*@ ) * (,] (,] ,k (,]P&v P&v bX&j` &xp (&h &xp X&^ &xp ސ&P &` & H&H 8& H& 0'( @' Q'F TH'W *'T 'u 'F h& & & & &v' B ' B 9` h^8 ' DpH=h H=h ` vF 1 =hp p  %p 3`. CX pb b  Pu b0 0  ۘx 0j j ` }P jE E I@ eH P E8!p 8!p !X 8! 8!pXX" XX" Z"Ő " $" H#H " +"ڨ " XX"xZ0H" Z0H" ZQ"4@ Zo" Zj!P Z@!P Z0H" Y! Y! Y!݈ Yh" Z! Y!gh/` gh/` g/@ g/ g/p g/ g/^ gh/`z87 z87 z7` z7` z7 z87xf4 xf4 xp40 xx40 x4 x4 x04 xyh4 xf4U U TX TX Tސ U p U TXSո+ Sո+ T5 S"X Sո+S1E S1E S=`X@ SwS S1ES87p S87p Sx< SG S*C( S87p 0: 0: : : :P :P -X:{ l:t v:_ `:J `:JxX: xX: ŷ:{ ū: Ź:` e:` K:` 6: 0:ħ;y ħ;y J;c >H;N X;0X Q;ĐP:p ĐP:p @:p ; ;"H ;Ep 0;S ;f@ ħ;y9p$p 9p$p 9@$x 9$p 9$ 9p$p 9T# 9T# 9D(# 9u`$ 9d$,( 9$,( 9T#81$h 81$h 8-@$< 8=$" 8I`$< 8G$dh 8($dh 8D$VX 88$Q 8#$VX 8 $30 81$h7# 7# 8 # 8-@#x 8/# 8$ 7# 7# 78#x 7#8 7# 7ݐ#x 7#8#d 8#d 9# 98# 8 #h 98#ɸ 9 # 8# 8#z 8#d8"p 8"p 8I`"p 8X"X 8|#0 8x@#8h 8\ #% 8u# 8H"ڨ 8I`" 8"p7" 7" 7@" 7" 7ֈ" 8x"0 8x" 7P" 7":dp%p :dp%p :%P :Ĉ%@ :% :dp%p?>' ?>'A(n A(n A(] AF( A( A(n@(8 @(8 @(r A`(p A( @(8A( A( A8(8 A8) A(x) A(AB@)E AB@)E An)S Ax()} AR)} A^`)r( AB@)E5?@%q 5?@%q 5J%a 5r%q 5%p 5V%0 510%p 5R% 5?@%q7p% 7p% 7%8 7(% 7P%0 7p%78%"@ 78%"@ 7%"@ 8h%5 78%"@8h%- 8h%- 80%Eh 8%@ 8h%-8%Lp 8%Lp 8=%U 81%h 8%Lp> O > O =xO( =ǠO =Op =uOp =RpO = O@ > O=MO =MO =W O =1O <O =gO =O =nO =zHP h =6PO8 =O@ <O܈ =Oh <O <ؐO` ~pOe ? Ouh >O@ >_O =,O(HJ@1 HJ@1 H<01` H71x H+2@ H2 H2 H P27x G82' H P2<( G2G G2<( G2S G2C0 G2a G2d G2o Gb82XH GHp2d GC2@ G3X2r G82m` F29 F2 G2 G%H2 F1 G 1 G@1X G 1 G81` G81~P Gx1h G1 HJ@1AR+( AR+( Alp+( AY+@ A^`+@ @x+P A+( A+ A+8 AR+(A+4( A+4(AYN AYN AN AM AMH A8M AM AM֐ AMX A@Mp AM B=M BY(M` AM AŀN ApN0 AN! AYNBN( BN( BVM ByM B`0M( BuHM B`M B~MH BM BMp BpMψ BhM CM C%Mx B(Mx CPM8 C)M֐ BMݘ BxM BɨM BM B0N( BbMh BMpN Bn@N! BAN( BHN1 BN0P1b0 0P1b0 0@1r 01t 01 01H 01p 02 010 11ٸ 01H 010 01] 0P1b001 01 0P1 01 01$x $x O(0 'P  0  $x(p (p  @  8  8 X (p4P( 4P( N8 /H =Ѱ  @h Ѱ  x8 4P(IhX IhX h h IhX  l @- c- fH(  0 0 aX  S S( GH / ( (   p @@ NPX  !͈ \`͈ \` 0X@( X@( HP `} @  `z ^ ;^ X@(    `x @  T H P d`  >rp t 8 7h  X   H&N@ H&N@ &v &` ]'  =& '&@ H&s H&N@ % % /& p&! % ڠ% `%0 % % % ň%ϰ 0%h x0%h % p% p% D%H % % @% p% \%@ \%@ I%m@ %U ;%9 \%@P P @h H@ PX| X|  Ũ8  H (  8  HP =0  `X` ?9 b<8 ^fh 6(a (7 `G  > `2  ' ` p  @ x  p x  8( X|H H  ΀    hx X  w   ˸ İ P HX" X" hV (8 Hm um s3` BhH X"9. 9. BhQ W< qHX PxX Yh K = *x 4X@ | @iH ] 9Q  (8 65 9.  F X b@ 8M( X  C M( 8 8 8*  Z`h vh H  Qp Qp t(~ I I @ P p  x ;X  ( ܨ G j X 00ܨ I  X & H Hu  u Qp`p `p | -P| `Θ # p YX 6 Wh 2h ` hh 8 ܨ H @ ݠz8 `pU`p U`p Lhs0 U~ >Xn 2  ~ X | | i p H[ 0HYh U`p` `  H  ` 2 (0 Lh 2  0 p` h x  0 @ i " H@F 3(C L%P m :0%P L8 8 :08 5 h ) :0ՠ ih ]XΘ X8 @ Q m  ǐ  X p 0  p ` P<8 P<8 Oh %h] @o o n Dhtx E x2 P<86#( 6#(;_8 ;_8 :  :t" ::@%8 :E  : : ;+0 :X ;_83xH 3xH 28ϐ 2 3xH20p 20p 2N8 2Q@ 2J8 20pp 2m`]@ 2_ 20p2G 2G! ! !@H !@H !9x !ǰ !@H P P 0ǰ p X P|x2P |x2P @Np ^L \ `Xc 8o@ ss  `   H  à RHx eq 1xa0 MS Gh |x2P  `X/ %> / & 8 %$@   P @ %p Fƀ ? @ ,` `p H D8 4 { 4 { 78 e } { @ aH f Z@  aH  E(  I  $X g ;  &H P ϐ x  ; 0 00  ox 4 {ۀ ۀ 8 Z8 x  @H  pX p  8`  0   h  ` ( 28 W#0 l' % Z3 WM` Th hY M` pg( 8R p ߨi (y X  Dp P(d KxH % H 'ר `( @ 8 d TD px (?Z ?Z ?> >@ ?Z9H 9H 9@ U 9Y@ x0 8 x0 8g ? 8̠ 9i 9H 5x8 5x8 5 5ޠ 588J 4J 4` 5 5x870 & 70 & 7UJ 7P 6ƨ} 6Sp 6(- 70 &7h`d 7h`d 7 7_X 7}xwX 7SH 7fp 77( 7 ˸ 74 6İ 6(P 70 h 79_ 7& 7UV 7h`d=+ =+ =G0 =MW =+!P !P !>( !q !hXX "( "̘ #  !o` 0 !P p X ) + 9 h 0 k d( 1( _x  x =h  =h (P i`  ` I J  T 0| X( !9x0 !P# # $8 $rx $0 TH %P ~x %h  %{P % %p h & &D P &= &8 P &P &( &K & ~x &N@ | & H ] &6 TH & bX '8 'i  '  'x P 'x Ѐ ' < 'H %h (@ ?0 (,` * (X O ) X )H 0 )d _x )  *> 0 *Gp +H P +  +j h +j +` +6 +` +& 8 + - * *x P *` > *( ) *I B *0 x *8 B * N *H j * oX * *Z0 @ ) 0 )>  (n oX (T8 B 'h 'B ( & P %P  $X $0 p $m $8 oX " P "^p # Ԩ %( ͠ $J #b "K !ր o #H

PM DC` D 8 Dh| Dp@ C0 C8H D  D D$P Dh D. D4% D K D4< DL`O D\A DZpR Dm0?P DxK D}Y DK D}: D`: Dt8 DHk DhTh Dpg( D8K D: D` E2A Eh] Eo EN0 Ep EKp E4h E@  EN0 Eo E@  EPX EN0Р EKX EjP@ El Ep E EŸ EjP E@ p EBx Ee EBx Eo 8 ER3 E@ 'X EWH( EeV8 E E E0 EJ EdH E.` EHV8 E E` El Eg EjP8 Es E ERa E6, E P D_ DkP D(J Dh DdH Dt8 D4 D"08 DPA DpA D0 DL Dm0A DXf DQS D>P_ D&a D@L DX DQA D)8Cx D>PH Dx

@ 5Q 6x;= = =@ P >H >' P > h >8  >r  >g ( >5 ( >iX 6 > P >@ IP >` p > p > N >H !x ?)  ?S  ?"  ? F ?7 48 ?] -0 ? 6 ?_p D ? K ?{ ` ?( ` ?Ɛ x0 ?H q( ? x0 ?JX ?0 | ?Xh ` ?Ԡ @ ?P ` @2` s @$P  ?H ( @  @ ( @ ̐ @Z8  @S0 @j h @8 @ @ @` p @  @ A A8 A @ ̐ @ @8 ڠ A X  @ h A @}` @ @t  @S0 @ , @;  @ H @^ Fp @Z8 O @vX i @N R( @I i @) b ? 8` @ ] ? ] @ b ?h p @H ~ ? z @ ( ?  ?Ԡ ? ?@ ? ~ ?k( ?9 ?7 ?} w ?  ?S `8 ? p ? b ?H T > ] > R( > : ?Q` 3 ?S  ?H ?5@ #H > 6 >  > >( ( >X  >bP h >:x >H Ә >  =( P = = h = ( = = x =0 8` = ?h =;  =x 8 =P #H =u 3 =W : =i K = H =P w = ] =ܸ p =ܸ p > ~ = > > @ >8 >< p >?( >( ` > ( > и >` >H  > h >pH ? (H ? h >  ?, >3( ? hC ?ZC ?.8b ?ow ?m ?d` ?.8 ? ?9 ? ?_p ?` ? ?5@p ? >@ >0 >h@ > > >H >0 >wh >@ >Vˀ >CP >Q8 >.` >' >H > > ` =Ψ =i =P =`t <`kh =Xˀ = = = = =` >n"8 >]2 >C >X > Q >t@ =/H< <ؐ"8 <ш h ;p ;P ; ;ab ;_8yx ;7`i ;&t ;EpVP ;f :VP :< :L : h :" : :@ :kx :]h @ :C ::@` :38 :p 8 :X 9( 9 ɰ 9  9 9 9 9 9= 9T 9F 8p 8 8@.x 8 7ݐ 7 P 8g 8Wp z 9?x ( 9s 9O 9w x 9|h X 9]  9 9|h 9(  9 ~ 9 :,0 p : |X 9 @ : 8 ; ; ; 6 < <=  8 " =n $X =x G >3p Z@ >5 v` < \ =n c <` j =? m < { < =Kh oX = p = =8 =X 8 =B = < =~ =p ` = h = ݀ =  = =H >?( x = =Ǡ =` >H 8 = 6( 6( 7P 8x@ P 90 H 8 ph 8/ d 7X u 6h 8( 6rH ' 6(.hǨ .hǨ / 0*x` 1T  0H y /8 wp /\8 | / /4` . .H ( . x .S` ph .LX .8 .h .hǨ.ȐP .ȐP /h8 /ep .p .08W( . ; -Kp -? .B . .G .ȐP!X !X " "H "h #uX "` #M+( "p- #6P "Xe "j( "`v( "*= ! P !ch ! ! !;}0 !X !>(p Ơ } >  y P J x !X)٨ )٨ *\ * * ( +g@ +K' +x' ,1HEx , ,d +@ +`{` *v *ja )v )LfH )GG *G )x>p *0` )`+ )` 8 )0' )_h (0 ( )٨-H$ -H$ -L .Ȑc .xv . -H -) - -y ,XU -H$+W +W ,,Z ,px ,y\` ,P -: l -@ -aH -p -0 , -A(, ,0 ,Mh? ,O, ,*@B +/P +!@ +X +8p ,  ,ؘ *j *ؘ *h *P( +q +`À +8h *h +/x *P *qx + ,?Xp +ӈ ,D +H , +jl +WT f T f TX  T Sl@ 8 S H T fV- ph V- ph V V^ P Vø V Ѐ U} U{ k V- phV bX V bX V r Vx ( V- i` U_x ] V" M@ V bXUv  Uv  VP 8( U'8 ,p VP A U{ TH T < U ` Uv E E E ` Fgp 0 Es hP E@ N Ex L0 E( 7 EU8 I E= 4 DP 7 D & E ) D  D 0 E 8 D E T2 T2 3 3S 3 C(3 J03 t`3 3P 3 4 4sX U`4 p4P X4 4 @5 5%x 5J (5@ h5 5 ?5H M6$ lH63 `6m `6_ (6m p60 H6 MH6ƨ h6 1(6 P7X x7P y7 X7>0 d7P 1(7; Q70 #7 7X 6 n7 Dp68 @6 (6 ʐ6 P6 6f e6a h 6H !5 H5Ɉ v5 r5 mX5 U5P L5 C(5 C(5` 25H >x5 '5X 5 5 x5 p5Ɉ Ę5h k6x 06  5 5 5 ~H6 6A 6f :P6 6yP 6v T6t@7 @7 W7 7 @76 6 6 6 06 68 606_ 06_ x6t ԰6 6t 06_yH3 yH3 yH3H 3Ѡ 4 P4- Z4/` o4i H4 4z` 4x א4 4 H4 40 4` 4p P4 b4 `4sX 4sX 4 `4sX ?84sX Q4/` b`48 J4Y ]4| 4| ɀ4sX `4- 24!P 3 Z3Ѡ yH320 20 f39H 03 3 3@ 4 4H Ơ4 3 X3e 2 2P 2 20?82 ?82 b`2 2 2@ ]2@ ?82 04lP 04lP 4| BP4h x84 H5, g588 4@5# 5 #4 84 04lPؠ2 ؠ2 P2 2H cp2P o(2 ؠ2 'T 'T 0'@ ' /( (p ( ( (( (x )  @)Z )d @) ݸ) ) ) 0) )X -h)H R) v)p )X )۠ @)0 ) @)p )͐ ) )X `) *+P *B *E *h *c X*P ؀*a8 *I x* /)0 X)ƈ =* D*+P 9 *4 * )ƈ h) ) \) X ) G) G)͐ $)۠ ) U)r( )@ ){ x) )] X)JP 8)O p(X X(H (y H( ( h(p (O ' `' 'B @'1 P'B `'g 0'DX 'T)x )x 8)` *x X)` ) )x* * * * * `*@ * x*x *H **x *x U*x h* x*; * h* )@*9` *0 h*x(0* (0* *p (* ՠ* @+ +4( +I@ p+` P+PH p+Y +? += +* s0+ *gx* gx* :*P (0*/8+` /8+` R`+;0 H+/x + x+( `+8 +p H+( P+ i+ڐ n+( l(+ T+e` F+x 6@+q /8+`, , ,: 0,F` ,] 5,Tp 1,r Hx, %P, O, F , M(- iH-3 m-r` Ap- F -X .- :h- 3`- (-f `-t -h ܨ-0 h.p ._ h.B .p .9 =H. `-@ P- -_ x-% -'` -7 P-dP -L -.h s-V@ W-X W-.h @(-) -V@ - X- - h,( v,H ,@ ,x 0, ,P , x- , :, W,P gx, p,|H ,h ,r H,~ , x- x- - -8 `-8 Ƞ- x-:+ :+ P+ P, #,*@ ,' ,( p+@ =H+`+F `+F X+ +H ,D H+X + `+F`+u `+u x, ,1H @,R ,p jX,p \H,O (,. , p &`+ ^+ W+X o+u 0+e` `+up* p* ;x+ K+ h+ cP+(p + +# +K U@+g K+ `+ + Ϩ* p*p*8 p*8 H*X `* ِ*p h*P *8+* +* 0+x + kh+ X+P + h, , ,Tp , k, ?h,` ,w ,] >+ d`+ p+ ]X+lh + kh+g m+WP +- `:` `:` Px: Y:@ :r : X: ^:`? ? ?E ?+ ? h ? X?+ ?-GM -GM W0Gm W0G /XG G[0 -GM I& I& H H H H H X@H \GX 0Gp G` G 4H P jxH zH H0x @G@ ߨG8 G /XGҸ ^8G0 bHH MH ;HH H̀ -H` *I( pI xIh I H `H ߨIx ʐH I- I- I\x xIc eINh IZ I> 4I6 I6 I$8 PI6 I$8(G:` (G:` @Gi@ pG GHp (G:`XD XD vD qE@ E E! pE E( E( ahEBx 9E6 E@ E XD7` 7` 7ֈ 7@ @7 7 P7X 7X P7P &7h 70 7` 7 7 Np7 j7ݐ ^7p x7 `7ݐ 7 9K0 9K0 9A 9 8x H9@ h9 H9 H9= 9: 9K0wHU wHU HJ@ |HH0x ¤ HX kH` “H ¡G G0 n8G8 |HH g0H ˆH VH n8G@ VG8 yG KG H"h G Gh Gh hGĨ G HG@ G lhGx nH  FHS H_X 0Hp 1HX H `HH ѸI HH 8I I `I xI jI0 }XI4 h@I! PI4 UIB 2XIG` &IS -Ia( pIs I HI I _hIp I I0 `I I0 J ހJ 0J(` xJ J!X J- J(` `J6p JB( JD JT JW@ XJlX xJP8 JeP w`Jj w`Jzh Jn |J| ~hJ J( QJ8 T8JX w`J@ J fJ J w`Jx PJx J@ ]J ]K K KX sJP J J J J0 xJ( J# J8 (J J I hI@ ѸI( IØ I I I0 1I =I FI x I I@X XI9P I6 PI9P I I( I9P IX Is hI}H I I Iz Iq Ij 0Ic IL lhII WPI9P INh IG` xI9P 0I2H xI4 xI kH bH –Hk HN wHU)K )K EK3 $K< JPK< LKMX Kg K5 Kp +K G< G< +G:` `G| ×H "HL H2 H0x H ޸H' ɠH` H 3G` Y G8 ]F HF0 װF`h F^ hFY` hF: F3 FP pE8 E8 ˜E `E E E »E Ex` ²0E ´Ex` šEg ½EY ŸpE\@ ´EK EK šE\@ |HEN0 iE$ ‘`Eg iEK D DD֨ #8D D (DP D hD pDX DX Dj Dx PDj  Dx %D *@D OD RD0 g0Dx ŠXD u@DȘ ŠXDݰ ¨D@ ¶E ɠE! ¦xE ¦xEP @E! »E6 xEg ޸Eg hEz EqX E Ex E E E XEP xE E "E 5pE V@E H0E 5pEz LEh XE yhE dPEH {EP ÉF åF ÐF  ÎFp êF(( -FRX \FKP ĥhF F% FRX F Ğ`Fp ėXFX ĜF ĒFX UF F G<5` 5` %5: 8h5bh gH5~ 5px H5# 5`gH5А gH5А w5 6 6'H uX68 i5h ?p6 gH5А5 5 C50 rx5@ h6 X6 p6$ 05H 5P6 P6 6 h6 26 26p 6` @6 P6)H6 )H6 Sx6.P G6H h6]0 6 7X6k@ 06x )H6}7 }7 (7- 7aX 7c 7f 7G 7" x7` }7 <0 <0 (< ;+ t;7` t;$|9 |9 d9w X9 |:  9H 9@ 09 (9 |9x:y x:y :T :E :,0 :. :i :w0 0: x:yv) v) a*( Q8*0 v)X9 X9 8ڰ F8 F9 X99( 9( `P9 X9 9(;0 ;0 ;p ; ;0Ȁ=8 Ȁ=8 ;ϸ ;ϸ: : :` : :8;@ 8;@ X;. P; ; H;. 8;@0.q 0.q . . .o .qw/&P w/&P /( /H / . . x.p . H@. f. X.q 5.{8 P.X .hx H.Q .>H .Q .@ ¨.7@ . g@.7@ .& z. -8 p-p g@-ـ O-p :- -x - - P- .ap \.ap BH.x `. Y. !x.0. . .x. x. {. v`/ x/ 7/x (/ "0 00% 0% P0A p0A 0F 0w `0 0 0h 0 0X `0 0| | 0s u0 C0 0M!x.0 !x.0 .. . p. .ݨ x.0.ap 0.ap {.ap . . E@. q. . . ݘ/( ψ// `/6 / ̨/ 0 Ӱ/ h0X p/ 00P 0, R@0np D00/( e0/( 0M 00 08 0 0H %01 k1 10 :H1Vx %01M :H1[( dx1M 1%@ 1Hh 1p@ 1r `1 1h 1 @10 p1 1Ұ 2 x1 7h2 Ex2 S2 }2@ U2 h2 fH20 L2P {`2X 2 2 P3 p3 &x36 3v8 3 3 4& H4 4 4n 4 N4u _@4 ٨4* x4  3 3q 34 M2 H2 2)h 2"` 1p 81 p1d U 1J 00 (0 !0z( 01 01 }/ _/ /jH x/^ Jx. ,.H 0.ap0.ap 0.ap {.ap . . E@. q. . . ݘ/( ψ// `/6 / ̨/ 0 Ӱ/ h0X p/ 00P 0, R@0np D00/( e0/( 0M 00 08 0 0H %01 k1 10 :H1Vx %01M :H1[( dx1M 1%@ 1Hh 1p@ 1r `1 1h 1 @10 p1 1Ұ 2 x1 7h2 Ex2 S2 }2@ U2 h2 fH20 L2P {`2X 2 2 P3 p3 &x36 3v8 3 3 4& H4 4 4n 4 N4u _@4 ٨4* x4  3 3q 34 M2 H2 2)h 2"` 1p 81 p1d U 1J 00 (0 !0z( 01 01 }/ _/ /jH x/^ Jx. ,.H 0.ap 0#p 0#p ~/ rP/( / p0 0%^2h ^2h /2\ 2X 10 11( j82S j82d ^2h0 0 1" 20` ZX0 t 0` 0 X2@ X2@ 42y GH2p 2ۈ o 3 83! ch3$0 2X H2 2 `2m` `2Q@ 2Q@ 2k 2k 2G 2C0 (2 (2 B28 ^03 P 3( 139H !@3( 34 3 (2_@0H _@0H S0h @0ܘ "P0 0`00 S0 _@0H0 0 80 p0 0P0` P0` >0H Q00 {0H P0{0 {0 w81 0 .0 {1,80( ,80( (0X `0 0` ,80ǀ.0X .0X .0 @0@ .0p0^ p0^ 0~ 0b 80O 0F p0``0M 0M 0`` x00 0 H0( 0` 00 H0 0h 1C 1p@ ո1p@ 1 Ǩ1 1 H1` 1` x1x `1 ,p1x TH2+ ?02r X2x d2 u2Ԁ bX2 n3 @3` 3! 03 h3 3$0 3 h 23 CX2 J`3 S3e 3B 3P x3- 3 $X3; 3- &3; I3- P3Z p3I (32@ 3GX 83L P34 @3N` 3\p 3GX 3 3cx 3( 3 2X (3x ̐2 02( 2( `2 2 H2 H2k x2k 2@ x20p x18 2$ '2 Mx1 V1 |X1 i1Ұ ~1 b1 g@1_ 1 0 008 (0 "0 A80 0RP 00O 0H P0*x |X/( /p p/ / uP/̸ |X/ K / d/p A/s *P/v k/v g@/\8 |X/qP /g nH/G ]// w/&P?05 ?05 5` 5k 5[` 05ip H5] Ƙ5MP 5:ø5P ø5P 5` 85P q(6 66.P *6L p6Jp #67 6 p6 ø55 5 6 6H `6Qx X6V( 6> 6> `6 85D6 ( D6 ( uP6 6: 6> 6) 6 5 5 ¨5 6 85h 5p 6" h5p >6 ( [6.P X6: 6> 56L 6L 6'H X6O ,6rH x6d8 63 06 D6 (C6 C6 x6 H6 6H x6H >X6( 0H7 7 7P 6( 6Ͱ H@6P 56 C65 5 Sp6 6) 6 p60 60 9 6 cP5 cP5 K5 \H5ޠ q`5h U@60 \H6) -h6: 6S 6E 6V( Zx6Z 06E p6O `6: 6 X55 5 h6 ( 5 5h 6) 6 @ X6x 5?5 ?5 X5X `6 86 ,6 KX5 6@5 ?56 6 X6Z 6 f68 6.P 6Z 6 6 h60 068 7" h7H :7 65` 5` m5P 5` p5p m5 X5А 5ט 515Y 15Y ?5d /p5k /p5 5ט 5ט 5 5 05 15Y4h 4h 4(4 4 yx4h p4^@ H3h ~(3z 3Z 53h( .x3Z 3$0 .x3 3` h2 Q2 ]X2 p2 kh2 1P 1 `1 1p@ 1~P 1p@ 1Q 01' 01 x 0 01p J0h h0 0ܘ $0H \H0h o0P 0 100 P0 KX0 s00 0| 0P ?10 !(1< p1J 1< z1' Ƞ15 1" f018 1%@ 1? 1{ 1 1( (1 )@25 h25 1 10 81 K1 l1ٸ K1˨ z1 1 @2 p1p W1( 2@ 2Z 2} P2m` 2 2H p2H H3 @3 (3+8 3S 3h( B3 23h D3 Y3 \H3x cP3 K3 9 3 3 4 4H x4 8 3 3 {H3 G3a a32@ c3` U2X c2P 7P28 3p p3; 3ب 3( 4Dx 4 `4x 4hx. x. p/6 wX/;h / y/ ~`. x. 2' 2' 2C0 29 2U 2N 2' cP2Q@ U@2<( e2 2 025 2 2)h82XH 82XH `2\ (2y 82 ,2o 82XH82k 82k Hx2o ǐ2x 2th 82kI3x I3x R4(X 9 4F @(4` -h4W8 &`4g !4[ 4eH 48 4 I3x}3 }3 4 40 s4 jX4I( 4Y `4q W4x @(4x 4p4u W4M cP3 z3*3& *3& (3& 34 3I 3I X3q y3P 13j 3GX 3- *3&JH3` JH3` ƀ3` 3p 2 $@3` 3( à3e 3 9X3E p3E 3W 3GX 34 H3E tx3W G3 $3e 3- >3 JH3`4p 4p 5 5< H5' P4 5P 4p4lP 4lP 4 `4 Р4 4Ǹ 4 Р4 4 4h (4 `4( 4( 4lP29 29 H2+ $29 E2S 82fX 2U 291 1 1 H1 "p1h X1x 1ٸ 1 1˨ 1 h1x 1XX0T XX0T L01 mp0P 80P 0h 00F XX0T1T 1T )x1,H $1T 710 mp1( 501 P1 1F 15 0 0 0( H0gh 70: h0e 200 20p 0X `0 $0X G0 >0 JH0 0 0H 0@ N1p @1" 1A` 1T 1r 1r 1X 1p 1( P1p 1{ 1 X1 x1p 10 h1h h81` 1` s1 1rz2\ z2\ 2 e2 !2y z2\5~ 5~ @5~ D5 -P5 6 }60 p5X p5~T6t T6t Ũ5` 5 P5P qH5` Y58 \05 /5p #5 Ip5P 5d \05] &H5] p5< U(5C 5 #5p `4@ @4 4 04 P4x 4x 4g 4b G4& 004!P X4& 3 "3 ר3( ް3` 03` 3p 3 3 3` 3 w3 d3h( d3}@ H3Z O36 p3& i3 M`3( K3P 8H3L A3cx '3 .3 p3x 3x 3s @3cx 3@P h3@P 3 `3 j2 [2  2 2 p2 %2 .2 .2 32( K2 O2H R2( bx2@ Y2p |@2 i2` u82 ]2 r2 K2P 2 2H 02 l`2 sh2 Y2v eX2\ R2XH `2G F2C0 P2C0 822 @2> 2G X29 2 01 P@1Ұ 1x H1 ,1` |@1` 1 10 29 2\ 2 3` 82Ԁ P2( ް3p 3p x39H H3I S3E 3 2ۈ 2 ;2 42m` 2> 02 2 / 2 T2O02Q@ O02Q@ 2k 2} x2k L2\ O02Q@H(1 H(1 h1Ұ h2 H @2 ~2 H rX1p J1 ;5Y" <hY ; Y <X ;vX ;X ;&X( :XX :@X :~8Y 9X 9OX 9gPX 9Xɰ 9X 9hX :{X :HX :38X :OXX :ҘX ;X :X|X :Xi ;yXi ;ȰXT <`Xi ;X ;ȰX( SX B Sp BаS BHS ByS DxS DxS Dt8R DXSp DxSCTH CTH CҀT: D(T` D T3x CTHC HT׈ C HT׈ BpT BT BPT C"Ty C `T CLT C0T CfT( C HT׈:٠[ :٠[ :\!( 9\R` 7\(0 7N\X 6o[ 6v[8 6[ 8R[ :٠[>M8\ >M8\ <] M8\B]V B]V A] @]( @E ] ?]` >] @P] A] B]VI6\A I6\A Jp\u Js`\p Ia(\ J\ JF] J@] K ][8 J]f J]y J&] F]( EP]( D0] FX\@ H\R` I6\Aݠ ݠ  h ( h  wLP Y@_ u`9 Tp ph Ƹ P w s Hx T ( H : /x `  h @  P ` XEH nEH H& !9 ֈϐ  xP Kl 1^ #N \ qH c(` 0s x @xP dxP i` ?xU( = Bh R8;` ] p6 gP u`* px sX ݠ  x  =Ƹ p #@ h ?`(  8 x  ) <p 'hX J i <  0 ŀ ` eh K U P@ p - Z` q   7f IN 4G c00 Z8  P @8 @8 p H P (! A 6H ŀ1x ` 8X X sH xe8 T hI * `I 2T ysH 0sH %^0 % XB M u p U  ?x Op Pp PX lh ! (  ܈X Xu u v vuZx vHְ v@8 vPH v P v u` v!hְ v1 vg v|ݸ v^X uH{H upP uxo u u_( uʰ u4 u` v!hZx v>X vKQ vlh@ vI@ v P v& u uwШh wШh x%F xV@M xXe x7 xHp x" w  w0 w wp w0n w?X3 wD wPF wX8 wKX w=H w/8 w@ wp w w~ wX wШ w w wp ws( s( t<@( t(` tX t;x tƈ2 t` t>cP t58 sPx s s? Ϩ s s|x sP s  3x H Ho Ph h H P@  x  H ! ^0E  8 I @ mP* ٨ H x e Ux P@` P 8 ΰ2  h   .y :Hp { w8 `p )x Z  ` th (    pE  [ P p0h {  {V h m 3@ (0 5   8 (h   %0 50 " h   ( `  ( uh@ x 0 h  Հ  r(h r(h r,P qs0 r:| rT rP r  qX q r(hq9(^ q9(^ q4x qgx q9(^  3x H Ho Ph h H P@  x  H ! ^0E  8 I @ mP* ٨ H x e Ux P@` P 8 ΰ2  h9 9 rx >pظ 9   .y :Hp { w8 `p )x Z  ` th (    pE  [ P p0h {  {V h m 3@ (0 5   8 (h   %0 50 " h   ( `  ( uh@ x 0 h  Հ  Ѩ_` Ѩ_` h50 n @ ` `E ذk  D HH *0 R͈ &8 & (` Ѩ_`8 8 WXX 8d Wk Ș %: %: x`p X H ` p ,  ?P Hk h x p P  RX %3 #x7wШh wШh x%F xV@M xXe x7 xHp x" w  w0 w wp w0n w?X3 wD wPF wX8 wKX w=H w/8 w@ wp w w~ wX wШ w w wp wz̸?P z̸?P zk {n0 z z z z`8 zP zx z zhH z> z`'X z 0S z&P z8@ zBp.` zjH@ z^ z zpX zs zx zP@ z z { k zxi z̸?P}  }  }e }Q@0 }kH } }pfh }pfh }8mp }mp }@ }  } }  ~(` ~=h }͈ ~` }8 } }(p ~P0 }@- }X- } }- } } }`͈ }r` }yr }Xk }9 }$ } } ~`0 ~P ~E ~h(@ @ & * q F ~( ~( ~x ~ ~I X ~<8 }<8 }XX }Z }pfh{[ɘ {[ɘ {O0 {n0 {@H |Ӏ |]ڈ |b0p |MӀ |(( {h |. |(WH |"* |Q | |( |`@ |m8 |t |Hh | = |)| {8 |h {8H {5 {k {H {[ɘzg zg zD ze` zR zph zqP 0 z* z? zM( zhX zPO z  z z zǐ z  ze zg< < ' 8 'H h : _ h 8 8 P' P<ƨ ƨ  x @@ H߈  Ͱp   ? Yh Ը| gx z8 >0| 8~ `   p| Ͱ gx ^ I I 8 JpDP 6@ (0 %  h  ƨwN8 wN8 wq` wio wkP w0N8| t | t | yH | | { } | |y |h | P | t{o {o {8 |X { | {@ {x {  { { {{h {k {ot$C t$C tX$~0 t$ t`$ th$ tH$ t$ t% t$ t_h% ( tCH$ tZ%tS%0 tS%0 t)%9t.0%@ t.0%@ t]%)H t$ t% t`% tƈ$ t$Ā u $٘ t$ tp$ ux$ t$8 u$8 t${ u $i t$Ct+%9 t+%9 s% t0%@w`(+ P w`(+ P w[x* w1H* wF`* w|H* w*X w`(+ Puh1J uh1J u1wH u1y ux1X u1 u1` u1{ vH1 u1x uX1@ u1 u 1 up1` u1 ux1vp.X vp.X vx/ v/̸ w/ w p0 vX0 v0 v/x v/̸ v/ v/ v/qP v. v. vp.Xs51{ s51{ sM01X s*18tV1 tV1 tJP1 ty01 th1` tv1wH t1t t1_ t01i8 t1Hh t۠1Vx t@1d t1T t1d u13P u(1,H u9`1,H u-1? uB1? uI1Hh uE1Vx uZ01C uc1T us1[( uh1Jr2\ r2\ s020 rP2 r82xr3E r3E r3L r3 s*3l݈2 l݈2 l2 l2k lx2Z l2Q@ m h2N m2Z l2x m2 lX2H m 28 l݈2s*1 s*1 s01Ұ r1H s1 s81{r82 r82 r2 r2 r2 r2@ r82 rP2S rp2_Ps5 s5 s5( sk5ip s5*( rh4Ǹ s4p rܰ4; r 3( r3 rը3H r3ErX6x rX6x rH6 rn6 rn6 rp6m r6s,`3߰ s,`3߰ s 4!P s<41 s54n sT84 s54 s3h4 sT85P spX4 s5C sH5H sP6)u`6P u`6P u6 uh6( u7W ux70 v7u1 u1 u{2  uh20p uq2+ u2E uW2L uc2\ uL 2\ u\2k u-2th u+P2 uNx20 u2 u42 ul28 uvP2 u>2 th2 t`2 u3 t3 t3x tH3` t2( t@2( t2h t(2( t2p t2 t}2 t2 tk 2 tv2P tV2 ta28 tL2 tQX2` t@2 tJP2 t>2 ta2  tV1sP6'H sP6'H t6> s6E sX68 s@6'H s060 s5hr68 r68 r60 rܰ6E r6( r6q;N q;N q: r(:@ r/@: r%:p rK`:p ri:@ r:@v8X v8X v8( v#8 vB89R8 v9! u09H uh9 u8 uH8 u8P u08@ u8* uH78 u07>0 u@7) u7@ u6Pv7 v7 v 8 p u08! u88X v8ڰrp:@ rp:@ rΠ: r: r:X r: r: ru: rRh: rP:ː rx: r; q;Ne%+1 e%+1 e|x+sp ei+ e`X+@ enh,h eRH+ eYP+̀ eA+ eRH+ eT+@ enh+H ew+u e%+1cP,P cP,P b,P c ,` b, cX, b8- b-'` c- b-L c`-J b- c- c - b- b. b8- b- b{- b- b- bH-h bx-p b(- b-H b- b@- b-yh b-r` b-S b-Q b-J b-H0 b-: b-H0 b-.h b,0 b8-H bH-8 b-8 b(, bt, bx,x bh,޸ bw,` bZ,0 b>,0 b>,@ b, a, b, b0,( bQ,( b:, b>,n8 bf, bp,p b{, bkP,H b,x bƸ, b, b(-) b-) b-, b0- bH, b8, cP, b8,X b, cP,P_h,0 _h,0 _P-% _-% _Ѱ-Q _-]H _Ѱ-{ _-H0 _p-dP _0-]H _h-w _x-@ _- _0-i _@- _h,0`( `( `8( ` (x `(H `)  `)h `|( `8(P `(,PL ,PL ,e ,x -8p -, -)p -7ʨ -S -Ex -]H -m -t/p -( - -8R - = -eX -8 -h -h -ـ -PH -` .XM - -iP -"h - 0 -0 ,8 ,pƀ -'` - ,0P ,޸ -P ,Ԑ ,~P ,[x9X ,|HNp ,Np# # $f $p  $x( %>`h %(Zx %+ &UH+ &2 + & &X$ &G8 & & & &6h &( &-p %H %`- %8p &P &` &x ' 'p ' & &4x % %X $Xc $& #p& #1`X #H #x #@ #v #gH #O0 # #= #,ְ "Ӡ@ " ";H "z #/ #H%H1 %H1 & '( '  'e(h ( 'x8 &؈ &UHp &@0=H &=H %R` %: %M %H17t 7t 7  7m\0 81@ 8Y 8xK 8XK 8x4X 8* 8G4X 8&H 8X2 8* 8X;` 8p4X 9:p5|0P 5|0P 5 5P/ 5A1x 588T 5|0YP 5i 5O 5X8 63 6 6 7X 7m 7 7tŨ1 1 1 H 28 2PH 2@ 2"`ް 2E 2\p 29P 2Z 2m` 2{p 2d 2H 2Hp 3e 3 4Dx 4*H( 4it 4M8 4H 4n 4sX 4H 4 55 5p 5)( 6 ( 5p)( 6& 6 2 6~2 6H8 6 6p 7  7`H 60 6H 6 6 6ݠ 6h` 6o֘ 6O H 6h 6> 6: 5p 60 6<` 5h9 5h( 5+ + ,d -)ո - -:  -p %h ,˜ V ,P k - Q -m [P -~ -ـ y -P - -ـ p - ސ - ސ -x  -S ( , x , P ,P ` - $ ,x J` ,] > ,x  + x *8  *q ~x * J +^X ( + wp + O + g + 8( , : +p ` +u 1 +  +I@ @ +  +T + +P , +%P %P %x %9ʈ %ʈ % '  'H &l( &X &;z '!098 '8v( 'H 'F ' '8 'x (* (O (Q (ހ (P (6X (0I '/P 'F 'h8 &BRx %&h $t $Pi $HB %; % %$, $h $, $kp6X $T8 $X $7 $8 $P4 #B #x# #VB #!@ ";H8 "z #(h #H "x8 "x #h( "8 " #P #: #nPqx $,(qx $C %P0WUX 0WUX 0UX 1.o 0`qx 1@ 15 1dX 0@ 1Vx` 00h 00 0 1' 1mh 18 1H0 1ٸP 1X 2@p 2"`H 2h 2X 20 2 3N` 3 3 4uP 4ʈ 5:@ 6ʈ 6Sѐ 6<` 6X 6` 6 7) 7; 68 6Dh 7L@Kp 6Kp 6Ͱw 5 5RzP 4Kp 5w 4( 4=p 41g 4 3`i 3 3X 3sH 3h( 32@sH 3L` 2C0 2<(Kp 1(T 1| 18sH 0Hg 1pM 0Րp 0Hn 0OY 0 0Wߠ / /jH .H .} . .{8 .pjp ._\` -I -PGH -&x .G /n20 /P /}z /Z 0TUX8#` 8#` 9u`H 8uӰ : :p :kx : ;}X ; ; < <` >u =* >x ?p0 ? =p <0 =3 >J P ?y8 p0 2+HX 2C 2 m 3H 2( 3(P 2 3Sx 3 38( 38 4; 3@P 3x 2h< 2X( 2r 8 2J( 2m`X8 2 J( 2h 1r@ 1h 1Mh 1j 13P 0KHy /̸S 08G /Ex /W+ /Ű+ /@ /p 1)h / 0 / / /Bp /RҠ .` .EPH / .v .Xh -k /( .@p0 /2dx .Qf .[ -hM .t0O` .&,8 /\83@ ." //x .f  h .0 /G H /8 0  0 b` Y w ɀ Mx n 3 7 3 H #H |( H A *P *   8 n  T : 4 *P 8   x :  ! X !( @ 8  !ր p "D " h "Y "  "-8 *P ! , !@ A "-8 D "* V !f K !- Y0 p b !@  !  O h " ( @ i   @ א  0@= @= l RH @=W0Hx W0Hx p      5  ?8"p X h P zX0 @ W0Hx";H ";H !>(  !GP !p@ !p ";H+@X +@X ,  + +P͈ + ,,ƀ , +̀h + ,4 ,K!,HL ,HL ,%7 +Gh +> +n + +( +`H +ڐ +X +͈ +` +@X9:p 9:p 8p4X 9= 9D 8W 98X 88 7x 7t7qP 7qP 7X 7 7P87P8 7P8 6b6`X 6`X 5P 5 5A 5rH 5(5 5 5bh 5y5 5 5dBh 5`Px 4} 4Ǹn 4hK 5 5p 5 5# p 5 4RG 41LP 4!Pc 4; 3x 3` 3 38 3 3` 3}@P 3}@0 3UhxP 3 3P 3+8(3-~ 3-~ 2 2x2x 2x 22 2 28 2@@ 2Ȉ 2`@ 2x 22 2 3x78 3X 3Uh; 3Lc 3z4 3Ѡ00 3`p 4R@ 4`$x 400 4` 4x0 4*0 46hX 3h 3GX 2 2H 2v 2_P 2E 2.~ 1XH 15x15x 15x 1 0 0` 0w 0H0H 0H 1H( 1$ $ %( %Z %9 %< %C %)H( %  $hP $P $6" 6" 6"h 6`" 6S" 6"'wJ 'wJ ']@ '> (%XH}`}zOzO{^| |wH||((|0}})h}2}a}8`}{p(}ph}(wp wp xXxa0xdPPx>zx,0xf`xO8-xtWHxanx`qxxx(Hy&HyLXXy\xyP5z`5z [pz̸?Pz(Jz(Jy\LxxxP{xP{xx{[ɘ{[ɘ{H| |:X|dH||}X}C0|8LP| | }'Ƹ}>H}ظ}ظ|~P0~P0~q+H~\p;}2P}B}eApApd?wu %xXXpqͰͰ`rHV(7ipz8ipz8[`Yhp`@K'H`k@N84p@@(xx`x`xx߈yzDzY{F9 |Q|{|8 {P{@{)@z@zyykhyݨ hy$ {`a{`a{np4{H)@zD҈ypyX0ykhyP"y$ @PE`PE`j0aHUpc}\}@JxH`h8]X{ Sq) p0 9 r R($h 3p x` x.P @p w. p ~Ǹ 1X R` BH 2x 2x @ T 3Ͱ x5X  |X8  ~X 1X PX ? H ? ?%x !x p rxrx"31@xΐXӀ)`Ӏk0pظp߀pUxE( DXzNzNe(H8Ph@0x`i+b0A ,!(H;(؀؀w:(hR.ϨϨ8He0Ϩn `(E`xA8-x3(p 8 H X D @l H XB P ڠǠ XhXhDH8 qXi&Xe @,/80#}P7Hxrh3 jXpW6yX`ְ׀H HXHCX*jXM8p8`(0hMRpgxYx|(whX(ܨh.u(H@p0-<8&QPx& h@LhvH%ظk0p F|,{``Xp ڈs *8((0(mx]@d"`@h@687Yx|Yx|Me KXX#h8H0#l<Xe0ְiʀLhxϸ@ f>$5h 0 H@  D @jh ӘD` zH u ň ҈҈HtCc uP  X8(}Px@~ x@gp0` x>eP8&XH 8bpX, p|uKXs`!(B(ʠxvWKlp/otpPXP9 Y0 8`' %X  p <  (:` NF m x ' {h aH%H I` P#x 9pX  ( ( DH -@ :` I wP F N~X eph M 8 P h 5( #H' K ` 3Nh ]S 8 s`XuXuX pL 8Nh d 69 Mx`PG(x- h hxQ* *(_w>,[H=H0gxK1[KXE`pˆHHH0`0`pE 0 0| " x @{ X H u wp wp   Hr $ P  " 00 g0 g r0 88 = E( k0( k0( k04p E0 ( ސ u i` 1X 1X R(h b O `h b1  xh 8 P( ( ΰ57A8P]X~(r@(`H҈8ˀCX9ِhP@")\݀҈6=pzxs-hLhhf0`U`8H.x@ yxGkh VP :0[LF )JΘ 3 # K ؀ l \  ݀ p 8   8 X 7uuv]("XΘ((*^F1(@/8x3G#d/8_`x{/88P2PPZ(8?  M[uxPH;xG0V8:0V8h%Xxp<V8H|@pxˀp|HsPXX0O P 8 , Hv Y &(@ 0 {w L0 * X( 80   7%ƀ%ƀMp&xۘ2`h Bm@@VCGHpx(H@^0pw3xDP(:1pZ@p&P@(?hoHyxYYx (*8HԐ(8}P& ˀ`@kbVJx]Xx:0xVPJkhyx @p0>@ɘ=ɘ=H=PQ30Sh PQ{Hh9Qr8r P `qh@S 7P xr 8ph+X+=2RjPjq`cRG0cPyx^]Xsx6oDepXX9 \H-۰hP !`!`%k[p g(FXP]?PH`mrp Qِ9X0H0sE`+H@(uGh7XLc%PsT0CàdT0(6xFeXx >::0ThKh8``h 8>>>>X:HXް 8 pp~DH 3 3#0Hp h-xX`26xn4 x0xUx2P*pB>>`~HpxPPh`y`8Hר'Xy`xK <h2x_cp4p+EH28s6xӸ#3 H#h@8̰phP(Z(7*pErPrPq&spLh@7Px4DpZxe@LhZx80_(XJxh5P$Xxxd0)@"80>(X.xx  d0 x T .H Jh Xh H HB N ^h0P  7  @  d `  6 IPj \o` \o` \x F ps X p( X8 VX C  `- H SH SH %  @ x P WP @ Z@ P ͠# p }H Qh(%(%X-SPP(H(Ph*P(HpIhKǰg((/`V`Php ,8X|pF^8Kx8x`܈`PÈp(P0H}8fHWS60`-.  0t0 (l@h)3Hi`,@MސOhxw@x8ٰ׈8xGvhH ߨr=hphgp)I ] (PԨT&;DpxpGPFppи8`"{hppMj@H0]0HuHW0>o(pX#)  cy1 7! H (!U!P!*"K-H#Ih#(=$ \($$E($w($P$$$h$Xp%5!%U%m@&@%%00&W&q&j' U'ZX'Bop'e('e(''`}(H(V!H!H"H"8"6P"֐##bop#R0c#N#pU#-#h@$% $% $$'x0$~0p$0%hV0%h>%%&(&e'P&&.X'@'?E'nO('(o'ܰd@(.(!@x!'P!P$!Cp!PO(!@!@!!E"L"("Wh"n("@"ڨ(`#@Up##P-#T$8#s!#6#>$"4$ $8$A@!$A@!$A@(#8#-#?ps#8@# o o 0 0f ͨX ԰ H  X!8`!!2p !x"8"P`x"&#c# `#V#nP#p#^#8#(#i`#|`p#`@H#i#M:#K(՘#]<#xb8#|`y#x #h˰#x#|`#(C8#y $@$H$5 $50$L$L $,($'xa$"h#@ '@ '@ '@} {@Xޘv0@@L<'~ẍe@?XјxP@p81 MۨlHX8`r0(EhEMH (` ) f  !8P!-!}p3p!!@"p"6e0"Kl8"ex/H"h1#w#Y8i#pn#B#`6P$P $0=X$J(@$OP $J$<`$73$PB#`l8#u#Y8p#A/H#,"W "zRp"j(g"exe0"K"-8@"6"("`!@!{!0!    : h.8VP@28286 h }8HxhH0hH08@CPL ($($5@8pmX0NUk|iX    @?(P`8IXp<c٠~8Ҩ{.t%88 ?q8 Nhn}g`yv~Hyv~HxHPx0xpx,wˠx08x8'w(Gx]Haxp{hx: w(wɠDwp^wPhw(x`@y@y2Ry\yHzXyhz@z!z&PHz=z^zWzvz{`<{3k{*x{M p{ 0|,H V |m yH|( f})h 0}v `}x 0}fX Ơ}X y5y5yXy{8'y\x9xr`x.hxـ xـ x xyyPXyzHzHz#Pz928zqPGPz\8cpzqzz zh1z80{KH`{?'{]{Ր|5|H|ɀ|0|Ġ| 5P| f{{{H`{60 {[H{]| xP|5|H|ɀ|x@|||8|8 "|_ S|X me1xϐe1xϐee e%e8hpe00ed8d\0A c PcCxcjdHb{bdHahu15u15t0pt08t`0itX03td0#ptp0:t20t /̸tG/hty0/xXt.0/tV.Nt -s-0s-Qs-'`s,ɠsu,~s,]s,3t58,HtE,'tP+PtP+ht+t+`tX*Gpt0*t8)ht`)8t)dtx)t(t(_uW(:puh'uh'uP'#uP&u4&pu &t'ty0't{'3t2'Ht'Xs'us&sp&0s&zsH&Ks&Bsp&`sx&@s%8s%Xs%t$Ct$Ct`#t0# tx#gHtP#D tP#t#%tv#8t"Hs"\s`!8tX!aPt! t sp Ơsh r@s +s s s t  (t  ot_h 8s@-,s@-,s,˜s,s,ys,Dwi+ Pwi+ Pw+Fw0+Yx+spw+8w,w`(+wMh+wh+ v+vx+@vsp+vK+@v/x+v4(+Ru+8uè*u*0u*juh*^u*+Pue*uP)ua8)u) tx(wV+gwV+gw.+?w:+ PwO+wD*k$,Y k$,Y kH,ika,Y kr@,:kXx, k,jא, j0,'ju ,Mhj1(,`(i,Hi,]ix,5iKx,=i,]h,h,(h^,gP-Hg-0g-f-f-'`fh-f_,(fx,fx,f ,e,`(e(,ieb,3ei,ei,Kei,Ke(,ke`,n8f , f:P,fb(,fb(,f-8f-f.hfp8.}f5.f .e.`f3H/(f3H/(f7.fr.f.f-hf-)f-g>x-g-3g-h-h-hU`,޸he,hq,˜\ ,r\ ,r],D\+x]*+]F +]+]+\]x+K]p+*]+&^>*(^v*^P*{_*_W*_`)_)_)0` )`j)X`)2`X) ]8+*]8+*] +- ]+I@]+\^+^+^h*^v*`^*s^H*>^H*>_*_W*_`)X_)X_)ƈ`)`j)X`)d`)d`)0`h(`h(ap(a8H(JbA (@b(%Xb( b( c$x(pc$x(cG(Hc9)+cX)@c\)ac)c)d**&dG*pd`*pd*(e#h+*cx)y0cx)y0c\)Vc;)+c;)+cI)c (c (b(xbx(b(kb(kb(Pb((Pb((PbCx(@b5h(b5h(a*8(Va (iPa (iP`(`x(c+c+c+(pc+(pc+B8c8+?c}+`cf+`cX+lhcLP+@c++c-+pc+c, c,#8ch,,b,.b,Y bH,wc,a)a)a8*!a(*Bb:*Z0bO0*bt*brX+b(+!hb+PHb+b+Xbp+HbJ+b]@,(b,1Hb>,n8_+^X_+^X`P@+&`+`*@`*(a`*oHa*a.*aR*0aY*ʰaFX*ѸaFX*8a[p+aR+`aD+Ha[p+ha]+̀aV,ai,[xa[p,wap,a,(ah,a,Шa,a,0\x+(p\x+(p\?+\l(* \%*\:*}X\#*e[*vP[H*e[*@[`*+P[Y*@[K* [H*Z`)ZX*0Z)Z()Zt@)Zx*(\,+`\,+`\6@+\i+\n+\+R\+\h+]*X]3`*]F *j],X*0\*+P\x*0\)۠\Θ)Ԙ\x)\`)8\%)S[)[h([([xh(([B(([(JZ`(M0Yˀ(`Y(Y(Y(]ZP(XZ(F(Z(M0[D([z(0[x([8(([([)s0060s0060s/ sH/Ps/0r/0rX/sre(/srF/`q/qPq؈/Pq(/qPqh/q@/vq/;hqG8/nqX/gq /p/p / p</vp+/eo/go@/Ro_/U0o0/+o]`.o]`.o,(/+n/n//(n8.m.m^p.m-8/m/ m/@lx03l 0Hl0Hl`18l1l1lq1xlX2k(2m`k2kH3Pkp3`kk83kp4j4&j|(4[jO4`j[X4xjJ4jh4qh7Xqh7XqcX7@qX70p7p7q@7tq7Up7-pָ70 p`6p6p6p(6~p6q`6~q4x6V(q+6>qP6'HqW5pq5q5Ɉq@5q5TXq4q4Yq4q(3q/3zqX3Lq!2q2q22p`1p1p1Jpx1 p<1pp&0Po00o0boP08mx0Wm@0|m0ܘl1lր1yl1 lH1l1 l@1`l1JlX0Hl80pa1(pa1(p7X1o0Րo80npo`0?n0KHnz0bm@0npm^p0Pm0@l1(l1_m1rl81rl1pl02Xk(2kP2@kH3rh4Hrh4Hri4Hr?4 qߐ4Xq4Hq4 p57p57p7X7p (7o 7po_7`o>86oX8o8Řo90o9Toy9hoH9o:]hp0:p2; p;p;<q;>hq;SqG8;Cq0;_8q;Nr:@r:@r:>sP: `s:t9Pu :ux:{vH:v/x;@v;v;Xu:u:v:v&;8ve`;Q(v;09Y@v;09Y@vD9Hu:hv:mvB8:vF;)PrAUrAUrArArpArpAr6HArBqBqBFhqBKq=B.qBApPB8XpjApAoAgomA`op A o]`AoA@oAIHnADnAnAn?pA=m̘AmAmuA;8m`AYm(AFlqA6lhX@l@@pl&@lAkxA#80``80``9H0``9M0=89T09/9x/09h/-X9/9/9.:X-:X-:J-:M-8:V`,h:J,9,?X9+9+9 +P9x+sp9`+T@0!@0!?0D@?H0!?0X?/>/H>/H>n/Ű>/`>/Ix=/D=x/&P=.=.B=.&=X.=0->->H-i>g->>-5p> -? - X?CP-7?o-)?fx-?t-?-?H,(@-,`@P,@,@,@`,w@,k@x,3@,=.`=.`>8-> @->Q-i>r->>-: >-?$-'`?@->?m-.h?t- ?-8?0-?͘-8@0,޸@S0,@,8A,8@X,x@,@,D@8,0;c9;c9;`9;9~;9= ;j98;<9:8̠:8P:w08p:i 8j0:.8 :AH7:7:p7:f7:]h7SH:570 :AH68:06 :AH6h:%(6Ը96:6yP96H:6):6096095H959595(9595~95`95O9@5,9@5 94949(494(:4:%(4:.4`:54-:f4!P:y40:P3(:3:03(:3z:3Uh;53P;j3/;y3Uh;3;Ȱ3;3X2>M82Ԁ>u28>2 >2?2?S3@P?JX3h(?Xh3I?03@-3?h3x?3?3Ð@ 3?x3@3x@3P@3x@3hA(x3lAn3o0A@3GXA3GXB 3!B3$0B x3/B`3N`B03IBH3-B 32@B03C%2CE2Cyp2C02ԀC2C2Dp2DSh2}D2DQ28DJ2HDv2HDQ2D82HD2D2D2hD2D2D2D2D2Dq3lDx2xE(2hEW2 E2Q@<=0O<=0O<0,=00:=;0=Yx0/(=s@0=(/=0>80O>*0=(0`=15=x1i8>H1`>n1>X1?@10? 1h?1@2 H@p2A 29A*2yA3A3+8B x3(BFh3+8B3BBH3(B 3+8B3`C `2CA02C2ۈC82D2 Dm02xD2D2(D2D`2pE2hE=2E2L:Ĉ3W:Ĉ3W:3=:H3/:p39H;$3N`;tP3/;3a ;3;@3X<;3<3Ѡ< 3xX2>?(2 >~p2ۈ>(2>28>2>2H? h2?3cx?Ɛ3@;3@3s@x3`A& 3jAc3jA3BAlp3BA83;Au3-A3BA3=A3-A3!A`2AM2A2vA2>@j2@@p1ٸ?1?r01?5@1>1>1>n1807)807)86868=58h5'747ֈ4I(748;P3߰8\ 38j04 89V4;9w4@9`4 983:4:,03`:V`3:3D9D9E9xE69Ev9[Ex8HEl7E7E7tEP7\E`6FP6F/06HFM6`F60E߀6E 5E5`F5FHFF5<FRX5pF,5 XF4E4qE 4bE4/`E@3E3ѠE3E3E3F`3F6834FRX3UhFgp3N`Fs(3+8F`h3xF*2\F*2\F#x2FKP2F`h3FP2F,2_PGx2kGx2kFh2{pF2oF2kF2XHF@2m`F2rF2F`2F2F2hF20F@2F2(Fܠ2F2Fp2Fp2G 2(G (2oEX;UEX;UE; 0E: E8:F,:)F`h: F9hFΐ98F9,F`8(G%H8G 8^xG 7πF7G7IGb86G˰6 (G5 GP5G5kGh5?@H. 4HL4HE4HS4Hd4HHXP4Hmh4HN4gG4`G˰4MG3XG03;G2G2PGp3Gx::@Gx::@G9G90G9G9AH9/H. 98pHS9PHQH98Ho8Hv8Hmh8H_X8=H>8#H$7xH@7H27HJ@7aXHS60HN6Hr6ChHh5H05ޠH5xH(5|0H5dH5FHHې4H4sXHQH4FH'4YH'4YH4bJ;oJ;oJF:JP:J!X:7J|:J9KX8KX8hK'8`K 7K.70Kg 7\K7"K6Kp6K86L.X6LO(6 L6L6pLư6k@L06hL6JpM60M;6 @M@6ChM6_M6JpM 6aM6d8M6xN6(N74I^<I^<IS8E^><E;p>QE+>8E>E>D?hDݰ?ԠD@@@D`@>Do@BDC@D @qCX@C@CҀ@C@C@C@@lB@@oPB@Bh@Br@B`0A^`B'AB'BFhAژBABACO@ACACxBD$BDACACAC{ABA@B׸AB׸AB@BBVB#@ABY(A`Bi@0B@B@B@eC~ @D@hHD;@B>hB>hB? hC?7CC?hCX?B(?HBx@B@Z8B@oPEcH:EcH:EcH:pE2:D:~8D:{Dh:D:`Cx:@C(;2CO@;LxC]P; C.p;hC]P;CdX<CL<@8B<C<0C<C@=C"=hC H=CL>:xCQ>dCk`>yC_>C(>Ct?)C3 ?VJb=Jb=J=e0J=;J=;J^H=%J^H=%J =Io8<ʀIo8<ʀIG`:7x9¸_98p9q8px8hp8(>@8I8u>@84H8q848;8Hhp98p89\:5t(:N:(h;f@h;:0/:0/: \0:En:Q:t@:AHRH:AHp7q7q7qP555y7+pU7+pU7x7HH7p808-@8U84xT4xT444-4@TP4=p4(Xɀ4 C`4B 4H 44!...X/4`a/Yh//X/g(/6/( /(q/@00K0@1(1[(YP1?0ܘ`00Έ0'0Pt0p1p`101]1<o11811xx1 =1@jx10\h1 1wHј1_1b0#1 [18h1pp0P00X00@[X0000h0 A0 m0 yH0 0 0ǀ 0Έ `0h 1y!81wH!&1`!f1H!65Xp65Xp5h@48ʐ4^@4!H3x%3H133Sp3$0sP2W02W02yB2\#2ox202 2a2a27xh8up8up7ݐup7V7F7}xs7Uw797p79X7&6:P6P6"6 J6rH(6`5 @585Q85Q85Y'5p< 5P.407p44|4T 4?4K"X3p)`3E303o0t`3I3-3202H282th`2}(2E82E21p1 x(pXP(pXP(8>x(\)J0)<@\* *p+4(+sp0,`,H8,a,˜c-_-x -=-I-HW-h -Z.X.$.-.Zh8...//Rh/p/P0P(P080A^80YX000@x&&h&&h%X%(8%(%X%h%Z0%dH&\P 8&07','s8J(k(k)E()P+- X+- X+6w+g{+Ƹ+x+x,4X,*@(,KG,X,X- @-t -.7@p.7@x.vr....`x//2 /xh/@ˠ/ /0  0KHC(0h.0C(1?H1]"x8"x8"h"p#Fxx##(Np$ $kp!$x%9x%X&(&&+H'P'[x'((9X)QX;) ()8*Gp*Wx*@++6ۘ+`+q+x,O>,O>,[x9X-0-0-E}-G-`-(.S`~`/r/./,X'XH'XH('H(`(Xx(pH(x(8X(F(#(1p' A' u (%X(Q)2 h)r(!$`)x!S@*7!x*\!U*{!*!+- !P+|!ZH+(!,8P"K,?X"X,r", # -x&t`&@0%&%&%qa%h`%8% (q$$Pʐ$t0# # #F$0(##@# %p$b`##א##:(#:("P-!Ѱ!"" " "(Y"?[p"BP"!(!݈'X!!o`!&@!  0.` ۸5h ͨ]@ h h!I!^!" !}p00 HSX SahXUhpy_n7880`&X0&X0&P=&-pY%&%0X%he%Ng%X(%>`$0$0##`#@̰"n"(""|"ah"p"8"YƸ!  !  0 0  Xxh O 7ޘЈ (x:Pޘ $<  "mX {hHxHx+0.qǐߨMC H 0!hX!HH"!H"iH"l3`"h"""Őn#8hR`#``p$,(8$/8$%aP%Q h%pp%@%p%Jxh$hG0%8G0%/$P$$$p$kp"G"G"?    yHx..`9 Jh} yHx#>X...; @  x g@ [p %2 b( (? zH ^h @ 8 F 6 ݀# PG  ( j@ `x  \F uw@ (7p  #H"X [ p # `T ppppi0Pvx0zph (߈M ehN8P# 8   O}ܐܐpupRH8;x8;x`(m8Sp4pXXXAxw FX<1@%X @c 4 P h` |Xp Y0JH ` HR` ߈ ?h ?hh Mx b` r   X 8 0 h # ` ø5 Z@m U @ h PSp pj J`t@ 5H  _( XqSpΰ((Sp Jm8 f0  5H Eq Sp >X `h Wkh HC  !x и-E-EDpEE4h`ED@E2E{hE/{hEBx_HEI5E-` DDXMDq.DP DN@D-HD>PiD+K@D8D-DZpD2xD+hD`c8DxPDHYDplEPxDpBhD(7A?7A?AsxЈA8kAA#A=A8A@AAHpApB B,X@BdxBBPfC C<C.C(CD(D-nDXnDXWD֨9D`;`D#D*Dp9D`Xastir-Release-2.2.4/xastir.10000664000175000017500000000435615151324131014725 0ustar hibbyhibby.TH XASTIR 1 "HI8GN on Apr 09 2002" "By Jose R. Marte A." "Xastir APRS(tm) Client APPLICATION" .SH NAME Xastir \- graphical application that interfaces HAM radio and APRS(tm) internet access to real-time mapping software. .SH "DESCRIPTION" This manual page briefly documents the .BR Xastir commands. .SH SYNOPSIS .B xastir .I "[options] Language ..." .SH OPTIONS The program follows the usual GNU command line syntax, with long options starting with one dash (`-'). A summary of options is included below. .TP .br .B \-c /path/dir Specify an optional config directory. Defaults to ~/.xastir .TP .br .B \-f callsign Track callsign .TP .br .B \-i Use a private colormap .TP .br .B \-geometry WxH+x+y Set Window Geometry/Position .TP .br .B \-l Language Xastir remembers the language once you set it the first time. .TP .br .B \-m Deselect Maps .TP .br .B \-p Disable popups .TP .br .B \-t Internal SIGSEGV handler enabled .TP .br .B \-v Level Set the debug level .TP .br .B \-? Show summary of options available. .br .SH AVAILABLE LANGUAGES Current choices are: .br .B Dutch English French German Italian Portuguese Spanish. .SH Usage is: .br .B xastir -i -v 2047 -l Dutch & .br .SH SIGNALS .B SIGINT, SIQQUIT, SIGTERM Cause Xastir to exit. .br .B SIGHUP Causes a restart. .br .B SIGUSR1 Causes a snapshot to occur. .br .SH NETWORK PORTS Enable these ports on this menu: "Interface->Enable Server Ports" .br .PP .B TCP:2023 Bidirectional TCP port for clients to connect to. Requires login if client will be transmitting. .br .B UDP:2023 Unidirectional UDP input port for clients to inject packets. See the documentation for the format. .br .SH "SEE ALSO" The program is documented fully by .IR "help-English.dat" , available via the HELP menu option in Xastir, plus the various README and INSTALL text files that come with the program. Also see and the Documentation Wiki there. .br .PP .B Xastir is a program for APRS(tm)... .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2026 The Xastir Group .SH AUTHOR This manual page was written by Jose , for the Debian GNU/Linux system (but may be used by others). Xastir-Release-2.2.4/xastir_udp_client.10000664000175000017500000000577115151324131017135 0ustar hibbyhibby.TH xastir_udp_client 1 2019-05-01 "The Xastir Group" .SH NAME xastir_udp_client \- send simple messages to xastir for APRS(tm) network. .SH SYNOPSIS .B xastir_udp_client .I {-identify | [-to_rf] } .SH DESCRIPTION xastir_udp_client sends packets into the UDP listening port of an enabled xastir instance. .SH EXAMPLES xastir_udp_client localhost 2023 "APRS Packet Goes Here" Currently that will inject the packet into Xastir's decoding routines and send it to any TCP-connected clients. It will also igate it to the INET if you have igating enabled. It will send the packet out the RF ports as third-party packets only if you add the "\-to_rf" flag after the passcode like this: xastir_udp_client localhost 2023 \-to_rf "APRS Packet" The UDP client is useful for generating and injecting APRS packets from external scripts. It can also be used to fetch the callsign of the remote xastir server by using the \-identify flag: xastir_udp_client localhost 2023 \-identify .SH NOTES This is a very simple utility that provides no validation of message content. The text passed as the last argument is directly injected into Xastir's incoming data stream and processed exactly as if it had come out of a TNC. As such, the text passed to it as "APRS Packet" must be a complete APRS packet, including FROM and TO call signs, not simply the payload. Thus to have it work properly, you should pass "MYCALL-0>APX219:payload goes here" as the string, not "payload goes here" (where obviously you should replace "MYCALL-0" with your own callsign and SSID). If the APRS payload provided is an object or item, and the call sign and SSID provided in the packet header match Xastir's exactly, then Xastir will "adopt" the object or item and treat it in the same manner as one that had been created in its own GUI --- that is, the object will be retransmitted with decaying intervals until deleted. This can be useful if one wishes to create objects external to Xastir and have it take control over them, but can be a bit surprising if you weren't expecting it. If you want the objects treated as Xastir's own, use the same callsign and ssid for the object as the callsign/SSID that Xastir is using, and if you DON'T want that, use a different SSID. If Xastir's callsign is "MYCALL-0" then this invocation will create an object that will be adopted and retransmitted: xastir_udp_client localhost 2023 MYCALL-0 "MYCALL-0>APX219,WIDE2-1:;foobar *202111z3501.53N/10619.04W/" while this invocation will create an object that will only be transmitted once and not adopted: xastir_udp_client localhost 2023 MYCALL-0 "MYCALL-1>APX219,WIDE2-1:;foobar *202111z3501.53N/10619.04W/" .SH SEE ALSO xastir help file .br .PP .B APRS[tm] is a Trademark of Bob Bruninga, his home page is at "http://www.aprs.org/aprs.html" .SH COPYING Copyright (C) 1999,2000 Frank Giannandrea KC2GJS .br Copyright (C) 2000-2026 The Xastir Group